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