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