2 #define MessageBox _MessageBox
3 #define WIN32_LEAN_AND_MEAN
9 public import static "ecere"
14 define ecpDefaultCommand = "ecp";
15 define eccDefaultCommand = "ecc";
16 define ecsDefaultCommand = "ecs";
17 define earDefaultCommand = "ear";
18 define cppDefaultCommand = "gcc"; // As per #624 we decided to default to "gcc"...
19 define ccDefaultCommand = "gcc";
20 define cxxDefaultCommand = "g++";
21 //define ldDefaultCommand = "gcc";
22 define arDefaultCommand = "ar";
23 define objectDefaultFileExt = "o";
24 define outputDefaultFileExt = "";
28 import "OldIDESettings"
32 enum DirTypes { includes, libraries, executables };
34 define defaultCompilerName = "Default";
36 define defaultObjDirExpression = "obj/$(CONFIG).$(PLATFORM)$(COMPILER_SUFFIX)$(DEBUG_SUFFIX)";
38 const char * settingsDirectoryNames[DirTypes] =
45 // This function cannot accept same pointer for source and output
46 // todo: rename ReplaceSpaces to EscapeSpaceAndSpecialChars or something
47 void ReplaceSpaces(char * output, const char * source)
52 for(c = 0, dc = 0; (ch = source[c]); c++, dc++)
54 if(ch == ' ') output[dc++] = '\\';
55 if(ch == '\"') output[dc++] = '\\';
56 if(ch == '&') output[dc++] = '\\';
59 if(ch == '(' || ch == ')') output[dc++] = '\\';
70 enum GlobalSettingsChange { none, editorSettings, projectOptions, compilerSettings };
72 enum PathRelationship { unrelated, identical, siblings, subPath, parentPath, insuficientInput, pathEmpty, toEmpty, pathNull, toNull, bothEmpty, bothNull };
73 PathRelationship eString_PathRelated(const char * path, const char * to, char * pathDiff)
75 PathRelationship result;
76 if(pathDiff) *pathDiff = '\0';
77 if(path && *path && to && *to)
79 char toPart[MAX_FILENAME], toRest[MAX_LOCATION];
80 char pathPart[MAX_FILENAME], pathRest[MAX_LOCATION];
82 strcpy(pathRest, path);
83 for(; toRest[0] && pathRest[0];)
85 SplitDirectory(toRest, toPart, toRest);
86 SplitDirectory(pathRest, pathPart, pathRest);
87 if(!fstrcmp(pathPart, toPart)) result = siblings;
90 if(result == siblings)
92 if(!*toRest && !*pathRest) result = identical;
93 else if(!*pathRest) result = parentPath;
94 else result = subPath;
95 if(pathDiff && result != identical) strcpy(pathDiff, *pathRest == '\0' ? toRest : pathRest);
97 else result = unrelated;
103 if(!*path && !*to) result = bothEmpty;
104 else if(!*path) result = pathEmpty;
105 else result = toEmpty;
107 else if(!path && !to) result = bothNull;
108 else if(!path) result = pathNull;
109 else result = toNull;
114 char * CopyValidateMakefilePath(const char * path)
116 const int map[] = { 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 7 };
117 const char * vars[] = { "$(MODULE)", "$(CONFIG)", "$(PLATFORM)", "$(COMPILER)", "$(TARGET)", "$(COMPILER_SUFFIX)", "$(DEBUG_SUFFIX)", "$(PROJECT)", "$(CONFIGURATION)", "$(TARGET_PLATFORM)",(char *)0 };
123 len = (int)strlen(path);
124 copy = CopyString(path);
130 Array<const char *> parts { };
137 for(v=0; vars[v]; v++)
139 if(SearchString(&tmp[c], 0, vars[v], false, false) == &tmp[c])
143 parts.Add(vars[map[v]]);
144 c += strlen(vars[v]);
158 for(c=0; c<parts.count; c++) len += strlen(parts[c]);
159 copy = new char[++len];
161 for(c=0; c<parts.count; c++) strcat(copy, parts[c]);
172 void ValidPathBufCopy(char *output, const char *input)
175 bool volumePath = false;
177 strcpy(output, input);
178 TrimLSpaces(output, output);
179 TrimRSpaces(output, output);
180 MakeSystemPath(output);
182 if(output[0] && output[1] == ':')
189 const char * chars = "*|:\",<>?";
190 char ch, * s = output, * o = output;
191 while((ch = *s++)) { if(!strchr(chars, ch)) *o++ = ch; }
195 if(volumePath && output[0])
200 void RemoveTrailingPathSeparator(char *path)
203 len = (int)strlen(path);
204 if(len>1 && path[len-1] == DIR_SEP)
208 void BasicValidatePathBoxPath(PathBox pathBox)
210 char path[MAX_LOCATION];
211 ValidPathBufCopy(path, pathBox.path);
212 RemoveTrailingPathSeparator(path);
216 CompilerConfig MakeDefaultCompiler(const char * name, bool readOnly)
218 CompilerConfig defaultCompiler
236 incref defaultCompiler;
237 return defaultCompiler;
241 define settingsName = "ecereIDE-SettingsTest";
243 define ideSettingsName = "ecereIDE";
246 class IDESettingsContainer : GlobalSettings
248 settingsName = ideSettingsName;
250 virtual void OnLoad(GlobalSettingsData data);
252 char moduleLocation[MAX_LOCATION];
255 FileSize settingsFileSize;
257 IDESettingsContainer()
259 char path[MAX_LOCATION];
261 LocateModule(null, moduleLocation);
262 strcpy(path, moduleLocation);
263 StripLastDirectory(moduleLocation, moduleLocation);
264 ChangeCh(moduleLocation, '\\', '/');
265 // PortableApps.com directory structure
266 if((start = strstr(path, "\\App\\EcereSDK\\bin\\ide.exe")))
268 char configFilePath[MAX_LOCATION];
269 char defaultConfigFilePath[MAX_LOCATION];
273 strcpy(configFilePath, path);
274 PathCat(configFilePath, "Data");
275 PathCat(configFilePath, ideSettingsName);
276 ChangeExtension(configFilePath, "ini", configFilePath);
278 strcpy(defaultConfigFilePath, path);
279 PathCat(defaultConfigFilePath, "App");
280 PathCat(defaultConfigFilePath, "DefaultData");
281 PathCat(defaultConfigFilePath, ideSettingsName);
282 ChangeExtension(defaultConfigFilePath, "ini", defaultConfigFilePath);
284 if(FileExists(defaultConfigFilePath))
286 if(!FileExists(configFilePath))
288 File f = FileOpen(defaultConfigFilePath, read);
289 f.CopyTo(configFilePath);
293 PathCat(path, "Data");
294 // the forced settings location will only be
295 // used if the running ide's path matches
296 // the PortableApps.com directory structure
297 // and the default ini file is found in
298 // the DefaultData directory
299 settingsLocation = path;
305 void OnAskReloadSettings()
307 FileSize newSettingsFileSize;
309 if(OpenAndLock(&newSettingsFileSize))
311 if((double)settingsFileSize - (double)newSettingsFileSize < 2048)
315 GuiApplication app = ((GuiApplication)__thisModule.application);
317 for(w = app.desktop.firstChild; w && (!w.created || !w.visible); w = w.next);
321 MessageBox { master = w, type = ok, isModal = true,
322 text = "Global Settings Modified Externally",
323 contents = "The global settings were modified by another process and a drastic shrinking of the settings file was detected.\n"
324 "The new settings will not be loaded to prevent loss of your ide settings.\n"
325 "Please check your settings file and make sure to save this IDE's global settings if your settings file has been compromised."
331 SettingsIOResult Load()
333 SettingsIOResult result = GlobalSettings::Load();
334 IDESettings data = (IDESettings)this.data;
335 CompilerConfig defaultCompiler = null;
338 this.data = IDESettings { };
340 *dataOwner = this.data;
342 if(result == fileNotCompatibleWithDriver)
345 OldIDESettings oldSettings { };
347 loaded = oldSettings.Load() == success;
351 data = (IDESettings)this.data;
353 for(c : oldSettings.compilerConfigs)
354 data.compilerConfigs.Add(c.Copy());
356 for(s : oldSettings.recentFiles) data.recentFiles.Add(CopyString(s));
357 for(s : oldSettings.recentProjects) data.recentProjects.Add(CopyString(s));
359 data.docDir = oldSettings.docDir;
360 data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
361 data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
362 data.useFreeCaret = oldSettings.useFreeCaret;
363 data.showLineNumbers = oldSettings.showLineNumbers;
364 data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
365 delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
366 data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
367 data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
374 if(result == fileNotFound || !data)
376 data = (IDESettings)this.data;
377 data.useFreeCaret = false; //true;
378 data.showLineNumbers = true;
379 data.caretFollowsScrolling = false; //true;
382 // Ensure we have a default compiler
383 defaultCompiler = data.GetCompilerConfig(defaultCompilerName);
386 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
387 data.compilerConfigs.Add(defaultCompiler);
390 // We incref the compilers below, so reset refCount to 0
391 defaultCompiler._refCount = 0;
394 FileGetSize(settingsFilePath, &settingsFileSize);
395 if(data.compilerConfigs)
397 for(ccfg : data.compilerConfigs)
399 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
400 ccfg.ecpCommand = ecpDefaultCommand;
401 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
402 ccfg.eccCommand = eccDefaultCommand;
403 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
404 ccfg.ecsCommand = ecsDefaultCommand;
405 if(!ccfg.earCommand || !ccfg.earCommand[0])
406 ccfg.earCommand = earDefaultCommand;
407 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
408 ccfg.cppCommand = cppDefaultCommand;
409 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
410 ccfg.ccCommand = ccDefaultCommand;
411 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
412 ccfg.cxxCommand = cxxDefaultCommand;
413 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
414 ccfg.ldCommand = ldDefaultCommand;*/
415 if(!ccfg.arCommand || !ccfg.arCommand[0])
416 ccfg.arCommand = arDefaultCommand;
417 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
418 ccfg.objectFileExt = objectDefaultFileExt;
419 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
420 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
421 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
422 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
423 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
424 ccfg.executableFileExt = outputDefaultFileExt;*/
428 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
429 data.ManagePortablePaths(moduleLocation, true);
430 data.ForcePathSeparatorStyle(true);
435 SettingsIOResult Save()
437 SettingsIOResult result;
439 IDESettings data = (IDESettings)this.data;
440 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
441 data.ManagePortablePaths(moduleLocation, false);
442 data.ForcePathSeparatorStyle(true);
443 result = GlobalSettings::Save();
444 if(result != success)
445 PrintLn("Error saving IDE settings");
446 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
447 data.ManagePortablePaths(moduleLocation, true);
449 FileGetSize(settingsFilePath, &settingsFileSize);
454 class IDESettings : GlobalSettingsData
457 List<CompilerConfig> compilerConfigs { };
458 Array<String> recentFiles { };
459 Array<String> recentProjects { };
460 property const char * docDir
462 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
463 get { return docDir ? docDir : ""; }
464 isset { return docDir && docDir[0]; }
466 property const char * ideFileDialogLocation
468 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
469 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
470 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
472 property const char * ideProjectFileDialogLocation
474 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
475 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
476 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
479 bool showLineNumbers;
480 bool caretFollowsScrolling;
481 char * displayDriver;
483 // TODO: Classify settings
484 //EditorSettings editor { };
486 property const char * projectDefaultTargetDir
488 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
489 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
490 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
492 property const char * projectDefaultIntermediateObjDir
494 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
495 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
496 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
499 property const char * compilerConfigsDir
501 set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
502 get { return compilerConfigsDir ? compilerConfigsDir : ""; }
503 isset { return compilerConfigsDir && compilerConfigsDir[0]; }
506 property const char * defaultCompiler
508 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
509 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
510 isset { return defaultCompiler && defaultCompiler[0]; }
513 property const String language
518 language = CopyString(value);
520 get { return language; }
521 isset { return language != null; }
524 property Array<NamedString> findInFileFileFilters
528 findInFileFileFilters.Free();
531 delete findInFileFileFilters;
532 findInFileFileFilters = value;
535 get { return findInFileFileFilters; }
536 isset { return findInFileFileFilters.count != 0; }
541 char * ideFileDialogLocation;
542 char * ideProjectFileDialogLocation;
543 char * projectDefaultTargetDir;
544 char * projectDefaultIntermediateObjDir;
545 char * compilerConfigsDir;
546 char * defaultCompiler;
548 Array<NamedString> findInFileFileFilters { };
550 CompilerConfig GetCompilerConfig(const String compilerName)
552 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
553 CompilerConfig compilerConfig = null;
554 for(compiler : compilerConfigs)
556 if(!strcmp(compiler.name, name))
558 compilerConfig = compiler;
562 if(!compilerConfig && compilerConfigs.count)
563 compilerConfig = compilerConfigs.firstIterator.data;
565 incref compilerConfig;
566 return compilerConfig;
571 compilerConfigs.Free();
572 delete compilerConfigs;
575 recentProjects.Free();
576 delete recentProjects;
579 delete projectDefaultTargetDir;
580 delete projectDefaultIntermediateObjDir;
581 delete compilerConfigsDir;
582 delete defaultCompiler;
585 delete ideFileDialogLocation;
586 delete ideProjectFileDialogLocation;
587 delete displayDriver;
589 if(findInFileFileFilters) findInFileFileFilters.Free();
592 void ForcePathSeparatorStyle(bool unixStyle)
596 from = '\\', to = '/';
598 from = '/', to = '\\';
599 if(compilerConfigs && compilerConfigs.count)
602 for(config : compilerConfigs)
604 if(config.includeDirs && config.includeDirs.count)
606 for(i = 0; i < config.includeDirs.count; i++)
608 if(config.includeDirs[i] && config.includeDirs[i][0])
609 ChangeCh(config.includeDirs[i], from, to);
612 if(config.libraryDirs && config.libraryDirs.count)
614 for(i = 0; i < config.libraryDirs.count; i++)
616 if(config.libraryDirs[i] && config.libraryDirs[i][0])
617 ChangeCh(config.libraryDirs[i], from, to);
620 if(config.executableDirs && config.executableDirs.count)
622 for(i = 0; i < config.executableDirs.count; i++)
624 if(config.executableDirs[i] && config.executableDirs[i][0])
625 ChangeCh(config.executableDirs[i], from, to);
630 if(recentFiles && recentFiles.count)
633 for(c = 0; c < recentFiles.count; c++)
635 if(recentFiles[c] && recentFiles[c][0])
636 ChangeCh(recentFiles[c], from, to);
639 if(recentProjects && recentProjects.count)
642 for(c = 0; c < recentProjects.count; c++)
644 if(recentProjects[c] && recentProjects[c][0])
645 ChangeCh(recentProjects[c], from, to);
648 if(docDir && docDir[0])
649 ChangeCh(docDir, from, to);
650 if(ideFileDialogLocation && ideFileDialogLocation[0])
651 ChangeCh(ideFileDialogLocation, from, to);
652 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
653 ChangeCh(ideProjectFileDialogLocation, from, to);
655 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
656 ChangeCh(projectDefaultTargetDir, from, to);
657 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
658 ChangeCh(projectDefaultIntermediateObjDir, from, to);
660 if(compilerConfigsDir && compilerConfigsDir[0])
661 ChangeCh(compilerConfigsDir, from, to);
664 void ManagePortablePaths(char * location, bool makeAbsolute)
667 if(compilerConfigs && compilerConfigs.count)
669 for(config : compilerConfigs)
672 for(t = 0; t < DirTypes::enumSize; t++)
674 Array<String> dirs = null;
675 if(t == executables) dirs = config.executableDirs;
676 else if(t == includes) dirs = config.includeDirs;
677 else if(t == libraries) dirs = config.libraryDirs;
678 if(dirs && dirs.count)
680 for(c = 0; c < dirs.count; c++)
682 if(dirs[c] && dirs[c][0])
683 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
689 if(recentFiles && recentFiles.count)
691 for(c = 0; c < recentFiles.count; c++)
693 if(recentFiles[c] && recentFiles[c][0])
694 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
697 if(recentProjects && recentProjects.count)
699 for(c = 0; c < recentProjects.count; c++)
701 if(recentProjects[c] && recentProjects[c][0])
702 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
705 if(docDir && docDir[0])
706 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
707 if(ideFileDialogLocation && ideFileDialogLocation[0])
708 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
709 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
710 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
712 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
713 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
714 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
715 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
717 if(compilerConfigsDir && compilerConfigsDir[0])
718 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
721 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
726 char p[MAX_LOCATION];
728 PathCatSlash(p, path);
730 output = CopyString(p);
734 PathRelationship rel = eString_PathRelated(path, location, null);
735 if(rel == subPath || rel == identical)
737 char p[MAX_LOCATION];
738 MakePathRelative(path, location, p);
739 if(!*p) strcpy(p, "./");
740 else ChangeCh(p, '\\', '/');
742 output = CopyString(p);
750 void AddRecentFile(const char * fileName)
753 char * filePath = CopyString(fileName);
754 ChangeCh(filePath, '\\', '/');
755 for(c = 0; c<recentFiles.count; c++)
757 if(recentFiles[c] && !fstrcmp(recentFiles[c], filePath))
759 recentFiles.Delete((void *)&recentFiles[c]);
763 while(recentFiles.count >= MaxRecent)
764 recentFiles.Delete(recentFiles.GetLast());
765 recentFiles.Insert(null, filePath);
766 //UpdateRecentMenus(owner);
769 void AddRecentProject(const char * projectName)
772 char * filePath = CopyString(projectName);
773 ChangeCh(filePath, '\\', '/');
774 for(c = 0; c<recentProjects.count; c++)
776 if(recentProjects[c] && !fstrcmp(recentProjects[c], filePath))
778 recentProjects.Delete((void *)&recentProjects[c]);
782 while(recentProjects.count >= MaxRecent)
783 recentProjects.Delete(recentProjects.GetLast());
784 recentProjects.Insert(null, filePath);
785 //UpdateRecentMenus(owner);
789 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
790 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
791 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
792 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
793 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
794 // TODO: i18n with Array
795 static Array<const String> compilerTypeLongNames
797 $"GNU Compiler Collection (GCC) / GNU Make",
798 $"Tiny C Compiler / GNU Make",
799 $"Portable C Compiler / GNU Make",
800 $"Microsoft Visual Studio 2005 (8.0) Compiler",
801 $"Microsoft Visual Studio 2008 (9.0) Compiler",
802 $"Microsoft Visual Studio 2010 (10.0) Compiler"
804 const CompilerType firstCompilerType = gcc;
805 const CompilerType lastCompilerType = vs10;
806 public enum CompilerType
808 gcc, tcc, pcc, vs8, vs9, vs10;
812 get { return this == vs8 || this == vs9 || this == vs10; }
815 property const char *
817 get { return OnGetString(null, null, null); }
823 for(c = firstCompilerType; c <= lastCompilerType; c++)
824 if(!strcmpi(value, compilerTypeNames[c]))
831 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
832 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
833 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
834 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
835 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
837 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
839 if(this >= firstCompilerType && this <= lastCompilerType)
842 strcpy(tempString, compilerTypeNames[this]);
843 if(fieldData == null)
844 return compilerTypeNames[this];
845 else if(fieldData == (void*)1)
846 return compilerTypeLongNames[this];
847 else if(fieldData == (void*)2)
848 return compilerTypeVersionString[this];
849 else if(fieldData == (void*)3)
850 return compilerTypeYearString[this];
851 else if(fieldData == (void*)4)
852 return compilerTypeProjectFileExtension[this];
853 else if(fieldData == (void*)5)
854 return compilerTypeSolutionFileVersionString[this];
866 property const char * name
872 name = CopyString(value);
878 Platform targetPlatform;
880 property const char * makeCommand
882 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
883 get { return makeCommand; }
884 isset { return makeCommand && makeCommand[0]; }
886 property const char * ecpCommand
888 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
889 get { return ecpCommand; }
890 isset { return ecpCommand && ecpCommand[0]; }
892 property const char * eccCommand
894 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
895 get { return eccCommand; }
896 isset { return eccCommand && eccCommand[0]; }
898 property const char * ecsCommand
900 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
901 get { return ecsCommand; }
902 isset { return ecsCommand && ecsCommand[0]; }
904 property const char * earCommand
906 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
907 get { return earCommand; }
908 isset { return earCommand && earCommand[0]; }
910 property const char * cppCommand
912 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
913 get { return cppCommand; }
914 isset { return cppCommand && cppCommand[0]; }
916 property const char * ccCommand
918 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
919 get { return ccCommand; }
920 isset { return ccCommand && ccCommand[0]; }
922 property const char * cxxCommand
924 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
925 get { return cxxCommand; }
926 isset { return cxxCommand && cxxCommand[0]; }
928 property const char * arCommand
930 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
931 get { return arCommand; }
932 isset { return arCommand && arCommand[0]; }
934 property const char * ldCommand
936 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
937 get { return ldCommand; }
938 isset { return ldCommand && ldCommand[0]; }
941 property const char * objectFileExt
943 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
944 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
945 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
947 property const char * staticLibFileExt
949 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
950 get { return staticLibFileExt; }
951 isset { return staticLibFileExt && staticLibFileExt[0]; }
953 property const char * sharedLibFileExt
955 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
956 get { return sharedLibFileExt; }
957 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
959 property const char * executableFileExt
961 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
962 get { return executableFileExt; }
963 isset { return executableFileExt && executableFileExt[0]; }
965 property const char * executableLauncher
967 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
968 get { return executableLauncher; }
969 isset { return executableLauncher && executableLauncher[0]; }
971 // TODO: implement CompilerConfig::windresCommand
975 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
977 property const char * distccHosts
979 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
980 get { return distccHosts; }
981 isset { return distccHosts && distccHosts[0]; }
983 property const char * gnuToolchainPrefix
985 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
986 get { return gnuToolchainPrefix; }
987 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
989 property const char * sysroot
991 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
992 get { return sysroot; }
993 isset { return sysroot && sysroot[0]; }
995 property Array<String> includeDirs
1003 includeDirs = value;
1006 get { return includeDirs; }
1007 isset { return includeDirs.count != 0; }
1009 property Array<String> libraryDirs
1017 libraryDirs = value;
1020 get { return libraryDirs; }
1021 isset { return libraryDirs.count != 0; }
1023 property Array<String> executableDirs
1027 executableDirs.Free();
1030 delete executableDirs;
1031 executableDirs = value;
1034 get { return executableDirs; }
1035 isset { return executableDirs.count != 0; }
1037 property Array<NamedString> environmentVars
1041 environmentVars.Free();
1044 delete environmentVars;
1045 environmentVars = value;
1048 get { return environmentVars; }
1049 isset { return environmentVars.count != 0; }
1051 property Array<String> prepDirectives
1055 prepDirectives.Free();
1058 delete prepDirectives;
1059 prepDirectives = value;
1062 get { return prepDirectives; }
1063 isset { return prepDirectives.count != 0; }
1065 property Array<String> excludeLibs
1073 excludeLibs = value;
1076 get { return excludeLibs; }
1077 isset { return excludeLibs.count != 0; }
1079 property Array<String> eCcompilerFlags
1083 eCcompilerFlags.Free();
1086 delete eCcompilerFlags;
1087 eCcompilerFlags = value;
1090 get { return eCcompilerFlags; }
1091 isset { return eCcompilerFlags.count != 0; }
1093 property Array<String> compilerFlags
1097 compilerFlags.Free();
1100 delete compilerFlags;
1101 compilerFlags = value;
1104 get { return compilerFlags; }
1105 isset { return compilerFlags.count != 0; }
1107 property Array<String> linkerFlags
1115 linkerFlags = value;
1118 get { return linkerFlags; }
1119 isset { return linkerFlags.count != 0; }
1121 // json backward compatibility
1122 property const char * gccPrefix
1124 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1125 get { return gnuToolchainPrefix; }
1126 isset { return false; }
1128 property const char * execPrefixCommand
1130 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1131 get { return executableLauncher; }
1132 isset { return false; }
1134 property const char * outputFileExt
1136 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1137 get { return executableFileExt; }
1138 isset { return false; }
1141 property bool hasDocumentOutput
1145 bool result = executableFileExt && executableFileExt[0] &&
1146 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1149 isset { return false; }
1152 Array<String> includeDirs { };
1153 Array<String> libraryDirs { };
1154 Array<String> executableDirs { };
1155 // TODO: Can JSON parse and serialize maps?
1156 //EnvironmentVariables { };
1157 Array<NamedString> environmentVars { };
1158 Array<String> prepDirectives { };
1159 Array<String> excludeLibs { };
1160 Array<String> eCcompilerFlags { };
1161 Array<String> compilerFlags { };
1162 Array<String> linkerFlags { };
1174 char * objectFileExt;
1175 char * staticLibFileExt;
1176 char * sharedLibFileExt;
1177 char * executableFileExt;
1178 char * executableLauncher;
1180 char * gnuToolchainPrefix;
1184 struct { Array<String> includes, libraries, executables; };
1185 Array<String> dirs[DirTypes];
1200 delete objectFileExt;
1201 delete staticLibFileExt;
1202 delete sharedLibFileExt;
1203 delete executableFileExt;
1205 delete executableLauncher;
1207 delete gnuToolchainPrefix;
1209 if(environmentVars) environmentVars.Free();
1210 if(includeDirs) { includeDirs.Free(); }
1211 if(libraryDirs) { libraryDirs.Free(); }
1212 if(executableDirs) { executableDirs.Free(); }
1213 if(prepDirectives) { prepDirectives.Free(); }
1214 if(excludeLibs) { excludeLibs.Free(); }
1215 if(compilerFlags) { compilerFlags.Free(); }
1216 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1217 if(linkerFlags) { linkerFlags.Free(); }
1221 CompilerConfig Copy()
1253 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1254 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1255 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1256 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1257 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1258 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1259 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1260 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1261 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1268 struct LanguageOption
1271 const String bitmap;
1275 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1280 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
1282 Bitmap icon = res ? res.bitmap : null;
1285 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
1286 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
1290 Array<LanguageOption> languages
1292 { "English", ":countryCode/gb.png", "" },
1293 { "汉语", ":countryCode/cn.png", "zh_CN" },
1294 { "Español", ":countryCode/es.png", "es" },
1295 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
1296 { "Русский (43%)", ":countryCode/ru.png", "ru" },
1297 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
1298 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
1299 { "मराठी (10%)", ":countryCode/in.png", "mr" },
1300 { "Hebrew (8%)", ":countryCode/il.png", "he" },
1301 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
1304 const String GetLanguageString()
1306 char * dot, * colon;
1307 static char lang[256];
1308 const String language = getenv("ECERE_LANGUAGE");
1309 if(!language) language = getenv("LANGUAGE");
1310 if(!language) language = getenv("LC_ALL");
1311 if(!language) language = getenv("LC_MESSAGES");
1312 if(!language) language = getenv("LANG");
1313 if(!language) language = "";
1314 if(language && (colon = strchr(language, ':')))
1316 if(lang != language)
1317 strncpy(lang, language, sizeof(lang));
1318 lang[sizeof(lang)-1] = 0;
1319 lang[colon - language] = 0;
1322 if(language && (dot = strchr(language, '.')))
1324 if(lang != language)
1325 strncpy(lang, language, sizeof(lang));
1326 lang[sizeof(lang)-1] = 0;
1327 lang[dot - language] = 0;
1333 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
1335 bool restart = true;
1336 String command = null;
1337 int arg0Len = (int)strlen(app.argv[0]);
1349 for(w = ide.firstChild; w; w = w.next)
1351 if(w.isActiveClient && w.isDocument)
1353 if(!w.CloseConfirmation(true))
1362 if(!projectView.CloseConfirmation(true))
1364 if(projectView.fileName)
1366 const char * name = projectView.fileName;
1369 for(j = 0; (ch = name[j]); j++)
1370 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1374 command = new char[len + 1];
1376 strcpy(command, app.argv[0]);
1378 if(projectView.fileName)
1380 strcat(command, " ");
1382 ReplaceSpaces(command + len, projectView.fileName);
1387 for(w = ide.firstChild; w; w = w.next)
1388 if(w.isActiveClient && w.isDocument)
1389 w.modifiedDocument = false;
1390 projectView.modifiedDocument = false;
1395 for(w = ide.firstChild; w; w = w.next)
1397 if(w.isActiveClient && w.isDocument)
1399 if(!w.CloseConfirmation(true))
1406 const char * name = w.fileName;
1408 for(j = 0; (ch = name[j]); j++)
1409 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1416 command = new char[len + 1];
1417 strcpy(command, app.argv[0]);
1420 for(w = ide.firstChild; w; w = w.next)
1422 if(w.isActiveClient && w.isDocument)
1424 const char * name = w.fileName;
1427 strcat(command, " ");
1429 ReplaceSpaces(command + len, name);
1430 len = (int)strlen(command);
1437 for(w = ide.firstChild; w; w = w.next)
1438 if(w.isActiveClient && w.isDocument)
1439 w.modifiedDocument = false;
1444 settings.language = code;
1445 settingsContainer.Save();
1447 #if defined(__WIN32__)
1448 // Set LANGUAGE environment variable
1451 uint16 wLanguage[256];
1455 RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1458 UTF8toUTF16Buffer(code, wLanguage, sizeof(wLanguage) / sizeof(uint16));
1459 RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
1465 if(eClass_IsDerived(app._class, class(GuiApplication)))
1467 GuiApplication guiApp = (GuiApplication)app;
1468 guiApp.desktop.Destroy(0);
1475 for(i = 1; i < app.argc; i++)
1477 const char * arg = app.argv[i];
1479 for(j = 0; (ch = arg[j]); j++)
1480 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
1483 command = new char[len + 1];
1484 strcpy(command, app.argv[0]);
1486 for(i = 1; i < app.argc; i++)
1488 strcat(command, " ");
1490 ReplaceSpaces(command + len, app.argv[i]);
1491 len = (int)strlen(command);
1497 SetEnvironment("ECERE_LANGUAGE", code);
1499 ExecuteWait(command);