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)
697 sf.file = FileOpen(mode == write ? sf.tmp : path, mode);
700 for(c = 0; c < 10 && !(locked = sf.file.Lock(lockType, 0, 0, false)); c++) Sleep(0.01);
703 else if(mode == write)
704 PrintLn($"warning: SafeFile::open: unable to obtain exclusive lock on temporary file for writing: ", sf.tmp);
706 PrintLn($"warning: SafeFile::open: unable to obtain shared lock on file for reading: ", path);
708 else if(mode == write)
709 PrintLn($"warning: SafeFile::open: unable to open temporary file for writing: ", sf.tmp);
711 PrintLn($"warning: SafeFile::open: unable to open file for reading: ", path);
717 PrintLn($"warning: SafeFile::open: does not yet support FileOpenMode::", mode);
723 if(file && mode == write)
726 File f = FileOpen(path, FileExists(path) ? read : write);
730 for(c = 0; c < 10 && !(locked = f.Lock(exclusive, 0,0, false)); c++) Sleep(0.01);
734 f.Unlock(0,0, false);
736 file.Unlock(0,0, false);
739 for(c = 0; c < 10; c++)
741 if(MoveFileEx(tmp, path, { true, true }))
750 PrintLn($"warning: SafeFile::sync: failed to lock file", mode);
761 file.Unlock(0,0, false);
767 class RecentFilesData
770 RecentFiles recentFiles;
773 class RecentWorkspacesData
776 RecentWorkspaces recentWorkspaces;
779 class IDESettings : GlobalSettingsData
782 property CompilerConfigs compilerConfigs
784 set { if(settingsContainer.oldConfig) { if(compilerConfigs) compilerConfigs.Free(); delete compilerConfigs; if(value) compilerConfigs = value; } }
785 get { return compilerConfigs; }
786 isset { return false; }
788 property RecentFiles recentFiles
790 set { if(recentFiles) recentFiles.Free(); delete recentFiles; if(value) recentFiles = value; }
791 get { return recentFiles; }
792 isset { return false; }
794 property RecentWorkspaces recentProjects
796 set { if(recentProjects) recentProjects.Free(); delete recentProjects; if(value) recentProjects = value; }
797 get { return recentProjects; }
798 isset { return false; }
800 property const char * docDir
802 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
803 get { return docDir ? docDir : ""; }
804 isset { return docDir && docDir[0]; }
806 property const char * ideFileDialogLocation
808 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
809 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
810 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
812 property const char * ideProjectFileDialogLocation
814 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
815 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
816 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
819 bool showLineNumbers;
820 bool caretFollowsScrolling;
821 char * displayDriver;
823 // TODO: Classify settings
824 //EditorSettings editor { };
826 property const char * projectDefaultTargetDir
828 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
829 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
830 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
832 property const char * projectDefaultIntermediateObjDir
834 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
835 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
836 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
839 property const char * compilerConfigsDir
841 set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
842 get { return compilerConfigsDir ? compilerConfigsDir : ""; }
843 isset { return compilerConfigsDir && compilerConfigsDir[0]; }
846 property const char * defaultCompiler
848 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
849 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
850 isset { return defaultCompiler && defaultCompiler[0]; }
853 property const String language
858 language = CopyString(value);
860 get { return language; }
861 isset { return language != null; }
865 CompilerConfigs compilerConfigs { };
867 char * ideFileDialogLocation;
868 char * ideProjectFileDialogLocation;
869 char * projectDefaultTargetDir;
870 char * projectDefaultIntermediateObjDir;
871 char * compilerConfigsDir;
872 char * defaultCompiler;
874 RecentFiles recentFiles { };
875 RecentWorkspaces recentProjects { };
879 compilerConfigs.Free();
880 delete compilerConfigs;
881 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
882 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
885 delete projectDefaultTargetDir;
886 delete projectDefaultIntermediateObjDir;
887 delete compilerConfigsDir;
888 delete defaultCompiler;
891 delete ideFileDialogLocation;
892 delete ideProjectFileDialogLocation;
893 delete displayDriver;
896 void ForcePathSeparatorStyle(bool unixStyle)
900 from = '\\', to = '/';
902 from = '/', to = '\\';
903 if(compilerConfigs && compilerConfigs.count)
906 for(config : compilerConfigs)
908 if(config.includeDirs && config.includeDirs.count)
910 for(i = 0; i < config.includeDirs.count; i++)
912 if(config.includeDirs[i] && config.includeDirs[i][0])
913 ChangeCh(config.includeDirs[i], from, to);
916 if(config.libraryDirs && config.libraryDirs.count)
918 for(i = 0; i < config.libraryDirs.count; i++)
920 if(config.libraryDirs[i] && config.libraryDirs[i][0])
921 ChangeCh(config.libraryDirs[i], from, to);
924 if(config.executableDirs && config.executableDirs.count)
926 for(i = 0; i < config.executableDirs.count; i++)
928 if(config.executableDirs[i] && config.executableDirs[i][0])
929 ChangeCh(config.executableDirs[i], from, to);
934 recentFiles.changeChar(from, to);
935 recentProjects.changeChar(from, to);
936 if(docDir && docDir[0])
937 ChangeCh(docDir, from, to);
938 if(ideFileDialogLocation && ideFileDialogLocation[0])
939 ChangeCh(ideFileDialogLocation, from, to);
940 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
941 ChangeCh(ideProjectFileDialogLocation, from, to);
943 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
944 ChangeCh(projectDefaultTargetDir, from, to);
945 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
946 ChangeCh(projectDefaultIntermediateObjDir, from, to);
948 if(compilerConfigsDir && compilerConfigsDir[0])
949 ChangeCh(compilerConfigsDir, from, to);
952 void ManagePortablePaths(char * location, bool makeAbsolute)
955 if(compilerConfigs && compilerConfigs.count)
957 for(config : compilerConfigs)
960 for(t = 0; t < DirTypes::enumSize; t++)
962 Array<String> dirs = null;
963 if(t == executables) dirs = config.executableDirs;
964 else if(t == includes) dirs = config.includeDirs;
965 else if(t == libraries) dirs = config.libraryDirs;
966 if(dirs && dirs.count)
968 for(c = 0; c < dirs.count; c++)
970 if(dirs[c] && dirs[c][0])
971 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
977 if(recentFiles && recentFiles.count)
979 for(c = 0; c < recentFiles.count; c++)
981 if(recentFiles[c] && recentFiles[c][0])
982 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
985 if(recentProjects && recentProjects.count)
987 for(c = 0; c < recentProjects.count; c++)
989 if(recentProjects[c] && recentProjects[c][0])
990 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
993 if(docDir && docDir[0])
994 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
995 if(ideFileDialogLocation && ideFileDialogLocation[0])
996 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
997 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
998 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
1000 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1001 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
1002 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1003 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
1005 if(compilerConfigsDir && compilerConfigsDir[0])
1006 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
1009 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
1014 char p[MAX_LOCATION];
1015 strcpy(p, location);
1016 PathCatSlash(p, path);
1018 output = CopyString(p);
1022 PathRelationship rel = eString_PathRelated(path, location, null);
1023 if(rel == subPath || rel == identical)
1025 char p[MAX_LOCATION];
1026 MakePathRelative(path, location, p);
1027 if(!*p) strcpy(p, "./");
1028 else ChangeCh(p, '\\', '/');
1030 output = CopyString(p);
1039 class RecentFiles : RecentPaths
1048 char path[MAX_LOCATION];
1049 RecentFilesData d = null;
1050 Class _class = class(RecentFilesData);
1051 getConfigFilePath(path, _class, null, null);
1052 readConfigFile(path, _class, &d);
1053 if(d && d.recentFiles && d.recentFiles.count)
1055 ideConfig.recentFiles = d.recentFiles;
1056 d.recentFiles = null;
1057 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1058 ide.updateRecentFilesMenu();
1062 settingsContainer.recentFilesMonitor.fileName = path;
1063 settingsContainer.recentFilesMonitor.StartMonitoring();
1068 char path[MAX_LOCATION];
1069 RecentFilesData d { };
1070 Class _class = class(RecentFilesData);
1071 getConfigFilePath(path, _class, null, null);
1072 d.recentFiles = this;
1073 writeConfigFile(path, _class, d);
1074 d.recentFiles = null;
1079 class RecentWorkspaces : RecentPaths
1088 char path[MAX_LOCATION];
1089 RecentWorkspacesData d = null;
1090 Class _class = class(RecentWorkspacesData);
1091 getConfigFilePath(path, _class, null, null);
1092 readConfigFile(path, _class, &d);
1093 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1095 ideConfig.recentProjects = d.recentWorkspaces;
1096 d.recentWorkspaces = null;
1097 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1098 ide.updateRecentProjectsMenu();
1101 settingsContainer.recentProjectsMonitor.fileName = path;
1102 settingsContainer.recentProjectsMonitor.StartMonitoring();
1108 char path[MAX_LOCATION];
1109 RecentWorkspacesData d { };
1110 Class _class = class(RecentWorkspacesData);
1111 getConfigFilePath(path, _class, null, null);
1112 d.recentWorkspaces = this;
1113 writeConfigFile(path, _class, d);
1114 d.recentWorkspaces = null;
1119 class RecentPaths : Array<String>
1121 virtual void onAdd();
1123 IteratorPointer Add(T value)
1126 char * filePath = (char *)value;
1127 ChangeCh(filePath, '\\', '/');
1128 for(c = 0; c < count; c++)
1130 if(this[c] && !fstrcmp(this[c], filePath))
1132 Delete((void *)&this[c]);
1136 return Array::Add((T)filePath);
1139 IteratorPointer addRecent(const String value)
1142 char * filePath = CopyString((char *)value);
1144 ChangeCh(filePath, '\\', '/');
1145 for(c = 0; c < count; c++)
1147 if(this[c] && !fstrcmp(this[c], filePath))
1149 Delete((void *)&this[c]);
1153 while(count >= MaxRecent)
1155 ip = Insert(null, filePath);
1160 void changeChar(char from, char to)
1165 for(c = 0; c < count; c++)
1167 if(this[c] && this[c][0])
1168 ChangeCh(this[c], from, to);
1174 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1175 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1176 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1177 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1178 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1179 // TODO: i18n with Array
1180 static Array<const String> compilerTypeLongNames
1182 $"GNU Compiler Collection (GCC) / GNU Make",
1183 $"Tiny C Compiler / GNU Make",
1184 $"Portable C Compiler / GNU Make",
1185 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1186 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1187 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1189 const CompilerType firstCompilerType = gcc;
1190 const CompilerType lastCompilerType = vs10;
1191 public enum CompilerType
1193 gcc, tcc, pcc, vs8, vs9, vs10;
1197 get { return this == vs8 || this == vs9 || this == vs10; }
1200 property const char *
1202 get { return OnGetString(null, null, null); }
1208 for(c = firstCompilerType; c <= lastCompilerType; c++)
1209 if(!strcmpi(value, compilerTypeNames[c]))
1216 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1217 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1218 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1219 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1220 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1222 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1224 if(this >= firstCompilerType && this <= lastCompilerType)
1227 strcpy(tempString, compilerTypeNames[this]);
1228 if(fieldData == null)
1229 return compilerTypeNames[this];
1230 else if(fieldData == (void*)1)
1231 return compilerTypeLongNames[this];
1232 else if(fieldData == (void*)2)
1233 return compilerTypeVersionString[this];
1234 else if(fieldData == (void*)3)
1235 return compilerTypeYearString[this];
1236 else if(fieldData == (void*)4)
1237 return compilerTypeProjectFileExtension[this];
1238 else if(fieldData == (void*)5)
1239 return compilerTypeSolutionFileVersionString[this];
1245 class CompilerConfig
1251 property const char * name
1253 set { delete name; if(value) name = CopyString(value); }
1254 get { return name; }
1258 Platform targetPlatform;
1260 property const char * makeCommand
1262 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1263 get { return makeCommand; }
1264 isset { return makeCommand && makeCommand[0]; }
1266 property const char * ecpCommand
1268 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1269 get { return ecpCommand; }
1270 isset { return ecpCommand && ecpCommand[0]; }
1272 property const char * eccCommand
1274 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1275 get { return eccCommand; }
1276 isset { return eccCommand && eccCommand[0]; }
1278 property const char * ecsCommand
1280 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1281 get { return ecsCommand; }
1282 isset { return ecsCommand && ecsCommand[0]; }
1284 property const char * earCommand
1286 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1287 get { return earCommand; }
1288 isset { return earCommand && earCommand[0]; }
1290 property const char * cppCommand
1292 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1293 get { return cppCommand; }
1294 isset { return cppCommand && cppCommand[0]; }
1296 property const char * ccCommand
1298 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1299 get { return ccCommand; }
1300 isset { return ccCommand && ccCommand[0]; }
1302 property const char * cxxCommand
1304 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1305 get { return cxxCommand; }
1306 isset { return cxxCommand && cxxCommand[0]; }
1308 property const char * arCommand
1310 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1311 get { return arCommand; }
1312 isset { return arCommand && arCommand[0]; }
1314 property const char * ldCommand
1316 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1317 get { return ldCommand; }
1318 isset { return ldCommand && ldCommand[0]; }
1320 property const char * objectFileExt
1322 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1323 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1324 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1326 property const char * staticLibFileExt
1328 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1329 get { return staticLibFileExt; }
1330 isset { return staticLibFileExt && staticLibFileExt[0]; }
1332 property const char * sharedLibFileExt
1334 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1335 get { return sharedLibFileExt; }
1336 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1338 property const char * executableFileExt
1340 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1341 get { return executableFileExt; }
1342 isset { return executableFileExt && executableFileExt[0]; }
1344 property const char * executableLauncher
1346 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1347 get { return executableLauncher; }
1348 isset { return executableLauncher && executableLauncher[0]; }
1350 // TODO: implement CompilerConfig::windresCommand
1354 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1356 property const char * distccHosts
1358 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1359 get { return distccHosts; }
1360 isset { return distccHosts && distccHosts[0]; }
1362 property const char * gnuToolchainPrefix
1364 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1365 get { return gnuToolchainPrefix; }
1366 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1368 property const char * sysroot
1370 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1371 get { return sysroot; }
1372 isset { return sysroot && sysroot[0]; }
1374 bool resourcesDotEar;
1376 property Array<String> includeDirs
1384 includeDirs = value;
1387 get { return includeDirs; }
1388 isset { return includeDirs.count != 0; }
1390 property Array<String> libraryDirs
1398 libraryDirs = value;
1401 get { return libraryDirs; }
1402 isset { return libraryDirs.count != 0; }
1404 property Array<String> executableDirs
1408 executableDirs.Free();
1411 delete executableDirs;
1412 executableDirs = value;
1415 get { return executableDirs; }
1416 isset { return executableDirs.count != 0; }
1418 property Array<NamedString> environmentVars
1422 environmentVars.Free();
1425 delete environmentVars;
1426 environmentVars = value;
1429 get { return environmentVars; }
1430 isset { return environmentVars.count != 0; }
1432 property Array<String> prepDirectives
1436 prepDirectives.Free();
1439 delete prepDirectives;
1440 prepDirectives = value;
1443 get { return prepDirectives; }
1444 isset { return prepDirectives.count != 0; }
1446 property Array<String> excludeLibs
1454 excludeLibs = value;
1457 get { return excludeLibs; }
1458 isset { return excludeLibs.count != 0; }
1460 property Array<String> eCcompilerFlags
1464 eCcompilerFlags.Free();
1467 delete eCcompilerFlags;
1468 eCcompilerFlags = value;
1471 get { return eCcompilerFlags; }
1472 isset { return eCcompilerFlags.count != 0; }
1474 property Array<String> compilerFlags
1478 compilerFlags.Free();
1481 delete compilerFlags;
1482 compilerFlags = value;
1485 get { return compilerFlags; }
1486 isset { return compilerFlags.count != 0; }
1488 property Array<String> cxxFlags
1499 get { return cxxFlags; }
1500 isset { return cxxFlags.count != 0; }
1502 property Array<String> linkerFlags
1510 linkerFlags = value;
1513 get { return linkerFlags; }
1514 isset { return linkerFlags.count != 0; }
1516 // json backward compatibility
1517 property const char * gccPrefix
1519 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1520 get { return gnuToolchainPrefix; }
1521 isset { return false; }
1523 property const char * execPrefixCommand
1525 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1526 get { return executableLauncher; }
1527 isset { return false; }
1529 property const char * outputFileExt
1531 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1532 get { return executableFileExt; }
1533 isset { return false; }
1536 property bool hasDocumentOutput
1540 bool result = executableFileExt && executableFileExt[0] &&
1541 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1544 isset { return false; }
1547 Array<String> includeDirs { };
1548 Array<String> libraryDirs { };
1549 Array<String> executableDirs { };
1550 // TODO: Can JSON parse and serialize maps?
1551 //EnvironmentVariables { };
1552 Array<NamedString> environmentVars { };
1553 Array<String> prepDirectives { };
1554 Array<String> excludeLibs { };
1555 Array<String> eCcompilerFlags { };
1556 Array<String> compilerFlags { };
1557 Array<String> cxxFlags { };
1558 Array<String> linkerFlags { };
1570 char * objectFileExt;
1571 char * staticLibFileExt;
1572 char * sharedLibFileExt;
1573 char * executableFileExt;
1574 char * executableLauncher;
1576 char * gnuToolchainPrefix;
1580 struct { Array<String> includes, libraries, executables; };
1581 Array<String> dirs[DirTypes];
1596 delete objectFileExt;
1597 delete staticLibFileExt;
1598 delete sharedLibFileExt;
1599 delete executableFileExt;
1601 delete executableLauncher;
1603 delete gnuToolchainPrefix;
1605 if(environmentVars) environmentVars.Free();
1606 if(includeDirs) { includeDirs.Free(); }
1607 if(libraryDirs) { libraryDirs.Free(); }
1608 if(executableDirs) { executableDirs.Free(); }
1609 if(prepDirectives) { prepDirectives.Free(); }
1610 if(excludeLibs) { excludeLibs.Free(); }
1611 if(compilerFlags) { compilerFlags.Free(); }
1612 if(cxxFlags) { cxxFlags.Free(); }
1613 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1614 if(linkerFlags) { linkerFlags.Free(); }
1617 int OnCompare(CompilerConfig b)
1621 !(result = type.OnCompare(b.type)) &&
1622 !(result = targetPlatform.OnCompare(b.targetPlatform)) &&
1623 !(result = numJobs.OnCompare(b.numJobs)));
1626 !(result = name.OnCompare(b.name)) &&
1627 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1628 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1629 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1630 !(result = earCommand.OnCompare(b.earCommand)) &&
1631 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1632 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1633 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1634 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1635 !(result = arCommand.OnCompare(b.arCommand)) &&
1636 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1637 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1638 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1639 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1640 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1641 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1642 !(result = sysroot.OnCompare(b.sysroot)));
1645 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1646 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1647 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1648 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1649 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1650 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1651 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1652 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1653 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1654 !(result = linkerFlags.OnCompare(b.linkerFlags)));
1659 CompilerConfig Copy()
1692 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1693 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1694 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1695 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1696 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1697 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1698 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1699 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
1700 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1701 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1707 CompilerConfig ::read(const char * path)
1709 CompilerConfig d = null;
1710 readConfigFile(path, class(CompilerConfig), &d);
1716 char dir[MAX_LOCATION];
1717 char path[MAX_LOCATION];
1718 const char * settingsFilePath = settingsContainer.settingsFilePath;
1719 getConfigFilePath(path, _class, dir, name);
1720 if(FileExists(settingsFilePath) && !FileExists(dir))
1723 if(!FileExists(dir))
1724 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1726 writeConfigFile(path, _class, this);
1730 class CompilerConfigs : List<CompilerConfig>
1732 CompilerConfig GetCompilerConfig(const String compilerName)
1734 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
1735 CompilerConfig compilerConfig = null;
1736 for(compiler : this)
1738 if(!strcmp(compiler.name, name))
1740 compilerConfig = compiler;
1744 if(!compilerConfig && count)
1745 compilerConfig = this[0];
1748 incref compilerConfig;
1749 if(compilerConfig._refCount == 1)
1750 incref compilerConfig;
1752 return compilerConfig;
1755 void ensureDefaults()
1757 // Ensure we have a default compiler
1758 CompilerConfig defaultCompiler = GetCompilerConfig(defaultCompilerName);
1759 if(!defaultCompiler)
1761 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
1762 Insert(null, defaultCompiler);
1763 defaultCompiler = null;
1765 delete defaultCompiler;
1769 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
1770 ccfg.ecpCommand = ecpDefaultCommand;
1771 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
1772 ccfg.eccCommand = eccDefaultCommand;
1773 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
1774 ccfg.ecsCommand = ecsDefaultCommand;
1775 if(!ccfg.earCommand || !ccfg.earCommand[0])
1776 ccfg.earCommand = earDefaultCommand;
1777 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
1778 ccfg.cppCommand = cppDefaultCommand;
1779 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
1780 ccfg.ccCommand = ccDefaultCommand;
1781 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
1782 ccfg.cxxCommand = cxxDefaultCommand;
1783 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
1784 ccfg.ldCommand = ldDefaultCommand;*/
1785 if(!ccfg.arCommand || !ccfg.arCommand[0])
1786 ccfg.arCommand = arDefaultCommand;
1787 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
1788 ccfg.objectFileExt = objectDefaultFileExt;
1789 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
1790 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
1791 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
1792 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
1793 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
1794 ccfg.executableFileExt = outputDefaultFileExt;*/
1795 if(!ccfg._refCount) incref ccfg;
1799 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
1801 AVLTree<String> list { };
1805 for(occfg : oldConfigs; !strcmp(ccfg.name, occfg.name))
1808 if(ccfg.OnCompare(occfg))
1809 list.Add(CopyString(ccfg.name));
1813 list.Add(CopyString(ccfg.name));
1820 if(settingsContainer.settingsFilePath)
1822 char dir[MAX_LOCATION];
1823 char path[MAX_LOCATION];
1824 Class _class = class(CompilerConfig);
1825 getConfigFilePath(path, _class, dir, null);
1828 AVLTree<const String> addedConfigs { };
1829 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
1830 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
1831 if(it.Index("Default", false))
1833 CompilerConfig ccfg = it.data;
1835 addedConfigs.Add(ccfg.name);
1837 for(ccfg : compilerConfigsByName)
1839 if(!addedConfigs.Find(ccfg.name))
1842 addedConfigs.Add(ccfg.name);
1848 if(!addedConfigs.Find(ccfg.name))
1852 delete addedConfigs;
1854 compilerConfigsByName.Free();
1855 delete compilerConfigsByName;
1856 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1857 ide.UpdateCompilerConfigs(true);
1863 void write(AVLTree<String> cfgsToWrite)
1865 char dir[MAX_LOCATION];
1866 char path[MAX_LOCATION];
1867 Map<String, String> paths;
1868 getConfigFilePath(path, class(CompilerConfig), dir, null);
1869 paths = getCompilerConfigFilePathsByName(dir);
1871 MapIterator<String, String> it { map = paths };
1874 CompilerConfig ccfg = c;
1875 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
1877 if(it.Index(ccfg.name, false))
1886 const char * path = p;
1894 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1895 struct LanguageOption
1898 const String bitmap;
1902 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1907 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
1909 Bitmap icon = res ? res.bitmap : null;
1912 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
1913 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
1917 Array<LanguageOption> languages
1919 { "English", ":countryCode/gb.png", "" },
1920 { "汉语", ":countryCode/cn.png", "zh_CN" },
1921 { "Español", ":countryCode/es.png", "es" },
1922 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
1923 { "Русский (43%)", ":countryCode/ru.png", "ru" },
1924 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
1925 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
1926 { "मराठी (10%)", ":countryCode/in.png", "mr" },
1927 { "Hebrew (8%)", ":countryCode/il.png", "he" },
1928 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
1931 const String GetLanguageString()
1933 char * dot, * colon;
1934 static char lang[256];
1935 const String language = getenv("ECERE_LANGUAGE");
1936 if(!language) language = getenv("LANGUAGE");
1937 if(!language) language = getenv("LC_ALL");
1938 if(!language) language = getenv("LC_MESSAGES");
1939 if(!language) language = getenv("LANG");
1940 if(!language) language = "";
1941 if(language && (colon = strchr(language, ':')))
1943 if(lang != language)
1944 strncpy(lang, language, sizeof(lang));
1945 lang[sizeof(lang)-1] = 0;
1946 lang[colon - language] = 0;
1949 if(language && (dot = strchr(language, '.')))
1951 if(lang != language)
1952 strncpy(lang, language, sizeof(lang));
1953 lang[sizeof(lang)-1] = 0;
1954 lang[dot - language] = 0;
1960 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
1962 bool restart = true;
1963 String command = null;
1964 int arg0Len = (int)strlen(app.argv[0]);
1976 for(w = ide.firstChild; w; w = w.next)
1978 if(w.isActiveClient && w.isDocument)
1980 if(!w.CloseConfirmation(true))
1989 if(!projectView.CloseConfirmation(true))
1991 if(projectView.fileName)
1993 const char * name = projectView.fileName;
1996 for(j = 0; (ch = name[j]); j++)
1997 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2001 command = new char[len + 1];
2003 strcpy(command, app.argv[0]);
2005 if(projectView.fileName)
2007 strcat(command, " ");
2009 ReplaceSpaces(command + len, projectView.fileName);
2014 for(w = ide.firstChild; w; w = w.next)
2015 if(w.isActiveClient && w.isDocument)
2016 w.modifiedDocument = false;
2017 projectView.modifiedDocument = false;
2022 for(w = ide.firstChild; w; w = w.next)
2024 if(w.isActiveClient && w.isDocument)
2026 if(!w.CloseConfirmation(true))
2033 const char * name = w.fileName;
2035 for(j = 0; (ch = name[j]); j++)
2036 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2043 command = new char[len + 1];
2044 strcpy(command, app.argv[0]);
2047 for(w = ide.firstChild; w; w = w.next)
2049 if(w.isActiveClient && w.isDocument)
2051 const char * name = w.fileName;
2054 strcat(command, " ");
2056 ReplaceSpaces(command + len, name);
2057 len = (int)strlen(command);
2064 for(w = ide.firstChild; w; w = w.next)
2065 if(w.isActiveClient && w.isDocument)
2066 w.modifiedDocument = false;
2071 settings.language = code;
2072 settingsContainer.Save();
2074 setEcereLanguageInWinRegEnvironment(code);
2076 if(eClass_IsDerived(app._class, class(GuiApplication)))
2078 GuiApplication guiApp = (GuiApplication)app;
2079 guiApp.desktop.Destroy(0);
2086 for(i = 1; i < app.argc; i++)
2088 const char * arg = app.argv[i];
2090 for(j = 0; (ch = arg[j]); j++)
2091 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2094 command = new char[len + 1];
2095 strcpy(command, app.argv[0]);
2097 for(i = 1; i < app.argc; i++)
2099 strcat(command, " ");
2101 ReplaceSpaces(command + len, app.argv[i]);
2102 len = (int)strlen(command);
2108 SetEnvironment("ECERE_LANGUAGE", code);
2110 ExecuteWait(command);