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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0