X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=src%2Fcommon%2Fconfig.c;fp=src%2Fcommon%2Fconfig.c;h=2328a885debf7d36905a4d19047b505e987d39a1;hb=6d657891a5410b7d93cc90f376a3ef27b72b20f6;hp=0000000000000000000000000000000000000000;hpb=9efbcb2400665aa3f54e51486e805711bec07587;p=tpg%2Fopendispense2.git diff --git a/src/common/config.c b/src/common/config.c new file mode 100644 index 0000000..2328a88 --- /dev/null +++ b/src/common/config.c @@ -0,0 +1,242 @@ +/* + * OpenDispense 2 + * UCC (University [of WA] Computer Club) Electronic Accounting System + * + * config.c - Configuration file parser + * + * This file is licenced under the 3-clause BSD Licence. See the file + * COPYING for full details. + */ +#include +#include +#include "config.h" +#include +#include +#include + +#define MAX_LINE_LEN 128 + +// === TYPES === +typedef struct sConfigValue tConfigValue; +typedef struct sConfigKey tConfigKey; + +// === STRUCTURES === +struct sConfigValue +{ + tConfigValue *Next; + char Data[]; +}; + +struct sConfigKey +{ + tConfigKey *NextKey; + tConfigValue *FirstValue; + tConfigValue *LastValue; + int ValueCount; + char KeyName[]; +}; + +// === PROTOTYPES === +void Config_ParseFile(const char *Filename); +void Config_AddValue(const char *Key, const char *Value); +void Config_int_AddValueToKey(tConfigKey *Key, const char *Value); +tConfigKey *Config_int_GetKey(const char *KeyName, int bCreate); + int Config_GetValueCount(const char *KeyName); +const char *Config_GetValue(const char *KeyName, int Index); + +// === GLOBALS === +tConfigKey *gConfig; + +// === CODE === +void Config_ParseFile(const char *Filename) +{ + FILE *fp; + char line[MAX_LINE_LEN]; + regex_t regexp_option; + regex_t regexp_empty; + + CompileRegex(®exp_option, "^\\s*([^ \t]+)\\s+(.+)$", REG_EXTENDED); // + CompileRegex(®exp_empty, "^\\s*$", REG_EXTENDED); // + + fp = fopen(Filename, "r"); + if(!fp) { + fprintf(stderr, "Unable to open config file '%s'\n", Filename); + perror("Config_ParseFile"); + exit(-1); + } + + while( fgets(line, sizeof(line), fp) ) + { + regmatch_t matches[3]; + + // Trim and clean up + { + int i; + for( i = 0; line[i]; i ++ ) + { + if( line[i] == '#' || line[i] == ';' ) { + line[i] = '\0'; + break; + } + } + + while( i --, isspace(line[i]) ) + line[i] = 0; + } + + + if( regexec(®exp_empty, line, 1, matches, 0) == 0 ) + continue ; + + if( RunRegex(®exp_option, line, 3, matches, "Parsing configuration file") ) + { + fprintf(stderr, "Syntax error\n- %s", line); + continue ; + } + + line[matches[1].rm_eo] = 0; + line[matches[2].rm_eo] = 0; + + Config_AddValue(line + matches[1].rm_so, line + matches[2].rm_so); + } + + fclose(fp); + regfree(®exp_option); + regfree(®exp_empty); +} + +void Config_AddValue(const char *Key, const char *Value) +{ + tConfigKey *key; + + // Find key (creating if needed) + key = Config_int_GetKey(Key, 1); + + Config_int_AddValueToKey(key, Value); +} + +void Config_int_AddValueToKey(tConfigKey *Key, const char *Value) +{ + tConfigValue *newVal; + // Create value + newVal = malloc(sizeof(tConfigValue) + strlen(Value) + 1); + newVal->Next = NULL; + strcpy(newVal->Data, Value); + + #if 1 + // Add to the end of the key's list + if(Key->LastValue) + Key->LastValue->Next = newVal; + else + Key->FirstValue = newVal; + Key->LastValue = newVal; + #else + // Add to the start of the key's list + if(Key->LastValue == NULL) + Key->LastValue = newVal; + newVal->Next = Key->FirstValue; + Key->FirstValue = newVal; + #endif + Key->ValueCount ++; +} + +/** + * \brief + */ +tConfigKey *Config_int_GetKey(const char *KeyName, int bCreate) +{ + tConfigKey *key, *prev = NULL; + + // Search the sorted list of keys + for( key = gConfig; key; prev = key, key = key->NextKey ) + { + int cmp = strcmp(key->KeyName, KeyName); + if(cmp == 0) return key; // Equal, return + if(cmp > 0) break; // Greater, fast exit + } + + if( bCreate ) + { + // Create new key + key = malloc(sizeof(tConfigKey) + strlen(KeyName) + 1); + key->FirstValue = NULL; + key->LastValue = NULL; + key->ValueCount = 0; + strcpy(key->KeyName, KeyName); + + // Append + if(prev) { + key->NextKey = prev->NextKey; + prev->NextKey = key; + } + else { + key->NextKey = gConfig; + gConfig = key; + } + } + else + { + key = NULL; + } + + return key; +} + +int Config_GetValueCount(const char *KeyName) +{ + tConfigKey *key = Config_int_GetKey(KeyName, 0); + if(!key) return 0; + + return key->ValueCount; +} + +const char *Config_GetValue(const char *KeyName, int Index) +{ + tConfigKey *key; + tConfigValue *val; + + key = Config_int_GetKey(KeyName, 0); + if(!key) { + fprintf(stderr, "Unknown key '%s'\n", KeyName); + exit(1); + return NULL; + } + + if(Index < 0 || Index >= key->ValueCount) return NULL; + + for( val = key->FirstValue; Index && val; val = val->Next, Index -- ); + + ASSERT(val != NULL); + + return val->Data; +} + +int Config_GetValue_Bool(const char *KeyName, int Index) +{ + const char *val = Config_GetValue(KeyName, Index); + if(!val) return -1; + + if( atoi(val) == 1 ) return 1; + if( val[0] == '0' && val[1] == '\0' ) return 0; + + if( strcasecmp(val, "true") == 0 ) return 1; + if( strcasecmp(val, "false") == 0 ) return 0; + + if( strcasecmp(val, "yes") == 0 ) return 1; + if( strcasecmp(val, "no") == 0 ) return 0; + + return -1; +} + +int Config_GetValue_Int(const char *KeyName, int Index) +{ + int tmp; + const char *val = Config_GetValue(KeyName, Index); + if(!val) return -1; + + if( (tmp = atoi(val)) ) return tmp; + if( val[0] == '0' && val[1] == '\0' ) return 0; + + return -1; +} +