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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0