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