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