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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0