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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0