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 * Process command line options. 13 * 14 * Each option is a single letter which controls a program variable. 15 * The options have defaults which may be changed via 16 * the command line option, toggled via the "-" command, 17 * or queried via the "_" command. 18 */ 19 20 #include "less.h" 21 #include "option.h" 22 23 static struct loption *pendopt; 24 public int plusoption = FALSE; 25 26 static char *optstring(); 27 static int flip_triple(); 28 29 extern int screen_trashed; 30 extern int less_is_more; 31 extern int quit_at_eof; 32 extern char *every_first_cmd; 33 34 /* 35 * Return a printable description of an option. 36 */ 37 static char * 38 opt_desc(o) 39 struct loption *o; 40 { 41 static char buf[OPTNAME_MAX + 10]; 42 if (o->oletter == OLETTER_NONE) 43 SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname); 44 else 45 SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname); 46 return (buf); 47 } 48 49 /* 50 * Return a string suitable for printing as the "name" of an option. 51 * For example, if the option letter is 'x', just return "-x". 52 */ 53 public char * 54 propt(c) 55 int c; 56 { 57 static char buf[8]; 58 59 sprintf(buf, "-%s", prchar(c)); 60 return (buf); 61 } 62 63 /* 64 * Scan an argument (either from the command line or from the 65 * LESS environment variable) and process it. 66 */ 67 public void 68 scan_option(s) 69 char *s; 70 { 71 register struct loption *o; 72 register int optc; 73 char *optname; 74 char *printopt; 75 char *str; 76 int set_default; 77 int lc; 78 int err; 79 PARG parg; 80 81 if (s == NULL) 82 return; 83 84 /* 85 * If we have a pending option which requires an argument, 86 * handle it now. 87 * This happens if the previous option was, for example, "-P" 88 * without a following string. In that case, the current 89 * option is simply the argument for the previous option. 90 */ 91 if (pendopt != NULL) 92 { 93 switch (pendopt->otype & OTYPE) 94 { 95 case STRING: 96 (*pendopt->ofunc)(INIT, s); 97 break; 98 case NUMBER: 99 printopt = opt_desc(pendopt); 100 *(pendopt->ovar) = getnum(&s, printopt, (int*)NULL); 101 break; 102 } 103 pendopt = NULL; 104 return; 105 } 106 107 set_default = FALSE; 108 optname = NULL; 109 110 while (*s != '\0') 111 { 112 /* 113 * Check some special cases first. 114 */ 115 switch (optc = *s++) 116 { 117 case ' ': 118 case '\t': 119 case END_OPTION_STRING: 120 continue; 121 case '-': 122 /* 123 * "--" indicates an option name instead of a letter. 124 */ 125 if (*s == '-') 126 { 127 optname = ++s; 128 break; 129 } 130 /* 131 * "-+" means set these options back to their defaults. 132 * (They may have been set otherwise by previous 133 * options.) 134 */ 135 set_default = (*s == '+'); 136 if (set_default) 137 s++; 138 continue; 139 case '+': 140 /* 141 * An option prefixed by a "+" is ungotten, so 142 * that it is interpreted as less commands 143 * processed at the start of the first input file. 144 * "++" means process the commands at the start of 145 * EVERY input file. 146 */ 147 plusoption = TRUE; 148 s = optstring(s, &str, propt('+'), NULL); 149 if (*str == '+') 150 every_first_cmd = save(++str); 151 else 152 ungetsc(str); 153 continue; 154 case '0': case '1': case '2': case '3': case '4': 155 case '5': case '6': case '7': case '8': case '9': 156 /* 157 * Special "more" compatibility form "-<number>" 158 * instead of -z<number> to set the scrolling 159 * window size. 160 */ 161 s--; 162 optc = 'z'; 163 break; 164 case 'n': 165 if (less_is_more) 166 optc = 'z'; 167 break; 168 } 169 170 /* 171 * Not a special case. 172 * Look up the option letter in the option table. 173 */ 174 err = 0; 175 if (optname == NULL) 176 { 177 printopt = propt(optc); 178 lc = ASCII_IS_LOWER(optc); 179 o = findopt(optc); 180 } else 181 { 182 printopt = optname; 183 lc = ASCII_IS_LOWER(optname[0]); 184 o = findopt_name(&optname, NULL, &err); 185 s = optname; 186 optname = NULL; 187 if (*s == '\0' || *s == ' ') 188 { 189 /* 190 * The option name matches exactly. 191 */ 192 ; 193 } else if (*s == '=') 194 { 195 /* 196 * The option name is followed by "=value". 197 */ 198 if (o != NULL && 199 (o->otype & OTYPE) != STRING && 200 (o->otype & OTYPE) != NUMBER) 201 { 202 parg.p_string = printopt; 203 error("The %s option should not be followed by =", 204 &parg); 205 quit(QUIT_ERROR); 206 } 207 s++; 208 } else 209 { 210 /* 211 * The specified name is longer than the 212 * real option name. 213 */ 214 o = NULL; 215 } 216 } 217 if (o == NULL) 218 { 219 parg.p_string = printopt; 220 if (err == OPT_AMBIG) 221 error("%s is an ambiguous abbreviation (\"less --help\" for help)", 222 &parg); 223 else 224 error("There is no %s option (\"less --help\" for help)", 225 &parg); 226 quit(QUIT_ERROR); 227 } 228 229 str = NULL; 230 switch (o->otype & OTYPE) 231 { 232 case BOOL: 233 if (set_default) 234 *(o->ovar) = o->odefault; 235 else 236 *(o->ovar) = ! o->odefault; 237 break; 238 case TRIPLE: 239 if (set_default) 240 *(o->ovar) = o->odefault; 241 else 242 *(o->ovar) = flip_triple(o->odefault, lc); 243 break; 244 case STRING: 245 if (*s == '\0') 246 { 247 /* 248 * Set pendopt and return. 249 * We will get the string next time 250 * scan_option is called. 251 */ 252 pendopt = o; 253 return; 254 } 255 /* 256 * Don't do anything here. 257 * All processing of STRING options is done by 258 * the handling function. 259 */ 260 while (*s == ' ') 261 s++; 262 s = optstring(s, &str, printopt, o->odesc[1]); 263 break; 264 case NUMBER: 265 if (*s == '\0') 266 { 267 pendopt = o; 268 return; 269 } 270 *(o->ovar) = getnum(&s, printopt, (int*)NULL); 271 break; 272 } 273 /* 274 * If the option has a handling function, call it. 275 */ 276 if (o->ofunc != NULL) 277 (*o->ofunc)(INIT, str); 278 } 279 } 280 281 /* 282 * Toggle command line flags from within the program. 283 * Used by the "-" and "_" commands. 284 * how_toggle may be: 285 * OPT_NO_TOGGLE just report the current setting, without changing it. 286 * OPT_TOGGLE invert the current setting 287 * OPT_UNSET set to the default value 288 * OPT_SET set to the inverse of the default value 289 */ 290 public void 291 toggle_option(o, lower, s, how_toggle) 292 struct loption *o; 293 int lower; 294 char *s; 295 int how_toggle; 296 { 297 register int num; 298 int no_prompt; 299 int err; 300 PARG parg; 301 302 no_prompt = (how_toggle & OPT_NO_PROMPT); 303 how_toggle &= ~OPT_NO_PROMPT; 304 305 if (o == NULL) 306 { 307 error("No such option", NULL_PARG); 308 return; 309 } 310 311 if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE)) 312 { 313 parg.p_string = opt_desc(o); 314 error("Cannot change the %s option", &parg); 315 return; 316 } 317 318 if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY)) 319 { 320 parg.p_string = opt_desc(o); 321 error("Cannot query the %s option", &parg); 322 return; 323 } 324 325 /* 326 * Check for something which appears to be a do_toggle 327 * (because the "-" command was used), but really is not. 328 * This could be a string option with no string, or 329 * a number option with no number. 330 */ 331 switch (o->otype & OTYPE) 332 { 333 case STRING: 334 case NUMBER: 335 if (how_toggle == OPT_TOGGLE && *s == '\0') 336 how_toggle = OPT_NO_TOGGLE; 337 break; 338 } 339 340 #if HILITE_SEARCH 341 if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 342 repaint_hilite(0); 343 #endif 344 345 /* 346 * Now actually toggle (change) the variable. 347 */ 348 if (how_toggle != OPT_NO_TOGGLE) 349 { 350 switch (o->otype & OTYPE) 351 { 352 case BOOL: 353 /* 354 * Boolean. 355 */ 356 switch (how_toggle) 357 { 358 case OPT_TOGGLE: 359 *(o->ovar) = ! *(o->ovar); 360 break; 361 case OPT_UNSET: 362 *(o->ovar) = o->odefault; 363 break; 364 case OPT_SET: 365 *(o->ovar) = ! o->odefault; 366 break; 367 } 368 break; 369 case TRIPLE: 370 /* 371 * Triple: 372 * If user gave the lower case letter, then switch 373 * to 1 unless already 1, in which case make it 0. 374 * If user gave the upper case letter, then switch 375 * to 2 unless already 2, in which case make it 0. 376 */ 377 switch (how_toggle) 378 { 379 case OPT_TOGGLE: 380 *(o->ovar) = flip_triple(*(o->ovar), lower); 381 break; 382 case OPT_UNSET: 383 *(o->ovar) = o->odefault; 384 break; 385 case OPT_SET: 386 *(o->ovar) = flip_triple(o->odefault, lower); 387 break; 388 } 389 break; 390 case STRING: 391 /* 392 * String: don't do anything here. 393 * The handling function will do everything. 394 */ 395 switch (how_toggle) 396 { 397 case OPT_SET: 398 case OPT_UNSET: 399 error("Cannot use \"-+\" or \"--\" for a string option", 400 NULL_PARG); 401 return; 402 } 403 break; 404 case NUMBER: 405 /* 406 * Number: set the variable to the given number. 407 */ 408 switch (how_toggle) 409 { 410 case OPT_TOGGLE: 411 num = getnum(&s, NULL, &err); 412 if (!err) 413 *(o->ovar) = num; 414 break; 415 case OPT_UNSET: 416 *(o->ovar) = o->odefault; 417 break; 418 case OPT_SET: 419 error("Can't use \"-!\" for a numeric option", 420 NULL_PARG); 421 return; 422 } 423 break; 424 } 425 } 426 427 /* 428 * Call the handling function for any special action 429 * specific to this option. 430 */ 431 if (o->ofunc != NULL) 432 (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s); 433 434 #if HILITE_SEARCH 435 if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) 436 chg_hilite(); 437 #endif 438 439 if (!no_prompt) 440 { 441 /* 442 * Print a message describing the new setting. 443 */ 444 switch (o->otype & OTYPE) 445 { 446 case BOOL: 447 case TRIPLE: 448 /* 449 * Print the odesc message. 450 */ 451 error(o->odesc[*(o->ovar)], NULL_PARG); 452 break; 453 case NUMBER: 454 /* 455 * The message is in odesc[1] and has a %d for 456 * the value of the variable. 457 */ 458 parg.p_int = *(o->ovar); 459 error(o->odesc[1], &parg); 460 break; 461 case STRING: 462 /* 463 * Message was already printed by the handling function. 464 */ 465 break; 466 } 467 } 468 469 if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) 470 screen_trashed = TRUE; 471 } 472 473 /* 474 * "Toggle" a triple-valued option. 475 */ 476 static int 477 flip_triple(val, lc) 478 int val; 479 int lc; 480 { 481 if (lc) 482 return ((val == OPT_ON) ? OPT_OFF : OPT_ON); 483 else 484 return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS); 485 } 486 487 /* 488 * Determine if an option takes a parameter. 489 */ 490 public int 491 opt_has_param(o) 492 struct loption *o; 493 { 494 if (o == NULL) 495 return (0); 496 if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) 497 return (0); 498 return (1); 499 } 500 501 /* 502 * Return the prompt to be used for a given option letter. 503 * Only string and number valued options have prompts. 504 */ 505 public char * 506 opt_prompt(o) 507 struct loption *o; 508 { 509 if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) 510 return ("?"); 511 return (o->odesc[0]); 512 } 513 514 /* 515 * Return whether or not there is a string option pending; 516 * that is, if the previous option was a string-valued option letter 517 * (like -P) without a following string. 518 * In that case, the current option is taken to be the string for 519 * the previous option. 520 */ 521 public int 522 isoptpending() 523 { 524 return (pendopt != NULL); 525 } 526 527 /* 528 * Print error message about missing string. 529 */ 530 static void 531 nostring(printopt) 532 char *printopt; 533 { 534 PARG parg; 535 parg.p_string = printopt; 536 error("Value is required after %s", &parg); 537 } 538 539 /* 540 * Print error message if a STRING type option is not followed by a string. 541 */ 542 public void 543 nopendopt() 544 { 545 nostring(opt_desc(pendopt)); 546 } 547 548 /* 549 * Scan to end of string or to an END_OPTION_STRING character. 550 * In the latter case, replace the char with a null char. 551 * Return a pointer to the remainder of the string, if any. 552 */ 553 static char * 554 optstring(s, p_str, printopt, validchars) 555 char *s; 556 char **p_str; 557 char *printopt; 558 char *validchars; 559 { 560 register char *p; 561 562 if (*s == '\0') 563 { 564 nostring(printopt); 565 quit(QUIT_ERROR); 566 } 567 *p_str = s; 568 for (p = s; *p != '\0'; p++) 569 { 570 if (*p == END_OPTION_STRING || 571 (validchars != NULL && strchr(validchars, *p) == NULL)) 572 { 573 switch (*p) 574 { 575 case END_OPTION_STRING: 576 case ' ': case '\t': case '-': 577 /* Replace the char with a null to terminate string. */ 578 *p++ = '\0'; 579 break; 580 default: 581 /* Cannot replace char; make a copy of the string. */ 582 *p_str = (char *) ecalloc(p-s+1, sizeof(char)); 583 strncpy(*p_str, s, p-s); 584 (*p_str)[p-s] = '\0'; 585 break; 586 } 587 break; 588 } 589 } 590 return (p); 591 } 592 593 /* 594 */ 595 static int 596 num_error(printopt, errp) 597 char *printopt; 598 int *errp; 599 { 600 PARG parg; 601 602 if (errp != NULL) 603 { 604 *errp = TRUE; 605 return (-1); 606 } 607 if (printopt != NULL) 608 { 609 parg.p_string = printopt; 610 error("Number is required after %s", &parg); 611 } 612 quit(QUIT_ERROR); 613 /* NOTREACHED */ 614 return (-1); 615 } 616 617 /* 618 * Translate a string into a number. 619 * Like atoi(), but takes a pointer to a char *, and updates 620 * the char * to point after the translated number. 621 */ 622 public int 623 getnum(sp, printopt, errp) 624 char **sp; 625 char *printopt; 626 int *errp; 627 { 628 register char *s; 629 register int n; 630 register int neg; 631 632 s = skipsp(*sp); 633 neg = FALSE; 634 if (*s == '-') 635 { 636 neg = TRUE; 637 s++; 638 } 639 if (*s < '0' || *s > '9') 640 return (num_error(printopt, errp)); 641 642 n = 0; 643 while (*s >= '0' && *s <= '9') 644 n = 10 * n + *s++ - '0'; 645 *sp = s; 646 if (errp != NULL) 647 *errp = FALSE; 648 if (neg) 649 n = -n; 650 return (n); 651 } 652 653 /* 654 * Translate a string into a fraction, represented by the part of a 655 * number which would follow a decimal point. 656 * The value of the fraction is returned as parts per NUM_FRAC_DENOM. 657 * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM. 658 */ 659 public long 660 getfraction(sp, printopt, errp) 661 char **sp; 662 char *printopt; 663 int *errp; 664 { 665 register char *s; 666 long frac = 0; 667 int fraclen = 0; 668 669 s = skipsp(*sp); 670 if (*s < '0' || *s > '9') 671 return (num_error(printopt, errp)); 672 673 for ( ; *s >= '0' && *s <= '9'; s++) 674 { 675 frac = (frac * 10) + (*s - '0'); 676 fraclen++; 677 } 678 if (fraclen > NUM_LOG_FRAC_DENOM) 679 while (fraclen-- > NUM_LOG_FRAC_DENOM) 680 frac /= 10; 681 else 682 while (fraclen++ < NUM_LOG_FRAC_DENOM) 683 frac *= 10; 684 *sp = s; 685 if (errp != NULL) 686 *errp = FALSE; 687 return (frac); 688 } 689 690 691 /* 692 * Get the value of the -e flag. 693 */ 694 public int 695 get_quit_at_eof() 696 { 697 if (!less_is_more) 698 return quit_at_eof; 699 /* When less_is_more is set, the -e flag semantics are different. */ 700 return quit_at_eof ? OPT_ON : OPT_ONPLUS; 701 } 702