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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0