/[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 - (hide annotations)
Tue Jan 1 21:03:23 2002 UTC (15 years, 9 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 bertho 1.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     }
787    

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0