/[CvsGraph]/cvsgraph/readconf.c
ViewVC logotype

Annotate of /cvsgraph/readconf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.9 - (hide annotations)
Sun Mar 9 22:36:50 2003 UTC (14 years, 9 months ago) by bertho
Branch: MAIN
Changes since 1.8: +5 -0 lines
File MIME type: text/plain
- add merge visualization
- Provide solution for possible XSS bug in tag expansions
1 bertho 1.1 /*
2     * CvsGraph graphical representation generator of brances and revisions
3     * of a file in cvs/rcs.
4     *
5 bertho 1.3 * Copyright (C) 2001,2002 B. Stultiens
6 bertho 1.1 *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     /*#define DEBUG 1*/
23    
24     #include <stdio.h>
25     #include <stdlib.h>
26     #include <string.h>
27     #include <ctype.h>
28     #include <assert.h>
29    
30     #include <gd.h>
31     #include <gdfontt.h>
32     #include <gdfonts.h>
33     #include <gdfontmb.h>
34     #include <gdfontl.h>
35     #include <gdfontg.h>
36    
37     #include "utils.h"
38     #include "cvsgraph.h"
39     #include "readconf.h"
40    
41     int line_number;
42    
43     typedef struct
44     {
45     char *keyword;
46     int type;
47     union {
48     void *v; /* join of other values */
49     int *i;
50     font_t *f;
51     char **s;
52     color_t *c;
53 bertho 1.2 double *d;
54 bertho 1.1 int val; /* FIXME: Oops, sizeof(int) must be sizeof(void *) */
55     } confref;
56     } keyword_t;
57    
58     typedef union {
59     keyword_t *kw;
60     int i;
61 bertho 1.2 double d;
62 bertho 1.1 char *str;
63     } YYSTYPE;
64    
65     static YYSTYPE yylval;
66    
67     static int nstacked_opts;
68     static char **stacked_opts;
69    
70     enum {
71     TYPE_dummy = 256,
72     TYPE_KEYWORD,
73     TYPE_NUMBER,
74     TYPE_VALUE,
75     TYPE_BOOLEAN,
76     TYPE_COLOR,
77     TYPE_FONT,
78 bertho 1.2 TYPE_STRING,
79     TYPE_DOUBLE
80 bertho 1.1 };
81    
82     static keyword_t keywords[] = {
83     { "branch_bgcolor", TYPE_COLOR, { &conf.branch_bgcolor } },
84     { "branch_bspace", TYPE_NUMBER, { &conf.branch_bspace } },
85     { "branch_color", TYPE_COLOR, { &conf.branch_color } },
86 bertho 1.2 { "branch_font", TYPE_FONT, { &conf.branch_font.gdfont } },
87     { "branch_ttfont", TYPE_STRING, { &conf.branch_font.ttfont } },
88     { "branch_ttsize", TYPE_DOUBLE, { &conf.branch_font.ttsize } },
89     { "branch_tag_color", TYPE_COLOR, { &conf.branch_tag_color } },
90     { "branch_tag_font", TYPE_FONT, { &conf.branch_tag_font.gdfont } },
91     { "branch_tag_ttfont", TYPE_STRING, { &conf.branch_tag_font.ttfont } },
92     { "branch_tag_ttsize", TYPE_DOUBLE, { &conf.branch_tag_font.ttsize } },
93 bertho 1.1 { "branch_lspace", TYPE_NUMBER, { &conf.branch_lspace } },
94     { "branch_rspace", TYPE_NUMBER, { &conf.branch_rspace } },
95     { "branch_tspace", TYPE_NUMBER, { &conf.branch_tspace } },
96     { "branch_connect", TYPE_NUMBER, { &conf.branch_connect } },
97     { "branch_margin", TYPE_NUMBER, { &conf.branch_margin } },
98     { "branch_dupbox", TYPE_BOOLEAN, { &conf.branch_dupbox } },
99     { "upside_down", TYPE_BOOLEAN, { &conf.upside_down } },
100 bertho 1.5 { "left_right", TYPE_BOOLEAN, { &conf.left_right } },
101 bertho 1.2 { "auto_stretch", TYPE_BOOLEAN, { &conf.auto_stretch } },
102 bertho 1.1 { "color_bg", TYPE_COLOR, { &conf.color_bg } },
103 bertho 1.2 { "transparent_bg", TYPE_BOOLEAN, { &conf.transparent_bg } },
104 bertho 1.1 { "cvsmodule", TYPE_STRING, { &conf.cvsmodule } },
105     { "cvsroot", TYPE_STRING, { &conf.cvsroot } },
106     { "date_format", TYPE_STRING, { &conf.date_format } },
107     { "box_shadow", TYPE_BOOLEAN, { &conf.box_shadow } },
108     { "strip_untagged", TYPE_BOOLEAN, { &conf.strip_untagged } },
109     { "strip_first_rev", TYPE_BOOLEAN, { &conf.strip_first_rev } },
110 bertho 1.2 { "anti_alias", TYPE_BOOLEAN, { &conf.anti_alias } },
111     { "use_ttf", TYPE_BOOLEAN, { &conf.use_ttf } },
112 bertho 1.4 { "parse_logs", TYPE_BOOLEAN, { &conf.parse_logs } },
113 bertho 1.8 { "html_level", TYPE_NUMBER, { &conf.html_level } },
114 bertho 1.3 { "thick_lines", TYPE_NUMBER, { &conf.thick_lines } },
115 bertho 1.1 { "rev_color", TYPE_COLOR, { &conf.rev_color } },
116     { "rev_bgcolor", TYPE_COLOR, { &conf.rev_bgcolor } },
117 bertho 1.2 { "rev_font", TYPE_FONT, { &conf.rev_font.gdfont } },
118     { "rev_ttfont", TYPE_STRING, { &conf.rev_font.ttfont } },
119     { "rev_ttsize", TYPE_DOUBLE, { &conf.rev_font.ttsize } },
120 bertho 1.1 { "rev_separator", TYPE_NUMBER, { &conf.rev_separator } },
121     { "rev_minline", TYPE_NUMBER, { &conf.rev_minline } },
122     { "rev_maxline", TYPE_NUMBER, { &conf.rev_maxline } },
123     { "rev_lspace", TYPE_NUMBER, { &conf.rev_lspace } },
124     { "rev_rspace", TYPE_NUMBER, { &conf.rev_rspace } },
125     { "rev_tspace", TYPE_NUMBER, { &conf.rev_tspace } },
126     { "rev_bspace", TYPE_NUMBER, { &conf.rev_bspace } },
127     { "rev_text", TYPE_STRING, { &conf.rev_text } },
128     { "rev_text_color", TYPE_COLOR, { &conf.rev_text_color } },
129 bertho 1.2 { "rev_text_font", TYPE_FONT, { &conf.rev_text_font.gdfont } },
130     { "rev_text_ttfont", TYPE_STRING, { &conf.rev_text_font.ttfont } },
131     { "rev_text_ttsize", TYPE_DOUBLE, { &conf.rev_text_font.ttsize } },
132 bertho 1.6 { "rev_maxtags", TYPE_NUMBER, { &conf.rev_maxtags } },
133 bertho 1.9 { "merge_color", TYPE_COLOR, { &conf.merge_color } },
134     { "merge_from", TYPE_STRING, { &conf.merge_from } },
135     { "merge_to", TYPE_STRING, { &conf.merge_to } },
136     { "merge_front", TYPE_BOOLEAN, { &conf.merge_front } },
137     { "merge_nocase", TYPE_BOOLEAN, { &conf.merge_nocase } },
138 bertho 1.1 { "tag_color", TYPE_COLOR, { &conf.tag_color } },
139 bertho 1.2 { "tag_font", TYPE_FONT, { &conf.tag_font.gdfont } },
140     { "tag_ttfont", TYPE_STRING, { &conf.tag_font.ttfont } },
141     { "tag_ttsize", TYPE_DOUBLE, { &conf.tag_font.ttsize } },
142 bertho 1.1 { "title", TYPE_STRING, { &conf.title } },
143     { "title_x", TYPE_NUMBER, { &conf.title_x } },
144     { "title_y", TYPE_NUMBER, { &conf.title_y } },
145 bertho 1.2 { "title_font", TYPE_FONT, { &conf.title_font.gdfont } },
146     { "title_ttfont", TYPE_STRING, { &conf.title_font.ttfont } },
147     { "title_ttsize", TYPE_DOUBLE, { &conf.title_font.ttsize } },
148 bertho 1.1 { "title_align", TYPE_NUMBER, { &conf.title_align } },
149     { "title_color", TYPE_COLOR, { &conf.title_color } },
150     { "margin_top", TYPE_NUMBER, { &conf.margin_top } },
151     { "margin_bottom", TYPE_NUMBER, { &conf.margin_bottom } },
152     { "margin_left", TYPE_NUMBER, { &conf.margin_left } },
153     { "margin_right", TYPE_NUMBER, { &conf.margin_right } },
154     { "image_type", TYPE_NUMBER, { &conf.image_type } },
155     { "image_quality", TYPE_NUMBER, { &conf.image_quality } },
156     { "map_name", TYPE_STRING, { &conf.map_name } },
157     { "map_branch_href", TYPE_STRING, { &conf.map_branch_href } },
158     { "map_branch_alt", TYPE_STRING, { &conf.map_branch_alt } },
159     { "map_rev_href", TYPE_STRING, { &conf.map_rev_href } },
160     { "map_rev_alt", TYPE_STRING, { &conf.map_rev_alt } },
161     { "map_diff_href", TYPE_STRING, { &conf.map_diff_href } },
162     { "map_diff_alt", TYPE_STRING, { &conf.map_diff_alt } },
163     { "jpeg", TYPE_VALUE, { (void *)IMAGE_JPEG } },
164     { "png", TYPE_VALUE, { (void *)IMAGE_PNG } },
165     { "gif", TYPE_VALUE, { (void *)IMAGE_GIF } },
166     { "true", TYPE_VALUE, { (void *)1 } },
167     { "false", TYPE_VALUE, { (void *)0 } },
168 bertho 1.3 { "not", TYPE_VALUE, { (void *)-1 } },
169 bertho 1.1 { "left", TYPE_VALUE, { (void *)0 } },
170     { "center", TYPE_VALUE, { (void *)1 } },
171     { "right", TYPE_VALUE, { (void *)2 } },
172     { "tiny", TYPE_VALUE, { (void *)0 } },
173     { "small", TYPE_VALUE, { (void *)1 } },
174     { "medium", TYPE_VALUE, { (void *)2 } },
175     { "large", TYPE_VALUE, { (void *)3 } },
176     { "giant", TYPE_VALUE, { (void *)4 } },
177 bertho 1.8 { "HTML3", TYPE_VALUE, { (void *)1 } },
178     { "HTML4", TYPE_VALUE, { (void *)2 } },
179     { "XHTML", TYPE_VALUE, { (void *)3 } },
180 bertho 1.1 };
181    
182     #define NKEYWORDS (sizeof(keywords) / sizeof(keywords[0]))
183    
184     static int cmp_kw(const void *k1, const void *k2)
185     {
186     return strcmp(((keyword_t *)k1)->keyword, ((keyword_t *)k2)->keyword);
187     }
188    
189     /*
190     **************************************************************************
191     * Debug routines
192     **************************************************************************
193     */
194     #ifdef DEBUG
195     #define DEBUGSTREAM stdout
196     static void debug_pname(const char *n)
197     {
198     fprintf(DEBUGSTREAM, "%-16s: ", n);
199     }
200    
201     static void debug_pstring(const char *n, const char *a)
202     {
203     debug_pname(n);
204     if(!a)
205     fprintf(DEBUGSTREAM, "<not-set>\n");
206     else
207     {
208     fputc('\'', DEBUGSTREAM);
209     for(; *a; a++)
210     {
211     if(isprint(*a))
212     fputc(*a, DEBUGSTREAM);
213     else
214     {
215     fputc('\\', DEBUGSTREAM);
216     switch(*a)
217     {
218     case '\a': fputc('a', DEBUGSTREAM); break;
219     case '\b': fputc('b', DEBUGSTREAM); break;
220     case '\f': fputc('f', DEBUGSTREAM); break;
221     case '\n': fputc('n', DEBUGSTREAM); break;
222     case '\r': fputc('r', DEBUGSTREAM); break;
223     case '\t': fputc('t', DEBUGSTREAM); break;
224     case '\v': fputc('v', DEBUGSTREAM); break;
225     default:
226     fprintf(DEBUGSTREAM, "x%02x", (unsigned char)*a);
227     }
228     }
229     }
230     fprintf(DEBUGSTREAM, "'\n");
231     }
232     }
233    
234     static void debug_pbool(const char *n, int b)
235     {
236     debug_pname(n);
237     fprintf(DEBUGSTREAM, "%s\n", b ? "true" : "false");
238     }
239    
240     static void debug_pint(const char *n, int i)
241     {
242     debug_pname(n);
243     fprintf(DEBUGSTREAM, "%i\n", i);
244     }
245    
246 bertho 1.2 static void debug_pdouble(const char *n, double d)
247     {
248     debug_pname(n);
249     fprintf(DEBUGSTREAM, "%g\n", d);
250     }
251    
252     static void debug_pfont(const char *n, gdFontPtr f)
253 bertho 1.1 {
254     const char *s = "<Unknown font>";
255     debug_pname(n);
256     if(f == gdFontTiny)
257     s = "gdFontTiny";
258     else if(f == gdFontSmall)
259     s = "gdFontSmall";
260     else if(f == gdFontMediumBold)
261     s = "gdFontMediumBold";
262     else if(f == gdFontLarge)
263     s = "gdFontLarge";
264     else if(f == gdFontGiant)
265     s = "gdFontGiant";
266     fprintf(DEBUGSTREAM, "%s\n", s);
267     }
268    
269     static void debug_pcolor(const char *n, color_t *c)
270     {
271     debug_pname(n);
272     fprintf(DEBUGSTREAM, "#%02x%02x%02x\n", c->r, c->g, c->b);
273     }
274    
275     void dump_config(void)
276     {
277     debug_pstring("cvsroot", conf.cvsroot);
278     debug_pstring("cvsmodule", conf.cvsmodule);
279     debug_pstring("date_format", conf.date_format);
280    
281     debug_pcolor("color_bg", &conf.color_bg);
282     debug_pbool("box_shadow", conf.box_shadow);
283     debug_pbool("upside_down", conf.upside_down);
284 bertho 1.5 debug_pbool("left_right", conf.left_right);
285 bertho 1.1 debug_pbool("strip_untagged", conf.strip_untagged);
286     debug_pbool("strip_first_rev", conf.strip_first_rev);
287 bertho 1.3 debug_pbool("auto_stretch", conf.auto_stretch);
288     debug_pbool("anti_alias", conf.anti_alias);
289     debug_pbool("use_ttf", conf.use_ttf);
290     debug_pint("thick_lines", conf.thick_lines);
291 bertho 1.1
292 bertho 1.2 debug_pfont("tag_font", conf.tag_font.gdfont);
293     debug_pstring("tag_ttfont", conf.tag_font.ttfont);
294     debug_psouble("tag_ttsize", conf.tag_font.ttsize);
295 bertho 1.1 debug_pcolor("tag_color", &conf.tag_color);
296    
297 bertho 1.2 debug_pfont("rev_font", conf.rev_font.gdfont);
298     debug_pstring("rev_ttfont", conf.rev_font.ttfont);
299     debug_pdouble("rev_ttsize", conf.rev_font.ttsize);
300 bertho 1.1 debug_pcolor("rev_color", &conf.rev_color);
301     debug_pcolor("rev_bgcolor", &conf.rev_bgcolor);
302     debug_pint("rev_separator", conf.rev_separator);
303     debug_pint("rev_minline", conf.rev_minline);
304     debug_pint("rev_maxline", conf.rev_maxline);
305     debug_pint("rev_lspace", conf.rev_lspace);
306     debug_pint("rev_rspace", conf.rev_rspace);
307     debug_pint("rev_tspace", conf.rev_tspace);
308     debug_pint("rev_bspace", conf.rev_bspace);
309     debug_pstring("rev_text", conf.rev_text);
310     debug_pcolor("rev_text_color", &conf.rev_text_color);
311 bertho 1.2 debug_pfont("rev_text_font", conf.rev_text_font.gdfont);
312     debug_pstring("rev_text_ttfont", conf.rev_text_font.ttfont);
313     debug_pdouble("rev_text_ttsize", conf.rev_text_font.ttsize);
314    
315     debug_pfont("branch_font", conf.branch_font.gdfont);
316     debug_pstring("branch_ttfont", conf.branch_font.ttfont);
317     debug_pdouble("branch_ttsize", conf.branch_font.ttsize);
318 bertho 1.1 debug_pcolor("branch_color", &conf.branch_color);
319 bertho 1.2 debug_pfont("branch_tag_font", conf.branch_tag_font.gdfont);
320     debug_pstring("branch_tag_ttfont", conf.branch_tag_font.ttfont);
321     debug_pdouble("branch_tag_ttsize", conf.branch_tag_font.ttsize);
322     debug_pcolor("branch_tag_color", &conf.branch_tag_color);
323 bertho 1.1 debug_pcolor("branch_bgcolor", &conf.branch_bgcolor);
324     debug_pint("branch_lspace", conf.branch_lspace);
325     debug_pint("branch_rspace", conf.branch_rspace);
326     debug_pint("branch_tspace", conf.branch_tspace);
327     debug_pint("branch_bspace", conf.branch_bspace);
328     debug_pint("branch_connect", conf.branch_connect);
329     debug_pint("branch_margin", conf.branch_margin);
330     debug_pint("branch_dupbox", conf.branch_dupbox);
331    
332     debug_pstring("title", conf.title);
333     debug_pint("title_x", conf.title_x);
334     debug_pint("title_y", conf.title_y);
335 bertho 1.2 debug_pfont("title_font", conf.title_font.gdfont);
336     debug_pstring("title_ttfont", conf.title_font.ttfont);
337     debug_pdouble("title_ttsize", conf.title_font.ttsize);
338 bertho 1.1 debug_pint("title_align", conf.title_align);
339     debug_pcolor("title_color", &conf.title_color);
340    
341     debug_pint("margin_top", conf.margin_top);
342     debug_pint("margin_bottom", conf.margin_bottom);
343     debug_pint("margin_left", conf.margin_left);
344     debug_pint("margin_right", conf.margin_right);
345    
346     debug_pint("image_type", conf.image_type);
347     debug_pint("image_quality", conf.image_quality);
348    
349     debug_pstring("map_name", conf.map_name);
350     debug_pstring("map_branch_href", conf.map_branch_href);
351     debug_pstring("map_branch_alt", conf.map_branch_alt);
352     debug_pstring("map_rev_href", conf.map_rev_href);
353     debug_pstring("map_rev_alt", conf.map_rev_alt);
354     debug_pstring("map_diff_href", conf.map_diff_href);
355     debug_pstring("map_diff_alt", conf.map_diff_alt);
356    
357     debug_pstring("expand[0]", conf.expand[0]);
358     debug_pstring("expand[1]", conf.expand[1]);
359     debug_pstring("expand[2]", conf.expand[2]);
360     debug_pstring("expand[3]", conf.expand[3]);
361     debug_pstring("expand[4]", conf.expand[4]);
362     debug_pstring("expand[5]", conf.expand[5]);
363     debug_pstring("expand[6]", conf.expand[6]);
364     debug_pstring("expand[7]", conf.expand[7]);
365     debug_pstring("expand[8]", conf.expand[8]);
366     debug_pstring("expand[9]", conf.expand[9]);
367     }
368     #endif
369    
370     /*
371     **************************************************************************
372     * String collection routines
373     **************************************************************************
374     */
375     #define STRALLOCSIZE 128
376     static char *str;
377     static int nstr;
378     static int nastr;
379    
380     static void reset_str(void)
381     {
382     nstr = 0;
383     }
384    
385     static void add_str(int c)
386     {
387     if(nstr + 1 + 1 > nastr)
388     {
389     str = xrealloc(str, nastr+STRALLOCSIZE);
390     nastr += STRALLOCSIZE;
391     }
392     str[nstr++] = c;
393     }
394    
395     static char *get_str(void)
396     {
397     if(!str)
398     return xstrdup("");
399    
400     str[nstr] = '\0';
401     return xstrdup(str);
402     }
403    
404     /*
405     **************************************************************************
406     * Input routines
407     **************************************************************************
408     */
409     static char *buf = NULL;
410     static int bufsize = 0;
411     static int bufalloc = 0;
412     static int bufpos = 0;
413     static int bufunput = -1;
414     static FILE *buffp;
415    
416     static void set_input(FILE *fp, char *s)
417     {
418     assert((fp == NULL && s != NULL) || (fp != NULL && s == NULL));
419     buffp = fp;
420     bufsize = bufpos = 0;
421     if(s)
422     {
423     if(!buf)
424     {
425     bufalloc = 8192;
426     buf = xmalloc(bufalloc * sizeof(*buf));
427     }
428     bufsize = strlen(s);
429     assert(bufsize < bufalloc);
430     strcpy(buf, s);
431     }
432     }
433    
434     static int get_input(void)
435     {
436     if(bufunput != -1)
437     {
438     int c = bufunput;
439     bufunput = -1;
440     return c;
441     }
442    
443     if(bufpos < bufsize)
444     {
445     assert(buf != NULL);
446     retry_input:
447     return (int)((unsigned char)buf[bufpos++]);
448     }
449    
450     if(!buf)
451     {
452     bufalloc = 8192;
453     buf = xmalloc(bufalloc * sizeof(*buf));
454     bufsize = bufpos = 0;
455     }
456     if(buffp)
457     {
458     bufsize = fread(buf, 1, bufalloc, buffp);
459     bufpos = 0;
460     if(!bufsize)
461     return EOF;
462     goto retry_input;
463     }
464     return EOF;
465     }
466    
467     static void unget_input(int c)
468     {
469     bufunput = c;
470     }
471    
472     /*
473     **************************************************************************
474     * Lexical scanner
475     **************************************************************************
476     */
477     static int config_lex(void)
478     {
479     int ch;
480     while(1)
481     {
482     ch = get_input();
483     if(ch == '\n')
484     line_number++;
485    
486     if(isspace(ch))
487     continue;
488    
489     switch(ch)
490     {
491     case EOF:
492     case '=':
493     case ';':
494     return ch;
495    
496     case '#': /* Comment */
497     while((ch = get_input()) != '\n' && ch != EOF)
498     ;
499     if(ch != EOF)
500     unget_input(ch);
501     break;
502    
503     case '"':
504     reset_str();
505     while(1)
506     {
507     char c[4];
508     ch = get_input();
509     switch(ch)
510     {
511     case '\\': /* Start an escape sequence */
512     switch(ch = get_input())
513     {
514     default: /* This includes '\\', '"' and embedded newlines */
515     add_str(ch);
516     break;
517     case 'a': add_str('\a'); break;
518     case 'b': add_str('\b'); break;
519     case 'f': add_str('\f'); break;
520     case 'n': add_str('\n'); break;
521     case 'r': add_str('\r'); break;
522     case 't': add_str('\t'); break;
523     case 'v': add_str('\v'); break;
524     case 'x':
525     case 'X': /* Hex escape */
526     c[0] = get_input();
527     c[1] = get_input();
528     c[2] = '\0';
529 bertho 1.7 if(!isxdigit((int)(unsigned char)c[0]) || !isxdigit((int)(unsigned char)c[1]))
530 bertho 1.1 yyerror("Invalid hex escape");
531     add_str((int)strtol(c, NULL, 16));
532     break;
533     case '0':
534     case '1':
535     case '2': /* Octal escape */
536     c[0] = ch;
537     c[1] = c[2] = c[3] = '\0';
538     if((ch = get_input()) >= '0' && ch <= '7')
539     c[1] = ch;
540     else
541     unget_input(ch);
542     if((ch = get_input()) >= '0' && ch <= '7')
543     c[2] = ch;
544     else
545     unget_input(ch);
546     add_str((int)strtol(c, NULL, 8));
547     break;
548     case EOF:
549     yyerror("Unexpected EOF in escape");
550     break;
551     }
552     break;
553     case '"':
554     yylval.str = get_str();
555     return TYPE_STRING;
556     case '\n':
557     yyerror("Newline in string");
558     break;
559     case EOF:
560     yyerror("Unexpected EOF in string");
561     break;
562     default:
563     add_str(ch);
564     break;
565     }
566     }
567     break;
568    
569     default:
570     if(isalpha(ch) || ch == '_')
571     {
572     keyword_t skw;
573     keyword_t *kw;
574     /* Collect keyword */
575     reset_str();
576     add_str(ch);
577     while(1)
578     {
579     ch = get_input();
580 bertho 1.8 if(isalnum(ch) || ch == '_')
581 bertho 1.1 add_str(ch);
582     else
583     {
584     unget_input(ch);
585     break;
586     }
587     }
588     skw.keyword = get_str();
589     kw = bsearch(&skw, keywords, NKEYWORDS, sizeof(keywords[0]), cmp_kw);
590     if(!kw)
591     yyerror("Unknown keyword '%s'", skw.keyword);
592     xfree(skw.keyword);
593     if(kw->type == TYPE_VALUE)
594     {
595     yylval.i = kw->confref.val;
596     return TYPE_NUMBER;
597     }
598     yylval.kw = kw;
599     return TYPE_KEYWORD;
600     }
601     else if(isdigit(ch) || ch == '+' || ch == '-')
602     {
603     char *s;
604     char *eptr;
605 bertho 1.2 int type = TYPE_NUMBER;
606 bertho 1.1 /* Collect number */
607     reset_str();
608     add_str(ch);
609     while(1)
610     {
611     ch = get_input();
612 bertho 1.2 if(isxdigit(ch) || ch == 'x' || ch == 'X' || ch == '.') /* Not exact, but close enough */
613 bertho 1.1 add_str(ch);
614     else
615     {
616     unget_input(ch);
617     break;
618     }
619 bertho 1.2 if(ch == '.')
620     type = TYPE_DOUBLE;
621 bertho 1.1 }
622     s = get_str();
623 bertho 1.2 if(type == TYPE_DOUBLE)
624     {
625     yylval.d = strtod(s, &eptr);
626     if(*eptr)
627     yyerror("Invalid floating point number");
628     }
629     else
630     {
631     yylval.i = strtol(s, &eptr, 0);
632     if(*eptr)
633     yyerror("Invalid number");
634     }
635 bertho 1.1 xfree(s);
636 bertho 1.2 return type;
637 bertho 1.1 }
638     else
639     yyerror("Unmatched text '%c' (0x%02x)", isprint(ch) ? ch : ' ', ch);
640     break;
641     }
642     }
643     }
644    
645     static void set_color(color_t *c, char *s)
646     {
647     char *cptr;
648     if(*s != '#' || strlen(s) != 7)
649     {
650     colorerror:
651     yyerror("Invalid color value");
652     }
653     c->b = strtol(s+5, &cptr, 16);
654     if(*cptr)
655     goto colorerror;
656     s[5] = '\0';
657     c->g = strtol(s+3, &cptr, 16);
658     if(*cptr)
659     goto colorerror;
660     s[3] = '\0';
661     c->r = strtol(s+1, &cptr, 16);
662     if(*cptr)
663     goto colorerror;
664     }
665    
666     static gdFontPtr get_font(int id)
667     {
668     switch(id)
669     {
670     case 0: return gdFontTiny;
671     case 1: return gdFontSmall;
672     default:
673     case 2: return gdFontMediumBold;
674     case 3: return gdFontLarge;
675     case 4: return gdFontGiant;
676     }
677     }
678    
679     /*
680     **************************************************************************
681     * The config parser
682     * Grammar:
683     * file : <Empty>
684     * | lines
685     * ;
686     *
687     * lines : line
688     * | lines line
689     * ;
690     *
691     * line : <keyword> '=' <value> ';'
692     * | ';'
693     * ;
694     **************************************************************************
695     */
696     static void config_parse(void)
697     {
698     int state = 0;
699     int token;
700     int t;
701     keyword_t *kw = NULL;
702    
703     while(1)
704     {
705     token = config_lex();
706     if(token == EOF)
707     {
708     if(state)
709     yyerror("Unexpected EOF");
710     break;
711     }
712    
713     switch(state)
714     {
715     case 0:
716     if(token == TYPE_KEYWORD)
717     {
718     kw = yylval.kw;
719     state = 1;
720     }
721     else if(token != ';')
722     yyerror("Keyword expected");
723     break;
724     case 1:
725     if(token != '=')
726     yyerror("'=' expected");
727     state = 2;
728     break;
729     case 2:
730     if(kw->type == TYPE_FONT || kw->type == TYPE_BOOLEAN)
731     t = TYPE_NUMBER;
732     else if(kw->type == TYPE_COLOR)
733     t = TYPE_STRING;
734     else
735     t = kw->type;
736 bertho 1.2
737     if(token == TYPE_NUMBER && kw->type == TYPE_DOUBLE)
738     {
739     /* Auto promote numbers to doubles if required */
740     yylval.d = (double)yylval.i;
741     token = TYPE_DOUBLE;
742     }
743    
744 bertho 1.1 if(token != t)
745     {
746     char *e;
747     switch(kw->type)
748     {
749     case TYPE_STRING: e = "String"; break;
750     case TYPE_NUMBER: e = "Number"; break;
751     case TYPE_COLOR: e = "Color"; break;
752     case TYPE_FONT: e = "Font"; break;
753     case TYPE_BOOLEAN: e = "Boolean"; break;
754 bertho 1.2 case TYPE_DOUBLE: e = "Double"; break;
755 bertho 1.1 default: e = "Internal error: Unknown type"; break;
756     }
757     yyerror("%s expected", e);
758     }
759     #ifdef DEBUG
760     printf("processing: '%s'\n", kw->keyword);
761     #endif
762     switch(kw->type)
763     {
764     case TYPE_STRING:
765     *kw->confref.s = yylval.str;
766     break;
767     case TYPE_NUMBER:
768     *kw->confref.i = yylval.i;
769     break;
770     case TYPE_BOOLEAN:
771 bertho 1.3 if(yylval.i == -1)
772     *kw->confref.i = !*kw->confref.i;
773     else
774     *kw->confref.i = yylval.i != 0;
775 bertho 1.1 break;
776     case TYPE_COLOR:
777     set_color(kw->confref.c, yylval.str);
778     break;
779     case TYPE_FONT:
780 bertho 1.2 kw->confref.f->gdfont = get_font(yylval.i);
781     break;
782     case TYPE_DOUBLE:
783     *kw->confref.d = yylval.d;
784 bertho 1.1 break;
785     default:
786     yyerror("Internal error: Unknown type passed %d", kw->type);
787     break;
788     }
789     state = 3;
790     break;
791     case 3:
792     if(token != ';')
793     yyerror("';' expected");
794     state = 0;
795     break;
796     default:
797     yyerror("Internal error: invalid state %d", state);
798     break;
799     }
800     }
801     }
802    
803     /*
804     **************************************************************************
805     * Configuration
806     **************************************************************************
807     */
808     void stack_option(const char *opt)
809     {
810     stacked_opts = xrealloc(stacked_opts, sizeof(*stacked_opts) * (nstacked_opts + 1));
811     stacked_opts[nstacked_opts] = xmalloc(strlen(opt) + 2);
812     strcpy(stacked_opts[nstacked_opts], opt);
813     strcat(stacked_opts[nstacked_opts], ";");
814     nstacked_opts++;
815     #ifdef DEBUG
816     printf("stacking option: '%s'\n", stacked_opts[nstacked_opts-1]);
817     #endif
818     }
819    
820     void read_config(const char *path)
821     {
822     FILE *fp;
823    
824     /* Make sure we have them sorted for bsearch */
825     qsort(keywords, NKEYWORDS, sizeof(keywords[0]), cmp_kw);
826    
827     if(path)
828     {
829     if((fp = fopen(path, "r")) != NULL)
830     input_file = path;
831     }
832     else
833     {
834     if((fp = fopen("./" CONFFILENAME, "r")) == NULL)
835     {
836     if((fp = fopen(ETCDIR "/" CONFFILENAME, "r")) != NULL)
837     input_file = ETCDIR "/" CONFFILENAME;
838     }
839     else
840     input_file = "./" CONFFILENAME;
841     }
842    
843     if(fp)
844     {
845     line_number = 1;
846     set_input(fp, NULL);
847     config_parse();
848     fclose(fp);
849     input_file = NULL;
850     }
851    
852     if(nstacked_opts)
853     {
854     int i;
855     for(i = 0; i < nstacked_opts; i++)
856     {
857     line_number = 0;
858     set_input(NULL, stacked_opts[i]);
859     input_file = stacked_opts[i];
860     #ifdef DEBUG
861     printf("parsing stacked option: '%s'\n", stacked_opts[i]);
862     #endif
863     config_parse();
864     }
865     input_file = NULL;
866     }
867     #ifdef DEBUG
868     dump_config();
869     #endif
870     }
871    

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0