9 import "OldIDESettings"
13 enum DirTypes { includes, libraries, executables };
15 define defaultCompilerName = "Default";
17 define defaultObjDirExpression = "obj/$(CONFIG).$(PLATFORM)";
19 char * settingsDirectoryNames[DirTypes] =
26 enum GlobalSettingsChange { none, editorSettings, projectOptions, compilerSettings };
28 enum PathRelationship { unrelated, identical, siblings, subPath, parentPath, insuficientInput, pathEmpty, toEmpty, pathNull, toNull, bothEmpty, bothNull };
29 PathRelationship eString_PathRelated(char * path, char * to, char * pathDiff)
31 PathRelationship result;
32 if(pathDiff) *pathDiff = '\0';
33 if(path && *path && to && *to)
35 char toPart[MAX_FILENAME], toRest[MAX_LOCATION];
36 char pathPart[MAX_FILENAME], pathRest[MAX_LOCATION];
38 strcpy(pathRest, path);
39 for(; toRest[0] && pathRest[0];)
41 SplitDirectory(toRest, toPart, toRest);
42 SplitDirectory(pathRest, pathPart, pathRest);
43 if(!fstrcmp(pathPart, toPart)) result = siblings;
46 if(result == siblings)
48 if(!*toRest && !*pathRest) result = identical;
49 else if(!*pathRest) result = parentPath;
50 else result = subPath;
51 if(pathDiff && result != identical) strcpy(pathDiff, *pathRest == '\0' ? toRest : pathRest);
53 else result = unrelated;
59 if(!*path && !*to) result = bothEmpty;
60 else if(!*path) result = pathEmpty;
61 else result = toEmpty;
63 else if(!path && !to) result = bothNull;
64 else if(!path) result = pathNull;
70 char * CopyValidateMakefilePath(char * path)
72 const int map[] = { 0, 1, 2, 3, 4, 0, 1, 7 };
73 const char * vars[] = { "$(MODULE)", "$(CONFIG)", "$(PLATFORM)", "$(COMPILER)", "$(TARGET)", "$(PROJECT)", "$(CONFIGURATION)", (char *)0 };
80 copy = CopyString(path);
86 Array<char *> parts { };
93 for(v=0; vars[v]; v++)
95 if(SearchString(&tmp[c], 0, vars[v], false, false) == &tmp[c])
99 parts.Add(vars[map[v]]);
100 c += strlen(vars[v]);
114 for(c=0; c<parts.count; c++) len += strlen(parts[c]);
115 copy = new char[++len];
117 for(c=0; c<parts.count; c++) strcat(copy, parts[c]);
128 CompilerConfig MakeDefaultCompiler(char * name, bool readOnly)
130 CompilerConfig defaultCompiler
135 GetRuntimePlatform(),
145 incref defaultCompiler;
146 return defaultCompiler;
149 class IDESettingsContainer : GlobalSettings
152 settingsName = "ecereIDESettingsTest";
154 settingsName = "ecereIDE";
157 virtual void OnLoad(GlobalSettingsData data);
159 char moduleLocation[MAX_LOCATION];
162 IDESettingsContainer()
164 char path[MAX_LOCATION];
166 LocateModule(null, moduleLocation);
167 strcpy(path, moduleLocation);
168 StripLastDirectory(moduleLocation, moduleLocation);
169 ChangeCh(moduleLocation, '\\', '/');
170 // PortableApps.com directory structure
171 if((start = strstr(path, "\\App\\EcereSDK\\bin\\ide.exe")))
173 char configFilePath[MAX_LOCATION];
174 char defaultConfigFilePath[MAX_LOCATION];
178 strcpy(configFilePath, path);
179 PathCat(configFilePath, "Data");
180 PathCat(configFilePath, "ecereIDE.ini");
182 strcpy(defaultConfigFilePath, path);
183 PathCat(defaultConfigFilePath, "App");
184 PathCat(defaultConfigFilePath, "DefaultData");
185 PathCat(defaultConfigFilePath, "ecereIDE.ini");
187 if(FileExists(defaultConfigFilePath))
189 if(!FileExists(configFilePath))
191 File f = FileOpen(defaultConfigFilePath, read);
192 f.CopyTo(configFilePath);
196 PathCat(path, "Data");
197 // the forced settings location will only be
198 // used if the running ide's path matches
199 // the PortableApps.com directory structure
200 // and the default ini file is found in
201 // the DefaultData directory
202 settingsLocation = path;
208 void OnAskReloadSettings()
210 /*if(MessageBox { type = YesNo, master = this,
211 text = "Global Settings Modified Externally",
212 contents = "The global settings were modified by another instance.\n"
213 "Would you like to reload them?" }.Modal() == Yes)*/
221 SettingsIOResult result = GlobalSettings::Load();
222 IDESettings data = (IDESettings)this.data;
223 CompilerConfig defaultCompiler = null;
226 this.data = IDESettings { };
228 *dataOwner = this.data;
230 if(result == fileNotCompatibleWithDriver)
233 OldIDESettings oldSettings { };
235 loaded = oldSettings.Load();
239 data = (IDESettings)this.data;
241 for(c : oldSettings.compilerConfigs)
242 data.compilerConfigs.Add(c.Copy());
244 for(s : oldSettings.recentFiles) data.recentFiles.Add(CopyString(s));
245 for(s : oldSettings.recentProjects) data.recentProjects.Add(CopyString(s));
247 data.docDir = oldSettings.docDir;
248 data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
249 data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
250 data.useFreeCaret = oldSettings.useFreeCaret;
251 data.showLineNumbers = oldSettings.showLineNumbers;
252 data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
253 delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
254 data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
255 data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
262 if(result == fileNotFound || !data)
264 data = (IDESettings)this.data;
265 data.useFreeCaret = true;
266 data.showLineNumbers = true;
267 data.caretFollowsScrolling = true;
270 // Ensure we have a default compiler
271 defaultCompiler = data.GetCompilerConfig(defaultCompilerName);
274 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
275 data.compilerConfigs.Add(defaultCompiler);
278 // We incref the compilers below, so reset refCount to 0
279 defaultCompiler._refCount = 0;
282 if(data.compilerConfigs)
284 for(c : data.compilerConfigs)
286 CompilerConfig compiler = c;
290 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
291 data.ManagePortablePaths(moduleLocation, true);
292 data.ForcePathSeparatorStyle(true);
298 IDESettings data = (IDESettings)this.data;
299 Platform runtimePlatform = GetRuntimePlatform();
300 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
301 data.ManagePortablePaths(moduleLocation, false);
302 data.ForcePathSeparatorStyle(true);
303 if(!GlobalSettings::Save())
304 PrintLn("Error saving IDE settings");
305 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
306 data.ManagePortablePaths(moduleLocation, true);
311 class IDESettings : GlobalSettingsData
314 List<CompilerConfig> compilerConfigs { };
315 Array<String> recentFiles { };
316 Array<String> recentProjects { };
317 property char * docDir
319 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
320 get { return docDir ? docDir : ""; }
321 isset { return docDir && docDir[0]; }
323 property char * ideFileDialogLocation
325 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
326 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
327 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
329 property char * ideProjectFileDialogLocation
331 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
332 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
333 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
336 bool showLineNumbers;
337 bool caretFollowsScrolling;
338 char * displayDriver;
340 // TODO: Classify settings
341 //EditorSettings editor { };
343 property char * projectDefaultTargetDir
345 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
346 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
347 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
349 property char * projectDefaultIntermediateObjDir
351 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
352 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
353 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
356 property char * portableLocation
358 set { delete portableLocation; if(value && value[0]) portableLocation = CopyString(value); }
359 get { return portableLocation ? portableLocation : ""; }
360 isset { return portableLocation && portableLocation[0]; }
363 property char * defaultCompiler
365 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
366 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
367 isset { return defaultCompiler && defaultCompiler[0]; }
372 char * ideFileDialogLocation;
373 char * ideProjectFileDialogLocation;
374 char * projectDefaultTargetDir;
375 char * projectDefaultIntermediateObjDir;
376 char * portableLocation;
377 char * defaultCompiler;
379 CompilerConfig GetCompilerConfig(String compilerName)
381 char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
382 CompilerConfig compilerConfig = null;
383 for(compiler : compilerConfigs)
385 if(!strcmp(compiler.name, name))
387 compilerConfig = compiler;
391 if(!compilerConfig && compilerConfigs.count)
392 compilerConfig = compilerConfigs.firstIterator.data;
394 incref compilerConfig;
395 return compilerConfig;
400 compilerConfigs.Free();
401 delete compilerConfigs;
404 recentProjects.Free();
405 delete recentProjects;
408 delete projectDefaultTargetDir;
409 delete projectDefaultIntermediateObjDir;
410 delete portableLocation;
411 delete defaultCompiler;
413 delete ideFileDialogLocation;
414 delete ideProjectFileDialogLocation;
415 delete displayDriver;
418 void ForcePathSeparatorStyle(bool unixStyle)
422 from = '\\', to = '/';
424 from = '/', to = '\\';
425 if(compilerConfigs && compilerConfigs.count)
428 for(config : compilerConfigs)
430 if(config.includeDirs && config.includeDirs.count)
432 for(i = 0; i < config.includeDirs.count; i++)
434 if(config.includeDirs[i] && config.includeDirs[i][0])
435 ChangeCh(config.includeDirs[i], from, to);
438 if(config.libraryDirs && config.libraryDirs.count)
440 for(i = 0; i < config.libraryDirs.count; i++)
442 if(config.libraryDirs[i] && config.libraryDirs[i][0])
443 ChangeCh(config.libraryDirs[i], from, to);
446 if(config.executableDirs && config.executableDirs.count)
448 for(i = 0; i < config.executableDirs.count; i++)
450 if(config.executableDirs[i] && config.executableDirs[i][0])
451 ChangeCh(config.executableDirs[i], from, to);
456 if(recentFiles && recentFiles.count)
459 for(c = 0; c < recentFiles.count; c++)
461 if(recentFiles[c] && recentFiles[c][0])
462 ChangeCh(recentFiles[c], from, to);
465 if(recentProjects && recentProjects.count)
468 for(c = 0; c < recentProjects.count; c++)
470 if(recentProjects[c] && recentProjects[c][0])
471 ChangeCh(recentProjects[c], from, to);
474 if(docDir && docDir[0])
475 ChangeCh(docDir, from, to);
476 if(ideFileDialogLocation && ideFileDialogLocation[0])
477 ChangeCh(ideFileDialogLocation, from, to);
478 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
479 ChangeCh(ideProjectFileDialogLocation, from, to);
481 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
482 ChangeCh(projectDefaultTargetDir, from, to);
483 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
484 ChangeCh(projectDefaultIntermediateObjDir, from, to);
486 if(portableLocation && portableLocation[0])
487 ChangeCh(portableLocation, from, to);
490 void ManagePortablePaths(char * location, bool makeAbsolute)
493 if(compilerConfigs && compilerConfigs.count)
495 for(config : compilerConfigs)
498 for(t = 0; t < DirTypes::enumSize; t++)
500 Array<String> dirs = null;
501 if(t == executables) dirs = config.executableDirs;
502 else if(t == includes) dirs = config.includeDirs;
503 else if(t == libraries) dirs = config.libraryDirs;
504 if(dirs && dirs.count)
506 for(c = 0; c < dirs.count; c++)
508 if(dirs[c] && dirs[c][0])
509 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
515 if(recentFiles && recentFiles.count)
517 for(c = 0; c < recentFiles.count; c++)
519 if(recentFiles[c] && recentFiles[c][0])
520 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
523 if(recentProjects && recentProjects.count)
525 for(c = 0; c < recentProjects.count; c++)
527 if(recentProjects[c] && recentProjects[c][0])
528 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
531 if(docDir && docDir[0])
532 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
533 if(ideFileDialogLocation && ideFileDialogLocation[0])
534 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
535 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
536 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
538 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
539 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
540 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
541 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
544 char * UpdatePortablePath(char * path, char * location, bool makeAbsolute)
549 char p[MAX_LOCATION];
551 PathCatSlash(p, path);
553 output = CopyString(p);
557 PathRelationship rel = eString_PathRelated(path, location, null);
558 if(rel == subPath || rel == identical)
560 char p[MAX_LOCATION];
561 MakePathRelative(path, location, p);
562 if(!*p) strcpy(p, "./");
563 else ChangeCh(p, '\\', '/');
565 output = CopyString(p);
573 void AddRecentFile(char * fileName)
576 char * filePath = CopyString(fileName);
577 ChangeCh(filePath, '\\', '/');
578 for(c = 0; c<recentFiles.count; c++)
580 if(recentFiles[c] && !fstrcmp(recentFiles[c], filePath))
582 recentFiles.Delete((void *)&recentFiles[c]);
586 while(recentFiles.count >= MaxRecent)
587 recentFiles.Delete(recentFiles.GetLast());
588 recentFiles.Insert(null, filePath);
589 //UpdateRecentMenus(owner);
592 void AddRecentProject(char * projectName)
595 char * filePath = CopyString(projectName);
596 ChangeCh(filePath, '\\', '/');
597 for(c = 0; c<recentProjects.count; c++)
599 if(recentProjects[c] && !fstrcmp(recentProjects[c], filePath))
601 recentProjects.Delete((void *)&recentProjects[c]);
605 while(recentProjects.count >= MaxRecent)
606 recentProjects.Delete(recentProjects.GetLast());
607 recentProjects.Insert(null, filePath);
608 //UpdateRecentMenus(owner);
612 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
613 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
614 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
615 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
616 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
617 // TODO: i18n with Array
618 static Array<String> compilerTypeLongNames
620 $"GNU Compiler Collection (GCC) / GNU Make",
621 $"Tiny C Compiler / GNU Make",
622 $"Portable C Compiler / GNU Make",
623 $"Microsoft Visual Studio 2005 (8.0) Compiler",
624 $"Microsoft Visual Studio 2008 (9.0) Compiler",
625 $"Microsoft Visual Studio 2010 (10.0) Compiler"
627 const CompilerType firstCompilerType = gcc;
628 const CompilerType lastCompilerType = vs10;
629 public enum CompilerType
631 gcc, tcc, pcc, vs8, vs9, vs10;
635 get { return this == vs8 || this == vs9 || this == vs10; }
640 get { return OnGetString(null, null, null); }
646 for(c = firstCompilerType; c <= lastCompilerType; c++)
647 if(!strcmpi(value, compilerTypeNames[c]))
654 property char * longName { get { return OnGetString(null, (void*)1, null); } };
655 property char * versionString { get { return OnGetString(null, (void*)2, null); } };
656 property char * yearString { get { return OnGetString(null, (void*)3, null); } };
657 property char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
658 property char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
660 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
662 if(this >= firstCompilerType && this <= lastCompilerType)
665 strcpy(tempString, compilerTypeNames[this]);
666 if(fieldData == null)
667 return compilerTypeNames[this];
668 else if(fieldData == (void*)1)
669 return compilerTypeLongNames[this];
670 else if(fieldData == (void*)2)
671 return compilerTypeVersionString[this];
672 else if(fieldData == (void*)3)
673 return compilerTypeYearString[this];
674 else if(fieldData == (void*)4)
675 return compilerTypeProjectFileExtension[this];
676 else if(fieldData == (void*)5)
677 return compilerTypeSolutionFileVersionString[this];
695 name = CopyString(value);
701 Platform targetPlatform;
703 property char * makeCommand
705 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
706 get { return makeCommand; }
707 isset { return makeCommand && makeCommand[0]; }
709 property char * ecpCommand
711 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
712 get { return ecpCommand; }
713 isset { return ecpCommand && ecpCommand[0]; }
715 property char * eccCommand
717 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
718 get { return eccCommand; }
719 isset { return eccCommand && eccCommand[0]; }
721 property char * ecsCommand
723 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
724 get { return ecsCommand; }
725 isset { return ecsCommand && ecsCommand[0]; }
727 property char * earCommand
729 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
730 get { return earCommand; }
731 isset { return earCommand && earCommand[0]; }
733 property char * cppCommand
735 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
736 get { return cppCommand; }
737 isset { return cppCommand && cppCommand[0]; }
739 property char * ccCommand
741 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
742 get { return ccCommand; }
743 isset { return ccCommand && ccCommand[0]; }
745 property char * execPrefixCommand
747 set { delete execPrefixCommand; if(value && value[0]) execPrefixCommand = CopyString(value); }
748 get { return execPrefixCommand; }
749 isset { return execPrefixCommand && execPrefixCommand[0]; }
753 property char * distccHosts
755 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
756 get { return distccHosts; }
757 isset { return distccHosts && distccHosts[0]; }
759 property Array<String> includeDirs
770 get { return includeDirs; }
771 isset { return includeDirs.count != 0; }
773 property Array<String> libraryDirs
784 get { return libraryDirs; }
785 isset { return libraryDirs.count != 0; }
787 property Array<String> executableDirs
791 executableDirs.Free();
794 delete executableDirs;
795 executableDirs = value;
798 get { return executableDirs; }
799 isset { return executableDirs.count != 0; }
801 property Array<NamedString> environmentVars
805 environmentVars.Free();
808 delete environmentVars;
809 environmentVars = value;
812 get { return environmentVars; }
813 isset { return environmentVars.count != 0; }
816 Array<String> includeDirs { };
817 Array<String> libraryDirs { };
818 Array<String> executableDirs { };
819 // TODO: Can JSON parse and serialize maps?
820 //EnvironmentVariables { };
821 Array<NamedString> environmentVars { };
830 char * execPrefixCommand;
834 struct { Array<String> includes, libraries, executables; };
835 Array<String> dirs[DirTypes];
848 delete execPrefixCommand;
850 if(environmentVars) environmentVars.Free();
851 if(includeDirs) { includeDirs.Free(); }
852 if(libraryDirs) { libraryDirs.Free(); }
853 if(executableDirs) { executableDirs.Free(); }
855 CompilerConfig Copy()
876 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
877 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
878 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
879 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });