/[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.26 - (hide annotations)
Wed May 21 13:33:35 2008 UTC (9 years, 6 months ago) by bertho
Branch: MAIN
CVS Tags: REL_1_7_0, merge_automake_dev1_20080521, HEAD
Changes since 1.25: +19 -18 lines
File MIME type: text/plain
Merge automake into head
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 bertho 1.24 condstring_t *cs;
56 bertho 1.23 colorlist_t *cl;
57 bertho 1.26 int val;
58 bertho 1.1 } confref;
59     } keyword_t;
60    
61     typedef union {
62     keyword_t *kw;
63     int i;
64 bertho 1.2 double d;
65 bertho 1.1 char *str;
66     } YYSTYPE;
67    
68     static YYSTYPE yylval;
69    
70     static int nstacked_opts;
71     static char **stacked_opts;
72    
73     static keyword_t keywords[] = {
74     { "branch_bgcolor", TYPE_COLOR, { &conf.branch_bgcolor } },
75     { "branch_bspace", TYPE_NUMBER, { &conf.branch_bspace } },
76     { "branch_color", TYPE_COLOR, { &conf.branch_color } },
77 bertho 1.2 { "branch_font", TYPE_FONT, { &conf.branch_font.gdfont } },
78     { "branch_ttfont", TYPE_STRING, { &conf.branch_font.ttfont } },
79     { "branch_ttsize", TYPE_DOUBLE, { &conf.branch_font.ttsize } },
80     { "branch_tag_color", TYPE_COLOR, { &conf.branch_tag_color } },
81     { "branch_tag_font", TYPE_FONT, { &conf.branch_tag_font.gdfont } },
82     { "branch_tag_ttfont", TYPE_STRING, { &conf.branch_tag_font.ttfont } },
83     { "branch_tag_ttsize", TYPE_DOUBLE, { &conf.branch_tag_font.ttsize } },
84 bertho 1.1 { "branch_lspace", TYPE_NUMBER, { &conf.branch_lspace } },
85     { "branch_rspace", TYPE_NUMBER, { &conf.branch_rspace } },
86     { "branch_tspace", TYPE_NUMBER, { &conf.branch_tspace } },
87     { "branch_connect", TYPE_NUMBER, { &conf.branch_connect } },
88     { "branch_margin", TYPE_NUMBER, { &conf.branch_margin } },
89     { "branch_dupbox", TYPE_BOOLEAN, { &conf.branch_dupbox } },
90 bertho 1.10 { "branch_fold", TYPE_BOOLEAN, { &conf.branch_fold } },
91 bertho 1.11 { "branch_foldall", TYPE_BOOLEAN, { &conf.branch_foldall } },
92 bertho 1.18 { "branch_resort", TYPE_BOOLEAN, { &conf.branch_resort } },
93 bertho 1.16 { "branch_subtree", TYPE_STRING, { &conf.branch_subtree } },
94 bertho 1.1 { "upside_down", TYPE_BOOLEAN, { &conf.upside_down } },
95 bertho 1.5 { "left_right", TYPE_BOOLEAN, { &conf.left_right } },
96 bertho 1.2 { "auto_stretch", TYPE_BOOLEAN, { &conf.auto_stretch } },
97 bertho 1.1 { "color_bg", TYPE_COLOR, { &conf.color_bg } },
98 bertho 1.2 { "transparent_bg", TYPE_BOOLEAN, { &conf.transparent_bg } },
99 bertho 1.1 { "cvsmodule", TYPE_STRING, { &conf.cvsmodule } },
100     { "cvsroot", TYPE_STRING, { &conf.cvsroot } },
101     { "date_format", TYPE_STRING, { &conf.date_format } },
102     { "box_shadow", TYPE_BOOLEAN, { &conf.box_shadow } },
103     { "strip_untagged", TYPE_BOOLEAN, { &conf.strip_untagged } },
104     { "strip_first_rev", TYPE_BOOLEAN, { &conf.strip_first_rev } },
105 bertho 1.2 { "anti_alias", TYPE_BOOLEAN, { &conf.anti_alias } },
106     { "use_ttf", TYPE_BOOLEAN, { &conf.use_ttf } },
107 bertho 1.4 { "parse_logs", TYPE_BOOLEAN, { &conf.parse_logs } },
108 bertho 1.8 { "html_level", TYPE_NUMBER, { &conf.html_level } },
109 bertho 1.3 { "thick_lines", TYPE_NUMBER, { &conf.thick_lines } },
110 bertho 1.16 { "msg_color", TYPE_COLOR, { &conf.msg_color } },
111     { "msg_font", TYPE_FONT, { &conf.msg_font.gdfont } },
112     { "msg_ttfont", TYPE_STRING, { &conf.msg_font.ttfont } },
113     { "msg_ttsize", TYPE_DOUBLE, { &conf.msg_font.ttsize } },
114 bertho 1.17 { "rev_hidenumber", TYPE_BOOLEAN, { &conf.rev_hidenumber } },
115 bertho 1.1 { "rev_color", TYPE_COLOR, { &conf.rev_color } },
116     { "rev_bgcolor", TYPE_COLOR, { &conf.rev_bgcolor } },
117 bertho 1.2 { "rev_font", TYPE_FONT, { &conf.rev_font.gdfont } },
118     { "rev_ttfont", TYPE_STRING, { &conf.rev_font.ttfont } },
119     { "rev_ttsize", TYPE_DOUBLE, { &conf.rev_font.ttsize } },
120 bertho 1.1 { "rev_separator", TYPE_NUMBER, { &conf.rev_separator } },
121     { "rev_minline", TYPE_NUMBER, { &conf.rev_minline } },
122     { "rev_maxline", TYPE_NUMBER, { &conf.rev_maxline } },
123     { "rev_lspace", TYPE_NUMBER, { &conf.rev_lspace } },
124     { "rev_rspace", TYPE_NUMBER, { &conf.rev_rspace } },
125     { "rev_tspace", TYPE_NUMBER, { &conf.rev_tspace } },
126     { "rev_bspace", TYPE_NUMBER, { &conf.rev_bspace } },
127 bertho 1.24 { "rev_text", TYPE_CSTRING, { &conf.rev_text } },
128     { "rev_idtext", TYPE_CSTRING, { &conf.rev_idtext } },
129 bertho 1.1 { "rev_text_color", TYPE_COLOR, { &conf.rev_text_color } },
130 bertho 1.2 { "rev_text_font", TYPE_FONT, { &conf.rev_text_font.gdfont } },
131     { "rev_text_ttfont", TYPE_STRING, { &conf.rev_text_font.ttfont } },
132     { "rev_text_ttsize", TYPE_DOUBLE, { &conf.rev_text_font.ttsize } },
133 bertho 1.6 { "rev_maxtags", TYPE_NUMBER, { &conf.rev_maxtags } },
134 bertho 1.23 { "merge_color", TYPE_COLORLIST, { &conf.merge_color } },
135     { "merge_from", TYPE_STRINGLIST, { &conf.merge_from } },
136     { "merge_to", TYPE_STRINGLIST, { &conf.merge_to } },
137 bertho 1.17 { "merge_findall", TYPE_BOOLEAN, { &conf.merge_findall } },
138 bertho 1.9 { "merge_front", TYPE_BOOLEAN, { &conf.merge_front } },
139     { "merge_nocase", TYPE_BOOLEAN, { &conf.merge_nocase } },
140 bertho 1.12 { "merge_arrows", TYPE_BOOLEAN, { &conf.merge_arrows } },
141 bertho 1.19 { "merge_cvsnt", TYPE_BOOLEAN, { &conf.merge_cvsnt } },
142     { "merge_cvsnt_color", TYPE_COLOR, { &conf.merge_cvsnt_color } },
143 bertho 1.25 { "merge_on_tag", TYPE_BOOLEAN, { &conf.merge_on_tag } },
144 bertho 1.12 { "arrow_width", TYPE_NUMBER, { &conf.arrow_width } },
145     { "arrow_length", TYPE_NUMBER, { &conf.arrow_length } },
146 bertho 1.1 { "tag_color", TYPE_COLOR, { &conf.tag_color } },
147 bertho 1.2 { "tag_font", TYPE_FONT, { &conf.tag_font.gdfont } },
148     { "tag_ttfont", TYPE_STRING, { &conf.tag_font.ttfont } },
149     { "tag_ttsize", TYPE_DOUBLE, { &conf.tag_font.ttsize } },
150 bertho 1.14 { "tag_ignore", TYPE_STRING, { &conf.tag_ignore } },
151 bertho 1.17 { "tag_ignore_merge", TYPE_BOOLEAN, { &conf.tag_ignore_merge } },
152 bertho 1.14 { "tag_nocase", TYPE_BOOLEAN, { &conf.tag_nocase } },
153 bertho 1.15 { "tag_negate", TYPE_BOOLEAN, { &conf.tag_negate } },
154 bertho 1.1 { "title", TYPE_STRING, { &conf.title } },
155     { "title_x", TYPE_NUMBER, { &conf.title_x } },
156     { "title_y", TYPE_NUMBER, { &conf.title_y } },
157 bertho 1.2 { "title_font", TYPE_FONT, { &conf.title_font.gdfont } },
158     { "title_ttfont", TYPE_STRING, { &conf.title_font.ttfont } },
159     { "title_ttsize", TYPE_DOUBLE, { &conf.title_font.ttsize } },
160 bertho 1.1 { "title_align", TYPE_NUMBER, { &conf.title_align } },
161     { "title_color", TYPE_COLOR, { &conf.title_color } },
162     { "margin_top", TYPE_NUMBER, { &conf.margin_top } },
163     { "margin_bottom", TYPE_NUMBER, { &conf.margin_bottom } },
164     { "margin_left", TYPE_NUMBER, { &conf.margin_left } },
165     { "margin_right", TYPE_NUMBER, { &conf.margin_right } },
166     { "image_type", TYPE_NUMBER, { &conf.image_type } },
167     { "image_quality", TYPE_NUMBER, { &conf.image_quality } },
168 bertho 1.20 { "image_compress", TYPE_NUMBER, { &conf.image_compress } },
169     { "image_interlace", TYPE_BOOLEAN, { &conf.image_interlace } },
170 bertho 1.1 { "map_name", TYPE_STRING, { &conf.map_name } },
171     { "map_branch_href", TYPE_STRING, { &conf.map_branch_href } },
172     { "map_branch_alt", TYPE_STRING, { &conf.map_branch_alt } },
173     { "map_rev_href", TYPE_STRING, { &conf.map_rev_href } },
174     { "map_rev_alt", TYPE_STRING, { &conf.map_rev_alt } },
175     { "map_diff_href", TYPE_STRING, { &conf.map_diff_href } },
176     { "map_diff_alt", TYPE_STRING, { &conf.map_diff_alt } },
177 bertho 1.16 { "map_merge_href", TYPE_STRING, { &conf.map_merge_href } },
178     { "map_merge_alt", TYPE_STRING, { &conf.map_merge_alt } },
179 bertho 1.26 { "jpeg", TYPE_VALUE, { val: IMAGE_JPEG } },
180     { "png", TYPE_VALUE, { val: IMAGE_PNG } },
181     { "gif", TYPE_VALUE, { val: IMAGE_GIF } },
182     { "true", TYPE_VALUE, { val: 1 } },
183     { "false", TYPE_VALUE, { val: 0 } },
184     { "not", TYPE_VALUE, { val: -1 } },
185     { "left", TYPE_VALUE, { val: 0 } },
186     { "center", TYPE_VALUE, { val: 1 } },
187     { "right", TYPE_VALUE, { val: 2 } },
188     { "tiny", TYPE_VALUE, { val: 0 } },
189     { "small", TYPE_VALUE, { val: 1 } },
190     { "medium", TYPE_VALUE, { val: 2 } },
191     { "large", TYPE_VALUE, { val: 3 } },
192     { "giant", TYPE_VALUE, { val: 4 } },
193     { "HTML3", TYPE_VALUE, { val: 1 } },
194     { "HTML4", TYPE_VALUE, { val: 2 } },
195     { "XHTML", TYPE_VALUE, { val: 3 } },
196 bertho 1.1 };
197    
198     #define NKEYWORDS (sizeof(keywords) / sizeof(keywords[0]))
199    
200     static int cmp_kw(const void *k1, const void *k2)
201     {
202     return strcmp(((keyword_t *)k1)->keyword, ((keyword_t *)k2)->keyword);
203     }
204    
205     /*
206     **************************************************************************
207     * Debug routines
208     **************************************************************************
209     */
210     #ifdef DEBUG
211     #define DEBUGSTREAM stdout
212     static void debug_pname(const char *n)
213     {
214     fprintf(DEBUGSTREAM, "%-16s: ", n);
215     }
216    
217     static void debug_pstring(const char *n, const char *a)
218     {
219     debug_pname(n);
220     if(!a)
221     fprintf(DEBUGSTREAM, "<not-set>\n");
222     else
223     {
224     fputc('\'', DEBUGSTREAM);
225     for(; *a; a++)
226     {
227     if(isprint(*a))
228     fputc(*a, DEBUGSTREAM);
229     else
230     {
231     fputc('\\', DEBUGSTREAM);
232     switch(*a)
233     {
234     case '\a': fputc('a', DEBUGSTREAM); break;
235     case '\b': fputc('b', DEBUGSTREAM); break;
236     case '\f': fputc('f', DEBUGSTREAM); break;
237     case '\n': fputc('n', DEBUGSTREAM); break;
238     case '\r': fputc('r', DEBUGSTREAM); break;
239     case '\t': fputc('t', DEBUGSTREAM); break;
240     case '\v': fputc('v', DEBUGSTREAM); break;
241     default:
242     fprintf(DEBUGSTREAM, "x%02x", (unsigned char)*a);
243     }
244     }
245     }
246     fprintf(DEBUGSTREAM, "'\n");
247     }
248     }
249    
250     static void debug_pbool(const char *n, int b)
251     {
252     debug_pname(n);
253     fprintf(DEBUGSTREAM, "%s\n", b ? "true" : "false");
254     }
255    
256     static void debug_pint(const char *n, int i)
257     {
258     debug_pname(n);
259     fprintf(DEBUGSTREAM, "%i\n", i);
260     }
261    
262 bertho 1.2 static void debug_pdouble(const char *n, double d)
263     {
264     debug_pname(n);
265     fprintf(DEBUGSTREAM, "%g\n", d);
266     }
267    
268     static void debug_pfont(const char *n, gdFontPtr f)
269 bertho 1.1 {
270     const char *s = "<Unknown font>";
271     debug_pname(n);
272     if(f == gdFontTiny)
273     s = "gdFontTiny";
274     else if(f == gdFontSmall)
275     s = "gdFontSmall";
276     else if(f == gdFontMediumBold)
277     s = "gdFontMediumBold";
278     else if(f == gdFontLarge)
279     s = "gdFontLarge";
280     else if(f == gdFontGiant)
281     s = "gdFontGiant";
282     fprintf(DEBUGSTREAM, "%s\n", s);
283     }
284    
285 bertho 1.24 static char *debug_op[] = { "=~", "=*", "!~", "!*", "==", "!_", ">=", ">", "<=", "<" };
286    
287     static void debug_pcolornode(node_t *n)
288     {
289     if(!n)
290     return;
291     if(n->op == TYPE_STRING)
292     fprintf(DEBUGSTREAM, "%s ", n->value.str);
293     else if(n->op == TYPE_COLOR)
294     fprintf(DEBUGSTREAM, "#%02x%02x%02x ", n->value.clr.r, n->value.clr.g, n->value.clr.b);
295     else
296     {
297     char *key;
298     fprintf(DEBUGSTREAM, "[ ");
299     switch(n->key)
300     {
301     case KEY_STATE: key = "state"; break;
302     case KEY_AUTHOR: key = "author"; break;
303     case KEY_TAG: key = "tag"; break;
304     case KEY_DATE: key = "date"; break;
305     case KEY_REV: key = "rev"; break;
306     case KEY_UNKNOWN: key = "unknown"; break;
307     default: key = "<undefined>"; break;
308     }
309     fprintf(DEBUGSTREAM, "%s ", key);
310     if(n->op > OP_FIRST && n->op < OP_LAST)
311     fprintf(DEBUGSTREAM, "%s ", debug_op[n->op - OP_FIRST - 1]);
312     else
313     fprintf(DEBUGSTREAM, "op(-?-) ");
314     fprintf(DEBUGSTREAM, "%s ", n->content);
315     debug_pcolornode(n->tcase);
316     debug_pcolornode(n->fcase);
317     fprintf(DEBUGSTREAM, "]");
318     }
319     }
320    
321 bertho 1.1 static void debug_pcolor(const char *n, color_t *c)
322     {
323     debug_pname(n);
324 bertho 1.24 if(c->node)
325     {
326     debug_pcolornode(c->node);
327     fprintf(DEBUGSTREAM, "\n");
328     }
329     else
330     fprintf(DEBUGSTREAM, "#%02x%02x%02x\n", c->r, c->g, c->b);
331     }
332    
333     static void debug_pcolorlist(const char *n, colorlist_t *cl)
334     {
335     int i;
336     char buf[128];
337     for(i = 0; i < cl->n; i++)
338     {
339     sprintf(buf, "%s{%d}", n, i);
340     debug_pcolor(buf, &cl->clrs[i]);
341     }
342     }
343    
344     static void debug_pstringlist(const char *n, stringlist_t *sl)
345     {
346     int i;
347     char buf[128];
348     for(i = 0; i < sl->n; i++)
349     {
350     sprintf(buf, "%s{%d}", n, i);
351     debug_pstring(buf, sl->strs[i]);
352     }
353 bertho 1.1 }
354    
355     void dump_config(void)
356     {
357     debug_pstring("cvsroot", conf.cvsroot);
358     debug_pstring("cvsmodule", conf.cvsmodule);
359     debug_pstring("date_format", conf.date_format);
360    
361     debug_pcolor("color_bg", &conf.color_bg);
362     debug_pbool("box_shadow", conf.box_shadow);
363     debug_pbool("upside_down", conf.upside_down);
364 bertho 1.5 debug_pbool("left_right", conf.left_right);
365 bertho 1.1 debug_pbool("strip_untagged", conf.strip_untagged);
366     debug_pbool("strip_first_rev", conf.strip_first_rev);
367 bertho 1.3 debug_pbool("auto_stretch", conf.auto_stretch);
368     debug_pbool("anti_alias", conf.anti_alias);
369     debug_pbool("use_ttf", conf.use_ttf);
370     debug_pint("thick_lines", conf.thick_lines);
371 bertho 1.24 debug_pint("html_level", conf.html_level);
372     debug_pbool("parse_logs", conf.parse_logs);
373     debug_pbool("transparent_bg", conf.transparent_bg);
374    
375     debug_pint("arrow_length", conf.arrow_length);
376     debug_pint("arrow_width", conf.arrow_width);
377    
378     debug_pbool("merge_arrows", conf.merge_arrows);
379     debug_pcolor("merge_cvsnt_color", &conf.merge_cvsnt_color);
380     debug_pbool("merge_cvsnt", conf.merge_cvsnt);
381     debug_pbool("merge_findall", conf.merge_findall);
382     debug_pcolorlist("merge_color", &conf.merge_color);
383     debug_pstringlist("merge_from", &conf.merge_from);
384     debug_pstringlist("merge_to", &conf.merge_to);
385     debug_pbool("merge_front", conf.merge_front);
386     debug_pbool("merge_nocase", conf.merge_nocase);
387 bertho 1.26 debug_pbool("merge_on_tag", conf.merge_on_tag);
388 bertho 1.24
389     debug_pcolor("msg_color", &conf.msg_color);
390     debug_pfont("msg_font", conf.msg_font.gdfont);
391     debug_pstring("msg_ttfont", conf.msg_font.ttfont);
392     debug_pdouble("msg_ttsize", conf.msg_font.ttsize);
393 bertho 1.1
394 bertho 1.2 debug_pfont("tag_font", conf.tag_font.gdfont);
395     debug_pstring("tag_ttfont", conf.tag_font.ttfont);
396 bertho 1.24 debug_pdouble("tag_ttsize", conf.tag_font.ttsize);
397 bertho 1.1 debug_pcolor("tag_color", &conf.tag_color);
398 bertho 1.24 debug_pbool("tag_ignore_merge", conf.tag_ignore_merge);
399     debug_pstring("tag_ignore", conf.tag_ignore);
400     debug_pbool("tag_negate", conf.tag_negate);
401     debug_pbool("tag_nocase", conf.tag_nocase);
402 bertho 1.1
403 bertho 1.2 debug_pfont("rev_font", conf.rev_font.gdfont);
404     debug_pstring("rev_ttfont", conf.rev_font.ttfont);
405     debug_pdouble("rev_ttsize", conf.rev_font.ttsize);
406 bertho 1.1 debug_pcolor("rev_color", &conf.rev_color);
407     debug_pcolor("rev_bgcolor", &conf.rev_bgcolor);
408     debug_pint("rev_separator", conf.rev_separator);
409     debug_pint("rev_minline", conf.rev_minline);
410     debug_pint("rev_maxline", conf.rev_maxline);
411 bertho 1.24 debug_pint("rev_maxtags", conf.rev_maxtags);
412 bertho 1.1 debug_pint("rev_lspace", conf.rev_lspace);
413     debug_pint("rev_rspace", conf.rev_rspace);
414     debug_pint("rev_tspace", conf.rev_tspace);
415     debug_pint("rev_bspace", conf.rev_bspace);
416 bertho 1.24 debug_pcstring("rev_text", conf.rev_text);
417 bertho 1.1 debug_pcolor("rev_text_color", &conf.rev_text_color);
418 bertho 1.2 debug_pfont("rev_text_font", conf.rev_text_font.gdfont);
419     debug_pstring("rev_text_ttfont", conf.rev_text_font.ttfont);
420     debug_pdouble("rev_text_ttsize", conf.rev_text_font.ttsize);
421 bertho 1.24 debug_pbool("rev_hidenumber", conf.rev_hidenumber);
422 bertho 1.2
423     debug_pfont("branch_font", conf.branch_font.gdfont);
424     debug_pstring("branch_ttfont", conf.branch_font.ttfont);
425     debug_pdouble("branch_ttsize", conf.branch_font.ttsize);
426 bertho 1.1 debug_pcolor("branch_color", &conf.branch_color);
427 bertho 1.2 debug_pfont("branch_tag_font", conf.branch_tag_font.gdfont);
428     debug_pstring("branch_tag_ttfont", conf.branch_tag_font.ttfont);
429     debug_pdouble("branch_tag_ttsize", conf.branch_tag_font.ttsize);
430     debug_pcolor("branch_tag_color", &conf.branch_tag_color);
431 bertho 1.1 debug_pcolor("branch_bgcolor", &conf.branch_bgcolor);
432     debug_pint("branch_lspace", conf.branch_lspace);
433     debug_pint("branch_rspace", conf.branch_rspace);
434     debug_pint("branch_tspace", conf.branch_tspace);
435     debug_pint("branch_bspace", conf.branch_bspace);
436     debug_pint("branch_connect", conf.branch_connect);
437     debug_pint("branch_margin", conf.branch_margin);
438     debug_pint("branch_dupbox", conf.branch_dupbox);
439 bertho 1.24 debug_pbool("branch_fold", conf.branch_fold);
440     debug_pbool("branch_foldall", conf.branch_foldall);
441     debug_pbool("branch_resort", conf.branch_resort);
442     debug_pstring("branch_subtree", conf.branch_subtree);
443 bertho 1.1
444     debug_pstring("title", conf.title);
445     debug_pint("title_x", conf.title_x);
446     debug_pint("title_y", conf.title_y);
447 bertho 1.2 debug_pfont("title_font", conf.title_font.gdfont);
448     debug_pstring("title_ttfont", conf.title_font.ttfont);
449     debug_pdouble("title_ttsize", conf.title_font.ttsize);
450 bertho 1.1 debug_pint("title_align", conf.title_align);
451     debug_pcolor("title_color", &conf.title_color);
452    
453     debug_pint("margin_top", conf.margin_top);
454     debug_pint("margin_bottom", conf.margin_bottom);
455     debug_pint("margin_left", conf.margin_left);
456     debug_pint("margin_right", conf.margin_right);
457    
458     debug_pint("image_type", conf.image_type);
459     debug_pint("image_quality", conf.image_quality);
460 bertho 1.24 debug_pint("image_compress", conf.image_compress);
461     debug_pbool("image_interlace", conf.image_interlace);
462 bertho 1.1
463     debug_pstring("map_name", conf.map_name);
464     debug_pstring("map_branch_href", conf.map_branch_href);
465     debug_pstring("map_branch_alt", conf.map_branch_alt);
466     debug_pstring("map_rev_href", conf.map_rev_href);
467     debug_pstring("map_rev_alt", conf.map_rev_alt);
468     debug_pstring("map_diff_href", conf.map_diff_href);
469     debug_pstring("map_diff_alt", conf.map_diff_alt);
470 bertho 1.24 debug_pstring("map_merge_href", conf.map_merge_href);
471     debug_pstring("map_merge_alt", conf.map_merge_alt);
472 bertho 1.1
473     debug_pstring("expand[0]", conf.expand[0]);
474     debug_pstring("expand[1]", conf.expand[1]);
475     debug_pstring("expand[2]", conf.expand[2]);
476     debug_pstring("expand[3]", conf.expand[3]);
477     debug_pstring("expand[4]", conf.expand[4]);
478     debug_pstring("expand[5]", conf.expand[5]);
479     debug_pstring("expand[6]", conf.expand[6]);
480     debug_pstring("expand[7]", conf.expand[7]);
481     debug_pstring("expand[8]", conf.expand[8]);
482     debug_pstring("expand[9]", conf.expand[9]);
483     }
484     #endif
485    
486     /*
487     **************************************************************************
488     * String collection routines
489     **************************************************************************
490     */
491     #define STRALLOCSIZE 128
492     static char *str;
493     static int nstr;
494     static int nastr;
495    
496     static void reset_str(void)
497     {
498     nstr = 0;
499     }
500    
501     static void add_str(int c)
502     {
503     if(nstr + 1 + 1 > nastr)
504     {
505     str = xrealloc(str, nastr+STRALLOCSIZE);
506     nastr += STRALLOCSIZE;
507     }
508     str[nstr++] = c;
509     }
510    
511     static char *get_str(void)
512     {
513     if(!str)
514     return xstrdup("");
515    
516     str[nstr] = '\0';
517     return xstrdup(str);
518     }
519    
520     /*
521     **************************************************************************
522     * Input routines
523     **************************************************************************
524     */
525     static char *buf = NULL;
526     static int bufsize = 0;
527     static int bufalloc = 0;
528     static int bufpos = 0;
529     static int bufunput = -1;
530     static FILE *buffp;
531    
532     static void set_input(FILE *fp, char *s)
533     {
534     assert((fp == NULL && s != NULL) || (fp != NULL && s == NULL));
535     buffp = fp;
536     bufsize = bufpos = 0;
537     if(s)
538     {
539     if(!buf)
540     {
541     bufalloc = 8192;
542     buf = xmalloc(bufalloc * sizeof(*buf));
543     }
544     bufsize = strlen(s);
545     assert(bufsize < bufalloc);
546     strcpy(buf, s);
547     }
548     }
549    
550     static int get_input(void)
551     {
552     if(bufunput != -1)
553     {
554     int c = bufunput;
555     bufunput = -1;
556     return c;
557     }
558    
559     if(bufpos < bufsize)
560     {
561     assert(buf != NULL);
562     retry_input:
563     return (int)((unsigned char)buf[bufpos++]);
564     }
565    
566     if(!buf)
567     {
568     bufalloc = 8192;
569     buf = xmalloc(bufalloc * sizeof(*buf));
570     bufsize = bufpos = 0;
571     }
572     if(buffp)
573     {
574     bufsize = fread(buf, 1, bufalloc, buffp);
575     bufpos = 0;
576     if(!bufsize)
577     return EOF;
578     goto retry_input;
579     }
580     return EOF;
581     }
582    
583     static void unget_input(int c)
584     {
585     bufunput = c;
586     }
587    
588     /*
589     **************************************************************************
590     * Lexical scanner
591     **************************************************************************
592     */
593     static int config_lex(void)
594     {
595     int ch;
596     while(1)
597     {
598     ch = get_input();
599     if(ch == '\n')
600     line_number++;
601    
602     if(isspace(ch))
603     continue;
604    
605     switch(ch)
606     {
607 bertho 1.24 case '=':
608     ch = get_input();
609     switch(ch)
610     {
611     case '~': return OP_CONTAINED;
612     case '*': return OP_CONTAINEDI;
613     case '=': return OP_EQ;
614     default:
615     unget_input(ch);
616     return '=';
617     }
618     break;
619    
620     case '!':
621     ch = get_input();
622     switch(ch)
623     {
624     case '~': return OP_NCONTAINED;
625     case '*': return OP_NCONTAINEDI;
626     case '=': return OP_NE;
627     default:
628     stack_msg(MSG_ERR, "config: %d: Invalid operator", line_number);
629     unget_input(ch);
630     return '!';
631     }
632     break;
633    
634     case '>':
635     ch = get_input();
636     if(ch == '=')
637     return OP_GE;
638     unget_input(ch);
639     return OP_GT;
640    
641     case '<':
642     ch = get_input();
643     if(ch == '=')
644     return OP_LE;
645     unget_input(ch);
646     return OP_LT;
647    
648 bertho 1.1 case EOF:
649     case ';':
650 bertho 1.24 case '[':
651     case ']':
652 bertho 1.1 return ch;
653    
654     case '#': /* Comment */
655     while((ch = get_input()) != '\n' && ch != EOF)
656     ;
657     if(ch != EOF)
658     unget_input(ch);
659     break;
660    
661     case '"':
662     reset_str();
663     while(1)
664     {
665     char c[4];
666     ch = get_input();
667     switch(ch)
668     {
669     case '\\': /* Start an escape sequence */
670     switch(ch = get_input())
671     {
672     default: /* This includes '\\', '"' and embedded newlines */
673     add_str(ch);
674     break;
675     case 'a': add_str('\a'); break;
676     case 'b': add_str('\b'); break;
677     case 'f': add_str('\f'); break;
678     case 'n': add_str('\n'); break;
679     case 'r': add_str('\r'); break;
680     case 't': add_str('\t'); break;
681     case 'v': add_str('\v'); break;
682     case 'x':
683     case 'X': /* Hex escape */
684     c[0] = get_input();
685     c[1] = get_input();
686     c[2] = '\0';
687 bertho 1.7 if(!isxdigit((int)(unsigned char)c[0]) || !isxdigit((int)(unsigned char)c[1]))
688 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Invalid hex escape", line_number);
689 bertho 1.1 add_str((int)strtol(c, NULL, 16));
690     break;
691     case '0':
692     case '1':
693     case '2': /* Octal escape */
694     c[0] = ch;
695     c[1] = c[2] = c[3] = '\0';
696     if((ch = get_input()) >= '0' && ch <= '7')
697     c[1] = ch;
698     else
699     unget_input(ch);
700     if((ch = get_input()) >= '0' && ch <= '7')
701     c[2] = ch;
702     else
703     unget_input(ch);
704     add_str((int)strtol(c, NULL, 8));
705     break;
706     case EOF:
707 bertho 1.17 yyerror("Unexpected EOF in escape");
708     break;
709 bertho 1.1 }
710     break;
711     case '"':
712     yylval.str = get_str();
713     return TYPE_STRING;
714     case '\n':
715     yyerror("Newline in string");
716     break;
717     case EOF:
718     yyerror("Unexpected EOF in string");
719     break;
720     default:
721     add_str(ch);
722     break;
723     }
724     }
725     break;
726    
727     default:
728     if(isalpha(ch) || ch == '_')
729     {
730     keyword_t skw;
731     keyword_t *kw;
732     /* Collect keyword */
733     reset_str();
734     add_str(ch);
735     while(1)
736     {
737     ch = get_input();
738 bertho 1.8 if(isalnum(ch) || ch == '_')
739 bertho 1.1 add_str(ch);
740     else
741     {
742     unget_input(ch);
743     break;
744     }
745     }
746     skw.keyword = get_str();
747     kw = bsearch(&skw, keywords, NKEYWORDS, sizeof(keywords[0]), cmp_kw);
748     if(!kw)
749 bertho 1.16 {
750     stack_msg(MSG_ERR, "config: %d: Unknown keyword '%s'", line_number, skw.keyword);
751     yylval.kw = NULL;
752     return TYPE_KEYWORD;
753     }
754 bertho 1.21 xfree((void *)skw.keyword);
755 bertho 1.1 if(kw->type == TYPE_VALUE)
756     {
757 bertho 1.13 yylval.i = (int)kw->confref.val;
758 bertho 1.1 return TYPE_NUMBER;
759     }
760     yylval.kw = kw;
761     return TYPE_KEYWORD;
762     }
763     else if(isdigit(ch) || ch == '+' || ch == '-')
764     {
765     char *s;
766     char *eptr;
767 bertho 1.2 int type = TYPE_NUMBER;
768 bertho 1.1 /* Collect number */
769     reset_str();
770     add_str(ch);
771     while(1)
772     {
773     ch = get_input();
774 bertho 1.2 if(isxdigit(ch) || ch == 'x' || ch == 'X' || ch == '.') /* Not exact, but close enough */
775 bertho 1.1 add_str(ch);
776     else
777     {
778     unget_input(ch);
779     break;
780     }
781 bertho 1.2 if(ch == '.')
782     type = TYPE_DOUBLE;
783 bertho 1.1 }
784     s = get_str();
785 bertho 1.2 if(type == TYPE_DOUBLE)
786     {
787     yylval.d = strtod(s, &eptr);
788     if(*eptr)
789 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Invalid floating point number", line_number);
790 bertho 1.2 }
791     else
792     {
793     yylval.i = strtol(s, &eptr, 0);
794     if(*eptr)
795 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Invalid number", line_number);
796 bertho 1.2 }
797 bertho 1.1 xfree(s);
798 bertho 1.2 return type;
799 bertho 1.1 }
800     else
801     yyerror("Unmatched text '%c' (0x%02x)", isprint(ch) ? ch : ' ', ch);
802     break;
803     }
804     }
805     }
806    
807     static void set_color(color_t *c, char *s)
808     {
809     char *cptr;
810 bertho 1.24 c->node = NULL;
811 bertho 1.1 if(*s != '#' || strlen(s) != 7)
812     {
813     colorerror:
814 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Invalid color value '%s'", line_number, s);
815     return;
816 bertho 1.1 }
817     c->b = strtol(s+5, &cptr, 16);
818     if(*cptr)
819     goto colorerror;
820     s[5] = '\0';
821     c->g = strtol(s+3, &cptr, 16);
822     if(*cptr)
823     goto colorerror;
824     s[3] = '\0';
825     c->r = strtol(s+1, &cptr, 16);
826     if(*cptr)
827     goto colorerror;
828     }
829    
830     static gdFontPtr get_font(int id)
831     {
832     switch(id)
833     {
834     case 0: return gdFontTiny;
835     case 1: return gdFontSmall;
836     default:
837     case 2: return gdFontMediumBold;
838     case 3: return gdFontLarge;
839     case 4: return gdFontGiant;
840     }
841     }
842    
843     /*
844     **************************************************************************
845     * The config parser
846     * Grammar:
847     * file : <Empty>
848     * | lines
849     * ;
850     *
851     * lines : line
852     * | lines line
853     * ;
854     *
855     * line : <keyword> '=' <value> ';'
856 bertho 1.24 * | <keyword> '=' expr ';'
857 bertho 1.1 * | ';'
858 bertho 1.24 *
859     * expr : '[' <kw> <op> <value> expr expr ']'
860     * | <value>
861 bertho 1.1 * ;
862     **************************************************************************
863     */
864 bertho 1.24 static int skip_to_semicolon(int state)
865     {
866     int token;
867     while(1)
868     {
869     token = config_lex();
870     if(token == ';')
871     return 0;
872     else if(token == EOF)
873     return state;
874     }
875     }
876    
877     static node_t *new_node(char *val)
878     {
879     node_t *n = xmalloc(sizeof(*n));
880     if(!strcmp(val, "state"))
881     n->key = KEY_STATE;
882     else if(!strcmp(val, "author"))
883     n->key = KEY_AUTHOR;
884     else if(!strcmp(val, "tag"))
885     n->key = KEY_TAG;
886     else if(!strcmp(val, "date"))
887     n->key = KEY_DATE;
888     else if(!strcmp(val, "rev"))
889     n->key = KEY_REV;
890     else
891     {
892     n->key = KEY_UNKNOWN;
893     stack_msg(MSG_ERR, "config: %d: Unknown key '%s'", line_number, val);
894     }
895     return n;
896     }
897    
898     typedef struct __statestack_t
899     {
900     int state;
901     node_t *node;
902     } statestack_t;
903    
904     static int nstatestack = 0;
905     static int nastatestack;
906     static statestack_t *statestack = NULL;
907    
908     static void push_state(node_t *node, int state)
909     {
910     if(!statestack)
911     {
912     statestack = xmalloc(4 * sizeof(*statestack));
913     nastatestack = 4;
914     nstatestack = 0;
915     }
916     else if(nstatestack >= nastatestack)
917     {
918     nastatestack *= 2;
919     statestack = xrealloc(statestack, nastatestack * sizeof(*statestack));
920     }
921     statestack[nstatestack].node = node;
922     statestack[nstatestack].state = state;
923     nstatestack++;
924     }
925    
926     static int pop_state(node_t **node, int *state)
927     {
928     if(nstatestack <= 0)
929     {
930     *state = 3;
931     return 0;
932     }
933     assert(*node != NULL);
934     if(statestack[nstatestack-1].state == 8)
935     statestack[nstatestack-1].node->tcase = *node;
936     else if(statestack[nstatestack-1].state == 9)
937     statestack[nstatestack-1].node->fcase = *node;
938     *state = statestack[nstatestack-1].state;
939     *node = statestack[nstatestack-1].node;
940     return nstatestack--;
941     }
942    
943     /* YYYY.MM.DD.hh.mm.ss */
944     /* 0123456789012345678 */
945     /* 111111111 */
946     static char *fixup_date(const char *str)
947     {
948     int i;
949     int y=1970, m=1, d=1, h=0, mi=0, s=0;
950     int l = strlen(str);
951     char date[6*16]; /* Should be wildly enough to hold 19 chars from 6 numbers with all possible errors */
952     if(l < 4 || l > 19)
953     {
954     date_err:
955     stack_msg(MSG_ERR, "config: %d: Invalid date string '%s'", line_number, str);
956     return "1970.01.01.00.00.00";
957     }
958     for(i = 0; i < l; i++)
959     {
960     if(!strchr("0123456789.", str[i]))
961     goto date_err;
962     }
963     i = sscanf(str, "%d.%d.%d.%d.%d.%d", &y, &m, &d, &h, &mi, &s);
964     if(i == EOF || i < 0 || i > 6)
965     goto date_err;
966     if(i >= 1 && (y < 1970 || y > 2037))
967     goto date_err;
968     if(i >= 2 && (m < 1 || m > 12))
969     goto date_err;
970     if(i >= 3 && (d < 1 || d > 31))
971     goto date_err;
972     if(i >= 4 && (h < 0 || h > 23))
973     goto date_err;
974     if(i >= 5 && (mi < 0 || mi > 59))
975     goto date_err;
976     if(i >= 6 && (s < 0 || s > 59))
977     goto date_err;
978     sprintf(date, "%04d.%02d.%02d.%02d.%02d.%02d", y, m, d, h, mi, s);
979     return strdup(date);
980     }
981    
982 bertho 1.1 static void config_parse(void)
983     {
984     int state = 0;
985     int token;
986     int t;
987     keyword_t *kw = NULL;
988 bertho 1.24 node_t *node = NULL;
989 bertho 1.1
990     while(1)
991     {
992     token = config_lex();
993     if(token == EOF)
994     {
995     if(state)
996 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Unexpected EOF", line_number);
997 bertho 1.1 break;
998     }
999    
1000     switch(state)
1001     {
1002     case 0:
1003     if(token == TYPE_KEYWORD)
1004     {
1005     kw = yylval.kw;
1006     state = 1;
1007     }
1008     else if(token != ';')
1009 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Keyword expected", line_number);
1010 bertho 1.1 break;
1011     case 1:
1012     if(token != '=')
1013 bertho 1.16 {
1014     stack_msg(MSG_ERR, "config: %d: '=' expected", line_number);
1015 bertho 1.24 state = skip_to_semicolon(state);
1016     break;
1017 bertho 1.16 }
1018     else
1019     state = 2;
1020 bertho 1.1 break;
1021     case 2:
1022 bertho 1.16 if(!kw)
1023     {
1024     /* Error recovery of failed keyword */
1025     state = 3;
1026     break;
1027     }
1028 bertho 1.24 if(token == '[')
1029     {
1030     if(kw->type != TYPE_COLOR && kw->type != TYPE_CSTRING)
1031     {
1032     stack_msg(MSG_ERR, "config: %d: Conditional expression not allowed for keyword", line_number);
1033     state = skip_to_semicolon(state);
1034     break;
1035     }
1036     state = 4;
1037     break;
1038     }
1039 bertho 1.1 if(kw->type == TYPE_FONT || kw->type == TYPE_BOOLEAN)
1040     t = TYPE_NUMBER;
1041 bertho 1.24 else if(kw->type == TYPE_COLOR || kw->type == TYPE_COLORLIST || kw->type == TYPE_STRINGLIST || kw->type == TYPE_CSTRING)
1042 bertho 1.1 t = TYPE_STRING;
1043     else
1044     t = kw->type;
1045 bertho 1.2
1046     if(token == TYPE_NUMBER && kw->type == TYPE_DOUBLE)
1047     {
1048     /* Auto promote numbers to doubles if required */
1049     yylval.d = (double)yylval.i;
1050     token = TYPE_DOUBLE;
1051     }
1052    
1053 bertho 1.1 if(token != t)
1054     {
1055     char *e;
1056     switch(kw->type)
1057     {
1058 bertho 1.16 case TYPE_STRING: e = "String"; yylval.str = xstrdup("error recovery"); break;
1059 bertho 1.23 case TYPE_STRINGLIST: e = "StringL"; yylval.str = xstrdup("error recovery"); break;
1060 bertho 1.24 case TYPE_CSTRING: e = "CString"; yylval.str = xstrdup("error recovery"); break;
1061 bertho 1.16 case TYPE_NUMBER: e = "Number"; yylval.i = 0; break;
1062     case TYPE_COLOR: e = "Color"; yylval.str = xstrdup("#123456"); break;
1063 bertho 1.23 case TYPE_COLORLIST: e = "ColorL"; yylval.str = xstrdup("#123456"); break;
1064 bertho 1.16 case TYPE_FONT: e = "Font"; yylval.i = 0; break;
1065     case TYPE_BOOLEAN: e = "Boolean"; yylval.i = 0; break;
1066     case TYPE_DOUBLE: e = "Double"; yylval.d = 0.0; break;
1067     default: e = "Internal error: Unknown type"; yylval.i = 0; break;
1068 bertho 1.1 }
1069 bertho 1.16 stack_msg(MSG_ERR, "config: %d: %s expected", line_number, e);
1070 bertho 1.1 }
1071     #ifdef DEBUG
1072     printf("processing: '%s'\n", kw->keyword);
1073     #endif
1074     switch(kw->type)
1075     {
1076     case TYPE_STRING:
1077     *kw->confref.s = yylval.str;
1078     break;
1079 bertho 1.23 case TYPE_STRINGLIST:
1080     kw->confref.sl->strs = xrealloc(kw->confref.sl->strs, sizeof(*kw->confref.sl->strs) * (kw->confref.sl->n + 1));
1081     kw->confref.sl->strs[kw->confref.sl->n] = yylval.str;
1082     kw->confref.sl->n++;
1083     break;
1084 bertho 1.24 case TYPE_CSTRING:
1085     kw->confref.cs->str = yylval.str;
1086     break;
1087 bertho 1.1 case TYPE_NUMBER:
1088     *kw->confref.i = yylval.i;
1089     break;
1090     case TYPE_BOOLEAN:
1091 bertho 1.3 if(yylval.i == -1)
1092     *kw->confref.i = !*kw->confref.i;
1093     else
1094     *kw->confref.i = yylval.i != 0;
1095 bertho 1.1 break;
1096     case TYPE_COLOR:
1097     set_color(kw->confref.c, yylval.str);
1098     break;
1099 bertho 1.23 case TYPE_COLORLIST:
1100     kw->confref.cl->clrs = xrealloc(kw->confref.cl->clrs, sizeof(*kw->confref.cl->clrs) * (kw->confref.cl->n + 1));
1101     set_color(&kw->confref.cl->clrs[kw->confref.cl->n], yylval.str);
1102     kw->confref.cl->n++;
1103     break;
1104 bertho 1.1 case TYPE_FONT:
1105 bertho 1.2 kw->confref.f->gdfont = get_font(yylval.i);
1106     break;
1107     case TYPE_DOUBLE:
1108     *kw->confref.d = yylval.d;
1109 bertho 1.1 break;
1110     default:
1111     yyerror("Internal error: Unknown type passed %d", kw->type);
1112     break;
1113     }
1114 bertho 1.24 kw = NULL;
1115 bertho 1.1 state = 3;
1116     break;
1117     case 3:
1118     if(token != ';')
1119 bertho 1.16 stack_msg(MSG_ERR, "config: %d: ';' expected", line_number);
1120 bertho 1.1 state = 0;
1121     break;
1122 bertho 1.24 case 4:
1123     if(token != TYPE_STRING)
1124     {
1125     stack_msg(MSG_ERR, "config: %d: String expected (condition key)", line_number);
1126     state = skip_to_semicolon(state);
1127     break;
1128     }
1129     node = new_node(yylval.str);
1130     state = 5;
1131     break;
1132     case 5:
1133     if(token <= OP_FIRST || token >= OP_LAST)
1134     {
1135     stack_msg(MSG_ERR, "config: %d: Operator expected", line_number);
1136     state = skip_to_semicolon(state);
1137     break;
1138     }
1139     node->op = token;
1140     state = 6;
1141     break;
1142     case 6:
1143     if(token != TYPE_STRING)
1144     {
1145     stack_msg(MSG_ERR, "config: %d: String expected (condition)", line_number);
1146     state = skip_to_semicolon(state);
1147     break;
1148     }
1149     if(node->key == KEY_DATE)
1150     node->content = fixup_date(yylval.str);
1151     else
1152     node->content = yylval.str;
1153     state = 7;
1154     break;
1155     case 7:
1156     if(token == '[')
1157     {
1158     push_state(node, 8);
1159     node = NULL;
1160     state = 4;
1161     break;
1162     }
1163     if(token != TYPE_STRING)
1164     {
1165     stack_msg(MSG_ERR, "config: %d: String or '[' expected (true case)", line_number);
1166     state = skip_to_semicolon(state);
1167     break;
1168     }
1169     node->tcase = xmalloc(sizeof(*node->tcase));
1170     if(kw->type == TYPE_COLOR || kw->type == TYPE_COLORLIST)
1171     {
1172     node->tcase->key = TYPE_COLOR;
1173     set_color(&node->tcase->value.clr, yylval.str);
1174     }
1175     else
1176     {
1177     node->tcase->key = TYPE_STRING;
1178     node->tcase->value.str = yylval.str;
1179     }
1180     state = 8;
1181     break;
1182     case 8:
1183     if(token == '[')
1184     {
1185     push_state(node, 9);
1186     node = NULL;
1187     state = 4;
1188     break;
1189     }
1190     if(token != TYPE_STRING)
1191     {
1192     stack_msg(MSG_ERR, "config: %d: String or '[' expected (false case)", line_number);
1193     state = skip_to_semicolon(state);
1194     break;
1195     }
1196     node->fcase = xmalloc(sizeof(*node->fcase));
1197     if(kw->type == TYPE_COLOR || kw->type == TYPE_COLORLIST)
1198     {
1199     node->fcase->key = TYPE_COLOR;
1200     set_color(&node->fcase->value.clr, yylval.str);
1201     }
1202     else
1203     {
1204     node->fcase->key = TYPE_STRING;
1205     node->fcase->value.str = yylval.str;
1206     }
1207     state = 9;
1208     break;
1209     case 9:
1210     if(token != ']')
1211     {
1212     stack_msg(MSG_ERR, "config: %d: ']' expected", line_number);
1213     state = skip_to_semicolon(state);
1214     break;
1215     }
1216     if(!pop_state(&node, &state))
1217     {
1218     if(kw->type == TYPE_COLOR)
1219     kw->confref.c->node = node;
1220     else if(kw->type == TYPE_CSTRING)
1221     kw->confref.cs->node = node;
1222     else
1223     stack_msg(MSG_ERR, "config: %d: Color or conditional string keyword expected", line_number);
1224     node = NULL;
1225     kw = NULL;
1226     }
1227     break;
1228 bertho 1.1 default:
1229     yyerror("Internal error: invalid state %d", state);
1230     break;
1231     }
1232     }
1233     }
1234    
1235     /*
1236     **************************************************************************
1237     * Configuration
1238     **************************************************************************
1239     */
1240     void stack_option(const char *opt)
1241     {
1242     stacked_opts = xrealloc(stacked_opts, sizeof(*stacked_opts) * (nstacked_opts + 1));
1243     stacked_opts[nstacked_opts] = xmalloc(strlen(opt) + 2);
1244     strcpy(stacked_opts[nstacked_opts], opt);
1245     strcat(stacked_opts[nstacked_opts], ";");
1246     nstacked_opts++;
1247     #ifdef DEBUG
1248     printf("stacking option: '%s'\n", stacked_opts[nstacked_opts-1]);
1249     #endif
1250     }
1251    
1252     void read_config(const char *path)
1253     {
1254     FILE *fp;
1255    
1256     /* Make sure we have them sorted for bsearch */
1257     qsort(keywords, NKEYWORDS, sizeof(keywords[0]), cmp_kw);
1258    
1259     if(path)
1260     {
1261     if((fp = fopen(path, "r")) != NULL)
1262     input_file = path;
1263     }
1264     else
1265     {
1266     if((fp = fopen("./" CONFFILENAME, "r")) == NULL)
1267     {
1268     if((fp = fopen(ETCDIR "/" CONFFILENAME, "r")) != NULL)
1269     input_file = ETCDIR "/" CONFFILENAME;
1270     }
1271     else
1272     input_file = "./" CONFFILENAME;
1273     }
1274    
1275     if(fp)
1276     {
1277     line_number = 1;
1278     set_input(fp, NULL);
1279     config_parse();
1280     fclose(fp);
1281     input_file = NULL;
1282     }
1283    
1284     if(nstacked_opts)
1285     {
1286     int i;
1287     for(i = 0; i < nstacked_opts; i++)
1288     {
1289     line_number = 0;
1290     set_input(NULL, stacked_opts[i]);
1291     input_file = stacked_opts[i];
1292     #ifdef DEBUG
1293     printf("parsing stacked option: '%s'\n", stacked_opts[i]);
1294     #endif
1295     config_parse();
1296     }
1297     input_file = NULL;
1298     }
1299 bertho 1.23
1300     if(conf.merge_from.n != conf.merge_to.n)
1301     {
1302     int x = conf.merge_from.n < conf.merge_to.n ? conf.merge_from.n : conf.merge_to.n;
1303     stack_msg(MSG_ERR, "config: merge_from(n=%d) does not match merge_to(n=%d)", conf.merge_from.n, conf.merge_to.n);
1304     conf.merge_from.n = x;
1305     conf.merge_to.n = x;
1306     }
1307     if(conf.merge_color.n < conf.merge_from.n)
1308     {
1309     /* Silently extend missing merge_color statements with black */
1310     int x;
1311     char c[] = "#000000";
1312     for(x = conf.merge_color.n; x < conf.merge_from.n; x++)
1313     {
1314     conf.merge_color.clrs = xrealloc(conf.merge_color.clrs, sizeof(*conf.merge_color.clrs) * (conf.merge_color.n + 1));
1315     set_color(&conf.merge_color.clrs[conf.merge_color.n], c);
1316     conf.merge_color.n++;
1317     }
1318     }
1319    
1320 bertho 1.1 #ifdef DEBUG
1321     dump_config();
1322     #endif
1323     }
1324    
1325 bertho 1.21 /*
1326     **************************************************************************
1327     * Color reference by name for late-binding color allocation
1328     **************************************************************************
1329     */
1330 bertho 1.23 color_t *get_colorref(const char *confcolor, int idx)
1331 bertho 1.21 {
1332     keyword_t skw;
1333     keyword_t *kw;
1334    
1335 bertho 1.24 if(!confcolor)
1336     return NULL;
1337 bertho 1.21
1338     skw.keyword = confcolor;
1339     kw = bsearch(&skw, keywords, NKEYWORDS, sizeof(keywords[0]), cmp_kw);
1340 bertho 1.23 if(!kw || (kw->type != TYPE_COLOR && kw->type != TYPE_COLORLIST))
1341 bertho 1.21 return NULL;
1342 bertho 1.23 if(kw->type == TYPE_COLORLIST)
1343     {
1344     if(idx >= kw->confref.cl->n)
1345     return NULL;
1346     return &kw->confref.cl->clrs[idx];
1347     }
1348 bertho 1.21 return kw->confref.c;
1349     }

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0