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