#include "sectionstore.h" #include "containers/sectionmap.h" #include "containers/sectionarray.h" #include "containers/stringarray.h" #include "cregex/pattern.h" #include #include #include #include #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 ); 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 SectionStoreAddLine(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); } else { if( parseBlank(line, store->blankPatternProgram) ) { SectionAddLine(section, line); } 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; } // --------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------- // 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); } 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); } return result; } 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); *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); } return result; }