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