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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0