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/sectionstore.c

346 lines
11 KiB

#include "sectionstore.h"
#include "containers/sectionmap.h"
#include "containers/sectionarray.h"
#include "containers/stringarray.h"
#include "containers/linearray.h"
#include "cregex/pattern.h"
#include "configfile.h"
#include <proto/exec.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define RX_SECTION_LINE "^[ \t\n\r\f\v]*\\[([a-z0-9]+)([ \t\n\r\f\v]*\"(.+)\")*\\][ \t\n\r\f\v]*($|#|;)"
#define RX_VARIABLE_LINE "^[ \t\n\r\f\v]*([a-z][a-z0-9]+)[ \t\n\r\f\v]*=[ \t\n\r\f\v]*(.+)[ \t\n\r\f\v]*($|#|;)"
#define RX_INTEGER "^-?[1-9][0-9]*$"
#define RX_BLANK_LINE "^[ \t\n\r\f\v]*($|#|;)"
STATIC SECTIONPTR parseSection(LINEPTR line, PATTERNPTR sectionPatternProgram);
STATIC VARIABLEPTR parseVariable(LINEPTR line, PATTERNPTR variablePatternProgram);
STATIC BOOL parseBlank(LINEPTR line, PATTERNPTR blankPatternProgram);
//STATIC BOOL parseBoolValue(CONST_STRPTR value, BOOL* outBool);
//STATIC BOOL parseIntegerValue(CONST_STRPTR value, LONG* outInt, PATTERNPTR integerProgram);
struct SectionStore
{
SectionMap map;
SectionArray array;
// here so we only create them once not each line
PATTERNPTR sectionPatternProgram;
PATTERNPTR variablePatternProgram;
PATTERNPTR blankPatternProgram;
PATTERNPTR integerPatternProgram;
};
SECTIONSTOREPTR SectionStoreNew(VOID)
{
struct SectionStore* result = AllocVec(sizeof(struct SectionStore), MEMF_CLEAR);
result->map = SectionMapNew();
result->array = SectionArrayNew();
result->sectionPatternProgram = PatternNew(RX_SECTION_LINE);
result->variablePatternProgram = PatternNew(RX_VARIABLE_LINE);
result->blankPatternProgram = PatternNew(RX_BLANK_LINE);
result->integerPatternProgram = PatternNew(RX_INTEGER);
return result;
}
VOID SectionStoreFree(SECTIONSTOREPTR abstractSectionStore)
{
if( abstractSectionStore != NULL )
{
struct SectionStore* store = (struct SectionStore*)abstractSectionStore;
if( store->map != NULL ) SectionMapFree( store->map );
if( store->array != NULL ) SectionArrayFree( store->array, TRUE );//free teh sections
if( store->sectionPatternProgram != NULL ) PatternFree(store->sectionPatternProgram);
if( store->variablePatternProgram != NULL ) PatternFree(store->variablePatternProgram);
if( store->blankPatternProgram != NULL ) PatternFree(store->blankPatternProgram);
if( store->integerPatternProgram != NULL ) PatternFree(store->integerPatternProgram);
FreeVec(store);
}
}
VOID SectionStoreAddSection(SECTIONSTOREPTR abstractSectionStore, SECTIONPTR section)
{
struct SectionStore* store = (struct SectionStore*)abstractSectionStore;
if( store != NULL && section != NULL )
{
CONST_STRPTR canonicalName = SectionCanonicalName(section);
if( canonicalName != NULL )
{
// the array acts as storage as it can free its contents
SectionArrayAppend(store->array, section);
// the map will copy the string key and free it, but not the section
SectionMapSet(store->map, canonicalName, section);
//free the canonical name as the map has copied it.
FreeVec((STRPTR)canonicalName);
}
}
}
SECTIONPTR SectionStoreGetSection(SECTIONSTOREPTR abstractSectionStore, CONST_STRPTR canonicalName)
{
struct SectionStore* store = (struct SectionStore*)abstractSectionStore;
if( store != NULL && canonicalName != NULL )
{
return SectionMapGet(store->map, canonicalName);
}
}
SECTIONPTR SectionStoreCurrentSection(SECTIONSTOREPTR abstractSectionStore)
{
struct SectionStore* store = (struct SectionStore*)abstractSectionStore;
SECTIONPTR result = NULL;
if( store != NULL && SizeOfArray(store->array) > 0 )
{
result = ArrayBackValue(SECTIONPTR, store->array);
}
return result;
}
VOID SectionStoreRemoveLines(SECTIONSTOREPTR sectionStore, CONST_STRPTR canonicalSectionName, CONST_STRPTR varKey)
{
SECTIONPTR section = SectionStoreGetSection(sectionStore, canonicalSectionName);
if( section != NULL )
{
SectionRemoveLinesForVariable(section, varKey);
}
}
LineArray SectionStoreFindLines(SECTIONSTOREPTR sectionStore, CONST_STRPTR canonicalSectionName, CONST_STRPTR varKey)
{
LineArray result = LineArrayNew();
SECTIONPTR section = SectionStoreGetSection(sectionStore, canonicalSectionName);
if( section != NULL )
{
SectionCollectLinesForVariable(section, varKey, result);
}
return result;
}
VariableArray SectionStoreGetAll(SECTIONSTOREPTR sectionStore, CONST_STRPTR canonicalSectionName, CONST_STRPTR varKey)
{
VariableArray result = VariableArrayNew();
LineArray lines = SectionStoreFindLines(sectionStore, canonicalSectionName, varKey);
ULONG index = 0;
for( index = 0; index < SizeOfArray(lines); index++)
{
LINEPTR line = LineArrayValues(lines)[index];
VariableArrayAppend(result, LineGetVariable(line));
}
LineArrayFree(lines, FALSE);
return result;
}
VARIABLEPTR SectionStoreGet(SECTIONSTOREPTR sectionStore, CONST_STRPTR canonicalSectionName, CONST_STRPTR varKey)
{
VARIABLEPTR result = NULL;
LineArray lines = SectionStoreFindLines(sectionStore, canonicalSectionName, varKey);
result = LineGetVariable((LINEPTR)ArrayBackValue(LINEPTR, lines));
LineArrayFree(lines, FALSE);
return result;
}
VOID SectionStoreAddLineToCurrentSection(SECTIONSTOREPTR abstractSectionStore, LINEPTR line)
{
struct SectionStore* store = (struct SectionStore*)abstractSectionStore;
if( store != NULL )
{
// if its a new section, just add it and move on
SECTIONPTR section = parseSection(line, store->sectionPatternProgram);
if( section )
{
SectionStoreAddSection(store, section);
SectionAddSectionLine(section, line);
}
else
{
// if its a variable or blank, parse it and add to current section
VARIABLEPTR variable = NULL;
section = SectionStoreCurrentSection(store);
// if no current section, we're adding variables at the state so create a blank section
if( section == NULL )
{
section = SectionCreateWithName("");
SectionStoreAddSection(store, section);
}
if( variable = parseVariable(line, store->variablePatternProgram) )
{
LineSetInitialVariable(line, variable);
SectionAddLine(section, line, FALSE);
}
else
{
if( parseBlank(line, store->blankPatternProgram) )
{
SectionAddLine(section, line, FALSE);
}
else
{
// wasnt a section, a variable or a comment so ignore it or complain
}
}
}
}
}
ULONG SectionStoreSectionCount(SECTIONSTOREPTR abstractSectionStore)
{
ULONG result = 0;
struct SectionStore* store = (struct SectionStore*)abstractSectionStore;
if( store != NULL )
{
return SizeOfArray(store->array);
}
return result;
}
SECTIONPTR SectionStoreSectionAt(SECTIONSTOREPTR abstractSectionStore, ULONG index)
{
SECTIONPTR result = NULL;
struct SectionStore* store = (struct SectionStore*)abstractSectionStore;
if( store != NULL )
{
if( index < SizeOfArray(store->array) )
{
result = SectionArrayValues(store->array)[index];
}
}
return result;
}
StringArray SectionStoreSubsectionsForSection(SECTIONSTOREPTR abstractSectionStore, CONST_STRPTR primarySection)
{
struct SectionStore* store = (struct SectionStore*)abstractSectionStore;
StringArray result = StringArrayNew();
ULONG index = 0;
for( index = 0; index < SizeOfArray(store->array); index++)
{
SECTIONPTR section = SectionArrayValues(store->array)[index];
if( SectionHasName(section, primarySection) )
{
CONST_STRPTR secondary = SectionGetRawSubsectionName(section);
if( secondary != NULL && strlen(secondary) > 0 )
{
StringArrayAppendAndRetain(result, secondary);
}
}
}
return result;
}
SECTIONPTR SectionStoreFindOrCreateSection(SECTIONSTOREPTR sectionStore, CONST_STRPTR compoundKey)
{
// now get the section
StringArray canonicalParts = CompoundKeySplitKeyForVar(compoundKey);
SECTIONPTR section = SectionStoreGetSection(sectionStore, StringArrayValues(canonicalParts)[0]);
if( section == NULL )
{
StringArray separateParts = CompoundKeySplitKeyCompletely(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);
SectionStoreAddSection(sectionStore, section); //section store will free it for us
StringArrayFree(separateParts, TRUE);
}
StringArrayFree(canonicalParts, TRUE);
return section;
}
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// PRIVATE
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
STATIC VARIABLEPTR parseVariable(LINEPTR line, PATTERNPTR variablePatternProgram)
{
VARIABLEPTR result = NULL;
StringArray matches = NULL;
if( matches = PatternRun(LineGetRawText(line), variablePatternProgram) )
{
result = VariableCreate(StringArrayValues(matches)[1], StringArrayValues(matches)[2]);
StringArrayFree(matches, TRUE);
}
return result;
}
STATIC SECTIONPTR parseSection(LINEPTR line, PATTERNPTR sectionPatternProgram)
{
SECTIONPTR result = NULL;
StringArray matches = NULL;
if( matches = PatternRun(LineGetRawText(line), sectionPatternProgram) )
{
if( SizeOfArray(matches) == 3 )
{
result = SectionCreateWithName(StringArrayValues(matches)[1]);
}
else if( SizeOfArray(matches) == 5 )
{
result = SectionCreateWithNameAndSubname(StringArrayValues(matches)[1], StringArrayValues(matches)[3]);
}
StringArrayFree(matches, TRUE);
}
return result;
}
// TODO I ended up not using these and just having all variable be strings.
// The calling code can decide how to parse the strings into ints or bools or whatever
// It just seemed like a step too far in complexity to have to decide for each
// variable what type it was and then keep track of that when we set, or collect values
// STATIC BOOL parseBoolValue(CONST_STRPTR value, BOOL* outBool)
// {
// BOOL result = FALSE;
// if( strcmp(value, "yes") == 0 || strcmp(value, "true") == 0 || strcmp(value, "on") == 0 ) {
// *outBool = TRUE;
// result = TRUE;
// }
// if( strcmp(value, "no") == 0 || strcmp(value, "false") == 0 || strcmp(value, "off") == 0 ) {
// *outBool = FALSE;
// result = TRUE;
// }
// return result;
// }
//
//
// STATIC BOOL parseIntegerValue(CONST_STRPTR value, LONG* outInt, PATTERNPTR integerProgram)
// {
// BOOL result = FALSE;
// StringArray matches = NULL;
//
// if( matches = PatternRun(value, integerProgram) )
// {
// StringArrayFree(matches, TRUE);
// *outInt = atol(value);
// result = TRUE;
// }
// return result;
// }
STATIC BOOL parseBlank(LINEPTR line, PATTERNPTR blankPatternProgram)
{
BOOL result = FALSE;
StringArray matches = NULL;
if( matches = PatternRun(LineGetRawText(line), blankPatternProgram) )
{
result = TRUE;
StringArrayFree(matches, TRUE);
}
return result;
}