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 * outputFileExt
1249 set { delete outputFileExt; if(value && value[0]) outputFileExt = CopyString(value); }
1250 get { return outputFileExt; }
1251 isset { return outputFileExt && outputFileExt[0]; }
1253 property const char * executableLauncher
1255 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1256 get { return executableLauncher; }
1257 isset { return executableLauncher && executableLauncher[0]; }
1259 // TODO: implement CompilerConfig::windresCommand
1263 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1265 property const char * distccHosts
1267 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1268 get { return distccHosts; }
1269 isset { return distccHosts && distccHosts[0]; }
1271 property const char * gnuToolchainPrefix
1273 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1274 get { return gnuToolchainPrefix; }
1275 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1277 property const char * sysroot
1279 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1280 get { return sysroot; }
1281 isset { return sysroot && sysroot[0]; }
1283 bool resourcesDotEar;
1284 property Array<String> includeDirs
1292 includeDirs = value;
1295 get { return includeDirs; }
1296 isset { return includeDirs.count != 0; }
1298 property Array<String> libraryDirs
1306 libraryDirs = value;
1309 get { return libraryDirs; }
1310 isset { return libraryDirs.count != 0; }
1312 property Array<String> executableDirs
1316 executableDirs.Free();
1319 delete executableDirs;
1320 executableDirs = value;
1323 get { return executableDirs; }
1324 isset { return executableDirs.count != 0; }
1326 property Array<NamedString> environmentVars
1330 environmentVars.Free();
1333 delete environmentVars;
1334 environmentVars = value;
1337 get { return environmentVars; }
1338 isset { return environmentVars.count != 0; }
1340 property Array<String> prepDirectives
1344 prepDirectives.Free();
1347 delete prepDirectives;
1348 prepDirectives = value;
1351 get { return prepDirectives; }
1352 isset { return prepDirectives.count != 0; }
1354 property Array<String> excludeLibs
1362 excludeLibs = value;
1365 get { return excludeLibs; }
1366 isset { return excludeLibs.count != 0; }
1368 property Array<String> eCcompilerFlags
1372 eCcompilerFlags.Free();
1375 delete eCcompilerFlags;
1376 eCcompilerFlags = value;
1379 get { return eCcompilerFlags; }
1380 isset { return eCcompilerFlags.count != 0; }
1382 property Array<String> compilerFlags
1386 compilerFlags.Free();
1389 delete compilerFlags;
1390 compilerFlags = value;
1393 get { return compilerFlags; }
1394 isset { return compilerFlags.count != 0; }
1396 property Array<String> linkerFlags
1404 linkerFlags = value;
1407 get { return linkerFlags; }
1408 isset { return linkerFlags.count != 0; }
1410 // json backward compatibility
1411 property const char * gccPrefix
1413 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1414 get { return gnuToolchainPrefix; }
1415 isset { return false; }
1417 property const char * execPrefixCommand
1419 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1420 get { return executableLauncher; }
1421 isset { return false; }
1424 Array<String> includeDirs { };
1425 Array<String> libraryDirs { };
1426 Array<String> executableDirs { };
1427 // TODO: Can JSON parse and serialize maps?
1428 //EnvironmentVariables { };
1429 Array<NamedString> environmentVars { };
1430 Array<String> prepDirectives { };
1431 Array<String> excludeLibs { };
1432 Array<String> eCcompilerFlags { };
1433 Array<String> compilerFlags { };
1434 Array<String> linkerFlags { };
1446 char * objectFileExt;
1447 char * outputFileExt;
1448 char * executableLauncher;
1450 char * gnuToolchainPrefix;
1454 struct { Array<String> includes, libraries, executables; };
1455 Array<String> dirs[DirTypes];
1470 delete objectFileExt;
1471 delete outputFileExt;
1473 delete executableLauncher;
1475 delete gnuToolchainPrefix;
1477 if(environmentVars) environmentVars.Free();
1478 if(includeDirs) { includeDirs.Free(); }
1479 if(libraryDirs) { libraryDirs.Free(); }
1480 if(executableDirs) { executableDirs.Free(); }
1481 if(prepDirectives) { prepDirectives.Free(); }
1482 if(excludeLibs) { excludeLibs.Free(); }
1483 if(compilerFlags) { compilerFlags.Free(); }
1484 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1485 if(linkerFlags) { linkerFlags.Free(); }
1488 int OnCompare(CompilerConfig b)
1491 if(!(result = name.OnCompare(b.name)) &&
1492 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1493 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1494 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1495 !(result = earCommand.OnCompare(b.earCommand)) &&
1496 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1497 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1498 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1499 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1500 !(result = arCommand.OnCompare(b.arCommand)) &&
1501 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1502 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1503 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1504 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1505 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1506 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1507 !(result = sysroot.OnCompare(b.sysroot)))
1511 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1512 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1513 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1514 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1515 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1516 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1517 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1518 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1519 !(result = linkerFlags.OnCompare(b.linkerFlags)))
1526 CompilerConfig Copy()
1556 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1557 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1558 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1559 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1560 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1561 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1562 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1563 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1564 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1570 CompilerConfig ::read(const char * path)
1572 CompilerConfig d = null;
1573 readConfigFile(path, class(CompilerConfig), &d);
1579 char dir[MAX_LOCATION];
1580 char path[MAX_LOCATION];
1581 const char * settingsFilePath = settingsContainer.settingsFilePath;
1582 getConfigFilePath(path, _class, dir, name);
1583 if(FileExists(settingsFilePath) && !FileExists(dir))
1586 if(!FileExists(dir))
1587 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1589 writeConfigFile(path, _class, this);
1593 class CompilerConfigs : List<CompilerConfig>
1597 IDESettings s = (IDESettings)settingsContainer.data;
1598 // Ensure we have a default compiler
1599 CompilerConfig defaultCompiler = null;
1600 defaultCompiler = s.GetCompilerConfig(defaultCompilerName);
1601 if(!defaultCompiler)
1603 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
1604 s.compilerConfigs.Insert(null, defaultCompiler);
1605 defaultCompiler = null;
1607 delete defaultCompiler;
1609 if(s.compilerConfigs)
1611 for(ccfg : s.compilerConfigs)
1613 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
1614 ccfg.ecpCommand = ecpDefaultCommand;
1615 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
1616 ccfg.eccCommand = eccDefaultCommand;
1617 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
1618 ccfg.ecsCommand = ecsDefaultCommand;
1619 if(!ccfg.earCommand || !ccfg.earCommand[0])
1620 ccfg.earCommand = earDefaultCommand;
1621 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
1622 ccfg.cppCommand = cppDefaultCommand;
1623 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
1624 ccfg.ccCommand = ccDefaultCommand;
1625 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
1626 ccfg.cxxCommand = cxxDefaultCommand;
1627 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
1628 ccfg.ldCommand = ldDefaultCommand;*/
1629 if(!ccfg.arCommand || !ccfg.arCommand[0])
1630 ccfg.arCommand = arDefaultCommand;
1631 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
1632 ccfg.objectFileExt = objectDefaultFileExt;
1633 /*if(!ccfg.outputFileExt || !ccfg.outputFileExt[0])
1634 ccfg.outputFileExt = outputDefaultFileExt;*/
1635 if(!ccfg._refCount) incref ccfg;
1640 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
1642 AVLTree<String> list { };
1645 for(occfg : oldConfigs)
1647 if(!strcmp(ccfg.name, occfg.name))
1649 if(ccfg.OnCompare(occfg))
1650 list.Add(CopyString(ccfg.name));
1660 if(settingsContainer.settingsFilePath)
1662 char dir[MAX_LOCATION];
1663 char path[MAX_LOCATION];
1664 Class _class = class(CompilerConfig);
1665 getConfigFilePath(path, _class, dir, null);
1668 CompilerConfigs ccfgs { };
1669 AVLTree<const String> addedConfigs { };
1670 IDESettings s = (IDESettings)settingsContainer.data;
1671 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
1672 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
1673 if(it.Index("Default", false))
1675 CompilerConfig ccfg = it.data;
1676 ccfgs.Add(ccfg.Copy());
1677 addedConfigs.Add(ccfg.name);
1679 for(ccfg : compilerConfigsByName)
1681 if(!addedConfigs.Find(ccfg.name))
1683 ccfgs.Add(ccfg.Copy());
1684 addedConfigs.Add(ccfg.name);
1687 for(ccfg : s.compilerConfigs)
1689 if(!addedConfigs.Find(ccfg.name))
1690 ccfgs.Add(ccfg.Copy());
1692 delete addedConfigs;
1693 s.property::compilerConfigs = ccfgs;
1695 compilerConfigsByName.Free();
1696 delete compilerConfigsByName;
1697 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1698 ide.UpdateCompilerConfigs(true);
1704 void ::write(AVLTree<String> cfgsToWrite)
1706 char dir[MAX_LOCATION];
1707 char path[MAX_LOCATION];
1708 Map<String, String> paths;
1709 IDESettings s = (IDESettings)settingsContainer.data;
1710 getConfigFilePath(path, class(CompilerConfig), dir, null);
1711 paths = getCompilerConfigFilePathsByName(dir);
1713 MapIterator<String, String> it { map = paths };
1714 for(c : s.compilerConfigs)
1716 CompilerConfig ccfg = c;
1717 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
1719 if(it.Index(ccfg.name, false))
1728 const char * path = p;
1736 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1737 struct LanguageOption
1740 const String bitmap;
1744 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1749 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
1751 Bitmap icon = res ? res.bitmap : null;
1754 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
1755 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
1759 Array<LanguageOption> languages
1761 { "English", ":countryCode/gb.png", "" },
1762 { "汉语", ":countryCode/cn.png", "zh_CN" },
1763 { "Español", ":countryCode/es.png", "es" },
1764 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
1765 { "Русский (43%)", ":countryCode/ru.png", "ru" },
1766 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
1767 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
1768 { "मराठी (10%)", ":countryCode/in.png", "mr" },
1769 { "Hebrew (8%)", ":countryCode/il.png", "he" },
1770 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
1773 const String GetLanguageString()
1775 char * dot, * colon;
1776 static char lang[256];
1777 const String language = getenv("ECERE_LANGUAGE");
1778 if(!language) language = getenv("LANGUAGE");
1779 if(!language) language = getenv("LC_ALL");
1780 if(!language) language = getenv("LC_MESSAGES");
1781 if(!language) language = getenv("LANG");
1782 if(!language) language = "";
1783 if(language && (colon = strchr(language, ':')))
1785 if(lang != language)
1786 strncpy(lang, language, sizeof(lang));
1787 lang[sizeof(lang)-1] = 0;
1788 lang[colon - language] = 0;
1791 if(language && (dot = strchr(language, '.')))
1793 if(lang != language)
1794 strncpy(lang, language, sizeof(lang));
1795 lang[sizeof(lang)-1] = 0;
1796 lang[dot - language] = 0;
1802 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
1804 bool restart = true;
1805 String command = null;
1806 int arg0Len = (int)strlen(app.argv[0]);
1818 for(w = ide.firstChild; w; w = w.next)
1820 if(w.isActiveClient && w.isDocument)
1822 if(!w.CloseConfirmation(true))
1831 if(!projectView.CloseConfirmation(true))
1833 if(projectView.fileName)
1835 const char * name = projectView.fileName;
1838 for(j = 0; (ch = name[j]); j++)
1839 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1843 command = new char[len + 1];
1845 strcpy(command, app.argv[0]);
1847 if(projectView.fileName)
1849 strcat(command, " ");
1851 ReplaceSpaces(command + len, projectView.fileName);
1856 for(w = ide.firstChild; w; w = w.next)
1857 if(w.isActiveClient && w.isDocument)
1858 w.modifiedDocument = false;
1859 projectView.modifiedDocument = false;
1864 for(w = ide.firstChild; w; w = w.next)
1866 if(w.isActiveClient && w.isDocument)
1868 if(!w.CloseConfirmation(true))
1875 const char * name = w.fileName;
1877 for(j = 0; (ch = name[j]); j++)
1878 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1885 command = new char[len + 1];
1886 strcpy(command, app.argv[0]);
1889 for(w = ide.firstChild; w; w = w.next)
1891 if(w.isActiveClient && w.isDocument)
1893 const char * name = w.fileName;
1896 strcat(command, " ");
1898 ReplaceSpaces(command + len, name);
1899 len = (int)strlen(command);
1906 for(w = ide.firstChild; w; w = w.next)
1907 if(w.isActiveClient && w.isDocument)
1908 w.modifiedDocument = false;
1913 settings.language = code;
1914 settingsContainer.Save();
1916 setEcereLanguageInWinRegEnvironment(code);
1918 if(eClass_IsDerived(app._class, class(GuiApplication)))
1920 GuiApplication guiApp = (GuiApplication)app;
1921 guiApp.desktop.Destroy(0);
1928 for(i = 1; i < app.argc; i++)
1930 const char * arg = app.argv[i];
1932 for(j = 0; (ch = arg[j]); j++)
1933 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1936 command = new char[len + 1];
1937 strcpy(command, app.argv[0]);
1939 for(i = 1; i < app.argc; i++)
1941 strcat(command, " ");
1943 ReplaceSpaces(command + len, app.argv[i]);
1944 len = (int)strlen(command);
1950 SetEnvironment("ECERE_LANGUAGE", code);
1952 ExecuteWait(command);