]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/dialog/rc.c
Merge ACPICA 20121114.
[FreeBSD/FreeBSD.git] / contrib / dialog / rc.c
1 /*
2  *  $Id: rc.c,v 1.49 2011/10/15 00:56:44 tom Exp $
3  *
4  *  rc.c -- routines for processing the configuration file
5  *
6  *  Copyright 2000-2010,2011    Thomas E. Dickey
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU Lesser General Public License, version 2.1
10  *  as published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful, but
13  *  WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this program; if not, write to
19  *      Free Software Foundation, Inc.
20  *      51 Franklin St., Fifth Floor
21  *      Boston, MA 02110, USA.
22  *
23  *  An earlier version of this program lists as authors
24  *      Savio Lam (lam836@cs.cuhk.hk)
25  */
26
27 #include <dialog.h>
28
29 #include <dlg_keys.h>
30
31 #ifdef HAVE_COLOR
32 #include <dlg_colors.h>
33
34 /*
35  * For matching color names with color values
36  */
37 static const color_names_st color_names[] =
38 {
39 #ifdef HAVE_USE_DEFAULT_COLORS
40     {"DEFAULT", -1},
41 #endif
42     {"BLACK", COLOR_BLACK},
43     {"RED", COLOR_RED},
44     {"GREEN", COLOR_GREEN},
45     {"YELLOW", COLOR_YELLOW},
46     {"BLUE", COLOR_BLUE},
47     {"MAGENTA", COLOR_MAGENTA},
48     {"CYAN", COLOR_CYAN},
49     {"WHITE", COLOR_WHITE},
50 };                              /* color names */
51 #define COLOR_COUNT     (sizeof(color_names) / sizeof(color_names[0]))
52 #endif /* HAVE_COLOR */
53
54 #define GLOBALRC "/etc/dialogrc"
55 #define DIALOGRC ".dialogrc"
56
57 /* Types of values */
58 #define VAL_INT  0
59 #define VAL_STR  1
60 #define VAL_BOOL 2
61
62 /* Type of line in configuration file */
63 typedef enum {
64     LINE_ERROR = -1,
65     LINE_EQUALS,
66     LINE_EMPTY
67 } PARSE_LINE;
68
69 /* number of configuration variables */
70 #define VAR_COUNT        (sizeof(vars) / sizeof(vars_st))
71
72 /* check if character is white space */
73 #define whitespace(c)    (c == ' ' || c == TAB)
74
75 /* check if character is string quoting characters */
76 #define isquote(c)       (c == '"' || c == '\'')
77
78 /* get last character of string */
79 #define lastch(str)      str[strlen(str)-1]
80
81 /*
82  * Configuration variables
83  */
84 typedef struct {
85     const char *name;           /* name of configuration variable as in DIALOGRC */
86     void *var;                  /* address of actual variable to change */
87     int type;                   /* type of value */
88     const char *comment;        /* comment to put in "rc" file */
89 } vars_st;
90
91 /*
92  * This table should contain only references to dialog_state, since dialog_vars
93  * is reset specially in dialog.c before each widget.
94  */
95 static const vars_st vars[] =
96 {
97     {"aspect",
98      &dialog_state.aspect_ratio,
99      VAL_INT,
100      "Set aspect-ration."},
101
102     {"separate_widget",
103      &dialog_state.separate_str,
104      VAL_STR,
105      "Set separator (for multiple widgets output)."},
106
107     {"tab_len",
108      &dialog_state.tab_len,
109      VAL_INT,
110      "Set tab-length (for textbox tab-conversion)."},
111
112     {"visit_items",
113      &dialog_state.visit_items,
114      VAL_BOOL,
115      "Make tab-traversal for checklist, etc., include the list."},
116
117 #ifdef HAVE_COLOR
118     {"use_shadow",
119      &dialog_state.use_shadow,
120      VAL_BOOL,
121      "Shadow dialog boxes? This also turns on color."},
122
123     {"use_colors",
124      &dialog_state.use_colors,
125      VAL_BOOL,
126      "Turn color support ON or OFF"},
127 #endif                          /* HAVE_COLOR */
128 };                              /* vars */
129
130 static int
131 skip_whitespace(char *str, int n)
132 {
133     while (whitespace(str[n]) && str[n] != '\0')
134         n++;
135     return n;
136 }
137
138 static int
139 skip_keyword(char *str, int n)
140 {
141     while (isalnum(UCH(str[n])) && str[n] != '\0')
142         n++;
143     return n;
144 }
145
146 static int
147 find_vars(char *name)
148 {
149     int result = -1;
150     unsigned i;
151
152     for (i = 0; i < VAR_COUNT; i++) {
153         if (dlg_strcmp(vars[i].name, name) == 0) {
154             result = (int) i;
155             break;
156         }
157     }
158     return result;
159 }
160
161 #ifdef HAVE_COLOR
162 static int
163 find_color(char *name)
164 {
165     int result = -1;
166     int i;
167     int limit = dlg_color_count();
168
169     for (i = 0; i < limit; i++) {
170         if (dlg_strcmp(dlg_color_table[i].name, name) == 0) {
171             result = i;
172             break;
173         }
174     }
175     return result;
176 }
177
178 /*
179  * Convert an attribute to a string representation like this:
180  *
181  * "(foreground,background,highlight)"
182  */
183 static char *
184 attr_to_str(char *str, int fg, int bg, int hl)
185 {
186     int i;
187
188     strcpy(str, "(");
189     /* foreground */
190     for (i = 0; fg != color_names[i].value; i++) ;
191     strcat(str, color_names[i].name);
192     strcat(str, ",");
193
194     /* background */
195     for (i = 0; bg != color_names[i].value; i++) ;
196     strcat(str, color_names[i].name);
197
198     /* highlight */
199     strcat(str, hl ? ",ON)" : ",OFF)");
200
201     return str;
202 }
203
204 /*
205  * Extract the foreground, background and highlight values from an attribute
206  * represented as a string in one of two forms:
207  *
208  * "(foreground,background,highlight)"
209  " "xxxx_color"
210  */
211 static int
212 str_to_attr(char *str, int *fg, int *bg, int *hl)
213 {
214     int i = 0, get_fg = 1;
215     unsigned j;
216     char tempstr[MAX_LEN + 1], *part;
217
218     if (str[0] != '(' || lastch(str) != ')') {
219         if ((i = find_color(str)) >= 0) {
220             *fg = dlg_color_table[i].fg;
221             *bg = dlg_color_table[i].bg;
222             *hl = dlg_color_table[i].hilite;
223             return 0;
224         }
225         return -1;              /* invalid representation */
226     }
227
228     /* remove the parenthesis */
229     strcpy(tempstr, str + 1);
230     lastch(tempstr) = '\0';
231
232     /* get foreground and background */
233
234     while (1) {
235         /* skip white space before fg/bg string */
236         i = skip_whitespace(tempstr, i);
237         if (tempstr[i] == '\0')
238             return -1;          /* invalid representation */
239         part = tempstr + i;     /* set 'part' to start of fg/bg string */
240
241         /* find end of fg/bg string */
242         while (!whitespace(tempstr[i]) && tempstr[i] != ','
243                && tempstr[i] != '\0')
244             i++;
245
246         if (tempstr[i] == '\0')
247             return -1;          /* invalid representation */
248         else if (whitespace(tempstr[i])) {      /* not yet ',' */
249             tempstr[i++] = '\0';
250
251             /* skip white space before ',' */
252             i = skip_whitespace(tempstr, i);
253             if (tempstr[i] != ',')
254                 return -1;      /* invalid representation */
255         }
256         tempstr[i++] = '\0';    /* skip the ',' */
257         for (j = 0; j < COLOR_COUNT && dlg_strcmp(part, color_names[j].name);
258              j++) ;
259         if (j == COLOR_COUNT)   /* invalid color name */
260             return -1;
261         if (get_fg) {
262             *fg = color_names[j].value;
263             get_fg = 0;         /* next we have to get the background */
264         } else {
265             *bg = color_names[j].value;
266             break;
267         }
268     }                           /* got foreground and background */
269
270     /* get highlight */
271
272     /* skip white space before highlight string */
273     i = skip_whitespace(tempstr, i);
274     if (tempstr[i] == '\0')
275         return -1;              /* invalid representation */
276     part = tempstr + i;         /* set 'part' to start of highlight string */
277
278     /* trim trailing white space from highlight string */
279     i = (int) strlen(part) - 1;
280     while (whitespace(part[i]) && i > 0)
281         i--;
282     part[i + 1] = '\0';
283
284     if (!dlg_strcmp(part, "ON"))
285         *hl = TRUE;
286     else if (!dlg_strcmp(part, "OFF"))
287         *hl = FALSE;
288     else
289         return -1;              /* invalid highlight value */
290
291     return 0;
292 }
293 #endif /* HAVE_COLOR */
294
295 /*
296  * Check if the line begins with a special keyword; if so, return true while
297  * pointing params to its parameters.
298  */
299 static int
300 begins_with(char *line, const char *keyword, char **params)
301 {
302     int i = skip_whitespace(line, 0);
303     int j = skip_keyword(line, i);
304
305     if ((j - i) == (int) strlen(keyword)) {
306         char save = line[j];
307         line[j] = 0;
308         if (!dlg_strcmp(keyword, line + i)) {
309             *params = line + skip_whitespace(line, j + 1);
310             return 1;
311         }
312         line[j] = save;
313     }
314
315     return 0;
316 }
317
318 /*
319  * Parse a line in the configuration file
320  *
321  * Each line is of the form:  "variable = value". On exit, 'var' will contain
322  * the variable name, and 'value' will contain the value string.
323  *
324  * Return values:
325  *
326  * LINE_EMPTY   - line is blank or comment
327  * LINE_EQUALS  - line contains "variable = value"
328  * LINE_ERROR   - syntax error in line
329  */
330 static PARSE_LINE
331 parse_line(char *line, char **var, char **value)
332 {
333     int i = 0;
334
335     /* ignore white space at beginning of line */
336     i = skip_whitespace(line, i);
337
338     if (line[i] == '\0')        /* line is blank */
339         return LINE_EMPTY;
340     else if (line[i] == '#')    /* line is comment */
341         return LINE_EMPTY;
342     else if (line[i] == '=')    /* variable names cannot start with a '=' */
343         return LINE_ERROR;
344
345     /* set 'var' to variable name */
346     *var = line + i++;          /* skip to next character */
347
348     /* find end of variable name */
349     while (!whitespace(line[i]) && line[i] != '=' && line[i] != '\0')
350         i++;
351
352     if (line[i] == '\0')        /* syntax error */
353         return LINE_ERROR;
354     else if (line[i] == '=')
355         line[i++] = '\0';
356     else {
357         line[i++] = '\0';
358
359         /* skip white space before '=' */
360         i = skip_whitespace(line, i);
361
362         if (line[i] != '=')     /* syntax error */
363             return LINE_ERROR;
364         else
365             i++;                /* skip the '=' */
366     }
367
368     /* skip white space after '=' */
369     i = skip_whitespace(line, i);
370
371     if (line[i] == '\0')
372         return LINE_ERROR;
373     else
374         *value = line + i;      /* set 'value' to value string */
375
376     /* trim trailing white space from 'value' */
377     i = (int) strlen(*value) - 1;
378     while (whitespace((*value)[i]) && i > 0)
379         i--;
380     (*value)[i + 1] = '\0';
381
382     return LINE_EQUALS;         /* no syntax error in line */
383 }
384
385 /*
386  * Create the configuration file
387  */
388 void
389 dlg_create_rc(const char *filename)
390 {
391     unsigned i;
392     FILE *rc_file;
393
394     if ((rc_file = fopen(filename, "wt")) == NULL)
395         dlg_exiterr("Error opening file for writing in dlg_create_rc().");
396
397     fprintf(rc_file, "#\n\
398 # Run-time configuration file for dialog\n\
399 #\n\
400 # Automatically generated by \"dialog --create-rc <file>\"\n\
401 #\n\
402 #\n\
403 # Types of values:\n\
404 #\n\
405 # Number     -  <number>\n\
406 # String     -  \"string\"\n\
407 # Boolean    -  <ON|OFF>\n"
408 #ifdef HAVE_COLOR
409             "\
410 # Attribute  -  (foreground,background,highlight?)\n"
411 #endif
412         );
413
414     /* Print an entry for each configuration variable */
415     for (i = 0; i < VAR_COUNT; i++) {
416         fprintf(rc_file, "\n# %s\n", vars[i].comment);
417         switch (vars[i].type) {
418         case VAL_INT:
419             fprintf(rc_file, "%s = %d\n", vars[i].name,
420                     *((int *) vars[i].var));
421             break;
422         case VAL_STR:
423             fprintf(rc_file, "%s = \"%s\"\n", vars[i].name,
424                     (char *) vars[i].var);
425             break;
426         case VAL_BOOL:
427             fprintf(rc_file, "%s = %s\n", vars[i].name,
428                     *((bool *) vars[i].var) ? "ON" : "OFF");
429             break;
430         }
431     }
432 #ifdef HAVE_COLOR
433     for (i = 0; i < (unsigned) dlg_color_count(); ++i) {
434         char buffer[MAX_LEN + 1];
435         unsigned j;
436         bool repeat = FALSE;
437
438         fprintf(rc_file, "\n# %s\n", dlg_color_table[i].comment);
439         for (j = 0; j != i; ++j) {
440             if (dlg_color_table[i].fg == dlg_color_table[j].fg
441                 && dlg_color_table[i].bg == dlg_color_table[j].bg
442                 && dlg_color_table[i].hilite == dlg_color_table[j].hilite) {
443                 fprintf(rc_file, "%s = %s\n",
444                         dlg_color_table[i].name,
445                         dlg_color_table[j].name);
446                 repeat = TRUE;
447                 break;
448             }
449         }
450
451         if (!repeat) {
452             fprintf(rc_file, "%s = %s\n", dlg_color_table[i].name,
453                     attr_to_str(buffer,
454                                 dlg_color_table[i].fg,
455                                 dlg_color_table[i].bg,
456                                 dlg_color_table[i].hilite));
457         }
458     }
459 #endif /* HAVE_COLOR */
460     dlg_dump_keys(rc_file);
461
462     (void) fclose(rc_file);
463 }
464
465 /*
466  * Parse the configuration file and set up variables
467  */
468 int
469 dlg_parse_rc(void)
470 {
471     int i;
472     int l = 1;
473     PARSE_LINE parse;
474     char str[MAX_LEN + 1];
475     char *var;
476     char *value;
477     char *tempptr;
478     int result = 0;
479     FILE *rc_file = 0;
480     char *params;
481
482     /*
483      *  At startup, dialog determines the settings to use as follows:
484      *
485      *  a) if the environment variable $DIALOGRC is set, its value determines
486      *     the name of the configuration file.
487      *
488      *  b) if the file in (a) can't be found, use the file $HOME/.dialogrc
489      *     as the configuration file.
490      *
491      *  c) if the file in (b) can't be found, try using the GLOBALRC file.
492      *     Usually this will be /etc/dialogrc.
493      *
494      *  d) if the file in (c) cannot be found, use the compiled-in defaults.
495      */
496
497     /* try step (a) */
498     if ((tempptr = getenv("DIALOGRC")) != NULL)
499         rc_file = fopen(tempptr, "rt");
500
501     if (rc_file == NULL) {      /* step (a) failed? */
502         /* try step (b) */
503         if ((tempptr = getenv("HOME")) != NULL
504             && strlen(tempptr) < MAX_LEN - (sizeof(DIALOGRC) + 3)) {
505             if (tempptr[0] == '\0' || lastch(tempptr) == '/')
506                 sprintf(str, "%s%s", tempptr, DIALOGRC);
507             else
508                 sprintf(str, "%s/%s", tempptr, DIALOGRC);
509             rc_file = fopen(tempptr = str, "rt");
510         }
511     }
512
513     if (rc_file == NULL) {      /* step (b) failed? */
514         /* try step (c) */
515         strcpy(str, GLOBALRC);
516         if ((rc_file = fopen(tempptr = str, "rt")) == NULL)
517             return 0;           /* step (c) failed, use default values */
518     }
519
520     DLG_TRACE(("opened rc file \"%s\"\n", tempptr));
521     /* Scan each line and set variables */
522     while ((result == 0) && (fgets(str, MAX_LEN, rc_file) != NULL)) {
523         DLG_TRACE(("rc:%s", str));
524         if (*str == '\0' || lastch(str) != '\n') {
525             /* ignore rest of file if line too long */
526             fprintf(stderr, "\nParse error: line %d of configuration"
527                     " file too long.\n", l);
528             result = -1;        /* parse aborted */
529             break;
530         }
531
532         lastch(str) = '\0';
533         if (begins_with(str, "bindkey", &params)) {
534             if (!dlg_parse_bindkey(params)) {
535                 fprintf(stderr, "\nParse error: line %d of configuration\n", l);
536                 result = -1;
537             }
538             continue;
539         }
540         parse = parse_line(str, &var, &value);  /* parse current line */
541
542         switch (parse) {
543         case LINE_EMPTY:        /* ignore blank lines and comments */
544             break;
545         case LINE_EQUALS:
546             /* search table for matching config variable name */
547             if ((i = find_vars(var)) >= 0) {
548                 switch (vars[i].type) {
549                 case VAL_INT:
550                     *((int *) vars[i].var) = atoi(value);
551                     break;
552                 case VAL_STR:
553                     if (!isquote(value[0]) || !isquote(lastch(value))
554                         || strlen(value) < 2) {
555                         fprintf(stderr, "\nParse error: string value "
556                                 "expected at line %d of configuration "
557                                 "file.\n", l);
558                         result = -1;    /* parse aborted */
559                     } else {
560                         /* remove the (") quotes */
561                         value++;
562                         lastch(value) = '\0';
563                         strcpy((char *) vars[i].var, value);
564                     }
565                     break;
566                 case VAL_BOOL:
567                     if (!dlg_strcmp(value, "ON"))
568                         *((bool *) vars[i].var) = TRUE;
569                     else if (!dlg_strcmp(value, "OFF"))
570                         *((bool *) vars[i].var) = FALSE;
571                     else {
572                         fprintf(stderr, "\nParse error: boolean value "
573                                 "expected at line %d of configuration "
574                                 "file (found %s).\n", l, value);
575                         result = -1;    /* parse aborted */
576                     }
577                     break;
578                 }
579 #ifdef HAVE_COLOR
580             } else if ((i = find_color(var)) >= 0) {
581                 int fg = 0;
582                 int bg = 0;
583                 int hl = 0;
584                 if (str_to_attr(value, &fg, &bg, &hl) == -1) {
585                     fprintf(stderr, "\nParse error: attribute "
586                             "value expected at line %d of configuration "
587                             "file.\n", l);
588                     result = -1;        /* parse aborted */
589                 } else {
590                     dlg_color_table[i].fg = fg;
591                     dlg_color_table[i].bg = bg;
592                     dlg_color_table[i].hilite = hl;
593                 }
594             } else {
595 #endif /* HAVE_COLOR */
596                 fprintf(stderr, "\nParse error: unknown variable "
597                         "at line %d of configuration file:\n\t%s\n", l, var);
598                 result = -1;    /* parse aborted */
599             }
600             break;
601         case LINE_ERROR:
602             fprintf(stderr, "\nParse error: syntax error at line %d of "
603                     "configuration file.\n", l);
604             result = -1;        /* parse aborted */
605             break;
606         }
607         l++;                    /* next line */
608     }
609
610     (void) fclose(rc_file);
611     return result;
612 }