upgrade to 466 version
[platform/upstream/less.git] / option.c
1 /*
2  * Copyright (C) 1984-2014  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();
27 static int flip_triple();
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(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         sprintf(buf, "-%s", prchar(c));
61         return (buf);
62 }
63
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 {
72         register struct loption *o;
73         register int optc;
74         char *optname;
75         char *printopt;
76         char *str;
77         int set_default;
78         int lc;
79         int err;
80         PARG parg;
81
82         if (s == NULL)
83                 return;
84
85         /*
86          * If we have a pending option which requires an argument,
87          * handle it now.
88          * This happens if the previous option was, for example, "-P"
89          * without a following string.  In that case, the current
90          * option is simply the argument for the previous option.
91          */
92         if (pendopt != NULL)
93         {
94                 switch (pendopt->otype & OTYPE)
95                 {
96                 case STRING:
97                         (*pendopt->ofunc)(INIT, s);
98                         break;
99                 case NUMBER:
100                         printopt = opt_desc(pendopt);
101                         *(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
102                         break;
103                 }
104                 pendopt = NULL;
105                 return;
106         }
107
108         set_default = FALSE;
109         optname = NULL;
110
111         while (*s != '\0')
112         {
113                 /*
114                  * Check some special cases first.
115                  */
116                 switch (optc = *s++)
117                 {
118                 case ' ':
119                 case '\t':
120                 case END_OPTION_STRING:
121                         continue;
122                 case '-':
123                         /*
124                          * "--" indicates an option name instead of a letter.
125                          */
126                         if (*s == '-')
127                         {
128                                 optname = ++s;
129                                 break;
130                         }
131                         /*
132                          * "-+" means set these options back to their defaults.
133                          * (They may have been set otherwise by previous 
134                          * options.)
135                          */
136                         set_default = (*s == '+');
137                         if (set_default)
138                                 s++;
139                         continue;
140                 case '+':
141                         /*
142                          * An option prefixed by a "+" is ungotten, so 
143                          * that it is interpreted as less commands 
144                          * processed at the start of the first input file.
145                          * "++" means process the commands at the start of
146                          * EVERY input file.
147                          */
148                         plusoption = TRUE;
149                         s = optstring(s, &str, propt('+'), NULL);
150                         if (s == NULL)
151                                 return;
152                         if (*str == '+')
153                                 every_first_cmd = save(str+1);
154                         else
155                                 ungetsc(str);
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(o, lower, s, how_toggle)
300         struct loption *o;
301         int lower;
302         char *s;
303         int how_toggle;
304 {
305         register int num;
306         int no_prompt;
307         int err;
308         PARG parg;
309
310         no_prompt = (how_toggle & OPT_NO_PROMPT);
311         how_toggle &= ~OPT_NO_PROMPT;
312
313         if (o == NULL)
314         {
315                 error("No such option", NULL_PARG);
316                 return;
317         }
318
319         if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
320         {
321                 parg.p_string = opt_desc(o);
322                 error("Cannot change the %s option", &parg);
323                 return;
324         }
325
326         if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
327         {
328                 parg.p_string = opt_desc(o);
329                 error("Cannot query the %s option", &parg);
330                 return;
331         } 
332
333         /*
334          * Check for something which appears to be a do_toggle
335          * (because the "-" command was used), but really is not.
336          * This could be a string option with no string, or
337          * a number option with no number.
338          */
339         switch (o->otype & OTYPE)
340         {
341         case STRING:
342         case NUMBER:
343                 if (how_toggle == OPT_TOGGLE && *s == '\0')
344                         how_toggle = OPT_NO_TOGGLE;
345                 break;
346         }
347
348 #if HILITE_SEARCH
349         if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
350                 repaint_hilite(0);
351 #endif
352
353         /*
354          * Now actually toggle (change) the variable.
355          */
356         if (how_toggle != OPT_NO_TOGGLE)
357         {
358                 switch (o->otype & OTYPE)
359                 {
360                 case BOOL:
361                         /*
362                          * Boolean.
363                          */
364                         switch (how_toggle)
365                         {
366                         case OPT_TOGGLE:
367                                 *(o->ovar) = ! *(o->ovar);
368                                 break;
369                         case OPT_UNSET:
370                                 *(o->ovar) = o->odefault;
371                                 break;
372                         case OPT_SET:
373                                 *(o->ovar) = ! o->odefault;
374                                 break;
375                         }
376                         break;
377                 case TRIPLE:
378                         /*
379                          * Triple:
380                          *      If user gave the lower case letter, then switch 
381                          *      to 1 unless already 1, in which case make it 0.
382                          *      If user gave the upper case letter, then switch
383                          *      to 2 unless already 2, in which case make it 0.
384                          */
385                         switch (how_toggle)
386                         {
387                         case OPT_TOGGLE:
388                                 *(o->ovar) = flip_triple(*(o->ovar), lower);
389                                 break;
390                         case OPT_UNSET:
391                                 *(o->ovar) = o->odefault;
392                                 break;
393                         case OPT_SET:
394                                 *(o->ovar) = flip_triple(o->odefault, lower);
395                                 break;
396                         }
397                         break;
398                 case STRING:
399                         /*
400                          * String: don't do anything here.
401                          *      The handling function will do everything.
402                          */
403                         switch (how_toggle)
404                         {
405                         case OPT_SET:
406                         case OPT_UNSET:
407                                 error("Cannot use \"-+\" or \"--\" for a string option",
408                                         NULL_PARG);
409                                 return;
410                         }
411                         break;
412                 case NUMBER:
413                         /*
414                          * Number: set the variable to the given number.
415                          */
416                         switch (how_toggle)
417                         {
418                         case OPT_TOGGLE:
419                                 num = getnum(&s, NULL, &err);
420                                 if (!err)
421                                         *(o->ovar) = num;
422                                 break;
423                         case OPT_UNSET:
424                                 *(o->ovar) = o->odefault;
425                                 break;
426                         case OPT_SET:
427                                 error("Can't use \"-!\" for a numeric option",
428                                         NULL_PARG);
429                                 return;
430                         }
431                         break;
432                 }
433         }
434
435         /*
436          * Call the handling function for any special action 
437          * specific to this option.
438          */
439         if (o->ofunc != NULL)
440                 (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
441
442 #if HILITE_SEARCH
443         if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
444                 chg_hilite();
445 #endif
446
447         if (!no_prompt)
448         {
449                 /*
450                  * Print a message describing the new setting.
451                  */
452                 switch (o->otype & OTYPE)
453                 {
454                 case BOOL:
455                 case TRIPLE:
456                         /*
457                          * Print the odesc message.
458                          */
459                         error(o->odesc[*(o->ovar)], NULL_PARG);
460                         break;
461                 case NUMBER:
462                         /*
463                          * The message is in odesc[1] and has a %d for 
464                          * the value of the variable.
465                          */
466                         parg.p_int = *(o->ovar);
467                         error(o->odesc[1], &parg);
468                         break;
469                 case STRING:
470                         /*
471                          * Message was already printed by the handling function.
472                          */
473                         break;
474                 }
475         }
476
477         if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
478                 screen_trashed = TRUE;
479 }
480
481 /*
482  * "Toggle" a triple-valued option.
483  */
484         static int
485 flip_triple(val, lc)
486         int val;
487         int lc;
488 {
489         if (lc)
490                 return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
491         else
492                 return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
493 }
494
495 /*
496  * Determine if an option takes a parameter.
497  */
498         public int
499 opt_has_param(o)
500         struct loption *o;
501 {
502         if (o == NULL)
503                 return (0);
504         if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE))
505                 return (0);
506         return (1);
507 }
508
509 /*
510  * Return the prompt to be used for a given option letter.
511  * Only string and number valued options have prompts.
512  */
513         public char *
514 opt_prompt(o)
515         struct loption *o;
516 {
517         if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
518                 return ("?");
519         return (o->odesc[0]);
520 }
521
522 /*
523  * Return whether or not there is a string option pending;
524  * that is, if the previous option was a string-valued option letter 
525  * (like -P) without a following string.
526  * In that case, the current option is taken to be the string for
527  * the previous option.
528  */
529         public int
530 isoptpending()
531 {
532         return (pendopt != NULL);
533 }
534
535 /*
536  * Print error message about missing string.
537  */
538         static void
539 nostring(printopt)
540         char *printopt;
541 {
542         PARG parg;
543         parg.p_string = printopt;
544         error("Value is required after %s", &parg);
545 }
546
547 /*
548  * Print error message if a STRING type option is not followed by a string.
549  */
550         public void
551 nopendopt()
552 {
553         nostring(opt_desc(pendopt));
554 }
555
556 /*
557  * Scan to end of string or to an END_OPTION_STRING character.
558  * In the latter case, replace the char with a null char.
559  * Return a pointer to the remainder of the string, if any.
560  */
561         static char *
562 optstring(s, p_str, printopt, validchars)
563         char *s;
564         char **p_str;
565         char *printopt;
566         char *validchars;
567 {
568         register char *p;
569         register char *out;
570
571         if (*s == '\0')
572         {
573                 nostring(printopt);
574                 return (NULL);
575         }
576         /* Alloc could be more than needed, but not worth trimming. */
577         *p_str = (char *) ecalloc(strlen(s)+1, sizeof(char));
578         out = *p_str;
579
580         for (p = s;  *p != '\0';  p++)
581         {
582                 if (opt_use_backslash && *p == '\\' && p[1] != '\0')
583                 {
584                         /* Take next char literally. */
585                         ++p;
586                 } else 
587                 {
588                         if (*p == END_OPTION_STRING || 
589                             (validchars != NULL && strchr(validchars, *p) == NULL))
590                                 /* End of option string. */
591                                 break;
592                 }
593                 *out++ = *p;
594         }
595         *out = '\0';
596         return (p);
597 }
598
599 /*
600  */
601         static int
602 num_error(printopt, errp)
603         char *printopt;
604         int *errp;
605 {
606         PARG parg;
607
608         if (errp != NULL)
609         {
610                 *errp = TRUE;
611                 return (-1);
612         }
613         if (printopt != NULL)
614         {
615                 parg.p_string = printopt;
616                 error("Number is required after %s", &parg);
617         }
618         return (-1);
619 }
620
621 /*
622  * Translate a string into a number.
623  * Like atoi(), but takes a pointer to a char *, and updates
624  * the char * to point after the translated number.
625  */
626         public int
627 getnum(sp, printopt, errp)
628         char **sp;
629         char *printopt;
630         int *errp;
631 {
632         register char *s;
633         register int n;
634         register int neg;
635
636         s = skipsp(*sp);
637         neg = FALSE;
638         if (*s == '-')
639         {
640                 neg = TRUE;
641                 s++;
642         }
643         if (*s < '0' || *s > '9')
644                 return (num_error(printopt, errp));
645
646         n = 0;
647         while (*s >= '0' && *s <= '9')
648                 n = 10 * n + *s++ - '0';
649         *sp = s;
650         if (errp != NULL)
651                 *errp = FALSE;
652         if (neg)
653                 n = -n;
654         return (n);
655 }
656
657 /*
658  * Translate a string into a fraction, represented by the part of a
659  * number which would follow a decimal point.
660  * The value of the fraction is returned as parts per NUM_FRAC_DENOM.
661  * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
662  */
663         public long
664 getfraction(sp, printopt, errp)
665         char **sp;
666         char *printopt;
667         int *errp;
668 {
669         register char *s;
670         long frac = 0;
671         int fraclen = 0;
672
673         s = skipsp(*sp);
674         if (*s < '0' || *s > '9')
675                 return (num_error(printopt, errp));
676
677         for ( ;  *s >= '0' && *s <= '9';  s++)
678         {
679                 frac = (frac * 10) + (*s - '0');
680                 fraclen++;
681         }
682         if (fraclen > NUM_LOG_FRAC_DENOM)
683                 while (fraclen-- > NUM_LOG_FRAC_DENOM)
684                         frac /= 10;
685         else
686                 while (fraclen++ < NUM_LOG_FRAC_DENOM)
687                         frac *= 10;
688         *sp = s;
689         if (errp != NULL)
690                 *errp = FALSE;
691         return (frac);
692 }
693
694
695 /*
696  * Get the value of the -e flag.
697  */
698         public int
699 get_quit_at_eof()
700 {
701         if (!less_is_more)
702                 return quit_at_eof;
703         /* When less_is_more is set, the -e flag semantics are different. */
704         return quit_at_eof ? OPT_ONPLUS : OPT_ON;
705 }