/[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.16 - (hide annotations)
Sun Aug 15 16:58:22 2004 UTC (13 years, 2 months ago) by bertho
Branch: MAIN
CVS Tags: REL_1_5_0
Changes since 1.15: +50 -18 lines
File MIME type: text/plain
- Added drawing of partial trees. You now can select a subtree based on a
  revision number, branch number or symbolic tag to show only that part of the
  tree. New config option branch_subtree selects which part is shown. If the
  subtree is empty, then the whole tree is shown.

- Most error and warning messages are now displayed in the graph, instead of
  being written to stderr. This enables you to see an image eventhough errors
  might be present. The old method would generate a corrupt image.
  New configuration options include msg_color and msg_font to control the looks
  of it. Messages are always printed at the bottom of the image.

- Fixed a bug in the folding code where subtrees would not fold correctly.

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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0