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