Annotation of src/usr.bin/less/option.c, Revision 1.1.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: }