#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) // - STRUCTS ----------------------------------------------------------------------------- struct ConfigFile { CONST_STRPTR filename; 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; }; // --------------------------------------------------------------------------------------- // - CONFIG FILE ------------------------------------------------------------------------- // --------------------------------------------------------------------------------------- VOID ConfigFileFree(CONFIGFILEPTR abstractConfigFile) { struct ConfigFile* configFile = (struct ConfigFile*)abstractConfigFile; if( configFile != NULL ) { if( configFile->sectionStore != NULL ) { SectionStoreFree(configFile->sectionStore); } FreeVec(configFile); } } STATIC LINEPTR configFileReadLine(BPTR file); 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 ) { SectionStoreAddLine(result->sectionStore, line); //LineDump(line); } 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 ----------------------------------------------------------------------------- // --------------------------------------------------------------------------------------- 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); } } 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 ---------------------------------------------------------------------------- // --------------------------------------------------------------------------------------- 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); } }