1 /* 2 * $Id: dialog.c,v 1.193 2011/06/29 09:10:56 tom Exp $ 3 * 4 * cdialog - Display simple dialog boxes from shell scripts 5 * 6 * Copyright 2000-2010,2011 Thomas E. Dickey 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License, version 2.1 10 * as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program; if not, write to 19 * Free Software Foundation, Inc. 20 * 51 Franklin St., Fifth Floor 21 * Boston, MA 02110, USA. 22 * 23 * An earlier version of this program lists as authors 24 * Savio Lam (lam836@cs.cuhk.hk) 25 */ 26 27 #include <dialog.h> 28 #include <string.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 32 #ifdef HAVE_SETLOCALE 33 #include <locale.h> 34 #endif 35 36 #define PASSARGS t, av, offset_add 37 #define CALLARGS const char *t, char *av[], int *offset_add 38 typedef int (callerFn) (CALLARGS); 39 40 typedef enum { 41 o_unknown = 0 42 ,o_allow_close 43 ,o_and_widget 44 ,o_ascii_lines 45 ,o_aspect 46 ,o_auto_placement 47 ,o_backtitle 48 ,o_beep 49 ,o_beep_after 50 ,o_begin 51 ,o_calendar 52 ,o_cancel_label 53 ,o_checklist 54 ,o_clear 55 ,o_colors 56 ,o_column_separator 57 ,o_cr_wrap 58 ,o_create_rc 59 ,o_date_format 60 ,o_default_item 61 ,o_defaultno 62 ,o_dselect 63 ,o_editbox 64 ,o_exit_label 65 ,o_extra_button 66 ,o_extra_label 67 ,o_fixed_font 68 ,o_form 69 ,o_fselect 70 ,o_fullbutton 71 ,o_gauge 72 ,o_help 73 ,o_help_button 74 ,o_help_file 75 ,o_help_label 76 ,o_help_line 77 ,o_help_status 78 ,o_icon 79 ,o_ignore 80 ,o_infobox 81 ,o_input_fd 82 ,o_inputbox 83 ,o_inputmenu 84 ,o_insecure 85 ,o_item_help 86 ,o_keep_colors 87 ,o_keep_tite 88 ,o_keep_window 89 ,o_max_input 90 ,o_menu 91 ,o_mixedform 92 ,o_mixedgauge 93 ,o_msgbox 94 ,o_no_close 95 ,o_no_collapse 96 ,o_no_cr_wrap 97 ,o_no_kill 98 ,o_no_label 99 ,o_no_lines 100 ,o_no_mouse 101 ,o_no_nl_expand 102 ,o_no_shadow 103 ,o_nocancel 104 ,o_noitem 105 ,o_nook 106 ,o_ok_label 107 ,o_output_fd 108 ,o_output_separator 109 ,o_passwordbox 110 ,o_passwordform 111 ,o_pause 112 ,o_prgbox 113 ,o_print_maxsize 114 ,o_print_size 115 ,o_print_version 116 ,o_programbox 117 ,o_progressbox 118 ,o_quoted 119 ,o_radiolist 120 ,o_screen_center 121 ,o_scrollbar 122 ,o_separate_output 123 ,o_separate_widget 124 ,o_separator 125 ,o_shadow 126 ,o_single_quoted 127 ,o_size_err 128 ,o_sleep 129 ,o_smooth 130 ,o_stderr 131 ,o_stdout 132 ,o_tab_correct 133 ,o_tab_len 134 ,o_tailbox 135 ,o_tailboxbg 136 ,o_textbox 137 ,o_time_format 138 ,o_timebox 139 ,o_timeout 140 ,o_title 141 ,o_trim 142 ,o_under_mouse 143 ,o_version 144 ,o_visit_items 145 ,o_wmclass 146 ,o_yes_label 147 ,o_yesno 148 #ifdef HAVE_DLG_TRACE 149 ,o_trace 150 #endif 151 } eOptions; 152 153 /* 154 * The bits in 'pass' are used to decide which options are applicable at 155 * different stages in the program: 156 * 1 flags before widgets 157 * 2 widgets 158 * 4 non-widget options 159 */ 160 typedef struct { 161 const char *name; 162 eOptions code; 163 int pass; /* 1,2,4 or combination */ 164 const char *help; /* NULL to suppress, non-empty to display params */ 165 } Options; 166 167 typedef struct { 168 eOptions code; 169 int argmin, argmax; 170 callerFn *jumper; 171 } Mode; 172 173 static bool *dialog_opts; 174 static char **dialog_argv; 175 176 static bool ignore_unknown = FALSE; 177 178 static const char *program = "dialog"; 179 180 /* 181 * The options[] table is organized this way to make it simple to maintain 182 * a sorted list of options for the help-message. 183 */ 184 /* *INDENT-OFF* */ 185 static const Options options[] = { 186 { "allow-close", o_allow_close, 1, NULL }, 187 { "and-widget", o_and_widget, 4, NULL }, 188 { "ascii-lines", o_ascii_lines, 1, "" }, 189 { "aspect", o_aspect, 1, "<ratio>" }, 190 { "auto-placement", o_auto_placement, 1, NULL }, 191 { "backtitle", o_backtitle, 1, "<backtitle>" }, 192 { "beep", o_beep, 1, NULL }, 193 { "beep-after", o_beep_after, 1, NULL }, 194 { "begin", o_begin, 1, "<y> <x>" }, 195 { "calendar", o_calendar, 2, "<text> <height> <width> <day> <month> <year>" }, 196 { "cancel-label", o_cancel_label, 1, "<str>" }, 197 { "checklist", o_checklist, 2, "<text> <height> <width> <list height> <tag1> <item1> <status1>..." }, 198 { "clear", o_clear, 1, "" }, 199 { "colors", o_colors, 1, "" }, 200 { "column-separator",o_column_separator, 1, "<str>" }, 201 { "cr-wrap", o_cr_wrap, 1, "" }, 202 { "create-rc", o_create_rc, 1, NULL }, 203 { "date-format", o_date_format, 1, "<str>" }, 204 { "default-item", o_default_item, 1, "<str>" }, 205 { "defaultno", o_defaultno, 1, "" }, 206 { "dselect", o_dselect, 2, "<directory> <height> <width>" }, 207 { "editbox", o_editbox, 2, "<file> <height> <width>" }, 208 { "exit-label", o_exit_label, 1, "<str>" }, 209 { "extra-button", o_extra_button, 1, "" }, 210 { "extra-label", o_extra_label, 1, "<str>" }, 211 { "fb", o_fullbutton, 1, NULL }, 212 { "fixed-font", o_fixed_font, 1, NULL }, 213 { "form", o_form, 2, "<text> <height> <width> <form height> <label1> <l_y1> <l_x1> <item1> <i_y1> <i_x1> <flen1> <ilen1>..." }, 214 { "fselect", o_fselect, 2, "<filepath> <height> <width>" }, 215 { "fullbutton", o_fullbutton, 1, NULL }, 216 { "gauge", o_gauge, 2, "<text> <height> <width> [<percent>]" }, 217 { "guage", o_gauge, 2, NULL }, 218 { "help", o_help, 4, "" }, 219 { "help-button", o_help_button, 1, "" }, 220 { "help-label", o_help_label, 1, "<str>" }, 221 { "help-status", o_help_status, 1, "" }, 222 { "hfile", o_help_file, 1, "<str>" }, 223 { "hline", o_help_line, 1, "<str>" }, 224 { "icon", o_icon, 1, NULL }, 225 { "ignore", o_ignore, 1, "" }, 226 { "infobox", o_infobox, 2, "<text> <height> <width>" }, 227 { "input-fd", o_input_fd, 1, "<fd>" }, 228 { "inputbox", o_inputbox, 2, "<text> <height> <width> [<init>]" }, 229 { "inputmenu", o_inputmenu, 2, "<text> <height> <width> <menu height> <tag1> <item1>..." }, 230 { "insecure", o_insecure, 1, "" }, 231 { "item-help", o_item_help, 1, "" }, 232 { "keep-colors", o_keep_colors, 1, NULL }, 233 { "keep-tite", o_keep_tite, 1, "" }, 234 { "keep-window", o_keep_window, 1, "" }, 235 { "max-input", o_max_input, 1, "<n>" }, 236 { "menu", o_menu, 2, "<text> <height> <width> <menu height> <tag1> <item1>..." }, 237 { "mixedform", o_mixedform, 2, "<text> <height> <width> <form height> <label1> <l_y1> <l_x1> <item1> <i_y1> <i_x1> <flen1> <ilen1> <itype>..." }, 238 { "mixedgauge", o_mixedgauge, 2, "<text> <height> <width> <percent> <tag1> <item1>..." }, 239 { "msgbox", o_msgbox, 2, "<text> <height> <width>" }, 240 { "no-cancel", o_nocancel, 1, "" }, 241 { "no-close", o_no_close, 1, NULL }, 242 { "no-collapse", o_no_collapse, 1, "" }, 243 { "no-cr-wrap", o_no_cr_wrap, 1, NULL }, 244 { "no-kill", o_no_kill, 1, "" }, 245 { "no-label", o_no_label, 1, "<str>" }, 246 { "no-lines", o_no_lines, 1, "" }, 247 { "no-mouse", o_no_mouse, 1, "" }, 248 { "no-nl-expand", o_no_nl_expand, 1, "" }, 249 { "no-ok", o_nook, 1, "" }, 250 { "no-shadow", o_no_shadow, 1, "" }, 251 { "nocancel", o_nocancel, 1, NULL }, /* see --no-cancel */ 252 { "noitem", o_noitem, 1, NULL }, 253 { "nook", o_nook, 1, "" }, /* See no-ok */ 254 { "ok-label", o_ok_label, 1, "<str>" }, 255 { "output-fd", o_output_fd, 1, "<fd>" }, 256 { "output-separator",o_output_separator, 1, "<str>" }, 257 { "passwordbox", o_passwordbox, 2, "<text> <height> <width> [<init>]" }, 258 { "passwordform", o_passwordform, 2, "<text> <height> <width> <form height> <label1> <l_y1> <l_x1> <item1> <i_y1> <i_x1> <flen1> <ilen1>..." }, 259 { "pause", o_pause, 2, "<text> <height> <width> <seconds>" }, 260 { "prgbox", o_prgbox, 2, "<text> <command> <height> <width>" }, 261 { "print-maxsize", o_print_maxsize, 1, "" }, 262 { "print-size", o_print_size, 1, "" }, 263 { "print-version", o_print_version, 5, "" }, 264 { "programbox", o_programbox, 2, "<text> <height> <width>" }, 265 { "progressbox", o_progressbox, 2, "<text> <height> <width>" }, 266 { "quoted", o_quoted, 1, "" }, 267 { "radiolist", o_radiolist, 2, "<text> <height> <width> <list height> <tag1> <item1> <status1>..." }, 268 { "screen-center", o_screen_center, 1, NULL }, 269 { "scrollbar", o_scrollbar, 1, "" }, 270 { "separate-output",o_separate_output, 1, "" }, 271 { "separate-widget",o_separate_widget, 1, "<str>" }, 272 { "separator", o_separator, 1, NULL }, 273 { "shadow", o_shadow, 1, "" }, 274 { "single-quoted", o_single_quoted, 1, "" }, 275 { "size-err", o_size_err, 1, "" }, 276 { "sleep", o_sleep, 1, "<secs>" }, 277 { "smooth", o_smooth, 1, NULL }, 278 { "stderr", o_stderr, 1, "" }, 279 { "stdout", o_stdout, 1, "" }, 280 { "tab-correct", o_tab_correct, 1, "" }, 281 { "tab-len", o_tab_len, 1, "<n>" }, 282 { "tailbox", o_tailbox, 2, "<file> <height> <width>" }, 283 { "tailboxbg", o_tailboxbg, 2, "<file> <height> <width>" }, 284 { "textbox", o_textbox, 2, "<file> <height> <width>" }, 285 { "time-format", o_time_format, 1, "<str>" }, 286 { "timebox", o_timebox, 2, "<text> <height> <width> <hour> <minute> <second>" }, 287 { "timeout", o_timeout, 1, "<secs>" }, 288 { "title", o_title, 1, "<title>" }, 289 { "trim", o_trim, 1, "" }, 290 { "under-mouse", o_under_mouse, 1, NULL }, 291 { "version", o_version, 5, "" }, 292 { "visit-items", o_visit_items, 1, "" }, 293 { "wmclass", o_wmclass, 1, NULL }, 294 { "yes-label", o_yes_label, 1, "<str>" }, 295 { "yesno", o_yesno, 2, "<text> <height> <width>" }, 296 #ifdef HAVE_DLG_TRACE 297 { "trace", o_trace, 1, "<file>" }, 298 #endif 299 }; 300 /* *INDENT-ON* */ 301 302 /* 303 * Make an array showing which argv[] entries are options. Use "--" as a 304 * special token to escape the next argument, allowing it to begin with "--". 305 * When we find a "--" argument, also remove it from argv[] and adjust argc. 306 * That appears to be an undocumented feature of the popt library. 307 * 308 * Also, if we see a "--file", expand it into the parameter list by reading the 309 * text from the given file and stripping quotes, treating whitespace outside 310 * quotes as a parameter delimiter. 311 * 312 * Finally, if we see a "--args", dump the current list of arguments to the 313 * standard error. This is used for debugging complex --file combinations. 314 */ 315 static void 316 unescape_argv(int *argcp, char ***argvp) 317 { 318 int j, k; 319 int limit_includes = 20 + *argcp; 320 int count_includes = 0; 321 bool changed = FALSE; 322 bool doalloc = FALSE; 323 char *filename; 324 325 dialog_opts = dlg_calloc(bool, (size_t) *argcp + 1); 326 assert_ptr(dialog_opts, "unescape_argv"); 327 328 for (j = 1; j < *argcp; j++) { 329 bool escaped = FALSE; 330 if (!strcmp((*argvp)[j], "--")) { 331 escaped = TRUE; 332 changed = dlg_eat_argv(argcp, argvp, j, 1); 333 } else if (!strcmp((*argvp)[j], "--args")) { 334 fprintf(stderr, "Showing arguments at arg%d\n", j); 335 for (k = 0; k < *argcp; ++k) { 336 fprintf(stderr, " arg%d:%s\n", k, (*argvp)[k]); 337 } 338 changed = dlg_eat_argv(argcp, argvp, j, 1); 339 } else if (!strcmp((*argvp)[j], "--file")) { 340 if (++count_includes > limit_includes) 341 dlg_exiterr("Too many --file options"); 342 343 if ((filename = (*argvp)[j + 1]) != 0) { 344 FILE *fp; 345 char **list; 346 char *blob; 347 int added; 348 size_t bytes_read; 349 size_t length; 350 int n; 351 352 if (*filename == '&') { 353 fp = fdopen(atoi(filename + sizeof(char)), "r"); 354 } else { 355 fp = fopen(filename, "r"); 356 } 357 358 if (fp) { 359 blob = NULL; 360 length = 0; 361 do { 362 blob = dlg_realloc(char, length + BUFSIZ + 1, blob); 363 assert_ptr(blob, "unescape_argv"); 364 bytes_read = fread(blob + length, 365 sizeof(char), 366 (size_t) BUFSIZ, 367 fp); 368 length += bytes_read; 369 if (ferror(fp)) 370 dlg_exiterr("error on filehandle in unescape_argv"); 371 } while (bytes_read == BUFSIZ); 372 fclose(fp); 373 374 blob[length] = '\0'; 375 376 list = dlg_string_to_argv(blob); 377 if ((added = dlg_count_argv(list)) != 0) { 378 if (added > 2) { 379 size_t need = (size_t) (*argcp + added + 1); 380 if (doalloc) { 381 *argvp = dlg_realloc(char *, need, *argvp); 382 assert_ptr(*argvp, "unescape_argv"); 383 } else { 384 char **newp = dlg_malloc(char *, need); 385 assert_ptr(newp, "unescape_argv"); 386 for (n = 0; n < *argcp; ++n) { 387 newp[n] = (*argvp)[n]; 388 } 389 *argvp = newp; 390 doalloc = TRUE; 391 } 392 dialog_opts = dlg_realloc(bool, need, dialog_opts); 393 assert_ptr(dialog_opts, "unescape_argv"); 394 } 395 for (n = *argcp; n >= j + 2; --n) { 396 (*argvp)[n + added - 2] = (*argvp)[n]; 397 dialog_opts[n + added - 2] = dialog_opts[n]; 398 } 399 for (n = 0; n < added; ++n) { 400 (*argvp)[n + j] = list[n]; 401 dialog_opts[n + j] = FALSE; 402 } 403 *argcp += added - 2; 404 free(list); 405 } 406 } else { 407 dlg_exiterr("Cannot open --file %s", filename); 408 } 409 (*argvp)[*argcp] = 0; 410 ++j; 411 continue; 412 } else { 413 dlg_exiterr("No value given for --file"); 414 } 415 } 416 if (!escaped 417 && (*argvp)[j] != 0 418 && !strncmp((*argvp)[j], "--", (size_t) 2) 419 && isalpha(UCH((*argvp)[j][2]))) { 420 dialog_opts[j] = TRUE; 421 } 422 } 423 424 /* if we didn't find any "--" tokens, there's no reason to do the table 425 * lookup in isOption() 426 */ 427 if (!changed) { 428 free(dialog_opts); 429 dialog_opts = 0; 430 } 431 dialog_argv = (*argvp); 432 } 433 434 /* 435 * Check if the given string from main's argv is an option. 436 */ 437 static bool 438 isOption(const char *arg) 439 { 440 bool result = FALSE; 441 442 if (arg != 0) { 443 if (dialog_opts != 0) { 444 int n; 445 for (n = 1; dialog_argv[n] != 0; ++n) { 446 if (dialog_argv[n] == arg) { 447 result = dialog_opts[n]; 448 break; 449 } 450 } 451 } else if (!strncmp(arg, "--", (size_t) 2) && isalpha(UCH(arg[2]))) { 452 result = TRUE; 453 } 454 } 455 return result; 456 } 457 458 static eOptions 459 lookupOption(const char *name, int pass) 460 { 461 unsigned n; 462 463 if (isOption(name)) { 464 name += 2; 465 for (n = 0; n < sizeof(options) / sizeof(options[0]); n++) { 466 if ((pass & options[n].pass) != 0 467 && !strcmp(name, options[n].name)) { 468 return options[n].code; 469 } 470 } 471 } 472 return o_unknown; 473 } 474 475 static void 476 Usage(const char *msg) 477 { 478 dlg_exiterr("Error: %s.\nUse --help to list options.\n\n", msg); 479 } 480 481 /* 482 * Count arguments, stopping at the end of the argument list, or on any of our 483 * "--" tokens. 484 */ 485 static int 486 arg_rest(char *argv[]) 487 { 488 int i = 1; /* argv[0] points to a "--" token */ 489 490 while (argv[i] != 0 491 && (!isOption(argv[i]) || lookupOption(argv[i], 7) == o_unknown)) 492 i++; 493 return i; 494 } 495 496 /* 497 * In MultiWidget this function is needed to count how many tags 498 * a widget (menu, checklist, radiolist) has 499 */ 500 static int 501 howmany_tags(char *argv[], int group) 502 { 503 int result = 0; 504 int have; 505 const char *format = "Expected %d arguments, found only %d"; 506 char temp[80]; 507 508 while (argv[0] != 0) { 509 if (isOption(argv[0])) 510 break; 511 if ((have = arg_rest(argv)) < group) { 512 sprintf(temp, format, group, have); 513 Usage(temp); 514 } 515 516 argv += group; 517 result++; 518 } 519 520 return result; 521 } 522 523 static int 524 numeric_arg(char **av, int n) 525 { 526 char *last = 0; 527 int result = (int) strtol(av[n], &last, 10); 528 char msg[80]; 529 530 if (last == 0 || *last != 0) { 531 sprintf(msg, "Expected a number for token %d of %.20s", n, av[0]); 532 Usage(msg); 533 } 534 return result; 535 } 536 537 static char * 538 optional_str(char **av, int n, char *dft) 539 { 540 char *ret = dft; 541 if (arg_rest(av) > n) 542 ret = av[n]; 543 return ret; 544 } 545 546 #if defined(HAVE_DLG_GAUGE) || defined(HAVE_XDIALOG) 547 static int 548 optional_num(char **av, int n, int dft) 549 { 550 int ret = dft; 551 if (arg_rest(av) > n) 552 ret = numeric_arg(av, n); 553 return ret; 554 } 555 #endif 556 557 /* 558 * On AIX 4.x, we have to flush the output right away since there is a bug in 559 * the curses package which discards stdout even when we've used newterm to 560 * redirect output to /dev/tty. 561 */ 562 static int 563 show_result(int ret) 564 { 565 bool either = FALSE; 566 567 switch (ret) { 568 case DLG_EXIT_OK: 569 case DLG_EXIT_EXTRA: 570 case DLG_EXIT_HELP: 571 case DLG_EXIT_ITEM_HELP: 572 if ((dialog_state.output_count > 1) && !dialog_vars.separate_output) { 573 fputs((dialog_state.separate_str 574 ? dialog_state.separate_str 575 : DEFAULT_SEPARATE_STR), 576 dialog_state.output); 577 either = TRUE; 578 } 579 if (dialog_vars.input_result != 0 580 && dialog_vars.input_result[0] != '\0') { 581 fputs(dialog_vars.input_result, dialog_state.output); 582 either = TRUE; 583 } 584 if (either) { 585 fflush(dialog_state.output); 586 } 587 break; 588 } 589 return ret; 590 } 591 592 /* 593 * These are the widget callers. 594 */ 595 596 static int 597 call_yesno(CALLARGS) 598 { 599 *offset_add = 4; 600 return dialog_yesno(t, 601 av[1], 602 numeric_arg(av, 2), 603 numeric_arg(av, 3)); 604 } 605 606 static int 607 call_msgbox(CALLARGS) 608 { 609 *offset_add = 4; 610 return dialog_msgbox(t, 611 av[1], 612 numeric_arg(av, 2), 613 numeric_arg(av, 3), 1); 614 } 615 616 static int 617 call_infobox(CALLARGS) 618 { 619 *offset_add = 4; 620 return dialog_msgbox(t, 621 av[1], 622 numeric_arg(av, 2), 623 numeric_arg(av, 3), 0); 624 } 625 626 static int 627 call_textbox(CALLARGS) 628 { 629 *offset_add = 4; 630 return dialog_textbox(t, 631 av[1], 632 numeric_arg(av, 2), 633 numeric_arg(av, 3)); 634 } 635 636 static int 637 call_menu(CALLARGS) 638 { 639 int tags = howmany_tags(av + 5, MENUBOX_TAGS); 640 *offset_add = 5 + tags * MENUBOX_TAGS; 641 642 return dialog_menu(t, 643 av[1], 644 numeric_arg(av, 2), 645 numeric_arg(av, 3), 646 numeric_arg(av, 4), 647 tags, av + 5); 648 } 649 650 static int 651 call_inputmenu(CALLARGS) 652 { 653 int tags = howmany_tags(av + 5, MENUBOX_TAGS); 654 bool free_extra_label = FALSE; 655 int result; 656 657 dialog_vars.input_menu = TRUE; 658 659 if (dialog_vars.max_input == 0) 660 dialog_vars.max_input = MAX_LEN / 2; 661 662 if (dialog_vars.extra_label == 0) { 663 free_extra_label = TRUE; 664 dialog_vars.extra_label = dlg_strclone(_("Rename")); 665 } 666 667 dialog_vars.extra_button = TRUE; 668 669 *offset_add = 5 + tags * MENUBOX_TAGS; 670 result = dialog_menu(t, 671 av[1], 672 numeric_arg(av, 2), 673 numeric_arg(av, 3), 674 numeric_arg(av, 4), 675 tags, av + 5); 676 if (free_extra_label) { 677 free(dialog_vars.extra_label); 678 dialog_vars.extra_label = 0; 679 } 680 return result; 681 } 682 683 static int 684 call_checklist(CALLARGS) 685 { 686 int tags = howmany_tags(av + 5, CHECKBOX_TAGS); 687 int code; 688 bool save_quoted = dialog_vars.quoted; 689 690 dialog_vars.quoted = !dialog_vars.separate_output; 691 *offset_add = 5 + tags * CHECKBOX_TAGS; 692 code = dialog_checklist(t, 693 av[1], 694 numeric_arg(av, 2), 695 numeric_arg(av, 3), 696 numeric_arg(av, 4), 697 tags, av + 5, FLAG_CHECK); 698 dialog_vars.quoted = save_quoted; 699 return code; 700 } 701 702 static int 703 call_radiolist(CALLARGS) 704 { 705 int tags = howmany_tags(av + 5, CHECKBOX_TAGS); 706 *offset_add = 5 + tags * CHECKBOX_TAGS; 707 return dialog_checklist(t, 708 av[1], 709 numeric_arg(av, 2), 710 numeric_arg(av, 3), 711 numeric_arg(av, 4), 712 tags, av + 5, FLAG_RADIO); 713 } 714 715 static int 716 call_inputbox(CALLARGS) 717 { 718 *offset_add = arg_rest(av); 719 return dialog_inputbox(t, 720 av[1], 721 numeric_arg(av, 2), 722 numeric_arg(av, 3), 723 optional_str(av, 4, 0), 0); 724 } 725 726 static int 727 call_passwordbox(CALLARGS) 728 { 729 *offset_add = arg_rest(av); 730 return dialog_inputbox(t, 731 av[1], 732 numeric_arg(av, 2), 733 numeric_arg(av, 3), 734 optional_str(av, 4, 0), 1); 735 } 736 737 #ifdef HAVE_XDIALOG 738 static int 739 call_calendar(CALLARGS) 740 { 741 *offset_add = arg_rest(av); 742 return dialog_calendar(t, 743 av[1], 744 numeric_arg(av, 2), 745 numeric_arg(av, 3), 746 optional_num(av, 4, -1), 747 optional_num(av, 5, -1), 748 optional_num(av, 6, -1)); 749 } 750 751 static int 752 call_dselect(CALLARGS) 753 { 754 *offset_add = arg_rest(av); 755 return dialog_dselect(t, 756 av[1], 757 numeric_arg(av, 2), 758 numeric_arg(av, 3)); 759 } 760 761 static int 762 call_editbox(CALLARGS) 763 { 764 *offset_add = 4; 765 return dialog_editbox(t, 766 av[1], 767 numeric_arg(av, 2), 768 numeric_arg(av, 3)); 769 } 770 771 static int 772 call_fselect(CALLARGS) 773 { 774 *offset_add = arg_rest(av); 775 return dialog_fselect(t, 776 av[1], 777 numeric_arg(av, 2), 778 numeric_arg(av, 3)); 779 } 780 781 static int 782 call_timebox(CALLARGS) 783 { 784 *offset_add = arg_rest(av); 785 return dialog_timebox(t, 786 av[1], 787 numeric_arg(av, 2), 788 numeric_arg(av, 3), 789 optional_num(av, 4, -1), 790 optional_num(av, 5, -1), 791 optional_num(av, 6, -1)); 792 } 793 #endif /* HAVE_XDIALOG */ 794 795 #ifdef HAVE_DLG_FORMBOX 796 static int 797 call_form(CALLARGS) 798 { 799 int group = FORMBOX_TAGS; 800 int tags = howmany_tags(av + 5, group); 801 *offset_add = 5 + tags * group; 802 803 return dialog_form(t, 804 av[1], 805 numeric_arg(av, 2), 806 numeric_arg(av, 3), 807 numeric_arg(av, 4), 808 tags, av + 5); 809 } 810 811 static int 812 call_password_form(CALLARGS) 813 { 814 unsigned save = dialog_vars.formitem_type; 815 int result; 816 817 dialog_vars.formitem_type = 1; 818 result = call_form(PASSARGS); 819 dialog_vars.formitem_type = save; 820 821 return result; 822 } 823 #endif /* HAVE_DLG_FORMBOX */ 824 825 #ifdef HAVE_DLG_MIXEDFORM 826 static int 827 call_mixed_form(CALLARGS) 828 { 829 int group = MIXEDFORM_TAGS; 830 int tags = howmany_tags(av + 5, group); 831 *offset_add = 5 + tags * group; 832 833 return dialog_mixedform(t, 834 av[1], 835 numeric_arg(av, 2), 836 numeric_arg(av, 3), 837 numeric_arg(av, 4), 838 tags, av + 5); 839 } 840 #endif /* HAVE_DLG_MIXEDFORM */ 841 842 #ifdef HAVE_DLG_GAUGE 843 static int 844 call_gauge(CALLARGS) 845 { 846 *offset_add = arg_rest(av); 847 return dialog_gauge(t, 848 av[1], 849 numeric_arg(av, 2), 850 numeric_arg(av, 3), 851 optional_num(av, 4, 0)); 852 } 853 854 static int 855 call_pause(CALLARGS) 856 { 857 *offset_add = arg_rest(av); 858 return dialog_pause(t, 859 av[1], 860 numeric_arg(av, 2), 861 numeric_arg(av, 3), 862 numeric_arg(av, 4)); 863 } 864 #endif 865 866 #ifdef HAVE_MIXEDGAUGE 867 static int 868 call_mixed_gauge(CALLARGS) 869 { 870 #define MIXEDGAUGE_BASE 5 871 int tags = howmany_tags(av + MIXEDGAUGE_BASE, MIXEDGAUGE_TAGS); 872 *offset_add = MIXEDGAUGE_BASE + tags * MIXEDGAUGE_TAGS; 873 return dialog_mixedgauge(t, 874 av[1], 875 numeric_arg(av, 2), 876 numeric_arg(av, 3), 877 numeric_arg(av, 4), 878 tags, av + MIXEDGAUGE_BASE); 879 } 880 #endif 881 882 #ifdef HAVE_DLG_GAUGE 883 static int 884 call_prgbox(CALLARGS) 885 { 886 *offset_add = arg_rest(av); 887 /* the original version does not accept a prompt string, but for 888 * consistency we allow it. 889 */ 890 return ((*offset_add == 5) 891 ? dialog_prgbox(t, 892 av[1], 893 av[2], 894 numeric_arg(av, 3), 895 numeric_arg(av, 4), TRUE) 896 : dialog_prgbox(t, 897 "", 898 av[1], 899 numeric_arg(av, 2), 900 numeric_arg(av, 3), TRUE)); 901 } 902 #endif 903 904 #ifdef HAVE_DLG_GAUGE 905 static int 906 call_programbox(CALLARGS) 907 { 908 int result; 909 910 *offset_add = arg_rest(av); 911 /* this function is a compromise between --prgbox and --progressbox. 912 */ 913 result = ((*offset_add == 4) 914 ? dlg_progressbox(t, 915 av[1], 916 numeric_arg(av, 2), 917 numeric_arg(av, 3), 918 TRUE, 919 dialog_state.pipe_input) 920 : dlg_progressbox(t, 921 "", 922 numeric_arg(av, 1), 923 numeric_arg(av, 2), 924 TRUE, 925 dialog_state.pipe_input)); 926 dialog_state.pipe_input = 0; 927 return result; 928 } 929 #endif 930 931 #ifdef HAVE_DLG_GAUGE 932 static int 933 call_progressbox(CALLARGS) 934 { 935 *offset_add = arg_rest(av); 936 /* the original version does not accept a prompt string, but for 937 * consistency we allow it. 938 */ 939 return ((*offset_add == 4) 940 ? dialog_progressbox(t, 941 av[1], 942 numeric_arg(av, 2), 943 numeric_arg(av, 3)) 944 : dialog_progressbox(t, 945 "", 946 numeric_arg(av, 1), 947 numeric_arg(av, 2))); 948 } 949 #endif 950 951 #ifdef HAVE_DLG_TAILBOX 952 static int 953 call_tailbox(CALLARGS) 954 { 955 *offset_add = 4; 956 return dialog_tailbox(t, 957 av[1], 958 numeric_arg(av, 2), 959 numeric_arg(av, 3), 960 FALSE); 961 } 962 963 static int 964 call_tailboxbg(CALLARGS) 965 { 966 *offset_add = 4; 967 return dialog_tailbox(t, 968 av[1], 969 numeric_arg(av, 2), 970 numeric_arg(av, 3), 971 TRUE); 972 } 973 #endif 974 /* *INDENT-OFF* */ 975 static const Mode modes[] = 976 { 977 {o_yesno, 4, 4, call_yesno}, 978 {o_msgbox, 4, 4, call_msgbox}, 979 {o_infobox, 4, 4, call_infobox}, 980 {o_textbox, 4, 4, call_textbox}, 981 {o_menu, 7, 0, call_menu}, 982 {o_inputmenu, 7, 0, call_inputmenu}, 983 {o_checklist, 8, 0, call_checklist}, 984 {o_radiolist, 8, 0, call_radiolist}, 985 {o_inputbox, 4, 5, call_inputbox}, 986 {o_passwordbox, 4, 5, call_passwordbox}, 987 #ifdef HAVE_DLG_GAUGE 988 {o_gauge, 4, 5, call_gauge}, 989 {o_pause, 5, 5, call_pause}, 990 {o_prgbox, 4, 5, call_prgbox}, 991 {o_programbox, 3, 4, call_programbox}, 992 {o_progressbox, 3, 4, call_progressbox}, 993 #endif 994 #ifdef HAVE_DLG_FORMBOX 995 {o_passwordform, 13, 0, call_password_form}, 996 {o_form, 13, 0, call_form}, 997 #endif 998 #ifdef HAVE_MIXEDGAUGE 999 {o_mixedgauge, MIXEDGAUGE_BASE, 0, call_mixed_gauge}, 1000 #endif 1001 #ifdef HAVE_DLG_MIXEDFORM 1002 {o_mixedform, 13, 0, call_mixed_form}, 1003 #endif 1004 #ifdef HAVE_DLG_TAILBOX 1005 {o_tailbox, 4, 4, call_tailbox}, 1006 {o_tailboxbg, 4, 4, call_tailboxbg}, 1007 #endif 1008 #ifdef HAVE_XDIALOG 1009 {o_calendar, 4, 7, call_calendar}, 1010 {o_dselect, 4, 5, call_dselect}, 1011 {o_editbox, 4, 4, call_editbox}, 1012 {o_fselect, 4, 5, call_fselect}, 1013 {o_timebox, 4, 7, call_timebox}, 1014 #endif 1015 }; 1016 /* *INDENT-ON* */ 1017 1018 static char * 1019 optionString(char **argv, int *num) 1020 { 1021 int next = *num + 1; 1022 char *result = argv[next]; 1023 if (result == 0) { 1024 char temp[80]; 1025 sprintf(temp, "Expected a string-parameter for %.20s", argv[*num]); 1026 Usage(temp); 1027 } 1028 *num = next; 1029 return result; 1030 } 1031 1032 static int 1033 optionValue(char **argv, int *num) 1034 { 1035 int next = *num + 1; 1036 char *src = argv[next]; 1037 char *tmp = 0; 1038 int result = 0; 1039 1040 if (src != 0) { 1041 result = (int) strtol(src, &tmp, 0); 1042 if (tmp == 0 || *tmp != 0) 1043 src = 0; 1044 } 1045 1046 if (src == 0) { 1047 char temp[80]; 1048 sprintf(temp, "Expected a numeric-parameter for %.20s", argv[*num]); 1049 Usage(temp); 1050 } 1051 *num = next; 1052 return result; 1053 } 1054 1055 /* 1056 * Print parts of a message 1057 */ 1058 static void 1059 PrintList(const char *const *list) 1060 { 1061 const char *leaf = strrchr(program, '/'); 1062 unsigned n = 0; 1063 1064 if (leaf != 0) 1065 leaf++; 1066 else 1067 leaf = program; 1068 1069 while (*list != 0) { 1070 fprintf(dialog_state.output, *list, n ? leaf : dialog_version()); 1071 (void) fputc('\n', dialog_state.output); 1072 n = 1; 1073 list++; 1074 } 1075 } 1076 1077 static const Mode * 1078 lookupMode(eOptions code) 1079 { 1080 const Mode *modePtr = 0; 1081 unsigned n; 1082 1083 for (n = 0; n < sizeof(modes) / sizeof(modes[0]); n++) { 1084 if (modes[n].code == code) { 1085 modePtr = &modes[n]; 1086 break; 1087 } 1088 } 1089 return modePtr; 1090 } 1091 1092 static int 1093 compare_opts(const void *a, const void *b) 1094 { 1095 Options *const *p = (Options * const *) a; 1096 Options *const *q = (Options * const *) b; 1097 return strcmp((*p)->name, (*q)->name); 1098 } 1099 1100 /* 1101 * Print program's version. 1102 */ 1103 static void 1104 PrintVersion(FILE *fp) 1105 { 1106 fprintf(fp, "Version: %s\n", dialog_version()); 1107 } 1108 1109 /* 1110 * Print program help-message 1111 */ 1112 static void 1113 Help(void) 1114 { 1115 static const char *const tbl_1[] = 1116 { 1117 "cdialog (ComeOn Dialog!) version %s", 1118 "Copyright 2000-2008,2011 Thomas E. Dickey", 1119 "This is free software; see the source for copying conditions. There is NO", 1120 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.", 1121 "", 1122 "* Display dialog boxes from shell scripts *", 1123 "", 1124 "Usage: %s <options> { --and-widget <options> }", 1125 "where options are \"common\" options, followed by \"box\" options", 1126 "", 1127 #ifdef HAVE_RC_FILE 1128 "Special options:", 1129 " [--create-rc \"file\"]", 1130 #endif 1131 0 1132 }, *const tbl_3[] = 1133 { 1134 "", 1135 "Auto-size with height and width = 0. Maximize with height and width = -1.", 1136 "Global-auto-size if also menu_height/list_height = 0.", 1137 0 1138 }; 1139 size_t limit = sizeof(options) / sizeof(options[0]); 1140 size_t j, k; 1141 const Options **opts; 1142 1143 end_dialog(); 1144 dialog_state.output = stdout; 1145 1146 opts = dlg_calloc(const Options *, limit); 1147 assert_ptr(opts, "Help"); 1148 for (j = 0; j < limit; ++j) { 1149 opts[j] = &(options[j]); 1150 } 1151 qsort(opts, limit, sizeof(Options *), compare_opts); 1152 1153 PrintList(tbl_1); 1154 fprintf(dialog_state.output, "Common options:\n "); 1155 for (j = k = 0; j < limit; j++) { 1156 if ((opts[j]->pass & 1) 1157 && opts[j]->help != 0) { 1158 size_t len = 6 + strlen(opts[j]->name) + strlen(opts[j]->help); 1159 k += len; 1160 if (k > 75) { 1161 fprintf(dialog_state.output, "\n "); 1162 k = len; 1163 } 1164 fprintf(dialog_state.output, " [--%s%s%s]", opts[j]->name, 1165 *(opts[j]->help) ? " " : "", opts[j]->help); 1166 } 1167 } 1168 fprintf(dialog_state.output, "\nBox options:\n"); 1169 for (j = 0; j < limit; j++) { 1170 if ((opts[j]->pass & 2) != 0 1171 && opts[j]->help != 0 1172 && lookupMode(opts[j]->code)) 1173 fprintf(dialog_state.output, " --%-12s %s\n", opts[j]->name, 1174 opts[j]->help); 1175 } 1176 PrintList(tbl_3); 1177 1178 free(opts); 1179 dlg_exit(DLG_EXIT_OK); 1180 } 1181 1182 /* 1183 * "Common" options apply to all widgets more/less. Most of the common options 1184 * set values in dialog_vars, a few set dialog_state and a couple write to the 1185 * output stream. 1186 */ 1187 static int 1188 process_common_options(int argc, char **argv, int offset, bool output) 1189 { 1190 #ifdef HAVE_DLG_TRACE 1191 int n; 1192 #endif 1193 bool done = FALSE; 1194 1195 while (offset < argc && !done) { /* Common options */ 1196 switch (lookupOption(argv[offset], 1)) { 1197 case o_title: 1198 dialog_vars.title = optionString(argv, &offset); 1199 break; 1200 case o_backtitle: 1201 dialog_vars.backtitle = optionString(argv, &offset); 1202 break; 1203 case o_separate_widget: 1204 dialog_state.separate_str = optionString(argv, &offset); 1205 break; 1206 case o_separate_output: 1207 dialog_vars.separate_output = TRUE; 1208 break; 1209 case o_colors: 1210 dialog_vars.colors = TRUE; 1211 break; 1212 case o_cr_wrap: 1213 dialog_vars.cr_wrap = TRUE; 1214 break; 1215 case o_no_nl_expand: 1216 dialog_vars.no_nl_expand = TRUE; 1217 break; 1218 case o_no_collapse: 1219 dialog_vars.nocollapse = TRUE; 1220 break; 1221 case o_no_kill: 1222 dialog_vars.cant_kill = TRUE; 1223 break; 1224 case o_nocancel: 1225 dialog_vars.nocancel = TRUE; 1226 break; 1227 case o_nook: 1228 dialog_vars.nook = TRUE; 1229 break; 1230 case o_quoted: 1231 dialog_vars.quoted = TRUE; 1232 break; 1233 case o_single_quoted: 1234 dialog_vars.single_quoted = TRUE; 1235 break; 1236 case o_size_err: 1237 dialog_vars.size_err = TRUE; 1238 break; 1239 case o_beep: 1240 dialog_vars.beep_signal = TRUE; 1241 break; 1242 case o_beep_after: 1243 dialog_vars.beep_after_signal = TRUE; 1244 break; 1245 case o_scrollbar: 1246 dialog_state.use_scrollbar = TRUE; 1247 break; 1248 case o_shadow: 1249 dialog_state.use_shadow = TRUE; 1250 break; 1251 case o_defaultno: 1252 dialog_vars.defaultno = TRUE; 1253 break; 1254 case o_default_item: 1255 dialog_vars.default_item = optionString(argv, &offset); 1256 break; 1257 case o_insecure: 1258 dialog_vars.insecure = TRUE; 1259 break; 1260 case o_item_help: 1261 dialog_vars.item_help = TRUE; 1262 break; 1263 case o_help_line: 1264 dialog_vars.help_line = optionString(argv, &offset); 1265 break; 1266 case o_help_file: 1267 dialog_vars.help_file = optionString(argv, &offset); 1268 break; 1269 case o_help_button: 1270 dialog_vars.help_button = TRUE; 1271 break; 1272 case o_help_status: 1273 dialog_vars.help_status = TRUE; 1274 break; 1275 case o_extra_button: 1276 dialog_vars.extra_button = TRUE; 1277 break; 1278 case o_ignore: 1279 ignore_unknown = TRUE; 1280 break; 1281 case o_keep_window: 1282 dialog_vars.keep_window = TRUE; 1283 break; 1284 case o_no_shadow: 1285 dialog_state.use_shadow = FALSE; 1286 break; 1287 case o_print_size: 1288 dialog_vars.print_siz = TRUE; 1289 break; 1290 case o_print_maxsize: 1291 if (output) { 1292 /* 1293 * If this is the last option, we do not want any error 1294 * messages - just our output. Calling end_dialog() cancels 1295 * the refresh() at the end of the program as well. 1296 */ 1297 if (argv[offset + 1] == 0) { 1298 ignore_unknown = TRUE; 1299 end_dialog(); 1300 } 1301 fflush(dialog_state.output); 1302 fprintf(dialog_state.output, "MaxSize: %d, %d\n", SLINES, SCOLS); 1303 } 1304 break; 1305 case o_print_version: 1306 if (output) { 1307 PrintVersion(dialog_state.output); 1308 } 1309 break; 1310 case o_separator: 1311 case o_output_separator: 1312 dialog_vars.output_separator = optionString(argv, &offset); 1313 break; 1314 case o_column_separator: 1315 dialog_vars.column_separator = optionString(argv, &offset); 1316 break; 1317 case o_tab_correct: 1318 dialog_vars.tab_correct = TRUE; 1319 break; 1320 case o_sleep: 1321 dialog_vars.sleep_secs = optionValue(argv, &offset); 1322 break; 1323 case o_timeout: 1324 dialog_vars.timeout_secs = optionValue(argv, &offset); 1325 break; 1326 case o_max_input: 1327 dialog_vars.max_input = optionValue(argv, &offset); 1328 break; 1329 case o_tab_len: 1330 dialog_state.tab_len = optionValue(argv, &offset); 1331 break; 1332 case o_trim: 1333 dialog_vars.trim_whitespace = TRUE; 1334 break; 1335 case o_visit_items: 1336 dialog_state.visit_items = TRUE; 1337 break; 1338 case o_aspect: 1339 dialog_state.aspect_ratio = optionValue(argv, &offset); 1340 break; 1341 case o_begin: 1342 dialog_vars.begin_set = TRUE; 1343 dialog_vars.begin_y = optionValue(argv, &offset); 1344 dialog_vars.begin_x = optionValue(argv, &offset); 1345 break; 1346 case o_clear: 1347 dialog_vars.dlg_clear_screen = TRUE; 1348 break; 1349 case o_yes_label: 1350 dialog_vars.yes_label = optionString(argv, &offset); 1351 break; 1352 case o_no_label: 1353 dialog_vars.no_label = optionString(argv, &offset); 1354 break; 1355 case o_ok_label: 1356 dialog_vars.ok_label = optionString(argv, &offset); 1357 break; 1358 case o_cancel_label: 1359 dialog_vars.cancel_label = optionString(argv, &offset); 1360 break; 1361 case o_extra_label: 1362 dialog_vars.extra_label = optionString(argv, &offset); 1363 break; 1364 case o_exit_label: 1365 dialog_vars.exit_label = optionString(argv, &offset); 1366 break; 1367 case o_help_label: 1368 dialog_vars.help_label = optionString(argv, &offset); 1369 break; 1370 case o_date_format: 1371 dialog_vars.date_format = optionString(argv, &offset); 1372 break; 1373 case o_time_format: 1374 dialog_vars.time_format = optionString(argv, &offset); 1375 break; 1376 case o_keep_tite: 1377 dialog_vars.keep_tite = TRUE; 1378 break; 1379 case o_ascii_lines: 1380 dialog_vars.ascii_lines = TRUE; 1381 dialog_vars.no_lines = FALSE; 1382 break; 1383 case o_no_lines: 1384 dialog_vars.no_lines = TRUE; 1385 dialog_vars.ascii_lines = FALSE; 1386 break; 1387 case o_no_mouse: 1388 dialog_state.no_mouse = TRUE; 1389 mouse_close(); 1390 break; 1391 case o_noitem: 1392 case o_fullbutton: 1393 /* ignore */ 1394 break; 1395 /* options of Xdialog which we ignore */ 1396 case o_icon: 1397 case o_wmclass: 1398 (void) optionString(argv, &offset); 1399 /* FALLTHRU */ 1400 case o_allow_close: 1401 case o_auto_placement: 1402 case o_fixed_font: 1403 case o_keep_colors: 1404 case o_no_close: 1405 case o_no_cr_wrap: 1406 case o_screen_center: 1407 case o_smooth: 1408 case o_under_mouse: 1409 break; 1410 case o_unknown: 1411 if (ignore_unknown) 1412 break; 1413 /* FALLTHRU */ 1414 default: /* no more common options */ 1415 done = TRUE; 1416 break; 1417 #ifdef HAVE_DLG_TRACE 1418 case o_trace: 1419 dlg_trace(optionString(argv, &offset)); 1420 for (n = 0; argv[n] != 0; ++n) { 1421 dlg_trace_msg("argv[%d] = %s\n", n, argv[n]); 1422 } 1423 break; 1424 #endif 1425 } 1426 if (!done) 1427 offset++; 1428 } 1429 return offset; 1430 } 1431 1432 /* 1433 * Initialize options at the start of a series of common options culminating 1434 * in a widget. 1435 */ 1436 static void 1437 init_result(char *buffer) 1438 { 1439 static bool first = TRUE; 1440 static char **special_argv = 0; 1441 static int special_argc = 0; 1442 1443 /* clear everything we do not save for the next widget */ 1444 memset(&dialog_vars, 0, sizeof(dialog_vars)); 1445 1446 dialog_vars.input_result = buffer; 1447 dialog_vars.input_result[0] = '\0'; 1448 1449 /* 1450 * The first time this is called, check for common options given by an 1451 * environment variable. 1452 */ 1453 if (first) { 1454 char *env = getenv("DIALOGOPTS"); 1455 if (env != 0) 1456 env = dlg_strclone(env); 1457 if (env != 0) { 1458 special_argv = dlg_string_to_argv(env); 1459 special_argc = dlg_count_argv(special_argv); 1460 } 1461 } 1462 if (special_argv != 0) { 1463 process_common_options(special_argc, special_argv, 0, FALSE); 1464 #ifdef NO_LEAKS 1465 free(special_argv[0]); 1466 free(special_argv); 1467 first = TRUE; 1468 #endif 1469 } 1470 } 1471 1472 int 1473 main(int argc, char *argv[]) 1474 { 1475 char temp[256]; 1476 bool esc_pressed = FALSE; 1477 bool keep_tite = FALSE; 1478 int offset = 1; 1479 int offset_add; 1480 int retval = DLG_EXIT_OK; 1481 int j, have; 1482 eOptions code; 1483 const Mode *modePtr; 1484 char my_buffer[MAX_LEN + 1]; 1485 1486 memset(&dialog_state, 0, sizeof(dialog_state)); 1487 memset(&dialog_vars, 0, sizeof(dialog_vars)); 1488 1489 #if defined(ENABLE_NLS) 1490 /* initialize locale support */ 1491 setlocale(LC_ALL, ""); 1492 bindtextdomain(NLS_TEXTDOMAIN, LOCALEDIR); 1493 textdomain(NLS_TEXTDOMAIN); 1494 #elif defined(HAVE_SETLOCALE) 1495 (void) setlocale(LC_ALL, ""); 1496 #endif 1497 1498 unescape_argv(&argc, &argv); 1499 program = argv[0]; 1500 dialog_state.output = stderr; 1501 dialog_state.input = stdin; 1502 1503 /* 1504 * Look for the last --stdout, --stderr or --output-fd option, and use 1505 * that. We can only write to one of them. If --stdout is used, that 1506 * can interfere with initializing the curses library, so we want to 1507 * know explicitly if it is used. 1508 * 1509 * Also, look for any --version or --help message, processing those 1510 * immediately. 1511 */ 1512 while (offset < argc) { 1513 int base = offset; 1514 switch (lookupOption(argv[offset], 7)) { 1515 case o_stdout: 1516 dialog_state.output = stdout; 1517 break; 1518 case o_stderr: 1519 dialog_state.output = stderr; 1520 break; 1521 case o_input_fd: 1522 if ((j = optionValue(argv, &offset)) < 0 1523 || (dialog_state.input = fdopen(j, "r")) == 0) 1524 dlg_exiterr("Cannot open input-fd\n"); 1525 break; 1526 case o_output_fd: 1527 if ((j = optionValue(argv, &offset)) < 0 1528 || (dialog_state.output = fdopen(j, "w")) == 0) 1529 dlg_exiterr("Cannot open output-fd\n"); 1530 break; 1531 case o_keep_tite: 1532 keep_tite = TRUE; 1533 break; 1534 case o_version: 1535 dialog_state.output = stdout; 1536 PrintVersion(dialog_state.output); 1537 exit(DLG_EXIT_OK); 1538 break; 1539 case o_help: 1540 Help(); 1541 break; 1542 default: 1543 ++offset; 1544 continue; 1545 } 1546 for (j = base; j < argc; ++j) { 1547 dialog_argv[j] = dialog_argv[j + 1 + (offset - base)]; 1548 if (dialog_opts != 0) 1549 dialog_opts[j] = dialog_opts[j + 1 + (offset - base)]; 1550 } 1551 argc -= (1 + offset - base); 1552 offset = base; 1553 } 1554 offset = 1; 1555 init_result(my_buffer); 1556 1557 /* 1558 * Dialog's output may be redirected (see above). Handle the special 1559 * case of options that only report information without interaction. 1560 */ 1561 if (argc == 2) { 1562 switch (lookupOption(argv[1], 7)) { 1563 case o_print_maxsize: 1564 (void) initscr(); 1565 endwin(); 1566 fflush(dialog_state.output); 1567 fprintf(dialog_state.output, "MaxSize: %d, %d\n", SLINES, SCOLS); 1568 break; 1569 case o_print_version: 1570 PrintVersion(dialog_state.output); 1571 break; 1572 case o_clear: 1573 initscr(); 1574 refresh(); 1575 endwin(); 1576 break; 1577 case o_ignore: 1578 break; 1579 default: 1580 Help(); 1581 break; 1582 } 1583 return DLG_EXIT_OK; 1584 } 1585 1586 if (argc < 2) { 1587 Help(); 1588 } 1589 #ifdef HAVE_RC_FILE 1590 if (lookupOption(argv[1], 7) == o_create_rc) { 1591 if (argc != 3) { 1592 sprintf(temp, "Expected a filename for %.50s", argv[1]); 1593 Usage(temp); 1594 } 1595 if (dlg_parse_rc() == -1) /* Read the configuration file */ 1596 dlg_exiterr("dialog: dlg_parse_rc"); 1597 dlg_create_rc(argv[2]); 1598 return DLG_EXIT_OK; 1599 } 1600 #endif 1601 1602 dialog_vars.keep_tite = keep_tite; /* init_result() cleared global */ 1603 1604 init_dialog(dialog_state.input, dialog_state.output); 1605 1606 while (offset < argc && !esc_pressed) { 1607 init_result(my_buffer); 1608 1609 offset = process_common_options(argc, argv, offset, TRUE); 1610 1611 if (argv[offset] == NULL) { 1612 if (ignore_unknown) 1613 break; 1614 Usage("Expected a box option"); 1615 } 1616 1617 if (lookupOption(argv[offset], 2) != o_checklist 1618 && dialog_vars.separate_output) { 1619 sprintf(temp, "Expected --checklist, not %.20s", argv[offset]); 1620 Usage(temp); 1621 } 1622 1623 if (dialog_state.aspect_ratio == 0) 1624 dialog_state.aspect_ratio = DEFAULT_ASPECT_RATIO; 1625 1626 dlg_put_backtitle(); 1627 1628 /* use a table to look for the requested mode, to avoid code duplication */ 1629 1630 modePtr = 0; 1631 if ((code = lookupOption(argv[offset], 2)) != o_unknown) 1632 modePtr = lookupMode(code); 1633 if (modePtr == 0) { 1634 sprintf(temp, "%s option %.20s", 1635 lookupOption(argv[offset], 7) != o_unknown 1636 ? "Unexpected" 1637 : "Unknown", 1638 argv[offset]); 1639 Usage(temp); 1640 } 1641 1642 have = arg_rest(&argv[offset]); 1643 if (have < modePtr->argmin) { 1644 sprintf(temp, "Expected at least %d tokens for %.20s, have %d", 1645 modePtr->argmin - 1, argv[offset], 1646 have - 1); 1647 Usage(temp); 1648 } 1649 if (modePtr->argmax && have > modePtr->argmax) { 1650 sprintf(temp, 1651 "Expected no more than %d tokens for %.20s, have %d", 1652 modePtr->argmax - 1, argv[offset], 1653 have - 1); 1654 Usage(temp); 1655 } 1656 1657 /* 1658 * Trim whitespace from non-title option values, e.g., the ones that 1659 * will be used as captions or prompts. Do that only for the widget 1660 * we are about to process, since the "--trim" option is reset before 1661 * accumulating options for each widget. 1662 */ 1663 for (j = offset + 1; j <= offset + have; j++) { 1664 switch (lookupOption(argv[j - 1], 7)) { 1665 case o_unknown: 1666 case o_title: 1667 case o_backtitle: 1668 case o_help_line: 1669 case o_help_file: 1670 break; 1671 default: 1672 if (argv[j] != 0) { 1673 dlg_trim_string(argv[j]); 1674 } 1675 break; 1676 } 1677 } 1678 1679 retval = show_result((*(modePtr->jumper)) (dialog_vars.title, 1680 argv + offset, 1681 &offset_add)); 1682 offset += offset_add; 1683 1684 if (dialog_vars.input_result != my_buffer) { 1685 free(dialog_vars.input_result); 1686 dialog_vars.input_result = 0; 1687 } 1688 1689 if (retval == DLG_EXIT_ESC) { 1690 esc_pressed = TRUE; 1691 } else { 1692 1693 if (dialog_vars.beep_after_signal) 1694 (void) beep(); 1695 1696 if (dialog_vars.sleep_secs) 1697 (void) napms(dialog_vars.sleep_secs * 1000); 1698 1699 if (offset < argc) { 1700 switch (lookupOption(argv[offset], 7)) { 1701 case o_and_widget: 1702 offset++; 1703 break; 1704 case o_unknown: 1705 sprintf(temp, "Expected --and-widget, not %.20s", 1706 argv[offset]); 1707 Usage(temp); 1708 break; 1709 default: 1710 /* if we got a cancel, etc., stop chaining */ 1711 if (retval != DLG_EXIT_OK) 1712 esc_pressed = TRUE; 1713 else 1714 dialog_vars.dlg_clear_screen = TRUE; 1715 break; 1716 } 1717 } 1718 if (dialog_vars.dlg_clear_screen) 1719 dlg_clear(); 1720 } 1721 } 1722 1723 dlg_killall_bg(&retval); 1724 if (dialog_state.screen_initialized) { 1725 (void) refresh(); 1726 end_dialog(); 1727 } 1728 dlg_exit(retval); 1729 } 1730