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 / command.c < prev    next >
C/C++ Source or Header  |  1991-07-03  |  25KB  |  809 lines

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