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