1 /* 2 * Copyright (C) 1984-2017 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 any_display; 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 int less_is_more; 54 #if LOGFILE 55 extern char *namelogfile; 56 extern int force_logfile; 57 extern int logfile; 58 #endif 59 #if TAGS 60 public char *tagoption = NULL; 61 extern char *tags; 62 extern char ztags[]; 63 #endif 64 #if MSDOS_COMPILER 65 extern int nm_fg_color, nm_bg_color; 66 extern int bo_fg_color, bo_bg_color; 67 extern int ul_fg_color, ul_bg_color; 68 extern int so_fg_color, so_bg_color; 69 extern int bl_fg_color, bl_bg_color; 70 extern int sgr_mode; 71 #endif 72 73 74 #if LOGFILE 75 /* 76 * Handler for -o option. 77 */ 78 public void 79 opt_o(type, s) 80 int type; 81 char *s; 82 { 83 PARG parg; 84 85 if (secure) 86 { 87 error("log file support is not available", NULL_PARG); 88 return; 89 } 90 switch (type) 91 { 92 case INIT: 93 namelogfile = save(s); 94 break; 95 case TOGGLE: 96 if (ch_getflags() & CH_CANSEEK) 97 { 98 error("Input is not a pipe", NULL_PARG); 99 return; 100 } 101 if (logfile >= 0) 102 { 103 error("Log file is already in use", NULL_PARG); 104 return; 105 } 106 s = skipsp(s); 107 if (namelogfile != NULL) 108 free(namelogfile); 109 namelogfile = lglob(s); 110 use_logfile(namelogfile); 111 sync_logfile(); 112 break; 113 case QUERY: 114 if (logfile < 0) 115 error("No log file", NULL_PARG); 116 else 117 { 118 parg.p_string = namelogfile; 119 error("Log file \"%s\"", &parg); 120 } 121 break; 122 } 123 } 124 125 /* 126 * Handler for -O option. 127 */ 128 public void 129 opt__O(type, s) 130 int type; 131 char *s; 132 { 133 force_logfile = TRUE; 134 opt_o(type, s); 135 } 136 #endif 137 138 /* 139 * Handlers for -j option. 140 */ 141 public void 142 opt_j(type, s) 143 int type; 144 char *s; 145 { 146 PARG parg; 147 char buf[16]; 148 int len; 149 int err; 150 151 switch (type) 152 { 153 case INIT: 154 case TOGGLE: 155 if (*s == '.') 156 { 157 s++; 158 jump_sline_fraction = getfraction(&s, "j", &err); 159 if (err) 160 error("Invalid line fraction", NULL_PARG); 161 else 162 calc_jump_sline(); 163 } else 164 { 165 int sline = getnum(&s, "j", &err); 166 if (err) 167 error("Invalid line number", NULL_PARG); 168 else 169 { 170 jump_sline = sline; 171 jump_sline_fraction = -1; 172 } 173 } 174 break; 175 case QUERY: 176 if (jump_sline_fraction < 0) 177 { 178 parg.p_int = jump_sline; 179 error("Position target at screen line %d", &parg); 180 } else 181 { 182 183 sprintf(buf, ".%06ld", jump_sline_fraction); 184 len = (int) strlen(buf); 185 while (len > 2 && buf[len-1] == '0') 186 len--; 187 buf[len] = '\0'; 188 parg.p_string = buf; 189 error("Position target at screen position %s", &parg); 190 } 191 break; 192 } 193 } 194 195 public void 196 calc_jump_sline() 197 { 198 if (jump_sline_fraction < 0) 199 return; 200 jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM; 201 } 202 203 /* 204 * Handlers for -# option. 205 */ 206 public void 207 opt_shift(type, s) 208 int type; 209 char *s; 210 { 211 PARG parg; 212 char buf[16]; 213 int len; 214 int err; 215 216 switch (type) 217 { 218 case INIT: 219 case TOGGLE: 220 if (*s == '.') 221 { 222 s++; 223 shift_count_fraction = getfraction(&s, "#", &err); 224 if (err) 225 error("Invalid column fraction", NULL_PARG); 226 else 227 calc_shift_count(); 228 } else 229 { 230 int hs = getnum(&s, "#", &err); 231 if (err) 232 error("Invalid column number", NULL_PARG); 233 else 234 { 235 shift_count = hs; 236 shift_count_fraction = -1; 237 } 238 } 239 break; 240 case QUERY: 241 if (shift_count_fraction < 0) 242 { 243 parg.p_int = shift_count; 244 error("Horizontal shift %d columns", &parg); 245 } else 246 { 247 248 sprintf(buf, ".%06ld", shift_count_fraction); 249 len = (int) strlen(buf); 250 while (len > 2 && buf[len-1] == '0') 251 len--; 252 buf[len] = '\0'; 253 parg.p_string = buf; 254 error("Horizontal shift %s of screen width", &parg); 255 } 256 break; 257 } 258 } 259 public void 260 calc_shift_count() 261 { 262 if (shift_count_fraction < 0) 263 return; 264 shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM; 265 } 266 267 #if USERFILE 268 public void 269 opt_k(type, s) 270 int type; 271 char *s; 272 { 273 PARG parg; 274 275 switch (type) 276 { 277 case INIT: 278 if (lesskey(s, 0)) 279 { 280 parg.p_string = s; 281 error("Cannot use lesskey file \"%s\"", &parg); 282 } 283 break; 284 } 285 } 286 #endif 287 288 #if TAGS 289 /* 290 * Handler for -t option. 291 */ 292 public void 293 opt_t(type, s) 294 int type; 295 char *s; 296 { 297 IFILE save_ifile; 298 POSITION pos; 299 300 switch (type) 301 { 302 case INIT: 303 tagoption = save(s); 304 /* Do the rest in main() */ 305 break; 306 case TOGGLE: 307 if (secure) 308 { 309 error("tags support is not available", NULL_PARG); 310 break; 311 } 312 findtag(skipsp(s)); 313 save_ifile = save_curr_ifile(); 314 /* 315 * Try to open the file containing the tag 316 * and search for the tag in that file. 317 */ 318 if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION) 319 { 320 /* Failed: reopen the old file. */ 321 reedit_ifile(save_ifile); 322 break; 323 } 324 unsave_ifile(save_ifile); 325 jump_loc(pos, jump_sline); 326 break; 327 } 328 } 329 330 /* 331 * Handler for -T option. 332 */ 333 public void 334 opt__T(type, s) 335 int type; 336 char *s; 337 { 338 PARG parg; 339 340 switch (type) 341 { 342 case INIT: 343 tags = save(s); 344 break; 345 case TOGGLE: 346 s = skipsp(s); 347 if (tags != NULL && tags != ztags) 348 free(tags); 349 tags = lglob(s); 350 break; 351 case QUERY: 352 parg.p_string = tags; 353 error("Tags file \"%s\"", &parg); 354 break; 355 } 356 } 357 #endif 358 359 /* 360 * Handler for -p option. 361 */ 362 public void 363 opt_p(type, s) 364 int type; 365 char *s; 366 { 367 switch (type) 368 { 369 case INIT: 370 /* 371 * Unget a command for the specified string. 372 */ 373 if (less_is_more) 374 { 375 /* 376 * In "more" mode, the -p argument is a command, 377 * not a search string, so we don't need a slash. 378 */ 379 every_first_cmd = save(s); 380 } else 381 { 382 plusoption = TRUE; 383 ungetcc(CHAR_END_COMMAND); 384 ungetsc(s); 385 /* 386 * {{ This won't work if the "/" command is 387 * changed or invalidated by a .lesskey file. }} 388 */ 389 ungetsc("/"); 390 } 391 break; 392 } 393 } 394 395 /* 396 * Handler for -P option. 397 */ 398 public void 399 opt__P(type, s) 400 int type; 401 char *s; 402 { 403 char **proto; 404 PARG parg; 405 406 switch (type) 407 { 408 case INIT: 409 case TOGGLE: 410 /* 411 * Figure out which prototype string should be changed. 412 */ 413 switch (*s) 414 { 415 case 's': proto = &prproto[PR_SHORT]; s++; break; 416 case 'm': proto = &prproto[PR_MEDIUM]; s++; break; 417 case 'M': proto = &prproto[PR_LONG]; s++; break; 418 case '=': proto = &eqproto; s++; break; 419 case 'h': proto = &hproto; s++; break; 420 case 'w': proto = &wproto; s++; break; 421 default: proto = &prproto[PR_SHORT]; break; 422 } 423 free(*proto); 424 *proto = save(s); 425 break; 426 case QUERY: 427 parg.p_string = prproto[pr_type]; 428 error("%s", &parg); 429 break; 430 } 431 } 432 433 /* 434 * Handler for the -b option. 435 */ 436 /*ARGSUSED*/ 437 public void 438 opt_b(type, s) 439 int type; 440 char *s; 441 { 442 switch (type) 443 { 444 case INIT: 445 case TOGGLE: 446 /* 447 * Set the new number of buffers. 448 */ 449 ch_setbufspace(bufspace); 450 break; 451 case QUERY: 452 break; 453 } 454 } 455 456 /* 457 * Handler for the -i option. 458 */ 459 /*ARGSUSED*/ 460 public void 461 opt_i(type, s) 462 int type; 463 char *s; 464 { 465 switch (type) 466 { 467 case TOGGLE: 468 chg_caseless(); 469 break; 470 case QUERY: 471 case INIT: 472 break; 473 } 474 } 475 476 /* 477 * Handler for the -V option. 478 */ 479 /*ARGSUSED*/ 480 public void 481 opt__V(type, s) 482 int type; 483 char *s; 484 { 485 switch (type) 486 { 487 case TOGGLE: 488 case QUERY: 489 dispversion(); 490 break; 491 case INIT: 492 /* 493 * Force output to stdout per GNU standard for --version output. 494 */ 495 any_display = 1; 496 putstr("less "); 497 putstr(version); 498 putstr(" ("); 499 #if HAVE_GNU_REGEX 500 putstr("GNU "); 501 #endif 502 #if HAVE_POSIX_REGCOMP 503 putstr("POSIX "); 504 #endif 505 #if HAVE_PCRE 506 putstr("PCRE "); 507 #endif 508 #if HAVE_RE_COMP 509 putstr("BSD "); 510 #endif 511 #if HAVE_REGCMP 512 putstr("V8 "); 513 #endif 514 #if HAVE_V8_REGCOMP 515 putstr("Spencer V8 "); 516 #endif 517 #if !HAVE_GNU_REGEX && !HAVE_POSIX_REGCOMP && !HAVE_PCRE && !HAVE_RE_COMP && !HAVE_REGCMP && !HAVE_V8_REGCOMP 518 putstr("no "); 519 #endif 520 putstr("regular expressions)\n"); 521 putstr("Copyright (C) 1984-2017 Mark Nudelman\n\n"); 522 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n"); 523 putstr("For information about the terms of redistribution,\n"); 524 putstr("see the file named README in the less distribution.\n"); 525 putstr("Homepage: http://www.greenwoodsoftware.com/less\n"); 526 quit(QUIT_OK); 527 break; 528 } 529 } 530 531 #if MSDOS_COMPILER 532 /* 533 * Parse an MSDOS color descriptor. 534 */ 535 static void 536 colordesc(s, fg_color, bg_color) 537 char *s; 538 int *fg_color; 539 int *bg_color; 540 { 541 int fg, bg; 542 int err; 543 544 fg = getnum(&s, "D", &err); 545 if (err) 546 { 547 error("Missing fg color in -D", NULL_PARG); 548 return; 549 } 550 if (*s != '.') 551 bg = nm_bg_color; 552 else 553 { 554 s++; 555 bg = getnum(&s, "D", &err); 556 if (err) 557 { 558 error("Missing bg color in -D", NULL_PARG); 559 return; 560 } 561 } 562 if (*s != '\0') 563 error("Extra characters at end of -D option", NULL_PARG); 564 *fg_color = fg; 565 *bg_color = bg; 566 } 567 568 /* 569 * Handler for the -D option. 570 */ 571 /*ARGSUSED*/ 572 public void 573 opt_D(type, s) 574 int type; 575 char *s; 576 { 577 PARG p; 578 579 switch (type) 580 { 581 case INIT: 582 case TOGGLE: 583 switch (*s++) 584 { 585 case 'n': 586 colordesc(s, &nm_fg_color, &nm_bg_color); 587 break; 588 case 'd': 589 colordesc(s, &bo_fg_color, &bo_bg_color); 590 break; 591 case 'u': 592 colordesc(s, &ul_fg_color, &ul_bg_color); 593 break; 594 case 'k': 595 colordesc(s, &bl_fg_color, &bl_bg_color); 596 break; 597 case 's': 598 colordesc(s, &so_fg_color, &so_bg_color); 599 break; 600 case 'a': 601 sgr_mode = !sgr_mode; 602 break; 603 default: 604 error("-D must be followed by n, d, u, k, s or a", NULL_PARG); 605 break; 606 } 607 if (type == TOGGLE) 608 { 609 at_enter(AT_STANDOUT); 610 at_exit(); 611 } 612 break; 613 case QUERY: 614 p.p_string = (sgr_mode) ? "on" : "off"; 615 error("SGR mode is %s", &p); 616 break; 617 } 618 } 619 #endif 620 621 /* 622 * Handler for the -x option. 623 */ 624 public void 625 opt_x(type, s) 626 int type; 627 char *s; 628 { 629 extern int tabstops[]; 630 extern int ntabstops; 631 extern int tabdefault; 632 char msg[60+(4*TABSTOP_MAX)]; 633 int i; 634 PARG p; 635 636 switch (type) 637 { 638 case INIT: 639 case TOGGLE: 640 /* Start at 1 because tabstops[0] is always zero. */ 641 for (i = 1; i < TABSTOP_MAX; ) 642 { 643 int n = 0; 644 s = skipsp(s); 645 while (*s >= '0' && *s <= '9') 646 n = (10 * n) + (*s++ - '0'); 647 if (n > tabstops[i-1]) 648 tabstops[i++] = n; 649 s = skipsp(s); 650 if (*s++ != ',') 651 break; 652 } 653 if (i < 2) 654 return; 655 ntabstops = i; 656 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2]; 657 break; 658 case QUERY: 659 strcpy(msg, "Tab stops "); 660 if (ntabstops > 2) 661 { 662 for (i = 1; i < ntabstops; i++) 663 { 664 if (i > 1) 665 strcat(msg, ","); 666 sprintf(msg+strlen(msg), "%d", tabstops[i]); 667 } 668 sprintf(msg+strlen(msg), " and then "); 669 } 670 sprintf(msg+strlen(msg), "every %d spaces", 671 tabdefault); 672 p.p_string = msg; 673 error("%s", &p); 674 break; 675 } 676 } 677 678 679 /* 680 * Handler for the -" option. 681 */ 682 public void 683 opt_quote(type, s) 684 int type; 685 char *s; 686 { 687 char buf[3]; 688 PARG parg; 689 690 switch (type) 691 { 692 case INIT: 693 case TOGGLE: 694 if (s[0] == '\0') 695 { 696 openquote = closequote = '\0'; 697 break; 698 } 699 if (s[1] != '\0' && s[2] != '\0') 700 { 701 error("-\" must be followed by 1 or 2 chars", NULL_PARG); 702 return; 703 } 704 openquote = s[0]; 705 if (s[1] == '\0') 706 closequote = openquote; 707 else 708 closequote = s[1]; 709 break; 710 case QUERY: 711 buf[0] = openquote; 712 buf[1] = closequote; 713 buf[2] = '\0'; 714 parg.p_string = buf; 715 error("quotes %s", &parg); 716 break; 717 } 718 } 719 720 /* 721 * "-?" means display a help message. 722 * If from the command line, exit immediately. 723 */ 724 /*ARGSUSED*/ 725 public void 726 opt_query(type, s) 727 int type; 728 char *s; 729 { 730 switch (type) 731 { 732 case QUERY: 733 case TOGGLE: 734 error("Use \"h\" for help", NULL_PARG); 735 break; 736 case INIT: 737 dohelp = 1; 738 } 739 } 740 741 /* 742 * Get the "screen window" size. 743 */ 744 public int 745 get_swindow() 746 { 747 if (swindow > 0) 748 return (swindow); 749 return (sc_height + swindow); 750 } 751 752