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

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0