xref: /dflybsd-src/contrib/dialog/rc.c (revision b2dabe2e739bd72461a68ac543307c2dedfb048c)
15382d832SPeter Avalos /*
2*a8e38dc0SAntonio Huete Jimenez  *  $Id: rc.c,v 1.62 2022/07/28 08:17:21 tom Exp $
35382d832SPeter Avalos  *
45382d832SPeter Avalos  *  rc.c -- routines for processing the configuration file
55382d832SPeter Avalos  *
6*a8e38dc0SAntonio Huete Jimenez  *  Copyright 2000-2020,2022	Thomas E. Dickey
75382d832SPeter Avalos  *
85382d832SPeter Avalos  *  This program is free software; you can redistribute it and/or modify
95382d832SPeter Avalos  *  it under the terms of the GNU Lesser General Public License, version 2.1
105382d832SPeter Avalos  *  as published by the Free Software Foundation.
115382d832SPeter Avalos  *
125382d832SPeter Avalos  *  This program is distributed in the hope that it will be useful, but
135382d832SPeter Avalos  *  WITHOUT ANY WARRANTY; without even the implied warranty of
145382d832SPeter Avalos  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
155382d832SPeter Avalos  *  Lesser General Public License for more details.
165382d832SPeter Avalos  *
175382d832SPeter Avalos  *  You should have received a copy of the GNU Lesser General Public
185382d832SPeter Avalos  *  License along with this program; if not, write to
195382d832SPeter Avalos  *	Free Software Foundation, Inc.
205382d832SPeter Avalos  *	51 Franklin St., Fifth Floor
215382d832SPeter Avalos  *	Boston, MA 02110, USA.
225382d832SPeter Avalos  *
235382d832SPeter Avalos  *  An earlier version of this program lists as authors
245382d832SPeter Avalos  *	Savio Lam (lam836@cs.cuhk.hk)
255382d832SPeter Avalos  */
265382d832SPeter Avalos 
27*a8e38dc0SAntonio Huete Jimenez #include <dlg_internals.h>
285382d832SPeter Avalos #include <dlg_keys.h>
295382d832SPeter Avalos 
305382d832SPeter Avalos #ifdef HAVE_COLOR
315382d832SPeter Avalos #include <dlg_colors.h>
325940c9abSDaniel Fojt 
335940c9abSDaniel Fojt #define L_PAREN '('
345940c9abSDaniel Fojt #define R_PAREN ')'
355940c9abSDaniel Fojt 
365940c9abSDaniel Fojt #define MIN_TOKEN 3
375940c9abSDaniel Fojt #ifdef HAVE_RC_FILE2
385940c9abSDaniel Fojt #define MAX_TOKEN 5
395940c9abSDaniel Fojt #else
405940c9abSDaniel Fojt #define MAX_TOKEN MIN_TOKEN
415940c9abSDaniel Fojt #endif
425940c9abSDaniel Fojt 
435940c9abSDaniel Fojt #define UNKNOWN_COLOR -2
445382d832SPeter Avalos 
455382d832SPeter Avalos /*
465382d832SPeter Avalos  * For matching color names with color values
475382d832SPeter Avalos  */
485382d832SPeter Avalos static const color_names_st color_names[] =
495382d832SPeter Avalos {
505382d832SPeter Avalos #ifdef HAVE_USE_DEFAULT_COLORS
515382d832SPeter Avalos     {"DEFAULT", -1},
525382d832SPeter Avalos #endif
535382d832SPeter Avalos     {"BLACK", COLOR_BLACK},
545382d832SPeter Avalos     {"RED", COLOR_RED},
555382d832SPeter Avalos     {"GREEN", COLOR_GREEN},
565382d832SPeter Avalos     {"YELLOW", COLOR_YELLOW},
575382d832SPeter Avalos     {"BLUE", COLOR_BLUE},
585382d832SPeter Avalos     {"MAGENTA", COLOR_MAGENTA},
595382d832SPeter Avalos     {"CYAN", COLOR_CYAN},
605382d832SPeter Avalos     {"WHITE", COLOR_WHITE},
615382d832SPeter Avalos };				/* color names */
625940c9abSDaniel Fojt #define COLOR_COUNT     TableSize(color_names)
635382d832SPeter Avalos #endif /* HAVE_COLOR */
645382d832SPeter Avalos 
655382d832SPeter Avalos #define GLOBALRC "/etc/dialogrc"
665382d832SPeter Avalos #define DIALOGRC ".dialogrc"
675382d832SPeter Avalos 
685382d832SPeter Avalos /* Types of values */
695382d832SPeter Avalos #define VAL_INT  0
705382d832SPeter Avalos #define VAL_STR  1
715382d832SPeter Avalos #define VAL_BOOL 2
725382d832SPeter Avalos 
735382d832SPeter Avalos /* Type of line in configuration file */
745382d832SPeter Avalos typedef enum {
755382d832SPeter Avalos     LINE_ERROR = -1,
765382d832SPeter Avalos     LINE_EQUALS,
775382d832SPeter Avalos     LINE_EMPTY
785382d832SPeter Avalos } PARSE_LINE;
795382d832SPeter Avalos 
805382d832SPeter Avalos /* number of configuration variables */
815940c9abSDaniel Fojt #define VAR_COUNT        TableSize(vars)
825382d832SPeter Avalos 
835382d832SPeter Avalos /* check if character is string quoting characters */
845940c9abSDaniel Fojt #define isquote(c)       ((c) == '"' || (c) == '\'')
855382d832SPeter Avalos 
865382d832SPeter Avalos /* get last character of string */
875382d832SPeter Avalos #define lastch(str)      str[strlen(str)-1]
885382d832SPeter Avalos 
895382d832SPeter Avalos /*
905382d832SPeter Avalos  * Configuration variables
915382d832SPeter Avalos  */
925382d832SPeter Avalos typedef struct {
935382d832SPeter Avalos     const char *name;		/* name of configuration variable as in DIALOGRC */
945382d832SPeter Avalos     void *var;			/* address of actual variable to change */
955382d832SPeter Avalos     int type;			/* type of value */
965382d832SPeter Avalos     const char *comment;	/* comment to put in "rc" file */
975382d832SPeter Avalos } vars_st;
985382d832SPeter Avalos 
995382d832SPeter Avalos /*
1005382d832SPeter Avalos  * This table should contain only references to dialog_state, since dialog_vars
1015382d832SPeter Avalos  * is reset specially in dialog.c before each widget.
1025382d832SPeter Avalos  */
1035382d832SPeter Avalos static const vars_st vars[] =
1045382d832SPeter Avalos {
1055382d832SPeter Avalos     {"aspect",
1065382d832SPeter Avalos      &dialog_state.aspect_ratio,
1075382d832SPeter Avalos      VAL_INT,
1085382d832SPeter Avalos      "Set aspect-ration."},
1095382d832SPeter Avalos 
1105382d832SPeter Avalos     {"separate_widget",
1115382d832SPeter Avalos      &dialog_state.separate_str,
1125382d832SPeter Avalos      VAL_STR,
1135382d832SPeter Avalos      "Set separator (for multiple widgets output)."},
1145382d832SPeter Avalos 
1155382d832SPeter Avalos     {"tab_len",
1165382d832SPeter Avalos      &dialog_state.tab_len,
1175382d832SPeter Avalos      VAL_INT,
1185382d832SPeter Avalos      "Set tab-length (for textbox tab-conversion)."},
1195382d832SPeter Avalos 
1205382d832SPeter Avalos     {"visit_items",
1215382d832SPeter Avalos      &dialog_state.visit_items,
1225382d832SPeter Avalos      VAL_BOOL,
1235382d832SPeter Avalos      "Make tab-traversal for checklist, etc., include the list."},
1245382d832SPeter Avalos 
125*a8e38dc0SAntonio Huete Jimenez     {"use_scrollbar",
126*a8e38dc0SAntonio Huete Jimenez      &dialog_state.use_scrollbar,
127*a8e38dc0SAntonio Huete Jimenez      VAL_BOOL,
128*a8e38dc0SAntonio Huete Jimenez      "Show scrollbar in dialog boxes?"},
129*a8e38dc0SAntonio Huete Jimenez 
1305382d832SPeter Avalos #ifdef HAVE_COLOR
1315382d832SPeter Avalos     {"use_shadow",
1325382d832SPeter Avalos      &dialog_state.use_shadow,
1335382d832SPeter Avalos      VAL_BOOL,
1345382d832SPeter Avalos      "Shadow dialog boxes? This also turns on color."},
1355382d832SPeter Avalos 
1365382d832SPeter Avalos     {"use_colors",
1375382d832SPeter Avalos      &dialog_state.use_colors,
1385382d832SPeter Avalos      VAL_BOOL,
1395382d832SPeter Avalos      "Turn color support ON or OFF"},
1405382d832SPeter Avalos #endif				/* HAVE_COLOR */
1415382d832SPeter Avalos };				/* vars */
1425382d832SPeter Avalos 
1435382d832SPeter Avalos static int
skip_whitespace(char * str,int n)1445382d832SPeter Avalos skip_whitespace(char *str, int n)
1455382d832SPeter Avalos {
1465940c9abSDaniel Fojt     while (isblank(UCH(str[n])) && str[n] != '\0')
1475382d832SPeter Avalos 	n++;
1485382d832SPeter Avalos     return n;
1495382d832SPeter Avalos }
1505382d832SPeter Avalos 
1515382d832SPeter Avalos static int
skip_keyword(char * str,int n)1525382d832SPeter Avalos skip_keyword(char *str, int n)
1535382d832SPeter Avalos {
1545382d832SPeter Avalos     while (isalnum(UCH(str[n])) && str[n] != '\0')
1555382d832SPeter Avalos 	n++;
1565382d832SPeter Avalos     return n;
1575382d832SPeter Avalos }
1585382d832SPeter Avalos 
1595940c9abSDaniel Fojt static void
trim_token(char ** tok)1605940c9abSDaniel Fojt trim_token(char **tok)
1615940c9abSDaniel Fojt {
1625940c9abSDaniel Fojt     char *tmp = *tok + skip_whitespace(*tok, 0);
1635940c9abSDaniel Fojt 
1645940c9abSDaniel Fojt     *tok = tmp;
1655940c9abSDaniel Fojt 
1665940c9abSDaniel Fojt     while (*tmp != '\0' && !isblank(UCH(*tmp)))
1675940c9abSDaniel Fojt 	tmp++;
1685940c9abSDaniel Fojt 
1695940c9abSDaniel Fojt     *tmp = '\0';
1705940c9abSDaniel Fojt }
1715940c9abSDaniel Fojt 
1725940c9abSDaniel Fojt static int
from_boolean(const char * str)1735940c9abSDaniel Fojt from_boolean(const char *str)
1745940c9abSDaniel Fojt {
1755940c9abSDaniel Fojt     int code = -1;
1765940c9abSDaniel Fojt 
1775940c9abSDaniel Fojt     if (str != NULL && *str != '\0') {
1785940c9abSDaniel Fojt 	if (!dlg_strcmp(str, "ON")) {
1795940c9abSDaniel Fojt 	    code = 1;
1805940c9abSDaniel Fojt 	} else if (!dlg_strcmp(str, "OFF")) {
1815940c9abSDaniel Fojt 	    code = 0;
1825940c9abSDaniel Fojt 	}
1835940c9abSDaniel Fojt     }
1845940c9abSDaniel Fojt     return code;
1855940c9abSDaniel Fojt }
1865940c9abSDaniel Fojt 
1875940c9abSDaniel Fojt static int
from_color_name(const char * str)1885940c9abSDaniel Fojt from_color_name(const char *str)
1895940c9abSDaniel Fojt {
1905940c9abSDaniel Fojt     int code = UNKNOWN_COLOR;
1915940c9abSDaniel Fojt 
1925940c9abSDaniel Fojt     if (str != NULL && *str != '\0') {
1935940c9abSDaniel Fojt 	size_t i;
1945940c9abSDaniel Fojt 
1955940c9abSDaniel Fojt 	for (i = 0; i < COLOR_COUNT; ++i) {
1965940c9abSDaniel Fojt 	    if (!dlg_strcmp(str, color_names[i].name)) {
1975940c9abSDaniel Fojt 		code = color_names[i].value;
1985940c9abSDaniel Fojt 		break;
1995940c9abSDaniel Fojt 	    }
2005940c9abSDaniel Fojt 	}
2015940c9abSDaniel Fojt     }
2025940c9abSDaniel Fojt     return code;
2035940c9abSDaniel Fojt }
2045940c9abSDaniel Fojt 
2055382d832SPeter Avalos static int
find_vars(char * name)2065382d832SPeter Avalos find_vars(char *name)
2075382d832SPeter Avalos {
2085382d832SPeter Avalos     int result = -1;
2095382d832SPeter Avalos     unsigned i;
2105382d832SPeter Avalos 
2115382d832SPeter Avalos     for (i = 0; i < VAR_COUNT; i++) {
2125382d832SPeter Avalos 	if (dlg_strcmp(vars[i].name, name) == 0) {
2135382d832SPeter Avalos 	    result = (int) i;
2145382d832SPeter Avalos 	    break;
2155382d832SPeter Avalos 	}
2165382d832SPeter Avalos     }
2175382d832SPeter Avalos     return result;
2185382d832SPeter Avalos }
2195382d832SPeter Avalos 
2205382d832SPeter Avalos #ifdef HAVE_COLOR
2215382d832SPeter Avalos static int
find_color(char * name)2225382d832SPeter Avalos find_color(char *name)
2235382d832SPeter Avalos {
2245382d832SPeter Avalos     int result = -1;
2255382d832SPeter Avalos     int i;
2265382d832SPeter Avalos     int limit = dlg_color_count();
2275382d832SPeter Avalos 
2285382d832SPeter Avalos     for (i = 0; i < limit; i++) {
2295382d832SPeter Avalos 	if (dlg_strcmp(dlg_color_table[i].name, name) == 0) {
2305382d832SPeter Avalos 	    result = i;
2315382d832SPeter Avalos 	    break;
2325382d832SPeter Avalos 	}
2335382d832SPeter Avalos     }
2345382d832SPeter Avalos     return result;
2355382d832SPeter Avalos }
2365382d832SPeter Avalos 
2375940c9abSDaniel Fojt static const char *
to_color_name(int code)2385940c9abSDaniel Fojt to_color_name(int code)
2395382d832SPeter Avalos {
2405940c9abSDaniel Fojt     const char *result = "?";
2415940c9abSDaniel Fojt     size_t n;
2425940c9abSDaniel Fojt     for (n = 0; n < TableSize(color_names); ++n) {
2435940c9abSDaniel Fojt 	if (code == color_names[n].value) {
2445940c9abSDaniel Fojt 	    result = color_names[n].name;
2455940c9abSDaniel Fojt 	    break;
2465940c9abSDaniel Fojt 	}
2475940c9abSDaniel Fojt     }
2485940c9abSDaniel Fojt     return result;
2495940c9abSDaniel Fojt }
2505382d832SPeter Avalos 
2515940c9abSDaniel Fojt static const char *
to_boolean(int code)2525940c9abSDaniel Fojt to_boolean(int code)
2535940c9abSDaniel Fojt {
2545940c9abSDaniel Fojt     return code ? "ON" : "OFF";
2555382d832SPeter Avalos }
2565382d832SPeter Avalos 
2575382d832SPeter Avalos /*
2585382d832SPeter Avalos  * Extract the foreground, background and highlight values from an attribute
2595940c9abSDaniel Fojt  * represented as a string in one of these forms:
2605382d832SPeter Avalos  *
2615940c9abSDaniel Fojt  * "(foreground,background,highlight,underline,reverse)"
2625940c9abSDaniel Fojt  * "(foreground,background,highlight,underline)"
2635382d832SPeter Avalos  * "(foreground,background,highlight)"
2645940c9abSDaniel Fojt  * "xxxx_color"
2655382d832SPeter Avalos  */
2665382d832SPeter Avalos static int
str_to_attr(char * str,DIALOG_COLORS * result)2675940c9abSDaniel Fojt str_to_attr(char *str, DIALOG_COLORS * result)
2685382d832SPeter Avalos {
2695940c9abSDaniel Fojt     char *tokens[MAX_TOKEN + 1];
2705940c9abSDaniel Fojt     char tempstr[MAX_LEN + 1];
2715382d832SPeter Avalos     size_t have;
2725940c9abSDaniel Fojt     size_t i = 0;
2735940c9abSDaniel Fojt     size_t tok_count = 0;
2745382d832SPeter Avalos 
2755940c9abSDaniel Fojt     memset(result, 0, sizeof(*result));
2765940c9abSDaniel Fojt     result->fg = -1;
2775940c9abSDaniel Fojt     result->bg = -1;
2785940c9abSDaniel Fojt     result->hilite = -1;
2795940c9abSDaniel Fojt 
2805940c9abSDaniel Fojt     if (str[0] != L_PAREN || lastch(str) != R_PAREN) {
2815940c9abSDaniel Fojt 	int ret;
2825940c9abSDaniel Fojt 
2835940c9abSDaniel Fojt 	if ((ret = find_color(str)) >= 0) {
2845940c9abSDaniel Fojt 	    *result = dlg_color_table[ret];
2855382d832SPeter Avalos 	    return 0;
2865382d832SPeter Avalos 	}
2875940c9abSDaniel Fojt 	/* invalid representation */
2885940c9abSDaniel Fojt 	return -1;
2895382d832SPeter Avalos     }
2905382d832SPeter Avalos 
2915382d832SPeter Avalos     /* remove the parenthesis */
2925382d832SPeter Avalos     have = strlen(str);
2935382d832SPeter Avalos     if (have > MAX_LEN) {
2945382d832SPeter Avalos 	have = MAX_LEN - 1;
2955382d832SPeter Avalos     } else {
2965382d832SPeter Avalos 	have -= 2;
2975382d832SPeter Avalos     }
2985382d832SPeter Avalos     memcpy(tempstr, str + 1, have);
2995382d832SPeter Avalos     tempstr[have] = '\0';
3005382d832SPeter Avalos 
3015940c9abSDaniel Fojt     /* parse comma-separated tokens, allow up to
3025940c9abSDaniel Fojt      * one more than max tokens to detect extras */
3035940c9abSDaniel Fojt     while (tok_count < TableSize(tokens)) {
3045382d832SPeter Avalos 
3055940c9abSDaniel Fojt 	tokens[tok_count++] = &tempstr[i];
3065382d832SPeter Avalos 
3075940c9abSDaniel Fojt 	while (tempstr[i] != '\0' && tempstr[i] != ',')
3085382d832SPeter Avalos 	    i++;
3095382d832SPeter Avalos 
3105382d832SPeter Avalos 	if (tempstr[i] == '\0')
3115382d832SPeter Avalos 	    break;
3125940c9abSDaniel Fojt 
3135940c9abSDaniel Fojt 	tempstr[i++] = '\0';
3145382d832SPeter Avalos     }
3155382d832SPeter Avalos 
3165940c9abSDaniel Fojt     if (tok_count < MIN_TOKEN || tok_count > MAX_TOKEN) {
3175940c9abSDaniel Fojt 	/* invalid representation */
3185940c9abSDaniel Fojt 	return -1;
3195940c9abSDaniel Fojt     }
3205382d832SPeter Avalos 
3215940c9abSDaniel Fojt     for (i = 0; i < tok_count; ++i)
3225940c9abSDaniel Fojt 	trim_token(&tokens[i]);
3235382d832SPeter Avalos 
3245940c9abSDaniel Fojt     /* validate */
3255940c9abSDaniel Fojt     if (UNKNOWN_COLOR == (result->fg = from_color_name(tokens[0]))
3265940c9abSDaniel Fojt 	|| UNKNOWN_COLOR == (result->bg = from_color_name(tokens[1]))
3275940c9abSDaniel Fojt 	|| UNKNOWN_COLOR == (result->hilite = from_boolean(tokens[2]))
3285940c9abSDaniel Fojt #ifdef HAVE_RC_FILE2
3295940c9abSDaniel Fojt 	|| (tok_count >= 4 && (result->ul = from_boolean(tokens[3])) == -1)
3305940c9abSDaniel Fojt 	|| (tok_count >= 5 && (result->rv = from_boolean(tokens[4])) == -1)
3315940c9abSDaniel Fojt #endif /* HAVE_RC_FILE2 */
3325940c9abSDaniel Fojt 	) {
3335940c9abSDaniel Fojt 	/* invalid representation */
3345940c9abSDaniel Fojt 	return -1;
3355940c9abSDaniel Fojt     }
3365382d832SPeter Avalos 
3375382d832SPeter Avalos     return 0;
3385382d832SPeter Avalos }
3395382d832SPeter Avalos #endif /* HAVE_COLOR */
3405382d832SPeter Avalos 
3415382d832SPeter Avalos /*
3425382d832SPeter Avalos  * Check if the line begins with a special keyword; if so, return true while
3435382d832SPeter Avalos  * pointing params to its parameters.
3445382d832SPeter Avalos  */
3455382d832SPeter Avalos static int
begins_with(char * line,const char * keyword,char ** params)3465382d832SPeter Avalos begins_with(char *line, const char *keyword, char **params)
3475382d832SPeter Avalos {
3485382d832SPeter Avalos     int i = skip_whitespace(line, 0);
3495382d832SPeter Avalos     int j = skip_keyword(line, i);
3505382d832SPeter Avalos 
3515382d832SPeter Avalos     if ((j - i) == (int) strlen(keyword)) {
3525382d832SPeter Avalos 	char save = line[j];
3535382d832SPeter Avalos 	line[j] = 0;
3545382d832SPeter Avalos 	if (!dlg_strcmp(keyword, line + i)) {
3555382d832SPeter Avalos 	    *params = line + skip_whitespace(line, j + 1);
3565382d832SPeter Avalos 	    return 1;
3575382d832SPeter Avalos 	}
3585382d832SPeter Avalos 	line[j] = save;
3595382d832SPeter Avalos     }
3605382d832SPeter Avalos 
3615382d832SPeter Avalos     return 0;
3625382d832SPeter Avalos }
3635382d832SPeter Avalos 
3645382d832SPeter Avalos /*
3655382d832SPeter Avalos  * Parse a line in the configuration file
3665382d832SPeter Avalos  *
3675382d832SPeter Avalos  * Each line is of the form:  "variable = value". On exit, 'var' will contain
3685382d832SPeter Avalos  * the variable name, and 'value' will contain the value string.
3695382d832SPeter Avalos  *
3705382d832SPeter Avalos  * Return values:
3715382d832SPeter Avalos  *
3725382d832SPeter Avalos  * LINE_EMPTY   - line is blank or comment
3735382d832SPeter Avalos  * LINE_EQUALS  - line contains "variable = value"
3745382d832SPeter Avalos  * LINE_ERROR   - syntax error in line
3755382d832SPeter Avalos  */
3765382d832SPeter Avalos static PARSE_LINE
parse_line(char * line,char ** var,char ** value)3775382d832SPeter Avalos parse_line(char *line, char **var, char **value)
3785382d832SPeter Avalos {
3795382d832SPeter Avalos     int i = 0;
3805382d832SPeter Avalos 
3815382d832SPeter Avalos     /* ignore white space at beginning of line */
3825382d832SPeter Avalos     i = skip_whitespace(line, i);
3835382d832SPeter Avalos 
3845382d832SPeter Avalos     if (line[i] == '\0')	/* line is blank */
3855382d832SPeter Avalos 	return LINE_EMPTY;
3865382d832SPeter Avalos     else if (line[i] == '#')	/* line is comment */
3875382d832SPeter Avalos 	return LINE_EMPTY;
3885382d832SPeter Avalos     else if (line[i] == '=')	/* variable names cannot start with a '=' */
3895382d832SPeter Avalos 	return LINE_ERROR;
3905382d832SPeter Avalos 
3915382d832SPeter Avalos     /* set 'var' to variable name */
3925382d832SPeter Avalos     *var = line + i++;		/* skip to next character */
3935382d832SPeter Avalos 
3945382d832SPeter Avalos     /* find end of variable name */
3955940c9abSDaniel Fojt     while (!isblank(UCH(line[i])) && line[i] != '=' && line[i] != '\0')
3965382d832SPeter Avalos 	i++;
3975382d832SPeter Avalos 
3985382d832SPeter Avalos     if (line[i] == '\0')	/* syntax error */
3995382d832SPeter Avalos 	return LINE_ERROR;
4005382d832SPeter Avalos     else if (line[i] == '=')
4015382d832SPeter Avalos 	line[i++] = '\0';
4025382d832SPeter Avalos     else {
4035382d832SPeter Avalos 	line[i++] = '\0';
4045382d832SPeter Avalos 
4055382d832SPeter Avalos 	/* skip white space before '=' */
4065382d832SPeter Avalos 	i = skip_whitespace(line, i);
4075382d832SPeter Avalos 
4085382d832SPeter Avalos 	if (line[i] != '=')	/* syntax error */
4095382d832SPeter Avalos 	    return LINE_ERROR;
4105382d832SPeter Avalos 	else
4115382d832SPeter Avalos 	    i++;		/* skip the '=' */
4125382d832SPeter Avalos     }
4135382d832SPeter Avalos 
4145382d832SPeter Avalos     /* skip white space after '=' */
4155382d832SPeter Avalos     i = skip_whitespace(line, i);
4165382d832SPeter Avalos 
4175382d832SPeter Avalos     if (line[i] == '\0')
4185382d832SPeter Avalos 	return LINE_ERROR;
4195382d832SPeter Avalos     else
4205382d832SPeter Avalos 	*value = line + i;	/* set 'value' to value string */
4215382d832SPeter Avalos 
4225382d832SPeter Avalos     /* trim trailing white space from 'value' */
4235382d832SPeter Avalos     i = (int) strlen(*value) - 1;
4245940c9abSDaniel Fojt     while (isblank(UCH((*value)[i])) && i > 0)
4255382d832SPeter Avalos 	i--;
4265382d832SPeter Avalos     (*value)[i + 1] = '\0';
4275382d832SPeter Avalos 
4285382d832SPeter Avalos     return LINE_EQUALS;		/* no syntax error in line */
4295382d832SPeter Avalos }
4305382d832SPeter Avalos 
4315382d832SPeter Avalos /*
4325382d832SPeter Avalos  * Create the configuration file
4335382d832SPeter Avalos  */
4345382d832SPeter Avalos void
dlg_create_rc(const char * filename)4355382d832SPeter Avalos dlg_create_rc(const char *filename)
4365382d832SPeter Avalos {
4375382d832SPeter Avalos     unsigned i;
4385382d832SPeter Avalos     FILE *rc_file;
4395382d832SPeter Avalos 
4405382d832SPeter Avalos     if ((rc_file = fopen(filename, "wt")) == NULL)
4415382d832SPeter Avalos 	dlg_exiterr("Error opening file for writing in dlg_create_rc().");
4425382d832SPeter Avalos 
4435382d832SPeter Avalos     fprintf(rc_file, "#\n\
4445382d832SPeter Avalos # Run-time configuration file for dialog\n\
4455382d832SPeter Avalos #\n\
4465382d832SPeter Avalos # Automatically generated by \"dialog --create-rc <file>\"\n\
4475382d832SPeter Avalos #\n\
4485382d832SPeter Avalos #\n\
4495382d832SPeter Avalos # Types of values:\n\
4505382d832SPeter Avalos #\n\
4515382d832SPeter Avalos # Number     -  <number>\n\
4525382d832SPeter Avalos # String     -  \"string\"\n\
4535382d832SPeter Avalos # Boolean    -  <ON|OFF>\n"
4545382d832SPeter Avalos #ifdef HAVE_COLOR
4555940c9abSDaniel Fojt #ifdef HAVE_RC_FILE2
4565940c9abSDaniel Fojt 	    "\
4575940c9abSDaniel Fojt # Attribute  -  (foreground,background,highlight?,underline?,reverse?)\n"
4585940c9abSDaniel Fojt #else /* HAVE_RC_FILE2 */
4595382d832SPeter Avalos 	    "\
4605382d832SPeter Avalos # Attribute  -  (foreground,background,highlight?)\n"
4615940c9abSDaniel Fojt #endif /* HAVE_RC_FILE2 */
4625940c9abSDaniel Fojt #endif /* HAVE_COLOR */
4635382d832SPeter Avalos 	);
4645382d832SPeter Avalos 
4655382d832SPeter Avalos     /* Print an entry for each configuration variable */
4665382d832SPeter Avalos     for (i = 0; i < VAR_COUNT; i++) {
4675382d832SPeter Avalos 	fprintf(rc_file, "\n# %s\n", vars[i].comment);
4685382d832SPeter Avalos 	switch (vars[i].type) {
4695382d832SPeter Avalos 	case VAL_INT:
4705382d832SPeter Avalos 	    fprintf(rc_file, "%s = %d\n", vars[i].name,
4715382d832SPeter Avalos 		    *((int *) vars[i].var));
4725382d832SPeter Avalos 	    break;
4735382d832SPeter Avalos 	case VAL_STR:
4745382d832SPeter Avalos 	    fprintf(rc_file, "%s = \"%s\"\n", vars[i].name,
4755382d832SPeter Avalos 		    (char *) vars[i].var);
4765382d832SPeter Avalos 	    break;
4775382d832SPeter Avalos 	case VAL_BOOL:
4785382d832SPeter Avalos 	    fprintf(rc_file, "%s = %s\n", vars[i].name,
4795382d832SPeter Avalos 		    *((bool *) vars[i].var) ? "ON" : "OFF");
4805382d832SPeter Avalos 	    break;
4815382d832SPeter Avalos 	}
4825382d832SPeter Avalos     }
4835382d832SPeter Avalos #ifdef HAVE_COLOR
4845382d832SPeter Avalos     for (i = 0; i < (unsigned) dlg_color_count(); ++i) {
4855382d832SPeter Avalos 	unsigned j;
4865382d832SPeter Avalos 	bool repeat = FALSE;
4875382d832SPeter Avalos 
4885382d832SPeter Avalos 	fprintf(rc_file, "\n# %s\n", dlg_color_table[i].comment);
4895382d832SPeter Avalos 	for (j = 0; j != i; ++j) {
4905382d832SPeter Avalos 	    if (dlg_color_table[i].fg == dlg_color_table[j].fg
4915382d832SPeter Avalos 		&& dlg_color_table[i].bg == dlg_color_table[j].bg
4925382d832SPeter Avalos 		&& dlg_color_table[i].hilite == dlg_color_table[j].hilite) {
4935382d832SPeter Avalos 		fprintf(rc_file, "%s = %s\n",
4945382d832SPeter Avalos 			dlg_color_table[i].name,
4955382d832SPeter Avalos 			dlg_color_table[j].name);
4965382d832SPeter Avalos 		repeat = TRUE;
4975382d832SPeter Avalos 		break;
4985382d832SPeter Avalos 	    }
4995382d832SPeter Avalos 	}
5005382d832SPeter Avalos 
5015382d832SPeter Avalos 	if (!repeat) {
5025940c9abSDaniel Fojt 	    fprintf(rc_file, "%s = %c", dlg_color_table[i].name, L_PAREN);
5035940c9abSDaniel Fojt 	    fprintf(rc_file, "%s", to_color_name(dlg_color_table[i].fg));
5045940c9abSDaniel Fojt 	    fprintf(rc_file, ",%s", to_color_name(dlg_color_table[i].bg));
5055940c9abSDaniel Fojt 	    fprintf(rc_file, ",%s", to_boolean(dlg_color_table[i].hilite));
5065940c9abSDaniel Fojt #ifdef HAVE_RC_FILE2
5075940c9abSDaniel Fojt 	    if (dlg_color_table[i].ul || dlg_color_table[i].rv)
5085940c9abSDaniel Fojt 		fprintf(rc_file, ",%s", to_boolean(dlg_color_table[i].ul));
5095940c9abSDaniel Fojt 	    if (dlg_color_table[i].rv)
5105940c9abSDaniel Fojt 		fprintf(rc_file, ",%s", to_boolean(dlg_color_table[i].rv));
5115940c9abSDaniel Fojt #endif /* HAVE_RC_FILE2 */
5125940c9abSDaniel Fojt 	    fprintf(rc_file, "%c\n", R_PAREN);
5135382d832SPeter Avalos 	}
5145382d832SPeter Avalos     }
5155382d832SPeter Avalos #endif /* HAVE_COLOR */
5165382d832SPeter Avalos     dlg_dump_keys(rc_file);
5175382d832SPeter Avalos 
5185382d832SPeter Avalos     (void) fclose(rc_file);
5195382d832SPeter Avalos }
5205382d832SPeter Avalos 
5215940c9abSDaniel Fojt static void
report_error(const char * filename,int line_no,const char * msg)5225940c9abSDaniel Fojt report_error(const char *filename, int line_no, const char *msg)
5235940c9abSDaniel Fojt {
5245940c9abSDaniel Fojt     fprintf(stderr, "%s:%d: %s\n", filename, line_no, msg);
5255940c9abSDaniel Fojt     dlg_trace_msg("%s:%d: %s\n", filename, line_no, msg);
5265940c9abSDaniel Fojt }
5275940c9abSDaniel Fojt 
5285382d832SPeter Avalos /*
5295382d832SPeter Avalos  * Parse the configuration file and set up variables
5305382d832SPeter Avalos  */
5315382d832SPeter Avalos int
dlg_parse_rc(void)5325382d832SPeter Avalos dlg_parse_rc(void)
5335382d832SPeter Avalos {
5345382d832SPeter Avalos     int i;
5355382d832SPeter Avalos     int l = 1;
5365382d832SPeter Avalos     PARSE_LINE parse;
5375382d832SPeter Avalos     char str[MAX_LEN + 1];
5385382d832SPeter Avalos     char *var;
5395382d832SPeter Avalos     char *value;
5405940c9abSDaniel Fojt     char *filename;
5415382d832SPeter Avalos     int result = 0;
5425382d832SPeter Avalos     FILE *rc_file = 0;
5435382d832SPeter Avalos     char *params;
5445382d832SPeter Avalos 
5455382d832SPeter Avalos     /*
5465382d832SPeter Avalos      *  At startup, dialog determines the settings to use as follows:
5475382d832SPeter Avalos      *
5485382d832SPeter Avalos      *  a) if the environment variable $DIALOGRC is set, its value determines
5495382d832SPeter Avalos      *     the name of the configuration file.
5505382d832SPeter Avalos      *
5515382d832SPeter Avalos      *  b) if the file in (a) can't be found, use the file $HOME/.dialogrc
5525382d832SPeter Avalos      *     as the configuration file.
5535382d832SPeter Avalos      *
5545382d832SPeter Avalos      *  c) if the file in (b) can't be found, try using the GLOBALRC file.
5555382d832SPeter Avalos      *     Usually this will be /etc/dialogrc.
5565382d832SPeter Avalos      *
5575382d832SPeter Avalos      *  d) if the file in (c) cannot be found, use the compiled-in defaults.
5585382d832SPeter Avalos      */
5595382d832SPeter Avalos 
5605382d832SPeter Avalos     /* try step (a) */
561*a8e38dc0SAntonio Huete Jimenez     if ((filename = dlg_getenv_str("DIALOGRC")) != NULL)
5625940c9abSDaniel Fojt 	rc_file = fopen(filename, "rt");
5635382d832SPeter Avalos 
5645382d832SPeter Avalos     if (rc_file == NULL) {	/* step (a) failed? */
5655382d832SPeter Avalos 	/* try step (b) */
566*a8e38dc0SAntonio Huete Jimenez 	if ((filename = dlg_getenv_str("HOME")) != NULL
5675940c9abSDaniel Fojt 	    && strlen(filename) < MAX_LEN - (sizeof(DIALOGRC) + 3)) {
5685940c9abSDaniel Fojt 	    if (filename[0] == '\0' || lastch(filename) == '/')
5695940c9abSDaniel Fojt 		sprintf(str, "%s%s", filename, DIALOGRC);
5705382d832SPeter Avalos 	    else
5715940c9abSDaniel Fojt 		sprintf(str, "%s/%s", filename, DIALOGRC);
5725940c9abSDaniel Fojt 	    rc_file = fopen(filename = str, "rt");
5735382d832SPeter Avalos 	}
5745382d832SPeter Avalos     }
5755382d832SPeter Avalos 
5765382d832SPeter Avalos     if (rc_file == NULL) {	/* step (b) failed? */
5775382d832SPeter Avalos 	/* try step (c) */
5785382d832SPeter Avalos 	strcpy(str, GLOBALRC);
5795940c9abSDaniel Fojt 	if ((rc_file = fopen(filename = str, "rt")) == NULL)
5805382d832SPeter Avalos 	    return 0;		/* step (c) failed, use default values */
5815382d832SPeter Avalos     }
5825382d832SPeter Avalos 
5835940c9abSDaniel Fojt     DLG_TRACE(("# opened rc file \"%s\"\n", filename));
5845382d832SPeter Avalos     /* Scan each line and set variables */
5855382d832SPeter Avalos     while ((result == 0) && (fgets(str, MAX_LEN, rc_file) != NULL)) {
5865940c9abSDaniel Fojt 	DLG_TRACE(("#\t%s", str));
5875382d832SPeter Avalos 	if (*str == '\0' || lastch(str) != '\n') {
5885382d832SPeter Avalos 	    /* ignore rest of file if line too long */
5895940c9abSDaniel Fojt 	    report_error(filename, l, "line too long");
5905382d832SPeter Avalos 	    result = -1;	/* parse aborted */
5915382d832SPeter Avalos 	    break;
5925382d832SPeter Avalos 	}
5935382d832SPeter Avalos 
5945382d832SPeter Avalos 	lastch(str) = '\0';
5955382d832SPeter Avalos 	if (begins_with(str, "bindkey", &params)) {
5965382d832SPeter Avalos 	    if (!dlg_parse_bindkey(params)) {
5975940c9abSDaniel Fojt 		report_error(filename, l, "invalid bindkey");
5985382d832SPeter Avalos 		result = -1;
5995382d832SPeter Avalos 	    }
6005382d832SPeter Avalos 	    continue;
6015382d832SPeter Avalos 	}
6025382d832SPeter Avalos 	parse = parse_line(str, &var, &value);	/* parse current line */
6035382d832SPeter Avalos 
6045382d832SPeter Avalos 	switch (parse) {
6055382d832SPeter Avalos 	case LINE_EMPTY:	/* ignore blank lines and comments */
6065382d832SPeter Avalos 	    break;
6075382d832SPeter Avalos 	case LINE_EQUALS:
6085382d832SPeter Avalos 	    /* search table for matching config variable name */
6095382d832SPeter Avalos 	    if ((i = find_vars(var)) >= 0) {
6105382d832SPeter Avalos 		switch (vars[i].type) {
6115382d832SPeter Avalos 		case VAL_INT:
6125382d832SPeter Avalos 		    *((int *) vars[i].var) = atoi(value);
6135382d832SPeter Avalos 		    break;
6145382d832SPeter Avalos 		case VAL_STR:
6155382d832SPeter Avalos 		    if (!isquote(value[0]) || !isquote(lastch(value))
6165382d832SPeter Avalos 			|| strlen(value) < 2) {
6175940c9abSDaniel Fojt 			report_error(filename, l, "expected string value");
6185382d832SPeter Avalos 			result = -1;	/* parse aborted */
6195382d832SPeter Avalos 		    } else {
6205382d832SPeter Avalos 			/* remove the (") quotes */
6215382d832SPeter Avalos 			value++;
6225382d832SPeter Avalos 			lastch(value) = '\0';
6235382d832SPeter Avalos 			strcpy((char *) vars[i].var, value);
6245382d832SPeter Avalos 		    }
6255382d832SPeter Avalos 		    break;
6265382d832SPeter Avalos 		case VAL_BOOL:
6275382d832SPeter Avalos 		    if (!dlg_strcmp(value, "ON"))
6285382d832SPeter Avalos 			*((bool *) vars[i].var) = TRUE;
6295382d832SPeter Avalos 		    else if (!dlg_strcmp(value, "OFF"))
6305382d832SPeter Avalos 			*((bool *) vars[i].var) = FALSE;
6315382d832SPeter Avalos 		    else {
6325940c9abSDaniel Fojt 			report_error(filename, l, "expected boolean value");
6335382d832SPeter Avalos 			result = -1;	/* parse aborted */
6345382d832SPeter Avalos 		    }
6355382d832SPeter Avalos 		    break;
6365382d832SPeter Avalos 		}
6375382d832SPeter Avalos #ifdef HAVE_COLOR
6385382d832SPeter Avalos 	    } else if ((i = find_color(var)) >= 0) {
6395940c9abSDaniel Fojt 		DIALOG_COLORS temp;
6405940c9abSDaniel Fojt 		if (str_to_attr(value, &temp) == -1) {
6415940c9abSDaniel Fojt 		    report_error(filename, l, "expected attribute value");
6425382d832SPeter Avalos 		    result = -1;	/* parse aborted */
6435382d832SPeter Avalos 		} else {
6445940c9abSDaniel Fojt 		    dlg_color_table[i].fg = temp.fg;
6455940c9abSDaniel Fojt 		    dlg_color_table[i].bg = temp.bg;
6465940c9abSDaniel Fojt 		    dlg_color_table[i].hilite = temp.hilite;
6475940c9abSDaniel Fojt #ifdef HAVE_RC_FILE2
6485940c9abSDaniel Fojt 		    dlg_color_table[i].ul = temp.ul;
6495940c9abSDaniel Fojt 		    dlg_color_table[i].rv = temp.rv;
6505940c9abSDaniel Fojt #endif /* HAVE_RC_FILE2 */
6515382d832SPeter Avalos 		}
6525382d832SPeter Avalos 	    } else {
6535382d832SPeter Avalos #endif /* HAVE_COLOR */
6545940c9abSDaniel Fojt 		report_error(filename, l, "unknown variable");
6555382d832SPeter Avalos 		result = -1;	/* parse aborted */
6565382d832SPeter Avalos 	    }
6575382d832SPeter Avalos 	    break;
6585382d832SPeter Avalos 	case LINE_ERROR:
6595940c9abSDaniel Fojt 	    report_error(filename, l, "syntax error");
6605382d832SPeter Avalos 	    result = -1;	/* parse aborted */
6615382d832SPeter Avalos 	    break;
6625382d832SPeter Avalos 	}
6635382d832SPeter Avalos 	l++;			/* next line */
6645382d832SPeter Avalos     }
6655382d832SPeter Avalos 
6665382d832SPeter Avalos     (void) fclose(rc_file);
6675382d832SPeter Avalos     return result;
6685382d832SPeter Avalos }
669