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