C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
init.c
Go to the documentation of this file.
1/** @file init.c
2 @brief Initialization for Menu Application Programs
3 @author Bill Waller
4 Copyright (c) 2025
5 MIT License
6 billxwaller@gmail.com
7 @date 2026-02-09
8 */
9
10/**
11 @defgroup init C-Menu Initialization
12 @brief Capture Data from the Environment, Command Line, and
13 Configuration File and Populate the Init and SIO Data Structures
14 @verbatim
15 SIO Struct for screen I/O settings (colors, gamma, etc.)
16 Init Struct for application settings (file paths, commands, flags, etc.)
17 @endverbatim
18 */
19
20#define _GNU_SOURCE
21#include <argp.h>
22#include <common.h>
23#include <locale.h>
24#include <stddef.h>
25#include <stdlib.h>
26#include <string.h>
27#include <time.h>
28#include <unistd.h>
29#include <wchar.h>
30
31typedef enum {
32 BG = 257,
89} InitVariables;
90
91bool f_write_config = false;
92int write_config(Init *init);
93void display_version();
94
95// Init *init = nullptr;
96void mapp_initialization(Init *, int, char **);
97void zero_opt_args(Init *);
98int process_config_files(Init *);
99int process_config_file(char *, Init *);
100int parse_opt_args(Init *, int, char **);
101void opt_prt_char(const char *o, const char *name, const char *value);
102void opt_prt_str(const char *o, const char *name, const char *value);
103void opt_prt_int(const char *o, const char *name, int value);
104void opt_prt_double(const char *o, const char *name, double value);
105void opt_prt_bool(const char *o, const char *name, bool value);
106
107bool derive_file_spec(char *, char *, char *);
108void print_argp_doc(FILE *, char *, char *);
109int executor = 0;
110
112const char *argp_program_bug_address = "billxwaller@gmail.com";
113static char doc[] = "C-Menu - User Interface Toolkit";
114static char args_doc[] = "[INPUT] [OUTPUT] [HELP] [ARG4] [ARG5]";
115// const int opt_doc_col = 33;
116
117static struct argp_option options[] = {
118 {"f_write_config", 'W', 0, OPTION_ARG_OPTIONAL, "write configuration", 0},
119 {"minitrc", 'a', "file_spec", 0, "configuration file spec", 1},
120 {"parent_cmd", 'k', 0, 0, "parent command", 1},
121 {"begx", 'X', "number", 0, "begin on column", 2},
122 {"begy", 'Y', "number", 0, "begin on line", 2},
123 {"cols", 'C', "number", 0, "width in columns", 2},
124 {"lines", 'L', "number", 0, "height in lines", 2},
125 {"title", 'T', "text", 0, "Window title", 2},
126 {"out_spec", 'o', "file_spec", 0, "output file spec", 3},
127 {"cmd", 'c', "file_spec", 0, "view cmd, first file", 3},
128 {"cmd_all", 'A', "file_spec", 0, "view cmd, all files", 3},
129 {"help_spec", 'H', "file_spec", 0, "help file spec", 3},
130 {"in_spec", 'i', "file_spec", 0, "input file spec", 3},
131 {"mapp_spec", 'd', "file_spec", 0, "description file spec", 3},
132 {"provider_cmd", 'S', "file_spec", 0, "execute provider of piped input", 3},
133 {"receiver_cmd", 'R', "file_spec", 0, "execute receiver of piped output", 3},
134 {"select_max", 'n', "number", 0, "number of selections", 5},
135 {"f_erase_remainder", 'e', "bool", OPTION_ARG_OPTIONAL, "erase remainder of line on enter", 5},
136 {"f_strip_ansi", 'j', "bool", OPTION_ARG_OPTIONAL, "always strip ansi when writing", 5},
137 {"f_multiple_cmd_args", 'M', "bool", OPTION_ARG_OPTIONAL, "allow multiple command arguments", 5},
138 {"f_read_theme", 'r', "bool", OPTION_ARG_OPTIONAL, "read and process theme file", 5},
139 {"f_squeeze", 's', "bool", OPTION_ARG_OPTIONAL, "squeeze multiple blank lines", 5},
140 {"f_ignore_case", 'x', "bool", OPTION_ARG_OPTIONAL, "ignore case in search", 5},
141 {"p_view_files", 'v', "bool", OPTION_ARG_OPTIONAL, "File View in Pick", 5},
142 {"wrap", 'w', "bool", OPTION_ARG_OPTIONAL, "view wrap lines", 5},
143 {"f_ln", 'N', "bool", OPTION_ARG_OPTIONAL, "line numbers in view", 5},
144 {"fill_char", 'f', "char", 0, "field fill_char (_,.,empty)", 5},
145 {"brackets", 'u', "text", 0, "brackets around fields ([]{}<>)", 5},
146 {"editor", CM_EDITOR, "text", 0, "default editor", 5},
147 {"tab_stop", 't', "number", 0, "number of spaces per tab (4)", 5},
148 {"h_shift", 'z', "number", 0, "horizontal shift width (16)", 5},
149 {"border", BORDER, "text", 0, "single, rounded, double, heavy, none", 5},
150 {"bg", BG, "hex_clr", 0, "Terminal (stdscr) background (#000000)", 6},
151 {"fg", FG, "hex_clr", 0, "Terminal (stdscr) foreground (#d0d0d0)", 6},
152
153 {"box_fg", BOX_FG, "hex_clr", 0, "box foreground (#d0d0d0)", 6},
154 {"box_bg", BOX_BG, "hex_clr", 0, "box background (#000000)", 6},
155 {"ind_fg", IND_FG, "hex_clr", 0, "indicator foreground (#d0d0d0)", 6},
156 {"ind_bg", IND_BG, "hex_clr", 0, "indicator background (#000000)", 6},
157 {"brackets_fg", BRACKETS_FG, "hex_clr", 0, "brackets foreground (#d0d0d0)", 6},
158 {"brackets_bg", BRACKETS_BG, "hex_clr", 0, "brackets background (#000000)", 6},
159 {"fill_char_fg", FILL_CHAR_FG, "hex_clr", 0, "fill character foreground (#d0d0d0)", 6},
160 {"fill_char_bg", FILL_CHAR_BG, "hex_clr", 0, "fill character background (#000000)", 6},
161 {"nt_fg", NT_FG, "hex_clr", 0, "normal foreground (#d0d0d0)", 6},
162 {"nt_bg", NT_BG, "hex_clr", 0, "normal background (#000000)", 6},
163 {"nt_rev_fg", NT_REV_FG, "hex_clr", 0, "normal reverse foreground (#000000)", 6},
164 {"nt_rev_bg", NT_REV_BG, "hex_clr", 0, "normal reverse background (#d0d0d0)", 6},
165 {"nt_hl_fg", NT_HL_FG, "hex_clr", 0, "normal highlight foreground (#ffffff)", 6},
166 {"nt_hl_bg", NT_HL_BG, "hex_clr", 0, "normal highlight background (#000000)", 6},
167 {"nt_hl_rev_fg", NT_HL_REV_FG, "hex_clr", 0, "normal highlight reverse foreground (#f00000)", 6},
168 {"nt_hl_rev_bg", NT_HL_REV_BG, "hex_clr", 0, "normal highlight reverse background (#d0d0d0)", 6},
169 {"ln_fg", LN_FG, "hex_clr", 0, "line number foreground (#0000b0)", 6},
170 {"ln_bg", LN_BG, "hex_clr", 0, "line number background (#202020)", 6},
171 {"cmdln_fg", CMDLN_FG, "hex_clr", 0, "line number foreground (#0000b0)", 6},
172 {"cmdln_bg", CMDLN_BG, "hex_clr", 0, "line number background (#202020)", 6},
173 {"title_fg", TITLE_FG, "hex_clr", 0, "title foreground (#d0d0d0)", 6},
174 {"title_bg", TITLE_BG, "hex_clr", 0, "title background (#000000)", 6},
175 {"ran_fg", RAN_FG, "hex_clr", 0, "ran foreground (#d0d0d0)", 6},
176 {"ran_bg", RAN_BG, "hex_clr", 0, "ran background (#000000)", 6},
177 {"blue_gamma", GM_BLUE, "float", 0, "blue_gamma (1.2)", 7},
178 {"gray_gamma", GM_GRAY, "float", 0, "gray gamma (1.2)", 7},
179 {"green_gamma", GM_GREEN, "float", 0, "green gamma (1.2)", 7},
180 {"red_gamma", GM_RED, "float", 0, "red gamma (View)", 7},
181 {"black", XBLACK, "hex_clr", 0, "black (#000000)", 8},
182 {"red", XRED, "hex_clr", 0, "red (#bf0000)", 8},
183 {"green", XGREEN, "hex_clr", 0, "green (#00cf00)", 8},
184 {"yellow", XYELLOW, "hex_clr", 0, "yellow (#efbf00)", 8},
185 {"blue", XBLUE, "hex_clr", 0, "blue (#0000FF)", 8},
186 {"magenta", XMAGENTA, "hex_clr", 0, "magenta (#9f009f)", 8},
187 {"cyan", XCYAN, "hex_clr", 0, "cyan (#00dfdf)", 8},
188 {"white", XWHITE, "hex_clr", 0, "white (#d0d0d0)", 8},
189 {"bblack", XBBLACK, "hex_clr", 0, "bright black (#7f7f7f)", 8},
190 {"bred", XBRED, "hex_clr", 0, "bright red (#FF3737)", 8},
191 {"bgreen", XBGREEN, "hex_clr", 0, "bright green (#00FF7f)", 8},
192 {"byellow", XBYELLOW, "hex_clr", 0, "bright yellow (#FFeF00)", 8},
193 {"bblue", XBBLUE, "hex_clr", 0, "bright blue (#00cfFF)", 8},
194 {"bmagenta", XMAGENTA, "hex_clr", 0, "bright magenta (#FF00FF)", 8},
195 {"bcyan", XBCYAN, "hex_clr", 0, "bright cyan (#00FFFF)", 8},
196 {"bwhite", XBWHITE, "hex_clr", 0, "bright white (#FFFFFF)", 8},
197 {"mapp_data", MAPP_DATA, "directory", 0, "data directory", 9},
198 {"mapp_help", MAPP_HELP, "directory", 0, "help directory", 9},
199 {"mapp_home", MAPP_HOME, "directory", 0, "home directory", 9},
200 {"mapp_msrc", MAPP_MSRC, "directory", 0, "source directory", 9},
201 {"mapp_user", MAPP_USER, "directory", 0, "user directory", 9},
202 {"mapp_theme", MAPP_THEME, "file", 0, "default theme file", 9},
203 {0},
204};
205
206static error_t
207parse_opt(int key, char *arg, struct argp_state *state) {
208 Init *init = state->input;
209 SIO *sio = init->sio;
210 switch (key) {
211 case 'W':
212 f_write_config = true;
213 break;
214 case 'a':
216 break;
217 case 'k':
219 break;
220 case 'C':
221 init->cols = atoi(arg);
222 break;
223 case 'L':
224 init->lines = atoi(arg);
225 break;
226 case 'T':
227 strnz__cpy(init->title, arg, MAXLEN - 1);
228 break;
229 case 'X':
230 init->begx = atoi(arg);
231 break;
232 case 'Y':
233 init->begy = atoi(arg);
234 break;
235 case 'A':
237 break;
238 case 'c':
239 strnz__cpy(init->cmd, arg, MAXLEN - 1);
240 break;
241 case 'd':
243 break;
244 case 'H':
246 break;
247 case 'i':
249 break;
250 case 'o':
252 break;
253 case 'R':
255 break;
256 case 'S':
258 break;
259 case 'e':
260 init->f_erase_remainder = true;
261 break;
262 case 'f':
264 break;
265 case 'j':
266 init->f_strip_ansi = true;
267 break;
268 case 'M':
269 init->f_multiple_cmd_args = true;
270 break;
271 case 'n':
272 init->select_max = atoi(arg);
273 break;
274 case 'N':
275 if (arg)
276 init->f_ln = str_to_bool(arg);
277 if (arg && arg[0] == 't')
278 init->f_ln = true;
279 else if (arg && arg[0] == 'f')
280 init->f_ln = false;
281 else
282 init->f_ln = true;
283 break;
284 case 'r':
285 init->f_read_theme = true;
286 break;
287 case 's':
288 init->f_squeeze = true;
289 break;
290 case 't':
291 init->tab_stop = atoi(arg);
292 if (init->tab_stop < 1)
293 init->tab_stop = 1;
294 break;
295 case 'z':
296 init->h_shift = atoi(arg);
297 if (init->h_shift < 1)
298 init->h_shift = 1;
299 break;
300 case 'u':
301 strnz__cpy(init->brackets, arg, 2);
302 break;
303 case 'w':
304 if (arg && arg[0] == 't')
305 init->wrap = true;
306 else if (arg && arg[0] == 'f')
307 init->wrap = false;
308 else
309 init->wrap = true;
310 break;
311 case 'v':
312 init->p_view_files = true;
313 if (arg)
315 break;
316 case BG:
317 sscanf(arg, "#%06x", &sio->bg);
318 break;
319 case FG:
320 sscanf(arg, "#%06x", &sio->fg);
321 break;
322 case BORDER:
323 char c = arg[0];
324 if (c == 'r' || c == 'R')
325 sio->border = 'r';
326 else if (c == 's' || c == 'S')
327 sio->border = 's';
328 else if (c == 'd' || c == 'D')
329 sio->border = 'd';
330 else if (c == 'h' || c == 'H')
331 sio->border = 'h';
332 else
333 sio->border = 'n';
334 break;
335 case BOX_FG:
336 sscanf(arg, "#%06x", &sio->box_fg);
337 break;
338 case BOX_BG:
339 sscanf(arg, "#%06x", &sio->box_bg);
340 break;
341 case IND_FG:
342 sscanf(arg, "#%06x", &sio->ind_fg);
343 break;
344 case IND_BG:
345 sscanf(arg, "#%06x", &sio->ind_bg);
346 break;
347 case BRACKETS_FG:
348 sscanf(arg, "#%06x", &sio->brackets_fg);
349 break;
350 case BRACKETS_BG:
351 sscanf(arg, "#%06x", &sio->brackets_bg);
352 break;
353 case FILL_CHAR_FG:
354 sscanf(arg, "#%06x", &sio->fill_char_fg);
355 break;
356 case FILL_CHAR_BG:
357 sscanf(arg, "#%06x", &sio->fill_char_bg);
358 break;
359 case NT_FG:
360 sscanf(arg, "#%06x", &sio->nt_fg);
361 break;
362 case NT_BG:
363 sscanf(arg, "#%06x", &sio->nt_bg);
364 break;
365 case NT_REV_FG:
366 sscanf(arg, "#%06x", &sio->nt_rev_fg);
367 break;
368 case NT_REV_BG:
369 sscanf(arg, "#%06x", &sio->nt_rev_bg);
370 break;
371 case NT_HL_FG:
372 sscanf(arg, "#%06x", &sio->nt_hl_fg);
373 break;
374 case NT_HL_BG:
375 sscanf(arg, "#%06x", &sio->nt_hl_bg);
376 break;
377 case NT_HL_REV_FG:
378 sscanf(arg, "#%06x", &sio->nt_hl_rev_fg);
379 break;
380 case NT_HL_REV_BG:
381 sscanf(arg, "#%06x", &sio->nt_hl_rev_bg);
382 break;
383 case TITLE_FG:
384 sscanf(arg, "#%06x", &sio->title_fg);
385 break;
386 case TITLE_BG:
387 sscanf(arg, "#%06x", &sio->title_bg);
388 break;
389 case LN_FG:
390 sscanf(arg, "#%06x", &sio->ln_fg);
391 break;
392 case LN_BG:
393 sscanf(arg, "#%06x", &sio->ln_bg);
394 break;
395 case CMDLN_FG:
396 sscanf(arg, "#%06x", &sio->cmdln_fg);
397 break;
398 case CMDLN_BG:
399 sscanf(arg, "#%06x", &sio->cmdln_bg);
400 break;
401 case RAN_FG:
402 sscanf(arg, "#%06x", &sio->ran_fg);
403 break;
404 case RAN_BG:
405 sscanf(arg, "#%06x", &sio->ran_bg);
406 break;
407 case GM_BLUE:
409 break;
410 case GM_GRAY:
412 break;
413 case GM_GREEN:
415 break;
416 case GM_RED:
418 break;
419 case MAPP_USER:
421 break;
422 case MAPP_DATA:
424 break;
425 case MAPP_HELP:
427 break;
428 case MAPP_HOME:
430 break;
431 case MAPP_MSRC:
433 break;
434 case MAPP_SPEC:
436 break;
437 case HELP_SPEC:
439 break;
440 case MAPP_THEME:
442 break;
443 case ARGP_KEY_ARG:
444 if (state->arg_num >= 35)
445 argp_usage(state);
446 init->argv[state->arg_num] = strdup(arg);
447 break;
448 case ARGP_KEY_END:
449 init->argc = state->arg_num;
450 init->argv[state->arg_num + 1] = nullptr;
451 break;
452 default:
453 return ARGP_ERR_UNKNOWN;
454 }
455 return 0;
456}
457
458static struct argp argp = {options, parse_opt, args_doc, doc,
459 nullptr, nullptr, nullptr};
460
461/** @brief Main initialization function for MAPP - Menu Application
462 @ingroup init
463 @param init - pointer to Init struct to be initialized
464 @param argc - argument count from main()
465 @param argv - argument vector from main()
466 @code
467 1. Read environment variables and set defaults
468 2. Parse configuration file
469 3. Parse command-line options
470 4. Set up SIO struct with colors and other settings
471 5. Handle special options like help and version
472 @endcode
473 */
474void mapp_initialization(Init *init, int argc, char **argv) {
475 char term[MAXLEN];
476 char tmp_str[MAXLEN];
477 char *e;
478 setlocale(LC_ALL, "en_US.UTF-8");
479 SIO *sio = init->sio;
480 if (!init) {
481 ssnprintf(tmp_str, sizeof(tmp_str), "%s",
482 "init struct not allocated on entry");
483 abend(-1, tmp_str);
484 exit(-1);
485 }
486#ifdef DEBUG_LOG
487 open_cmenu_log();
488#endif
489 e = getenv("CMENU_HOME");
490 if (!e || *e == '\0')
491 strnz__cpy(init->mapp_home, "~/menuapp", MAXLEN);
492 else
494
495 if (init->mapp_home[0] != '\0') {
497 if (!verify_dir(init->mapp_home, R_OK))
498 abend(-1, "MAPP_HOME directory invalid");
499 }
500 // CMENU_RC should be an absolute path
501 e = getenv("CMENU_RC");
502 if (!e || *e == '\0') {
504 strnz__cat(init->minitrc, "/.minitrc", MAXLEN);
505 } else
507 if (init->mapp_user[0] == '\0') {
509 strnz__cat(init->mapp_user, "/user", MAXLEN - 1);
510 }
511 if (init->mapp_theme[0] == '\0') {
513 strnz__cat(init->mapp_theme, "/themes/default", MAXLEN - 1);
514 }
515 if (init->mapp_msrc[0] == '\0') {
517 strnz__cat(init->mapp_msrc, "/msrc", MAXLEN - 1);
518 }
519 if (init->mapp_data[0] == '\0') {
521 strnz__cat(init->mapp_data, "/data", MAXLEN - 1);
522 }
523 if (init->mapp_help[0] == '\0') {
525 strnz__cat(init->mapp_help, "/help", MAXLEN - 1);
526 }
527 init->mapp_spec[0] = '\0'; /**< menu specification file */
528 // Set default colors and settings in SIO struct
529 // These can be overridden by the config file or command-line options
530 // Included here to ensure SIO has valid defaults even if config parsing fails
531
532 sio->border = 'r'; /**< default border style */
533 sio->bg = 0x000000;
534 sio->fg = 0xc0c0c0;
535 sio->border = 'r';
536 sio->box_fg = 0xf00000;
537 sio->box_bg = 0x000000;
538 sio->ind_fg = 0xf00000;
539 sio->ind_bg = 0x000000;
540 sio->ran_fg = 0xf00000;
541 sio->ran_bg = 0x000000;
542 sio->title_fg = 0xf0f0f0;
543 sio->title_bg = 0x000000;
544 sio->nt_fg = 0xc0c0c0;
545 sio->nt_bg = 0x000000;
546 sio->nt_rev_fg = 0x000000;
547 sio->nt_rev_bg = 0xc0c0c0;
548 sio->nt_hl_fg = 0xf00000;
549 sio->nt_hl_bg = 0x000000;
550 sio->nt_hl_rev_fg = 0x000000;
551 sio->nt_hl_rev_bg = 0xc0c0c0;
552 sio->ln_fg = 0x0070ff;
553 sio->ln_bg = 0x101010;
554 sio->cmdln_fg = 0xd0d0d0;
555 sio->cmdln_bg = 0x000000;
556 init->f_erase_remainder = true; /**< erase remainder on enter */
557 init->brackets[0] = '\0'; /**< field enclosure brackets */
558 strnz__cpy(init->fill_char, " ", MAXLEN - 1); /**< field fill character */
559 e = getenv("TERM");
560 if (e == nullptr || *e == '\0')
561 strnz__cpy(term, "xterm-256color", MAXLEN);
562 else
563 strnz__cpy(term, e, MAXLEN - 1);
564 e = getenv("EDITOR");
565 if (e && *e != '\0')
566 strnz__cpy(init->editor, "vi", MAXLEN - 1);
567 else
570 init->mapp_spec[0] = '\0';
571 init->argc = argc;
572 argp_parse(&argp, argc, argv, 0, 0, init);
575 if (f_write_config) {
576 write_config(init);
577 exit(EXIT_SUCCESS);
578 }
579}
580/** @brief Parse command-line options and set Init struct values accordingly
581 @ingroup init
582 @param init - pointer to Init struct to be populated with option values
583 @param argc - argument count from main()
584 @param argv - argument vector from main()
585 @returns 0 on success, -1 on failure
586 @details This function uses the argp library to parse command-line
587 options defined in the options array. It updates the Init struct with
588 values from the options and handles any special flags for dumping or
589 writing configuration.
590 */
591int parse_opt_args(Init *init, int argc, char **argv) {
592 init->argc = destroy_argv(init->argc, init->argv);
593 argp_parse(&argp, argc, argv, 0, 0, init);
594 return 0;
595}
596
597/** @brief Initialize optional arguments in the Init struct to default
598 values
599 @ingroup init
600 @param init - pointer to Init struct to be initialized This function
601 sets all optional argument fields in the Init struct to their default
602 values before parsing command-line options or configuration file. This
603 ensures that any fields not specified by the user will have known default
604 values.
605 */
606void zero_opt_args(Init *init) {
607 init->lines = 0;
608 init->cols = 0;
609 init->begx = 0;
610 init->begy = 0;
611 init->f_mapp_desc = false;
612 init->f_provider_cmd = false;
613 init->f_receiver_cmd = false;
614 init->f_title = false;
615 init->f_mapp_spec = false;
616 init->f_help_spec = false;
617 init->f_in_spec = false;
618 init->f_out_spec = false;
619 init->p_view_files = false;
620 init->h_shift = 0;
621 init->mapp_spec[0] = init->help_spec[0] = '\0';
622 init->provider_cmd[0] = init->receiver_cmd[0] = '\0';
623 init->title[0] = '\0';
624 init->cmd[0] = init->cmd_all[0] = '\0';
625 init->parent_cmd[0] = '\0';
626 init->in_spec[0] = init->out_spec[0] = '\0';
627 init->help_spec[0] = '\0';
628 init->in_spec[0] = '\0';
629 init->out_spec[0] = '\0';
630}
631/** @brief parse the configuration file specified in init->minitrc and set
632 Init struct values accordingly
633 @ingroup init
634 @returns on success, -1 on failure
635 @details Lines beginning with '#" are comments, discard.
636 Copy line to tmp_str removing quotes, spaces, semicolons, and
637 newlines.
638 Record structure is "parse key=value pairs".
639 Skip lines without '='.
640 Set init struct values based on key.
641 Skip unknown keys. */
642int process_config_files(Init *init) {
643 char config_file_name[MAXLEN];
644 int rc;
645 if (!init->minitrc[0]) {
646 char *e = getenv("MINITRC");
647 if (e)
649 else
650 strnz__cpy(init->minitrc, "~/.minitrc", MAXLEN - 1);
651 }
652
654 strnz__cpy(config_file_name, init->minitrc, MAXLEN - 1);
655 rc = process_config_file(config_file_name, init);
656
658 strnz__cpy(config_file_name, init->mapp_theme, MAXLEN - 1);
659 rc = process_config_file(config_file_name, init);
660 return rc;
661}
662
663int process_config_file(char *config_file_name, Init *init) {
664 char include_file_name[MAXLEN];
665 char tmp_str[MAXLEN];
666 char *src_p, *dp;
667 SIO *sio = init->sio;
668 char hex_clr_str[8];
669 char key[MAXLEN];
670 char value[MAXLEN];
671 FILE *config_fp = fopen(config_file_name, "r");
672 char quote_char = '\0';
673 if (!config_fp) {
674 fprintf(stderr, "failed to read file: %s %s\n", config_file_name, strerror(errno));
675 return (-1);
676 }
677 while (fgets(tmp_str, sizeof(tmp_str), config_fp)) {
678 bool inquotes = false;
679 if (tmp_str[0] == '#')
680 continue;
681 src_p = tmp_str;
682 key[0] = '\0';
683 dp = key;
684 // copy delimited by "=" into value
685 while (*src_p != '\0') {
686 if (*src_p == '\n')
687 *dp = *src_p = '\0';
688 if (*src_p == '=') {
689 *dp = '\0';
690 src_p++;
691 break;
692 }
693 if (*src_p == '"' && *src_p == ' ') {
694 src_p++;
695 continue;
696 }
697 *dp++ = *src_p++;
698 }
699 value[0] = '\0';
700 dp = value;
701 // copy delimited by newline or unquoted "#" into value, removing quotes, spaces, semicolons, and newlines, but respecting quotes
702 while (*src_p != '\0') {
703 if ((*src_p == '"' || *src_p == '\'') && (*(src_p + 1) != '\\')) {
704 if (!inquotes) {
705 inquotes = true;
706 quote_char = *src_p++;
707 } else if (*src_p == quote_char) {
708 inquotes = false;
709 quote_char = '\0';
710 }
711 }
712 if (!inquotes) {
713 if (*src_p == '#') {
714 if (unstr_hex_clr(hex_clr_str, src_p)) {
715 strnz__cpy(value, hex_clr_str, MAXLEN - 1);
716 dp = value + strlen(value);
717 }
718 break;
719 }
720 }
721 if (*src_p == ' ' || *src_p == ';') {
722 src_p++;
723 continue;
724 }
725 if (*src_p == '\n') {
726 *src_p = '\0';
727 break;
728 }
729 *dp++ = *src_p++;
730 }
731 *dp = '\0';
732 if (key[0] == '\0')
733 continue;
734 if (value[0] == '\0')
735 continue;
736 if (!strcmp(key, "include")) {
737 strnz__cpy(include_file_name, value, MAXLEN - 1);
738 expand_tilde(include_file_name, MAXLEN - 1);
739 process_config_file(include_file_name, init);
740 continue;
741 }
742 if (!strcmp(key, "minitrc")) {
743 strnz__cpy(init->minitrc, value, MAXLEN - 1);
744 continue;
745 }
746 if (!strcmp(key, "lines")) {
747 init->lines = atoi(value);
748 continue;
749 }
750 if (!strcmp(key, "cols")) {
751 init->cols = atoi(value);
752 continue;
753 }
754 if (!strcmp(key, "begy")) {
755 init->begy = atoi(value);
756 continue;
757 }
758 if (!strcmp(key, "begx")) {
759 init->begx = atoi(value);
760 continue;
761 }
762 if (!strcmp(key, "f_ln")) {
763 init->f_ln = str_to_bool(value);
764 continue;
765 }
766 if (!strcmp(key, "f_at_end_remove")) {
768 continue;
769 }
770 if (!strcmp(key, "f_erase_remainder")) {
772 continue;
773 }
774 if (!strcmp(key, "brackets")) {
775 strnz__cpy(init->brackets, value, 2);
776 continue;
777 }
778 if (!strcmp(key, "fill_char")) {
779 if (strlen(value) > 1)
780 value[1] = '\0';
781 if (wcwidth((int)value[0]) > 1)
782 value[0] = '?';
783 strnz__cpy(init->fill_char, value, 4);
784 continue;
785 }
786 if (!strcmp(key, "f_ignore_case")) {
788 continue;
789 }
790 if (!strcmp(key, "p_view_files")) {
791 init->p_view_files = str_to_bool(value);
792 continue;
793 }
794 if (!strcmp(key, "f_read_theme")) {
795 init->f_read_theme = str_to_bool(value);
796 continue;
797 }
798 if (!strcmp(key, "f_squeeze")) {
799 init->f_squeeze = str_to_bool(value);
800 continue;
801 }
802 if (!strcmp(key, "f_strip_ansi")) {
803 init->f_strip_ansi = str_to_bool(value);
804 continue;
805 }
806 if (!strcmp(key, "f_multiple_cmd_args")) {
808 continue;
809 }
810 if (!strcmp(key, "select_max")) {
811 init->select_max = atoi(value);
812 continue;
813 }
814 if (!strcmp(key, "tab_stop")) {
815 init->tab_stop = atoi(value);
816 continue;
817 }
818 if (!strcmp(key, "h_shift")) {
819 init->h_shift = atoi(value);
820 continue;
821 }
822 if (!strcmp(key, "wrap")) {
823 init->wrap = str_to_bool(value);
824 continue;
825 }
826 if (!strcmp(key, "title")) {
827 strnz__cpy(init->title, value, MAXLEN - 1);
828 continue;
829 }
830 if (!strcmp(key, "cmd")) {
831 strnz__cpy(init->cmd, value, MAXLEN - 1);
832 continue;
833 }
834 if (!strcmp(key, "cmd_all")) {
835 strnz__cpy(init->cmd_all, value, MAXLEN - 1);
836 continue;
837 }
838 if (!strcmp(key, "parent_cmd")) {
840 continue;
841 }
842 if (!strcmp(key, "provider_cmd")) {
844 continue;
845 }
846 if (!strcmp(key, "receiver_cmd")) {
848 continue;
849 }
850 if (!strcmp(key, "editor")) {
851 strnz__cpy(init->editor, value, MAXLEN - 1);
852 continue;
853 }
854 if (!strcmp(key, "border")) {
855 char c = value[0];
856 if (c == 'r' || c == 'R')
857 sio->border = 'r';
858 else if (c == 's' || c == 'S')
859 sio->border = 's';
860 else if (c == 'd' || c == 'D')
861 sio->border = 'd';
862 else if (c == 'h' || c == 'H')
863 sio->border = 'h';
864 else
865 sio->border = 'n';
866 continue;
867 }
868 if (!strcmp(key, "fg")) {
869 sscanf(value, "#%06x", &sio->fg);
870 continue;
871 }
872 if (!strcmp(key, "bg")) {
873 sscanf(value, "#%06x", &sio->bg);
874 continue;
875 }
876 if (!strcmp(key, "box_fg")) {
877 sscanf(value, "#%06x", &sio->fg);
878 continue;
879 }
880 if (!strcmp(key, "box_bg")) {
881 sscanf(value, "#%06x", &sio->box_bg);
882 continue;
883 }
884 if (!strcmp(key, "ind_fg")) {
885 sscanf(value, "#%06x", &sio->ind_fg);
886 continue;
887 }
888 if (!strcmp(key, "ind_bg")) {
889 sscanf(value, "#%06x", &sio->ind_bg);
890 continue;
891 }
892 if (!strcmp(key, "brackets_fg")) {
893 sscanf(value, "#%06x", &sio->brackets_fg);
894 continue;
895 }
896 if (!strcmp(key, "brackets_bg")) {
897 sscanf(value, "#%06x", &sio->brackets_bg);
898 continue;
899 }
900 if (!strcmp(key, "fill_char_fg")) {
901 sscanf(value, "#%06x", &sio->fill_char_fg);
902 continue;
903 }
904 if (!strcmp(key, "fill_char_bg")) {
905 sscanf(value, "#%06x", &sio->fill_char_bg);
906 continue;
907 }
908 if (!strcmp(key, "ln_fg")) {
909 sscanf(value, "#%06x", &sio->ln_fg);
910 continue;
911 }
912 if (!strcmp(key, "ln_bg")) {
913 sscanf(value, "#%06x", &sio->ln_bg);
914 continue;
915 }
916 if (!strcmp(key, "cmdln_fg")) {
917 sscanf(value, "#%06x", &sio->cmdln_fg);
918 continue;
919 }
920 if (!strcmp(key, "cmdln_bg")) {
921 sscanf(value, "#%06x", &sio->cmdln_bg);
922 continue;
923 }
924 if (!strcmp(key, "nt_fg")) {
925 sscanf(value, "#%06x", &sio->nt_fg);
926 continue;
927 }
928 if (!strcmp(key, "nt_bg")) {
929 sscanf(value, "#%06x", &sio->nt_bg);
930 continue;
931 }
932 if (!strcmp(key, "nt_rev_fg")) {
933 sscanf(value, "#%06x", &sio->nt_rev_fg);
934 continue;
935 }
936 if (!strcmp(key, "nt_rev_bg")) {
937 sscanf(value, "#%06x", &sio->nt_rev_bg);
938 continue;
939 }
940 if (!strcmp(key, "nt_hl_fg")) {
941 sscanf(value, "#%06x", &sio->nt_hl_fg);
942 continue;
943 }
944 if (!strcmp(key, "nt_hl_bg")) {
945 sscanf(value, "#%06x", &sio->nt_hl_bg);
946 continue;
947 }
948 if (!strcmp(key, "nt_hl_rev_fg")) {
949 sscanf(value, "#%06x", &sio->nt_hl_rev_fg);
950 continue;
951 }
952 if (!strcmp(key, "nt_hl_rev_bg")) {
953 sscanf(value, "#%06x", &sio->nt_hl_rev_bg);
954 continue;
955 }
956 if (!strcmp(key, "title_fg")) {
957 sscanf(value, "#%06x", &sio->title_fg);
958 continue;
959 }
960 if (!strcmp(key, "title_bg")) {
961 sscanf(value, "#%06x", &sio->title_bg);
962 continue;
963 }
964 if (!strcmp(key, "ran_fg")) {
965 sscanf(value, "#%06x", &sio->ran_fg);
966 continue;
967 }
968 if (!strcmp(key, "ran_bg")) {
969 sscanf(value, "#%06x", &sio->ran_bg);
970 continue;
971 }
972 if (!strcmp(key, "red_gamma")) {
974 continue;
975 }
976 if (!strcmp(key, "green_gamma")) {
978 continue;
979 }
980 if (!strcmp(key, "blue_gamma")) {
982 continue;
983 }
984 if (!strcmp(key, "gray_gamma")) {
986 continue;
987 }
988 if (!strcmp(key, "black")) {
989 sscanf(value, "#%06x", &sio->black);
990 continue;
991 }
992 if (!strcmp(key, "red")) {
993 sscanf(value, "#%06x", &sio->red);
994 continue;
995 }
996 if (!strcmp(key, "green")) {
997 sscanf(value, "#%06x", &sio->green);
998 continue;
999 }
1000 if (!strcmp(key, "yellow")) {
1001 sscanf(value, "#%06x", &sio->yellow);
1002 continue;
1003 }
1004 if (!strcmp(key, "blue")) {
1005 sscanf(value, "#%06x", &sio->blue);
1006 continue;
1007 }
1008 if (!strcmp(key, "magenta")) {
1009 sscanf(value, "#%06x", &sio->magenta);
1010 continue;
1011 }
1012 if (!strcmp(key, "cyan")) {
1013 sscanf(value, "#%06x", &sio->cyan);
1014 continue;
1015 }
1016 if (!strcmp(key, "white")) {
1017 sscanf(value, "#%06x", &sio->white);
1018 continue;
1019 }
1020 if (!strcmp(key, "orange")) {
1021 sscanf(value, "#%06x", &sio->orange);
1022 continue;
1023 }
1024 if (!strcmp(key, "bblack")) {
1025 sscanf(value, "#%06x", &sio->bblack);
1026 continue;
1027 }
1028 if (!strcmp(key, "bred")) {
1029 sscanf(value, "#%06x", &sio->bred);
1030 continue;
1031 }
1032 if (!strcmp(key, "bgreen")) {
1033 sscanf(value, "#%06x", &sio->bgreen);
1034 continue;
1035 }
1036 if (!strcmp(key, "byellow")) {
1037 sscanf(value, "#%06x", &sio->byellow);
1038 continue;
1039 }
1040 if (!strcmp(key, "bblue")) {
1041 sscanf(value, "#%06x", &sio->bblue);
1042 continue;
1043 }
1044 if (!strcmp(key, "bmagenta")) {
1045 sscanf(value, "#%06x", &sio->bmagenta);
1046 continue;
1047 }
1048 if (!strcmp(key, "bcyan")) {
1049 sscanf(value, "#%06x", &sio->bcyan);
1050 continue;
1051 }
1052 if (!strcmp(key, "bwhite")) {
1053 sscanf(value, "#%06x", &sio->bwhite);
1054 continue;
1055 }
1056 if (!strcmp(key, "borange")) {
1057 sscanf(value, "#%06x", &sio->borange);
1058 continue;
1059 }
1060 if (!strcmp(key, "mapp_spec")) {
1061 strnz__cpy(init->mapp_spec, value, MAXLEN - 1);
1062 continue;
1063 }
1064 if (!strcmp(key, "mapp_data")) {
1065 strnz__cpy(init->mapp_data, value, MAXLEN - 1);
1066 continue;
1067 }
1068 if (!strcmp(key, "mapp_help")) {
1069 strnz__cpy(init->mapp_help, value, MAXLEN - 1);
1070 continue;
1071 }
1072 if (!strcmp(key, "mapp_home")) {
1073 strnz__cpy(init->mapp_home, value, MAXLEN - 1);
1074 continue;
1075 }
1076 if (!strcmp(key, "mapp_msrc")) {
1077 strnz__cpy(init->mapp_msrc, value, MAXLEN - 1);
1078 continue;
1079 }
1080 if (!strcmp(key, "mapp_user")) {
1081 strnz__cpy(init->mapp_user, value, MAXLEN - 1);
1082 continue;
1083 }
1084 if (!strcmp(key, "mapp_theme")) {
1085 strnz__cpy(init->mapp_theme, value, MAXLEN - 1);
1086 continue;
1087 }
1088 }
1089 (void)fclose(config_fp);
1090 return 0;
1091}
1092/** @brief Write the current configuration to a file specified in
1093 init->minitrc
1094 @ingroup init
1095 @param init - pointer to Init struct containing current configuration
1096 @returns 0 on success, -1 on failure
1097 @details The configuration is written in key=value format, one per line.
1098 Lines beginning with '#' are comments and are ignored when reading
1099 the config file.
1100 The file is created if it does not exist, and overwritten if it
1101 does exist
1102 */
1103int write_config(Init *init) {
1104 char *e;
1105 char minitrc_dmp[MAXLEN];
1106 char tmp_str[MAXLEN];
1107 SIO *sio = init->sio;
1108 e = getenv("CMENU_HOME");
1109 minitrc_dmp[0] = '\0';
1110 char config_s[MAXLEN];
1111 if (e) {
1112 strnz__cpy(minitrc_dmp, e, MAXLEN - 1);
1113 strnz__cat(minitrc_dmp, "/", MAXLEN - 1);
1114 }
1115 strnz__cat(minitrc_dmp, "minitrc.dmp", MAXLEN - 1);
1116 FILE *minitrc_fp = fopen(minitrc_dmp, "w");
1117 if (minitrc_fp == (FILE *)0) {
1118 fprintf(stderr, "failed to open file: %s\n", minitrc_dmp);
1119 return (-1);
1120 }
1121 (void)fprintf(minitrc_fp, "# %s\n", minitrc_dmp);
1122 char *doc_tbl[50] = {
1123 "# C-Menu example configuration file",
1124 "#",
1125 "# This file is generated by C-Menu when run with the -W option.",
1126 "# Copy this file and edit the copy because this file will be",
1127 "# overwritten each time C-Menu is run with the - W option.",
1128 "#",
1129 "# C-Menu processes key value pairs in reading order from its",
1130 "# main configuraiton file, ~/ menuapp /.minitrc, and any other",
1131 "# configuration files sourced with include statements such as",
1132 "# the following:",
1133 "#",
1134 "# include = ~/menuapp/theme/default",
1135 "#",
1136 "# Assuming your configuration file is in ~/menuapp/theme/Red,",
1137 "# you could create a symbolic link named default that points to",
1138 "# Red, and then include default in your main configuration file.",
1139 "# (Actually ~/menuapp/.minitrc already includes default, so you",
1140 "# would only need to create the theme file and the symbolic link.",
1141 "#",
1142 "# ln -s Red default",
1143 "#",
1144 "# Key value pairs included from configuration files are",
1145 "# processed in reading order as they are included.",
1146 "#",
1147 "# This is significant in the event that a key is included more",
1148 "# than once in the configuration file and / or included files.",
1149 "# Only the last value read for a key will be used by C-Menu.",
1150 "#",
1151 "# If you want to override key values in the C-Menu configuration",
1152 "# file, you can do so by inserting an include statement for a",
1153 "# supplemental configuration file below the keys you want to",
1154 "# override in the C-Menu configuration file. Conversely, if you",
1155 "# want to use a supplemental configuration as the default,",
1156 "# include it first.",
1157 "#",
1158 "# Parsing: Lines beginning with # are comments and are ignored.",
1159 "# Lines containing key=value pairs are parsed and the key and",
1160 "# value are extracted. Lines without an '=' are ignored. Values",
1161 "# are stripped of leading and trailing whitespace and quotes.",
1162 "# Values can be enclosed in single or double quotes to preserve",
1163 "# leading and trailing whitespace. Values can also be specified",
1164 "# as hex color codes such as #ff0000 for red. If a value is",
1165 "# specified as a hex color code, it is parsed and stored as a",
1166 "# hex color code in the configuration. An unquoted '#' that is",
1167 "# not part of a six digit hex color code and after key values",
1168 "# have been extracted is the beginning of a comment.", ""};
1169 for (int i = 0; doc_tbl[i][0] != '\0'; i++)
1170 (void)fprintf(minitrc_fp, "%s\n", doc_tbl[i]);
1171 (void)fprintf(minitrc_fp, "#\n");
1172 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "parent_cmd", init->parent_cmd);
1173 print_argp_doc(minitrc_fp, config_s, "parent_cmd");
1174 ssnprintf(config_s, MAXLEN - 1, "%s=%d", "cols", init->cols);
1175 print_argp_doc(minitrc_fp, config_s, "cols");
1176 ssnprintf(config_s, MAXLEN - 1, "%s=%d", "lines", init->lines);
1177 print_argp_doc(minitrc_fp, config_s, "lines");
1178 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "title", init->title);
1179 print_argp_doc(minitrc_fp, config_s, "title");
1180 ssnprintf(config_s, MAXLEN - 1, "%s=%d", "begx", init->begx);
1181 print_argp_doc(minitrc_fp, config_s, "begx");
1182 ssnprintf(config_s, MAXLEN - 1, "%s=%d", "begy", init->begy);
1183 print_argp_doc(minitrc_fp, config_s, "begy");
1184 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "cmd_all", init->cmd_all);
1185 print_argp_doc(minitrc_fp, config_s, "cmd_all");
1186 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "cmd", init->cmd);
1187 print_argp_doc(minitrc_fp, config_s, "cmd");
1188 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "mapp_spec", init->mapp_spec);
1189 print_argp_doc(minitrc_fp, config_s, "mapp_spec");
1190 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "help_spec", init->help_spec);
1191 print_argp_doc(minitrc_fp, config_s, "help_spec");
1192 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "in_spec", init->in_spec);
1193 print_argp_doc(minitrc_fp, config_s, "in_spec");
1194 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "out_spec", init->out_spec);
1195 print_argp_doc(minitrc_fp, config_s, "out_spec");
1196 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "receiver_cmd", init->receiver_cmd);
1197 print_argp_doc(minitrc_fp, config_s, "receiver_cmd");
1198 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "provider_cmd", init->provider_cmd);
1199 print_argp_doc(minitrc_fp, config_s, "provider_cmd");
1200 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "f_erase_remainder", init->f_erase_remainder ? "true" : "false");
1201 print_argp_doc(minitrc_fp, config_s, "f_erase_remainder");
1202 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "fill_char", init->fill_char);
1203 print_argp_doc(minitrc_fp, config_s, "fill_char");
1204 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "f_strip_ansi", init->f_strip_ansi ? "true" : "false");
1205 print_argp_doc(minitrc_fp, config_s, "f_strip_ansi");
1206 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "f_multiple_cmd_args", init->f_multiple_cmd_args ? "true" : "false");
1207 print_argp_doc(minitrc_fp, config_s, "f_multiple_cmd_args");
1208 ssnprintf(config_s, MAXLEN - 1, "%s=%d", "select_max", init->select_max);
1209 print_argp_doc(minitrc_fp, config_s, "select_max");
1210
1211 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "f_ln", init->f_ln ? "true" : "false");
1212 print_argp_doc(minitrc_fp, config_s, "f_ln");
1213
1214 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "f_squeeze", init->f_squeeze ? "true" : "false");
1215 print_argp_doc(minitrc_fp, config_s, "f_squeeze");
1216 ssnprintf(config_s, MAXLEN - 1, "%s=%d", "tab_stop", init->tab_stop);
1217 print_argp_doc(minitrc_fp, config_s, "tab_stop");
1218 ssnprintf(config_s, MAXLEN - 1, "%s=%d", "h_shift", init->h_shift);
1219 print_argp_doc(minitrc_fp, config_s, "h_shift");
1220 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "brackets", init->brackets);
1221 print_argp_doc(minitrc_fp, config_s, "brackets");
1222
1223 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "wrap", init->wrap ? "true" : "false");
1224 print_argp_doc(minitrc_fp, config_s, "wrap");
1225
1226 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "f_ignore_case", init->f_ignore_case ? "true" : "false");
1227 print_argp_doc(minitrc_fp, config_s, "f_ignore_case");
1228 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "p_view_files", init->p_view_files ? "true" : "false");
1229 print_argp_doc(minitrc_fp, config_s, "p_view_files");
1230 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "f_read_theme", init->f_read_theme ? "true" : "false");
1231 print_argp_doc(minitrc_fp, config_s, "f_read_theme");
1232 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "editor", init->editor);
1233 print_argp_doc(minitrc_fp, config_s, "editor");
1234 ssnprintf(config_s, MAXLEN - 1, "%s=%c", "border", sio->border);
1235 print_argp_doc(minitrc_fp, config_s, "border");
1236 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "bg", sio->bg);
1237 print_argp_doc(minitrc_fp, config_s, "bg");
1238 ssnprintf(config_s, MAXLEN - 1, "%s=#%6x", "fg", sio->fg);
1239 print_argp_doc(minitrc_fp, config_s, "fg");
1240 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "box_fg", sio->box_fg);
1241 print_argp_doc(minitrc_fp, config_s, "box_fg");
1242 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "box_bg", sio->box_bg);
1243 print_argp_doc(minitrc_fp, config_s, "box_bg");
1244 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "ind_fg", sio->ind_fg);
1245 print_argp_doc(minitrc_fp, config_s, "ind_fg");
1246 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "ind_bg", sio->ind_bg);
1247 print_argp_doc(minitrc_fp, config_s, "ind_bg");
1248 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "brackets_fg", sio->brackets_fg);
1249 print_argp_doc(minitrc_fp, config_s, "brackets_fg");
1250 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "brackets_bg", sio->brackets_bg);
1251 print_argp_doc(minitrc_fp, config_s, "brackets_bg");
1252 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "fill_char_fg", sio->fill_char_fg);
1253 print_argp_doc(minitrc_fp, config_s, "fill_char_fg");
1254 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "fill_char_bg", sio->fill_char_bg);
1255 print_argp_doc(minitrc_fp, config_s, "fill_char_bg");
1256 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "ln_bg", sio->ln_bg);
1257 print_argp_doc(minitrc_fp, config_s, "ln_bg");
1258 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "ln_fg", sio->ln_fg);
1259 print_argp_doc(minitrc_fp, config_s, "ln_bg");
1260 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "cmdln_bg", sio->cmdln_bg);
1261 print_argp_doc(minitrc_fp, config_s, "cmdln_bg");
1262 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "cmdln_fg", sio->cmdln_fg);
1263 print_argp_doc(minitrc_fp, config_s, "cmdln_fg");
1264
1265 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "nt_fg", sio->nt_fg);
1266 print_argp_doc(minitrc_fp, config_s, "nt_fg");
1267 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "nt_bg", sio->nt_bg);
1268 print_argp_doc(minitrc_fp, config_s, "nt_bg");
1269 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "nt_hl_fg", sio->nt_hl_fg);
1270 print_argp_doc(minitrc_fp, config_s, "nt_hl_fg");
1271 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "nt_hl_bg", sio->nt_hl_bg);
1272 print_argp_doc(minitrc_fp, config_s, "nt_hl_bg");
1273 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "nt_rev_fg", sio->nt_rev_fg);
1274 print_argp_doc(minitrc_fp, config_s, "nt_rev_fg");
1275 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "nt_rev_bg", sio->nt_rev_bg);
1276 print_argp_doc(minitrc_fp, config_s, "nt_rev_bg");
1277 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "nt_hl_rev_fg", sio->nt_hl_rev_fg);
1278 print_argp_doc(minitrc_fp, config_s, "nt_hl_rev_fg");
1279 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "nt_hl_rev_bg", sio->nt_hl_rev_bg);
1280 print_argp_doc(minitrc_fp, config_s, "nt_hl_rev_bg");
1281 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "title_fg", sio->title_fg);
1282 print_argp_doc(minitrc_fp, config_s, "title_fg");
1283 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "title_bg", sio->title_bg);
1284 print_argp_doc(minitrc_fp, config_s, "title_bg");
1285 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "ran_fg", sio->ran_fg);
1286 print_argp_doc(minitrc_fp, config_s, "ran_fg");
1287 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "ran_bg", sio->ran_bg);
1288 print_argp_doc(minitrc_fp, config_s, "ran_bg");
1289 ssnprintf(config_s, MAXLEN - 1, "%s=%0.2f", "blue_gamma", sio->blue_gamma);
1290 print_argp_doc(minitrc_fp, config_s, "blue_gamma");
1291 ssnprintf(config_s, MAXLEN - 1, "%s=%0.2f", "gray_gamma", sio->gray_gamma);
1292 print_argp_doc(minitrc_fp, config_s, "gray_gamma");
1293 ssnprintf(config_s, MAXLEN - 1, "%s=%0.2f", "green_gamma", sio->green_gamma);
1294 print_argp_doc(minitrc_fp, config_s, "green_gamma");
1295 ssnprintf(config_s, MAXLEN - 1, "%s=%0.2f", "red_gamma", sio->red_gamma);
1296 print_argp_doc(minitrc_fp, config_s, "red_gamma");
1297 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "black", sio->black);
1298 print_argp_doc(minitrc_fp, config_s, "black");
1299 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "red", sio->red);
1300 print_argp_doc(minitrc_fp, config_s, "red");
1301 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "green", sio->green);
1302 print_argp_doc(minitrc_fp, config_s, "green");
1303 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "yellow", sio->yellow);
1304 print_argp_doc(minitrc_fp, config_s, "yellow");
1305 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "blue", sio->blue);
1306 print_argp_doc(minitrc_fp, config_s, "blue");
1307 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "magenta", sio->magenta);
1308 print_argp_doc(minitrc_fp, config_s, "magenta");
1309 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "cyan", sio->cyan);
1310 print_argp_doc(minitrc_fp, config_s, "cyan");
1311 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "white", sio->white);
1312 print_argp_doc(minitrc_fp, config_s, "white");
1313 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "bblack", sio->bblack);
1314 print_argp_doc(minitrc_fp, config_s, "bblack");
1315 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "bred", sio->bred);
1316 print_argp_doc(minitrc_fp, config_s, "bred");
1317 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "bgreen", sio->bgreen);
1318 print_argp_doc(minitrc_fp, config_s, "bgreen");
1319 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "byellow", sio->byellow);
1320 print_argp_doc(minitrc_fp, config_s, "byellow");
1321 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "bblue", sio->bblue);
1322 print_argp_doc(minitrc_fp, config_s, "bblue");
1323 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "bmagenta", sio->bmagenta);
1324 print_argp_doc(minitrc_fp, config_s, "bmagenta");
1325 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "bcyan", sio->bcyan);
1326 print_argp_doc(minitrc_fp, config_s, "bcyan");
1327 ssnprintf(config_s, MAXLEN - 1, "%s=#%06x", "bwhite", sio->bwhite);
1328 print_argp_doc(minitrc_fp, config_s, "bwhite");
1329 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "mapp_data", init->mapp_data);
1330 print_argp_doc(minitrc_fp, config_s, "mapp_data");
1331 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "mapp_help", init->mapp_help);
1332 print_argp_doc(minitrc_fp, config_s, "mapp_help");
1333 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "mapp_home", init->mapp_home);
1334 print_argp_doc(minitrc_fp, config_s, "mapp_home");
1335 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "mapp_msrc", init->mapp_msrc);
1336 print_argp_doc(minitrc_fp, config_s, "mapp_msrc");
1337 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "mapp_user", init->mapp_user);
1338 print_argp_doc(minitrc_fp, config_s, "mapp_user");
1339 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "mapp_theme", init->mapp_theme);
1340 print_argp_doc(minitrc_fp, config_s, "mapp_theme");
1341 ssnprintf(config_s, MAXLEN - 1, "%s=%s", "include", init->mapp_theme);
1342 (void)fprintf(minitrc_fp, "%-34s # default theme file\n", config_s);
1343 strnz__cpy(tmp_str, "Configuration written to file: ", MAXLEN - 1);
1344 strnz__cat(tmp_str, minitrc_dmp, MAXLEN - 1);
1345 Perror(tmp_str);
1346 return 0;
1347}
1348void print_argp_doc(FILE *minitrc_fp, char *config_s, char *key) {
1349 char comment[MAXLEN];
1350 comment[0] = '\0';
1351 if (get_argp_doc_by_name(comment, options, key))
1352 (void)fprintf(minitrc_fp, "%-34s # %s\n", config_s, comment);
1353 else
1354 (void)fprintf(minitrc_fp, "%-34s #\n", config_s);
1355}
1356/** @brief Derive full file specification from directory and file name
1357 @ingroup init
1358 @param file_spec - output full file specification
1359 @param dir - directory path
1360 @param file_name - file name
1361 @returns true if file_spec is derived, false otherwise
1362 @details If dir is nullptr, use MAPP_DIR environment variable or default
1363 directory, ~/menuapp.
1364 file_spec should be a pre-allocated char array of size MAXLEN to
1365 hold the resulting file specification
1366 */
1367bool derive_file_spec(char *file_spec, char *dir, char *file_name) {
1368 char tmp_str[MAXLEN];
1369 char ts2[MAXLEN];
1370 char *e;
1371
1372 if (!file_name || !*file_name) {
1373 *file_spec = '\0';
1374 return false;
1375 }
1376 if (dir) {
1377 strnz__cpy(tmp_str, dir, MAXLEN - 1);
1378 } else {
1379 e = getenv("MAPP_DIR");
1380 if (e) {
1381 strnz__cpy(tmp_str, e, MAXLEN - 1);
1382 } else {
1383 strnz__cpy(tmp_str, "~/menuapp", MAXLEN - 1);
1384 }
1385 }
1386 trim_path(tmp_str);
1387 strnz__cpy(ts2, tmp_str, MAXLEN - 1);
1388 // construct the full file specification
1389 // check that the file exists and is readable
1390 strnz__cpy(file_spec, ts2, MAXLEN - 1);
1391 strnz__cat(file_spec, "/", MAXLEN - 1);
1392 strnz__cat(file_spec, file_name, MAXLEN - 1);
1393 return true;
1394}
1395/** @brief Display the version information of the application
1396 @ingroup init
1397 @details The version information is defined in the mapp_version variable
1398 and is printed to stdout when this function is called. */
1400 fprintf(stdout, "\nC-Menu %s\n", CM_VERSION);
1401 fprintf(stdout, "\nC-Menu %s\n", CM_VERSION);
1402 fprintf(stdout, "C version: %ld\n", __STDC_VERSION__);
1403}
1404/** @brief Print an option and its value in a formatted manner
1405 @ingroup init
1406 @param o - option flag (e.g., "-a:")
1407 @param name - option name (e.g., "--minitrc")
1408 @param value - option value to print
1409 @details This function is used to display the current configuration options
1410 and their values in a readable format. */
1411void opt_prt_char(const char *o, const char *name, const char *value) {
1412 fprintf(stdout, "%3s %-15s: %s\n", o, name, value);
1413}
1414/** @brief Print an option and its value in a formatted manner for integer
1415 values
1416 @ingroup init
1417 @param o - option flag (e.g., "-C:")
1418 @param name - option name (e.g., "--cols")
1419 @param value - integer option value to print
1420 @details This function is used to display the current configuration options
1421 and their integer values in a readable format. */
1422void opt_prt_str(const char *o, const char *name, const char *value) {
1423 fprintf(stdout, "%3s %-15s: %s\n", o, name, value);
1424}
1425/** @brief Print an option and its value in a formatted manner for integer
1426 values
1427 @ingroup init
1428 @param o - option flag (e.g., "-C:")
1429 @param name - option name (e.g., "--cols")
1430 @param value - integer option value to print
1431 @details This function is used to display the current configuration options
1432 and their integer values in a readable format. */
1433void opt_prt_int(const char *o, const char *name, int value) {
1434 fprintf(stdout, "%3s %-15s: %d\n", o, name, value);
1435}
1436/** @brief Print an option and its value in a formatted manner for double
1437 values
1438 @ingroup init
1439 @param o - option flag (e.g., "-r:")
1440 @param name - option name (e.g., "red_gamma")
1441 @param value - double option value to print
1442 @details This function is used to display the current configuration options
1443 and their double values in a readable format. */
1444void opt_prt_double(const char *o, const char *name, double value) {
1445 fprintf(stdout, "%3s %-15s: %0.2f\n", o, name, value);
1446}
1447/** @brief Print an option and its value in a formatted manner for boolean
1448 values
1449 @ingroup init
1450 @param o - option flag (e.g., "-z")
1451 @param name - option name (e.g., "f_squeeze")
1452 @param value - boolean option value to print
1453 @details This function is used to display the current configuration options
1454 and their boolean values in a readable format, printing "true" or "false"
1455 based on the value. */
1456void opt_prt_bool(const char *o, const char *name, bool value) {
1457 fprintf(stdout, "%3s %-15s: %s\n", o, name, value ? "true" : "false");
1458}
bool str_to_bool(const char *)
Converts String to boolean true or false.
Definition futil.c:934
#define CM_VERSION
Definition version.h:7
#define MAXLEN
Definition curskeys.c:15
const char * argp_program_version
Definition init.c:111
int process_config_file(char *, Init *)
Definition init.c:663
void print_argp_doc(FILE *, char *, char *)
Definition init.c:1348
@ XBBLACK
Definition init.c:59
@ XBCYAN
Definition init.c:61
@ MAPP_THEME
Definition init.c:87
@ IND_BG
Definition init.c:37
@ NT_HL_REV_FG
Definition init.c:48
@ XYELLOW
Definition init.c:75
@ RAN_BG
Definition init.c:57
@ LN_BG
Definition init.c:53
@ XRED
Definition init.c:73
@ MAPP_USER
Definition init.c:84
@ NT_BG
Definition init.c:43
@ XBLACK
Definition init.c:63
@ CMDLN_FG
Definition init.c:54
@ FILL_CHAR_BG
Definition init.c:41
@ XBWHITE
Definition init.c:67
@ XBLUE
Definition init.c:64
@ FILL_CHAR_FG
Definition init.c:40
@ NT_REV_BG
Definition init.c:45
@ BORDER
Definition init.c:58
@ XGREEN
Definition init.c:71
@ NT_HL_FG
Definition init.c:46
@ MAPP_HELP
Definition init.c:81
@ XBBLUE
Definition init.c:60
@ XBYELLOW
Definition init.c:68
@ CMDLN_BG
Definition init.c:55
@ XCYAN
Definition init.c:69
@ TITLE_BG
Definition init.c:51
@ BRACKETS_FG
Definition init.c:38
@ NT_HL_REV_BG
Definition init.c:49
@ NT_FG
Definition init.c:42
@ GM_RED
Definition init.c:79
@ BRACKETS_BG
Definition init.c:39
@ NT_REV_FG
Definition init.c:44
@ HELP_SPEC
Definition init.c:86
@ XBMAGENTA
Definition init.c:65
@ CM_EDITOR
Definition init.c:70
@ FG
Definition init.c:33
@ GM_GRAY
Definition init.c:77
@ BG
Definition init.c:32
@ MAPP_MSRC
Definition init.c:83
@ GM_GREEN
Definition init.c:78
@ XBGREEN
Definition init.c:62
@ IND_FG
Definition init.c:36
@ XWHITE
Definition init.c:74
@ MAPP_HOME
Definition init.c:82
@ RAN_FG
Definition init.c:56
@ BOX_BG
Definition init.c:35
@ XMAGENTA
Definition init.c:72
@ MAPP_DATA
Definition init.c:80
@ NT_HL_BG
Definition init.c:47
@ MAPP_SPEC
Definition init.c:85
@ LN_FG
Definition init.c:52
@ END_INIT_VARS
Definition init.c:88
@ XBRED
Definition init.c:66
@ TITLE_FG
Definition init.c:50
@ BOX_FG
Definition init.c:34
@ GM_BLUE
Definition init.c:76
int executor
Definition init.c:109
bool f_write_config
Definition init.c:91
const char * argp_program_bug_address
Definition init.c:112
int Perror(char *emsg_str)
Display a simple error message window or print to stderr.
Definition dwin.c:841
void abend(int ec, char *s)
Abnormal program termination.
Definition dwin.c:1204
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:537
double str_to_double(char *)
converts string to double
Definition futil.c:922
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:413
bool expand_tilde(char *, uint)
Replaces "~/" in string with the user's home directory.
Definition futil.c:963
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
Definition futil.c:566
bool get_argp_doc_by_name(char *comment, const struct argp_option *, const char *)
Retrieves the documentation string for a given key name from an argp options array.
Definition futil.c:169
int destroy_argv(uint argc, char **argv)
Deallocates memory allocated for argument strings in argv.
Definition futil.c:487
bool verify_dir(char *, uint)
Verifies that the directory specified by "spec" exists and is accessible with the permissions specifi...
Definition futil.c:1172
bool trim_path(char *)
Trims trailing spaces and slashes from directory path in place.
Definition futil.c:981
bool unstr_hex_clr(char *, char *)
Validates that a string is a hex color code in the format "#RRGGBB".
Definition futil.c:225
void opt_prt_str(const char *o, const char *name, const char *value)
Print an option and its value in a formatted manner for integer values.
Definition init.c:1422
int parse_opt_args(Init *, int, char **)
Parse command-line options and set Init struct values accordingly.
Definition init.c:591
bool derive_file_spec(char *, char *, char *)
Derive full file specification from directory and file name.
Definition init.c:1367
void display_version()
Display the version information of the application.
Definition init.c:1399
void opt_prt_double(const char *o, const char *name, double value)
Print an option and its value in a formatted manner for double values.
Definition init.c:1444
void opt_prt_char(const char *o, const char *name, const char *value)
Print an option and its value in a formatted manner.
Definition init.c:1411
int write_config(Init *init)
Write the current configuration to a file specified in init->minitrc.
Definition init.c:1103
void opt_prt_bool(const char *o, const char *name, bool value)
Print an option and its value in a formatted manner for boolean values.
Definition init.c:1456
void opt_prt_int(const char *o, const char *name, int value)
Print an option and its value in a formatted manner for integer values.
Definition init.c:1433
int process_config_files(Init *)
parse the configuration file specified in init->minitrc and set Init struct values accordingly
Definition init.c:642
void mapp_initialization(Init *, int, char **)
Main initialization function for MAPP - Menu Application.
Definition init.c:474
void zero_opt_args(Init *)
Initialize optional arguments in the Init struct to default values.
Definition init.c:606
uint32_t ran_bg
Definition cm.h:737
double green_gamma
Definition cm.h:690
uint32_t ln_bg
Definition cm.h:723
double blue_gamma
Definition cm.h:691
char brackets[3]
Definition cm.h:750
uint32_t magenta
Definition cm.h:698
uint32_t cmdln_bg
Definition cm.h:725
uint32_t cmdln_fg
Definition cm.h:724
uint32_t nt_hl_rev_fg
Definition cm.h:732
uint32_t ran_fg
Definition cm.h:736
uint32_t bgreen
Definition cm.h:704
double red_gamma
Definition cm.h:689
uint32_t green
Definition cm.h:695
char fill_char[2]
Definition cm.h:751
uint32_t nt_fg
Definition cm.h:726
uint32_t yellow
Definition cm.h:696
uint32_t fill_char_fg
Definition cm.h:720
uint32_t box_fg
Definition cm.h:714
uint32_t orange
Definition cm.h:701
uint32_t ln_fg
Definition cm.h:722
uint32_t ind_bg
Definition cm.h:717
uint32_t bmagenta
Definition cm.h:707
uint32_t ind_fg
Definition cm.h:716
uint32_t byellow
Definition cm.h:705
uint32_t bblue
Definition cm.h:706
uint32_t borange
Definition cm.h:710
uint32_t title_bg
Definition cm.h:735
uint32_t fg
Definition cm.h:712
uint32_t cyan
Definition cm.h:699
uint32_t bblack
Definition cm.h:702
uint32_t red
Definition cm.h:694
uint32_t nt_hl_rev_bg
Definition cm.h:733
uint32_t title_fg
Definition cm.h:734
uint32_t bred
Definition cm.h:703
uint32_t fill_char_bg
Definition cm.h:721
uint32_t black
Definition cm.h:693
uint32_t nt_rev_bg
Definition cm.h:729
uint32_t brackets_bg
Definition cm.h:719
uint32_t bcyan
Definition cm.h:708
uint32_t nt_bg
Definition cm.h:727
uint32_t blue
Definition cm.h:697
uint32_t brackets_fg
Definition cm.h:718
uint32_t white
Definition cm.h:700
uint32_t box_bg
Definition cm.h:715
uint32_t nt_hl_fg
Definition cm.h:730
uint32_t bwhite
Definition cm.h:709
char border
Definition cm.h:752
uint32_t nt_rev_fg
Definition cm.h:728
double gray_gamma
Definition cm.h:692
uint32_t nt_hl_bg
Definition cm.h:731
uint32_t bg
Definition cm.h:713
char title[MAXLEN]
Definition common.h:129
char mapp_data[MAXLEN]
Definition common.h:148
char minitrc[MAXLEN]
Definition common.h:174
bool f_out_spec
Definition common.h:171
char mapp_help[MAXLEN]
Definition common.h:149
int begx
Definition common.h:118
bool f_title
Definition common.h:166
SIO * sio
Definition common.h:114
char in_spec[MAXLEN]
Definition common.h:168
char cmd_all[MAXLEN]
Definition common.h:123
int argc
Definition common.h:130
char fill_char[2]
Definition common.h:146
char mapp_msrc[MAXLEN]
Definition common.h:150
int cols
Definition common.h:116
int tab_stop
Definition common.h:181
bool f_erase_remainder
Definition common.h:141
bool f_read_theme
Definition common.h:142
bool f_mapp_desc
Definition common.h:161
char mapp_home[MAXLEN]
Definition common.h:147
bool f_squeeze
Definition common.h:137
int begy
Definition common.h:117
char parent_cmd[MAXLEN]
Definition common.h:124
char mapp_spec[MAXLEN]
Definition common.h:176
char receiver_cmd[MAXLEN]
Definition common.h:121
int h_shift
Definition common.h:182
bool wrap
Definition common.h:144
bool f_multiple_cmd_args
Definition common.h:139
int select_max
Definition common.h:179
bool f_ln
Definition common.h:143
bool f_mapp_spec
Definition common.h:156
char provider_cmd[MAXLEN]
Definition common.h:120
char out_spec[MAXLEN]
Definition common.h:169
bool f_strip_ansi
Definition common.h:136
bool p_view_files
Definition common.h:134
bool f_at_end_remove
Definition common.h:135
char brackets[3]
Definition common.h:145
bool f_ignore_case
Definition common.h:133
char ** argv
Definition common.h:131
int lines
Definition common.h:115
char mapp_user[MAXLEN]
Definition common.h:151
char cmd[MAXLEN]
Definition common.h:122
char mapp_theme[MAXLEN]
Definition common.h:152
bool f_help_spec
Definition common.h:167
bool f_receiver_cmd
Definition common.h:163
bool f_provider_cmd
Definition common.h:162
char help_spec[MAXLEN]
Definition common.h:177
char editor[MAXLEN]
Definition common.h:172
bool f_in_spec
Definition common.h:170