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