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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0