Annotation of src/usr.bin/less/option.c, Revision 1.9
1.1 etheisen 1: /*
1.8 shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.1 etheisen 3: *
1.5 millert 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.
1.1 etheisen 6: *
1.8 shadchin 7: * For more information, see the README file.
1.1 etheisen 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:
1.5 millert 23: static struct loption *pendopt;
1.1 etheisen 24: public int plusoption = FALSE;
25:
26: static char *optstring();
27: static int flip_triple();
28:
29: extern int screen_trashed;
1.7 shadchin 30: extern int less_is_more;
31: extern int quit_at_eof;
1.1 etheisen 32: extern char *every_first_cmd;
1.8 shadchin 33: extern int opt_use_backslash;
1.1 etheisen 34:
1.7 shadchin 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: snprintf(buf, sizeof(buf), "-%s", prchar(c));
61: return (buf);
62: }
63:
1.1 etheisen 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: {
1.5 millert 72: register struct loption *o;
73: register int optc;
74: char *optname;
75: char *printopt;
1.1 etheisen 76: char *str;
77: int set_default;
1.5 millert 78: int lc;
79: int err;
1.1 etheisen 80: PARG parg;
81:
82: if (s == NULL)
83: return;
84:
85: /*
1.5 millert 86: * If we have a pending option which requires an argument,
87: * handle it now.
1.1 etheisen 88: * This happens if the previous option was, for example, "-P"
89: * without a following string. In that case, the current
1.5 millert 90: * option is simply the argument for the previous option.
1.1 etheisen 91: */
92: if (pendopt != NULL)
93: {
1.5 millert 94: switch (pendopt->otype & OTYPE)
95: {
96: case STRING:
97: (*pendopt->ofunc)(INIT, s);
98: break;
99: case NUMBER:
1.7 shadchin 100: printopt = opt_desc(pendopt);
1.5 millert 101: *(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
102: break;
103: }
1.1 etheisen 104: pendopt = NULL;
105: return;
106: }
107:
108: set_default = FALSE;
1.5 millert 109: optname = NULL;
1.1 etheisen 110:
111: while (*s != '\0')
112: {
113: /*
114: * Check some special cases first.
115: */
1.5 millert 116: switch (optc = *s++)
1.1 etheisen 117: {
118: case ' ':
119: case '\t':
120: case END_OPTION_STRING:
121: continue;
122: case '-':
1.6 millert 123: #if GNU_OPTIONS
1.1 etheisen 124: /*
1.5 millert 125: * "--" indicates an option name instead of a letter.
126: */
127: if (*s == '-')
128: {
129: optname = ++s;
130: break;
131: }
1.6 millert 132: #endif
1.5 millert 133: /*
1.1 etheisen 134: * "-+" means set these options back to their defaults.
135: * (They may have been set otherwise by previous
136: * options.)
137: */
1.5 millert 138: set_default = (*s == '+');
139: if (set_default)
1.1 etheisen 140: s++;
141: continue;
142: case '+':
143: /*
144: * An option prefixed by a "+" is ungotten, so
145: * that it is interpreted as less commands
146: * processed at the start of the first input file.
147: * "++" means process the commands at the start of
148: * EVERY input file.
149: */
150: plusoption = TRUE;
1.5 millert 151: s = optstring(s, &str, propt('+'), NULL);
1.8 shadchin 152: if (s == NULL)
153: return;
1.5 millert 154: if (*str == '+')
1.8 shadchin 155: every_first_cmd = save(str+1);
1.1 etheisen 156: else
1.5 millert 157: ungetsc(str);
1.8 shadchin 158: free(str);
1.1 etheisen 159: continue;
160: case '0': case '1': case '2': case '3': case '4':
161: case '5': case '6': case '7': case '8': case '9':
162: /*
163: * Special "more" compatibility form "-<number>"
164: * instead of -z<number> to set the scrolling
165: * window size.
166: */
167: s--;
1.5 millert 168: optc = 'z';
1.1 etheisen 169: break;
1.7 shadchin 170: case 'n':
171: if (less_is_more)
172: optc = 'z';
173: break;
1.1 etheisen 174: }
175:
176: /*
177: * Not a special case.
178: * Look up the option letter in the option table.
179: */
1.5 millert 180: err = 0;
181: if (optname == NULL)
182: {
183: printopt = propt(optc);
1.7 shadchin 184: lc = ASCII_IS_LOWER(optc);
1.5 millert 185: o = findopt(optc);
1.6 millert 186: }
187: #if GNU_OPTIONS
188: else
1.5 millert 189: {
190: printopt = optname;
1.7 shadchin 191: lc = ASCII_IS_LOWER(optname[0]);
1.5 millert 192: o = findopt_name(&optname, NULL, &err);
193: s = optname;
194: optname = NULL;
195: if (*s == '\0' || *s == ' ')
196: {
197: /*
198: * The option name matches exactly.
199: */
200: ;
201: } else if (*s == '=')
202: {
203: /*
204: * The option name is followed by "=value".
205: */
206: if (o != NULL &&
207: (o->otype & OTYPE) != STRING &&
208: (o->otype & OTYPE) != NUMBER)
209: {
210: parg.p_string = printopt;
211: error("The %s option should not be followed by =",
212: &parg);
1.8 shadchin 213: return;
1.5 millert 214: }
215: s++;
216: } else
217: {
218: /*
219: * The specified name is longer than the
220: * real option name.
221: */
222: o = NULL;
223: }
224: }
1.6 millert 225: #endif
1.1 etheisen 226: if (o == NULL)
227: {
1.5 millert 228: parg.p_string = printopt;
229: if (err == OPT_AMBIG)
230: error("%s is an ambiguous abbreviation (\"less --help\" for help)",
231: &parg);
232: else
233: error("There is no %s option (\"less --help\" for help)",
234: &parg);
1.8 shadchin 235: return;
1.1 etheisen 236: }
237:
1.5 millert 238: str = NULL;
1.1 etheisen 239: switch (o->otype & OTYPE)
240: {
241: case BOOL:
242: if (set_default)
243: *(o->ovar) = o->odefault;
244: else
245: *(o->ovar) = ! o->odefault;
246: break;
247: case TRIPLE:
248: if (set_default)
249: *(o->ovar) = o->odefault;
250: else
1.5 millert 251: *(o->ovar) = flip_triple(o->odefault, lc);
1.1 etheisen 252: break;
253: case STRING:
254: if (*s == '\0')
255: {
256: /*
257: * Set pendopt and return.
258: * We will get the string next time
259: * scan_option is called.
260: */
261: pendopt = o;
262: return;
263: }
264: /*
265: * Don't do anything here.
266: * All processing of STRING options is done by
267: * the handling function.
268: */
1.5 millert 269: while (*s == ' ')
270: s++;
271: s = optstring(s, &str, printopt, o->odesc[1]);
1.8 shadchin 272: if (s == NULL)
273: return;
1.1 etheisen 274: break;
275: case NUMBER:
1.5 millert 276: if (*s == '\0')
277: {
278: pendopt = o;
279: return;
280: }
281: *(o->ovar) = getnum(&s, printopt, (int*)NULL);
1.1 etheisen 282: break;
283: }
284: /*
285: * If the option has a handling function, call it.
286: */
287: if (o->ofunc != NULL)
288: (*o->ofunc)(INIT, str);
1.8 shadchin 289: if (str != NULL)
290: free(str);
1.1 etheisen 291: }
292: }
293:
294: /*
295: * Toggle command line flags from within the program.
296: * Used by the "-" and "_" commands.
297: * how_toggle may be:
298: * OPT_NO_TOGGLE just report the current setting, without changing it.
299: * OPT_TOGGLE invert the current setting
300: * OPT_UNSET set to the default value
301: * OPT_SET set to the inverse of the default value
302: */
303: public void
1.7 shadchin 304: toggle_option(o, lower, s, how_toggle)
305: struct loption *o;
306: int lower;
1.1 etheisen 307: char *s;
308: int how_toggle;
309: {
1.5 millert 310: register int num;
311: int no_prompt;
1.1 etheisen 312: int err;
313: PARG parg;
314:
1.5 millert 315: no_prompt = (how_toggle & OPT_NO_PROMPT);
316: how_toggle &= ~OPT_NO_PROMPT;
317:
1.1 etheisen 318: if (o == NULL)
319: {
1.7 shadchin 320: error("No such option", NULL_PARG);
1.1 etheisen 321: return;
322: }
323:
324: if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
325: {
1.7 shadchin 326: parg.p_string = opt_desc(o);
1.5 millert 327: error("Cannot change the %s option", &parg);
1.1 etheisen 328: return;
1.7 shadchin 329: }
1.1 etheisen 330:
331: if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
332: {
1.7 shadchin 333: parg.p_string = opt_desc(o);
1.5 millert 334: error("Cannot query the %s option", &parg);
1.1 etheisen 335: return;
336: }
337:
338: /*
339: * Check for something which appears to be a do_toggle
340: * (because the "-" command was used), but really is not.
341: * This could be a string option with no string, or
342: * a number option with no number.
343: */
344: switch (o->otype & OTYPE)
345: {
346: case STRING:
347: case NUMBER:
348: if (how_toggle == OPT_TOGGLE && *s == '\0')
349: how_toggle = OPT_NO_TOGGLE;
350: break;
351: }
352:
353: #if HILITE_SEARCH
354: if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
355: repaint_hilite(0);
356: #endif
357:
358: /*
359: * Now actually toggle (change) the variable.
360: */
361: if (how_toggle != OPT_NO_TOGGLE)
362: {
363: switch (o->otype & OTYPE)
364: {
365: case BOOL:
366: /*
367: * Boolean.
368: */
369: switch (how_toggle)
370: {
371: case OPT_TOGGLE:
372: *(o->ovar) = ! *(o->ovar);
373: break;
374: case OPT_UNSET:
375: *(o->ovar) = o->odefault;
376: break;
377: case OPT_SET:
378: *(o->ovar) = ! o->odefault;
379: break;
380: }
381: break;
382: case TRIPLE:
383: /*
384: * Triple:
385: * If user gave the lower case letter, then switch
386: * to 1 unless already 1, in which case make it 0.
387: * If user gave the upper case letter, then switch
388: * to 2 unless already 2, in which case make it 0.
389: */
390: switch (how_toggle)
391: {
392: case OPT_TOGGLE:
1.7 shadchin 393: *(o->ovar) = flip_triple(*(o->ovar), lower);
1.1 etheisen 394: break;
395: case OPT_UNSET:
396: *(o->ovar) = o->odefault;
397: break;
398: case OPT_SET:
1.7 shadchin 399: *(o->ovar) = flip_triple(o->odefault, lower);
1.1 etheisen 400: break;
401: }
402: break;
403: case STRING:
404: /*
405: * String: don't do anything here.
406: * The handling function will do everything.
407: */
408: switch (how_toggle)
409: {
410: case OPT_SET:
411: case OPT_UNSET:
1.5 millert 412: error("Cannot use \"-+\" or \"--\" for a string option",
1.1 etheisen 413: NULL_PARG);
414: return;
415: }
416: break;
417: case NUMBER:
418: /*
419: * Number: set the variable to the given number.
420: */
421: switch (how_toggle)
422: {
423: case OPT_TOGGLE:
1.5 millert 424: num = getnum(&s, NULL, &err);
1.1 etheisen 425: if (!err)
426: *(o->ovar) = num;
427: break;
428: case OPT_UNSET:
429: *(o->ovar) = o->odefault;
430: break;
431: case OPT_SET:
1.5 millert 432: error("Can't use \"-!\" for a numeric option",
1.1 etheisen 433: NULL_PARG);
434: return;
435: }
436: break;
437: }
438: }
439:
440: /*
441: * Call the handling function for any special action
442: * specific to this option.
443: */
444: if (o->ofunc != NULL)
445: (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
446:
447: #if HILITE_SEARCH
448: if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
449: chg_hilite();
450: #endif
451:
1.5 millert 452: if (!no_prompt)
1.1 etheisen 453: {
454: /*
1.5 millert 455: * Print a message describing the new setting.
1.1 etheisen 456: */
1.5 millert 457: switch (o->otype & OTYPE)
458: {
459: case BOOL:
460: case TRIPLE:
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: }
1.1 etheisen 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: /*
1.7 shadchin 501: * Determine if an option takes a parameter.
1.1 etheisen 502: */
503: public int
1.7 shadchin 504: opt_has_param(o)
505: struct loption *o;
1.1 etheisen 506: {
507: if (o == NULL)
1.7 shadchin 508: return (0);
509: if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
510: return (0);
511: return (1);
1.1 etheisen 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 *
1.7 shadchin 519: opt_prompt(o)
520: struct loption *o;
1.1 etheisen 521: {
522: if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
1.7 shadchin 523: return ("?");
1.1 etheisen 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
1.5 millert 544: nostring(printopt)
545: char *printopt;
1.1 etheisen 546: {
547: PARG parg;
1.5 millert 548: parg.p_string = printopt;
549: error("Value is required after %s", &parg);
1.1 etheisen 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: {
1.7 shadchin 558: nostring(opt_desc(pendopt));
1.1 etheisen 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 *
1.5 millert 567: optstring(s, p_str, printopt, validchars)
1.1 etheisen 568: char *s;
1.5 millert 569: char **p_str;
570: char *printopt;
571: char *validchars;
1.1 etheisen 572: {
1.5 millert 573: register char *p;
1.8 shadchin 574: register char *out;
1.1 etheisen 575:
576: if (*s == '\0')
577: {
1.5 millert 578: nostring(printopt);
1.8 shadchin 579: return (NULL);
1.1 etheisen 580: }
1.8 shadchin 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:
1.1 etheisen 585: for (p = s; *p != '\0'; p++)
1.5 millert 586: {
1.8 shadchin 587: if (opt_use_backslash && *p == '\\' && p[1] != '\0')
588: {
589: /* Take next char literally. */
590: ++p;
591: } else
1.1 etheisen 592: {
1.8 shadchin 593: if (*p == END_OPTION_STRING ||
594: (validchars != NULL && strchr(validchars, *p) == NULL))
595: /* End of option string. */
1.5 millert 596: break;
1.1 etheisen 597: }
1.8 shadchin 598: *out++ = *p;
1.5 millert 599: }
1.8 shadchin 600: *out = '\0';
1.1 etheisen 601: return (p);
602: }
603:
604: /*
1.7 shadchin 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: /*
1.1 etheisen 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
1.5 millert 632: getnum(sp, printopt, errp)
1.1 etheisen 633: char **sp;
1.5 millert 634: char *printopt;
1.1 etheisen 635: int *errp;
636: {
1.5 millert 637: register char *s;
638: register int n;
639: register int neg;
1.1 etheisen 640:
641: s = skipsp(*sp);
642: neg = FALSE;
643: if (*s == '-')
644: {
645: neg = TRUE;
646: s++;
647: }
648: if (*s < '0' || *s > '9')
1.7 shadchin 649: return (num_error(printopt, errp));
1.1 etheisen 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);
1.7 shadchin 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. */
1.9 ! schwarze 709: return quit_at_eof ? OPT_ONPLUS : OPT_ON;
1.1 etheisen 710: }