1 /* 2 * Copyright (C) 1984-2023 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 30 extern int nbufs; 31 extern int bufspace; 32 extern int pr_type; 33 extern int plusoption; 34 extern int swindow; 35 extern int sc_width; 36 extern int sc_height; 37 extern int secure; 38 extern int dohelp; 39 extern int is_tty; 40 extern char openquote; 41 extern char closequote; 42 extern char *prproto[]; 43 extern char *eqproto; 44 extern char *hproto; 45 extern char *wproto; 46 extern char *every_first_cmd; 47 extern IFILE curr_ifile; 48 extern char version[]; 49 extern int jump_sline; 50 extern long jump_sline_fraction; 51 extern int shift_count; 52 extern long shift_count_fraction; 53 extern char rscroll_char; 54 extern int rscroll_attr; 55 extern int mousecap; 56 extern int wheel_lines; 57 extern int less_is_more; 58 extern int linenum_width; 59 extern int status_col_width; 60 extern int use_color; 61 extern int want_filesize; 62 extern int header_lines; 63 extern int header_cols; 64 extern int def_search_type; 65 extern int chopline; 66 extern int tabstops[]; 67 extern int ntabstops; 68 extern int tabdefault; 69 extern char intr_char; 70 #if LOGFILE 71 extern char *namelogfile; 72 extern int force_logfile; 73 extern int logfile; 74 #endif 75 #if TAGS 76 public char *tagoption = NULL; 77 extern char *tags; 78 extern char ztags[]; 79 #endif 80 #if LESSTEST 81 extern char *ttyin_name; 82 #endif /*LESSTEST*/ 83 #if MSDOS_COMPILER 84 extern int nm_fg_color, nm_bg_color; 85 extern int bo_fg_color, bo_bg_color; 86 extern int ul_fg_color, ul_bg_color; 87 extern int so_fg_color, so_bg_color; 88 extern int bl_fg_color, bl_bg_color; 89 extern int sgr_mode; 90 #if MSDOS_COMPILER==WIN32C 91 #ifndef COMMON_LVB_UNDERSCORE 92 #define COMMON_LVB_UNDERSCORE 0x8000 93 #endif 94 #endif 95 #endif 96 97 98 #if LOGFILE 99 /* 100 * Handler for -o option. 101 */ 102 public void opt_o(int type, char *s) 103 { 104 PARG parg; 105 char *filename; 106 107 if (secure) 108 { 109 error("log file support is not available", NULL_PARG); 110 return; 111 } 112 switch (type) 113 { 114 case INIT: 115 namelogfile = save(s); 116 break; 117 case TOGGLE: 118 if (ch_getflags() & CH_CANSEEK) 119 { 120 error("Input is not a pipe", NULL_PARG); 121 return; 122 } 123 if (logfile >= 0) 124 { 125 error("Log file is already in use", NULL_PARG); 126 return; 127 } 128 s = skipsp(s); 129 if (namelogfile != NULL) 130 free(namelogfile); 131 filename = lglob(s); 132 namelogfile = shell_unquote(filename); 133 free(filename); 134 use_logfile(namelogfile); 135 sync_logfile(); 136 break; 137 case QUERY: 138 if (logfile < 0) 139 error("No log file", NULL_PARG); 140 else 141 { 142 parg.p_string = namelogfile; 143 error("Log file \"%s\"", &parg); 144 } 145 break; 146 } 147 } 148 149 /* 150 * Handler for -O option. 151 */ 152 public void opt__O(int type, char *s) 153 { 154 force_logfile = TRUE; 155 opt_o(type, s); 156 } 157 #endif 158 159 /* 160 * Handlers for -j option. 161 */ 162 public void opt_j(int type, char *s) 163 { 164 PARG parg; 165 int len; 166 int err; 167 168 switch (type) 169 { 170 case INIT: 171 case TOGGLE: 172 if (*s == '.') 173 { 174 s++; 175 jump_sline_fraction = getfraction(&s, "j", &err); 176 if (err) 177 error("Invalid line fraction", NULL_PARG); 178 else 179 calc_jump_sline(); 180 } else 181 { 182 int sline = getnum(&s, "j", &err); 183 if (err) 184 error("Invalid line number", NULL_PARG); 185 else 186 { 187 jump_sline = sline; 188 jump_sline_fraction = -1; 189 } 190 } 191 break; 192 case QUERY: 193 if (jump_sline_fraction < 0) 194 { 195 parg.p_int = jump_sline; 196 error("Position target at screen line %d", &parg); 197 } else 198 { 199 char buf[INT_STRLEN_BOUND(long)+2]; 200 SNPRINTF1(buf, sizeof(buf), ".%06ld", jump_sline_fraction); 201 len = (int) strlen(buf); 202 while (len > 2 && buf[len-1] == '0') 203 len--; 204 buf[len] = '\0'; 205 parg.p_string = buf; 206 error("Position target at screen position %s", &parg); 207 } 208 break; 209 } 210 } 211 212 public void calc_jump_sline(void) 213 { 214 if (jump_sline_fraction < 0) 215 return; 216 jump_sline = (int) muldiv(sc_height, jump_sline_fraction, NUM_FRAC_DENOM); 217 } 218 219 /* 220 * Handlers for -# option. 221 */ 222 public void opt_shift(int type, char *s) 223 { 224 PARG parg; 225 int len; 226 int err; 227 228 switch (type) 229 { 230 case INIT: 231 case TOGGLE: 232 if (*s == '.') 233 { 234 s++; 235 shift_count_fraction = getfraction(&s, "#", &err); 236 if (err) 237 error("Invalid column fraction", NULL_PARG); 238 else 239 calc_shift_count(); 240 } else 241 { 242 int hs = getnum(&s, "#", &err); 243 if (err) 244 error("Invalid column number", NULL_PARG); 245 else 246 { 247 shift_count = hs; 248 shift_count_fraction = -1; 249 } 250 } 251 break; 252 case QUERY: 253 if (shift_count_fraction < 0) 254 { 255 parg.p_int = shift_count; 256 error("Horizontal shift %d columns", &parg); 257 } else 258 { 259 char buf[INT_STRLEN_BOUND(long)+2]; 260 SNPRINTF1(buf, sizeof(buf), ".%06ld", shift_count_fraction); 261 len = (int) strlen(buf); 262 while (len > 2 && buf[len-1] == '0') 263 len--; 264 buf[len] = '\0'; 265 parg.p_string = buf; 266 error("Horizontal shift %s of screen width", &parg); 267 } 268 break; 269 } 270 } 271 272 public void calc_shift_count(void) 273 { 274 if (shift_count_fraction < 0) 275 return; 276 shift_count = (int) muldiv(sc_width, shift_count_fraction, NUM_FRAC_DENOM); 277 } 278 279 #if USERFILE 280 public void opt_k(int type, char *s) 281 { 282 PARG parg; 283 284 switch (type) 285 { 286 case INIT: 287 if (lesskey(s, 0)) 288 { 289 parg.p_string = s; 290 error("Cannot use lesskey file \"%s\"", &parg); 291 } 292 break; 293 } 294 } 295 296 #if HAVE_LESSKEYSRC 297 public void opt_ks(int type, char *s) 298 { 299 PARG parg; 300 301 switch (type) 302 { 303 case INIT: 304 if (lesskey_src(s, 0)) 305 { 306 parg.p_string = s; 307 error("Cannot use lesskey source file \"%s\"", &parg); 308 } 309 break; 310 } 311 } 312 #endif /* HAVE_LESSKEYSRC */ 313 #endif /* USERFILE */ 314 315 #if TAGS 316 /* 317 * Handler for -t option. 318 */ 319 public void opt_t(int type, char *s) 320 { 321 IFILE save_ifile; 322 POSITION pos; 323 324 switch (type) 325 { 326 case INIT: 327 tagoption = save(s); 328 /* Do the rest in main() */ 329 break; 330 case TOGGLE: 331 if (secure) 332 { 333 error("tags support is not available", NULL_PARG); 334 break; 335 } 336 findtag(skipsp(s)); 337 save_ifile = save_curr_ifile(); 338 /* 339 * Try to open the file containing the tag 340 * and search for the tag in that file. 341 */ 342 if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION) 343 { 344 /* Failed: reopen the old file. */ 345 reedit_ifile(save_ifile); 346 break; 347 } 348 unsave_ifile(save_ifile); 349 jump_loc(pos, jump_sline); 350 break; 351 } 352 } 353 354 /* 355 * Handler for -T option. 356 */ 357 public void opt__T(int type, char *s) 358 { 359 PARG parg; 360 char *filename; 361 362 switch (type) 363 { 364 case INIT: 365 tags = save(s); 366 break; 367 case TOGGLE: 368 s = skipsp(s); 369 if (tags != NULL && tags != ztags) 370 free(tags); 371 filename = lglob(s); 372 tags = shell_unquote(filename); 373 free(filename); 374 break; 375 case QUERY: 376 parg.p_string = tags; 377 error("Tags file \"%s\"", &parg); 378 break; 379 } 380 } 381 #endif 382 383 /* 384 * Handler for -p option. 385 */ 386 public void opt_p(int type, char *s) 387 { 388 switch (type) 389 { 390 case INIT: 391 /* 392 * Unget a command for the specified string. 393 */ 394 if (less_is_more) 395 { 396 /* 397 * In "more" mode, the -p argument is a command, 398 * not a search string, so we don't need a slash. 399 */ 400 every_first_cmd = save(s); 401 } else 402 { 403 plusoption = TRUE; 404 /* 405 * {{ This won't work if the "/" command is 406 * changed or invalidated by a .lesskey file. }} 407 */ 408 ungetsc("/"); 409 ungetsc(s); 410 ungetcc_back(CHAR_END_COMMAND); 411 } 412 break; 413 } 414 } 415 416 /* 417 * Handler for -P option. 418 */ 419 public void opt__P(int type, char *s) 420 { 421 char **proto; 422 PARG parg; 423 424 switch (type) 425 { 426 case INIT: 427 case TOGGLE: 428 /* 429 * Figure out which prototype string should be changed. 430 */ 431 switch (*s) 432 { 433 case 's': proto = &prproto[PR_SHORT]; s++; break; 434 case 'm': proto = &prproto[PR_MEDIUM]; s++; break; 435 case 'M': proto = &prproto[PR_LONG]; s++; break; 436 case '=': proto = &eqproto; s++; break; 437 case 'h': proto = &hproto; s++; break; 438 case 'w': proto = &wproto; s++; break; 439 default: proto = &prproto[PR_SHORT]; break; 440 } 441 free(*proto); 442 *proto = save(s); 443 break; 444 case QUERY: 445 parg.p_string = prproto[pr_type]; 446 error("%s", &parg); 447 break; 448 } 449 } 450 451 /* 452 * Handler for the -b option. 453 */ 454 /*ARGSUSED*/ 455 public void opt_b(int type, char *s) 456 { 457 switch (type) 458 { 459 case INIT: 460 case TOGGLE: 461 /* 462 * Set the new number of buffers. 463 */ 464 ch_setbufspace(bufspace); 465 break; 466 case QUERY: 467 break; 468 } 469 } 470 471 /* 472 * Handler for the -i option. 473 */ 474 /*ARGSUSED*/ 475 public void opt_i(int type, char *s) 476 { 477 switch (type) 478 { 479 case TOGGLE: 480 chg_caseless(); 481 break; 482 case QUERY: 483 case INIT: 484 break; 485 } 486 } 487 488 /* 489 * Handler for the -V option. 490 */ 491 /*ARGSUSED*/ 492 public void opt__V(int type, char *s) 493 { 494 switch (type) 495 { 496 case TOGGLE: 497 case QUERY: 498 dispversion(); 499 break; 500 case INIT: 501 set_output(1); /* Force output to stdout per GNU standard for --version output. */ 502 putstr("less "); 503 putstr(version); 504 putstr(" ("); 505 putstr(pattern_lib_name()); 506 putstr(" regular expressions)\n"); 507 { 508 char constant *copyright = 509 "Copyright (C) 1984-2023 Mark Nudelman\n\n"; 510 putstr(copyright); 511 } 512 if (version[strlen(version)-1] == 'x') 513 { 514 putstr("** This is an EXPERIMENTAL build of the 'less' software,\n"); 515 putstr("** and may not function correctly.\n"); 516 putstr("** Obtain release builds from the web page below.\n\n"); 517 } 518 #if LESSTEST 519 putstr("This build supports LESSTEST.\n"); 520 #endif /*LESSTEST*/ 521 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n"); 522 putstr("For information about the terms of redistribution,\n"); 523 putstr("see the file named README in the less distribution.\n"); 524 putstr("Home page: https://greenwoodsoftware.com/less\n"); 525 quit(QUIT_OK); 526 break; 527 } 528 } 529 530 #if MSDOS_COMPILER 531 /* 532 * Parse an MSDOS color descriptor. 533 */ 534 static void colordesc(char *s, int *fg_color, int *bg_color) 535 { 536 int fg, bg; 537 #if MSDOS_COMPILER==WIN32C 538 int ul = 0; 539 540 if (*s == 'u') 541 { 542 ul = COMMON_LVB_UNDERSCORE; 543 s++; 544 if (*s == '\0') 545 { 546 *fg_color = nm_fg_color | ul; 547 *bg_color = nm_bg_color; 548 return; 549 } 550 } 551 #endif 552 if (parse_color(s, &fg, &bg) == CT_NULL) 553 { 554 PARG p; 555 p.p_string = s; 556 error("Invalid color string \"%s\"", &p); 557 } else 558 { 559 if (fg == CV_NOCHANGE) 560 fg = nm_fg_color; 561 if (bg == CV_NOCHANGE) 562 bg = nm_bg_color; 563 #if MSDOS_COMPILER==WIN32C 564 fg |= ul; 565 #endif 566 *fg_color = fg; 567 *bg_color = bg; 568 } 569 } 570 #endif 571 572 static int color_from_namechar(char namechar) 573 { 574 switch (namechar) 575 { 576 case 'B': return AT_COLOR_BIN; 577 case 'C': return AT_COLOR_CTRL; 578 case 'E': return AT_COLOR_ERROR; 579 case 'H': return AT_COLOR_HEADER; 580 case 'M': return AT_COLOR_MARK; 581 case 'N': return AT_COLOR_LINENUM; 582 case 'P': return AT_COLOR_PROMPT; 583 case 'R': return AT_COLOR_RSCROLL; 584 case 'S': return AT_COLOR_SEARCH; 585 case 'W': case 'A': return AT_COLOR_ATTN; 586 case 'n': return AT_NORMAL; 587 case 's': return AT_STANDOUT; 588 case 'd': return AT_BOLD; 589 case 'u': return AT_UNDERLINE; 590 case 'k': return AT_BLINK; 591 default: 592 if (namechar >= '1' && namechar <= '0'+NUM_SEARCH_COLORS) 593 return AT_COLOR_SUBSEARCH(namechar-'0'); 594 return -1; 595 } 596 } 597 598 /* 599 * Handler for the -D option. 600 */ 601 /*ARGSUSED*/ 602 public void opt_D(int type, char *s) 603 { 604 PARG p; 605 int attr; 606 607 switch (type) 608 { 609 case INIT: 610 case TOGGLE: 611 #if MSDOS_COMPILER 612 if (*s == 'a') 613 { 614 sgr_mode = !sgr_mode; 615 break; 616 } 617 #endif 618 attr = color_from_namechar(s[0]); 619 if (attr < 0) 620 { 621 p.p_char = s[0]; 622 error("Invalid color specifier '%c'", &p); 623 return; 624 } 625 if (!use_color && (attr & AT_COLOR)) 626 { 627 error("Set --use-color before changing colors", NULL_PARG); 628 return; 629 } 630 s++; 631 #if MSDOS_COMPILER 632 if (!(attr & AT_COLOR)) 633 { 634 switch (attr) 635 { 636 case AT_NORMAL: 637 colordesc(s, &nm_fg_color, &nm_bg_color); 638 break; 639 case AT_BOLD: 640 colordesc(s, &bo_fg_color, &bo_bg_color); 641 break; 642 case AT_UNDERLINE: 643 colordesc(s, &ul_fg_color, &ul_bg_color); 644 break; 645 case AT_BLINK: 646 colordesc(s, &bl_fg_color, &bl_bg_color); 647 break; 648 case AT_STANDOUT: 649 colordesc(s, &so_fg_color, &so_bg_color); 650 break; 651 } 652 if (type == TOGGLE) 653 { 654 at_enter(AT_STANDOUT); 655 at_exit(); 656 } 657 } else 658 #endif 659 if (set_color_map(attr, s) < 0) 660 { 661 p.p_string = s; 662 error("Invalid color string \"%s\"", &p); 663 return; 664 } 665 break; 666 #if MSDOS_COMPILER 667 case QUERY: 668 p.p_string = (sgr_mode) ? "on" : "off"; 669 error("SGR mode is %s", &p); 670 break; 671 #endif 672 } 673 } 674 675 /* 676 */ 677 public void set_tabs(char *s, int len) 678 { 679 int i; 680 char *es = s + len; 681 /* Start at 1 because tabstops[0] is always zero. */ 682 for (i = 1; i < TABSTOP_MAX; ) 683 { 684 int n = 0; 685 int v = FALSE; 686 while (s < es && *s == ' ') 687 s++; 688 for (; s < es && *s >= '0' && *s <= '9'; s++) 689 { 690 v |= ckd_mul(&n, n, 10); 691 v |= ckd_add(&n, n, *s - '0'); 692 } 693 if (!v && n > tabstops[i-1]) 694 tabstops[i++] = n; 695 while (s < es && *s == ' ') 696 s++; 697 if (s == es || *s++ != ',') 698 break; 699 } 700 if (i < 2) 701 return; 702 ntabstops = i; 703 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2]; 704 } 705 706 /* 707 * Handler for the -x option. 708 */ 709 public void opt_x(int type, char *s) 710 { 711 char msg[60+((INT_STRLEN_BOUND(int)+1)*TABSTOP_MAX)]; 712 int i; 713 PARG p; 714 715 switch (type) 716 { 717 case INIT: 718 case TOGGLE: 719 set_tabs(s, strlen(s)); 720 break; 721 case QUERY: 722 strcpy(msg, "Tab stops "); 723 if (ntabstops > 2) 724 { 725 for (i = 1; i < ntabstops; i++) 726 { 727 if (i > 1) 728 strcat(msg, ","); 729 sprintf(msg+strlen(msg), "%d", tabstops[i]); 730 } 731 sprintf(msg+strlen(msg), " and then "); 732 } 733 sprintf(msg+strlen(msg), "every %d spaces", 734 tabdefault); 735 p.p_string = msg; 736 error("%s", &p); 737 break; 738 } 739 } 740 741 742 /* 743 * Handler for the -" option. 744 */ 745 public void opt_quote(int type, char *s) 746 { 747 char buf[3]; 748 PARG parg; 749 750 switch (type) 751 { 752 case INIT: 753 case TOGGLE: 754 if (s[0] == '\0') 755 { 756 openquote = closequote = '\0'; 757 break; 758 } 759 if (s[1] != '\0' && s[2] != '\0') 760 { 761 error("-\" must be followed by 1 or 2 chars", NULL_PARG); 762 return; 763 } 764 openquote = s[0]; 765 if (s[1] == '\0') 766 closequote = openquote; 767 else 768 closequote = s[1]; 769 break; 770 case QUERY: 771 buf[0] = openquote; 772 buf[1] = closequote; 773 buf[2] = '\0'; 774 parg.p_string = buf; 775 error("quotes %s", &parg); 776 break; 777 } 778 } 779 780 /* 781 * Handler for the --rscroll option. 782 */ 783 /*ARGSUSED*/ 784 public void opt_rscroll(int type, char *s) 785 { 786 PARG p; 787 788 switch (type) 789 { 790 case INIT: 791 case TOGGLE: { 792 char *fmt; 793 int attr = AT_STANDOUT; 794 setfmt(s, &fmt, &attr, "*s>", FALSE); 795 if (strcmp(fmt, "-") == 0) 796 { 797 rscroll_char = 0; 798 } else 799 { 800 rscroll_char = *fmt ? *fmt : '>'; 801 rscroll_attr = attr|AT_COLOR_RSCROLL; 802 } 803 break; } 804 case QUERY: { 805 p.p_string = rscroll_char ? prchar(rscroll_char) : "-"; 806 error("rscroll character is %s", &p); 807 break; } 808 } 809 } 810 811 /* 812 * "-?" means display a help message. 813 * If from the command line, exit immediately. 814 */ 815 /*ARGSUSED*/ 816 public void opt_query(int type, char *s) 817 { 818 switch (type) 819 { 820 case QUERY: 821 case TOGGLE: 822 error("Use \"h\" for help", NULL_PARG); 823 break; 824 case INIT: 825 dohelp = 1; 826 } 827 } 828 829 /* 830 * Handler for the --mouse option. 831 */ 832 /*ARGSUSED*/ 833 public void opt_mousecap(int type, char *s) 834 { 835 switch (type) 836 { 837 case TOGGLE: 838 if (mousecap == OPT_OFF) 839 deinit_mouse(); 840 else 841 init_mouse(); 842 break; 843 case INIT: 844 case QUERY: 845 break; 846 } 847 } 848 849 /* 850 * Handler for the --wheel-lines option. 851 */ 852 /*ARGSUSED*/ 853 public void opt_wheel_lines(int type, char *s) 854 { 855 switch (type) 856 { 857 case INIT: 858 case TOGGLE: 859 if (wheel_lines <= 0) 860 wheel_lines = default_wheel_lines(); 861 break; 862 case QUERY: 863 break; 864 } 865 } 866 867 /* 868 * Handler for the --line-number-width option. 869 */ 870 /*ARGSUSED*/ 871 public void opt_linenum_width(int type, char *s) 872 { 873 PARG parg; 874 875 switch (type) 876 { 877 case INIT: 878 case TOGGLE: 879 if (linenum_width > MAX_LINENUM_WIDTH) 880 { 881 parg.p_int = MAX_LINENUM_WIDTH; 882 error("Line number width must not be larger than %d", &parg); 883 linenum_width = MIN_LINENUM_WIDTH; 884 } 885 break; 886 case QUERY: 887 break; 888 } 889 } 890 891 /* 892 * Handler for the --status-column-width option. 893 */ 894 /*ARGSUSED*/ 895 public void opt_status_col_width(int type, char *s) 896 { 897 PARG parg; 898 899 switch (type) 900 { 901 case INIT: 902 case TOGGLE: 903 if (status_col_width > MAX_STATUSCOL_WIDTH) 904 { 905 parg.p_int = MAX_STATUSCOL_WIDTH; 906 error("Status column width must not be larger than %d", &parg); 907 status_col_width = 2; 908 } 909 break; 910 case QUERY: 911 break; 912 } 913 } 914 915 /* 916 * Handler for the --file-size option. 917 */ 918 /*ARGSUSED*/ 919 public void opt_filesize(int type, char *s) 920 { 921 switch (type) 922 { 923 case INIT: 924 case TOGGLE: 925 if (want_filesize && curr_ifile != NULL && ch_length() == NULL_POSITION) 926 scan_eof(); 927 break; 928 case QUERY: 929 break; 930 } 931 } 932 933 /* 934 * Handler for the --intr option. 935 */ 936 /*ARGSUSED*/ 937 public void opt_intr(int type, char *s) 938 { 939 PARG p; 940 941 switch (type) 942 { 943 case INIT: 944 case TOGGLE: 945 intr_char = *s; 946 if (intr_char == '^' && s[1] != '\0') 947 intr_char = CONTROL(s[1]); 948 break; 949 case QUERY: { 950 p.p_string = prchar(intr_char); 951 error("interrupt character is %s", &p); 952 break; } 953 } 954 } 955 956 /* 957 * Handler for the --header option. 958 */ 959 /*ARGSUSED*/ 960 public void opt_header(int type, char *s) 961 { 962 int err; 963 int n; 964 965 switch (type) 966 { 967 case INIT: 968 case TOGGLE: 969 header_lines = 0; 970 header_cols = 0; 971 if (*s != ',') 972 { 973 n = getnum(&s, "header", &err); 974 if (err) 975 { 976 error("invalid number of lines", NULL_PARG); 977 return; 978 } 979 header_lines = n; 980 } 981 if (*s == ',') 982 { 983 ++s; 984 n = getnum(&s, "header", &err); 985 if (err) 986 error("invalid number of columns", NULL_PARG); 987 else 988 header_cols = n; 989 } 990 break; 991 case QUERY: 992 { 993 char buf[2*INT_STRLEN_BOUND(int)+2]; 994 PARG parg; 995 SNPRINTF2(buf, sizeof(buf), "%d,%d", header_lines, header_cols); 996 parg.p_string = buf; 997 error("header (lines,columns) is %s", &parg); 998 } 999 break; 1000 } 1001 } 1002 1003 /* 1004 * Handler for the --search-options option. 1005 */ 1006 /*ARGSUSED*/ 1007 public void opt_search_type(int type, char *s) 1008 { 1009 int st; 1010 PARG parg; 1011 char buf[16]; 1012 char *bp; 1013 int i; 1014 1015 switch (type) 1016 { 1017 case INIT: 1018 case TOGGLE: 1019 st = 0; 1020 for (; *s != '\0'; s++) 1021 { 1022 switch (*s) 1023 { 1024 case 'E': case 'e': case CONTROL('E'): st |= SRCH_PAST_EOF; break; 1025 case 'F': case 'f': case CONTROL('F'): st |= SRCH_FIRST_FILE; break; 1026 case 'K': case 'k': case CONTROL('K'): st |= SRCH_NO_MOVE; break; 1027 case 'N': case 'n': case CONTROL('N'): st |= SRCH_NO_MATCH; break; 1028 case 'R': case 'r': case CONTROL('R'): st |= SRCH_NO_REGEX; break; 1029 case 'W': case 'w': case CONTROL('W'): st |= SRCH_WRAP; break; 1030 case '-': st = 0; break; 1031 case '^': break; 1032 default: 1033 if (*s >= '1' && *s <= '0'+NUM_SEARCH_COLORS) 1034 { 1035 st |= SRCH_SUBSEARCH(*s-'0'); 1036 break; 1037 } 1038 parg.p_char = *s; 1039 error("invalid search option '%c'", &parg); 1040 return; 1041 } 1042 } 1043 def_search_type = norm_search_type(st); 1044 break; 1045 case QUERY: 1046 bp = buf; 1047 if (def_search_type & SRCH_PAST_EOF) *bp++ = 'E'; 1048 if (def_search_type & SRCH_FIRST_FILE) *bp++ = 'F'; 1049 if (def_search_type & SRCH_NO_MOVE) *bp++ = 'K'; 1050 if (def_search_type & SRCH_NO_MATCH) *bp++ = 'N'; 1051 if (def_search_type & SRCH_NO_REGEX) *bp++ = 'R'; 1052 if (def_search_type & SRCH_WRAP) *bp++ = 'W'; 1053 for (i = 1; i <= NUM_SEARCH_COLORS; i++) 1054 if (def_search_type & SRCH_SUBSEARCH(i)) 1055 *bp++ = '0'+i; 1056 if (bp == buf) 1057 *bp++ = '-'; 1058 *bp = '\0'; 1059 parg.p_string = buf; 1060 error("search options: %s", &parg); 1061 break; 1062 } 1063 } 1064 1065 #if LESSTEST 1066 /* 1067 * Handler for the --tty option. 1068 */ 1069 /*ARGSUSED*/ 1070 public void opt_ttyin_name(int type, char *s) 1071 { 1072 switch (type) 1073 { 1074 case INIT: 1075 ttyin_name = s; 1076 is_tty = 1; 1077 break; 1078 } 1079 } 1080 #endif /*LESSTEST*/ 1081 1082 public int chop_line(void) 1083 { 1084 return (chopline || header_cols > 0 || header_lines > 0); 1085 } 1086 1087 /* 1088 * Get the "screen window" size. 1089 */ 1090 public int get_swindow(void) 1091 { 1092 if (swindow > 0) 1093 return (swindow); 1094 return (sc_height - header_lines + swindow); 1095 } 1096 1097