2 public import static "ecere"
7 define ecpDefaultCommand = "ecp";
8 define eccDefaultCommand = "ecc";
9 define ecsDefaultCommand = "ecs";
10 define earDefaultCommand = "ear";
11 define cppDefaultCommand = "gcc"; // As per #624 we decided to default to "gcc"...
12 define ccDefaultCommand = "gcc";
13 define cxxDefaultCommand = "g++";
14 //define ldDefaultCommand = "gcc";
15 define arDefaultCommand = "ar";
16 define objectDefaultFileExt = "o";
17 define outputDefaultFileExt = "";
21 import "OldIDESettings"
24 #define WIN32_LEAN_AND_MEAN
35 enum DirTypes { includes, libraries, executables };
37 define defaultCompilerName = "Default";
39 define defaultObjDirExpression = "obj/$(CONFIG).$(PLATFORM)$(COMPILER_SUFFIX)$(DEBUG_SUFFIX)";
41 const char * settingsDirectoryNames[DirTypes] =
48 // This function cannot accept same pointer for source and output
49 // todo: rename ReplaceSpaces to EscapeSpaceAndSpecialChars or something
50 void ReplaceSpaces(char * output, const char * source)
55 for(c = 0, dc = 0; (ch = source[c]); c++, dc++)
57 if(ch == ' ') output[dc++] = '\\';
58 if(ch == '\"') output[dc++] = '\\';
59 if(ch == '&') output[dc++] = '\\';
62 if(ch == '(' || ch == ')') output[dc++] = '\\';
73 enum GlobalSettingsChange { none, editorSettings, projectOptions, compilerSettings };
75 enum PathRelationship { unrelated, identical, siblings, subPath, parentPath, insuficientInput, pathEmpty, toEmpty, pathNull, toNull, bothEmpty, bothNull };
76 PathRelationship eString_PathRelated(const char * path, const char * to, char * pathDiff)
78 PathRelationship result;
79 if(pathDiff) *pathDiff = '\0';
80 if(path && *path && to && *to)
82 char toPart[MAX_FILENAME], toRest[MAX_LOCATION];
83 char pathPart[MAX_FILENAME], pathRest[MAX_LOCATION];
85 strcpy(pathRest, path);
86 for(; toRest[0] && pathRest[0];)
88 SplitDirectory(toRest, toPart, toRest);
89 SplitDirectory(pathRest, pathPart, pathRest);
90 if(!fstrcmp(pathPart, toPart)) result = siblings;
93 if(result == siblings)
95 if(!*toRest && !*pathRest) result = identical;
96 else if(!*pathRest) result = parentPath;
97 else result = subPath;
98 if(pathDiff && result != identical) strcpy(pathDiff, *pathRest == '\0' ? toRest : pathRest);
100 else result = unrelated;
106 if(!*path && !*to) result = bothEmpty;
107 else if(!*path) result = pathEmpty;
108 else result = toEmpty;
110 else if(!path && !to) result = bothNull;
111 else if(!path) result = pathNull;
112 else result = toNull;
117 char * CopyValidateMakefilePath(const char * path)
119 const int map[] = { 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 7 };
120 const char * vars[] = { "$(MODULE)", "$(CONFIG)", "$(PLATFORM)", "$(COMPILER)", "$(TARGET)", "$(COMPILER_SUFFIX)", "$(DEBUG_SUFFIX)", "$(PROJECT)", "$(CONFIGURATION)", "$(TARGET_PLATFORM)",(char *)0 };
126 len = (int)strlen(path);
127 copy = CopyString(path);
133 Array<const char *> parts { };
140 for(v=0; vars[v]; v++)
142 if(SearchString(&tmp[c], 0, vars[v], false, false) == &tmp[c])
146 parts.Add(vars[map[v]]);
147 c += strlen(vars[v]);
161 for(c=0; c<parts.count; c++) len += strlen(parts[c]);
162 copy = new char[++len];
164 for(c=0; c<parts.count; c++) strcat(copy, parts[c]);
175 void ValidPathBufCopy(char *output, const char *input)
178 bool volumePath = false;
180 strcpy(output, input);
181 TrimLSpaces(output, output);
182 TrimRSpaces(output, output);
183 MakeSystemPath(output);
185 if(output[0] && output[1] == ':')
192 const char * chars = "*|:\",<>?";
193 char ch, * s = output, * o = output;
194 while((ch = *s++)) { if(!strchr(chars, ch)) *o++ = ch; }
198 if(volumePath && output[0])
203 void RemoveTrailingPathSeparator(char *path)
206 len = (int)strlen(path);
207 if(len>1 && path[len-1] == DIR_SEP)
211 void BasicValidatePathBoxPath(PathBox pathBox)
213 char path[MAX_LOCATION];
214 ValidPathBufCopy(path, pathBox.path);
215 RemoveTrailingPathSeparator(path);
219 CompilerConfig MakeDefaultCompiler(const char * name, bool readOnly)
221 CompilerConfig defaultCompiler
239 incref defaultCompiler;
240 return defaultCompiler;
243 //#define SETTINGS_TEST
245 define settingsDir = ".ecereIDE-SettingsTest";
246 define ideSettingsName = "ecereIDE-SettingsTest";
248 define settingsDir = ".ecereIDE";
249 define ideSettingsName = "ecereIDE";
252 class IDEConfigHolder
254 CompilerConfigs compilers { };
255 RecentFiles recentFiles { };
256 RecentWorkspaces recentWorkspaces { };
258 property CompilerConfigs compilers
260 set { compilers.Free(); delete compilers; compilers = value; }
261 get { return compilers; }
263 property RecentFiles recentFiles
265 set { recentFiles.Free(); delete recentFiles; recentFiles = value; }
266 get { return recentFiles; }
268 property RecentWorkspaces recentProjects
270 set { recentWorkspaces.Free(); delete recentWorkspaces; recentWorkspaces = value; }
271 get { return recentWorkspaces; }
278 recentWorkspaces.Free();
281 void forcePathSeparatorStyle(bool unixStyle)
285 from = '\\', to = '/';
287 from = '/', to = '\\';
288 recentFiles.changeChar(from, to);
289 recentWorkspaces.changeChar(from, to);
293 class IDESettingsContainer : GlobalSettings
295 virtual void onLoadCompilerConfigs();
296 virtual void onLoadRecentFiles();
297 virtual void onLoadRecentProjects();
299 CompilerConfigs compilerConfigs;
300 RecentFiles recentFiles;
301 RecentWorkspaces recentProjects;
303 property bool useNewConfigurationFiles
310 settingsName = "config";
311 settingsExtension = "econ";
312 settingsDirectory = settingsDir;
317 settingsName = ideSettingsName;
318 settingsExtension = null;
319 settingsDirectory = null;
324 char moduleLocation[MAX_LOCATION];
326 FileMonitor recentFilesMonitor
328 this, fileChange = { modified = true };
330 bool OnFileNotify(FileChange action, const char * param)
333 recentFilesMonitor.StopMonitoring();
334 f = FileOpen(recentFilesMonitor.fileName, read);
339 for(c = 0; c < 10 && !(locked = f.Lock(shared, 0, 0, false)); c++) ecere::sys::Sleep(0.01);
340 recentFiles.read(this);
348 FileMonitor recentProjectsMonitor
350 this, fileChange = { modified = true };
352 bool OnFileNotify(FileChange action, const char * param)
355 recentProjectsMonitor.StopMonitoring();
356 f = FileOpen(recentProjectsMonitor.fileName, read);
361 for(c = 0; c < 10 && !(locked = f.Lock(shared, 0, 0, false)); c++) ecere::sys::Sleep(0.01);
362 recentProjects.read(this);
370 static void getConfigFilePath(char * path, Class _class, char * dir, const char * configName)
373 strcpy(path, settingsFilePath);
374 StripLastDirectory(path, path);
376 PathCatSlash(path, settingsDir);
377 if(_class == class(CompilerConfig))
379 PathCatSlash(path, "compilerConfigs");
384 PathCatSlash(path, configName);
385 strcat(path, ".econ");
388 else if(_class == class(RecentFilesData))
389 PathCatSlash(path, "recentFiles.econ");
390 else if(_class == class(RecentWorkspacesData))
391 PathCatSlash(path, "recentWorkspaces.econ");
396 FileSize settingsFileSize;
398 IDESettingsContainer()
400 char path[MAX_LOCATION];
402 LocateModule(null, moduleLocation);
403 strcpy(path, moduleLocation);
404 StripLastDirectory(moduleLocation, moduleLocation);
405 ChangeCh(moduleLocation, '\\', '/');
406 // PortableApps.com directory structure
407 if((start = strstr(path, "\\App\\EcereSDK\\bin\\ecere-ide.exe")))
409 char configFilePath[MAX_LOCATION];
410 char defaultConfigFilePath[MAX_LOCATION];
414 strcpy(configFilePath, path);
415 PathCat(configFilePath, "Data");
416 PathCat(configFilePath, ideSettingsName);
417 ChangeExtension(configFilePath, "ini", configFilePath);
419 strcpy(defaultConfigFilePath, path);
420 PathCat(defaultConfigFilePath, "App");
421 PathCat(defaultConfigFilePath, "DefaultData");
422 PathCat(defaultConfigFilePath, ideSettingsName);
423 ChangeExtension(defaultConfigFilePath, "ini", defaultConfigFilePath);
425 if(FileExists(defaultConfigFilePath))
427 if(!FileExists(configFilePath))
429 File f = FileOpen(defaultConfigFilePath, read);
430 f.CopyTo(configFilePath);
434 PathCat(path, "Data");
435 // the forced settings location will only be
436 // used if the running ide's path matches
437 // the PortableApps.com directory structure
438 // and the default ini file is found in
439 // the DefaultData directory
440 settingsLocation = path;
446 void OnAskReloadSettings()
448 FileSize newSettingsFileSize;
450 if(OpenAndLock(&newSettingsFileSize))
452 if((double)settingsFileSize - (double)newSettingsFileSize < 2048)
456 GuiApplication app = ((GuiApplication)__thisModule.application);
458 for(w = app.desktop.firstChild; w && (!w.created || !w.visible); w = w.next);
462 MessageBox { master = w, type = ok, isModal = true,
463 creationActivation = flash,
464 text = "Global Settings Modified Externally",
465 contents = "The global settings were modified by another process and a drastic shrinking of the settings file was detected.\n"
466 "The new settings will not be loaded to prevent loss of your ide settings.\n"
467 "Please check your settings file and make sure to save this IDE's global settings if your settings file has been compromised."
473 SettingsIOResult Load()
476 SettingsIOResult result;
477 useNewConfigurationFiles = true;
478 result = GlobalSettings::Load();
479 data = (IDESettings)this.data;
481 if(result == fileNotFound)
484 useNewConfigurationFiles = false;
485 result = GlobalSettings::Load();
487 data = (IDESettings)this.data;
490 this.data = IDESettings { };
492 *dataOwner = this.data;
494 if(result == fileNotCompatibleWithDriver)
497 OldIDESettings oldSettings { };
499 loaded = oldSettings.Load() == success;
503 data = (IDESettings)this.data;
505 for(c : oldSettings.compilerConfigs)
506 data.compilerConfigs.Add(c.Copy());
508 for(s : oldSettings.recentFiles) data.recentFiles.Add(s);
509 for(s : oldSettings.recentProjects) data.recentProjects.Add(s);
511 data.docDir = oldSettings.docDir;
512 data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
513 data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
514 data.useFreeCaret = oldSettings.useFreeCaret;
515 data.showLineNumbers = oldSettings.showLineNumbers;
516 data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
517 delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
518 data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
519 data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
526 if(result == fileNotFound || !data)
528 data = (IDESettings)this.data;
529 data.useFreeCaret = false; //true;
530 data.showLineNumbers = true;
531 data.caretFollowsScrolling = false; //true;
536 FileGetSize(settingsFilePath, &settingsFileSize);
537 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
538 data.ManagePortablePaths(moduleLocation, true);
539 data.ForcePathSeparatorStyle(true);
541 // Import from previous ecereIDE settings
544 data.compilerConfigs.ensureDefaults();
545 data.compilerConfigs.write(this, null);
546 data.compilerConfigs.Free();
548 data.recentFiles.write(this);
549 data.recentFiles.Free();
551 data.recentProjects.write(this);
552 data.recentProjects.Free();
559 SettingsIOResult Save()
561 SettingsIOResult result;
563 useNewConfigurationFiles = true;
564 data = (IDESettings)this.data;
565 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
566 data.ManagePortablePaths(moduleLocation, false);
567 data.ForcePathSeparatorStyle(true);
569 settingsFilePath = null;
570 result = GlobalSettings::Save();
571 if(result != success)
572 PrintLn("Error saving IDE settings");
575 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
576 data.ManagePortablePaths(moduleLocation, true);
579 FileGetSize(settingsFilePath, &settingsFileSize);
585 static Map<String, String> getCompilerConfigFilePathsByName(const char * path)
587 Map<String, String> map { };
588 FileListing fl { path, extensions = "econ" };
591 if(fl.stats.attribs.isFile)
593 char name[MAX_FILENAME];
594 char * path = CopyString(fl.path);
596 GetLastDirectory(path, name);
597 StripExtension(name);
604 static Map<String, CompilerConfig> getCompilerConfigsByName(const char * path)
606 Map<String, CompilerConfig> map { };
607 FileListing fl { path, extensions = "econ" };
610 if(fl.stats.attribs.isFile)
612 char name[MAX_FILENAME];
613 char * path = CopyString(fl.path);
615 GetLastDirectory(path, name);
616 StripExtension(name);
618 CompilerConfig ccfg = CompilerConfig::read(path);
628 static SettingsIOResult writeConfigFile(const char * path, Class dataType, void * data)
630 SettingsIOResult result = error;
631 SafeFile sf = SafeFile::open(path, write);
634 WriteECONObject(sf.file, dataType, data, 0);
640 PrintLn($"error: could not safely open file for writing configuration: ", path);
644 static SettingsIOResult readConfigFile(const char * path, Class dataType, void ** data)
646 SettingsIOResult result = error;
648 if(!FileExists(path))
649 result = fileNotFound;
650 else if((sf = SafeFile::open(path, read)))
652 JSONResult jsonResult;
654 ECONParser parser { f = sf.file };
655 sf.file.Seek(0, start);
656 jsonResult = parser.GetObject(dataType, data);
657 if(jsonResult != success)
661 if(jsonResult == success)
665 result = fileNotCompatibleWithDriver;
666 PrintLn($"error: could not parse configuration file: ", path);
677 char path[MAX_LOCATION];
678 char tmp[MAX_LOCATION];
680 SafeFile ::open(const char * path, FileOpenMode mode)
682 SafeFile result = null;
683 if(mode == write || mode == read)
685 SafeFile sf { mode = mode };
688 FileLock lockType = mode == write ? exclusive : shared;
690 strcpy(sf.path, path);
691 strcpy(sf.tmp, path);
692 strcat(sf.tmp, ".tmp");
693 if(mode == write && FileExists(sf.tmp).isFile)
698 sf.file = FileOpen(sf.tmp, readWrite);
701 sf.file = FileOpen(sf.tmp, writeRead);
705 sf.file = FileOpen(sf.tmp, readWrite);
710 sf.file = FileOpen(path, mode);
713 for(c = 0; c < 10 && !(locked = sf.file.Lock(lockType, 0, 0, false)); c++) Sleep(0.01);
716 else if(mode == write)
717 PrintLn($"warning: SafeFile::open: unable to obtain exclusive lock on temporary file for writing: ", sf.tmp);
719 PrintLn($"warning: SafeFile::open: unable to obtain shared lock on file for reading: ", path);
721 else if(mode == write)
722 PrintLn($"warning: SafeFile::open: unable to open temporary file for writing: ", sf.tmp);
724 PrintLn($"warning: SafeFile::open: unable to open file for reading: ", path);
730 PrintLn($"warning: SafeFile::open: does not yet support FileOpenMode::", mode);
736 if(file && mode == write)
739 File f = FileOpen(path, readWrite);
742 f = FileOpen(path, writeRead);
746 f = FileOpen(path, readWrite);
752 for(c = 0; c < 10 && !(locked = f.Lock(exclusive, 0,0, false)); c++) Sleep(0.01);
756 f.Unlock(0,0, false);
758 file.Unlock(0,0, false);
761 for(c = 0; c < 10; c++)
763 if(MoveFileEx(tmp, path, { true, true }))
772 PrintLn($"warning: SafeFile::sync: failed to lock file for ", mode);
783 file.Unlock(0,0, false);
789 class RecentFilesData
792 RecentFiles recentFiles;
795 class RecentWorkspacesData
798 RecentWorkspaces recentWorkspaces;
801 class IDESettings : GlobalSettingsData
804 property CompilerConfigs compilerConfigs
806 set { /*if(settingsContainer.oldConfig)*/ { if(compilerConfigs) compilerConfigs.Free(); delete compilerConfigs; if(value) compilerConfigs = value; } }
807 get { return compilerConfigs; }
808 isset { return false; }
810 property RecentFiles recentFiles
812 set { if(recentFiles) recentFiles.Free(); delete recentFiles; if(value) recentFiles = value; }
813 get { return recentFiles; }
814 isset { return false; }
816 property RecentWorkspaces recentProjects
818 set { if(recentProjects) recentProjects.Free(); delete recentProjects; if(value) recentProjects = value; }
819 get { return recentProjects; }
820 isset { return false; }
822 property const char * docDir
824 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
825 get { return docDir ? docDir : ""; }
826 isset { return docDir && docDir[0]; }
828 property const char * ideFileDialogLocation
830 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
831 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
832 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
834 property const char * ideProjectFileDialogLocation
836 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
837 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
838 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
841 bool showLineNumbers;
842 bool caretFollowsScrolling;
843 char * displayDriver;
845 // TODO: Classify settings
846 //EditorSettings editor { };
848 property const char * projectDefaultTargetDir
850 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
851 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
852 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
854 property const char * projectDefaultIntermediateObjDir
856 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
857 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
858 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
861 property const char * compilerConfigsDir
863 set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
864 get { return compilerConfigsDir ? compilerConfigsDir : ""; }
865 isset { return compilerConfigsDir && compilerConfigsDir[0]; }
868 property const char * defaultCompiler
870 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
871 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
872 isset { return defaultCompiler && defaultCompiler[0]; }
875 property const String language
880 language = CopyString(value);
882 get { return language; }
883 isset { return language != null; }
886 property const String codeEditorFont
890 delete codeEditorFont;
891 codeEditorFont = CopyString(value);
893 get { return codeEditorFont; }
896 float codeEditorFontSize;
897 bool showFixedPitchFontsOnly;
900 CompilerConfigs compilerConfigs { };
902 char * ideFileDialogLocation;
903 char * ideProjectFileDialogLocation;
904 char * projectDefaultTargetDir;
905 char * projectDefaultIntermediateObjDir;
906 char * compilerConfigsDir;
907 char * defaultCompiler;
909 RecentFiles recentFiles { };
910 RecentWorkspaces recentProjects { };
912 String codeEditorFont;
914 showFixedPitchFontsOnly = true;
915 codeEditorFontSize = 12;
916 codeEditorFont = CopyString("Courier New");
920 compilerConfigs.Free();
921 delete compilerConfigs;
922 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
923 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
926 delete projectDefaultTargetDir;
927 delete projectDefaultIntermediateObjDir;
928 delete compilerConfigsDir;
929 delete defaultCompiler;
932 delete ideFileDialogLocation;
933 delete ideProjectFileDialogLocation;
934 delete displayDriver;
936 delete codeEditorFont;
939 void ForcePathSeparatorStyle(bool unixStyle)
943 from = '\\', to = '/';
945 from = '/', to = '\\';
946 if(compilerConfigs && compilerConfigs.count)
949 for(config : compilerConfigs)
951 if(config.includeDirs && config.includeDirs.count)
953 for(i = 0; i < config.includeDirs.count; i++)
955 if(config.includeDirs[i] && config.includeDirs[i][0])
956 ChangeCh(config.includeDirs[i], from, to);
959 if(config.libraryDirs && config.libraryDirs.count)
961 for(i = 0; i < config.libraryDirs.count; i++)
963 if(config.libraryDirs[i] && config.libraryDirs[i][0])
964 ChangeCh(config.libraryDirs[i], from, to);
967 if(config.executableDirs && config.executableDirs.count)
969 for(i = 0; i < config.executableDirs.count; i++)
971 if(config.executableDirs[i] && config.executableDirs[i][0])
972 ChangeCh(config.executableDirs[i], from, to);
977 recentFiles.changeChar(from, to);
978 recentProjects.changeChar(from, to);
979 if(docDir && docDir[0])
980 ChangeCh(docDir, from, to);
981 if(ideFileDialogLocation && ideFileDialogLocation[0])
982 ChangeCh(ideFileDialogLocation, from, to);
983 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
984 ChangeCh(ideProjectFileDialogLocation, from, to);
986 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
987 ChangeCh(projectDefaultTargetDir, from, to);
988 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
989 ChangeCh(projectDefaultIntermediateObjDir, from, to);
991 if(compilerConfigsDir && compilerConfigsDir[0])
992 ChangeCh(compilerConfigsDir, from, to);
995 void ManagePortablePaths(char * location, bool makeAbsolute)
998 if(compilerConfigs && compilerConfigs.count)
1000 for(config : compilerConfigs)
1003 for(t = 0; t < DirTypes::enumSize; t++)
1005 Array<String> dirs = null;
1006 if(t == executables) dirs = config.executableDirs;
1007 else if(t == includes) dirs = config.includeDirs;
1008 else if(t == libraries) dirs = config.libraryDirs;
1009 if(dirs && dirs.count)
1011 for(c = 0; c < dirs.count; c++)
1013 if(dirs[c] && dirs[c][0])
1014 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
1020 if(recentFiles && recentFiles.count)
1022 for(c = 0; c < recentFiles.count; c++)
1024 if(recentFiles[c] && recentFiles[c][0])
1025 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
1028 if(recentProjects && recentProjects.count)
1030 for(c = 0; c < recentProjects.count; c++)
1032 if(recentProjects[c] && recentProjects[c][0])
1033 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
1036 if(docDir && docDir[0])
1037 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
1038 if(ideFileDialogLocation && ideFileDialogLocation[0])
1039 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
1040 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1041 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
1043 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1044 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
1045 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1046 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
1048 if(compilerConfigsDir && compilerConfigsDir[0])
1049 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
1052 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
1057 char p[MAX_LOCATION];
1058 strcpy(p, location);
1059 PathCatSlash(p, path);
1061 output = CopyString(p);
1065 PathRelationship rel = eString_PathRelated(path, location, null);
1066 if(rel == subPath || rel == identical)
1068 char p[MAX_LOCATION];
1069 MakePathRelative(path, location, p);
1070 if(!*p) strcpy(p, "./");
1071 else ChangeCh(p, '\\', '/');
1073 output = CopyString(p);
1082 class RecentFiles : RecentPaths
1084 void read(IDESettingsContainer settingsContainer)
1086 char path[MAX_LOCATION];
1087 RecentFilesData d = null;
1088 Class _class = class(RecentFilesData);
1089 settingsContainer.getConfigFilePath(path, _class, null, null);
1090 readConfigFile(path, _class, &d);
1091 if(d && d.recentFiles && d.recentFiles.count)
1094 Copy((void *)d.recentFiles);
1095 settingsContainer.recentFiles = this; // Merge IDEConfigHolder / IDESettingsContainer?
1098 settingsContainer.recentFilesMonitor.fileName = path;
1099 settingsContainer.recentFilesMonitor.StartMonitoring();
1100 settingsContainer.onLoadRecentFiles();
1103 void write(IDESettingsContainer settingsContainer)
1105 char path[MAX_LOCATION];
1106 RecentFilesData d { };
1107 Class _class = class(RecentFilesData);
1108 settingsContainer.getConfigFilePath(path, _class, null, null);
1109 d.recentFiles = this;
1110 writeConfigFile(path, _class, d);
1111 d.recentFiles = null;
1116 class RecentWorkspaces : RecentPaths
1118 void read(IDESettingsContainer settingsContainer)
1120 char path[MAX_LOCATION];
1121 RecentWorkspacesData d = null;
1122 Class _class = class(RecentWorkspacesData);
1123 settingsContainer.getConfigFilePath(path, _class, null, null);
1124 readConfigFile(path, _class, &d);
1125 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1128 Copy((void *)d.recentWorkspaces);
1129 settingsContainer.recentProjects = this; // Merge IDEConfigHolder / IDESettingsContainer?
1132 settingsContainer.recentProjectsMonitor.fileName = path;
1133 settingsContainer.recentProjectsMonitor.StartMonitoring();
1134 settingsContainer.onLoadRecentProjects();
1137 void write(IDESettingsContainer settingsContainer)
1139 char path[MAX_LOCATION];
1140 RecentWorkspacesData d { };
1141 Class _class = class(RecentWorkspacesData);
1142 settingsContainer.getConfigFilePath(path, _class, null, null);
1143 d.recentWorkspaces = this;
1144 writeConfigFile(path, _class, d);
1145 d.recentWorkspaces = null;
1150 class RecentPaths : Array<String>
1152 IteratorPointer Add(T value)
1155 char * filePath = (char *)value;
1156 ChangeCh(filePath, '\\', '/');
1157 for(c = 0; c < count; c++)
1159 if(this[c] && !fstrcmp(this[c], filePath))
1161 Delete((void *)&this[c]);
1165 return Array::Add((T)filePath);
1168 IteratorPointer addRecent(const String value)
1171 char * filePath = CopyString((char *)value);
1173 ChangeCh(filePath, '\\', '/');
1174 for(c = 0; c < count; c++)
1176 if(this[c] && !fstrcmp(this[c], filePath))
1178 Delete((void *)&this[c]);
1182 while(count >= MaxRecent)
1184 ip = Insert(null, filePath);
1188 void changeChar(char from, char to)
1193 for(c = 0; c < count; c++)
1195 if(this[c] && this[c][0])
1196 ChangeCh(this[c], from, to);
1202 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1203 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1204 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1205 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1206 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1207 // TODO: i18n with Array
1208 static Array<const String> compilerTypeLongNames
1210 $"GNU Compiler Collection (GCC) / GNU Make",
1211 $"Tiny C Compiler / GNU Make",
1212 $"Portable C Compiler / GNU Make",
1213 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1214 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1215 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1217 const CompilerType firstCompilerType = gcc;
1218 const CompilerType lastCompilerType = vs10;
1219 public enum CompilerType
1221 gcc, tcc, pcc, vs8, vs9, vs10;
1225 get { return this == vs8 || this == vs9 || this == vs10; }
1228 property const char *
1230 get { return OnGetString(null, null, null); }
1236 for(c = firstCompilerType; c <= lastCompilerType; c++)
1237 if(!strcmpi(value, compilerTypeNames[c]))
1244 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1245 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1246 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1247 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1248 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1250 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1252 if(this >= firstCompilerType && this <= lastCompilerType)
1255 strcpy(tempString, compilerTypeNames[this]);
1256 if(fieldData == null)
1257 return compilerTypeNames[this];
1258 else if(fieldData == (void*)1)
1259 return compilerTypeLongNames[this];
1260 else if(fieldData == (void*)2)
1261 return compilerTypeVersionString[this];
1262 else if(fieldData == (void*)3)
1263 return compilerTypeYearString[this];
1264 else if(fieldData == (void*)4)
1265 return compilerTypeProjectFileExtension[this];
1266 else if(fieldData == (void*)5)
1267 return compilerTypeSolutionFileVersionString[this];
1273 class CompilerConfig
1279 property const char * name
1281 set { delete name; if(value) name = CopyString(value); }
1282 get { return name; }
1286 Platform targetPlatform;
1288 property const char * makeCommand
1290 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1291 get { return makeCommand; }
1292 isset { return makeCommand && makeCommand[0]; }
1294 property const char * ecpCommand
1296 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1297 get { return ecpCommand; }
1298 isset { return ecpCommand && ecpCommand[0]; }
1300 property const char * eccCommand
1302 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1303 get { return eccCommand; }
1304 isset { return eccCommand && eccCommand[0]; }
1306 property const char * ecsCommand
1308 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1309 get { return ecsCommand; }
1310 isset { return ecsCommand && ecsCommand[0]; }
1312 property const char * earCommand
1314 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1315 get { return earCommand; }
1316 isset { return earCommand && earCommand[0]; }
1318 property const char * cppCommand
1320 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1321 get { return cppCommand; }
1322 isset { return cppCommand && cppCommand[0]; }
1324 property const char * ccCommand
1326 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1327 get { return ccCommand; }
1328 isset { return ccCommand && ccCommand[0]; }
1330 property const char * cxxCommand
1332 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1333 get { return cxxCommand; }
1334 isset { return cxxCommand && cxxCommand[0]; }
1336 property const char * arCommand
1338 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1339 get { return arCommand; }
1340 isset { return arCommand && arCommand[0]; }
1342 property const char * ldCommand
1344 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1345 get { return ldCommand; }
1346 isset { return ldCommand && ldCommand[0]; }
1348 property const char * objectFileExt
1350 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1351 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1352 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1354 property const char * staticLibFileExt
1356 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1357 get { return staticLibFileExt; }
1358 isset { return staticLibFileExt && staticLibFileExt[0]; }
1360 property const char * sharedLibFileExt
1362 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1363 get { return sharedLibFileExt; }
1364 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1366 property const char * executableFileExt
1368 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1369 get { return executableFileExt; }
1370 isset { return executableFileExt && executableFileExt[0]; }
1372 property const char * executableLauncher
1374 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1375 get { return executableLauncher; }
1376 isset { return executableLauncher && executableLauncher[0]; }
1378 // TODO: implement CompilerConfig::windresCommand
1382 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1384 property const char * distccHosts
1386 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1387 get { return distccHosts; }
1388 isset { return distccHosts && distccHosts[0]; }
1390 property const char * gnuToolchainPrefix
1392 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1393 get { return gnuToolchainPrefix; }
1394 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1396 property const char * sysroot
1398 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1399 get { return sysroot; }
1400 isset { return sysroot && sysroot[0]; }
1402 bool resourcesDotEar;
1404 property Array<String> includeDirs
1412 includeDirs = value;
1415 get { return includeDirs; }
1416 isset { return includeDirs.count != 0; }
1418 property Array<String> libraryDirs
1426 libraryDirs = value;
1429 get { return libraryDirs; }
1430 isset { return libraryDirs.count != 0; }
1432 property Array<String> executableDirs
1436 executableDirs.Free();
1439 delete executableDirs;
1440 executableDirs = value;
1443 get { return executableDirs; }
1444 isset { return executableDirs.count != 0; }
1446 property Array<NamedString> environmentVars
1450 environmentVars.Free();
1453 delete environmentVars;
1454 environmentVars = value;
1457 get { return environmentVars; }
1458 isset { return environmentVars.count != 0; }
1460 property Array<String> prepDirectives
1464 prepDirectives.Free();
1467 delete prepDirectives;
1468 prepDirectives = value;
1471 get { return prepDirectives; }
1472 isset { return prepDirectives.count != 0; }
1474 property Array<String> excludeLibs
1482 excludeLibs = value;
1485 get { return excludeLibs; }
1486 isset { return excludeLibs.count != 0; }
1488 property Array<String> eCcompilerFlags
1492 eCcompilerFlags.Free();
1495 delete eCcompilerFlags;
1496 eCcompilerFlags = value;
1499 get { return eCcompilerFlags; }
1500 isset { return eCcompilerFlags.count != 0; }
1502 property Array<String> compilerFlags
1506 compilerFlags.Free();
1509 delete compilerFlags;
1510 compilerFlags = value;
1513 get { return compilerFlags; }
1514 isset { return compilerFlags.count != 0; }
1516 property Array<String> cxxFlags
1527 get { return cxxFlags; }
1528 isset { return cxxFlags.count != 0; }
1530 property Array<String> linkerFlags
1538 linkerFlags = value;
1541 get { return linkerFlags; }
1542 isset { return linkerFlags.count != 0; }
1544 // json backward compatibility
1545 property const char * gccPrefix
1547 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1548 get { return gnuToolchainPrefix; }
1549 isset { return false; }
1551 property const char * execPrefixCommand
1553 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1554 get { return executableLauncher; }
1555 isset { return false; }
1557 property const char * outputFileExt
1559 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1560 get { return executableFileExt; }
1561 isset { return false; }
1564 property bool hasDocumentOutput
1568 bool result = executableFileExt && executableFileExt[0] &&
1569 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1572 isset { return false; }
1575 Array<String> includeDirs { };
1576 Array<String> libraryDirs { };
1577 Array<String> executableDirs { };
1578 // TODO: Can JSON parse and serialize maps?
1579 //EnvironmentVariables { };
1580 Array<NamedString> environmentVars { };
1581 Array<String> prepDirectives { };
1582 Array<String> excludeLibs { };
1583 Array<String> eCcompilerFlags { };
1584 Array<String> compilerFlags { };
1585 Array<String> cxxFlags { };
1586 Array<String> linkerFlags { };
1598 char * objectFileExt;
1599 char * staticLibFileExt;
1600 char * sharedLibFileExt;
1601 char * executableFileExt;
1602 char * executableLauncher;
1604 char * gnuToolchainPrefix;
1608 struct { Array<String> includes, libraries, executables; };
1609 Array<String> dirs[DirTypes];
1624 delete objectFileExt;
1625 delete staticLibFileExt;
1626 delete sharedLibFileExt;
1627 delete executableFileExt;
1629 delete executableLauncher;
1631 delete gnuToolchainPrefix;
1633 if(environmentVars) environmentVars.Free();
1634 if(includeDirs) { includeDirs.Free(); }
1635 if(libraryDirs) { libraryDirs.Free(); }
1636 if(executableDirs) { executableDirs.Free(); }
1637 if(prepDirectives) { prepDirectives.Free(); }
1638 if(excludeLibs) { excludeLibs.Free(); }
1639 if(compilerFlags) { compilerFlags.Free(); }
1640 if(cxxFlags) { cxxFlags.Free(); }
1641 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1642 if(linkerFlags) { linkerFlags.Free(); }
1645 int OnCompare(CompilerConfig b)
1649 !(result = type.OnCompare(b.type)) &&
1650 !(result = targetPlatform.OnCompare(b.targetPlatform)) &&
1651 !(result = numJobs.OnCompare(b.numJobs)) &&
1652 !(result = ccacheEnabled.OnCompare(b.ccacheEnabled)) &&
1653 !(result = distccEnabled.OnCompare(b.distccEnabled)) &&
1654 !(result = resourcesDotEar.OnCompare(b.resourcesDotEar)) &&
1655 !(result = noStripTarget.OnCompare(b.noStripTarget))
1659 !(result = name.OnCompare(b.name)) &&
1660 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1661 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1662 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1663 !(result = earCommand.OnCompare(b.earCommand)) &&
1664 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1665 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1666 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1667 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1668 !(result = arCommand.OnCompare(b.arCommand)) &&
1669 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1670 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1671 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1672 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1673 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1674 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1675 !(result = sysroot.OnCompare(b.sysroot)));
1678 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1679 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1680 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1681 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1682 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1683 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1684 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1685 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1686 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1687 !(result = linkerFlags.OnCompare(b.linkerFlags)));
1692 CompilerConfig Copy()
1725 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1726 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1727 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1728 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1729 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1730 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1731 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1732 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
1733 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1734 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1740 CompilerConfig ::read(const char * path)
1742 CompilerConfig d = null;
1743 readConfigFile(path, class(CompilerConfig), &d);
1747 void write(IDESettingsContainer settingsContainer)
1749 char dir[MAX_LOCATION];
1750 char path[MAX_LOCATION];
1751 const char * settingsFilePath = settingsContainer.settingsFilePath;
1752 settingsContainer.getConfigFilePath(path, _class, dir, name);
1753 if(FileExists(settingsFilePath) && !FileExists(dir))
1756 if(!FileExists(dir))
1757 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1759 writeConfigFile(path, _class, this);
1763 class CompilerConfigs : List<CompilerConfig>
1765 CompilerConfig GetCompilerConfig(const String compilerName)
1767 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
1768 CompilerConfig compilerConfig = null;
1769 for(compiler : this)
1771 if(!strcmp(compiler.name, name))
1773 compilerConfig = compiler;
1777 if(!compilerConfig && count)
1778 compilerConfig = this[0];
1781 incref compilerConfig;
1782 if(compilerConfig._refCount == 1)
1783 incref compilerConfig;
1785 return compilerConfig;
1788 void ensureDefaults()
1790 // Ensure we have a default compiler
1791 CompilerConfig defaultCompiler = GetCompilerConfig(defaultCompilerName);
1792 if(!defaultCompiler)
1794 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
1795 Insert(null, defaultCompiler);
1796 defaultCompiler = null;
1798 delete defaultCompiler;
1802 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
1803 ccfg.ecpCommand = ecpDefaultCommand;
1804 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
1805 ccfg.eccCommand = eccDefaultCommand;
1806 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
1807 ccfg.ecsCommand = ecsDefaultCommand;
1808 if(!ccfg.earCommand || !ccfg.earCommand[0])
1809 ccfg.earCommand = earDefaultCommand;
1810 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
1811 ccfg.cppCommand = cppDefaultCommand;
1812 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
1813 ccfg.ccCommand = ccDefaultCommand;
1814 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
1815 ccfg.cxxCommand = cxxDefaultCommand;
1816 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
1817 ccfg.ldCommand = ldDefaultCommand;*/
1818 if(!ccfg.arCommand || !ccfg.arCommand[0])
1819 ccfg.arCommand = arDefaultCommand;
1820 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
1821 ccfg.objectFileExt = objectDefaultFileExt;
1822 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
1823 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
1824 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
1825 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
1826 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
1827 ccfg.executableFileExt = outputDefaultFileExt;*/
1828 if(!ccfg._refCount) incref ccfg;
1832 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
1834 AVLTree<String> list { };
1838 for(occfg : oldConfigs; !strcmp(ccfg.name, occfg.name))
1841 if(ccfg.OnCompare(occfg))
1842 list.Add(CopyString(ccfg.name));
1846 list.Add(CopyString(ccfg.name));
1851 bool read(IDESettingsContainer settingsContainer)
1853 if(settingsContainer.settingsFilePath)
1855 char dir[MAX_LOCATION];
1856 char path[MAX_LOCATION];
1857 Class _class = class(CompilerConfig);
1858 settingsContainer.getConfigFilePath(path, _class, dir, null);
1861 AVLTree<const String> addedConfigs { };
1862 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
1863 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
1865 settingsContainer.compilerConfigs = this; // Merge IDEConfigHolder / IDESettingsContainer?
1866 if(it.Index("Default", false))
1868 CompilerConfig ccfg = it.data;
1870 addedConfigs.Add(ccfg.name);
1872 for(ccfg : compilerConfigsByName)
1874 if(!addedConfigs.Find(ccfg.name))
1877 addedConfigs.Add(ccfg.name);
1880 delete addedConfigs;
1882 compilerConfigsByName.Free();
1883 delete compilerConfigsByName;
1884 settingsContainer.onLoadCompilerConfigs();
1891 void write(IDESettingsContainer settingsContainer, AVLTree<String> cfgsToWrite)
1893 char dir[MAX_LOCATION];
1894 char path[MAX_LOCATION];
1895 Map<String, String> paths;
1896 settingsContainer.getConfigFilePath(path, class(CompilerConfig), dir, null);
1897 paths = getCompilerConfigFilePathsByName(dir);
1899 MapIterator<String, String> it { map = paths };
1902 CompilerConfig ccfg = c;
1903 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
1904 ccfg.write(settingsContainer);
1905 if(it.Index(ccfg.name, false))
1914 const char * path = p;
1922 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1923 struct LanguageOption
1926 const String bitmap;
1930 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1935 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
1937 Bitmap icon = res ? res.bitmap : null;
1940 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
1941 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
1945 Array<LanguageOption> languages
1947 { "English", ":countryCode/gb.png", "" },
1948 { "汉语", ":countryCode/cn.png", "zh_CN" },
1949 { "Español", ":countryCode/es.png", "es" },
1950 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
1951 { "Русский (43%)", ":countryCode/ru.png", "ru" },
1952 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
1953 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
1954 { "मराठी (10%)", ":countryCode/in.png", "mr" },
1955 { "Hebrew (8%)", ":countryCode/il.png", "he" },
1956 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
1959 const String GetLanguageString()
1961 char * dot, * colon;
1962 static char lang[256];
1963 const String language = getenv("ECERE_LANGUAGE");
1964 if(!language) language = getenv("LANGUAGE");
1965 if(!language) language = getenv("LC_ALL");
1966 if(!language) language = getenv("LC_MESSAGES");
1967 if(!language) language = getenv("LANG");
1968 if(!language) language = "";
1969 if(language && (colon = strchr(language, ':')))
1971 if(lang != language)
1972 strncpy(lang, language, sizeof(lang));
1973 lang[sizeof(lang)-1] = 0;
1974 lang[colon - language] = 0;
1977 if(language && (dot = strchr(language, '.')))
1979 if(lang != language)
1980 strncpy(lang, language, sizeof(lang));
1981 lang[sizeof(lang)-1] = 0;
1982 lang[dot - language] = 0;
1988 void setEcereLanguageInWinRegEnvironment(const char * languageCode)
1992 uint16 wLanguage[256];
1996 RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1999 UTF8toUTF16Buffer(languageCode, wLanguage, sizeof(wLanguage) / sizeof(uint16));
2000 RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
2006 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
2008 bool restart = true;
2009 String command = null;
2010 int arg0Len = (int)strlen(app.argv[0]);
2022 for(w = ide.firstChild; w; w = w.next)
2024 if(w.isActiveClient && w.isDocument)
2026 if(!w.CloseConfirmation(true))
2035 if(!projectView.CloseConfirmation(true))
2037 if(projectView.fileName)
2039 const char * name = projectView.fileName;
2042 for(j = 0; (ch = name[j]); j++)
2043 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2047 command = new char[len + 1];
2049 strcpy(command, app.argv[0]);
2051 if(projectView.fileName)
2053 strcat(command, " ");
2055 ReplaceSpaces(command + len, projectView.fileName);
2060 for(w = ide.firstChild; w; w = w.next)
2061 if(w.isActiveClient && w.isDocument)
2062 w.modifiedDocument = false;
2063 projectView.modifiedDocument = false;
2068 for(w = ide.firstChild; w; w = w.next)
2070 if(w.isActiveClient && w.isDocument)
2072 if(!w.CloseConfirmation(true))
2079 const char * name = w.fileName;
2081 for(j = 0; (ch = name[j]); j++)
2082 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2089 command = new char[len + 1];
2090 strcpy(command, app.argv[0]);
2093 for(w = ide.firstChild; w; w = w.next)
2095 if(w.isActiveClient && w.isDocument)
2097 const char * name = w.fileName;
2100 strcat(command, " ");
2102 ReplaceSpaces(command + len, name);
2103 len = (int)strlen(command);
2110 for(w = ide.firstChild; w; w = w.next)
2111 if(w.isActiveClient && w.isDocument)
2112 w.modifiedDocument = false;
2117 settings.language = code;
2118 settingsContainer.Save();
2120 setEcereLanguageInWinRegEnvironment(code);
2122 if(eClass_IsDerived(app._class, class(GuiApplication)))
2124 GuiApplication guiApp = (GuiApplication)app;
2125 guiApp.desktop.Destroy(0);
2132 for(i = 1; i < app.argc; i++)
2134 const char * arg = app.argv[i];
2136 for(j = 0; (ch = arg[j]); j++)
2137 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2140 command = new char[len + 1];
2141 strcpy(command, app.argv[0]);
2143 for(i = 1; i < app.argc; i++)
2145 strcat(command, " ");
2147 ReplaceSpaces(command + len, app.argv[i]);
2148 len = (int)strlen(command);
2154 SetEnvironment("ECERE_LANGUAGE", code);
2156 ExecuteWait(command);