Merge from vendor branch TCPDUMP:
[dragonfly.git] / gnu / lib / libdialog / rc.c
1 /*
2  *  rc.c -- routines for processing the configuration file
3  *
4  *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation; either version 2
9  *  of the License, or (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <dialog.h>
22 #include "dialog.priv.h"
23 #include "colors.h"
24 #include "rc.h"
25
26
27 static unsigned char *attr_to_str(int fg, int bg, int hl);
28 static int str_to_attr(unsigned char *str, int *fg, int *bg, int *hl);
29 static int parse_line(unsigned char *line, unsigned char **var, unsigned char **value);
30
31
32 /*
33  * Create the configuration file
34  */
35 void dialog_create_rc(unsigned char *filename)
36 {
37   int i;
38   FILE *rc_file;
39
40   if ((rc_file = fopen(filename, "wt")) == NULL) {
41     fprintf(stderr, "\nError opening file for writing in create_rc().\n");
42     exit(-1);
43   }
44
45   fprintf(rc_file, "#\
46 \n# Run-time configuration file for dialog\
47 \n#\
48 \n# Automatically generated by \"dialog --create-rc <file>\"\
49 \n#\
50 \n#\
51 \n# Types of values:\
52 \n#\
53 \n# Number     -  <number>\
54 \n# String     -  \"string\"\
55 \n# Boolean    -  <ON|OFF>\
56 \n# Attribute  -  (foreground,background,highlight?)\
57 \n#\n\n");
58
59   /* Print an entry for each configuration variable */
60   for (i = 0; i < VAR_COUNT; i++) {
61     fprintf(rc_file, "\n# %s\n", vars[i].comment);    /* print comment */
62     switch (vars[i].type) {
63       case VAL_INT:
64         fprintf(rc_file, "%s = %d\n", vars[i].name, *((int *) vars[i].var));
65         break;
66       case VAL_STR:
67         fprintf(rc_file, "%s = \"%s\"\n", vars[i].name, (unsigned char *) vars[i].var);
68         break;
69       case VAL_BOOL:
70         fprintf(rc_file, "%s = %s\n", vars[i].name, *((bool *) vars[i].var) ? "ON" : "OFF");
71         break;
72       case VAL_ATTR:
73         fprintf(rc_file, "%s = %s\n", vars[i].name, attr_to_str(((int *) vars[i].var)[0], ((int *) vars[i].var)[1], ((int *) vars[i].var)[2]));
74         break;
75     }
76   }
77
78   fclose(rc_file);
79 }
80 /* End of create_rc() */
81
82
83 /*
84  * Parse the configuration file and set up variables
85  */
86 int parse_rc(void)
87 {
88   int i, l = 1, parse, fg, bg, hl;
89   unsigned char str[MAX_LEN+1], *var, *value, *tempptr;
90   FILE *rc_file;
91
92   /*
93    *
94    *  At start, 'dialog' determines the settings to use as follows:
95    *
96    *  a) if environment variable DIALOGRC is set, it's value determines the
97    *     name of the configuration file.
98    *
99    *  b) if the file in (a) can't be found, use the file $HOME/.dialogrc
100    *     as the configuration file.
101    *
102    *  c) if the file in (b) can't be found, use compiled in defaults.
103    *
104    */
105
106   if ((tempptr = getenv("DIALOGRC")) != NULL)
107     rc_file = fopen(tempptr, "rt");
108
109   if (tempptr == NULL || rc_file == NULL) {    /* step (a) failed? */
110     /* try step (b) */
111     if ((tempptr = getenv("HOME")) == NULL)
112       return 0;    /* step (b) failed, use default values */
113
114     if (tempptr[0] == '\0' || lastch(tempptr) == '/')
115       sprintf(str, "%s%s", tempptr, DIALOGRC);
116     else
117       sprintf(str, "%s/%s", tempptr, DIALOGRC);
118
119     if ((rc_file = fopen(str, "rt")) == NULL)
120       return 0;    /* step (b) failed, use default values */
121   }
122
123   /* Scan each line and set variables */
124   while (fgets(str, MAX_LEN, rc_file) != NULL) {
125     if (lastch(str) != '\n') {    /* ignore rest of file if line too long */
126       fprintf(stderr, "\nParse error: line %d of configuration file too long.\n", l);
127       fclose(rc_file);
128       return -1;    /* parse aborted */
129     }
130     else {
131       lastch(str) = '\0';
132       parse = parse_line(str, &var, &value);    /* parse current line */
133
134       switch (parse) {
135         case LINE_BLANK:    /* ignore blank lines and comments */
136         case LINE_COMMENT:
137           break;
138         case LINE_OK:
139           /* search table for matching config variable name */
140           for (i = 0; i < VAR_COUNT && strcmp(vars[i].name, var); i++);
141
142           if (i == VAR_COUNT) {    /* no match */
143             fprintf(stderr, "\nParse error: unknown variable at line %d of configuration file.\n", l);
144             return -1;    /* parse aborted */
145           }
146           else {    /* variable found in table, set run time variables */
147             switch (vars[i].type) {
148               case VAL_INT:
149                 *((int *) vars[i].var) = atoi(value);
150                 break;
151               case VAL_STR:
152                 if (!isquote(value[0]) || !isquote(lastch(value)) || strlen(value) < 2) {
153                   fprintf(stderr, "\nParse error: string value expected at line %d of configuration file.\n", l);
154                   return -1;    /* parse aborted */
155                 }
156                 else {
157                   /* remove the (") quotes */
158                   value++;
159                   lastch(value) = '\0';
160                   strcpy((unsigned char *) vars[i].var, value);
161                 }
162                 break;
163               case VAL_BOOL:
164                 if (!strcasecmp(value, "ON"))
165                   *((bool *) vars[i].var) = TRUE;
166                 else if (!strcasecmp(value, "OFF"))
167                   *((bool *) vars[i].var) = FALSE;
168                 else {
169                   fprintf(stderr, "\nParse error: boolean value expected at line %d of configuration file.\n", l);
170                   return -1;    /* parse aborted */
171                 }
172                 break;
173               case VAL_ATTR:
174                 if (str_to_attr(value, &fg, &bg, &hl) == -1) {
175                   fprintf(stderr, "\nParse error: attribute value expected at line %d of configuration file.\n", l);
176                   return -1;    /* parse aborted */
177                 }
178                 ((int *) vars[i].var)[0] = fg;
179                 ((int *) vars[i].var)[1] = bg;
180                 ((int *) vars[i].var)[2] = hl;
181                 break;
182             }
183           }
184           break;
185         case LINE_ERROR:
186           fprintf(stderr, "\nParse error: syntax error at line %d of configuration file.\n", l);
187           return -1;    /* parse aborted */
188       }
189     }
190
191     l++;    /* next line */
192   }
193
194   fclose(rc_file);
195   return 0;    /* parse successful */
196 }
197 /* End of parse_rc() */
198
199
200 /*
201  * Convert an attribute to a string representation like this:
202  *
203  * "(foreground,background,highlight)"
204  */
205 static unsigned char *attr_to_str(int fg, int bg, int hl)
206 {
207   int i;
208   static unsigned char str[MAX_LEN+1];
209
210   strcpy(str, "(");
211   /* foreground */
212   for (i = 0; fg != color_names[i].value; i++);
213   strcat(str, color_names[i].name);
214   strcat(str, ",");
215
216   /* background */
217   for (i = 0; bg != color_names[i].value; i++);
218   strcat(str, color_names[i].name);
219
220   /* highlight */
221   strcat(str, hl ? ",ON)" : ",OFF)");
222
223   return str;
224 }
225 /* End of attr_to_str() */
226
227
228 /*
229  * Extract the foreground, background and highlight values from an attribute
230  * represented as a string in this form:
231  *
232  * "(foreground,background,highlight)"
233  */
234 static int str_to_attr(unsigned char *str, int *fg, int *bg, int *hl)
235 {
236   int i = 0, j, get_fg = 1;
237   unsigned char tempstr[MAX_LEN+1], *part;
238
239   if (str[0] != '(' || lastch(str) != ')')
240     return -1;    /* invalid representation */
241
242   /* remove the parenthesis */
243   strcpy(tempstr, str + 1);
244   lastch(tempstr) = '\0';
245
246
247   /* get foreground and background */
248
249   while (1) {
250     /* skip white space before fg/bg string */
251     while (whitespace(tempstr[i]) && tempstr[i] != '\0') i++;
252     if (tempstr[i] == '\0')
253       return -1;    /* invalid representation */
254     part = tempstr + i;    /* set 'part' to start of fg/bg string */
255
256     /* find end of fg/bg string */
257     while(!whitespace(tempstr[i]) && tempstr[i] != ',' && tempstr[i] != '\0') i++;
258
259     if (tempstr[i] == '\0')
260       return -1;    /* invalid representation */
261     else if (whitespace(tempstr[i])) {   /* not yet ',' */
262       tempstr[i++] = '\0';
263
264       /* skip white space before ',' */
265       while(whitespace(tempstr[i]) && tempstr[i] != '\0') i++;
266
267       if (tempstr[i] != ',')
268         return -1;    /* invalid representation */
269     }
270
271     tempstr[i++] = '\0';    /* skip the ',' */
272     for (j = 0; j < COLOR_COUNT && strcasecmp(part, color_names[j].name); j++);
273     if (j == COLOR_COUNT)    /* invalid color name */
274       return -1;
275     if (get_fg) {
276       *fg = color_names[j].value;
277       get_fg = 0;    /* next we have to get the background */
278     }
279     else {
280       *bg = color_names[j].value;
281       break;
282     }
283   }   /* got foreground and background */
284
285
286   /* get highlight */
287
288   /* skip white space before highlight string */
289   while (whitespace(tempstr[i]) && tempstr[i] != '\0') i++;
290   if (tempstr[i] == '\0')
291     return -1;    /* invalid representation */
292   part = tempstr + i;    /* set 'part' to start of highlight string */
293
294   /* trim trailing white space from highlight string */
295   i = strlen(part) - 1;
296   while(whitespace(part[i])) i--;
297   part[i+1] = '\0';
298
299   if (!strcasecmp(part, "ON"))
300     *hl = TRUE;
301   else if (!strcasecmp(part, "OFF"))
302     *hl = FALSE;
303   else
304     return -1;    /* invalid highlight value */
305
306   return 0;
307 }
308 /* End of str_to_attr() */
309
310
311 /*
312  * Parse a line in the configuration file
313  *
314  * Each line is of the form:  "variable = value". On exit, 'var' will contain
315  * the variable name, and 'value' will contain the value string.
316  *
317  * Return values:
318  *
319  * LINE_BLANK   - line is blank
320  * LINE_COMMENT - line is comment
321  * LINE_OK      - line is ok
322  * LINE_ERROR   - syntax error in line
323  */
324 static int parse_line(unsigned char *line, unsigned char **var, unsigned char **value)
325 {
326   int i = 0;
327
328   /* ignore white space at beginning of line */
329   while(whitespace(line[i]) && line[i] != '\0') i++;
330
331   if (line[i] == '\0')    /* line is blank */
332     return LINE_BLANK;
333   else if (line[i] == '#')    /* line is comment */
334     return LINE_COMMENT;
335   else if (line[i] == '=')    /* variables names can't strart with a '=' */
336     return LINE_ERROR;
337
338   /* set 'var' to variable name */
339   *var = line + i++;    /* skip to next character */
340
341   /* find end of variable name */
342   while(!whitespace(line[i]) && line[i] != '=' && line[i] != '\0') i++;
343
344   if (line[i] == '\0')    /* syntax error */
345     return LINE_ERROR;
346   else if (line[i] == '=')
347     line[i++] = '\0';
348   else {
349     line[i++] = '\0';
350
351     /* skip white space before '=' */
352     while(whitespace(line[i]) && line[i] != '\0') i++;
353
354     if (line[i] != '=')    /* syntax error */
355       return LINE_ERROR;
356     else
357       i++;    /* skip the '=' */
358   }
359
360   /* skip white space after '=' */
361   while(whitespace(line[i]) && line[i] != '\0') i++;
362
363   if (line[i] == '\0')
364     return LINE_ERROR;
365   else
366     *value = line + i;    /* set 'value' to value string */
367
368   /* trim trailing white space from 'value' */
369   i = strlen(*value) - 1;
370   while(whitespace((*value)[i])) i--;
371   (*value)[i+1] = '\0';
372
373   return LINE_OK;    /* no syntax error in line */
374 }
375 /* End of parse_line() */