home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d9xx / d902 / less.lha / Less / Source / source.lha / command.c < prev    next >
C/C++ Source or Header  |  1993-01-21  |  25KB  |  805 lines

  1. /*
  2.  * User-level command processor.
  3.  */
  4.  
  5. #include "less.h"
  6.  
  7. #include "position.h"
  8. #include <setjmp.h>
  9.  
  10. extern jmp_buf main_loop;
  11. extern int erase_char, kill_char;
  12. extern int pr_type;
  13. extern int sigs;
  14. extern int ispipe;
  15. extern int quit_at_eof;
  16. extern int hit_eof;
  17. extern int sc_width, sc_height;
  18. extern int sc_window;
  19. extern char *first_cmd;
  20. extern char *every_first_cmd;
  21. extern char version[];
  22. extern char current_file[];
  23. extern char *editor;
  24.  
  25. #ifdef AMIGA
  26. extern int scroll;
  27. extern curr_ac, ac;             /* local argc for file names */
  28. extern char **av;
  29. int user_errors = 0;
  30. #endif
  31.  
  32. static char cmdbuf[90];         /* Buffer for holding a multi-char command */
  33. #if SHELL_ESCAPE
  34. static char shellcmd[200];      /* For holding last shell command for "!!" */
  35. #endif
  36. static char *cp;                /* Pointer into cmdbuf */
  37. static int cmd_col;             /* Current column of the multi-char command */
  38. static char mcc;                /* The multi-char command letter (e.g. '/') */
  39. static char last_mcc;           /* The previous mcc */
  40. #ifdef AMIGA
  41. int screen_trashed;             /* The screen has been overwritten */
  42. #else
  43. static int screen_trashed;      /* The screen has been overwritten */
  44. #endif
  45.  
  46. /* Prototypes for functions defined in command.c */
  47.  
  48. static int cmd_erase __PROTO((void));
  49. static int cmd_char __PROTO((int c));
  50. static int cmd_int __PROTO((void));
  51. static void cmd_exec __PROTO((void));
  52. static void prompt __PROTO((void));
  53. static int getcc __PROTO((void));
  54.  
  55.  
  56. /*
  57.  * Reset command buffer (to empty).
  58.  */
  59. #ifdef __STDC__
  60. void cmd_reset (void)
  61. #else
  62. cmd_reset()
  63. #endif
  64. {
  65.         cp = cmdbuf;
  66. }
  67.  
  68. /*
  69.  * Backspace in command buffer.
  70.  */
  71. #ifdef __STDC__
  72. static int cmd_erase (void)
  73. #else
  74.         static int
  75. cmd_erase()
  76. #endif
  77. {
  78.         if (cp == cmdbuf)
  79.                 /*
  80.                  * Backspace past beginning of the string:
  81.                  * this usually means abort the command.
  82.                  */
  83.                 return (1);
  84.  
  85.         if (control_char(*--cp))
  86.         {
  87.                 /*
  88.                  * Erase an extra character, for the carat.
  89.                  */
  90.                 backspace();
  91.                 cmd_col--;
  92.         }
  93.         backspace();
  94.         cmd_col--;
  95.         return (0);
  96. }
  97.  
  98. /*
  99.  * Set up the display to start a new multi-character command.
  100.  */
  101. #ifdef __STDC__
  102. void start_mcc (int c)
  103. #else
  104. start_mcc(c)
  105.         int c;
  106. #endif
  107. {
  108.         mcc = c;
  109.         lower_left();
  110.         clear_eol();
  111.         putchr(mcc);
  112.         cmd_col = 1;
  113. }
  114.  
  115. /*
  116.  * Process a single character of a multi-character command, such as
  117.  * a number, or the pattern of a search command.
  118.  */
  119. #ifdef __STDC__
  120. static int cmd_char (int c)
  121. #else
  122.         static int
  123. cmd_char(c)
  124.         int c;
  125. #endif
  126. {
  127.         if (c == erase_char)
  128.         {
  129.                 if (cmd_erase())
  130.                         return (1);
  131.         } else if (c == kill_char)
  132.         {
  133.                 /* {{ Could do this faster, but who cares? }} */
  134.                 while (cmd_erase() == 0)
  135.                         ;
  136.         } else
  137.         {
  138.                 /*
  139.                  * Append the character to the string,
  140.                  * if there is room in the buffer and on the screen.
  141.                  */
  142.                 if (cp < &cmdbuf[sizeof(cmdbuf)-1] && cmd_col < sc_width-3)
  143.                 {
  144.                         *cp++ = c;
  145.                         if (control_char(c))
  146.                         {
  147.                                 putchr('^');
  148.                                 cmd_col++;
  149.                                 c = carat_char(c);
  150.                         }
  151.                         putchr(c);
  152.                         cmd_col++;
  153.                 } else
  154.                         bell();
  155.         }
  156.         return (0);
  157. }
  158.  
  159. /*
  160.  * Return the number currently in the command buffer.
  161.  */
  162. #ifdef __STDC__
  163. static int cmd_int (void)
  164. #else
  165.         static int
  166. cmd_int()
  167. #endif
  168. {
  169.         *cp = '\0';
  170.         cp = cmdbuf;
  171.         return (atoi(cmdbuf));
  172. }
  173.  
  174. /*
  175.  * Move the cursor to lower left before executing a command.
  176.  * This looks nicer if the command takes a long time before
  177.  * updating the screen.
  178.  */
  179. #ifdef __STDC__
  180. static void cmd_exec (void)
  181. #else
  182.         static void
  183. cmd_exec()
  184. #endif
  185. {
  186.         lower_left();
  187.         flush();
  188. }
  189.  
  190. /*
  191.  * Display the appropriate prompt.
  192.  */
  193. #ifdef __STDC__
  194. static void prompt (void)
  195. #else
  196.         static void
  197. prompt()
  198. #endif
  199. {
  200.         register char *p;
  201.  
  202.         if (first_cmd != NULL && *first_cmd != '\0')
  203.                 /*
  204.                  * No prompt necessary if commands are from first_cmd
  205.                  * rather than from the user.
  206.                  */
  207.                 return;
  208.  
  209.         /*
  210.          * If nothing is displayed yet, display starting from line 1.
  211.          */
  212.         if (position(TOP) == NULL_POSITION)
  213.                 jump_back(1);
  214.         else if (screen_trashed)
  215.                 repaint();
  216.         screen_trashed = 0;
  217.  
  218.         /*
  219.          * Select the proper prompt and display it.
  220.          */
  221.         lower_left();
  222.         clear_eol();
  223.         p = pr_string();
  224.         if (p == NULL)
  225.                 putchr(':');
  226.         else
  227.         {
  228. #ifdef AMIGA
  229.                 if ( strlen(p) > sc_width )
  230.                     screen_trashed = 1;
  231. #endif
  232.                 so_enter();
  233.                 putstr(p);
  234.                 so_exit();
  235.         }
  236. }
  237.  
  238. /*
  239.  * Get command character.
  240.  * The character normally comes from the keyboard,
  241.  * but may come from the "first_cmd" string.
  242.  */
  243. #ifdef __STDC__
  244. static int getcc (void)
  245. #else
  246.         static int
  247. getcc()
  248. #endif
  249. {
  250.         if (first_cmd == NULL)
  251.                 return (getchr());
  252.  
  253.         if (*first_cmd == '\0')
  254.         {
  255.                 /*
  256.                  * Reached end of first_cmd input.
  257.                  */
  258.                 first_cmd = NULL;
  259.                 if (cp > cmdbuf && position(TOP) == NULL_POSITION)
  260.                 {
  261.                         /*
  262.                          * Command is incomplete, so try to complete it.
  263.                          * There are only two cases:
  264.                          * 1. We have "/string" but no newline.  Add the \n.
  265.                          * 2. We have a number but no command.  Treat as #g.
  266.                          * (This is all pretty hokey.)
  267.                          */
  268.                         if (mcc != ':')
  269.                                 /* Not a number; must be search string */
  270.                                 return ('\n');
  271.                         else
  272.                                 /* A number; append a 'g' */
  273.                                 return ('g');
  274.                 }
  275.                 return (getchr());
  276.         }
  277.         return (int)(*first_cmd++);
  278. }
  279.  
  280. /*
  281.  * Main command processor.
  282.  * Accept and execute commands until a quit command, then return.
  283.  */
  284. #ifdef __STDC__
  285. void commands (void)
  286. #else
  287.         public void
  288. commands()
  289. #endif
  290. {
  291.         register int c;
  292.         register int n;
  293. #ifndef AMIGA
  294.         register int scroll = 10;
  295. #endif
  296.  
  297.         last_mcc = 0;
  298.         n = 0;
  299.         setjmp(main_loop);
  300.         mcc = 0;
  301.  
  302.         for (;;)
  303.         {
  304.                 /*
  305.                  * Display prompt and accept a character.
  306.                  */
  307.                 psignals();     /* See if any signals need processing */
  308.  
  309. #ifdef AMIGA
  310.                 if (quit_at_eof == 2 && hit_eof > 1)
  311. #else
  312.                 if (quit_at_eof && (quit_at_eof + hit_eof) > 2)
  313. #endif
  314.                         /*
  315.                          * After hitting end-of-file for the second time,
  316.                          * automatically advance to the next file.
  317.                          * If there are no more files, quit.
  318.                          */
  319.                         next_file(1);
  320.                 cmd_reset();
  321.                 prompt();
  322.                 c = getcc();
  323.  
  324.         again:
  325.                 if (sigs)
  326.                         continue;
  327.                 if (mcc)
  328.                 {
  329.                         /*
  330.                          * We are in a multi-character command.
  331.                          * All chars until newline go into the command buffer.
  332.                          * (Note that mcc == ':' is a special case that
  333.                          *  means a number is being entered.)
  334.                          */
  335.                         if (mcc != ':' && (c == '\n' || c == '\r'))
  336.                         {
  337.                                 char *p;
  338.                                 static char fcbuf[100];
  339.  
  340.                                 /*
  341.                                  * Execute the command.
  342.                                  */
  343.                                 *cp = '\0';
  344.                                 cmd_exec();
  345.                                 switch (mcc)
  346.                                 {
  347.                                 case '/': case '?':
  348.                                         search(mcc, cmdbuf, n);
  349.                                         break;
  350.                                 case '+':
  351.                                         for (p = cmdbuf;  *p == '+' || *p == ' ';  p++) ;
  352.                                         if (*p == '\0')
  353.                                                 every_first_cmd = NULL;
  354.                                         else
  355.                                         {
  356.                                                 strtcpy(fcbuf, p, sizeof(fcbuf));
  357.                                                 every_first_cmd = fcbuf;
  358.                                         }
  359.                                         break;
  360.                                 case '-':
  361.                                         toggle_option(cmdbuf);
  362.                                         break;
  363.                                 case 'E':
  364.                                         /*
  365.                                          * Ignore leading spaces
  366.                                          * in the filename.
  367.                                          */
  368.                                         for (p = cmdbuf;  *p == ' ';  p++) ;
  369.                                         edit(glob(p));
  370.                                         break;
  371. #if SHELL_ESCAPE
  372.                                 case '!':
  373.                                         /*
  374.                                          * !! just uses whatever is in shellcmd.
  375.                                          * Otherwise, copy cmdbuf to shellcmd,
  376.                                          * replacing any '%' with the current
  377.                                          * file name.
  378.                                          */
  379.                                         if (*cmdbuf != '!')
  380.                                         {
  381.                                                 register char *fr, *to;
  382.                                                 to = shellcmd;
  383.                                                 for (fr = cmdbuf;
  384.                                                         *fr != '\0';  fr++)
  385.                                                 {
  386.                                                         if (*fr != '%')
  387.                                                                 *to++ = *fr;
  388.                                                         else
  389.                                                         {
  390.                                                                 strcpy(to,
  391.                                                                  current_file);
  392.                                                                 to += strlen(to);
  393.                                                         }
  394.                                                 }
  395.                                                 *to = '\0';
  396.                                         }
  397.                                         lsystem(shellcmd);
  398.                                         screen_trashed = 1;
  399.                                         error("!done");
  400.                                         break;
  401. #endif
  402.                                 }
  403.                                 mcc = 0;
  404.                         } else
  405.                         {
  406.                                 if (mcc == ':' && (c < '0' || c > '9') &&
  407.                                         c != erase_char && c != kill_char)
  408.                                 {
  409.                                         /*
  410.                                          * This is not part of the number
  411.                                          * we were entering.  Process
  412.                                          * it as a regular character.
  413.                                          */
  414.                                         mcc = 0;
  415.                                         goto again;
  416.                                 }
  417.  
  418.                                 /*
  419.                                  * Append the char to the command buffer.
  420.                                  */
  421.                                 if (cmd_char(c))
  422.                                 {
  423.                                         /* Abort the multi-char command. */
  424.                                         mcc = 0;
  425.                                         continue;
  426.                                 }
  427.                                 c = getcc();
  428.                                 goto again;
  429.                         }
  430.                 } else switch (c)
  431.                 {
  432.                 case '0': case '1': case '2': case '3': case '4':
  433.                 case '5': case '6': case '7': case '8': case '9':
  434.                         /*
  435.                          * First digit of a number.
  436.                          */
  437.                         start_mcc(':');
  438.                         goto again;
  439.  
  440.                 case 'f':
  441.                 case ' ':
  442.                 case CONTROL('F'):
  443. #ifdef AMIGA
  444.                 case CONTROL('V'):
  445. #endif
  446.                         /*
  447.                          * Forward one screen.
  448.                          */
  449. #ifdef AMIGA
  450.                         if (hit_eof && quit_at_eof == 1)
  451.                         {
  452.                                 if (curr_ac+1 == ac)
  453.                                         return;
  454.                                 else
  455.                                         next_file(1);
  456.                         } else
  457. #endif
  458.                         {
  459.                                 n = cmd_int();
  460.                                 if (n <= 0)
  461.                                         n = sc_window;
  462.                                 cmd_exec();
  463.                                 forward(n, 1);
  464.                         }
  465.                         break;
  466.  
  467.                 case 'b':
  468. #ifdef AMIGA
  469.                 case 'B':
  470. #endif
  471.                 case CONTROL('B'):
  472.                         /*
  473.                          * Backward one screen.
  474.                          */
  475.                         n = cmd_int();
  476.                         if (n <= 0)
  477.                                 n = sc_window;
  478.                         cmd_exec();
  479.                         backward(n, 1);
  480.                         break;
  481.  
  482.                 case 'e':
  483.                 case 'j':
  484.                 case '\r':
  485.                 case '\n':
  486.                 case CONTROL('E'):
  487. #ifdef AMIGA
  488.                 case CONTROL('N'):
  489. #endif
  490.                         /*
  491.                          * Forward N (default 1) line.
  492.                          */
  493.                         n = cmd_int();
  494.                         if (n <= 0)
  495.                                 n = 1;
  496.                         cmd_exec();
  497.                         forward(n, 0);
  498.                         break;
  499.  
  500.                 case 'y':
  501.                 case 'k':
  502.                 case CONTROL('K'):
  503.                 case CONTROL('Y'):
  504. #ifdef AMIGA
  505.                 case '\b':
  506.                 case CONTROL('P'):
  507. #endif
  508.                         /*
  509.                          * Backward N (default 1) line.
  510.                          */
  511.                         n = cmd_int();
  512.                         if (n <= 0)
  513.                                 n = 1;
  514.                         cmd_exec();
  515.                         backward(n, 0);
  516.                         break;
  517.  
  518.                 case 'd':
  519.                 case CONTROL('D'):
  520.                         /*
  521.                          * Forward N lines
  522.                          * (default same as last 'd' or 'u' command).
  523.                          */
  524.                         n = cmd_int();
  525.                         if (n > 0)
  526.                                 scroll = n;
  527.                         cmd_exec();
  528.                         forward(scroll, 0);
  529.                         break;
  530.  
  531.                 case 'u':
  532.                 case CONTROL('U'):
  533.                         /*
  534.                          * Backward N lines
  535.                          * (default same as last 'd' or 'u' command).
  536.                          */
  537.                         n = cmd_int();
  538.                         if (n > 0)
  539.                                 scroll = n;
  540.                         cmd_exec();
  541.                         backward(scroll, 0);
  542.                         break;
  543.  
  544.                 case 'R':
  545.                         /*
  546.                          * Flush buffers, then repaint screen.
  547.                          * Don't flush the buffers on a pipe!
  548.                          */
  549.                         if (!ispipe)
  550.                                 ch_init(0);
  551.                         /* Fall thru */
  552.                 case 'r':
  553.                 case CONTROL('R'):
  554.                 case CONTROL('L'):
  555.                         /*
  556.                          * Repaint screen.
  557.                          */
  558.                         repaint();
  559.                         break;
  560.  
  561.                 case 'g':
  562. #ifdef AMIGA
  563.                 case '<':
  564. #endif
  565.                         /*
  566.                          * Go to line N, default beginning of file.
  567.                          */
  568.                         n = cmd_int();
  569.                         if (n <= 0)
  570.                                 n = 1;
  571.                         cmd_exec();
  572.                         jump_back(n);
  573.                         break;
  574.  
  575.                 case 'p':
  576.                 case '%':
  577.                         /*
  578.                          * Go to a specified percentage into the file.
  579.                          */
  580.                         n = cmd_int();
  581.                         if (n < 0)
  582.                                 n = 0;
  583.                         if (n > 100)
  584.                                 n = 100;
  585.                         cmd_exec();
  586.                         jump_percent(n);
  587.                         break;
  588.  
  589.                 case 'G':
  590. #ifdef AMIGA
  591.                 case '>':
  592. #endif
  593.                         /*
  594.                          * Go to line N, default end of file.
  595.                          */
  596.                         n = cmd_int();
  597.                         cmd_exec();
  598.                         if (n <= 0)
  599.                                 jump_forw();
  600.                         else
  601.                                 jump_back(n);
  602.                         break;
  603.  
  604.                 case '=':
  605.                 case CONTROL('G'):
  606.                         /*
  607.                          * Print file name, etc.
  608.                          */
  609.                         error(eq_message());
  610.                         break;
  611.  
  612.                 case 'V':
  613.                         /*
  614.                          * Print version number, without the "$VER: ".
  615.                          */
  616.                         error(Ver);
  617.                         break;
  618.  
  619.                 case 'q':
  620. #ifdef AMIGA
  621.                 case 'Q':
  622. #endif
  623.                         /*
  624.                          * Exit.
  625.                          */
  626.                         /*setjmp(main_loop);*/
  627.                         quit();
  628.  
  629. #ifdef AMIGA
  630.                 case CONTROL('S'):
  631.                         c = '/';
  632.                         /* v v v  fall through  v v v */
  633. #endif
  634.                 case '/':
  635.                 case '?':
  636.                         /*
  637.                          * Search for a pattern.
  638.                          * Accept chars of the pattern until \n.
  639.                          */
  640.                         n = cmd_int();
  641.                         if (n <= 0)
  642.                                 n = 1;
  643.                         start_mcc(c);
  644.                         last_mcc = c;
  645.                         c = getcc();
  646.                         goto again;
  647.  
  648.                 case 'n':
  649.                         /*
  650.                          * Repeat previous search.
  651.                          */
  652.                         n = cmd_int();
  653.                         if (n <= 0)
  654.                                 n = 1;
  655.                         start_mcc(last_mcc);
  656.                         cmd_exec();
  657.                         search(mcc, (char *)NULL, n);
  658.                         mcc = 0;
  659.                         break;
  660. #ifdef AMIGA
  661.  
  662.                 /* I didn't want a separate help file because people might
  663.                         not donwload it and then where would we be */
  664.                 case 'H':
  665.                 case 'h':
  666.                         screen_trashed = 1;
  667.                         help();
  668.                         break;
  669. #else
  670.                 case 'H':
  671.                         /*
  672.                          * Help.
  673.                          */
  674.                         lower_left();
  675.                         clear_eol();
  676.                         putstr("help");
  677.                         cmd_exec();
  678.                         help();
  679.                         screen_trashed = 1;
  680.                         break;
  681. #endif
  682.  
  683.                 case 'E':
  684.                         /*
  685.                          * Edit a new file.  Get the filename.
  686.                          */
  687.                         cmd_reset();
  688.                         start_mcc('E');
  689.                         putstr("xamine: ");     /* This looks nicer */
  690.                         cmd_col += 8;
  691.                         c = getcc();
  692.                         goto again;
  693.  
  694.                 case '!':
  695. #if SHELL_ESCAPE
  696.                         /*
  697.                          * Shell escape.
  698.                          */
  699.                         cmd_reset();
  700.                         start_mcc('!');
  701.                         c = getcc();
  702.                         goto again;
  703. #else
  704.                         error("Command not available");
  705.                         break;
  706. #endif
  707.  
  708.                 case 'v':
  709. #if EDITOR
  710.                         if (ispipe)
  711.                         {
  712.                                 error("Cannot edit standard input");
  713.                                 break;
  714.                         }
  715.                         sprintf(cmdbuf, "%s %s", editor, current_file);
  716.                         lsystem(cmdbuf);
  717.                         ch_init(0);
  718.                         screen_trashed = 1;
  719.                         break;
  720. #else
  721.                         error("Command not available");
  722.                         break;
  723. #endif
  724.  
  725.                 case 'N':
  726.                         /*
  727.                          * Examine next file.
  728.                          */
  729.                         n = cmd_int();
  730.                         if (n <= 0)
  731.                                 n = 1;
  732.                         next_file(n);
  733.                         break;
  734.  
  735.                 case 'P':
  736.                         /*
  737.                          * Examine previous file.
  738.                          */
  739.                         n = cmd_int();
  740.                         if (n <= 0)
  741.                                 n = 1;
  742.                         prev_file(n);
  743.                         break;
  744.  
  745.                 case '-':
  746.                         /*
  747.                          * Toggle a flag setting.
  748.                          */
  749.                         cmd_reset();
  750.                         start_mcc('-');
  751.                         c = getcc();
  752.                         goto again;
  753.  
  754.                 case '+':
  755.                         cmd_reset();
  756.                         start_mcc('+');
  757.                         c = getcc();
  758.                         goto again;
  759.  
  760.                 case 'm':
  761.                         /*
  762.                          * Set a mark.
  763.                          */
  764.                         lower_left();
  765.                         clear_eol();
  766.                         putstr("mark: ");
  767.                         c = getcc();
  768.                         if (c == erase_char || c == kill_char)
  769.                                 break;
  770.                         setmark(c);
  771.                         break;
  772.  
  773.                 case '\'':
  774.                         /*
  775.                          * Go to a mark.
  776.                          */
  777.                         lower_left();
  778.                         clear_eol();
  779.                         putstr("goto mark: ");
  780.                         c = getcc();
  781.                         if (c == erase_char || c == kill_char)
  782.                                 break;
  783.                         gomark(c);
  784.                         break;
  785.  
  786.                 default:
  787. #ifdef AMIGA
  788.                 if (++user_errors > 2) {
  789.                    lower_left();
  790.                    clear_eol();
  791.                    so_enter();
  792.                    putchr(c);
  793.                    putstr(" is an Invalid Command, Type H for help, or Q to quit");
  794.                    so_exit();
  795.                    /* give him some time to read it, and three more trys */
  796.                    Delay(3 * 50L);
  797.                    user_errors = 0;
  798.                 } else
  799. #endif
  800.                         bell();
  801.                         break;
  802.                 }
  803.         }
  804. }
  805.