]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * config.c: | |
3 | * | |
4 | * Facilities for handling the config file | |
5 | */ | |
6 | ||
7 | #define __USE_GNU | |
8 | #include <string.h> | |
9 | ||
10 | #include "../lib/sstring.h" | |
11 | #include "../lib/array.h" | |
12 | #include "error.h" | |
13 | #include "config.h" | |
14 | #include <stdio.h> | |
15 | #include <stdlib.h> | |
16 | ||
17 | extern void modulerehash(void); | |
18 | ||
19 | char *theconfig; | |
20 | ||
21 | typedef struct { | |
22 | sstring *key; | |
23 | array values; | |
24 | } configitem; | |
25 | ||
26 | typedef struct { | |
27 | sstring *modulename; | |
28 | array items; | |
29 | } configsection; | |
30 | ||
31 | array sections; | |
32 | ||
33 | void rehashconfig() { | |
34 | Error("config",ERR_INFO,"Rehashing config file."); | |
35 | freeconfig(); | |
36 | initconfig(NULL); | |
37 | modulerehash(); | |
38 | } | |
39 | ||
40 | void freeconfig() { | |
41 | int i,j,k; | |
42 | configsection *sects; | |
43 | configitem *items; | |
44 | sstring **values; | |
45 | ||
46 | sects=(configsection *)(sections.content); | |
47 | for (i=0;i<sections.cursi;i++) { | |
48 | items=(configitem *)(sects[i].items.content); | |
49 | for (j=0;j<sects[i].items.cursi;j++) { | |
50 | freesstring(items[j].key); | |
51 | values=(sstring **)(items[j].values.content); | |
52 | for (k=0;k<items[j].values.cursi;k++) { | |
53 | freesstring(values[k]); | |
54 | } | |
55 | array_free(&(items[j].values)); | |
56 | } | |
57 | array_free(&(sects[i].items)); | |
58 | freesstring(sects[i].modulename); | |
59 | } | |
60 | array_free(§ions); | |
61 | } | |
62 | ||
63 | void initconfig(char *filename) { | |
64 | FILE *fp; | |
65 | configsection *sects=NULL; | |
66 | configitem *items=NULL; | |
67 | sstring **values=NULL; | |
68 | char buf[255]; | |
69 | char *cp; | |
70 | int si=-1; | |
71 | int ii,j; | |
72 | int matched; | |
73 | ||
74 | if (filename==NULL) { | |
75 | filename=theconfig; | |
76 | } else { | |
77 | theconfig=filename; | |
78 | } | |
79 | ||
80 | array_init((§ions),sizeof(configsection)); | |
81 | ||
82 | if ((fp=fopen(filename,"r"))==NULL) { | |
83 | Error("core",ERR_STOP,"Couldn't load config file '%s'.", filename); | |
84 | exit(1); | |
85 | } | |
86 | ||
87 | while (!feof(fp)) { | |
88 | /* Read in a line */ | |
89 | fgets(buf,255,fp); | |
90 | /* Check we got something */ | |
91 | if (feof(fp)) | |
92 | break; | |
93 | ||
94 | /* Allow some comment chars */ | |
95 | if (buf[0]=='#' || buf[0]==';' || (buf[0]=='/' && buf[1]=='/')) | |
96 | continue; | |
97 | ||
98 | /* Blow away the line ending */ | |
99 | for (cp=buf;*cp;cp++) | |
100 | if (*cp=='\n' || *cp=='\r') { | |
101 | *cp='\0'; | |
102 | break; | |
103 | } | |
104 | ||
105 | /* Check it's long enough */ | |
106 | if (strlen(buf)<3) | |
107 | continue; | |
108 | ||
109 | if (buf[0]=='[') { | |
110 | /* New section (possibly) -- hunt for the ']' */ | |
111 | for (cp=&(buf[2]);*cp;cp++) { | |
112 | if (*cp==']') { | |
113 | si=array_getfreeslot(§ions); | |
114 | sects=(configsection *)(sections.content); | |
115 | array_init(&(sects[si].items),sizeof(configitem)); | |
116 | array_setlim1(&(sects[si].items),10); | |
117 | *cp='\0'; | |
118 | sects[si].modulename=getsstring(&(buf[1]),255); | |
119 | break; | |
120 | } | |
121 | } | |
122 | } else { | |
123 | /* Ignore if we're not in a valid section */ | |
124 | if (si<0) | |
125 | continue; | |
126 | ||
127 | for (cp=buf;*cp;cp++) { | |
128 | if (*cp=='=') { | |
129 | *cp='\0'; | |
130 | matched=0; | |
131 | for (ii=0;ii<sects[si].items.cursi;ii++) { | |
132 | if (!strcmp(items[ii].key->content,buf)) { | |
133 | /* Another value for an existing key */ | |
134 | j=array_getfreeslot(&(items[ii].values)); | |
135 | values=(sstring **)(items[ii].values.content); | |
136 | values[j]=getsstring(cp+1,512); | |
137 | matched=1; | |
138 | } | |
139 | } | |
140 | ||
141 | if (matched==0) { | |
142 | /* New key */ | |
143 | ii=array_getfreeslot(&(sects[si].items)); | |
144 | items=(configitem *)(sects[si].items.content); | |
145 | items[ii].key=getsstring(buf,512); | |
146 | array_init(&(items[ii].values),sizeof(sstring *)); | |
147 | array_setlim1(&(items[ii].values),5); | |
148 | j=array_getfreeslot(&(items[ii].values)); | |
149 | values=(sstring **)(items[ii].values.content); | |
150 | values[j]=getsstring(cp+1,512); /* looks nasty but is OK, this char is '=' | |
151 | * and we know 'buf' is null-terminated */ | |
152 | } | |
153 | break; | |
154 | } | |
155 | } | |
156 | } | |
157 | } | |
158 | ||
159 | fclose(fp); | |
160 | } | |
161 | ||
162 | void dumpconfig() { | |
163 | int i,j,k; | |
164 | configsection *sects; | |
165 | configitem *items; | |
166 | sstring **values; | |
167 | ||
168 | printf("Dumping complete configuration database.\n"); | |
169 | printf("Total sections: %d\n",sections.cursi); | |
170 | ||
171 | sects=(configsection *)(sections.content); | |
172 | for (i=0;i<sections.cursi;i++) { | |
173 | printf ("\nSection %02d: [%s] has %d items\n",i,sects[i].modulename->content,sects[i].items.cursi); | |
174 | items=(configitem *)(sects[i].items.content); | |
175 | for(j=0;j<sects[i].items.cursi;j++) { | |
176 | printf(" Item %02d: [%s] has %d values\n",j,items[j].key->content,items[j].values.cursi); | |
177 | values=(sstring **)(items[j].values.content); | |
178 | for (k=0;k<items[j].values.cursi;k++) { | |
179 | printf(" Value %2d: [%s]\n",k,values[k]->content); | |
180 | } | |
181 | } | |
182 | } | |
183 | ||
184 | printf("\n\nEnd of configuration database.\n"); | |
185 | } | |
186 | ||
187 | /* | |
188 | * Two routes for extacting config info: | |
189 | * | |
190 | * - getconfigitem() is for keys which can only meaningfully have one value. | |
191 | * It returns the last value for that key (so the config file has "last | |
192 | * value overrides" semantics. | |
193 | * - getconfigitems() is for keys which can have multiple values, it returns | |
194 | * a pointer to the array of values. | |
195 | */ | |
196 | ||
197 | array *getconfigitems(char *module, char *key) { | |
198 | int i,j; | |
199 | configsection *sects; | |
200 | configitem *items; | |
201 | ||
202 | sects=(configsection *)(sections.content); | |
203 | for (i=0;i<sections.cursi;i++) { | |
204 | if (!strcmp(module,sects[i].modulename->content)) { | |
205 | /* Found the module */ | |
206 | items=(configitem *)(sects[i].items.content); | |
207 | for (j=0;j<sects[i].items.cursi;j++) { | |
208 | if (!strcmp(key,items[j].key->content)) { | |
209 | return (&items[j].values); | |
210 | } | |
211 | } | |
212 | return NULL; | |
213 | } | |
214 | } | |
215 | return NULL; | |
216 | } | |
217 | ||
218 | sstring *getconfigitem(char *module, char *key) { | |
219 | array *a; | |
220 | sstring **values; | |
221 | ||
222 | if ((a=getconfigitems(module,key))==NULL) { | |
223 | return NULL; | |
224 | } | |
225 | ||
226 | values=(sstring **)(a->content); | |
227 | return values[(a->cursi-1)]; | |
228 | } | |
229 | ||
230 | sstring *getcopyconfigitem(char *module, char *key, char *defaultvalue, int len) { | |
231 | sstring *ss; | |
232 | ||
233 | ss=getconfigitem(module,key); | |
234 | if (ss!=NULL) { | |
235 | return getsstring(ss->content,len); | |
236 | } else { | |
237 | return getsstring(defaultvalue,len); | |
238 | } | |
239 | } |