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.
17 #define MAX_LINE_LEN 128
20 typedef struct sConfigValue tConfigValue;
21 typedef struct sConfigKey tConfigKey;
33 tConfigValue *FirstValue;
34 tConfigValue *LastValue;
40 void Config_ParseFile(const char *Filename);
41 void Config_AddValue(const char *Key, const char *Value);
42 void Config_int_AddValueToKey(tConfigKey *Key, const char *Value);
43 tConfigKey *Config_int_GetKey(const char *KeyName, int bCreate);
44 int Config_GetValueCount(const char *KeyName);
45 const char *Config_GetValue(const char *KeyName, int Index);
51 void 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 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 while( i --, isspace(line[i]) )
88 if( 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);
108 void Config_AddValue(const char *Key, const char *Value)
112 // Find key (creating if needed)
113 key = Config_int_GetKey(Key, 1);
115 Config_int_AddValueToKey(key, Value);
118 void Config_int_AddValueToKey(tConfigKey *Key, const char *Value)
120 tConfigValue *newVal;
122 newVal = malloc(sizeof(tConfigValue) + strlen(Value) + 1);
124 strcpy(newVal->Data, Value);
127 // Add to the end of the key's list
129 Key->LastValue->Next = newVal;
131 Key->FirstValue = newVal;
132 Key->LastValue = newVal;
134 // Add to the start of the key's list
135 if(Key->LastValue == NULL)
136 Key->LastValue = newVal;
137 newVal->Next = Key->FirstValue;
138 Key->FirstValue = newVal;
146 tConfigKey *Config_int_GetKey(const char *KeyName, int bCreate)
148 tConfigKey *key, *prev = NULL;
150 // Search the sorted list of keys
151 for( key = gConfig; key; prev = key, key = key->NextKey )
153 int cmp = strcmp(key->KeyName, KeyName);
154 if(cmp == 0) return key; // Equal, return
155 if(cmp > 0) break; // Greater, fast exit
161 key = malloc(sizeof(tConfigKey) + strlen(KeyName) + 1);
162 key->FirstValue = NULL;
163 key->LastValue = NULL;
165 strcpy(key->KeyName, KeyName);
169 key->NextKey = prev->NextKey;
173 key->NextKey = gConfig;
185 int Config_GetValueCount(const char *KeyName)
187 tConfigKey *key = Config_int_GetKey(KeyName, 0);
190 return key->ValueCount;
193 const char *Config_GetValue(const char *KeyName, int Index)
198 key = Config_int_GetKey(KeyName, 0);
200 fprintf(stderr, "Unknown key '%s'\n", KeyName);
205 if(Index < 0 || Index >= key->ValueCount) return NULL;
207 for( val = key->FirstValue; Index && val; val = val->Next, Index -- );
214 int Config_GetValue_Bool(const char *KeyName, int Index)
216 const char *val = Config_GetValue(KeyName, Index);
219 if( atoi(val) == 1 ) return 1;
220 if( val[0] == '0' && val[1] == '\0' ) return 0;
222 if( strcasecmp(val, "true") == 0 ) return 1;
223 if( strcasecmp(val, "false") == 0 ) return 0;
225 if( strcasecmp(val, "yes") == 0 ) return 1;
226 if( strcasecmp(val, "no") == 0 ) return 0;
231 int Config_GetValue_Int(const char *KeyName, int Index)
234 const char *val = Config_GetValue(KeyName, Index);
237 if( (tmp = atoi(val)) ) return tmp;
238 if( val[0] == '0' && val[1] == '\0' ) return 0;