diff --git a/uppsrc/Core/Ini.cpp b/uppsrc/Core/Ini.cpp index ba295eb04..13116a4b7 100644 --- a/uppsrc/Core/Ini.cpp +++ b/uppsrc/Core/Ini.cpp @@ -1,375 +1,403 @@ -#include "Core.h" - -namespace Upp { - -static void LoadIniStream(Stream &sin, VectorMap& ret, const char *sfile); - -static void LoadIniFile(const char *filename, VectorMap& ret) -{ - FileIn in(filename); - if(in) LoadIniStream(in, ret, filename); -} - -static void LoadIniStream(Stream& in, VectorMap& key, const char *sfile) -{ - while(!in.IsEof()) { - String line = in.GetLine(); - CParser p(line); - if(p.IsId()) { - String k = p.ReadId(); - if(p.Char('=')) - key.Add(k, p.GetPtr()); - } - else - if(p.Char('@')) { - if(p.Id("include")) { - String fn = p.GetPtr(); - if(!IsFullPath(fn) && sfile) - fn = AppendFileName(GetFileFolder(GetFullPath(sfile)), fn); - LoadIniFile(fn, key); - } - else - if(p.Id("end")) - return; - } - } -} - -VectorMap LoadIniStream(Stream &sin) -{ - VectorMap ret; - LoadIniStream(sin, ret, NULL); - return ret; -} - -VectorMap LoadIniFile(const char *filename) -{ - VectorMap ret; - LoadIniFile(filename, ret); - return ret; -} - -static StaticMutex sMtx; -static char sIniFile[512]; - -int ini_version__ = 1; - -void ReloadIniFile() -{ - Mutex::Lock __(sMtx); - ini_version__++; -} - -void SetIniFile(const char *name) { - Mutex::Lock __(sMtx); - strncpy(sIniFile, name, 511); - ReloadIniFile(); -} - -void IniSet__(int& version) -{ - BarrierWrite(version, ini_version__); -} - -#ifdef flagSO -bool IniChanged__(int version) -{ - return version != ReadWithBarrier(ini_version__); -} -#endif - -String GetIniFile() -{ - return *sIniFile ? sIniFile : ~ConfigFile("q.ini"); -} - -static VectorMap& sIniKeys() -{ - static VectorMap key; - return key; -} - -VectorMap GetIniKeys() -{ - Mutex::Lock __(sMtx); - return VectorMap(sIniKeys(), 0); -} - -String GetIniKey(const char *id, const String& def) { - ASSERT_(IsMainRunning(), "GetIniKey is allowed only after APP_MAIN has started"); - Mutex::Lock __(sMtx); - VectorMap& key = sIniKeys(); - static int version; - if(version != ini_version__) { - version = ini_version__; - key = LoadIniFile(GetIniFile()); - #ifdef PLATFORM_WIN32 - if(key.GetCount() == 0) - key = LoadIniFile(~GetExeDirFile("q.ini")); - if(key.GetCount() == 0) - key = LoadIniFile("c:\\q.ini"); - #endif - #ifdef PLATFORM_POSIX - if(key.GetCount() == 0) - key = LoadIniFile(GetHomeDirFile("q.ini")); - #endif - } - return key.Get(id, def); -} - -String GetIniKey(const char *id) -{ - return GetIniKey(id, String()); -} - -static StaticMutex strMtx; - -IniString::operator String() -{ - String x; - { - Mutex::Lock __(strMtx); - String& s = (*ref_fn)(); - if(IniChanged__(version)) { - s = TrimBoth(GetIniKey(id)); - if(IsNull(s)) - s = (*def)(); - } - x = s; - IniSet__(version); - } - return x; -} - -String IniString::operator=(const String& s) -{ - Mutex::Lock __(strMtx); - (*ref_fn)() = s; - IniSet__(version); - return s; -} - -String IniString::ToString() const -{ - return (String)const_cast(*this); -} - -int64 ReadIniInt(const char *id) -{ - String s = GetIniKey(id); - CParser p(s); - int64 num; - int sgn = 1; - if(p.Char('-')) - sgn = -1; - else - p.Char('+'); - if(p.Char2('0', 'x') || p.Char2('0', 'X')) - num = p.ReadNumber64(16); - else - if(p.IsNumber()) - num = p.ReadNumber(); - else - return Null; - num = sgn * num; - if(p.Char('K')) - num <<= 10; - else - if(p.Char('M')) - num <<= 20; - else - if(p.Char('G')) - num <<= 30; - else - if(p.Char('T')) - num <<= 40; - return num; -} - -int IniInt::Load() { - Mutex::Lock __(sMtx); - if(IniChanged__(version)) { - int64 v = ReadIniInt(id); - value = IsNull(v) ? (*def)() : (int)v; - IniSet__(version); - } - return value; -} - -int IniInt::operator=(int b) { - Mutex::Lock __(sMtx); - BarrierWrite(version, -1); - value = b; - IniSet__(version); - return b; -} - -String IniInt::ToString() const -{ - return AsString((int)const_cast(*this)); -} - -static StaticMutex si64Mtx; - -IniInt64::operator int64() -{ - Mutex::Lock __(si64Mtx); - if(IniChanged__(version)) { - value = ReadIniInt(id); - if(IsNull(value)) - value = (*def)(); - IniSet__(version); - } - return value; -} - -int64 IniInt64::operator=(int64 b) -{ - Mutex::Lock __(si64Mtx); - value = b; - return b; -} - -String IniInt64::ToString() const -{ - return AsString((int64)const_cast(*this)); -} - -double IniDouble::Load() -{ - Mutex::Lock __(sMtx); - if(IniChanged__(version)) { - value = ScanDouble(TrimBoth(ToLower(GetIniKey(id)))); - if(IsNull(value)) - value = (*def)(); - IniSet__(version); - } - return value; -} - -double IniDouble::operator=(double b) -{ - Mutex::Lock __(sMtx); - BarrierWrite(version, -1); - value = b; - IniSet__(version); - return b; -} - -String IniDouble::ToString() const -{ - return AsString((double)const_cast(*this)); -} - -bool IniBool::Load() { - Mutex::Lock __(sMtx); - if(IniChanged__(version)) { - String h = TrimBoth(ToLower(GetIniKey(id))); - if(h.GetCount()) - value = h == "1" || h == "yes" || h == "true" || h == "y"; - else - value = (*def)(); - IniSet__(version); - } - return value; -} - -bool IniBool::operator=(bool b) { - Mutex::Lock __(sMtx); - BarrierWrite(version, -1); - value = b; - IniSet__(version); - return b; -} - -String IniBool::ToString() const -{ - return AsString((bool)const_cast(*this)); -} - -Array& sIniInfo() -{ - static Array s; - return s; -} - -void AddIniInfo(const char *id, String (*current)(), String (*def)(), const char *info) -{ - IniInfo& f = sIniInfo().Add(); - f.id = id; - f.current = current; - f.def = def; - f.info = info; -} - -const Array GetIniInfo() -{ - return sIniInfo(); -} - -String GetIniInfoFormatted() -{ - String r; - for(int i = 0; i < sIniInfo().GetCount(); i++) { - IniInfo& f = sIniInfo()[i]; - r << f.id << " = " << (*f.current)() << " [default: " << (*f.def)() << "]\r\n" - << " " << f.info << "\r\n"; - } - return r; -} - -void TextSettings::Load(const char *filename) -{ - FileIn in(filename); - int themei = 0; - settings.Add(""); - while(!in.IsEof()) { - String ln = in.GetLine(); - const char *s = ln; - if(*s == '[') { - s++; - String theme; - while(*s && *s != ']') - theme.Cat(*s++); - themei = settings.FindAdd(theme); - } - else { - if(themei >= 0) { - String key; - while(*s && *s != '=') { - key.Cat(*s++); - } - if(*s == '=') s++; - String value; - while(*s) { - value.Cat(*s++); - } - if(!IsEmpty(key)) - settings[themei].GetAdd(TrimBoth(key)) = TrimBoth(value); - } - } - } -} - -String TextSettings::Get(const char *group, const char *key) const -{ - int itemi = settings.Find(group); - return itemi < 0 ? Null : settings.Get(group).Get(key, Null); -} - -String TextSettings::Get(int groupIndex, const char *key) const -{ - return groupIndex >= 0 && groupIndex < settings.GetCount() ? - settings[groupIndex].Get(key, Null) : Null; -} - -String TextSettings::Get(int groupIndex, int keyIndex) const -{ - if (groupIndex >= 0 && groupIndex < settings.GetCount()) - return keyIndex >= 0 && keyIndex < settings[groupIndex].GetCount() ? - settings[groupIndex][keyIndex] : Null; - else - return Null; -} - -}; \ No newline at end of file +#include "Core.h" + +namespace Upp { + +String ReplaceEnvVars(CParser& p) { + const VectorMap& vars = Environment(); + String r; + const char* s = p.GetPtr(); + while (!p.IsEof()) { + if(p.Char2('$', '$')) { + r.Cat('$'); + } else if(p.Char('$') && p.IsId()) { + String id = p.ReadId(); + int q = vars.Find(id); + if(q >= 0) + r.Cat(vars[q]); + } else { + p.SkipTerm(); + r.Cat(s, p.GetPtr()); + } + s = p.GetPtr(); + } + return r; +} + +static void LoadIniStream(Stream &sin, VectorMap& ret, const char *sfile); + +static void LoadIniFile(const char *filename, VectorMap& ret) +{ + FileIn in(filename); + if(in) LoadIniStream(in, ret, filename); +} + +static void LoadIniStream(Stream& in, VectorMap& key, const char *sfile) +{ + bool env = false; + while(!in.IsEof()) { + String line = in.GetLine(); + CParser p(line); + if(p.IsId()) { + String k = p.ReadId(); + if(p.Char('=')) + key.Add(k, env ? ReplaceEnvVars(p) : (String)p.GetPtr()); + } + else + if(p.Char('@')) { + if(p.Id("include")) { + String fn = p.GetPtr(); + if(!IsFullPath(fn) && sfile) + fn = AppendFileName(GetFileFolder(GetFullPath(sfile)), fn); + LoadIniFile(fn, key); + } + else + if(p.Id("end")) + return; + else + if(p.Id("replace-env")) + env = true; + else + if(p.Id("ignore-env")) + env = false; + } + } +} + +VectorMap LoadIniStream(Stream &sin) +{ + VectorMap ret; + LoadIniStream(sin, ret, NULL); + return ret; +} + +VectorMap LoadIniFile(const char *filename) +{ + VectorMap ret; + LoadIniFile(filename, ret); + return ret; +} + +static StaticMutex sMtx; +static char sIniFile[512]; + +int ini_version__ = 1; + +void ReloadIniFile() +{ + Mutex::Lock __(sMtx); + ini_version__++; +} + +void SetIniFile(const char *name) { + Mutex::Lock __(sMtx); + strncpy(sIniFile, name, 511); + ReloadIniFile(); +} + +void IniSet__(int& version) +{ + BarrierWrite(version, ini_version__); +} + +#ifdef flagSO +bool IniChanged__(int version) +{ + return version != ReadWithBarrier(ini_version__); +} +#endif + +String GetIniFile() +{ + return *sIniFile ? sIniFile : ~ConfigFile("q.ini"); +} + +static VectorMap& sIniKeys() +{ + static VectorMap key; + return key; +} + +VectorMap GetIniKeys() +{ + Mutex::Lock __(sMtx); + return VectorMap(sIniKeys(), 0); +} + +String GetIniKey(const char *id, const String& def) { + ASSERT_(IsMainRunning(), "GetIniKey is allowed only after APP_MAIN has started"); + Mutex::Lock __(sMtx); + VectorMap& key = sIniKeys(); + static int version; + if(version != ini_version__) { + version = ini_version__; + key = LoadIniFile(GetIniFile()); + #ifdef PLATFORM_WIN32 + if(key.GetCount() == 0) + key = LoadIniFile(~GetExeDirFile("q.ini")); + if(key.GetCount() == 0) + key = LoadIniFile("c:\\q.ini"); + #endif + #ifdef PLATFORM_POSIX + if(key.GetCount() == 0) + key = LoadIniFile(GetHomeDirFile("q.ini")); + #endif + } + return key.Get(id, def); +} + +String GetIniKey(const char *id) +{ + return GetIniKey(id, String()); +} + +static StaticMutex strMtx; + +IniString::operator String() +{ + String x; + { + Mutex::Lock __(strMtx); + String& s = (*ref_fn)(); + if(IniChanged__(version)) { + s = TrimBoth(GetIniKey(id)); + if(IsNull(s)) + s = (*def)(); + } + x = s; + IniSet__(version); + } + return x; +} + +String IniString::operator=(const String& s) +{ + Mutex::Lock __(strMtx); + (*ref_fn)() = s; + IniSet__(version); + return s; +} + +String IniString::ToString() const +{ + return (String)const_cast(*this); +} + +int64 ReadIniInt(const char *id) +{ + String s = GetIniKey(id); + CParser p(s); + int64 num; + int sgn = 1; + if(p.Char('-')) + sgn = -1; + else + p.Char('+'); + if(p.Char2('0', 'x') || p.Char2('0', 'X')) + num = p.ReadNumber64(16); + else + if(p.IsNumber()) + num = p.ReadNumber(); + else + return Null; + num = sgn * num; + if(p.Char('K')) + num <<= 10; + else + if(p.Char('M')) + num <<= 20; + else + if(p.Char('G')) + num <<= 30; + else + if(p.Char('T')) + num <<= 40; + return num; +} + +int IniInt::Load() { + Mutex::Lock __(sMtx); + if(IniChanged__(version)) { + int64 v = ReadIniInt(id); + value = IsNull(v) ? (*def)() : (int)v; + IniSet__(version); + } + return value; +} + +int IniInt::operator=(int b) { + Mutex::Lock __(sMtx); + BarrierWrite(version, -1); + value = b; + IniSet__(version); + return b; +} + +String IniInt::ToString() const +{ + return AsString((int)const_cast(*this)); +} + +static StaticMutex si64Mtx; + +IniInt64::operator int64() +{ + Mutex::Lock __(si64Mtx); + if(IniChanged__(version)) { + value = ReadIniInt(id); + if(IsNull(value)) + value = (*def)(); + IniSet__(version); + } + return value; +} + +int64 IniInt64::operator=(int64 b) +{ + Mutex::Lock __(si64Mtx); + value = b; + return b; +} + +String IniInt64::ToString() const +{ + return AsString((int64)const_cast(*this)); +} + +double IniDouble::Load() +{ + Mutex::Lock __(sMtx); + if(IniChanged__(version)) { + value = ScanDouble(TrimBoth(ToLower(GetIniKey(id)))); + if(IsNull(value)) + value = (*def)(); + IniSet__(version); + } + return value; +} + +double IniDouble::operator=(double b) +{ + Mutex::Lock __(sMtx); + BarrierWrite(version, -1); + value = b; + IniSet__(version); + return b; +} + +String IniDouble::ToString() const +{ + return AsString((double)const_cast(*this)); +} + +bool IniBool::Load() { + Mutex::Lock __(sMtx); + if(IniChanged__(version)) { + String h = TrimBoth(ToLower(GetIniKey(id))); + if(h.GetCount()) + value = h == "1" || h == "yes" || h == "true" || h == "y"; + else + value = (*def)(); + IniSet__(version); + } + return value; +} + +bool IniBool::operator=(bool b) { + Mutex::Lock __(sMtx); + BarrierWrite(version, -1); + value = b; + IniSet__(version); + return b; +} + +String IniBool::ToString() const +{ + return AsString((bool)const_cast(*this)); +} + +Array& sIniInfo() +{ + static Array s; + return s; +} + +void AddIniInfo(const char *id, String (*current)(), String (*def)(), const char *info) +{ + IniInfo& f = sIniInfo().Add(); + f.id = id; + f.current = current; + f.def = def; + f.info = info; +} + +const Array GetIniInfo() +{ + return sIniInfo(); +} + +String GetIniInfoFormatted() +{ + String r; + for(int i = 0; i < sIniInfo().GetCount(); i++) { + IniInfo& f = sIniInfo()[i]; + r << f.id << " = " << (*f.current)() << " [default: " << (*f.def)() << "]\r\n" + << " " << f.info << "\r\n"; + } + return r; +} + +void TextSettings::Load(const char *filename) +{ + FileIn in(filename); + int themei = 0; + settings.Add(""); + while(!in.IsEof()) { + String ln = in.GetLine(); + const char *s = ln; + if(*s == '[') { + s++; + String theme; + while(*s && *s != ']') + theme.Cat(*s++); + themei = settings.FindAdd(theme); + } + else { + if(themei >= 0) { + String key; + while(*s && *s != '=') { + key.Cat(*s++); + } + if(*s == '=') s++; + String value; + while(*s) { + value.Cat(*s++); + } + if(!IsEmpty(key)) + settings[themei].GetAdd(TrimBoth(key)) = TrimBoth(value); + } + } + } +} + +String TextSettings::Get(const char *group, const char *key) const +{ + int itemi = settings.Find(group); + return itemi < 0 ? Null : settings.Get(group).Get(key, Null); +} + +String TextSettings::Get(int groupIndex, const char *key) const +{ + return groupIndex >= 0 && groupIndex < settings.GetCount() ? + settings[groupIndex].Get(key, Null) : Null; +} + +String TextSettings::Get(int groupIndex, int keyIndex) const +{ + if (groupIndex >= 0 && groupIndex < settings.GetCount()) + return keyIndex >= 0 && keyIndex < settings[groupIndex].GetCount() ? + settings[groupIndex][keyIndex] : Null; + else + return Null; +} + +}; diff --git a/uppsrc/Core/parser.cpp b/uppsrc/Core/parser.cpp index 97f09269a..d303c88af 100644 --- a/uppsrc/Core/parser.cpp +++ b/uppsrc/Core/parser.cpp @@ -171,7 +171,7 @@ int64 CParser::ReadInt64() throw(Error) int64 CParser::ReadInt64(int64 min, int64 max) throw(Error) { - int64 n = ReadInt(); + int64 n = ReadInt64(); if(n < min || n > max) ThrowError("number is out of range"); return n;