+
+ CompilerConfig ::read(const char * path)
+ {
+ CompilerConfig d = null;
+ readConfigFile(path, class(CompilerConfig), &d);
+ return d;
+ }
+
+ void write(IDESettingsContainer settingsContainer)
+ {
+ char dir[MAX_LOCATION];
+ char path[MAX_LOCATION];
+ const char * settingsFilePath = settingsContainer.settingsFilePath;
+ settingsContainer.getConfigFilePath(path, _class, dir, name);
+ if(FileExists(settingsFilePath) && !FileExists(dir))
+ {
+ MakeDir(dir);
+ if(!FileExists(dir))
+ PrintLn($"Error creating compiler configs directory at ", dir, " location.");
+ }
+ writeConfigFile(path, _class, this);
+ }
+}
+
+class CompilerConfigs : List<CompilerConfig>
+{
+ CompilerConfig GetCompilerConfig(const String compilerName)
+ {
+ const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
+ CompilerConfig compilerConfig = null;
+ for(compiler : this)
+ {
+ if(!strcmp(compiler.name, name))
+ {
+ compilerConfig = compiler;
+ break;
+ }
+ }
+ if(!compilerConfig && count)
+ compilerConfig = this[0];
+ if(compilerConfig)
+ {
+ incref compilerConfig;
+ if(compilerConfig._refCount == 1)
+ incref compilerConfig;
+ }
+ return compilerConfig;
+ }
+
+ void ensureDefaults()
+ {
+ // Ensure we have a default compiler
+ CompilerConfig defaultCompiler = GetCompilerConfig(defaultCompilerName);
+ if(!defaultCompiler)
+ {
+ defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
+ Insert(null, defaultCompiler);
+ defaultCompiler = null;
+ }
+ delete defaultCompiler;
+
+ for(ccfg : this)
+ {
+ if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
+ ccfg.ecpCommand = ecpDefaultCommand;
+ if(!ccfg.eccCommand || !ccfg.eccCommand[0])
+ ccfg.eccCommand = eccDefaultCommand;
+ if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
+ ccfg.ecsCommand = ecsDefaultCommand;
+ if(!ccfg.earCommand || !ccfg.earCommand[0])
+ ccfg.earCommand = earDefaultCommand;
+ if(!ccfg.cppCommand || !ccfg.cppCommand[0])
+ ccfg.cppCommand = cppDefaultCommand;
+ if(!ccfg.ccCommand || !ccfg.ccCommand[0])
+ ccfg.ccCommand = ccDefaultCommand;
+ if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
+ ccfg.cxxCommand = cxxDefaultCommand;
+ /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
+ ccfg.ldCommand = ldDefaultCommand;*/
+ if(!ccfg.arCommand || !ccfg.arCommand[0])
+ ccfg.arCommand = arDefaultCommand;
+ if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
+ ccfg.objectFileExt = objectDefaultFileExt;
+ /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
+ ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
+ /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
+ ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
+ /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
+ ccfg.executableFileExt = outputDefaultFileExt;*/
+ if(!ccfg._refCount) incref ccfg;
+ }
+ }
+
+ AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
+ {
+ AVLTree<String> list { };
+ for(ccfg : this)
+ {
+ bool found = false;
+ for(occfg : oldConfigs; !strcmp(ccfg.name, occfg.name))
+ {
+ found = true;
+ if(ccfg.OnCompare(occfg))
+ list.Add(CopyString(ccfg.name));
+ break;
+ }
+ if(!found)
+ list.Add(CopyString(ccfg.name));
+ }
+ return list;
+ }
+
+ bool read(IDESettingsContainer settingsContainer)
+ {
+ if(settingsContainer.settingsFilePath)
+ {
+ char dir[MAX_LOCATION];
+ char path[MAX_LOCATION];
+ Class _class = class(CompilerConfig);
+ settingsContainer.getConfigFilePath(path, _class, dir, null);
+ if(dir[0])
+ {
+ AVLTree<const String> addedConfigs { };
+ Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
+ MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
+ Free();
+ settingsContainer.compilerConfigs = this; // Merge IDEConfigHolder / IDESettingsContainer?
+ if(it.Index("Default", false))
+ {
+ CompilerConfig ccfg = it.data;
+ Add(ccfg.Copy());
+ addedConfigs.Add(ccfg.name);
+ }
+ for(ccfg : compilerConfigsByName)
+ {
+ if(!addedConfigs.Find(ccfg.name))
+ {
+ Add(ccfg.Copy());
+ addedConfigs.Add(ccfg.name);
+ }
+ }
+ delete addedConfigs;
+ ensureDefaults();
+ compilerConfigsByName.Free();
+ delete compilerConfigsByName;
+ settingsContainer.onLoadCompilerConfigs();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void write(IDESettingsContainer settingsContainer, AVLTree<String> cfgsToWrite)
+ {
+ char dir[MAX_LOCATION];
+ char path[MAX_LOCATION];
+ Map<String, String> paths;
+ settingsContainer.getConfigFilePath(path, class(CompilerConfig), dir, null);
+ paths = getCompilerConfigFilePathsByName(dir);
+ {
+ MapIterator<String, String> it { map = paths };
+ for(c : this)
+ {
+ CompilerConfig ccfg = c;
+ if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
+ ccfg.write(settingsContainer);
+ if(it.Index(ccfg.name, false))
+ {
+ delete it.data;
+ it.Remove();
+ }
+ }
+ }
+ for(p : paths)
+ {
+ const char * path = p;
+ DeleteFile(path);
+ }
+ paths.Free();
+ delete paths;
+ }
+}
+
+#if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
+struct LanguageOption
+{
+ const String name;
+ const String bitmap;
+ const String code;
+ BitmapResource res;
+
+ const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
+ {
+ return name;
+ }
+
+ void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
+ {
+ Bitmap icon = res ? res.bitmap : null;
+ int w = 8 + 16;
+ if(icon)
+ surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
+ class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
+ }
+};
+
+Array<LanguageOption> languages
+{ [
+ { "English", ":countryCode/gb.png", "" },
+ { "汉语", ":countryCode/cn.png", "zh_CN" },
+ { "Español", ":countryCode/es.png", "es" },
+ { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
+ { "Русский (43%)", ":countryCode/ru.png", "ru" },
+ { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
+ { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
+ { "मराठी (10%)", ":countryCode/in.png", "mr" },
+ { "Hebrew (8%)", ":countryCode/il.png", "he" },
+ { "Magyar (8%)", ":countryCode/hu.png", "hu" }
+] };
+
+const String GetLanguageString()
+{
+ char * dot, * colon;
+ static char lang[256];
+ const String language = getenv("ECERE_LANGUAGE");
+ if(!language) language = getenv("LANGUAGE");
+ if(!language) language = getenv("LC_ALL");
+ if(!language) language = getenv("LC_MESSAGES");
+ if(!language) language = getenv("LANG");
+ if(!language) language = "";
+ if(language && (colon = strchr(language, ':')))
+ {
+ if(lang != language)
+ strncpy(lang, language, sizeof(lang));
+ lang[sizeof(lang)-1] = 0;
+ lang[colon - language] = 0;
+ language = lang;
+ }
+ if(language && (dot = strchr(language, '.')))
+ {
+ if(lang != language)
+ strncpy(lang, language, sizeof(lang));
+ lang[sizeof(lang)-1] = 0;
+ lang[dot - language] = 0;
+ language = lang;
+ }
+ return language;
+}
+
+void setEcereLanguageInWinRegEnvironment(const char * languageCode)
+{
+#ifdef __WIN32__
+ HKEY key = null;
+ uint16 wLanguage[256];
+ DWORD status;
+ wLanguage[0] = 0;
+
+ RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
+ if(key)
+ {
+ UTF8toUTF16Buffer(languageCode, wLanguage, sizeof(wLanguage) / sizeof(uint16));
+ RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
+ RegCloseKey(key);
+ }
+#endif