home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 036 / less232.zip / OPTION.C < prev    next >
C/C++ Source or Header  |  1994-07-26  |  11KB  |  528 lines

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