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