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