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