1 /* $NetBSD: option.c,v 1.4 2013/09/04 19:44:21 tron Exp $ */ 2 3 /* 4 * Copyright (C) 1984-2012 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, see the README file. 10 */ 11 12 13 /* 14 * Process command line options. 15 * 16 * Each option is a single letter which controls a program variable. 17 * The options have defaults which may be changed via 18 * the command line option, toggled via the "-" command, 19 * or queried via the "_" command. 20 */ 21 22 #include "less.h" 23 #include "option.h" 24 25 static struct loption *pendopt; 26 public int plusoption = FALSE; 27 28 static char *optstring __P((char *, char **, char *, char *)); 29 static int flip_triple __P((int, int)); 30 static void nostring __P((char *)); 31 32 extern int screen_trashed; 33 extern int less_is_more; 34 extern int quit_at_eof; 35 extern char *every_first_cmd; 36 extern int opt_use_backslash; 37 38 /* 39 * Return a printable description of an option. 40 */ 41 static char * 42 opt_desc(o) 43 struct loption *o; 44 { 45 static char buf[OPTNAME_MAX + 10]; 46 if (o->oletter == OLETTER_NONE) 47 SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname); 48 else 49 SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname); 50 return (buf); 51 } 52 53 /* 54 * Return a string suitable for printing as the "name" of an option. 55 * For example, if the option letter is 'x', just return "-x". 56 */ 57 public char * 58 propt(c) 59 int c; 60 { 61 static char buf[8]; 62 63 sprintf(buf, "-%s", prchar(c)); 64 return (buf); 65 } 66 67 /* 68 * Scan an argument (either from the command line or from the 69 * LESS environment variable) and process it. 70 */ 71 public void 72 scan_option(s) 73 char *s; 74 { 75 register struct loption *o; 76 register int optc; 77 char *optname; 78 char *printopt; 79 char *str; 80 int set_default; 81 int lc; 82 int err; 83 PARG parg; 84 85 if (s == NULL) 86 return; 87 88 /* 89 * If we have a pending option which requires an argument, 90 * handle it now. 91 * This happens if the previous option was, for example, "-P" 92 * without a following string. In that case, the current 93 * option is simply the argument for the previous option. 94 */ 95 if (pendopt != NULL) 96 { 97 switch (pendopt->otype & OTYPE) 98 { 99 case STRING: 100 (*pendopt->ofunc)(INIT, s); 101 break; 102 case NUMBER: 103 printopt = opt_desc(pendopt); 104 *(pendopt->ovar) = getnum(&s, printopt, (int*)NULL); 105 break; 106 } 107 pendopt = NULL; 108 return; 109 } 110 111 set_default = FALSE; 112 optname = NULL; 113 114 while (*s != '\0') 115 { 116 /* 117 * Check some special cases first. 118 */ 119 switch (optc = *s++) 120 { 121 case ' ': 122 case '\t': 123 case END_OPTION_STRING: 124 continue; 125 case '-': 126 /* 127 * "--" indicates an option name instead of a letter. 128 */ 129 if (*s == '-') 130 { 131 optname = ++s; 132 break; 133 } 134 /* 135 * "-+" means set these options back to their defaults. 136 * (They may have been set otherwise by previous 137 * options.) 138 */ 139 set_default = (*s == '+'); 140 if (set_default) 141 s++; 142 continue; 143 case '+': 144 /* 145 * An option prefixed by a "+" is ungotten, so 146 * that it is interpreted as less commands 147 * processed at the start of the first input file. 148 * "++" means process the commands at the start of 149 * EVERY input file. 150 */ 151 plusoption = TRUE; 152 s = optstring(s, &str, propt('+'), NULL); 153 if (s == NULL) 154 return; 155 if (*str == '+') 156 every_first_cmd = save(str+1); 157 else 158 ungetsc(str); 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 register 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 if (*(o->ovar) < 0) 460 error("Negative option is invalid", NULL_PARG); 461 /* 462 * Print the odesc message. 463 */ 464 error(o->odesc[*(o->ovar)], NULL_PARG); 465 break; 466 case NUMBER: 467 /* 468 * The message is in odesc[1] and has a %d for 469 * the value of the variable. 470 */ 471 parg.p_int = *(o->ovar); 472 error(o->odesc[1], &parg); 473 break; 474 case STRING: 475 /* 476 * Message was already printed by the handling function. 477 */ 478 break; 479 } 480 } 481 482 if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) 483 screen_trashed = TRUE; 484 } 485 486 /* 487 * "Toggle" a triple-valued option. 488 */ 489 static int 490 flip_triple(val, lc) 491 int val; 492 int lc; 493 { 494 if (lc) 495 return ((val == OPT_ON) ? OPT_OFF : OPT_ON); 496 else 497 return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS); 498 } 499 500 /* 501 * Determine if an option takes a parameter. 502 */ 503 public int 504 opt_has_param(o) 505 struct loption *o; 506 { 507 if (o == NULL) 508 return (0); 509 if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) 510 return (0); 511 return (1); 512 } 513 514 /* 515 * Return the prompt to be used for a given option letter. 516 * Only string and number valued options have prompts. 517 */ 518 public char * 519 opt_prompt(o) 520 struct loption *o; 521 { 522 if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) 523 return ("?"); 524 return (o->odesc[0]); 525 } 526 527 /* 528 * Return whether or not there is a string option pending; 529 * that is, if the previous option was a string-valued option letter 530 * (like -P) without a following string. 531 * In that case, the current option is taken to be the string for 532 * the previous option. 533 */ 534 public int 535 isoptpending() 536 { 537 return (pendopt != NULL); 538 } 539 540 /* 541 * Print error message about missing string. 542 */ 543 static void 544 nostring(printopt) 545 char *printopt; 546 { 547 PARG parg; 548 parg.p_string = printopt; 549 error("Value is required after %s", &parg); 550 } 551 552 /* 553 * Print error message if a STRING type option is not followed by a string. 554 */ 555 public void 556 nopendopt() 557 { 558 nostring(opt_desc(pendopt)); 559 } 560 561 /* 562 * Scan to end of string or to an END_OPTION_STRING character. 563 * In the latter case, replace the char with a null char. 564 * Return a pointer to the remainder of the string, if any. 565 */ 566 static char * 567 optstring(s, p_str, printopt, validchars) 568 char *s; 569 char **p_str; 570 char *printopt; 571 char *validchars; 572 { 573 register char *p; 574 register char *out; 575 576 if (*s == '\0') 577 { 578 nostring(printopt); 579 return (NULL); 580 } 581 /* Alloc could be more than needed, but not worth trimming. */ 582 *p_str = (char *) ecalloc(strlen(s)+1, sizeof(char)); 583 out = *p_str; 584 585 for (p = s; *p != '\0'; p++) 586 { 587 if (opt_use_backslash && *p == '\\' && p[1] != '\0') 588 { 589 /* Take next char literally. */ 590 ++p; 591 } else 592 { 593 if (*p == END_OPTION_STRING || 594 (validchars != NULL && strchr(validchars, *p) == NULL)) 595 /* End of option string. */ 596 break; 597 } 598 *out++ = *p; 599 } 600 *out = '\0'; 601 return (p); 602 } 603 604 /* 605 */ 606 static int 607 num_error(printopt, errp) 608 char *printopt; 609 int *errp; 610 { 611 PARG parg; 612 613 if (errp != NULL) 614 { 615 *errp = TRUE; 616 return (-1); 617 } 618 if (printopt != NULL) 619 { 620 parg.p_string = printopt; 621 error("Number is required after %s", &parg); 622 } 623 return (-1); 624 } 625 626 /* 627 * Translate a string into a number. 628 * Like atoi(), but takes a pointer to a char *, and updates 629 * the char * to point after the translated number. 630 */ 631 public int 632 getnum(sp, printopt, errp) 633 char **sp; 634 char *printopt; 635 int *errp; 636 { 637 register char *s; 638 register int n; 639 register int neg; 640 641 s = skipsp(*sp); 642 neg = FALSE; 643 if (*s == '-') 644 { 645 neg = TRUE; 646 s++; 647 } 648 if (*s < '0' || *s > '9') 649 return (num_error(printopt, errp)); 650 651 n = 0; 652 while (*s >= '0' && *s <= '9') 653 n = 10 * n + *s++ - '0'; 654 *sp = s; 655 if (errp != NULL) 656 *errp = FALSE; 657 if (neg) 658 n = -n; 659 return (n); 660 } 661 662 /* 663 * Translate a string into a fraction, represented by the part of a 664 * number which would follow a decimal point. 665 * The value of the fraction is returned as parts per NUM_FRAC_DENOM. 666 * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM. 667 */ 668 public long 669 getfraction(sp, printopt, errp) 670 char **sp; 671 char *printopt; 672 int *errp; 673 { 674 register char *s; 675 long frac = 0; 676 int fraclen = 0; 677 678 s = skipsp(*sp); 679 if (*s < '0' || *s > '9') 680 return (num_error(printopt, errp)); 681 682 for ( ; *s >= '0' && *s <= '9'; s++) 683 { 684 frac = (frac * 10) + (*s - '0'); 685 fraclen++; 686 } 687 if (fraclen > NUM_LOG_FRAC_DENOM) 688 while (fraclen-- > NUM_LOG_FRAC_DENOM) 689 frac /= 10; 690 else 691 while (fraclen++ < NUM_LOG_FRAC_DENOM) 692 frac *= 10; 693 *sp = s; 694 if (errp != NULL) 695 *errp = FALSE; 696 return (frac); 697 } 698 699 700 /* 701 * Get the value of the -e flag. 702 */ 703 public int 704 get_quit_at_eof() 705 { 706 if (!less_is_more) 707 return quit_at_eof; 708 /* When less_is_more is set, the -e flag semantics are different. */ 709 return quit_at_eof ? OPT_ON : OPT_ONPLUS; 710 } 711