dialogrc.c revision 274116
119370Spst/*-
2130803Smarcel * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
398944Sobrien * All rights reserved.
419370Spst *
598944Sobrien * Redistribution and use in source and binary forms, with or without
619370Spst * modification, are permitted provided that the following conditions
798944Sobrien * are met:
898944Sobrien * 1. Redistributions of source code must retain the above copyright
998944Sobrien *    notice, this list of conditions and the following disclaimer.
1098944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1119370Spst *    notice, this list of conditions and the following disclaimer in the
1298944Sobrien *    documentation and/or other materials provided with the distribution.
1398944Sobrien *
1498944Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1598944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1619370Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1798944Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1898944Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1998944Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2098944Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2119370Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2219370Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2319370Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2419370Spst * SUCH DAMAGE.
2519370Spst */
2619370Spst
2719370Spst#include <sys/cdefs.h>
2819370Spst__FBSDID("$FreeBSD: head/lib/libdpv/dialogrc.c 274116 2014-11-04 23:46:01Z dteske $");
2998944Sobrien
30130803Smarcel#include <sys/types.h>
31130803Smarcel
32130803Smarcel#include <err.h>
33130803Smarcel#include <errno.h>
34130803Smarcel#include <figpar.h>
35130803Smarcel#include <limits.h>
3619370Spst#include <stdio.h>
3798944Sobrien#include <stdlib.h>
3898944Sobrien#include <string.h>
3946283Sdfr#include <string_m.h>
4019370Spst
4119370Spst#include "dialogrc.h"
4219370Spst
4319370Spst#define STR_BUFSIZE 255
4419370Spst
45130803Smarcel/* dialog(1) `.dialogrc' characteristics */
4619370Spstuint8_t use_colors = 1;
47130803Smarceluint8_t use_shadow = 1;
48130803Smarcelchar gauge_color[STR_BUFSIZE]	= "47b"; /* (BLUE,WHITE,ON) */
49130803Smarcelchar separator[STR_BUFSIZE]	= "";
5019370Spst
5119370Spst/* Function prototypes */
52130803Smarcelstatic int setattr(struct config *, uint32_t, char *, char *);
53130803Smarcelstatic int setbool(struct config *, uint32_t, char *, char *);
5419370Spststatic int setnum(struct config *, uint32_t, char *, char *);
55130803Smarcelstatic int setstr(struct config *, uint32_t, char *, char *);
56130803Smarcel
57130803Smarcel/*
58130803Smarcel * Anatomy of DIALOGRC (~/.dialogrc by default)
59130803Smarcel * NOTE: Must appear after private function prototypes (above)
60130803Smarcel * NB: Brace-initialization of union requires cast to *first* member of union
6119370Spst */
62130803Smarcelstatic struct config dialogrc_config[] = {
63130803Smarcel    /* TYPE     Directive			DEFAULT		HANDLER */
6419370Spst    {TYPE_INT,	"aspect",			{(void *)0},	&setnum},
65130803Smarcel    {TYPE_STR,	"separate_widget",		{separator},	&setstr},
66130803Smarcel    {TYPE_INT,	"tab_len",			{(void *)0},	&setnum},
67130803Smarcel    {TYPE_BOOL,	"visit_items",			{(void *)0},	&setbool},
6819370Spst    {TYPE_BOOL, "use_shadow",			{(void *)1},	&setbool},
69130803Smarcel    {TYPE_BOOL, "use_colors",			{(void *)1},	&setbool},
70130803Smarcel    {TYPE_STR,	"screen_color",			{NULL},		&setattr},
7119370Spst    {TYPE_STR,	"shadow_color",			{NULL},		&setattr},
7219370Spst    {TYPE_STR,	"dialog_color",			{NULL},		&setattr},
7319370Spst    {TYPE_STR,	"title_color",			{NULL},		&setattr},
7498944Sobrien    {TYPE_STR,	"border_color",			{NULL},		&setattr},
7519370Spst    {TYPE_STR,	"button_active_color",		{NULL},		&setattr},
7646283Sdfr    {TYPE_STR,	"button_inactive_color",	{NULL},		&setattr},
7746283Sdfr    {TYPE_STR,	"button_key_active_color",	{NULL},		&setattr},
7846283Sdfr    {TYPE_STR,	"button_key_inactive_color",	{NULL},		&setattr},
7919370Spst    {TYPE_STR,	"button_label_active_color",	{NULL},		&setattr},
8019370Spst    {TYPE_STR,	"button_label_inactive_color",	{NULL},		&setattr},
8119370Spst    {TYPE_STR,	"inputbox_color",		{NULL},		&setattr},
8246283Sdfr    {TYPE_STR,	"inputbox_border_color",	{NULL},		&setattr},
8346283Sdfr    {TYPE_STR,	"searchbox_color",		{NULL},		&setattr},
8446283Sdfr    {TYPE_STR,	"searchbox_title_color",	{NULL},		&setattr},
8546283Sdfr    {TYPE_STR,	"searchbox_border_color",	{NULL},		&setattr},
8619370Spst    {TYPE_STR,	"position_indicator_color",	{NULL},		&setattr},
8719370Spst    {TYPE_STR,	"menubox_color",		{NULL},		&setattr},
8898944Sobrien    {TYPE_STR,	"menubox_border_color",		{NULL},		&setattr},
8998944Sobrien    {TYPE_STR,	"item_color",			{NULL},		&setattr},
9019370Spst    {TYPE_STR,	"item_selected_color",		{NULL},		&setattr},
91130803Smarcel    {TYPE_STR,	"tag_color",			{NULL},		&setattr},
9219370Spst    {TYPE_STR,	"tag_selected_color",		{NULL},		&setattr},
9319370Spst    {TYPE_STR,	"tag_key_color",		{NULL},		&setattr},
9419370Spst    {TYPE_STR,	"tag_key_selected_color",	{NULL},		&setattr},
9519370Spst    {TYPE_STR,	"check_color",			{NULL},		&setattr},
9619370Spst    {TYPE_STR,	"check_selected_color",		{NULL},		&setattr},
9719370Spst    {TYPE_STR,	"uarrow_color",			{NULL},		&setattr},
9819370Spst    {TYPE_STR,	"darrow_color",			{NULL},		&setattr},
9946283Sdfr    {TYPE_STR,	"itemhelp_color",		{NULL},		&setattr},
10046283Sdfr    {TYPE_STR,	"form_active_text_color",	{NULL},		&setattr},
10198944Sobrien    {TYPE_STR,	"form_text_color",		{NULL},		&setattr},
10298944Sobrien    {TYPE_STR,	"form_item_readonly_color",	{NULL},		&setattr},
10319370Spst    {TYPE_STR,	"gauge_color",			{gauge_color},	&setattr},
10419370Spst    {0, NULL, {0}, NULL}
10519370Spst};
10619370Spst
10719370Spst/*
10819370Spst * figpar call-back for interpreting value as .dialogrc `Attribute'
10919370Spst */
11019370Spststatic int
11119370Spstsetattr(struct config *option, uint32_t line __unused,
11219370Spst    char *directive __unused, char *value)
11319370Spst{
11498944Sobrien	char *cp = value;
11519370Spst	char *val;
11619370Spst	size_t len;
11719370Spst	char attrbuf[4];
11846283Sdfr
11919370Spst	if (option == NULL) {
12019370Spst		warnx("%s:%d:%s: Missing callback parameter", __FILE__,
12119370Spst		    __LINE__, __func__);
12219370Spst		return (-1); /* Abort processing */
12319370Spst	}
12419370Spst
12519370Spst	/* Allocate memory for the data if not already done */
12619370Spst	if (option->value.str == NULL) {
12719370Spst		if ((option->value.str = malloc(STR_BUFSIZE)) == NULL)
12846283Sdfr			return (-1);
12946283Sdfr	}
13019370Spst
13119370Spst	/*
13246283Sdfr	 * If the first character is left-parenthesis, the format is
13346283Sdfr	 * `(background,foreground,highlight)' otherwise, we should take it
13498944Sobrien	 * as a reference to another color.
13519370Spst	 */
13619370Spst	if (*cp != '(') {
13719370Spst		/* Copy the [current] value from the referenced color */
13819370Spst		val = dialogrc_config_option(cp)->value.str;
13919370Spst		if (val != NULL)
14019370Spst			snprintf(option->value.str, STR_BUFSIZE, "%s", val);
14119370Spst
14219370Spst		return (0);
14319370Spst	} else
14419370Spst		cp++;
14519370Spst
14619370Spst	strtolower(cp);
14719370Spst
14819370Spst	/* Initialize the attrbuf (fg,bg,hi,NUL) */
14919370Spst	attrbuf[0] = '0';
15046283Sdfr	attrbuf[1] = '0';
15119370Spst	attrbuf[2] = 'B'; /* \ZB = disable; \Zb = enable (see dialog(1)) */
15219370Spst	attrbuf[3] = '\0';
15319370Spst
15419370Spst	/* Interpret the foreground color */
15519370Spst	if      (strncmp(cp, "red,",     4) == 0) attrbuf[0] = '1';
15619370Spst	else if (strncmp(cp, "green,",   6) == 0) attrbuf[0] = '2';
15719370Spst	else if (strncmp(cp, "yellow,",  7) == 0) attrbuf[0] = '3';
15819370Spst	else if (strncmp(cp, "blue,",    5) == 0) attrbuf[0] = '4';
15919370Spst	else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[0] = '5';
16019370Spst	else if (strncmp(cp, "cyan,",    5) == 0) attrbuf[0] = '6';
16119370Spst	else if (strncmp(cp, "white,",   6) == 0) attrbuf[0] = '7';
16219370Spst	else if (strncmp(cp, "black,",   6) == 0) attrbuf[0] = '8';
16319370Spst
16419370Spst	/* Advance to the background color */
16519370Spst	cp = strchr(cp, ',');
16646283Sdfr	if (cp == NULL)
16719370Spst		goto write_attrbuf;
16819370Spst	else
16919370Spst		cp++;
17019370Spst
17119370Spst	/* Interpret the background color */
17219370Spst	if      (strncmp(cp, "red,",     4) == 0) attrbuf[1] = '1';
17319370Spst	else if (strncmp(cp, "green,",   6) == 0) attrbuf[1] = '2';
17419370Spst	else if (strncmp(cp, "yellow,",  7) == 0) attrbuf[1] = '3';
17519370Spst	else if (strncmp(cp, "blue,",    5) == 0) attrbuf[1] = '4';
17619370Spst	else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[1] = '5';
17719370Spst	else if (strncmp(cp, "cyan,",    5) == 0) attrbuf[1] = '6';
17819370Spst	else if (strncmp(cp, "white,",   6) == 0) attrbuf[1] = '7';
17919370Spst	else if (strncmp(cp, "black,",   6) == 0) attrbuf[1] = '8';
18019370Spst
18119370Spst	/* Advance to the highlight */
18219370Spst	cp = strchr(cp, ',');
18319370Spst	if (cp == NULL)
18419370Spst		goto write_attrbuf;
18519370Spst	else
18619370Spst		cp++;
18719370Spst
18819370Spst	/* Trim trailing parenthesis */
18919370Spst	len = strlen(cp);
19019370Spst	if (cp[len - 1] == ')')
19119370Spst		cp[len - 1] = '\0';
19219370Spst
19319370Spst	/* Interpret the highlight (initialized to off above) */
19419370Spst	if (strcmp(cp, "on") == 0 || strncmp(cp, "on,", 3) == 0)
19519370Spst		attrbuf[2] = 'b'; /* \Zb = enable bold (see dialog(1)) */
19619370Spst
19719370Spstwrite_attrbuf:
19819370Spst	sprintf(option->value.str, "%s", attrbuf);
19919370Spst
20019370Spst	return (0);
20119370Spst}
20219370Spst
20319370Spst/*
20419370Spst * figpar call-back for interpreting value as .dialogrc `Boolean'
20519370Spst */
20619370Spststatic int
20719370Spstsetbool(struct config *option, uint32_t line __unused,
20898944Sobrien    char *directive __unused, char *value)
20919370Spst{
210130803Smarcel
21119370Spst	if (option == NULL) {
21219370Spst		warnx("%s:%d:%s: Missing callback parameter", __FILE__,
21319370Spst		    __LINE__, __func__);
21498944Sobrien		return (-1); /* Abort processing */
21598944Sobrien	}
21698944Sobrien
21798944Sobrien	/* Assume ON, check for OFF (case-insensitive) */
21898944Sobrien	option->value.boolean = 1;
21998944Sobrien	strtolower(value);
22098944Sobrien	if (strcmp(value, "off") == 0)
22198944Sobrien		option->value.boolean = 0;
22298944Sobrien
22398944Sobrien	return (0);
22498944Sobrien}
22598944Sobrien
22698944Sobrien/*
22798944Sobrien * figpar call-back for interpreting value as .dialogrc `Number'
22898944Sobrien */
22998944Sobrienstatic int
23098944Sobriensetnum(struct config *option, uint32_t line __unused, char *directive __unused,
23198944Sobrien    char *value)
23298944Sobrien{
23398944Sobrien
23498944Sobrien	if (option == NULL) {
23598944Sobrien		warnx("%s:%d:%s: Missing callback parameter", __FILE__,
23698944Sobrien		    __LINE__, __func__);
23798944Sobrien		return (-1); /* Abort processing */
23898944Sobrien	}
23998944Sobrien
24098944Sobrien	/* Convert the string to a 32-bit signed integer */
24198944Sobrien	option->value.num = (int32_t)strtol(value, (char **)NULL, 10);
24298944Sobrien
24398944Sobrien	return (0);
24498944Sobrien}
24598944Sobrien
24698944Sobrien/*
24798944Sobrien * figpar call-back for interpreting value as .dialogrc `String'
24898944Sobrien */
24998944Sobrienstatic int
25098944Sobriensetstr(struct config *option, uint32_t line __unused, char *directive __unused,
25198944Sobrien    char *value)
25298944Sobrien{
25398944Sobrien	size_t len;
25498944Sobrien
25598944Sobrien	if (option == NULL) {
25698944Sobrien		warnx("%s:%d:%s: Missing callback parameter", __FILE__,
25798944Sobrien		    __LINE__, __func__);
25898944Sobrien		return (-1); /* Abort processing */
25998944Sobrien	}
26098944Sobrien
26198944Sobrien	/* Allocate memory for the data if not already done */
26298944Sobrien	if (option->value.str == NULL) {
26398944Sobrien		if ((option->value.str = malloc(STR_BUFSIZE)) == NULL)
26498944Sobrien			return (-1);
26598944Sobrien	}
26698944Sobrien
26798944Sobrien	/* Trim leading quote */
26898944Sobrien	if (*value == '"')
26998944Sobrien		value++;
27098944Sobrien
27198944Sobrien	/* Write the data into the buffer */
27298944Sobrien	snprintf(option->value.str, STR_BUFSIZE, "%s", value);
27398944Sobrien
27498944Sobrien	/* Trim trailing quote */
27598944Sobrien	len = strlen(option->value.str);
27698944Sobrien	if (option->value.str[len - 1] == '"')
27798944Sobrien		option->value.str[len - 1] = '\0';
27898944Sobrien
27998944Sobrien	return (0);
28098944Sobrien}
28198944Sobrien
28298944Sobrien/*
28398944Sobrien * Parse (in order of preference) $DIALOGRC or `$HOME/.dialogrc'. Returns zero
28498944Sobrien * on success, -1 on failure (and errno should be consulted).
28598944Sobrien */
28698944Sobrienint
28798944Sobrienparse_dialogrc(void)
28898944Sobrien{
28998944Sobrien	char *cp;
29098944Sobrien	int res;
29198944Sobrien	size_t len;
29298944Sobrien	char path[PATH_MAX];
29398944Sobrien
29498944Sobrien	/* Allow $DIALOGRC to override `$HOME/.dialogrc' default */
29598944Sobrien	if ((cp = getenv(ENV_DIALOGRC)) != NULL && *cp != '\0')
29698944Sobrien		snprintf(path, PATH_MAX, "%s", cp);
29798944Sobrien	else if ((cp = getenv(ENV_HOME)) != NULL) {
29898944Sobrien		/* Copy $HOME into buffer and append trailing `/' if missing */
29998944Sobrien		snprintf(path, PATH_MAX, "%s", cp);
30098944Sobrien		len = strlen(path);
30198944Sobrien		cp = path + len;
30298944Sobrien		if (len > 0 && len < (PATH_MAX - 1) && *(cp - 1) != '/') {
30398944Sobrien			*cp++ = '/';
30498944Sobrien			*cp = '\0';
30598944Sobrien			len++;
30698944Sobrien		}
30798944Sobrien
30898944Sobrien		/* If we still have room, shove in the name of rc file */
30998944Sobrien		if (len < (PATH_MAX - 1))
31098944Sobrien			snprintf(cp, PATH_MAX - len, "%s", DIALOGRC);
31198944Sobrien	} else {
31298944Sobrien		/* Like dialog(1), don't process a file if $HOME is unset */
31398944Sobrien		errno = ENOENT;
31498944Sobrien		return (-1);
31598944Sobrien	}
31698944Sobrien
31798944Sobrien	/* Process file (either $DIALOGRC if set, or `$HOME/.dialogrc') */
31898944Sobrien	res = parse_config(dialogrc_config, path, NULL, BREAK_ON_EQUALS);
31998944Sobrien
32098944Sobrien	/* Set some globals based on what we parsed */
32198944Sobrien	use_shadow = dialogrc_config_option("use_shadow")->value.boolean;
32298944Sobrien	use_colors = dialogrc_config_option("use_colors")->value.boolean;
32398944Sobrien	snprintf(gauge_color, STR_BUFSIZE, "%s",
324130803Smarcel	    dialogrc_config_option("gauge_color")->value.str);
325130803Smarcel
326130803Smarcel	return (res);
327130803Smarcel}
328130803Smarcel
329130803Smarcel/*
330130803Smarcel * Return a pointer to the `.dialogrc' config option specific to `directive' or
331130803Smarcel * static dummy_config (full of NULLs) if none found (see get_config_option(3);
332130803Smarcel * part of figpar(3)).
333130803Smarcel */
334130803Smarcelstruct config *
335130803Smarceldialogrc_config_option(const char *directive)
336130803Smarcel{
337130803Smarcel	return (get_config_option(dialogrc_config, directive));
338130803Smarcel}
339130803Smarcel
340130803Smarcel/*
341130803Smarcel * Free allocated items initialized by setattr() (via parse_config() callback
342130803Smarcel * matrix [dialogrc_config] used in parse_dialogrc() above).
343130803Smarcel */
344130803Smarcelvoid
345130803Smarceldialogrc_free(void)
346130803Smarcel{
347130803Smarcel	char *value;
34898944Sobrien	uint32_t n;
34998944Sobrien
35098944Sobrien	for (n = 0; dialogrc_config[n].directive != NULL; n++) {
35198944Sobrien		if (dialogrc_config[n].action != &setattr)
35298944Sobrien			continue;
35398944Sobrien		value = dialogrc_config[n].value.str;
35419370Spst		if (value != NULL && value != gauge_color) {
35519370Spst			free(dialogrc_config[n].value.str);
35698944Sobrien			dialogrc_config[n].value.str = NULL;
357130803Smarcel		}
35819370Spst	}
359130803Smarcel}
360130803Smarcel