1 /*- 2 * Copyright (c) 2013-2015 Devin Teske <dteske@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/types.h> 31 32 #include <err.h> 33 #include <errno.h> 34 #include <figpar.h> 35 #include <limits.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <string_m.h> 40 41 #include "dialogrc.h" 42 43 #define STR_BUFSIZE 255 44 45 /* dialog(1) `.dialogrc' characteristics */ 46 uint8_t use_colors = 1; 47 uint8_t use_shadow = 1; 48 char gauge_color[STR_BUFSIZE] = "47b"; /* (BLUE,WHITE,ON) */ 49 char separator[STR_BUFSIZE] = ""; 50 51 /* Function prototypes */ 52 static int setattr(struct figpar_config *, uint32_t, char *, char *); 53 static int setbool(struct figpar_config *, uint32_t, char *, char *); 54 static int setnum(struct figpar_config *, uint32_t, char *, char *); 55 static int setstr(struct figpar_config *, uint32_t, char *, char *); 56 57 /* 58 * Anatomy of DIALOGRC (~/.dialogrc by default) 59 * NOTE: Must appear after private function prototypes (above) 60 * NB: Brace-initialization of union requires cast to *first* member of union 61 */ 62 static struct figpar_config dialogrc_config[] = { 63 /* TYPE DIRECTIVE DEFAULT HANDLER */ 64 {FIGPAR_TYPE_INT, "aspect", {(void *)0}, &setnum}, 65 {FIGPAR_TYPE_STR, "separate_widget", {separator}, &setstr}, 66 {FIGPAR_TYPE_INT, "tab_len", {(void *)0}, &setnum}, 67 {FIGPAR_TYPE_BOOL, "visit_items", {(void *)0}, &setbool}, 68 {FIGPAR_TYPE_BOOL, "use_shadow", {(void *)1}, &setbool}, 69 {FIGPAR_TYPE_BOOL, "use_colors", {(void *)1}, &setbool}, 70 {FIGPAR_TYPE_STR, "screen_color", {NULL}, &setattr}, 71 {FIGPAR_TYPE_STR, "shadow_color", {NULL}, &setattr}, 72 {FIGPAR_TYPE_STR, "dialog_color", {NULL}, &setattr}, 73 {FIGPAR_TYPE_STR, "title_color", {NULL}, &setattr}, 74 {FIGPAR_TYPE_STR, "border_color", {NULL}, &setattr}, 75 {FIGPAR_TYPE_STR, "button_active_color", {NULL}, &setattr}, 76 {FIGPAR_TYPE_STR, "button_inactive_color", {NULL}, &setattr}, 77 {FIGPAR_TYPE_STR, "button_key_active_color", {NULL}, &setattr}, 78 {FIGPAR_TYPE_STR, "button_key_inactive_color", {NULL}, &setattr}, 79 {FIGPAR_TYPE_STR, "button_label_active_color", {NULL}, &setattr}, 80 {FIGPAR_TYPE_STR, "button_label_inactive_color", {NULL}, &setattr}, 81 {FIGPAR_TYPE_STR, "inputbox_color", {NULL}, &setattr}, 82 {FIGPAR_TYPE_STR, "inputbox_border_color", {NULL}, &setattr}, 83 {FIGPAR_TYPE_STR, "searchbox_color", {NULL}, &setattr}, 84 {FIGPAR_TYPE_STR, "searchbox_title_color", {NULL}, &setattr}, 85 {FIGPAR_TYPE_STR, "searchbox_border_color", {NULL}, &setattr}, 86 {FIGPAR_TYPE_STR, "position_indicator_color", {NULL}, &setattr}, 87 {FIGPAR_TYPE_STR, "menubox_color", {NULL}, &setattr}, 88 {FIGPAR_TYPE_STR, "menubox_border_color", {NULL}, &setattr}, 89 {FIGPAR_TYPE_STR, "item_color", {NULL}, &setattr}, 90 {FIGPAR_TYPE_STR, "item_selected_color", {NULL}, &setattr}, 91 {FIGPAR_TYPE_STR, "tag_color", {NULL}, &setattr}, 92 {FIGPAR_TYPE_STR, "tag_selected_color", {NULL}, &setattr}, 93 {FIGPAR_TYPE_STR, "tag_key_color", {NULL}, &setattr}, 94 {FIGPAR_TYPE_STR, "tag_key_selected_color", {NULL}, &setattr}, 95 {FIGPAR_TYPE_STR, "check_color", {NULL}, &setattr}, 96 {FIGPAR_TYPE_STR, "check_selected_color", {NULL}, &setattr}, 97 {FIGPAR_TYPE_STR, "uarrow_color", {NULL}, &setattr}, 98 {FIGPAR_TYPE_STR, "darrow_color", {NULL}, &setattr}, 99 {FIGPAR_TYPE_STR, "itemhelp_color", {NULL}, &setattr}, 100 {FIGPAR_TYPE_STR, "form_active_text_color", {NULL}, &setattr}, 101 {FIGPAR_TYPE_STR, "form_text_color", {NULL}, &setattr}, 102 {FIGPAR_TYPE_STR, "form_item_readonly_color", {NULL}, &setattr}, 103 {FIGPAR_TYPE_STR, "gauge_color", {gauge_color}, &setattr}, 104 {0, NULL, {0}, NULL} 105 }; 106 107 /* 108 * figpar call-back for interpreting value as .dialogrc `Attribute' 109 */ 110 static int 111 setattr(struct figpar_config *option, uint32_t line __unused, 112 char *directive __unused, char *value) 113 { 114 char *cp = value; 115 char *val; 116 size_t len; 117 char attrbuf[4]; 118 119 if (option == NULL) { 120 warnx("%s:%d:%s: Missing callback parameter", __FILE__, 121 __LINE__, __func__); 122 return (-1); /* Abort processing */ 123 } 124 125 /* Allocate memory for the data if not already done */ 126 if (option->value.str == NULL) { 127 if ((option->value.str = malloc(STR_BUFSIZE)) == NULL) 128 return (-1); 129 } 130 131 /* 132 * If the first character is left-parenthesis, the format is 133 * `(background,foreground,highlight)' otherwise, we should take it 134 * as a reference to another color. 135 */ 136 if (*cp != '(') { 137 /* Copy the [current] value from the referenced color */ 138 val = dialogrc_config_option(cp)->value.str; 139 if (val != NULL) 140 snprintf(option->value.str, STR_BUFSIZE, "%s", val); 141 142 return (0); 143 } else 144 cp++; 145 146 strtolower(cp); 147 148 /* Initialize the attrbuf (fg,bg,hi,NUL) */ 149 attrbuf[0] = '0'; 150 attrbuf[1] = '0'; 151 attrbuf[2] = 'B'; /* \ZB = disable; \Zb = enable (see dialog(1)) */ 152 attrbuf[3] = '\0'; 153 154 /* Interpret the foreground color */ 155 if (strncmp(cp, "red,", 4) == 0) attrbuf[0] = '1'; 156 else if (strncmp(cp, "green,", 6) == 0) attrbuf[0] = '2'; 157 else if (strncmp(cp, "yellow,", 7) == 0) attrbuf[0] = '3'; 158 else if (strncmp(cp, "blue,", 5) == 0) attrbuf[0] = '4'; 159 else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[0] = '5'; 160 else if (strncmp(cp, "cyan,", 5) == 0) attrbuf[0] = '6'; 161 else if (strncmp(cp, "white,", 6) == 0) attrbuf[0] = '7'; 162 else if (strncmp(cp, "black,", 6) == 0) attrbuf[0] = '8'; 163 164 /* Advance to the background color */ 165 cp = strchr(cp, ','); 166 if (cp == NULL) 167 goto write_attrbuf; 168 else 169 cp++; 170 171 /* Interpret the background color */ 172 if (strncmp(cp, "red,", 4) == 0) attrbuf[1] = '1'; 173 else if (strncmp(cp, "green,", 6) == 0) attrbuf[1] = '2'; 174 else if (strncmp(cp, "yellow,", 7) == 0) attrbuf[1] = '3'; 175 else if (strncmp(cp, "blue,", 5) == 0) attrbuf[1] = '4'; 176 else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[1] = '5'; 177 else if (strncmp(cp, "cyan,", 5) == 0) attrbuf[1] = '6'; 178 else if (strncmp(cp, "white,", 6) == 0) attrbuf[1] = '7'; 179 else if (strncmp(cp, "black,", 6) == 0) attrbuf[1] = '8'; 180 181 /* Advance to the highlight */ 182 cp = strchr(cp, ','); 183 if (cp == NULL) 184 goto write_attrbuf; 185 else 186 cp++; 187 188 /* Trim trailing parenthesis */ 189 len = strlen(cp); 190 if (cp[len - 1] == ')') 191 cp[len - 1] = '\0'; 192 193 /* Interpret the highlight (initialized to off above) */ 194 if (strcmp(cp, "on") == 0 || strncmp(cp, "on,", 3) == 0) 195 attrbuf[2] = 'b'; /* \Zb = enable bold (see dialog(1)) */ 196 197 write_attrbuf: 198 sprintf(option->value.str, "%s", attrbuf); 199 200 return (0); 201 } 202 203 /* 204 * figpar call-back for interpreting value as .dialogrc `Boolean' 205 */ 206 static int 207 setbool(struct figpar_config *option, uint32_t line __unused, 208 char *directive __unused, char *value) 209 { 210 211 if (option == NULL) { 212 warnx("%s:%d:%s: Missing callback parameter", __FILE__, 213 __LINE__, __func__); 214 return (-1); /* Abort processing */ 215 } 216 217 /* Assume ON, check for OFF (case-insensitive) */ 218 option->value.boolean = 1; 219 strtolower(value); 220 if (strcmp(value, "off") == 0) 221 option->value.boolean = 0; 222 223 return (0); 224 } 225 226 /* 227 * figpar call-back for interpreting value as .dialogrc `Number' 228 */ 229 static int 230 setnum(struct figpar_config *option, uint32_t line __unused, 231 char *directive __unused, char *value) 232 { 233 234 if (option == NULL) { 235 warnx("%s:%d:%s: Missing callback parameter", __FILE__, 236 __LINE__, __func__); 237 return (-1); /* Abort processing */ 238 } 239 240 /* Convert the string to a 32-bit signed integer */ 241 option->value.num = (int32_t)strtol(value, (char **)NULL, 10); 242 243 return (0); 244 } 245 246 /* 247 * figpar call-back for interpreting value as .dialogrc `String' 248 */ 249 static int 250 setstr(struct figpar_config *option, uint32_t line __unused, 251 char *directive __unused, char *value) 252 { 253 size_t len; 254 255 if (option == NULL) { 256 warnx("%s:%d:%s: Missing callback parameter", __FILE__, 257 __LINE__, __func__); 258 return (-1); /* Abort processing */ 259 } 260 261 /* Allocate memory for the data if not already done */ 262 if (option->value.str == NULL) { 263 if ((option->value.str = malloc(STR_BUFSIZE)) == NULL) 264 return (-1); 265 } 266 267 /* Trim leading quote */ 268 if (*value == '"') 269 value++; 270 271 /* Write the data into the buffer */ 272 snprintf(option->value.str, STR_BUFSIZE, "%s", value); 273 274 /* Trim trailing quote */ 275 len = strlen(option->value.str); 276 if (option->value.str[len - 1] == '"') 277 option->value.str[len - 1] = '\0'; 278 279 return (0); 280 } 281 282 /* 283 * Parse (in order of preference) $DIALOGRC or `$HOME/.dialogrc'. Returns zero 284 * on success, -1 on failure (and errno should be consulted). 285 */ 286 int 287 parse_dialogrc(void) 288 { 289 char *cp; 290 int res; 291 size_t len; 292 char path[PATH_MAX]; 293 294 /* Allow $DIALOGRC to override `$HOME/.dialogrc' default */ 295 if ((cp = getenv(ENV_DIALOGRC)) != NULL && *cp != '\0') 296 snprintf(path, PATH_MAX, "%s", cp); 297 else if ((cp = getenv(ENV_HOME)) != NULL) { 298 /* Copy $HOME into buffer and append trailing `/' if missing */ 299 snprintf(path, PATH_MAX, "%s", cp); 300 len = strlen(path); 301 cp = path + len; 302 if (len > 0 && len < (PATH_MAX - 1) && *(cp - 1) != '/') { 303 *cp++ = '/'; 304 *cp = '\0'; 305 len++; 306 } 307 308 /* If we still have room, shove in the name of rc file */ 309 if (len < (PATH_MAX - 1)) 310 snprintf(cp, PATH_MAX - len, "%s", DIALOGRC); 311 } else { 312 /* Like dialog(1), don't process a file if $HOME is unset */ 313 errno = ENOENT; 314 return (-1); 315 } 316 317 /* Process file (either $DIALOGRC if set, or `$HOME/.dialogrc') */ 318 res = parse_config(dialogrc_config, 319 path, NULL, FIGPAR_BREAK_ON_EQUALS); 320 321 /* Set some globals based on what we parsed */ 322 use_shadow = dialogrc_config_option("use_shadow")->value.boolean; 323 use_colors = dialogrc_config_option("use_colors")->value.boolean; 324 snprintf(gauge_color, STR_BUFSIZE, "%s", 325 dialogrc_config_option("gauge_color")->value.str); 326 327 return (res); 328 } 329 330 /* 331 * Return a pointer to the `.dialogrc' config option specific to `directive' or 332 * static figpar_dummy_config (full of NULLs) if none found (see 333 * get_config_option(3); part of figpar(3)). 334 */ 335 struct figpar_config * 336 dialogrc_config_option(const char *directive) 337 { 338 return (get_config_option(dialogrc_config, directive)); 339 } 340 341 /* 342 * Free allocated items initialized by setattr() (via parse_config() callback 343 * matrix [dialogrc_config] used in parse_dialogrc() above). 344 */ 345 void 346 dialogrc_free(void) 347 { 348 char *value; 349 uint32_t n; 350 351 for (n = 0; dialogrc_config[n].directive != NULL; n++) { 352 if (dialogrc_config[n].action != &setattr) 353 continue; 354 value = dialogrc_config[n].value.str; 355 if (value != NULL && value != gauge_color) { 356 free(dialogrc_config[n].value.str); 357 dialogrc_config[n].value.str = NULL; 358 } 359 } 360 } 361