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)
351 property ProjectConfig config
356 ProjectConfig result = null;
357 if(configurations && (prj = property::project) && prj.config)
359 const char * projectConfigName = prj.config.name;
360 for(config : configurations)
362 if(!strcmpi(config.name, projectConfigName))
373 ProjectConfig GetMatchingNodeConfig(ProjectConfig config)
375 ProjectConfig nodeConfig = null;
376 if(property::configurations)
378 const char * configName = config.name;
379 for(cfg : property::configurations)
381 if(!strcmpi(cfg.name, configName))
391 property bool ecflags
395 ProjectConfig config = this.config;
396 ProjectOptions options = property::options;
397 SetBool memoryGuard = localMemoryGuard;
398 String defaultNameSpace = localDefaultNameSpace;
399 SetBool strictNameSpaces = localStrictNameSpaces;
400 SetBool noLineNumbers = localNoLineNumbers;
402 if(memoryGuard || defaultNameSpace || strictNameSpaces || noLineNumbers)
404 else if(parent.parent)
405 return parent.ecflags;
410 property bool memoryGuard
414 ProjectConfig config = this.config;
415 ProjectOptions options = property::options;
416 SetBool memoryGuard = localMemoryGuard;
420 return parent.memoryGuard;
422 return memoryGuard == true;
425 property String defaultNameSpace
429 ProjectConfig config = this.config;
430 ProjectOptions options = property::options;
431 String defaultNameSpace = localDefaultNameSpace;
432 if(!defaultNameSpace)
435 return parent.defaultNameSpace;
437 return defaultNameSpace;
440 property bool strictNameSpaces
444 ProjectConfig config = this.config;
445 ProjectOptions options = property::options;
446 SetBool strictNameSpaces = localStrictNameSpaces;
447 if(!strictNameSpaces)
450 return parent.strictNameSpaces;
452 return strictNameSpaces == true;
455 property bool noLineNumbers
459 ProjectConfig config = this.config;
460 ProjectOptions options = property::options;
461 SetBool noLineNumbers = localNoLineNumbers;
465 return parent.noLineNumbers;
467 return noLineNumbers == true;
471 property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
473 property bool containsFile
482 if(child.type == file ||
483 ((child.type == folder || child.type == folderOpen) && child.containsFile))
496 char * GetFullFilePath(char * buffer)
500 strcpy(buffer, root.path);
501 PathCatSlash(buffer, path);
502 PathCatSlash(buffer, name);
507 char * GetFileSysMatchingPath(char * buffer)
511 ProjectNode n, root = this.root;
512 for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
514 strcpy(buffer, root.path);
516 PathCatSlash(buffer, n.path);
517 if(FileExists(buffer).isDirectory)
520 if(!(n && (n.type == folder || n.type == project)))
526 void CollectPerFileAndDirOptions(ProjectConfig projectConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
528 ProjectNode node = null;
529 ProjectConfig config = GetMatchingNodeConfig(projectConfig);
530 List<ProjectNode> nodeStack { };
532 for(node = this; node && node.parent; node = node.parent)
535 // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse?
537 // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
538 while((node = nodeStack.lastIterator.data))
540 ProjectOptions nodeOptions = node.property::options;
541 if(nodeOptions && nodeOptions.preprocessorDefinitions)
543 for(def : nodeOptions.preprocessorDefinitions)
544 perFilePreprocessorDefs.Add(CopyString(def));
546 if(config && config.options && config.options.preprocessorDefinitions)
548 for(def : config.options.preprocessorDefinitions)
549 perFilePreprocessorDefs.Add(CopyString(def));
551 if(nodeOptions && nodeOptions.includeDirs)
553 for(dir : nodeOptions.includeDirs)
554 perFileIncludeDirs.Add(CopySystemPath(dir));
556 if(config && config.options && config.options.includeDirs)
558 for(dir : config.options.includeDirs)
559 perFileIncludeDirs.Add(CopySystemPath(dir));
561 nodeStack.lastIterator.Remove();
567 ProjectOptions options;
568 Array<PlatformOptions> platforms;
569 List<ProjectConfig> configurations;
570 ProjectNodeType nodeType;
575 // This holds the absolute path of the .epj for the project topnode (without the filename)
576 // It holds a relative path to the topNode (project) for other nodes (folders and files)
577 // For folders, it includes the folder it refers to. If there is a name difference between the
578 // file system folder and the grouping folder of the project view, it maps to that folder.
588 // This is only set for Top Nodes
591 property Project project
595 ProjectNode n = this;
596 while(n && n.type != project) n = n.parent;
597 return n ? (*&n.project) : null;
601 void RenameConfig(char * oldName, char * newName)
605 for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
607 if(property::configurations)
609 for(c : property::configurations; !strcmp(c.name, oldName))
612 c.name = CopyString(newName);
617 void DeleteConfig(ProjectConfig configToDelete)
621 for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
623 if(property::configurations)
625 Iterator<ProjectConfig> c { property::configurations };
628 ProjectConfig config = c.data;
629 if(!strcmp(configToDelete.name, config.name))
636 if(!property::configurations.count)
637 property::configurations = null;
643 ProjectNode backupNode { };
647 backupNode.files = { };
648 for(f : files) backupNode.files.Add(f.Backup());
650 if(property::options)
651 backupNode.options = property::options.Copy();
653 if(property::platforms)
655 backupNode.platforms = { };
656 for(p : property::platforms)
657 backupNode.platforms.Add(p.Copy());
660 if(property::configurations)
662 backupNode.configurations = { };
663 for(c : property::configurations)
664 backupNode.configurations.Add(c.Copy());
669 void Revert(ProjectNode backupNode)
673 Iterator<ProjectNode> it { backupNode.files };
681 property::options = backupNode.options ? backupNode.options.Copy() : null;
682 if(backupNode.platforms)
684 Array<PlatformOptions> platforms { };
685 property::platforms = platforms;
687 for(p : backupNode.platforms)
688 platforms.Add(p.Copy());
690 if(backupNode.configurations)
692 List<ProjectConfig> configurations { };
693 property::configurations = configurations;
694 for(c : backupNode.configurations)
695 configurations.Add(c.Copy());
699 void FixupNode(char * parentPath)
705 else if(nodeType == file)
710 path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
713 else if(nodeType == folder)
719 char temp[MAX_LOCATION];
720 strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
721 PathCatSlash(temp, name);
722 path = CopyString(temp);
726 indent = parent ? parent.indent + 1 : 0;
729 icon = NodeIcons::SelectFileIcon(name);
731 icon = NodeIcons::SelectNodeIcon(type);
740 parentPath[0] = '\0';
741 else if(type == resources || type == folder)
742 strcpy(parentPath, path);
744 f.FixupNode(parentPath);
749 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
753 // TOCHECK: Called from JSON writer
754 if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
756 strcpy(tempString, "\"");
757 strcat(tempString, property::fileName);
758 strcat(tempString, "\"");
765 // TOCHECK: Called from ProjectView rendering
766 return name ? name : "";
779 if(!project && platforms)
784 if(!project && configurations)
786 configurations.Free();
787 delete configurations;
790 /////////////////////////////
796 property bool isInResources
801 for(node = this; node; node = node.parent)
803 if(node.type == resources)
810 property TwoStrings platformSpecificFu
814 TwoStrings result { a = CopyString(""), b = CopyString("") };
815 // note: unknown platform is for common
816 Map<Platform, SetBool> exclusionInfo { };
817 MapNode<Platform, SetBool> mn;
822 CollectExclusionInfo(exclusionInfo);
823 common = exclusionInfo[unknown];
825 Map<Platform, SetBool> cleaned { };
826 SetBool opposite = common == true ? false : true;
827 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
829 if(mn.key == unknown || mn.value == opposite)
830 cleaned[mn.key] = mn.value;
832 delete exclusionInfo;
833 exclusionInfo = cleaned;
836 if(exclusionInfo.count > 1)
838 if(exclusionInfo.count > 2)
841 len = strlen(exp) + strlen("$(if $(or ");
842 exp = renew exp char[len+1];
843 strcat(exp, "$(if $(or ");
846 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
848 if(mn.key != unknown)
850 char * comma = mn.next ? "," : "";
852 var = PlatformToMakefileVariable(mn.key);
855 len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
856 exp = renew exp char[len+1];
866 len = strlen(exp) + strlen("),");
867 exp = renew exp char[len+1];
871 if(exclusionInfo.root.minimum.key != unknown)
872 var = PlatformToMakefileVariable(exclusionInfo.root.minimum.key);
874 var = PlatformToMakefileVariable(exclusionInfo.root.minimum.next.key);
877 len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
878 exp = renew exp char[len+1];
879 strcat(exp, "$(if $(");
886 exp = common == true ? result.b : result.a;
887 len = strlen(exp) + strlen(",");
888 exp = renew exp char[len+1];
890 if(common == true) result.b = exp; else result.a = exp;
893 len = strlen(exp) + strlen(")");
894 exp = renew exp char[len+1];
898 delete exclusionInfo;
904 property bool isExcluded
909 // note: unknown platform is for common
910 Map<Platform, SetBool> exclusionInfo { };
911 CollectExclusionInfo(exclusionInfo);
912 if(exclusionInfo.count == 0)
914 else if(exclusionInfo.count == 1)
915 result = exclusionInfo.root.minimum.value == true;
918 SetBool check = exclusionInfo.root.minimum.value;
919 MapNode<Platform, SetBool> mn;
920 for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
922 if(check != mn.value)
925 if(!mn) // all are same
926 result = check == true;
930 delete exclusionInfo;
936 void CollectExclusionInfo(Map<Platform, SetBool> output)
938 // note: unknown platform is for common
940 ProjectConfig config = property::config;
941 ProjectOptions options = property::options;
942 Array<PlatformOptions> platforms = property::platforms;
943 List<ProjectConfig> configurations = property::configurations;
946 parent.CollectExclusionInfo(output);
948 output[unknown] = unset;
950 if(options && options.excludeFromBuild)
951 output[unknown] = options.excludeFromBuild;
953 if(config && config.options && config.options.excludeFromBuild)
954 output[unknown] = config.options.excludeFromBuild;
960 if(p.options.excludeFromBuild && (platform = p.name))
961 output[platform] = p.options.excludeFromBuild;
964 if(config && config.platforms)
966 for(p : config.platforms)
968 if(p.options.excludeFromBuild && (platform = p.name))
969 output[platform] = p.options.excludeFromBuild;
977 parent.EnsureVisible();
978 row.collapsed = false;
984 parent.files.Delete(this);
987 ProjectNode Find(char * name, bool includeResources)
989 ProjectNode result = null;
994 if(includeResources || child.type != resources)
996 if(child.type != folder && child.name && !strcmpi(child.name, name))
1001 result = child.Find(name, includeResources);
1010 ProjectNode FindWithPath(char * name, bool includeResources)
1012 ProjectNode result = null;
1017 if(includeResources || child.type != resources)
1019 char path[MAX_LOCATION];
1020 strcpy(path, child.path);
1021 if(child.type != folder && child.name)
1023 PathCatSlash(path, child.name);
1024 if(!strcmpi(path, name))
1030 result = child.FindWithPath(name, includeResources);
1039 ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
1041 ProjectNode result = null;
1046 if(includeResources || child.type != resources)
1048 if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
1054 result = child.FindSpecial(name, recursive, includeResources, includeFolders);
1063 ProjectNode FindSameNameConflict(char * name, bool includeResources, Map<Platform, SetBool> exclusionInfo)
1065 ProjectNode result = null;
1066 Map<Platform, SetBool> compareExclusion { };
1067 SetBool common, commonComp;
1068 SetBool actual, actualComp;
1073 if(includeResources || child.type != resources)
1075 if(child.type != folder && child.name && !strcmpi(child.name, name))
1077 child.CollectExclusionInfo(compareExclusion);
1078 common = exclusionInfo[unknown];
1079 commonComp = compareExclusion[unknown];
1080 if(exclusionInfo.count == 1 && compareExclusion.count == 1)
1082 if(!(common == true || commonComp == true))
1091 for(platform = (Platform)1; platform < Platform::enumSize; platform++)
1094 actualComp = commonComp;
1095 if(exclusionInfo[platform] != unset)
1096 actual = exclusionInfo[platform];
1097 if(compareExclusion[platform] != unset)
1098 actualComp = compareExclusion[platform];
1099 if(!(actual == true || actualComp == true))
1107 compareExclusion.Free();
1110 result = child.FindSameNameConflict(name, includeResources, exclusionInfo);
1114 compareExclusion.Free();
1116 delete compareExclusion;
1120 ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
1122 ProjectNode node = null;
1123 char temp[MAX_LOCATION];
1124 Map<Platform, SetBool> exclusionInfo { };
1126 GetLastDirectory(filePath, temp);
1127 //if(!checkIfExists || !project.topNode.Find(temp, false))
1128 CollectExclusionInfo(exclusionInfo);
1129 if(!checkIfExists || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo))
1131 // Do the check for folder in the same parent or resource files only here
1132 if(type == folder || !checkIfExists)
1136 if(node.name && !strcmpi(node.name, temp))
1141 node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
1145 node.nodeType = folder;
1151 StripLastDirectory(filePath, temp);
1152 MakePathRelative(temp, project.topNode.path, temp);
1153 node.path = CopyUnixPath(temp);
1155 node.nodeType = file;
1159 strcpy(temp, (type == NodeTypes::project) ? "" : path);
1160 PathCatSlash(temp, node.name);
1161 node.path = CopyString(temp);
1163 files.Insert(after, node);
1165 delete exclusionInfo;
1169 #ifndef MAKEFILE_GENERATOR
1170 void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
1172 char label[MAX_FILENAME];
1178 bool showConfig = true;
1183 projectView = ide.projectView;
1186 bmp = projectView.icons[icon].bitmap;
1187 xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
1189 GetLastDirectory(name, label);
1190 if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
1192 if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
1194 if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
1197 addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
1198 if(strlen(addendum))
1200 strcat(label, " (");
1201 strcat(label, addendum);
1204 addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
1205 if(strlen(addendum))
1207 strcat(label, " (");
1208 strcat(label, addendum);
1214 else if(!projectView.drawingInProjectSettingsDialog)
1217 strcat(label, " *");
1218 if(type == project && info)
1220 int len = strlen(info) + 4;
1221 char * more = new char[len];
1222 sprintf(more, " (%s)", info);
1223 strcat(label, more);
1227 len = strlen(label);
1231 if(type == folder || type == folderOpen)
1232 surface.SetForeground(yellow);
1236 surface.TextOpacity(false);
1237 surface.TextExtent(label, len, &w, &h);
1240 // Draw the current row stipple
1241 if(displayFlags.selected)
1242 //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1243 //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1244 surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1246 surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1250 if(displayFlags.current)
1252 if(displayFlags.active)
1254 surface.LineStipple(0x5555);
1255 if(displayFlags.selected)
1256 surface.SetForeground(projectView.fileList.stippleColor);
1258 surface.SetForeground(projectView.fileList.foreground);
1262 surface.SetForeground(SELECTION_COLOR);
1264 surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1265 surface.LineStipple(0);
1270 surface.SetForeground(white);
1271 surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1277 int OnCompare(ProjectNode b)
1280 if(type == b.type /*|| type >= TYPE_DRIVE*/)
1281 result = strcmpi(name, b.name);
1284 if(type == folder && b.type == file) result = -1;
1285 else if(type == file && b.type == folder) result = 1;
1290 void GenFileFlags(File f, Project project)
1292 ProjectNode node = null;
1293 List<ProjectNode> nodeStack { };
1295 for(node = this; node && node.parent; node = node.parent)
1296 nodeStack.Add(node);
1298 // Should we reverse this stack to give priority to the per-file includes?
1300 while((node = nodeStack.lastIterator.data))
1302 ProjectOptions nodeOptions = node.property::options;
1303 ProjectConfig config = node.config;
1304 if(nodeOptions && nodeOptions.preprocessorDefinitions)
1305 OutputListOption(f, "D", nodeOptions.preprocessorDefinitions, inPlace, false);
1306 if(config && config.options && config.options.preprocessorDefinitions)
1307 OutputListOption(f, "D", config.options.preprocessorDefinitions, inPlace, false);
1308 if(nodeOptions && nodeOptions.includeDirs)
1309 OutputListOption(f, "I", nodeOptions.includeDirs, inPlace, true);
1310 if(config && config.options && config.options.includeDirs)
1311 OutputListOption(f, "I", config.options.includeDirs, inPlace, true);
1313 nodeStack.lastIterator.Remove();
1318 void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo)
1322 char extension[MAX_EXTENSION];
1323 GetExtension(name, extension);
1324 if(!strcmpi(extension, "ec") || !strcmpi(extension, "c") ||
1325 !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1326 !strcmpi(extension, "cxx") || !strcmpi(extension, "m"))
1328 char moduleName[MAX_FILENAME];
1329 NameCollisionInfo info;
1330 ReplaceSpaces(moduleName, name);
1331 StripExtension(moduleName);
1332 info = namesInfo[moduleName];
1334 info = NameCollisionInfo { };
1335 info.count++; // += 1; unless this is for a bug?
1336 if(!strcmpi(extension, "ec"))
1338 else if(!strcmpi(extension, "c"))
1340 else if(!strcmpi(extension, "cpp"))
1342 else if(!strcmpi(extension, "cc"))
1344 else if(!strcmpi(extension, "cxx"))
1346 else if(!strcmpi(extension, "m"))
1348 namesInfo[moduleName] = info;
1355 if(child.type != resources && (child.type == folder || !child.isExcluded))
1356 child.GenMakefileGetNameCollisionInfo(namesInfo);
1361 int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType, Map<String, NameCollisionInfo> namesInfo, Array<String> items)
1367 TwoStrings ts = platformSpecificFu;
1368 char moduleName[MAX_FILENAME];
1369 char extension[MAX_EXTENSION];
1370 GetExtension(name, extension);
1371 if(printType == resources)
1374 char tempPath[MAX_LOCATION];
1375 char modulePath[MAX_LOCATION];
1378 if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1381 PathCatSlash(tempPath, name);
1386 strcpy(tempPath, path);
1387 PathCatSlash(tempPath, name);
1389 ReplaceSpaces(modulePath, tempPath);
1390 sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1391 items.Add(CopyString(s));
1393 else if(printType == sources)
1395 if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1396 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1397 !strcmpi(extension, "ec") || !strcmpi(extension, "m"))
1399 char modulePath[MAX_LOCATION];
1401 ReplaceSpaces(modulePath, path);
1402 ReplaceSpaces(moduleName, name);
1403 sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1404 items.Add(CopyString(s));
1407 else if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1408 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1409 !strcmpi(extension, "m"))
1411 if(printType == objects)
1414 NameCollisionInfo info;
1415 ReplaceSpaces(moduleName, name);
1416 StripExtension(moduleName);
1417 info = namesInfo[moduleName];
1418 collision = info ? info.IsExtensionColliding(extension) : false;
1419 sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1420 items.Add(CopyString(s));
1423 else if(!strcmpi(extension, "ec"))
1425 ReplaceSpaces(moduleName, name);
1426 StripExtension(moduleName);
1427 if(printType == objects)
1430 if(printType == objects)
1431 sprintf(s, "%s$(OBJ)%s.o%s", ts.a, moduleName, ts.b);
1432 else if(printType == cObjects)
1433 sprintf(s, "%s$(OBJ)%s.c%s", ts.a, moduleName, ts.b);
1434 else if(printType == symbols)
1435 sprintf(s, "%s$(OBJ)%s.sym%s", ts.a, moduleName, ts.b);
1436 else if(printType == imports)
1437 sprintf(s, "%s$(OBJ)%s.imp%s", ts.a, moduleName, ts.b);
1439 items.Add(CopyString(s));
1447 if(child.type != resources && (child.type == folder || !child.isExcluded))
1448 count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items);
1454 void GenMakefilePrintSymbolRules(File f, Project project)
1456 //ProjectNode child;
1457 //char objDir[MAX_LOCATION];
1458 CompilerConfig compiler = GetCompilerConfig();
1459 //ReplaceSpaces(objDir, project.config.objDir.dir);
1461 //eSystem_Log("Printing Symbol Rules\n");
1464 char extension[MAX_EXTENSION];
1465 char modulePath[MAX_LOCATION];
1466 char moduleName[MAX_FILENAME];
1468 GetExtension(name, extension);
1469 if(!strcmpi(extension, "ec"))
1474 ReplaceSpaces(moduleName, name);
1475 StripExtension(moduleName);
1477 ReplaceSpaces(modulePath, path);
1478 if(modulePath[0]) strcat(modulePath, SEPS);
1481 // *** Dependency command ***
1482 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1483 modulePath, moduleName, extension);
1485 // System Includes (from global settings)
1486 for(item : compiler.dirs[Includes])
1488 strcat(command, " -isystem ");
1489 if(strchr(item, ' '))
1491 strcat(command, "\"");
1492 strcat(command, item);
1493 strcat(command, "\"");
1496 strcat(command, item);
1499 for(item : project.includeDirs)
1501 strcat(command, " -I");
1502 if(strchr(item, ' '))
1504 strcat(command, "\"");
1505 strcat(command, item);
1506 strcat(command, "\"");
1509 strcat(command, item);
1511 for(item : project.preprocessorDefs)
1513 strcat(command, " -D");
1514 strcat(command, item);
1518 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1521 bool firstLine = true;
1524 // To do some time: auto save external dependencies?
1527 if(dep.GetLine(line, sizeof(line)-1))
1531 char * colon = strstr(line, ":");
1532 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1546 // If we failed to generate dependencies...
1550 f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1551 moduleName, modulePath, moduleName, extension);
1557 f.Printf("\t$(ECP) %s%s.%s %s.sym\n\n",
1558 modulePath, moduleName, extension, moduleName);
1561 f.Printf("\t$(ECP)");
1562 // Give priority to file flags
1563 GenFileFlags(f, project);
1565 f.Printf(" $(CECFLAGS)");
1569 f.Printf(" -memguard");
1570 if(strictNameSpaces)
1571 f.Printf(" -strictns");
1573 char * s = defaultNameSpace;
1575 f.Printf(" -defaultns %s", s);
1579 f.Printf(" $(ECFLAGS)");
1580 f.Printf(" $(CFLAGS)");
1582 f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n\n",
1583 modulePath, moduleName, extension, moduleName);
1590 // TODO: Platform specific options
1591 if(child.type != resources && (child.type == folder || !child.isExcluded))
1592 child.GenMakefilePrintSymbolRules(f, project);
1598 void GenMakefilePrintCObjectRules(File f, Project project)
1600 //ProjectNode child;
1601 //char objDir[MAX_LOCATION];
1602 CompilerConfig compiler = GetCompilerConfig();
1603 //ReplaceSpaces(objDir, project.config.objDir.dir);
1604 //eSystem_Log("Printing C Object Rules\n");
1607 char extension[MAX_EXTENSION];
1608 char modulePath[MAX_LOCATION];
1609 char moduleName[MAX_FILENAME];
1611 GetExtension(name, extension);
1612 if(!strcmpi(extension, "ec"))
1617 ReplaceSpaces(moduleName, name);
1618 StripExtension(moduleName);
1620 ReplaceSpaces(modulePath, path);
1621 if(modulePath[0]) strcat(modulePath, SEPS);
1624 // *** Dependency command ***
1625 sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1626 moduleName, modulePath, moduleName, extension);
1628 // System Includes (from global settings)
1629 for(item : compiler.dirs[Includes])
1631 strcat(command, " -isystem ");
1632 if(strchr(item, ' '))
1634 strcat(command, "\"");
1635 strcat(command, item);
1636 strcat(command, "\"");
1639 strcat(command, item);
1642 for(item : project.config.includeDirs)
1644 strcat(command, " -I");
1645 if(strchr(item, ' '))
1647 strcat(command, "\"");
1648 strcat(command, item);
1649 strcat(command, "\"");
1652 strcat(command, item);
1654 for(item : project.config.preprocessorDefs)
1656 strcat(command, " -D");
1657 strcat(command, item);
1661 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1665 bool firstLine = true;
1667 // To do some time: auto save external dependencies?
1670 if(dep.GetLine(line, sizeof(line)-1))
1674 char * colon = strstr(line, ":");
1675 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1689 // If we failed to generate dependencies...
1692 /* COMMENTED OUT FOR NOW
1693 f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1694 moduleName, modulePath, moduleName, extension);
1697 f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1698 moduleName, modulePath, moduleName, extension, moduleName);
1704 f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1705 modulePath, moduleName, extension, moduleName);
1708 f.Printf("\t$(ECC)");
1709 // Give priority to file flags
1710 GenFileFlags(f, project);
1713 f.Printf("%s $(CECFLAGS)", noLineNumbers ? " -nolinenumbers" : "");
1715 f.Printf(" -memguard");
1716 if(strictNameSpaces)
1717 f.Printf(" -strictns");
1719 char * s = defaultNameSpace;
1721 f.Printf(" -defaultns %s", s);
1725 f.Printf(" $(CECFLAGS) $(ECFLAGS)");
1726 f.Printf(" $(CFLAGS) $(FVISIBILITY)");
1728 f.Printf(" -c %s%s.%s -o $(OBJ)%s.c -symbols $(OBJ)\n\n",
1729 modulePath, moduleName, extension, moduleName);
1736 // TODO: Platform specific options
1737 if(child.type != resources && (child.type == folder || !child.isExcluded))
1738 child.GenMakefilePrintCObjectRules(f, project);
1744 void GenMakefilePrintObjectRules(File f, Project project, Map<String, NameCollisionInfo> namesInfo)
1746 //ProjectNode child;
1747 //char objDir[MAX_LOCATION];
1748 CompilerConfig compiler = GetCompilerConfig();
1749 //ReplaceSpaces(objDir, project.config.objDir.dir);
1750 //eSystem_Log("Printing Object Rules\n");
1754 char extension[MAX_EXTENSION];
1755 char modulePath[MAX_LOCATION];
1756 char moduleName[MAX_FILENAME];
1758 GetExtension(name, extension);
1759 /*if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1760 !strcmpi(extension, "ec") || !strcmpi(extension, "cc") ||
1761 !strcmpi(extension, "cxx"))*/
1762 if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1763 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1764 !strcmpi(extension, "m") || !strcmpi(extension, "ec"))
1768 NameCollisionInfo info;
1770 ReplaceSpaces(moduleName, name);
1771 StripExtension(moduleName);
1773 info = namesInfo[moduleName];
1774 collision = info ? info.IsExtensionColliding(extension) : false;
1776 ReplaceSpaces(modulePath, path);
1777 if(modulePath[0]) strcat(modulePath, SEPS);
1779 // *** Dependency command ***
1780 if(!strcmpi(extension, "ec"))
1781 sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", compiler.ccCommand, moduleName, moduleName);
1783 sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", compiler.ccCommand, moduleName, modulePath, moduleName, extension);
1785 if(!strcmpi(extension, "ec"))
1786 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1790 // System Includes (from global settings)
1791 for(item : compiler.dirs[includes])
1793 strcat(command, " -isystem ");
1794 if(strchr(item, ' '))
1796 strcat(command, "\"");
1797 strcat(command, item);
1798 strcat(command, "\"");
1801 strcat(command, item);
1804 for(item : project.config.includeDirs)
1806 strcat(command, " -I");
1807 if(strchr(item, ' '))
1809 strcat(command, "\"");
1810 strcat(command, item);
1811 strcat(command, "\"");
1814 strcat(command, item);
1816 for(item : project.config.preprocessorDefs)
1818 strcat(command, " -D");
1819 strcat(command, item);
1823 if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1826 bool firstLine = true;
1829 // To do some time: auto save external dependencies?
1833 if(dep.GetLine(line, sizeof(line)-1))
1837 char * colon = strstr(line, ":");
1838 if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1852 // If we failed to generate dependencies...
1856 /*if(!strcmpi(extension, "ec"))
1857 f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1859 f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName,
1860 collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
1866 f.Printf("\t$(CC)");
1867 // Give priority to file flags
1868 GenFileFlags(f, project);
1870 f.Printf(" $(CFLAGS)");
1872 if(!strcmpi(extension, "ec"))
1873 f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(OBJ)%s.o\n\n", moduleName, moduleName);
1875 f.Printf(" -c %s%s.%s -o $(OBJ)%s%s%s.o\n\n",
1876 modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension, moduleName,
1877 collision ? "." : "", collision ? extension : "");
1884 // TODO: Platform specific options
1885 if(child.type != resources && (child.type == folder || !child.isExcluded))
1886 child.GenMakefilePrintObjectRules(f, project, namesInfo);
1892 void GenMakefileAddResources(File f, String resourcesPath)
1899 //Iterator<ProjectNode> i { files };
1900 //Iterator<ProjectNode> prev { files };
1901 //for(child : files)
1903 for(c = 0; c < files.count; c++)
1905 ProjectNode child = files[c];
1906 TwoStrings ts = child.platformSpecificFu;
1909 if(child.type == file && !child.isExcluded && !(count > 0 && ts))
1912 char tempPath[MAX_LOCATION];
1913 char resPath[MAX_LOCATION];
1917 // $(EAR) aw%s --- /*quiet ? "q" : */""
1919 f.Printf("\t%s$(EAR) aw $(TARGET)", ts.a);
1922 if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
1925 PathCatSlash(tempPath, child.name);
1930 strcpy(tempPath, child.path);
1931 PathCatSlash(tempPath, child.name);
1933 ReplaceSpaces(resPath, tempPath);
1934 if(strchr(tempPath, ' '))
1938 f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", resPath, quotes);
1941 if(count == 10 || (count > 0 && (ts || !child.next)))
1943 char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
1946 for(parent = this; parent.type == folder; parent = parent.parent)
1949 strcpy(path, parent.name);
1956 f.Printf(" \"%s\"%s\n", path, ts.b);
1968 if(child.type == folder)
1969 child.GenMakefileAddResources(f, resourcesPath);
1975 class NameCollisionInfo
1985 bool IsExtensionColliding(char * extension)
1988 if(count > 1 && ((!strcmpi(extension, "c") && ec) ||
1989 (!strcmpi(extension, "cpp") && (ec || c)) ||
1990 (!strcmpi(extension, "cc") && (ec || c || cpp)) ||
1991 (!strcmpi(extension, "cxx") && (ec || c || cpp || cc)) ||
1992 !strcmpi(extension, "m")))