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