mirror of
https://github.com/bearstonem/openmohaa-vr.git
synced 2026-10-19 00:00:24 +02:00
938 lines
25 KiB
C++
938 lines
25 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2015 the OpenMoHAA team
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
// configurator.cpp: Config class for INI files.
|
|
|
|
#include "configurator.h"
|
|
|
|
CLASS_DECLARATION(Class, Configurator, NULL) {
|
|
{NULL, NULL}
|
|
};
|
|
|
|
Configurator::Configurator(const char *filename)
|
|
{
|
|
Parse(filename);
|
|
}
|
|
|
|
Configurator::Configurator()
|
|
{
|
|
m_bNoWrite = false;
|
|
m_bNeedWrite = false;
|
|
}
|
|
|
|
Configurator::~Configurator()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
size_t Configurator::GetLine(char *dest, const char *data, size_t size)
|
|
{
|
|
const char *p = data;
|
|
size_t i = 0;
|
|
|
|
while (*p == '\n') {
|
|
p++;
|
|
}
|
|
|
|
if (p >= data + size) {
|
|
return 0;
|
|
}
|
|
|
|
while (*p && *p != '\n' && i < size) {
|
|
dest[i++] = *p++;
|
|
}
|
|
|
|
if (i < size) {
|
|
dest[i++] = '\n';
|
|
}
|
|
|
|
dest[i] = 0;
|
|
|
|
return p - data;
|
|
}
|
|
|
|
void Configurator::RemoveSection(configSection_t *section)
|
|
{
|
|
configKey_t *key;
|
|
int i;
|
|
|
|
for (i = 0; i < section->key.NumObjects(); i++) {
|
|
key = section->key[i];
|
|
RemoveKey(section, key);
|
|
}
|
|
|
|
m_reverseSections.RemoveObject(section);
|
|
m_sections.remove(section->name);
|
|
}
|
|
|
|
void Configurator::RemoveKey(configSection_t *section, configKey_t *key)
|
|
{
|
|
section->key.RemoveObject(key);
|
|
delete key;
|
|
}
|
|
|
|
configSection_t *Configurator::CreateSection(const char *section)
|
|
{
|
|
configSection_t *s = &m_sections.addKeyValue(section);
|
|
|
|
if (s->key.NumObjects()) {
|
|
RemoveSection(s);
|
|
s = &m_sections.addKeyValue(section);
|
|
} else {
|
|
m_reverseSections.AddObject(s);
|
|
}
|
|
|
|
s->name = section;
|
|
return s;
|
|
}
|
|
|
|
int Configurator::GetKeyArray(char *key)
|
|
{
|
|
int count;
|
|
size_t len;
|
|
int arrayindex = -1;
|
|
char *p1, *p2;
|
|
|
|
len = strlen(key) + 1;
|
|
p1 = new char[len];
|
|
p2 = new char[len];
|
|
|
|
count = sscanf(key, "%[^[] [%[^]]", p1, p2);
|
|
if (count == 2) {
|
|
// Check for an array [num]
|
|
strcpy(key, p1);
|
|
arrayindex = atoi(p2);
|
|
if (arrayindex < 0 || arrayindex > MAX_CONFIGURATOR_ARRAY_SIZE) {
|
|
arrayindex = -2;
|
|
}
|
|
}
|
|
|
|
delete[] p1;
|
|
delete[] p2;
|
|
|
|
return arrayindex;
|
|
}
|
|
|
|
int Configurator::GetKeyArray(str& key)
|
|
{
|
|
int count;
|
|
size_t len;
|
|
int arrayindex = -1;
|
|
str arrayval;
|
|
char *p1, *p2;
|
|
|
|
len = key.length() + 1;
|
|
p1 = new char[len];
|
|
p2 = new char[len];
|
|
|
|
count = sscanf(key, "%[^[] [%[^]]", p1, p2);
|
|
if (count == 2) {
|
|
// Check for an array [num]
|
|
arrayval = p2;
|
|
arrayindex = atoi(arrayval.c_str());
|
|
|
|
key = p1;
|
|
|
|
if (arrayindex < 0 || arrayindex > MAX_CONFIGURATOR_ARRAY_SIZE) {
|
|
arrayindex = -2;
|
|
}
|
|
}
|
|
|
|
delete[] p1;
|
|
delete[] p2;
|
|
|
|
return arrayindex;
|
|
}
|
|
|
|
configKey_t *Configurator::CreateKey(configSection_t *section, const char *key, unsigned int *index)
|
|
{
|
|
configKey_t *k;
|
|
str keyname;
|
|
int arrayindex;
|
|
|
|
if (index) {
|
|
*index = 0;
|
|
}
|
|
|
|
keyname = key;
|
|
|
|
arrayindex = GetKeyArray(keyname);
|
|
if (arrayindex == -2) {
|
|
return NULL;
|
|
} else if (arrayindex >= 0) {
|
|
if (index) {
|
|
*index = arrayindex;
|
|
}
|
|
}
|
|
|
|
k = FindKey(section, keyname);
|
|
if (k) {
|
|
if (arrayindex == -1 || !k->value.NumObjects()) {
|
|
RemoveKey(section, k);
|
|
k = NULL;
|
|
}
|
|
}
|
|
|
|
if (!k) {
|
|
k = new configKey_t;
|
|
section->key.AddObject(k);
|
|
k->name = keyname;
|
|
k->m_bArray = arrayindex != -1;
|
|
k->m_bNeedWrite = false;
|
|
}
|
|
|
|
if (arrayindex >= k->value.MaxObjects()) {
|
|
k->value.Resize((arrayindex + 1) * 2);
|
|
}
|
|
|
|
return k;
|
|
}
|
|
|
|
configSection_t *Configurator::FindSection(const char *section)
|
|
{
|
|
configSection_t *s = m_sections.findKeyValue(section);
|
|
return s;
|
|
}
|
|
|
|
configKey_t *Configurator::FindKey(configSection_t *section, const char *key)
|
|
{
|
|
configKey_t *k;
|
|
int i;
|
|
|
|
for (i = 0; i < section->key.NumObjects(); i++) {
|
|
k = section->key[i];
|
|
if (!k->name.icmp(key)) {
|
|
return k;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int Configurator::CutLine(char *data)
|
|
{
|
|
char *p = data;
|
|
while (*p == '\n') {
|
|
*p++ = 0;
|
|
}
|
|
while (*p && *p != '\n') {
|
|
*p++ = 0;
|
|
}
|
|
return p - data;
|
|
}
|
|
|
|
bool Configurator::SetupLine(char *line, int& lineno, size_t& len, size_t& last)
|
|
{
|
|
lineno++;
|
|
len = (int)strlen(line) - 1;
|
|
if (len <= 0) {
|
|
return false;
|
|
}
|
|
|
|
if (line[len] != '\n') {
|
|
last = 0;
|
|
glbs.DPrintf("Configurator::SetupLine: input line too long in %s (line %d)\n", m_filename.c_str(), lineno);
|
|
return false;
|
|
}
|
|
|
|
while ((len >= 0) && ((line[len] == '\n') || (isspace(line[len])))) {
|
|
line[len] = 0;
|
|
len--;
|
|
}
|
|
if (line[len] == '\\') {
|
|
last = len;
|
|
return false;
|
|
} else {
|
|
last = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Configurator::WriteData(char **data, size_t *size)
|
|
{
|
|
configSection_t *section;
|
|
configKey_t *key;
|
|
configValue_t *val;
|
|
str value;
|
|
char *oldData = *data;
|
|
char *currentData = *data;
|
|
size_t currentSize = *size;
|
|
size_t len, tlen = 0;
|
|
int i, j, k;
|
|
size_t offset, offset2;
|
|
bool bFound;
|
|
|
|
for (i = 1; i <= m_reverseSections.NumObjects(); i++) {
|
|
section = m_reverseSections.ObjectAt(i);
|
|
|
|
if (!FindData(LINE_SECTION, section->name, NULL, &offset, currentData, currentSize)) {
|
|
oldData = currentData;
|
|
|
|
len = (offset ? 2 : 0) + 1 + section->name.length() + 1; // \n\n + [ + section + ]
|
|
currentSize += len;
|
|
currentData = new char[currentSize + 1];
|
|
strncpy(currentData, oldData, offset);
|
|
Com_sprintf(
|
|
currentData + offset, currentSize + 1 - offset, offset ? "\n\n[%s]" : "[%s]", section->name.c_str()
|
|
);
|
|
Q_strncpyz(currentData + offset + len, oldData + offset, currentSize + 1 - offset - len);
|
|
|
|
if (currentData != oldData) {
|
|
delete[] oldData;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < section->key.NumObjects(); j++) {
|
|
key = section->key[j];
|
|
if (!key->m_bNeedWrite) {
|
|
continue;
|
|
}
|
|
|
|
if (key->m_bArray) {
|
|
for (k = 0; k < key->value.NumObjects(); k++) {
|
|
val = &key->value[k];
|
|
if (!val->m_bNeedWrite) {
|
|
continue;
|
|
}
|
|
value = val->value;
|
|
|
|
bFound = FindData(
|
|
LINE_VALUE, section->name, key->name + "[" + k + "]", &offset, currentData, currentSize
|
|
);
|
|
{
|
|
int digits, l;
|
|
|
|
oldData = currentData;
|
|
|
|
l = k;
|
|
digits = 0;
|
|
if (!l) {
|
|
l = 1;
|
|
}
|
|
while (l) {
|
|
l /= 10;
|
|
digits++;
|
|
}
|
|
|
|
if (bFound) {
|
|
len = CutLine(currentData + offset);
|
|
currentSize -= len;
|
|
offset2 = offset + len;
|
|
} else {
|
|
offset2 = offset;
|
|
}
|
|
|
|
len = 1 + key->name.length() + 1 + digits + 1 + 1
|
|
+ value.length(); // \n + name + [ + digits + ] + = + value
|
|
currentSize += len;
|
|
currentData = new char[currentSize + 1];
|
|
strncpy(currentData, oldData, offset);
|
|
Com_sprintf(
|
|
currentData + offset,
|
|
currentSize + 1 - offset,
|
|
"\n%s[%d]=%s",
|
|
key->name.c_str(),
|
|
k,
|
|
value.c_str()
|
|
);
|
|
Q_strncpyz(currentData + offset + len, oldData + offset2, currentSize + 1 - offset - len);
|
|
|
|
if (currentData != oldData) {
|
|
delete[] oldData;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
val = &key->value[0];
|
|
if (!val->m_bNeedWrite) {
|
|
continue;
|
|
}
|
|
value = val->value;
|
|
|
|
bFound = FindData(LINE_VALUE, section->name, key->name, &offset, currentData, currentSize);
|
|
{
|
|
oldData = currentData;
|
|
|
|
if (bFound) {
|
|
len = CutLine(currentData + offset);
|
|
currentSize -= len;
|
|
offset2 = offset + len;
|
|
} else {
|
|
offset2 = offset;
|
|
}
|
|
|
|
len = 1 + key->name.length() + 1 + value.length(); // \n + name + = + value
|
|
currentSize += len;
|
|
currentData = new char[currentSize + 1];
|
|
strncpy(currentData, oldData, offset);
|
|
Com_sprintf(
|
|
currentData + offset, currentSize + 1 - offset "\n%s=%s", key->name.c_str(), value.c_str()
|
|
);
|
|
Q_strncpyz(currentData + offset + len, oldData + offset2, currentSize + 1 - offset - len);
|
|
|
|
if (currentData != oldData) {
|
|
delete[] oldData;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (currentData[currentSize - 1] != '\n') {
|
|
currentData[currentSize] = '\n';
|
|
currentSize++;
|
|
}
|
|
|
|
*data = currentData;
|
|
*size = currentSize;
|
|
}
|
|
|
|
void Configurator::WriteData2(char **data, size_t *size)
|
|
{
|
|
configSection_t *section;
|
|
configKey_t *key;
|
|
configValue_t *val;
|
|
str value;
|
|
char *oldData = *data;
|
|
char *currentData = *data;
|
|
size_t currentSize = *size;
|
|
char *p = currentData;
|
|
size_t tlen = 0;
|
|
int i, j, k;
|
|
|
|
for (i = 1; i <= m_reverseSections.NumObjects(); i++) {
|
|
section = m_reverseSections.ObjectAt(i);
|
|
|
|
if (i == 1) {
|
|
tlen += 1 + section->name.length() + 1 + 1; // [ + name + ] + \n
|
|
} else {
|
|
tlen += 1 + 1 + section->name.length() + 1 + 1; // \n + [ name + ] + \n
|
|
}
|
|
|
|
if (tlen > currentSize) {
|
|
oldData = currentData;
|
|
|
|
currentSize = tlen + 1024;
|
|
currentData = new char[currentSize];
|
|
p = currentData + (p - oldData);
|
|
Q_strncpyz(currentData, oldData, currentSize);
|
|
|
|
delete[] oldData;
|
|
}
|
|
|
|
if (i == 1) {
|
|
p += Com_sprintf(p, currentSize - (p - currentData), "[%s]\n", section->name.c_str());
|
|
} else {
|
|
p += Com_sprintf(p, currentSize - (p - currentData), "\n[%s]\n", section->name.c_str());
|
|
}
|
|
|
|
for (j = 0; j < section->key.NumObjects(); j++) {
|
|
key = section->key[j];
|
|
if (!key->m_bNeedWrite) {
|
|
continue;
|
|
}
|
|
|
|
if (key->m_bArray) {
|
|
for (k = 0; k < key->value.NumObjects(); k++) {
|
|
val = &key->value[k];
|
|
if (!val->m_bNeedWrite) {
|
|
continue;
|
|
}
|
|
value = val->value;
|
|
|
|
{
|
|
int digits, l;
|
|
|
|
l = k;
|
|
digits = 0;
|
|
if (!l) {
|
|
l = 1;
|
|
}
|
|
while (l) {
|
|
l /= 10;
|
|
digits++;
|
|
}
|
|
|
|
tlen += key->name.length() + 1 + digits + 1 + 1 + value.length()
|
|
+ 1; // name + [ + digits + ] + = + value + \n
|
|
if (tlen > currentSize) {
|
|
oldData = currentData;
|
|
|
|
currentSize = tlen + 1024;
|
|
currentData = new char[currentSize];
|
|
p = currentData + (p - oldData);
|
|
strcpy(currentData, oldData);
|
|
|
|
delete[] oldData;
|
|
}
|
|
|
|
p += Com_sprintf(
|
|
p, currentSize - (p - currentData), "%s[%d]=%s\n", key->name.c_str(), k, value.c_str()
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
val = &key->value[0];
|
|
if (!val->m_bNeedWrite) {
|
|
continue;
|
|
}
|
|
value = val->value;
|
|
|
|
tlen += key->name.length() + 1 + value.length() + 1; // name + = + value + \n
|
|
if (tlen > currentSize) {
|
|
oldData = currentData;
|
|
|
|
currentSize = tlen + 1024;
|
|
currentData = new char[currentSize];
|
|
p = currentData + (p - oldData);
|
|
strcpy(currentData, oldData);
|
|
|
|
delete[] oldData;
|
|
}
|
|
|
|
p += Com_sprintf(p, currentSize - (p - currentData), "%s=%s\n", key->name.c_str(), value.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
*data = currentData;
|
|
*size = tlen;
|
|
}
|
|
|
|
bool Configurator::FindData(int type, const char *s, const char *k, size_t *offset, const char *data, size_t size)
|
|
{
|
|
static char line[MAX_STRING_TOKENS + 1];
|
|
static char section[MAX_STRING_TOKENS + 1];
|
|
static char key[MAX_STRING_TOKENS + 1];
|
|
static char val[MAX_STRING_TOKENS + 1];
|
|
|
|
size_t last = 0;
|
|
size_t len;
|
|
size_t olen = 0;
|
|
size_t tlen = 0;
|
|
int lineno = 0;
|
|
int arrayindex;
|
|
|
|
bool bFoundSection = false;
|
|
|
|
*offset = 0;
|
|
|
|
while ((olen = GetLine(line + last, data + tlen, MAX_STRING_TOKENS - last)) != 0) {
|
|
tlen += olen;
|
|
if (!SetupLine(line + last, lineno, len, last)) {
|
|
continue;
|
|
}
|
|
|
|
switch (ParseLine(line, section, key, val)) {
|
|
case LINE_SECTION:
|
|
if (bFoundSection) {
|
|
// Return the last line of the section to append
|
|
*offset = tlen - olen;
|
|
return false;
|
|
}
|
|
|
|
if (!Q_stricmp(s, section)) {
|
|
bFoundSection = true;
|
|
|
|
if (type == LINE_SECTION) {
|
|
*offset = tlen;
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LINE_VALUE:
|
|
arrayindex = GetKeyArray(key);
|
|
if (arrayindex >= 0) {
|
|
Com_sprintf(key, sizeof(key), "%s[%d]", key, arrayindex);
|
|
}
|
|
|
|
if (type == LINE_VALUE && bFoundSection && !Q_stricmp(k, key)) {
|
|
*offset = tlen - olen;
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
*offset = tlen;
|
|
return false;
|
|
}
|
|
|
|
void Configurator::ParseData(const char *data, size_t size)
|
|
{
|
|
static char line[MAX_STRING_TOKENS + 1];
|
|
static char section[MAX_STRING_TOKENS + 1];
|
|
static char key[MAX_STRING_TOKENS + 1];
|
|
static char val[MAX_STRING_TOKENS + 1];
|
|
|
|
size_t last = 0;
|
|
size_t len;
|
|
size_t tlen = 0;
|
|
int lineno = 0;
|
|
unsigned int index = 0;
|
|
|
|
configSection_t *current;
|
|
configKey_t *k;
|
|
configValue_t v;
|
|
|
|
while ((len = GetLine(line + last, data + tlen, MAX_STRING_TOKENS - last)) != 0) {
|
|
tlen += len;
|
|
if (!SetupLine(line + last, lineno, len, last)) {
|
|
continue;
|
|
}
|
|
|
|
switch (ParseLine(line, section, key, val)) {
|
|
case LINE_EMPTY:
|
|
case LINE_COMMENT:
|
|
break;
|
|
|
|
case LINE_SECTION:
|
|
current = CreateSection(section);
|
|
break;
|
|
|
|
case LINE_VALUE:
|
|
k = CreateKey(current, key, &index);
|
|
if (!k) {
|
|
glbs.DPrintf("Configurator::ParseData: Could not create key:\n");
|
|
goto __error;
|
|
}
|
|
v.m_bNeedWrite = false;
|
|
v.value = val;
|
|
k->value.AddObjectAt(index + 1, v);
|
|
break;
|
|
|
|
case LINE_ERROR:
|
|
glbs.DPrintf("Configurator::ParseData: syntax error:\n");
|
|
|
|
__error:
|
|
glbs.DPrintf("(%s, %d):", m_filename.c_str(), lineno);
|
|
glbs.DPrintf("%s\n", line);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int Configurator::ParseLine(char *line, char *section, char *key, char *value)
|
|
{
|
|
size_t len;
|
|
int result;
|
|
|
|
len = strlen(line);
|
|
|
|
if (len < 1) {
|
|
result = LINE_EMPTY;
|
|
} else if (line[0] == ';') {
|
|
result = LINE_COMMENT;
|
|
} else if (line[0] == '[' && line[len - 1] == ']') {
|
|
sscanf(line, "[%[^]]", section);
|
|
strcpy(section, strstrip(section));
|
|
strlwc(section);
|
|
|
|
result = LINE_SECTION;
|
|
} else if ((sscanf(line, "%[^=] = \"%[^\"]\"", key, value)) == 2
|
|
|| (sscanf(line, "%[^=] = %[^;]", key, value)) == 2) {
|
|
strcpy(key, strstrip(key));
|
|
strlwc(key);
|
|
strcpy(value, strstrip(value));
|
|
|
|
// sscanf cannot handle empty "" values
|
|
if (!strcmp(value, "\"\"")) {
|
|
value = "";
|
|
}
|
|
|
|
result = LINE_VALUE;
|
|
} else if ((sscanf(line, "%[^=] = %[;]", key, value)) == 2 || (sscanf(line, "%[^=] %[=]", key, value)) == 2) {
|
|
strcpy(key, strstrip(key));
|
|
strlwc(key);
|
|
value[0] = 0;
|
|
|
|
result = LINE_VALUE;
|
|
} else {
|
|
result = LINE_ERROR;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
str Configurator::GetValue(const char *section, const char *key, str defaultValue, int index)
|
|
{
|
|
configKey_t *k = GetKey(section, key, index);
|
|
configValue_t val;
|
|
|
|
if (!k) {
|
|
return defaultValue;
|
|
}
|
|
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
|
|
if (k->m_bNeedWrite) {
|
|
val.m_bNeedWrite = true;
|
|
val.value = defaultValue;
|
|
k->value.AddObjectAt(index + 1, val);
|
|
}
|
|
|
|
return k->value[index].value;
|
|
}
|
|
|
|
configKey_t *Configurator::GetKey(const char *section, const char *key, int index)
|
|
{
|
|
configSection_t *s;
|
|
configKey_t *k;
|
|
|
|
bool bArray = index >= 0;
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
|
|
s = FindSection(section);
|
|
if (!s) {
|
|
if (m_bNoWrite) {
|
|
return NULL;
|
|
}
|
|
|
|
s = CreateSection(section);
|
|
s->m_bNeedWrite = true;
|
|
m_bNeedWrite = true;
|
|
}
|
|
|
|
k = FindKey(s, key);
|
|
if (!k) {
|
|
if (m_bNoWrite) {
|
|
return NULL;
|
|
}
|
|
|
|
str keyname;
|
|
if (bArray) {
|
|
keyname = str(key) + "[" + str(index) + "]";
|
|
} else {
|
|
keyname = key;
|
|
}
|
|
k = CreateKey(s, keyname, NULL);
|
|
k->m_bNeedWrite = true;
|
|
m_bNeedWrite = true;
|
|
} else if (index >= k->value.NumObjects()) {
|
|
k->m_bNeedWrite = true;
|
|
m_bNeedWrite = true;
|
|
}
|
|
|
|
return k;
|
|
}
|
|
|
|
//======================================
|
|
// Configurator::GetString
|
|
//======================================
|
|
str Configurator::GetString(const char *section, const char *key, str defaultValue, int index)
|
|
{
|
|
str value = GetValue(section, key, defaultValue, index);
|
|
return value;
|
|
}
|
|
|
|
//======================================
|
|
// Configurator::GetInteger
|
|
//======================================
|
|
int Configurator::GetInteger(const char *section, const char *key, int defaultValue, int index)
|
|
{
|
|
str value = GetValue(section, key, defaultValue, index);
|
|
return atoi(value.c_str());
|
|
}
|
|
|
|
//======================================
|
|
// Configurator::GetFloat
|
|
//======================================
|
|
float Configurator::GetFloat(const char *section, const char *key, float defaultValue, int index)
|
|
{
|
|
str value = GetValue(section, key, defaultValue, index);
|
|
return atof(value.c_str());
|
|
}
|
|
|
|
//======================================
|
|
// Configurator::SetString
|
|
//======================================
|
|
void Configurator::SetString(const char *section, const char *key, str value, int index)
|
|
{
|
|
configKey_t *k = GetKey(section, key, index);
|
|
configValue_t v;
|
|
|
|
if (!k) {
|
|
return;
|
|
}
|
|
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
|
|
if (index >= k->value.NumObjects() || k->value[index].value != value) {
|
|
m_bNeedWrite = true;
|
|
v.m_bNeedWrite = true;
|
|
v.value = value;
|
|
k->m_bNeedWrite = true;
|
|
k->value.AddObjectAt(index + 1, v);
|
|
}
|
|
}
|
|
|
|
//======================================
|
|
// Configurator::SetInteger
|
|
//======================================
|
|
void Configurator::SetInteger(const char *section, const char *key, int value, int index)
|
|
{
|
|
return SetString(section, key, value, index);
|
|
}
|
|
|
|
//======================================
|
|
// Configurator::SetFloat
|
|
//======================================
|
|
void Configurator::SetFloat(const char *section, const char *key, float value, int index)
|
|
{
|
|
return SetString(section, key, value, index);
|
|
}
|
|
|
|
//======================================
|
|
// Configurator::SetWrite
|
|
//======================================
|
|
void Configurator::SetWrite(bool bWrite)
|
|
{
|
|
m_bNoWrite = !bWrite;
|
|
}
|
|
|
|
//======================================
|
|
// Configurator::Parse
|
|
//======================================
|
|
void Configurator::Parse(const char *filename)
|
|
{
|
|
FILE *file;
|
|
size_t size;
|
|
char *buffer;
|
|
|
|
m_bNoWrite = false;
|
|
m_bNeedWrite = false;
|
|
|
|
this->m_filename = filename;
|
|
|
|
file = fopen(filename, "r");
|
|
if (!file) {
|
|
return;
|
|
}
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
size = ftell(file);
|
|
rewind(file);
|
|
|
|
buffer = new char[size + 1];
|
|
size = fread(buffer, 1, size, file);
|
|
buffer[size] = 0;
|
|
|
|
fclose(file);
|
|
|
|
ParseData(buffer, size);
|
|
}
|
|
|
|
//======================================
|
|
// Configurator::Close
|
|
//======================================
|
|
void Configurator::Close(void)
|
|
{
|
|
FILE *file;
|
|
char *buffer;
|
|
int i;
|
|
size_t size;
|
|
|
|
if (!m_filename.length() || !m_bNeedWrite) {
|
|
goto _cleanup;
|
|
}
|
|
|
|
file = fopen(m_filename.c_str(), "r+");
|
|
if (!file) {
|
|
file = fopen(m_filename.c_str(), "w+");
|
|
if (!file) {
|
|
return;
|
|
}
|
|
file = freopen(m_filename.c_str(), "r+", file);
|
|
if (!file) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
size = ftell(file);
|
|
rewind(file);
|
|
|
|
buffer = new char[size + 1];
|
|
size = fread(buffer, 1, size, file);
|
|
buffer[size] = 0;
|
|
|
|
glbs.DPrintf("Configurator::Close: Writing data to %s...\n", m_filename.c_str());
|
|
WriteData(&buffer, &size);
|
|
glbs.DPrintf("Configurator::Close: Done.\n");
|
|
file = freopen(m_filename.c_str(), "w+", file);
|
|
fwrite(buffer, size, 1, file);
|
|
fclose(file);
|
|
|
|
m_filename = "";
|
|
|
|
delete[] buffer;
|
|
|
|
_cleanup:
|
|
for (i = m_reverseSections.NumObjects(); i > 0; i--) {
|
|
RemoveSection(m_reverseSections.ObjectAt(i));
|
|
}
|
|
}
|
|
|
|
void test_config(void)
|
|
{
|
|
Configurator config("test.ini");
|
|
str value;
|
|
|
|
value = config.GetString("section1", "testvar1", "100");
|
|
glbs.DPrintf("value = %s\n", value.c_str());
|
|
value = config.GetString("section1", "testarray1", "100", 0);
|
|
glbs.DPrintf("array1 = %s\n", value.c_str());
|
|
value = config.GetString("section1", "testarray1", "100", 1);
|
|
glbs.DPrintf("array2 = %s\n", value.c_str());
|
|
value = config.GetString("section1", "testarray1", "100", 2);
|
|
glbs.DPrintf("array3 = %s\n", value.c_str());
|
|
|
|
value = config.GetString("section1", "testforcewrite", "500");
|
|
glbs.DPrintf("testforcewrite = %s\n", value.c_str());
|
|
|
|
value = config.GetString("section2", "testforcewrite2", "500");
|
|
glbs.DPrintf("testforcewrite2 = %s\n", value.c_str());
|
|
|
|
//for( int i = 0; i < 2048; i++ )
|
|
//{
|
|
// value = config.GetString( "section1", "testforcewrite5", "2048", i );
|
|
//}
|
|
|
|
config.SetString("section1", "testforcewrite5", "newstring", 2048);
|
|
|
|
config.Close();
|
|
}
|