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.
346 lines
11 KiB
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;
|
|
}
|
|
|
|
|