1274116Sdteske/*- 2293619Sdteske * Copyright (c) 2013-2015 Devin Teske <dteske@FreeBSD.org> 3274116Sdteske * All rights reserved. 4274116Sdteske * 5274116Sdteske * Redistribution and use in source and binary forms, with or without 6274116Sdteske * modification, are permitted provided that the following conditions 7274116Sdteske * are met: 8274116Sdteske * 1. Redistributions of source code must retain the above copyright 9274116Sdteske * notice, this list of conditions and the following disclaimer. 10274116Sdteske * 2. Redistributions in binary form must reproduce the above copyright 11274116Sdteske * notice, this list of conditions and the following disclaimer in the 12274116Sdteske * documentation and/or other materials provided with the distribution. 13274116Sdteske * 14274116Sdteske * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15274116Sdteske * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16274116Sdteske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17274116Sdteske * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18274116Sdteske * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19274116Sdteske * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20274116Sdteske * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21274116Sdteske * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22274116Sdteske * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23274116Sdteske * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24274116Sdteske * SUCH DAMAGE. 25274116Sdteske */ 26274116Sdteske 27274116Sdteske#include <sys/cdefs.h> 28274116Sdteske__FBSDID("$FreeBSD: releng/10.3/lib/libdpv/dialogrc.c 293619 2016-01-09 23:33:44Z dteske $"); 29274116Sdteske 30274116Sdteske#include <sys/types.h> 31274116Sdteske 32274116Sdteske#include <err.h> 33274116Sdteske#include <errno.h> 34274116Sdteske#include <figpar.h> 35274116Sdteske#include <limits.h> 36274116Sdteske#include <stdio.h> 37274116Sdteske#include <stdlib.h> 38274116Sdteske#include <string.h> 39274116Sdteske#include <string_m.h> 40274116Sdteske 41274116Sdteske#include "dialogrc.h" 42274116Sdteske 43274116Sdteske#define STR_BUFSIZE 255 44274116Sdteske 45274116Sdteske/* dialog(1) `.dialogrc' characteristics */ 46274116Sdteskeuint8_t use_colors = 1; 47274116Sdteskeuint8_t use_shadow = 1; 48274116Sdteskechar gauge_color[STR_BUFSIZE] = "47b"; /* (BLUE,WHITE,ON) */ 49274116Sdteskechar separator[STR_BUFSIZE] = ""; 50274116Sdteske 51274116Sdteske/* Function prototypes */ 52293619Sdteskestatic int setattr(struct figpar_config *, uint32_t, char *, char *); 53293619Sdteskestatic int setbool(struct figpar_config *, uint32_t, char *, char *); 54293619Sdteskestatic int setnum(struct figpar_config *, uint32_t, char *, char *); 55293619Sdteskestatic int setstr(struct figpar_config *, uint32_t, char *, char *); 56274116Sdteske 57274116Sdteske/* 58274116Sdteske * Anatomy of DIALOGRC (~/.dialogrc by default) 59274116Sdteske * NOTE: Must appear after private function prototypes (above) 60274116Sdteske * NB: Brace-initialization of union requires cast to *first* member of union 61274116Sdteske */ 62293619Sdteskestatic struct figpar_config dialogrc_config[] = { 63293619Sdteske /* TYPE DIRECTIVE DEFAULT HANDLER */ 64293619Sdteske {FIGPAR_TYPE_INT, "aspect", {(void *)0}, &setnum}, 65293619Sdteske {FIGPAR_TYPE_STR, "separate_widget", {separator}, &setstr}, 66293619Sdteske {FIGPAR_TYPE_INT, "tab_len", {(void *)0}, &setnum}, 67293619Sdteske {FIGPAR_TYPE_BOOL, "visit_items", {(void *)0}, &setbool}, 68293619Sdteske {FIGPAR_TYPE_BOOL, "use_shadow", {(void *)1}, &setbool}, 69293619Sdteske {FIGPAR_TYPE_BOOL, "use_colors", {(void *)1}, &setbool}, 70293619Sdteske {FIGPAR_TYPE_STR, "screen_color", {NULL}, &setattr}, 71293619Sdteske {FIGPAR_TYPE_STR, "shadow_color", {NULL}, &setattr}, 72293619Sdteske {FIGPAR_TYPE_STR, "dialog_color", {NULL}, &setattr}, 73293619Sdteske {FIGPAR_TYPE_STR, "title_color", {NULL}, &setattr}, 74293619Sdteske {FIGPAR_TYPE_STR, "border_color", {NULL}, &setattr}, 75293619Sdteske {FIGPAR_TYPE_STR, "button_active_color", {NULL}, &setattr}, 76293619Sdteske {FIGPAR_TYPE_STR, "button_inactive_color", {NULL}, &setattr}, 77293619Sdteske {FIGPAR_TYPE_STR, "button_key_active_color", {NULL}, &setattr}, 78293619Sdteske {FIGPAR_TYPE_STR, "button_key_inactive_color", {NULL}, &setattr}, 79293619Sdteske {FIGPAR_TYPE_STR, "button_label_active_color", {NULL}, &setattr}, 80293619Sdteske {FIGPAR_TYPE_STR, "button_label_inactive_color", {NULL}, &setattr}, 81293619Sdteske {FIGPAR_TYPE_STR, "inputbox_color", {NULL}, &setattr}, 82293619Sdteske {FIGPAR_TYPE_STR, "inputbox_border_color", {NULL}, &setattr}, 83293619Sdteske {FIGPAR_TYPE_STR, "searchbox_color", {NULL}, &setattr}, 84293619Sdteske {FIGPAR_TYPE_STR, "searchbox_title_color", {NULL}, &setattr}, 85293619Sdteske {FIGPAR_TYPE_STR, "searchbox_border_color", {NULL}, &setattr}, 86293619Sdteske {FIGPAR_TYPE_STR, "position_indicator_color", {NULL}, &setattr}, 87293619Sdteske {FIGPAR_TYPE_STR, "menubox_color", {NULL}, &setattr}, 88293619Sdteske {FIGPAR_TYPE_STR, "menubox_border_color", {NULL}, &setattr}, 89293619Sdteske {FIGPAR_TYPE_STR, "item_color", {NULL}, &setattr}, 90293619Sdteske {FIGPAR_TYPE_STR, "item_selected_color", {NULL}, &setattr}, 91293619Sdteske {FIGPAR_TYPE_STR, "tag_color", {NULL}, &setattr}, 92293619Sdteske {FIGPAR_TYPE_STR, "tag_selected_color", {NULL}, &setattr}, 93293619Sdteske {FIGPAR_TYPE_STR, "tag_key_color", {NULL}, &setattr}, 94293619Sdteske {FIGPAR_TYPE_STR, "tag_key_selected_color", {NULL}, &setattr}, 95293619Sdteske {FIGPAR_TYPE_STR, "check_color", {NULL}, &setattr}, 96293619Sdteske {FIGPAR_TYPE_STR, "check_selected_color", {NULL}, &setattr}, 97293619Sdteske {FIGPAR_TYPE_STR, "uarrow_color", {NULL}, &setattr}, 98293619Sdteske {FIGPAR_TYPE_STR, "darrow_color", {NULL}, &setattr}, 99293619Sdteske {FIGPAR_TYPE_STR, "itemhelp_color", {NULL}, &setattr}, 100293619Sdteske {FIGPAR_TYPE_STR, "form_active_text_color", {NULL}, &setattr}, 101293619Sdteske {FIGPAR_TYPE_STR, "form_text_color", {NULL}, &setattr}, 102293619Sdteske {FIGPAR_TYPE_STR, "form_item_readonly_color", {NULL}, &setattr}, 103293619Sdteske {FIGPAR_TYPE_STR, "gauge_color", {gauge_color}, &setattr}, 104274116Sdteske {0, NULL, {0}, NULL} 105274116Sdteske}; 106274116Sdteske 107274116Sdteske/* 108274116Sdteske * figpar call-back for interpreting value as .dialogrc `Attribute' 109274116Sdteske */ 110274116Sdteskestatic int 111293619Sdteskesetattr(struct figpar_config *option, uint32_t line __unused, 112274116Sdteske char *directive __unused, char *value) 113274116Sdteske{ 114274116Sdteske char *cp = value; 115274116Sdteske char *val; 116274116Sdteske size_t len; 117274116Sdteske char attrbuf[4]; 118274116Sdteske 119274116Sdteske if (option == NULL) { 120274116Sdteske warnx("%s:%d:%s: Missing callback parameter", __FILE__, 121274116Sdteske __LINE__, __func__); 122274116Sdteske return (-1); /* Abort processing */ 123274116Sdteske } 124274116Sdteske 125274116Sdteske /* Allocate memory for the data if not already done */ 126274116Sdteske if (option->value.str == NULL) { 127274116Sdteske if ((option->value.str = malloc(STR_BUFSIZE)) == NULL) 128274116Sdteske return (-1); 129274116Sdteske } 130274116Sdteske 131274116Sdteske /* 132274116Sdteske * If the first character is left-parenthesis, the format is 133274116Sdteske * `(background,foreground,highlight)' otherwise, we should take it 134274116Sdteske * as a reference to another color. 135274116Sdteske */ 136274116Sdteske if (*cp != '(') { 137274116Sdteske /* Copy the [current] value from the referenced color */ 138274116Sdteske val = dialogrc_config_option(cp)->value.str; 139274116Sdteske if (val != NULL) 140274116Sdteske snprintf(option->value.str, STR_BUFSIZE, "%s", val); 141274116Sdteske 142274116Sdteske return (0); 143274116Sdteske } else 144274116Sdteske cp++; 145274116Sdteske 146274116Sdteske strtolower(cp); 147274116Sdteske 148274116Sdteske /* Initialize the attrbuf (fg,bg,hi,NUL) */ 149274116Sdteske attrbuf[0] = '0'; 150274116Sdteske attrbuf[1] = '0'; 151274116Sdteske attrbuf[2] = 'B'; /* \ZB = disable; \Zb = enable (see dialog(1)) */ 152274116Sdteske attrbuf[3] = '\0'; 153274116Sdteske 154274116Sdteske /* Interpret the foreground color */ 155274116Sdteske if (strncmp(cp, "red,", 4) == 0) attrbuf[0] = '1'; 156274116Sdteske else if (strncmp(cp, "green,", 6) == 0) attrbuf[0] = '2'; 157274116Sdteske else if (strncmp(cp, "yellow,", 7) == 0) attrbuf[0] = '3'; 158274116Sdteske else if (strncmp(cp, "blue,", 5) == 0) attrbuf[0] = '4'; 159274116Sdteske else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[0] = '5'; 160274116Sdteske else if (strncmp(cp, "cyan,", 5) == 0) attrbuf[0] = '6'; 161274116Sdteske else if (strncmp(cp, "white,", 6) == 0) attrbuf[0] = '7'; 162274116Sdteske else if (strncmp(cp, "black,", 6) == 0) attrbuf[0] = '8'; 163274116Sdteske 164274116Sdteske /* Advance to the background color */ 165274116Sdteske cp = strchr(cp, ','); 166274116Sdteske if (cp == NULL) 167274116Sdteske goto write_attrbuf; 168274116Sdteske else 169274116Sdteske cp++; 170274116Sdteske 171274116Sdteske /* Interpret the background color */ 172274116Sdteske if (strncmp(cp, "red,", 4) == 0) attrbuf[1] = '1'; 173274116Sdteske else if (strncmp(cp, "green,", 6) == 0) attrbuf[1] = '2'; 174274116Sdteske else if (strncmp(cp, "yellow,", 7) == 0) attrbuf[1] = '3'; 175274116Sdteske else if (strncmp(cp, "blue,", 5) == 0) attrbuf[1] = '4'; 176274116Sdteske else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[1] = '5'; 177274116Sdteske else if (strncmp(cp, "cyan,", 5) == 0) attrbuf[1] = '6'; 178274116Sdteske else if (strncmp(cp, "white,", 6) == 0) attrbuf[1] = '7'; 179274116Sdteske else if (strncmp(cp, "black,", 6) == 0) attrbuf[1] = '8'; 180274116Sdteske 181274116Sdteske /* Advance to the highlight */ 182274116Sdteske cp = strchr(cp, ','); 183274116Sdteske if (cp == NULL) 184274116Sdteske goto write_attrbuf; 185274116Sdteske else 186274116Sdteske cp++; 187274116Sdteske 188274116Sdteske /* Trim trailing parenthesis */ 189274116Sdteske len = strlen(cp); 190274116Sdteske if (cp[len - 1] == ')') 191274116Sdteske cp[len - 1] = '\0'; 192274116Sdteske 193274116Sdteske /* Interpret the highlight (initialized to off above) */ 194274116Sdteske if (strcmp(cp, "on") == 0 || strncmp(cp, "on,", 3) == 0) 195274116Sdteske attrbuf[2] = 'b'; /* \Zb = enable bold (see dialog(1)) */ 196274116Sdteske 197274116Sdteskewrite_attrbuf: 198274116Sdteske sprintf(option->value.str, "%s", attrbuf); 199274116Sdteske 200274116Sdteske return (0); 201274116Sdteske} 202274116Sdteske 203274116Sdteske/* 204274116Sdteske * figpar call-back for interpreting value as .dialogrc `Boolean' 205274116Sdteske */ 206274116Sdteskestatic int 207293619Sdteskesetbool(struct figpar_config *option, uint32_t line __unused, 208274116Sdteske char *directive __unused, char *value) 209274116Sdteske{ 210274116Sdteske 211274116Sdteske if (option == NULL) { 212274116Sdteske warnx("%s:%d:%s: Missing callback parameter", __FILE__, 213274116Sdteske __LINE__, __func__); 214274116Sdteske return (-1); /* Abort processing */ 215274116Sdteske } 216274116Sdteske 217274116Sdteske /* Assume ON, check for OFF (case-insensitive) */ 218274116Sdteske option->value.boolean = 1; 219274116Sdteske strtolower(value); 220274116Sdteske if (strcmp(value, "off") == 0) 221274116Sdteske option->value.boolean = 0; 222274116Sdteske 223274116Sdteske return (0); 224274116Sdteske} 225274116Sdteske 226274116Sdteske/* 227274116Sdteske * figpar call-back for interpreting value as .dialogrc `Number' 228274116Sdteske */ 229274116Sdteskestatic int 230293619Sdteskesetnum(struct figpar_config *option, uint32_t line __unused, 231275040Sdteske char *directive __unused, char *value) 232274116Sdteske{ 233274116Sdteske 234274116Sdteske if (option == NULL) { 235274116Sdteske warnx("%s:%d:%s: Missing callback parameter", __FILE__, 236274116Sdteske __LINE__, __func__); 237274116Sdteske return (-1); /* Abort processing */ 238274116Sdteske } 239274116Sdteske 240274116Sdteske /* Convert the string to a 32-bit signed integer */ 241274116Sdteske option->value.num = (int32_t)strtol(value, (char **)NULL, 10); 242274116Sdteske 243274116Sdteske return (0); 244274116Sdteske} 245274116Sdteske 246274116Sdteske/* 247274116Sdteske * figpar call-back for interpreting value as .dialogrc `String' 248274116Sdteske */ 249274116Sdteskestatic int 250293619Sdteskesetstr(struct figpar_config *option, uint32_t line __unused, 251275040Sdteske char *directive __unused, char *value) 252274116Sdteske{ 253274116Sdteske size_t len; 254274116Sdteske 255274116Sdteske if (option == NULL) { 256274116Sdteske warnx("%s:%d:%s: Missing callback parameter", __FILE__, 257274116Sdteske __LINE__, __func__); 258274116Sdteske return (-1); /* Abort processing */ 259274116Sdteske } 260274116Sdteske 261274116Sdteske /* Allocate memory for the data if not already done */ 262274116Sdteske if (option->value.str == NULL) { 263274116Sdteske if ((option->value.str = malloc(STR_BUFSIZE)) == NULL) 264274116Sdteske return (-1); 265274116Sdteske } 266274116Sdteske 267274116Sdteske /* Trim leading quote */ 268274116Sdteske if (*value == '"') 269274116Sdteske value++; 270274116Sdteske 271274116Sdteske /* Write the data into the buffer */ 272274116Sdteske snprintf(option->value.str, STR_BUFSIZE, "%s", value); 273274116Sdteske 274274116Sdteske /* Trim trailing quote */ 275274116Sdteske len = strlen(option->value.str); 276274116Sdteske if (option->value.str[len - 1] == '"') 277274116Sdteske option->value.str[len - 1] = '\0'; 278274116Sdteske 279274116Sdteske return (0); 280274116Sdteske} 281274116Sdteske 282274116Sdteske/* 283274116Sdteske * Parse (in order of preference) $DIALOGRC or `$HOME/.dialogrc'. Returns zero 284274116Sdteske * on success, -1 on failure (and errno should be consulted). 285274116Sdteske */ 286274116Sdteskeint 287274116Sdteskeparse_dialogrc(void) 288274116Sdteske{ 289274116Sdteske char *cp; 290274116Sdteske int res; 291274116Sdteske size_t len; 292274116Sdteske char path[PATH_MAX]; 293274116Sdteske 294274116Sdteske /* Allow $DIALOGRC to override `$HOME/.dialogrc' default */ 295274116Sdteske if ((cp = getenv(ENV_DIALOGRC)) != NULL && *cp != '\0') 296274116Sdteske snprintf(path, PATH_MAX, "%s", cp); 297274116Sdteske else if ((cp = getenv(ENV_HOME)) != NULL) { 298274116Sdteske /* Copy $HOME into buffer and append trailing `/' if missing */ 299274116Sdteske snprintf(path, PATH_MAX, "%s", cp); 300274116Sdteske len = strlen(path); 301274116Sdteske cp = path + len; 302274116Sdteske if (len > 0 && len < (PATH_MAX - 1) && *(cp - 1) != '/') { 303274116Sdteske *cp++ = '/'; 304274116Sdteske *cp = '\0'; 305274116Sdteske len++; 306274116Sdteske } 307274116Sdteske 308274116Sdteske /* If we still have room, shove in the name of rc file */ 309274116Sdteske if (len < (PATH_MAX - 1)) 310274116Sdteske snprintf(cp, PATH_MAX - len, "%s", DIALOGRC); 311274116Sdteske } else { 312274116Sdteske /* Like dialog(1), don't process a file if $HOME is unset */ 313274116Sdteske errno = ENOENT; 314274116Sdteske return (-1); 315274116Sdteske } 316274116Sdteske 317274116Sdteske /* Process file (either $DIALOGRC if set, or `$HOME/.dialogrc') */ 318293619Sdteske res = parse_config(dialogrc_config, 319293619Sdteske path, NULL, FIGPAR_BREAK_ON_EQUALS); 320274116Sdteske 321274116Sdteske /* Set some globals based on what we parsed */ 322274116Sdteske use_shadow = dialogrc_config_option("use_shadow")->value.boolean; 323274116Sdteske use_colors = dialogrc_config_option("use_colors")->value.boolean; 324274116Sdteske snprintf(gauge_color, STR_BUFSIZE, "%s", 325274116Sdteske dialogrc_config_option("gauge_color")->value.str); 326274116Sdteske 327274116Sdteske return (res); 328274116Sdteske} 329274116Sdteske 330274116Sdteske/* 331274116Sdteske * Return a pointer to the `.dialogrc' config option specific to `directive' or 332293619Sdteske * static figpar_dummy_config (full of NULLs) if none found (see 333275040Sdteske * get_config_option(3); part of figpar(3)). 334274116Sdteske */ 335293619Sdteskestruct figpar_config * 336274116Sdteskedialogrc_config_option(const char *directive) 337274116Sdteske{ 338274116Sdteske return (get_config_option(dialogrc_config, directive)); 339274116Sdteske} 340274116Sdteske 341274116Sdteske/* 342274116Sdteske * Free allocated items initialized by setattr() (via parse_config() callback 343274116Sdteske * matrix [dialogrc_config] used in parse_dialogrc() above). 344274116Sdteske */ 345274116Sdteskevoid 346274116Sdteskedialogrc_free(void) 347274116Sdteske{ 348274116Sdteske char *value; 349274116Sdteske uint32_t n; 350274116Sdteske 351274116Sdteske for (n = 0; dialogrc_config[n].directive != NULL; n++) { 352274116Sdteske if (dialogrc_config[n].action != &setattr) 353274116Sdteske continue; 354274116Sdteske value = dialogrc_config[n].value.str; 355274116Sdteske if (value != NULL && value != gauge_color) { 356274116Sdteske free(dialogrc_config[n].value.str); 357274116Sdteske dialogrc_config[n].value.str = NULL; 358274116Sdteske } 359274116Sdteske } 360274116Sdteske} 361