ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/confparse.C
Revision: 1.5
Committed: Tue Aug 28 22:18:31 2007 UTC (16 years, 9 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.4: +3 -7 lines
Log Message:
added type traits

File Contents

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