ide:ProjectView:ProjectNode:NodeProperties: fixed superfluous folder changes causing...
[sdk] / ide / src / project / ProjectNode.ec
1 #ifndef MAKEFILE_GENERATOR
2 import "ide"
3 #else
4 #ifdef ECERE_STATIC
5 import static "ecere"
6 #else
7 import "ecere"
8 #endif
9
10 import "Project"
11
12 static define app = ((GuiApplication)__thisModule);
13 #endif
14
15 bool eString_PathInsideOfMore(char * path, char * of, char * pathRest)
16 {
17    if(!path[0] || !of[0])
18       return false;  // What to do here? Ever used?
19    else
20    {
21       char ofPart[MAX_FILENAME], ofRest[MAX_LOCATION];
22       char pathPart[MAX_FILENAME]; //, pathRest[MAX_LOCATION];
23       strcpy(ofRest, of);
24       strcpy(pathRest, path);
25       for(; ofRest[0] && pathRest[0];)
26       {
27          SplitDirectory(ofRest, ofPart, ofRest);      
28          SplitDirectory(pathRest, pathPart, pathRest);
29          if(fstrcmp(pathPart, ofPart))
30             return false;
31       }
32       if(!ofRest[0] && !pathRest[0])
33          return false;
34       else if(!pathRest[0])           // not inside of, it's the other way around
35          return false;
36       return true;
37    }
38 }
39
40 enum NodeTypes { project, file, folder, resources, folderOpen };
41 enum NodeIcons
42 {
43    genFile, ewsFile, epjFile, folder, openFolder, ecFile, ehFile,
44    cFile, hFile, cppFile, hppFile, textFile, webFile, pictureFile, soundFile,
45    archiveFile, packageFile, opticalMediaImageFile, mFile;
46
47    NodeIcons ::SelectFileIcon(char * filePath)
48    {
49       NodeIcons icon;
50       if(filePath && filePath[0])
51       {
52          char extension[MAX_EXTENSION];
53          GetExtension(filePath, extension);
54          if(strlen(extension))
55          {
56             if(!strcmpi(extension, WorkspaceExtension))
57                icon = ewsFile;
58             else if(!strcmpi(extension, ProjectExtension))
59                icon = epjFile;
60             else if(!strcmpi(extension, "ec"))
61                icon = ecFile;
62             else if(!strcmpi(extension, "eh"))
63                icon = ehFile;
64             else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
65                   !strcmpi(extension, "cxx"))
66                icon = cppFile;
67             else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") ||
68                   !strcmpi(extension, "hxx"))
69                icon = hppFile;
70             else if(!strcmpi(extension, "c"))
71                icon = cFile;
72             else if(!strcmpi(extension, "h"))
73                icon = hFile;
74             else if(!strcmpi(extension, "m"))
75                icon = mFile;
76             else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
77                   !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
78                icon = textFile;
79             else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
80                   !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
81                   !strcmpi(extension, "js"))
82                icon = webFile;
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"))
87                icon = pictureFile;
88             else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
89                   !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
90                icon = soundFile;
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"))
97                icon = archiveFile;
98             else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
99                   !strcmpi(extension, "rpm"))
100                icon = packageFile;
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;
106             else
107                icon = genFile;
108          }
109          else
110             icon = genFile;
111       }
112       else
113          icon = genFile; // tocheck: error icon?
114       return icon;
115    }
116
117    NodeIcons ::SelectNodeIcon(NodeTypes type)
118    {
119       switch(type)
120       {
121          case project:
122             return epjFile;
123          case file:
124             return genFile;
125          case folder:
126             return folder;
127          case resources:
128             return archiveFile;
129          case folderOpen:
130             return openFolder;
131       }
132       return genFile;
133    }
134 };
135
136 #define SELECTION_COLOR Color { 10, 36, 106 }
137
138 // On Windows & UNIX
139 #define SEPS    "/"
140 #define SEP     '/'
141
142 // this is so not working, why!
143 //struct TwoStrings
144 // return result was not even executed (did not step on while debugging)
145 class TwoStrings : struct
146 {
147    char * a;
148    char * b;
149
150    property bool
151    {
152       get
153       {
154          return a && a[0];
155       }
156    }
157
158    ~TwoStrings()
159    {
160       delete a;
161       delete b;
162    }
163 }
164
165 class ProjectNode : ListItem
166 {
167 public:
168    property String
169    {
170       set { return { fileName = value }; }
171       // TOCHECK: Is this isset necessary at all?
172       isset { return nodeType == file && !options && !configurations && !platforms && !files; }
173    };
174    property String folder
175    {
176       set
177       {
178          nodeType = folder;
179          if(strchr(value, '/'))
180          {
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);
187          }
188          else
189             name = CopyString(value);
190       }
191       get
192       {
193          // TOCHECK: Non Reentrant
194          static char insidePath[MAX_LOCATION];
195
196          strcpy(insidePath, (parent.type == project) ? "" : parent.path);
197          PathCatSlash(insidePath, name);
198
199          if(!fstrcmp(path, insidePath))
200             return name;
201          else
202          {
203             strcpy(insidePath, path);
204             if(!insidePath[0]) strcpy(insidePath, ".");
205             PathCatSlash(insidePath, name);
206             return insidePath;
207          }
208       }
209       isset { return nodeType == folder; }
210    };
211    property String fileName
212    {
213       set
214       {
215          nodeType = file;
216          if(strchr(value, '/'))
217          {
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);
224          }
225          else
226             name = CopyValidateMakefilePath(value);
227       }
228       get
229       {
230          // TOCHECK: Non Reentrant
231          static char insidePath[MAX_LOCATION];
232
233          strcpy(insidePath, (parent.type == project) ? "" : parent.path);
234          if(!fstrcmp(path, insidePath))
235             return name;
236          else
237          {
238             strcpy(insidePath, path);
239             if(!insidePath[0]) strcpy(insidePath, ".");
240             PathCatSlash(insidePath, name);
241             return insidePath;
242          }
243       }
244       isset { return nodeType == file && (options || configurations || platforms); }
245    };
246
247    LinkList<ProjectNode> files;
248    ProjectOptions options;
249    Array<PlatformOptions> platforms;
250    List<ProjectConfig> configurations;
251
252    property ProjectConfig config
253    {
254       get
255       {
256          Project prj;
257          ProjectConfig result = null;
258          /*if(configurations)
259             printf("test\n");
260          if(prj)
261             printf("test\n");*/
262          if(configurations && (prj = property::project) && prj.config)
263          {
264             const char * projectConfigName = prj.config.name;
265             for(config : configurations)
266             {
267                if(!strcmpi(config.name, projectConfigName))
268                {
269                   result = config;
270                   break;
271                }
272             }
273          }
274          return result;
275       }
276    }
277
278    ProjectConfig GetMatchingNodeConfig(ProjectConfig config)
279    {
280       ProjectConfig nodeConfig = null;
281       if(configurations)
282       {
283          const char * configName = config.name;
284          for(cfg : configurations)
285          {
286             if(!strcmpi(cfg.name, configName))
287             {
288                nodeConfig = cfg;
289                break;
290             }
291          }
292       }
293       return nodeConfig;
294    }
295
296    property bool ecflags
297    {
298       get
299       {
300          ProjectConfig config = this.config;
301          ProjectOptions options = this.options;
302          SetBool memoryGuard = localMemoryGuard;
303          String defaultNameSpace = localDefaultNameSpace;
304          SetBool strictNameSpaces = localStrictNameSpaces;
305          SetBool noLineNumbers = localNoLineNumbers;
306
307          if(memoryGuard || defaultNameSpace || strictNameSpaces || noLineNumbers)
308             return true;
309          else if(parent.parent)
310             return parent.ecflags;
311          else
312             return false;
313       }
314    }
315    property bool memoryGuard
316    {
317       get
318       {
319          ProjectConfig config = this.config;
320          ProjectOptions options = this.options;
321          SetBool memoryGuard = localMemoryGuard;
322          if(!memoryGuard)
323          {
324             if(parent)
325                return parent.memoryGuard;
326          }
327          return memoryGuard == true;
328       }
329    }
330    property String defaultNameSpace
331    {
332       get
333       {
334          ProjectConfig config = this.config;
335          ProjectOptions options = this.options;
336          String defaultNameSpace = localDefaultNameSpace;
337          if(!defaultNameSpace)
338          {
339             if(parent)
340                return parent.defaultNameSpace;
341          }
342          return defaultNameSpace;
343       }
344    }
345    property bool strictNameSpaces
346    {
347       get
348       {
349          ProjectConfig config = this.config;
350          ProjectOptions options = this.options;
351          SetBool strictNameSpaces = localStrictNameSpaces;
352          if(!strictNameSpaces)
353          {
354             if(parent)
355                return parent.strictNameSpaces;
356          }
357          return strictNameSpaces == true;
358       }
359    }
360    property bool noLineNumbers
361    {
362       get
363       {
364          ProjectConfig config = this.config;
365          ProjectOptions options = this.options;
366          SetBool noLineNumbers = localNoLineNumbers;
367          if(!noLineNumbers)
368          {
369             if(parent)
370                return parent.noLineNumbers;
371          }
372          return noLineNumbers == true;
373       }
374    }
375
376    property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
377
378    property bool containsFile
379    {
380       get
381       {
382          bool result;
383          if(files)
384          {
385             for(child : files)
386             {
387                if(child.type == file ||
388                      ((child.type == folder || child.type == folderOpen) && child.containsFile))
389                {
390                   result = true;
391                   break;
392                }
393             }
394          }
395          else
396             result = false;
397          return result;
398       }
399    }
400
401    char * GetFullFilePath(char * buffer)
402    {
403       if(buffer)
404       {
405          strcpy(buffer, root.path);
406          PathCatSlash(buffer, path);
407          PathCatSlash(buffer, name);
408       }
409       return buffer;
410    }
411
412    char * GetFileSysMatchingPath(char * buffer)
413    {
414       if(buffer)
415       {
416          ProjectNode n, root = this.root;
417          for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
418          {
419             strcpy(buffer, root.path);
420             if(n != root)
421                PathCatSlash(buffer, n.path);
422             if(FileExists(buffer).isDirectory)
423                break;
424          }
425          if(!(n && (n.type == folder || n.type == project)))
426             buffer[0] = '\0';
427       }
428       return buffer;
429    }
430
431    void CollectPerFileAndDirOptions(ProjectConfig projectConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
432    {
433       ProjectNode node = null;
434       ProjectConfig config = GetMatchingNodeConfig(projectConfig);
435       List<ProjectNode> nodeStack { };
436       
437       for(node = this; node && node.parent; node = node.parent)
438          nodeStack.Add(node);
439
440       // Should we reverse this stack to give priority to the per-file includes? Does the following technique already reverse? 
441
442       // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
443       while((node = nodeStack.lastIterator.data))
444       {
445          if(node.options && node.options.preprocessorDefinitions)
446          {
447             for(def : node.options.preprocessorDefinitions)
448                perFilePreprocessorDefs.Add(CopyString(def));
449          }
450          if(config && config.options && config.options.preprocessorDefinitions)
451          {
452             for(def : config.options.preprocessorDefinitions)
453                perFilePreprocessorDefs.Add(CopyString(def));
454          }
455          if(node.options && node.options.includeDirs)
456          {
457             for(dir : node.options.includeDirs)
458                perFileIncludeDirs.Add(CopySystemPath(dir));
459          }
460          if(config && config.options && config.options.includeDirs)
461          {
462             for(dir : config.options.includeDirs)
463                perFileIncludeDirs.Add(CopySystemPath(dir));
464          }
465          nodeStack.lastIterator.Remove();
466       }
467       delete nodeStack;
468    }
469
470 private:
471    ProjectNodeType nodeType;
472    ProjectNode parent;
473    char * name;
474    char * info;
475
476    // This holds the absolute path of the .epj for the project topnode (without the filename)
477    // It holds a relative path to the topNode (project) for other nodes (folders and files)
478    // For folders, it includes the folder it refers to. If there is a name difference between the
479    // file system folder and the grouping folder of the project view, it maps to that folder.
480    char * path;
481    
482    NodeTypes type;
483    NodeIcons icon;
484    int indent;
485    DataRow row;
486
487    bool modified;
488    
489    // This is only set for Top Nodes
490    Project project;
491
492    property Project project
493    {
494       get
495       {
496          ProjectNode n = this;
497          while(n && n.type != project) n = n.parent;
498          return n ? (*&n.project) : null;
499       }
500    }   
501
502    void RenameConfig(char * oldName, char * newName)
503    {
504       if(files)
505       {
506          for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
507       }
508       if(configurations)
509       {
510          for(c : configurations; !strcmp(c.name, oldName))
511          {
512             delete c.name;
513             c.name = CopyString(newName);
514          }
515       }
516    }
517
518    void DeleteConfig(ProjectConfig configToDelete)
519    {
520       if(files)
521       {
522          for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
523       }
524       if(configurations)
525       {
526          Iterator<ProjectConfig> c { configurations };
527          while(c.Next())
528          {
529             ProjectConfig config = c.data;
530             if(!strcmp(configToDelete.name, config.name))
531             {               
532                c.Remove();
533                delete config;
534                break;
535             }
536          }
537          if(!configurations.count)
538          {
539             delete configurations;
540          }
541       }
542    }
543
544    ProjectNode Backup()
545    {
546       ProjectNode backupNode { };
547
548       if(files)
549       {
550          backupNode.files = { };
551          for(f : files) backupNode.files.Add(f.Backup());
552       }
553       if(options)
554          backupNode.options = options.Copy();
555
556       if(platforms)
557       {
558          backupNode.platforms = { };
559          for(p : platforms)
560             backupNode.platforms.Add(p.Copy());
561       }
562
563       if(configurations)
564       {
565          backupNode.configurations = { };
566          for(c : configurations)
567             backupNode.configurations.Add(c.Copy());
568       }
569       return backupNode;
570    }
571
572    void Revert(ProjectNode backupNode)
573    {
574       if(files)
575       {
576          Iterator<ProjectNode> it { backupNode.files };
577          for(f : files)
578          {
579             it.Next();
580             f.Revert(it.data);
581          }
582       }
583
584       delete options;
585       if(platforms)
586       {
587          platforms.Free();
588          delete platforms;
589       }
590       if(configurations)
591       {
592          configurations.Free();
593          delete configurations;
594       }
595
596       options = backupNode.options ? backupNode.options.Copy() : null;
597       if(backupNode.platforms)
598       {
599          platforms = { };
600          for(p : backupNode.platforms)
601             platforms.Add(p.Copy());
602       }
603       if(backupNode.configurations)
604       {
605          configurations = { };
606          for(c : backupNode.configurations)
607             configurations.Add(c.Copy());
608       }
609    }
610
611    void FixupNode(char * parentPath)
612    {
613       if(!parent)
614       {
615          type = project;
616       }
617       else if(nodeType == file)
618       {
619          type = file;
620          if(!path)
621          {
622             path = CopyString((parent.type == folder || parent.type == resources) ? parentPath : "");
623          }
624       }
625       else if(nodeType == folder)
626       {
627          type = folder;
628
629          if(!path)
630          {
631             char temp[MAX_LOCATION];
632             strcpy(temp, (parent.type == folder || parent.type == resources) ? parentPath : "");
633             PathCatSlash(temp, name);
634             path = CopyString(temp);
635          }
636       }
637
638       indent = parent ? parent.indent + 1 : 0;
639
640       if(type == file)
641          icon = NodeIcons::SelectFileIcon(name);
642       else
643          icon = NodeIcons::SelectNodeIcon(type);
644
645       if(files)
646       {
647          for(f : files)
648          {
649             f.parent = this;
650
651             if(type == project)
652                parentPath[0] = '\0';
653             else if(type == resources || type == folder)
654                strcpy(parentPath, path);
655
656             f.FixupNode(parentPath);
657          }
658       }
659    }
660
661    char * OnGetString(char * tempString, void * fieldData, bool * needClass)
662    {
663       if(!needClass)
664       {
665          // TOCHECK: Called from JSON writer
666          if(nodeType == file && !options && !configurations && !platforms && name)
667          {
668             strcpy(tempString, "\"");
669             strcat(tempString, property::fileName);
670             strcat(tempString, "\"");
671             return tempString;
672          }
673          else
674             return null;
675       }
676       else
677          // TOCHECK: Called from ProjectView rendering
678          return name ? name : "";
679    }
680
681    ~ProjectNode()
682    {
683       if(files)
684       {
685          files.Free();
686          delete files;
687       }
688       delete options;
689
690       if(platforms)
691       {
692          platforms.Free();
693          delete platforms;
694       };
695       if(configurations)
696       {
697          configurations.Free();
698          delete configurations;
699       }
700
701       /////////////////////////////
702       delete path;
703       delete name;
704       delete info;
705    }
706
707    property bool isInResources
708    {
709       get
710       {
711          ProjectNode node;
712          for(node = this; node; node = node.parent)
713          {
714             if(node.type == resources)
715                return true;
716          }
717          return false;
718       }
719    }
720
721    property TwoStrings platformSpecificExclusionFu
722    {
723       get
724       {
725          // TODO: Proper folder exclusion fix: collect platform names across parents and then build exclusion expression
726          //       Find solution to excluding a drivers folder for all platforms and overriting that exclusion on children files/folders
727          TwoStrings result { };
728          int nestingCount = 0, c, len;
729          Platform platform;
730          ProjectConfig config = property::config;
731          Map<String, bool> platformNames { };
732          if(platforms)
733          {
734             for(p : platforms)
735                if(p.options.excludeFromBuild == true)
736                   platformNames[p.name] = true;
737          }
738          if(config && config.platforms)
739          {
740             for(p : config.platforms)
741                if(p.options.excludeFromBuild == true)
742                   platformNames[p.name] = true;
743          }
744          if(platformNames.count)
745          {
746             len = 0;
747             result.a = new char[1];
748             result.a[0] = '\0';
749             for(s : platformNames)
750             {
751                for(platform = (Platform)1; platform < Platform::enumSize; platform++)
752                   if(!strcmpi(&s, platform))
753                      break;
754                if(platform < Platform::enumSize)
755                {
756                   const char * opening = "$(if $(";
757                   const char * close = "),,";
758                   char * t = PlatformToMakefileVariable(platform);
759                   nestingCount++;
760                   len += strlen(t) + strlen(opening) + strlen(close);
761                   result.a = renew result.a char[len + 1];
762                   strcat(result.a, opening);
763                   strcat(result.a, t);
764                   strcat(result.a, close);
765                }
766             }
767             result.b = new char[nestingCount + 1];
768             for(c = 0; c < nestingCount; c++)
769                result.b[c] = ')';
770             result.b[nestingCount] = '\0';
771          }
772          else
773          {
774             result.a = CopyString("");
775             result.b = CopyString("");
776          }
777          delete platformNames;
778          if(parent)
779          {
780             TwoStrings parentResult = parent.platformSpecificExclusionFu;
781             if(parentResult.a && parentResult.a[0])
782             {
783                len = strlen(result.a) + strlen(parentResult.a);
784                result.a = renew result.a char[len + 1];
785                strcat(result.a, parentResult.a);
786                len = strlen(result.b) + strlen(parentResult.b);
787                result.b = renew result.b char[len + 1];
788                strcat(result.b, parentResult.b);
789             }
790             delete parentResult;
791          }
792          return result;
793       }
794    }
795
796    property bool isExcluded
797    {
798       get
799       {
800          // THIS IS THE GENERIC (ALL PLATFORMS) EXCLUDED FROM BUILD
801          // TODO: We can also have platform specific exclusion...
802          ProjectConfig config = property::config;
803          if(config && config.options && config.options.excludeFromBuild)
804             return config.options.excludeFromBuild == true;            
805          if(options && options.excludeFromBuild)
806             return options.excludeFromBuild == true;
807          if(parent)
808             return parent.isExcluded;
809          return false;
810       }
811    }
812
813    void EnsureVisible()
814    {
815       if(parent)
816          parent.EnsureVisible();
817       row.collapsed = false;
818    }
819
820    void Delete()
821    {
822       if(parent)
823          parent.files.Delete(this);
824    }
825
826    ProjectNode Find(char * name, bool includeResources)
827    {
828       ProjectNode result = null;
829       if(files)
830       {
831          for(child : files)
832          {
833             if(includeResources || child.type != resources)
834             {
835                if(child.type != folder && child.name && !strcmpi(child.name, name))
836                {
837                   result = child;
838                   break;
839                }
840                result = child.Find(name, includeResources);
841                if(result)
842                   break;
843             }
844          }
845       }
846       return result;
847    }
848
849    ProjectNode FindWithPath(char * name, bool includeResources)
850    {
851       ProjectNode result = null;
852       if(files)
853       {
854          for(child : files)
855          {
856             if(includeResources || child.type != resources)
857             {
858                char path[MAX_LOCATION];
859                strcpy(path, child.path);
860                if(child.type != folder && child.name)
861                {
862                   PathCatSlash(path, child.name);
863                   if(!strcmpi(path, name))
864                   {
865                      result = child;
866                      break;
867                   }
868                }
869                result = child.FindWithPath(name, includeResources);
870                if(result)
871                   break;
872             }
873          }
874       }
875       return result;
876    }
877
878    ProjectNode FindSpecial(char * name, bool recursive, bool includeResources, bool includeFolders)
879    {
880       ProjectNode result = null;
881       if(files)
882       {
883          for(child : files)
884          {
885             if(includeResources || child.type != resources)
886             {
887                if((includeFolders || child.type != folder) && child.name && !strcmpi(child.name, name))
888                {
889                   result = child;
890                   break;
891                }
892                if(recursive)
893                   result = child.FindSpecial(name, recursive, includeResources, includeFolders);
894                if(result)
895                   break;
896             }
897          }
898       }
899       return result;
900    }
901
902    ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
903    {
904       ProjectNode node = null;
905       char temp[MAX_LOCATION];
906
907       GetLastDirectory(filePath, temp);
908       if(!checkIfExists || !project.topNode.Find(temp, false))
909       {
910          // Do the check for folder in the same parent or resource files only here
911          if(type == folder || !checkIfExists)
912          {
913             for(node : files)
914             {
915                if(node.name && !strcmpi(node.name, temp))
916                   return null;
917             }
918          }
919
920          node = ProjectNode { parent = this, indent = indent + 1, type = type, icon = icon, name = CopyString(temp) };
921          if(type != file)
922          {
923             node.files = { }; 
924             node.nodeType = folder;
925          }
926          if(type != folder)
927          {
928             if(filePath)
929             {
930                StripLastDirectory(filePath, temp);
931                MakePathRelative(temp, project.topNode.path, temp);
932                node.path = CopyUnixPath(temp);
933             }
934             node.nodeType = file;
935          }
936          else
937          {
938             strcpy(temp, (type == NodeTypes::project) ? "" : path);
939             PathCatSlash(temp, node.name);
940             node.path = CopyString(temp);
941          }
942          files.Insert(after, node);
943       }
944       return node;
945    }
946
947 #ifndef MAKEFILE_GENERATOR
948    void OnDisplay(Surface surface, int x, int y, int width, ProjectView projectView, Alignment alignment, DataDisplayFlags displayFlags)
949    {
950       char label[MAX_FILENAME];
951       int indent = 16;
952       int xStart;
953       int len;
954       int w, h;
955       Bitmap bmp;
956       bool showConfig = true;
957
958       if(!projectView)
959       {
960          showConfig = false;
961          projectView = ide.projectView;
962       }         
963       
964       bmp = projectView.icons[icon].bitmap;
965       xStart = /*indent * indent + */x + (bmp ? (bmp.width + 5) : 0);
966
967       GetLastDirectory(name, label);
968       if(!showConfig || projectView.drawingInProjectSettingsDialogHeader)
969       {
970          if(projectView.drawingInProjectSettingsDialogHeader || (type == project && info))
971          {
972             if(projectView.projectSettingsDialog && projectView.projectSettingsDialog.buildTab)
973             {
974                char * addendum;
975                addendum = projectView.projectSettingsDialog.buildTab.selectedConfigName;
976                if(strlen(addendum))
977                {
978                   strcat(label, " (");
979                   strcat(label, addendum);
980                   strcat(label, ")");
981                }
982                addendum = projectView.projectSettingsDialog.buildTab.selectedPlatformName;
983                if(strlen(addendum))
984                {
985                   strcat(label, " (");
986                   strcat(label, addendum);
987                   strcat(label, ")");
988                }
989             }
990          }
991       }
992       else if(!projectView.drawingInProjectSettingsDialog)
993       {
994          if(modified)
995             strcat(label, " *");
996          if(type == project && info)
997          {
998             int len = strlen(info) + 4;
999             char * more = new char[len];
1000             sprintf(more, " (%s)", info);
1001             strcat(label, more);
1002             delete more;
1003          }
1004       }
1005       len = strlen(label);
1006       
1007       if(!bmp)
1008       {
1009          if(type == folder || type == folderOpen)
1010             surface.SetForeground(yellow);
1011          indent = 8;
1012       }
1013
1014       surface.TextOpacity(false);
1015       surface.TextExtent(label, len, &w, &h);
1016       h = Max(h, 16);
1017     
1018       // Draw the current row stipple
1019       if(displayFlags.selected)
1020          //surface.Area(xStart - 1, y, xStart - 1, y + h - 1);
1021          //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1);
1022          surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1);
1023       
1024       surface.WriteTextDots(alignment, xStart, y + 2, width, label, len);
1025       
1026       if(!app.textMode)
1027       {
1028          if(displayFlags.current)
1029          {
1030             if(displayFlags.active)
1031             {
1032                surface.LineStipple(0x5555);
1033                if(displayFlags.selected)
1034                   surface.SetForeground(0xFFFFFF80);
1035                else
1036                   surface.SetForeground(black);
1037             }
1038             else
1039             {
1040                surface.SetForeground(SELECTION_COLOR);
1041             }
1042             surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1);
1043             surface.LineStipple(0);
1044          }
1045
1046          if(bmp)
1047          {
1048             surface.SetForeground(white);
1049             surface.Blit(bmp, x /*+ indent * indent*/,y,0,0, bmp.width, bmp.height);
1050          }
1051       }
1052    }
1053 #endif
1054
1055    int OnCompare(ProjectNode b)
1056    {
1057       int result;
1058       if(type == b.type /*|| type >= TYPE_DRIVE*/)
1059          result = strcmpi(name, b.name);
1060       else
1061       {
1062          if(type == folder && b.type == file) result = -1;
1063          else if(type == file && b.type == folder) result = 1;
1064       }
1065       return result;
1066    }
1067
1068    void GenFileFlags(File f, Project project)
1069    {
1070       ProjectNode node = null;
1071       List<ProjectNode> nodeStack { };
1072       
1073       for(node = this; node && node.parent; node = node.parent)
1074          nodeStack.Add(node);
1075
1076       // Should we reverse this stack to give priority to the per-file includes?
1077
1078       while((node = nodeStack.lastIterator.data))
1079       {
1080          ProjectConfig config = node.config;
1081          if(node.options && node.options.preprocessorDefinitions)
1082             OutputListOption(f, "D", node.options.preprocessorDefinitions, inPlace, false);
1083          if(config && config.options && config.options.preprocessorDefinitions)
1084             OutputListOption(f, "D", config.options.preprocessorDefinitions, inPlace, false);
1085          if(node.options && node.options.includeDirs)
1086             OutputListOption(f, "I", node.options.includeDirs, inPlace, true);
1087          if(config && config.options && config.options.includeDirs)
1088             OutputListOption(f, "I", config.options.includeDirs, inPlace, true);
1089
1090          nodeStack.lastIterator.Remove();
1091       }
1092       delete nodeStack;
1093    }
1094
1095    void GenMakefileGetNameCollisionInfo(Map<String, NameCollisionInfo> namesInfo)
1096    {
1097       if(type == file)
1098       {
1099          char extension[MAX_EXTENSION];
1100          GetExtension(name, extension);
1101          if(!strcmpi(extension, "ec") || !strcmpi(extension, "c") ||
1102                !strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
1103                !strcmpi(extension, "cxx") || !strcmpi(extension, "m"))
1104          {
1105             char moduleName[MAX_FILENAME];
1106             NameCollisionInfo info;
1107             ReplaceSpaces(moduleName, name);
1108             StripExtension(moduleName);
1109             info = namesInfo[moduleName];
1110             if(!info)
1111                info = NameCollisionInfo { };
1112             info.count++; // += 1; unless this is for a bug?
1113             if(!strcmpi(extension, "ec"))
1114                info.ec = true;
1115             else if(!strcmpi(extension, "c"))
1116                info.c = true;
1117             else if(!strcmpi(extension, "cpp"))
1118                info.cpp = true;
1119             else if(!strcmpi(extension, "cc"))
1120                info.cc = true;
1121             else if(!strcmpi(extension, "cxx"))
1122                info.cxx = true;
1123             else if(!strcmpi(extension, "m"))
1124                info.m = true;
1125             namesInfo[moduleName] = info;
1126          }
1127       }
1128       else if(files)
1129       {
1130          for(child : files)
1131          {
1132             if(child.type != resources && (child.type == folder || !child.isExcluded))
1133                child.GenMakefileGetNameCollisionInfo(namesInfo);
1134          }
1135       }
1136    }
1137    
1138    int GenMakefilePrintNode(File f, Project project, GenMakefilePrintTypes printType, Map<String, NameCollisionInfo> namesInfo, Array<String> items)
1139    {
1140       int count = 0;
1141       if(type == file)
1142       {
1143          char s[2048];
1144          // TOCHECK: Does this take care of parent folder platform specific exclusions?
1145          TwoStrings ts = platformSpecificExclusionFu;
1146          char moduleName[MAX_FILENAME];
1147          char extension[MAX_EXTENSION];
1148          GetExtension(name, extension);
1149          if(printType == resources)
1150          {
1151             bool useRes;
1152             char tempPath[MAX_LOCATION];
1153             char modulePath[MAX_LOCATION];
1154
1155             tempPath[0] = '\0';
1156             if(eString_PathInsideOfMore(path, project.resNode.path, tempPath))
1157             {
1158                useRes = true;
1159                PathCatSlash(tempPath, name);
1160             }
1161             else
1162             {
1163                useRes = false;
1164                strcpy(tempPath, path);
1165                PathCatSlash(tempPath, name);
1166             }
1167             ReplaceSpaces(modulePath, tempPath);
1168             sprintf(s, "%s%s%s%s", ts.a, useRes ? "$(RES)" : "", modulePath, ts.b);
1169             items.Add(CopyString(s));
1170          }
1171          else if(printType == sources)
1172          {
1173             if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1174                   !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1175                   !strcmpi(extension, "ec") || !strcmpi(extension, "m"))
1176             {
1177                char modulePath[MAX_LOCATION];
1178
1179                ReplaceSpaces(modulePath, path);
1180                ReplaceSpaces(moduleName, name);
1181                sprintf(s, "%s%s%s%s%s", ts.a, modulePath, path[0] ? SEPS : "", moduleName, ts.b);
1182                items.Add(CopyString(s));
1183             }
1184          }
1185          else if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1186                !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
1187                !strcmpi(extension, "m"))
1188          {
1189             if(printType == objects)
1190             {
1191                bool collision;
1192                NameCollisionInfo info;
1193                ReplaceSpaces(moduleName, name);
1194                StripExtension(moduleName);
1195                info = namesInfo[moduleName];
1196                collision = info ? info.IsExtensionColliding(extension) : false;
1197                sprintf(s, "%s$(OBJ)%s%s%s.o%s", ts.a, moduleName, collision ? "." : "", collision ? extension : "", ts.b);
1198                items.Add(CopyString(s));
1199             }
1200          }
1201          else if(!strcmpi(extension, "ec"))
1202          {
1203             ReplaceSpaces(moduleName, name);
1204             StripExtension(moduleName);
1205             if(printType == objects)
1206                count++;
1207             s[0] = '\0';
1208             if(printType == objects)
1209                sprintf(s, "%s$(OBJ)%s.o%s", ts.a, moduleName, ts.b);
1210             else if(printType == cObjects)
1211                sprintf(s, "%s$(OBJ)%s.c%s", ts.a, moduleName, ts.b);
1212             else if(printType == symbols)
1213                sprintf(s, "%s$(OBJ)%s.sym%s", ts.a, moduleName, ts.b);
1214             else if(printType == imports)
1215                sprintf(s, "%s$(OBJ)%s.imp%s", ts.a, moduleName, ts.b);
1216             if(s[0])
1217                items.Add(CopyString(s));
1218          }
1219          delete ts;
1220       }
1221       else if(files)
1222       {
1223          for(child : files)
1224          {
1225             if(child.type != resources && (child.type == folder || !child.isExcluded))
1226                count += child.GenMakefilePrintNode(f, project, printType, namesInfo, items);
1227          }
1228       }
1229       return count;
1230    }
1231
1232    void GenMakefilePrintSymbolRules(File f, Project project)
1233    {
1234       //ProjectNode child;
1235       //char objDir[MAX_LOCATION];
1236       CompilerConfig compiler = GetCompilerConfig();
1237       //ReplaceSpaces(objDir, project.config.objDir.dir);
1238
1239       //eSystem_Log("Printing Symbol Rules\n");
1240       if(type == file)
1241       {
1242          char extension[MAX_EXTENSION];
1243          char modulePath[MAX_LOCATION];
1244          char moduleName[MAX_FILENAME];
1245          
1246          GetExtension(name, extension);
1247          if(!strcmpi(extension, "ec"))
1248          {
1249             DualPipe dep;
1250             char command[2048];
1251
1252             ReplaceSpaces(moduleName, name);
1253             StripExtension(moduleName);
1254
1255             ReplaceSpaces(modulePath, path);
1256             if(modulePath[0]) strcat(modulePath, SEPS);
1257
1258 #if 0
1259             // *** Dependency command ***
1260             sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s", moduleName,
1261                modulePath, moduleName, extension);
1262
1263             // System Includes (from global settings)
1264             for(item : compiler.dirs[Includes])
1265             {
1266                strcat(command, " -isystem ");
1267                if(strchr(item, ' '))
1268                {
1269                   strcat(command, "\"");
1270                   strcat(command, item);
1271                   strcat(command, "\"");
1272                }
1273                else
1274                   strcat(command, item);
1275             }
1276
1277             for(item : project.includeDirs)
1278             {
1279                strcat(command, " -I");
1280                if(strchr(item, ' '))
1281                {
1282                   strcat(command, "\"");
1283                   strcat(command, item);
1284                   strcat(command, "\"");
1285                }
1286                else
1287                   strcat(command, item);
1288             }
1289             for(item : project.preprocessorDefs)
1290             {
1291                strcat(command, " -D");
1292                strcat(command, item);
1293             }
1294
1295             // Execute it
1296             if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1297             {
1298                char line[1024];
1299                bool firstLine = true;
1300                bool result = true;
1301
1302                // To do some time: auto save external dependencies?
1303                while(!dep.Eof())
1304                {
1305                   if(dep.GetLine(line, sizeof(line)-1))
1306                   {
1307                      if(firstLine)
1308                      {
1309                         char * colon = strstr(line, ":");
1310                         if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1311                         {
1312                            result = false;
1313                            break;
1314                         }
1315                         firstLine = false;
1316                      }
1317                      f.Puts(line);
1318                      f.Puts("\n");
1319                   }
1320                   if(!result) break;
1321                }
1322                delete dep;
1323
1324                // If we failed to generate dependencies...
1325                if(!result)
1326                {
1327 #endif
1328                   f.Printf("$(OBJ)%s.sym: %s%s.%s\n",
1329                      moduleName, modulePath, moduleName, extension);
1330 #if 0
1331                }
1332             }
1333 #endif
1334          /*
1335             f.Printf("\t$(ECP) %s%s.%s %s.sym\n\n",
1336                modulePath, moduleName, extension, moduleName);
1337             */
1338
1339             f.Printf("\t$(ECP) $(CECFLAGS)");
1340             if(ecflags)
1341             {
1342                if(memoryGuard)
1343                   f.Printf(" -memguard");
1344                if(strictNameSpaces)
1345                   f.Printf(" -strictns");
1346                {
1347                   char * s = defaultNameSpace;
1348                   if(s && s[0])
1349                      f.Printf(" -defaultns %s", s);
1350                }
1351             }
1352             else
1353                f.Printf(" $(ECFLAGS)");
1354             f.Printf(" $(CFLAGS)");
1355             GenFileFlags(f, project);
1356             f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n\n",
1357                modulePath, moduleName, extension, moduleName);
1358          }
1359       }
1360       if(files)
1361       {
1362          for(child : files)
1363          {
1364             // TODO: Platform specific options
1365             if(child.type != resources && (child.type == folder || !child.isExcluded))
1366                child.GenMakefilePrintSymbolRules(f, project);
1367          }
1368       }
1369       delete compiler;
1370    }
1371
1372    void GenMakefilePrintCObjectRules(File f, Project project)
1373    {
1374       //ProjectNode child;
1375       //char objDir[MAX_LOCATION];
1376       CompilerConfig compiler = GetCompilerConfig();
1377       //ReplaceSpaces(objDir, project.config.objDir.dir);
1378       //eSystem_Log("Printing C Object Rules\n");
1379       if(type == file)
1380       {
1381          char extension[MAX_EXTENSION];
1382          char modulePath[MAX_LOCATION];
1383          char moduleName[MAX_FILENAME];
1384          
1385          GetExtension(name, extension);
1386          if(!strcmpi(extension, "ec"))
1387          {
1388             DualPipe dep;
1389             char command[2048];
1390
1391             ReplaceSpaces(moduleName, name);
1392             StripExtension(moduleName);
1393
1394             ReplaceSpaces(modulePath, path);
1395             if(modulePath[0]) strcat(modulePath, SEPS);
1396
1397 #if 0
1398             // *** Dependency command ***
1399             sprintf(command, "gcc -MT $(OBJ)%s.o -MM %s%s.%s",
1400                moduleName, modulePath, moduleName, extension);
1401
1402             // System Includes (from global settings)
1403             for(item : compiler.dirs[Includes])
1404             {
1405                strcat(command, " -isystem ");
1406                if(strchr(item, ' '))
1407                {
1408                   strcat(command, "\"");
1409                   strcat(command, item);
1410                   strcat(command, "\"");
1411                }
1412                else
1413                   strcat(command, item);
1414             }
1415
1416             for(item : project.config.includeDirs)
1417             {
1418                strcat(command, " -I");
1419                if(strchr(item, ' '))
1420                {
1421                   strcat(command, "\"");
1422                   strcat(command, item);
1423                   strcat(command, "\"");
1424                }
1425                else
1426                   strcat(command, item);
1427             }
1428             for(item : project.config.preprocessorDefs)
1429             {
1430                strcat(command, " -D");
1431                strcat(command, item);
1432             }
1433
1434             // Execute it
1435             if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1436             {
1437                char line[1024];
1438                bool result = true;
1439                bool firstLine = true;
1440
1441                // To do some time: auto save external dependencies?
1442                while(!dep.Eof())
1443                {
1444                   if(dep.GetLine(line, sizeof(line)-1))
1445                   {
1446                      if(firstLine)
1447                      {
1448                         char * colon = strstr(line, ":");
1449                         if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1450                         {
1451                            result = false;
1452                            break;
1453                         }
1454                         firstLine = false;
1455                      }
1456                      f.Puts(line);
1457                      f.Puts("\n");
1458                   }
1459                   if(!result) break;
1460                }
1461                delete dep;
1462
1463                // If we failed to generate dependencies...
1464                if(!result)
1465                {
1466                   /* COMMENTED OUT FOR NOW
1467                   f.Printf("$(OBJ)%s.c: %s%s.%s $(Symbols)\n",
1468                      moduleName, modulePath, moduleName, extension);
1469                   */
1470 #endif
1471                   f.Printf("$(OBJ)%s.c: %s%s.%s $(OBJ)%s.sym | $(SYMBOLS)\n",
1472                      moduleName, modulePath, moduleName, extension, moduleName);
1473 #if 0
1474                }
1475             }
1476 #endif
1477          /*
1478             f.Printf("\t$(ECC) %s%s.%s $(OBJ)%s.c\n\n",
1479                modulePath, moduleName, extension, moduleName);
1480          */
1481
1482             f.Printf("\t$(ECC)");
1483             if(ecflags)
1484             {
1485                f.Printf("%s $(CECFLAGS)", noLineNumbers ? " -nolinenumbers" : "");
1486                if(memoryGuard)
1487                   f.Printf(" -memguard");
1488                if(strictNameSpaces)
1489                   f.Printf(" -strictns");
1490                {
1491                   char * s = defaultNameSpace;
1492                   if(s && s[0])
1493                      f.Printf(" -defaultns %s", s);
1494                }
1495             }
1496             else
1497                f.Printf(" $(CECFLAGS) $(ECFLAGS)");
1498             f.Printf(" $(CFLAGS) $(FVISIBILITY)");
1499             GenFileFlags(f, project);
1500             f.Printf(" -c %s%s.%s -o $(OBJ)%s.c -symbols $(OBJ)\n\n",
1501                modulePath, moduleName, extension, moduleName);
1502          }
1503       }
1504       if(files)
1505       {
1506          for(child : files)
1507          {
1508             // TODO: Platform specific options
1509             if(child.type != resources && (child.type == folder || !child.isExcluded))
1510                child.GenMakefilePrintCObjectRules(f, project);
1511          }
1512       }
1513       delete compiler;
1514    }
1515
1516    void GenMakefilePrintObjectRules(File f, Project project, Map<String, NameCollisionInfo> namesInfo)
1517    {
1518       //ProjectNode child;
1519       //char objDir[MAX_LOCATION];
1520       CompilerConfig compiler = GetCompilerConfig();
1521       //ReplaceSpaces(objDir, project.config.objDir.dir);
1522       //eSystem_Log("Printing Object Rules\n");
1523       if(type == file)
1524       {
1525          bool collision;
1526          char extension[MAX_EXTENSION];
1527          char modulePath[MAX_LOCATION];
1528          char moduleName[MAX_FILENAME];
1529          
1530          GetExtension(name, extension);
1531          /*if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1532                !strcmpi(extension, "ec") || !strcmpi(extension, "cc") ||
1533                !strcmpi(extension, "cxx"))*/
1534          if((!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
1535                !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")) ||
1536                !strcmpi(extension, "ec"))
1537          {
1538             DualPipe dep;
1539             char command[2048];
1540             NameCollisionInfo info;
1541
1542             ReplaceSpaces(moduleName, name);
1543             StripExtension(moduleName);
1544
1545             info = namesInfo[moduleName];
1546             collision = info ? info.IsExtensionColliding(extension) : false;
1547             
1548             ReplaceSpaces(modulePath, path);
1549             if(modulePath[0]) strcat(modulePath, SEPS);
1550
1551             // *** Dependency command ***
1552             if(!strcmpi(extension, "ec"))
1553                sprintf(command, "%s -MT $(OBJ)%s.o -MM $(OBJ)%s.c", compiler.ccCommand, moduleName, moduleName);
1554             else
1555                sprintf(command, "%s -MT $(OBJ)%s.o -MM %s%s.%s", compiler.ccCommand, moduleName, modulePath, moduleName, extension);
1556
1557             if(!strcmpi(extension, "ec"))
1558                f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1559             else
1560             {
1561 #if 0
1562                // System Includes (from global settings)
1563                for(item : compiler.dirs[includes])
1564                {
1565                   strcat(command, " -isystem ");
1566                   if(strchr(item, ' '))
1567                   {
1568                      strcat(command, "\"");
1569                      strcat(command, item);
1570                      strcat(command, "\"");
1571                   }
1572                   else
1573                      strcat(command, item);
1574                }
1575
1576                for(item : project.config.includeDirs)
1577                {
1578                   strcat(command, " -I");
1579                   if(strchr(item, ' '))
1580                   {
1581                      strcat(command, "\"");
1582                      strcat(command, item);
1583                      strcat(command, "\"");
1584                   }
1585                   else
1586                      strcat(command, item);
1587                }
1588                for(item : project.config.preprocessorDefs)
1589                {
1590                   strcat(command, " -D");
1591                   strcat(command, item);
1592                }
1593
1594                // Execute it
1595                if((dep = DualPipeOpen(PipeOpenMode { output = 1, error = 1, input = 2 }, command)))
1596                {
1597                   char line[1024];
1598                   bool firstLine = true;
1599                   bool result = true;
1600
1601                   // To do some time: auto save external dependencies?
1602
1603                   while(!dep.Eof())
1604                   {
1605                      if(dep.GetLine(line, sizeof(line)-1))
1606                      {
1607                         if(firstLine)
1608                         {
1609                            char * colon = strstr(line, ":");
1610                            if(strstr(line, "No such file") || strstr(line, ",") || (colon && strstr(colon+1, ":")))
1611                            {
1612                               result = false;
1613                               break;
1614                            }
1615                            firstLine = false;
1616                         }
1617                         f.Puts(line);
1618                         f.Puts("\n");
1619                      }
1620                      if(!result) break;
1621                   }
1622                   delete dep;
1623
1624                   // If we failed to generate dependencies...
1625                   if(!result)
1626                   {
1627 #endif
1628                      /*if(!strcmpi(extension, "ec"))
1629                         f.Printf("$(OBJ)%s.o: $(OBJ)%s.c\n", moduleName, moduleName);
1630                      else*/
1631                         f.Printf("$(OBJ)%s%s%s.o: %s%s.%s\n", moduleName, 
1632                               collision ? "." : "", collision ? extension : "", modulePath, moduleName, extension);
1633 #if 0
1634                   }
1635                }
1636 #endif
1637             }
1638             f.Printf("\t$(CC) $(CFLAGS)");
1639             GenFileFlags(f, project);
1640             if(!strcmpi(extension, "ec"))
1641                f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(OBJ)%s.o\n\n", moduleName, moduleName);
1642             else
1643                f.Printf(" -c %s%s.%s -o $(OBJ)%s%s%s.o\n\n",
1644                      modulePath, moduleName, !strcmpi(extension, "ec") ? "c" : extension, moduleName,
1645                      collision ? "." : "", collision ? extension : "");
1646          }
1647       }
1648       if(files)
1649       {
1650          for(child : files)
1651          {
1652             // TODO: Platform specific options
1653             if(child.type != resources && (child.type == folder || !child.isExcluded))
1654                child.GenMakefilePrintObjectRules(f, project, namesInfo);
1655          }
1656       }
1657       delete compiler;
1658    }
1659
1660    void GenMakefileAddResources(File f, String resourcesPath)
1661    {
1662       int count = 0;
1663       if(files)
1664       {
1665          int c;
1666          bool prev = false;
1667          //Iterator<ProjectNode> i { files };
1668          //Iterator<ProjectNode> prev { files };
1669          //for(child : files)
1670          //while(i.Next())
1671          for(c = 0; c < files.count; c++)
1672          {
1673             ProjectNode child = files[c];
1674             TwoStrings ts = child.platformSpecificExclusionFu;
1675             if(count > 0 && ts)
1676                prev = true;
1677             if(child.type == file && !child.isExcluded && !(count > 0 && ts))
1678             {
1679                bool useRes;
1680                char tempPath[MAX_LOCATION];
1681                char resPath[MAX_LOCATION];
1682
1683                char * quotes;
1684
1685                // $(EAR) aw%s --- /*quiet ? "q" : */""
1686                if(count == 0)
1687                   f.Printf("\t%s$(EAR) aw $(TARGET)", ts.a);
1688
1689                tempPath[0] = '\0';
1690                if(eString_PathInsideOfMore(child.path, resourcesPath, tempPath))
1691                {
1692                   useRes = true;
1693                   PathCatSlash(tempPath, child.name);
1694                }
1695                else
1696                {
1697                   useRes = false;
1698                   strcpy(tempPath, child.path);
1699                   PathCatSlash(tempPath, child.name);
1700                }
1701                ReplaceSpaces(resPath, tempPath);
1702                if(strchr(tempPath, ' '))
1703                   quotes = "\"";
1704                else
1705                   quotes = "";
1706                f.Printf(" %s%s%s%s", quotes, useRes ? "$(RES)" : "", resPath, quotes);
1707                count++;
1708             }
1709             if(count == 10 || (count > 0 && (ts || !child.next)))
1710             {
1711                char path[MAX_LOCATION] = "", temp[MAX_LOCATION];
1712                ProjectNode parent;
1713
1714                for(parent = this; parent.type == folder; parent = parent.parent)
1715                {
1716                   strcpy(temp, path);
1717                   strcpy(path, parent.name);
1718                   if(temp[0])
1719                   {
1720                      strcat(path, "/");
1721                      strcat(path, temp);
1722                   }
1723                }
1724                f.Printf(" \"%s\"%s\n", path, ts.b);
1725                count = 0;
1726                if(prev)
1727                {
1728                   c--;
1729                   prev = false;
1730                }
1731             }
1732             delete ts;
1733          }
1734          for(child : files)
1735          {
1736             if(child.type == folder)
1737                child.GenMakefileAddResources(f, resourcesPath);
1738          }
1739       }
1740    }
1741 }
1742
1743 class NameCollisionInfo
1744 {
1745    bool ec;
1746    bool c;
1747    bool cpp;
1748    bool cc;
1749    bool cxx;
1750    bool m;
1751    byte count;
1752
1753    bool IsExtensionColliding(char * extension)
1754    {
1755       bool colliding;
1756       if(count > 1 && ((!strcmpi(extension, "c") && ec) ||
1757             (!strcmpi(extension, "cpp") && (ec || c)) ||
1758             (!strcmpi(extension, "cc") && (ec || c || cpp)) ||
1759             (!strcmpi(extension, "cxx") && (ec || c || cpp || cc)) ||
1760             !strcmpi(extension, "m")))
1761          colliding = true;
1762       else
1763          colliding = false;
1764      return colliding;
1765    }
1766 }