home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2994 / option.c < prev    next >
C/C++ Source or Header  |  1991-03-05  |  9KB  |  499 lines

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