Initial git commit -- Transition from CodeGuard repository
[sdk] / ide / src / IDESettings.ec
1 #ifdef ECERE_STATIC
2 import static "ecere"
3 #else
4 import "ecere"
5 #endif
6
7 import "StringsBox"
8
9 import "OldIDESettings"
10
11 define MaxRecent = 9;
12
13 enum DirTypes { includes, libraries, executables };
14
15 define defaultCompilerName = "Default";
16
17 define defaultObjDirExpression = "obj/$(CONFIG).$(PLATFORM)";
18
19 char * settingsDirectoryNames[DirTypes] = 
20 {
21    "Include Files",
22    "Library Files",
23    "Executable Files"
24 };
25
26 enum GlobalSettingsChange { none, editorSettings, projectOptions, compilerSettings };
27
28 char * CopyValidateMakefilePath(char * path)
29 {
30    const int map[]  =    { 0,           1,           2,             3,             4,           0,            1,                  7         };
31    const char * vars[] = { "$(MODULE)", "$(CONFIG)", "$(PLATFORM)", "$(COMPILER)", "$(TARGET)", "$(PROJECT)", "$(CONFIGURATION)", (char *)0 };
32
33    char * copy = null;
34    if(path)
35    {
36       int len;
37       len = strlen(path);
38       copy = CopyString(path);
39       if(len)
40       {
41          int c;
42          char * tmp = copy;
43          char * start = tmp;
44          Array<char *> parts { };
45          
46          for(c=0; c<len; c++)
47          {
48             if(tmp[c] == '$')
49             {
50                int v;
51                for(v=0; vars[v]; v++)
52                {
53                   if(SearchString(&tmp[c], 0, vars[v], false, false) == &tmp[c])
54                   {
55                      tmp[c] = '\0';
56                      parts.Add(start);
57                      parts.Add(vars[map[v]]);
58                      c += strlen(vars[v]);
59                      start = &tmp[c];
60                      c--;
61                      break;
62                   }
63                }
64             }
65          }
66          if(start[0])
67             parts.Add(start);
68
69          if(parts.count)
70          {
71             /*int c, */len = 0;
72             for(c=0; c<parts.count; c++) len += strlen(parts[c]);
73             copy = new char[++len];
74             copy[0] = '\0';
75             for(c=0; c<parts.count; c++) strcat(copy, parts[c]);
76          }
77          else
78             copy = null;
79          delete parts;
80          delete tmp;
81       }
82    }
83    return copy;
84 }
85
86 CompilerConfig MakeDefaultCompiler(char * name, bool readOnly)
87 {
88    CompilerConfig defaultCompiler
89    {
90       name,
91       readOnly,
92       gcc,
93       GetRuntimePlatform(),
94       1,
95       makeDefaultCommand,
96       ecpDefaultCommand,
97       eccDefaultCommand,
98       ecsDefaultCommand,
99       earDefaultCommand,
100       cppDefaultCommand,
101       ccDefaultCommand
102    };
103    incref defaultCompiler;
104    return defaultCompiler;
105 }
106
107 class IDESettingsContainer : GlobalSettings
108 {
109 #ifdef SETTINGS_TEST
110    settingsName = "ecereIDESettingsTest";
111 #else
112    settingsName = "ecereIDE";
113 #endif
114
115    virtual void OnLoad(GlobalSettingsData data);
116
117 private:
118    IDESettingsContainer()
119    {
120       char path[MAX_LOCATION];
121       char * start;
122       LocateModule(null, path);
123       // PortableApps.com directory structure
124       if((start = strstr(path, "\\App\\EcereSDK\\bin\\ide.exe")))
125       {
126          char configFilePath[MAX_LOCATION];
127          char defaultConfigFilePath[MAX_LOCATION];
128
129          start[0] = '\0';
130
131          strcpy(configFilePath, path);
132          PathCat(configFilePath, "Data");
133          PathCat(configFilePath, "ecereIDE.ini");
134
135          strcpy(defaultConfigFilePath, path);
136          PathCat(defaultConfigFilePath, "App");
137          PathCat(defaultConfigFilePath, "DefaultData");
138          PathCat(defaultConfigFilePath, "ecereIDE.ini");
139          
140          if(FileExists(defaultConfigFilePath))
141          {
142             if(!FileExists(configFilePath))
143             {
144                File f = FileOpen(defaultConfigFilePath, read);
145                f.CopyTo(configFilePath);
146                f.Flush();
147                delete f;
148             }
149             PathCat(path, "Data");
150             // the forced settings location will only be
151             // used if the running ide's path matches 
152             // the PortableApps.com directory structure
153             // and the default ini file is found in 
154             // the DefaultData directory
155             settingsLocation = path;
156             portable = true;
157          }
158       }
159    }
160
161    void OnAskReloadSettings()
162    {
163       /*if(MessageBox { type = YesNo, master = this, 
164             text = "Global Settings Modified Externally", 
165             contents = "The global settings were modified by another instance.\n"
166             "Would you like to reload them?" }.Modal() == Yes)*/
167       {
168          Load();
169       }
170    }
171
172    void Load()
173    {
174       SettingsIOResult result = GlobalSettings::Load();
175       IDESettings data = (IDESettings)this.data;
176       //if(result == success)
177       if(!data)
178       {
179          this.data = IDESettings { };
180          if(dataOwner)
181             *dataOwner = this.data;
182
183          if(result == fileNotCompatibleWithDriver)
184          {
185             bool loaded;
186             OldIDESettings oldSettings { };
187             Close();
188             loaded = oldSettings.Load();
189             oldSettings.Close();
190             if(loaded)
191             {
192                data = (IDESettings)this.data;
193
194                for(c : oldSettings.compilerConfigs)
195                   data.compilerConfigs.Add(c.Copy());
196
197                for(s : oldSettings.recentFiles) data.recentFiles.Add(CopyString(s));
198                for(s : oldSettings.recentProjects) data.recentProjects.Add(CopyString(s));
199
200                data.docDir = oldSettings.docDir;
201                data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
202                data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
203                data.useFreeCaret = oldSettings.useFreeCaret;
204                data.showLineNumbers = oldSettings.showLineNumbers;
205                data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
206                delete data.displayDriver;
207                data.displayDriver = oldSettings.displayDriver;
208                data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
209                data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
210                         
211                Save();
212                result = success;
213             }
214             delete oldSettings;
215          }
216          if(result == fileNotFound || !data)
217          {
218             CompilerConfig defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
219             data = (IDESettings)this.data;
220             data.compilerConfigs = { };
221             data.compilerConfigs.Add(defaultCompiler);
222             data.useFreeCaret = true;
223             data.showLineNumbers = true;
224             data.caretFollowsScrolling = true;
225          }
226       }
227       CloseAndMonitor();
228       if(data.compilerConfigs)
229       {
230          for(c : data.compilerConfigs)
231          {
232             CompilerConfig compiler = c;
233             incref compiler;
234          }
235       }
236       if(portable)
237       {
238          char location[MAX_LOCATION];
239          LocateModule(null, location);
240          StripLastDirectory(location, location);
241          if(location[0] && FileExists(location).isDirectory)
242          {
243             if(data.portableLocation && data.portableLocation[0] && strcmp(data.portableLocation, location))
244             {
245                data.UpdatePortablePaths(data.portableLocation, location);
246                data.portableLocation = location;
247                Save();
248             }
249          }
250       }
251       data.ForcePathSeparatorStyle(true);
252       OnLoad(data);
253    }
254
255    void Save()
256    {
257       IDESettings data = (IDESettings)this.data;
258       Platform runtimePlatform = GetRuntimePlatform();
259       data.ForcePathSeparatorStyle(runtimePlatform != win32);
260       if(!GlobalSettings::Save())
261          PrintLn("Error saving IDE settings");
262       if(runtimePlatform == win32)
263          data.ForcePathSeparatorStyle(true);
264       CloseAndMonitor();
265    }
266 }
267
268 class IDESettings : GlobalSettingsData
269 {
270 public:
271    List<CompilerConfig> compilerConfigs { };
272    Array<String> recentFiles { };
273    Array<String> recentProjects { };
274    property char * docDir
275    {
276       set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
277       get { return docDir ? docDir : ""; }
278       isset { return docDir && docDir[0]; }
279    }
280    property char * ideFileDialogLocation
281    {
282       set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
283       get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
284       isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
285    }
286    property char * ideProjectFileDialogLocation
287    {
288       set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
289       get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
290       isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
291    }
292    bool useFreeCaret;
293    bool showLineNumbers;
294    bool caretFollowsScrolling;
295    char * displayDriver;
296    
297    // TODO: Classify settings
298    //EditorSettings editor { };
299
300    property char * projectDefaultTargetDir
301    {
302       set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
303       get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
304       isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
305    }
306    property char * projectDefaultIntermediateObjDir
307    {
308       set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
309       get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
310       isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
311    }
312
313    property char * portableLocation
314    {
315       set { delete portableLocation; if(value && value[0]) portableLocation = CopyString(value); }
316       get { return portableLocation ? portableLocation : ""; }
317       isset { return portableLocation && portableLocation[0]; }
318    }
319
320    property char * defaultCompiler
321    {
322       set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
323       get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
324       isset { return defaultCompiler && defaultCompiler[0]; }
325    }
326
327 private:
328    char * docDir;
329    char * ideFileDialogLocation;
330    char * ideProjectFileDialogLocation;
331    char * projectDefaultTargetDir;
332    char * projectDefaultIntermediateObjDir;
333    char * portableLocation;
334    char * defaultCompiler;
335
336    CompilerConfig GetCompilerConfig(String compilerName)
337    {
338       char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
339       CompilerConfig compilerConfig = null;
340       for(compiler : compilerConfigs)
341       {
342          if(!strcmp(compiler.name, name))
343          {
344             compilerConfig = compiler;
345             break;
346          }
347       }
348       if(!compilerConfig && compilerConfigs.count)
349          compilerConfig = compilerConfigs.firstIterator.data;
350       if(compilerConfig)
351          incref compilerConfig;
352       return compilerConfig;
353    }
354
355    ~IDESettings()
356    {
357       compilerConfigs.Free();
358       delete compilerConfigs;
359       recentFiles.Free();
360       delete recentFiles;
361       recentProjects.Free();
362       delete recentProjects;
363       delete docDir;
364    
365       delete projectDefaultTargetDir;
366       delete projectDefaultIntermediateObjDir;
367       delete portableLocation;
368       delete defaultCompiler;
369
370       delete ideFileDialogLocation;
371       delete ideProjectFileDialogLocation;
372       delete displayDriver;
373    }
374
375    void ForcePathSeparatorStyle(bool unixStyle)
376    {
377       char from, to;
378       if(unixStyle)
379          from = '\\', to = '/';
380       else
381          from = '/', to = '\\';
382       if(compilerConfigs && compilerConfigs.count)
383       {
384          int i;
385          for(config : compilerConfigs)
386          {
387             if(config.includeDirs && config.includeDirs.count)
388             {
389                for(i = 0; i < config.includeDirs.count; i++)
390                {
391                   if(config.includeDirs[i] && config.includeDirs[i][0])
392                      ChangeCh(config.includeDirs[i], from, to);
393                }
394             }
395             if(config.libraryDirs && config.libraryDirs.count)
396             {
397                for(i = 0; i < config.libraryDirs.count; i++)
398                {
399                   if(config.libraryDirs[i] && config.libraryDirs[i][0])
400                      ChangeCh(config.libraryDirs[i], from, to);
401                }
402             }
403             if(config.executableDirs && config.executableDirs.count)
404             {
405                for(i = 0; i < config.executableDirs.count; i++)
406                {
407                   if(config.executableDirs[i] && config.executableDirs[i][0])
408                      ChangeCh(config.executableDirs[i], from, to);
409                }
410             }
411          }
412       }
413       if(recentFiles && recentFiles.count)
414       {
415          int c;
416          for(c = 0; c < recentFiles.count; c++)
417          {
418             if(recentFiles[c] && recentFiles[c][0])
419                ChangeCh(recentFiles[c], from, to);
420          }
421       }
422       if(recentProjects && recentProjects.count)
423       {
424          int c;
425          for(c = 0; c < recentProjects.count; c++)
426          {
427             if(recentProjects[c] && recentProjects[c][0])
428                ChangeCh(recentProjects[c], from, to);
429          }
430       }
431       if(docDir && docDir[0])
432          ChangeCh(docDir, from, to);
433       if(ideFileDialogLocation && ideFileDialogLocation[0])
434          ChangeCh(ideFileDialogLocation, from, to);
435       if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
436          ChangeCh(ideProjectFileDialogLocation, from, to);
437
438       if(projectDefaultTargetDir && projectDefaultTargetDir[0])
439          ChangeCh(projectDefaultTargetDir, from, to);
440       if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
441          ChangeCh(projectDefaultIntermediateObjDir, from, to);
442
443       if(portableLocation && portableLocation[0])
444          ChangeCh(portableLocation, from, to);
445    }
446
447    bool UpdatePortablePaths(char * oldPath, char * newPath)
448    {
449       int oldLen = strlen(oldPath);
450       int newLen = strlen(newPath);
451       if(compilerConfigs && compilerConfigs.count)
452       {
453          for(config : compilerConfigs)
454          {
455             DirTypes c;
456             for(c = 0; c < DirTypes::enumSize; c++)
457             {
458                Array<String> dirs;
459                if(c == executables) dirs = config.executableDirs;
460                else if(c == includes) dirs = config.includeDirs;
461                else if(c == libraries) dirs = config.libraryDirs;
462                if(dirs && dirs.count)
463                {
464                   int i;
465                   for(i = 0; i < dirs.count; i++)
466                   {
467                      if(dirs[i] && dirs[i][0])
468                         dirs[i] = ReplaceInCopyString(dirs[i], oldPath, oldLen, newPath, newLen);
469                   }
470                }
471             }
472          }
473       }
474       if(recentFiles && recentFiles.count)
475       {
476          int c;
477          for(c = 0; c < recentFiles.count; c++)
478          {
479             if(recentFiles[c] && recentFiles[c][0])
480                recentFiles[c] = ReplaceInCopyString(recentFiles[c], oldPath, oldLen, newPath, newLen);
481          }
482       }
483       if(recentProjects && recentProjects.count)
484       {
485          int c;
486          for(c = 0; c < recentProjects.count; c++)
487          {
488             if(recentProjects[c] && recentProjects[c][0])
489                recentProjects[c] = ReplaceInCopyString(recentProjects[c], oldPath, oldLen, newPath, newLen);
490          }
491       }
492       if(docDir && docDir[0])
493          docDir = ReplaceInCopyString(docDir, oldPath, oldLen, newPath, newLen);
494       if(ideFileDialogLocation && ideFileDialogLocation[0])
495          ideFileDialogLocation = ReplaceInCopyString(ideFileDialogLocation, oldPath, oldLen, newPath, newLen);
496       if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
497          ideProjectFileDialogLocation = ReplaceInCopyString(ideProjectFileDialogLocation, oldPath, oldLen, newPath, newLen);
498
499       if(projectDefaultTargetDir && projectDefaultTargetDir[0])
500          projectDefaultTargetDir = ReplaceInCopyString(projectDefaultTargetDir, oldPath, oldLen, newPath, newLen);
501       if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
502          projectDefaultIntermediateObjDir = ReplaceInCopyString(projectDefaultIntermediateObjDir, oldPath, oldLen, newPath, newLen);
503    }
504
505    char * ReplaceInCopyString(char * string, char * find, int lenFind, char * replace, int lenReplace)
506    {
507       char * output = string;
508       char * start;
509       if(/*string && string[0] && */(start = strstr(string, find)))
510       {
511          if(lenFind == lenReplace)
512             strncpy(start, replace, lenReplace);
513          else
514          {
515             int newLen = strlen(string) + lenReplace - lenFind + 1;
516             char * newString = new char[newLen];
517             start[0] = '\0';
518             strcpy(newString, string);
519             start += lenFind;
520             strcat(newString, replace);
521             strcat(newString, start);
522             delete string;
523             return newString;
524          }
525       }
526       return output;
527    }
528
529    void AddRecentFile(char * fileName)
530    {
531       int c;
532       char * filePath = CopyString(fileName);
533       ChangeCh(filePath, '\\', '/');
534       for(c = 0; c<recentFiles.count; c++)
535       {
536          if(recentFiles[c] && !fstrcmp(recentFiles[c], filePath))
537          {
538             recentFiles.Delete((void *)&recentFiles[c]);
539             c--;
540          }
541       }
542       while(recentFiles.count >= MaxRecent)
543          recentFiles.Delete(recentFiles.GetLast());
544       recentFiles.Insert(null, filePath);
545       //UpdateRecentMenus(owner);
546    }
547
548    void AddRecentProject(char * projectName)
549    {
550       int c;
551       char * filePath = CopyString(projectName);
552       ChangeCh(filePath, '\\', '/');
553       for(c = 0; c<recentProjects.count; c++)
554       {
555          if(recentProjects[c] && !fstrcmp(recentProjects[c], filePath))
556          {
557             recentProjects.Delete((void *)&recentProjects[c]);
558             c--;
559          }
560       }
561       while(recentProjects.count >= MaxRecent)
562          recentProjects.Delete(recentProjects.GetLast());
563       recentProjects.Insert(null, filePath);
564       //UpdateRecentMenus(owner);
565    }
566 }
567
568 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
569 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
570 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
571 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
572 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
573 static const char * compilerTypeLongNames[CompilerType] =
574 {
575    "GNU Compiler Collection (GCC) / GNU Make",
576    "Tiny C Compiler / GNU Make",
577    "Portable C Compiler / GNU Make",
578    "Microsoft Visual Studio 2005 (8.0) Compiler",
579    "Microsoft Visual Studio 2008 (9.0) Compiler",
580    "Microsoft Visual Studio 2010 (10.0) Compiler"
581 };
582 const CompilerType firstCompilerType = gcc;
583 const CompilerType lastCompilerType = vs10;
584 public enum CompilerType
585 {
586    gcc, tcc, pcc, vs8, vs9, vs10;
587
588    property bool isVC
589    {
590       get { return this == vs8 || this == vs9 || this == vs10; }
591    }
592
593    property char *
594    {
595       get { return OnGetString(null, null, null); }
596       set
597       {  
598          if(value)
599          {
600             Platform c;
601             for(c = firstCompilerType; c <= lastCompilerType; c++)
602                if(!strcmpi(value, compilerTypeNames[c]))
603                   return c;
604          }
605          return gcc;
606       }
607    };
608
609    property char * longName { get { return OnGetString(null, (void*)1, null); } };
610    property char * versionString { get { return OnGetString(null, (void*)2, null); } };
611    property char * yearString { get { return OnGetString(null, (void*)3, null); } };
612    property char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
613    property char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
614
615    char * OnGetString(char * tempString, void * fieldData, bool * needClass)
616    {
617       if(this >= firstCompilerType && this <= lastCompilerType)
618       {
619          if(tempString)
620             strcpy(tempString, compilerTypeNames[this]);
621          if(fieldData == null)
622             return compilerTypeNames[this];
623          else if(fieldData == (void*)1)
624             return compilerTypeLongNames[this];
625          else if(fieldData == (void*)2)
626             return compilerTypeVersionString[this];
627          else if(fieldData == (void*)3)
628             return compilerTypeYearString[this];
629          else if(fieldData == (void*)4)
630             return compilerTypeProjectFileExtension[this];
631          else if(fieldData == (void*)5)
632             return compilerTypeSolutionFileVersionString[this];
633       }
634       return null;
635    }
636 };
637
638 class CompilerConfig
639 {
640    class_no_expansion;
641
642    numJobs = 1;
643 public:
644    property char * name
645    {
646       set
647       {
648          delete name;
649          if(value)
650             name = CopyString(value);
651       }
652       get { return name; }
653    }
654    bool readOnly;
655    CompilerType type;
656    Platform targetPlatform;
657    int numJobs;
658    property char * makeCommand
659    {
660       set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
661       get { return makeCommand; }
662       isset { return makeCommand && makeCommand[0]; }
663    }
664    property char * ecpCommand
665    {
666       set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
667       get { return ecpCommand; }
668       isset { return ecpCommand && ecpCommand[0]; }
669    }
670    property char * eccCommand
671    {
672       set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
673       get { return eccCommand; }
674       isset { return eccCommand && eccCommand[0]; }
675    }
676    property char * ecsCommand
677    {
678       set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
679       get { return ecsCommand; }
680       isset { return ecsCommand && ecsCommand[0]; }
681    }
682    property char * earCommand
683    {
684       set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
685       get { return earCommand; }
686       isset { return earCommand && earCommand[0]; }
687    }
688    property char * cppCommand
689    {
690       set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
691       get { return cppCommand; }
692       isset { return cppCommand && cppCommand[0]; }
693    }
694    property char * ccCommand
695    {
696       set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
697       get { return ccCommand; }
698       isset { return ccCommand && ccCommand[0]; }
699    }
700    property char * execPrefixCommand
701    {
702       set { delete execPrefixCommand; if(value && value[0]) execPrefixCommand = CopyString(value); }
703       get { return execPrefixCommand; }
704       isset { return execPrefixCommand && execPrefixCommand[0]; }
705    }
706    Array<String> includeDirs { };
707    Array<String> libraryDirs { };
708    Array<String> executableDirs { };
709    // TODO: Can JSON parse and serialize maps?
710    //EnvironmentVariables { };
711    Array<NamedString> environmentVars { };
712 private:
713    char * name;
714    char * makeCommand;
715    char * ecpCommand;
716    char * eccCommand;
717    char * ecsCommand;
718    char * earCommand;
719    char * cppCommand;
720    char * ccCommand;
721    char * execPrefixCommand;
722    /*union
723    {
724       struct { Array<String> includes, libraries, executables; };
725       Array<String> dirs[DirTypes];
726    }*/
727
728    ~CompilerConfig()
729    {
730       delete name;
731       delete ecpCommand;
732       delete eccCommand;
733       delete ecsCommand;
734       delete earCommand;
735       delete cppCommand;
736       delete ccCommand;
737       delete makeCommand;
738       delete execPrefixCommand;
739       if(includeDirs) { includeDirs.Free(); delete includeDirs; }
740       if(libraryDirs) { libraryDirs.Free(); delete libraryDirs; }
741       if(executableDirs) { executableDirs.Free(); delete executableDirs; }
742    }
743    CompilerConfig Copy()
744    {
745       CompilerConfig copy
746       {
747          name,
748          readOnly,
749          type,
750          targetPlatform,
751          numJobs,
752          makeCommand,
753          ecpCommand,
754          eccCommand,
755          ecsCommand,
756          earCommand,
757          cppCommand,
758          ccCommand,
759          execPrefixCommand
760       };
761       for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
762       for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
763       for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
764       for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = CopyString(ns.name), string = CopyString(ns.string) });
765
766       incref copy;
767       return copy;
768    }
769 }