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\\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; }
887 CompilerConfigs compilerConfigs { };
889 char * ideFileDialogLocation;
890 char * ideProjectFileDialogLocation;
891 char * projectDefaultTargetDir;
892 char * projectDefaultIntermediateObjDir;
893 char * compilerConfigsDir;
894 char * defaultCompiler;
896 RecentFiles recentFiles { };
897 RecentWorkspaces recentProjects { };
901 compilerConfigs.Free();
902 delete compilerConfigs;
903 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
904 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
907 delete projectDefaultTargetDir;
908 delete projectDefaultIntermediateObjDir;
909 delete compilerConfigsDir;
910 delete defaultCompiler;
913 delete ideFileDialogLocation;
914 delete ideProjectFileDialogLocation;
915 delete displayDriver;
918 void ForcePathSeparatorStyle(bool unixStyle)
922 from = '\\', to = '/';
924 from = '/', to = '\\';
925 if(compilerConfigs && compilerConfigs.count)
928 for(config : compilerConfigs)
930 if(config.includeDirs && config.includeDirs.count)
932 for(i = 0; i < config.includeDirs.count; i++)
934 if(config.includeDirs[i] && config.includeDirs[i][0])
935 ChangeCh(config.includeDirs[i], from, to);
938 if(config.libraryDirs && config.libraryDirs.count)
940 for(i = 0; i < config.libraryDirs.count; i++)
942 if(config.libraryDirs[i] && config.libraryDirs[i][0])
943 ChangeCh(config.libraryDirs[i], from, to);
946 if(config.executableDirs && config.executableDirs.count)
948 for(i = 0; i < config.executableDirs.count; i++)
950 if(config.executableDirs[i] && config.executableDirs[i][0])
951 ChangeCh(config.executableDirs[i], from, to);
956 recentFiles.changeChar(from, to);
957 recentProjects.changeChar(from, to);
958 if(docDir && docDir[0])
959 ChangeCh(docDir, from, to);
960 if(ideFileDialogLocation && ideFileDialogLocation[0])
961 ChangeCh(ideFileDialogLocation, from, to);
962 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
963 ChangeCh(ideProjectFileDialogLocation, from, to);
965 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
966 ChangeCh(projectDefaultTargetDir, from, to);
967 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
968 ChangeCh(projectDefaultIntermediateObjDir, from, to);
970 if(compilerConfigsDir && compilerConfigsDir[0])
971 ChangeCh(compilerConfigsDir, from, to);
974 void ManagePortablePaths(char * location, bool makeAbsolute)
977 if(compilerConfigs && compilerConfigs.count)
979 for(config : compilerConfigs)
982 for(t = 0; t < DirTypes::enumSize; t++)
984 Array<String> dirs = null;
985 if(t == executables) dirs = config.executableDirs;
986 else if(t == includes) dirs = config.includeDirs;
987 else if(t == libraries) dirs = config.libraryDirs;
988 if(dirs && dirs.count)
990 for(c = 0; c < dirs.count; c++)
992 if(dirs[c] && dirs[c][0])
993 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
999 if(recentFiles && recentFiles.count)
1001 for(c = 0; c < recentFiles.count; c++)
1003 if(recentFiles[c] && recentFiles[c][0])
1004 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
1007 if(recentProjects && recentProjects.count)
1009 for(c = 0; c < recentProjects.count; c++)
1011 if(recentProjects[c] && recentProjects[c][0])
1012 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
1015 if(docDir && docDir[0])
1016 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
1017 if(ideFileDialogLocation && ideFileDialogLocation[0])
1018 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
1019 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1020 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
1022 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1023 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
1024 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1025 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
1027 if(compilerConfigsDir && compilerConfigsDir[0])
1028 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
1031 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
1036 char p[MAX_LOCATION];
1037 strcpy(p, location);
1038 PathCatSlash(p, path);
1040 output = CopyString(p);
1044 PathRelationship rel = eString_PathRelated(path, location, null);
1045 if(rel == subPath || rel == identical)
1047 char p[MAX_LOCATION];
1048 MakePathRelative(path, location, p);
1049 if(!*p) strcpy(p, "./");
1050 else ChangeCh(p, '\\', '/');
1052 output = CopyString(p);
1061 class RecentFiles : RecentPaths
1063 void read(IDESettingsContainer settingsContainer)
1065 char path[MAX_LOCATION];
1066 RecentFilesData d = null;
1067 Class _class = class(RecentFilesData);
1068 settingsContainer.getConfigFilePath(path, _class, null, null);
1069 readConfigFile(path, _class, &d);
1070 if(d && d.recentFiles && d.recentFiles.count)
1073 Copy((void *)d.recentFiles);
1074 settingsContainer.recentFiles = this; // Merge IDEConfigHolder / IDESettingsContainer?
1077 settingsContainer.recentFilesMonitor.fileName = path;
1078 settingsContainer.recentFilesMonitor.StartMonitoring();
1079 settingsContainer.onLoadRecentFiles();
1082 void write(IDESettingsContainer settingsContainer)
1084 char path[MAX_LOCATION];
1085 RecentFilesData d { };
1086 Class _class = class(RecentFilesData);
1087 settingsContainer.getConfigFilePath(path, _class, null, null);
1088 d.recentFiles = this;
1089 writeConfigFile(path, _class, d);
1090 d.recentFiles = null;
1095 class RecentWorkspaces : RecentPaths
1097 void read(IDESettingsContainer settingsContainer)
1099 char path[MAX_LOCATION];
1100 RecentWorkspacesData d = null;
1101 Class _class = class(RecentWorkspacesData);
1102 settingsContainer.getConfigFilePath(path, _class, null, null);
1103 readConfigFile(path, _class, &d);
1104 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1107 Copy((void *)d.recentWorkspaces);
1108 settingsContainer.recentProjects = this; // Merge IDEConfigHolder / IDESettingsContainer?
1111 settingsContainer.recentProjectsMonitor.fileName = path;
1112 settingsContainer.recentProjectsMonitor.StartMonitoring();
1113 settingsContainer.onLoadRecentProjects();
1116 void write(IDESettingsContainer settingsContainer)
1118 char path[MAX_LOCATION];
1119 RecentWorkspacesData d { };
1120 Class _class = class(RecentWorkspacesData);
1121 settingsContainer.getConfigFilePath(path, _class, null, null);
1122 d.recentWorkspaces = this;
1123 writeConfigFile(path, _class, d);
1124 d.recentWorkspaces = null;
1129 class RecentPaths : Array<String>
1131 IteratorPointer Add(T value)
1134 char * filePath = (char *)value;
1135 ChangeCh(filePath, '\\', '/');
1136 for(c = 0; c < count; c++)
1138 if(this[c] && !fstrcmp(this[c], filePath))
1140 Delete((void *)&this[c]);
1144 return Array::Add((T)filePath);
1147 IteratorPointer addRecent(const String value)
1150 char * filePath = CopyString((char *)value);
1152 ChangeCh(filePath, '\\', '/');
1153 for(c = 0; c < count; c++)
1155 if(this[c] && !fstrcmp(this[c], filePath))
1157 Delete((void *)&this[c]);
1161 while(count >= MaxRecent)
1163 ip = Insert(null, filePath);
1167 void changeChar(char from, char to)
1172 for(c = 0; c < count; c++)
1174 if(this[c] && this[c][0])
1175 ChangeCh(this[c], from, to);
1181 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1182 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1183 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1184 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1185 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1186 // TODO: i18n with Array
1187 static Array<const String> compilerTypeLongNames
1189 $"GNU Compiler Collection (GCC) / GNU Make",
1190 $"Tiny C Compiler / GNU Make",
1191 $"Portable C Compiler / GNU Make",
1192 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1193 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1194 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1196 const CompilerType firstCompilerType = gcc;
1197 const CompilerType lastCompilerType = vs10;
1198 public enum CompilerType
1200 gcc, tcc, pcc, vs8, vs9, vs10;
1204 get { return this == vs8 || this == vs9 || this == vs10; }
1207 property const char *
1209 get { return OnGetString(null, null, null); }
1215 for(c = firstCompilerType; c <= lastCompilerType; c++)
1216 if(!strcmpi(value, compilerTypeNames[c]))
1223 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1224 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1225 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1226 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1227 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1229 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1231 if(this >= firstCompilerType && this <= lastCompilerType)
1234 strcpy(tempString, compilerTypeNames[this]);
1235 if(fieldData == null)
1236 return compilerTypeNames[this];
1237 else if(fieldData == (void*)1)
1238 return compilerTypeLongNames[this];
1239 else if(fieldData == (void*)2)
1240 return compilerTypeVersionString[this];
1241 else if(fieldData == (void*)3)
1242 return compilerTypeYearString[this];
1243 else if(fieldData == (void*)4)
1244 return compilerTypeProjectFileExtension[this];
1245 else if(fieldData == (void*)5)
1246 return compilerTypeSolutionFileVersionString[this];
1252 class CompilerConfig
1258 property const char * name
1260 set { delete name; if(value) name = CopyString(value); }
1261 get { return name; }
1265 Platform targetPlatform;
1267 property const char * makeCommand
1269 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1270 get { return makeCommand; }
1271 isset { return makeCommand && makeCommand[0]; }
1273 property const char * ecpCommand
1275 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1276 get { return ecpCommand; }
1277 isset { return ecpCommand && ecpCommand[0]; }
1279 property const char * eccCommand
1281 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1282 get { return eccCommand; }
1283 isset { return eccCommand && eccCommand[0]; }
1285 property const char * ecsCommand
1287 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1288 get { return ecsCommand; }
1289 isset { return ecsCommand && ecsCommand[0]; }
1291 property const char * earCommand
1293 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1294 get { return earCommand; }
1295 isset { return earCommand && earCommand[0]; }
1297 property const char * cppCommand
1299 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1300 get { return cppCommand; }
1301 isset { return cppCommand && cppCommand[0]; }
1303 property const char * ccCommand
1305 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1306 get { return ccCommand; }
1307 isset { return ccCommand && ccCommand[0]; }
1309 property const char * cxxCommand
1311 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1312 get { return cxxCommand; }
1313 isset { return cxxCommand && cxxCommand[0]; }
1315 property const char * arCommand
1317 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1318 get { return arCommand; }
1319 isset { return arCommand && arCommand[0]; }
1321 property const char * ldCommand
1323 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1324 get { return ldCommand; }
1325 isset { return ldCommand && ldCommand[0]; }
1327 property const char * objectFileExt
1329 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1330 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1331 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1333 property const char * staticLibFileExt
1335 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1336 get { return staticLibFileExt; }
1337 isset { return staticLibFileExt && staticLibFileExt[0]; }
1339 property const char * sharedLibFileExt
1341 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1342 get { return sharedLibFileExt; }
1343 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1345 property const char * executableFileExt
1347 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1348 get { return executableFileExt; }
1349 isset { return executableFileExt && executableFileExt[0]; }
1351 property const char * executableLauncher
1353 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1354 get { return executableLauncher; }
1355 isset { return executableLauncher && executableLauncher[0]; }
1357 // TODO: implement CompilerConfig::windresCommand
1361 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1363 property const char * distccHosts
1365 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1366 get { return distccHosts; }
1367 isset { return distccHosts && distccHosts[0]; }
1369 property const char * gnuToolchainPrefix
1371 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1372 get { return gnuToolchainPrefix; }
1373 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1375 property const char * sysroot
1377 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1378 get { return sysroot; }
1379 isset { return sysroot && sysroot[0]; }
1381 bool resourcesDotEar;
1383 property Array<String> includeDirs
1391 includeDirs = value;
1394 get { return includeDirs; }
1395 isset { return includeDirs.count != 0; }
1397 property Array<String> libraryDirs
1405 libraryDirs = value;
1408 get { return libraryDirs; }
1409 isset { return libraryDirs.count != 0; }
1411 property Array<String> executableDirs
1415 executableDirs.Free();
1418 delete executableDirs;
1419 executableDirs = value;
1422 get { return executableDirs; }
1423 isset { return executableDirs.count != 0; }
1425 property Array<NamedString> environmentVars
1429 environmentVars.Free();
1432 delete environmentVars;
1433 environmentVars = value;
1436 get { return environmentVars; }
1437 isset { return environmentVars.count != 0; }
1439 property Array<String> prepDirectives
1443 prepDirectives.Free();
1446 delete prepDirectives;
1447 prepDirectives = value;
1450 get { return prepDirectives; }
1451 isset { return prepDirectives.count != 0; }
1453 property Array<String> excludeLibs
1461 excludeLibs = value;
1464 get { return excludeLibs; }
1465 isset { return excludeLibs.count != 0; }
1467 property Array<String> eCcompilerFlags
1471 eCcompilerFlags.Free();
1474 delete eCcompilerFlags;
1475 eCcompilerFlags = value;
1478 get { return eCcompilerFlags; }
1479 isset { return eCcompilerFlags.count != 0; }
1481 property Array<String> compilerFlags
1485 compilerFlags.Free();
1488 delete compilerFlags;
1489 compilerFlags = value;
1492 get { return compilerFlags; }
1493 isset { return compilerFlags.count != 0; }
1495 property Array<String> cxxFlags
1506 get { return cxxFlags; }
1507 isset { return cxxFlags.count != 0; }
1509 property Array<String> linkerFlags
1517 linkerFlags = value;
1520 get { return linkerFlags; }
1521 isset { return linkerFlags.count != 0; }
1523 // json backward compatibility
1524 property const char * gccPrefix
1526 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1527 get { return gnuToolchainPrefix; }
1528 isset { return false; }
1530 property const char * execPrefixCommand
1532 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1533 get { return executableLauncher; }
1534 isset { return false; }
1536 property const char * outputFileExt
1538 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1539 get { return executableFileExt; }
1540 isset { return false; }
1543 property bool hasDocumentOutput
1547 bool result = executableFileExt && executableFileExt[0] &&
1548 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1551 isset { return false; }
1554 Array<String> includeDirs { };
1555 Array<String> libraryDirs { };
1556 Array<String> executableDirs { };
1557 // TODO: Can JSON parse and serialize maps?
1558 //EnvironmentVariables { };
1559 Array<NamedString> environmentVars { };
1560 Array<String> prepDirectives { };
1561 Array<String> excludeLibs { };
1562 Array<String> eCcompilerFlags { };
1563 Array<String> compilerFlags { };
1564 Array<String> cxxFlags { };
1565 Array<String> linkerFlags { };
1577 char * objectFileExt;
1578 char * staticLibFileExt;
1579 char * sharedLibFileExt;
1580 char * executableFileExt;
1581 char * executableLauncher;
1583 char * gnuToolchainPrefix;
1587 struct { Array<String> includes, libraries, executables; };
1588 Array<String> dirs[DirTypes];
1603 delete objectFileExt;
1604 delete staticLibFileExt;
1605 delete sharedLibFileExt;
1606 delete executableFileExt;
1608 delete executableLauncher;
1610 delete gnuToolchainPrefix;
1612 if(environmentVars) environmentVars.Free();
1613 if(includeDirs) { includeDirs.Free(); }
1614 if(libraryDirs) { libraryDirs.Free(); }
1615 if(executableDirs) { executableDirs.Free(); }
1616 if(prepDirectives) { prepDirectives.Free(); }
1617 if(excludeLibs) { excludeLibs.Free(); }
1618 if(compilerFlags) { compilerFlags.Free(); }
1619 if(cxxFlags) { cxxFlags.Free(); }
1620 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1621 if(linkerFlags) { linkerFlags.Free(); }
1624 int OnCompare(CompilerConfig b)
1628 !(result = type.OnCompare(b.type)) &&
1629 !(result = targetPlatform.OnCompare(b.targetPlatform)) &&
1630 !(result = numJobs.OnCompare(b.numJobs)) &&
1631 !(result = ccacheEnabled.OnCompare(b.ccacheEnabled)) &&
1632 !(result = distccEnabled.OnCompare(b.distccEnabled)) &&
1633 !(result = resourcesDotEar.OnCompare(b.resourcesDotEar)) &&
1634 !(result = noStripTarget.OnCompare(b.noStripTarget))
1638 !(result = name.OnCompare(b.name)) &&
1639 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1640 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1641 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1642 !(result = earCommand.OnCompare(b.earCommand)) &&
1643 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1644 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1645 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1646 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1647 !(result = arCommand.OnCompare(b.arCommand)) &&
1648 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1649 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1650 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1651 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1652 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1653 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1654 !(result = sysroot.OnCompare(b.sysroot)));
1657 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1658 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1659 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1660 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1661 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1662 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1663 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1664 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1665 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1666 !(result = linkerFlags.OnCompare(b.linkerFlags)));
1671 CompilerConfig Copy()
1704 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1705 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1706 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1707 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1708 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1709 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1710 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1711 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
1712 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1713 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1719 CompilerConfig ::read(const char * path)
1721 CompilerConfig d = null;
1722 readConfigFile(path, class(CompilerConfig), &d);
1726 void write(IDESettingsContainer settingsContainer)
1728 char dir[MAX_LOCATION];
1729 char path[MAX_LOCATION];
1730 const char * settingsFilePath = settingsContainer.settingsFilePath;
1731 settingsContainer.getConfigFilePath(path, _class, dir, name);
1732 if(FileExists(settingsFilePath) && !FileExists(dir))
1735 if(!FileExists(dir))
1736 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1738 writeConfigFile(path, _class, this);
1742 class CompilerConfigs : List<CompilerConfig>
1744 CompilerConfig GetCompilerConfig(const String compilerName)
1746 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
1747 CompilerConfig compilerConfig = null;
1748 for(compiler : this)
1750 if(!strcmp(compiler.name, name))
1752 compilerConfig = compiler;
1756 if(!compilerConfig && count)
1757 compilerConfig = this[0];
1760 incref compilerConfig;
1761 if(compilerConfig._refCount == 1)
1762 incref compilerConfig;
1764 return compilerConfig;
1767 void ensureDefaults()
1769 // Ensure we have a default compiler
1770 CompilerConfig defaultCompiler = GetCompilerConfig(defaultCompilerName);
1771 if(!defaultCompiler)
1773 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
1774 Insert(null, defaultCompiler);
1775 defaultCompiler = null;
1777 delete defaultCompiler;
1781 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
1782 ccfg.ecpCommand = ecpDefaultCommand;
1783 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
1784 ccfg.eccCommand = eccDefaultCommand;
1785 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
1786 ccfg.ecsCommand = ecsDefaultCommand;
1787 if(!ccfg.earCommand || !ccfg.earCommand[0])
1788 ccfg.earCommand = earDefaultCommand;
1789 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
1790 ccfg.cppCommand = cppDefaultCommand;
1791 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
1792 ccfg.ccCommand = ccDefaultCommand;
1793 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
1794 ccfg.cxxCommand = cxxDefaultCommand;
1795 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
1796 ccfg.ldCommand = ldDefaultCommand;*/
1797 if(!ccfg.arCommand || !ccfg.arCommand[0])
1798 ccfg.arCommand = arDefaultCommand;
1799 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
1800 ccfg.objectFileExt = objectDefaultFileExt;
1801 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
1802 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
1803 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
1804 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
1805 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
1806 ccfg.executableFileExt = outputDefaultFileExt;*/
1807 if(!ccfg._refCount) incref ccfg;
1811 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
1813 AVLTree<String> list { };
1817 for(occfg : oldConfigs; !strcmp(ccfg.name, occfg.name))
1820 if(ccfg.OnCompare(occfg))
1821 list.Add(CopyString(ccfg.name));
1825 list.Add(CopyString(ccfg.name));
1830 bool read(IDESettingsContainer settingsContainer)
1832 if(settingsContainer.settingsFilePath)
1834 char dir[MAX_LOCATION];
1835 char path[MAX_LOCATION];
1836 Class _class = class(CompilerConfig);
1837 settingsContainer.getConfigFilePath(path, _class, dir, null);
1840 AVLTree<const String> addedConfigs { };
1841 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
1842 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
1844 settingsContainer.compilerConfigs = this; // Merge IDEConfigHolder / IDESettingsContainer?
1845 if(it.Index("Default", false))
1847 CompilerConfig ccfg = it.data;
1849 addedConfigs.Add(ccfg.name);
1851 for(ccfg : compilerConfigsByName)
1853 if(!addedConfigs.Find(ccfg.name))
1856 addedConfigs.Add(ccfg.name);
1859 delete addedConfigs;
1861 compilerConfigsByName.Free();
1862 delete compilerConfigsByName;
1863 settingsContainer.onLoadCompilerConfigs();
1870 void write(IDESettingsContainer settingsContainer, AVLTree<String> cfgsToWrite)
1872 char dir[MAX_LOCATION];
1873 char path[MAX_LOCATION];
1874 Map<String, String> paths;
1875 settingsContainer.getConfigFilePath(path, class(CompilerConfig), dir, null);
1876 paths = getCompilerConfigFilePathsByName(dir);
1878 MapIterator<String, String> it { map = paths };
1881 CompilerConfig ccfg = c;
1882 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
1883 ccfg.write(settingsContainer);
1884 if(it.Index(ccfg.name, false))
1893 const char * path = p;
1901 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1902 struct LanguageOption
1905 const String bitmap;
1909 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1914 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
1916 Bitmap icon = res ? res.bitmap : null;
1919 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
1920 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
1924 Array<LanguageOption> languages
1926 { "English", ":countryCode/gb.png", "" },
1927 { "汉语", ":countryCode/cn.png", "zh_CN" },
1928 { "Español", ":countryCode/es.png", "es" },
1929 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
1930 { "Русский (43%)", ":countryCode/ru.png", "ru" },
1931 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
1932 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
1933 { "मराठी (10%)", ":countryCode/in.png", "mr" },
1934 { "Hebrew (8%)", ":countryCode/il.png", "he" },
1935 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
1938 const String GetLanguageString()
1940 char * dot, * colon;
1941 static char lang[256];
1942 const String language = getenv("ECERE_LANGUAGE");
1943 if(!language) language = getenv("LANGUAGE");
1944 if(!language) language = getenv("LC_ALL");
1945 if(!language) language = getenv("LC_MESSAGES");
1946 if(!language) language = getenv("LANG");
1947 if(!language) language = "";
1948 if(language && (colon = strchr(language, ':')))
1950 if(lang != language)
1951 strncpy(lang, language, sizeof(lang));
1952 lang[sizeof(lang)-1] = 0;
1953 lang[colon - language] = 0;
1956 if(language && (dot = strchr(language, '.')))
1958 if(lang != language)
1959 strncpy(lang, language, sizeof(lang));
1960 lang[sizeof(lang)-1] = 0;
1961 lang[dot - language] = 0;
1967 void setEcereLanguageInWinRegEnvironment(const char * languageCode)
1971 uint16 wLanguage[256];
1975 RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1978 UTF8toUTF16Buffer(languageCode, wLanguage, sizeof(wLanguage) / sizeof(uint16));
1979 RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
1985 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
1987 bool restart = true;
1988 String command = null;
1989 int arg0Len = (int)strlen(app.argv[0]);
2001 for(w = ide.firstChild; w; w = w.next)
2003 if(w.isActiveClient && w.isDocument)
2005 if(!w.CloseConfirmation(true))
2014 if(!projectView.CloseConfirmation(true))
2016 if(projectView.fileName)
2018 const char * name = projectView.fileName;
2021 for(j = 0; (ch = name[j]); j++)
2022 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2026 command = new char[len + 1];
2028 strcpy(command, app.argv[0]);
2030 if(projectView.fileName)
2032 strcat(command, " ");
2034 ReplaceSpaces(command + len, projectView.fileName);
2039 for(w = ide.firstChild; w; w = w.next)
2040 if(w.isActiveClient && w.isDocument)
2041 w.modifiedDocument = false;
2042 projectView.modifiedDocument = false;
2047 for(w = ide.firstChild; w; w = w.next)
2049 if(w.isActiveClient && w.isDocument)
2051 if(!w.CloseConfirmation(true))
2058 const char * name = w.fileName;
2060 for(j = 0; (ch = name[j]); j++)
2061 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2068 command = new char[len + 1];
2069 strcpy(command, app.argv[0]);
2072 for(w = ide.firstChild; w; w = w.next)
2074 if(w.isActiveClient && w.isDocument)
2076 const char * name = w.fileName;
2079 strcat(command, " ");
2081 ReplaceSpaces(command + len, name);
2082 len = (int)strlen(command);
2089 for(w = ide.firstChild; w; w = w.next)
2090 if(w.isActiveClient && w.isDocument)
2091 w.modifiedDocument = false;
2096 settings.language = code;
2097 settingsContainer.Save();
2099 setEcereLanguageInWinRegEnvironment(code);
2101 if(eClass_IsDerived(app._class, class(GuiApplication)))
2103 GuiApplication guiApp = (GuiApplication)app;
2104 guiApp.desktop.Destroy(0);
2111 for(i = 1; i < app.argc; i++)
2113 const char * arg = app.argv[i];
2115 for(j = 0; (ch = arg[j]); j++)
2116 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2119 command = new char[len + 1];
2120 strcpy(command, app.argv[0]);
2122 for(i = 1; i < app.argc; i++)
2124 strcat(command, " ");
2126 ReplaceSpaces(command + len, app.argv[i]);
2127 len = (int)strlen(command);
2133 SetEnvironment("ECERE_LANGUAGE", code);
2135 ExecuteWait(command);