raze/source/blood/src/inifile.cpp
Christoph Oelckers 8114309e89 - compat.h cleanup.
* use static_assert directly. Raze is C++17, no need for that macro shit.
* removed CONSTEXPR - I seriously fail to see the use here, many of the functions marked as CONSTEXPR cannot possibly even be constant evaluated so the declaration makes no sense. Removed most of these and replaced the valid ones with the official constexpr keyword.
* got rid of EDUKE_PREDICT_FALSE - this makes zero sense in script parsing code, at best it will save a few microseconds. Clean code wins.
* replaced Blrintf with xs_CRoundToInt. Shitty name is shitty name, even if derived from POSIX.
* replaced Bstr*casecmp with str*icmp. As these get defined in the CMake project based on actual compiler checks they are preferable here.
* removed lots of other stuff that is not needed with a minimum compiler requirement of C++17.
2020-09-04 21:24:48 +02:00

443 lines
9.5 KiB
C++

//-------------------------------------------------------------------------
/*
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
#include "ns.h" // Must come before everything else!
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "common_game.h"
#include "inifile.h"
#include "misc.h"
BEGIN_BLD_NS
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;
}
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));
dassert(curNode->next != NULL);
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;
auto fp = fileSystem.OpenFileReader(fileName);
if (fp.isOpen())
{
int nSize = fp.GetLength();
auto pBuffer = fp.Read();
LoadRes(pBuffer.Data());
}
else
curNode->next = &head;
}
void IniFile::Save(void)
{
char buffer[256];
FILE *hFile = fopen(fileName, "w");
dassert(hFile != NULL);
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;
} while(stricmp(curNode->name, buffer) != 0);
}
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;
dassert(pEqual != NULL);
// 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));
dassert(newNode != NULL);
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));
dassert(newNode != NULL);
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));
dassert(newNode != NULL);
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));
dassert(newNode != NULL);
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);
}
}
END_BLD_NS