1 #ifndef MAKEFILE_GENERATOR
12 static define app = ((GuiApplication)__thisModule);
15 bool eString_PathInsideOfMore(char * path, char * of, char * pathRest)
17 if(!path[0] || !of[0])
18 return false; // What to do here? Ever used?
21 char ofPart[MAX_FILENAME], ofRest[MAX_LOCATION];
22 char pathPart[MAX_FILENAME]; //, pathRest[MAX_LOCATION];
24 strcpy(pathRest, path);
25 for(; ofRest[0] && pathRest[0];)
27 SplitDirectory(ofRest, ofPart, ofRest);
28 SplitDirectory(pathRest, pathPart, pathRest);
29 if(fstrcmp(pathPart, ofPart))
32 if(!ofRest[0] && !pathRest[0])
34 else if(!pathRest[0]) // not inside of, it's the other way around
40 enum NodeTypes { project, file, folder, resources, folderOpen };
43 genFile, ewsFile, epjFile, folder, openFolder, ecFile, ehFile,
44 cFile, hFile, cppFile, hppFile, textFile, webFile, pictureFile, soundFile,
45 archiveFile, packageFile, opticalMediaImageFile, mFile;
47 NodeIcons ::SelectFileIcon(char * filePath)
50 if(filePath && filePath[0])
52 char extension[MAX_EXTENSION];
53 GetExtension(filePath, extension);
56 if(!strcmpi(extension, WorkspaceExtension))
58 else if(!strcmpi(extension, ProjectExtension))
60 else if(!strcmpi(extension, "ec"))
62 else if(!strcmpi(extension, "eh"))
64 else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
65 !strcmpi(extension, "cxx"))
67 else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") ||
68 !strcmpi(extension, "hxx"))
70 else if(!strcmpi(extension, "c"))
72 else if(!strcmpi(extension, "h"))
74 else if(!strcmpi(extension, "m"))
76 else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
77 !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
79 else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
80 !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
81 !strcmpi(extension, "js"))
83 else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
84 !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
85 !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
86 !strcmpi(extension, "ico"))
88 else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
89 !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
91 else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
92 !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
93 !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
94 !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
95 !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
96 !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
98 else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
99 !strcmpi(extension, "rpm"))
101 else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
102 !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
103 !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
104 !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
105 icon = opticalMediaImageFile;
113 icon = genFile; // tocheck: error icon?
117 NodeIcons ::SelectNodeIcon(NodeTypes type)
136 #define SELECTION_COLOR Color { 10, 36, 106 }
142 // this is so not working, why!
144 // return result was not even executed (did not step on while debugging)
145 class TwoStrings : struct
165 class ProjectNode : ListItem
170 set { return { fileName = value }; }
171 // TOCHECK: Is this isset necessary at all?
172 isset { return nodeType == file && !options && !configurations && !platforms && !files; }
174 property String folder
179 if(strchr(value, '/'))
181 char p[MAX_LOCATION];
182 char n[MAX_FILENAME];
183 GetLastDirectory(value, n);
184 StripLastDirectory(value, p);
185 name = CopyString(n);
186 path = CopyString(p);
189 name = CopyString(value);
193 // TOCHECK: Non Reentrant
194 static char insidePath[MAX_LOCATION];
196 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
197 PathCatSlash(insidePath, name);
199 if(!fstrcmp(path, insidePath))
203 strcpy(insidePath, path);
204 if(!insidePath[0]) strcpy(insidePath, ".");
205 PathCatSlash(insidePath, name);
209 isset { return nodeType == folder; }
211 property String fileName
216 if(strchr(value, '/'))
218 char p[MAX_LOCATION];
219 char n[MAX_FILENAME];
220 GetLastDirectory(value, n);
221 StripLastDirectory(value, p);
222 name = CopyValidateMakefilePath(n);
223 path = CopyValidateMakefilePath(p);
226 name = CopyValidateMakefilePath(value);
230 // TOCHECK: Non Reentrant
231 static char insidePath[MAX_LOCATION];
233 strcpy(insidePath, (parent.type == project) ? "" : parent.path);
234 if(!fstrcmp(path, insidePath))
238 strcpy(insidePath, path);
239 if(!insidePath[0]) strcpy(insidePath, ".");
240 PathCatSlash(insidePath, name);
244 isset { return nodeType == file && (options || configurations || platforms); }
247 LinkList<ProjectNode> files;
248 property ProjectOptions options
250 get { return project ? project.options : options; }
251 set { if(project) project.options = value; else options = value; }
252 isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
254 property Array<PlatformOptions> platforms
256 get { return project ? project.platforms : platforms; }
259 if(project) { project.platforms = value; }
262 if(platforms) { platforms.Free(); delete platforms; }
265 List<PlatformOptions> empty { };
266 Iterator<PlatformOptions> it { value };
268 for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
269 for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
276 Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
281 if(p.options && !p.options.isEmpty)
288 property List<ProjectConfig> configurations
290 get { return project ? project.configurations : configurations; }
293 if(project) { project.configurations = value; }
296 if(configurations) { configurations.Free(); delete configurations; }
299 List<ProjectConfig> empty { };
300 Iterator<ProjectConfig> it { value };
301 configurations = value;
302 for(c : configurations)
304 bool somethingSet = c.options && !c.options.isEmpty;
305 // TODO: Implement isset keyword
306 if(!somethingSet && c.platforms && c.platforms.count)
310 if(p.options && !p.options.isEmpty)
320 for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
327 if(!parent) return true;
330 for(c : configurations)
332 bool somethingSet = c.options && !c.options.isEmpty;
333 if(!somethingSet && c.platforms && c.platforms.count)
337 if(p.options && !p.options.isEmpty)
352 ProjectOptions options;
353 Array<PlatformOptions> platforms;
354 List<ProjectConfig> configurations;
355 ProjectNodeType nodeType;
360 // This holds the absolute path of the .epj for the project topnode (without the filename)
361 // It holds a relative path to the topNode (project) for other nodes (folders and files)
362 // For folders, it includes the folder it refers to. If there is a name difference between the
363 // file system folder and the grouping folder of the project view, it maps to that folder.
373 // This is only set for Top Nodes
376 ProjectConfig GetMatchingNodeConfig(ProjectConfig prjConfig)
378 ProjectConfig nodeConfig = null;
379 if(property::configurations && prjConfig)
381 const char * configName = prjConfig.name;
382 for(cfg : property::configurations)
384 if(!strcmpi(cfg.name, configName))
394 // For makefile generation:
395 bool GetECFLAGS(ProjectConfig prjConfig)
397 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
398 ProjectOptions options = property::options;
399 SetBool memoryGuard = localMemoryGuard;
400 String defaultNameSpace = localDefaultNameSpace;
401 SetBool strictNameSpaces = localStrictNameSpaces;
402 SetBool noLineNumbers = localNoLineNumbers;
404 if(memoryGuard || defaultNameSpace || strictNameSpaces || noLineNumbers)
406 else if(parent.parent)
407 return parent.GetECFLAGS(prjConfig);
412 bool GetMemoryGuard(ProjectConfig prjConfig)
414 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
415 ProjectOptions options = property::options;
416 SetBool memoryGuard = localMemoryGuard;
420 return parent.GetMemoryGuard(prjConfig);
422 return memoryGuard == true;
425 String GetDefaultNameSpace(ProjectConfig prjConfig)
427 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
428 ProjectOptions options = property::options;
429 String defaultNameSpace = localDefaultNameSpace;
430 if(!defaultNameSpace)
433 return parent.GetDefaultNameSpace(prjConfig);
435 return defaultNameSpace;
438 bool GetStrictNameSpaces(ProjectConfig prjConfig)
440 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
441 ProjectOptions options = property::options;
442 SetBool strictNameSpaces = localStrictNameSpaces;
443 if(!strictNameSpaces)
446 return parent.GetStrictNameSpaces(prjConfig);
448 return strictNameSpaces == true;
451 bool GetNoLineNumbers(ProjectConfig prjConfig)
453 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
454 ProjectOptions options = property::options;
455 SetBool noLineNumbers = localNoLineNumbers;
459 return parent.GetNoLineNumbers(prjConfig);
461 return noLineNumbers == true;
464 property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
466 property bool containsFile
475 if(child.type == file ||
476 ((child.type == folder || child.type == folderOpen) && child.containsFile))
489 char * GetFullFilePath(char * buffer)
493 strcpy(buffer, root.path);
494 PathCatSlash(buffer, path);
495 PathCatSlash(buffer, name);
500 char * GetFileSysMatchingPath(char * buffer)
504 ProjectNode n, root = this.root;
505 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
507 strcpy(buffer, root.path);
509 PathCatSlash(buffer, n.path);
510 if(FileExists(buffer).isDirectory)
513 if(!(n && (n.type == folder || n.type == project)))
519 void CollectPerFileAndDirOptions(ProjectConfig prjConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
521 ProjectNode node = null;
522 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
523 List<ProjectNode> nodeStack { };
525 for(node = this; node && node.parent; node = node.parent)
528 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
530 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
531 while((node = nodeStack.lastIterator.data))
533 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
534 ProjectOptions nodeOptions = node.property::options;
535 if(nodeOptions && nodeOptions.preprocessorDefinitions)
537 for(def : nodeOptions.preprocessorDefinitions)
538 perFilePreprocessorDefs.Add(CopyString(def));
540 if(config && config.options && config.options.preprocessorDefinitions)
542 for(def : config.options.preprocessorDefinitions)
543 perFilePreprocessorDefs.Add(CopyString(def));
545 if(nodeOptions && nodeOptions.includeDirs)
547 for(dir : nodeOptions.includeDirs)
548 perFileIncludeDirs.Add(CopySystemPath(dir));
550 if(config && config.options && config.options.includeDirs)
552 for(dir : config.options.includeDirs)
553 perFileIncludeDirs.Add(CopySystemPath(dir));
555 nodeStack.lastIterator.Remove();
561 property Project project
565 ProjectNode n = this;
566 while(n && n.type != project) n = n.parent;
567 return n ? (*&n.project) : null;
571 void RenameConfig(char * oldName, char * newName)
575 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
577 if(property::configurations)
579 for(c : property::configurations; !strcmp(c.name, oldName))
582 c.name = CopyString(newName);
587 void DeleteConfig(ProjectConfig configToDelete)
591 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
593 if(property::configurations)
595 Iterator<ProjectConfig> c { property::configurations };
598 ProjectConfig config = c.data;
599 if(!strcmp(configToDelete.name, config.name))
606 if(!property::configurations.count)
607 property::configurations = null;
613 ProjectNode backupNode { };
617 backupNode.files = { };
618 for(f : files) backupNode.files.Add(f.Backup());
620 if(property::options)
621 backupNode.options = property::options.Copy();
623 if(property::platforms)
625 backupNode.platforms = { };
626 for(p : property::platforms)
627 backupNode.platforms.Add(p.Copy());
630 if(property::configurations)
632 backupNode.configurations = { };
633 for(c : property::configurations)
634 backupNode.configurations.Add(c.Copy());
639 void Revert(ProjectNode backupNode)
643 Iterator<ProjectNode> it { backupNode.files };
651 property::options = backupNode.options ? backupNode.options.Copy() : null;
652 if(backupNode.platforms)
654 Array<PlatformOptions> platforms { };
655 property::platforms = platforms;
657 for(p : backupNode.platforms)
658 platforms.Add(p.Copy());
660 if(backupNode.configurations)
662 List<ProjectConfig> configurations { };
663 property::configurations = configurations;
664 for(c : backupNode.configurations)
665 configurations.Add(c.Copy());
669 void FixupNode(char * parentPath)
675 else if(nodeType == file)
680 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
683 else if(nodeType == folder)
689 char temp[MAX_LOCATION];
690 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
691 PathCatSlash(temp, name);
692 path = CopyString(temp);
696 indent = parent ? parent.indent + 1 : 0;
699 icon = NodeIcons::SelectFileIcon(name);
701 icon = NodeIcons::SelectNodeIcon(type);
710 parentPath[0] = '\0';
711 else if(type == resources || type == folder)
712 strcpy(parentPath, path);
714 f.FixupNode(parentPath);
719 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
723 // TOCHECK: Called from JSON writer
724 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
726 strcpy(tempString, "\"");
727 strcat(tempString, property::fileName);
728 strcat(tempString, "\"");
735 // TOCHECK: Called from ProjectView rendering
736 return name ? name : "";
749 if(!project && platforms)
754 if(!project && configurations)
756 configurations.Free();
757 delete configurations;
760 /////////////////////////////
766 property bool isInResources
771 for(node = this; node; node = node.parent)
773 if(node.type == resources)
780 TwoStrings GetPlatformSpecificFu(ProjectConfig prjConfig)
782 TwoStrings result { a = CopyString(""), b = CopyString("") };
783 // note: unknown platform is for common
784 Map<Platform, SetBool> exclusionInfo { };
785 MapNode<Platform, SetBool> mn;
790 CollectExclusionInfo(exclusionInfo, prjConfig);
791 common = exclusionInfo[unknown];
793 Map<Platform, SetBool> cleaned { };
794 SetBool opposite = common == true ? false : true;
795 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
797 if(mn.key == unknown || mn.value == opposite)
798 cleaned[mn.key] = mn.value;
800 delete exclusionInfo;
801 exclusionInfo = cleaned;
804 if(exclusionInfo.count > 1)
806 if(exclusionInfo.count > 2)
809 len = strlen(exp) + strlen("$(if $(or ");
810 exp = renew exp char[len+1];
811 strcat(exp, "$(if $(or ");
814 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
816 if(mn.key != unknown)
818 char * comma = mn.next ? "," : "";
820 var = PlatformToMakefileVariable(mn.key);
823 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
824 exp = renew exp char[len+1];
834 len = strlen(exp) + strlen("),");
835 exp = renew exp char[len+1];
839 if(exclusionInfo.root.minimum.key != unknown)
840 var = PlatformToMakefileVariable(exclusionInfo.root.minimum.key);
842 var = PlatformToMakefileVariable(exclusionInfo.root.minimum.next.key);
845 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
846 exp = renew exp char[len+1];
847 strcat(exp, "$(if $(");
854 exp = common == true ? result.b : result.a;
855 len = strlen(exp) + strlen(",");
856 exp = renew exp char[len+1];
858 if(common == true) result.b = exp; else result.a = exp;
861 len = strlen(exp) + strlen(")");
862 exp = renew exp char[len+1];
866 delete exclusionInfo;
871 bool GetIsExcluded(ProjectConfig prjConfig)
874 // note: unknown platform is for common
875 Map<Platform, SetBool> exclusionInfo { };
876 CollectExclusionInfo(exclusionInfo, prjConfig);
877 if(exclusionInfo.count == 0)
879 else if(exclusionInfo.count == 1)
880 result = exclusionInfo.root.minimum.value == true;
883 SetBool check = exclusionInfo.root.minimum.value;
884 MapNode<Platform, SetBool> mn;
885 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
887 if(check != mn.value)
890 if(!mn) // all are same
891 result = check == true;
895 delete exclusionInfo;
899 void CollectExclusionInfo(Map<Platform, SetBool> output, ProjectConfig prjConfig)
901 // note: unknown platform is for common
903 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
904 ProjectOptions options = property::options;
905 Array<PlatformOptions> platforms = property::platforms;
906 List<ProjectConfig> configurations = property::configurations;
909 parent.CollectExclusionInfo(output, prjConfig);
911 output[unknown] = unset;
913 if(options && options.excludeFromBuild)
914 output[unknown] = options.excludeFromBuild;
916 if(config && config.options && config.options.excludeFromBuild)
917 output[unknown] = config.options.excludeFromBuild;
923 if(p.options.excludeFromBuild && (platform = p.name))
924 output[platform] = p.options.excludeFromBuild;
927 if(config && config.platforms)
929 for(p : config.platforms)
931 if(p.options.excludeFromBuild && (platform = p.name))
932 output[platform] = p.options.excludeFromBuild;
940 parent.EnsureVisible();
941 row.collapsed = false;
947 parent.files.Delete(this);
950 ProjectNode Find(char * name, bool includeResources)
952 ProjectNode result = null;
957 if(includeResources || child.type != resources)
959 if(child.type != folder && child.name && !strcmpi(child.name, name))
964 result = child.Find(name, includeResources);
973 ProjectNode FindWithPath(char * name, bool includeResources)
975 ProjectNode result = null;
980 if(includeResources || child.type != resources)
982 char path[MAX_LOCATION];
983 strcpy(path, child.path);
984 if(child.type != folder && child.name)
986 PathCatSlash(path, child.name);
987 if(!strcmpi(path, name))
993 result = child.FindWithPath(name, includeResources);
1002 ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
1004 ProjectNode result = null;
1009 if(includeResources || child.type != resources)
1011 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1017 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1026 ProjectNode FindSameNameConflict(char * name, bool includeResources,
1027 Map<Platform, SetBool> exclusionInfo, ProjectConfig prjConfig)
1029 ProjectNode result = null;
1030 Map<Platform, SetBool> compareExclusion { };
1031 SetBool common, commonComp;
1032 SetBool actual, actualComp;
1037 if(includeResources || child.type != resources)
1039 if(child.type != folder && child.name && !strcmpi(child.name, name))
1041 child.CollectExclusionInfo(compareExclusion, prjConfig);
1042 common = exclusionInfo[unknown];
1043 commonComp = compareExclusion[unknown];
1044 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1046 if(!(common == true || commonComp == true))
1055 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1058 actualComp = commonComp;
1059 if(exclusionInfo[platform] != unset)
1060 actual = exclusionInfo[platform];
1061 if(compareExclusion[platform] != unset)
1062 actualComp = compareExclusion[platform];
1063 if(!(actual == true || actualComp == true))
1071 compareExclusion.Free();
1074 result = child.FindSameNameConflict(name, includeResources, exclusionInfo, prjConfig);
1078 compareExclusion.Free();
1080 delete compareExclusion;
1084 ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1086 ProjectNode node = null;
1087 char temp[MAX_LOCATION];
1088 Map<Platform, SetBool> exclusionInfo { };
1090 GetLastDirectory(filePath, temp);
1091 //if(!checkIfExists || !project.topNode.Find(temp, false))
1093 // TOCHECK: Shouldn't this apply either for all configs or none?
1094 CollectExclusionInfo(exclusionInfo, project.config);
1095 if(!checkIfExists || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo, project.config))
1097 // Do the check for folder in the same parent or resource files only here
1098 if(type == folder || !checkIfExists)
1102 if(node.name && !strcmpi(node.name, temp))
1107 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1111 node.nodeType = folder;
1117 StripLastDirectory(filePath, temp);
1118 MakePathRelative(temp, project.topNode.path, temp);
1119 node.path = CopyUnixPath(temp);
1121 node.nodeType = file;
1125 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1126 PathCatSlash(temp, node.name);
1127 node.path = CopyString(temp);
1129 files.Insert(after, node);
1131 delete exclusionInfo;
1135 #ifndef MAKEFILE_GENERATOR
1136 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1138 char label[MAX_FILENAME];
1144 bool showConfig = true;
1149 projectView = ide.projectView;
1152 bmp = projectView.icons[icon].bitmap;
1153 xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
1155 GetLastDirectory(name, label);
1156 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1158 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1160 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1163 addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1164 if(strlen(addendum))
1166 strcat(label, " (");
1167 strcat(label, addendum);
1170 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1171 if(strlen(addendum))
1173 strcat(label, " (");
1174 strcat(label, addendum);
1180 else if(!projectView.drawingInProjectSettingsDialog)
1183 strcat(label, " *");
1184 if(type == project && info)
1186 int len = strlen(info) + 4;
1187 char * more = new char[len];
1188 sprintf(more, " (%s)", info);
1189 strcat(label, more);
1193 len = strlen(label);
1197 if(type == folder || type == folderOpen)
1198 surface.SetForeground(yellow);
1202 surface.TextOpacity(false);
1203 surface.TextExtent(label, len, &w, &h);
1206 // Draw the current row stipple
1207 if(displayFlags.selected)
1208 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1209 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1210 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1212 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1216 if(displayFlags.current)
1218 if(displayFlags.active)
1220 surface.LineStipple(0x5555);
1221 if(displayFlags.selected)
1222 surface.SetForeground(projectView.fileList.stippleColor);
1224 surface.SetForeground(projectView.fileList.foreground);
1228 surface.SetForeground(SELECTION_COLOR);
1230 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1231 surface.LineStipple(0);
1236 surface.SetForeground(white);
1237 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1243 int OnCompare(ProjectNode b)
1246 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1247 result = strcmpi(name, b.name);
1250 if(type == folder && b.type == file) result = -1;
1251 else if(type == file && b.type == folder) result = 1;
1256 void GenFileFlags(File f, Project project, ProjectConfig prjConfig)
1258 ProjectNode node = null;
1259 List<ProjectNode> nodeStack { };
1261 for(node = this; node && node.parent; node = node.parent)
1262 nodeStack.Add(node);
1264 // Should we reverse this stack to give priority to the per-file includes?
1266 while((node = nodeStack.lastIterator.data))
1268 ProjectOptions nodeOptions = node.property::options;
1269 ProjectConfig config = node.GetMatchingNodeConfig(prjConfig);
1270 if(nodeOptions && nodeOptions.preprocessorDefinitions)
1271 OutputListOption(f, "D", nodeOptions.preprocessorDefinitions, inPlace, false);
1272 if(config && config.options && config.options.preprocessorDefinitions)
1273 OutputListOption(f, "D", config.options.preprocessorDefinitions, inPlace, false);
1274 if(nodeOptions && nodeOptions.includeDirs)
1275 OutputListOption(f, "I", nodeOptions.includeDirs, inPlace, true);
1276 if(config && config.options && config.options.includeDirs)
1277 OutputListOption(f, "I", config.options.includeDirs, inPlace, true);
1279 nodeStack.lastIterator.Remove();
1284 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo, ProjectConfig prjConfig)
1288 char extension[MAX_EXTENSION];
1289 GetExtension(name, extension);
1290 if(!strcmpi(extension, "ec") || !strcmpi(extension, "c") ||
1291 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1292 !strcmpi(extension, "cxx") || !strcmpi(extension, "m"))
1294 char moduleName[MAX_FILENAME];
1295 NameCollisionInfo info;
1296 ReplaceSpaces(moduleName, name);
1297 StripExtension(moduleName);
1298 info = namesInfo[moduleName];
1300 info = NameCollisionInfo { };
1301 info.count++; // += 1; unless this is for a bug?
1302 if(!strcmpi(extension, "ec"))
1304 else if(!strcmpi(extension, "c"))
1306 else if(!strcmpi(extension, "cpp"))
1308 else if(!strcmpi(extension, "cc"))
1310 else if(!strcmpi(extension, "cxx"))
1312 else if(!strcmpi(extension, "m"))
1314 namesInfo[moduleName] = info;
1321 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1322 child.GenMakefileGetNameCollisionInfo(namesInfo, prjConfig);
1327 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType,
1328 Map<String, NameCollisionInfo> namesInfo, Array<String> items,
1329 ProjectConfig prjConfig)
1335 TwoStrings ts = GetPlatformSpecificFu(prjConfig);
1336 char moduleName[MAX_FILENAME];
1337 char extension[MAX_EXTENSION];
1338 GetExtension(name, extension);
1339 if(printType == resources)
1342 char tempPath[MAX_LOCATION];
1343 char modulePath[MAX_LOCATION];
1346 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1349 PathCatSlash(tempPath, name);
1354 strcpy(tempPath, path);
1355 PathCatSlash(tempPath, name);
1357 ReplaceSpaces(modulePath, tempPath);
1358 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1359 items.Add(CopyString(s));
1361 else if(printType == sources)
1363 if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1364 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1365 !strcmpi(extension, "ec") || !strcmpi(extension, "m"))
1367 char modulePath[MAX_LOCATION];
1369 ReplaceSpaces(modulePath, path);
1370 ReplaceSpaces(moduleName, name);
1371 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1372 items.Add(CopyString(s));
1375 else if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1376 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1377 !strcmpi(extension, "m"))
1379 if(printType == objects)
1382 NameCollisionInfo info;
1383 ReplaceSpaces(moduleName, name);
1384 StripExtension(moduleName);
1385 info = namesInfo[moduleName];
1386 collision = info ? info.IsExtensionColliding(extension) : false;
1387 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1388 items.Add(CopyString(s));
1391 else if(!strcmpi(extension, "ec"))
1393 ReplaceSpaces(moduleName, name);
1394 StripExtension(moduleName);
1395 if(printType == objects)
1398 if(printType == objects)
1399 sprintf(s, "%s$(OBJ)%s.o%s", ts.a, moduleName, ts.b);
1400 else if(printType == cObjects)
1401 sprintf(s, "%s$(OBJ)%s.c%s", ts.a, moduleName, ts.b);
1402 else if(printType == symbols)
1403 sprintf(s, "%s$(OBJ)%s.sym%s", ts.a, moduleName, ts.b);
1404 else if(printType == imports)
1405 sprintf(s, "%s$(OBJ)%s.imp%s", ts.a, moduleName, ts.b);
1407 items.Add(CopyString(s));
1415 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1416 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items, prjConfig);
1422 void GenMakefilePrintSymbolRules(File f, Project project, CompilerConfig compiler, ProjectConfig prjConfig)
1424 //ProjectNode child;
1425 //char objDir[MAX_LOCATION];
1426 //ReplaceSpaces(objDir, config.objDir.dir);
1428 //eSystem_Log("Printing Symbol Rules\n");
1431 char extension[MAX_EXTENSION];
1432 char modulePath[MAX_LOCATION];
1433 char moduleName[MAX_FILENAME];
1435 GetExtension(name, extension);
1436 if(!strcmpi(extension, "ec"))
1441 ReplaceSpaces(moduleName, name);
1442 StripExtension(moduleName);
1444 ReplaceSpaces(modulePath, path);
1445 if(modulePath[0]) strcat(modulePath, SEPS);
1448 // *** Dependency command ***
1449 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1450 modulePath, moduleName, extension);
1452 // System Includes (from global settings)
1453 for(item : compiler.dirs[Includes])
1455 strcat(command, " -isystem ");
1456 if(strchr(item, ' '))
1458 strcat(command, "\"");
1459 strcat(command, item);
1460 strcat(command, "\"");
1463 strcat(command, item);
1466 for(item : project.includeDirs)
1468 strcat(command, " -I");
1469 if(strchr(item, ' '))
1471 strcat(command, "\"");
1472 strcat(command, item);
1473 strcat(command, "\"");
1476 strcat(command, item);
1478 for(item : project.preprocessorDefs)
1480 strcat(command, " -D");
1481 strcat(command, item);
1485 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1488 bool firstLine = true;
1491 // To do some time: auto save external dependencies?
1494 if(dep.GetLine(line, sizeof(line)-1))
1498 char * colon = strstr(line, ":");
1499 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1513 // If we failed to generate dependencies...
1517 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1518 moduleName, modulePath, moduleName, extension);
1524 f.Printf("\t$(ECP) %s%s.%s %s.sym\n\n",
1525 modulePath, moduleName, extension, moduleName);
1528 f.Printf("\t$(ECP)");
1529 // Give priority to file flags
1530 GenFileFlags(f, project, prjConfig);
1532 f.Printf(" $(CECFLAGS)");
1533 if(GetECFLAGS(prjConfig))
1535 if(GetMemoryGuard(prjConfig))
1536 f.Printf(" -memguard");
1537 if(GetStrictNameSpaces(prjConfig))
1538 f.Printf(" -strictns");
1540 char * s = GetDefaultNameSpace(prjConfig);
1542 f.Printf(" -defaultns %s", s);
1546 f.Printf(" $(ECFLAGS)");
1547 f.Printf(" $(CFLAGS)");
1549 f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n\n",
1550 modulePath, moduleName, extension, moduleName);
1557 // TODO: Platform specific options
1558 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1559 child.GenMakefilePrintSymbolRules(f, project, compiler, prjConfig);
1564 void GenMakefilePrintCObjectRules(File f, Project project, CompilerConfig compiler, ProjectConfig prjConfig)
1566 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1567 //ProjectNode child;
1568 //char objDir[MAX_LOCATION];
1569 //ReplaceSpaces(objDir, config.objDir.dir);
1570 //eSystem_Log("Printing C Object Rules\n");
1573 char extension[MAX_EXTENSION];
1574 char modulePath[MAX_LOCATION];
1575 char moduleName[MAX_FILENAME];
1577 GetExtension(name, extension);
1578 if(!strcmpi(extension, "ec"))
1583 ReplaceSpaces(moduleName, name);
1584 StripExtension(moduleName);
1586 ReplaceSpaces(modulePath, path);
1587 if(modulePath[0]) strcat(modulePath, SEPS);
1590 // *** Dependency command ***
1591 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1592 moduleName, modulePath, moduleName, extension);
1594 // System Includes (from global settings)
1595 for(item : compiler.dirs[Includes])
1597 strcat(command, " -isystem ");
1598 if(strchr(item, ' '))
1600 strcat(command, "\"");
1601 strcat(command, item);
1602 strcat(command, "\"");
1605 strcat(command, item);
1608 for(item : config.includeDirs)
1610 strcat(command, " -I");
1611 if(strchr(item, ' '))
1613 strcat(command, "\"");
1614 strcat(command, item);
1615 strcat(command, "\"");
1618 strcat(command, item);
1620 for(item : config.preprocessorDefs)
1622 strcat(command, " -D");
1623 strcat(command, item);
1627 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1631 bool firstLine = true;
1633 // To do some time: auto save external dependencies?
1636 if(dep.GetLine(line, sizeof(line)-1))
1640 char * colon = strstr(line, ":");
1641 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1655 // If we failed to generate dependencies...
1658 /* COMMENTED OUT FOR NOW
1659 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1660 moduleName, modulePath, moduleName, extension);
1663 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1664 moduleName, modulePath, moduleName, extension, moduleName);
1670 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1671 modulePath, moduleName, extension, moduleName);
1674 f.Printf("\t$(ECC)");
1675 // Give priority to file flags
1676 GenFileFlags(f, project, prjConfig);
1677 if(GetECFLAGS(prjConfig))
1679 f.Printf("%s $(CECFLAGS)", GetNoLineNumbers(prjConfig) ? " -nolinenumbers" : "");
1680 if(GetMemoryGuard(prjConfig))
1681 f.Printf(" -memguard");
1682 if(GetStrictNameSpaces(prjConfig))
1683 f.Printf(" -strictns");
1685 char * s = GetDefaultNameSpace(prjConfig);
1687 f.Printf(" -defaultns %s", s);
1691 f.Printf(" $(CECFLAGS) $(ECFLAGS)");
1692 f.Printf(" $(CFLAGS) $(FVISIBILITY)");
1694 f.Printf(" -c %s%s.%s -o $(OBJ)%s.c -symbols $(OBJ)\n\n",
1695 modulePath, moduleName, extension, moduleName);
1702 // TODO: Platform specific options
1703 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1704 child.GenMakefilePrintCObjectRules(f, project, compiler, prjConfig);
1709 void GenMakefilePrintObjectRules(File f, Project project,
1710 Map<String, NameCollisionInfo> namesInfo,
1711 CompilerConfig compiler, ProjectConfig prjConfig)
1713 ProjectConfig config = GetMatchingNodeConfig(prjConfig);
1714 //ProjectNode child;
1715 //char objDir[MAX_LOCATION];
1716 //ReplaceSpaces(objDir, config.objDir.dir);
1717 //eSystem_Log("Printing Object Rules\n");
1721 char extension[MAX_EXTENSION];
1722 char modulePath[MAX_LOCATION];
1723 char moduleName[MAX_FILENAME];
1725 GetExtension(name, extension);
1726 /*if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1727 !strcmpi(extension, "ec") || !strcmpi(extension, "cc") ||
1728 !strcmpi(extension, "cxx"))*/
1729 if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1730 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1731 !strcmpi(extension, "m") || !strcmpi(extension, "ec"))
1735 NameCollisionInfo info;
1737 ReplaceSpaces(moduleName, name);
1738 StripExtension(moduleName);
1740 info = namesInfo[moduleName];
1741 collision = info ? info.IsExtensionColliding(extension) : false;
1743 ReplaceSpaces(modulePath, path);
1744 if(modulePath[0]) strcat(modulePath, SEPS);
1746 // *** Dependency command ***
1747 if(!strcmpi(extension, "ec"))
1748 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", compiler.ccCommand, moduleName, moduleName);
1750 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", compiler.ccCommand, moduleName, modulePath, moduleName, extension);
1752 if(!strcmpi(extension, "ec"))
1753 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1757 // System Includes (from global settings)
1758 for(item : compiler.dirs[includes])
1760 strcat(command, " -isystem ");
1761 if(strchr(item, ' '))
1763 strcat(command, "\"");
1764 strcat(command, item);
1765 strcat(command, "\"");
1768 strcat(command, item);
1771 for(item : config.includeDirs)
1773 strcat(command, " -I");
1774 if(strchr(item, ' '))
1776 strcat(command, "\"");
1777 strcat(command, item);
1778 strcat(command, "\"");
1781 strcat(command, item);
1783 for(item : config.preprocessorDefs)
1785 strcat(command, " -D");
1786 strcat(command, item);
1790 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1793 bool firstLine = true;
1796 // To do some time: auto save external dependencies?
1800 if(dep.GetLine(line, sizeof(line)-1))
1804 char * colon = strstr(line, ":");
1805 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1819 // If we failed to generate dependencies...
1823 /*if(!strcmpi(extension, "ec"))
1824 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1826 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
1827 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
1833 f.Printf("\t$(CC)");
1834 // Give priority to file flags
1835 GenFileFlags(f, project, prjConfig);
1837 f.Printf(" $(CFLAGS)");
1839 if(!strcmpi(extension, "ec"))
1840 f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(OBJ)%s.o\n\n", moduleName, moduleName);
1842 f.Printf(" -c %s%s.%s -o $(OBJ)%s%s%s.o\n\n",
1843 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension, moduleName,
1844 collision ? "." : "", collision ? extension : "");
1851 // TODO: Platform specific options
1852 if(child.type != resources && (child.type == folder || !child.GetIsExcluded(prjConfig)))
1853 child.GenMakefilePrintObjectRules(f, project, namesInfo, compiler, prjConfig);
1858 void GenMakefileAddResources(File f, String resourcesPath, ProjectConfig prjConfig)
1865 //Iterator<ProjectNode> i { files };
1866 //Iterator<ProjectNode> prev { files };
1867 //for(child : files)
1869 for(c = 0; c < files.count; c++)
1871 ProjectNode child = files[c];
1872 TwoStrings ts = child.GetPlatformSpecificFu(prjConfig);
1875 if(child.type == file && !child.GetIsExcluded(prjConfig) && !(count > 0 && ts))
1878 char tempPath[MAX_LOCATION];
1879 char resPath[MAX_LOCATION];
1883 // $(EAR) aw%s --- /*quiet ? "q" : */""
1885 f.Printf("\t%s$(EAR) aw $(TARGET)", ts.a);
1888 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
1891 PathCatSlash(tempPath, child.name);
1896 strcpy(tempPath, child.path);
1897 PathCatSlash(tempPath, child.name);
1899 ReplaceSpaces(resPath, tempPath);
1900 if(strchr(tempPath, ' '))
1904 f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", resPath, quotes);
1907 if(count == 10 || (count > 0 && (ts || !child.next)))
1909 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
1912 for(parent = this; parent.type == folder; parent = parent.parent)
1915 strcpy(path, parent.name);
1922 f.Printf(" \"%s\"%s\n", path, ts.b);
1934 if(child.type == folder)
1935 child.GenMakefileAddResources(f, resourcesPath, prjConfig);
1941 class NameCollisionInfo
1951 bool IsExtensionColliding(char * extension)
1954 if(count > 1 && ((!strcmpi(extension, "c") && ec) ||
1955 (!strcmpi(extension, "cpp") && (ec || c)) ||
1956 (!strcmpi(extension, "cc") && (ec || c || cpp)) ||
1957 (!strcmpi(extension, "cxx") && (ec || c || cpp || cc)) ||
1958 !strcmpi(extension, "m")))