home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / less-321-src.tgz / tar.out / fsf / less / option.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  11KB  |  551 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994,1995,1996  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.             set_default = (*s == '+');
  100.             if (set_default)
  101.                 s++;
  102.             continue;
  103.         case '+':
  104.             /*
  105.              * An option prefixed by a "+" is ungotten, so 
  106.              * that it is interpreted as less commands 
  107.              * processed at the start of the first input file.
  108.              * "++" means process the commands at the start of
  109.              * EVERY input file.
  110.              */
  111.             plusoption = TRUE;
  112.             if (*s == '+')
  113.                 every_first_cmd = save(++s);
  114.             else
  115.                 ungetsc(s);
  116.             s = optstring(s, c);
  117.             continue;
  118.         case '0':  case '1':  case '2':  case '3':  case '4':
  119.         case '5':  case '6':  case '7':  case '8':  case '9':
  120.             /*
  121.              * Special "more" compatibility form "-<number>"
  122.              * instead of -z<number> to set the scrolling 
  123.              * window size.
  124.              */
  125.             s--;
  126.             c = 'z';
  127.             break;
  128.         }
  129.  
  130.         /*
  131.          * Not a special case.
  132.          * Look up the option letter in the option table.
  133.          */
  134.         o = findopt(c);
  135.         if (o == NULL)
  136.         {
  137.             parg.p_string = propt(c);
  138. #if SHELL_META_QUEST
  139.             error("There is no %s option (\"less -\\?\" for help)",
  140.                 &parg);
  141. #else
  142.             error("There is no %s option (\"less -?\" for help)",
  143.                 &parg);
  144. #endif
  145.             quit(QUIT_ERROR);
  146.         }
  147.  
  148.         switch (o->otype & OTYPE)
  149.         {
  150.         case BOOL:
  151.             if (set_default)
  152.                 *(o->ovar) = o->odefault;
  153.             else
  154.                 *(o->ovar) = ! o->odefault;
  155.             break;
  156.         case TRIPLE:
  157.             if (set_default)
  158.                 *(o->ovar) = o->odefault;
  159.             else
  160.                 *(o->ovar) = flip_triple(o->odefault,
  161.                         (o->oletter == c));
  162.             break;
  163.         case STRING:
  164.             if (*s == '\0')
  165.             {
  166.                 /*
  167.                  * Set pendopt and return.
  168.                  * We will get the string next time
  169.                  * scan_option is called.
  170.                  */
  171.                 pendopt = o;
  172.                 return;
  173.             }
  174.             /*
  175.              * Don't do anything here.
  176.              * All processing of STRING options is done by 
  177.              * the handling function.
  178.              */
  179.             str = s;
  180.             s = optstring(s, c);
  181.             break;
  182.         case NUMBER:
  183.             *(o->ovar) = getnum(&s, c, (int*)NULL);
  184.             break;
  185.         }
  186.         /*
  187.          * If the option has a handling function, call it.
  188.          */
  189.         if (o->ofunc != NULL)
  190.             (*o->ofunc)(INIT, str);
  191.     }
  192. }
  193.  
  194. /*
  195.  * Toggle command line flags from within the program.
  196.  * Used by the "-" and "_" commands.
  197.  * how_toggle may be:
  198.  *    OPT_NO_TOGGLE    just report the current setting, without changing it.
  199.  *    OPT_TOGGLE    invert the current setting
  200.  *    OPT_UNSET    set to the default value
  201.  *    OPT_SET        set to the inverse of the default value
  202.  */
  203.     public void
  204. toggle_option(c, s, how_toggle)
  205.     int c;
  206.     char *s;
  207.     int how_toggle;
  208. {
  209.     register struct option *o;
  210.     register int num;
  211.     int err;
  212.     PARG parg;
  213.  
  214.     /*
  215.      * Look up the option letter in the option table.
  216.      */
  217.     o = findopt(c);
  218.     if (o == NULL)
  219.     {
  220.         parg.p_string = propt(c);
  221.         error("There is no %s option", &parg);
  222.         return;
  223.     }
  224.  
  225.     if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
  226.     {
  227.         parg.p_string = propt(c);
  228.         error("Cannot change the %s option", &parg);
  229.         return;
  230.     } 
  231.  
  232.     if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
  233.     {
  234.         parg.p_string = propt(c);
  235.         error("Cannot query the %s option", &parg);
  236.         return;
  237.     } 
  238.  
  239.     /*
  240.      * Check for something which appears to be a do_toggle
  241.      * (because the "-" command was used), but really is not.
  242.      * This could be a string option with no string, or
  243.      * a number option with no number.
  244.      */
  245.     switch (o->otype & OTYPE)
  246.     {
  247.     case STRING:
  248.     case NUMBER:
  249.         if (how_toggle == OPT_TOGGLE && *s == '\0')
  250.             how_toggle = OPT_NO_TOGGLE;
  251.         break;
  252.     }
  253.  
  254. #if HILITE_SEARCH
  255.     if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
  256.         repaint_hilite(0);
  257. #endif
  258.  
  259.     /*
  260.      * Now actually toggle (change) the variable.
  261.      */
  262.     if (how_toggle != OPT_NO_TOGGLE)
  263.     {
  264.         switch (o->otype & OTYPE)
  265.         {
  266.         case BOOL:
  267.             /*
  268.              * Boolean.
  269.              */
  270.             switch (how_toggle)
  271.             {
  272.             case OPT_TOGGLE:
  273.                 *(o->ovar) = ! *(o->ovar);
  274.                 break;
  275.             case OPT_UNSET:
  276.                 *(o->ovar) = o->odefault;
  277.                 break;
  278.             case OPT_SET:
  279.                 *(o->ovar) = ! o->odefault;
  280.                 break;
  281.             }
  282.             break;
  283.         case TRIPLE:
  284.             /*
  285.              * Triple:
  286.              *    If user gave the lower case letter, then switch 
  287.              *    to 1 unless already 1, in which case make it 0.
  288.              *    If user gave the upper case letter, then switch
  289.              *    to 2 unless already 2, in which case make it 0.
  290.              */
  291.             switch (how_toggle)
  292.             {
  293.             case OPT_TOGGLE:
  294.                 *(o->ovar) = flip_triple(*(o->ovar), 
  295.                         o->oletter == c);
  296.                 break;
  297.             case OPT_UNSET:
  298.                 *(o->ovar) = o->odefault;
  299.                 break;
  300.             case OPT_SET:
  301.                 *(o->ovar) = flip_triple(o->odefault,
  302.                         o->oletter == c);
  303.                 break;
  304.             }
  305.             break;
  306.         case STRING:
  307.             /*
  308.              * String: don't do anything here.
  309.              *    The handling function will do everything.
  310.              */
  311.             switch (how_toggle)
  312.             {
  313.             case OPT_SET:
  314.             case OPT_UNSET:
  315.                 error("Can't use \"-+\" or \"--\" for a string option",
  316.                     NULL_PARG);
  317.                 return;
  318.             }
  319.             break;
  320.         case NUMBER:
  321.             /*
  322.              * Number: set the variable to the given number.
  323.              */
  324.             switch (how_toggle)
  325.             {
  326.             case OPT_TOGGLE:
  327.                 num = getnum(&s, '\0', &err);
  328.                 if (!err)
  329.                     *(o->ovar) = num;
  330.                 break;
  331.             case OPT_UNSET:
  332.                 *(o->ovar) = o->odefault;
  333.                 break;
  334.             case OPT_SET:
  335.                 error("Can't use \"--\" for a numeric option",
  336.                     NULL_PARG);
  337.                 return;
  338.             }
  339.             break;
  340.         }
  341.     }
  342.  
  343.     /*
  344.      * Call the handling function for any special action 
  345.      * specific to this option.
  346.      */
  347.     if (o->ofunc != NULL)
  348.         (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
  349.  
  350. #if HILITE_SEARCH
  351.     if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
  352.         chg_hilite();
  353. #endif
  354.  
  355.     /*
  356.      * Print a message describing the new setting.
  357.      */
  358.     switch (o->otype & OTYPE)
  359.     {
  360.     case BOOL:
  361.     case TRIPLE:
  362.         /*
  363.          * Print the odesc message.
  364.          */
  365.         error(o->odesc[*(o->ovar)], NULL_PARG);
  366.         break;
  367.     case NUMBER:
  368.         /*
  369.          * The message is in odesc[1] and has a %d for 
  370.          * the value of the variable.
  371.          */
  372.         parg.p_int = *(o->ovar);
  373.         error(o->odesc[1], &parg);
  374.         break;
  375.     case STRING:
  376.         /*
  377.          * Message was already printed by the handling function.
  378.          */
  379.         break;
  380.     }
  381.  
  382.     if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
  383.         screen_trashed = TRUE;
  384. }
  385.  
  386. /*
  387.  * "Toggle" a triple-valued option.
  388.  */
  389.     static int
  390. flip_triple(val, lc)
  391.     int val;
  392.     int lc;
  393. {
  394.     if (lc)
  395.         return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
  396.     else
  397.         return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
  398. }
  399.  
  400. /*
  401.  * Return a string suitable for printing as the "name" of an option.
  402.  * For example, if the option letter is 'x', just return "-x".
  403.  */
  404.     static char *
  405. propt(c)
  406.     int c;
  407. {
  408.     static char buf[8];
  409.  
  410.     sprintf(buf, "-%s", prchar(c));
  411.     return (buf);
  412. }
  413.  
  414. /*
  415.  * Determine if an option is a single character option (BOOL or TRIPLE),
  416.  * or if it a multi-character option (NUMBER).
  417.  */
  418.     public int
  419. single_char_option(c)
  420.     int c;
  421. {
  422.     register struct option *o;
  423.  
  424.     o = findopt(c);
  425.     if (o == NULL)
  426.         return (TRUE);
  427.     return ((o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) != 0);
  428. }
  429.  
  430. /*
  431.  * Return the prompt to be used for a given option letter.
  432.  * Only string and number valued options have prompts.
  433.  */
  434.     public char *
  435. opt_prompt(c)
  436.     int c;
  437. {
  438.     register struct option *o;
  439.  
  440.     o = findopt(c);
  441.     if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
  442.         return (NULL);
  443.     return (o->odesc[0]);
  444. }
  445.  
  446. /*
  447.  * Return whether or not there is a string option pending;
  448.  * that is, if the previous option was a string-valued option letter 
  449.  * (like -P) without a following string.
  450.  * In that case, the current option is taken to be the string for
  451.  * the previous option.
  452.  */
  453.     public int
  454. isoptpending()
  455. {
  456.     return (pendopt != NULL);
  457. }
  458.  
  459. /*
  460.  * Print error message about missing string.
  461.  */
  462.     static void
  463. nostring(c)
  464.     int c;
  465. {
  466.     PARG parg;
  467.     parg.p_string = propt(c);
  468.     error("String is required after %s", &parg);
  469. }
  470.  
  471. /*
  472.  * Print error message if a STRING type option is not followed by a string.
  473.  */
  474.     public void
  475. nopendopt()
  476. {
  477.     nostring(pendopt->oletter);
  478. }
  479.  
  480. /*
  481.  * Scan to end of string or to an END_OPTION_STRING character.
  482.  * In the latter case, replace the char with a null char.
  483.  * Return a pointer to the remainder of the string, if any.
  484.  */
  485.     static char *
  486. optstring(s, c)
  487.     char *s;
  488.     int c;
  489. {
  490.     register char *p;
  491.  
  492.     if (*s == '\0')
  493.     {
  494.         nostring(c);
  495.         quit(QUIT_ERROR);
  496.     }
  497.     for (p = s;  *p != '\0';  p++)
  498.         if (*p == END_OPTION_STRING)
  499.         {
  500.             *p = '\0';
  501.             return (p+1);
  502.         }
  503.     return (p);
  504. }
  505.  
  506. /*
  507.  * Translate a string into a number.
  508.  * Like atoi(), but takes a pointer to a char *, and updates
  509.  * the char * to point after the translated number.
  510.  */
  511.     public int
  512. getnum(sp, c, errp)
  513.     char **sp;
  514.     int c;
  515.     int *errp;
  516. {
  517.     register char *s;
  518.     register int n;
  519.     register int neg;
  520.     PARG parg;
  521.  
  522.     s = skipsp(*sp);
  523.     neg = FALSE;
  524.     if (*s == '-')
  525.     {
  526.         neg = TRUE;
  527.         s++;
  528.     }
  529.     if (*s < '0' || *s > '9')
  530.     {
  531.         if (errp != NULL)
  532.         {
  533.             *errp = TRUE;
  534.             return (-1);
  535.         }
  536.         parg.p_string = propt(c);
  537.         error("Number is required after %s", &parg);
  538.         quit(QUIT_ERROR);
  539.     }
  540.  
  541.     n = 0;
  542.     while (*s >= '0' && *s <= '9')
  543.         n = 10 * n + *s++ - '0';
  544.     *sp = s;
  545.     if (errp != NULL)
  546.         *errp = FALSE;
  547.     if (neg)
  548.         n = -n;
  549.     return (n);
  550. }
  551.