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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0