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