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