]> jfr.im git - irc/quakenet/newserv.git/blame - core/config.c
Implement --help parameter.
[irc/quakenet/newserv.git] / core / config.c
CommitLineData
2c5db955
CP
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>
4ad1cf7a 15#include <stdlib.h>
2c5db955 16
37867865 17extern void modulerehash(void);
18
2c5db955
CP
19char *theconfig;
20
21typedef struct {
22 sstring *key;
23 array values;
24} configitem;
25
26typedef struct {
27 sstring *modulename;
28 array items;
29} configsection;
30
31array sections;
32
33void rehashconfig() {
34 Error("config",ERR_INFO,"Rehashing config file.");
35 freeconfig();
36 initconfig(NULL);
37867865 37 modulerehash();
2c5db955
CP
38}
39
40void 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(&sections);
61}
62
63void 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((&sections),sizeof(configsection));
81
82 if ((fp=fopen(filename,"r"))==NULL) {
e29554df 83 Error("core",ERR_STOP,"Couldn't load config file '%s'.", filename);
2c5db955
CP
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(&sections);
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
162void 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
197array *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
218sstring *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
230sstring *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}