ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/confparse.C
Revision: 1.3
Committed: Sat Jul 21 13:23:21 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.2: +1 -1 lines
Log Message:
- added rcsid to some files
- more documentation tweaks
- made most protocol commands local to phandler.C
- added ircd metadata (inspircd only for now)
- added inspircd swhois support

File Contents

# Content
1 /*
2 * confparse.C: Parsing of the configuration file.
3 * Rights to this code are documented in doc/pod/license.pod.
4 *
5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 */
7
8 static char const rcsid[] = "$Id$";
9
10 #include "atheme.h"
11
12 static void config_error (char *format, ...);
13 static config_file_t *config_parse (char *filename, char *confdata);
14 static void config_entry_free (config_entry_t *ceptr);
15
16 static void
17 config_error (char *format, ...)
18 {
19 va_list ap;
20 char buffer[1024];
21 char *ptr;
22
23 va_start (ap, format);
24 vsnprintf (buffer, 1024, format, ap);
25 va_end (ap);
26 if ((ptr = strchr (buffer, '\n')) != NULL)
27 *ptr = '\0';
28 slog (LG_ERROR, "config_parse(): %s", buffer);
29 }
30
31 static config_file_t *
32 config_parse (char *filename, char *confdata)
33 {
34 char *ptr;
35 char *start;
36 int linenumber = 1;
37 config_entry_t *curce;
38 config_entry_t **lastce;
39 config_entry_t *cursection;
40
41 config_file_t *curcf;
42 config_file_t *lastcf;
43
44 lastcf = curcf = (config_file_t *) smalloc (sizeof (config_file_t));
45 memset (curcf, 0, sizeof (config_file_t));
46 curcf->cf_filename = sstrdup (filename);
47 lastce = &(curcf->cf_entries);
48 curce = NULL;
49 cursection = NULL;
50
51 for (ptr = confdata; *ptr; ptr++)
52 {
53 switch (*ptr)
54 {
55 case '#':
56 while (*++ptr && (*ptr != '\n'))
57 ;
58 if (!*ptr)
59 {
60 /* make for(;;) exit from the loop */
61 ptr--;
62 continue;
63 }
64 linenumber++;
65 break;
66 case ';':
67 if (!curce)
68 {
69 config_error ("%s:%i Ignoring extra semicolon\n", filename, linenumber);
70 break;
71 }
72 if (!strcmp (curce->ce_varname, "include"))
73 {
74 config_file_t *cfptr;
75
76 if (!curce->ce_vardata)
77 {
78 config_error ("%s:%i Ignoring \"include\": No filename given\n", filename, linenumber);
79 config_entry_free (curce);
80 curce = NULL;
81 continue;
82 }
83 if (strlen (curce->ce_vardata) > 255)
84 curce->ce_vardata[255] = '\0';
85 cfptr = config_load (curce->ce_vardata);
86 if (cfptr)
87 {
88 lastcf->cf_next = cfptr;
89 lastcf = cfptr;
90 }
91 config_entry_free (curce);
92 curce = NULL;
93 continue;
94 }
95 *lastce = curce;
96 lastce = &(curce->ce_next);
97 curce->ce_fileposend = (ptr - confdata);
98 curce = NULL;
99 break;
100 case '{':
101 if (!curce)
102 {
103 config_error ("%s:%i: No name for section start\n", filename, linenumber);
104 continue;
105 }
106 else if (curce->ce_entries)
107 {
108 config_error ("%s:%i: Ignoring extra section start\n", filename, linenumber);
109 continue;
110 }
111 curce->ce_sectlinenum = linenumber;
112 lastce = &(curce->ce_entries);
113 cursection = curce;
114 curce = NULL;
115 break;
116 case '}':
117 if (curce)
118 {
119 config_error ("%s:%i: Missing semicolon before close brace\n", filename, linenumber);
120 config_entry_free (curce);
121 config_free (curcf);
122 return NULL;
123 }
124 else if (!cursection)
125 {
126 config_error ("%s:%i: Ignoring extra close brace\n", filename, linenumber);
127 continue;
128 }
129 curce = cursection;
130 cursection->ce_fileposend = (ptr - confdata);
131 cursection = cursection->ce_prevlevel;
132 if (!cursection)
133 lastce = &(curcf->cf_entries);
134 else
135 lastce = &(cursection->ce_entries);
136 for (; *lastce; lastce = &((*lastce)->ce_next))
137 continue;
138 break;
139 case '/':
140 if (*(ptr + 1) == '/')
141 {
142 ptr += 2;
143 while (*ptr && (*ptr != '\n'))
144 ptr++;
145 if (!*ptr)
146 break;
147 ptr--; /* grab the \n on next loop thru */
148 continue;
149 }
150 else if (*(ptr + 1) == '*')
151 {
152 int commentstart = linenumber;
153
154 for (ptr += 2; *ptr; ptr++)
155 {
156 if ((*ptr == '*') && (*(ptr + 1) == '/'))
157 {
158 ptr++;
159 break;
160 }
161 else if (*ptr == '\n')
162 linenumber++;
163 }
164 if (!*ptr)
165 {
166 config_error ("%s:%i Comment on this line does not end\n", filename, commentstart);
167 config_entry_free (curce);
168 config_free (curcf);
169 return NULL;
170 }
171 }
172 break;
173 case '\"':
174 start = ++ptr;
175 for (; *ptr; ptr++)
176 {
177 if ((*ptr == '\\') && (*(ptr + 1) == '\"'))
178 {
179 char *tptr = ptr;
180 while ((*tptr = *(tptr + 1)))
181 tptr++;
182 }
183 else if ((*ptr == '\"') || (*ptr == '\n'))
184 break;
185 }
186 if (!*ptr || (*ptr == '\n'))
187 {
188 config_error ("%s:%i: Unterminated quote found\n", filename, linenumber);
189 config_entry_free (curce);
190 config_free (curcf);
191 return NULL;
192 }
193 if (curce)
194 {
195 if (curce->ce_vardata)
196 {
197 config_error ("%s:%i: Ignoring extra data\n", filename, linenumber);
198 }
199 else
200 {
201 char *eptr;
202
203 curce->ce_vardata = (char *) smalloc (ptr - start + 1);
204 strlcpy (curce->ce_vardata, start, ptr - start + 1);
205 curce->ce_vardatanum = strtol (curce->ce_vardata, &eptr, 0) & 0xffffffff; /* we only want 32bits and long is 64bit on 64bit compiles */
206 if (eptr != (curce->ce_vardata + (ptr - start)))
207 {
208 curce->ce_vardatanum = 0;
209 }
210 }
211 }
212 else
213 {
214 curce = (config_entry_t *) smalloc (sizeof (config_entry_t));
215 memset (curce, 0, sizeof (config_entry_t));
216 curce->ce_varname = (char *) smalloc (ptr - start + 1);
217 strlcpy (curce->ce_varname, start, ptr - start + 1);
218 curce->ce_varlinenum = linenumber;
219 curce->ce_fileptr = curcf;
220 curce->ce_prevlevel = cursection;
221 curce->ce_fileposstart = (start - confdata);
222 }
223 break;
224 case '\n':
225 linenumber++;
226 break;
227 case '\t':
228 case ' ':
229 case '=':
230 case '\r':
231 break;
232 default:
233 if ((*ptr == '*') && (*(ptr + 1) == '/'))
234 {
235 config_error ("%s:%i Ignoring extra end comment\n", filename, linenumber);
236 ptr++;
237 break;
238 }
239 start = ptr;
240 for (; *ptr; ptr++)
241 {
242 if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\n') || (*ptr == ';'))
243 break;
244 }
245 if (!*ptr)
246 {
247 if (curce)
248 config_error ("%s: Unexpected EOF for variable starting at %i\n", filename, curce->ce_varlinenum);
249 else if (cursection)
250 config_error ("%s: Unexpected EOF for section starting at %i\n", filename, curce->ce_sectlinenum);
251 else
252 config_error ("%s: Unexpected EOF.\n", filename);
253 config_entry_free (curce);
254 config_free (curcf);
255 return NULL;
256 }
257 if (curce)
258 {
259 if (curce->ce_vardata)
260 {
261 config_error ("%s:%i: Ignoring extra data\n", filename, linenumber);
262 }
263 else
264 {
265 char *eptr;
266
267 curce->ce_vardata = (char *) smalloc (ptr - start + 1);
268 strlcpy (curce->ce_vardata, start, ptr - start + 1);
269 curce->ce_vardatanum = strtol (curce->ce_vardata, &eptr, 0) & 0xffffffff; /* we only want 32bits and long is 64bit on 64bit compiles */
270 if (eptr != (curce->ce_vardata + (ptr - start)))
271 {
272 curce->ce_vardatanum = 0;
273 }
274 }
275 }
276 else
277 {
278 curce = (config_entry_t *) smalloc (sizeof (config_entry_t));
279 memset (curce, 0, sizeof (config_entry_t));
280 curce->ce_varname = (char *) smalloc (ptr - start + 1);
281 strlcpy (curce->ce_varname, start, ptr - start + 1);
282 curce->ce_varlinenum = linenumber;
283 curce->ce_fileptr = curcf;
284 curce->ce_prevlevel = cursection;
285 curce->ce_fileposstart = (start - confdata);
286 }
287 if ((*ptr == ';') || (*ptr == '\n'))
288 ptr--;
289 break;
290 } /* switch */
291 } /* for */
292 if (curce)
293 {
294 config_error ("%s: Unexpected EOF for variable starting on line %i\n", filename, curce->ce_varlinenum);
295 config_entry_free (curce);
296 config_free (curcf);
297 return NULL;
298 }
299 else if (cursection)
300 {
301 config_error ("%s: Unexpected EOF for section starting on line %i\n", filename, cursection->ce_sectlinenum);
302 config_free (curcf);
303 return NULL;
304 }
305 return curcf;
306 }
307
308 static void
309 config_entry_free (config_entry_t *ceptr)
310 {
311 config_entry_t *nptr;
312
313 for (; ceptr; ceptr = nptr)
314 {
315 nptr = ceptr->ce_next;
316 if (ceptr->ce_entries)
317 config_entry_free (ceptr->ce_entries);
318 if (ceptr->ce_varname)
319 free (ceptr->ce_varname);
320 if (ceptr->ce_vardata)
321 free (ceptr->ce_vardata);
322 free (ceptr);
323 }
324 }
325
326 void
327 config_free (config_file_t *cfptr)
328 {
329 config_file_t *nptr;
330
331 for (; cfptr; cfptr = nptr)
332 {
333 nptr = cfptr->cf_next;
334 if (cfptr->cf_entries)
335 config_entry_free (cfptr->cf_entries);
336 if (cfptr->cf_filename)
337 free (cfptr->cf_filename);
338 free (cfptr);
339 }
340 }
341
342 config_file_t *
343 config_load (char *filename)
344 {
345 struct stat sb;
346 FILE *fd;
347 int ret;
348 char *buf = NULL;
349 config_file_t *cfptr;
350
351 fd = fopen (filename, "rb");
352 if (!fd)
353 {
354 config_error ("Couldn't open \"%s\": %s\n", filename, strerror (errno));
355 return NULL;
356 }
357 if (stat (filename, &sb) == -1)
358 {
359 config_error ("Couldn't fstat \"%s\": %s\n", filename, strerror (errno));
360 fclose (fd);
361 return NULL;
362 }
363 if (!sb.st_size)
364 {
365 fclose (fd);
366 return NULL;
367 }
368 buf = (char *) smalloc (sb.st_size + 1);
369 if (buf == NULL)
370 {
371 config_error ("Out of memory trying to load \"%s\"\n", filename);
372 fclose (fd);
373 return NULL;
374 }
375 ret = fread (buf, 1, sb.st_size, fd);
376 if (ret != sb.st_size)
377 {
378 config_error ("Error reading \"%s\": %s\n", filename, ret == -1 ? strerror (errno) : strerror (EFAULT));
379 free (buf);
380 fclose (fd);
381 return NULL;
382 }
383 buf[ret] = '\0';
384 fclose (fd);
385 cfptr = config_parse (filename, buf);
386 free (buf);
387 return cfptr;
388 }
389
390 config_entry_t *
391 config_find (config_entry_t *ceptr, char *name)
392 {
393 for (; ceptr; ceptr = ceptr->ce_next)
394 if (!strcmp (ceptr->ce_varname, name))
395 break;
396 return ceptr;
397 }
398
399 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
400 * vim:ts=8
401 * vim:sw=8
402 * vim:noexpandtab
403 */