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