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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0