home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_10_01 / 1001038a < prev    next >
Text File  |  1991-10-05  |  6KB  |  288 lines

  1. /*
  2.  * Get input string, with VMS-style input line editing
  3.  * and previous-command scrolling.
  4.  *
  5.  * Written for Turbo C 2.0 / Borland C++ 2.0
  6.  * Bob Bybee, 2/91
  7.  */
  8. #include <stdio.h>
  9. #include <string.h>
  10.  
  11. /* ASCII key definitions */
  12. #define ESC_KEY            0x1b
  13. #define DELETE_KEY        0x7f
  14. #define BACKSPACE_KEY    0x08
  15. #define RETURN_KEY         0x0d
  16. #define CTRL(x) ((x) & 0x1f)
  17.  
  18. /* Arbitrary values for tracking cursor key entry.
  19.  * These happen to match PC BIOS scan codes, but any
  20.  * unique values would work.
  21.  */
  22. #define UP_ARROW    0x4800
  23. #define DOWN_ARROW  0x5000
  24. #define RIGHT_ARROW 0x4d00
  25. #define LEFT_ARROW  0x4b00
  26.  
  27. /* MAX_RECALL is two greater than the number of lines
  28.  * we want in the "lastlines" recall buffer.
  29.  */
  30. #define MAX_RECALL 22
  31. #define RECSUB(x) (((x) + MAX_RECALL) % MAX_RECALL)
  32. #define RECALL_LEN 100
  33. static char lastlines[MAX_RECALL][RECALL_LEN];
  34.  
  35. static int num_got;            /* # chars in input buffer */
  36. static int cursor_pos;        /* cursor position on line */
  37. static int lastptr = 0;        /* ptr to last line entered */
  38. static char erase_one[] = "\b \b";    /* erase one character */
  39. static char *str_ptr;        /* ptr to current input string */
  40.  
  41.  
  42. /* prototypes for this file */
  43. static void clear_line( void );
  44. static int cursor_right( void );
  45. static int cursor_left( void );
  46. static int get_char_esc( void );
  47. static void put_str( char *str );
  48.  
  49. /* external functions (see listing2.c) */
  50. void sys_putchar( char ch );
  51. int sys_getchar( void );
  52.  
  53.  
  54.  
  55. /*
  56.  * get_str() is called by main() to get a line of input.
  57.  * The input line is placed in "str" and will be no
  58.  * more than "len" characters.
  59.  */
  60. void get_str( char *str, int len )
  61.     {
  62.     int i, c, curptr, insert_mode = 1;
  63.  
  64.     num_got = 0;
  65.     cursor_pos = 0;
  66.     str_ptr = str;                /* copy the buffer pointer */
  67.     curptr = RECSUB(lastptr + 1);
  68.     lastlines[curptr][0] = '\0';
  69.     lastlines[RECSUB(curptr + 1)][0] = '\0';
  70.     if (len > RECALL_LEN - 1)    /* limit len to RECALL_LEN */
  71.         len = RECALL_LEN - 1;
  72.  
  73.     while (1)
  74.         {
  75.         c = get_char_esc();
  76.  
  77.         if (c == RETURN_KEY)
  78.             break;
  79.         else if (c == DELETE_KEY || c == BACKSPACE_KEY)
  80.             {
  81.             if (cursor_left())
  82.                 {
  83.                 ++cursor_pos;
  84.                 for (i = cursor_pos; i < num_got; ++i)
  85.                     {
  86.                     str[i - 1] = str[i];
  87.                     sys_putchar(str[i]);
  88.                     }
  89.                 sys_putchar(' ');
  90.                 for (i = cursor_pos; i <= num_got; ++i)
  91.                     sys_putchar('\b');
  92.                 --num_got;
  93.                 --cursor_pos;
  94.                 }
  95.             }
  96.         else if (c == CTRL('X'))    /* erase line? */
  97.             clear_line();
  98.         else if (c == CTRL('A'))    /* insert/overtype? */
  99.             insert_mode ^= 1;
  100.         else if (c == CTRL('B'))    /* beginning-of-line? */
  101.             {
  102.             while (cursor_left())
  103.                 ;
  104.             }
  105.         else if (c == CTRL('E'))    /* end-of-line? */
  106.             {
  107.             while (cursor_right())
  108.                 ;
  109.             }
  110.         else if (c == CTRL('R'))    /* recall last line? */
  111.             {
  112.             clear_line();
  113.             strcpy(str, lastlines[lastptr]);
  114.             if ((num_got = strlen(str)) > 0)
  115.                 {
  116.                 put_str(str);
  117.                 break;
  118.                 }
  119.             }
  120.         else if (c == UP_ARROW)
  121.             {
  122.             clear_line();
  123.             if (lastlines[curptr][0] != '\0' ||
  124.                 lastlines[RECSUB(curptr - 1)][0] != '\0')
  125.                 {
  126.                 curptr = RECSUB(curptr - 1);
  127.                 strcpy(str, lastlines[curptr]);
  128.                 put_str(str);
  129.                 cursor_pos = num_got = strlen(str);
  130.                 }
  131.             }
  132.         else if (c == DOWN_ARROW)
  133.             {
  134.             clear_line();
  135.             if (lastlines[curptr][0] != '\0' ||
  136.                 lastlines[RECSUB(curptr + 1)][0] != '\0')
  137.                 {
  138.                 curptr = RECSUB(curptr + 1);
  139.                 strcpy(str, lastlines[curptr]);
  140.                 put_str(str);
  141.                 cursor_pos = num_got = strlen(str);
  142.                 }
  143.             }
  144.         else if (c == LEFT_ARROW)
  145.             {
  146.             if (cursor_pos > 0)
  147.                 {
  148.                 sys_putchar('\b');
  149.                 --cursor_pos;
  150.                 }
  151.             }
  152.         else if (c == RIGHT_ARROW)
  153.             cursor_right();
  154.         else if (' ' <= c && c < 0x7f && num_got < len - 1)
  155.             {
  156.             if (insert_mode)
  157.                 {
  158.                 /* Move right, all the characters
  159.                  * to the right of cursor_pos.
  160.                  */
  161.                 for (i = num_got; i > cursor_pos; --i)
  162.                     str[i] = str[i - 1];
  163.                 str[cursor_pos] = c;
  164.                 for (i = cursor_pos; i <= num_got; ++i)
  165.                     sys_putchar(str[i]);
  166.                 for (i = cursor_pos; i < num_got; ++i)
  167.                     sys_putchar('\b');
  168.                 ++num_got;
  169.                 ++cursor_pos;
  170.                 }
  171.             else    /* insert is off, use overtype mode */
  172.                 {
  173.                 str[cursor_pos] = c;
  174.                 sys_putchar(c);
  175.                 if (cursor_pos == num_got)
  176.                     ++num_got;
  177.                 ++cursor_pos;
  178.                 }
  179.             }
  180.         }
  181.  
  182.     str[num_got] = '\0';
  183.     sys_putchar('\n');
  184.  
  185.     /* If this line is non-empty, and different
  186.      * from the last one accepted, store it into
  187.      * the recall buffer.
  188.      */
  189.     if (num_got > 0 && strcmp(str, lastlines[lastptr]) != 0)
  190.         {
  191.         lastptr = RECSUB(lastptr + 1);
  192.         strcpy(lastlines[lastptr], str);
  193.         }
  194.     }
  195.  
  196.  
  197. /*
  198.  * Move the cursor right one position, by echoing the
  199.  * character it's currently over.
  200.  * Return 1-OK, 0-can't move.
  201.  */
  202. static int cursor_right( void )
  203.     {
  204.     if (cursor_pos < num_got)
  205.         {
  206.         sys_putchar(str_ptr[cursor_pos]);
  207.         ++cursor_pos;
  208.         return (1);
  209.         }
  210.     return (0);
  211.     }
  212.  
  213.  
  214. /*
  215.  * Move the cursor left one position, by echoing
  216.  * a backspace.  Return 1-OK, 0-can't move.
  217.  */
  218. static int cursor_left( void )
  219.     {
  220.     if (cursor_pos > 0)
  221.         {
  222.         sys_putchar('\b');
  223.         --cursor_pos;
  224.         return (1);
  225.         }
  226.     return (0);
  227.     }
  228.  
  229.  
  230. /*
  231.  * Erase all characters on the current line.
  232.  */
  233. static void clear_line( void )
  234.     {
  235.  
  236.     while (cursor_right())
  237.         ;        /* move right, to end of line */
  238.  
  239.     cursor_pos = 0;
  240.     while (num_got > 0)
  241.         {
  242.         put_str(erase_one);        /* then, erase to left */
  243.         --num_got;
  244.         }
  245.     }
  246.  
  247.  
  248. /*
  249.  * Get a character, with escape processing.
  250.  * Handles special sequences like "ESC [ A" for up-arrow.
  251.  * This function would need to be modified to handle
  252.  * keyboards that are neither PC's nor VT-100's.
  253.  */
  254. static int get_char_esc( void )
  255.     {
  256.     int ch;
  257.  
  258.     ch = sys_getchar();
  259.     if (ch != ESC_KEY)
  260.         return (ch);
  261.  
  262.     ch = sys_getchar();
  263.     if (ch != '[')
  264.         return (ch);
  265.  
  266.     ch = sys_getchar();
  267.     if (ch == 'A')
  268.         return (UP_ARROW);        /* was ESC [ A */
  269.     else if (ch == 'B')
  270.         return (DOWN_ARROW);    /* was ESC [ B */
  271.     else if (ch == 'C')
  272.         return (RIGHT_ARROW);    /* was ESC [ C */
  273.     else if (ch == 'D')
  274.         return (LEFT_ARROW);    /* was ESC [ D */
  275.     else
  276.         return (ch);
  277.     }
  278.  
  279.  
  280. /*
  281.  * Put a string to sys_putchar().
  282.  */
  283. static void put_str( char *str )
  284.     {
  285.     while (*str != '\0')
  286.         sys_putchar(*str++);
  287.     }
  288.