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"
23 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
28 IDEConfigHolder ideConfig { };
30 IDESettings ideSettings;
32 IDESettingsContainer settingsContainer
34 dataOwner = &ideSettings;
35 dataClass = class(IDESettings);
40 enum DirTypes { includes, libraries, executables };
42 define defaultCompilerName = "Default";
44 define defaultObjDirExpression = "obj/$(CONFIG).$(PLATFORM)$(COMPILER_SUFFIX)$(DEBUG_SUFFIX)";
46 const char * settingsDirectoryNames[DirTypes] =
53 // This function cannot accept same pointer for source and output
54 // todo: rename ReplaceSpaces to EscapeSpaceAndSpecialChars or something
55 void ReplaceSpaces(char * output, const char * source)
60 for(c = 0, dc = 0; (ch = source[c]); c++, dc++)
62 if(ch == ' ') output[dc++] = '\\';
63 if(ch == '\"') output[dc++] = '\\';
64 if(ch == '&') output[dc++] = '\\';
67 if(ch == '(' || ch == ')') output[dc++] = '\\';
78 enum GlobalSettingsChange { none, editorSettings, projectOptions, compilerSettings };
80 enum PathRelationship { unrelated, identical, siblings, subPath, parentPath, insuficientInput, pathEmpty, toEmpty, pathNull, toNull, bothEmpty, bothNull };
81 PathRelationship eString_PathRelated(const char * path, const char * to, char * pathDiff)
83 PathRelationship result;
84 if(pathDiff) *pathDiff = '\0';
85 if(path && *path && to && *to)
87 char toPart[MAX_FILENAME], toRest[MAX_LOCATION];
88 char pathPart[MAX_FILENAME], pathRest[MAX_LOCATION];
90 strcpy(pathRest, path);
91 for(; toRest[0] && pathRest[0];)
93 SplitDirectory(toRest, toPart, toRest);
94 SplitDirectory(pathRest, pathPart, pathRest);
95 if(!fstrcmp(pathPart, toPart)) result = siblings;
98 if(result == siblings)
100 if(!*toRest && !*pathRest) result = identical;
101 else if(!*pathRest) result = parentPath;
102 else result = subPath;
103 if(pathDiff && result != identical) strcpy(pathDiff, *pathRest == '\0' ? toRest : pathRest);
105 else result = unrelated;
111 if(!*path && !*to) result = bothEmpty;
112 else if(!*path) result = pathEmpty;
113 else result = toEmpty;
115 else if(!path && !to) result = bothNull;
116 else if(!path) result = pathNull;
117 else result = toNull;
122 char * CopyValidateMakefilePath(const char * path)
124 const int map[] = { 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 7 };
125 const char * vars[] = { "$(MODULE)", "$(CONFIG)", "$(PLATFORM)", "$(COMPILER)", "$(TARGET)", "$(COMPILER_SUFFIX)", "$(DEBUG_SUFFIX)", "$(PROJECT)", "$(CONFIGURATION)", "$(TARGET_PLATFORM)",(char *)0 };
131 len = (int)strlen(path);
132 copy = CopyString(path);
138 Array<const char *> parts { };
145 for(v=0; vars[v]; v++)
147 if(SearchString(&tmp[c], 0, vars[v], false, false) == &tmp[c])
151 parts.Add(vars[map[v]]);
152 c += strlen(vars[v]);
166 for(c=0; c<parts.count; c++) len += strlen(parts[c]);
167 copy = new char[++len];
169 for(c=0; c<parts.count; c++) strcat(copy, parts[c]);
180 void ValidPathBufCopy(char *output, const char *input)
183 bool volumePath = false;
185 strcpy(output, input);
186 TrimLSpaces(output, output);
187 TrimRSpaces(output, output);
188 MakeSystemPath(output);
190 if(output[0] && output[1] == ':')
197 const char * chars = "*|:\",<>?";
198 char ch, * s = output, * o = output;
199 while((ch = *s++)) { if(!strchr(chars, ch)) *o++ = ch; }
203 if(volumePath && output[0])
208 void RemoveTrailingPathSeparator(char *path)
211 len = (int)strlen(path);
212 if(len>1 && path[len-1] == DIR_SEP)
216 void BasicValidatePathBoxPath(PathBox pathBox)
218 char path[MAX_LOCATION];
219 ValidPathBufCopy(path, pathBox.path);
220 RemoveTrailingPathSeparator(path);
224 CompilerConfig MakeDefaultCompiler(const char * name, bool readOnly)
226 CompilerConfig defaultCompiler
244 incref defaultCompiler;
245 return defaultCompiler;
248 //#define SETTINGS_TEST
250 define settingsDir = ".ecereIDE-SettingsTest";
251 define ideSettingsName = "ecereIDE-SettingsTest";
253 define settingsDir = ".ecereIDE";
254 define ideSettingsName = "ecereIDE";
257 class IDEConfigHolder
259 CompilerConfigs compilers { };
260 RecentFiles recentFiles { };
261 RecentWorkspaces recentWorkspaces { };
263 property CompilerConfigs compilers
265 set { compilers.Free(); delete compilers; compilers = value; }
266 get { return compilers; }
268 property RecentFiles recentFiles
270 set { recentFiles.Free(); delete recentFiles; recentFiles = value; }
271 get { return recentFiles; }
273 property RecentWorkspaces recentProjects
275 set { recentWorkspaces.Free(); delete recentWorkspaces; recentWorkspaces = value; }
276 get { return recentWorkspaces; }
283 recentWorkspaces.Free();
286 void forcePathSeparatorStyle(bool unixStyle)
290 from = '\\', to = '/';
292 from = '/', to = '\\';
293 recentFiles.changeChar(from, to);
294 recentWorkspaces.changeChar(from, to);
298 class IDESettingsContainer : GlobalSettings
300 property bool useNewConfigurationFiles
306 settingsContainer.driver = "ECON";
307 settingsName = "config";
308 settingsExtension = "econ";
309 settingsDirectory = settingsDir;
313 settingsContainer.driver = "JSON";
314 settingsName = ideSettingsName;
315 settingsExtension = null;
316 settingsDirectory = null;
321 char moduleLocation[MAX_LOCATION];
323 FileMonitor recentFilesMonitor
325 this, fileChange = { modified = true };
327 bool OnFileNotify(FileChange action, const char * param)
330 recentFilesMonitor.StopMonitoring();
331 f = FileOpen(recentFilesMonitor.fileName, read);
336 for(c = 0; c < 10 && !(locked = f.Lock(shared, 0, 0, false)); c++) ecere::sys::Sleep(0.01);
345 FileMonitor recentProjectsMonitor
347 this, fileChange = { modified = true };
349 bool OnFileNotify(FileChange action, const char * param)
352 recentProjectsMonitor.StopMonitoring();
353 f = FileOpen(recentProjectsMonitor.fileName, read);
358 for(c = 0; c < 10 && !(locked = f.Lock(shared, 0, 0, false)); c++) ecere::sys::Sleep(0.01);
359 RecentWorkspaces::read();
369 FileSize settingsFileSize;
371 IDESettingsContainer()
373 char path[MAX_LOCATION];
375 LocateModule(null, moduleLocation);
376 strcpy(path, moduleLocation);
377 StripLastDirectory(moduleLocation, moduleLocation);
378 ChangeCh(moduleLocation, '\\', '/');
379 // PortableApps.com directory structure
380 if((start = strstr(path, "\\App\\EcereSDK\\bin\\ide.exe")))
382 char configFilePath[MAX_LOCATION];
383 char defaultConfigFilePath[MAX_LOCATION];
387 strcpy(configFilePath, path);
388 PathCat(configFilePath, "Data");
389 PathCat(configFilePath, ideSettingsName);
390 ChangeExtension(configFilePath, "ini", configFilePath);
392 strcpy(defaultConfigFilePath, path);
393 PathCat(defaultConfigFilePath, "App");
394 PathCat(defaultConfigFilePath, "DefaultData");
395 PathCat(defaultConfigFilePath, ideSettingsName);
396 ChangeExtension(defaultConfigFilePath, "ini", defaultConfigFilePath);
398 if(FileExists(defaultConfigFilePath))
400 if(!FileExists(configFilePath))
402 File f = FileOpen(defaultConfigFilePath, read);
403 f.CopyTo(configFilePath);
407 PathCat(path, "Data");
408 // the forced settings location will only be
409 // used if the running ide's path matches
410 // the PortableApps.com directory structure
411 // and the default ini file is found in
412 // the DefaultData directory
413 settingsLocation = path;
419 void OnAskReloadSettings()
421 FileSize newSettingsFileSize;
423 if(OpenAndLock(&newSettingsFileSize))
425 if((double)settingsFileSize - (double)newSettingsFileSize < 2048)
429 GuiApplication app = ((GuiApplication)__thisModule.application);
431 for(w = app.desktop.firstChild; w && (!w.created || !w.visible); w = w.next);
435 MessageBox { master = w, type = ok, isModal = true,
436 creationActivation = flash,
437 text = "Global Settings Modified Externally",
438 contents = "The global settings were modified by another process and a drastic shrinking of the settings file was detected.\n"
439 "The new settings will not be loaded to prevent loss of your ide settings.\n"
440 "Please check your settings file and make sure to save this IDE's global settings if your settings file has been compromised."
446 SettingsIOResult Load()
449 SettingsIOResult result;
450 useNewConfigurationFiles = true;
451 result = GlobalSettings::Load();
452 data = (IDESettings)this.data;
454 if(result == fileNotFound)
457 useNewConfigurationFiles = false;
458 result = GlobalSettings::Load();
460 data = (IDESettings)this.data;
463 this.data = IDESettings { };
465 *dataOwner = this.data;
467 if(result == fileNotCompatibleWithDriver)
470 OldIDESettings oldSettings { };
472 loaded = oldSettings.Load() == success;
476 data = (IDESettings)this.data;
478 for(c : oldSettings.compilerConfigs)
479 data.compilerConfigs.Add(c.Copy());
481 for(s : oldSettings.recentFiles) data.recentFiles.Add(s);
482 for(s : oldSettings.recentProjects) data.recentProjects.Add(s);
484 data.docDir = oldSettings.docDir;
485 data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
486 data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
487 data.useFreeCaret = oldSettings.useFreeCaret;
488 data.showLineNumbers = oldSettings.showLineNumbers;
489 data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
490 delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
491 data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
492 data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
499 if(result == fileNotFound || !data)
501 data = (IDESettings)this.data;
502 data.useFreeCaret = false; //true;
503 data.showLineNumbers = true;
504 data.caretFollowsScrolling = false; //true;
509 FileGetSize(settingsFilePath, &settingsFileSize);
510 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
511 data.ManagePortablePaths(moduleLocation, true);
512 data.ForcePathSeparatorStyle(true);
514 // Import from previous ecereIDE settings
517 data.compilerConfigs.ensureDefaults();
518 data.compilerConfigs.write(null);
519 data.compilerConfigs.Free();
521 data.recentFiles.write();
522 data.recentFiles.Free();
524 data.recentProjects.write();
525 data.recentProjects.Free();
530 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
531 globalSettingsDialog.ideSettings = data;
536 SettingsIOResult Save()
538 SettingsIOResult result;
540 useNewConfigurationFiles = true;
541 data = (IDESettings)this.data;
542 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
543 data.ManagePortablePaths(moduleLocation, false);
544 data.ForcePathSeparatorStyle(true);
546 settingsFilePath = null;
547 result = GlobalSettings::Save();
548 if(result != success)
549 PrintLn("Error saving IDE settings");
552 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
553 data.ManagePortablePaths(moduleLocation, true);
556 FileGetSize(settingsFilePath, &settingsFileSize);
562 static Map<String, String> getCompilerConfigFilePathsByName(const char * path)
564 Map<String, String> map { };
565 FileListing fl { path, extensions = "econ" };
568 if(fl.stats.attribs.isFile)
570 char name[MAX_FILENAME];
571 char * path = CopyString(fl.path);
573 GetLastDirectory(path, name);
574 StripExtension(name);
581 static Map<String, CompilerConfig> getCompilerConfigsByName(const char * path)
583 Map<String, CompilerConfig> map { };
584 FileListing fl { path, extensions = "econ" };
587 if(fl.stats.attribs.isFile)
589 char name[MAX_FILENAME];
590 char * path = CopyString(fl.path);
592 GetLastDirectory(path, name);
593 StripExtension(name);
595 CompilerConfig ccfg = CompilerConfig::read(path);
605 static void getConfigFilePath(char * path, Class _class, char * dir, const char * configName)
608 strcpy(path, settingsContainer.settingsFilePath);
609 StripLastDirectory(path, path);
610 if(settingsContainer.oldConfig)
611 PathCatSlash(path, settingsDir);
612 if(_class == class(CompilerConfig))
614 PathCatSlash(path, "compilerConfigs");
619 PathCatSlash(path, configName);
620 strcat(path, ".econ");
623 else if(_class == class(RecentFilesData))
624 PathCatSlash(path, "recentFiles.econ");
625 else if(_class == class(RecentWorkspacesData))
626 PathCatSlash(path, "recentWorkspaces.econ");
629 static SettingsIOResult writeConfigFile(const char * path, Class dataType, void * data)
631 SettingsIOResult result = error;
632 SafeFile sf = SafeFile::open(path, write);
635 WriteECONObject(sf.file, dataType, data, 0);
641 PrintLn($"error: could not safely open file for writing configuration: ", path);
645 static SettingsIOResult readConfigFile(const char * path, Class dataType, void ** data)
647 SettingsIOResult result = error;
649 if(!FileExists(path))
650 result = fileNotFound;
651 else if((sf = SafeFile::open(path, read)))
653 JSONResult jsonResult;
655 ECONParser parser { f = sf.file };
656 sf.file.Seek(0, start);
657 jsonResult = parser.GetObject(dataType, data);
658 if(jsonResult != success)
662 if(jsonResult == success)
666 result = fileNotCompatibleWithDriver;
667 PrintLn($"error: could not parse configuration file: ", path);
678 char path[MAX_LOCATION];
679 char tmp[MAX_LOCATION];
681 SafeFile ::open(const char * path, FileOpenMode mode)
683 SafeFile result = null;
684 if(mode == write || mode == read)
686 SafeFile sf { mode = mode };
689 FileLock lockType = mode == write ? exclusive : shared;
691 strcpy(sf.path, path);
692 strcpy(sf.tmp, path);
693 strcat(sf.tmp, ".tmp");
694 if(mode == write && FileExists(sf.tmp).isFile)
699 sf.file = FileOpen(sf.tmp, readWrite);
702 sf.file = FileOpen(sf.tmp, writeRead);
706 sf.file = FileOpen(sf.tmp, readWrite);
711 sf.file = FileOpen(path, mode);
714 for(c = 0; c < 10 && !(locked = sf.file.Lock(lockType, 0, 0, false)); c++) Sleep(0.01);
717 else if(mode == write)
718 PrintLn($"warning: SafeFile::open: unable to obtain exclusive lock on temporary file for writing: ", sf.tmp);
720 PrintLn($"warning: SafeFile::open: unable to obtain shared lock on file for reading: ", path);
722 else if(mode == write)
723 PrintLn($"warning: SafeFile::open: unable to open temporary file for writing: ", sf.tmp);
725 PrintLn($"warning: SafeFile::open: unable to open file for reading: ", path);
731 PrintLn($"warning: SafeFile::open: does not yet support FileOpenMode::", mode);
737 if(file && mode == write)
740 File f = FileOpen(path, readWrite);
743 f = FileOpen(path, writeRead);
747 f = FileOpen(path, readWrite);
753 for(c = 0; c < 10 && !(locked = f.Lock(exclusive, 0,0, false)); c++) Sleep(0.01);
757 f.Unlock(0,0, false);
759 file.Unlock(0,0, false);
762 for(c = 0; c < 10; c++)
764 if(MoveFileEx(tmp, path, { true, true }))
773 PrintLn($"warning: SafeFile::sync: failed to lock file for ", mode);
784 file.Unlock(0,0, false);
790 class RecentFilesData
793 RecentFiles recentFiles;
796 class RecentWorkspacesData
799 RecentWorkspaces recentWorkspaces;
802 class IDESettings : GlobalSettingsData
805 property CompilerConfigs compilerConfigs
807 set { if(settingsContainer.oldConfig) { if(compilerConfigs) compilerConfigs.Free(); delete compilerConfigs; if(value) compilerConfigs = value; } }
808 get { return compilerConfigs; }
809 isset { return false; }
811 property RecentFiles recentFiles
813 set { if(recentFiles) recentFiles.Free(); delete recentFiles; if(value) recentFiles = value; }
814 get { return recentFiles; }
815 isset { return false; }
817 property RecentWorkspaces recentProjects
819 set { if(recentProjects) recentProjects.Free(); delete recentProjects; if(value) recentProjects = value; }
820 get { return recentProjects; }
821 isset { return false; }
823 property const char * docDir
825 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
826 get { return docDir ? docDir : ""; }
827 isset { return docDir && docDir[0]; }
829 property const char * ideFileDialogLocation
831 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
832 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
833 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
835 property const char * ideProjectFileDialogLocation
837 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
838 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
839 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
842 bool showLineNumbers;
843 bool caretFollowsScrolling;
844 char * displayDriver;
846 // TODO: Classify settings
847 //EditorSettings editor { };
849 property const char * projectDefaultTargetDir
851 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
852 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
853 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
855 property const char * projectDefaultIntermediateObjDir
857 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
858 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
859 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
862 property const char * compilerConfigsDir
864 set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
865 get { return compilerConfigsDir ? compilerConfigsDir : ""; }
866 isset { return compilerConfigsDir && compilerConfigsDir[0]; }
869 property const char * defaultCompiler
871 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
872 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
873 isset { return defaultCompiler && defaultCompiler[0]; }
876 property const String language
881 language = CopyString(value);
883 get { return language; }
884 isset { return language != null; }
888 CompilerConfigs compilerConfigs { };
890 char * ideFileDialogLocation;
891 char * ideProjectFileDialogLocation;
892 char * projectDefaultTargetDir;
893 char * projectDefaultIntermediateObjDir;
894 char * compilerConfigsDir;
895 char * defaultCompiler;
897 RecentFiles recentFiles { };
898 RecentWorkspaces recentProjects { };
902 compilerConfigs.Free();
903 delete compilerConfigs;
904 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
905 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
908 delete projectDefaultTargetDir;
909 delete projectDefaultIntermediateObjDir;
910 delete compilerConfigsDir;
911 delete defaultCompiler;
914 delete ideFileDialogLocation;
915 delete ideProjectFileDialogLocation;
916 delete displayDriver;
919 void ForcePathSeparatorStyle(bool unixStyle)
923 from = '\\', to = '/';
925 from = '/', to = '\\';
926 if(compilerConfigs && compilerConfigs.count)
929 for(config : compilerConfigs)
931 if(config.includeDirs && config.includeDirs.count)
933 for(i = 0; i < config.includeDirs.count; i++)
935 if(config.includeDirs[i] && config.includeDirs[i][0])
936 ChangeCh(config.includeDirs[i], from, to);
939 if(config.libraryDirs && config.libraryDirs.count)
941 for(i = 0; i < config.libraryDirs.count; i++)
943 if(config.libraryDirs[i] && config.libraryDirs[i][0])
944 ChangeCh(config.libraryDirs[i], from, to);
947 if(config.executableDirs && config.executableDirs.count)
949 for(i = 0; i < config.executableDirs.count; i++)
951 if(config.executableDirs[i] && config.executableDirs[i][0])
952 ChangeCh(config.executableDirs[i], from, to);
957 recentFiles.changeChar(from, to);
958 recentProjects.changeChar(from, to);
959 if(docDir && docDir[0])
960 ChangeCh(docDir, from, to);
961 if(ideFileDialogLocation && ideFileDialogLocation[0])
962 ChangeCh(ideFileDialogLocation, from, to);
963 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
964 ChangeCh(ideProjectFileDialogLocation, from, to);
966 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
967 ChangeCh(projectDefaultTargetDir, from, to);
968 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
969 ChangeCh(projectDefaultIntermediateObjDir, from, to);
971 if(compilerConfigsDir && compilerConfigsDir[0])
972 ChangeCh(compilerConfigsDir, from, to);
975 void ManagePortablePaths(char * location, bool makeAbsolute)
978 if(compilerConfigs && compilerConfigs.count)
980 for(config : compilerConfigs)
983 for(t = 0; t < DirTypes::enumSize; t++)
985 Array<String> dirs = null;
986 if(t == executables) dirs = config.executableDirs;
987 else if(t == includes) dirs = config.includeDirs;
988 else if(t == libraries) dirs = config.libraryDirs;
989 if(dirs && dirs.count)
991 for(c = 0; c < dirs.count; c++)
993 if(dirs[c] && dirs[c][0])
994 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
1000 if(recentFiles && recentFiles.count)
1002 for(c = 0; c < recentFiles.count; c++)
1004 if(recentFiles[c] && recentFiles[c][0])
1005 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
1008 if(recentProjects && recentProjects.count)
1010 for(c = 0; c < recentProjects.count; c++)
1012 if(recentProjects[c] && recentProjects[c][0])
1013 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
1016 if(docDir && docDir[0])
1017 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
1018 if(ideFileDialogLocation && ideFileDialogLocation[0])
1019 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
1020 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1021 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
1023 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1024 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
1025 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1026 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
1028 if(compilerConfigsDir && compilerConfigsDir[0])
1029 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
1032 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
1037 char p[MAX_LOCATION];
1038 strcpy(p, location);
1039 PathCatSlash(p, path);
1041 output = CopyString(p);
1045 PathRelationship rel = eString_PathRelated(path, location, null);
1046 if(rel == subPath || rel == identical)
1048 char p[MAX_LOCATION];
1049 MakePathRelative(path, location, p);
1050 if(!*p) strcpy(p, "./");
1051 else ChangeCh(p, '\\', '/');
1053 output = CopyString(p);
1062 class RecentFiles : RecentPaths
1071 char path[MAX_LOCATION];
1072 RecentFilesData d = null;
1073 Class _class = class(RecentFilesData);
1074 getConfigFilePath(path, _class, null, null);
1075 readConfigFile(path, _class, &d);
1076 if(d && d.recentFiles && d.recentFiles.count)
1078 ideConfig.recentFiles = d.recentFiles;
1079 d.recentFiles = null;
1080 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1081 ide.updateRecentFilesMenu();
1085 settingsContainer.recentFilesMonitor.fileName = path;
1086 settingsContainer.recentFilesMonitor.StartMonitoring();
1091 char path[MAX_LOCATION];
1092 RecentFilesData d { };
1093 Class _class = class(RecentFilesData);
1094 getConfigFilePath(path, _class, null, null);
1095 d.recentFiles = this;
1096 writeConfigFile(path, _class, d);
1097 d.recentFiles = null;
1102 class RecentWorkspaces : RecentPaths
1111 char path[MAX_LOCATION];
1112 RecentWorkspacesData d = null;
1113 Class _class = class(RecentWorkspacesData);
1114 getConfigFilePath(path, _class, null, null);
1115 readConfigFile(path, _class, &d);
1116 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1118 ideConfig.recentProjects = d.recentWorkspaces;
1119 d.recentWorkspaces = null;
1120 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1121 ide.updateRecentProjectsMenu();
1124 settingsContainer.recentProjectsMonitor.fileName = path;
1125 settingsContainer.recentProjectsMonitor.StartMonitoring();
1131 char path[MAX_LOCATION];
1132 RecentWorkspacesData d { };
1133 Class _class = class(RecentWorkspacesData);
1134 getConfigFilePath(path, _class, null, null);
1135 d.recentWorkspaces = this;
1136 writeConfigFile(path, _class, d);
1137 d.recentWorkspaces = null;
1142 class RecentPaths : Array<String>
1144 virtual void onAdd();
1146 IteratorPointer Add(T value)
1149 char * filePath = (char *)value;
1150 ChangeCh(filePath, '\\', '/');
1151 for(c = 0; c < count; c++)
1153 if(this[c] && !fstrcmp(this[c], filePath))
1155 Delete((void *)&this[c]);
1159 return Array::Add((T)filePath);
1162 IteratorPointer addRecent(const String value)
1165 char * filePath = CopyString((char *)value);
1167 ChangeCh(filePath, '\\', '/');
1168 for(c = 0; c < count; c++)
1170 if(this[c] && !fstrcmp(this[c], filePath))
1172 Delete((void *)&this[c]);
1176 while(count >= MaxRecent)
1178 ip = Insert(null, filePath);
1183 void changeChar(char from, char to)
1188 for(c = 0; c < count; c++)
1190 if(this[c] && this[c][0])
1191 ChangeCh(this[c], from, to);
1197 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1198 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1199 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1200 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1201 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1202 // TODO: i18n with Array
1203 static Array<const String> compilerTypeLongNames
1205 $"GNU Compiler Collection (GCC) / GNU Make",
1206 $"Tiny C Compiler / GNU Make",
1207 $"Portable C Compiler / GNU Make",
1208 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1209 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1210 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1212 const CompilerType firstCompilerType = gcc;
1213 const CompilerType lastCompilerType = vs10;
1214 public enum CompilerType
1216 gcc, tcc, pcc, vs8, vs9, vs10;
1220 get { return this == vs8 || this == vs9 || this == vs10; }
1223 property const char *
1225 get { return OnGetString(null, null, null); }
1231 for(c = firstCompilerType; c <= lastCompilerType; c++)
1232 if(!strcmpi(value, compilerTypeNames[c]))
1239 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1240 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1241 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1242 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1243 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1245 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1247 if(this >= firstCompilerType && this <= lastCompilerType)
1250 strcpy(tempString, compilerTypeNames[this]);
1251 if(fieldData == null)
1252 return compilerTypeNames[this];
1253 else if(fieldData == (void*)1)
1254 return compilerTypeLongNames[this];
1255 else if(fieldData == (void*)2)
1256 return compilerTypeVersionString[this];
1257 else if(fieldData == (void*)3)
1258 return compilerTypeYearString[this];
1259 else if(fieldData == (void*)4)
1260 return compilerTypeProjectFileExtension[this];
1261 else if(fieldData == (void*)5)
1262 return compilerTypeSolutionFileVersionString[this];
1268 class CompilerConfig
1274 property const char * name
1276 set { delete name; if(value) name = CopyString(value); }
1277 get { return name; }
1281 Platform targetPlatform;
1283 property const char * makeCommand
1285 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1286 get { return makeCommand; }
1287 isset { return makeCommand && makeCommand[0]; }
1289 property const char * ecpCommand
1291 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1292 get { return ecpCommand; }
1293 isset { return ecpCommand && ecpCommand[0]; }
1295 property const char * eccCommand
1297 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1298 get { return eccCommand; }
1299 isset { return eccCommand && eccCommand[0]; }
1301 property const char * ecsCommand
1303 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1304 get { return ecsCommand; }
1305 isset { return ecsCommand && ecsCommand[0]; }
1307 property const char * earCommand
1309 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1310 get { return earCommand; }
1311 isset { return earCommand && earCommand[0]; }
1313 property const char * cppCommand
1315 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1316 get { return cppCommand; }
1317 isset { return cppCommand && cppCommand[0]; }
1319 property const char * ccCommand
1321 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1322 get { return ccCommand; }
1323 isset { return ccCommand && ccCommand[0]; }
1325 property const char * cxxCommand
1327 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1328 get { return cxxCommand; }
1329 isset { return cxxCommand && cxxCommand[0]; }
1331 property const char * arCommand
1333 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1334 get { return arCommand; }
1335 isset { return arCommand && arCommand[0]; }
1337 property const char * ldCommand
1339 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1340 get { return ldCommand; }
1341 isset { return ldCommand && ldCommand[0]; }
1343 property const char * objectFileExt
1345 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1346 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1347 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1349 property const char * staticLibFileExt
1351 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1352 get { return staticLibFileExt; }
1353 isset { return staticLibFileExt && staticLibFileExt[0]; }
1355 property const char * sharedLibFileExt
1357 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1358 get { return sharedLibFileExt; }
1359 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1361 property const char * executableFileExt
1363 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1364 get { return executableFileExt; }
1365 isset { return executableFileExt && executableFileExt[0]; }
1367 property const char * executableLauncher
1369 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1370 get { return executableLauncher; }
1371 isset { return executableLauncher && executableLauncher[0]; }
1373 // TODO: implement CompilerConfig::windresCommand
1377 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1379 property const char * distccHosts
1381 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1382 get { return distccHosts; }
1383 isset { return distccHosts && distccHosts[0]; }
1385 property const char * gnuToolchainPrefix
1387 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1388 get { return gnuToolchainPrefix; }
1389 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1391 property const char * sysroot
1393 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1394 get { return sysroot; }
1395 isset { return sysroot && sysroot[0]; }
1397 bool resourcesDotEar;
1399 property Array<String> includeDirs
1407 includeDirs = value;
1410 get { return includeDirs; }
1411 isset { return includeDirs.count != 0; }
1413 property Array<String> libraryDirs
1421 libraryDirs = value;
1424 get { return libraryDirs; }
1425 isset { return libraryDirs.count != 0; }
1427 property Array<String> executableDirs
1431 executableDirs.Free();
1434 delete executableDirs;
1435 executableDirs = value;
1438 get { return executableDirs; }
1439 isset { return executableDirs.count != 0; }
1441 property Array<NamedString> environmentVars
1445 environmentVars.Free();
1448 delete environmentVars;
1449 environmentVars = value;
1452 get { return environmentVars; }
1453 isset { return environmentVars.count != 0; }
1455 property Array<String> prepDirectives
1459 prepDirectives.Free();
1462 delete prepDirectives;
1463 prepDirectives = value;
1466 get { return prepDirectives; }
1467 isset { return prepDirectives.count != 0; }
1469 property Array<String> excludeLibs
1477 excludeLibs = value;
1480 get { return excludeLibs; }
1481 isset { return excludeLibs.count != 0; }
1483 property Array<String> eCcompilerFlags
1487 eCcompilerFlags.Free();
1490 delete eCcompilerFlags;
1491 eCcompilerFlags = value;
1494 get { return eCcompilerFlags; }
1495 isset { return eCcompilerFlags.count != 0; }
1497 property Array<String> compilerFlags
1501 compilerFlags.Free();
1504 delete compilerFlags;
1505 compilerFlags = value;
1508 get { return compilerFlags; }
1509 isset { return compilerFlags.count != 0; }
1511 property Array<String> cxxFlags
1522 get { return cxxFlags; }
1523 isset { return cxxFlags.count != 0; }
1525 property Array<String> linkerFlags
1533 linkerFlags = value;
1536 get { return linkerFlags; }
1537 isset { return linkerFlags.count != 0; }
1539 // json backward compatibility
1540 property const char * gccPrefix
1542 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1543 get { return gnuToolchainPrefix; }
1544 isset { return false; }
1546 property const char * execPrefixCommand
1548 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1549 get { return executableLauncher; }
1550 isset { return false; }
1552 property const char * outputFileExt
1554 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1555 get { return executableFileExt; }
1556 isset { return false; }
1559 property bool hasDocumentOutput
1563 bool result = executableFileExt && executableFileExt[0] &&
1564 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1567 isset { return false; }
1570 Array<String> includeDirs { };
1571 Array<String> libraryDirs { };
1572 Array<String> executableDirs { };
1573 // TODO: Can JSON parse and serialize maps?
1574 //EnvironmentVariables { };
1575 Array<NamedString> environmentVars { };
1576 Array<String> prepDirectives { };
1577 Array<String> excludeLibs { };
1578 Array<String> eCcompilerFlags { };
1579 Array<String> compilerFlags { };
1580 Array<String> cxxFlags { };
1581 Array<String> linkerFlags { };
1593 char * objectFileExt;
1594 char * staticLibFileExt;
1595 char * sharedLibFileExt;
1596 char * executableFileExt;
1597 char * executableLauncher;
1599 char * gnuToolchainPrefix;
1603 struct { Array<String> includes, libraries, executables; };
1604 Array<String> dirs[DirTypes];
1619 delete objectFileExt;
1620 delete staticLibFileExt;
1621 delete sharedLibFileExt;
1622 delete executableFileExt;
1624 delete executableLauncher;
1626 delete gnuToolchainPrefix;
1628 if(environmentVars) environmentVars.Free();
1629 if(includeDirs) { includeDirs.Free(); }
1630 if(libraryDirs) { libraryDirs.Free(); }
1631 if(executableDirs) { executableDirs.Free(); }
1632 if(prepDirectives) { prepDirectives.Free(); }
1633 if(excludeLibs) { excludeLibs.Free(); }
1634 if(compilerFlags) { compilerFlags.Free(); }
1635 if(cxxFlags) { cxxFlags.Free(); }
1636 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1637 if(linkerFlags) { linkerFlags.Free(); }
1640 int OnCompare(CompilerConfig b)
1644 !(result = type.OnCompare(b.type)) &&
1645 !(result = targetPlatform.OnCompare(b.targetPlatform)) &&
1646 !(result = numJobs.OnCompare(b.numJobs)) &&
1647 !(result = ccacheEnabled.OnCompare(b.ccacheEnabled)) &&
1648 !(result = distccEnabled.OnCompare(b.distccEnabled)) &&
1649 !(result = resourcesDotEar.OnCompare(b.resourcesDotEar)) &&
1650 !(result = noStripTarget.OnCompare(b.noStripTarget))
1654 !(result = name.OnCompare(b.name)) &&
1655 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1656 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1657 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1658 !(result = earCommand.OnCompare(b.earCommand)) &&
1659 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1660 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1661 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1662 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1663 !(result = arCommand.OnCompare(b.arCommand)) &&
1664 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1665 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1666 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1667 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1668 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1669 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1670 !(result = sysroot.OnCompare(b.sysroot)));
1673 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1674 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1675 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1676 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1677 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1678 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1679 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1680 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1681 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1682 !(result = linkerFlags.OnCompare(b.linkerFlags)));
1687 CompilerConfig Copy()
1720 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1721 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1722 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1723 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1724 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1725 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1726 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1727 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
1728 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1729 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1735 CompilerConfig ::read(const char * path)
1737 CompilerConfig d = null;
1738 readConfigFile(path, class(CompilerConfig), &d);
1744 char dir[MAX_LOCATION];
1745 char path[MAX_LOCATION];
1746 const char * settingsFilePath = settingsContainer.settingsFilePath;
1747 getConfigFilePath(path, _class, dir, name);
1748 if(FileExists(settingsFilePath) && !FileExists(dir))
1751 if(!FileExists(dir))
1752 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1754 writeConfigFile(path, _class, this);
1758 class CompilerConfigs : List<CompilerConfig>
1760 CompilerConfig GetCompilerConfig(const String compilerName)
1762 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
1763 CompilerConfig compilerConfig = null;
1764 for(compiler : this)
1766 if(!strcmp(compiler.name, name))
1768 compilerConfig = compiler;
1772 if(!compilerConfig && count)
1773 compilerConfig = this[0];
1776 incref compilerConfig;
1777 if(compilerConfig._refCount == 1)
1778 incref compilerConfig;
1780 return compilerConfig;
1783 void ensureDefaults()
1785 // Ensure we have a default compiler
1786 CompilerConfig defaultCompiler = GetCompilerConfig(defaultCompilerName);
1787 if(!defaultCompiler)
1789 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
1790 Insert(null, defaultCompiler);
1791 defaultCompiler = null;
1793 delete defaultCompiler;
1797 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
1798 ccfg.ecpCommand = ecpDefaultCommand;
1799 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
1800 ccfg.eccCommand = eccDefaultCommand;
1801 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
1802 ccfg.ecsCommand = ecsDefaultCommand;
1803 if(!ccfg.earCommand || !ccfg.earCommand[0])
1804 ccfg.earCommand = earDefaultCommand;
1805 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
1806 ccfg.cppCommand = cppDefaultCommand;
1807 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
1808 ccfg.ccCommand = ccDefaultCommand;
1809 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
1810 ccfg.cxxCommand = cxxDefaultCommand;
1811 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
1812 ccfg.ldCommand = ldDefaultCommand;*/
1813 if(!ccfg.arCommand || !ccfg.arCommand[0])
1814 ccfg.arCommand = arDefaultCommand;
1815 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
1816 ccfg.objectFileExt = objectDefaultFileExt;
1817 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
1818 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
1819 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
1820 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
1821 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
1822 ccfg.executableFileExt = outputDefaultFileExt;*/
1823 if(!ccfg._refCount) incref ccfg;
1827 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
1829 AVLTree<String> list { };
1833 for(occfg : oldConfigs; !strcmp(ccfg.name, occfg.name))
1836 if(ccfg.OnCompare(occfg))
1837 list.Add(CopyString(ccfg.name));
1841 list.Add(CopyString(ccfg.name));
1848 if(settingsContainer.settingsFilePath)
1850 char dir[MAX_LOCATION];
1851 char path[MAX_LOCATION];
1852 Class _class = class(CompilerConfig);
1853 getConfigFilePath(path, _class, dir, null);
1856 AVLTree<const String> addedConfigs { };
1857 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
1858 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
1859 if(it.Index("Default", false))
1861 CompilerConfig ccfg = it.data;
1863 addedConfigs.Add(ccfg.name);
1865 for(ccfg : compilerConfigsByName)
1867 if(!addedConfigs.Find(ccfg.name))
1870 addedConfigs.Add(ccfg.name);
1876 if(!addedConfigs.Find(ccfg.name))
1880 delete addedConfigs;
1882 compilerConfigsByName.Free();
1883 delete compilerConfigsByName;
1884 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1885 ide.UpdateCompilerConfigs(true);
1891 void write(AVLTree<String> cfgsToWrite)
1893 char dir[MAX_LOCATION];
1894 char path[MAX_LOCATION];
1895 Map<String, String> paths;
1896 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))
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 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
1990 bool restart = true;
1991 String command = null;
1992 int arg0Len = (int)strlen(app.argv[0]);
2004 for(w = ide.firstChild; w; w = w.next)
2006 if(w.isActiveClient && w.isDocument)
2008 if(!w.CloseConfirmation(true))
2017 if(!projectView.CloseConfirmation(true))
2019 if(projectView.fileName)
2021 const char * name = projectView.fileName;
2024 for(j = 0; (ch = name[j]); j++)
2025 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2029 command = new char[len + 1];
2031 strcpy(command, app.argv[0]);
2033 if(projectView.fileName)
2035 strcat(command, " ");
2037 ReplaceSpaces(command + len, projectView.fileName);
2042 for(w = ide.firstChild; w; w = w.next)
2043 if(w.isActiveClient && w.isDocument)
2044 w.modifiedDocument = false;
2045 projectView.modifiedDocument = false;
2050 for(w = ide.firstChild; w; w = w.next)
2052 if(w.isActiveClient && w.isDocument)
2054 if(!w.CloseConfirmation(true))
2061 const char * name = w.fileName;
2063 for(j = 0; (ch = name[j]); j++)
2064 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2071 command = new char[len + 1];
2072 strcpy(command, app.argv[0]);
2075 for(w = ide.firstChild; w; w = w.next)
2077 if(w.isActiveClient && w.isDocument)
2079 const char * name = w.fileName;
2082 strcat(command, " ");
2084 ReplaceSpaces(command + len, name);
2085 len = (int)strlen(command);
2092 for(w = ide.firstChild; w; w = w.next)
2093 if(w.isActiveClient && w.isDocument)
2094 w.modifiedDocument = false;
2099 settings.language = code;
2100 settingsContainer.Save();
2102 setEcereLanguageInWinRegEnvironment(code);
2104 if(eClass_IsDerived(app._class, class(GuiApplication)))
2106 GuiApplication guiApp = (GuiApplication)app;
2107 guiApp.desktop.Destroy(0);
2114 for(i = 1; i < app.argc; i++)
2116 const char * arg = app.argv[i];
2118 for(j = 0; (ch = arg[j]); j++)
2119 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2122 command = new char[len + 1];
2123 strcpy(command, app.argv[0]);
2125 for(i = 1; i < app.argc; i++)
2127 strcat(command, " ");
2129 ReplaceSpaces(command + len, app.argv[i]);
2130 len = (int)strlen(command);
2136 SetEnvironment("ECERE_LANGUAGE", code);
2138 ExecuteWait(command);