1 /* 2 * Copyright (C) 1984-2026 Mark Nudelman 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Less License, as specified in the README file. 6 * 7 * For more information, see the README file. 8 */ 9 10 11 /* 12 * Handling functions for command line options. 13 * 14 * Most options are handled by the generic code in option.c. 15 * But all string options, and a few non-string options, require 16 * special handling specific to the particular option. 17 * This special processing is done by the "handling functions" in this file. 18 * 19 * Each handling function is passed a "type" and, if it is a string 20 * option, the string which should be "assigned" to the option. 21 * The type may be one of: 22 * INIT The option is being initialized from the command line. 23 * TOGGLE The option is being changed from within the program. 24 * QUERY The setting of the option is merely being queried. 25 */ 26 27 #include "less.h" 28 #include "option.h" 29 #include "position.h" 30 31 extern int bufspace; 32 extern int pr_type; 33 extern lbool plusoption; 34 extern int swindow; 35 extern int sc_width; 36 extern int sc_height; 37 extern int dohelp; 38 extern char openquote; 39 extern char closequote; 40 extern char *prproto[]; 41 extern char *eqproto; 42 extern char *hproto; 43 extern char *wproto; 44 extern char *every_first_cmd; 45 extern IFILE curr_ifile; 46 extern char version[]; 47 extern int jump_sline_arg; 48 extern int jump_sline; 49 extern long jump_sline_fraction; 50 extern int shift_count; 51 extern long shift_count_fraction; 52 extern int match_shift; 53 extern long match_shift_fraction; 54 extern LWCHAR rscroll_char; 55 extern int rscroll_attr; 56 extern int mousecap; 57 extern int wheel_lines; 58 extern int less_is_more; 59 extern int linenum_width; 60 extern int status_col_width; 61 extern int use_color; 62 extern int want_filesize; 63 extern int header_lines; 64 extern int header_cols; 65 extern int def_search_type; 66 extern int chopline; 67 extern int tabstops[]; 68 extern int ntabstops; 69 extern int tabdefault; 70 extern int no_paste; 71 extern char intr_char; 72 extern int nosearch_header_lines; 73 extern int nosearch_header_cols; 74 extern POSITION header_start_pos; 75 extern char *init_header; 76 extern char *first_cmd_at_prompt; 77 extern char *autosave; 78 #if LOGFILE 79 extern char *namelogfile; 80 extern lbool force_logfile; 81 extern int logfile; 82 #endif 83 #if TAGS 84 public char *tagoption = NULL; 85 extern char *tags; 86 extern char ztags[]; 87 #endif 88 #if LESSTEST 89 extern constant char *ttyin_name; 90 extern int is_tty; 91 #endif /*LESSTEST*/ 92 #if MSDOS_COMPILER 93 extern int nm_fg_color, nm_bg_color, nm_attr; 94 extern int bo_fg_color, bo_bg_color, bo_attr; 95 extern int ul_fg_color, ul_bg_color, ul_attr; 96 extern int so_fg_color, so_bg_color, so_attr; 97 extern int bl_fg_color, bl_bg_color, bl_attr; 98 extern int sgr_mode; 99 #if MSDOS_COMPILER==WIN32C 100 #ifndef COMMON_LVB_UNDERSCORE 101 #define COMMON_LVB_UNDERSCORE 0x8000 102 #endif 103 #ifndef COMMON_LVB_REVERSE_VIDEO 104 #define COMMON_LVB_REVERSE_VIDEO 0x4000 105 #endif 106 #endif 107 #endif 108 109 110 #if LOGFILE 111 /* 112 * Handler for -o option. 113 */ 114 public void opt_o(int type, constant char *s) 115 { 116 PARG parg; 117 char *filename; 118 119 if (!secure_allow(SF_LOGFILE)) 120 { 121 error("log file support is not available", NULL_PARG); 122 return; 123 } 124 switch (type) 125 { 126 case INIT: 127 namelogfile = save(s); 128 break; 129 case TOGGLE: 130 if (ch_getflags() & CH_CANSEEK) 131 { 132 error("Input is not a pipe", NULL_PARG); 133 return; 134 } 135 if (logfile >= 0) 136 { 137 error("Log file is already in use", NULL_PARG); 138 return; 139 } 140 s = skipspc(s); 141 if (namelogfile != NULL) 142 free(namelogfile); 143 filename = lglob(s); 144 namelogfile = shell_unquote(filename); 145 free(filename); 146 use_logfile(namelogfile); 147 sync_logfile(); 148 break; 149 case QUERY: 150 if (logfile < 0) 151 error("No log file", NULL_PARG); 152 else 153 { 154 parg.p_string = namelogfile; 155 error("Log file \"%s\"", &parg); 156 } 157 break; 158 } 159 } 160 161 /* 162 * Handler for -O option. 163 */ 164 public void opt__O(int type, constant char *s) 165 { 166 force_logfile = TRUE; 167 opt_o(type, s); 168 } 169 #endif 170 171 static void toggle_fraction(int *num, long *frac, constant char *s, constant char *printopt, lbool neg_ok, void (*calc)(void)) 172 { 173 if (s == NULL) 174 { 175 } else if (*s == '.') 176 { 177 s++; 178 if (!getfraction(&s, frac)) 179 { 180 PARG parg; 181 parg.p_string = printopt; 182 error("Invalid fraction in %s", &parg); 183 return; 184 } 185 } else 186 { 187 if (!getnumc(&s, printopt, neg_ok, num)) 188 return; 189 *frac = -1; 190 } 191 (*calc)(); 192 } 193 194 static void query_fraction(int value, long fraction, constant char *int_msg, constant char *frac_msg) 195 { 196 PARG parg; 197 198 if (fraction < 0) 199 { 200 parg.p_int = value; 201 error(int_msg, &parg); 202 } else 203 { 204 char buf[INT_STRLEN_BOUND(long)+2]; 205 size_t len; 206 SNPRINTF1(buf, sizeof(buf), ".%06ld", fraction); 207 len = strlen(buf); 208 while (len > 2 && buf[len-1] == '0') 209 len--; 210 buf[len] = '\0'; 211 parg.p_string = buf; 212 error(frac_msg, &parg); 213 } 214 } 215 216 /* 217 * Handlers for -j option. 218 */ 219 public void opt_j(int type, constant char *s) 220 { 221 switch (type) 222 { 223 case INIT: 224 case TOGGLE: 225 toggle_fraction(&jump_sline_arg, &jump_sline_fraction, 226 s, "-j", TRUE, calc_jump_sline); 227 break; 228 case QUERY: 229 query_fraction(jump_sline_arg, jump_sline_fraction, 230 "Position target at screen line %d", "Position target at screen position %s"); 231 break; 232 } 233 } 234 235 public void calc_jump_sline(void) 236 { 237 jump_sline = jump_sline_arg; 238 /* If jump_sline_fraction is set, calculate jump_sline from it. */ 239 if (jump_sline_fraction >= 0) 240 jump_sline = (int) muldiv(sc_height, jump_sline_fraction, NUM_FRAC_DENOM); 241 /* Negative jump_sline means relative to bottom of screen. */ 242 if (jump_sline < 0) 243 jump_sline += sc_height; 244 /* If jump_sline is obscured by header, move it after the header. */ 245 if (jump_sline <= header_lines) 246 jump_sline = header_lines + 1; 247 /* If jump_sline is past bottom of screen, move it to the bottom. */ 248 if (jump_sline >= sc_height) 249 jump_sline = sc_height - 1; 250 } 251 252 /* 253 * Handlers for -# option. 254 */ 255 public void opt_shift(int type, constant char *s) 256 { 257 switch (type) 258 { 259 case INIT: 260 case TOGGLE: 261 toggle_fraction(&shift_count, &shift_count_fraction, 262 s, "-#", FALSE, calc_shift_count); 263 break; 264 case QUERY: 265 query_fraction(shift_count, shift_count_fraction, 266 "Horizontal shift %d columns", "Horizontal shift %s of screen width"); 267 break; 268 } 269 } 270 271 public void calc_shift_count(void) 272 { 273 if (shift_count_fraction < 0) 274 return; 275 shift_count = (int) muldiv(sc_width, shift_count_fraction, NUM_FRAC_DENOM); 276 } 277 278 #if USERFILE 279 public void opt_k(int type, constant char *s) 280 { 281 PARG parg; 282 283 switch (type) 284 { 285 case INIT: 286 if (lesskey(s, 0)) 287 { 288 parg.p_string = s; 289 error("Cannot use lesskey file \"%s\"", &parg); 290 } 291 break; 292 } 293 } 294 295 #if HAVE_LESSKEYSRC 296 public void opt_ks(int type, constant char *s) 297 { 298 PARG parg; 299 300 switch (type) 301 { 302 case INIT: 303 if (lesskey_src(s, 0)) 304 { 305 parg.p_string = s; 306 error("Cannot use lesskey source file \"%s\"", &parg); 307 } 308 break; 309 } 310 } 311 312 public void opt_kc(int type, constant char *s) 313 { 314 switch (type) 315 { 316 case INIT: 317 if (lesskey_content(s, 0)) 318 { 319 error("Error in lesskey content", NULL_PARG); 320 } 321 break; 322 } 323 } 324 325 #endif /* HAVE_LESSKEYSRC */ 326 #endif /* USERFILE */ 327 328 /* 329 * Handler for -S option. 330 */ 331 public void opt__S(int type, constant char *s) 332 { 333 switch (type) 334 { 335 case TOGGLE: 336 pos_rehead(); 337 break; 338 } 339 } 340 341 #if TAGS 342 /* 343 * Handler for -t option. 344 */ 345 public void opt_t(int type, constant char *s) 346 { 347 IFILE save_ifile; 348 POSITION pos; 349 350 switch (type) 351 { 352 case INIT: 353 tagoption = save(s); 354 /* Do the rest in main() */ 355 break; 356 case TOGGLE: 357 if (!secure_allow(SF_TAGS)) 358 { 359 error("tags support is not available", NULL_PARG); 360 break; 361 } 362 findtag(skipspc(s)); 363 save_ifile = save_curr_ifile(); 364 /* 365 * Try to open the file containing the tag 366 * and search for the tag in that file. 367 */ 368 if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION) 369 { 370 /* Failed: reopen the old file. */ 371 reedit_ifile(save_ifile); 372 break; 373 } 374 unsave_ifile(save_ifile); 375 jump_loc(pos, jump_sline); 376 break; 377 } 378 } 379 380 /* 381 * Handler for -T option. 382 */ 383 public void opt__T(int type, constant char *s) 384 { 385 PARG parg; 386 char *filename; 387 388 switch (type) 389 { 390 case INIT: 391 tags = save(s); 392 break; 393 case TOGGLE: 394 s = skipspc(s); 395 if (tags != NULL && tags != ztags) 396 free(tags); 397 filename = lglob(s); 398 tags = shell_unquote(filename); 399 free(filename); 400 break; 401 case QUERY: 402 parg.p_string = tags; 403 error("Tags file \"%s\"", &parg); 404 break; 405 } 406 } 407 #endif 408 409 /* 410 * Handler for -p option. 411 */ 412 public void opt_p(int type, constant char *s) 413 { 414 switch (type) 415 { 416 case INIT: 417 /* 418 * Unget a command for the specified string. 419 */ 420 if (less_is_more) 421 { 422 /* 423 * In "more" mode, the -p argument is a command, 424 * not a search string, so we don't need a slash. 425 */ 426 every_first_cmd = save(s); 427 } else 428 { 429 plusoption = TRUE; 430 /* 431 * {{ This won't work if the "/" command is 432 * changed or invalidated by a .lesskey file. }} 433 */ 434 ungetsc("/"); 435 ungetsc(s); 436 ungetcc_end_command(); 437 } 438 break; 439 } 440 } 441 442 /* 443 * Handler for -P option. 444 */ 445 public void opt__P(int type, constant char *s) 446 { 447 char **proto; 448 PARG parg; 449 450 switch (type) 451 { 452 case INIT: 453 case TOGGLE: 454 /* 455 * Figure out which prototype string should be changed. 456 */ 457 switch (*s) 458 { 459 case 's': proto = &prproto[PR_SHORT]; s++; break; 460 case 'm': proto = &prproto[PR_MEDIUM]; s++; break; 461 case 'M': proto = &prproto[PR_LONG]; s++; break; 462 case '=': proto = &eqproto; s++; break; 463 case 'h': proto = &hproto; s++; break; 464 case 'w': proto = &wproto; s++; break; 465 default: proto = &prproto[PR_SHORT]; break; 466 } 467 free(*proto); 468 *proto = save(s); 469 break; 470 case QUERY: 471 parg.p_string = prproto[pr_type]; 472 error("%s", &parg); 473 break; 474 } 475 } 476 477 /* 478 * Handler for --autosave option. 479 */ 480 public void opt_autosave(int type, constant char *s) 481 { 482 PARG parg; 483 484 switch (type) 485 { 486 case INIT: 487 case TOGGLE: 488 if (s == NULL) 489 s = "-"; 490 if (autosave != NULL) 491 free(autosave); 492 autosave = save(s); 493 break; 494 case QUERY: 495 parg.p_string = (autosave != NULL) ? autosave : "-"; 496 error("Autosave actions: %s", &parg); 497 break; 498 } 499 } 500 501 /* 502 * Handler for the -b option. 503 */ 504 /*ARGSUSED*/ 505 public void opt_b(int type, constant char *s) 506 { 507 switch (type) 508 { 509 case INIT: 510 case TOGGLE: 511 /* 512 * Set the new number of buffers. 513 */ 514 ch_setbufspace((ssize_t) bufspace); 515 break; 516 case QUERY: 517 break; 518 } 519 } 520 521 /* 522 * Handler for the -i option. 523 */ 524 /*ARGSUSED*/ 525 public void opt_i(int type, constant char *s) 526 { 527 switch (type) 528 { 529 case TOGGLE: 530 chg_caseless(); 531 break; 532 case QUERY: 533 case INIT: 534 break; 535 } 536 } 537 538 /* 539 * Handler for the -V option. 540 */ 541 /*ARGSUSED*/ 542 public void opt__V(int type, constant char *s) 543 { 544 switch (type) 545 { 546 case TOGGLE: 547 case QUERY: 548 dispversion(); 549 break; 550 case INIT: 551 set_output(1, TRUE); /* Force output to stdout per GNU standard for --version output. */ 552 putstr("less "); 553 putstr(version); 554 putstr(" ("); 555 putstr(pattern_lib_name()); 556 putstr(" regular expressions)\n"); 557 { 558 char constant *copyright = 559 "Copyright (C) 1984-2026 Mark Nudelman\n\n"; 560 putstr(copyright); 561 } 562 if (version[strlen(version)-1] == 'x') 563 { 564 putstr("** This is an EXPERIMENTAL build of the 'less' software,\n"); 565 putstr("** and may not function correctly.\n"); 566 putstr("** Obtain release builds from the web page below.\n\n"); 567 } 568 #if LESSTEST 569 putstr("This build supports LESSTEST.\n"); 570 #endif /*LESSTEST*/ 571 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n"); 572 putstr("For information about the terms of redistribution,\n"); 573 putstr("see the file named README in the less distribution.\n"); 574 putstr("Home page: https://greenwoodsoftware.com/less\n"); 575 quit(QUIT_OK); 576 break; 577 } 578 } 579 580 #if MSDOS_COMPILER 581 /* 582 * Parse an MSDOS color descriptor. 583 */ 584 static void colordesc(constant char *s, int *fg_color, int *bg_color, int *dattr) 585 { 586 int fg, bg; 587 CHAR_ATTR attr; 588 if (parse_color(s, &fg, &bg, &attr) == CT_NULL) 589 { 590 PARG p; 591 p.p_string = s; 592 error("Invalid color string \"%s\"", &p); 593 } else 594 { 595 *fg_color = fg; 596 *bg_color = bg; 597 *dattr = 0; 598 #if MSDOS_COMPILER==WIN32C 599 if (attr & CATTR_UNDERLINE) 600 *dattr |= COMMON_LVB_UNDERSCORE; 601 if (attr & CATTR_STANDOUT) 602 *dattr |= COMMON_LVB_REVERSE_VIDEO; 603 #endif 604 } 605 } 606 #endif 607 608 static int color_from_namechar(char namechar) 609 { 610 switch (namechar) 611 { 612 case 'B': return AT_COLOR_BIN; 613 case 'C': return AT_COLOR_CTRL; 614 case 'E': return AT_COLOR_ERROR; 615 case 'H': return AT_COLOR_HEADER; 616 case 'M': return AT_COLOR_MARK; 617 case 'N': return AT_COLOR_LINENUM; 618 case 'P': return AT_COLOR_PROMPT; 619 case 'R': return AT_COLOR_RSCROLL; 620 case 'S': return AT_COLOR_SEARCH; 621 case 'W': case 'A': return AT_COLOR_ATTN; 622 case 'n': return AT_NORMAL; 623 case 's': return AT_STANDOUT; 624 case 'd': return AT_BOLD; 625 case 'u': return AT_UNDERLINE; 626 case 'k': return AT_BLINK; 627 default: 628 if (namechar >= '1' && namechar <= '0'+NUM_SEARCH_COLORS) 629 return AT_COLOR_SUBSEARCH(namechar-'0'); 630 return -1; 631 } 632 } 633 634 /* 635 * Handler for the -D option. 636 */ 637 /*ARGSUSED*/ 638 public void opt_D(int type, constant char *s) 639 { 640 PARG p; 641 int attr; 642 643 switch (type) 644 { 645 case INIT: 646 case TOGGLE: 647 #if MSDOS_COMPILER 648 if (*s == 'a') 649 { 650 sgr_mode = !sgr_mode; 651 break; 652 } 653 #endif 654 attr = color_from_namechar(s[0]); 655 if (attr < 0) 656 { 657 p.p_char = s[0]; 658 error("Invalid color specifier '%c'", &p); 659 return; 660 } 661 if (!use_color && (attr & AT_COLOR)) 662 { 663 error("Set --use-color before changing colors", NULL_PARG); 664 return; 665 } 666 s++; 667 #if MSDOS_COMPILER 668 if (!(attr & AT_COLOR)) 669 { 670 switch (attr) 671 { 672 case AT_NORMAL: 673 colordesc(s, &nm_fg_color, &nm_bg_color, &nm_attr); 674 break; 675 case AT_BOLD: 676 colordesc(s, &bo_fg_color, &bo_bg_color, &bo_attr); 677 break; 678 case AT_UNDERLINE: 679 colordesc(s, &ul_fg_color, &ul_bg_color, &ul_attr); 680 break; 681 case AT_BLINK: 682 colordesc(s, &bl_fg_color, &bl_bg_color, &bl_attr); 683 break; 684 case AT_STANDOUT: 685 colordesc(s, &so_fg_color, &so_bg_color, &so_attr); 686 break; 687 } 688 if (type == TOGGLE) 689 { 690 init_win_colors(); 691 at_enter(AT_STANDOUT); 692 at_exit(); 693 } 694 } else 695 #endif 696 if (set_color_map(attr, s) < 0) 697 { 698 p.p_string = s; 699 error("Invalid color string \"%s\"", &p); 700 return; 701 } 702 break; 703 #if MSDOS_COMPILER 704 case QUERY: 705 p.p_string = (sgr_mode) ? "on" : "off"; 706 error("SGR mode is %s", &p); 707 break; 708 #endif 709 } 710 } 711 712 /* 713 */ 714 public void set_tabs(constant char *s, size_t len) 715 { 716 int i; 717 constant char *es = s + len; 718 /* Start at 1 because tabstops[0] is always zero. */ 719 for (i = 1; i < TABSTOP_MAX; ) 720 { 721 int n = 0; 722 lbool v = FALSE; 723 while (s < es && *s == ' ') 724 s++; 725 for (; s < es && *s >= '0' && *s <= '9'; s++) 726 { 727 v = v || ckd_mul(&n, n, 10); 728 v = v || ckd_add(&n, n, *s - '0'); 729 } 730 if (!v && n > tabstops[i-1]) 731 tabstops[i++] = n; 732 while (s < es && *s == ' ') 733 s++; 734 if (s == es || *s++ != ',') 735 break; 736 } 737 if (i < 2) 738 return; 739 ntabstops = i; 740 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2]; 741 } 742 743 /* 744 * Handler for the -x option. 745 */ 746 public void opt_x(int type, constant char *s) 747 { 748 char msg[60+((INT_STRLEN_BOUND(int)+1)*TABSTOP_MAX)]; 749 int i; 750 PARG p; 751 752 switch (type) 753 { 754 case INIT: 755 case TOGGLE: 756 set_tabs(s, strlen(s)); 757 break; 758 case QUERY: 759 strcpy(msg, "Tab stops "); 760 if (ntabstops > 2) 761 { 762 for (i = 1; i < ntabstops; i++) 763 { 764 if (i > 1) 765 strcat(msg, ","); 766 sprintf(msg+strlen(msg), "%d", tabstops[i]); 767 } 768 sprintf(msg+strlen(msg), " and then "); 769 } 770 sprintf(msg+strlen(msg), "every %d spaces", 771 tabdefault); 772 p.p_string = msg; 773 error("%s", &p); 774 break; 775 } 776 } 777 778 779 /* 780 * Handler for the -" option. 781 */ 782 public void opt_quote(int type, constant char *s) 783 { 784 char buf[3]; 785 PARG parg; 786 787 switch (type) 788 { 789 case INIT: 790 case TOGGLE: 791 if (s[0] == '\0') 792 { 793 openquote = closequote = '\0'; 794 break; 795 } 796 if (s[1] != '\0' && s[2] != '\0') 797 { 798 error("-\" must be followed by 1 or 2 chars", NULL_PARG); 799 return; 800 } 801 openquote = s[0]; 802 if (s[1] == '\0') 803 closequote = openquote; 804 else 805 closequote = s[1]; 806 break; 807 case QUERY: 808 buf[0] = openquote; 809 buf[1] = closequote; 810 buf[2] = '\0'; 811 parg.p_string = buf; 812 error("quotes %s", &parg); 813 break; 814 } 815 } 816 817 /* 818 * Handler for the --rscroll option. 819 */ 820 /*ARGSUSED*/ 821 public void opt_rscroll(int type, constant char *s) 822 { 823 PARG p; 824 825 switch (type) 826 { 827 case INIT: 828 case TOGGLE: { 829 constant char *fmt; 830 int attr = AT_STANDOUT; 831 setfmt(s, &fmt, &attr, "*s>", FALSE); 832 if (strcmp(fmt, "-") == 0) 833 { 834 rscroll_char = 0; 835 } else 836 { 837 rscroll_attr = attr|AT_COLOR_RSCROLL; 838 if (*fmt == '\0') 839 rscroll_char = '>'; 840 else 841 { 842 LWCHAR ch = step_charc(&fmt, +1, fmt+strlen(fmt)); 843 if (pwidth(ch, rscroll_attr, 0, 0) > 1) 844 error("cannot set rscroll to a wide character", NULL_PARG); 845 else 846 rscroll_char = ch; 847 } 848 } 849 break; } 850 case QUERY: { 851 p.p_string = rscroll_char ? prchar((LWCHAR) rscroll_char) : "-"; 852 error("rscroll character is %s", &p); 853 break; } 854 } 855 } 856 857 /* 858 * "-?" means display a help message. 859 * If from the command line, exit immediately. 860 */ 861 /*ARGSUSED*/ 862 public void opt_query(int type, constant char *s) 863 { 864 switch (type) 865 { 866 case QUERY: 867 case TOGGLE: 868 error("Use \"h\" for help", NULL_PARG); 869 break; 870 case INIT: 871 dohelp = 1; 872 } 873 } 874 875 /*ARGSUSED*/ 876 public void opt_match_shift(int type, constant char *s) 877 { 878 switch (type) 879 { 880 case INIT: 881 case TOGGLE: 882 toggle_fraction(&match_shift, &match_shift_fraction, 883 s, "--match-shift", FALSE, calc_match_shift); 884 break; 885 case QUERY: 886 query_fraction(match_shift, match_shift_fraction, 887 "Search match shift is %d", "Search match shift is %s of screen width"); 888 break; 889 } 890 } 891 892 public void calc_match_shift(void) 893 { 894 if (match_shift_fraction < 0) 895 return; 896 match_shift = (int) muldiv(sc_width, match_shift_fraction, NUM_FRAC_DENOM); 897 } 898 899 /* 900 * Handler for the --mouse option. 901 */ 902 /*ARGSUSED*/ 903 public void opt_mousecap(int type, constant char *s) 904 { 905 switch (type) 906 { 907 case TOGGLE: 908 if (mousecap == OPT_OFF) 909 deinit_mouse(); 910 else 911 init_mouse(); 912 break; 913 case INIT: 914 case QUERY: 915 break; 916 } 917 } 918 919 /* 920 * Handler for the --wheel-lines option. 921 */ 922 /*ARGSUSED*/ 923 public void opt_wheel_lines(int type, constant char *s) 924 { 925 switch (type) 926 { 927 case INIT: 928 case TOGGLE: 929 if (wheel_lines <= 0) 930 wheel_lines = default_wheel_lines(); 931 break; 932 case QUERY: 933 break; 934 } 935 } 936 937 /* 938 * Handler for the --line-number-width option. 939 */ 940 /*ARGSUSED*/ 941 public void opt_linenum_width(int type, constant char *s) 942 { 943 PARG parg; 944 945 switch (type) 946 { 947 case INIT: 948 case TOGGLE: 949 if (linenum_width > MAX_LINENUM_WIDTH) 950 { 951 parg.p_int = MAX_LINENUM_WIDTH; 952 error("Line number width must not be larger than %d", &parg); 953 linenum_width = MIN_LINENUM_WIDTH; 954 } 955 break; 956 case QUERY: 957 break; 958 } 959 } 960 961 /* 962 * Handler for the --status-column-width option. 963 */ 964 /*ARGSUSED*/ 965 public void opt_status_col_width(int type, constant char *s) 966 { 967 PARG parg; 968 969 switch (type) 970 { 971 case INIT: 972 case TOGGLE: 973 if (status_col_width > MAX_STATUSCOL_WIDTH) 974 { 975 parg.p_int = MAX_STATUSCOL_WIDTH; 976 error("Status column width must not be larger than %d", &parg); 977 status_col_width = 2; 978 } 979 break; 980 case QUERY: 981 break; 982 } 983 } 984 985 /* 986 * Handler for the --file-size option. 987 */ 988 /*ARGSUSED*/ 989 public void opt_filesize(int type, constant char *s) 990 { 991 switch (type) 992 { 993 case INIT: 994 case TOGGLE: 995 if (want_filesize && curr_ifile != NULL && ch_length() == NULL_POSITION) 996 scan_eof(); 997 break; 998 case QUERY: 999 break; 1000 } 1001 } 1002 1003 /* 1004 * Handler for the --cmd option. 1005 */ 1006 /*ARGSUSED*/ 1007 public void opt_first_cmd_at_prompt(int type, constant char *s) 1008 { 1009 switch (type) 1010 { 1011 case INIT: 1012 case TOGGLE: 1013 first_cmd_at_prompt = save(s); 1014 break; 1015 case QUERY: 1016 break; 1017 } 1018 } 1019 1020 /* 1021 * Handler for the --intr option. 1022 */ 1023 /*ARGSUSED*/ 1024 public void opt_intr(int type, constant char *s) 1025 { 1026 PARG p; 1027 1028 switch (type) 1029 { 1030 case INIT: 1031 case TOGGLE: 1032 intr_char = *s; 1033 if (intr_char == '^' && s[1] != '\0') 1034 intr_char = CONTROL(s[1]); 1035 break; 1036 case QUERY: { 1037 p.p_string = prchar((LWCHAR) intr_char); 1038 error("interrupt character is %s", &p); 1039 break; } 1040 } 1041 } 1042 1043 /* 1044 * Return the next number from a comma-separated list. 1045 * Return -1 if the list entry is missing or empty. 1046 * Updates *sp to point to the first char of the next number in the list. 1047 */ 1048 static lbool next_cnum(constant char **sp, constant char *printopt, mutable int *p_num) 1049 { 1050 if (**sp == '\0') /* at end of line */ 1051 { 1052 *p_num = -1; 1053 return TRUE; 1054 } 1055 if (**sp == ',') /* that's the next comma; we have an empty string */ 1056 { 1057 ++(*sp); 1058 *p_num = -1; 1059 return TRUE; 1060 } 1061 if (!getnumc(sp, printopt, FALSE, p_num)) 1062 return FALSE; 1063 if (**sp == ',') 1064 ++(*sp); 1065 return TRUE; 1066 } 1067 1068 /* 1069 * Parse a parameter to the --header option. 1070 * Value is "L,C,N", where each field is a decimal number or empty. 1071 */ 1072 static lbool parse_header(constant char *s, int *lines, int *cols, POSITION *start_pos) 1073 { 1074 int n; 1075 1076 if (*s == '-') 1077 s = "0,0"; 1078 if (!next_cnum(&s, "--header", &n)) 1079 return FALSE; 1080 if (n >= 0) *lines = n; 1081 if (!next_cnum(&s, "--header", &n)) 1082 return FALSE; 1083 if (n >= 0) *cols = n; 1084 if (!next_cnum(&s, "--header", &n)) 1085 return FALSE; 1086 if (n > 0) 1087 { 1088 if (n < 1) n = 1; 1089 *start_pos = find_pos((LINENUM)n); 1090 } 1091 return TRUE; 1092 } 1093 1094 /* 1095 * Handler for the --header option. 1096 */ 1097 /*ARGSUSED*/ 1098 public void opt_header(int type, constant char *s) 1099 { 1100 switch (type) 1101 { 1102 case INIT: 1103 /* Can't call parse_header now because input file is not yet opened, 1104 * so find_pos won't work. */ 1105 init_header = save(s); 1106 break; 1107 case TOGGLE: { 1108 int lines = header_lines; 1109 int cols = header_cols; 1110 POSITION start_pos = (type == INIT) ? ch_zero() : position(TOP); 1111 if (start_pos == NULL_POSITION) start_pos = ch_zero(); 1112 if (!parse_header(s, &lines, &cols, &start_pos)) 1113 break; 1114 header_lines = lines; 1115 header_cols = cols; 1116 set_header(start_pos); 1117 calc_jump_sline(); 1118 break; } 1119 case QUERY: { 1120 char buf[3*INT_STRLEN_BOUND(long)+3]; 1121 PARG parg; 1122 SNPRINTF3(buf, sizeof(buf), "%ld,%ld,%ld", (long) header_lines, (long) header_cols, (long) find_linenum(header_start_pos)); 1123 parg.p_string = buf; 1124 error("Header (lines,columns,line-number) is %s", &parg); 1125 break; } 1126 } 1127 } 1128 1129 /* 1130 * Handler for the --search-options option. 1131 */ 1132 /*ARGSUSED*/ 1133 public void opt_search_type(int type, constant char *s) 1134 { 1135 int st; 1136 PARG parg; 1137 char buf[16]; 1138 char *bp; 1139 int i; 1140 1141 switch (type) 1142 { 1143 case INIT: 1144 case TOGGLE: 1145 st = 0; 1146 for (; *s != '\0'; s++) 1147 { 1148 switch (*s) 1149 { 1150 case 'E': case 'e': case CONTROL('E'): st |= SRCH_PAST_EOF; break; 1151 case 'F': case 'f': case CONTROL('F'): st |= SRCH_FIRST_FILE; break; 1152 case 'K': case 'k': case CONTROL('K'): st |= SRCH_NO_MOVE; break; 1153 case 'N': case 'n': case CONTROL('N'): st |= SRCH_NO_MATCH; break; 1154 case 'R': case 'r': case CONTROL('R'): st |= SRCH_NO_REGEX; break; 1155 case 'W': case 'w': case CONTROL('W'): st |= SRCH_WRAP; break; 1156 case '-': st = 0; break; 1157 case '^': break; 1158 default: 1159 if (*s >= '1' && *s <= '0'+NUM_SEARCH_COLORS) 1160 { 1161 st |= SRCH_SUBSEARCH(*s-'0'); 1162 break; 1163 } 1164 parg.p_char = *s; 1165 error("invalid search option '%c'", &parg); 1166 return; 1167 } 1168 } 1169 def_search_type = norm_search_type(st); 1170 break; 1171 case QUERY: 1172 bp = buf; 1173 if (def_search_type & SRCH_PAST_EOF) *bp++ = 'E'; 1174 if (def_search_type & SRCH_FIRST_FILE) *bp++ = 'F'; 1175 if (def_search_type & SRCH_NO_MOVE) *bp++ = 'K'; 1176 if (def_search_type & SRCH_NO_MATCH) *bp++ = 'N'; 1177 if (def_search_type & SRCH_NO_REGEX) *bp++ = 'R'; 1178 if (def_search_type & SRCH_WRAP) *bp++ = 'W'; 1179 for (i = 1; i <= NUM_SEARCH_COLORS; i++) 1180 if (def_search_type & SRCH_SUBSEARCH(i)) 1181 *bp++ = (char) ('0'+i); 1182 if (bp == buf) 1183 *bp++ = '-'; 1184 *bp = '\0'; 1185 parg.p_string = buf; 1186 error("search options: %s", &parg); 1187 break; 1188 } 1189 } 1190 1191 /* 1192 * Handler for the --no-search-headers, --no-search-header-lines 1193 * and --no-search-header-cols options. 1194 */ 1195 static void do_nosearch_headers(int type, int no_header_lines, int no_header_cols) 1196 { 1197 switch (type) 1198 { 1199 case INIT: 1200 case TOGGLE: 1201 nosearch_header_lines = no_header_lines; 1202 nosearch_header_cols = no_header_cols; 1203 if (type != TOGGLE) break; 1204 /*FALLTHRU*/ 1205 case QUERY: 1206 if (nosearch_header_lines && nosearch_header_cols) 1207 error("Search does not include header lines or columns", NULL_PARG); 1208 else if (nosearch_header_lines) 1209 error("Search includes header columns but not header lines", NULL_PARG); 1210 else if (nosearch_header_cols) 1211 error("Search includes header lines but not header columns", NULL_PARG); 1212 else 1213 error("Search includes header lines and columns", NULL_PARG); 1214 } 1215 } 1216 1217 /*ARGSUSED*/ 1218 public void opt_nosearch_headers(int type, constant char *s) 1219 { 1220 do_nosearch_headers(type, 1, 1); 1221 } 1222 1223 /*ARGSUSED*/ 1224 public void opt_nosearch_header_lines(int type, constant char *s) 1225 { 1226 do_nosearch_headers(type, 1, 0); 1227 } 1228 1229 /*ARGSUSED*/ 1230 public void opt_nosearch_header_cols(int type, constant char *s) 1231 { 1232 do_nosearch_headers(type, 0, 1); 1233 } 1234 1235 /*ARGSUSED*/ 1236 public void opt_no_paste(int type, constant char *s) 1237 { 1238 switch (type) 1239 { 1240 case TOGGLE: 1241 if (no_paste) 1242 init_bracketed_paste(); 1243 else 1244 deinit_bracketed_paste(); 1245 break; 1246 case INIT: 1247 case QUERY: 1248 break; 1249 } 1250 } 1251 1252 #if LESSTEST 1253 /* 1254 * Handler for the --tty option. 1255 */ 1256 /*ARGSUSED*/ 1257 public void opt_ttyin_name(int type, constant char *s) 1258 { 1259 switch (type) 1260 { 1261 case INIT: 1262 ttyin_name = s; 1263 is_tty = 1; 1264 break; 1265 } 1266 } 1267 #endif /*LESSTEST*/ 1268 1269 public int chop_line(void) 1270 { 1271 return (chopline || header_cols > 0 || header_lines > 0); 1272 } 1273 1274 /* 1275 * Get the "screen window" size. 1276 */ 1277 public int get_swindow(void) 1278 { 1279 if (swindow > 0) 1280 return (swindow); 1281 return (sc_height - header_lines + swindow); 1282 } 1283 1284 /* 1285 * Should an action initiate an autosave? 1286 */ 1287 public lbool autosave_action(char act) 1288 { 1289 return strchr(autosave, act) != NULL || strchr(autosave, '*') != NULL; 1290 } 1291