buildsystem,ide,epj2make; sorted out platform variables and uses. now using HOST_PLAT...
[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)$(COMPILER_SUFFIX)$(DEBUG_SUFFIX)";
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 enum PathRelationship { unrelated, identical, siblings, subPath, parentPath, insuficientInput, pathEmpty, toEmpty, pathNull, toNull, bothEmpty, bothNull };
29 PathRelationship eString_PathRelated(char * path, char * to, char * pathDiff)
30 {
31    PathRelationship result;
32    if(pathDiff) *pathDiff = '\0';
33    if(path && *path && to && *to)
34    {
35       char toPart[MAX_FILENAME], toRest[MAX_LOCATION];
36       char pathPart[MAX_FILENAME], pathRest[MAX_LOCATION];
37       strcpy(toRest, to);
38       strcpy(pathRest, path);
39       for(; toRest[0] && pathRest[0];)
40       {
41          SplitDirectory(toRest, toPart, toRest);
42          SplitDirectory(pathRest, pathPart, pathRest);
43          if(!fstrcmp(pathPart, toPart)) result = siblings;
44          else break;
45       }
46       if(result == siblings)
47       {
48          if(!*toRest && !*pathRest) result = identical;
49          else if(!*pathRest) result = parentPath;
50          else result = subPath;
51          if(pathDiff && result != identical) strcpy(pathDiff, *pathRest == '\0' ? toRest : pathRest);
52       }
53       else result = unrelated;
54    }
55    else
56    {
57       if(path && to)
58       {
59          if(!*path && !*to) result = bothEmpty;
60          else if(!*path) result = pathEmpty;
61          else result = toEmpty;
62       }
63       else if(!path && !to) result = bothNull;
64       else if(!path) result = pathNull;
65       else result = toNull;
66    }
67    return result;
68 }
69
70 char * CopyValidateMakefilePath(char * path)
71 {
72    const int map[]  =    {           0,           1,             2,             3,           4,                    5,                 6,            0,                   1,                    2,        7 };
73    const char * vars[] = { "$(MODULE)", "$(CONFIG)", "$(PLATFORM)", "$(COMPILER)", "$(TARGET)", "$(COMPILER_SUFFIX)", "$(DEBUG_SUFFIX)", "$(PROJECT)",  "$(CONFIGURATION)", "$(TARGET_PLATFORM)",(char *)0 };
74
75    char * copy = null;
76    if(path)
77    {
78       int len;
79       len = strlen(path);
80       copy = CopyString(path);
81       if(len)
82       {
83          int c;
84          char * tmp = copy;
85          char * start = tmp;
86          Array<char *> parts { };
87          
88          for(c=0; c<len; c++)
89          {
90             if(tmp[c] == '$')
91             {
92                int v;
93                for(v=0; vars[v]; v++)
94                {
95                   if(SearchString(&tmp[c], 0, vars[v], false, false) == &tmp[c])
96                   {
97                      tmp[c] = '\0';
98                      parts.Add(start);
99                      parts.Add(vars[map[v]]);
100                      c += strlen(vars[v]);
101                      start = &tmp[c];
102                      c--;
103                      break;
104                   }
105                }
106             }
107          }
108          if(start[0])
109             parts.Add(start);
110
111          if(parts.count)
112          {
113             /*int c, */len = 0;
114             for(c=0; c<parts.count; c++) len += strlen(parts[c]);
115             copy = new char[++len];
116             copy[0] = '\0';
117             for(c=0; c<parts.count; c++) strcat(copy, parts[c]);
118          }
119          else
120             copy = null;
121          delete parts;
122          delete tmp;
123       }
124    }
125    return copy;
126 }
127
128 CompilerConfig MakeDefaultCompiler(char * name, bool readOnly)
129 {
130    CompilerConfig defaultCompiler
131    {
132       name,
133       readOnly,
134       gcc,
135       GetRuntimePlatform(),
136       1,
137       makeDefaultCommand,
138       ecpDefaultCommand,
139       eccDefaultCommand,
140       ecsDefaultCommand,
141       earDefaultCommand,
142       cppDefaultCommand,
143       ccDefaultCommand,
144       cxxDefaultCommand
145    };
146    incref defaultCompiler;
147    return defaultCompiler;
148 }
149
150 class IDESettingsContainer : GlobalSettings
151 {
152 #ifdef SETTINGS_TEST
153    settingsName = "ecereIDESettingsTest";
154 #else
155    settingsName = "ecereIDE";
156 #endif
157
158    virtual void OnLoad(GlobalSettingsData data);
159
160    char moduleLocation[MAX_LOCATION];
161
162 private:
163    IDESettingsContainer()
164    {
165       char path[MAX_LOCATION];
166       char * start;
167       LocateModule(null, moduleLocation);
168       strcpy(path, moduleLocation);
169       StripLastDirectory(moduleLocation, moduleLocation);
170       ChangeCh(moduleLocation, '\\', '/');
171       // PortableApps.com directory structure
172       if((start = strstr(path, "\\App\\EcereSDK\\bin\\ide.exe")))
173       {
174          char configFilePath[MAX_LOCATION];
175          char defaultConfigFilePath[MAX_LOCATION];
176
177          start[0] = '\0';
178
179          strcpy(configFilePath, path);
180          PathCat(configFilePath, "Data");
181          PathCat(configFilePath, "ecereIDE.ini");
182
183          strcpy(defaultConfigFilePath, path);
184          PathCat(defaultConfigFilePath, "App");
185          PathCat(defaultConfigFilePath, "DefaultData");
186          PathCat(defaultConfigFilePath, "ecereIDE.ini");
187          
188          if(FileExists(defaultConfigFilePath))
189          {
190             if(!FileExists(configFilePath))
191             {
192                File f = FileOpen(defaultConfigFilePath, read);
193                f.CopyTo(configFilePath);
194                f.Flush();
195                delete f;
196             }
197             PathCat(path, "Data");
198             // the forced settings location will only be
199             // used if the running ide's path matches 
200             // the PortableApps.com directory structure
201             // and the default ini file is found in 
202             // the DefaultData directory
203             settingsLocation = path;
204             portable = true;
205          }
206       }
207    }
208
209    void OnAskReloadSettings()
210    {
211       /*if(MessageBox { type = YesNo, master = this, 
212             text = "Global Settings Modified Externally", 
213             contents = "The global settings were modified by another instance.\n"
214             "Would you like to reload them?" }.Modal() == Yes)*/
215       {
216          Load();
217       }
218    }
219
220    void Load()
221    {
222       SettingsIOResult result = GlobalSettings::Load();
223       IDESettings data = (IDESettings)this.data;
224       CompilerConfig defaultCompiler = null;
225       if(!data)
226       {
227          this.data = IDESettings { };
228          if(dataOwner)
229             *dataOwner = this.data;
230
231          if(result == fileNotCompatibleWithDriver)
232          {
233             bool loaded;
234             OldIDESettings oldSettings { };
235             Close();
236             loaded = oldSettings.Load();
237             oldSettings.Close();
238             if(loaded)
239             {
240                data = (IDESettings)this.data;
241
242                for(c : oldSettings.compilerConfigs)
243                   data.compilerConfigs.Add(c.Copy());
244
245                for(s : oldSettings.recentFiles) data.recentFiles.Add(CopyString(s));
246                for(s : oldSettings.recentProjects) data.recentProjects.Add(CopyString(s));
247
248                data.docDir = oldSettings.docDir;
249                data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
250                data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
251                data.useFreeCaret = oldSettings.useFreeCaret;
252                data.showLineNumbers = oldSettings.showLineNumbers;
253                data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
254                delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
255                data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
256                data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
257                         
258                Save();
259                result = success;
260             }
261             delete oldSettings;
262          }
263          if(result == fileNotFound || !data)
264          {
265             data = (IDESettings)this.data;
266             data.useFreeCaret = true;
267             data.showLineNumbers = true;
268             data.caretFollowsScrolling = true;
269          }
270       }
271       // Ensure we have a default compiler
272       defaultCompiler = data.GetCompilerConfig(defaultCompilerName);
273       if(!defaultCompiler)
274       {
275          defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
276          data.compilerConfigs.Add(defaultCompiler);
277       }
278
279       // We incref the compilers below, so reset refCount to 0
280       defaultCompiler._refCount = 0;
281
282       CloseAndMonitor();
283       if(data.compilerConfigs)
284       {
285          for(c : data.compilerConfigs)
286          {
287             CompilerConfig compiler = c;
288             char * cxxCommand = compiler.cxxCommand;
289             if(!cxxCommand || !cxxCommand[0])
290                compiler.cxxCommand = cxxDefaultCommand;
291             incref compiler;
292          }
293       }
294       if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
295          data.ManagePortablePaths(moduleLocation, true);
296       data.ForcePathSeparatorStyle(true);
297       OnLoad(data);
298    }
299
300    void Save()
301    {
302       IDESettings data = (IDESettings)this.data;
303       Platform runtimePlatform = GetRuntimePlatform();
304       if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
305          data.ManagePortablePaths(moduleLocation, false);
306       data.ForcePathSeparatorStyle(true);
307       if(!GlobalSettings::Save())
308          PrintLn("Error saving IDE settings");
309       if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
310          data.ManagePortablePaths(moduleLocation, true);
311       CloseAndMonitor();
312    }
313 }
314
315 class IDESettings : GlobalSettingsData
316 {
317 public:
318    List<CompilerConfig> compilerConfigs { };
319    Array<String> recentFiles { };
320    Array<String> recentProjects { };
321    property char * docDir
322    {
323       set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
324       get { return docDir ? docDir : ""; }
325       isset { return docDir && docDir[0]; }
326    }
327    property char * ideFileDialogLocation
328    {
329       set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
330       get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
331       isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
332    }
333    property char * ideProjectFileDialogLocation
334    {
335       set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
336       get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
337       isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
338    }
339    bool useFreeCaret;
340    bool showLineNumbers;
341    bool caretFollowsScrolling;
342    char * displayDriver;
343    
344    // TODO: Classify settings
345    //EditorSettings editor { };
346
347    property char * projectDefaultTargetDir
348    {
349       set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
350       get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
351       isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
352    }
353    property char * projectDefaultIntermediateObjDir
354    {
355       set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
356       get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
357       isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
358    }
359
360    property char * compilerConfigsDir
361    {
362       set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
363       get { return compilerConfigsDir ? compilerConfigsDir : ""; }
364       isset { return compilerConfigsDir && compilerConfigsDir[0]; }
365    }
366
367    property char * defaultCompiler
368    {
369       set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
370       get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
371       isset { return defaultCompiler && defaultCompiler[0]; }
372    }
373
374 private:
375    char * docDir;
376    char * ideFileDialogLocation;
377    char * ideProjectFileDialogLocation;
378    char * projectDefaultTargetDir;
379    char * projectDefaultIntermediateObjDir;
380    char * compilerConfigsDir;
381    char * defaultCompiler;
382
383    CompilerConfig GetCompilerConfig(String compilerName)
384    {
385       char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
386       CompilerConfig compilerConfig = null;
387       for(compiler : compilerConfigs)
388       {
389          if(!strcmp(compiler.name, name))
390          {
391             compilerConfig = compiler;
392             break;
393          }
394       }
395       if(!compilerConfig && compilerConfigs.count)
396          compilerConfig = compilerConfigs.firstIterator.data;
397       if(compilerConfig)
398          incref compilerConfig;
399       return compilerConfig;
400    }
401
402    ~IDESettings()
403    {
404       compilerConfigs.Free();
405       delete compilerConfigs;
406       recentFiles.Free();
407       delete recentFiles;
408       recentProjects.Free();
409       delete recentProjects;
410       delete docDir;
411    
412       delete projectDefaultTargetDir;
413       delete projectDefaultIntermediateObjDir;
414       delete compilerConfigsDir;
415       delete defaultCompiler;
416
417       delete ideFileDialogLocation;
418       delete ideProjectFileDialogLocation;
419       delete displayDriver;
420    }
421
422    void ForcePathSeparatorStyle(bool unixStyle)
423    {
424       char from, to;
425       if(unixStyle)
426          from = '\\', to = '/';
427       else
428          from = '/', to = '\\';
429       if(compilerConfigs && compilerConfigs.count)
430       {
431          int i;
432          for(config : compilerConfigs)
433          {
434             if(config.includeDirs && config.includeDirs.count)
435             {
436                for(i = 0; i < config.includeDirs.count; i++)
437                {
438                   if(config.includeDirs[i] && config.includeDirs[i][0])
439                      ChangeCh(config.includeDirs[i], from, to);
440                }
441             }
442             if(config.libraryDirs && config.libraryDirs.count)
443             {
444                for(i = 0; i < config.libraryDirs.count; i++)
445                {
446                   if(config.libraryDirs[i] && config.libraryDirs[i][0])
447                      ChangeCh(config.libraryDirs[i], from, to);
448                }
449             }
450             if(config.executableDirs && config.executableDirs.count)
451             {
452                for(i = 0; i < config.executableDirs.count; i++)
453                {
454                   if(config.executableDirs[i] && config.executableDirs[i][0])
455                      ChangeCh(config.executableDirs[i], from, to);
456                }
457             }
458          }
459       }
460       if(recentFiles && recentFiles.count)
461       {
462          int c;
463          for(c = 0; c < recentFiles.count; c++)
464          {
465             if(recentFiles[c] && recentFiles[c][0])
466                ChangeCh(recentFiles[c], from, to);
467          }
468       }
469       if(recentProjects && recentProjects.count)
470       {
471          int c;
472          for(c = 0; c < recentProjects.count; c++)
473          {
474             if(recentProjects[c] && recentProjects[c][0])
475                ChangeCh(recentProjects[c], from, to);
476          }
477       }
478       if(docDir && docDir[0])
479          ChangeCh(docDir, from, to);
480       if(ideFileDialogLocation && ideFileDialogLocation[0])
481          ChangeCh(ideFileDialogLocation, from, to);
482       if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
483          ChangeCh(ideProjectFileDialogLocation, from, to);
484
485       if(projectDefaultTargetDir && projectDefaultTargetDir[0])
486          ChangeCh(projectDefaultTargetDir, from, to);
487       if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
488          ChangeCh(projectDefaultIntermediateObjDir, from, to);
489
490       if(compilerConfigsDir && compilerConfigsDir[0])
491          ChangeCh(compilerConfigsDir, from, to);
492    }
493
494    void ManagePortablePaths(char * location, bool makeAbsolute)
495    {
496       int c;
497       if(compilerConfigs && compilerConfigs.count)
498       {
499          for(config : compilerConfigs)
500          {
501             DirTypes t;
502             for(t = 0; t < DirTypes::enumSize; t++)
503             {
504                Array<String> dirs = null;
505                if(t == executables) dirs = config.executableDirs;
506                else if(t == includes) dirs = config.includeDirs;
507                else if(t == libraries) dirs = config.libraryDirs;
508                if(dirs && dirs.count)
509                {
510                   for(c = 0; c < dirs.count; c++)
511                   {
512                      if(dirs[c] && dirs[c][0])
513                         dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
514                   }
515                }
516             }
517          }
518       }
519       if(recentFiles && recentFiles.count)
520       {
521          for(c = 0; c < recentFiles.count; c++)
522          {
523             if(recentFiles[c] && recentFiles[c][0])
524                recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
525          }
526       }
527       if(recentProjects && recentProjects.count)
528       {
529          for(c = 0; c < recentProjects.count; c++)
530          {
531             if(recentProjects[c] && recentProjects[c][0])
532                recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
533          }
534       }
535       if(docDir && docDir[0])
536          docDir = UpdatePortablePath(docDir, location, makeAbsolute);
537       if(ideFileDialogLocation && ideFileDialogLocation[0])
538          ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
539       if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
540          ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
541
542       if(projectDefaultTargetDir && projectDefaultTargetDir[0])
543          projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
544       if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
545          projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
546
547       if(compilerConfigsDir && compilerConfigsDir[0])
548          compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
549    }
550
551    char * UpdatePortablePath(char * path, char * location, bool makeAbsolute)
552    {
553       char * output;
554       if(makeAbsolute)
555       {
556          char p[MAX_LOCATION];
557          strcpy(p, location);
558          PathCatSlash(p, path);
559          delete path;
560          output = CopyString(p);
561       }
562       else
563       {
564          PathRelationship rel = eString_PathRelated(path, location, null);
565          if(rel == subPath || rel == identical)
566          {
567             char p[MAX_LOCATION];
568             MakePathRelative(path, location, p);
569             if(!*p) strcpy(p, "./");
570             else ChangeCh(p, '\\', '/');
571             delete path;
572             output = CopyString(p);
573          }
574          else
575             output = path;
576       }
577       return output;
578    }
579
580    void AddRecentFile(char * fileName)
581    {
582       int c;
583       char * filePath = CopyString(fileName);
584       ChangeCh(filePath, '\\', '/');
585       for(c = 0; c<recentFiles.count; c++)
586       {
587          if(recentFiles[c] && !fstrcmp(recentFiles[c], filePath))
588          {
589             recentFiles.Delete((void *)&recentFiles[c]);
590             c--;
591          }
592       }
593       while(recentFiles.count >= MaxRecent)
594          recentFiles.Delete(recentFiles.GetLast());
595       recentFiles.Insert(null, filePath);
596       //UpdateRecentMenus(owner);
597    }
598
599    void AddRecentProject(char * projectName)
600    {
601       int c;
602       char * filePath = CopyString(projectName);
603       ChangeCh(filePath, '\\', '/');
604       for(c = 0; c<recentProjects.count; c++)
605       {
606          if(recentProjects[c] && !fstrcmp(recentProjects[c], filePath))
607          {
608             recentProjects.Delete((void *)&recentProjects[c]);
609             c--;
610          }
611       }
612       while(recentProjects.count >= MaxRecent)
613          recentProjects.Delete(recentProjects.GetLast());
614       recentProjects.Insert(null, filePath);
615       //UpdateRecentMenus(owner);
616    }
617 }
618
619 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
620 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
621 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
622 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
623 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
624 // TODO: i18n with Array
625 static Array<String> compilerTypeLongNames
626 { [
627    $"GNU Compiler Collection (GCC) / GNU Make",
628    $"Tiny C Compiler / GNU Make",
629    $"Portable C Compiler / GNU Make",
630    $"Microsoft Visual Studio 2005 (8.0) Compiler",
631    $"Microsoft Visual Studio 2008 (9.0) Compiler",
632    $"Microsoft Visual Studio 2010 (10.0) Compiler"
633 ] };
634 const CompilerType firstCompilerType = gcc;
635 const CompilerType lastCompilerType = vs10;
636 public enum CompilerType
637 {
638    gcc, tcc, pcc, vs8, vs9, vs10;
639
640    property bool isVC
641    {
642       get { return this == vs8 || this == vs9 || this == vs10; }
643    }
644
645    property char *
646    {
647       get { return OnGetString(null, null, null); }
648       set
649       {  
650          if(value)
651          {
652             Platform c;
653             for(c = firstCompilerType; c <= lastCompilerType; c++)
654                if(!strcmpi(value, compilerTypeNames[c]))
655                   return c;
656          }
657          return gcc;
658       }
659    };
660
661    property char * longName { get { return OnGetString(null, (void*)1, null); } };
662    property char * versionString { get { return OnGetString(null, (void*)2, null); } };
663    property char * yearString { get { return OnGetString(null, (void*)3, null); } };
664    property char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
665    property char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
666
667    char * OnGetString(char * tempString, void * fieldData, bool * needClass)
668    {
669       if(this >= firstCompilerType && this <= lastCompilerType)
670       {
671          if(tempString)
672             strcpy(tempString, compilerTypeNames[this]);
673          if(fieldData == null)
674             return compilerTypeNames[this];
675          else if(fieldData == (void*)1)
676             return compilerTypeLongNames[this];
677          else if(fieldData == (void*)2)
678             return compilerTypeVersionString[this];
679          else if(fieldData == (void*)3)
680             return compilerTypeYearString[this];
681          else if(fieldData == (void*)4)
682             return compilerTypeProjectFileExtension[this];
683          else if(fieldData == (void*)5)
684             return compilerTypeSolutionFileVersionString[this];
685       }
686       return null;
687    }
688 };
689
690 class CompilerConfig
691 {
692    class_no_expansion;
693
694    numJobs = 1;
695    supportsBitDepth = true;
696 public:
697    property char * name
698    {
699       set
700       {
701          delete name;
702          if(value)
703             name = CopyString(value);
704       }
705       get { return name; }
706    }
707    bool readOnly;
708    CompilerType type;
709    Platform targetPlatform;
710    int numJobs;
711    property char * makeCommand
712    {
713       set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
714       get { return makeCommand; }
715       isset { return makeCommand && makeCommand[0]; }
716    }
717    property char * ecpCommand
718    {
719       set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
720       get { return ecpCommand; }
721       isset { return ecpCommand && ecpCommand[0]; }
722    }
723    property char * eccCommand
724    {
725       set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
726       get { return eccCommand; }
727       isset { return eccCommand && eccCommand[0]; }
728    }
729    property char * ecsCommand
730    {
731       set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
732       get { return ecsCommand; }
733       isset { return ecsCommand && ecsCommand[0]; }
734    }
735    property char * earCommand
736    {
737       set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
738       get { return earCommand; }
739       isset { return earCommand && earCommand[0]; }
740    }
741    property char * cppCommand
742    {
743       set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
744       get { return cppCommand; }
745       isset { return cppCommand && cppCommand[0]; }
746    }
747    property char * ccCommand
748    {
749       set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
750       get { return ccCommand; }
751       isset { return ccCommand && ccCommand[0]; }
752    }
753    property char * cxxCommand
754    {
755       set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
756       get { return cxxCommand; }
757       isset { return cxxCommand && cxxCommand[0]; }
758    }
759    property char * execPrefixCommand
760    {
761       set { delete execPrefixCommand; if(value && value[0]) execPrefixCommand = CopyString(value); }
762       get { return execPrefixCommand; }
763       isset { return execPrefixCommand && execPrefixCommand[0]; }
764    }
765    bool ccacheEnabled;
766    bool distccEnabled;
767    property bool supportsBitDepth
768    {
769       set { supportsBitDepth = value; }
770       get { return supportsBitDepth; }
771       isset { return !supportsBitDepth; }
772    }
773
774    property char * distccHosts
775    {
776       set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
777       get { return distccHosts; }
778       isset { return distccHosts && distccHosts[0]; }
779    }
780    property Array<String> includeDirs
781    {
782       set
783       {
784          includeDirs.Free();
785          if(value)
786          {
787             delete includeDirs;
788             includeDirs = value;
789          }
790       }
791       get { return includeDirs; }
792       isset { return includeDirs.count != 0; }
793    }
794    property Array<String> libraryDirs
795    {
796       set
797       {
798          libraryDirs.Free();
799          if(value)
800          {
801             delete libraryDirs;
802             libraryDirs = value;
803          }
804       }
805       get { return libraryDirs; }
806       isset { return libraryDirs.count != 0; }
807    }
808    property Array<String> executableDirs
809    {
810       set
811       {
812          executableDirs.Free();
813          if(value)
814          {
815             delete executableDirs;
816             executableDirs = value;
817          }
818       }
819       get { return executableDirs; }
820       isset { return executableDirs.count != 0; }
821    }
822    property Array<NamedString> environmentVars
823    {
824       set
825       {
826          environmentVars.Free();
827          if(value)
828          {
829             delete environmentVars;
830             environmentVars = value;
831          }
832       }
833       get { return environmentVars; }
834       isset { return environmentVars.count != 0; }
835    }
836    property Array<String> prepDirectives
837    {
838       set
839       {
840          prepDirectives.Free();
841          if(value)
842          {
843             delete prepDirectives;
844             prepDirectives = value;
845          }
846       }
847       get { return prepDirectives; }
848       isset { return prepDirectives.count != 0; }
849    }
850    property Array<String> excludeLibs
851    {
852       set
853       {
854          excludeLibs.Free();
855          if(value)
856          {
857             delete excludeLibs;
858             excludeLibs = value;
859          }
860       }
861       get { return excludeLibs; }
862       isset { return excludeLibs.count != 0; }
863    }
864    property Array<String> linkerFlags
865    {
866       set
867       {
868          linkerFlags.Free();
869          if(value)
870          {
871             delete linkerFlags;
872             linkerFlags = value;
873          }
874       }
875       get { return linkerFlags; }
876       isset { return linkerFlags.count != 0; }
877    }
878 private:
879    Array<String> includeDirs { };
880    Array<String> libraryDirs { };
881    Array<String> executableDirs { };
882    // TODO: Can JSON parse and serialize maps?
883    //EnvironmentVariables { };
884    Array<NamedString> environmentVars { };
885    Array<String> prepDirectives { };
886    Array<String> excludeLibs { };
887    Array<String> linkerFlags { };
888    char * name;
889    char * makeCommand;
890    char * ecpCommand;
891    char * eccCommand;
892    char * ecsCommand;
893    char * earCommand;
894    char * cppCommand;
895    char * ccCommand;
896    char * cxxCommand;
897    char * execPrefixCommand;
898    char * distccHosts;
899    bool supportsBitDepth;
900    /*union
901    {
902       struct { Array<String> includes, libraries, executables; };
903       Array<String> dirs[DirTypes];
904    }*/
905
906    ~CompilerConfig()
907    {
908       delete name;
909       delete ecpCommand;
910       delete eccCommand;
911       delete ecsCommand;
912       delete earCommand;
913       delete cppCommand;
914       delete ccCommand;
915       delete cxxCommand;
916       delete makeCommand;
917       delete execPrefixCommand;
918       delete distccHosts;
919       if(environmentVars) environmentVars.Free();
920       if(includeDirs) { includeDirs.Free(); }
921       if(libraryDirs) { libraryDirs.Free(); }
922       if(executableDirs) { executableDirs.Free(); }
923       if(prepDirectives) { prepDirectives.Free(); }
924       if(excludeLibs) { excludeLibs.Free(); }
925       if(linkerFlags) { linkerFlags.Free(); }
926    }
927    CompilerConfig Copy()
928    {
929       CompilerConfig copy
930       {
931          name,
932          readOnly,
933          type,
934          targetPlatform,
935          numJobs,
936          makeCommand,
937          ecpCommand,
938          eccCommand,
939          ecsCommand,
940          earCommand,
941          cppCommand,
942          ccCommand,
943          cxxCommand,
944          execPrefixCommand,
945          ccacheEnabled,
946          distccEnabled,
947          supportsBitDepth,
948          distccHosts
949       };
950       for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
951       for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
952       for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
953       for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
954       for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
955       for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
956       for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
957
958       incref copy;
959       return copy;
960    }
961 }