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;
246 //#define SETTINGS_TEST
248 define settingsDir = ".ecereIDE-SettingsTest";
249 define ideSettingsName = "ecereIDE-SettingsTest";
251 define settingsDir = ".ecereIDE";
252 define ideSettingsName = "ecereIDE";
255 class IDESettingsContainer : GlobalSettings
257 property bool useNewConfigurationFiles
263 settingsContainer.driver = "ECON";
264 settingsName = "config";
265 settingsExtension = "econ";
266 settingsDirectory = settingsDir;
270 settingsContainer.driver = "JSON";
271 settingsName = ideSettingsName;
272 settingsExtension = null;
273 settingsDirectory = null;
278 char moduleLocation[MAX_LOCATION];
282 FileSize settingsFileSize;
284 IDESettingsContainer()
286 char path[MAX_LOCATION];
288 LocateModule(null, moduleLocation);
289 strcpy(path, moduleLocation);
290 StripLastDirectory(moduleLocation, moduleLocation);
291 ChangeCh(moduleLocation, '\\', '/');
292 // PortableApps.com directory structure
293 if((start = strstr(path, "\\App\\EcereSDK\\bin\\ide.exe")))
295 char configFilePath[MAX_LOCATION];
296 char defaultConfigFilePath[MAX_LOCATION];
300 strcpy(configFilePath, path);
301 PathCat(configFilePath, "Data");
302 PathCat(configFilePath, ideSettingsName);
303 ChangeExtension(configFilePath, "ini", configFilePath);
305 strcpy(defaultConfigFilePath, path);
306 PathCat(defaultConfigFilePath, "App");
307 PathCat(defaultConfigFilePath, "DefaultData");
308 PathCat(defaultConfigFilePath, ideSettingsName);
309 ChangeExtension(defaultConfigFilePath, "ini", defaultConfigFilePath);
311 if(FileExists(defaultConfigFilePath))
313 if(!FileExists(configFilePath))
315 File f = FileOpen(defaultConfigFilePath, read);
316 f.CopyTo(configFilePath);
320 PathCat(path, "Data");
321 // the forced settings location will only be
322 // used if the running ide's path matches
323 // the PortableApps.com directory structure
324 // and the default ini file is found in
325 // the DefaultData directory
326 settingsLocation = path;
332 void OnAskReloadSettings()
334 FileSize newSettingsFileSize;
336 if(OpenAndLock(&newSettingsFileSize))
338 if((double)settingsFileSize - (double)newSettingsFileSize < 2048)
342 GuiApplication app = ((GuiApplication)__thisModule.application);
344 for(w = app.desktop.firstChild; w && (!w.created || !w.visible); w = w.next);
348 MessageBox { master = w, type = ok, isModal = true,
349 creationActivation = flash,
350 text = "Global Settings Modified Externally",
351 contents = "The global settings were modified by another process and a drastic shrinking of the settings file was detected.\n"
352 "The new settings will not be loaded to prevent loss of your ide settings.\n"
353 "Please check your settings file and make sure to save this IDE's global settings if your settings file has been compromised."
359 SettingsIOResult Load()
362 SettingsIOResult result;
363 useNewConfigurationFiles = true;
364 result = GlobalSettings::Load();
365 data = (IDESettings)this.data;
367 if(result == fileNotFound)
370 useNewConfigurationFiles = false;
371 result = GlobalSettings::Load();
373 data = (IDESettings)this.data;
376 this.data = IDESettings { };
378 *dataOwner = this.data;
380 if(result == fileNotCompatibleWithDriver)
383 OldIDESettings oldSettings { };
385 loaded = oldSettings.Load() == success;
389 data = (IDESettings)this.data;
391 for(c : oldSettings.compilerConfigs)
392 data.compilerConfigs.Add(c.Copy());
394 for(s : oldSettings.recentFiles) data.recentFiles.Add(s);
395 for(s : oldSettings.recentProjects) data.recentProjects.Add(s);
397 data.docDir = oldSettings.docDir;
398 data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
399 data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
400 data.useFreeCaret = oldSettings.useFreeCaret;
401 data.showLineNumbers = oldSettings.showLineNumbers;
402 data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
403 delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
404 data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
405 data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
412 if(result == fileNotFound || !data)
414 data = (IDESettings)this.data;
415 data.useFreeCaret = false; //true;
416 data.showLineNumbers = true;
417 data.caretFollowsScrolling = false; //true;
422 FileGetSize(settingsFilePath, &settingsFileSize);
423 CompilerConfigs::fix();
424 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
425 data.ManagePortablePaths(moduleLocation, true);
426 data.ForcePathSeparatorStyle(true);
428 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
429 globalSettingsDialog.ideSettings = data;
432 ide.updateRecentMenus();
433 ide.UpdateCompilerConfigs(true);
439 useNewConfigurationFiles = true;
441 CompilerConfigs::write(null);
446 SettingsIOResult Save()
448 SettingsIOResult result;
450 useNewConfigurationFiles = true;
451 data = (IDESettings)this.data;
452 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
453 data.ManagePortablePaths(moduleLocation, false);
454 data.ForcePathSeparatorStyle(true);
456 settingsFilePath = null;
457 result = GlobalSettings::Save();
458 if(result != success)
459 PrintLn("Error saving IDE settings");
462 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
463 data.ManagePortablePaths(moduleLocation, true);
466 FileGetSize(settingsFilePath, &settingsFileSize);
472 static Map<String, String> getCompilerConfigFilePathsByName(const char * path)
474 Map<String, String> map { };
475 FileListing fl { path, extensions = "econ" };
478 if(fl.stats.attribs.isFile)
480 char name[MAX_FILENAME];
481 char * path = CopyString(fl.path);
483 GetLastDirectory(path, name);
485 char * s = strstr(name, ".");
494 static Map<String, CompilerConfig> getCompilerConfigsByName(const char * path)
496 Map<String, CompilerConfig> map { };
497 FileListing fl { path, extensions = "econ" };
500 if(fl.stats.attribs.isFile)
502 char name[MAX_FILENAME];
503 char * path = CopyString(fl.path);
505 GetLastDirectory(path, name);
507 char * s = strstr(name, ".");
511 CompilerConfig ccfg = CompilerConfig::read(path);
521 static void getConfigFilePath(char * path, Class _class, char * dir, const char * configName)
524 strcpy(path, settingsContainer.settingsFilePath);
525 StripLastDirectory(path, path);
526 if(settingsContainer.oldConfig)
527 PathCatSlash(path, settingsDir);
528 if(_class == class(CompilerConfig))
530 PathCatSlash(path, "compilerConfigs");
535 PathCatSlash(path, configName);
536 ChangeExtension(path, "econ", path);
539 else if(_class == class(RecentFilesData))
540 PathCatSlash(path, "recentFiles.econ");
541 else if(_class == class(RecentWorkspacesData))
542 PathCatSlash(path, "recentWorkspaces.econ");
545 static SettingsIOResult writeConfigFile(const char * path, Class dataType, void * data)
547 SettingsIOResult result = error;
549 sf = safeWriteFileOpen(path, write);
552 WriteECONObject(sf.file, dataType, data, 0);
557 PrintLn($"error: could not safely open file for writing configuration: ", path);
561 static SettingsIOResult readConfigFile(const char * path, Class dataType, void ** data)
563 SettingsIOResult result = error;
565 if(!FileExists(path))
566 result = fileNotFound;
567 else if((sf = safeWriteFileOpen(path, read)))
569 JSONResult jsonResult;
571 ECONParser parser { f = sf.file };
572 sf.file.Seek(0, start);
573 jsonResult = parser.GetObject(dataType, data);
574 if(jsonResult != success)
578 if(jsonResult == success)
582 result = fileNotCompatibleWithDriver;
583 PrintLn($"error: could not parse configuration file: ", path);
594 char path[MAX_LOCATION];
595 char tmp[MAX_LOCATION];
600 // how to make this atomic ?
604 for(c = 0; c < 10; c++)
606 if(FileExists(path).isFile)
611 if(FileExists(path).isFile)
619 SafeFile safeWriteFileOpen(const char * path, FileOpenMode mode)
621 SafeFile sf { mode = mode };
624 strcpy(sf.path, path);
625 strcpy(sf.tmp, path);
626 strcat(sf.tmp, ".tmp");
629 if(FileExists(sf.tmp).isFile)
631 sf.file = FileOpen(sf.tmp, write);
634 for(c = 0; c < 10 && !(locked = sf.file.Lock(exclusive, 0, 0, false)); c++);
638 PrintLn($"warning: safeWriteFileOpen: unable to obtain exclusive lock on temporary file for writing: ", sf.tmp);
642 PrintLn($"warning: safeWriteFileOpen: unable to open temporary file for writing: ", sf.tmp);
644 else if(mode == read)
646 sf.file = FileOpen(path, read);
649 for(c = 0; c < 10 && !(locked = sf.file.Lock(shared, 0, 0, false)); c++) Sleep(0.01);
653 PrintLn($"warning: safeWriteFileOpen: unable to obtain shared lock on file for reading: ", path);
658 PrintLn($"warning: safeWriteFileOpen: does not yet support FileOpenMode::", mode);
662 class RecentFilesData
665 RecentFiles recentFiles;
668 class RecentWorkspacesData
671 RecentWorkspaces recentWorkspaces;
674 class IDESettings : GlobalSettingsData
677 property CompilerConfigs compilerConfigs
679 set { if(compilerConfigs) compilerConfigs.Free(); delete compilerConfigs; if(value) compilerConfigs = value; }
680 get { return compilerConfigs; }
681 isset { return false; }
683 property RecentFiles recentFiles
685 set { if(recentFiles) recentFiles.Free(); delete recentFiles; if(value) recentFiles = value; }
686 get { return recentFiles; }
687 isset { return false; }
689 property RecentWorkspaces recentProjects
691 set { if(recentProjects) recentProjects.Free(); delete recentProjects; if(value) recentProjects = value; }
692 get { return recentProjects; }
693 isset { return false; }
695 property const char * docDir
697 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
698 get { return docDir ? docDir : ""; }
699 isset { return docDir && docDir[0]; }
701 property const char * ideFileDialogLocation
703 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
704 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
705 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
707 property const char * ideProjectFileDialogLocation
709 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
710 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
711 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
714 bool showLineNumbers;
715 bool caretFollowsScrolling;
716 char * displayDriver;
718 // TODO: Classify settings
719 //EditorSettings editor { };
721 property const char * projectDefaultTargetDir
723 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
724 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
725 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
727 property const char * projectDefaultIntermediateObjDir
729 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
730 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
731 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
734 property const char * compilerConfigsDir
736 set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
737 get { return compilerConfigsDir ? compilerConfigsDir : ""; }
738 isset { return compilerConfigsDir && compilerConfigsDir[0]; }
741 property const char * defaultCompiler
743 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
744 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
745 isset { return defaultCompiler && defaultCompiler[0]; }
748 property const String language
753 language = CopyString(value);
755 get { return language; }
756 isset { return language != null; }
760 CompilerConfigs compilerConfigs { };
762 char * ideFileDialogLocation;
763 char * ideProjectFileDialogLocation;
764 char * projectDefaultTargetDir;
765 char * projectDefaultIntermediateObjDir;
766 char * compilerConfigsDir;
767 char * defaultCompiler;
769 RecentFiles recentFiles { };
770 RecentWorkspaces recentProjects { };
772 CompilerConfig GetCompilerConfig(const String compilerName)
774 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
775 CompilerConfig compilerConfig = null;
776 for(compiler : compilerConfigs)
778 if(!strcmp(compiler.name, name))
780 compilerConfig = compiler;
784 if(!compilerConfig && compilerConfigs.count)
785 compilerConfig = compilerConfigs.firstIterator.data;
787 incref compilerConfig;
788 return compilerConfig;
793 compilerConfigs.Free();
794 delete compilerConfigs;
795 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
796 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
799 delete projectDefaultTargetDir;
800 delete projectDefaultIntermediateObjDir;
801 delete compilerConfigsDir;
802 delete defaultCompiler;
805 delete ideFileDialogLocation;
806 delete ideProjectFileDialogLocation;
807 delete displayDriver;
810 void ForcePathSeparatorStyle(bool unixStyle)
814 from = '\\', to = '/';
816 from = '/', to = '\\';
817 if(compilerConfigs && compilerConfigs.count)
820 for(config : compilerConfigs)
822 if(config.includeDirs && config.includeDirs.count)
824 for(i = 0; i < config.includeDirs.count; i++)
826 if(config.includeDirs[i] && config.includeDirs[i][0])
827 ChangeCh(config.includeDirs[i], from, to);
830 if(config.libraryDirs && config.libraryDirs.count)
832 for(i = 0; i < config.libraryDirs.count; i++)
834 if(config.libraryDirs[i] && config.libraryDirs[i][0])
835 ChangeCh(config.libraryDirs[i], from, to);
838 if(config.executableDirs && config.executableDirs.count)
840 for(i = 0; i < config.executableDirs.count; i++)
842 if(config.executableDirs[i] && config.executableDirs[i][0])
843 ChangeCh(config.executableDirs[i], from, to);
848 recentFiles.changeChar(from, to);
849 recentProjects.changeChar(from, to);
850 if(docDir && docDir[0])
851 ChangeCh(docDir, from, to);
852 if(ideFileDialogLocation && ideFileDialogLocation[0])
853 ChangeCh(ideFileDialogLocation, from, to);
854 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
855 ChangeCh(ideProjectFileDialogLocation, from, to);
857 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
858 ChangeCh(projectDefaultTargetDir, from, to);
859 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
860 ChangeCh(projectDefaultIntermediateObjDir, from, to);
862 if(compilerConfigsDir && compilerConfigsDir[0])
863 ChangeCh(compilerConfigsDir, from, to);
866 void ManagePortablePaths(char * location, bool makeAbsolute)
869 if(compilerConfigs && compilerConfigs.count)
871 for(config : compilerConfigs)
874 for(t = 0; t < DirTypes::enumSize; t++)
876 Array<String> dirs = null;
877 if(t == executables) dirs = config.executableDirs;
878 else if(t == includes) dirs = config.includeDirs;
879 else if(t == libraries) dirs = config.libraryDirs;
880 if(dirs && dirs.count)
882 for(c = 0; c < dirs.count; c++)
884 if(dirs[c] && dirs[c][0])
885 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
891 if(recentFiles && recentFiles.count)
893 for(c = 0; c < recentFiles.count; c++)
895 if(recentFiles[c] && recentFiles[c][0])
896 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
899 if(recentProjects && recentProjects.count)
901 for(c = 0; c < recentProjects.count; c++)
903 if(recentProjects[c] && recentProjects[c][0])
904 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
907 if(docDir && docDir[0])
908 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
909 if(ideFileDialogLocation && ideFileDialogLocation[0])
910 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
911 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
912 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
914 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
915 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
916 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
917 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
919 if(compilerConfigsDir && compilerConfigsDir[0])
920 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
923 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
928 char p[MAX_LOCATION];
930 PathCatSlash(p, path);
932 output = CopyString(p);
936 PathRelationship rel = eString_PathRelated(path, location, null);
937 if(rel == subPath || rel == identical)
939 char p[MAX_LOCATION];
940 MakePathRelative(path, location, p);
941 if(!*p) strcpy(p, "./");
942 else ChangeCh(p, '\\', '/');
944 output = CopyString(p);
953 class RecentFiles : RecentPaths
962 char path[MAX_LOCATION];
963 RecentFilesData d = null;
964 Class _class = class(RecentFilesData);
965 getConfigFilePath(path, _class, null, null);
966 readConfigFile(path, _class, &d);
967 if(d && d.recentFiles && d.recentFiles.count)
969 IDESettings s = (IDESettings)settingsContainer.data;
970 s.property::recentFiles = d.recentFiles;
971 d.recentFiles = null;
972 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
973 ide.updateRecentFilesMenu();
981 char path[MAX_LOCATION];
982 IDESettings s = (IDESettings)settingsContainer.data;
983 RecentFilesData d { };
984 Class _class = class(RecentFilesData);
985 getConfigFilePath(path, _class, null, null);
986 d.recentFiles = s.recentFiles;
987 writeConfigFile(path, _class, d);
988 d.recentFiles = null;
993 class RecentWorkspaces : RecentPaths
1002 char path[MAX_LOCATION];
1003 RecentWorkspacesData d = null;
1004 Class _class = class(RecentWorkspacesData);
1005 getConfigFilePath(path, _class, null, null);
1006 readConfigFile(path, _class, &d);
1007 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1009 IDESettings s = (IDESettings)settingsContainer.data;
1010 s.property::recentProjects = d.recentWorkspaces;
1011 d.recentWorkspaces = null;
1012 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1013 ide.updateRecentProjectsMenu();
1021 char path[MAX_LOCATION];
1022 IDESettings s = (IDESettings)settingsContainer.data;
1023 RecentWorkspacesData d { };
1024 Class _class = class(RecentWorkspacesData);
1025 getConfigFilePath(path, _class, null, null);
1026 d.recentWorkspaces = s.recentProjects;
1027 writeConfigFile(path, _class, d);
1028 d.recentWorkspaces = null;
1033 class RecentPaths : Array<String>
1035 virtual void onAdd();
1037 IteratorPointer Add(T value)
1040 char * filePath = (char *)value;
1041 ChangeCh(filePath, '\\', '/');
1042 for(c = 0; c < count; c++)
1044 if(this[c] && !fstrcmp(this[c], filePath))
1046 Delete((void *)&this[c]);
1050 return Array::Add((T)filePath);
1053 IteratorPointer addRecent(T value)
1056 char * filePath = (char *)value;
1058 ChangeCh(filePath, '\\', '/');
1059 for(c = 0; c < count; c++)
1061 if(this[c] && !fstrcmp(this[c], filePath))
1063 Delete((void *)&this[c]);
1067 while(count >= MaxRecent)
1069 ip = Insert(null, filePath);
1074 void changeChar(char from, char to)
1079 for(c = 0; c < count; c++)
1081 if(this[c] && this[c][0])
1082 ChangeCh(this[c], from, to);
1088 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1089 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1090 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1091 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1092 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1093 // TODO: i18n with Array
1094 static Array<const String> compilerTypeLongNames
1096 $"GNU Compiler Collection (GCC) / GNU Make",
1097 $"Tiny C Compiler / GNU Make",
1098 $"Portable C Compiler / GNU Make",
1099 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1100 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1101 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1103 const CompilerType firstCompilerType = gcc;
1104 const CompilerType lastCompilerType = vs10;
1105 public enum CompilerType
1107 gcc, tcc, pcc, vs8, vs9, vs10;
1111 get { return this == vs8 || this == vs9 || this == vs10; }
1114 property const char *
1116 get { return OnGetString(null, null, null); }
1122 for(c = firstCompilerType; c <= lastCompilerType; c++)
1123 if(!strcmpi(value, compilerTypeNames[c]))
1130 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1131 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1132 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1133 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1134 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1136 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1138 if(this >= firstCompilerType && this <= lastCompilerType)
1141 strcpy(tempString, compilerTypeNames[this]);
1142 if(fieldData == null)
1143 return compilerTypeNames[this];
1144 else if(fieldData == (void*)1)
1145 return compilerTypeLongNames[this];
1146 else if(fieldData == (void*)2)
1147 return compilerTypeVersionString[this];
1148 else if(fieldData == (void*)3)
1149 return compilerTypeYearString[this];
1150 else if(fieldData == (void*)4)
1151 return compilerTypeProjectFileExtension[this];
1152 else if(fieldData == (void*)5)
1153 return compilerTypeSolutionFileVersionString[this];
1159 class CompilerConfig
1165 property const char * name
1167 set { delete name; if(value) name = CopyString(value); }
1168 get { return name; }
1172 Platform targetPlatform;
1174 property const char * makeCommand
1176 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1177 get { return makeCommand; }
1178 isset { return makeCommand && makeCommand[0]; }
1180 property const char * ecpCommand
1182 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1183 get { return ecpCommand; }
1184 isset { return ecpCommand && ecpCommand[0]; }
1186 property const char * eccCommand
1188 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1189 get { return eccCommand; }
1190 isset { return eccCommand && eccCommand[0]; }
1192 property const char * ecsCommand
1194 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1195 get { return ecsCommand; }
1196 isset { return ecsCommand && ecsCommand[0]; }
1198 property const char * earCommand
1200 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1201 get { return earCommand; }
1202 isset { return earCommand && earCommand[0]; }
1204 property const char * cppCommand
1206 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1207 get { return cppCommand; }
1208 isset { return cppCommand && cppCommand[0]; }
1210 property const char * ccCommand
1212 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1213 get { return ccCommand; }
1214 isset { return ccCommand && ccCommand[0]; }
1216 property const char * cxxCommand
1218 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1219 get { return cxxCommand; }
1220 isset { return cxxCommand && cxxCommand[0]; }
1222 property const char * arCommand
1224 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1225 get { return arCommand; }
1226 isset { return arCommand && arCommand[0]; }
1228 property const char * ldCommand
1230 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1231 get { return ldCommand; }
1232 isset { return ldCommand && ldCommand[0]; }
1234 property const char * objectFileExt
1236 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1237 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1238 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1240 property const char * staticLibFileExt
1242 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1243 get { return staticLibFileExt; }
1244 isset { return staticLibFileExt && staticLibFileExt[0]; }
1246 property const char * sharedLibFileExt
1248 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1249 get { return sharedLibFileExt; }
1250 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1252 property const char * executableFileExt
1254 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1255 get { return executableFileExt; }
1256 isset { return executableFileExt && executableFileExt[0]; }
1258 property const char * executableLauncher
1260 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1261 get { return executableLauncher; }
1262 isset { return executableLauncher && executableLauncher[0]; }
1264 // TODO: implement CompilerConfig::windresCommand
1268 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1270 property const char * distccHosts
1272 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1273 get { return distccHosts; }
1274 isset { return distccHosts && distccHosts[0]; }
1276 property const char * gnuToolchainPrefix
1278 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1279 get { return gnuToolchainPrefix; }
1280 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1282 property const char * sysroot
1284 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1285 get { return sysroot; }
1286 isset { return sysroot && sysroot[0]; }
1288 bool resourcesDotEar;
1290 property Array<String> includeDirs
1298 includeDirs = value;
1301 get { return includeDirs; }
1302 isset { return includeDirs.count != 0; }
1304 property Array<String> libraryDirs
1312 libraryDirs = value;
1315 get { return libraryDirs; }
1316 isset { return libraryDirs.count != 0; }
1318 property Array<String> executableDirs
1322 executableDirs.Free();
1325 delete executableDirs;
1326 executableDirs = value;
1329 get { return executableDirs; }
1330 isset { return executableDirs.count != 0; }
1332 property Array<NamedString> environmentVars
1336 environmentVars.Free();
1339 delete environmentVars;
1340 environmentVars = value;
1343 get { return environmentVars; }
1344 isset { return environmentVars.count != 0; }
1346 property Array<String> prepDirectives
1350 prepDirectives.Free();
1353 delete prepDirectives;
1354 prepDirectives = value;
1357 get { return prepDirectives; }
1358 isset { return prepDirectives.count != 0; }
1360 property Array<String> excludeLibs
1368 excludeLibs = value;
1371 get { return excludeLibs; }
1372 isset { return excludeLibs.count != 0; }
1374 property Array<String> eCcompilerFlags
1378 eCcompilerFlags.Free();
1381 delete eCcompilerFlags;
1382 eCcompilerFlags = value;
1385 get { return eCcompilerFlags; }
1386 isset { return eCcompilerFlags.count != 0; }
1388 property Array<String> compilerFlags
1392 compilerFlags.Free();
1395 delete compilerFlags;
1396 compilerFlags = value;
1399 get { return compilerFlags; }
1400 isset { return compilerFlags.count != 0; }
1402 property Array<String> cxxFlags
1413 get { return cxxFlags; }
1414 isset { return cxxFlags.count != 0; }
1416 property Array<String> linkerFlags
1424 linkerFlags = value;
1427 get { return linkerFlags; }
1428 isset { return linkerFlags.count != 0; }
1430 // json backward compatibility
1431 property const char * gccPrefix
1433 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1434 get { return gnuToolchainPrefix; }
1435 isset { return false; }
1437 property const char * execPrefixCommand
1439 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1440 get { return executableLauncher; }
1441 isset { return false; }
1443 property const char * outputFileExt
1445 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1446 get { return executableFileExt; }
1447 isset { return false; }
1450 property bool hasDocumentOutput
1454 bool result = executableFileExt && executableFileExt[0] &&
1455 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1458 isset { return false; }
1461 Array<String> includeDirs { };
1462 Array<String> libraryDirs { };
1463 Array<String> executableDirs { };
1464 // TODO: Can JSON parse and serialize maps?
1465 //EnvironmentVariables { };
1466 Array<NamedString> environmentVars { };
1467 Array<String> prepDirectives { };
1468 Array<String> excludeLibs { };
1469 Array<String> eCcompilerFlags { };
1470 Array<String> compilerFlags { };
1471 Array<String> cxxFlags { };
1472 Array<String> linkerFlags { };
1484 char * objectFileExt;
1485 char * staticLibFileExt;
1486 char * sharedLibFileExt;
1487 char * executableFileExt;
1488 char * executableLauncher;
1490 char * gnuToolchainPrefix;
1494 struct { Array<String> includes, libraries, executables; };
1495 Array<String> dirs[DirTypes];
1510 delete objectFileExt;
1511 delete staticLibFileExt;
1512 delete sharedLibFileExt;
1513 delete executableFileExt;
1515 delete executableLauncher;
1517 delete gnuToolchainPrefix;
1519 if(environmentVars) environmentVars.Free();
1520 if(includeDirs) { includeDirs.Free(); }
1521 if(libraryDirs) { libraryDirs.Free(); }
1522 if(executableDirs) { executableDirs.Free(); }
1523 if(prepDirectives) { prepDirectives.Free(); }
1524 if(excludeLibs) { excludeLibs.Free(); }
1525 if(compilerFlags) { compilerFlags.Free(); }
1526 if(cxxFlags) { cxxFlags.Free(); }
1527 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1528 if(linkerFlags) { linkerFlags.Free(); }
1531 int OnCompare(CompilerConfig b)
1534 if(!(result = name.OnCompare(b.name)) &&
1535 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1536 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1537 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1538 !(result = earCommand.OnCompare(b.earCommand)) &&
1539 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1540 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1541 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1542 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1543 !(result = arCommand.OnCompare(b.arCommand)) &&
1544 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1545 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1546 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1547 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1548 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1549 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1550 !(result = sysroot.OnCompare(b.sysroot)))
1554 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1555 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1556 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1557 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1558 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1559 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1560 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1561 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1562 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1563 !(result = linkerFlags.OnCompare(b.linkerFlags)))
1570 CompilerConfig Copy()
1603 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1604 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1605 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1606 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1607 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1608 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1609 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1610 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
1611 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1612 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1618 CompilerConfig ::read(const char * path)
1620 CompilerConfig d = null;
1621 readConfigFile(path, class(CompilerConfig), &d);
1627 char dir[MAX_LOCATION];
1628 char path[MAX_LOCATION];
1629 const char * settingsFilePath = settingsContainer.settingsFilePath;
1630 getConfigFilePath(path, _class, dir, name);
1631 if(FileExists(settingsFilePath) && !FileExists(dir))
1634 if(!FileExists(dir))
1635 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1637 writeConfigFile(path, _class, this);
1641 class CompilerConfigs : List<CompilerConfig>
1645 IDESettings s = (IDESettings)settingsContainer.data;
1646 // Ensure we have a default compiler
1647 CompilerConfig defaultCompiler = null;
1648 defaultCompiler = s.GetCompilerConfig(defaultCompilerName);
1649 if(!defaultCompiler)
1651 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
1652 s.compilerConfigs.Insert(null, defaultCompiler);
1653 defaultCompiler = null;
1655 delete defaultCompiler;
1657 if(s.compilerConfigs)
1659 for(ccfg : s.compilerConfigs)
1661 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
1662 ccfg.ecpCommand = ecpDefaultCommand;
1663 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
1664 ccfg.eccCommand = eccDefaultCommand;
1665 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
1666 ccfg.ecsCommand = ecsDefaultCommand;
1667 if(!ccfg.earCommand || !ccfg.earCommand[0])
1668 ccfg.earCommand = earDefaultCommand;
1669 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
1670 ccfg.cppCommand = cppDefaultCommand;
1671 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
1672 ccfg.ccCommand = ccDefaultCommand;
1673 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
1674 ccfg.cxxCommand = cxxDefaultCommand;
1675 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
1676 ccfg.ldCommand = ldDefaultCommand;*/
1677 if(!ccfg.arCommand || !ccfg.arCommand[0])
1678 ccfg.arCommand = arDefaultCommand;
1679 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
1680 ccfg.objectFileExt = objectDefaultFileExt;
1681 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
1682 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
1683 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
1684 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
1685 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
1686 ccfg.executableFileExt = outputDefaultFileExt;*/
1687 if(!ccfg._refCount) incref ccfg;
1692 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
1694 AVLTree<String> list { };
1697 for(occfg : oldConfigs)
1699 if(!strcmp(ccfg.name, occfg.name))
1701 if(ccfg.OnCompare(occfg))
1702 list.Add(CopyString(ccfg.name));
1712 if(settingsContainer.settingsFilePath)
1714 char dir[MAX_LOCATION];
1715 char path[MAX_LOCATION];
1716 Class _class = class(CompilerConfig);
1717 getConfigFilePath(path, _class, dir, null);
1720 CompilerConfigs ccfgs { };
1721 AVLTree<const String> addedConfigs { };
1722 IDESettings s = (IDESettings)settingsContainer.data;
1723 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
1724 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
1725 if(it.Index("Default", false))
1727 CompilerConfig ccfg = it.data;
1728 ccfgs.Add(ccfg.Copy());
1729 addedConfigs.Add(ccfg.name);
1731 for(ccfg : compilerConfigsByName)
1733 if(!addedConfigs.Find(ccfg.name))
1735 ccfgs.Add(ccfg.Copy());
1736 addedConfigs.Add(ccfg.name);
1739 for(ccfg : s.compilerConfigs)
1741 if(!addedConfigs.Find(ccfg.name))
1742 ccfgs.Add(ccfg.Copy());
1744 delete addedConfigs;
1745 s.property::compilerConfigs = ccfgs;
1747 compilerConfigsByName.Free();
1748 delete compilerConfigsByName;
1749 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1750 ide.UpdateCompilerConfigs(true);
1756 void ::write(AVLTree<String> cfgsToWrite)
1758 char dir[MAX_LOCATION];
1759 char path[MAX_LOCATION];
1760 Map<String, String> paths;
1761 IDESettings s = (IDESettings)settingsContainer.data;
1762 getConfigFilePath(path, class(CompilerConfig), dir, null);
1763 paths = getCompilerConfigFilePathsByName(dir);
1765 MapIterator<String, String> it { map = paths };
1766 for(c : s.compilerConfigs)
1768 CompilerConfig ccfg = c;
1769 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
1771 if(it.Index(ccfg.name, false))
1780 const char * path = p;
1788 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
1789 struct LanguageOption
1792 const String bitmap;
1796 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1801 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
1803 Bitmap icon = res ? res.bitmap : null;
1806 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
1807 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
1811 Array<LanguageOption> languages
1813 { "English", ":countryCode/gb.png", "" },
1814 { "汉语", ":countryCode/cn.png", "zh_CN" },
1815 { "Español", ":countryCode/es.png", "es" },
1816 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
1817 { "Русский (43%)", ":countryCode/ru.png", "ru" },
1818 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
1819 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
1820 { "मराठी (10%)", ":countryCode/in.png", "mr" },
1821 { "Hebrew (8%)", ":countryCode/il.png", "he" },
1822 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
1825 const String GetLanguageString()
1827 char * dot, * colon;
1828 static char lang[256];
1829 const String language = getenv("ECERE_LANGUAGE");
1830 if(!language) language = getenv("LANGUAGE");
1831 if(!language) language = getenv("LC_ALL");
1832 if(!language) language = getenv("LC_MESSAGES");
1833 if(!language) language = getenv("LANG");
1834 if(!language) language = "";
1835 if(language && (colon = strchr(language, ':')))
1837 if(lang != language)
1838 strncpy(lang, language, sizeof(lang));
1839 lang[sizeof(lang)-1] = 0;
1840 lang[colon - language] = 0;
1843 if(language && (dot = strchr(language, '.')))
1845 if(lang != language)
1846 strncpy(lang, language, sizeof(lang));
1847 lang[sizeof(lang)-1] = 0;
1848 lang[dot - language] = 0;
1854 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
1856 bool restart = true;
1857 String command = null;
1858 int arg0Len = (int)strlen(app.argv[0]);
1870 for(w = ide.firstChild; w; w = w.next)
1872 if(w.isActiveClient && w.isDocument)
1874 if(!w.CloseConfirmation(true))
1883 if(!projectView.CloseConfirmation(true))
1885 if(projectView.fileName)
1887 const char * name = projectView.fileName;
1890 for(j = 0; (ch = name[j]); j++)
1891 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1895 command = new char[len + 1];
1897 strcpy(command, app.argv[0]);
1899 if(projectView.fileName)
1901 strcat(command, " ");
1903 ReplaceSpaces(command + len, projectView.fileName);
1908 for(w = ide.firstChild; w; w = w.next)
1909 if(w.isActiveClient && w.isDocument)
1910 w.modifiedDocument = false;
1911 projectView.modifiedDocument = false;
1916 for(w = ide.firstChild; w; w = w.next)
1918 if(w.isActiveClient && w.isDocument)
1920 if(!w.CloseConfirmation(true))
1927 const char * name = w.fileName;
1929 for(j = 0; (ch = name[j]); j++)
1930 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1937 command = new char[len + 1];
1938 strcpy(command, app.argv[0]);
1941 for(w = ide.firstChild; w; w = w.next)
1943 if(w.isActiveClient && w.isDocument)
1945 const char * name = w.fileName;
1948 strcat(command, " ");
1950 ReplaceSpaces(command + len, name);
1951 len = (int)strlen(command);
1958 for(w = ide.firstChild; w; w = w.next)
1959 if(w.isActiveClient && w.isDocument)
1960 w.modifiedDocument = false;
1965 settings.language = code;
1966 settingsContainer.Save();
1968 setEcereLanguageInWinRegEnvironment(code);
1970 if(eClass_IsDerived(app._class, class(GuiApplication)))
1972 GuiApplication guiApp = (GuiApplication)app;
1973 guiApp.desktop.Destroy(0);
1980 for(i = 1; i < app.argc; i++)
1982 const char * arg = app.argv[i];
1984 for(j = 0; (ch = arg[j]); j++)
1985 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1988 command = new char[len + 1];
1989 strcpy(command, app.argv[0]);
1991 for(i = 1; i < app.argc; i++)
1993 strcat(command, " ");
1995 ReplaceSpaces(command + len, app.argv[i]);
1996 len = (int)strlen(command);
2002 SetEnvironment("ECERE_LANGUAGE", code);
2004 ExecuteWait(command);