1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/ioctl.h>
29
30 #include <getopt.h>
31 #include <locale.h>
32 #include <signal.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <term.h>
37 #include <time.h>
38 #include <unistd.h>
39
40 #include <bsddialog.h>
41 #include <bsddialog_theme.h>
42
43 #include "util_theme.h"
44
45 enum OPTS {
46 /* Options */
47 ALTERNATE_SCREEN = '?' + 1,
48 AND_DIALOG,
49 ASCII_LINES,
50 BACKTITLE,
51 BEGIN_X,
52 BEGIN_Y,
53 BIKESHED,
54 CANCEL_LABEL,
55 CLEAR_DIALOG,
56 CLEAR_SCREEN,
57 COLORS,
58 COLUMNS_PER_ROW,
59 CR_WRAP,
60 DATE_FORMAT,
61 DEFAULT_BUTTON,
62 DEFAULT_ITEM,
63 DEFAULT_NO,
64 DISABLE_ESC,
65 ESC_RETURNCANCEL,
66 EXIT_LABEL,
67 EXTRA_BUTTON,
68 EXTRA_LABEL,
69 GENERIC_BUTTON1,
70 GENERIC_BUTTON2,
71 HELP_BUTTON,
72 HELP_LABEL,
73 HELP_PRINT_NAME,
74 HELP_STATUS,
75 HFILE,
76 HLINE,
77 HMSG,
78 IGNORE,
79 INSECURE,
80 ITEM_BOTTOM_DESC,
81 ITEM_DEPTH,
82 ITEM_PREFIX,
83 LOAD_THEME,
84 MAX_INPUT,
85 NO_CANCEL,
86 NO_DESCRIPTIONS,
87 NO_LINES,
88 NO_NAMES,
89 NO_OK,
90 NO_SHADOW,
91 NORMAL_SCREEN,
92 OK_LABEL,
93 OUTPUT_FD,
94 OUTPUT_SEPARATOR,
95 PRINT_MAXSIZE,
96 PRINT_SIZE,
97 PRINT_VERSION,
98 QUOTED,
99 SAVE_THEME,
100 SEPARATE_OUTPUT,
101 SHADOW,
102 SINGLE_QUOTED,
103 SLEEP,
104 STDERR,
105 STDOUT,
106 SWITCH_BUTTONS,
107 TAB_ESCAPE,
108 TAB_LEN,
109 TEXT_UNCHANGED,
110 THEME,
111 TIME_FORMAT,
112 TITLE,
113 /* Dialogs */
114 CALENDAR,
115 CHECKLIST,
116 DATEBOX,
117 FORM,
118 GAUGE,
119 INFOBOX,
120 INPUTBOX,
121 MENU,
122 MIXEDFORM,
123 MIXEDGAUGE,
124 MSGBOX,
125 PASSWORDBOX,
126 PASSWORDFORM,
127 PAUSE,
128 RADIOLIST,
129 RANGEBOX,
130 TEXTBOX,
131 TIMEBOX,
132 TREEVIEW,
133 YESNO
134 };
135
136 /* options descriptor */
137 static struct option longopts[] = {
138 /* Options */
139 {"alternate-screen", no_argument, NULL, ALTERNATE_SCREEN},
140 {"and-dialog", no_argument, NULL, AND_DIALOG},
141 {"and-widget", no_argument, NULL, AND_DIALOG},
142 {"ascii-lines", no_argument, NULL, ASCII_LINES},
143 {"backtitle", required_argument, NULL, BACKTITLE},
144 {"begin-x", required_argument, NULL, BEGIN_X},
145 {"begin-y", required_argument, NULL, BEGIN_Y},
146 {"bikeshed", no_argument, NULL, BIKESHED},
147 {"cancel-label", required_argument, NULL, CANCEL_LABEL},
148 {"clear", no_argument, NULL, CLEAR_SCREEN},
149 {"clear-dialog", no_argument, NULL, CLEAR_DIALOG},
150 {"clear-screen", no_argument, NULL, CLEAR_SCREEN},
151 {"colors", no_argument, NULL, COLORS},
152 {"columns-per-row", required_argument, NULL, COLUMNS_PER_ROW},
153 {"cr-wrap", no_argument, NULL, CR_WRAP},
154 {"date-format", required_argument, NULL, DATE_FORMAT},
155 {"defaultno", no_argument, NULL, DEFAULT_NO},
156 {"default-button", required_argument, NULL, DEFAULT_BUTTON},
157 {"default-item", required_argument, NULL, DEFAULT_ITEM},
158 {"default-no", no_argument, NULL, DEFAULT_NO},
159 {"disable-esc", no_argument, NULL, DISABLE_ESC},
160 {"esc-return-cancel", no_argument, NULL, ESC_RETURNCANCEL},
161 {"exit-label", required_argument, NULL, EXIT_LABEL},
162 {"extra-button", no_argument, NULL, EXTRA_BUTTON},
163 {"extra-label", required_argument, NULL, EXTRA_LABEL},
164 {"generic-button1", required_argument, NULL, GENERIC_BUTTON1},
165 {"generic-button2", required_argument, NULL, GENERIC_BUTTON2},
166 {"help-button", no_argument, NULL, HELP_BUTTON},
167 {"help-label", required_argument, NULL, HELP_LABEL},
168 {"help-print-name", no_argument, NULL, HELP_PRINT_NAME},
169 {"help-status", no_argument, NULL, HELP_STATUS},
170 {"help-tags", no_argument, NULL, HELP_PRINT_NAME},
171 {"hfile", required_argument, NULL, HFILE},
172 {"hline", required_argument, NULL, HLINE},
173 {"hmsg", required_argument, NULL, HMSG},
174 {"ignore", no_argument, NULL, IGNORE},
175 {"insecure", no_argument, NULL, INSECURE},
176 {"item-bottom-desc", no_argument, NULL, ITEM_BOTTOM_DESC},
177 {"item-depth", no_argument, NULL, ITEM_DEPTH},
178 {"item-help", no_argument, NULL, ITEM_BOTTOM_DESC},
179 {"item-prefix", no_argument, NULL, ITEM_PREFIX},
180 {"keep-tite", no_argument, NULL, ALTERNATE_SCREEN},
181 {"load-theme", required_argument, NULL, LOAD_THEME},
182 {"max-input", required_argument, NULL, MAX_INPUT},
183 {"no-cancel", no_argument, NULL, NO_CANCEL},
184 {"nocancel", no_argument, NULL, NO_CANCEL},
185 {"no-descriptions", no_argument, NULL, NO_DESCRIPTIONS},
186 {"no-items", no_argument, NULL, NO_DESCRIPTIONS},
187 {"no-label", required_argument, NULL, CANCEL_LABEL},
188 {"no-lines", no_argument, NULL, NO_LINES},
189 {"no-names", no_argument, NULL, NO_NAMES},
190 {"no-ok", no_argument, NULL, NO_OK},
191 {"nook ", no_argument, NULL, NO_OK},
192 {"no-shadow", no_argument, NULL, NO_SHADOW},
193 {"no-tags", no_argument, NULL, NO_NAMES},
194 {"normal-screen", no_argument, NULL, NORMAL_SCREEN},
195 {"ok-label", required_argument, NULL, OK_LABEL},
196 {"output-fd", required_argument, NULL, OUTPUT_FD},
197 {"output-separator", required_argument, NULL, OUTPUT_SEPARATOR},
198 {"print-maxsize", no_argument, NULL, PRINT_MAXSIZE},
199 {"print-size", no_argument, NULL, PRINT_SIZE},
200 {"print-version", no_argument, NULL, PRINT_VERSION},
201 {"quoted", no_argument, NULL, QUOTED},
202 {"save-theme", required_argument, NULL, SAVE_THEME},
203 {"separate-output", no_argument, NULL, SEPARATE_OUTPUT},
204 {"separator", required_argument, NULL, OUTPUT_SEPARATOR},
205 {"shadow", no_argument, NULL, SHADOW},
206 {"single-quoted", no_argument, NULL, SINGLE_QUOTED},
207 {"sleep", required_argument, NULL, SLEEP},
208 {"stderr", no_argument, NULL, STDERR},
209 {"stdout", no_argument, NULL, STDOUT},
210 {"switch-buttons", no_argument, NULL, SWITCH_BUTTONS},
211 {"tab-escape", no_argument, NULL, TAB_ESCAPE},
212 {"tab-len", required_argument, NULL, TAB_LEN},
213 {"text-unchanged", no_argument, NULL, TEXT_UNCHANGED},
214 {"theme", required_argument, NULL, THEME},
215 {"time-format", required_argument, NULL, TIME_FORMAT},
216 {"title", required_argument, NULL, TITLE},
217 {"yes-label", required_argument, NULL, OK_LABEL},
218 /* Dialogs */
219 {"calendar", no_argument, NULL, CALENDAR},
220 {"checklist", no_argument, NULL, CHECKLIST},
221 {"datebox", no_argument, NULL, DATEBOX},
222 {"form", no_argument, NULL, FORM},
223 {"gauge", no_argument, NULL, GAUGE},
224 {"infobox", no_argument, NULL, INFOBOX},
225 {"inputbox", no_argument, NULL, INPUTBOX},
226 {"menu", no_argument, NULL, MENU},
227 {"mixedform", no_argument, NULL, MIXEDFORM},
228 {"mixedgauge", no_argument, NULL, MIXEDGAUGE},
229 {"msgbox", no_argument, NULL, MSGBOX},
230 {"passwordbox", no_argument, NULL, PASSWORDBOX},
231 {"passwordform", no_argument, NULL, PASSWORDFORM},
232 {"pause", no_argument, NULL, PAUSE},
233 {"radiolist", no_argument, NULL, RADIOLIST},
234 {"rangebox", no_argument, NULL, RANGEBOX},
235 {"textbox", no_argument, NULL, TEXTBOX},
236 {"timebox", no_argument, NULL, TIMEBOX},
237 {"treeview", no_argument, NULL, TREEVIEW},
238 {"yesno", no_argument, NULL, YESNO},
239 /* END */
240 { NULL, 0, NULL, 0}
241 };
242
243 /* Menus options */
244 static bool item_prefix_opt;
245 static bool item_bottomdesc_opt;
246 static bool item_output_sepnl_opt;
247 static bool item_singlequote_opt;
248 static bool list_items_on_opt;
249 static bool item_help_print_name_opt;
250 static bool item_always_quote_opt;
251 static bool item_depth_opt;
252 static char *item_output_sep_opt;
253 static char *item_default_opt;
254 /* Date and Time options */
255 static char *date_fmt_opt;
256 static char *time_fmt_opt;
257 /* Forms options */
258 static int unsigned max_input_form_opt;
259 /* General options */
260 static bool esc_return_cancel_opt;
261 static bool ignore_opt;
262 static int output_fd_opt;
263 static int getH_opt;
264 static int getW_opt;
265 /* Text option */
266 static bool cr_wrap_opt;
267 static bool tab_escape_opt;
268 static bool text_unchanged_opt;
269 /* Theme and Screen options*/
270 static bool bikeshed_opt;
271 static enum bsddialog_default_theme theme_opt;
272 static char *backtitle_opt;
273 static bool clear_screen_opt;
274 static char *loadthemefile;
275 static char *savethemefile;
276 static const char *screen_mode_opt;
277
278 /* Functions */
279 #define UNUSED_PAR(x) UNUSED_ ## x __attribute__((__unused__))
280 static void custom_text(char *text, char *buf);
281 static void usage(void);
282 /* Dialogs */
283 #define BUILDER_ARGS struct bsddialog_conf *conf, char* text, int rows, \
284 int cols, int argc, char **argv
285 static int calendar_builder(BUILDER_ARGS);
286 static int checklist_builder(BUILDER_ARGS);
287 static int datebox_builder(BUILDER_ARGS);
288 static int form_builder(BUILDER_ARGS);
289 static int gauge_builder(BUILDER_ARGS);
290 static int infobox_builder(BUILDER_ARGS);
291 static int inputbox_builder(BUILDER_ARGS);
292 static int menu_builder(BUILDER_ARGS);
293 static int mixedform_builder(BUILDER_ARGS);
294 static int mixedgauge_builder(BUILDER_ARGS);
295 static int msgbox_builder(BUILDER_ARGS);
296 static int passwordbox_builder(BUILDER_ARGS);
297 static int passwordform_builder(BUILDER_ARGS);
298 static int pause_builder(BUILDER_ARGS);
299 static int radiolist_builder(BUILDER_ARGS);
300 static int rangebox_builder(BUILDER_ARGS);
301 static int textbox_builder(BUILDER_ARGS);
302 static int timebox_builder(BUILDER_ARGS);
303 static int treeview_builder(BUILDER_ARGS);
304 static int yesno_builder(BUILDER_ARGS);
305
306 /* init, exit and internals */
307 static bool in_bsddialog_mode;
308 static bool mandatory_dialog;
309 static int (*dialogbuilder)(BUILDER_ARGS);
310
exit_error(const char * errstr,bool with_usage)311 static void exit_error(const char *errstr, bool with_usage)
312 {
313 if (in_bsddialog_mode)
314 bsddialog_end();
315
316 printf("Error: %s.\n\n", errstr);
317 if (with_usage) {
318 printf("See \'bsddialog --help\' or \'man 1 bsddialog\' ");
319 printf("for more information.\n");
320 }
321
322 exit (255);
323 }
324
sigint_handler(int UNUSED_PAR (sig))325 static void sigint_handler(int UNUSED_PAR(sig))
326 {
327 bsddialog_end();
328
329 exit(255);
330 }
331
start_bsddialog_mode(void)332 static void start_bsddialog_mode(void)
333 {
334 if (in_bsddialog_mode)
335 return;
336
337 if (bsddialog_init() != BSDDIALOG_OK)
338 exit_error(bsddialog_geterror(), false);
339
340 in_bsddialog_mode = true;
341 signal(SIGINT, sigint_handler);
342 }
343
error_args(const char * dialog,int argc,char ** argv)344 static void error_args(const char *dialog, int argc, char **argv)
345 {
346 int i;
347
348 if (in_bsddialog_mode)
349 bsddialog_end();
350
351 printf("Error: %s unexpected argument%s:", dialog,
352 argc > 1 ? "s" : "");
353 for (i = 0; i < argc; i++)
354 printf(" \"%s\"", argv[i]);
355 printf(".\n\n");
356 printf("See \'bsddialog --help\' or \'man 1 bsddialog\' ");
357 printf("for more information.\n");
358
359 exit (255);
360 }
361
usage(void)362 static void usage(void)
363 {
364 printf("usage: bsddialog --help\n");
365 printf(" bsddialog --version\n");
366 printf(" bsddialog [--<opt>] --<dialog> <text> <rows> <cols> "
367 "[<arg>]\n");
368 printf(" bsddialog --<dialog1> ... [--and-dialog --<dialog2> "
369 "...] ...\n");
370 printf("\n");
371
372 printf("Options:\n");
373 printf(" --alternate-screen, --ascii-lines, --backtitle <backtitle>,"
374 " --begin-x <x>,\n --begin-y <y>, --bikeshed, --calendar,"
375 " --cancel-label <label>, --clear-dialog,\n --clear-screen,"
376 " --colors, --columns-per-row <columns>, --cr-wrap,\n"
377 " --date-format <format>, --default-button <label>,"
378 " --default-item <name>,\n --default-no, --disable-esc,"
379 " --esc-return-cancel, --exit-label <label>,\n --extra-button,"
380 " --extra-label <label>, --generic-button1 <label>,\n"
381 " --generic-button2 <label>, --help-button, --help-label <label>,\n"
382 " --help-print-name, --help-status, --hfile <file>,"
383 " --hline <string>,\n --hmsg <string>, --ignore, --insecure,"
384 " --item-bottom-desc, --item-depth,\n --item-prefix,"
385 " --load-theme <file>, --max-input <size>, --no-cancel,\n"
386 " --no-descriptions, --no-label <label>, --no-lines, --no-names,"
387 " --no-ok,\n --no-shadow, --normal-screen, --ok-label <label>,"
388 " --output-fd <fd>,\n --output-separator <sep>, --print-maxsize,"
389 " --print-size, --print-version,\n --quoted, --save-theme <file>,"
390 " --separate-output, --separator <sep>, --shadow,\n"
391 " --single-quoted, --sleep <secs>, --stderr, --stdout,"
392 " --tab-escape,\n --tab-len <spaces>, --text-unchanged,"
393 " --switch-buttons,\n --theme <blackwhite|bsddialog|flat|dialog>,"
394 " --time-format <format>,\n --title <title>,"
395 " --yes-label <label>.\n");
396 printf("\n");
397
398 printf("Dialogs:\n");
399 printf(" --calendar <text> <rows> <cols> [<dd> <mm> <yy>]\n");
400 printf(" --checklist <text> <rows> <cols> <menurows> [<name> <desc> "
401 "<on|off>] ...\n");
402 printf(" --datebox <text> <rows> <cols> [<dd> <mm> <yy>]\n");
403 printf(" --form <text> <rows> <cols> <formrows> [<label> <ylabel> "
404 "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxletters>] "
405 "...\n");
406 printf(" --gauge <text> <rows> <cols> [<perc>]\n");
407 printf(" --infobox <text> <rows> <cols>\n");
408 printf(" --inputbox <text> <rows> <cols> [init]\n");
409 printf(" --menu <text> <rows> <cols> <menurows> [<name> <desc>] ...\n");
410 printf(" --mixedform <text> <rows> <cols> <formrows> [<label> <ylabel> "
411 "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxletters> "
412 "<0|1|2>] ...\n");
413 printf(" --mixedgauge <text> <rows> <cols> <mainperc> [<minilabel> "
414 "<miniperc>] ...\n");
415 printf(" --msgbox <text> <rows> <cols>\n");
416 printf(" --passwordbox <text> <rows> <cols> [init]\n");
417 printf(" --passwordform <text> <rows> <cols> <formrows> [<label> "
418 "<ylabel> <xlabel> <init> <yfield> <xfield> <fieldlen> "
419 "<maxletters>] ...\n");
420 printf(" --pause <text> <rows> <cols> <secs>\n");
421 printf(" --radiolist <text> <rows> <cols> <menurows> [<name> <desc> "
422 "<on|off>] ...\n");
423 printf(" --rangebox <text> <rows> <cols> <min> <max> [<init>]\n");
424 printf(" --textbox <file> <rows> <cols>\n");
425 printf(" --timebox <text> <rows> <cols> [<hh> <mm> <ss>]\n");
426 printf(" --treeview <text> <rows> <cols> <menurows> [<depth> <name> "
427 "<desc> <on|off>] ...\n");
428 printf(" --yesno <text> <rows> <cols>\n");
429 printf("\n");
430
431 printf("See 'man 1 bsddialog' for more information.\n");
432 }
433
parseargs(int argc,char ** argv,struct bsddialog_conf * conf)434 static int parseargs(int argc, char **argv, struct bsddialog_conf *conf)
435 {
436 int arg, parsed, i;
437 struct winsize ws;
438
439 bsddialog_initconf(conf);
440 conf->key.enable_esc = true;
441 conf->menu.on_without_ok = true;
442 conf->form.value_without_ok = true;
443 conf->button.always_active = true;
444
445 dialogbuilder = NULL;
446
447 backtitle_opt = NULL;
448 theme_opt = -1;
449 output_fd_opt = STDERR_FILENO;
450 ignore_opt = false;
451 cr_wrap_opt = false;
452 tab_escape_opt = false;
453 text_unchanged_opt = false;
454 esc_return_cancel_opt = false;
455 bikeshed_opt = false;
456 savethemefile = NULL;
457 loadthemefile = NULL;
458 clear_screen_opt = false;
459 screen_mode_opt = NULL;
460
461 item_output_sepnl_opt = false;
462 item_singlequote_opt = false;
463 item_prefix_opt = false;
464 item_bottomdesc_opt = false;
465 item_depth_opt = false;
466 list_items_on_opt = false;
467 item_help_print_name_opt = false;
468 item_always_quote_opt = false;
469 item_output_sep_opt = NULL;
470 item_default_opt = NULL;
471
472 date_fmt_opt = NULL;
473 time_fmt_opt = NULL;
474
475 max_input_form_opt = 2048;
476
477 for (i = 0; i < argc; i++) {
478 if (strcmp(argv[i], "--and-dialog") == 0 ||
479 strcmp(argv[i], "--and-widget") == 0) {
480 argc = i + 1;
481 break;
482 }
483 }
484 parsed = argc;
485 while ((arg = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
486 switch (arg) {
487 /* Options */
488 case ALTERNATE_SCREEN:
489 screen_mode_opt = "smcup";
490 break;
491 case AND_DIALOG:
492 if (dialogbuilder == NULL)
493 exit_error("--and-dialog without previous "
494 "--<dialog>", true);
495 break;
496 case ASCII_LINES:
497 conf->ascii_lines = true;
498 break;
499 case BACKTITLE:
500 backtitle_opt = optarg;
501 if (conf->y == BSDDIALOG_CENTER)
502 conf->auto_topmargin = 2;
503 break;
504 case BEGIN_X:
505 conf->x = (int)strtol(optarg, NULL, 10);
506 if (conf->x < BSDDIALOG_CENTER)
507 exit_error("--begin-x < -1", false);
508 break;
509 case BEGIN_Y:
510 conf->y = (int)strtol(optarg, NULL, 10);
511 if (conf->y < BSDDIALOG_CENTER)
512 exit_error("--begin-y < -1", false);
513 conf->auto_topmargin = 0;
514 break;
515 case BIKESHED:
516 bikeshed_opt = true;
517 break;
518 case CANCEL_LABEL:
519 conf->button.cancel_label = optarg;
520 break;
521 case CLEAR_DIALOG:
522 conf->clear = true;
523 break;
524 case CLEAR_SCREEN:
525 mandatory_dialog = false;
526 clear_screen_opt = true;
527 break;
528 case COLORS:
529 conf->text.highlight = true;
530 break;
531 case COLUMNS_PER_ROW:
532 conf->text.cols_per_row =
533 (u_int)strtoul(optarg, NULL, 10);
534 break;
535 case CR_WRAP:
536 cr_wrap_opt = true;
537 break;
538 case DATE_FORMAT:
539 date_fmt_opt = optarg;
540 break;
541 case DEFAULT_BUTTON:
542 conf->button.default_label = optarg;
543 break;
544 case DEFAULT_ITEM:
545 item_default_opt = optarg;
546 break;
547 case DEFAULT_NO:
548 conf->button.default_cancel = true;
549 break;
550 case DISABLE_ESC:
551 conf->key.enable_esc = false;
552 break;
553 case ESC_RETURNCANCEL:
554 esc_return_cancel_opt = true;
555 break;
556 case EXIT_LABEL:
557 conf->button.ok_label = optarg;
558 break;
559 case EXTRA_BUTTON:
560 conf->button.with_extra = true;
561 break;
562 case EXTRA_LABEL:
563 conf->button.extra_label = optarg;
564 break;
565 case GENERIC_BUTTON1:
566 conf->button.generic1_label = optarg;
567 break;
568 case GENERIC_BUTTON2:
569 conf->button.generic2_label = optarg;
570 break;
571 case HELP_BUTTON:
572 conf->button.with_help = true;
573 break;
574 case HELP_LABEL:
575 conf->button.help_label = optarg;
576 break;
577 case HELP_PRINT_NAME:
578 item_help_print_name_opt = true;
579 break;
580 case HELP_STATUS:
581 list_items_on_opt = true;
582 break;
583 case HFILE:
584 conf->key.f1_file = optarg;
585 break;
586 case HLINE:
587 if (optarg[0] != '\0')
588 conf->bottomtitle = optarg;
589 break;
590 case HMSG:
591 conf->key.f1_message = optarg;
592 break;
593 case IGNORE:
594 ignore_opt = true;
595 break;
596 case INSECURE:
597 conf->form.securech = '*';
598 break;
599 case ITEM_BOTTOM_DESC:
600 item_bottomdesc_opt = true;
601 break;
602 case ITEM_DEPTH:
603 item_depth_opt = true;
604 break;
605 case ITEM_PREFIX:
606 item_prefix_opt = true;
607 break;
608 case LOAD_THEME:
609 loadthemefile = optarg;
610 break;
611 case MAX_INPUT:
612 max_input_form_opt = (u_int)strtoul(optarg, NULL, 10);
613 break;
614 case NO_CANCEL:
615 conf->button.without_cancel = true;
616 break;
617 case NO_DESCRIPTIONS:
618 conf->menu.no_desc = true;
619 break;
620 case NO_LINES:
621 conf->no_lines = true;
622 break;
623 case NO_NAMES:
624 conf->menu.no_name = true;
625 break;
626 case NO_OK:
627 conf->button.without_ok = true;
628 break;
629 case NO_SHADOW:
630 conf->shadow = false;
631 break;
632 case NORMAL_SCREEN:
633 screen_mode_opt = "rmcup";
634 break;
635 case OK_LABEL:
636 conf->button.ok_label = optarg;
637 break;
638 case OUTPUT_FD:
639 output_fd_opt = (int)strtol(optarg, NULL, 10);
640 break;
641 case OUTPUT_SEPARATOR:
642 item_output_sep_opt = optarg;
643 break;
644 case QUOTED:
645 item_always_quote_opt = true;
646 break;
647 case PRINT_MAXSIZE:
648 mandatory_dialog = false;
649 ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
650 dprintf(output_fd_opt, "MaxSize: %d, %d\n",
651 ws.ws_row, ws.ws_col);
652 break;
653 case PRINT_SIZE:
654 conf->get_height = &getH_opt;
655 conf->get_width = &getW_opt;
656 break;
657 case PRINT_VERSION:
658 mandatory_dialog = false;
659 dprintf(output_fd_opt, "Version: %s\n",
660 LIBBSDDIALOG_VERSION);
661 break;
662 case SAVE_THEME:
663 mandatory_dialog = false;
664 savethemefile = optarg;
665 break;
666 case SEPARATE_OUTPUT:
667 item_output_sepnl_opt = true;
668 break;
669 case SHADOW:
670 conf->shadow = true;
671 break;
672 case SINGLE_QUOTED:
673 item_singlequote_opt = true;
674 break;
675 case SLEEP:
676 conf->sleep = (u_int)strtoul(optarg, NULL, 10);
677 break;
678 case STDERR:
679 output_fd_opt = STDERR_FILENO;
680 break;
681 case STDOUT:
682 output_fd_opt = STDOUT_FILENO;
683 break;
684 case SWITCH_BUTTONS:
685 conf->button.always_active = false;
686 break;
687 case TAB_ESCAPE:
688 tab_escape_opt = true;
689 break;
690 case TAB_LEN:
691 conf->text.tablen = (u_int)strtoul(optarg, NULL, 10);
692 break;
693 case TEXT_UNCHANGED:
694 text_unchanged_opt = true;
695 break;
696 case THEME:
697 if (strcasecmp(optarg, "bsddialog") == 0)
698 theme_opt = BSDDIALOG_THEME_BSDDIALOG;
699 else if (strcasecmp(optarg, "blackwhite") == 0)
700 theme_opt = BSDDIALOG_THEME_BLACKWHITE;
701 else if (strcasecmp(optarg, "flat") == 0)
702 theme_opt = BSDDIALOG_THEME_FLAT;
703 else if (strcasecmp(optarg, "dialog") == 0)
704 theme_opt = BSDDIALOG_THEME_DIALOG;
705 else
706 exit_error("--theme: <unknown> theme", false);
707 break;
708 case TIME_FORMAT:
709 time_fmt_opt = optarg;
710 break;
711 case TITLE:
712 conf->title = optarg;
713 break;
714 /* Dialogs */
715 case CALENDAR:
716 if (dialogbuilder != NULL)
717 exit_error("unexpected --calendar", true);
718 dialogbuilder = calendar_builder;
719 break;
720 case CHECKLIST:
721 if (dialogbuilder != NULL)
722 exit_error("unexpected --checklist", true);
723 dialogbuilder = checklist_builder;
724 conf->auto_downmargin = 1;
725 break;
726 case DATEBOX:
727 if (dialogbuilder != NULL)
728 exit_error("unexpected --datebox", true);
729 dialogbuilder = datebox_builder;
730 break;
731 case FORM:
732 if (dialogbuilder != NULL)
733 exit_error("unexpected --form", true);
734 dialogbuilder = form_builder;
735 conf->auto_downmargin = 1;
736 break;
737 case GAUGE:
738 if (dialogbuilder != NULL)
739 exit_error("unexpected --gauge", true);
740 dialogbuilder = gauge_builder;
741 break;
742 case INFOBOX:
743 if (dialogbuilder != NULL)
744 exit_error("unexpected --infobox", true);
745 dialogbuilder = infobox_builder;
746 break;
747 case INPUTBOX:
748 if (dialogbuilder != NULL)
749 exit_error("unexpected --inputbox", true);
750 dialogbuilder = inputbox_builder;
751 conf->auto_downmargin = 1;
752 break;
753 case MENU:
754 if (dialogbuilder != NULL)
755 exit_error("unexpected --menu", true);
756 dialogbuilder = menu_builder;
757 conf->auto_downmargin = 1;
758 break;
759 case MIXEDFORM:
760 if (dialogbuilder != NULL)
761 exit_error("unexpected --mixedform", true);
762 dialogbuilder = mixedform_builder;
763 conf->auto_downmargin = 1;
764 break;
765 case MIXEDGAUGE:
766 if (dialogbuilder != NULL)
767 exit_error("unexpected --mixedgauge", true);
768 dialogbuilder = mixedgauge_builder;
769 break;
770 case MSGBOX:
771 if (dialogbuilder != NULL)
772 exit_error("unexpected --msgbox", true);
773 dialogbuilder = msgbox_builder;
774 break;
775 case PAUSE:
776 if (dialogbuilder != NULL)
777 exit_error("unexpected --pause", true);
778 dialogbuilder = pause_builder;
779 break;
780 case PASSWORDBOX:
781 if (dialogbuilder != NULL)
782 exit_error("unexpected --passwordbox", true);
783 dialogbuilder = passwordbox_builder;
784 conf->auto_downmargin = 1;
785 break;
786 case PASSWORDFORM:
787 if (dialogbuilder != NULL)
788 exit_error("unexpected --passwordform", true);
789 dialogbuilder = passwordform_builder;
790 conf->auto_downmargin = 1;
791 break;
792 case RADIOLIST:
793 if (dialogbuilder != NULL)
794 exit_error("unexpected --radiolist", true);
795 dialogbuilder = radiolist_builder;
796 conf->auto_downmargin = 1;
797 break;
798 case RANGEBOX:
799 if (dialogbuilder != NULL)
800 exit_error("unexpected --rangebox", true);
801 dialogbuilder = rangebox_builder;
802 break;
803 case TEXTBOX:
804 if (dialogbuilder != NULL)
805 exit_error("unexpected --textbox", true);
806 dialogbuilder = textbox_builder;
807 break;
808 case TIMEBOX:
809 if (dialogbuilder != NULL)
810 exit_error("unexpected --timebox", true);
811 dialogbuilder = timebox_builder;
812 break;
813 case TREEVIEW:
814 if (dialogbuilder != NULL)
815 exit_error("unexpected --treeview", true);
816 dialogbuilder = treeview_builder;
817 conf->auto_downmargin = 1;
818 break;
819 case YESNO:
820 if (dialogbuilder != NULL)
821 exit_error("unexpected --yesno", true);
822 dialogbuilder = yesno_builder;
823 break;
824 default: /* Error */
825 if (ignore_opt == true)
826 break;
827 exit_error("--ignore to continue", true);
828 }
829 }
830
831 return (parsed);
832 }
833
main(int argc,char * argv[argc])834 int main(int argc, char *argv[argc])
835 {
836 int i, rows, cols, retval, parsed, nargc, firstoptind;
837 char *text, **nargv, *pn;
838 struct bsddialog_conf conf;
839
840 setlocale(LC_ALL, "");
841
842 in_bsddialog_mode = false;
843 mandatory_dialog = true;
844 firstoptind = optind;
845 pn = argv[0];
846 retval = BSDDIALOG_OK;
847
848 for (i = 0; i < argc; i++) {
849 if (strcmp(argv[i], "--version") == 0) {
850 printf("Version: %s\n", LIBBSDDIALOG_VERSION);
851 return (BSDDIALOG_OK);
852 }
853 if (strcmp(argv[i], "--help") == 0) {
854 usage();
855 return (BSDDIALOG_OK);
856 }
857 }
858
859 while (true) {
860 parsed = parseargs(argc, argv, &conf);
861 nargc = argc - parsed;
862 nargv = argv + parsed;
863 argc = parsed - optind;
864 argv += optind;
865
866 if (mandatory_dialog && dialogbuilder == NULL)
867 exit_error("expected a --<dialog>", true);
868
869 if (dialogbuilder == NULL && argc > 0)
870 error_args("(no --<dialog>)", argc, argv);
871
872 /* --print-maxsize or --print-version */
873 if (mandatory_dialog == false && savethemefile == NULL &&
874 clear_screen_opt == false)
875 return (BSDDIALOG_OK);
876
877 /* --<dialog>, --save-theme or clear-screen */
878 if (dialogbuilder != NULL) {
879 if (argc < 3)
880 exit_error("expected <text> <rows> <cols>",
881 true);
882 if ((text = strdup(argv[0])) == NULL)
883 exit_error("cannot allocate text", false);
884 if (dialogbuilder != textbox_builder)
885 custom_text(argv[0], text);
886 rows = (int)strtol(argv[1], NULL, 10);
887 cols = (int)strtol(argv[2], NULL, 10);
888 argc -= 3;
889 argv += 3;
890 }
891
892 /* bsddialog terminal mode (first iteration) */
893 start_bsddialog_mode();
894
895 if (screen_mode_opt != NULL) {
896 screen_mode_opt = tigetstr(screen_mode_opt);
897 if (screen_mode_opt != NULL &&
898 screen_mode_opt != (char*)-1) {
899 tputs(screen_mode_opt, 1, putchar);
900 fflush(stdout);
901 /* only to refresh, useless in the library */
902 bsddialog_clearterminal();
903 }
904 }
905
906 /* theme */
907 if (theme_opt >= 0)
908 bsddialog_set_default_theme(theme_opt);
909 if (loadthemefile != NULL)
910 loadtheme(loadthemefile);
911 if (bikeshed_opt)
912 bikeshed(&conf);
913 if (savethemefile != NULL)
914 savetheme(savethemefile, LIBBSDDIALOG_VERSION);
915
916 /* backtitle and dialog */
917 if (dialogbuilder == NULL)
918 break;
919 if (backtitle_opt != NULL)
920 if(bsddialog_backtitle(&conf, backtitle_opt))
921 exit_error(bsddialog_geterror(), false);
922 retval = dialogbuilder(&conf, text, rows, cols, argc, argv);
923 free(text);
924 if (retval == BSDDIALOG_ERROR)
925 exit_error(bsddialog_geterror(), false);
926 if (retval == BSDDIALOG_ESC && esc_return_cancel_opt)
927 retval = BSDDIALOG_CANCEL;
928 if (conf.get_height != NULL && conf.get_width != NULL)
929 dprintf(output_fd_opt, "DialogSize: %d, %d\n",
930 *conf.get_height, *conf.get_width);
931 if (clear_screen_opt)
932 bsddialog_clearterminal();
933 clear_screen_opt = false;
934 /* --and-dialog ends loop with Cancel or ESC */
935 if (retval == BSDDIALOG_CANCEL || retval == BSDDIALOG_ESC)
936 break;
937 argc = nargc;
938 argv = nargv;
939 if (argc <= 0)
940 break;
941 /* prepare next parseargs() call */
942 argc++;
943 argv--;
944 argv[0] = pn;
945 optind = firstoptind;
946 }
947
948 if (in_bsddialog_mode) {
949 /* --clear-screen can be a single option */
950 if (clear_screen_opt)
951 bsddialog_clearterminal();
952 bsddialog_end();
953 }
954 /* end bsddialog terminal mode */
955
956 return (retval);
957 }
958
custom_text(char * text,char * buf)959 void custom_text(char *text, char *buf)
960 {
961 bool trim, crwrap;
962 int i, j;
963
964 if (strstr(text, "\\n") == NULL) {
965 /* "hasnl" mode */
966 trim = true;
967 crwrap = true;
968 } else {
969 trim = false;
970 crwrap = cr_wrap_opt;
971 }
972 if (text_unchanged_opt) {
973 trim = false;
974 crwrap = true;
975 }
976
977 i = j = 0;
978 while (text[i] != '\0') {
979 switch (text[i]) {
980 case '\\':
981 buf[j] = '\\';
982 switch (text[i+1]) {
983 case 'n': /* implicitly in "hasnl" mode */
984 buf[j] = '\n';
985 i++;
986 if (text[i+1] == '\n')
987 i++;
988 break;
989 case 't':
990 if (tab_escape_opt) {
991 buf[j] = '\t';
992 } else {
993 j++;
994 buf[j] = 't';
995 }
996 i++;
997 break;
998 }
999 break;
1000 case '\n':
1001 buf[j] = crwrap ? '\n' : ' ';
1002 break;
1003 case '\t':
1004 buf[j] = text_unchanged_opt ? '\t' : ' ';
1005 break;
1006 default:
1007 buf[j] = text[i];
1008 }
1009 i++;
1010 if (!trim || buf[j] != ' ' || j == 0 || buf[j-1] != ' ')
1011 j++;
1012 }
1013 buf[j] = '\0';
1014 }
1015
1016 /* Dialogs */
gauge_builder(BUILDER_ARGS)1017 int gauge_builder(BUILDER_ARGS)
1018 {
1019 int output;
1020 unsigned int perc;
1021
1022 perc = 0;
1023 if (argc == 1) {
1024 perc = (u_int)strtoul(argv[0], NULL, 10);
1025 perc = perc > 100 ? 100 : perc;
1026 } else if (argc > 1) {
1027 error_args("--gauge", argc - 1, argv + 1);
1028 }
1029
1030 output = bsddialog_gauge(conf, text, rows, cols, perc, STDIN_FILENO,
1031 "XXX");
1032
1033 return (output);
1034 }
1035
infobox_builder(BUILDER_ARGS)1036 int infobox_builder(BUILDER_ARGS)
1037 {
1038 if (argc > 0)
1039 error_args("--infobox", argc, argv);
1040
1041 return (bsddialog_infobox(conf, text, rows, cols));
1042 }
1043
mixedgauge_builder(BUILDER_ARGS)1044 int mixedgauge_builder(BUILDER_ARGS)
1045 {
1046 int output, *minipercs;
1047 unsigned int i, mainperc, nminibars;
1048 const char **minilabels;
1049
1050 if (argc < 1 || (((argc-1) % 2) != 0) )
1051 exit_error("bad --mixedgauge arguments", true);
1052
1053 mainperc = (u_int)strtoul(argv[0], NULL, 10);
1054 mainperc = mainperc > 100 ? 100 : mainperc;
1055 argc--;
1056 argv++;
1057
1058 nminibars = argc / 2;
1059 if ((minilabels = calloc(nminibars, sizeof(char*))) == NULL)
1060 exit_error("Cannot allocate memory for minilabels", false);
1061 if ((minipercs = calloc(nminibars, sizeof(int))) == NULL)
1062 exit_error("Cannot allocate memory for minipercs", false);
1063
1064 for (i = 0; i < nminibars; i++) {
1065 minilabels[i] = argv[i * 2];
1066 minipercs[i] = (int)strtol(argv[i * 2 + 1], NULL, 10);
1067 }
1068
1069 output = bsddialog_mixedgauge(conf, text, rows, cols, mainperc,
1070 nminibars, minilabels, minipercs);
1071
1072 return (output);
1073 }
1074
msgbox_builder(BUILDER_ARGS)1075 int msgbox_builder(BUILDER_ARGS)
1076 {
1077 if (argc > 0)
1078 error_args("--msgbox", argc, argv);
1079
1080 return (bsddialog_msgbox(conf, text, rows, cols));
1081 }
1082
pause_builder(BUILDER_ARGS)1083 int pause_builder(BUILDER_ARGS)
1084 {
1085 int output;
1086 unsigned int secs;
1087
1088 if (argc == 0)
1089 exit_error("--pause missing <seconds>", true);
1090 if (argc > 1)
1091 error_args("--pause", argc - 1, argv + 1);
1092
1093 secs = (u_int)strtoul(argv[0], NULL, 10);
1094 output = bsddialog_pause(conf, text, rows, cols, secs);
1095
1096 return (output);
1097 }
1098
rangebox_builder(BUILDER_ARGS)1099 int rangebox_builder(BUILDER_ARGS)
1100 {
1101 int output, min, max, value;
1102
1103 if (argc < 2)
1104 exit_error("--rangebox missing <min> <max> [<init>]", true);
1105 if (argc > 3)
1106 error_args("--rangebox", argc - 3, argv + 3);
1107
1108 min = (int)strtol(argv[0], NULL, 10);
1109 max = (int)strtol(argv[1], NULL, 10);
1110
1111 if (argc == 3) {
1112 value = (int)strtol(argv[2], NULL, 10);
1113 value = value < min ? min : value;
1114 value = value > max ? max : value;
1115 } else
1116 value = min;
1117
1118 output = bsddialog_rangebox(conf, text, rows, cols, min, max, &value);
1119 dprintf(output_fd_opt, "%d", value);
1120
1121 return (output);
1122 }
1123
textbox_builder(BUILDER_ARGS)1124 int textbox_builder(BUILDER_ARGS)
1125 {
1126 if (argc > 0)
1127 error_args("--textbox", argc, argv);
1128
1129 return (bsddialog_textbox(conf, text, rows, cols));
1130 }
1131
yesno_builder(BUILDER_ARGS)1132 int yesno_builder(BUILDER_ARGS)
1133 {
1134 if (argc > 0)
1135 error_args("--yesno", argc, argv);
1136
1137 return (bsddialog_yesno(conf, text, rows, cols));
1138 }
1139
1140 /* CALENDAR, DATE and TIME */
date(BUILDER_ARGS,bool is_datebox)1141 static int date(BUILDER_ARGS, bool is_datebox)
1142 {
1143 int ret;
1144 unsigned int yy, mm, dd;
1145 time_t cal;
1146 struct tm *localtm;
1147 char stringdate[1024];
1148 const char *name;
1149
1150 name = is_datebox ? "--datebox" : "--calendar";
1151 time(&cal);
1152 localtm = localtime(&cal);
1153 yy = localtm->tm_year + 1900;
1154 mm = localtm->tm_mon + 1;
1155 dd = localtm->tm_mday;
1156
1157 if (argc > 3) {
1158 error_args(name, argc - 3, argv + 3);
1159 } else if (argc == 3) {
1160 dd = (u_int)strtoul(argv[0], NULL, 10);
1161 mm = (u_int)strtoul(argv[1], NULL, 10);
1162 yy = (u_int)strtoul(argv[2], NULL, 10);
1163 if (yy < 1900)
1164 yy = 1900;
1165 /* max yy check is in lib */
1166 }
1167
1168 if (is_datebox)
1169 ret = bsddialog_datebox(conf, text, rows, cols, &yy, &mm, &dd);
1170 else
1171 ret = bsddialog_calendar(conf, text, rows, cols, &yy, &mm, &dd);
1172 if (ret != BSDDIALOG_OK)
1173 return (ret);
1174
1175 if (date_fmt_opt != NULL) {
1176 time(&cal);
1177 localtm = localtime(&cal);
1178 localtm->tm_year = yy - 1900;
1179 localtm->tm_mon = mm - 1;
1180 localtm->tm_mday = dd;
1181 strftime(stringdate, 1024, date_fmt_opt, localtm);
1182 dprintf(output_fd_opt, "%s", stringdate);
1183 } else if (bikeshed_opt && (dd % 2 == 0)) {
1184 dprintf(output_fd_opt, "%u/%u/%u", dd, mm, yy);
1185 } else {
1186 dprintf(output_fd_opt, "%02u/%02u/%u", dd, mm, yy);
1187 }
1188
1189 return (ret);
1190 }
1191
calendar_builder(BUILDER_ARGS)1192 int calendar_builder(BUILDER_ARGS)
1193 {
1194 if (rows == 2) {
1195 /*
1196 * (bsdconfig/share/dialog.subr:1352) f_dialog_calendar_size()
1197 * computes height 2 for `dialog --calendar' in
1198 * (bsdconfig/usermgmt/share/user_input.subr:517)
1199 * f_dialog_input_expire_password() and
1200 * (bsdconfig/usermgmt/share/user_input.subr:660)
1201 * f_dialog_input_expire_account().
1202 * Use height auto-sizing that is min height like dialog,
1203 * documented in bsddialog(1).
1204 */
1205 rows = 0;
1206 }
1207
1208 return (date(conf, text, rows, cols, argc, argv, false));
1209 }
1210
datebox_builder(BUILDER_ARGS)1211 int datebox_builder(BUILDER_ARGS)
1212 {
1213 return (date(conf, text, rows, cols, argc, argv, true));
1214 }
1215
timebox_builder(BUILDER_ARGS)1216 int timebox_builder(BUILDER_ARGS)
1217 {
1218 int output;
1219 unsigned int hh, mm, ss;
1220 time_t clock;
1221 struct tm *localtm;
1222 char stringtime[1024];
1223
1224 time(&clock);
1225 localtm = localtime(&clock);
1226 hh = localtm->tm_hour;
1227 mm = localtm->tm_min;
1228 ss = localtm->tm_sec;
1229
1230 if (argc > 3) {
1231 error_args("--timebox", argc - 3, argv + 3);
1232 } else if (argc == 3) {
1233 hh = (u_int)strtoul(argv[0], NULL, 10);
1234 mm = (u_int)strtoul(argv[1], NULL, 10);
1235 ss = (u_int)strtoul(argv[2], NULL, 10);
1236 }
1237
1238 output = bsddialog_timebox(conf, text, rows, cols, &hh, &mm, &ss);
1239 if (output != BSDDIALOG_OK)
1240 return (output);
1241
1242 if (time_fmt_opt != NULL) {
1243 time(&clock);
1244 localtm = localtime(&clock);
1245 localtm->tm_hour = hh;
1246 localtm->tm_min = mm;
1247 localtm->tm_sec = ss;
1248 strftime(stringtime, 1024, time_fmt_opt, localtm);
1249 dprintf(output_fd_opt, "%s", stringtime);
1250 } else if (bikeshed_opt && (ss % 2 == 0)) {
1251 dprintf(output_fd_opt, "%u:%u:%u", hh, mm, ss);
1252 } else {
1253 dprintf(output_fd_opt, "%02u:%02u:%02u", hh, mm, ss);
1254 }
1255
1256 return (output);
1257 }
1258
1259 /* MENU */
1260 static void
get_menu_items(int argc,char ** argv,bool setprefix,bool setdepth,bool setname,bool setdesc,bool setstatus,bool sethelp,unsigned int * nitems,struct bsddialog_menuitem ** items,int * focusitem)1261 get_menu_items(int argc, char **argv, bool setprefix, bool setdepth,
1262 bool setname, bool setdesc, bool setstatus, bool sethelp,
1263 unsigned int *nitems, struct bsddialog_menuitem **items, int *focusitem)
1264 {
1265 unsigned int i, j, sizeitem;
1266
1267 *focusitem = -1;
1268
1269 sizeitem = 0;
1270 sizeitem += setprefix ? 1 : 0;
1271 sizeitem += setdepth ? 1 : 0;
1272 sizeitem += setname ? 1 : 0;
1273 sizeitem += setdesc ? 1 : 0;
1274 sizeitem += setstatus ? 1 : 0;
1275 sizeitem += sethelp ? 1 : 0;
1276 if ((argc % sizeitem) != 0)
1277 exit_error("\"menu\" bad arguments items number", true);
1278
1279 *nitems = argc / sizeitem;
1280
1281 *items = calloc(*nitems, sizeof(struct bsddialog_menuitem));
1282 if (items == NULL)
1283 exit_error("cannot allocate memory \"menu\" items", false);
1284
1285 j = 0;
1286 for (i = 0; i < *nitems; i++) {
1287 (*items)[i].prefix = setprefix ? argv[j++] : "";
1288 (*items)[i].depth = setdepth ?
1289 (u_int)strtoul(argv[j++], NULL, 0) : 0;
1290 (*items)[i].name = setname ? argv[j++] : "";
1291 (*items)[i].desc = setdesc ? argv[j++] : "";
1292 if (setstatus)
1293 (*items)[i].on = strcmp(argv[j++], "on") == 0 ?
1294 true : false;
1295 else
1296 (*items)[i].on = false;
1297 (*items)[i].bottomdesc = sethelp ? argv[j++] : "";
1298
1299 if (item_default_opt != NULL && *focusitem == -1)
1300 if (strcmp((*items)[i].name, item_default_opt) == 0)
1301 *focusitem = i;
1302 }
1303 }
1304
1305 static void
print_menu_items(int output,int nitems,struct bsddialog_menuitem * items,int focusitem,bool ismenu)1306 print_menu_items(int output, int nitems, struct bsddialog_menuitem *items,
1307 int focusitem, bool ismenu)
1308 {
1309 bool sep, sepfirst, seplast, toquote;
1310 int i;
1311 char quotech;
1312 const char *focusname, *sepstr;
1313
1314 sep = false;
1315 quotech = item_singlequote_opt ? '\'' : '"';
1316
1317 if (output == BSDDIALOG_ERROR || output == BSDDIALOG_CANCEL ||
1318 output == BSDDIALOG_ESC)
1319 return;
1320
1321 if (output == BSDDIALOG_HELP) {
1322 dprintf(output_fd_opt, "HELP ");
1323
1324 if (focusitem >= 0) {
1325 focusname = items[focusitem].name;
1326 if (item_bottomdesc_opt &&
1327 item_help_print_name_opt == false)
1328 focusname = items[focusitem].bottomdesc;
1329
1330 toquote = false;
1331 if (strchr(focusname, ' ') != NULL) {
1332 toquote = item_always_quote_opt;
1333 if (ismenu == false &&
1334 item_output_sepnl_opt == false)
1335 toquote = true;
1336 }
1337 if (toquote) {
1338 dprintf(output_fd_opt, "%c%s%c",
1339 quotech, focusname, quotech);
1340 } else
1341 dprintf(output_fd_opt, "%s", focusname);
1342 }
1343
1344 if (ismenu || list_items_on_opt == false)
1345 return;
1346 sep = true;
1347 }
1348
1349 sepfirst = false;
1350 if ((sepstr = item_output_sep_opt) == NULL)
1351 sepstr = item_output_sepnl_opt ? "\n" : " ";
1352 else
1353 sepfirst = true;
1354
1355 seplast = false;
1356 if (item_output_sepnl_opt) {
1357 sepfirst = false;
1358 seplast = true;
1359 }
1360
1361 for (i = 0; i < nitems; i++) {
1362 if (items[i].on == false)
1363 continue;
1364
1365 if (sep || sepfirst)
1366 dprintf(output_fd_opt, "%s", sepstr);
1367 sep = false;
1368
1369 toquote = false;
1370 if (strchr(items[i].name, ' ') != NULL) {
1371 toquote = item_always_quote_opt;
1372 if (ismenu == false && item_output_sepnl_opt == false)
1373 toquote = true;
1374 }
1375 if (toquote)
1376 dprintf(output_fd_opt, "%c%s%c",
1377 quotech, items[i].name, quotech);
1378 else
1379 dprintf(output_fd_opt, "%s", items[i].name);
1380
1381 if (seplast)
1382 dprintf(output_fd_opt, "%s", sepstr);
1383 }
1384 }
1385
checklist_builder(BUILDER_ARGS)1386 int checklist_builder(BUILDER_ARGS)
1387 {
1388 int output, focusitem;
1389 unsigned int menurows, nitems;
1390 struct bsddialog_menuitem *items;
1391
1392 if (argc < 1)
1393 exit_error("--checklist missing <menurows>", true);
1394 menurows = (u_int)strtoul(argv[0], NULL, 10);
1395
1396 get_menu_items(argc-1, argv+1, item_prefix_opt, item_depth_opt, true,
1397 true, true, item_bottomdesc_opt, &nitems, &items, &focusitem);
1398
1399 output = bsddialog_checklist(conf, text, rows, cols, menurows, nitems,
1400 items, &focusitem);
1401
1402 print_menu_items(output, nitems, items, focusitem, false);
1403
1404 free(items);
1405
1406 return (output);
1407 }
1408
menu_builder(BUILDER_ARGS)1409 int menu_builder(BUILDER_ARGS)
1410 {
1411 int output, focusitem;
1412 unsigned int menurows, nitems;
1413 struct bsddialog_menuitem *items;
1414
1415 if (argc < 1)
1416 exit_error("--menu missing <menurows>", true);
1417 menurows = (u_int)strtoul(argv[0], NULL, 10);
1418
1419 get_menu_items(argc-1, argv+1, item_prefix_opt, item_depth_opt, true,
1420 true, false, item_bottomdesc_opt, &nitems, &items, &focusitem);
1421
1422 output = bsddialog_menu(conf, text, rows, cols, menurows, nitems,
1423 items, &focusitem);
1424
1425 print_menu_items(output, nitems, items, focusitem, true);
1426
1427 free(items);
1428
1429 return (output);
1430 }
1431
radiolist_builder(BUILDER_ARGS)1432 int radiolist_builder(BUILDER_ARGS)
1433 {
1434 int output, focusitem;
1435 unsigned int menurows, nitems;
1436 struct bsddialog_menuitem *items;
1437
1438 if (argc < 1)
1439 exit_error("--radiolist missing <menurows>", true);
1440 menurows = (u_int)strtoul(argv[0], NULL, 10);
1441
1442 get_menu_items(argc-1, argv+1, item_prefix_opt, item_depth_opt, true,
1443 true, true, item_bottomdesc_opt, &nitems, &items, &focusitem);
1444
1445 output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
1446 items, &focusitem);
1447
1448 print_menu_items(output, nitems, items, focusitem, false);
1449
1450 free(items);
1451
1452 return (output);
1453 }
1454
treeview_builder(BUILDER_ARGS)1455 int treeview_builder(BUILDER_ARGS)
1456 {
1457 int output, focusitem;
1458 unsigned int menurows, nitems;
1459 struct bsddialog_menuitem *items;
1460
1461 if (argc < 1)
1462 exit_error("--treeview missing <menurows>", true);
1463 menurows = (u_int)strtoul(argv[0], NULL, 10);
1464
1465 get_menu_items(argc-1, argv+1, item_prefix_opt, true, true, true, true,
1466 item_bottomdesc_opt, &nitems, &items, &focusitem);
1467
1468 conf->menu.no_name = true;
1469 conf->menu.align_left = true;
1470
1471 output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
1472 items, &focusitem);
1473
1474 print_menu_items(output, nitems, items, focusitem, false);
1475
1476 free(items);
1477
1478 return (output);
1479 }
1480
1481 /* FORM */
1482 static void
print_form_items(int output,int nitems,struct bsddialog_formitem * items)1483 print_form_items(int output, int nitems, struct bsddialog_formitem *items)
1484 {
1485 int i;
1486
1487 if (output == BSDDIALOG_ERROR)
1488 return;
1489
1490 for (i = 0; i < nitems; i++) {
1491 dprintf(output_fd_opt, "%s\n", items[i].value);
1492 free(items[i].value);
1493 }
1494 }
1495
form_builder(BUILDER_ARGS)1496 int form_builder(BUILDER_ARGS)
1497 {
1498 int output, fieldlen, valuelen;
1499 unsigned int i, j, flags, formheight, nitems, sizeitem;
1500 struct bsddialog_formitem *items;
1501
1502 if (argc < 1)
1503 exit_error("--form missing <formheight>", true);
1504 formheight = (u_int)strtoul(argv[0], NULL, 10);
1505
1506 argc--;
1507 argv++;
1508 sizeitem = item_bottomdesc_opt ? 9 : 8;
1509 if (argc % sizeitem != 0)
1510 exit_error("--form bad number of arguments items", true);
1511
1512 nitems = argc / sizeitem;
1513 if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
1514 exit_error("cannot allocate memory for form items", false);
1515 j = 0;
1516 for (i = 0; i < nitems; i++) {
1517 items[i].label = argv[j++];
1518 items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10);
1519 items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10);
1520 items[i].init = argv[j++];
1521 items[i].yfield = (u_int)strtoul(argv[j++], NULL, 10);
1522 items[i].xfield = (u_int)strtoul(argv[j++], NULL, 10);
1523
1524 fieldlen = (int)strtol(argv[j++], NULL, 10);
1525 items[i].fieldlen = abs(fieldlen);
1526
1527 valuelen = (int)strtol(argv[j++], NULL, 10);
1528 items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
1529
1530 flags = (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
1531 items[i].flags = flags;
1532
1533 items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
1534 }
1535
1536 output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
1537 items);
1538 print_form_items(output, nitems, items);
1539 free(items);
1540
1541 return (output);
1542 }
1543
inputbox_builder(BUILDER_ARGS)1544 int inputbox_builder(BUILDER_ARGS)
1545 {
1546 int output;
1547 struct bsddialog_formitem item;
1548
1549 if (argc > 1)
1550 error_args("--inputbox", argc - 1, argv + 1);
1551
1552 item.label = "";
1553 item.ylabel = 0;
1554 item.xlabel = 0;
1555 item.init = argc > 0 ? argv[0] : "";
1556 item.yfield = 0;
1557 item.xfield = 0;
1558 item.fieldlen = 1;
1559 item.maxvaluelen = max_input_form_opt;
1560 item.flags = BSDDIALOG_FIELDNOCOLOR;
1561 item.flags |= BSDDIALOG_FIELDCURSOREND;
1562 item.flags |= BSDDIALOG_FIELDEXTEND;
1563 item.bottomdesc = "";
1564
1565 output = bsddialog_form(conf, text, rows, cols, 1, 1, &item);
1566 print_form_items(output, 1, &item);
1567
1568 return (output);
1569 }
1570
mixedform_builder(BUILDER_ARGS)1571 int mixedform_builder(BUILDER_ARGS)
1572 {
1573 int output;
1574 unsigned int i, j, formheight, nitems, sizeitem;
1575 struct bsddialog_formitem *items;
1576
1577 if (argc < 1)
1578 exit_error("--mixedform missing <formheight>", true);
1579 formheight = (u_int)strtoul(argv[0], NULL, 10);
1580
1581 argc--;
1582 argv++;
1583 sizeitem = item_bottomdesc_opt ? 10 : 9;
1584 if (argc % sizeitem != 0)
1585 exit_error("--mixedform bad number of arguments items", true);
1586
1587 nitems = argc / sizeitem;
1588 if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
1589 exit_error("cannot allocate memory for form items", false);
1590 j = 0;
1591 for (i = 0; i < nitems; i++) {
1592 items[i].label = argv[j++];
1593 items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10);
1594 items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10);
1595 items[i].init = argv[j++];
1596 items[i].yfield = (u_int)strtoul(argv[j++], NULL, 10);
1597 items[i].xfield = (u_int)strtoul(argv[j++], NULL, 10);
1598 items[i].fieldlen = (u_int)strtoul(argv[j++], NULL, 10);
1599 items[i].maxvaluelen = (u_int)strtoul(argv[j++], NULL, 10);
1600 items[i].flags = (u_int)strtoul(argv[j++], NULL, 10);
1601 items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
1602 }
1603
1604 output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
1605 items);
1606 print_form_items(output, nitems, items);
1607 free(items);
1608
1609 return (output);
1610 }
1611
passwordbox_builder(BUILDER_ARGS)1612 int passwordbox_builder(BUILDER_ARGS)
1613 {
1614 int output;
1615 struct bsddialog_formitem item;
1616
1617 if (argc > 1)
1618 error_args("--passwordbox", argc - 1, argv + 1);
1619
1620 item.label = "";
1621 item.ylabel = 0;
1622 item.xlabel = 0;
1623 item.init = argc > 0 ? argv[0] : "";
1624 item.yfield = 0;
1625 item.xfield = 0;
1626 item.fieldlen = 1;
1627 item.maxvaluelen = max_input_form_opt;
1628 item.flags = BSDDIALOG_FIELDHIDDEN;
1629 item.flags |= BSDDIALOG_FIELDNOCOLOR;
1630 item.flags |= BSDDIALOG_FIELDCURSOREND;
1631 item.flags |= BSDDIALOG_FIELDEXTEND;
1632 item.bottomdesc = "";
1633
1634 output = bsddialog_form(conf, text, rows, cols, 1, 1, &item);
1635 print_form_items(output, 1, &item);
1636
1637 return (output);
1638 }
1639
passwordform_builder(BUILDER_ARGS)1640 int passwordform_builder(BUILDER_ARGS)
1641 {
1642 int output, fieldlen, valuelen;
1643 unsigned int i, j, flags, formheight, nitems, sizeitem;
1644 struct bsddialog_formitem *items;
1645
1646 if (argc < 1)
1647 exit_error("--passwordform missing <formheight>", true);
1648 formheight = (u_int)strtoul(argv[0], NULL, 10);
1649
1650 argc--;
1651 argv++;
1652 sizeitem = item_bottomdesc_opt ? 9 : 8;
1653 if (argc % sizeitem != 0)
1654 exit_error("--passwordform bad arguments items number", true);
1655
1656 flags = BSDDIALOG_FIELDHIDDEN;
1657 nitems = argc / sizeitem;
1658 if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
1659 exit_error("cannot allocate memory for form items", false);
1660 j = 0;
1661 for (i = 0; i < nitems; i++) {
1662 items[i].label = argv[j++];
1663 items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10);
1664 items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10);
1665 items[i].init = argv[j++];
1666 items[i].yfield = (u_int)strtoul(argv[j++], NULL, 10);
1667 items[i].xfield = (u_int)strtoul(argv[j++], NULL, 10);
1668
1669 fieldlen = (int)strtol(argv[j++], NULL, 10);
1670 items[i].fieldlen = abs(fieldlen);
1671
1672 valuelen = (int)strtol(argv[j++], NULL, 10);
1673 items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
1674
1675 flags |= (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
1676 items[i].flags = flags;
1677
1678 items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
1679 }
1680
1681 output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
1682 items);
1683 print_form_items(output, nitems, items);
1684 free(items);
1685
1686 return (output);
1687 }
1688