optfunc.c revision 221715
1238384Sjkim/* 2238384Sjkim * Copyright (C) 1984-2011 Mark Nudelman 3238384Sjkim * 4238384Sjkim * You may distribute under the terms of either the GNU General Public 5238384Sjkim * License or the Less License, as specified in the README file. 6238384Sjkim * 7238384Sjkim * For more information about less, or for information on how to 8238384Sjkim * contact the author, see the README file. 9238384Sjkim */ 10238384Sjkim 11238384Sjkim 12238384Sjkim/* 13238384Sjkim * Handling functions for command line options. 14238384Sjkim * 15238384Sjkim * Most options are handled by the generic code in option.c. 16238384Sjkim * But all string options, and a few non-string options, require 17238384Sjkim * special handling specific to the particular option. 18238384Sjkim * This special processing is done by the "handling functions" in this file. 19238384Sjkim * 20238384Sjkim * Each handling function is passed a "type" and, if it is a string 21238384Sjkim * option, the string which should be "assigned" to the option. 22238384Sjkim * The type may be one of: 23238384Sjkim * INIT The option is being initialized from the command line. 24238384Sjkim * TOGGLE The option is being changed from within the program. 25238384Sjkim * QUERY The setting of the option is merely being queried. 26238384Sjkim */ 27238384Sjkim 28238384Sjkim#include "less.h" 29238384Sjkim#include "option.h" 30238384Sjkim 31238384Sjkimextern int nbufs; 32238384Sjkimextern int bufspace; 33238384Sjkimextern int pr_type; 34238384Sjkimextern int plusoption; 35238384Sjkimextern int swindow; 36238384Sjkimextern int sc_width; 37238384Sjkimextern int sc_height; 38238384Sjkimextern int secure; 39238384Sjkimextern int dohelp; 40238384Sjkimextern int any_display; 41238384Sjkimextern char openquote; 42238384Sjkimextern char closequote; 43238384Sjkimextern char *prproto[]; 44238384Sjkimextern char *eqproto; 45238384Sjkimextern char *hproto; 46238384Sjkimextern char *wproto; 47238384Sjkimextern IFILE curr_ifile; 48238384Sjkimextern char version[]; 49238384Sjkimextern int jump_sline; 50238384Sjkimextern int jump_sline_fraction; 51238384Sjkimextern int shift_count; 52238384Sjkimextern int shift_count_fraction; 53238384Sjkimextern int less_is_more; 54238384Sjkim#if LOGFILE 55238384Sjkimextern char *namelogfile; 56238384Sjkimextern int force_logfile; 57238384Sjkimextern int logfile; 58238384Sjkim#endif 59238384Sjkim#if TAGS 60238384Sjkimpublic char *tagoption = NULL; 61238384Sjkimextern char *tags; 62238384Sjkim#endif 63238384Sjkim#if MSDOS_COMPILER 64238384Sjkimextern int nm_fg_color, nm_bg_color; 65238384Sjkimextern int bo_fg_color, bo_bg_color; 66238384Sjkimextern int ul_fg_color, ul_bg_color; 67238384Sjkimextern int so_fg_color, so_bg_color; 68238384Sjkimextern int bl_fg_color, bl_bg_color; 69238384Sjkim#endif 70238384Sjkim 71238384Sjkim 72238384Sjkim#if LOGFILE 73238384Sjkim/* 74238384Sjkim * Handler for -o option. 75238384Sjkim */ 76238384Sjkim public void 77238384Sjkimopt_o(type, s) 78238384Sjkim int type; 79238384Sjkim char *s; 80238384Sjkim{ 81238384Sjkim PARG parg; 82238384Sjkim 83238384Sjkim if (secure) 84238384Sjkim { 85238384Sjkim error("log file support is not available", NULL_PARG); 86238384Sjkim return; 87238384Sjkim } 88238384Sjkim switch (type) 89238384Sjkim { 90238384Sjkim case INIT: 91238384Sjkim namelogfile = s; 92238384Sjkim break; 93238384Sjkim case TOGGLE: 94238384Sjkim if (ch_getflags() & CH_CANSEEK) 95238384Sjkim { 96238384Sjkim error("Input is not a pipe", NULL_PARG); 97238384Sjkim return; 98238384Sjkim } 99238384Sjkim if (logfile >= 0) 100238384Sjkim { 101238384Sjkim error("Log file is already in use", NULL_PARG); 102238384Sjkim return; 103238384Sjkim } 104238384Sjkim s = skipsp(s); 105238384Sjkim namelogfile = lglob(s); 106238384Sjkim use_logfile(namelogfile); 107238384Sjkim sync_logfile(); 108238384Sjkim break; 109238384Sjkim case QUERY: 110238384Sjkim if (logfile < 0) 111238384Sjkim error("No log file", NULL_PARG); 112238384Sjkim else 113238384Sjkim { 114238384Sjkim parg.p_string = namelogfile; 115238384Sjkim error("Log file \"%s\"", &parg); 116238384Sjkim } 117238384Sjkim break; 118238384Sjkim } 119238384Sjkim} 120238384Sjkim 121238384Sjkim/* 122238384Sjkim * Handler for -O option. 123238384Sjkim */ 124238384Sjkim public void 125238384Sjkimopt__O(type, s) 126238384Sjkim int type; 127238384Sjkim char *s; 128238384Sjkim{ 129238384Sjkim force_logfile = TRUE; 130238384Sjkim opt_o(type, s); 131238384Sjkim} 132238384Sjkim#endif 133238384Sjkim 134238384Sjkim/* 135238384Sjkim * Handlers for -l option. 136238384Sjkim */ 137238384Sjkim public void 138238384Sjkimopt_l(type, s) 139238384Sjkim int type; 140238384Sjkim char *s; 141238384Sjkim{ 142238384Sjkim int err; 143238384Sjkim int n; 144238384Sjkim char *t; 145238384Sjkim 146238384Sjkim switch (type) 147238384Sjkim { 148238384Sjkim case INIT: 149238384Sjkim t = s; 150238384Sjkim n = getnum(&t, "l", &err); 151238384Sjkim if (err || n <= 0) 152238384Sjkim { 153238384Sjkim error("Line number is required after -l", NULL_PARG); 154238384Sjkim return; 155238384Sjkim } 156238384Sjkim plusoption = TRUE; 157238384Sjkim ungetsc(s); 158238384Sjkim break; 159238384Sjkim } 160238384Sjkim} 161238384Sjkim 162238384Sjkim/* 163238384Sjkim * Handlers for -j option. 164238384Sjkim */ 165238384Sjkim public void 166238384Sjkimopt_j(type, s) 167238384Sjkim int type; 168238384Sjkim char *s; 169238384Sjkim{ 170238384Sjkim PARG parg; 171238384Sjkim char buf[16]; 172238384Sjkim int len; 173238384Sjkim int err; 174238384Sjkim 175238384Sjkim switch (type) 176238384Sjkim { 177238384Sjkim case INIT: 178238384Sjkim case TOGGLE: 179238384Sjkim if (*s == '.') 180238384Sjkim { 181238384Sjkim s++; 182238384Sjkim jump_sline_fraction = getfraction(&s, "j", &err); 183238384Sjkim if (err) 184238384Sjkim error("Invalid line fraction", NULL_PARG); 185238384Sjkim else 186238384Sjkim calc_jump_sline(); 187238384Sjkim } else 188238384Sjkim { 189238384Sjkim int sline = getnum(&s, "j", &err); 190238384Sjkim if (err) 191238384Sjkim error("Invalid line number", NULL_PARG); 192238384Sjkim else 193238384Sjkim { 194238384Sjkim jump_sline = sline; 195238384Sjkim jump_sline_fraction = -1; 196238384Sjkim } 197238384Sjkim } 198238384Sjkim break; 199238384Sjkim case QUERY: 200238384Sjkim if (jump_sline_fraction < 0) 201238384Sjkim { 202238384Sjkim parg.p_int = jump_sline; 203238384Sjkim error("Position target at screen line %d", &parg); 204238384Sjkim } else 205238384Sjkim { 206238384Sjkim 207238384Sjkim sprintf(buf, ".%06d", jump_sline_fraction); 208238384Sjkim len = strlen(buf); 209238384Sjkim while (len > 2 && buf[len-1] == '0') 210238384Sjkim len--; 211238384Sjkim buf[len] = '\0'; 212238384Sjkim parg.p_string = buf; 213238384Sjkim error("Position target at screen position %s", &parg); 214238384Sjkim } 215238384Sjkim break; 216238384Sjkim } 217238384Sjkim} 218238384Sjkim 219238384Sjkim public void 220238384Sjkimcalc_jump_sline() 221238384Sjkim{ 222238384Sjkim if (jump_sline_fraction < 0) 223238384Sjkim return; 224238384Sjkim jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM; 225238384Sjkim} 226238384Sjkim 227238384Sjkim/* 228238384Sjkim * Handlers for -# option. 229238384Sjkim */ 230238384Sjkim public void 231238384Sjkimopt_shift(type, s) 232238384Sjkim int type; 233238384Sjkim char *s; 234238384Sjkim{ 235238384Sjkim PARG parg; 236238384Sjkim char buf[16]; 237238384Sjkim int len; 238238384Sjkim int err; 239238384Sjkim 240238384Sjkim switch (type) 241238384Sjkim { 242238384Sjkim case INIT: 243238384Sjkim case TOGGLE: 244238384Sjkim if (*s == '.') 245238384Sjkim { 246238384Sjkim s++; 247238384Sjkim shift_count_fraction = getfraction(&s, "#", &err); 248238384Sjkim if (err) 249238384Sjkim error("Invalid column fraction", NULL_PARG); 250238384Sjkim else 251238384Sjkim calc_shift_count(); 252238384Sjkim } else 253238384Sjkim { 254238384Sjkim int hs = getnum(&s, "#", &err); 255238384Sjkim if (err) 256238384Sjkim error("Invalid column number", NULL_PARG); 257238384Sjkim else 258238384Sjkim { 259238384Sjkim shift_count = hs; 260238384Sjkim shift_count_fraction = -1; 261279264Sdelphij } 262279264Sdelphij } 263279264Sdelphij break; 264279264Sdelphij case QUERY: 265279264Sdelphij if (shift_count_fraction < 0) 266279264Sdelphij { 267238384Sjkim parg.p_int = shift_count; 268238384Sjkim error("Horizontal shift %d columns", &parg); 269238384Sjkim } else 270238384Sjkim { 271238384Sjkim 272238384Sjkim sprintf(buf, ".%06d", shift_count_fraction); 273238384Sjkim len = strlen(buf); 274238384Sjkim while (len > 2 && buf[len-1] == '0') 275238384Sjkim len--; 276238384Sjkim buf[len] = '\0'; 277238384Sjkim parg.p_string = buf; 278238384Sjkim error("Horizontal shift %s of screen width", &parg); 279238384Sjkim } 280238384Sjkim break; 281238384Sjkim } 282238384Sjkim} 283238384Sjkim public void 284238384Sjkimcalc_shift_count() 285238384Sjkim{ 286238384Sjkim if (shift_count_fraction < 0) 287238384Sjkim return; 288238384Sjkim shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM; 289238384Sjkim} 290238384Sjkim 291238384Sjkim#if USERFILE 292238384Sjkim public void 293238384Sjkimopt_k(type, s) 294238384Sjkim int type; 295238384Sjkim char *s; 296238384Sjkim{ 297238384Sjkim PARG parg; 298238384Sjkim 299238384Sjkim switch (type) 300238384Sjkim { 301238384Sjkim case INIT: 302238384Sjkim if (lesskey(s, 0)) 303238384Sjkim { 304238384Sjkim parg.p_string = s; 305238384Sjkim error("Cannot use lesskey file \"%s\"", &parg); 306238384Sjkim } 307238384Sjkim break; 308238384Sjkim } 309238384Sjkim} 310238384Sjkim#endif 311238384Sjkim 312238384Sjkim#if TAGS 313238384Sjkim/* 314238384Sjkim * Handler for -t option. 315238384Sjkim */ 316238384Sjkim public void 317238384Sjkimopt_t(type, s) 318238384Sjkim int type; 319238384Sjkim char *s; 320238384Sjkim{ 321238384Sjkim IFILE save_ifile; 322238384Sjkim POSITION pos; 323238384Sjkim 324238384Sjkim switch (type) 325238384Sjkim { 326238384Sjkim case INIT: 327238384Sjkim tagoption = s; 328238384Sjkim /* Do the rest in main() */ 329238384Sjkim break; 330238384Sjkim case TOGGLE: 331238384Sjkim if (secure) 332238384Sjkim { 333238384Sjkim error("tags support is not available", NULL_PARG); 334238384Sjkim break; 335238384Sjkim } 336238384Sjkim findtag(skipsp(s)); 337238384Sjkim save_ifile = save_curr_ifile(); 338238384Sjkim /* 339238384Sjkim * Try to open the file containing the tag 340238384Sjkim * and search for the tag in that file. 341238384Sjkim */ 342238384Sjkim if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION) 343238384Sjkim { 344238384Sjkim /* Failed: reopen the old file. */ 345238384Sjkim reedit_ifile(save_ifile); 346238384Sjkim break; 347238384Sjkim } 348238384Sjkim unsave_ifile(save_ifile); 349238384Sjkim jump_loc(pos, jump_sline); 350238384Sjkim break; 351238384Sjkim } 352238384Sjkim} 353238384Sjkim 354238384Sjkim/* 355238384Sjkim * Handler for -T option. 356238384Sjkim */ 357238384Sjkim public void 358238384Sjkimopt__T(type, s) 359238384Sjkim int type; 360238384Sjkim char *s; 361238384Sjkim{ 362238384Sjkim PARG parg; 363238384Sjkim 364238384Sjkim switch (type) 365238384Sjkim { 366238384Sjkim case INIT: 367238384Sjkim tags = s; 368238384Sjkim break; 369238384Sjkim case TOGGLE: 370238384Sjkim s = skipsp(s); 371238384Sjkim tags = lglob(s); 372238384Sjkim break; 373238384Sjkim case QUERY: 374238384Sjkim parg.p_string = tags; 375238384Sjkim error("Tags file \"%s\"", &parg); 376238384Sjkim break; 377238384Sjkim } 378238384Sjkim} 379238384Sjkim#endif 380238384Sjkim 381238384Sjkim/* 382238384Sjkim * Handler for -p option. 383238384Sjkim */ 384238384Sjkim public void 385238384Sjkimopt_p(type, s) 386238384Sjkim int type; 387238384Sjkim register char *s; 388238384Sjkim{ 389238384Sjkim switch (type) 390238384Sjkim { 391238384Sjkim case INIT: 392238384Sjkim /* 393238384Sjkim * Unget a search command for the specified string. 394238384Sjkim * {{ This won't work if the "/" command is 395238384Sjkim * changed or invalidated by a .lesskey file. }} 396238384Sjkim */ 397238384Sjkim plusoption = TRUE; 398238384Sjkim ungetsc(s); 399238384Sjkim /* 400238384Sjkim * In "more" mode, the -p argument is a command, 401238384Sjkim * not a search string, so we don't need a slash. 402238384Sjkim */ 403238384Sjkim if (!less_is_more) 404238384Sjkim ungetsc("/"); 405238384Sjkim break; 406238384Sjkim } 407238384Sjkim} 408238384Sjkim 409238384Sjkim/* 410238384Sjkim * Handler for -P option. 411238384Sjkim */ 412238384Sjkim public void 413238384Sjkimopt__P(type, s) 414238384Sjkim int type; 415238384Sjkim register char *s; 416238384Sjkim{ 417238384Sjkim register char **proto; 418238384Sjkim PARG parg; 419238384Sjkim 420238384Sjkim switch (type) 421238384Sjkim { 422238384Sjkim case INIT: 423238384Sjkim case TOGGLE: 424238384Sjkim /* 425238384Sjkim * Figure out which prototype string should be changed. 426238384Sjkim */ 427238384Sjkim switch (*s) 428238384Sjkim { 429238384Sjkim case 's': proto = &prproto[PR_SHORT]; s++; break; 430238384Sjkim case 'm': proto = &prproto[PR_MEDIUM]; s++; break; 431238384Sjkim case 'M': proto = &prproto[PR_LONG]; s++; break; 432238384Sjkim case '=': proto = &eqproto; s++; break; 433238384Sjkim case 'h': proto = &hproto; s++; break; 434238384Sjkim case 'w': proto = &wproto; s++; break; 435238384Sjkim default: proto = &prproto[PR_SHORT]; break; 436238384Sjkim } 437238384Sjkim free(*proto); 438238384Sjkim *proto = save(s); 439238384Sjkim break; 440238384Sjkim case QUERY: 441238384Sjkim parg.p_string = prproto[pr_type]; 442238384Sjkim error("%s", &parg); 443238384Sjkim break; 444238384Sjkim } 445238384Sjkim} 446238384Sjkim 447238384Sjkim/* 448238384Sjkim * Handler for the -b option. 449238384Sjkim */ 450238384Sjkim /*ARGSUSED*/ 451238384Sjkim public void 452238384Sjkimopt_b(type, s) 453238384Sjkim int type; 454238384Sjkim char *s; 455238384Sjkim{ 456238384Sjkim switch (type) 457238384Sjkim { 458238384Sjkim case INIT: 459238384Sjkim case TOGGLE: 460238384Sjkim /* 461238384Sjkim * Set the new number of buffers. 462238384Sjkim */ 463238384Sjkim ch_setbufspace(bufspace); 464238384Sjkim break; 465238384Sjkim case QUERY: 466 break; 467 } 468} 469 470/* 471 * Handler for the -i option. 472 */ 473 /*ARGSUSED*/ 474 public void 475opt_i(type, s) 476 int type; 477 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 495opt__V(type, s) 496 int type; 497 char *s; 498{ 499 switch (type) 500 { 501 case TOGGLE: 502 case QUERY: 503 dispversion(); 504 break; 505 case INIT: 506 /* 507 * Force output to stdout per GNU standard for --version output. 508 */ 509 any_display = 1; 510 putstr("less "); 511 putstr(version); 512 putstr("\nCopyright (C) 1984-2009 Mark Nudelman\n\n"); 513 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n"); 514 putstr("For information about the terms of redistribution,\n"); 515 putstr("see the file named README in the less distribution.\n"); 516 putstr("Homepage: http://www.greenwoodsoftware.com/less\n"); 517 quit(QUIT_OK); 518 break; 519 } 520} 521 522#if MSDOS_COMPILER 523/* 524 * Parse an MSDOS color descriptor. 525 */ 526 static void 527colordesc(s, fg_color, bg_color) 528 char *s; 529 int *fg_color; 530 int *bg_color; 531{ 532 int fg, bg; 533 int err; 534 535 fg = getnum(&s, "D", &err); 536 if (err) 537 { 538 error("Missing fg color in -D", NULL_PARG); 539 return; 540 } 541 if (*s != '.') 542 bg = nm_bg_color; 543 else 544 { 545 s++; 546 bg = getnum(&s, "D", &err); 547 if (err) 548 { 549 error("Missing bg color in -D", NULL_PARG); 550 return; 551 } 552 } 553 if (*s != '\0') 554 error("Extra characters at end of -D option", NULL_PARG); 555 *fg_color = fg; 556 *bg_color = bg; 557} 558 559/* 560 * Handler for the -D option. 561 */ 562 /*ARGSUSED*/ 563 public void 564opt_D(type, s) 565 int type; 566 char *s; 567{ 568 switch (type) 569 { 570 case INIT: 571 case TOGGLE: 572 switch (*s++) 573 { 574 case 'n': 575 colordesc(s, &nm_fg_color, &nm_bg_color); 576 break; 577 case 'd': 578 colordesc(s, &bo_fg_color, &bo_bg_color); 579 break; 580 case 'u': 581 colordesc(s, &ul_fg_color, &ul_bg_color); 582 break; 583 case 'k': 584 colordesc(s, &bl_fg_color, &bl_bg_color); 585 break; 586 case 's': 587 colordesc(s, &so_fg_color, &so_bg_color); 588 break; 589 default: 590 error("-D must be followed by n, d, u, k or s", NULL_PARG); 591 break; 592 } 593 if (type == TOGGLE) 594 { 595 at_enter(AT_STANDOUT); 596 at_exit(); 597 } 598 break; 599 case QUERY: 600 break; 601 } 602} 603#endif 604 605/* 606 * Handler for the -x option. 607 */ 608 public void 609opt_x(type, s) 610 int type; 611 register char *s; 612{ 613 extern int tabstops[]; 614 extern int ntabstops; 615 extern int tabdefault; 616 char msg[60+(4*TABSTOP_MAX)]; 617 int i; 618 PARG p; 619 620 switch (type) 621 { 622 case INIT: 623 case TOGGLE: 624 /* Start at 1 because tabstops[0] is always zero. */ 625 for (i = 1; i < TABSTOP_MAX; ) 626 { 627 int n = 0; 628 s = skipsp(s); 629 while (*s >= '0' && *s <= '9') 630 n = (10 * n) + (*s++ - '0'); 631 if (n > tabstops[i-1]) 632 tabstops[i++] = n; 633 s = skipsp(s); 634 if (*s++ != ',') 635 break; 636 } 637 if (i < 2) 638 return; 639 ntabstops = i; 640 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2]; 641 break; 642 case QUERY: 643 strcpy(msg, "Tab stops "); 644 if (ntabstops > 2) 645 { 646 for (i = 1; i < ntabstops; i++) 647 { 648 if (i > 1) 649 strcat(msg, ","); 650 sprintf(msg+strlen(msg), "%d", tabstops[i]); 651 } 652 sprintf(msg+strlen(msg), " and then "); 653 } 654 sprintf(msg+strlen(msg), "every %d spaces", 655 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 667opt_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 710opt_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 729get_swindow() 730{ 731 if (swindow > 0) 732 return (swindow); 733 return (sc_height + swindow); 734} 735 736