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