home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 531.lha / Less_v1.4Z / src.LZH / src / option.c < prev    next >
C/C++ Source or Header  |  1991-07-03  |  16KB  |  524 lines

  1. /*
  2.  * Process command line options.
  3.  * Each option is a single letter which controls a program variable.
  4.  * The options have defaults which may be changed via
  5.  * the command line option, or toggled via the "-" command.
  6.  */
  7.  
  8. #ifdef AMIGA
  9. /* Compile with -HPreHeader.q to get "less.h"! */
  10. #else
  11. #include "less.h"
  12. #endif
  13.  
  14.  
  15. #ifdef AMIGA
  16. /* use the old-style toupper() that doesn't check its arguement */
  17. #undef toupper
  18. #define toupper(c)      ((c)-'a'+'A')
  19. #endif
  20.  
  21. #define END_OPTION_STRING       ('$')
  22.  
  23. /*
  24.  * Types of options.
  25.  */
  26. #define BOOL            01      /* Boolean option: 0 or 1 */
  27. #define TRIPLE          02      /* Triple-valued option: 0, 1 or 2 */
  28. #define NUMBER          04      /* Numeric option */
  29. #define REPAINT         040     /* Repaint screen after toggling option */
  30. #define NO_TOGGLE       0100    /* Option cannot be toggled with "-" cmd */
  31.  
  32. /* Prototypes for functions defined in option.c */
  33.  
  34. static char *optstring __PROTO((char *s));
  35. static int getnum __PROTO((char **sp, int c));
  36.  
  37.  
  38. /*
  39.  * Variables controlled by command line options.
  40.  */
  41. public int p_nbufs, f_nbufs;    /* Number of buffers.  There are two values,
  42.                                    one used for input from a pipe and
  43.                                    the other for input from a file. */
  44. #ifndef AMIGA
  45. public int clean_data;          /* Can we assume the data is "clean"?
  46.                                    (That is, free of nulls, etc) */
  47. #endif
  48. public int quiet;               /* Should we suppress the audible bell? */
  49. public int top_search;          /* Should forward searches start at the top
  50.                                    of the screen? (alternative is bottom) */
  51. public int top_scroll;          /* Repaint screen from top?
  52.                                    (alternative is scroll from bottom) */
  53. public int pr_type;             /* Type of prompt (short, medium, long) */
  54. public int bs_mode;             /* How to process backspaces */
  55. #ifdef DUMBTERM
  56. public int know_dumb;           /* Don't complain about dumb terminals */
  57. #endif
  58. public int quit_at_eof;         /* Quit after hitting end of file twice */
  59. public int squeeze;             /* Squeeze multiple blank lines into one */
  60. public int tabstop;             /* Tab settings */
  61. public int back_scroll;         /* Repaint screen on backwards movement */
  62. public int twiddle;             /* Display "~" for lines after EOF */
  63.  
  64. extern char *prproto[];
  65. extern int nbufs;
  66. extern int sc_window;
  67. #ifdef AMIGA
  68. public int scroll;
  69. public int sc_window_spec;      /* user's requested -z */
  70. extern int Wind_Spec[4];        /* User-specified window size/position */
  71. #endif
  72. extern char *first_cmd;
  73. extern char *every_first_cmd;
  74. #if LOGFILE
  75. extern char *namelogfile;
  76. extern int force_logfile;
  77. #endif
  78.  
  79. #define DEF_F_NBUFS     5       /* Default for f_nbufs */
  80. #define DEF_P_NBUFS     12      /* Default for p_nbufs */
  81.  
  82. static struct option
  83. {
  84.         char oletter;           /* The controlling letter (a-z) */
  85.         char otype;             /* Type of the option */
  86.         int odefault;           /* Default value */
  87.         int *ovar;              /* Pointer to the associated variable */
  88.         char *odesc[3];         /* Description of each value */
  89. } option[] =
  90. {
  91.         { 'c', TRIPLE, 2, &top_scroll,
  92.                 { "Repaint by scrolling from bottom of screen",
  93.                   "Repaint by clearing each line",
  94.                   "Repaint by painting from top of screen"
  95.                 }
  96.         },
  97. #ifdef DUMBTERM
  98.         { 'd', BOOL|NO_TOGGLE, 0, &know_dumb,
  99.                 { NULL, NULL, NULL}
  100.         },
  101. #endif
  102.         { 'e', TRIPLE, 1, &quit_at_eof,
  103.                 { "Don't quit at end-of-file",
  104. #ifdef AMIGA
  105.                   "Space bar quits at end-of-file",
  106.                   "Quit at end-of-file"
  107. #else
  108.                   "Quit at end-of-file",
  109.                   "Quit immediately at end-of-file"
  110. #endif
  111.                 }
  112.         },
  113. #ifndef AMIGA
  114.         { 'f', BOOL, 0, &clean_data,
  115.                 { "Don't assume data is clean",
  116.                   "Assume data is clean",
  117.                   NULL
  118.                 }
  119.         },
  120. #endif
  121.         { 'h', NUMBER, -1, &back_scroll, /* default set at window open */
  122.                 { "Backwards scroll limit is %d lines",
  123.                   NULL, NULL
  124.                 }
  125.         },
  126.         { 'm', TRIPLE, 1, &pr_type,
  127.                 { "Short prompt",
  128.                   "Medium prompt",
  129.                   "Long prompt"
  130.                 }
  131.         },
  132.         { 'q', TRIPLE, 0, &quiet,
  133.                 { "Ring the bell for errors AND at eof/bof",
  134.                   "Ring the bell for errors but not at eof/bof",
  135.                   "Never ring the bell"
  136.                 }
  137.         },
  138.         { 's', BOOL|REPAINT, 0, &squeeze,
  139.                 { "Don't squeeze multiple blank lines",
  140.                   "Squeeze multiple blank lines",
  141.                   NULL
  142.                 }
  143.         },
  144.         { 't', BOOL, 1, &top_search,
  145.                 { "Forward search starts from bottom of screen",
  146.                   "Forward search starts from top of screen",
  147.                   NULL
  148.                 }
  149.         },
  150.         { 'u', TRIPLE|REPAINT, 0, &bs_mode,
  151.  
  152.                 { "Underlined text displayed in underline mode",
  153.                   "Backspaces cause overstrike",
  154.                   "Backspaces print as ^H"
  155.                 }
  156.         },
  157.         { 'w', BOOL|REPAINT, 1, &twiddle,
  158.                 { "Display nothing for lines after end-of-file",
  159.                   "Display ~ for lines after end-of-file",
  160.                   NULL
  161.                 }
  162.         },
  163.         { 'x', NUMBER|REPAINT, 8, &tabstop,
  164.                 { "Tab stops every %d spaces",
  165.                   NULL, NULL
  166.                 }
  167.         },
  168.         { 'z', NUMBER|REPAINT, -1, &sc_window,
  169.                 { "Scroll window size is %d lines",
  170.                   NULL, NULL
  171.                 }
  172.         },
  173.         { '\0' }
  174. };
  175.  
  176. public char all_options[64];    /* List of all valid options */
  177.  
  178. /*
  179.  * Initialize each option to its default value.
  180.  */
  181. #ifdef __STDC__
  182. void init_option (void)
  183. #else
  184.         public void
  185. init_option()
  186. #endif
  187. {
  188.         register struct option *o;
  189.         register char *p;
  190.  
  191.         /*
  192.          * First do special cases, not in option table.
  193.          */
  194.         first_cmd = every_first_cmd = NULL;
  195.         f_nbufs = DEF_F_NBUFS;          /* -bf */
  196.         p_nbufs = DEF_P_NBUFS;          /* -bp */
  197.  
  198.         p = all_options;
  199.         *p++ = 'b';
  200.  
  201.         for (o = option;  o->oletter != '\0';  o++)
  202.         {
  203.                 /*
  204.                  * Set each variable to its default.
  205.                  * Also make a list of all options, in "all_options".
  206.                  */
  207.                 *(o->ovar) = o->odefault;
  208.                 *p++ = o->oletter;
  209.                 if (o->otype & TRIPLE)
  210.                         *p++ = toupper(o->oletter);
  211.         }
  212.         *p = '\0';
  213. }
  214.  
  215. /*
  216.  * Toggle command line flags from within the program.
  217.  * Used by the "-" command.
  218.  */
  219. #ifdef __STDC__
  220. void toggle_option (char *s)
  221. #else
  222.         public void
  223. toggle_option(s)
  224.         char *s;
  225. #endif
  226. {
  227.         int c;
  228.         register struct option *o;
  229.         char *msg;
  230.         int n;
  231.         int dorepaint;
  232.         char message[100];
  233.         char buf[5];
  234.  
  235.         c = *s++;
  236.  
  237.         /*
  238.          * First check for special cases not handled by the option table.
  239.          */
  240.         switch (c)
  241.         {
  242.         case 'b':
  243.                 sprintf(message, "%d buffers", nbufs);
  244.                 error(message);
  245.                 return;
  246.         }
  247.  
  248.         msg = NULL;
  249.         for (o = option;  o->oletter != '\0';  o++)
  250.         {
  251.                 if (o->otype & NO_TOGGLE)
  252.                         continue;
  253.                 dorepaint = (o->otype & REPAINT);
  254.                 if ((o->otype & BOOL) && (o->oletter == c))
  255.                 {
  256.                         /*
  257.                          * Boolean option:
  258.                          * just toggle it.
  259.                          */
  260.                         *(o->ovar) = ! *(o->ovar);
  261.                 } else if ((o->otype & TRIPLE) && (o->oletter == c))
  262.                 {
  263.                         /*
  264.                          * Triple-valued option with lower case letter:
  265.                          * make it 1 unless already 1, then make it 0.
  266.                          */
  267.                         *(o->ovar) = (*(o->ovar) == 1) ? 0 : 1;
  268.                 } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
  269.                 {
  270.                         /*
  271.                          * Triple-valued option with upper case letter:
  272.                          * make it 2 unless already 2, then make it 0.
  273.                          */
  274.                         *(o->ovar) = (*(o->ovar) == 2) ? 0 : 2;
  275.                 } else if ((o->otype & NUMBER) && (o->oletter == c))
  276.                 {
  277.                         n = getnum(&s, '\0');
  278.                         if (n < 0)
  279.                         {
  280.                                 /*
  281.                                  * No number; just a query.
  282.                                  * No need to repaint screen.
  283.                                  */
  284.                                 dorepaint = 0;
  285.                         } else
  286.                         {
  287.                                 /*
  288.                                  * Number follows the option letter.
  289.                                  * Set the variable to that number.
  290.                                  */
  291.                                 *(o->ovar) = n;
  292. #ifdef AMIGA
  293.                                 if ( c == 'z' )
  294.                                 {
  295.                                         sc_window_spec = sc_window;
  296.                                         set_scroll();
  297.                                 }
  298. #endif
  299.                         }
  300.                         sprintf(message, o->odesc[0],
  301.                                 (o->ovar == &back_scroll) ?
  302.                                 get_back_scroll() : *(o->ovar));
  303.                         msg = message;
  304.                 } else
  305.                         continue;
  306.  
  307.  
  308.                 if (dorepaint)
  309.                         repaint();
  310.                 if (msg == NULL)
  311.                         msg = o->odesc[*(o->ovar)];
  312.                 error(msg);
  313.                 return;
  314.         }
  315.  
  316.         if (control_char(c))
  317.                 sprintf(buf, "^%c", carat_char(c));
  318.         else
  319.                 sprintf(buf, "%c", c);
  320.         sprintf(message, "\"-%s\": no such flag.  Use one of \"%s\"",
  321.                 buf, all_options);
  322.         error(message);
  323. }
  324.  
  325. /*
  326.  * Scan to end of string or to an END_OPTION_STRING character.
  327.  * In the latter case, replace the char with a null char.
  328.  * Return a pointer to the remainder of the string, if any.
  329.  */
  330. #ifdef __STDC__
  331. static char *optstring (char *s)
  332. #else
  333.         static char *
  334. optstring(s)
  335.         char *s;
  336. #endif
  337. {
  338.         register char *p;
  339.  
  340.         for (p = s;  *p != '\0';  p++)
  341.                 if (*p == END_OPTION_STRING)
  342.                 {
  343.                         *p = '\0';
  344.                         return (p+1);
  345.                 }
  346.         return (p);
  347. }
  348.  
  349. /*
  350.  * Scan an argument (either from command line or from LESS environment
  351.  * variable) and process it.
  352.  */
  353. #ifdef __STDC__
  354. void scan_option (char *s)
  355. #else
  356.         public void
  357. scan_option(s)
  358.         char *s;
  359. #endif
  360. {
  361.         register struct option *o;
  362.         register int c;
  363.         char message[80];
  364.  
  365.         if (s == NULL)
  366.                 return;
  367.  
  368.     next:
  369.         if (*s == '\0')
  370.         {
  371.                 sc_window_spec = sc_window;
  372.                 return;
  373.         }
  374.         switch (c = *s++)
  375.         {
  376.         case '-':
  377.         case ' ':
  378.         case '\t':
  379.         case END_OPTION_STRING:
  380.                 goto next;
  381.         case '+':
  382.                 if (*s == '+')
  383.                         every_first_cmd = ++s;
  384.                 first_cmd = s;
  385.                 s = optstring(s);
  386.                 goto next;
  387.         case 'P':
  388.                 switch (*s)
  389.                 {
  390.                 case 'm':  prproto[PR_MEDIUM] = ++s;  break;
  391.                 case 'M':  prproto[PR_LONG] = ++s;    break;
  392.                 default:   prproto[PR_SHORT] = s;     break;
  393.                 }
  394.                 s = optstring(s);
  395.                 goto next;
  396. #if LOGFILE
  397.         case 'L':
  398.                 force_logfile = 1;
  399.                 /* fall thru */
  400.         case 'l':
  401.                 namelogfile = s;
  402.                 s = optstring(s);
  403.                 goto next;
  404. #endif
  405.         case 'b':
  406.                 switch (*s)
  407.                 {
  408.                 case 'f':
  409.                         s++;
  410.                         f_nbufs = getnum(&s, 'b');
  411.                         break;
  412.                 case 'p':
  413.                         s++;
  414.                         p_nbufs = getnum(&s, 'b');
  415.                         break;
  416.                 default:
  417.                         f_nbufs = p_nbufs = getnum(&s, 'b');
  418.                         break;
  419.                 }
  420.                 goto next;
  421.         case '0':  case '1':  case '2':  case '3':  case '4':
  422.         case '5':  case '6':  case '7':  case '8':  case '9':
  423.                 {
  424.                         /*
  425.                          * Handle special "more" compatibility form "-number"
  426.                          * to set the scrolling window size.
  427.                          */
  428.                         s--;
  429.                         sc_window = getnum(&s, '-');
  430.                         goto next;
  431.                 }
  432. #ifdef AMIGA
  433.         case '[':   /* window specifier */
  434.                 {
  435.                         int i, rel;
  436.  
  437.                         for (i = 0; i < 4; i++)
  438.                         {
  439.                             rel = 1;
  440.                             while ( *s == ' ' ) s++;
  441.                             if ( *s == ',' )
  442.                                 { s++; continue; }
  443.                             if ( *s == '-' )
  444.                                 { s++; rel = -1; }
  445.                             if ( *s == ']' || *s == '\0' ) break;
  446.                             Wind_Spec[i] = rel * getnum ( &s, s[-1] );
  447.                             if ( *s == ',' ) s++;
  448.                         }
  449.                         if ( *s++ != ']' )
  450.                         {
  451.                             error ("Invalid window specification");
  452.                             quit();
  453.                         }
  454.                         goto next;
  455.                 }
  456. #endif
  457.         }
  458.  
  459.         for (o = option;  o->oletter != '\0';  o++)
  460.         {
  461.                 if ((o->otype & BOOL) && (o->oletter == c))
  462.                 {
  463.                         *(o->ovar) = ! o->odefault;
  464.                         goto next;
  465.                 } else if ((o->otype & TRIPLE) && (o->oletter == c))
  466.                 {
  467.                         *(o->ovar) = (o->odefault == 1) ? 0 : 1;
  468.                         goto next;
  469.                 } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
  470.                 {
  471.                         *(o->ovar) = (o->odefault == 2) ? 0 : 2;
  472.                         goto next;
  473.                 } else if ((o->otype & NUMBER) && (o->oletter == c))
  474.                 {
  475.                         *(o->ovar) = getnum(&s, c);
  476.                         goto next;
  477.                 }
  478.         }
  479.  
  480.         sprintf(message, "\"-%c\": invalid flag", c);
  481.         error(message);
  482.         quit();
  483. }
  484.  
  485. /*
  486.  * Translate a string into a number.
  487.  * Like atoi(), but takes a pointer to a char *, and updates
  488.  * the char * to point after the translated number.
  489.  */
  490. #ifdef __STDC__
  491. static int getnum (char **sp, int c)
  492. #else
  493.         static int
  494. getnum(sp, c)
  495.         char **sp;
  496.         int c;
  497. #endif
  498. {
  499.         register char *s;
  500.         register int n;
  501.         char message[80];
  502.  
  503.         s = *sp;
  504.         if (*s < '0' || *s > '9')
  505.         {
  506.                 if (c == '\0')
  507.                         return (-1);
  508. #ifdef AMIGA
  509.                 sprintf(message,
  510.                     "number is required in option after '%c'", c);
  511. #else
  512.                 sprintf(message, "number is required after -%c", c);
  513. #endif
  514.                 error(message);
  515.                 quit();
  516.         }
  517.  
  518.         n = 0;
  519.         while (*s >= '0' && *s <= '9')
  520.                 n = 10 * n + *s++ - '0';
  521.         *sp = s;
  522.         return (n);
  523. }
  524.