/[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.25 - (hide annotations)
Wed May 21 01:41:18 2008 UTC (9 years, 5 months ago) by bertho
Branch: MAIN
CVS Tags: REL_1_6_2, source_head_20080521
Changes since 1.24: +1 -0 lines
File MIME type: text/plain
- Do a better job at drawing the merge lines by selecting the shortest path
  from the revision boxes. An analysis is now done whether the source and
  destinations should be on the left or right side.
- Fix the left_right case for merge lines to display correctly.
- Fix a +/-1 error on the merge lines to account for both rounding errors and
  the shadow of the revision boxes.
- Add configuration option 'merge_on_tag' to force the left_right case to
  display merge lines on the tags instead of on the top/bottom sides. This
  also solves imagemap overlaps where multiple sources or destinations would
  be displayed at the same position.
- Fix the imagemap function to record the correct position of the merges.
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.13 INTTYPE 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.1 { "jpeg", TYPE_VALUE, { (void *)IMAGE_JPEG } },
180     { "png", TYPE_VALUE, { (void *)IMAGE_PNG } },
181     { "gif", TYPE_VALUE, { (void *)IMAGE_GIF } },
182     { "true", TYPE_VALUE, { (void *)1 } },
183     { "false", TYPE_VALUE, { (void *)0 } },
184 bertho 1.3 { "not", TYPE_VALUE, { (void *)-1 } },
185 bertho 1.1 { "left", TYPE_VALUE, { (void *)0 } },
186     { "center", TYPE_VALUE, { (void *)1 } },
187     { "right", TYPE_VALUE, { (void *)2 } },
188     { "tiny", TYPE_VALUE, { (void *)0 } },
189     { "small", TYPE_VALUE, { (void *)1 } },
190     { "medium", TYPE_VALUE, { (void *)2 } },
191     { "large", TYPE_VALUE, { (void *)3 } },
192     { "giant", TYPE_VALUE, { (void *)4 } },
193 bertho 1.8 { "HTML3", TYPE_VALUE, { (void *)1 } },
194     { "HTML4", TYPE_VALUE, { (void *)2 } },
195     { "XHTML", TYPE_VALUE, { (void *)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    
388     debug_pcolor("msg_color", &conf.msg_color);
389     debug_pfont("msg_font", conf.msg_font.gdfont);
390     debug_pstring("msg_ttfont", conf.msg_font.ttfont);
391     debug_pdouble("msg_ttsize", conf.msg_font.ttsize);
392 bertho 1.1
393 bertho 1.2 debug_pfont("tag_font", conf.tag_font.gdfont);
394     debug_pstring("tag_ttfont", conf.tag_font.ttfont);
395 bertho 1.24 debug_pdouble("tag_ttsize", conf.tag_font.ttsize);
396 bertho 1.1 debug_pcolor("tag_color", &conf.tag_color);
397 bertho 1.24 debug_pbool("tag_ignore_merge", conf.tag_ignore_merge);
398     debug_pstring("tag_ignore", conf.tag_ignore);
399     debug_pbool("tag_negate", conf.tag_negate);
400     debug_pbool("tag_nocase", conf.tag_nocase);
401 bertho 1.1
402 bertho 1.2 debug_pfont("rev_font", conf.rev_font.gdfont);
403     debug_pstring("rev_ttfont", conf.rev_font.ttfont);
404     debug_pdouble("rev_ttsize", conf.rev_font.ttsize);
405 bertho 1.1 debug_pcolor("rev_color", &conf.rev_color);
406     debug_pcolor("rev_bgcolor", &conf.rev_bgcolor);
407     debug_pint("rev_separator", conf.rev_separator);
408     debug_pint("rev_minline", conf.rev_minline);
409     debug_pint("rev_maxline", conf.rev_maxline);
410 bertho 1.24 debug_pint("rev_maxtags", conf.rev_maxtags);
411 bertho 1.1 debug_pint("rev_lspace", conf.rev_lspace);
412     debug_pint("rev_rspace", conf.rev_rspace);
413     debug_pint("rev_tspace", conf.rev_tspace);
414     debug_pint("rev_bspace", conf.rev_bspace);
415 bertho 1.24 debug_pcstring("rev_text", conf.rev_text);
416 bertho 1.1 debug_pcolor("rev_text_color", &conf.rev_text_color);
417 bertho 1.2 debug_pfont("rev_text_font", conf.rev_text_font.gdfont);
418     debug_pstring("rev_text_ttfont", conf.rev_text_font.ttfont);
419     debug_pdouble("rev_text_ttsize", conf.rev_text_font.ttsize);
420 bertho 1.24 debug_pbool("rev_hidenumber", conf.rev_hidenumber);
421 bertho 1.2
422     debug_pfont("branch_font", conf.branch_font.gdfont);
423     debug_pstring("branch_ttfont", conf.branch_font.ttfont);
424     debug_pdouble("branch_ttsize", conf.branch_font.ttsize);
425 bertho 1.1 debug_pcolor("branch_color", &conf.branch_color);
426 bertho 1.2 debug_pfont("branch_tag_font", conf.branch_tag_font.gdfont);
427     debug_pstring("branch_tag_ttfont", conf.branch_tag_font.ttfont);
428     debug_pdouble("branch_tag_ttsize", conf.branch_tag_font.ttsize);
429     debug_pcolor("branch_tag_color", &conf.branch_tag_color);
430 bertho 1.1 debug_pcolor("branch_bgcolor", &conf.branch_bgcolor);
431     debug_pint("branch_lspace", conf.branch_lspace);
432     debug_pint("branch_rspace", conf.branch_rspace);
433     debug_pint("branch_tspace", conf.branch_tspace);
434     debug_pint("branch_bspace", conf.branch_bspace);
435     debug_pint("branch_connect", conf.branch_connect);
436     debug_pint("branch_margin", conf.branch_margin);
437     debug_pint("branch_dupbox", conf.branch_dupbox);
438 bertho 1.24 debug_pbool("branch_fold", conf.branch_fold);
439     debug_pbool("branch_foldall", conf.branch_foldall);
440     debug_pbool("branch_resort", conf.branch_resort);
441     debug_pstring("branch_subtree", conf.branch_subtree);
442 bertho 1.1
443     debug_pstring("title", conf.title);
444     debug_pint("title_x", conf.title_x);
445     debug_pint("title_y", conf.title_y);
446 bertho 1.2 debug_pfont("title_font", conf.title_font.gdfont);
447     debug_pstring("title_ttfont", conf.title_font.ttfont);
448     debug_pdouble("title_ttsize", conf.title_font.ttsize);
449 bertho 1.1 debug_pint("title_align", conf.title_align);
450     debug_pcolor("title_color", &conf.title_color);
451    
452     debug_pint("margin_top", conf.margin_top);
453     debug_pint("margin_bottom", conf.margin_bottom);
454     debug_pint("margin_left", conf.margin_left);
455     debug_pint("margin_right", conf.margin_right);
456    
457     debug_pint("image_type", conf.image_type);
458     debug_pint("image_quality", conf.image_quality);
459 bertho 1.24 debug_pint("image_compress", conf.image_compress);
460     debug_pbool("image_interlace", conf.image_interlace);
461 bertho 1.1
462     debug_pstring("map_name", conf.map_name);
463     debug_pstring("map_branch_href", conf.map_branch_href);
464     debug_pstring("map_branch_alt", conf.map_branch_alt);
465     debug_pstring("map_rev_href", conf.map_rev_href);
466     debug_pstring("map_rev_alt", conf.map_rev_alt);
467     debug_pstring("map_diff_href", conf.map_diff_href);
468     debug_pstring("map_diff_alt", conf.map_diff_alt);
469 bertho 1.24 debug_pstring("map_merge_href", conf.map_merge_href);
470     debug_pstring("map_merge_alt", conf.map_merge_alt);
471 bertho 1.1
472     debug_pstring("expand[0]", conf.expand[0]);
473     debug_pstring("expand[1]", conf.expand[1]);
474     debug_pstring("expand[2]", conf.expand[2]);
475     debug_pstring("expand[3]", conf.expand[3]);
476     debug_pstring("expand[4]", conf.expand[4]);
477     debug_pstring("expand[5]", conf.expand[5]);
478     debug_pstring("expand[6]", conf.expand[6]);
479     debug_pstring("expand[7]", conf.expand[7]);
480     debug_pstring("expand[8]", conf.expand[8]);
481     debug_pstring("expand[9]", conf.expand[9]);
482     }
483     #endif
484    
485     /*
486     **************************************************************************
487     * String collection routines
488     **************************************************************************
489     */
490     #define STRALLOCSIZE 128
491     static char *str;
492     static int nstr;
493     static int nastr;
494    
495     static void reset_str(void)
496     {
497     nstr = 0;
498     }
499    
500     static void add_str(int c)
501     {
502     if(nstr + 1 + 1 > nastr)
503     {
504     str = xrealloc(str, nastr+STRALLOCSIZE);
505     nastr += STRALLOCSIZE;
506     }
507     str[nstr++] = c;
508     }
509    
510     static char *get_str(void)
511     {
512     if(!str)
513     return xstrdup("");
514    
515     str[nstr] = '\0';
516     return xstrdup(str);
517     }
518    
519     /*
520     **************************************************************************
521     * Input routines
522     **************************************************************************
523     */
524     static char *buf = NULL;
525     static int bufsize = 0;
526     static int bufalloc = 0;
527     static int bufpos = 0;
528     static int bufunput = -1;
529     static FILE *buffp;
530    
531     static void set_input(FILE *fp, char *s)
532     {
533     assert((fp == NULL && s != NULL) || (fp != NULL && s == NULL));
534     buffp = fp;
535     bufsize = bufpos = 0;
536     if(s)
537     {
538     if(!buf)
539     {
540     bufalloc = 8192;
541     buf = xmalloc(bufalloc * sizeof(*buf));
542     }
543     bufsize = strlen(s);
544     assert(bufsize < bufalloc);
545     strcpy(buf, s);
546     }
547     }
548    
549     static int get_input(void)
550     {
551     if(bufunput != -1)
552     {
553     int c = bufunput;
554     bufunput = -1;
555     return c;
556     }
557    
558     if(bufpos < bufsize)
559     {
560     assert(buf != NULL);
561     retry_input:
562     return (int)((unsigned char)buf[bufpos++]);
563     }
564    
565     if(!buf)
566     {
567     bufalloc = 8192;
568     buf = xmalloc(bufalloc * sizeof(*buf));
569     bufsize = bufpos = 0;
570     }
571     if(buffp)
572     {
573     bufsize = fread(buf, 1, bufalloc, buffp);
574     bufpos = 0;
575     if(!bufsize)
576     return EOF;
577     goto retry_input;
578     }
579     return EOF;
580     }
581    
582     static void unget_input(int c)
583     {
584     bufunput = c;
585     }
586    
587     /*
588     **************************************************************************
589     * Lexical scanner
590     **************************************************************************
591     */
592     static int config_lex(void)
593     {
594     int ch;
595     while(1)
596     {
597     ch = get_input();
598     if(ch == '\n')
599     line_number++;
600    
601     if(isspace(ch))
602     continue;
603    
604     switch(ch)
605     {
606 bertho 1.24 case '=':
607     ch = get_input();
608     switch(ch)
609     {
610     case '~': return OP_CONTAINED;
611     case '*': return OP_CONTAINEDI;
612     case '=': return OP_EQ;
613     default:
614     unget_input(ch);
615     return '=';
616     }
617     break;
618    
619     case '!':
620     ch = get_input();
621     switch(ch)
622     {
623     case '~': return OP_NCONTAINED;
624     case '*': return OP_NCONTAINEDI;
625     case '=': return OP_NE;
626     default:
627     stack_msg(MSG_ERR, "config: %d: Invalid operator", line_number);
628     unget_input(ch);
629     return '!';
630     }
631     break;
632    
633     case '>':
634     ch = get_input();
635     if(ch == '=')
636     return OP_GE;
637     unget_input(ch);
638     return OP_GT;
639    
640     case '<':
641     ch = get_input();
642     if(ch == '=')
643     return OP_LE;
644     unget_input(ch);
645     return OP_LT;
646    
647 bertho 1.1 case EOF:
648     case ';':
649 bertho 1.24 case '[':
650     case ']':
651 bertho 1.1 return ch;
652    
653     case '#': /* Comment */
654     while((ch = get_input()) != '\n' && ch != EOF)
655     ;
656     if(ch != EOF)
657     unget_input(ch);
658     break;
659    
660     case '"':
661     reset_str();
662     while(1)
663     {
664     char c[4];
665     ch = get_input();
666     switch(ch)
667     {
668     case '\\': /* Start an escape sequence */
669     switch(ch = get_input())
670     {
671     default: /* This includes '\\', '"' and embedded newlines */
672     add_str(ch);
673     break;
674     case 'a': add_str('\a'); break;
675     case 'b': add_str('\b'); break;
676     case 'f': add_str('\f'); break;
677     case 'n': add_str('\n'); break;
678     case 'r': add_str('\r'); break;
679     case 't': add_str('\t'); break;
680     case 'v': add_str('\v'); break;
681     case 'x':
682     case 'X': /* Hex escape */
683     c[0] = get_input();
684     c[1] = get_input();
685     c[2] = '\0';
686 bertho 1.7 if(!isxdigit((int)(unsigned char)c[0]) || !isxdigit((int)(unsigned char)c[1]))
687 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Invalid hex escape", line_number);
688 bertho 1.1 add_str((int)strtol(c, NULL, 16));
689     break;
690     case '0':
691     case '1':
692     case '2': /* Octal escape */
693     c[0] = ch;
694     c[1] = c[2] = c[3] = '\0';
695     if((ch = get_input()) >= '0' && ch <= '7')
696     c[1] = ch;
697     else
698     unget_input(ch);
699     if((ch = get_input()) >= '0' && ch <= '7')
700     c[2] = ch;
701     else
702     unget_input(ch);
703     add_str((int)strtol(c, NULL, 8));
704     break;
705     case EOF:
706 bertho 1.17 yyerror("Unexpected EOF in escape");
707     break;
708 bertho 1.1 }
709     break;
710     case '"':
711     yylval.str = get_str();
712     return TYPE_STRING;
713     case '\n':
714     yyerror("Newline in string");
715     break;
716     case EOF:
717     yyerror("Unexpected EOF in string");
718     break;
719     default:
720     add_str(ch);
721     break;
722     }
723     }
724     break;
725    
726     default:
727     if(isalpha(ch) || ch == '_')
728     {
729     keyword_t skw;
730     keyword_t *kw;
731     /* Collect keyword */
732     reset_str();
733     add_str(ch);
734     while(1)
735     {
736     ch = get_input();
737 bertho 1.8 if(isalnum(ch) || ch == '_')
738 bertho 1.1 add_str(ch);
739     else
740     {
741     unget_input(ch);
742     break;
743     }
744     }
745     skw.keyword = get_str();
746     kw = bsearch(&skw, keywords, NKEYWORDS, sizeof(keywords[0]), cmp_kw);
747     if(!kw)
748 bertho 1.16 {
749     stack_msg(MSG_ERR, "config: %d: Unknown keyword '%s'", line_number, skw.keyword);
750     yylval.kw = NULL;
751     return TYPE_KEYWORD;
752     }
753 bertho 1.21 xfree((void *)skw.keyword);
754 bertho 1.1 if(kw->type == TYPE_VALUE)
755     {
756 bertho 1.13 yylval.i = (int)kw->confref.val;
757 bertho 1.1 return TYPE_NUMBER;
758     }
759     yylval.kw = kw;
760     return TYPE_KEYWORD;
761     }
762     else if(isdigit(ch) || ch == '+' || ch == '-')
763     {
764     char *s;
765     char *eptr;
766 bertho 1.2 int type = TYPE_NUMBER;
767 bertho 1.1 /* Collect number */
768     reset_str();
769     add_str(ch);
770     while(1)
771     {
772     ch = get_input();
773 bertho 1.2 if(isxdigit(ch) || ch == 'x' || ch == 'X' || ch == '.') /* Not exact, but close enough */
774 bertho 1.1 add_str(ch);
775     else
776     {
777     unget_input(ch);
778     break;
779     }
780 bertho 1.2 if(ch == '.')
781     type = TYPE_DOUBLE;
782 bertho 1.1 }
783     s = get_str();
784 bertho 1.2 if(type == TYPE_DOUBLE)
785     {
786     yylval.d = strtod(s, &eptr);
787     if(*eptr)
788 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Invalid floating point number", line_number);
789 bertho 1.2 }
790     else
791     {
792     yylval.i = strtol(s, &eptr, 0);
793     if(*eptr)
794 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Invalid number", line_number);
795 bertho 1.2 }
796 bertho 1.1 xfree(s);
797 bertho 1.2 return type;
798 bertho 1.1 }
799     else
800     yyerror("Unmatched text '%c' (0x%02x)", isprint(ch) ? ch : ' ', ch);
801     break;
802     }
803     }
804     }
805    
806     static void set_color(color_t *c, char *s)
807     {
808     char *cptr;
809 bertho 1.24 c->node = NULL;
810 bertho 1.1 if(*s != '#' || strlen(s) != 7)
811     {
812     colorerror:
813 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Invalid color value '%s'", line_number, s);
814     return;
815 bertho 1.1 }
816     c->b = strtol(s+5, &cptr, 16);
817     if(*cptr)
818     goto colorerror;
819     s[5] = '\0';
820     c->g = strtol(s+3, &cptr, 16);
821     if(*cptr)
822     goto colorerror;
823     s[3] = '\0';
824     c->r = strtol(s+1, &cptr, 16);
825     if(*cptr)
826     goto colorerror;
827     }
828    
829     static gdFontPtr get_font(int id)
830     {
831     switch(id)
832     {
833     case 0: return gdFontTiny;
834     case 1: return gdFontSmall;
835     default:
836     case 2: return gdFontMediumBold;
837     case 3: return gdFontLarge;
838     case 4: return gdFontGiant;
839     }
840     }
841    
842     /*
843     **************************************************************************
844     * The config parser
845     * Grammar:
846     * file : <Empty>
847     * | lines
848     * ;
849     *
850     * lines : line
851     * | lines line
852     * ;
853     *
854     * line : <keyword> '=' <value> ';'
855 bertho 1.24 * | <keyword> '=' expr ';'
856 bertho 1.1 * | ';'
857 bertho 1.24 *
858     * expr : '[' <kw> <op> <value> expr expr ']'
859     * | <value>
860 bertho 1.1 * ;
861     **************************************************************************
862     */
863 bertho 1.24 static int skip_to_semicolon(int state)
864     {
865     int token;
866     while(1)
867     {
868     token = config_lex();
869     if(token == ';')
870     return 0;
871     else if(token == EOF)
872     return state;
873     }
874     }
875    
876     static node_t *new_node(char *val)
877     {
878     node_t *n = xmalloc(sizeof(*n));
879     if(!strcmp(val, "state"))
880     n->key = KEY_STATE;
881     else if(!strcmp(val, "author"))
882     n->key = KEY_AUTHOR;
883     else if(!strcmp(val, "tag"))
884     n->key = KEY_TAG;
885     else if(!strcmp(val, "date"))
886     n->key = KEY_DATE;
887     else if(!strcmp(val, "rev"))
888     n->key = KEY_REV;
889     else
890     {
891     n->key = KEY_UNKNOWN;
892     stack_msg(MSG_ERR, "config: %d: Unknown key '%s'", line_number, val);
893     }
894     return n;
895     }
896    
897     typedef struct __statestack_t
898     {
899     int state;
900     node_t *node;
901     } statestack_t;
902    
903     static int nstatestack = 0;
904     static int nastatestack;
905     static statestack_t *statestack = NULL;
906    
907     static void push_state(node_t *node, int state)
908     {
909     if(!statestack)
910     {
911     statestack = xmalloc(4 * sizeof(*statestack));
912     nastatestack = 4;
913     nstatestack = 0;
914     }
915     else if(nstatestack >= nastatestack)
916     {
917     nastatestack *= 2;
918     statestack = xrealloc(statestack, nastatestack * sizeof(*statestack));
919     }
920     statestack[nstatestack].node = node;
921     statestack[nstatestack].state = state;
922     nstatestack++;
923     }
924    
925     static int pop_state(node_t **node, int *state)
926     {
927     if(nstatestack <= 0)
928     {
929     *state = 3;
930     return 0;
931     }
932     assert(*node != NULL);
933     if(statestack[nstatestack-1].state == 8)
934     statestack[nstatestack-1].node->tcase = *node;
935     else if(statestack[nstatestack-1].state == 9)
936     statestack[nstatestack-1].node->fcase = *node;
937     *state = statestack[nstatestack-1].state;
938     *node = statestack[nstatestack-1].node;
939     return nstatestack--;
940     }
941    
942     /* YYYY.MM.DD.hh.mm.ss */
943     /* 0123456789012345678 */
944     /* 111111111 */
945     static char *fixup_date(const char *str)
946     {
947     int i;
948     int y=1970, m=1, d=1, h=0, mi=0, s=0;
949     int l = strlen(str);
950     char date[6*16]; /* Should be wildly enough to hold 19 chars from 6 numbers with all possible errors */
951     if(l < 4 || l > 19)
952     {
953     date_err:
954     stack_msg(MSG_ERR, "config: %d: Invalid date string '%s'", line_number, str);
955     return "1970.01.01.00.00.00";
956     }
957     for(i = 0; i < l; i++)
958     {
959     if(!strchr("0123456789.", str[i]))
960     goto date_err;
961     }
962     i = sscanf(str, "%d.%d.%d.%d.%d.%d", &y, &m, &d, &h, &mi, &s);
963     if(i == EOF || i < 0 || i > 6)
964     goto date_err;
965     if(i >= 1 && (y < 1970 || y > 2037))
966     goto date_err;
967     if(i >= 2 && (m < 1 || m > 12))
968     goto date_err;
969     if(i >= 3 && (d < 1 || d > 31))
970     goto date_err;
971     if(i >= 4 && (h < 0 || h > 23))
972     goto date_err;
973     if(i >= 5 && (mi < 0 || mi > 59))
974     goto date_err;
975     if(i >= 6 && (s < 0 || s > 59))
976     goto date_err;
977     sprintf(date, "%04d.%02d.%02d.%02d.%02d.%02d", y, m, d, h, mi, s);
978     return strdup(date);
979     }
980    
981 bertho 1.1 static void config_parse(void)
982     {
983     int state = 0;
984     int token;
985     int t;
986     keyword_t *kw = NULL;
987 bertho 1.24 node_t *node = NULL;
988 bertho 1.1
989     while(1)
990     {
991     token = config_lex();
992     if(token == EOF)
993     {
994     if(state)
995 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Unexpected EOF", line_number);
996 bertho 1.1 break;
997     }
998    
999     switch(state)
1000     {
1001     case 0:
1002     if(token == TYPE_KEYWORD)
1003     {
1004     kw = yylval.kw;
1005     state = 1;
1006     }
1007     else if(token != ';')
1008 bertho 1.16 stack_msg(MSG_ERR, "config: %d: Keyword expected", line_number);
1009 bertho 1.1 break;
1010     case 1:
1011     if(token != '=')
1012 bertho 1.16 {
1013     stack_msg(MSG_ERR, "config: %d: '=' expected", line_number);
1014 bertho 1.24 state = skip_to_semicolon(state);
1015     break;
1016 bertho 1.16 }
1017     else
1018     state = 2;
1019 bertho 1.1 break;
1020     case 2:
1021 bertho 1.16 if(!kw)
1022     {
1023     /* Error recovery of failed keyword */
1024     state = 3;
1025     break;
1026     }
1027 bertho 1.24 if(token == '[')
1028     {
1029     if(kw->type != TYPE_COLOR && kw->type != TYPE_CSTRING)
1030     {
1031     stack_msg(MSG_ERR, "config: %d: Conditional expression not allowed for keyword", line_number);
1032     state = skip_to_semicolon(state);
1033     break;
1034     }
1035     state = 4;
1036     break;
1037     }
1038 bertho 1.1 if(kw->type == TYPE_FONT || kw->type == TYPE_BOOLEAN)
1039     t = TYPE_NUMBER;
1040 bertho 1.24 else if(kw->type == TYPE_COLOR || kw->type == TYPE_COLORLIST || kw->type == TYPE_STRINGLIST || kw->type == TYPE_CSTRING)
1041 bertho 1.1 t = TYPE_STRING;
1042     else
1043     t = kw->type;
1044 bertho 1.2
1045     if(token == TYPE_NUMBER && kw->type == TYPE_DOUBLE)
1046     {
1047     /* Auto promote numbers to doubles if required */
1048     yylval.d = (double)yylval.i;
1049     token = TYPE_DOUBLE;
1050     }
1051    
1052 bertho 1.1 if(token != t)
1053     {
1054     char *e;
1055     switch(kw->type)
1056     {
1057 bertho 1.16 case TYPE_STRING: e = "String"; yylval.str = xstrdup("error recovery"); break;
1058 bertho 1.23 case TYPE_STRINGLIST: e = "StringL"; yylval.str = xstrdup("error recovery"); break;
1059 bertho 1.24 case TYPE_CSTRING: e = "CString"; yylval.str = xstrdup("error recovery"); break;
1060 bertho 1.16 case TYPE_NUMBER: e = "Number"; yylval.i = 0; break;
1061     case TYPE_COLOR: e = "Color"; yylval.str = xstrdup("#123456"); break;
1062 bertho 1.23 case TYPE_COLORLIST: e = "ColorL"; yylval.str = xstrdup("#123456"); break;
1063 bertho 1.16 case TYPE_FONT: e = "Font"; yylval.i = 0; break;
1064     case TYPE_BOOLEAN: e = "Boolean"; yylval.i = 0; break;
1065     case TYPE_DOUBLE: e = "Double"; yylval.d = 0.0; break;
1066     default: e = "Internal error: Unknown type"; yylval.i = 0; break;
1067 bertho 1.1 }
1068 bertho 1.16 stack_msg(MSG_ERR, "config: %d: %s expected", line_number, e);
1069 bertho 1.1 }
1070     #ifdef DEBUG
1071     printf("processing: '%s'\n", kw->keyword);
1072     #endif
1073     switch(kw->type)
1074     {
1075     case TYPE_STRING:
1076     *kw->confref.s = yylval.str;
1077     break;
1078 bertho 1.23 case TYPE_STRINGLIST:
1079     kw->confref.sl->strs = xrealloc(kw->confref.sl->strs, sizeof(*kw->confref.sl->strs) * (kw->confref.sl->n + 1));
1080     kw->confref.sl->strs[kw->confref.sl->n] = yylval.str;
1081     kw->confref.sl->n++;
1082     break;
1083 bertho 1.24 case TYPE_CSTRING:
1084     kw->confref.cs->str = yylval.str;
1085     break;
1086 bertho 1.1 case TYPE_NUMBER:
1087     *kw->confref.i = yylval.i;
1088     break;
1089     case TYPE_BOOLEAN:
1090 bertho 1.3 if(yylval.i == -1)
1091     *kw->confref.i = !*kw->confref.i;
1092     else
1093     *kw->confref.i = yylval.i != 0;
1094 bertho 1.1 break;
1095     case TYPE_COLOR:
1096     set_color(kw->confref.c, yylval.str);
1097     break;
1098 bertho 1.23 case TYPE_COLORLIST:
1099     kw->confref.cl->clrs = xrealloc(kw->confref.cl->clrs, sizeof(*kw->confref.cl->clrs) * (kw->confref.cl->n + 1));
1100     set_color(&kw->confref.cl->clrs[kw->confref.cl->n], yylval.str);
1101     kw->confref.cl->n++;
1102     break;
1103 bertho 1.1 case TYPE_FONT:
1104 bertho 1.2 kw->confref.f->gdfont = get_font(yylval.i);
1105     break;
1106     case TYPE_DOUBLE:
1107     *kw->confref.d = yylval.d;
1108 bertho 1.1 break;
1109     default:
1110     yyerror("Internal error: Unknown type passed %d", kw->type);
1111     break;
1112     }
1113 bertho 1.24 kw = NULL;
1114 bertho 1.1 state = 3;
1115     break;
1116     case 3:
1117     if(token != ';')
1118 bertho 1.16 stack_msg(MSG_ERR, "config: %d: ';' expected", line_number);
1119 bertho 1.1 state = 0;
1120     break;
1121 bertho 1.24 case 4:
1122     if(token != TYPE_STRING)
1123     {
1124     stack_msg(MSG_ERR, "config: %d: String expected (condition key)", line_number);
1125     state = skip_to_semicolon(state);
1126     break;
1127     }
1128     node = new_node(yylval.str);
1129     state = 5;
1130     break;
1131     case 5:
1132     if(token <= OP_FIRST || token >= OP_LAST)
1133     {
1134     stack_msg(MSG_ERR, "config: %d: Operator expected", line_number);
1135     state = skip_to_semicolon(state);
1136     break;
1137     }
1138     node->op = token;
1139     state = 6;
1140     break;
1141     case 6:
1142     if(token != TYPE_STRING)
1143     {
1144     stack_msg(MSG_ERR, "config: %d: String expected (condition)", line_number);
1145     state = skip_to_semicolon(state);
1146     break;
1147     }
1148     if(node->key == KEY_DATE)
1149     node->content = fixup_date(yylval.str);
1150     else
1151     node->content = yylval.str;
1152     state = 7;
1153     break;
1154     case 7:
1155     if(token == '[')
1156     {
1157     push_state(node, 8);
1158     node = NULL;
1159     state = 4;
1160     break;
1161     }
1162     if(token != TYPE_STRING)
1163     {
1164     stack_msg(MSG_ERR, "config: %d: String or '[' expected (true case)", line_number);
1165     state = skip_to_semicolon(state);
1166     break;
1167     }
1168     node->tcase = xmalloc(sizeof(*node->tcase));
1169     if(kw->type == TYPE_COLOR || kw->type == TYPE_COLORLIST)
1170     {
1171     node->tcase->key = TYPE_COLOR;
1172     set_color(&node->tcase->value.clr, yylval.str);
1173     }
1174     else
1175     {
1176     node->tcase->key = TYPE_STRING;
1177     node->tcase->value.str = yylval.str;
1178     }
1179     state = 8;
1180     break;
1181     case 8:
1182     if(token == '[')
1183     {
1184     push_state(node, 9);
1185     node = NULL;
1186     state = 4;
1187     break;
1188     }
1189     if(token != TYPE_STRING)
1190     {
1191     stack_msg(MSG_ERR, "config: %d: String or '[' expected (false case)", line_number);
1192     state = skip_to_semicolon(state);
1193     break;
1194     }
1195     node->fcase = xmalloc(sizeof(*node->fcase));
1196     if(kw->type == TYPE_COLOR || kw->type == TYPE_COLORLIST)
1197     {
1198     node->fcase->key = TYPE_COLOR;
1199     set_color(&node->fcase->value.clr, yylval.str);
1200     }
1201     else
1202     {
1203     node->fcase->key = TYPE_STRING;
1204     node->fcase->value.str = yylval.str;
1205     }
1206     state = 9;
1207     break;
1208     case 9:
1209     if(token != ']')
1210     {
1211     stack_msg(MSG_ERR, "config: %d: ']' expected", line_number);
1212     state = skip_to_semicolon(state);
1213     break;
1214     }
1215     if(!pop_state(&node, &state))
1216     {
1217     if(kw->type == TYPE_COLOR)
1218     kw->confref.c->node = node;
1219     else if(kw->type == TYPE_CSTRING)
1220     kw->confref.cs->node = node;
1221     else
1222     stack_msg(MSG_ERR, "config: %d: Color or conditional string keyword expected", line_number);
1223     node = NULL;
1224     kw = NULL;
1225     }
1226     break;
1227 bertho 1.1 default:
1228     yyerror("Internal error: invalid state %d", state);
1229     break;
1230     }
1231     }
1232     }
1233    
1234     /*
1235     **************************************************************************
1236     * Configuration
1237     **************************************************************************
1238     */
1239     void stack_option(const char *opt)
1240     {
1241     stacked_opts = xrealloc(stacked_opts, sizeof(*stacked_opts) * (nstacked_opts + 1));
1242     stacked_opts[nstacked_opts] = xmalloc(strlen(opt) + 2);
1243     strcpy(stacked_opts[nstacked_opts], opt);
1244     strcat(stacked_opts[nstacked_opts], ";");
1245     nstacked_opts++;
1246     #ifdef DEBUG
1247     printf("stacking option: '%s'\n", stacked_opts[nstacked_opts-1]);
1248     #endif
1249     }
1250    
1251     void read_config(const char *path)
1252     {
1253     FILE *fp;
1254    
1255     /* Make sure we have them sorted for bsearch */
1256     qsort(keywords, NKEYWORDS, sizeof(keywords[0]), cmp_kw);
1257    
1258     if(path)
1259     {
1260     if((fp = fopen(path, "r")) != NULL)
1261     input_file = path;
1262     }
1263     else
1264     {
1265     if((fp = fopen("./" CONFFILENAME, "r")) == NULL)
1266     {
1267     if((fp = fopen(ETCDIR "/" CONFFILENAME, "r")) != NULL)
1268     input_file = ETCDIR "/" CONFFILENAME;
1269     }
1270     else
1271     input_file = "./" CONFFILENAME;
1272     }
1273    
1274     if(fp)
1275     {
1276     line_number = 1;
1277     set_input(fp, NULL);
1278     config_parse();
1279     fclose(fp);
1280     input_file = NULL;
1281     }
1282    
1283     if(nstacked_opts)
1284     {
1285     int i;
1286     for(i = 0; i < nstacked_opts; i++)
1287     {
1288     line_number = 0;
1289     set_input(NULL, stacked_opts[i]);
1290     input_file = stacked_opts[i];
1291     #ifdef DEBUG
1292     printf("parsing stacked option: '%s'\n", stacked_opts[i]);
1293     #endif
1294     config_parse();
1295     }
1296     input_file = NULL;
1297     }
1298 bertho 1.23
1299     if(conf.merge_from.n != conf.merge_to.n)
1300     {
1301     int x = conf.merge_from.n < conf.merge_to.n ? conf.merge_from.n : conf.merge_to.n;
1302     stack_msg(MSG_ERR, "config: merge_from(n=%d) does not match merge_to(n=%d)", conf.merge_from.n, conf.merge_to.n);
1303     conf.merge_from.n = x;
1304     conf.merge_to.n = x;
1305     }
1306     if(conf.merge_color.n < conf.merge_from.n)
1307     {
1308     /* Silently extend missing merge_color statements with black */
1309     int x;
1310     char c[] = "#000000";
1311     for(x = conf.merge_color.n; x < conf.merge_from.n; x++)
1312     {
1313     conf.merge_color.clrs = xrealloc(conf.merge_color.clrs, sizeof(*conf.merge_color.clrs) * (conf.merge_color.n + 1));
1314     set_color(&conf.merge_color.clrs[conf.merge_color.n], c);
1315     conf.merge_color.n++;
1316     }
1317     }
1318    
1319 bertho 1.1 #ifdef DEBUG
1320     dump_config();
1321     #endif
1322     }
1323    
1324 bertho 1.21 /*
1325     **************************************************************************
1326     * Color reference by name for late-binding color allocation
1327     **************************************************************************
1328     */
1329 bertho 1.23 color_t *get_colorref(const char *confcolor, int idx)
1330 bertho 1.21 {
1331     keyword_t skw;
1332     keyword_t *kw;
1333    
1334 bertho 1.24 if(!confcolor)
1335     return NULL;
1336 bertho 1.21
1337     skw.keyword = confcolor;
1338     kw = bsearch(&skw, keywords, NKEYWORDS, sizeof(keywords[0]), cmp_kw);
1339 bertho 1.23 if(!kw || (kw->type != TYPE_COLOR && kw->type != TYPE_COLORLIST))
1340 bertho 1.21 return NULL;
1341 bertho 1.23 if(kw->type == TYPE_COLORLIST)
1342     {
1343     if(idx >= kw->confref.cl->n)
1344     return NULL;
1345     return &kw->confref.cl->clrs[idx];
1346     }
1347 bertho 1.21 return kw->confref.c;
1348     }

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0