2019-09-19 22:42:45 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
Copyright (C) 2019 sirlemonhead, Nuke.YKT
|
|
|
|
|
|
|
|
This file is part of NBlood.
|
|
|
|
|
|
|
|
NBlood is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Note: This module is based on the sirlemonhead's work
|
|
|
|
|
2019-09-21 18:59:54 +00:00
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
2020-12-09 14:56:32 +00:00
|
|
|
#include "blood.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
#include "inifile.h"
|
|
|
|
|
2019-09-22 06:39:22 +00:00
|
|
|
BEGIN_BLD_NS
|
|
|
|
|
2020-09-01 17:49:05 +00:00
|
|
|
static void *ResReadLine(char *buffer, unsigned int nBytes, void **pRes)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
char ch;
|
|
|
|
if (!pRes || !*pRes || *((char*)*pRes) == 0)
|
|
|
|
return NULL;
|
|
|
|
for (i = 0; i < nBytes; i++)
|
|
|
|
{
|
|
|
|
ch = *((char*)*pRes);
|
|
|
|
if(ch == 0 || ch == '\n')
|
|
|
|
break;
|
|
|
|
buffer[i] = ch;
|
|
|
|
*pRes = ((char*)*pRes)+1;
|
|
|
|
}
|
|
|
|
if (*((char*)*pRes) == '\n' && i < nBytes)
|
|
|
|
{
|
|
|
|
ch = *((char*)*pRes);
|
|
|
|
buffer[i] = ch;
|
|
|
|
*pRes = ((char*)*pRes)+1;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
ch = *((char*)*pRes);
|
|
|
|
if (ch == 0 || ch == '\n')
|
|
|
|
break;
|
|
|
|
*pRes = ((char*)*pRes)+1;
|
|
|
|
}
|
|
|
|
if (*((char*)*pRes) == '\n')
|
|
|
|
*pRes = ((char*)*pRes)+1;
|
|
|
|
}
|
|
|
|
if (i < nBytes)
|
|
|
|
buffer[i] = 0;
|
|
|
|
return *pRes;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
IniFile::IniFile(const char *fileName)
|
|
|
|
{
|
|
|
|
head.next = &head;
|
|
|
|
|
|
|
|
// debug stuff
|
|
|
|
// curNode = NULL;
|
|
|
|
// anotherNode = NULL;
|
|
|
|
//_13 = NULL;
|
|
|
|
|
|
|
|
strcpy(this->fileName, fileName);
|
|
|
|
Load();
|
|
|
|
}
|
|
|
|
|
|
|
|
IniFile::IniFile(void *res)
|
|
|
|
{
|
|
|
|
head.next = &head;
|
|
|
|
strcpy(fileName, "menus.mat");
|
|
|
|
LoadRes(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::LoadRes(void *res)
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
|
|
|
|
curNode = &head;
|
|
|
|
|
|
|
|
while (ResReadLine(buffer, sizeof(buffer), &res) != 0)
|
|
|
|
{
|
|
|
|
char *ch = strchr(buffer, '\n');
|
|
|
|
if (ch != NULL) {
|
|
|
|
ch[0] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
// do the same for carriage return?
|
|
|
|
ch = strchr(buffer, '\r');
|
|
|
|
if (ch != NULL) {
|
|
|
|
ch[0] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
char *pBuffer = buffer;
|
|
|
|
|
|
|
|
// remove whitespace from buffer
|
|
|
|
while (isspace(*pBuffer)) {
|
|
|
|
pBuffer++;
|
|
|
|
}
|
|
|
|
|
|
|
|
curNode->next = (FNODE*)malloc(strlen(pBuffer) + sizeof(FNODE));
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(curNode->next != NULL);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
anotherNode = curNode;
|
|
|
|
curNode = curNode->next;
|
|
|
|
|
|
|
|
|
|
|
|
strcpy(curNode->name, pBuffer);
|
|
|
|
|
|
|
|
/*
|
|
|
|
check for:
|
|
|
|
; - comment line. continue and grab a new line (59)
|
|
|
|
[ - start of section marker (91)
|
|
|
|
] - end of section marker (93)
|
|
|
|
= - key and value seperator (61)
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (*pBuffer)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case ';': // comment line
|
|
|
|
break;
|
|
|
|
case '[':
|
|
|
|
if (!strchr(pBuffer, ']'))
|
|
|
|
{
|
|
|
|
free(curNode);
|
|
|
|
curNode = anotherNode;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
|
|
|
|
if (strchr(pBuffer, '=') <= pBuffer) {
|
|
|
|
free(curNode);
|
|
|
|
curNode = anotherNode;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
curNode->next = &head;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::Load()
|
|
|
|
{
|
|
|
|
// char buffer[256];
|
|
|
|
|
|
|
|
curNode = &head;
|
|
|
|
|
2020-04-11 21:54:33 +00:00
|
|
|
auto fp = fileSystem.OpenFileReader(fileName);
|
2019-10-21 15:16:08 +00:00
|
|
|
if (fp.isOpen())
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-10-21 15:16:08 +00:00
|
|
|
auto pBuffer = fp.Read();
|
|
|
|
LoadRes(pBuffer.Data());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
curNode->next = &head;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::Save(void)
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
FILE *hFile = fopen(fileName, "w");
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(hFile != NULL);
|
2019-09-19 22:42:45 +00:00
|
|
|
curNode = head.next;
|
|
|
|
while (curNode != &head)
|
|
|
|
{
|
|
|
|
sprintf(buffer, "%s\n", curNode->name);
|
|
|
|
fwrite(buffer, 1, strlen(buffer), hFile);
|
|
|
|
curNode = curNode->next;
|
|
|
|
}
|
|
|
|
fclose(hFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IniFile::FindSection(const char *section)
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
curNode = anotherNode = &head;
|
|
|
|
if (section)
|
|
|
|
{
|
|
|
|
sprintf(buffer, "[%s]", section);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
anotherNode = curNode;
|
|
|
|
curNode = curNode->next;
|
|
|
|
if (curNode == &head)
|
|
|
|
return false;
|
2020-09-04 19:24:48 +00:00
|
|
|
} while(stricmp(curNode->name, buffer) != 0);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IniFile::SectionExists(const char *section)
|
|
|
|
{
|
|
|
|
return FindSection(section);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IniFile::FindKey(const char *key)
|
|
|
|
{
|
|
|
|
anotherNode = curNode;
|
|
|
|
curNode = curNode->next;
|
|
|
|
while (curNode != &head)
|
|
|
|
{
|
|
|
|
char c = curNode->name[0];
|
|
|
|
|
|
|
|
if (c == ';' || c == '\0') {
|
|
|
|
anotherNode = curNode;
|
|
|
|
curNode = curNode->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '[') {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *pEqual = strchr(curNode->name, '=');
|
|
|
|
char *pEqualStart = pEqual;
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(pEqual != NULL);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
// remove whitespace
|
|
|
|
while (isspace(*(pEqual - 1))) {
|
|
|
|
pEqual--;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = *pEqual;
|
|
|
|
*pEqual = '\0';
|
|
|
|
|
|
|
|
if (strcmp(key, curNode->name) == 0)
|
|
|
|
{
|
|
|
|
// strings match
|
|
|
|
*pEqual = c;
|
|
|
|
_13 = ++pEqualStart;
|
|
|
|
while (isspace(*_13)) {
|
|
|
|
_13++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
*pEqual = c;
|
|
|
|
anotherNode = curNode;
|
|
|
|
curNode = curNode->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::AddSection(const char *section)
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
|
|
|
|
if (anotherNode != &head)
|
|
|
|
{
|
|
|
|
FNODE *newNode = (FNODE*)malloc(sizeof(FNODE));
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(newNode != NULL);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
newNode->name[0] = 0;
|
|
|
|
newNode->next = anotherNode->next;
|
|
|
|
anotherNode->next = newNode;
|
|
|
|
anotherNode = newNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(buffer, "[%s]", section);
|
|
|
|
FNODE *newNode = (FNODE*)malloc(strlen(buffer) + sizeof(FNODE));
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(newNode != NULL);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
strcpy(newNode->name, buffer);
|
|
|
|
|
|
|
|
newNode->next = anotherNode->next;
|
|
|
|
anotherNode->next = newNode;
|
|
|
|
anotherNode = newNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::AddKeyString(const char *key, const char *value)
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
|
|
|
|
sprintf(buffer, "%s=%s", key, value);
|
|
|
|
|
|
|
|
FNODE *newNode = (FNODE*)malloc(strlen(buffer) + sizeof(FNODE));
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(newNode != NULL);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
strcpy(newNode->name, buffer);
|
|
|
|
|
|
|
|
newNode->next = anotherNode->next;
|
|
|
|
anotherNode->next = newNode;
|
|
|
|
curNode = newNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::ChangeKeyString(const char *key, const char *value)
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
|
|
|
|
sprintf(buffer, "%s=%s", key, value);
|
|
|
|
|
|
|
|
FNODE *newNode = (FNODE*)realloc(curNode, strlen(buffer) + sizeof(FNODE));
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(newNode != NULL);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
strcpy(newNode->name, buffer);
|
|
|
|
|
|
|
|
anotherNode->next = newNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IniFile::KeyExists(const char *section, const char *key)
|
|
|
|
{
|
|
|
|
if (FindSection(section) && FindKey(key))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::PutKeyString(const char *section, const char *key, const char *value)
|
|
|
|
{
|
|
|
|
if (FindSection(section))
|
|
|
|
{
|
|
|
|
if (FindKey(key))
|
|
|
|
{
|
|
|
|
ChangeKeyString(key, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
AddSection(section);
|
|
|
|
}
|
|
|
|
|
|
|
|
AddKeyString(key, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* IniFile::GetKeyString(const char *section, const char *key, const char *defaultValue)
|
|
|
|
{
|
|
|
|
if (FindSection(section) && FindKey(key))
|
|
|
|
return _13;
|
|
|
|
return defaultValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::PutKeyInt(const char *section, const char *key, int value)
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
|
|
|
|
// convert int to string
|
|
|
|
sprintf(buffer,"%d",value);
|
|
|
|
|
|
|
|
PutKeyString(section, key, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
int IniFile::GetKeyInt(const char *section, const char *key, int defaultValue)
|
|
|
|
{
|
|
|
|
if (FindSection(section) && FindKey(key))
|
|
|
|
{
|
|
|
|
// convert string to int int
|
|
|
|
return strtol(_13, NULL, 0);
|
|
|
|
}
|
|
|
|
return defaultValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::PutKeyHex(const char *section, const char *key, int value)
|
|
|
|
{
|
|
|
|
char buffer[256] = "0x";
|
|
|
|
|
|
|
|
// convert int to string
|
|
|
|
sprintf(buffer,"%x",value);
|
|
|
|
|
|
|
|
PutKeyString(section, key, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
int IniFile::GetKeyHex(const char *section, const char *key, int defaultValue)
|
|
|
|
{
|
|
|
|
return GetKeyInt(section, key, defaultValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IniFile::GetKeyBool(const char *section, const char *key, int defaultValue)
|
|
|
|
{
|
|
|
|
return (bool)GetKeyInt(section, key, defaultValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::RemoveKey(const char *section, const char *key)
|
|
|
|
{
|
|
|
|
if (FindSection(section) && FindKey(key))
|
|
|
|
{
|
|
|
|
anotherNode->next = curNode->next;
|
|
|
|
free(curNode);
|
|
|
|
curNode = anotherNode->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniFile::RemoveSection(const char *section)
|
|
|
|
{
|
|
|
|
if (FindSection(section))
|
|
|
|
{
|
|
|
|
anotherNode = curNode;
|
|
|
|
|
|
|
|
curNode = curNode->next;
|
|
|
|
|
|
|
|
while (curNode != &head)
|
|
|
|
{
|
|
|
|
if (curNode->name[0] == '[') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
anotherNode->next = curNode->next;
|
|
|
|
free(curNode);
|
|
|
|
curNode = anotherNode->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IniFile::~IniFile()
|
|
|
|
{
|
|
|
|
curNode = head.next;
|
|
|
|
|
|
|
|
while (curNode != &head)
|
|
|
|
{
|
|
|
|
anotherNode = curNode;
|
|
|
|
curNode = curNode->next;
|
|
|
|
free(anotherNode);
|
|
|
|
}
|
|
|
|
}
|
2019-09-22 06:39:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
END_BLD_NS
|