mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2026-03-29 08:19:38 -06:00
- Buildable on OSX and Linux now - Fixed filename casing mismatches - Inicrunch fixes, osx and linux versions, added Makefile Note: gnu's cpp doesn't understand the -Wno-invalid-pp-token flag, the absence of which causes ignorable preprocessing warnings on strings with unmatched quotes.
260 lines
5.2 KiB
C++
260 lines
5.2 KiB
C++
#include <stdlib.h>
|
|
#include <memory.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "ini.h"
|
|
|
|
// IniScanf / VIniScanf
|
|
//
|
|
// Supports:
|
|
// %s : "trimmed string", matches a string with interleaving spaces. Removes
|
|
// leading and trailing white space, with ini-friendly delimiters
|
|
// %s+: means %s plus store index of matching string
|
|
// %+ : means store current buffer index
|
|
// '*' after % is supported and means match but don't store
|
|
// ' ', '\t', '\n' : match for optional white space (space, tab, newline)
|
|
|
|
#define IsWhiteSpace(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
|
|
#ifdef IsDigit
|
|
#undef IsDigit
|
|
#endif
|
|
#define IsDigit(ch) ((ch) >= '0' && (ch) <= '9')
|
|
|
|
int IniScanf(char *pszBuff, char *pszFmt, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, pszFmt);
|
|
int c = VIniScanf(pszBuff, pszFmt, va);
|
|
va_end(va);
|
|
return c;
|
|
}
|
|
|
|
int VIniScanf(char *pszBuff, char *pszFmt, va_list va)
|
|
{
|
|
char *pszBuffT = pszBuff;
|
|
char *pszFmtT = pszFmt;
|
|
int cArgs = 0;
|
|
while (*pszFmtT != 0) {
|
|
// Make this special check before checking for end
|
|
// of buffer
|
|
|
|
if (pszFmtT[0] == '%' && pszFmtT[1] == '+') {
|
|
pszFmtT += 2;
|
|
*va_arg(va, int *) = pszBuffT - pszBuff;
|
|
cArgs++;
|
|
continue;
|
|
}
|
|
|
|
switch (*pszFmtT) {
|
|
case ' ':
|
|
case '\n':
|
|
case '\t':
|
|
// Eat white space (space, tab, newline)
|
|
|
|
while (IsWhiteSpace(*pszBuffT))
|
|
pszBuffT++;
|
|
pszFmtT++;
|
|
continue;
|
|
}
|
|
|
|
// End of buffer? Bail.
|
|
|
|
if (*pszBuffT == 0)
|
|
break;
|
|
|
|
bool fSuppress;
|
|
switch (*pszFmtT) {
|
|
case '%':
|
|
// Suppress?
|
|
|
|
pszFmtT++;
|
|
fSuppress = false;
|
|
if (*pszFmtT == '*') {
|
|
fSuppress = true;
|
|
pszFmtT++;
|
|
}
|
|
|
|
// Format specification
|
|
|
|
switch (*pszFmtT) {
|
|
case 's':
|
|
// Trimmed string.
|
|
{
|
|
pszFmtT++;
|
|
|
|
// If %s+, it means save the location of substring
|
|
|
|
bool fSaveLocation = false;
|
|
if (*pszFmtT == '+') {
|
|
fSaveLocation = true;
|
|
pszFmtT++;
|
|
}
|
|
|
|
// Go past initial whitespace
|
|
|
|
int nchStart = pszBuffT - pszBuff;
|
|
while (IsWhiteSpace(*pszBuffT)) {
|
|
nchStart++;
|
|
pszBuffT++;
|
|
}
|
|
|
|
// Copy the string into pszT. Figure out when to stop
|
|
// and remember trimming information.
|
|
|
|
char chStop = *pszFmtT;
|
|
char *pszT = va_arg(va, char *);
|
|
char *pszWhiteLast = NULL;
|
|
while (*pszBuffT != chStop) {
|
|
if (*pszBuffT == 0)
|
|
break;
|
|
if (!IsWhiteSpace(*pszBuffT)) {
|
|
pszWhiteLast = NULL;
|
|
} else if (pszWhiteLast == NULL) {
|
|
pszWhiteLast = pszT;
|
|
}
|
|
if (!fSuppress)
|
|
*pszT++ = *pszBuffT++;
|
|
}
|
|
if (!fSuppress) {
|
|
*pszT = 0;
|
|
if (pszWhiteLast != NULL)
|
|
*pszWhiteLast = 0;
|
|
cArgs++;
|
|
}
|
|
|
|
// %s+ means save location string started
|
|
|
|
if (!fSuppress && fSaveLocation) {
|
|
*va_arg(va, int *) = nchStart;
|
|
cArgs++;
|
|
}
|
|
}
|
|
continue;
|
|
|
|
default:
|
|
// Non-recognized % command
|
|
|
|
return cArgs;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// Match character
|
|
|
|
if (*pszBuffT == *pszFmtT) {
|
|
pszBuffT++;
|
|
pszFmtT++;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// If we're here it means stop
|
|
|
|
break;
|
|
}
|
|
|
|
return cArgs;
|
|
}
|
|
|
|
bool NewSection(char *pszSec, dword nch, IniSection **ppsec, int *pcsec)
|
|
{
|
|
IniSection *psec = new IniSection[(*pcsec) + 1];
|
|
if (psec == NULL)
|
|
return false;
|
|
if (*ppsec != NULL) {
|
|
memcpy(psec, *ppsec, sizeof(IniSection) * (*pcsec));
|
|
delete *ppsec;
|
|
}
|
|
*ppsec = psec;
|
|
psec = &(*ppsec)[*pcsec];
|
|
(*pcsec)++;
|
|
|
|
psec->nchSec = nch;
|
|
psec->cchSec = strlen(pszSec);
|
|
psec->cprop = 0;
|
|
psec->pprop = NULL;
|
|
return true;
|
|
}
|
|
|
|
bool NewProperty(IniSection *psec, char *pszProp, dword nchProp, char *pszValue, dword nchValue)
|
|
{
|
|
IniProperty *pprop = new IniProperty[psec->cprop + 1];
|
|
if (pprop == NULL)
|
|
return false;
|
|
if (psec->pprop != NULL) {
|
|
memcpy(pprop, psec->pprop, sizeof(IniProperty) * psec->cprop);
|
|
delete psec->pprop;
|
|
}
|
|
psec->pprop = pprop;
|
|
pprop = &psec->pprop[psec->cprop];
|
|
psec->cprop++;
|
|
|
|
pprop->nchProp = nchProp;
|
|
pprop->cchProp = strlen(pszProp);
|
|
pprop->nchValue = nchValue;
|
|
pprop->cchValue = strlen(pszValue);
|
|
return true;
|
|
}
|
|
|
|
IniSection *LoadIniFile(char *pszFn, int *pcSections)
|
|
{
|
|
IniSection *psec = NULL;
|
|
int csec = 0;
|
|
|
|
FILE *pf = fopen(pszFn, "rb");
|
|
if (pf == NULL)
|
|
return NULL;
|
|
|
|
while (true) {
|
|
// Get the next line
|
|
|
|
dword nchLine = ftell(pf);
|
|
char szLine[50 * 1024];
|
|
if (fgets(szLine, sizeof(szLine) - 1, pf) == NULL)
|
|
break;
|
|
|
|
// Is it a section header? If so, add it
|
|
|
|
char szT[1024];
|
|
int nchSec;
|
|
if (IniScanf(szLine, "\t[%s+]\t", szT, &nchSec) == 2) {
|
|
if (!NewSection(szT, nchLine + nchSec, &psec, &csec))
|
|
return NULL;
|
|
continue;
|
|
}
|
|
|
|
// Is it just whitespace? Allow leading ; for comments
|
|
|
|
bool fAllWhiteSpace = true;
|
|
int cch = strlen(szLine);
|
|
for (int n = 0; n < cch; n++) {
|
|
if (!IsWhiteSpace(szLine[n])) {
|
|
if (szLine[n] == ';')
|
|
break;
|
|
fAllWhiteSpace = false;
|
|
break;
|
|
}
|
|
}
|
|
if (fAllWhiteSpace)
|
|
continue;
|
|
|
|
// See if it is property = value
|
|
|
|
int nchProp;
|
|
int nchValue;
|
|
char szValue[50 * 1024];
|
|
if (IniScanf(szLine, "%s+=%s+", szT, &nchProp, szValue, &nchValue) == 4) {
|
|
if (!NewProperty(&psec[csec - 1], szT, nchLine + nchProp, szValue, nchLine + nchValue))
|
|
return NULL;
|
|
continue;
|
|
}
|
|
|
|
// Otherwise ignore it
|
|
}
|
|
|
|
*pcSections = csec;
|
|
return psec;
|
|
}
|
|
|