You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
847 lines
22 KiB
847 lines
22 KiB
#include "configmodel.h"
|
|
#include "sectionstore.h"
|
|
|
|
#include "cregex/cregex.h"
|
|
#include "containers/stringarray.h"
|
|
#include "containers/linearray.h"
|
|
#include "containers/sectionarray.h"
|
|
|
|
#include <proto/exec.h>
|
|
#include <proto/dos.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
STATIC VOID downcaseString(STRPTR string);
|
|
|
|
#define ZERO ((BPTR)0)
|
|
|
|
// - STRUCTS -----------------------------------------------------------------------------
|
|
struct ConfigFile
|
|
{
|
|
CONST_STRPTR filename;
|
|
SECTIONSTOREPTR sectionStore;
|
|
};
|
|
|
|
struct Section
|
|
{
|
|
CONST_STRPTR primary;
|
|
CONST_STRPTR secondary;
|
|
LineArray lines;
|
|
BOOL lastLineWasEmpty;
|
|
};
|
|
|
|
enum VariableType
|
|
{
|
|
TypeBool=0,
|
|
TypeInteger=1,
|
|
TypeString=2,
|
|
};
|
|
|
|
struct Variable
|
|
{
|
|
enum VariableType type;
|
|
CONST_STRPTR key;
|
|
CONST_STRPTR normalizedKey;
|
|
struct
|
|
{
|
|
CONST_STRPTR stringValue;
|
|
BOOL boolValue;
|
|
LONG longValue;
|
|
} value;
|
|
};
|
|
|
|
struct Line
|
|
{
|
|
STRPTR rawText;
|
|
struct Variable* variable;
|
|
struct Section* section;
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// - CONFIG FILE -------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------------------
|
|
|
|
VOID ConfigFileFree(CONFIGFILEPTR abstractConfigFile)
|
|
{
|
|
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
|
|
if( configFile != NULL )
|
|
{
|
|
if( configFile->sectionStore != NULL )
|
|
{
|
|
SectionStoreFree(configFile->sectionStore);
|
|
}
|
|
FreeVec(configFile);
|
|
}
|
|
}
|
|
|
|
STATIC LINEPTR configFileReadLine(BPTR file);
|
|
|
|
CONFIGFILEPTR ConfigFileRead(CONST_STRPTR filename)
|
|
{
|
|
struct ConfigFile* result = NULL;
|
|
BPTR configFile = Open(filename, MODE_OLDFILE);
|
|
if( configFile != ZERO )
|
|
{
|
|
|
|
LINEPTR line = NULL;
|
|
result = AllocVec(sizeof(struct ConfigFile), MEMF_CLEAR);
|
|
result->sectionStore = SectionStoreNew();
|
|
while( (line = configFileReadLine(configFile)) != NULL )
|
|
{
|
|
SectionStoreAddLineToCurrentSection(result->sectionStore, line);
|
|
//LineDump(line);
|
|
}
|
|
Close(configFile);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// a key is "foo.bar.baz.blah" where "foo" is the primary section name
|
|
// "bar.baz" is the secondary section name and "blah" is the variable name.
|
|
// this splits foo.bar.baz.blah into foo, bar.baz amd blah.
|
|
// section, subsection and variable.
|
|
// we'll get empty strings for the parts that arent present
|
|
StringArray ConfigFileSplitKeyCompletely(CONST_STRPTR key)
|
|
{
|
|
StringArray result = StringArrayNew();
|
|
StringArray parts = StringArrayNew();
|
|
ULONG numberOfParts = 0;
|
|
|
|
STRPTR token = NULL;
|
|
// we need to make a copy of the key because strtok modifies it.
|
|
STRPTR keyCopy = AllocVec(strlen(key)+1, MEMF_CLEAR);
|
|
CopyMem(key, keyCopy, strlen(key));
|
|
|
|
token = strtok(keyCopy, ".");
|
|
while (token != NULL)
|
|
{
|
|
StringArrayAppendAndRetain(parts, token);
|
|
token = strtok(NULL, ".");
|
|
}
|
|
FreeVec(keyCopy);
|
|
|
|
// now we join all but the first and last part
|
|
numberOfParts = SizeOfArray(parts);
|
|
if( numberOfParts == 1 ) //just a variable ["","","var"]
|
|
{
|
|
StringArrayAppendAndRetain(result, "");
|
|
StringArrayAppendAndRetain(result, "");
|
|
StringArrayAppendAndRetain(result, (STRPTR)ArrayBackValue(STRPTR, parts));
|
|
}
|
|
else if( numberOfParts == 2 ) // section and variable ["section","","var"]
|
|
{
|
|
StringArrayAppendAndRetain(result, StringArrayValues(parts)[0]);
|
|
StringArrayAppendAndRetain(result, "");
|
|
StringArrayAppendAndRetain(result, StringArrayValues(parts)[1]);
|
|
}
|
|
else if( numberOfParts == 3 ) // section and subsection and variable ["section","subsec","var"]
|
|
{
|
|
StringArrayAppendAndRetain(result, StringArrayValues(parts)[0]);
|
|
StringArrayAppendAndRetain(result, StringArrayValues(parts)[1]);
|
|
StringArrayAppendAndRetain(result, StringArrayValues(parts)[2]);
|
|
}
|
|
else if( numberOfParts > 3 ) // subsections needs dotted ["section", "subsec1.subsec2", "var""]
|
|
{
|
|
StringArrayAppendAndRetain(result, StringArrayValues(parts)[0]); //section
|
|
|
|
// start at index 1, and add (size -2 (start+end)) parts
|
|
StringArrayAppend(result, StringArrayJoinedParts(parts, '.', 1, SizeOfArray(parts)-2));
|
|
|
|
StringArrayAppendAndRetain(result, (STRPTR)ArrayBackValue(STRPTR, parts)); // variable
|
|
}
|
|
StringArrayFree(parts, TRUE);
|
|
return result;
|
|
}
|
|
|
|
StringArray ConfigFileSplitKeyForVar(CONST_STRPTR key)
|
|
{
|
|
// a key is "foo.bar.baz.blah" where "foo" is the primary section name
|
|
// "bar.baz" is the secondary section name and "blah" is the variable name.
|
|
// In this case we'll just break it down into the canonical section name,
|
|
// foo.bar.baz and the variable name blah.
|
|
|
|
StringArray result = StringArrayNew();
|
|
StringArray parts = StringArrayNew();
|
|
STRPTR sectionPart = NULL;
|
|
STRPTR varPart = NULL;
|
|
|
|
STRPTR token = NULL;
|
|
// we need to make a copy of the key because strtok modifies it.
|
|
STRPTR keyCopy = AllocVec(strlen(key)+1, MEMF_CLEAR);
|
|
CopyMem(key, keyCopy, strlen(key));
|
|
|
|
token = strtok(keyCopy, ".");
|
|
while (token != NULL)
|
|
{
|
|
StringArrayAppendAndRetain(parts, token);
|
|
token = strtok(NULL, ".");
|
|
}
|
|
FreeVec(keyCopy);
|
|
|
|
// now we join all but the last part
|
|
sectionPart = StringArrayJoinedParts(parts, '.', 0, SizeOfArray(parts)-1);
|
|
StringArrayAppend(result, sectionPart); // its been alloced so dont copy
|
|
varPart = (STRPTR)ArrayBackValue(STRPTR, parts);
|
|
StringArrayAppendAndRetain(result, varPart); // its a reference so copy
|
|
StringArrayFree(parts, TRUE);
|
|
return result;
|
|
}
|
|
|
|
STRPTR ConfigFileGet(CONFIGFILEPTR abstractConfigFile, CONST_STRPTR compoundKey)
|
|
{
|
|
STRPTR result = NULL;
|
|
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
|
|
if( configFile != NULL )
|
|
{
|
|
StringArray split = ConfigFileSplitKeyForVar(compoundKey);
|
|
VARIABLEPTR var = SectionStoreGet(configFile->sectionStore, StringArrayValues(split)[0], StringArrayValues(split)[1]);
|
|
if( var != NULL )
|
|
{
|
|
CONST_STRPTR value = VariableGetRawValue(var);
|
|
result = AllocVec(strlen(value)+1, MEMF_CLEAR);
|
|
CopyMem(value, result, strlen(value));
|
|
}
|
|
StringArrayFree(split, TRUE);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
StringArray ConfigFileGetAll(CONFIGFILEPTR abstractConfigFile, CONST_STRPTR compoundKey)
|
|
{
|
|
StringArray result = StringArrayNew();
|
|
ULONG index = 0;
|
|
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
|
|
if( configFile != NULL )
|
|
{
|
|
StringArray split = ConfigFileSplitKeyForVar(compoundKey);
|
|
VariableArray vars = SectionStoreGetAll(configFile->sectionStore, StringArrayValues(split)[0], StringArrayValues(split)[1]);
|
|
for( index = 0; index < SizeOfArray(vars); index++ )
|
|
{
|
|
StringArrayAppendAndRetain(result, VariableGetRawValue(VariableArrayValues(vars)[index]));
|
|
}
|
|
VariableArrayFree(vars, FALSE);
|
|
StringArrayFree(split, TRUE);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
VOID ConfigFileAdd(CONFIGFILEPTR abstractConfigFile, CONST_STRPTR compoundKey, CONST_STRPTR stringValue)
|
|
{
|
|
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
|
|
if( configFile != NULL )
|
|
{
|
|
SECTIONPTR section = NULL;
|
|
VARIABLEPTR var = NULL;
|
|
CONST_STRPTR varLine = NULL;
|
|
LINEPTR line = NULL;
|
|
StringArray canonicalParts = NULL;
|
|
|
|
// get canonical section name and var name
|
|
canonicalParts = ConfigFileSplitKeyForVar(compoundKey);
|
|
|
|
// build a var line
|
|
var = VariableCreate(StringArrayValues(canonicalParts)[1], stringValue);
|
|
varLine = VariableSerialize(var);
|
|
line = LineNew(varLine);
|
|
FreeVec((STRPTR)varLine);
|
|
LineSetInitialVariable(line, var);
|
|
|
|
// now get the section
|
|
section = SectionStoreGetSection(configFile->sectionStore, StringArrayValues(canonicalParts)[0]);
|
|
if( section == NULL )
|
|
{
|
|
StringArray separateParts = ConfigFileSplitKeyCompletely(compoundKey);
|
|
CONST_STRPTR sectionLineText = NULL;
|
|
LINEPTR sectionLine = NULL;
|
|
|
|
section = SectionCreateWithNameAndSubname(StringArrayValues(separateParts)[0], StringArrayValues(separateParts)[1]);
|
|
sectionLineText = SectionSerialize(section);
|
|
sectionLine = LineNew(sectionLineText);
|
|
SectionAddSectionLine(section, sectionLine);
|
|
FreeVec((STRPTR)sectionLineText);
|
|
SectionDump(section);
|
|
SectionStoreAddSection(configFile->sectionStore, section); //section store will free it for us
|
|
SectionDump(section);
|
|
StringArrayFree(separateParts, TRUE);
|
|
}
|
|
// add the line to the section
|
|
SectionAddLine(section, line);
|
|
SectionDump(section);
|
|
|
|
StringArrayFree(canonicalParts, TRUE);
|
|
}
|
|
}
|
|
|
|
VOID ConfigFileSet(CONFIGFILEPTR abstractConfigFile, CONST_STRPTR compoundKey, CONST_STRPTR stringValue)
|
|
{
|
|
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
|
|
if( configFile != NULL )
|
|
{
|
|
StringArray parts = ConfigFileSplitKeyCompletely(compoundKey);
|
|
|
|
StringArrayFree(parts, TRUE);
|
|
}
|
|
}
|
|
|
|
VOID ConfigFileReplaceAll(CONFIGFILEPTR abstractConfigFile, CONST_STRPTR compoundKey, CONST_STRPTR stringValue)
|
|
{
|
|
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
|
|
if( configFile != NULL )
|
|
{
|
|
StringArray parts = ConfigFileSplitKeyCompletely(compoundKey);
|
|
|
|
StringArrayFree(parts, TRUE);
|
|
}
|
|
}
|
|
|
|
VOID ConfigFileUnset(CONFIGFILEPTR abstractConfigFile, CONST_STRPTR compoundKey, CONST_STRPTR stringValue)
|
|
{
|
|
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
|
|
if( configFile != NULL )
|
|
{
|
|
StringArray parts = ConfigFileSplitKeyCompletely(compoundKey);
|
|
|
|
StringArrayFree(parts, TRUE);
|
|
}
|
|
}
|
|
|
|
VOID ConfigFileUnsetAll(CONFIGFILEPTR abstractConfigFile, CONST_STRPTR compoundKey, CONST_STRPTR stringValue)
|
|
{
|
|
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
|
|
if( configFile != NULL )
|
|
{
|
|
StringArray parts = ConfigFileSplitKeyCompletely(compoundKey);
|
|
|
|
StringArrayFree(parts, TRUE);
|
|
}
|
|
}
|
|
|
|
VOID ConfigFileDump(CONFIGFILEPTR abstractConfigFile)
|
|
{
|
|
ULONG index = 0;
|
|
ULONG count = 0;
|
|
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
|
|
if( configFile != NULL )
|
|
{
|
|
count = SectionStoreSectionCount(configFile->sectionStore);
|
|
for( index = 0; index < count; index++ )
|
|
{
|
|
SECTIONPTR section = SectionStoreSectionAt(configFile->sectionStore, index);
|
|
SectionDump(section);
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC LINEPTR configFileReadLine(BPTR file)
|
|
{
|
|
UBYTE* buffer = AllocVec(512, MEMF_CLEAR);
|
|
ULONG bufLength = 512;
|
|
ULONG bytesReadTotal = 0;
|
|
UBYTE* read = NULL;
|
|
struct Line* result = NULL;
|
|
|
|
// read the whole line including continuation
|
|
do
|
|
{
|
|
read = FGets(file, &(buffer[bytesReadTotal]), bufLength-bytesReadTotal);
|
|
bytesReadTotal = strlen(buffer);
|
|
}
|
|
while( read != NULL && bytesReadTotal >= 2 && bytesReadTotal < bufLength && buffer[bytesReadTotal-1] == '\n' && buffer[bytesReadTotal-2] == '\\' );
|
|
|
|
|
|
// make a line
|
|
if( bytesReadTotal > 0 )
|
|
{
|
|
buffer[bytesReadTotal] = '\0';
|
|
result = LineNew(buffer);
|
|
}
|
|
|
|
FreeVec(buffer);
|
|
return result;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// - LINE --------------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------------------
|
|
|
|
LINEPTR LineNew(CONST_STRPTR buffer)
|
|
{
|
|
struct Line* result = NULL;
|
|
if( buffer != 0 )
|
|
{
|
|
result = AllocVec(sizeof(struct Line), MEMF_CLEAR);
|
|
result->rawText = AllocVec(strlen(buffer)+1, MEMF_CLEAR);
|
|
CopyMem(buffer, result->rawText, strlen(buffer));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
STATIC VOID lineDumpRecreate(LINEPTR abstractLine);
|
|
|
|
VOID LineDump(LINEPTR abstractLine)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
if( line->rawText != NULL )
|
|
{
|
|
Printf("%s", line->rawText);
|
|
}
|
|
else
|
|
{
|
|
lineDumpRecreate(line);
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC VOID lineDumpRecreate(LINEPTR abstractLine)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
|
|
if( line->variable == NULL && line->section == NULL )
|
|
{
|
|
// blank
|
|
Printf("# blank line\n");
|
|
}
|
|
else if( line->variable == NULL && line->section != NULL )
|
|
{
|
|
// section
|
|
struct Section* section = (struct Section*)LineGetSection(abstractLine);
|
|
STRPTR sectionText = SectionSerialize(section);
|
|
Printf(sectionText);
|
|
FreeVec(sectionText);
|
|
}
|
|
else
|
|
{
|
|
struct Variable* var = (struct Variable*)LineGetVariable(abstractLine);
|
|
STRPTR varText = VariableSerialize(var);
|
|
Printf(varText);
|
|
FreeVec(varText);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID LineSetSection(LINEPTR abstractLine, SECTIONPTR abstractSection)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
// we dont own the section
|
|
line->section = abstractSection;
|
|
}
|
|
}
|
|
|
|
SECTIONPTR LineGetSection(LINEPTR abstractLine)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
return line->section;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// first time through we need to preserve rawText
|
|
VOID LineSetInitialVariable(LINEPTR abstractLine, VARIABLEPTR abstractVariable)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
// we take ownership of the variable
|
|
if( line->variable != NULL )
|
|
{
|
|
VariableFree(line->variable);
|
|
}
|
|
line->variable = abstractVariable;
|
|
}
|
|
}
|
|
|
|
// any further change to the variable means we wipe the raw text
|
|
VOID LineSetVariable(LINEPTR abstractLine, VARIABLEPTR abstractVariable)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
if( line->rawText != NULL )
|
|
{
|
|
// if we change the variable we remove any original text
|
|
FreeVec(line->rawText);
|
|
line->rawText = NULL;
|
|
}
|
|
// we take ownership of the variable
|
|
if( line->variable != NULL )
|
|
{
|
|
VariableFree(line->variable);
|
|
}
|
|
line->variable = abstractVariable;
|
|
}
|
|
}
|
|
|
|
VARIABLEPTR LineGetVariable(LINEPTR abstractLine)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
return line->variable;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL LineHasVariable(LINEPTR line, CONST_STRPTR varKey)
|
|
{
|
|
VARIABLEPTR var = LineGetVariable(line);
|
|
return (BOOL)(var != NULL && VariableHasKey(var, varKey));
|
|
}
|
|
|
|
VOID LineFree(LINEPTR abstractLine)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
if( line->rawText != NULL )
|
|
{
|
|
FreeVec(line->rawText);
|
|
}
|
|
if( line->variable != NULL )
|
|
{
|
|
VariableFree(line->variable);
|
|
}
|
|
FreeVec(line);
|
|
}
|
|
}
|
|
|
|
CONST_STRPTR LineGetRawText(LINEPTR abstractLine)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
return (CONST_STRPTR)line->rawText;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
BOOL LineIsEmpty(LINEPTR abstractLine)
|
|
{
|
|
struct Line* line = (struct Line*)abstractLine;
|
|
if( line != NULL )
|
|
{
|
|
STRPTR start = line->rawText;
|
|
STRPTR end = start + strlen(line->rawText);
|
|
while( start != end )
|
|
{
|
|
if(!isspace(*start))
|
|
{
|
|
return FALSE;
|
|
}
|
|
start++;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// - SECTION -----------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------------------
|
|
|
|
SECTIONPTR SectionCreateWithName(CONST_STRPTR primary)
|
|
{
|
|
return SectionCreateWithNameAndSubname(primary, NULL);
|
|
}
|
|
|
|
SECTIONPTR SectionCreateWithNameAndSubname(CONST_STRPTR primary, CONST_STRPTR secondary)
|
|
{
|
|
struct Section* result = NULL;
|
|
|
|
if( primary != NULL )
|
|
{
|
|
ULONG length = strlen(primary);
|
|
result = AllocVec(sizeof(struct Section), MEMF_CLEAR);
|
|
result->lastLineWasEmpty = FALSE;
|
|
result->primary = AllocVec(length+1, MEMF_CLEAR);
|
|
CopyMem(primary, (STRPTR)result->primary, length);
|
|
|
|
if( secondary != NULL && strlen(secondary) > 0 )
|
|
{
|
|
ULONG length = strlen(secondary);
|
|
result->secondary = AllocVec(length+1, MEMF_CLEAR);
|
|
CopyMem(secondary, (STRPTR)result->secondary, length);
|
|
}
|
|
|
|
result->lines = LineArrayNew();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
VOID SectionAddSectionLine(SECTIONPTR abstractSection, LINEPTR abstractLine)
|
|
{
|
|
// sets self onto line and then adds line to the collection
|
|
LineSetSection(abstractLine, abstractSection);
|
|
SectionAddLine(abstractSection, abstractLine);
|
|
}
|
|
|
|
// we need to know if there are blank lines at the end and if this is a variable,
|
|
//insert this before them
|
|
//
|
|
// otherwise we go from
|
|
// [foo]
|
|
// bar = 1
|
|
//
|
|
// [baz]
|
|
// etc
|
|
// to
|
|
//
|
|
// [foo]
|
|
// bar = 1
|
|
//
|
|
// fubar = 1
|
|
// [baz]
|
|
// etc
|
|
|
|
VOID SectionAddLine(SECTIONPTR abstractSection, LINEPTR abstractLine)
|
|
{
|
|
struct Section* section = (struct Section*)abstractSection;
|
|
if( section != NULL )
|
|
{
|
|
//Printf("\n\SAD1 (%ld bytes avail)\n\n", AvailMem(0));
|
|
|
|
// if the last line is empty and new line is NOT, insert new line before the blank.
|
|
if( section->lastLineWasEmpty && !LineIsEmpty(abstractLine) )
|
|
{
|
|
LINEPTR lastLine = ArrayBackValue(LINEPTR, section->lines);
|
|
ULONG lastIndex = SizeOfArray(section->lines)-1;
|
|
//Printf("\n\SAD2 (%ld bytes avail)\n\n", AvailMem(0));
|
|
LineArrayValues(section->lines)[lastIndex] = abstractLine;
|
|
LineArrayAppend(section->lines, lastLine);
|
|
//Printf("\n\SAD3 (%ld bytes avail)\n\n", AvailMem(0));
|
|
}
|
|
else
|
|
{
|
|
//Printf("\n\SAD4 (%ld bytes avail)\n\n", AvailMem(0));
|
|
LineArrayAppend(section->lines, abstractLine);
|
|
//Printf("\n\SAD5 (%ld bytes avail)\n\n", AvailMem(0));
|
|
}
|
|
//Printf("\n\SAD6 (%ld bytes avail)\n\n", AvailMem(0));
|
|
section->lastLineWasEmpty = LineIsEmpty(abstractLine);
|
|
//Printf("\n\SAD7 (%ld bytes avail)\n\n", AvailMem(0));
|
|
}
|
|
}
|
|
|
|
VOID SectionCollectLinesForVariable(SECTIONPTR abstractSection, CONST_STRPTR varKey, LineArray collecting)
|
|
{
|
|
struct Section* section = (struct Section*)abstractSection;
|
|
if( section != NULL )
|
|
{
|
|
ULONG lineCount = SizeOfArray(section->lines);
|
|
ULONG index = 0;
|
|
STRPTR normalizedKey = AllocVec(strlen(varKey)+1, MEMF_CLEAR);
|
|
CopyMem(varKey, normalizedKey, strlen(varKey));
|
|
downcaseString(normalizedKey);
|
|
|
|
for( index = 0; index < lineCount; index++ )
|
|
{
|
|
LINEPTR line = LineArrayValues(section->lines)[index];
|
|
if( LineHasVariable(line, normalizedKey) )
|
|
{
|
|
LineArrayAppend(collecting, line);
|
|
}
|
|
}
|
|
FreeVec(normalizedKey);
|
|
}
|
|
else
|
|
{
|
|
Printf("null section\n");
|
|
}
|
|
}
|
|
|
|
VOID SectionDump(SECTIONPTR abstractSection)
|
|
{
|
|
struct Section* section = (struct Section*)abstractSection;
|
|
if( section != NULL && section->lines != NULL )
|
|
{
|
|
ArrayForEach(LINEPTR, aLine, section->lines, LineDump(aLine););
|
|
}
|
|
}
|
|
|
|
CONST_STRPTR SectionSerialize(SECTIONPTR abstractSection)
|
|
{
|
|
struct Section* section = (struct Section*)abstractSection;
|
|
STRPTR result = NULL;
|
|
ULONG size = 0;
|
|
if( section != NULL && section->primary != NULL )
|
|
{
|
|
if( strlen(section->primary) > 0 )
|
|
{
|
|
size += 1; // [
|
|
size += strlen(section->primary);
|
|
if( section->secondary != NULL )
|
|
{
|
|
size += 2; // ' \"'
|
|
size += strlen(section->secondary);
|
|
size += 1; // \"
|
|
}
|
|
size += 2; // ]\n
|
|
|
|
result = AllocVec(size+1, MEMF_CLEAR);
|
|
if( section->secondary == NULL )
|
|
{
|
|
sprintf(result, "[%s]\n", section->primary);
|
|
}
|
|
else
|
|
{
|
|
sprintf(result, "[%s \"%s\"]\n", section->primary, section->secondary);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
VOID SectionFree(SECTIONPTR abstractSection)
|
|
{
|
|
struct Section* section = (struct Section*)abstractSection;
|
|
if( section != NULL )
|
|
{
|
|
if( section->primary != NULL )
|
|
{
|
|
FreeVec((STRPTR)section->primary);
|
|
}
|
|
if( section->secondary != NULL )
|
|
{
|
|
FreeVec((STRPTR)section->secondary);
|
|
}
|
|
if( section->lines != NULL )
|
|
{
|
|
LineArrayFree(section->lines, TRUE); // free the lines when we free the section
|
|
}
|
|
FreeVec(section);
|
|
}
|
|
}
|
|
|
|
CONST_STRPTR SectionCanonicalName(SECTIONPTR abstractSection)
|
|
{
|
|
struct Section* section = (struct Section*)abstractSection;
|
|
STRPTR result = NULL;
|
|
if(section != NULL)
|
|
{
|
|
ULONG primaryLength = 0;
|
|
ULONG secondaryLength = 0;
|
|
if(section->primary != NULL)
|
|
{
|
|
primaryLength = strlen(section->primary);
|
|
}
|
|
if(section->secondary != NULL)
|
|
{
|
|
secondaryLength = strlen(section->secondary);
|
|
}
|
|
result = AllocVec(primaryLength+1+secondaryLength+1, MEMF_CLEAR);
|
|
CopyMem(section->primary, result, primaryLength);
|
|
result[primaryLength] = '.';
|
|
CopyMem(section->secondary, result+primaryLength+1, secondaryLength);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// - VARIABLE ----------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------------------
|
|
|
|
VARIABLEPTR VariableCreate(CONST_STRPTR key, CONST_STRPTR rawValue)
|
|
{
|
|
struct Variable* result = NULL;
|
|
if( key != NULL )
|
|
{
|
|
ULONG length = strlen(key);
|
|
result = AllocVec(sizeof(struct Variable), MEMF_CLEAR);
|
|
result->key = AllocVec(length+1, MEMF_CLEAR);
|
|
CopyMem(key, (STRPTR)result->key, length);
|
|
result->normalizedKey = AllocVec(length+1, MEMF_CLEAR);
|
|
CopyMem(key, (STRPTR)result->normalizedKey, length);
|
|
downcaseString((STRPTR)result->normalizedKey);
|
|
}
|
|
result->type = TypeString;
|
|
if( rawValue != NULL )
|
|
{
|
|
ULONG length = strlen(rawValue);
|
|
result->value.stringValue = AllocVec(length+1, MEMF_CLEAR);
|
|
CopyMem(rawValue, (STRPTR)result->value.stringValue, length);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
CONST_STRPTR VariableGetRawValue(VARIABLEPTR abstractVariable)
|
|
{
|
|
struct Variable* variable = (struct Variable*)abstractVariable;
|
|
if( variable != NULL )
|
|
{
|
|
return variable->value.stringValue;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL VariableHasKey(VARIABLEPTR abstractVariable, CONST_STRPTR varKey)
|
|
{
|
|
struct Variable* variable = (struct Variable*)abstractVariable;
|
|
if( variable != NULL )
|
|
{
|
|
if( strcmp(varKey, variable->normalizedKey) == 0 )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
VOID VariableFree(VARIABLEPTR abstractVariable)
|
|
{
|
|
struct Variable* variable = (struct Variable*)abstractVariable;
|
|
if( variable != NULL )
|
|
{
|
|
if( variable->key != NULL )
|
|
{
|
|
FreeVec((STRPTR)variable->key);
|
|
}
|
|
if( variable->normalizedKey != NULL )
|
|
{
|
|
FreeVec((STRPTR)variable->normalizedKey);
|
|
}
|
|
if( variable->type == TypeString && variable->value.stringValue != NULL )
|
|
{
|
|
FreeVec((STRPTR)variable->value.stringValue);
|
|
}
|
|
FreeVec(variable);
|
|
|
|
}
|
|
}
|
|
|
|
CONST_STRPTR VariableSerialize(VARIABLEPTR abstractVariable)
|
|
{
|
|
STRPTR result = NULL;
|
|
struct Variable* variable = (struct Variable*)abstractVariable;
|
|
if( variable != NULL && variable->key != NULL && variable->value.stringValue != NULL )
|
|
{
|
|
ULONG size = strlen(variable->key) + 3 + strlen(variable->value.stringValue) + 1;
|
|
result = AllocVec(size, MEMF_CLEAR);
|
|
sprintf(result, "\t%s = %s\n", variable->key, variable->value.stringValue);
|
|
}
|
|
return (CONST_STRPTR)result;
|
|
}
|
|
|
|
|
|
STATIC VOID downcaseString(STRPTR string)
|
|
{
|
|
BYTE* p = NULL;
|
|
for(p=string; *p; p++)
|
|
{
|
|
*p=tolower(*p);
|
|
}
|
|
}
|
|
|