mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
425 lines
8.2 KiB
C++
425 lines
8.2 KiB
C++
#include "Core.h"
|
|
|
|
namespace Upp {
|
|
|
|
static void LoadIniStream(Stream &sin, VectorMap<String, String>& ret, const char *sfile);
|
|
|
|
static void LoadIniFile(const char *filename, VectorMap<String, String>& ret)
|
|
{
|
|
FileIn in(filename);
|
|
if(in) LoadIniStream(in, ret, filename);
|
|
}
|
|
|
|
static void LoadIniStream(Stream& in, VectorMap<String, String>& 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('=')) {
|
|
String h = TrimBoth((String)p.GetSpacePtr());
|
|
if(env) {
|
|
String hh;
|
|
const char *s = ~h;
|
|
while(*s) {
|
|
if(*s == '$') {
|
|
s++;
|
|
if(*s == '$') {
|
|
hh.Cat('$');
|
|
s++;
|
|
}
|
|
else {
|
|
String id;
|
|
if (*s == '{') {
|
|
while(*++s != '}')
|
|
id.Cat(*s);
|
|
s++;
|
|
} else {
|
|
while(iscid(*s))
|
|
id.Cat(*s++);
|
|
}
|
|
hh.Cat(GetEnv(id));
|
|
}
|
|
}
|
|
else
|
|
hh.Cat(*s++);
|
|
}
|
|
key.Add(k, hh);
|
|
}
|
|
else
|
|
key.Add(k, h);
|
|
}
|
|
}
|
|
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<String, String> LoadIniStream(Stream &sin)
|
|
{
|
|
VectorMap<String, String> ret;
|
|
LoadIniStream(sin, ret, NULL);
|
|
return ret;
|
|
}
|
|
|
|
VectorMap<String, String> LoadIniFile(const char *filename)
|
|
{
|
|
VectorMap<String, String> 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)
|
|
{
|
|
version = ini_version__;
|
|
}
|
|
|
|
String GetIniFile()
|
|
{
|
|
return *sIniFile ? sIniFile : ~ConfigFile("q.ini");
|
|
}
|
|
|
|
static VectorMap<String, String>& sIniKeys()
|
|
{
|
|
static VectorMap<String, String> key;
|
|
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;
|
|
}
|
|
|
|
VectorMap<String, String> GetIniKeys()
|
|
{
|
|
Mutex::Lock __(sMtx);
|
|
return clone(sIniKeys());
|
|
}
|
|
|
|
String GetIniKey(const char *id, const String& def) {
|
|
ASSERT_(IsMainRunning(), "GetIniKey is allowed only after APP_MAIN has started");
|
|
Mutex::Lock __(sMtx);
|
|
return sIniKeys().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<IniString&>(*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);
|
|
value = b;
|
|
IniSet__(version);
|
|
return b;
|
|
}
|
|
|
|
String IniInt::ToString() const
|
|
{
|
|
return AsString((int)const_cast<IniInt&>(*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<IniInt64&>(*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);
|
|
value = b;
|
|
IniSet__(version);
|
|
return b;
|
|
}
|
|
|
|
String IniDouble::ToString() const
|
|
{
|
|
return AsString((double)const_cast<IniDouble&>(*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);
|
|
value = b;
|
|
IniSet__(version);
|
|
return b;
|
|
}
|
|
|
|
String IniBool::ToString() const
|
|
{
|
|
return AsString((bool)const_cast<IniBool&>(*this));
|
|
}
|
|
|
|
Array<IniInfo>& sIniInfo()
|
|
{
|
|
static Array<IniInfo> 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<IniInfo>& 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;
|
|
}
|
|
|
|
String DefaultIniFileContent()
|
|
{
|
|
String r;
|
|
for(int i = 0; i < sIniInfo().GetCount(); i++) {
|
|
IniInfo& f = sIniInfo()[i];
|
|
r << "#" << f.info << "\r\n" << f.id << '=' << (*f.def)() << "\r\n\r\n";
|
|
}
|
|
return r;
|
|
}
|
|
|
|
String CurrentIniFileContent(bool comment_defaults)
|
|
{
|
|
String r;
|
|
for(int i = 0; i < sIniInfo().GetCount(); i++) {
|
|
IniInfo& f = sIniInfo()[i];
|
|
r << "#" << f.info << "\r\n";
|
|
if (comment_defaults && (*f.current)() == (*f.def)())
|
|
r << '#';
|
|
r << f.id << '=' << (*f.current)() << "\r\n\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;
|
|
}
|
|
|
|
};
|