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 void 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 void Config_ParseFile(const char *Filename)
55 char line[MAX_LINE_LEN];
56 regex_t regexp_option;
59 CompileRegex(®exp_option, "^\\s*([^ \t]+)\\s+(.+)$", REG_EXTENDED); //
60 CompileRegex(®exp_empty, "^\\s*$", REG_EXTENDED); //
62 fp = fopen(Filename, "r");
64 fprintf(stderr, "Unable to open config file '%s'\n", Filename);
65 perror("Config_ParseFile");
69 while( fgets(line, sizeof(line), fp) )
71 regmatch_t matches[3];
76 for( i = 0; line[i]; i ++ )
78 if( line[i] == '#' || line[i] == ';' ) {
84 while( i --, isspace(line[i]) )
89 if( regexec(®exp_empty, line, 1, matches, 0) == 0 )
92 if( RunRegex(®exp_option, line, 3, matches, "Parsing configuration file") )
94 fprintf(stderr, "Syntax error\n- %s", line);
98 line[matches[1].rm_eo] = 0;
99 line[matches[2].rm_eo] = 0;
101 Config_AddValue(line + matches[1].rm_so, line + matches[2].rm_so);
105 regfree(®exp_option);
106 regfree(®exp_empty);
109 void Config_AddValue(const char *Key, const char *Value)
113 // Find key (creating if needed)
114 key = Config_int_GetKey(Key, 1);
116 Config_int_AddValueToKey(key, Value);
119 void Config_int_AddValueToKey(tConfigKey *Key, const char *Value)
121 tConfigValue *newVal;
123 newVal = malloc(sizeof(tConfigValue) + strlen(Value) + 1);
125 strcpy(newVal->Data, Value);
128 // Add to the end of the key's list
130 Key->LastValue->Next = newVal;
132 Key->FirstValue = newVal;
133 Key->LastValue = newVal;
135 // Add to the start of the key's list
136 if(Key->LastValue == NULL)
137 Key->LastValue = newVal;
138 newVal->Next = Key->FirstValue;
139 Key->FirstValue = newVal;
147 tConfigKey *Config_int_GetKey(const char *KeyName, int bCreate)
149 tConfigKey *key, *prev = NULL;
151 // Search the sorted list of keys
152 for( key = gConfig; key; prev = key, key = key->NextKey )
154 int cmp = strcmp(key->KeyName, KeyName);
155 if(cmp == 0) return key; // Equal, return
156 if(cmp > 0) break; // Greater, fast exit
162 key = malloc(sizeof(tConfigKey) + strlen(KeyName) + 1);
163 key->FirstValue = NULL;
164 key->LastValue = NULL;
166 strcpy(key->KeyName, KeyName);
170 key->NextKey = prev->NextKey;
174 key->NextKey = gConfig;
186 int Config_GetValueCount(const char *KeyName)
188 tConfigKey *key = Config_int_GetKey(KeyName, 0);
191 return key->ValueCount;
194 const char *Config_GetValue(const char *KeyName, int Index)
199 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 -- );
215 int Config_GetValue_Bool(const char *KeyName, int Index)
217 const char *val = Config_GetValue(KeyName, Index);
220 if( atoi(val) == 1 ) return 1;
221 if( val[0] == '0' && val[1] == '\0' ) return 0;
223 if( strcasecmp(val, "true") == 0 ) return 1;
224 if( strcasecmp(val, "false") == 0 ) return 0;
226 if( strcasecmp(val, "yes") == 0 ) return 1;
227 if( strcasecmp(val, "no") == 0 ) return 0;
232 int Config_GetValue_Int(const char *KeyName, int Index)
235 const char *val = Config_GetValue(KeyName, Index);
238 if( (tmp = atoi(val)) ) return tmp;
239 if( val[0] == '0' && val[1] == '\0' ) return 0;