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