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.
configreader/configmodel.c

481 lines
11 KiB

1 year ago
#include "configmodel.h"
#include "sectionstore.h"
1 year ago
1 year ago
#include "cregex/cregex.h"
#include "containers/stringarray.h"
#include "containers/linearray.h"
1 year ago
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>
#include <stdio.h>
1 year ago
#define ZERO ((BPTR)0)
// - STRUCTS -----------------------------------------------------------------------------
1 year ago
struct ConfigFile
{
CONST_STRPTR filename;
SECTIONSTOREPTR sectionStore;
1 year ago
};
1 year ago
struct Section
{
CONST_STRPTR primary;
CONST_STRPTR secondary;
1 year ago
LineArray lines;
1 year ago
};
enum VariableType
{
TypeBool=0,
TypeInteger=1,
TypeString=2,
};
struct Variable
{
enum VariableType type;
CONST_STRPTR key;
1 year ago
union
{
CONST_STRPTR stringValue;
BOOL boolValue;
LONG longValue;
} value;
};
struct Line
{
STRPTR rawText;
struct Variable* variable;
struct Section* section;
1 year ago
};
// ---------------------------------------------------------------------------------------
// - CONFIG FILE -------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
1 year ago
VOID ConfigFileFree(CONFIGFILEPTR abstractConfigFile)
{
struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile;
if( configFile != NULL )
{
if( configFile->sectionStore != NULL )
{
SectionStoreFree(configFile->sectionStore);
}
1 year ago
FreeVec(configFile);
}
}
STATIC LINEPTR configFileReadLine(BPTR file);
1 year ago
CONFIGFILEPTR ConfigFileRead(CONST_STRPTR filename)
{
struct ConfigFile* result = AllocVec(sizeof(struct ConfigFile), MEMF_CLEAR);
BPTR configFile = Open(filename, MODE_OLDFILE);
if( configFile != ZERO )
{
LINEPTR line = NULL;
result->sectionStore = SectionStoreNew();
while( (line = configFileReadLine(configFile)) != NULL )
1 year ago
{
SectionStoreAddLine(result->sectionStore, line);
//LineDump(line);
1 year ago
}
Close(configFile);
}
return result;
}
StringArray ConfigFileSplitKey(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, '.', 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);
return result;
}
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 )
{
result = LineNew(buffer, bytesReadTotal);
}
FreeVec(buffer);
return result;
}
// ---------------------------------------------------------------------------------------
// - LINE --------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
LINEPTR LineNew(CONST_STRPTR buffer, ULONG size)
{
struct Line* result = NULL;
if( size > 0 )
{
result = AllocVec(sizeof(struct Line), MEMF_CLEAR);
result->rawText = AllocVec(size, MEMF_CLEAR);
CopyMem(buffer, result->rawText, size-1); // drop the \\n
}
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\n", 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);
if( section != NULL && section->primary != NULL )
{
if( strlen(section->primary) > 0 )
{
Printf("[%s", section->primary);
if( section->secondary != NULL )
{
Printf(" \"%s\"", section->secondary);
}
Printf("]\n");
}
}
}
else
{
struct Variable* var = (struct Variable*)LineGetVariable(abstractLine);
Printf("%s = %s\n", var->key, var->value.stringValue);
}
}
}
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;
}
VOID LineFree(LINEPTR abstractLine)
{
struct Line* line = (struct Line*)abstractLine;
if( line != NULL )
{
if( line->rawText != NULL )
{
FreeVec(line->rawText);
}
// we dont free the section as its stored in the section store
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;
}
}
// ---------------------------------------------------------------------------------------
// - SECTION -----------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
1 year ago
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->primary = AllocVec(length+1, MEMF_CLEAR);
CopyMem(primary, (STRPTR)result->primary, length);
if( secondary != NULL )
{
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);
}
VOID SectionAddLine(SECTIONPTR abstractSection, LINEPTR abstractLine)
{
struct Section* section = (struct Section*)abstractSection;
if( section != NULL )
{
LineArrayAppend(section->lines, abstractLine);
}
}
VOID SectionDump(SECTIONPTR abstractSection)
{
struct Section* section = (struct Section*)abstractSection;
if( section != NULL && section->lines != NULL )
{
ArrayForEach(LINEPTR, aLine, section->lines, LineDump(aLine););
}
}
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);
}
}
1 year ago
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 ----------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
1 year ago
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->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;
}
VOID VariableFree(VARIABLEPTR abstractVariable)
{
struct Variable* variable = (struct Variable*)abstractVariable;
if( variable != NULL )
{
if( variable->key != NULL )
{
FreeVec((STRPTR)variable->key);
}
if( variable->type == TypeString && variable->value.stringValue != NULL )
{
FreeVec((STRPTR)variable->value.stringValue);
}
FreeVec(variable);
}
}