vkernel - Fixup previous commit, where some bits got lost during rebaseing.
[dragonfly.git] / contrib / dialog / rc.c
blob4a1345508961e8d29bffe91f4f137e836dec4e6f
1 /*
2 * $Id: rc.c,v 1.51 2012/11/30 21:32:39 tom Exp $
4 * rc.c -- routines for processing the configuration file
6 * Copyright 2000-2011,2012 Thomas E. Dickey
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.
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.
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.
23 * An earlier version of this program lists as authors
24 * Savio Lam (lam836@cs.cuhk.hk)
27 #include <dialog.h>
29 #include <dlg_keys.h>
31 #ifdef HAVE_COLOR
32 #include <dlg_colors.h>
35 * For matching color names with color values
37 static const color_names_st color_names[] =
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 */
54 #define GLOBALRC "/etc/dialogrc"
55 #define DIALOGRC ".dialogrc"
57 /* Types of values */
58 #define VAL_INT 0
59 #define VAL_STR 1
60 #define VAL_BOOL 2
62 /* Type of line in configuration file */
63 typedef enum {
64 LINE_ERROR = -1,
65 LINE_EQUALS,
66 LINE_EMPTY
67 } PARSE_LINE;
69 /* number of configuration variables */
70 #define VAR_COUNT (sizeof(vars) / sizeof(vars_st))
72 /* check if character is white space */
73 #define whitespace(c) (c == ' ' || c == TAB)
75 /* check if character is string quoting characters */
76 #define isquote(c) (c == '"' || c == '\'')
78 /* get last character of string */
79 #define lastch(str) str[strlen(str)-1]
82 * Configuration variables
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;
92 * This table should contain only references to dialog_state, since dialog_vars
93 * is reset specially in dialog.c before each widget.
95 static const vars_st vars[] =
97 {"aspect",
98 &dialog_state.aspect_ratio,
99 VAL_INT,
100 "Set aspect-ration."},
102 {"separate_widget",
103 &dialog_state.separate_str,
104 VAL_STR,
105 "Set separator (for multiple widgets output)."},
107 {"tab_len",
108 &dialog_state.tab_len,
109 VAL_INT,
110 "Set tab-length (for textbox tab-conversion)."},
112 {"visit_items",
113 &dialog_state.visit_items,
114 VAL_BOOL,
115 "Make tab-traversal for checklist, etc., include the list."},
117 #ifdef HAVE_COLOR
118 {"use_shadow",
119 &dialog_state.use_shadow,
120 VAL_BOOL,
121 "Shadow dialog boxes? This also turns on color."},
123 {"use_colors",
124 &dialog_state.use_colors,
125 VAL_BOOL,
126 "Turn color support ON or OFF"},
127 #endif /* HAVE_COLOR */
128 }; /* vars */
130 static int
131 skip_whitespace(char *str, int n)
133 while (whitespace(str[n]) && str[n] != '\0')
134 n++;
135 return n;
138 static int
139 skip_keyword(char *str, int n)
141 while (isalnum(UCH(str[n])) && str[n] != '\0')
142 n++;
143 return n;
146 static int
147 find_vars(char *name)
149 int result = -1;
150 unsigned i;
152 for (i = 0; i < VAR_COUNT; i++) {
153 if (dlg_strcmp(vars[i].name, name) == 0) {
154 result = (int) i;
155 break;
158 return result;
161 #ifdef HAVE_COLOR
162 static int
163 find_color(char *name)
165 int result = -1;
166 int i;
167 int limit = dlg_color_count();
169 for (i = 0; i < limit; i++) {
170 if (dlg_strcmp(dlg_color_table[i].name, name) == 0) {
171 result = i;
172 break;
175 return result;
179 * Convert an attribute to a string representation like this:
181 * "(foreground,background,highlight)"
183 static char *
184 attr_to_str(char *str, int fg, int bg, int hl)
186 int i;
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, ",");
194 /* background */
195 for (i = 0; bg != color_names[i].value; i++) ;
196 strcat(str, color_names[i].name);
198 /* highlight */
199 strcat(str, hl ? ",ON)" : ",OFF)");
201 return str;
205 * Extract the foreground, background and highlight values from an attribute
206 * represented as a string in one of two forms:
208 * "(foreground,background,highlight)"
209 " "xxxx_color"
211 static int
212 str_to_attr(char *str, int *fg, int *bg, int *hl)
214 int i = 0, get_fg = 1;
215 unsigned j;
216 char tempstr[MAX_LEN + 1], *part;
217 size_t have;
219 if (str[0] != '(' || lastch(str) != ')') {
220 if ((i = find_color(str)) >= 0) {
221 *fg = dlg_color_table[i].fg;
222 *bg = dlg_color_table[i].bg;
223 *hl = dlg_color_table[i].hilite;
224 return 0;
226 return -1; /* invalid representation */
229 /* remove the parenthesis */
230 have = strlen(str);
231 if (have > MAX_LEN) {
232 have = MAX_LEN - 1;
233 } else {
234 have -= 2;
236 memcpy(tempstr, str + 1, have);
237 tempstr[have] = '\0';
239 /* get foreground and background */
241 while (1) {
242 /* skip white space before fg/bg string */
243 i = skip_whitespace(tempstr, i);
244 if (tempstr[i] == '\0')
245 return -1; /* invalid representation */
246 part = tempstr + i; /* set 'part' to start of fg/bg string */
248 /* find end of fg/bg string */
249 while (!whitespace(tempstr[i]) && tempstr[i] != ','
250 && tempstr[i] != '\0')
251 i++;
253 if (tempstr[i] == '\0')
254 return -1; /* invalid representation */
255 else if (whitespace(tempstr[i])) { /* not yet ',' */
256 tempstr[i++] = '\0';
258 /* skip white space before ',' */
259 i = skip_whitespace(tempstr, i);
260 if (tempstr[i] != ',')
261 return -1; /* invalid representation */
263 tempstr[i++] = '\0'; /* skip the ',' */
264 for (j = 0; j < COLOR_COUNT && dlg_strcmp(part, color_names[j].name);
265 j++) ;
266 if (j == COLOR_COUNT) /* invalid color name */
267 return -1;
268 if (get_fg) {
269 *fg = color_names[j].value;
270 get_fg = 0; /* next we have to get the background */
271 } else {
272 *bg = color_names[j].value;
273 break;
275 } /* got foreground and background */
277 /* get highlight */
279 /* skip white space before highlight string */
280 i = skip_whitespace(tempstr, i);
281 if (tempstr[i] == '\0')
282 return -1; /* invalid representation */
283 part = tempstr + i; /* set 'part' to start of highlight string */
285 /* trim trailing white space from highlight string */
286 i = (int) strlen(part) - 1;
287 while (whitespace(part[i]) && i > 0)
288 i--;
289 part[i + 1] = '\0';
291 if (!dlg_strcmp(part, "ON"))
292 *hl = TRUE;
293 else if (!dlg_strcmp(part, "OFF"))
294 *hl = FALSE;
295 else
296 return -1; /* invalid highlight value */
298 return 0;
300 #endif /* HAVE_COLOR */
303 * Check if the line begins with a special keyword; if so, return true while
304 * pointing params to its parameters.
306 static int
307 begins_with(char *line, const char *keyword, char **params)
309 int i = skip_whitespace(line, 0);
310 int j = skip_keyword(line, i);
312 if ((j - i) == (int) strlen(keyword)) {
313 char save = line[j];
314 line[j] = 0;
315 if (!dlg_strcmp(keyword, line + i)) {
316 *params = line + skip_whitespace(line, j + 1);
317 return 1;
319 line[j] = save;
322 return 0;
326 * Parse a line in the configuration file
328 * Each line is of the form: "variable = value". On exit, 'var' will contain
329 * the variable name, and 'value' will contain the value string.
331 * Return values:
333 * LINE_EMPTY - line is blank or comment
334 * LINE_EQUALS - line contains "variable = value"
335 * LINE_ERROR - syntax error in line
337 static PARSE_LINE
338 parse_line(char *line, char **var, char **value)
340 int i = 0;
342 /* ignore white space at beginning of line */
343 i = skip_whitespace(line, i);
345 if (line[i] == '\0') /* line is blank */
346 return LINE_EMPTY;
347 else if (line[i] == '#') /* line is comment */
348 return LINE_EMPTY;
349 else if (line[i] == '=') /* variable names cannot start with a '=' */
350 return LINE_ERROR;
352 /* set 'var' to variable name */
353 *var = line + i++; /* skip to next character */
355 /* find end of variable name */
356 while (!whitespace(line[i]) && line[i] != '=' && line[i] != '\0')
357 i++;
359 if (line[i] == '\0') /* syntax error */
360 return LINE_ERROR;
361 else if (line[i] == '=')
362 line[i++] = '\0';
363 else {
364 line[i++] = '\0';
366 /* skip white space before '=' */
367 i = skip_whitespace(line, i);
369 if (line[i] != '=') /* syntax error */
370 return LINE_ERROR;
371 else
372 i++; /* skip the '=' */
375 /* skip white space after '=' */
376 i = skip_whitespace(line, i);
378 if (line[i] == '\0')
379 return LINE_ERROR;
380 else
381 *value = line + i; /* set 'value' to value string */
383 /* trim trailing white space from 'value' */
384 i = (int) strlen(*value) - 1;
385 while (whitespace((*value)[i]) && i > 0)
386 i--;
387 (*value)[i + 1] = '\0';
389 return LINE_EQUALS; /* no syntax error in line */
393 * Create the configuration file
395 void
396 dlg_create_rc(const char *filename)
398 unsigned i;
399 FILE *rc_file;
401 if ((rc_file = fopen(filename, "wt")) == NULL)
402 dlg_exiterr("Error opening file for writing in dlg_create_rc().");
404 fprintf(rc_file, "#\n\
405 # Run-time configuration file for dialog\n\
406 #\n\
407 # Automatically generated by \"dialog --create-rc <file>\"\n\
408 #\n\
409 #\n\
410 # Types of values:\n\
411 #\n\
412 # Number - <number>\n\
413 # String - \"string\"\n\
414 # Boolean - <ON|OFF>\n"
415 #ifdef HAVE_COLOR
417 # Attribute - (foreground,background,highlight?)\n"
418 #endif
421 /* Print an entry for each configuration variable */
422 for (i = 0; i < VAR_COUNT; i++) {
423 fprintf(rc_file, "\n# %s\n", vars[i].comment);
424 switch (vars[i].type) {
425 case VAL_INT:
426 fprintf(rc_file, "%s = %d\n", vars[i].name,
427 *((int *) vars[i].var));
428 break;
429 case VAL_STR:
430 fprintf(rc_file, "%s = \"%s\"\n", vars[i].name,
431 (char *) vars[i].var);
432 break;
433 case VAL_BOOL:
434 fprintf(rc_file, "%s = %s\n", vars[i].name,
435 *((bool *) vars[i].var) ? "ON" : "OFF");
436 break;
439 #ifdef HAVE_COLOR
440 for (i = 0; i < (unsigned) dlg_color_count(); ++i) {
441 char buffer[MAX_LEN + 1];
442 unsigned j;
443 bool repeat = FALSE;
445 fprintf(rc_file, "\n# %s\n", dlg_color_table[i].comment);
446 for (j = 0; j != i; ++j) {
447 if (dlg_color_table[i].fg == dlg_color_table[j].fg
448 && dlg_color_table[i].bg == dlg_color_table[j].bg
449 && dlg_color_table[i].hilite == dlg_color_table[j].hilite) {
450 fprintf(rc_file, "%s = %s\n",
451 dlg_color_table[i].name,
452 dlg_color_table[j].name);
453 repeat = TRUE;
454 break;
458 if (!repeat) {
459 fprintf(rc_file, "%s = %s\n", dlg_color_table[i].name,
460 attr_to_str(buffer,
461 dlg_color_table[i].fg,
462 dlg_color_table[i].bg,
463 dlg_color_table[i].hilite));
466 #endif /* HAVE_COLOR */
467 dlg_dump_keys(rc_file);
469 (void) fclose(rc_file);
473 * Parse the configuration file and set up variables
476 dlg_parse_rc(void)
478 int i;
479 int l = 1;
480 PARSE_LINE parse;
481 char str[MAX_LEN + 1];
482 char *var;
483 char *value;
484 char *tempptr;
485 int result = 0;
486 FILE *rc_file = 0;
487 char *params;
490 * At startup, dialog determines the settings to use as follows:
492 * a) if the environment variable $DIALOGRC is set, its value determines
493 * the name of the configuration file.
495 * b) if the file in (a) can't be found, use the file $HOME/.dialogrc
496 * as the configuration file.
498 * c) if the file in (b) can't be found, try using the GLOBALRC file.
499 * Usually this will be /etc/dialogrc.
501 * d) if the file in (c) cannot be found, use the compiled-in defaults.
504 /* try step (a) */
505 if ((tempptr = getenv("DIALOGRC")) != NULL)
506 rc_file = fopen(tempptr, "rt");
508 if (rc_file == NULL) { /* step (a) failed? */
509 /* try step (b) */
510 if ((tempptr = getenv("HOME")) != NULL
511 && strlen(tempptr) < MAX_LEN - (sizeof(DIALOGRC) + 3)) {
512 if (tempptr[0] == '\0' || lastch(tempptr) == '/')
513 sprintf(str, "%s%s", tempptr, DIALOGRC);
514 else
515 sprintf(str, "%s/%s", tempptr, DIALOGRC);
516 rc_file = fopen(tempptr = str, "rt");
520 if (rc_file == NULL) { /* step (b) failed? */
521 /* try step (c) */
522 strcpy(str, GLOBALRC);
523 if ((rc_file = fopen(tempptr = str, "rt")) == NULL)
524 return 0; /* step (c) failed, use default values */
527 DLG_TRACE(("opened rc file \"%s\"\n", tempptr));
528 /* Scan each line and set variables */
529 while ((result == 0) && (fgets(str, MAX_LEN, rc_file) != NULL)) {
530 DLG_TRACE(("rc:%s", str));
531 if (*str == '\0' || lastch(str) != '\n') {
532 /* ignore rest of file if line too long */
533 fprintf(stderr, "\nParse error: line %d of configuration"
534 " file too long.\n", l);
535 result = -1; /* parse aborted */
536 break;
539 lastch(str) = '\0';
540 if (begins_with(str, "bindkey", &params)) {
541 if (!dlg_parse_bindkey(params)) {
542 fprintf(stderr, "\nParse error: line %d of configuration\n", l);
543 result = -1;
545 continue;
547 parse = parse_line(str, &var, &value); /* parse current line */
549 switch (parse) {
550 case LINE_EMPTY: /* ignore blank lines and comments */
551 break;
552 case LINE_EQUALS:
553 /* search table for matching config variable name */
554 if ((i = find_vars(var)) >= 0) {
555 switch (vars[i].type) {
556 case VAL_INT:
557 *((int *) vars[i].var) = atoi(value);
558 break;
559 case VAL_STR:
560 if (!isquote(value[0]) || !isquote(lastch(value))
561 || strlen(value) < 2) {
562 fprintf(stderr, "\nParse error: string value "
563 "expected at line %d of configuration "
564 "file.\n", l);
565 result = -1; /* parse aborted */
566 } else {
567 /* remove the (") quotes */
568 value++;
569 lastch(value) = '\0';
570 strcpy((char *) vars[i].var, value);
572 break;
573 case VAL_BOOL:
574 if (!dlg_strcmp(value, "ON"))
575 *((bool *) vars[i].var) = TRUE;
576 else if (!dlg_strcmp(value, "OFF"))
577 *((bool *) vars[i].var) = FALSE;
578 else {
579 fprintf(stderr, "\nParse error: boolean value "
580 "expected at line %d of configuration "
581 "file (found %s).\n", l, value);
582 result = -1; /* parse aborted */
584 break;
586 #ifdef HAVE_COLOR
587 } else if ((i = find_color(var)) >= 0) {
588 int fg = 0;
589 int bg = 0;
590 int hl = 0;
591 if (str_to_attr(value, &fg, &bg, &hl) == -1) {
592 fprintf(stderr, "\nParse error: attribute "
593 "value expected at line %d of configuration "
594 "file.\n", l);
595 result = -1; /* parse aborted */
596 } else {
597 dlg_color_table[i].fg = fg;
598 dlg_color_table[i].bg = bg;
599 dlg_color_table[i].hilite = hl;
601 } else {
602 #endif /* HAVE_COLOR */
603 fprintf(stderr, "\nParse error: unknown variable "
604 "at line %d of configuration file:\n\t%s\n", l, var);
605 result = -1; /* parse aborted */
607 break;
608 case LINE_ERROR:
609 fprintf(stderr, "\nParse error: syntax error at line %d of "
610 "configuration file.\n", l);
611 result = -1; /* parse aborted */
612 break;
614 l++; /* next line */
617 (void) fclose(rc_file);
618 return result;