Annotation of src/usr.bin/less/option.c, Revision 1.1
1.1 ! etheisen 1: /*
! 2: * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice in the documentation and/or other materials provided with
! 12: * the distribution.
! 13: *
! 14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
! 15: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 16: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 17: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
! 18: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 19: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
! 20: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
! 21: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
! 23: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
! 24: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 25: */
! 26:
! 27:
! 28: /*
! 29: * Process command line options.
! 30: *
! 31: * Each option is a single letter which controls a program variable.
! 32: * The options have defaults which may be changed via
! 33: * the command line option, toggled via the "-" command,
! 34: * or queried via the "_" command.
! 35: */
! 36:
! 37: #include "less.h"
! 38: #include "option.h"
! 39:
! 40: static struct option *pendopt;
! 41: public int plusoption = FALSE;
! 42:
! 43: static char *propt();
! 44: static char *optstring();
! 45: static int flip_triple();
! 46:
! 47: extern int screen_trashed;
! 48: extern char *every_first_cmd;
! 49:
! 50: /*
! 51: * Scan an argument (either from the command line or from the
! 52: * LESS environment variable) and process it.
! 53: */
! 54: public void
! 55: scan_option(s)
! 56: char *s;
! 57: {
! 58: register struct option *o;
! 59: register int c;
! 60: char *str;
! 61: int set_default;
! 62: PARG parg;
! 63:
! 64: if (s == NULL)
! 65: return;
! 66:
! 67: /*
! 68: * If we have a pending string-valued option, handle it now.
! 69: * This happens if the previous option was, for example, "-P"
! 70: * without a following string. In that case, the current
! 71: * option is simply the string for the previous option.
! 72: */
! 73: if (pendopt != NULL)
! 74: {
! 75: (*pendopt->ofunc)(INIT, s);
! 76: pendopt = NULL;
! 77: return;
! 78: }
! 79:
! 80: set_default = FALSE;
! 81:
! 82: while (*s != '\0')
! 83: {
! 84: /*
! 85: * Check some special cases first.
! 86: */
! 87: switch (c = *s++)
! 88: {
! 89: case ' ':
! 90: case '\t':
! 91: case END_OPTION_STRING:
! 92: continue;
! 93: case '-':
! 94: /*
! 95: * "-+" means set these options back to their defaults.
! 96: * (They may have been set otherwise by previous
! 97: * options.)
! 98: */
! 99: if (set_default = (*s == '+'))
! 100: s++;
! 101: continue;
! 102: case '+':
! 103: /*
! 104: * An option prefixed by a "+" is ungotten, so
! 105: * that it is interpreted as less commands
! 106: * processed at the start of the first input file.
! 107: * "++" means process the commands at the start of
! 108: * EVERY input file.
! 109: */
! 110: plusoption = TRUE;
! 111: if (*s == '+')
! 112: every_first_cmd = save(++s);
! 113: else
! 114: ungetsc(s);
! 115: s = optstring(s, c);
! 116: continue;
! 117: case '0': case '1': case '2': case '3': case '4':
! 118: case '5': case '6': case '7': case '8': case '9':
! 119: /*
! 120: * Special "more" compatibility form "-<number>"
! 121: * instead of -z<number> to set the scrolling
! 122: * window size.
! 123: */
! 124: s--;
! 125: c = 'z';
! 126: break;
! 127: }
! 128:
! 129: /*
! 130: * Not a special case.
! 131: * Look up the option letter in the option table.
! 132: */
! 133: o = findopt(c);
! 134: if (o == NULL)
! 135: {
! 136: parg.p_string = propt(c);
! 137: #if MSOFTC || OS2
! 138: error("There is no %s flag (\"less -?\" for help)",
! 139: &parg);
! 140: #else
! 141: error("There is no %s flag (\"less -\\?\" for help)",
! 142: &parg);
! 143: #endif
! 144: quit(QUIT_ERROR);
! 145: }
! 146:
! 147: switch (o->otype & OTYPE)
! 148: {
! 149: case BOOL:
! 150: if (set_default)
! 151: *(o->ovar) = o->odefault;
! 152: else
! 153: *(o->ovar) = ! o->odefault;
! 154: break;
! 155: case TRIPLE:
! 156: if (set_default)
! 157: *(o->ovar) = o->odefault;
! 158: else
! 159: *(o->ovar) = flip_triple(o->odefault,
! 160: (o->oletter == c));
! 161: break;
! 162: case STRING:
! 163: if (*s == '\0')
! 164: {
! 165: /*
! 166: * Set pendopt and return.
! 167: * We will get the string next time
! 168: * scan_option is called.
! 169: */
! 170: pendopt = o;
! 171: return;
! 172: }
! 173: /*
! 174: * Don't do anything here.
! 175: * All processing of STRING options is done by
! 176: * the handling function.
! 177: */
! 178: str = s;
! 179: s = optstring(s, c);
! 180: break;
! 181: case NUMBER:
! 182: *(o->ovar) = getnum(&s, c, (int*)NULL);
! 183: break;
! 184: }
! 185: /*
! 186: * If the option has a handling function, call it.
! 187: */
! 188: if (o->ofunc != NULL)
! 189: (*o->ofunc)(INIT, str);
! 190: }
! 191: }
! 192:
! 193: /*
! 194: * Toggle command line flags from within the program.
! 195: * Used by the "-" and "_" commands.
! 196: * how_toggle may be:
! 197: * OPT_NO_TOGGLE just report the current setting, without changing it.
! 198: * OPT_TOGGLE invert the current setting
! 199: * OPT_UNSET set to the default value
! 200: * OPT_SET set to the inverse of the default value
! 201: */
! 202: public void
! 203: toggle_option(c, s, how_toggle)
! 204: int c;
! 205: char *s;
! 206: int how_toggle;
! 207: {
! 208: register struct option *o;
! 209: register int num;
! 210: int err;
! 211: PARG parg;
! 212:
! 213: /*
! 214: * Look up the option letter in the option table.
! 215: */
! 216: o = findopt(c);
! 217: if (o == NULL)
! 218: {
! 219: parg.p_string = propt(c);
! 220: error("There is no %s flag", &parg);
! 221: return;
! 222: }
! 223:
! 224: if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
! 225: {
! 226: parg.p_string = propt(c);
! 227: error("Cannot change the %s flag", &parg);
! 228: return;
! 229: }
! 230:
! 231: if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
! 232: {
! 233: parg.p_string = propt(c);
! 234: error("Cannot query the %s flag", &parg);
! 235: return;
! 236: }
! 237:
! 238: /*
! 239: * Check for something which appears to be a do_toggle
! 240: * (because the "-" command was used), but really is not.
! 241: * This could be a string option with no string, or
! 242: * a number option with no number.
! 243: */
! 244: switch (o->otype & OTYPE)
! 245: {
! 246: case STRING:
! 247: case NUMBER:
! 248: if (how_toggle == OPT_TOGGLE && *s == '\0')
! 249: how_toggle = OPT_NO_TOGGLE;
! 250: break;
! 251: }
! 252:
! 253: #if HILITE_SEARCH
! 254: if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
! 255: repaint_hilite(0);
! 256: #endif
! 257:
! 258: /*
! 259: * Now actually toggle (change) the variable.
! 260: */
! 261: if (how_toggle != OPT_NO_TOGGLE)
! 262: {
! 263: switch (o->otype & OTYPE)
! 264: {
! 265: case BOOL:
! 266: /*
! 267: * Boolean.
! 268: */
! 269: switch (how_toggle)
! 270: {
! 271: case OPT_TOGGLE:
! 272: *(o->ovar) = ! *(o->ovar);
! 273: break;
! 274: case OPT_UNSET:
! 275: *(o->ovar) = o->odefault;
! 276: break;
! 277: case OPT_SET:
! 278: *(o->ovar) = ! o->odefault;
! 279: break;
! 280: }
! 281: break;
! 282: case TRIPLE:
! 283: /*
! 284: * Triple:
! 285: * If user gave the lower case letter, then switch
! 286: * to 1 unless already 1, in which case make it 0.
! 287: * If user gave the upper case letter, then switch
! 288: * to 2 unless already 2, in which case make it 0.
! 289: */
! 290: switch (how_toggle)
! 291: {
! 292: case OPT_TOGGLE:
! 293: *(o->ovar) = flip_triple(*(o->ovar),
! 294: o->oletter == c);
! 295: break;
! 296: case OPT_UNSET:
! 297: *(o->ovar) = o->odefault;
! 298: break;
! 299: case OPT_SET:
! 300: *(o->ovar) = flip_triple(o->odefault,
! 301: o->oletter == c);
! 302: break;
! 303: }
! 304: break;
! 305: case STRING:
! 306: /*
! 307: * String: don't do anything here.
! 308: * The handling function will do everything.
! 309: */
! 310: switch (how_toggle)
! 311: {
! 312: case OPT_SET:
! 313: case OPT_UNSET:
! 314: error("Can't use \"-+\" or \"--\" for a string flag",
! 315: NULL_PARG);
! 316: return;
! 317: }
! 318: break;
! 319: case NUMBER:
! 320: /*
! 321: * Number: set the variable to the given number.
! 322: */
! 323: switch (how_toggle)
! 324: {
! 325: case OPT_TOGGLE:
! 326: num = getnum(&s, '\0', &err);
! 327: if (!err)
! 328: *(o->ovar) = num;
! 329: break;
! 330: case OPT_UNSET:
! 331: *(o->ovar) = o->odefault;
! 332: break;
! 333: case OPT_SET:
! 334: error("Can't use \"--\" for a numeric flag",
! 335: NULL_PARG);
! 336: return;
! 337: }
! 338: break;
! 339: }
! 340: }
! 341:
! 342: /*
! 343: * Call the handling function for any special action
! 344: * specific to this option.
! 345: */
! 346: if (o->ofunc != NULL)
! 347: (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
! 348:
! 349: #if HILITE_SEARCH
! 350: if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
! 351: chg_hilite();
! 352: #endif
! 353:
! 354: /*
! 355: * Print a message describing the new setting.
! 356: */
! 357: switch (o->otype & OTYPE)
! 358: {
! 359: case BOOL:
! 360: case TRIPLE:
! 361: /*
! 362: * Print the odesc message.
! 363: */
! 364: error(o->odesc[*(o->ovar)], NULL_PARG);
! 365: break;
! 366: case NUMBER:
! 367: /*
! 368: * The message is in odesc[1] and has a %d for
! 369: * the value of the variable.
! 370: */
! 371: parg.p_int = *(o->ovar);
! 372: error(o->odesc[1], &parg);
! 373: break;
! 374: case STRING:
! 375: /*
! 376: * Message was already printed by the handling function.
! 377: */
! 378: break;
! 379: }
! 380:
! 381: if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
! 382: screen_trashed = TRUE;
! 383: }
! 384:
! 385: /*
! 386: * "Toggle" a triple-valued option.
! 387: */
! 388: static int
! 389: flip_triple(val, lc)
! 390: int val;
! 391: int lc;
! 392: {
! 393: if (lc)
! 394: return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
! 395: else
! 396: return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
! 397: }
! 398:
! 399: /*
! 400: * Return a string suitable for printing as the "name" of an option.
! 401: * For example, if the option letter is 'x', just return "-x".
! 402: */
! 403: static char *
! 404: propt(c)
! 405: int c;
! 406: {
! 407: static char buf[8];
! 408:
! 409: sprintf(buf, "-%s", prchar(c));
! 410: return (buf);
! 411: }
! 412:
! 413: /*
! 414: * Determine if an option is a single character option (BOOL or TRIPLE),
! 415: * or if it a multi-character option (NUMBER).
! 416: */
! 417: public int
! 418: single_char_option(c)
! 419: int c;
! 420: {
! 421: register struct option *o;
! 422:
! 423: o = findopt(c);
! 424: if (o == NULL)
! 425: return (TRUE);
! 426: return ((o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) != 0);
! 427: }
! 428:
! 429: /*
! 430: * Return the prompt to be used for a given option letter.
! 431: * Only string and number valued options have prompts.
! 432: */
! 433: public char *
! 434: opt_prompt(c)
! 435: int c;
! 436: {
! 437: register struct option *o;
! 438:
! 439: o = findopt(c);
! 440: if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
! 441: return (NULL);
! 442: return (o->odesc[0]);
! 443: }
! 444:
! 445: /*
! 446: * Return whether or not there is a string option pending;
! 447: * that is, if the previous option was a string-valued option letter
! 448: * (like -P) without a following string.
! 449: * In that case, the current option is taken to be the string for
! 450: * the previous option.
! 451: */
! 452: public int
! 453: isoptpending()
! 454: {
! 455: return (pendopt != NULL);
! 456: }
! 457:
! 458: /*
! 459: * Print error message about missing string.
! 460: */
! 461: static void
! 462: nostring(c)
! 463: int c;
! 464: {
! 465: PARG parg;
! 466: parg.p_string = propt(c);
! 467: error("String is required after %s", &parg);
! 468: }
! 469:
! 470: /*
! 471: * Print error message if a STRING type option is not followed by a string.
! 472: */
! 473: public void
! 474: nopendopt()
! 475: {
! 476: nostring(pendopt->oletter);
! 477: }
! 478:
! 479: /*
! 480: * Scan to end of string or to an END_OPTION_STRING character.
! 481: * In the latter case, replace the char with a null char.
! 482: * Return a pointer to the remainder of the string, if any.
! 483: */
! 484: static char *
! 485: optstring(s, c)
! 486: char *s;
! 487: int c;
! 488: {
! 489: register char *p;
! 490:
! 491: if (*s == '\0')
! 492: {
! 493: nostring(c);
! 494: quit(QUIT_ERROR);
! 495: }
! 496: for (p = s; *p != '\0'; p++)
! 497: if (*p == END_OPTION_STRING)
! 498: {
! 499: *p = '\0';
! 500: return (p+1);
! 501: }
! 502: return (p);
! 503: }
! 504:
! 505: /*
! 506: * Translate a string into a number.
! 507: * Like atoi(), but takes a pointer to a char *, and updates
! 508: * the char * to point after the translated number.
! 509: */
! 510: public int
! 511: getnum(sp, c, errp)
! 512: char **sp;
! 513: int c;
! 514: int *errp;
! 515: {
! 516: register char *s;
! 517: register int n;
! 518: register int neg;
! 519: PARG parg;
! 520:
! 521: s = skipsp(*sp);
! 522: neg = FALSE;
! 523: if (*s == '-')
! 524: {
! 525: neg = TRUE;
! 526: s++;
! 527: }
! 528: if (*s < '0' || *s > '9')
! 529: {
! 530: if (errp != NULL)
! 531: {
! 532: *errp = TRUE;
! 533: return (-1);
! 534: }
! 535: parg.p_string = propt(c);
! 536: error("Number is required after %s", &parg);
! 537: quit(QUIT_ERROR);
! 538: }
! 539:
! 540: n = 0;
! 541: while (*s >= '0' && *s <= '9')
! 542: n = 10 * n + *s++ - '0';
! 543: *sp = s;
! 544: if (errp != NULL)
! 545: *errp = FALSE;
! 546: if (neg)
! 547: n = -n;
! 548: return (n);
! 549: }