home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d0xx / d034 / less.lha / Less / command.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-09-03  |  9.4 KB  |  596 lines

  1. /*
  2.  * User-level command processor.
  3.  */
  4.  
  5. #include "less.h"
  6. #include "position.h"
  7. #include <setjmp.h>
  8.  
  9. extern jmp_buf main_loop;
  10. extern int erase_char, kill_char;
  11. extern int pr_type;
  12. extern int sigs;
  13. extern int ispipe;
  14. extern int quit_at_eof;
  15. extern int hit_eof;
  16. extern int sc_width, sc_height;
  17. extern char *first_cmd;
  18. extern char version[];
  19. extern char current_file[];
  20. extern char *editor;
  21.  
  22. static char cmdbuf[90];         /* Buffer for holding a multi-char command */
  23. static char *cp;                /* Pointer into cmdbuf */
  24. static int cmd_col;             /* Current column of the multi-char command */
  25. static char mcc;                /* The multi-char command letter (e.g. '/') */
  26. static char last_mcc;           /* The previous mcc */
  27.  
  28. /*
  29.  * Reset command buffer (to empty).
  30.  */
  31. cmd_reset()
  32. {
  33.     cp = cmdbuf;
  34. }
  35.  
  36. /*
  37.  * Backspace in command buffer.
  38.  */
  39.     static int
  40. cmd_erase()
  41. {
  42.     if (cp == cmdbuf)
  43.         /*
  44.          * Backspace past beginning of the string:
  45.          * this usually means abort the command.
  46.          */
  47.         return (1);
  48.  
  49.     if (control_char(*--cp))
  50.     {
  51.         /*
  52.          * Erase an extra character, for the carat.
  53.          */
  54.         backspace();
  55.         cmd_col--;
  56.     }
  57.     backspace();
  58.     cmd_col--;
  59.     return (0);
  60. }
  61.  
  62. /*
  63.  * Set up the display to start a new multi-character command.
  64.  */
  65. start_mcc()
  66. {
  67.     lower_left();
  68.     clear_eol();
  69.     putc(mcc);
  70.     cmd_col = 1;
  71. }
  72.  
  73. /*
  74.  * Process a single character of a multi-character command, such as
  75.  * a number, or the pattern of a search command.
  76.  */
  77.     static int
  78. cmd_char(c)
  79.     int c;
  80. {
  81.     if (c == erase_char)
  82.     {
  83.         if (cmd_erase())
  84.             return (1);
  85.     } else if (c == kill_char)
  86.     {
  87.         /* {{ Could do this faster, but who cares? }} */
  88.         while (cmd_erase() == 0)
  89.             ;
  90.     } else
  91.     {
  92.         /*
  93.          * Append the character to the string,
  94.          * if there is room in the buffer and on the screen.
  95.          */
  96.         if (cp < &cmdbuf[sizeof(cmdbuf)-1] && cmd_col < sc_width-3)
  97.         {
  98.             *cp++ = c;
  99.             if (control_char(c))
  100.             {
  101.                 putc('^');
  102.                 cmd_col++;
  103.                 c = carat_char(c);
  104.             }
  105.             putc(c);
  106.             cmd_col++;
  107.         } else
  108.             bell();
  109.     }
  110.     return (0);
  111. }
  112.  
  113. /*
  114.  * Return the number currently in the command buffer.
  115.  */
  116.     static int
  117. cmd_int()
  118. {
  119.     *cp = '\0';
  120.     cp = cmdbuf;
  121.     return (atoi(cmdbuf));
  122. }
  123.  
  124. /*
  125.  * Move the cursor to lower left before executing a command.
  126.  * This looks nicer if the command takes a long time before
  127.  * updating the screen.
  128.  */
  129.     static void
  130. cmd_exec()
  131. {
  132.     lower_left();
  133.     flush();
  134. }
  135.  
  136. /*
  137.  * Display the appropriate prompt.
  138.  */
  139.     static void
  140. prompt()
  141. {
  142.     register char *p;
  143.  
  144.     if (first_cmd != NULL && *first_cmd != '\0')
  145.         /*
  146.          * No prompt necessary if commands are from first_cmd
  147.          * rather than from the user.
  148.          */
  149.         return;
  150.  
  151.     /*
  152.      * Select the proper prompt and display it.
  153.      */
  154.     p = pr_string();
  155.     if (p == NULL)
  156.         putc(':');
  157.     else
  158.     {
  159.         so_enter();
  160.         puts(p);
  161.         so_exit();
  162.     }
  163. }
  164.  
  165. /*
  166.  * Get command character.
  167.  * The character normally comes from the keyboard,
  168.  * but may come from the "first_cmd" string.
  169.  */
  170.     static int
  171. getcc()
  172. {
  173.     if (first_cmd == NULL)
  174.         return (getc());
  175.  
  176.     if (*first_cmd == '\0')
  177.     {
  178.         /*
  179.          * Reached end of first_cmd input.
  180.          */
  181.         first_cmd = NULL;
  182.         if (cp > cmdbuf && position(TOP) == NULL_POSITION)
  183.         {
  184.             /*
  185.              * Command is incomplete, so try to complete it.
  186.              * There are only two cases:
  187.              * 1. We have "/string" but no newline.  Add the \n.
  188.              * 2. We have a number but no command.  Treat as #g.
  189.              * (This is all pretty hokey.)
  190.              */
  191.             if (mcc != ':')
  192.                 return ('\n'); 
  193.             else
  194.                 return ('g');
  195.         }
  196.         return (getc());
  197.     }
  198.     return (*first_cmd++);
  199. }
  200.  
  201. /*
  202.  * Main command processor.
  203.  * Accept and execute commands until a quit command, then return.
  204.  */
  205.     public void
  206. commands()
  207. {
  208.     register int c;
  209.     register int n;
  210.     register int scroll = 10;
  211.  
  212.     mcc = last_mcc = 0;
  213.  
  214.     setjmp(main_loop);
  215.     for (;;)
  216.     {
  217.         /*
  218.          * Display prompt and accept a character.
  219.          */
  220.         psignals();     /* See if any signals need processing */
  221.  
  222.         if (quit_at_eof && hit_eof > 1)
  223.             /*
  224.              * After hitting end-of-file for the second time,
  225.              * automatically advance to the next file.
  226.              * If there are no more files, quit.
  227.              */
  228.             next_file(1);
  229.  
  230.         cmd_reset();
  231.         lower_left();
  232.         clear_eol();
  233.         prompt();
  234.         c = getcc();
  235.  
  236.     again:
  237.         if (sigs)
  238.             continue;
  239.  
  240.         if (mcc)
  241.         {
  242.             /*
  243.              * We are in a multi-character command.  
  244.              * All chars until newline go into the command buffer.
  245.              * (Note that mcc == ':' is a special case that
  246.              *  means a number is being entered.)
  247.              */
  248.             if (mcc != ':' && (c == '\n' || c == '\r'))
  249.             {
  250.                 /*
  251.                  * Execute the command.
  252.                  */
  253.                 *cp = '\0';
  254.                 cmd_exec();
  255.                 if (mcc == 'E')
  256.                 {
  257.                     char *p;
  258.                     /*
  259.                      * Ignore leading spaces 
  260.                      * in the filename.
  261.                      */
  262.                     for (p = cmdbuf;  *p == ' ';  p++) ;
  263.                     edit(p);
  264. #if SHELL_ESCAPE
  265.                 } else if (mcc == '!')
  266.                 {
  267.                     lsystem(cmdbuf);
  268.                     error("!done");
  269.                     first_cmd = "r";        /* Repaint */
  270. #endif
  271.                 } else
  272.                     search(mcc, cmdbuf, n);
  273.                 mcc = 0;
  274.             } else
  275.             {
  276.                 if (mcc == ':' && (c < '0' || c > '9') &&
  277.                     c != erase_char && c != kill_char)
  278.                 {
  279.                     /*
  280.                      * This is not part of the number
  281.                      * we were entering.  Process
  282.                      * it as a regular character.
  283.                      */
  284.                     mcc = 0;
  285.                     goto again;
  286.                 }
  287.  
  288.                 /*
  289.                  * Append the char to the command buffer.
  290.                  */
  291.                 if (cmd_char(c))
  292.                 {
  293.                     /* Abort the multi-char command. */
  294.                     mcc = 0;
  295.                     continue;
  296.                 }
  297.                 c = getcc();
  298.                 goto again;
  299.             }
  300.         } else switch (c)
  301.         {
  302.         case '0': case '1': case '2': case '3': case '4':
  303.         case '5': case '6': case '7': case '8': case '9':
  304.             /*
  305.              * First digit of a number.
  306.              */
  307.             mcc = ':';
  308.             start_mcc();
  309.             goto again;
  310.  
  311.         case 'f':
  312.         case ' ':
  313.         case CONTROL('F'):
  314.             /*
  315.              * Forward one screen.
  316.              */
  317.             n = cmd_int();
  318.             if (n <= 0)
  319.                 n = sc_height - 1;
  320.             forward(n, 1);
  321.             break;
  322.  
  323.         case 'b':
  324.         case CONTROL('B'):
  325.             /*
  326.              * Backward one screen.
  327.              */
  328.             n = cmd_int();
  329.             if (n <= 0)
  330.                 n = sc_height - 1;
  331.             backward(n, 1);
  332.             break;
  333.  
  334.         case 'e':
  335.         case 'j':
  336.         case '\r':
  337.         case '\n':
  338.         case CONTROL('E'):
  339.             /*
  340.              * Forward N (default 1) line.
  341.              */
  342.             n = cmd_int();
  343.             if (n <= 0)
  344.                 n = 1;
  345.             forward(n, 0);
  346.             break;
  347.  
  348.         case 'y':
  349.         case 'k':
  350.         case CONTROL('K'):
  351.         case CONTROL('Y'):
  352.             /*
  353.              * Backward N (default 1) line.
  354.              */
  355.             n = cmd_int();
  356.             if (n <= 0)
  357.                 n = 1;
  358.             backward(n, 0);
  359.             break;
  360.  
  361.         case 'd':
  362.         case CONTROL('D'):
  363.             /*
  364.              * Forward N lines 
  365.              * (default same as last 'd' or 'u' command).
  366.              */
  367.             n = cmd_int();
  368.             if (n > 0)
  369.                 scroll = n;
  370.             forward(scroll, 0);
  371.             break;
  372.  
  373.         case 'u':
  374.         case CONTROL('U'):
  375.             /*
  376.              * Forward N lines 
  377.              * (default same as last 'd' or 'u' command).
  378.              */
  379.             n = cmd_int();
  380.             if (n > 0)
  381.                 scroll = n;
  382.             backward(scroll, 0);
  383.             break;
  384.  
  385.         case 'R':
  386.             /*
  387.              * Flush buffers, then repaint screen.
  388.              */
  389.             ch_init(0);
  390.             /* Fall thru */
  391.         case 'r':
  392.         case CONTROL('R'):
  393.         case CONTROL('L'):
  394.             /*
  395.              * Repaint screen.
  396.              */
  397.             repaint();
  398.             break;
  399.  
  400.         case 'g':
  401.             /*
  402.              * Go to line N, default beginning of file.
  403.              */
  404.             n = cmd_int();
  405.             if (n <= 0)
  406.                 n = 1;
  407.             cmd_exec();
  408.             jump_back(n);
  409.             break;
  410.  
  411.         case 'p':
  412.         case '%':
  413.             /*
  414.              * Go to a specified percentage into the file.
  415.              */
  416.             n = cmd_int();
  417.             if (n < 0)
  418.                 n = 0;
  419.             if (n > 100)
  420.                 n = 100;
  421.             cmd_exec();
  422.             jump_percent(n);
  423.             break;
  424.  
  425.         case 'G':
  426.             /*
  427.              * Go to line N, default end of file.
  428.              */
  429.             n = cmd_int();
  430.             cmd_exec();
  431.             if (n <= 0)
  432.                 jump_forw();
  433.             else
  434.                 jump_back(n);
  435.             break;
  436.  
  437.         case '=':
  438.         case CONTROL('G'):
  439.             /*
  440.              * Print file name, etc.
  441.              */
  442.             error(eq_message());
  443.             break;
  444.             
  445.         case 'V':
  446.             /*
  447.              * Print version number, without the "@(#)".
  448.              */
  449.             error(version+4);
  450.             break;
  451.  
  452.         case 'q':
  453.             /*
  454.              * Exit.
  455.              */
  456.             return;
  457.  
  458.         case '/':
  459.         case '?':
  460.             /*
  461.              * Search for a pattern.
  462.              * Accept chars of the pattern until \n.
  463.              */
  464.             n = cmd_int();
  465.             if (n <= 0)
  466.                 n = 1;
  467.             mcc = last_mcc = c;
  468.             start_mcc();
  469.             c = getcc();
  470.             goto again;
  471.  
  472.         case 'n':
  473.             /*
  474.              * Repeat previous search.
  475.              */
  476.             n = cmd_int();
  477.             if (n <= 0)
  478.                 n = 1;
  479.             mcc = last_mcc;
  480.             start_mcc();
  481.             cmd_exec();
  482.             search(mcc, (char *)NULL, n);
  483.             mcc = 0;
  484.             break;
  485.  
  486.         case 'h':
  487.             /*
  488.              * Help.
  489.              */
  490.             help();
  491.             repaint();
  492.             break;
  493.  
  494.         case 'E':
  495.             /*
  496.              * Edit a new file.  Get the filename.
  497.              */
  498.             cmd_reset();
  499.             mcc = 'E';
  500.             start_mcc();
  501.             puts("dit: ");  /* This looks nicer */
  502.             cmd_col += 5;
  503.             c = getcc();
  504.             goto again;
  505.             
  506. #if SHELL_ESCAPE
  507.         case '!':
  508.             /*
  509.              * Shell escape.
  510.              */
  511.             cmd_reset();
  512.             mcc = '!';
  513.             start_mcc();
  514.             c = getcc();
  515.             goto again;
  516. #endif
  517.  
  518. #if EDITOR
  519.         case 'v':
  520.             if (ispipe)
  521.             {
  522.                 error("Cannot edit standard input");
  523.                 break;
  524.             }
  525.             sprintf(cmdbuf, "%s %s", editor, current_file);
  526.             lsystem(cmdbuf);
  527.             first_cmd = "R";
  528.             break;
  529. #endif
  530.  
  531.         case 'N':
  532.             /*
  533.              * Examine next file.
  534.              */
  535.             n = cmd_int();
  536.             if (n <= 0)
  537.                 n = 1;
  538.             next_file(n);
  539.             break;
  540.  
  541.         case 'P':
  542.             /*
  543.              * Examine previous file.
  544.              */
  545.             n = cmd_int();
  546.             if (n <= 0)
  547.                 n = 1;
  548.             prev_file(n);
  549.             break;
  550.  
  551.         case '-':
  552.             /*
  553.              * Toggle a flag setting.
  554.              */
  555.             mcc = '-';
  556.             start_mcc();
  557.             c = getcc();
  558.             mcc = 0;
  559.             if (c == erase_char || c == kill_char)
  560.                 break;
  561.             toggle_option(c);
  562.             break;
  563.  
  564.         case 'm':
  565.             /*
  566.              * Set a mark.
  567.              */
  568.             lower_left();
  569.             clear_eol();
  570.             puts("mark: ");
  571.             c = getcc();
  572.             if (c == erase_char || c == kill_char)
  573.                 break;
  574.             setmark(c);
  575.             break;
  576.  
  577.         case '\'':
  578.             /*
  579.              * Go to a mark.
  580.              */
  581.             lower_left();
  582.             clear_eol();
  583.             puts("goto mark: ");
  584.             c = getcc();
  585.             if (c == erase_char || c == kill_char)
  586.                 break;
  587.             gomark(c);
  588.             break;
  589.  
  590.         default:
  591.             bell();
  592.             break;
  593.         }
  594.     }
  595. }
  596.