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