ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/confparse.C
Revision: 1.4
Committed: Tue Aug 28 17:08:12 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.3: +47 -53 lines
Log Message:
- changed name
- updated the example config to the new system
- added more documentation
- enhanced documentation generators
- added a link to the pdf to the website
- added an RSS feed generator
- transitioned hooks to c++ callbacks
- did various merges with upstream along the way
- added const where appropriate
- removed the old block allocator
- fixed most memory leaks
- transitioned some dictionaries to std::map
- transitioned some lists to std::vector
- made some free functions members where appropriate
- renamed string to dynstr and added a static string ststr
- use NOW instead of time (NULL) if possible
- completely reworked database backends, crypto handlers and protocol handlers
  to use an object factory
- removed the old module system. ermyth does not do any dynamic loading anymore
- fixed most of the build system
- reworked how protocol commands work

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.4 static char const rcsid[] = "$Id: confparse.C,v 1.3 2007-07-21 13:23:21 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     {
227     config_error ("%s:%i: Ignoring extra data\n", filename, linenumber);
228     }
229     else
230     {
231     char *eptr;
232    
233 pippijn 1.4 curce->ce_vardata = alloc<char> (ptr - start + 1);
234 pippijn 1.1 strlcpy (curce->ce_vardata, start, ptr - start + 1);
235     curce->ce_vardatanum = strtol (curce->ce_vardata, &eptr, 0) & 0xffffffff; /* we only want 32bits and long is 64bit on 64bit compiles */
236     if (eptr != (curce->ce_vardata + (ptr - start)))
237     {
238     curce->ce_vardatanum = 0;
239     }
240     }
241     }
242     else
243     {
244 pippijn 1.4 curce = new config_entry_t;
245     curce->ce_varname = alloc<char> (ptr - start + 1);
246 pippijn 1.1 strlcpy (curce->ce_varname, start, ptr - start + 1);
247     curce->ce_varlinenum = linenumber;
248     curce->ce_fileptr = curcf;
249     curce->ce_prevlevel = cursection;
250     curce->ce_fileposstart = (start - confdata);
251     }
252     break;
253     case '\n':
254     linenumber++;
255     break;
256     case '\t':
257     case ' ':
258     case '=':
259     case '\r':
260     break;
261     default:
262     if ((*ptr == '*') && (*(ptr + 1) == '/'))
263     {
264     config_error ("%s:%i Ignoring extra end comment\n", filename, linenumber);
265     ptr++;
266     break;
267     }
268     start = ptr;
269     for (; *ptr; ptr++)
270     {
271     if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\n') || (*ptr == ';'))
272     break;
273     }
274     if (!*ptr)
275     {
276     if (curce)
277     config_error ("%s: Unexpected EOF for variable starting at %i\n", filename, curce->ce_varlinenum);
278     else if (cursection)
279     config_error ("%s: Unexpected EOF for section starting at %i\n", filename, curce->ce_sectlinenum);
280     else
281     config_error ("%s: Unexpected EOF.\n", filename);
282     config_entry_free (curce);
283     config_free (curcf);
284     return NULL;
285     }
286     if (curce)
287     {
288     if (curce->ce_vardata)
289     {
290     config_error ("%s:%i: Ignoring extra data\n", filename, linenumber);
291     }
292     else
293     {
294     char *eptr;
295    
296 pippijn 1.4 curce->ce_vardata = alloc<char> (ptr - start + 1);
297 pippijn 1.1 strlcpy (curce->ce_vardata, start, ptr - start + 1);
298     curce->ce_vardatanum = strtol (curce->ce_vardata, &eptr, 0) & 0xffffffff; /* we only want 32bits and long is 64bit on 64bit compiles */
299     if (eptr != (curce->ce_vardata + (ptr - start)))
300     {
301     curce->ce_vardatanum = 0;
302     }
303     }
304     }
305     else
306     {
307 pippijn 1.4 curce = new config_entry_t;
308     curce->ce_varname = alloc<char> (ptr - start + 1);
309 pippijn 1.1 strlcpy (curce->ce_varname, start, ptr - start + 1);
310     curce->ce_varlinenum = linenumber;
311     curce->ce_fileptr = curcf;
312     curce->ce_prevlevel = cursection;
313     curce->ce_fileposstart = (start - confdata);
314     }
315     if ((*ptr == ';') || (*ptr == '\n'))
316     ptr--;
317     break;
318     } /* switch */
319     } /* for */
320     if (curce)
321     {
322     config_error ("%s: Unexpected EOF for variable starting on line %i\n", filename, curce->ce_varlinenum);
323     config_entry_free (curce);
324     config_free (curcf);
325     return NULL;
326     }
327     else if (cursection)
328     {
329     config_error ("%s: Unexpected EOF for section starting on line %i\n", filename, cursection->ce_sectlinenum);
330     config_free (curcf);
331     return NULL;
332     }
333     return curcf;
334     }
335    
336     config_file_t *
337     config_load (char *filename)
338     {
339     struct stat sb;
340     FILE *fd;
341     int ret;
342     char *buf = NULL;
343     config_file_t *cfptr;
344    
345     fd = fopen (filename, "rb");
346     if (!fd)
347     {
348     config_error ("Couldn't open \"%s\": %s\n", filename, strerror (errno));
349     return NULL;
350     }
351     if (stat (filename, &sb) == -1)
352     {
353     config_error ("Couldn't fstat \"%s\": %s\n", filename, strerror (errno));
354     fclose (fd);
355     return NULL;
356     }
357     if (!sb.st_size)
358     {
359     fclose (fd);
360     return NULL;
361     }
362 pippijn 1.4 buf = alloc<char> (sb.st_size + 1);
363 pippijn 1.1 if (buf == NULL)
364     {
365     config_error ("Out of memory trying to load \"%s\"\n", filename);
366     fclose (fd);
367     return NULL;
368     }
369     ret = fread (buf, 1, sb.st_size, fd);
370     if (ret != sb.st_size)
371     {
372     config_error ("Error reading \"%s\": %s\n", filename, ret == -1 ? strerror (errno) : strerror (EFAULT));
373 pippijn 1.4 sfree (buf);
374 pippijn 1.1 fclose (fd);
375     return NULL;
376     }
377     buf[ret] = '\0';
378     fclose (fd);
379     cfptr = config_parse (filename, buf);
380 pippijn 1.4 sfree (buf);
381 pippijn 1.1 return cfptr;
382     }
383    
384     config_entry_t *
385     config_find (config_entry_t *ceptr, char *name)
386     {
387     for (; ceptr; ceptr = ceptr->ce_next)
388     if (!strcmp (ceptr->ce_varname, name))
389     break;
390     return ceptr;
391     }
392    
393     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
394     * vim:ts=8
395     * vim:sw=8
396     * vim:noexpandtab
397     */