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)
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
42 {"BLACK", COLOR_BLACK
},
44 {"GREEN", COLOR_GREEN
},
45 {"YELLOW", COLOR_YELLOW
},
47 {"MAGENTA", COLOR_MAGENTA
},
49 {"WHITE", COLOR_WHITE
},
51 #define COLOR_COUNT (sizeof(color_names) / sizeof(color_names[0]))
52 #endif /* HAVE_COLOR */
54 #define GLOBALRC "/etc/dialogrc"
55 #define DIALOGRC ".dialogrc"
62 /* Type of line in configuration file */
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
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 */
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
[] =
98 &dialog_state
.aspect_ratio
,
100 "Set aspect-ration."},
103 &dialog_state
.separate_str
,
105 "Set separator (for multiple widgets output)."},
108 &dialog_state
.tab_len
,
110 "Set tab-length (for textbox tab-conversion)."},
113 &dialog_state
.visit_items
,
115 "Make tab-traversal for checklist, etc., include the list."},
119 &dialog_state
.use_shadow
,
121 "Shadow dialog boxes? This also turns on color."},
124 &dialog_state
.use_colors
,
126 "Turn color support ON or OFF"},
127 #endif /* HAVE_COLOR */
131 skip_whitespace(char *str
, int n
)
133 while (whitespace(str
[n
]) && str
[n
] != '\0')
139 skip_keyword(char *str
, int n
)
141 while (isalnum(UCH(str
[n
])) && str
[n
] != '\0')
147 find_vars(char *name
)
152 for (i
= 0; i
< VAR_COUNT
; i
++) {
153 if (dlg_strcmp(vars
[i
].name
, name
) == 0) {
163 find_color(char *name
)
167 int limit
= dlg_color_count();
169 for (i
= 0; i
< limit
; i
++) {
170 if (dlg_strcmp(dlg_color_table
[i
].name
, name
) == 0) {
179 * Convert an attribute to a string representation like this:
181 * "(foreground,background,highlight)"
184 attr_to_str(char *str
, int fg
, int bg
, int hl
)
190 for (i
= 0; fg
!= color_names
[i
].value
; i
++) ;
191 strcat(str
, color_names
[i
].name
);
195 for (i
= 0; bg
!= color_names
[i
].value
; i
++) ;
196 strcat(str
, color_names
[i
].name
);
199 strcat(str
, hl
? ",ON)" : ",OFF)");
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)"
212 str_to_attr(char *str
, int *fg
, int *bg
, int *hl
)
214 int i
= 0, get_fg
= 1;
216 char tempstr
[MAX_LEN
+ 1], *part
;
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
;
226 return -1; /* invalid representation */
229 /* remove the parenthesis */
231 if (have
> MAX_LEN
) {
236 memcpy(tempstr
, str
+ 1, have
);
237 tempstr
[have
] = '\0';
239 /* get foreground and background */
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')
253 if (tempstr
[i
] == '\0')
254 return -1; /* invalid representation */
255 else if (whitespace(tempstr
[i
])) { /* not yet ',' */
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
);
266 if (j
== COLOR_COUNT
) /* invalid color name */
269 *fg
= color_names
[j
].value
;
270 get_fg
= 0; /* next we have to get the background */
272 *bg
= color_names
[j
].value
;
275 } /* got foreground and background */
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)
291 if (!dlg_strcmp(part
, "ON"))
293 else if (!dlg_strcmp(part
, "OFF"))
296 return -1; /* invalid highlight value */
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.
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
)) {
315 if (!dlg_strcmp(keyword
, line
+ i
)) {
316 *params
= line
+ skip_whitespace(line
, j
+ 1);
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.
333 * LINE_EMPTY - line is blank or comment
334 * LINE_EQUALS - line contains "variable = value"
335 * LINE_ERROR - syntax error in line
338 parse_line(char *line
, char **var
, char **value
)
342 /* ignore white space at beginning of line */
343 i
= skip_whitespace(line
, i
);
345 if (line
[i
] == '\0') /* line is blank */
347 else if (line
[i
] == '#') /* line is comment */
349 else if (line
[i
] == '=') /* variable names cannot start with a '=' */
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')
359 if (line
[i
] == '\0') /* syntax error */
361 else if (line
[i
] == '=')
366 /* skip white space before '=' */
367 i
= skip_whitespace(line
, i
);
369 if (line
[i
] != '=') /* syntax error */
372 i
++; /* skip the '=' */
375 /* skip white space after '=' */
376 i
= skip_whitespace(line
, i
);
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)
387 (*value
)[i
+ 1] = '\0';
389 return LINE_EQUALS
; /* no syntax error in line */
393 * Create the configuration file
396 dlg_create_rc(const char *filename
)
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\
407 # Automatically generated by \"dialog --create-rc <file>\"\n\
410 # Types of values:\n\
412 # Number - <number>\n\
413 # String - \"string\"\n\
414 # Boolean - <ON|OFF>\n"
417 # Attribute - (foreground,background,highlight?)\n"
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
) {
426 fprintf(rc_file
, "%s = %d\n", vars
[i
].name
,
427 *((int *) vars
[i
].var
));
430 fprintf(rc_file
, "%s = \"%s\"\n", vars
[i
].name
,
431 (char *) vars
[i
].var
);
434 fprintf(rc_file
, "%s = %s\n", vars
[i
].name
,
435 *((bool *) vars
[i
].var
) ? "ON" : "OFF");
440 for (i
= 0; i
< (unsigned) dlg_color_count(); ++i
) {
441 char buffer
[MAX_LEN
+ 1];
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
);
459 fprintf(rc_file
, "%s = %s\n", dlg_color_table
[i
].name
,
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
481 char str
[MAX_LEN
+ 1];
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.
505 if ((tempptr
= getenv("DIALOGRC")) != NULL
)
506 rc_file
= fopen(tempptr
, "rt");
508 if (rc_file
== NULL
) { /* step (a) failed? */
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
);
515 sprintf(str
, "%s/%s", tempptr
, DIALOGRC
);
516 rc_file
= fopen(tempptr
= str
, "rt");
520 if (rc_file
== NULL
) { /* step (b) failed? */
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 */
540 if (begins_with(str
, "bindkey", ¶ms
)) {
541 if (!dlg_parse_bindkey(params
)) {
542 fprintf(stderr
, "\nParse error: line %d of configuration\n", l
);
547 parse
= parse_line(str
, &var
, &value
); /* parse current line */
550 case LINE_EMPTY
: /* ignore blank lines and comments */
553 /* search table for matching config variable name */
554 if ((i
= find_vars(var
)) >= 0) {
555 switch (vars
[i
].type
) {
557 *((int *) vars
[i
].var
) = atoi(value
);
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 "
565 result
= -1; /* parse aborted */
567 /* remove the (") quotes */
569 lastch(value
) = '\0';
570 strcpy((char *) vars
[i
].var
, value
);
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
;
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 */
587 } else if ((i
= find_color(var
)) >= 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 "
595 result
= -1; /* parse aborted */
597 dlg_color_table
[i
].fg
= fg
;
598 dlg_color_table
[i
].bg
= bg
;
599 dlg_color_table
[i
].hilite
= hl
;
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 */
609 fprintf(stderr
, "\nParse error: syntax error at line %d of "
610 "configuration file.\n", l
);
611 result
= -1; /* parse aborted */
617 (void) fclose(rc_file
);