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