ultimatepp/uppsrc/Core/Ini.cpp
cxl 822cfb6bce uppsrc: Removed flagSO #ifdefs (actually to make SO compilation possible)
git-svn-id: svn://ultimatepp.org/upp/trunk@12997 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2019-04-14 08:34:13 +00:00

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;
}
};