optfunc.c revision 294286
1193323Sed/* 2193323Sed * Copyright (C) 1984-2015 Mark Nudelman 3193323Sed * 4193323Sed * You may distribute under the terms of either the GNU General Public 5193323Sed * License or the Less License, as specified in the README file. 6193323Sed * 7193323Sed * For more information, see the README file. 8193323Sed */ 9193323Sed 10193323Sed 11193323Sed/* 12193323Sed * Handling functions for command line options. 13249423Sdim * 14243830Sdim * Most options are handled by the generic code in option.c. 15218893Sdim * But all string options, and a few non-string options, require 16206083Srdivacky * special handling specific to the particular option. 17193323Sed * This special processing is done by the "handling functions" in this file. 18249423Sdim * 19193323Sed * Each handling function is passed a "type" and, if it is a string 20193323Sed * option, the string which should be "assigned" to the option. 21193323Sed * The type may be one of: 22193323Sed * INIT The option is being initialized from the command line. 23206083Srdivacky * TOGGLE The option is being changed from within the program. 24193323Sed * QUERY The setting of the option is merely being queried. 25198090Srdivacky */ 26193323Sed 27206083Srdivacky#include "less.h" 28206083Srdivacky#include "option.h" 29206083Srdivacky 30206083Srdivackyextern int nbufs; 31206083Srdivackyextern int bufspace; 32206083Srdivackyextern int pr_type; 33206083Srdivackyextern int plusoption; 34206083Srdivackyextern int swindow; 35206083Srdivackyextern int sc_width; 36206083Srdivackyextern int sc_height; 37206083Srdivackyextern int secure; 38206083Srdivackyextern int dohelp; 39206083Srdivackyextern int any_display; 40206083Srdivackyextern char openquote; 41206083Srdivackyextern char closequote; 42206083Srdivackyextern char *prproto[]; 43206083Srdivackyextern char *eqproto; 44206083Srdivackyextern char *hproto; 45206083Srdivackyextern char *wproto; 46206083Srdivackyextern char *every_first_cmd; 47206083Srdivackyextern IFILE curr_ifile; 48206083Srdivackyextern char version[]; 49206083Srdivackyextern int jump_sline; 50206083Srdivackyextern int jump_sline_fraction; 51206083Srdivackyextern int shift_count; 52206083Srdivackyextern int shift_count_fraction; 53206083Srdivackyextern int less_is_more; 54206083Srdivacky#if LOGFILE 55206083Srdivackyextern char *namelogfile; 56206083Srdivackyextern int force_logfile; 57206083Srdivackyextern int logfile; 58206083Srdivacky#endif 59206083Srdivacky#if TAGS 60206083Srdivackypublic char *tagoption = NULL; 61206083Srdivackyextern char *tags; 62206083Srdivackyextern char ztags[]; 63206083Srdivacky#endif 64206083Srdivacky#if MSDOS_COMPILER 65206083Srdivackyextern int nm_fg_color, nm_bg_color; 66206083Srdivackyextern int bo_fg_color, bo_bg_color; 67206083Srdivackyextern int ul_fg_color, ul_bg_color; 68206083Srdivackyextern int so_fg_color, so_bg_color; 69206083Srdivackyextern int bl_fg_color, bl_bg_color; 70206083Srdivacky#endif 71206083Srdivacky 72193323Sed 73198090Srdivacky#if LOGFILE 74193323Sed/* 75193323Sed * Handler for -o option. 76249423Sdim */ 77193323Sed public void 78193323Sedopt_o(type, s) 79193323Sed int type; 80193323Sed char *s; 81206083Srdivacky{ 82206083Srdivacky PARG parg; 83193323Sed 84193323Sed if (secure) 85206083Srdivacky { 86206083Srdivacky error("log file support is not available", NULL_PARG); 87193323Sed return; 88206083Srdivacky } 89206083Srdivacky switch (type) 90206083Srdivacky { 91206083Srdivacky case INIT: 92206083Srdivacky namelogfile = save(s); 93193323Sed break; 94206083Srdivacky case TOGGLE: 95193323Sed if (ch_getflags() & CH_CANSEEK) 96193323Sed { 97206083Srdivacky error("Input is not a pipe", NULL_PARG); 98193323Sed return; 99206083Srdivacky } 100206083Srdivacky if (logfile >= 0) 101206083Srdivacky { 102206083Srdivacky error("Log file is already in use", NULL_PARG); 103206083Srdivacky return; 104206083Srdivacky } 105206083Srdivacky s = skipsp(s); 106206083Srdivacky if (namelogfile != NULL) 107193323Sed free(namelogfile); 108193323Sed namelogfile = lglob(s); 109193323Sed use_logfile(namelogfile); 110193323Sed sync_logfile(); 111193323Sed break; 112193323Sed case QUERY: 113193323Sed if (logfile < 0) 114193323Sed error("No log file", NULL_PARG); 115193323Sed else 116193323Sed { 117193323Sed parg.p_string = namelogfile; 118193323Sed error("Log file \"%s\"", &parg); 119193323Sed } 120193323Sed break; 121193323Sed } 122193323Sed} 123193323Sed 124249423Sdim/* 125193323Sed * Handler for -O option. 126193323Sed */ 127193323Sed public void 128193323Sedopt__O(type, s) 129243830Sdim int type; 130193323Sed char *s; 131193323Sed{ 132193323Sed force_logfile = TRUE; 133193323Sed opt_o(type, s); 134193323Sed} 135206083Srdivacky#endif 136193323Sed 137193323Sed/* 138206083Srdivacky * Handlers for -j option. 139193323Sed */ 140193323Sed public void 141193323Sedopt_j(type, s) 142193323Sed int type; 143193323Sed char *s; 144193323Sed{ 145193323Sed PARG parg; 146193323Sed char buf[16]; 147193323Sed int len; 148193323Sed int err; 149210299Sed 150210299Sed switch (type) 151210299Sed { 152210299Sed case INIT: 153193323Sed case TOGGLE: 154193323Sed if (*s == '.') 155193323Sed { 156193323Sed s++; 157193323Sed jump_sline_fraction = getfraction(&s, "j", &err); 158193323Sed if (err) 159193323Sed error("Invalid line fraction", NULL_PARG); 160193323Sed else 161193323Sed calc_jump_sline(); 162193323Sed } else 163206083Srdivacky { 164206083Srdivacky int sline = getnum(&s, "j", &err); 165206083Srdivacky if (err) 166206083Srdivacky error("Invalid line number", NULL_PARG); 167243830Sdim else 168243830Sdim { 169193323Sed jump_sline = sline; 170206083Srdivacky jump_sline_fraction = -1; 171206083Srdivacky } 172193323Sed } 173206083Srdivacky break; 174206083Srdivacky case QUERY: 175206083Srdivacky if (jump_sline_fraction < 0) 176206083Srdivacky { 177206083Srdivacky parg.p_int = jump_sline; 178206083Srdivacky error("Position target at screen line %d", &parg); 179206083Srdivacky } else 180206083Srdivacky { 181193323Sed 182193323Sed sprintf(buf, ".%06d", jump_sline_fraction); 183206083Srdivacky len = (int) strlen(buf); 184206083Srdivacky while (len > 2 && buf[len-1] == '0') 185206083Srdivacky len--; 186193323Sed buf[len] = '\0'; 187193323Sed parg.p_string = buf; 188193323Sed error("Position target at screen position %s", &parg); 189193323Sed } 190193323Sed break; 191 } 192} 193 194 public void 195calc_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 206opt_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 259calc_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 268opt_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 292opt_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 333opt__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 362opt_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 398opt__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 437opt_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 460opt_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 480opt__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 535colordesc(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 572opt_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 617opt_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 675opt_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 718opt_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 737get_swindow() 738{ 739 if (swindow > 0) 740 return (swindow); 741 return (sc_height + swindow); 742} 743 744