#include "configmodel.h" #include "sectionstore.h" #include "cregex/cregex.h" #include "containers/stringarray.h" #include "containers/linearray.h" #include #include #include #include #define ZERO ((BPTR)0) cregex_program_t* InitialisePattern(CONST_STRPTR pattern); Array RunPattern(CONST_STRPTR text, cregex_program_t* patternProgram); SECTIONPTR LineGetSection(LINEPTR abstractLine); VARIABLEPTR LineGetVariable(LINEPTR abstractLine); VOID LineDump(LINEPTR abstractLine); SECTIONPTR SectionCreateWithName(CONST_STRPTR primary); SECTIONPTR SectionCreateWithNameAndSubname(CONST_STRPTR primary, CONST_STRPTR secondary); VOID SectionFree(SECTIONPTR abstractSection); VARIABLEPTR VariableCreate(CONST_STRPTR key, CONST_STRPTR rawValue); VOID VariableFree(VARIABLEPTR abstractVariable); #define WHITESPACE "[ \\t\\n\\r\\f\\v]" #define RX_BLANK_LINE "^[ \t\n\r\f\v]*($|#|;)" #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]*$" STATIC cregex_program_t* sectionPatternProgram = NULL; STATIC cregex_program_t* variablePatternProgram = NULL; STATIC cregex_program_t* blankPatternProgram = NULL; STATIC cregex_program_t* integerPatternProgram = NULL; struct ConfigFile { CONST_STRPTR filename; LineArray lines; SECTIONSTOREPTR sectionStore; }; struct Section { CONST_STRPTR primary; CONST_STRPTR secondary; LineArray lines; }; enum VariableType { TypeBool=0, TypeInteger=1, TypeString=2, }; struct Variable { enum VariableType type; CONST_STRPTR key; union { CONST_STRPTR stringValue; BOOL boolValue; LONG longValue; } value; }; struct Line { STRPTR rawText; struct Variable* variable; struct Section* section; }; VOID ConfigFileFree(CONFIGFILEPTR abstractConfigFile) { struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile; if( configFile != NULL ) { if( configFile->lines != NULL ) { LineArrayFree(configFile->lines, TRUE); //also frees lines } if( configFile->sectionStore != NULL ) { SectionStoreFree(configFile->sectionStore); } FreeVec(configFile); } } 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; SECTIONPTR currentSection = NULL;//SectionCreateWithName(""); // initial empty section result->sectionStore = SectionStoreNew(); result->lines = LineArrayNew(); InitialisePatterns(); while( (line = LineReadIncludingContinuation(configFile, currentSection)) != NULL ) { // add it to the flat list of lines LineArrayAppend(result->lines, line); LineDump(line); if( LineGetSection(line) != NULL ) { currentSection = LineGetSection(line); } } ReleasePatterns(); Close(configFile); } return result; } VOID ConfigFileSave(CONFIGFILEPTR config) { } LINEPTR LineCreate(CONST_STRPTR buffer, ULONG size) { struct Line* result = NULL; StringArray matches = 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 if( matches = RunPattern(result->rawText, sectionPatternProgram) ) { if( SizeOfArray(matches) == 3 ) { result->section = SectionCreateWithName(StringArrayValues(matches)[1]); } else if( SizeOfArray(matches) == 5 ) { result->section = SectionCreateWithNameAndSubname(StringArrayValues(matches)[1], StringArrayValues(matches)[3]); } StringArrayFree(matches); } else { if( matches = RunPattern(result->rawText, variablePatternProgram) ) { result->variable = VariableCreate(StringArrayValues(matches)[1], StringArrayValues(matches)[2]); StringArrayFree(matches); } else { if( matches = RunPattern(result->rawText, blankPatternProgram) ) { StringArrayFree(matches); } else { Printf("\nDIDNT MATCH ANYTHING %s\n", result->rawText); } } } } return result; } VOID LineDump(LINEPTR abstractLine) { struct Line* line = (struct Line*)abstractLine; if( line != NULL ) { Printf("> %s\n", line->rawText); if( line->variable == NULL && line->section == NULL ) { Printf("(blank)\n"); } else if( line->variable == NULL && line->section != NULL ) { struct Section* section = (struct Section*)LineGetSection(abstractLine); CONST_STRPTR canonical = NULL; Printf("(new section %s", section->primary); if( section->secondary ) { Printf("[%s]", section->secondary); } Printf(")\n"); canonical = SectionCanonicalName(section); Printf("...((%s))...\n", canonical); FreeVec((STRPTR)canonical); } else { struct Section* section = (struct Section*)LineGetSection(abstractLine); struct Variable* var = (struct Variable*)LineGetVariable(abstractLine); Printf("(variable in section %s", section->primary); if( section->secondary ) { Printf("[%s]\n", section->secondary); } Printf(") %s = %s\n", var->key, var->value.stringValue); } } } LINEPTR LineReadIncludingContinuation(BPTR file, SECTIONPTR currentSection) { 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 = LineCreate(buffer, bytesReadTotal); if( result->variable != NULL && result->section == NULL ) { result->section = currentSection; } } FreeVec(buffer); return result; } SECTIONPTR LineGetSection(LINEPTR abstractLine) { struct Line* line = (struct Line*)abstractLine; if( line != NULL ) { return line->section; } return NULL; } 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); } if( line->section != NULL && line->variable == NULL ) { //only free the section in a section line, //not a variable line as thats just a weak ref SectionFree(line->section); } 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; } } 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 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, FALSE); // dont free the lines they are only weak } 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; } 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); } } // ---------------------------------------------------- // ---------------------------------------------------- // ---------------------------------------------------- // ---------------------------------------------------- // ---------------------------------------------------- VOID InitialisePatterns(VOID) { sectionPatternProgram = InitialisePattern(RX_SECTION_LINE); variablePatternProgram = InitialisePattern(RX_VARIABLE_LINE); blankPatternProgram = InitialisePattern(RX_BLANK_LINE); integerPatternProgram = InitialisePattern(RX_INTEGER); } VOID ReleasePatterns(VOID) { if( sectionPatternProgram != NULL ) cregex_compile_free( sectionPatternProgram ); if( variablePatternProgram != NULL ) cregex_compile_free( variablePatternProgram ); if( blankPatternProgram != NULL ) cregex_compile_free( blankPatternProgram ); if( integerPatternProgram != NULL ) cregex_compile_free( integerPatternProgram ); } cregex_program_t* InitialisePattern(CONST_STRPTR pattern) { cregex_program_t* result = NULL; cregex_node_t* patternNode = cregex_parse(pattern); if( patternNode ) { result = cregex_compile_node( patternNode ); if( result != NULL ) { //Printf("successfully compiled %s\n", pattern); } else { Printf("failed to compile %s\n", pattern); } cregex_parse_free( patternNode ); } else { Printf("could not parse %s\n", pattern); } return result; } Array RunPattern(CONST_STRPTR text, cregex_program_t* patternProgram) { Array result = NULL; char* localMatches[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; if (cregex_program_run(patternProgram, text, localMatches, 20) > 0) { int j = 0; int nmatches = 0; // count the matches for (j = 0; j < 20; ++j) if (localMatches[j]) nmatches = j; if( nmatches > 0 ) { result = StringArrayNew(); // loop the matches for (j = 0; j <= nmatches; j += 2) { if (localMatches[j] && localMatches[j + 1]) { int len = (int)(localMatches[j + 1] - localMatches[j]); STRPTR buffer = AllocVec(len+1, MEMF_CLEAR); // freed in the array sprintf(buffer, "%.*s", len, localMatches[j]); if( buffer[len-1] == '\n' ) { buffer[len-1] = '\0'; } StringArrayAppend(result, buffer); } else { //Printf("(NULL,NULL)\n"); } } } // end } else { //Printf("\"%s\": no match\n", text); } return result; }