Tidy up initialisation in doregex.c
[tpg/opendispense2.git] / src / common / config.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * config.c - Configuration file parser
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file
8  * COPYING for full details.
9  */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include "config.h"
13 #include "doregex.h"
14 #include <regex.h>
15 #include <string.h>
16 #include <ctype.h>
17
18 #define MAX_LINE_LEN    128
19
20 // === TYPES ===
21 typedef struct sConfigValue     tConfigValue;
22 typedef struct sConfigKey       tConfigKey;
23
24 // === STRUCTURES ===
25 struct sConfigValue
26 {
27         tConfigValue    *Next;
28         char    Data[];
29 };
30
31 struct sConfigKey
32 {
33         tConfigKey      *NextKey;
34         tConfigValue    *FirstValue;
35         tConfigValue    *LastValue;
36          int    ValueCount;
37         char    KeyName[];
38 };
39
40 // === PROTOTYPES ===
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);
47
48 // === GLOBALS ===
49 tConfigKey      *gConfig;
50
51 // === CODE ===
52 void Config_ParseFile(const char *Filename)
53 {
54         FILE    *fp;
55         char    line[MAX_LINE_LEN];
56         regex_t regexp_option;
57         regex_t regexp_empty;
58
59         CompileRegex(&regexp_option, "^\\s*([^ \t]+)\\s+(.+)$", REG_EXTENDED);  //
60         CompileRegex(&regexp_empty, "^\\s*$", REG_EXTENDED);    //
61         
62         fp = fopen(Filename, "r");
63         if(!fp) {
64                 fprintf(stderr, "Unable to open config file '%s'\n", Filename);
65                 perror("Config_ParseFile");
66                 exit(-1);
67         }
68         
69         while( fgets(line, sizeof(line), fp) )
70         {
71                 regmatch_t      matches[3];
72
73                 // Trim and clean up
74                 {
75                          int    i;
76                         for( i = 0; line[i]; i ++ )
77                         {
78                                 if( line[i] == '#' || line[i] == ';' ) {
79                                         line[i] = '\0';
80                                         break;
81                                 }
82                         }
83                         
84                         while( i --, isspace(line[i]) )
85                                 line[i] = 0;
86                 }
87                 
88                                 
89                 if( regexec(&regexp_empty, line, 1, matches, 0) == 0 )
90                         continue ;
91
92                 if( RunRegex(&regexp_option, line, 3, matches, "Parsing configuration file") )
93                 {
94                         fprintf(stderr, "Syntax error\n- %s", line);
95                         continue ;
96                 }
97                 
98                 line[matches[1].rm_eo] = 0;
99                 line[matches[2].rm_eo] = 0;
100         
101                 Config_AddValue(line + matches[1].rm_so, line + matches[2].rm_so);
102         }
103         
104         fclose(fp);
105         regfree(&regexp_option);
106         regfree(&regexp_empty);
107 }
108
109 void Config_AddValue(const char *Key, const char *Value)
110 {
111         tConfigKey      *key;
112         
113         // Find key (creating if needed)
114         key = Config_int_GetKey(Key, 1);
115
116         Config_int_AddValueToKey(key, Value);   
117 }
118
119 void Config_int_AddValueToKey(tConfigKey *Key, const char *Value)
120 {
121         tConfigValue    *newVal;
122         // Create value
123         newVal = malloc(sizeof(tConfigValue) + strlen(Value) + 1);
124         newVal->Next = NULL;
125         strcpy(newVal->Data, Value);
126         
127         #if 1
128         // Add to the end of the key's list
129         if(Key->LastValue)
130                 Key->LastValue->Next = newVal;
131         else
132                 Key->FirstValue = newVal;
133         Key->LastValue = newVal;
134         #else
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;
140         #endif
141         Key->ValueCount ++;
142 }
143
144 /**
145  * \brief 
146  */
147 tConfigKey *Config_int_GetKey(const char *KeyName, int bCreate)
148 {
149         tConfigKey      *key, *prev = NULL;
150         
151         // Search the sorted list of keys
152         for( key = gConfig; key; prev = key, key = key->NextKey )
153         {
154                 int cmp = strcmp(key->KeyName, KeyName);
155                 if(cmp == 0)    return key;     // Equal, return
156                 if(cmp > 0)     break;  // Greater, fast exit
157         }
158         
159         if( bCreate )
160         {
161                 // Create new key
162                 key = malloc(sizeof(tConfigKey) + strlen(KeyName) + 1);
163                 key->FirstValue = NULL;
164                 key->LastValue = NULL;
165                 key->ValueCount = 0;
166                 strcpy(key->KeyName, KeyName);
167                 
168                 // Append
169                 if(prev) {
170                         key->NextKey = prev->NextKey;
171                         prev->NextKey = key;
172                 }
173                 else {
174                         key->NextKey = gConfig;
175                         gConfig = key;
176                 }
177         }
178         else
179         {
180                 key = NULL;
181         }
182         
183         return key;
184 }
185
186 int Config_GetValueCount(const char *KeyName)
187 {
188         tConfigKey      *key = Config_int_GetKey(KeyName, 0);
189         if(!key)        return 0;
190         
191         return key->ValueCount;
192 }
193
194 const char *Config_GetValue(const char *KeyName, int Index)
195 {
196         tConfigKey      *key;
197         tConfigValue    *val;   
198
199         key = Config_int_GetKey(KeyName, 0);
200         if(!key) {
201                 fprintf(stderr, "Unknown key '%s'\n", KeyName);
202                 exit(1);
203                 return NULL;
204         }
205         
206         if(Index < 0 || Index >= key->ValueCount)       return NULL;
207         
208         for( val = key->FirstValue; Index && val; val = val->Next, Index -- );
209
210         ASSERT(val != NULL);
211         
212         return val->Data;
213 }
214
215 int Config_GetValue_Bool(const char *KeyName, int Index)
216 {
217         const char *val = Config_GetValue(KeyName, Index);
218         if(!val)        return -1;
219         
220         if( atoi(val) == 1 )    return 1;
221         if( val[0] == '0' && val[1] == '\0' )   return 0;
222         
223         if( strcasecmp(val, "true") == 0 )      return 1;
224         if( strcasecmp(val, "false") == 0 )     return 0;
225         
226         if( strcasecmp(val, "yes") == 0 )       return 1;
227         if( strcasecmp(val, "no") == 0 )        return 0;
228         
229         return -1;
230 }
231
232 int Config_GetValue_Int(const char *KeyName, int Index)
233 {
234          int    tmp;
235         const char *val = Config_GetValue(KeyName, Index);
236         if(!val)        return -1;
237         
238         if( (tmp = atoi(val)) ) return tmp;
239         if( val[0] == '0' && val[1] == '\0' )   return 0;
240         
241         return -1;
242 }
243

UCC git Repository :: git.ucc.asn.au