ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/confparse.C
Revision: 1.2
Committed: Sat Jul 21 01:29:10 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
- moved to new documentation system
- fixed small build error

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     * 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     */