2
3
4
5
6
7
8
11
12
13
14
15
16
17
18
98void opt_prt_char(
const char *o,
const char *name,
const char *value);
99void opt_prt_str(
const char *o,
const char *name,
const char *value);
100void opt_prt_int(
const char *o,
const char *name,
int value);
101void opt_prt_double(
const char *o,
const char *name,
double value);
102void opt_prt_bool(
const char *o,
const char *name,
bool value);
110static char doc[] =
"C-Menu - User Interface Toolkit";
111static char args_doc[] =
"[INPUT] [OUTPUT] [HELP] [ARG4] [ARG5]";
114static struct argp_option options[] = {
115 {
"f_write_config",
'W', 0, OPTION_ARG_OPTIONAL,
"write configuration", 0},
116 {
"minitrc",
'a',
"file_spec", 0,
"configuration file spec", 1},
117 {
"parent_cmd",
'k', 0, 0,
"parent command", 1},
118 {
"begx",
'X',
"number", 0,
"begin on column", 2},
119 {
"begy",
'Y',
"number", 0,
"begin on line", 2},
120 {
"cols",
'C',
"number", 0,
"width in columns", 2},
121 {
"lines",
'L',
"number", 0,
"height in lines", 2},
122 {
"title",
'T',
"text", 0,
"Window title", 2},
123 {
"out_spec",
'o',
"file_spec", 0,
"output file spec", 3},
124 {
"cmd",
'c',
"file_spec", 0,
"view cmd, first file", 3},
125 {
"cmd_all",
'A',
"file_spec", 0,
"view cmd, all files", 3},
126 {
"help_spec",
'H',
"file_spec", 0,
"help file spec", 3},
127 {
"in_spec",
'i',
"file_spec", 0,
"input file spec", 3},
128 {
"mapp_spec",
'd',
"file_spec", 0,
"description file spec", 3},
129 {
"provider_cmd",
'S',
"file_spec", 0,
"execute provider of piped input", 3},
130 {
"receiver_cmd",
'R',
"file_spec", 0,
"execute receiver of piped output", 3},
131 {
"wait_timeout",
'w',
"seconds", 0,
"Wait timer", 5},
132 {
"select_max",
'n',
"number", 0,
"number of selections", 5},
133 {
"f_erase_remainder",
'e',
"bool", OPTION_ARG_OPTIONAL,
"erase remainder of line on enter", 5},
134 {
"f_strip_ansi",
'j',
"bool", OPTION_ARG_OPTIONAL,
"always strip ansi when writing", 5},
135 {
"f_multiple_cmd_args",
'M',
"bool", OPTION_ARG_OPTIONAL,
"allow multiple command arguments", 5},
136 {
"f_read_theme",
'r',
"bool", OPTION_ARG_OPTIONAL,
"read and process theme file", 5},
137 {
"f_squeeze",
's',
"bool", OPTION_ARG_OPTIONAL,
"squeeze multiple blank lines", 5},
138 {
"f_ignore_case",
'x',
"bool", OPTION_ARG_OPTIONAL,
"ignore case in search", 5},
139 {
"p_view_files",
'v',
"bool", OPTION_ARG_OPTIONAL,
"File View in Pick", 5},
140 {
"f_ln",
'N',
"bool", OPTION_ARG_OPTIONAL,
"line numbers in view", 5},
141 {
"fill_char",
'f',
"char", 0,
"field fill_char (_,.,empty)", 5},
142 {
"brackets",
'u',
"text", 0,
"brackets around fields ([]{}<>)", 5},
143 {
"editor",
CM_EDITOR,
"text", 0,
"default editor", 5},
144 {
"tab_stop",
't',
"number", 0,
"number of spaces per tab (4)", 5},
145 {
"h_shift",
'z',
"number", 0,
"horizontal shift width (16)", 5},
146 {
"bg",
BG,
"hex_clr", 0,
"Terminal (stdscr) background (#000000)", 6},
147 {
"fg",
FG,
"hex_clr", 0,
"Terminal (stdscr) foreground (#d0d0d0)", 6},
148 {
"box_fg",
BOX_FG,
"hex_clr", 0,
"box foreground (#d0d0d0)", 6},
149 {
"box_bg",
BOX_BG,
"hex_clr", 0,
"box background (#000000)", 6},
150 {
"ind_fg",
IND_FG,
"hex_clr", 0,
"indicator foreground (#d0d0d0)", 6},
151 {
"ind_bg",
IND_BG,
"hex_clr", 0,
"indicator background (#000000)", 6},
152 {
"brackets_fg",
BRACKETS_FG,
"hex_clr", 0,
"brackets foreground (#d0d0d0)", 6},
153 {
"brackets_bg",
BRACKETS_BG,
"hex_clr", 0,
"brackets background (#000000)", 6},
154 {
"fill_char_fg",
FILL_CHAR_FG,
"hex_clr", 0,
"fill character foreground (#d0d0d0)", 6},
155 {
"fill_char_bg",
FILL_CHAR_BG,
"hex_clr", 0,
"fill character background (#000000)", 6},
156 {
"nt_fg",
NT_FG,
"hex_clr", 0,
"normal foreground (#d0d0d0)", 6},
157 {
"nt_bg",
NT_BG,
"hex_clr", 0,
"normal background (#000000)", 6},
158 {
"nt_rev_fg",
NT_REV_FG,
"hex_clr", 0,
"normal reverse foreground (#000000)", 6},
159 {
"nt_rev_bg",
NT_REV_BG,
"hex_clr", 0,
"normal reverse background (#d0d0d0)", 6},
160 {
"nt_hl_fg",
NT_HL_FG,
"hex_clr", 0,
"normal highlight foreground (#ffffff)", 6},
161 {
"nt_hl_bg",
NT_HL_BG,
"hex_clr", 0,
"normal highlight background (#000000)", 6},
162 {
"nt_hl_rev_fg",
NT_HL_REV_FG,
"hex_clr", 0,
"normal highlight reverse foreground (#f00000)", 6},
163 {
"nt_hl_rev_bg",
NT_HL_REV_BG,
"hex_clr", 0,
"normal highlight reverse background (#d0d0d0)", 6},
165 {
"ln_fg",
LN_FG,
"hex_clr", 0,
"line number foreground (#0000b0)", 6},
166 {
"ln_bg",
LN_BG,
"hex_clr", 0,
"line number background (#202020)", 6},
167 {
"cmdln_fg",
CMDLN_FG,
"hex_clr", 0,
"line number foreground (#0000b0)", 6},
168 {
"cmdln_bg",
CMDLN_BG,
"hex_clr", 0,
"line number background (#202020)", 6},
169 {
"title_fg",
TITLE_FG,
"hex_clr", 0,
"title foreground (#d0d0d0)", 6},
170 {
"title_bg",
TITLE_BG,
"hex_clr", 0,
"title background (#000000)", 6},
171 {
"blue_gamma",
GM_BLUE,
"float", 0,
"blue_gamma (1.2)", 7},
172 {
"gray_gamma",
GM_GRAY,
"float", 0,
"gray gamma (1.2)", 7},
173 {
"green_gamma",
GM_GREEN,
"float", 0,
"green gamma (1.2)", 7},
174 {
"red_gamma",
GM_RED,
"float", 0,
"red gamma (View)", 7},
175 {
"black",
XBLACK,
"hex_clr", 0,
"black (#000000)", 8},
176 {
"red",
XRED,
"hex_clr", 0,
"red (#bf0000)", 8},
177 {
"green",
XGREEN,
"hex_clr", 0,
"green (#00cf00)", 8},
178 {
"yellow",
XYELLOW,
"hex_clr", 0,
"yellow (#efbf00)", 8},
179 {
"blue",
XBLUE,
"hex_clr", 0,
"blue (#0000FF)", 8},
180 {
"magenta",
XMAGENTA,
"hex_clr", 0,
"magenta (#9f009f)", 8},
181 {
"cyan",
XCYAN,
"hex_clr", 0,
"cyan (#00dfdf)", 8},
182 {
"white",
XWHITE,
"hex_clr", 0,
"white (#d0d0d0)", 8},
183 {
"bblack",
XBBLACK,
"hex_clr", 0,
"bright black (#7f7f7f)", 8},
184 {
"bred",
XBRED,
"hex_clr", 0,
"bright red (#FF3737)", 8},
185 {
"bgreen",
XBGREEN,
"hex_clr", 0,
"bright green (#00FF7f)", 8},
186 {
"byellow",
XBYELLOW,
"hex_clr", 0,
"bright yellow (#FFeF00)", 8},
187 {
"bblue",
XBBLUE,
"hex_clr", 0,
"bright blue (#00cfFF)", 8},
188 {
"bmagenta",
XMAGENTA,
"hex_clr", 0,
"bright magenta (#FF00FF)", 8},
189 {
"bcyan",
XBCYAN,
"hex_clr", 0,
"bright cyan (#00FFFF)", 8},
190 {
"bwhite",
XBWHITE,
"hex_clr", 0,
"bright white (#FFFFFF)", 8},
191 {
"mapp_data",
MAPP_DATA,
"directory", 0,
"data directory", 9},
192 {
"mapp_help",
MAPP_HELP,
"directory", 0,
"help directory", 9},
193 {
"mapp_home",
MAPP_HOME,
"directory", 0,
"home directory", 9},
194 {
"mapp_msrc",
MAPP_MSRC,
"directory", 0,
"source directory", 9},
195 {
"mapp_user",
MAPP_USER,
"directory", 0,
"user directory", 9},
196 {
"mapp_theme",
MAPP_THEME,
"file", 0,
"default theme file", 9},
201parse_opt(
int key,
char *arg,
struct argp_state *state) {
202 Init *init = state->input;
203 SIO *sio = init
->sio;
411 if (state->arg_num >= 35)
413 init
->argv[state->arg_num] = strdup(arg);
416 init
->argc = state->arg_num;
417 init
->argv[state->arg_num + 1] =
nullptr;
420 return ARGP_ERR_UNKNOWN;
425static struct argp argp = {options, parse_opt, args_doc, doc,
426 nullptr,
nullptr,
nullptr};
429
430
431
432
433
434
435
436
437
438
439
440
445 setlocale(LC_ALL,
"en_US.UTF-8");
446 SIO *sio = init
->sio;
449 "init struct not allocated on entry");
456 e = getenv(
"CMENU_HOME");
457 if (!e || *e ==
'\0')
465 abend(-1
, "MAPP_HOME directory invalid");
468 e = getenv(
"CMENU_RC");
469 if (!e || *e ==
'\0') {
530 if (e ==
nullptr || *e ==
'\0')
534 e = getenv(
"EDITOR");
542 argp_parse(&argp, argc, argv, 0, 0, init);
549
550
551
552
553
554
555
556
557
558
561 argp_parse(&argp, argc, argv, 0, 0, init);
566
567
568
569
570
571
572
573
600
601
602
603
604
605
606
607
608
609
611 char config_file_name[
MAXLEN];
614 char *e = getenv(
"MINITRC");
632 char include_file_name[
MAXLEN];
635 SIO *sio = init
->sio;
639 FILE *config_fp = fopen(config_file_name,
"r");
640 char quote_char =
'\0';
642 fprintf(stderr,
"failed to read file: %s %s\n", config_file_name, strerror(errno));
645 while (fgets(tmp_str,
sizeof(tmp_str), config_fp)) {
646 bool inquotes =
false;
647 if (tmp_str[0] ==
'#')
653 while (*src_p !=
'\0') {
661 if (*src_p ==
'"' && *src_p ==
' ') {
670 while (*src_p !=
'\0') {
671 if ((*src_p ==
'"' || *src_p ==
'\'') && (*(src_p + 1) !=
'\\')) {
674 quote_char = *src_p++;
675 }
else if (*src_p == quote_char) {
684 dp = value + strlen(value);
689 if (*src_p ==
' ' || *src_p ==
';') {
693 if (*src_p ==
'\n') {
702 if (value[0] ==
'\0')
704 if (!strcmp(key,
"include")) {
710 if (!strcmp(key,
"minitrc")) {
714 if (!strcmp(key,
"lines")) {
718 if (!strcmp(key,
"cols")) {
722 if (!strcmp(key,
"begy")) {
726 if (!strcmp(key,
"begx")) {
730 if (!strcmp(key,
"f_ln")) {
734 if (!strcmp(key,
"f_at_end_remove")) {
738 if (!strcmp(key,
"f_erase_remainder")) {
742 if (!strcmp(key,
"brackets")) {
746 if (!strcmp(key,
"fill_char")) {
747 if (strlen(value) > 1)
749 if (wcwidth((
int)value[0]) > 1)
754 if (!strcmp(key,
"f_ignore_case")) {
758 if (!strcmp(key,
"p_view_files")) {
762 if (!strcmp(key,
"f_read_theme")) {
766 if (!strcmp(key,
"f_squeeze")) {
770 if (!strcmp(key,
"f_strip_ansi")) {
774 if (!strcmp(key,
"f_multiple_cmd_args")) {
778 if (!strcmp(key,
"select_max")) {
782 if (!strcmp(key,
"tab_stop")) {
786 if (!strcmp(key,
"h_shift")) {
790 if (!strcmp(key,
"wait_timeout")) {
794 if (!strcmp(key,
"title")) {
798 if (!strcmp(key,
"cmd")) {
802 if (!strcmp(key,
"cmd_all")) {
806 if (!strcmp(key,
"parent_cmd")) {
810 if (!strcmp(key,
"provider_cmd")) {
814 if (!strcmp(key,
"receiver_cmd")) {
818 if (!strcmp(key,
"editor")) {
822 if (!strcmp(key,
"fg")) {
826 if (!strcmp(key,
"bg")) {
830 if (!strcmp(key,
"box_fg")) {
834 if (!strcmp(key,
"box_bg")) {
838 if (!strcmp(key,
"ind_fg")) {
842 if (!strcmp(key,
"ind_bg")) {
846 if (!strcmp(key,
"brackets_fg")) {
850 if (!strcmp(key,
"brackets_bg")) {
854 if (!strcmp(key,
"fill_char_fg")) {
858 if (!strcmp(key,
"fill_char_bg")) {
862 if (!strcmp(key,
"ln_fg")) {
866 if (!strcmp(key,
"ln_bg")) {
870 if (!strcmp(key,
"cmdln_fg")) {
874 if (!strcmp(key,
"cmdln_bg")) {
878 if (!strcmp(key,
"nt_fg")) {
882 if (!strcmp(key,
"nt_bg")) {
886 if (!strcmp(key,
"nt_rev_fg")) {
890 if (!strcmp(key,
"nt_rev_bg")) {
894 if (!strcmp(key,
"nt_hl_fg")) {
898 if (!strcmp(key,
"nt_hl_bg")) {
902 if (!strcmp(key,
"nt_hl_rev_fg")) {
906 if (!strcmp(key,
"nt_hl_rev_bg")) {
910 if (!strcmp(key,
"title_fg")) {
914 if (!strcmp(key,
"title_bg")) {
918 if (!strcmp(key,
"red_gamma")) {
922 if (!strcmp(key,
"green_gamma")) {
926 if (!strcmp(key,
"blue_gamma")) {
930 if (!strcmp(key,
"gray_gamma")) {
934 if (!strcmp(key,
"black")) {
938 if (!strcmp(key,
"red")) {
942 if (!strcmp(key,
"green")) {
946 if (!strcmp(key,
"yellow")) {
950 if (!strcmp(key,
"blue")) {
954 if (!strcmp(key,
"magenta")) {
958 if (!strcmp(key,
"cyan")) {
962 if (!strcmp(key,
"white")) {
966 if (!strcmp(key,
"orange")) {
970 if (!strcmp(key,
"bblack")) {
974 if (!strcmp(key,
"bred")) {
978 if (!strcmp(key,
"bgreen")) {
982 if (!strcmp(key,
"byellow")) {
986 if (!strcmp(key,
"bblue")) {
990 if (!strcmp(key,
"bmagenta")) {
994 if (!strcmp(key,
"bcyan")) {
998 if (!strcmp(key,
"bwhite")) {
1002 if (!strcmp(key,
"borange")) {
1006 if (!strcmp(key,
"mapp_spec")) {
1010 if (!strcmp(key,
"mapp_data")) {
1014 if (!strcmp(key,
"mapp_help")) {
1018 if (!strcmp(key,
"mapp_home")) {
1022 if (!strcmp(key,
"mapp_msrc")) {
1026 if (!strcmp(key,
"mapp_user")) {
1030 if (!strcmp(key,
"mapp_theme")) {
1035 (
void)fclose(config_fp);
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1051 char minitrc_dmp[
MAXLEN];
1053 SIO *sio = init
->sio;
1054 e = getenv(
"CMENU_HOME");
1055 minitrc_dmp[0] =
'\0';
1062 FILE *minitrc_fp = fopen(minitrc_dmp,
"w");
1063 if (minitrc_fp == (FILE *)0) {
1064 fprintf(stderr,
"failed to open file: %s\n", minitrc_dmp);
1067 (
void)fprintf(minitrc_fp,
"# %s\n", minitrc_dmp);
1068 char *doc_tbl[50] = {
1069 "# C-Menu example configuration file",
1071 "# This file is generated by C-Menu when run with the -W option.",
1072 "# Copy this file and edit the copy because this file will be",
1073 "# overwritten each time C-Menu is run with the - W option.",
1075 "# C-Menu processes key value pairs in reading order from its",
1076 "# main configuraiton file, ~/ menuapp /.minitrc, and any other",
1077 "# configuration files sourced with include statements such as",
1080 "# include = ~/menuapp/theme/default",
1082 "# Assuming your configuration file is in ~/menuapp/theme/Red,",
1083 "# you could create a symbolic link named default that points to",
1084 "# Red, and then include default in your main configuration file.",
1085 "# (Actually ~/menuapp/.minitrc already includes default, so you",
1086 "# would only need to create the theme file and the symbolic link.",
1088 "# ln -s Red default",
1090 "# Key value pairs included from configuration files are",
1091 "# processed in reading order as they are included.",
1093 "# This is significant in the event that a key is included more",
1094 "# than once in the configuration file and / or included files.",
1095 "# Only the last value read for a key will be used by C-Menu.",
1097 "# If you want to override key values in the C-Menu configuration",
1098 "# file, you can do so by inserting an include statement for a",
1099 "# supplemental configuration file below the keys you want to",
1100 "# override in the C-Menu configuration file. Conversely, if you",
1101 "# want to use a supplemental configuration as the default,",
1102 "# include it first.",
1104 "# Parsing: Lines beginning with # are comments and are ignored.",
1105 "# Lines containing key=value pairs are parsed and the key and",
1106 "# value are extracted. Lines without an '=' are ignored. Values",
1107 "# are stripped of leading and trailing whitespace and quotes.",
1108 "# Values can be enclosed in single or double quotes to preserve",
1109 "# leading and trailing whitespace. Values can also be specified",
1110 "# as hex color codes such as #ff0000 for red. If a value is",
1111 "# specified as a hex color code, it is parsed and stored as a",
1112 "# hex color code in the configuration. An unquoted '#' that is",
1113 "# not part of a six digit hex color code and after key values",
1114 "# have been extracted is the beginning of a comment.",
""};
1115 for (
int i = 0; doc_tbl[i][0] !=
'\0'; i++)
1116 (
void)fprintf(minitrc_fp,
"%s\n", doc_tbl[i]);
1117 (
void)fprintf(minitrc_fp,
"#\n");
1281 (
void)fprintf(minitrc_fp,
"%-34s # default theme file\n", config_s);
1291 (
void)fprintf(minitrc_fp,
"%-34s # %s\n", config_s, comment);
1293 (
void)fprintf(minitrc_fp,
"%-34s #\n", config_s);
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1311 if (!file_name || !*file_name) {
1318 e = getenv(
"MAPP_DIR");
1335
1336
1337
1339 fprintf(stdout,
"\nC-Menu %s\n",
CM_VERSION);
1340 fprintf(stdout,
"\nC-Menu %s\n",
CM_VERSION);
1341 fprintf(stdout,
"C version: %ld\n", __STDC_VERSION__);
1344
1345
1346
1347
1348
1349
1351 fprintf(stdout,
"%3s %-15s: %s\n", o, name, value);
1354
1355
1356
1357
1358
1359
1360
1362 fprintf(stdout,
"%3s %-15s: %s\n", o, name, value);
1365
1366
1367
1368
1369
1370
1371
1373 fprintf(stdout,
"%3s %-15s: %d\n", o, name, value);
1376
1377
1378
1379
1380
1381
1382
1384 fprintf(stdout,
"%3s %-15s: %0.2f\n", o, name, value);
1387
1388
1389
1390
1391
1392
1393
1394
1396 fprintf(stdout,
"%3s %-15s: %s\n", o, name, value ?
"true" :
"false");
int process_config_file(char *, Init *)
#define min(x, y)
min macro evaluates two expressions, returning least result
bool str_to_bool(const char *)
Converts String to boolean true or false.
#define max(a, b)
max macro evaluates two expressions, returning greatest result.
const char * argp_program_version
void print_argp_doc(FILE *, char *, char *)
const char * argp_program_bug_address
int Perror(char *)
Display a simple error message window or print to stderr.
void abend(int, char *)
Abnormal program termination.
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
int destroy_argv(int argc, char **argv)
Deallocates memory allocated for argument strings in argv.
double str_to_double(char *)
converts string to double
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
bool expand_tilde(char *, int)
Replaces "~/" in string with the user's home directory.
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
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.
bool verify_dir(char *, int)
Verifies that the directory specified by "spec" exists and is accessible with the permissions specifi...
bool trim_path(char *)
Trims trailing spaces and slashes from directory path in place.
bool unstr_hex_clr(char *, char *)
Validates that a string is a hex color code in the format "#RRGGBB".
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.
int parse_opt_args(Init *, int, char **)
Parse command-line options and set Init struct values accordingly.
bool derive_file_spec(char *, char *, char *)
Derive full file specification from directory and file name.
void display_version()
Display the version information of the application.
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.
void opt_prt_char(const char *o, const char *name, const char *value)
Print an option and its value in a formatted manner.
int write_config(Init *)
Write the current configuration to a file specified in init->minitrc.
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.
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.
int process_config_files(Init *)
parse the configuration file specified in init->minitrc and set Init struct values accordingly
void mapp_initialization(Init *, int, char **)
Main initialization function for MAPP - Menu Application.
void zero_opt_args(Init *)
Initialize optional arguments in the Init struct to default values.
char receiver_cmd[MAXLEN]
char provider_cmd[MAXLEN]
char nt_hl_rev_bg[COLOR_LEN]
char nt_rev_bg[COLOR_LEN]
char nt_rev_fg[COLOR_LEN]
char brackets_fg[COLOR_LEN]
char fill_char_fg[COLOR_LEN]
char brackets_bg[COLOR_LEN]
char fill_char_bg[COLOR_LEN]
char nt_hl_rev_fg[COLOR_LEN]