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 IDESettings ideSettings;
30 IDESettingsContainer settingsContainer
32 dataOwner = &ideSettings;
33 dataClass = class(IDESettings);
38 enum DirTypes { includes, libraries, executables };
40 define defaultCompilerName = "Default";
42 define defaultObjDirExpression = "obj/$(CONFIG).$(PLATFORM)$(COMPILER_SUFFIX)$(DEBUG_SUFFIX)";
44 const char * settingsDirectoryNames[DirTypes] =
51 // This function cannot accept same pointer for source and output
52 // todo: rename ReplaceSpaces to EscapeSpaceAndSpecialChars or something
53 void ReplaceSpaces(char * output, const char * source)
58 for(c = 0, dc = 0; (ch = source[c]); c++, dc++)
60 if(ch == ' ') output[dc++] = '\\';
61 if(ch == '\"') output[dc++] = '\\';
62 if(ch == '&') output[dc++] = '\\';
65 if(ch == '(' || ch == ')') output[dc++] = '\\';
76 enum GlobalSettingsChange { none, editorSettings, projectOptions, compilerSettings };
78 enum PathRelationship { unrelated, identical, siblings, subPath, parentPath, insuficientInput, pathEmpty, toEmpty, pathNull, toNull, bothEmpty, bothNull };
79 PathRelationship eString_PathRelated(const char * path, const char * to, char * pathDiff)
81 PathRelationship result;
82 if(pathDiff) *pathDiff = '\0';
83 if(path && *path && to && *to)
85 char toPart[MAX_FILENAME], toRest[MAX_LOCATION];
86 char pathPart[MAX_FILENAME], pathRest[MAX_LOCATION];
88 strcpy(pathRest, path);
89 for(; toRest[0] && pathRest[0];)
91 SplitDirectory(toRest, toPart, toRest);
92 SplitDirectory(pathRest, pathPart, pathRest);
93 if(!fstrcmp(pathPart, toPart)) result = siblings;
96 if(result == siblings)
98 if(!*toRest && !*pathRest) result = identical;
99 else if(!*pathRest) result = parentPath;
100 else result = subPath;
101 if(pathDiff && result != identical) strcpy(pathDiff, *pathRest == '\0' ? toRest : pathRest);
103 else result = unrelated;
109 if(!*path && !*to) result = bothEmpty;
110 else if(!*path) result = pathEmpty;
111 else result = toEmpty;
113 else if(!path && !to) result = bothNull;
114 else if(!path) result = pathNull;
115 else result = toNull;
120 char * CopyValidateMakefilePath(const char * path)
122 const int map[] = { 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 7 };
123 const char * vars[] = { "$(MODULE)", "$(CONFIG)", "$(PLATFORM)", "$(COMPILER)", "$(TARGET)", "$(COMPILER_SUFFIX)", "$(DEBUG_SUFFIX)", "$(PROJECT)", "$(CONFIGURATION)", "$(TARGET_PLATFORM)",(char *)0 };
129 len = (int)strlen(path);
130 copy = CopyString(path);
136 Array<const char *> parts { };
143 for(v=0; vars[v]; v++)
145 if(SearchString(&tmp[c], 0, vars[v], false, false) == &tmp[c])
149 parts.Add(vars[map[v]]);
150 c += strlen(vars[v]);
164 for(c=0; c<parts.count; c++) len += strlen(parts[c]);
165 copy = new char[++len];
167 for(c=0; c<parts.count; c++) strcat(copy, parts[c]);
178 void ValidPathBufCopy(char *output, const char *input)
181 bool volumePath = false;
183 strcpy(output, input);
184 TrimLSpaces(output, output);
185 TrimRSpaces(output, output);
186 MakeSystemPath(output);
188 if(output[0] && output[1] == ':')
195 const char * chars = "*|:\",<>?";
196 char ch, * s = output, * o = output;
197 while((ch = *s++)) { if(!strchr(chars, ch)) *o++ = ch; }
201 if(volumePath && output[0])
206 void RemoveTrailingPathSeparator(char *path)
209 len = (int)strlen(path);
210 if(len>1 && path[len-1] == DIR_SEP)
214 void BasicValidatePathBoxPath(PathBox pathBox)
216 char path[MAX_LOCATION];
217 ValidPathBufCopy(path, pathBox.path);
218 RemoveTrailingPathSeparator(path);
222 CompilerConfig MakeDefaultCompiler(const char * name, bool readOnly)
224 CompilerConfig defaultCompiler
242 incref defaultCompiler;
243 return defaultCompiler;
247 define settingsDir = ".ecereIDE-SettingsTest";
248 define ideSettingsName = "ecereIDE-SettingsTest";
250 define settingsDir = ".ecereIDE";
251 define ideSettingsName = "ecereIDE";
254 class IDESettingsContainer : GlobalSettings
256 property bool useNewConfigurationFiles
262 settingsContainer.driver = "ECON";
263 settingsName = "config";
264 settingsExtension = "econ";
265 settingsDirectory = settingsDir;
269 settingsContainer.driver = "JSON";
270 settingsName = ideSettingsName;
271 settingsExtension = null;
272 settingsDirectory = null;
277 char moduleLocation[MAX_LOCATION];
281 FileSize settingsFileSize;
283 IDESettingsContainer()
285 char path[MAX_LOCATION];
287 LocateModule(null, moduleLocation);
288 strcpy(path, moduleLocation);
289 StripLastDirectory(moduleLocation, moduleLocation);
290 ChangeCh(moduleLocation, '\\', '/');
291 // PortableApps.com directory structure
292 if((start = strstr(path, "\\App\\EcereSDK\\bin\\ide.exe")))
294 char configFilePath[MAX_LOCATION];
295 char defaultConfigFilePath[MAX_LOCATION];
299 strcpy(configFilePath, path);
300 PathCat(configFilePath, "Data");
301 PathCat(configFilePath, ideSettingsName);
302 ChangeExtension(configFilePath, "ini", configFilePath);
304 strcpy(defaultConfigFilePath, path);
305 PathCat(defaultConfigFilePath, "App");
306 PathCat(defaultConfigFilePath, "DefaultData");
307 PathCat(defaultConfigFilePath, ideSettingsName);
308 ChangeExtension(defaultConfigFilePath, "ini", defaultConfigFilePath);
310 if(FileExists(defaultConfigFilePath))
312 if(!FileExists(configFilePath))
314 File f = FileOpen(defaultConfigFilePath, read);
315 f.CopyTo(configFilePath);
319 PathCat(path, "Data");
320 // the forced settings location will only be
321 // used if the running ide's path matches
322 // the PortableApps.com directory structure
323 // and the default ini file is found in
324 // the DefaultData directory
325 settingsLocation = path;
331 void OnAskReloadSettings()
333 FileSize newSettingsFileSize;
335 if(OpenAndLock(&newSettingsFileSize))
337 if((double)settingsFileSize - (double)newSettingsFileSize < 2048)
341 GuiApplication app = ((GuiApplication)__thisModule.application);
343 for(w = app.desktop.firstChild; w && (!w.created || !w.visible); w = w.next);
347 MessageBox { master = w, type = ok, isModal = true,
348 creationActivation = flash,
349 text = "Global Settings Modified Externally",
350 contents = "The global settings were modified by another process and a drastic shrinking of the settings file was detected.\n"
351 "The new settings will not be loaded to prevent loss of your ide settings.\n"
352 "Please check your settings file and make sure to save this IDE's global settings if your settings file has been compromised."
358 SettingsIOResult Load()
361 SettingsIOResult result;
362 useNewConfigurationFiles = true;
363 result = GlobalSettings::Load();
364 data = (IDESettings)this.data;
366 if(result == fileNotFound)
369 useNewConfigurationFiles = false;
370 result = GlobalSettings::Load();
372 data = (IDESettings)this.data;
375 this.data = IDESettings { };
377 *dataOwner = this.data;
379 if(result == fileNotCompatibleWithDriver)
382 OldIDESettings oldSettings { };
384 loaded = oldSettings.Load() == success;
388 data = (IDESettings)this.data;
390 for(c : oldSettings.compilerConfigs)
391 data.compilerConfigs.Add(c.Copy());
393 for(s : oldSettings.recentFiles) data.recentFiles.Add(s);
394 for(s : oldSettings.recentProjects) data.recentProjects.Add(s);
396 data.docDir = oldSettings.docDir;
397 data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
398 data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
399 data.useFreeCaret = oldSettings.useFreeCaret;
400 data.showLineNumbers = oldSettings.showLineNumbers;
401 data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
402 delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
403 data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
404 data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
411 if(result == fileNotFound || !data)
413 data = (IDESettings)this.data;
414 data.useFreeCaret = false; //true;
415 data.showLineNumbers = true;
416 data.caretFollowsScrolling = false; //true;
421 FileGetSize(settingsFilePath, &settingsFileSize);
422 CompilerConfigs::fix();
423 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
424 data.ManagePortablePaths(moduleLocation, true);
425 data.ForcePathSeparatorStyle(true);
427 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
428 globalSettingsDialog.ideSettings = data;
431 ide.updateRecentMenus();
432 ide.UpdateCompilerConfigs(true);
438 useNewConfigurationFiles = true;
440 CompilerConfigs::write(null);
445 SettingsIOResult Save()
447 SettingsIOResult result;
449 useNewConfigurationFiles = true;
450 data = (IDESettings)this.data;
451 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
452 data.ManagePortablePaths(moduleLocation, false);
453 data.ForcePathSeparatorStyle(true);
455 settingsFilePath = null;
456 result = GlobalSettings::Save();
457 if(result != success)
458 PrintLn("Error saving IDE settings");
461 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
462 data.ManagePortablePaths(moduleLocation, true);
465 FileGetSize(settingsFilePath, &settingsFileSize);
471 static Map<String, String> getCompilerConfigFilePathsByName(const char * path)
473 Map<String, String> map { };
474 FileListing fl { path, extensions = "econ" };
477 if(fl.stats.attribs.isFile)
479 char name[MAX_FILENAME];
480 char * path = CopyString(fl.path);
482 GetLastDirectory(path, name);
484 char * s = strstr(name, ".");
493 static Map<String, CompilerConfig> getCompilerConfigsByName(const char * path)
495 Map<String, CompilerConfig> map { };
496 FileListing fl { path, extensions = "econ" };
499 if(fl.stats.attribs.isFile)
501 char name[MAX_FILENAME];
502 char * path = CopyString(fl.path);
504 GetLastDirectory(path, name);
506 char * s = strstr(name, ".");
510 CompilerConfig ccfg = CompilerConfig::read(path);
520 static void getConfigFilePath(char * path, Class _class, char * dir, const char * configName)
523 strcpy(path, settingsContainer.settingsFilePath);
524 StripLastDirectory(path, path);
525 if(settingsContainer.oldConfig)
526 PathCatSlash(path, settingsDir);
527 if(_class == class(CompilerConfig))
529 PathCatSlash(path, "compilerConfigs");
534 PathCatSlash(path, configName);
535 ChangeExtension(path, "econ", path);
538 else if(_class == class(RecentFilesData))
539 PathCatSlash(path, "recentFiles.econ");
540 else if(_class == class(RecentWorkspacesData))
541 PathCatSlash(path, "recentWorkspaces.econ");
544 static SettingsIOResult writeConfigFile(const char * path, Class dataType, void * data)
546 SettingsIOResult result = error;
548 sf = safeWriteFileOpen(path, write);
551 WriteECONObject(sf.file, dataType, data, 0);
556 PrintLn($"error: could not safely open file for writing configuration: ", path);
560 static SettingsIOResult readConfigFile(const char * path, Class dataType, void ** data)
562 SettingsIOResult result = error;
564 if(!FileExists(path))
565 result = fileNotFound;
566 else if((sf = safeWriteFileOpen(path, read)))
568 JSONResult jsonResult;
570 ECONParser parser { f = sf.file };
571 sf.file.Seek(0, start);
572 jsonResult = parser.GetObject(dataType, data);
573 if(jsonResult != success)
577 if(jsonResult == success)
581 result = fileNotCompatibleWithDriver;
582 PrintLn($"error: could not parse configuration file: ", path);
594 char tmp[MAX_LOCATION];
595 char lck[MAX_LOCATION];
610 SafeFile safeWriteFileOpen(const char * path, FileOpenMode mode)
612 SafeFile sf { mode = mode };
613 strcpy(sf.lck, path);
614 strcat(sf.lck, ".lck");
615 strcpy(sf.tmp, path);
616 strcat(sf.tmp, ".tmp");
619 sf.lock = FileOpen(sf.lck, write);
620 if(sf.lock && sf.lock.Lock(exclusive, 0, 0, false))
622 if(sf.tmp && FileExists(path).isFile)
623 MoveFile(path, sf.tmp);
624 sf.file = FileOpen(path, write);
627 PrintLn($"warning: safeWriteFileOpen: unable to obtain exclusive lock for writing: ", sf.lck);
629 else if(mode == read)
634 for(c = 0; c < 10 && !(failed = sf.tmp && FileExists(sf.tmp).isFile); c++) Sleep(0.01);
637 sf.lock = FileOpen(sf.lck, write);
638 if(sf.lock && sf.lock.Lock(exclusive, 0, 0, false))
640 if(FileExists(sf.tmp).isFile)
642 if(FileExists(path).isFile)
644 MoveFile(sf.tmp, path);
647 PrintLn($"warning: safeWriteFileOpen: file is gone: ", sf.tmp);
652 PrintLn($"warning: safeWriteFileOpen: unable to obtain exclusive lock for failed write repair: ", sf.lck);
654 sf.lock = FileOpen(sf.lck, write);
655 if(sf.lock) delete sf.lock;
656 sf.lock = FileOpen(sf.lck, read);
659 for(c = 0; c < 10 && !(locked = sf.lock.Lock(shared, 0, 0, false)); c++) Sleep(0.01);
661 sf.file = FileOpen(path, read);
665 PrintLn($"warning: safeWriteFileOpen: does not yet support FileOpenMode::", mode);
669 class RecentFilesData
672 RecentFiles recentFiles;
675 class RecentWorkspacesData
678 RecentWorkspaces recentWorkspaces;
681 class IDESettings : GlobalSettingsData
684 property CompilerConfigs compilerConfigs
686 set { if(compilerConfigs) compilerConfigs.Free(); delete compilerConfigs; if(value) compilerConfigs = value; }
687 get { return compilerConfigs; }
688 isset { return false; }
690 property RecentFiles recentFiles
692 set { if(recentFiles) recentFiles.Free(); delete recentFiles; if(value) recentFiles = value; }
693 get { return recentFiles; }
694 isset { return false; }
696 property RecentWorkspaces recentProjects
698 set { if(recentProjects) recentProjects.Free(); delete recentProjects; if(value) recentProjects = value; }
699 get { return recentProjects; }
700 isset { return false; }
702 property const char * docDir
704 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
705 get { return docDir ? docDir : ""; }
706 isset { return docDir && docDir[0]; }
708 property const char * ideFileDialogLocation
710 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
711 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
712 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
714 property const char * ideProjectFileDialogLocation
716 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
717 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
718 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
721 bool showLineNumbers;
722 bool caretFollowsScrolling;
723 char * displayDriver;
725 // TODO: Classify settings
726 //EditorSettings editor { };
728 property const char * projectDefaultTargetDir
730 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
731 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
732 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
734 property const char * projectDefaultIntermediateObjDir
736 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
737 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
738 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
741 property const char * compilerConfigsDir
743 set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
744 get { return compilerConfigsDir ? compilerConfigsDir : ""; }
745 isset { return compilerConfigsDir && compilerConfigsDir[0]; }
748 property const char * defaultCompiler
750 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
751 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
752 isset { return defaultCompiler && defaultCompiler[0]; }
755 property const String language
760 language = CopyString(value);
762 get { return language; }
763 isset { return language != null; }
767 CompilerConfigs compilerConfigs { };
769 char * ideFileDialogLocation;
770 char * ideProjectFileDialogLocation;
771 char * projectDefaultTargetDir;
772 char * projectDefaultIntermediateObjDir;
773 char * compilerConfigsDir;
774 char * defaultCompiler;
776 RecentFiles recentFiles { };
777 RecentWorkspaces recentProjects { };
779 CompilerConfig GetCompilerConfig(const String compilerName)
781 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
782 CompilerConfig compilerConfig = null;
783 for(compiler : compilerConfigs)
785 if(!strcmp(compiler.name, name))
787 compilerConfig = compiler;
791 if(!compilerConfig && compilerConfigs.count)
792 compilerConfig = compilerConfigs.firstIterator.data;
794 incref compilerConfig;
795 return compilerConfig;
800 compilerConfigs.Free();
801 delete compilerConfigs;
802 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
803 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
806 delete projectDefaultTargetDir;
807 delete projectDefaultIntermediateObjDir;
808 delete compilerConfigsDir;
809 delete defaultCompiler;
812 delete ideFileDialogLocation;
813 delete ideProjectFileDialogLocation;
814 delete displayDriver;
817 void ForcePathSeparatorStyle(bool unixStyle)
821 from = '\\', to = '/';
823 from = '/', to = '\\';
824 if(compilerConfigs && compilerConfigs.count)
827 for(config : compilerConfigs)
829 if(config.includeDirs && config.includeDirs.count)
831 for(i = 0; i < config.includeDirs.count; i++)
833 if(config.includeDirs[i] && config.includeDirs[i][0])
834 ChangeCh(config.includeDirs[i], from, to);
837 if(config.libraryDirs && config.libraryDirs.count)
839 for(i = 0; i < config.libraryDirs.count; i++)
841 if(config.libraryDirs[i] && config.libraryDirs[i][0])
842 ChangeCh(config.libraryDirs[i], from, to);
845 if(config.executableDirs && config.executableDirs.count)
847 for(i = 0; i < config.executableDirs.count; i++)
849 if(config.executableDirs[i] && config.executableDirs[i][0])
850 ChangeCh(config.executableDirs[i], from, to);
855 recentFiles.changeChar(from, to);
856 recentProjects.changeChar(from, to);
857 if(docDir && docDir[0])
858 ChangeCh(docDir, from, to);
859 if(ideFileDialogLocation && ideFileDialogLocation[0])
860 ChangeCh(ideFileDialogLocation, from, to);
861 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
862 ChangeCh(ideProjectFileDialogLocation, from, to);
864 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
865 ChangeCh(projectDefaultTargetDir, from, to);
866 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
867 ChangeCh(projectDefaultIntermediateObjDir, from, to);
869 if(compilerConfigsDir && compilerConfigsDir[0])
870 ChangeCh(compilerConfigsDir, from, to);
873 void ManagePortablePaths(char * location, bool makeAbsolute)
876 if(compilerConfigs && compilerConfigs.count)
878 for(config : compilerConfigs)
881 for(t = 0; t < DirTypes::enumSize; t++)
883 Array<String> dirs = null;
884 if(t == executables) dirs = config.executableDirs;
885 else if(t == includes) dirs = config.includeDirs;
886 else if(t == libraries) dirs = config.libraryDirs;
887 if(dirs && dirs.count)
889 for(c = 0; c < dirs.count; c++)
891 if(dirs[c] && dirs[c][0])
892 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
898 if(recentFiles && recentFiles.count)
900 for(c = 0; c < recentFiles.count; c++)
902 if(recentFiles[c] && recentFiles[c][0])
903 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
906 if(recentProjects && recentProjects.count)
908 for(c = 0; c < recentProjects.count; c++)
910 if(recentProjects[c] && recentProjects[c][0])
911 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
914 if(docDir && docDir[0])
915 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
916 if(ideFileDialogLocation && ideFileDialogLocation[0])
917 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
918 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
919 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
921 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
922 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
923 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
924 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
926 if(compilerConfigsDir && compilerConfigsDir[0])
927 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
930 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
935 char p[MAX_LOCATION];
937 PathCatSlash(p, path);
939 output = CopyString(p);
943 PathRelationship rel = eString_PathRelated(path, location, null);
944 if(rel == subPath || rel == identical)
946 char p[MAX_LOCATION];
947 MakePathRelative(path, location, p);
948 if(!*p) strcpy(p, "./");
949 else ChangeCh(p, '\\', '/');
951 output = CopyString(p);
960 class RecentFiles : RecentPaths
969 char path[MAX_LOCATION];
970 RecentFilesData d = null;
971 Class _class = class(RecentFilesData);
972 getConfigFilePath(path, _class, null, null);
973 readConfigFile(path, _class, &d);
974 if(d && d.recentFiles && d.recentFiles.count)
976 IDESettings s = (IDESettings)settingsContainer.data;
977 s.property::recentFiles = d.recentFiles;
978 d.recentFiles = null;
979 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
980 ide.updateRecentFilesMenu();
988 char path[MAX_LOCATION];
989 IDESettings s = (IDESettings)settingsContainer.data;
990 RecentFilesData d { };
991 Class _class = class(RecentFilesData);
992 getConfigFilePath(path, _class, null, null);
993 d.recentFiles = s.recentFiles;
994 writeConfigFile(path, _class, d);
995 d.recentFiles = null;
1000 class RecentWorkspaces : RecentPaths
1009 char path[MAX_LOCATION];
1010 RecentWorkspacesData d = null;
1011 Class _class = class(RecentWorkspacesData);
1012 getConfigFilePath(path, _class, null, null);
1013 readConfigFile(path, _class, &d);
1014 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1016 IDESettings s = (IDESettings)settingsContainer.data;
1017 s.property::recentProjects = d.recentWorkspaces;
1018 d.recentWorkspaces = null;
1019 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1020 ide.updateRecentProjectsMenu();
1028 char path[MAX_LOCATION];
1029 IDESettings s = (IDESettings)settingsContainer.data;
1030 RecentWorkspacesData d { };
1031 Class _class = class(RecentWorkspacesData);
1032 getConfigFilePath(path, _class, null, null);
1033 d.recentWorkspaces = s.recentProjects;
1034 writeConfigFile(path, _class, d);
1035 d.recentWorkspaces = null;
1040 class RecentPaths : Array<String>
1042 virtual void onAdd();
1044 IteratorPointer Add(T value)
1047 char * filePath = (char *)value;
1048 ChangeCh(filePath, '\\', '/');
1049 for(c = 0; c < count; c++)
1051 if(this[c] && !fstrcmp(this[c], filePath))
1053 Delete((void *)&this[c]);
1057 return Array::Add((T)filePath);
1060 IteratorPointer addRecent(T value)
1063 char * filePath = (char *)value;
1065 ChangeCh(filePath, '\\', '/');
1066 for(c = 0; c < count; c++)
1068 if(this[c] && !fstrcmp(this[c], filePath))
1070 Delete((void *)&this[c]);
1074 while(count >= MaxRecent)
1076 ip = Insert(null, filePath);
1081 void changeChar(char from, char to)
1086 for(c = 0; c < count; c++)
1088 if(this[c] && this[c][0])
1089 ChangeCh(this[c], from, to);
1095 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1096 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1097 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1098 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1099 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1100 // TODO: i18n with Array
1101 static Array<const String> compilerTypeLongNames
1103 $"GNU Compiler Collection (GCC) / GNU Make",
1104 $"Tiny C Compiler / GNU Make",
1105 $"Portable C Compiler / GNU Make",
1106 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1107 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1108 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1110 const CompilerType firstCompilerType = gcc;
1111 const CompilerType lastCompilerType = vs10;
1112 public enum CompilerType
1114 gcc, tcc, pcc, vs8, vs9, vs10;
1118 get { return this == vs8 || this == vs9 || this == vs10; }
1121 property const char *
1123 get { return OnGetString(null, null, null); }
1129 for(c = firstCompilerType; c <= lastCompilerType; c++)
1130 if(!strcmpi(value, compilerTypeNames[c]))
1137 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1138 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1139 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1140 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1141 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1143 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1145 if(this >= firstCompilerType && this <= lastCompilerType)
1148 strcpy(tempString, compilerTypeNames[this]);
1149 if(fieldData == null)
1150 return compilerTypeNames[this];
1151 else if(fieldData == (void*)1)
1152 return compilerTypeLongNames[this];
1153 else if(fieldData == (void*)2)
1154 return compilerTypeVersionString[this];
1155 else if(fieldData == (void*)3)
1156 return compilerTypeYearString[this];
1157 else if(fieldData == (void*)4)
1158 return compilerTypeProjectFileExtension[this];
1159 else if(fieldData == (void*)5)
1160 return compilerTypeSolutionFileVersionString[this];
1166 class CompilerConfig
1172 property const char * name
1174 set { delete name; if(value) name = CopyString(value); }
1175 get { return name; }
1179 Platform targetPlatform;
1181 property const char * makeCommand
1183 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1184 get { return makeCommand; }
1185 isset { return makeCommand && makeCommand[0]; }
1187 property const char * ecpCommand
1189 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1190 get { return ecpCommand; }
1191 isset { return ecpCommand && ecpCommand[0]; }
1193 property const char * eccCommand
1195 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1196 get { return eccCommand; }
1197 isset { return eccCommand && eccCommand[0]; }
1199 property const char * ecsCommand
1201 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1202 get { return ecsCommand; }
1203 isset { return ecsCommand && ecsCommand[0]; }
1205 property const char * earCommand
1207 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1208 get { return earCommand; }
1209 isset { return earCommand && earCommand[0]; }
1211 property const char * cppCommand
1213 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1214 get { return cppCommand; }
1215 isset { return cppCommand && cppCommand[0]; }
1217 property const char * ccCommand
1219 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1220 get { return ccCommand; }
1221 isset { return ccCommand && ccCommand[0]; }
1223 property const char * cxxCommand
1225 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1226 get { return cxxCommand; }
1227 isset { return cxxCommand && cxxCommand[0]; }
1229 property const char * arCommand
1231 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1232 get { return arCommand; }
1233 isset { return arCommand && arCommand[0]; }
1235 property const char * ldCommand
1237 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1238 get { return ldCommand; }
1239 isset { return ldCommand && ldCommand[0]; }
1241 property const char * objectFileExt
1243 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1244 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1245 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1247 property const char * staticLibFileExt
1249 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1250 get { return staticLibFileExt; }
1251 isset { return staticLibFileExt && staticLibFileExt[0]; }
1253 property const char * sharedLibFileExt
1255 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1256 get { return sharedLibFileExt; }
1257 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1259 property const char * executableFileExt
1261 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1262 get { return executableFileExt; }
1263 isset { return executableFileExt && executableFileExt[0]; }
1265 property const char * executableLauncher
1267 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1268 get { return executableLauncher; }
1269 isset { return executableLauncher && executableLauncher[0]; }
1271 // TODO: implement CompilerConfig::windresCommand
1275 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1277 property const char * distccHosts
1279 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1280 get { return distccHosts; }
1281 isset { return distccHosts && distccHosts[0]; }
1283 property const char * gnuToolchainPrefix
1285 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1286 get { return gnuToolchainPrefix; }
1287 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1289 property const char * sysroot
1291 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1292 get { return sysroot; }
1293 isset { return sysroot && sysroot[0]; }
1295 bool resourcesDotEar;
1297 property Array<String> includeDirs
1305 includeDirs = value;
1308 get { return includeDirs; }
1309 isset { return includeDirs.count != 0; }
1311 property Array<String> libraryDirs
1319 libraryDirs = value;
1322 get { return libraryDirs; }
1323 isset { return libraryDirs.count != 0; }
1325 property Array<String> executableDirs
1329 executableDirs.Free();
1332 delete executableDirs;
1333 executableDirs = value;
1336 get { return executableDirs; }
1337 isset { return executableDirs.count != 0; }
1339 property Array<NamedString> environmentVars
1343 environmentVars.Free();
1346 delete environmentVars;
1347 environmentVars = value;
1350 get { return environmentVars; }
1351 isset { return environmentVars.count != 0; }
1353 property Array<String> prepDirectives
1357 prepDirectives.Free();
1360 delete prepDirectives;
1361 prepDirectives = value;
1364 get { return prepDirectives; }
1365 isset { return prepDirectives.count != 0; }
1367 property Array<String> excludeLibs
1375 excludeLibs = value;
1378 get { return excludeLibs; }
1379 isset { return excludeLibs.count != 0; }
1381 property Array<String> eCcompilerFlags
1385 eCcompilerFlags.Free();
1388 delete eCcompilerFlags;
1389 eCcompilerFlags = value;
1392 get { return eCcompilerFlags; }
1393 isset { return eCcompilerFlags.count != 0; }
1395 property Array<String> compilerFlags
1399 compilerFlags.Free();
1402 delete compilerFlags;
1403 compilerFlags = value;
1406 get { return compilerFlags; }
1407 isset { return compilerFlags.count != 0; }
1409 property Array<String> cxxFlags
1420 get { return cxxFlags; }
1421 isset { return cxxFlags.count != 0; }
1423 property Array<String> linkerFlags
1431 linkerFlags = value;
1434 get { return linkerFlags; }
1435 isset { return linkerFlags.count != 0; }
1437 // json backward compatibility
1438 property const char * gccPrefix
1440 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1441 get { return gnuToolchainPrefix; }
1442 isset { return false; }
1444 property const char * execPrefixCommand
1446 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1447 get { return executableLauncher; }
1448 isset { return false; }
1450 property const char * outputFileExt
1452 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1453 get { return executableFileExt; }
1454 isset { return false; }
1457 property bool hasDocumentOutput
1461 bool result = executableFileExt && executableFileExt[0] &&
1462 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1465 isset { return false; }
1468 Array<String> includeDirs { };
1469 Array<String> libraryDirs { };
1470 Array<String> executableDirs { };
1471 // TODO: Can JSON parse and serialize maps?
1472 //EnvironmentVariables { };
1473 Array<NamedString> environmentVars { };
1474 Array<String> prepDirectives { };
1475 Array<String> excludeLibs { };
1476 Array<String> eCcompilerFlags { };
1477 Array<String> compilerFlags { };
1478 Array<String> cxxFlags { };
1479 Array<String> linkerFlags { };
1491 char * objectFileExt;
1492 char * staticLibFileExt;
1493 char * sharedLibFileExt;
1494 char * executableFileExt;
1495 char * executableLauncher;
1497 char * gnuToolchainPrefix;
1501 struct { Array<String> includes, libraries, executables; };
1502 Array<String> dirs[DirTypes];
1517 delete objectFileExt;
1518 delete staticLibFileExt;
1519 delete sharedLibFileExt;
1520 delete executableFileExt;
1522 delete executableLauncher;
1524 delete gnuToolchainPrefix;
1526 if(environmentVars) environmentVars.Free();
1527 if(includeDirs) { includeDirs.Free(); }
1528 if(libraryDirs) { libraryDirs.Free(); }
1529 if(executableDirs) { executableDirs.Free(); }
1530 if(prepDirectives) { prepDirectives.Free(); }
1531 if(excludeLibs) { excludeLibs.Free(); }
1532 if(compilerFlags) { compilerFlags.Free(); }
1533 if(cxxFlags) { cxxFlags.Free(); }
1534 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1535 if(linkerFlags) { linkerFlags.Free(); }
1538 int OnCompare(CompilerConfig b)
1541 if(!(result = name.OnCompare(b.name)) &&
1542 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1543 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1544 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1545 !(result = earCommand.OnCompare(b.earCommand)) &&
1546 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1547 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1548 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1549 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1550 !(result = arCommand.OnCompare(b.arCommand)) &&
1551 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1552 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1553 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1554 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1555 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1556 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1557 !(result = sysroot.OnCompare(b.sysroot)))
1561 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1562 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1563 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1564 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1565 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1566 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1567 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1568 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1569 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1570 !(result = linkerFlags.OnCompare(b.linkerFlags)))
1577 CompilerConfig Copy()
1610 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1611 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1612 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1613 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1614 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1615 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1616 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1617 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
1618 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1619 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1625 CompilerConfig ::read(const char * path)
1627 CompilerConfig d = null;
1628 readConfigFile(path, class(CompilerConfig), &d);
1634 char dir[MAX_LOCATION];
1635 char path[MAX_LOCATION];
1636 const char * settingsFilePath = settingsContainer.settingsFilePath;
1637 getConfigFilePath(path, _class, dir, name);
1638 if(FileExists(settingsFilePath) && !FileExists(dir))
1641 if(!FileExists(dir))
1642 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1644 writeConfigFile(path, _class, this);
1648 class CompilerConfigs : List<CompilerConfig>
1652 IDESettings s = (IDESettings)settingsContainer.data;
1653 // Ensure we have a default compiler
1654 CompilerConfig defaultCompiler = null;
1655 defaultCompiler = s.GetCompilerConfig(defaultCompilerName);
1656 if(!defaultCompiler)
1658 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
1659 s.compilerConfigs.Insert(null, defaultCompiler);
1660 defaultCompiler = null;
1662 delete defaultCompiler;
1664 if(s.compilerConfigs)
1666 for(ccfg : s.compilerConfigs)
1668 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
1669 ccfg.ecpCommand = ecpDefaultCommand;
1670 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
1671 ccfg.eccCommand = eccDefaultCommand;
1672 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
1673 ccfg.ecsCommand = ecsDefaultCommand;
1674 if(!ccfg.earCommand || !ccfg.earCommand[0])
1675 ccfg.earCommand = earDefaultCommand;
1676 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
1677 ccfg.cppCommand = cppDefaultCommand;
1678 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
1679 ccfg.ccCommand = ccDefaultCommand;
1680 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
1681 ccfg.cxxCommand = cxxDefaultCommand;
1682 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
1683 ccfg.ldCommand = ldDefaultCommand;*/
1684 if(!ccfg.arCommand || !ccfg.arCommand[0])
1685 ccfg.arCommand = arDefaultCommand;
1686 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
1687 ccfg.objectFileExt = objectDefaultFileExt;
1688 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
1689 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
1690 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
1691 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
1692 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
1693 ccfg.executableFileExt = outputDefaultFileExt;*/
1694 if(!ccfg._refCount) incref ccfg;
1699 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
1701 AVLTree<String> list { };
1704 for(occfg : oldConfigs)
1706 if(!strcmp(ccfg.name, occfg.name))
1708 if(ccfg.OnCompare(occfg))
1709 list.Add(CopyString(ccfg.name));
1719 if(settingsContainer.settingsFilePath)
1721 char dir[MAX_LOCATION];
1722 char path[MAX_LOCATION];
1723 Class _class = class(CompilerConfig);
1724 getConfigFilePath(path, _class, dir, null);
1727 CompilerConfigs ccfgs { };
1728 AVLTree<const String> addedConfigs { };
1729 IDESettings s = (IDESettings)settingsContainer.data;
1730 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
1731 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
1732 if(it.Index("Default", false))
1734 CompilerConfig ccfg = it.data;
1735 ccfgs.Add(ccfg.Copy());
1736 addedConfigs.Add(ccfg.name);
1738 for(ccfg : compilerConfigsByName)
1740 if(!addedConfigs.Find(ccfg.name))
1742 ccfgs.Add(ccfg.Copy());
1743 addedConfigs.Add(ccfg.name);
1746 for(ccfg : s.compilerConfigs)
1748 if(!addedConfigs.Find(ccfg.name))
1749 ccfgs.Add(ccfg.Copy());
1751 delete addedConfigs;
1752 s.property::compilerConfigs = ccfgs;
1754 compilerConfigsByName.Free();
1755 delete compilerConfigsByName;
1756 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1757 ide.UpdateCompilerConfigs(true);
1763 void ::write(AVLTree<String> cfgsToWrite)
1765 char dir[MAX_LOCATION];
1766 char path[MAX_LOCATION];
1767 Map<String, String> paths;
1768 IDESettings s = (IDESettings)settingsContainer.data;
1769 getConfigFilePath(path, class(CompilerConfig), dir, null);
1770 paths = getCompilerConfigFilePathsByName(dir);
1772 MapIterator<String, String> it { map = paths };
1773 for(c : s.compilerConfigs)
1775 CompilerConfig ccfg = c;
1776 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
1778 if(it.Index(ccfg.name, false))
1787 const char * path = p;
1795 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1796 struct LanguageOption
1799 const String bitmap;
1803 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1808 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
1810 Bitmap icon = res ? res.bitmap : null;
1813 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
1814 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
1818 Array<LanguageOption> languages
1820 { "English", ":countryCode/gb.png", "" },
1821 { "汉语", ":countryCode/cn.png", "zh_CN" },
1822 { "Español", ":countryCode/es.png", "es" },
1823 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
1824 { "Русский (43%)", ":countryCode/ru.png", "ru" },
1825 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
1826 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
1827 { "मराठी (10%)", ":countryCode/in.png", "mr" },
1828 { "Hebrew (8%)", ":countryCode/il.png", "he" },
1829 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
1832 const String GetLanguageString()
1834 char * dot, * colon;
1835 static char lang[256];
1836 const String language = getenv("ECERE_LANGUAGE");
1837 if(!language) language = getenv("LANGUAGE");
1838 if(!language) language = getenv("LC_ALL");
1839 if(!language) language = getenv("LC_MESSAGES");
1840 if(!language) language = getenv("LANG");
1841 if(!language) language = "";
1842 if(language && (colon = strchr(language, ':')))
1844 if(lang != language)
1845 strncpy(lang, language, sizeof(lang));
1846 lang[sizeof(lang)-1] = 0;
1847 lang[colon - language] = 0;
1850 if(language && (dot = strchr(language, '.')))
1852 if(lang != language)
1853 strncpy(lang, language, sizeof(lang));
1854 lang[sizeof(lang)-1] = 0;
1855 lang[dot - language] = 0;
1861 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
1863 bool restart = true;
1864 String command = null;
1865 int arg0Len = (int)strlen(app.argv[0]);
1877 for(w = ide.firstChild; w; w = w.next)
1879 if(w.isActiveClient && w.isDocument)
1881 if(!w.CloseConfirmation(true))
1890 if(!projectView.CloseConfirmation(true))
1892 if(projectView.fileName)
1894 const char * name = projectView.fileName;
1897 for(j = 0; (ch = name[j]); j++)
1898 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1902 command = new char[len + 1];
1904 strcpy(command, app.argv[0]);
1906 if(projectView.fileName)
1908 strcat(command, " ");
1910 ReplaceSpaces(command + len, projectView.fileName);
1915 for(w = ide.firstChild; w; w = w.next)
1916 if(w.isActiveClient && w.isDocument)
1917 w.modifiedDocument = false;
1918 projectView.modifiedDocument = false;
1923 for(w = ide.firstChild; w; w = w.next)
1925 if(w.isActiveClient && w.isDocument)
1927 if(!w.CloseConfirmation(true))
1934 const char * name = w.fileName;
1936 for(j = 0; (ch = name[j]); j++)
1937 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1944 command = new char[len + 1];
1945 strcpy(command, app.argv[0]);
1948 for(w = ide.firstChild; w; w = w.next)
1950 if(w.isActiveClient && w.isDocument)
1952 const char * name = w.fileName;
1955 strcat(command, " ");
1957 ReplaceSpaces(command + len, name);
1958 len = (int)strlen(command);
1965 for(w = ide.firstChild; w; w = w.next)
1966 if(w.isActiveClient && w.isDocument)
1967 w.modifiedDocument = false;
1972 settings.language = code;
1973 settingsContainer.Save();
1975 setEcereLanguageInWinRegEnvironment(code);
1977 if(eClass_IsDerived(app._class, class(GuiApplication)))
1979 GuiApplication guiApp = (GuiApplication)app;
1980 guiApp.desktop.Destroy(0);
1987 for(i = 1; i < app.argc; i++)
1989 const char * arg = app.argv[i];
1991 for(j = 0; (ch = arg[j]); j++)
1992 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1995 command = new char[len + 1];
1996 strcpy(command, app.argv[0]);
1998 for(i = 1; i < app.argc; i++)
2000 strcat(command, " ");
2002 ReplaceSpaces(command + len, app.argv[i]);
2003 len = (int)strlen(command);
2009 SetEnvironment("ECERE_LANGUAGE", code);
2011 ExecuteWait(command);