cleaned all trailing white space from source files.
[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 void ValidPathBufCopy(char *output, char *input)
129 {
130 #ifdef __WIN32__
131    bool volumePath = false;
132 #endif
133    strcpy(output, input);
134    TrimLSpaces(output, output);
135    TrimRSpaces(output, output);
136    MakeSystemPath(output);
137 #ifdef __WIN32__
138    if(output[0] && output[1] == ':')
139    {
140       output[1] = '_';
141       volumePath = true;
142    }
143 #endif
144    {
145       char * chars = "*|:\",<>?";
146       char ch, * s = output, * o = output;
147       while((ch = *s++)) { if(!strchr(chars, ch)) *o++ = ch; }
148       *o = '\0';
149    }
150 #ifdef __WIN32__
151    if(volumePath && output[0])
152       output[1] = ':';
153 #endif
154 }
155
156 void RemoveTrailingPathSeparator(char *path)
157 {
158    int len;
159    len = strlen(path);
160    if(len>1 && path[len-1] == DIR_SEP)
161       path[--len] = '\0';
162 }
163
164 void BasicValidatePathBoxPath(PathBox pathBox)
165 {
166    char path[MAX_LOCATION];
167    ValidPathBufCopy(path, pathBox.path);
168    RemoveTrailingPathSeparator(path);
169    pathBox.path = path;
170 }
171
172 CompilerConfig MakeDefaultCompiler(char * name, bool readOnly)
173 {
174    CompilerConfig defaultCompiler
175    {
176       name,
177       readOnly,
178       gcc,
179       GetRuntimePlatform(),
180       1,
181       makeDefaultCommand,
182       ecpDefaultCommand,
183       eccDefaultCommand,
184       ecsDefaultCommand,
185       earDefaultCommand,
186       cppDefaultCommand,
187       ccDefaultCommand,
188       cxxDefaultCommand
189    };
190    incref defaultCompiler;
191    return defaultCompiler;
192 }
193
194 class IDESettingsContainer : GlobalSettings
195 {
196 #ifdef SETTINGS_TEST
197    settingsName = "ecereIDESettingsTest";
198 #else
199    settingsName = "ecereIDE";
200 #endif
201
202    virtual void OnLoad(GlobalSettingsData data);
203
204    char moduleLocation[MAX_LOCATION];
205
206 private:
207    FileSize settingsFileSize;
208
209    IDESettingsContainer()
210    {
211       char path[MAX_LOCATION];
212       char * start;
213       LocateModule(null, moduleLocation);
214       strcpy(path, moduleLocation);
215       StripLastDirectory(moduleLocation, moduleLocation);
216       ChangeCh(moduleLocation, '\\', '/');
217       // PortableApps.com directory structure
218       if((start = strstr(path, "\\App\\EcereSDK\\bin\\ide.exe")))
219       {
220          char configFilePath[MAX_LOCATION];
221          char defaultConfigFilePath[MAX_LOCATION];
222
223          start[0] = '\0';
224
225          strcpy(configFilePath, path);
226          PathCat(configFilePath, "Data");
227          PathCat(configFilePath, "ecereIDE.ini");
228
229          strcpy(defaultConfigFilePath, path);
230          PathCat(defaultConfigFilePath, "App");
231          PathCat(defaultConfigFilePath, "DefaultData");
232          PathCat(defaultConfigFilePath, "ecereIDE.ini");
233
234          if(FileExists(defaultConfigFilePath))
235          {
236             if(!FileExists(configFilePath))
237             {
238                File f = FileOpen(defaultConfigFilePath, read);
239                f.CopyTo(configFilePath);
240                f.Flush();
241                delete f;
242             }
243             PathCat(path, "Data");
244             // the forced settings location will only be
245             // used if the running ide's path matches
246             // the PortableApps.com directory structure
247             // and the default ini file is found in
248             // the DefaultData directory
249             settingsLocation = path;
250             portable = true;
251          }
252       }
253    }
254
255    void OnAskReloadSettings()
256    {
257       /*if(MessageBox { type = YesNo, master = this,
258             text = "Global Settings Modified Externally",
259             contents = "The global settings were modified by another instance.\n"
260             "Would you like to reload them?" }.Modal() == Yes)*/
261       {
262          double o, n;
263          FileSize newSettingsFileSize;
264          FileGetSize(settingsFilePath, &newSettingsFileSize);
265          o = settingsFileSize;
266          n = newSettingsFileSize;
267          if(o - n < 2048)
268             Load();
269          else
270          {
271             GuiApplication app = ((GuiApplication)__thisModule.application);
272             Window w;
273             for(w = app.desktop.firstChild; w && (!w.created || !w.visible); w = w.next);
274             MessageBox { master = w, type = ok,
275                   text = "Global Settings Modified Externally",
276                   contents = "The global settings were modified by another process and a drastic shrinking of the settings file was detected.\n"
277                   "The new settings will not be loaded to prevent loss of your ide settings.\n"
278                   "Please check your settings file and make sure to save this IDE's global settings if your settings file has been compromised."
279                   }.Create();
280             //Save();
281          }
282       }
283    }
284
285    SettingsIOResult Load()
286    {
287       SettingsIOResult result = GlobalSettings::Load();
288       IDESettings data = (IDESettings)this.data;
289       CompilerConfig defaultCompiler = null;
290       if(!data)
291       {
292          this.data = IDESettings { };
293          if(dataOwner)
294             *dataOwner = this.data;
295
296          if(result == fileNotCompatibleWithDriver)
297          {
298             bool loaded;
299             OldIDESettings oldSettings { };
300             Close();
301             loaded = oldSettings.Load() == success;
302             oldSettings.Close();
303             if(loaded)
304             {
305                data = (IDESettings)this.data;
306
307                for(c : oldSettings.compilerConfigs)
308                   data.compilerConfigs.Add(c.Copy());
309
310                for(s : oldSettings.recentFiles) data.recentFiles.Add(CopyString(s));
311                for(s : oldSettings.recentProjects) data.recentProjects.Add(CopyString(s));
312
313                data.docDir = oldSettings.docDir;
314                data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
315                data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
316                data.useFreeCaret = oldSettings.useFreeCaret;
317                data.showLineNumbers = oldSettings.showLineNumbers;
318                data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
319                delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
320                data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
321                data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
322
323                Save();
324                result = success;
325             }
326             delete oldSettings;
327          }
328          if(result == fileNotFound || !data)
329          {
330             data = (IDESettings)this.data;
331             data.useFreeCaret = false; //true;
332             data.showLineNumbers = true;
333             data.caretFollowsScrolling = false; //true;
334          }
335       }
336       // Ensure we have a default compiler
337       defaultCompiler = data.GetCompilerConfig(defaultCompilerName);
338       if(!defaultCompiler)
339       {
340          defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
341          data.compilerConfigs.Add(defaultCompiler);
342       }
343
344       // We incref the compilers below, so reset refCount to 0
345       defaultCompiler._refCount = 0;
346
347       CloseAndMonitor();
348       FileGetSize(settingsFilePath, &settingsFileSize);
349       if(data.compilerConfigs)
350       {
351          for(c : data.compilerConfigs)
352          {
353             CompilerConfig compiler = c;
354             char * cxxCommand = compiler.cxxCommand;
355             if(!cxxCommand || !cxxCommand[0])
356                compiler.cxxCommand = cxxDefaultCommand;
357             incref compiler;
358          }
359       }
360       if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
361          data.ManagePortablePaths(moduleLocation, true);
362       data.ForcePathSeparatorStyle(true);
363       OnLoad(data);
364       return result;
365    }
366
367    SettingsIOResult Save()
368    {
369       SettingsIOResult result;
370
371       IDESettings data = (IDESettings)this.data;
372       Platform runtimePlatform = GetRuntimePlatform();
373       if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
374          data.ManagePortablePaths(moduleLocation, false);
375       data.ForcePathSeparatorStyle(true);
376       result = GlobalSettings::Save();
377       if(result != success)
378          PrintLn("Error saving IDE settings");
379       if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
380          data.ManagePortablePaths(moduleLocation, true);
381       CloseAndMonitor();
382       FileGetSize(settingsFilePath, &settingsFileSize);
383       return result;
384    }
385 }
386
387 class IDESettings : GlobalSettingsData
388 {
389 public:
390    List<CompilerConfig> compilerConfigs { };
391    Array<String> recentFiles { };
392    Array<String> recentProjects { };
393    property char * docDir
394    {
395       set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
396       get { return docDir ? docDir : ""; }
397       isset { return docDir && docDir[0]; }
398    }
399    property char * ideFileDialogLocation
400    {
401       set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
402       get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
403       isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
404    }
405    property char * ideProjectFileDialogLocation
406    {
407       set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
408       get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
409       isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
410    }
411    bool useFreeCaret;
412    bool showLineNumbers;
413    bool caretFollowsScrolling;
414    char * displayDriver;
415
416    // TODO: Classify settings
417    //EditorSettings editor { };
418
419    property char * projectDefaultTargetDir
420    {
421       set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
422       get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
423       isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
424    }
425    property char * projectDefaultIntermediateObjDir
426    {
427       set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
428       get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
429       isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
430    }
431
432    property char * compilerConfigsDir
433    {
434       set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
435       get { return compilerConfigsDir ? compilerConfigsDir : ""; }
436       isset { return compilerConfigsDir && compilerConfigsDir[0]; }
437    }
438
439    property char * defaultCompiler
440    {
441       set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
442       get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
443       isset { return defaultCompiler && defaultCompiler[0]; }
444    }
445
446 private:
447    char * docDir;
448    char * ideFileDialogLocation;
449    char * ideProjectFileDialogLocation;
450    char * projectDefaultTargetDir;
451    char * projectDefaultIntermediateObjDir;
452    char * compilerConfigsDir;
453    char * defaultCompiler;
454
455    CompilerConfig GetCompilerConfig(String compilerName)
456    {
457       char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
458       CompilerConfig compilerConfig = null;
459       for(compiler : compilerConfigs)
460       {
461          if(!strcmp(compiler.name, name))
462          {
463             compilerConfig = compiler;
464             break;
465          }
466       }
467       if(!compilerConfig && compilerConfigs.count)
468          compilerConfig = compilerConfigs.firstIterator.data;
469       if(compilerConfig)
470          incref compilerConfig;
471       return compilerConfig;
472    }
473
474    ~IDESettings()
475    {
476       compilerConfigs.Free();
477       delete compilerConfigs;
478       recentFiles.Free();
479       delete recentFiles;
480       recentProjects.Free();
481       delete recentProjects;
482       delete docDir;
483
484       delete projectDefaultTargetDir;
485       delete projectDefaultIntermediateObjDir;
486       delete compilerConfigsDir;
487       delete defaultCompiler;
488
489       delete ideFileDialogLocation;
490       delete ideProjectFileDialogLocation;
491       delete displayDriver;
492    }
493
494    void ForcePathSeparatorStyle(bool unixStyle)
495    {
496       char from, to;
497       if(unixStyle)
498          from = '\\', to = '/';
499       else
500          from = '/', to = '\\';
501       if(compilerConfigs && compilerConfigs.count)
502       {
503          int i;
504          for(config : compilerConfigs)
505          {
506             if(config.includeDirs && config.includeDirs.count)
507             {
508                for(i = 0; i < config.includeDirs.count; i++)
509                {
510                   if(config.includeDirs[i] && config.includeDirs[i][0])
511                      ChangeCh(config.includeDirs[i], from, to);
512                }
513             }
514             if(config.libraryDirs && config.libraryDirs.count)
515             {
516                for(i = 0; i < config.libraryDirs.count; i++)
517                {
518                   if(config.libraryDirs[i] && config.libraryDirs[i][0])
519                      ChangeCh(config.libraryDirs[i], from, to);
520                }
521             }
522             if(config.executableDirs && config.executableDirs.count)
523             {
524                for(i = 0; i < config.executableDirs.count; i++)
525                {
526                   if(config.executableDirs[i] && config.executableDirs[i][0])
527                      ChangeCh(config.executableDirs[i], from, to);
528                }
529             }
530          }
531       }
532       if(recentFiles && recentFiles.count)
533       {
534          int c;
535          for(c = 0; c < recentFiles.count; c++)
536          {
537             if(recentFiles[c] && recentFiles[c][0])
538                ChangeCh(recentFiles[c], from, to);
539          }
540       }
541       if(recentProjects && recentProjects.count)
542       {
543          int c;
544          for(c = 0; c < recentProjects.count; c++)
545          {
546             if(recentProjects[c] && recentProjects[c][0])
547                ChangeCh(recentProjects[c], from, to);
548          }
549       }
550       if(docDir && docDir[0])
551          ChangeCh(docDir, from, to);
552       if(ideFileDialogLocation && ideFileDialogLocation[0])
553          ChangeCh(ideFileDialogLocation, from, to);
554       if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
555          ChangeCh(ideProjectFileDialogLocation, from, to);
556
557       if(projectDefaultTargetDir && projectDefaultTargetDir[0])
558          ChangeCh(projectDefaultTargetDir, from, to);
559       if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
560          ChangeCh(projectDefaultIntermediateObjDir, from, to);
561
562       if(compilerConfigsDir && compilerConfigsDir[0])
563          ChangeCh(compilerConfigsDir, from, to);
564    }
565
566    void ManagePortablePaths(char * location, bool makeAbsolute)
567    {
568       int c;
569       if(compilerConfigs && compilerConfigs.count)
570       {
571          for(config : compilerConfigs)
572          {
573             DirTypes t;
574             for(t = 0; t < DirTypes::enumSize; t++)
575             {
576                Array<String> dirs = null;
577                if(t == executables) dirs = config.executableDirs;
578                else if(t == includes) dirs = config.includeDirs;
579                else if(t == libraries) dirs = config.libraryDirs;
580                if(dirs && dirs.count)
581                {
582                   for(c = 0; c < dirs.count; c++)
583                   {
584                      if(dirs[c] && dirs[c][0])
585                         dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
586                   }
587                }
588             }
589          }
590       }
591       if(recentFiles && recentFiles.count)
592       {
593          for(c = 0; c < recentFiles.count; c++)
594          {
595             if(recentFiles[c] && recentFiles[c][0])
596                recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
597          }
598       }
599       if(recentProjects && recentProjects.count)
600       {
601          for(c = 0; c < recentProjects.count; c++)
602          {
603             if(recentProjects[c] && recentProjects[c][0])
604                recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
605          }
606       }
607       if(docDir && docDir[0])
608          docDir = UpdatePortablePath(docDir, location, makeAbsolute);
609       if(ideFileDialogLocation && ideFileDialogLocation[0])
610          ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
611       if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
612          ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
613
614       if(projectDefaultTargetDir && projectDefaultTargetDir[0])
615          projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
616       if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
617          projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
618
619       if(compilerConfigsDir && compilerConfigsDir[0])
620          compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
621    }
622
623    char * UpdatePortablePath(char * path, char * location, bool makeAbsolute)
624    {
625       char * output;
626       if(makeAbsolute)
627       {
628          char p[MAX_LOCATION];
629          strcpy(p, location);
630          PathCatSlash(p, path);
631          delete path;
632          output = CopyString(p);
633       }
634       else
635       {
636          PathRelationship rel = eString_PathRelated(path, location, null);
637          if(rel == subPath || rel == identical)
638          {
639             char p[MAX_LOCATION];
640             MakePathRelative(path, location, p);
641             if(!*p) strcpy(p, "./");
642             else ChangeCh(p, '\\', '/');
643             delete path;
644             output = CopyString(p);
645          }
646          else
647             output = path;
648       }
649       return output;
650    }
651
652    void AddRecentFile(char * fileName)
653    {
654       int c;
655       char * filePath = CopyString(fileName);
656       ChangeCh(filePath, '\\', '/');
657       for(c = 0; c<recentFiles.count; c++)
658       {
659          if(recentFiles[c] && !fstrcmp(recentFiles[c], filePath))
660          {
661             recentFiles.Delete((void *)&recentFiles[c]);
662             c--;
663          }
664       }
665       while(recentFiles.count >= MaxRecent)
666          recentFiles.Delete(recentFiles.GetLast());
667       recentFiles.Insert(null, filePath);
668       //UpdateRecentMenus(owner);
669    }
670
671    void AddRecentProject(char * projectName)
672    {
673       int c;
674       char * filePath = CopyString(projectName);
675       ChangeCh(filePath, '\\', '/');
676       for(c = 0; c<recentProjects.count; c++)
677       {
678          if(recentProjects[c] && !fstrcmp(recentProjects[c], filePath))
679          {
680             recentProjects.Delete((void *)&recentProjects[c]);
681             c--;
682          }
683       }
684       while(recentProjects.count >= MaxRecent)
685          recentProjects.Delete(recentProjects.GetLast());
686       recentProjects.Insert(null, filePath);
687       //UpdateRecentMenus(owner);
688    }
689 }
690
691 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
692 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
693 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
694 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
695 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
696 // TODO: i18n with Array
697 static Array<String> compilerTypeLongNames
698 { [
699    $"GNU Compiler Collection (GCC) / GNU Make",
700    $"Tiny C Compiler / GNU Make",
701    $"Portable C Compiler / GNU Make",
702    $"Microsoft Visual Studio 2005 (8.0) Compiler",
703    $"Microsoft Visual Studio 2008 (9.0) Compiler",
704    $"Microsoft Visual Studio 2010 (10.0) Compiler"
705 ] };
706 const CompilerType firstCompilerType = gcc;
707 const CompilerType lastCompilerType = vs10;
708 public enum CompilerType
709 {
710    gcc, tcc, pcc, vs8, vs9, vs10;
711
712    property bool isVC
713    {
714       get { return this == vs8 || this == vs9 || this == vs10; }
715    }
716
717    property char *
718    {
719       get { return OnGetString(null, null, null); }
720       set
721       {
722          if(value)
723          {
724             Platform c;
725             for(c = firstCompilerType; c <= lastCompilerType; c++)
726                if(!strcmpi(value, compilerTypeNames[c]))
727                   return c;
728          }
729          return gcc;
730       }
731    };
732
733    property char * longName { get { return OnGetString(null, (void*)1, null); } };
734    property char * versionString { get { return OnGetString(null, (void*)2, null); } };
735    property char * yearString { get { return OnGetString(null, (void*)3, null); } };
736    property char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
737    property char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
738
739    char * OnGetString(char * tempString, void * fieldData, bool * needClass)
740    {
741       if(this >= firstCompilerType && this <= lastCompilerType)
742       {
743          if(tempString)
744             strcpy(tempString, compilerTypeNames[this]);
745          if(fieldData == null)
746             return compilerTypeNames[this];
747          else if(fieldData == (void*)1)
748             return compilerTypeLongNames[this];
749          else if(fieldData == (void*)2)
750             return compilerTypeVersionString[this];
751          else if(fieldData == (void*)3)
752             return compilerTypeYearString[this];
753          else if(fieldData == (void*)4)
754             return compilerTypeProjectFileExtension[this];
755          else if(fieldData == (void*)5)
756             return compilerTypeSolutionFileVersionString[this];
757       }
758       return null;
759    }
760 };
761
762 class CompilerConfig
763 {
764    class_no_expansion;
765
766    numJobs = 1;
767 public:
768    property char * name
769    {
770       set
771       {
772          delete name;
773          if(value)
774             name = CopyString(value);
775       }
776       get { return name; }
777    }
778    bool readOnly;
779    CompilerType type;
780    Platform targetPlatform;
781    int numJobs;
782    property char * makeCommand
783    {
784       set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
785       get { return makeCommand; }
786       isset { return makeCommand && makeCommand[0]; }
787    }
788    property char * ecpCommand
789    {
790       set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
791       get { return ecpCommand; }
792       isset { return ecpCommand && ecpCommand[0]; }
793    }
794    property char * eccCommand
795    {
796       set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
797       get { return eccCommand; }
798       isset { return eccCommand && eccCommand[0]; }
799    }
800    property char * ecsCommand
801    {
802       set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
803       get { return ecsCommand; }
804       isset { return ecsCommand && ecsCommand[0]; }
805    }
806    property char * earCommand
807    {
808       set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
809       get { return earCommand; }
810       isset { return earCommand && earCommand[0]; }
811    }
812    property char * cppCommand
813    {
814       set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
815       get { return cppCommand; }
816       isset { return cppCommand && cppCommand[0]; }
817    }
818    property char * ccCommand
819    {
820       set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
821       get { return ccCommand; }
822       isset { return ccCommand && ccCommand[0]; }
823    }
824    property char * cxxCommand
825    {
826       set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
827       get { return cxxCommand; }
828       isset { return cxxCommand && cxxCommand[0]; }
829    }
830    property char * execPrefixCommand // <-- old name for json ide settings file compatibility
831    {
832       set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
833       get { return executableLauncher; }
834       isset { return executableLauncher && executableLauncher[0]; }
835    }
836    // TODO: implement CompilerConfig::windresCommand
837    bool ccacheEnabled;
838    bool distccEnabled;
839    // deprecated
840    property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
841
842    property char * distccHosts
843    {
844       set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
845       get { return distccHosts; }
846       isset { return distccHosts && distccHosts[0]; }
847    }
848    property char * gccPrefix // <-- old name for json ide settings file compatibility
849    {
850       set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
851       get { return gnuToolchainPrefix; }
852       isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
853    }
854    property char * sysroot
855    {
856       set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
857       get { return sysroot; }
858       isset { return sysroot && sysroot[0]; }
859    }
860    property Array<String> includeDirs
861    {
862       set
863       {
864          includeDirs.Free();
865          if(value)
866          {
867             delete includeDirs;
868             includeDirs = value;
869          }
870       }
871       get { return includeDirs; }
872       isset { return includeDirs.count != 0; }
873    }
874    property Array<String> libraryDirs
875    {
876       set
877       {
878          libraryDirs.Free();
879          if(value)
880          {
881             delete libraryDirs;
882             libraryDirs = value;
883          }
884       }
885       get { return libraryDirs; }
886       isset { return libraryDirs.count != 0; }
887    }
888    property Array<String> executableDirs
889    {
890       set
891       {
892          executableDirs.Free();
893          if(value)
894          {
895             delete executableDirs;
896             executableDirs = value;
897          }
898       }
899       get { return executableDirs; }
900       isset { return executableDirs.count != 0; }
901    }
902    property Array<NamedString> environmentVars
903    {
904       set
905       {
906          environmentVars.Free();
907          if(value)
908          {
909             delete environmentVars;
910             environmentVars = value;
911          }
912       }
913       get { return environmentVars; }
914       isset { return environmentVars.count != 0; }
915    }
916    property Array<String> prepDirectives
917    {
918       set
919       {
920          prepDirectives.Free();
921          if(value)
922          {
923             delete prepDirectives;
924             prepDirectives = value;
925          }
926       }
927       get { return prepDirectives; }
928       isset { return prepDirectives.count != 0; }
929    }
930    property Array<String> excludeLibs
931    {
932       set
933       {
934          excludeLibs.Free();
935          if(value)
936          {
937             delete excludeLibs;
938             excludeLibs = value;
939          }
940       }
941       get { return excludeLibs; }
942       isset { return excludeLibs.count != 0; }
943    }
944    property Array<String> compilerFlags
945    {
946       set
947       {
948          compilerFlags.Free();
949          if(value)
950          {
951             delete compilerFlags;
952             compilerFlags = value;
953          }
954       }
955       get { return compilerFlags; }
956       isset { return compilerFlags.count != 0; }
957    }
958    property Array<String> linkerFlags
959    {
960       set
961       {
962          linkerFlags.Free();
963          if(value)
964          {
965             delete linkerFlags;
966             linkerFlags = value;
967          }
968       }
969       get { return linkerFlags; }
970       isset { return linkerFlags.count != 0; }
971    }
972 private:
973    Array<String> includeDirs { };
974    Array<String> libraryDirs { };
975    Array<String> executableDirs { };
976    // TODO: Can JSON parse and serialize maps?
977    //EnvironmentVariables { };
978    Array<NamedString> environmentVars { };
979    Array<String> prepDirectives { };
980    Array<String> excludeLibs { };
981    Array<String> compilerFlags { };
982    Array<String> linkerFlags { };
983    char * name;
984    char * makeCommand;
985    char * ecpCommand;
986    char * eccCommand;
987    char * ecsCommand;
988    char * earCommand;
989    char * cppCommand;
990    char * ccCommand;
991    char * cxxCommand;
992    char * executableLauncher;
993    char * distccHosts;
994    char * gnuToolchainPrefix;
995    char * sysroot;
996    /*union
997    {
998       struct { Array<String> includes, libraries, executables; };
999       Array<String> dirs[DirTypes];
1000    }*/
1001
1002    ~CompilerConfig()
1003    {
1004       delete name;
1005       delete ecpCommand;
1006       delete eccCommand;
1007       delete ecsCommand;
1008       delete earCommand;
1009       delete cppCommand;
1010       delete ccCommand;
1011       delete cxxCommand;
1012       delete makeCommand;
1013       delete executableLauncher;
1014       delete distccHosts;
1015       delete gnuToolchainPrefix;
1016       delete sysroot;
1017       if(environmentVars) environmentVars.Free();
1018       if(includeDirs) { includeDirs.Free(); }
1019       if(libraryDirs) { libraryDirs.Free(); }
1020       if(executableDirs) { executableDirs.Free(); }
1021       if(prepDirectives) { prepDirectives.Free(); }
1022       if(excludeLibs) { excludeLibs.Free(); }
1023       if(compilerFlags) { compilerFlags.Free(); }
1024       if(linkerFlags) { linkerFlags.Free(); }
1025    }
1026    CompilerConfig Copy()
1027    {
1028       CompilerConfig copy
1029       {
1030          name,
1031          readOnly,
1032          type,
1033          targetPlatform,
1034          numJobs,
1035          makeCommand,
1036          ecpCommand,
1037          eccCommand,
1038          ecsCommand,
1039          earCommand,
1040          cppCommand,
1041          ccCommand,
1042          cxxCommand,
1043          executableLauncher,
1044          ccacheEnabled,
1045          distccEnabled,
1046          false,
1047          distccHosts,
1048          gnuToolchainPrefix,
1049          sysroot
1050       };
1051       for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1052       for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1053       for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1054       for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1055       for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1056       for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1057       for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1058       for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1059
1060       incref copy;
1061       return copy;
1062    }
1063 }