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, 7 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

# Content
1 /*
2 * confparse.C: Parsing of the configuration file.
3 *
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 * Rights to this code are documented in doc/pod/license.pod.
10 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
11 */
12
13 static char const rcsid[] = "$Id: confparse.C,v 1.8 2007-09-16 18:54:44 pippijn Exp $";
14
15 #include "atheme.h"
16 #include "confparse.h"
17
18 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 config_entry_free (ceptr->ce_entries);
28 if (ceptr->ce_varname)
29 sfree (ceptr->ce_varname);
30 if (ceptr->ce_vardata)
31 sfree (ceptr->ce_vardata);
32 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
53 static void
54 config_error (char const * const format, ...)
55 {
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 lastcf = curcf = new config_file_t;
82 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 config_error ("%s:%i: Ignoring extra data\n", filename, linenumber);
233 else
234 {
235 char *eptr;
236
237 curce->ce_vardata = salloc<char> (ptr - start + 1);
238 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 curce->ce_vardatanum = 0;
242 }
243 }
244 else
245 {
246 curce = new config_entry_t;
247 curce->ce_varname = salloc<char> (ptr - start + 1);
248 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 curce->ce_vardata = salloc<char> (ptr - start + 1);
299 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 curce = new config_entry_t;
310 curce->ce_varname = salloc<char> (ptr - start + 1);
311 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 buf = salloc<char> (sb.st_size + 1);
365 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 sfree (buf);
376 fclose (fd);
377 return NULL;
378 }
379 buf[ret] = '\0';
380 fclose (fd);
381 cfptr = config_parse (filename, buf);
382 sfree (buf);
383 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 */