ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/confparse.C
Revision: 1.9
Committed: Sat Sep 22 14:27:30 2007 UTC (16 years, 8 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +4 -4 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

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