3 * UCC (University [of WA] Computer Club) Electronic Accounting System
5 * config.c - Configuration file parser
7 * This file is licenced under the 3-clause BSD Licence. See the file
8 * COPYING for full details.
18 #define MAX_LINE_LEN 128
21 typedef struct sConfigValue tConfigValue;
22 typedef struct sConfigKey tConfigKey;
34 tConfigValue *FirstValue;
35 tConfigValue *LastValue;
41 //int Config_ParseFile(const char *Filename);
42 void Config_AddValue(const char *Key, const char *Value);
43 void Config_int_AddValueToKey(tConfigKey *Key, const char *Value);
44 tConfigKey *Config_int_GetKey(const char *KeyName, int bCreate);
45 int Config_GetValueCount(const char *KeyName);
46 const char *Config_GetValue(const char *KeyName, int Index);
52 int Config_ParseFile(const char *Filename)
54 char line[MAX_LINE_LEN];
55 regex_t regexp_option;
58 CompileRegex(®exp_option, "^\\s*([^ \t]+)\\s+(.+)$", REG_EXTENDED); //
59 CompileRegex(®exp_empty, "^\\s*$", REG_EXTENDED); //
61 FILE *fp = fopen(Filename, "r");
63 fprintf(stderr, "Unable to open config file '%s'\n", Filename);
64 perror("Config_ParseFile");
68 while( fgets(line, sizeof(line), fp) )
70 regmatch_t matches[3];
75 for( i = 0; line[i]; i ++ )
77 if( line[i] == '#' || line[i] == ';' ) {
83 // Trim trailing whitespace
84 while( i -- && isspace(line[i]) )
88 if( line[0] == '\0' ) // regexec(®exp_empty, line, 1, matches, 0) == 0 )
91 if( RunRegex(®exp_option, line, 3, matches, "Parsing configuration file") )
93 fprintf(stderr, "Syntax error\n- %s", line);
97 line[matches[1].rm_eo] = 0;
98 line[matches[2].rm_eo] = 0;
100 Config_AddValue(line + matches[1].rm_so, line + matches[2].rm_so);
104 regfree(®exp_option);
105 regfree(®exp_empty);
110 void Config_AddValue(const char *Key, const char *Value)
114 // Find key (creating if needed)
115 key = Config_int_GetKey(Key, 1);
117 Config_int_AddValueToKey(key, Value);
120 void Config_int_AddValueToKey(tConfigKey *Key, const char *Value)
122 tConfigValue *newVal;
124 newVal = malloc(sizeof(tConfigValue) + strlen(Value) + 1);
126 strcpy(newVal->Data, Value);
129 // Add to the end of the key's list
131 Key->LastValue->Next = newVal;
133 Key->FirstValue = newVal;
134 Key->LastValue = newVal;
136 // Add to the start of the key's list
137 if(Key->LastValue == NULL)
138 Key->LastValue = newVal;
139 newVal->Next = Key->FirstValue;
140 Key->FirstValue = newVal;
148 tConfigKey *Config_int_GetKey(const char *KeyName, int bCreate)
150 tConfigKey *key, *prev = NULL;
152 // Search the sorted list of keys
153 for( key = gConfig; key; prev = key, key = key->NextKey )
155 int cmp = strcmp(key->KeyName, KeyName);
156 if(cmp == 0) return key; // Equal, return
157 if(cmp > 0) break; // Greater, fast exit
163 key = malloc(sizeof(tConfigKey) + strlen(KeyName) + 1);
164 key->FirstValue = NULL;
165 key->LastValue = NULL;
167 strcpy(key->KeyName, KeyName);
171 key->NextKey = prev->NextKey;
175 key->NextKey = gConfig;
187 int Config_GetValueCount(const char *KeyName)
189 tConfigKey *key = Config_int_GetKey(KeyName, 0);
192 return key->ValueCount;
195 const tConfigValue *Config_int_GetValue(const char *KeyName, int Index)
199 tConfigKey *key = Config_int_GetKey(KeyName, 0);
201 fprintf(stderr, "Unknown key '%s'\n", KeyName);
206 if(Index < 0 || Index >= key->ValueCount) return NULL;
208 for( val = key->FirstValue; Index && val; val = val->Next, Index -- );
214 const char *Config_GetValue_Idx(const char *KeyName, int Index)
216 const tConfigValue* val = Config_int_GetValue(KeyName, Index);
217 if( !val ) return NULL;
221 bool Config_GetValue_Str(const char *KeyName, const char** Value)
223 const tConfigValue* val = Config_int_GetValue(KeyName, 0);
224 if(!val) return false;
228 bool str_to_bool(const char *val)
230 if( atoi(val) == 1 ) return 1;
231 if( val[0] == '0' && val[1] == '\0' ) return 0;
233 if( strcasecmp(val, "true") == 0 ) return 1;
234 if( strcasecmp(val, "false") == 0 ) return 0;
236 if( strcasecmp(val, "yes") == 0 ) return 1;
237 if( strcasecmp(val, "no") == 0 ) return 0;
239 // INVALID, TODO: Error message
242 bool Config_GetValue_Bool(const char *KeyName, bool* Value)
244 const tConfigValue* val = Config_int_GetValue(KeyName, 0);
245 if(!val) return false;
247 *Value = str_to_bool(val->Data);
252 bool Config_GetValue_Int(const char *KeyName, int* Value)
254 const tConfigValue* val = Config_int_GetValue(KeyName, 0);
255 if(!val) return false;
258 int value = strtol(val->Data, &end, 0);