1 /* 2 * Copyright (C) 1984-2009 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 about less, or for information on how to 8 * contact the author, see the README file. 9 */ 10 11 12 /* 13 * Handling functions for command line options. 14 * 15 * Most options are handled by the generic code in option.c. 16 * But all string options, and a few non-string options, require 17 * special handling specific to the particular option. 18 * This special processing is done by the "handling functions" in this file. 19 * 20 * Each handling function is passed a "type" and, if it is a string 21 * option, the string which should be "assigned" to the option. 22 * The type may be one of: 23 * INIT The option is being initialized from the command line. 24 * TOGGLE The option is being changed from within the program. 25 * QUERY The setting of the option is merely being queried. 26 */ 27 28 #include "less.h" 29 #include "option.h" 30 31 extern int nbufs; 32 extern int bufspace; 33 extern int pr_type; 34 extern int plusoption; 35 extern int swindow; 36 extern int sc_width; 37 extern int sc_height; 38 extern int secure; 39 extern int dohelp; 40 extern int any_display; 41 extern char openquote; 42 extern char closequote; 43 extern char *prproto[]; 44 extern char *eqproto; 45 extern char *hproto; 46 extern char *wproto; 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 #endif 63 #if MSDOS_COMPILER 64 extern int nm_fg_color, nm_bg_color; 65 extern int bo_fg_color, bo_bg_color; 66 extern int ul_fg_color, ul_bg_color; 67 extern int so_fg_color, so_bg_color; 68 extern int bl_fg_color, bl_bg_color; 69 #endif 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 -l option. 136 */ 137 public void 138 opt_l(type, s) 139 int type; 140 char *s; 141 { 142 int err; 143 int n; 144 char *t; 145 146 switch (type) 147 { 148 case INIT: 149 t = s; 150 n = getnum(&t, "l", &err); 151 if (err || n <= 0) 152 { 153 error("Line number is required after -l", NULL_PARG); 154 return; 155 } 156 plusoption = TRUE; 157 ungetsc(s); 158 break; 159 } 160 } 161 162 /* 163 * Handlers for -j option. 164 */ 165 public void 166 opt_j(type, s) 167 int type; 168 char *s; 169 { 170 PARG parg; 171 char buf[16]; 172 int len; 173 int err; 174 175 switch (type) 176 { 177 case INIT: 178 case TOGGLE: 179 if (*s == '.') 180 { 181 s++; 182 jump_sline_fraction = getfraction(&s, "j", &err); 183 if (err) 184 error("Invalid line fraction", NULL_PARG); 185 else 186 calc_jump_sline(); 187 } else 188 { 189 int sline = getnum(&s, "j", &err); 190 if (err) 191 error("Invalid line number", NULL_PARG); 192 else 193 { 194 jump_sline = sline; 195 jump_sline_fraction = -1; 196 } 197 } 198 break; 199 case QUERY: 200 if (jump_sline_fraction < 0) 201 { 202 parg.p_int = jump_sline; 203 error("Position target at screen line %d", &parg); 204 } else 205 { 206 207 sprintf(buf, ".%06d", jump_sline_fraction); 208 len = strlen(buf); 209 while (len > 2 && buf[len-1] == '0') 210 len--; 211 buf[len] = '\0'; 212 parg.p_string = buf; 213 error("Position target at screen position %s", &parg); 214 } 215 break; 216 } 217 } 218 219 public void 220 calc_jump_sline() 221 { 222 if (jump_sline_fraction < 0) 223 return; 224 jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM; 225 } 226 227 /* 228 * Handlers for -# option. 229 */ 230 public void 231 opt_shift(type, s) 232 int type; 233 char *s; 234 { 235 PARG parg; 236 char buf[16]; 237 int len; 238 int err; 239 240 switch (type) 241 { 242 case INIT: 243 case TOGGLE: 244 if (*s == '.') 245 { 246 s++; 247 shift_count_fraction = getfraction(&s, "#", &err); 248 if (err) 249 error("Invalid column fraction", NULL_PARG); 250 else 251 calc_shift_count(); 252 } else 253 { 254 int hs = getnum(&s, "#", &err); 255 if (err) 256 error("Invalid column number", NULL_PARG); 257 else 258 { 259 shift_count = hs; 260 shift_count_fraction = -1; 261 } 262 } 263 break; 264 case QUERY: 265 if (shift_count_fraction < 0) 266 { 267 parg.p_int = shift_count; 268 error("Horizontal shift %d columns", &parg); 269 } else 270 { 271 272 sprintf(buf, ".%06d", shift_count_fraction); 273 len = strlen(buf); 274 while (len > 2 && buf[len-1] == '0') 275 len--; 276 buf[len] = '\0'; 277 parg.p_string = buf; 278 error("Horizontal shift %s of screen width", &parg); 279 } 280 break; 281 } 282 } 283 public void 284 calc_shift_count() 285 { 286 if (shift_count_fraction < 0) 287 return; 288 shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM; 289 } 290 291 #if USERFILE 292 public void 293 opt_k(type, s) 294 int type; 295 char *s; 296 { 297 PARG parg; 298 299 switch (type) 300 { 301 case INIT: 302 if (lesskey(s, 0)) 303 { 304 parg.p_string = s; 305 error("Cannot use lesskey file \"%s\"", &parg); 306 } 307 break; 308 } 309 } 310 #endif 311 312 #if TAGS 313 /* 314 * Handler for -t option. 315 */ 316 public void 317 opt_t(type, s) 318 int type; 319 char *s; 320 { 321 IFILE save_ifile; 322 POSITION pos; 323 324 switch (type) 325 { 326 case INIT: 327 tagoption = s; 328 /* Do the rest in main() */ 329 break; 330 case TOGGLE: 331 if (secure) 332 { 333 error("tags support is not available", NULL_PARG); 334 break; 335 } 336 findtag(skipsp(s)); 337 save_ifile = save_curr_ifile(); 338 /* 339 * Try to open the file containing the tag 340 * and search for the tag in that file. 341 */ 342 if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION) 343 { 344 /* Failed: reopen the old file. */ 345 reedit_ifile(save_ifile); 346 break; 347 } 348 unsave_ifile(save_ifile); 349 jump_loc(pos, jump_sline); 350 break; 351 } 352 } 353 354 /* 355 * Handler for -T option. 356 */ 357 public void 358 opt__T(type, s) 359 int type; 360 char *s; 361 { 362 PARG parg; 363 364 switch (type) 365 { 366 case INIT: 367 tags = s; 368 break; 369 case TOGGLE: 370 s = skipsp(s); 371 tags = lglob(s); 372 break; 373 case QUERY: 374 parg.p_string = tags; 375 error("Tags file \"%s\"", &parg); 376 break; 377 } 378 } 379 #endif 380 381 /* 382 * Handler for -p option. 383 */ 384 public void 385 opt_p(type, s) 386 int type; 387 register char *s; 388 { 389 switch (type) 390 { 391 case INIT: 392 /* 393 * Unget a search command for the specified string. 394 * {{ This won't work if the "/" command is 395 * changed or invalidated by a .lesskey file. }} 396 */ 397 plusoption = TRUE; 398 ungetsc(s); 399 /* 400 * In "more" mode, the -p argument is a command, 401 * not a search string, so we don't need a slash. 402 */ 403 if (!less_is_more) 404 ungetsc("/"); 405 break; 406 } 407 } 408 409 /* 410 * Handler for -P option. 411 */ 412 public void 413 opt__P(type, s) 414 int type; 415 register char *s; 416 { 417 register char **proto; 418 PARG parg; 419 420 switch (type) 421 { 422 case INIT: 423 case TOGGLE: 424 /* 425 * Figure out which prototype string should be changed. 426 */ 427 switch (*s) 428 { 429 case 's': proto = &prproto[PR_SHORT]; s++; break; 430 case 'm': proto = &prproto[PR_MEDIUM]; s++; break; 431 case 'M': proto = &prproto[PR_LONG]; s++; break; 432 case '=': proto = &eqproto; s++; break; 433 case 'h': proto = &hproto; s++; break; 434 case 'w': proto = &wproto; s++; break; 435 default: proto = &prproto[PR_SHORT]; break; 436 } 437 free(*proto); 438 *proto = save(s); 439 break; 440 case QUERY: 441 parg.p_string = prproto[pr_type]; 442 error("%s", &parg); 443 break; 444 } 445 } 446 447 /* 448 * Handler for the -b option. 449 */ 450 /*ARGSUSED*/ 451 public void 452 opt_b(type, s) 453 int type; 454 char *s; 455 { 456 switch (type) 457 { 458 case INIT: 459 case TOGGLE: 460 /* 461 * Set the new number of buffers. 462 */ 463 ch_setbufspace(bufspace); 464 break; 465 case QUERY: 466 break; 467 } 468 } 469 470 /* 471 * Handler for the -i option. 472 */ 473 /*ARGSUSED*/ 474 public void 475 opt_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 495 opt__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 527 colordesc(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 564 opt_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 609 opt_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 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