home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / program / d / elvis / Source / c / tio < prev    next >
Encoding:
Text File  |  1990-03-08  |  10.2 KB  |  561 lines

  1. /* tio.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    16820 SW Tallac Way
  6.  *    Beaverton, OR 97006
  7.  *    kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
  8.  */
  9.  
  10.  
  11. /* This file contains terminal I/O functions */
  12.  
  13. #include <signal.h>
  14. #include "vi.h"
  15.  
  16.  
  17. /* This function reads in a line from the terminal. */
  18. int vgets(prompt, buf, bsize)
  19.     char    prompt;    /* the prompt character, or '\0' for none */
  20.     char    *buf;    /* buffer into which the string is read */
  21.     int    bsize;    /* size of the buffer */
  22. {
  23.     int    len;    /* how much we've read so far */
  24.     int    ch;    /* a character from the user */
  25.     int    quoted;    /* is the next char quoted? */
  26.     int    tab;    /* column position of cursor */
  27.     char    widths[132];    /* widths of characters */
  28.  
  29.     /* show the prompt */
  30.     move(LINES - 1, 0);
  31.     tab = 0;
  32.     if (prompt)
  33.     {
  34.         addch(prompt);
  35.         tab = 1;
  36.     }
  37.     clrtoeol();
  38.     refresh();
  39.  
  40.     /* read in the line */
  41.     quoted = len = 0;
  42.     for (;;)
  43.     {
  44.         ch = getkey(quoted ? 0 : WHEN_EX);
  45.  
  46.         /* some special conversions */
  47.         if (ch == ctrl('D') && len == 0)
  48.             ch = ctrl('[');
  49.  
  50.         /* inhibit detection of special chars (except ^J) after a ^V */
  51.         if (quoted && ch != '\n')
  52.         {
  53.             ch |= 256;
  54.         }
  55.  
  56.         /* process the character */
  57.         switch(ch)
  58.         {
  59.           case ctrl('V'):
  60.             qaddch('^');
  61.             qaddch('\b');
  62.             quoted = TRUE;
  63.             break;
  64.  
  65.           case ctrl('['):
  66.             return -1;
  67.  
  68.           case '\n':
  69.           case '\r':
  70.             clrtoeol();
  71.             goto BreakBreak;
  72.  
  73.           case '\b':
  74.             if (len > 0)
  75.             {
  76.                 len--;
  77.                 addstr("\b\b\b\b\b\b\b\b" + 8 - widths[len]);
  78.                 tab -= widths[len];
  79.             }
  80.             else
  81.             {
  82.                 return -1;
  83.             }
  84.             break;
  85.  
  86.           default:
  87.             /* strip off quotation bit */
  88.             if (ch & 256)
  89.             {
  90.                 ch &= ~256;
  91.                 quoted = FALSE;
  92.                 qaddch(' ');
  93.                 qaddch('\b');
  94.             }
  95.             /* add & echo the char */
  96.             if (len < bsize - 1)
  97.             {
  98.                 if (ch == '\t')
  99.                 {
  100.                     widths[len] = *o_tabstop - (tab % *o_tabstop);
  101.                     addstr("        " + 8 - widths[len]);
  102.                     tab += widths[len];
  103.                 }
  104.                 else if (ch < ' ')
  105.                 {
  106.                     addch('^');
  107.                     addch(ch + '@');
  108.                     widths[len] = 2;
  109.                     tab += 2;
  110.                 }
  111.                 else if (ch == '\177')
  112.                 {
  113.                     addch('^');
  114.                     addch('?');
  115.                     widths[len] = 2;
  116.                     tab += 2;
  117.                 }
  118.                 else
  119.                 {
  120.                     addch(ch);
  121.                     widths[len] = 1;
  122.                     tab++;
  123.                 }
  124.                 buf[len++] = ch;
  125.             }
  126.             else
  127.             {
  128.                 beep();
  129.             }
  130.         }
  131.     }
  132. BreakBreak:
  133.     refresh();
  134.     buf[len] = '\0';
  135.     return len;
  136. }
  137.  
  138.  
  139. /* ring the terminal's bell */
  140. beep()
  141. {
  142.     if (*o_vbell)
  143.     {
  144.         tputs(VB, 1, faddch);
  145.         refresh();
  146.     }
  147.     else
  148.     {
  149.         write(1, "\007", 1);
  150.     }
  151. }
  152.  
  153. static manymsgs; /* This variable keeps msgs from overwriting each other */
  154.  
  155. /* Write a message in an appropriate way.  This should really be a varargs
  156.  * function, but there is no such thing as vwprintw.  Hack!!!  Also uses a
  157.  * little sleaze in the way it saves messages for repetition later.
  158.  *
  159.  * msg((char *)0)    - repeats the previous message
  160.  * msg("")        - clears the message line
  161.  * msg("%s %d", ...)    - does a printf onto the message line
  162.  */
  163. msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
  164.     char    *fmt;
  165.     char    *arg1, *arg2, *arg3, *arg4, *arg5, *arg6, *arg7;
  166. {
  167.     static char    pmsg[80];    /* previous message */
  168.     char        *start;        /* start of current message */
  169.  
  170.     if (mode != MODE_VI)
  171.     {
  172.         wprintw(stdscr, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
  173.         addch('\n');
  174.         exrefresh();
  175.     }
  176.     else
  177.     {
  178.         /* redrawing previous message? */
  179.         if (!fmt)
  180.         {
  181.             move(LINES - 1, 0);
  182.             standout();
  183.             qaddch(' ');
  184.             addstr(pmsg);
  185.             qaddch(' ');
  186.             standend();
  187.             clrtoeol();
  188.             return;
  189.         }
  190.  
  191.         /* just blanking out message line? */
  192.         if (!*fmt)
  193.         {
  194.             if (!*pmsg) return;
  195.             *pmsg = '\0';
  196.             move(LINES - 1, 0);
  197.             clrtoeol();
  198.             return;
  199.         }
  200.  
  201.         /* wait for keypress between consecutive msgs */
  202.         if (manymsgs)
  203.         {
  204.             qaddstr("[More...]");
  205.             wqrefresh(stdscr);
  206.             getkey(0);
  207.         }
  208.  
  209.         /* real message */
  210.         move(LINES - 1, 0);
  211.         standout();
  212.         qaddch(' ');
  213.         start = stdscr;
  214.         wprintw(stdscr, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
  215.         strcpy(pmsg, start);
  216.         qaddch(' ');
  217.         standend();
  218.         clrtoeol();
  219.         refresh();
  220.     }
  221.     manymsgs = TRUE;
  222. }
  223.  
  224.  
  225. /* This function calls refresh() if the option exrefresh is set */
  226. exrefresh()
  227. {
  228.     /* If this ex command wrote ANYTHING set exwrote so vi's  :  command
  229.      * can tell that it must wait for a user keystroke before redrawing.
  230.      */
  231.     if (stdscr > kbuf)
  232.     {
  233.         exwrote = TRUE;
  234.     }
  235.  
  236.     /* now we do the refresh thing */
  237.     if (*o_exrefresh)
  238.     {
  239.         refresh();
  240.     }
  241.     else
  242.     {
  243.         wqrefresh(stdscr);
  244.     }
  245.     manymsgs = FALSE;
  246. }
  247.  
  248.  
  249. /* This variable holds a single ungotten key, or 0 for no key */
  250. static int ungotten;
  251. ungetkey(key)
  252.     int    key;
  253. {
  254.     ungotten = key;
  255. }
  256.  
  257. /* This array describes mapped key sequences */
  258. static struct _keymap
  259. {
  260.     char    rawin[LONGKEY];    /* the unmapped version of input */
  261.     char    cooked[80];    /* the mapped version of input */
  262.     int    len;        /* length of the unmapped version */
  263.     int    when;        /* when is this key mapped? */
  264. }
  265.     mapped[MAXMAPS];
  266.  
  267. /* This function reads in a keystroke for VI mode.  It automatically handles
  268.  * key mapping.
  269.  */
  270. static int dummy(){} /* for timeout */
  271. int getkey(when)
  272.     int        when;        /* which bits must be ON? */
  273. {
  274.     static char    keybuf[100];    /* array of already-read keys */
  275.     static int    nkeys;        /* total number of keys in keybuf */
  276.     static int    next;        /* index of next key to return */
  277.     static char    *cooked;    /* rawin, or pointer to converted key */ 
  278.     register char    *kptr;        /* &keybuf[next] */
  279.     register struct _keymap *km;    /* used to count through keymap */
  280.     register int    i, j, k;
  281.  
  282.     /* if this key is needed for delay between multiple error messages,
  283.      * then reset the manymsgs flag and abort any mapped key sequence.
  284.      */
  285.     if (manymsgs)
  286.     {
  287.         manymsgs = FALSE;
  288.         cooked = (char *)0;
  289.         ungotten = 0;
  290.     }
  291.  
  292.     /* if we have an ungotten key, use it */
  293.     if (ungotten != 0)
  294.     {
  295.         k = ungotten;
  296.         ungotten = 0;
  297.         return k;
  298.     }
  299.  
  300.     /* if we're doing a mapped key, get the next char */
  301.     if (cooked && *cooked)
  302.     {
  303.         return *cooked++;
  304.     }
  305.  
  306.     /* if keybuf is empty, fill it */
  307.     if (next == nkeys)
  308.     {
  309.         /* redraw if getting a VI command, refresh always */
  310.         if (when & WHEN_VICMD)
  311.         {
  312.             redraw(cursor, FALSE);
  313.         }
  314.         refresh();
  315.  
  316.         /* read the rawin keystrokes */
  317.         while ((nkeys = read(0, keybuf, sizeof keybuf)) < 0)
  318.         {
  319.             /* terminal was probably resized */
  320.             *o_lines = LINES;
  321.             *o_columns = COLS;
  322.             if (when & (WHEN_VICMD|WHEN_VIINP|WHEN_VIREP))
  323.             {
  324.                 redraw(MARK_UNSET, FALSE);
  325.                 redraw(cursor, (when & WHEN_VICMD) == 0);
  326.                 refresh();
  327.             }
  328.         }
  329.         next = 0;
  330.     }
  331.  
  332.     /* see how many mapped keys this might be */
  333.     kptr = &keybuf[next];
  334.     for (i = j = 0, k = -1, km = mapped; i < MAXMAPS; i++, km++)
  335.     {
  336.         if ((km->when & when) && km->len > 0 && *km->rawin == *kptr)
  337.         {
  338.             if (km->len > nkeys - next
  339.              && !strncmp(km->rawin, kptr, nkeys - next))
  340.             {
  341.                 j++;
  342.             }
  343.             else if (km->len <= nkeys - next
  344.              && !strncmp(km->rawin, kptr, km->len))
  345.             {
  346.                 j++;
  347.                 k = i;
  348.             }
  349.         }
  350.     }
  351.  
  352.     /* if more than one, try to read some more */
  353.     if (j > 1 && *o_keytime > 0)
  354.     {
  355.         alarm((unsigned)*o_keytime);
  356.         k = read(0, keybuf + nkeys, sizeof keybuf - nkeys);
  357.         alarm(0);
  358.  
  359.         /* if we couldn't read any more, pretend 0 mapped keys */
  360.         if (k < 1)
  361.         {
  362.             j = 0;
  363.         }
  364.         else /* else we got some more - try again */
  365.         {
  366.             nkeys += k;
  367.             for (i = j = 0, km = mapped; i < MAXMAPS; i++, km++)
  368.             {
  369.                 if ((km->when & when)
  370.                  && km->len <= nkeys - next
  371.                  && *km->rawin == *kptr
  372.                  && !strncmp(km->rawin, kptr, km->len))
  373.                 {
  374.                     j++;
  375.                     k = i;
  376.                 }
  377.             }
  378.         }
  379.     }
  380.  
  381.     /* if unambiguously mapped key, use it! */
  382.     if (j == 1 && k >= 0)
  383.     {
  384.         next += mapped[k].len;
  385.         cooked = mapped[k].cooked;
  386.         return *cooked++;
  387.     }
  388.     else
  389.     /* assume key is unmapped, but still translate weird erase key to '\b' */
  390.     if (keybuf[next] == ERASEKEY && when != 0)
  391.     {
  392.         next++;
  393.         return '\b';
  394.     }
  395.     else
  396.     {
  397.         return keybuf[next++];
  398.     }
  399. }
  400.  
  401.  
  402. mapkey(rawin, cooked, when)
  403.     char    *rawin;    /* the input key sequence, before mapping */
  404.     char    *cooked;/* after mapping */
  405. {
  406.     int    i, j;
  407.  
  408.     /* see if the key sequence was mapped before */
  409.     j = strlen(rawin);
  410.     for (i = 0; i < MAXMAPS; i++)
  411.     {
  412.         if (mapped[i].len == j && !strncmp(mapped[i].rawin, rawin, j))
  413.         {
  414.             break;
  415.         }
  416.     }
  417.  
  418.     /* if not, then try to find a new slot to use */
  419.     if (i == MAXMAPS)
  420.     {
  421.         for (i = 0; i < MAXMAPS && mapped[i].len > 0; i++)
  422.         {
  423.         }
  424.     }
  425.  
  426.     /* no room for the new key? */
  427.     if (i == MAXMAPS)
  428.     {
  429.         msg("No room left in the key map table");
  430.         return;
  431.     }
  432.  
  433.     if (cooked && *cooked)
  434.     {
  435.         /* Map the key */
  436.         mapped[i].len = j;
  437.         strncpy(mapped[i].rawin, rawin, j);
  438.         strcpy(mapped[i].cooked, cooked);
  439.         mapped[i].when = when;
  440.     }
  441.     else
  442.     {
  443.         mapped[i].len = 0;
  444.     }
  445. }
  446.  
  447.  
  448. dumpkey()
  449. {
  450.     int    i;
  451.     char    *scan;
  452.  
  453.     for (i = 0; i < MAXMAPS; i++)
  454.     {
  455.         /* skip unused entries */
  456.         if (mapped[i].len <= 0)
  457.         {
  458.             continue;
  459.         }
  460.  
  461.         /* dump the key label, if any */
  462.         if (KU && !strncmp(KU, mapped[i].rawin, mapped[i].len))
  463.         {
  464.             qaddstr("<up>");
  465.         }
  466.         else if (KD && !strncmp(KD, mapped[i].rawin, mapped[i].len))
  467.         {
  468.             qaddstr("<down>");
  469.         }
  470.         else if (KL && !strncmp(KL, mapped[i].rawin, mapped[i].len))
  471.         {
  472.             qaddstr("<left>");
  473.         }
  474.         else if (KR && !strncmp(KR, mapped[i].rawin, mapped[i].len))
  475.         {
  476.             qaddstr("<right>");
  477.         }
  478.         qaddch('\t');
  479.  
  480.         /* write a '!' if defined with map! */
  481.         if (mapped[i].when & (WHEN_EX|WHEN_VIINP))
  482.         {
  483.             qaddch('!');
  484.         }
  485.         else
  486.         {
  487.             qaddch(' ');
  488.         }
  489.         qaddch(' ');
  490.  
  491.         /* dump the raw version */
  492.         for (scan = mapped[i].rawin; scan < mapped[i].rawin + mapped[i].len; scan++)
  493.         {
  494.             if (*scan >= 0 && *scan < ' ' || *scan == '\177')
  495.             {
  496.                 qaddch('^');
  497.                 qaddch(*scan ^ '@');
  498.             }
  499.             else
  500.             {
  501.                 qaddch(*scan);
  502.             }
  503.         }
  504.  
  505.         qaddch('\t');
  506.  
  507.         /* dump the mapped version */
  508.         for (scan = mapped[i].cooked; *scan; scan++)
  509.         {
  510.             if (*scan >= 0 && *scan < ' ' || *scan == '\177')
  511.             {
  512.                 qaddch('^');
  513.                 qaddch(*scan ^ '@');
  514.             }
  515.             else
  516.             {
  517.                 qaddch(*scan);
  518.             }
  519.         }
  520.  
  521.         addch('\n');
  522.     }
  523.     exrefresh();
  524. }
  525.  
  526.  
  527.  
  528. /* This function saves the current configuration of mapped keys to a file */
  529. savekeys(fd)
  530.     int    fd;    /* file descriptor to save them to */
  531. {
  532.     int    i;
  533.  
  534.     /* HACK! refresh the screen now, so the output buffer is empty. */
  535.     refresh();
  536.  
  537.     /* now write a map command for each key other thna the arrows */
  538.     for (i = 4; i < MAXMAPS; i++)
  539.     {
  540.         /* If this isn't used, ignore it */
  541.         if (mapped[i].len <= 0)
  542.         {
  543.             continue;
  544.         }
  545.  
  546.         /* write the map command */
  547.         wprintw(stdscr, "map%c %.*s %s",
  548.             (mapped[i].when & (WHEN_EX|WHEN_VIINP)) ? '!' : ' ',
  549.             mapped[i].len, mapped[i].rawin,
  550.             mapped[i].cooked);
  551.         qaddch('\n');
  552.     }
  553.  
  554.     /* now write the buffer to the file */
  555.     if (stdscr != kbuf)
  556.     {
  557.         write(fd, kbuf, (stdscr - kbuf));
  558.         stdscr = kbuf;
  559.     }
  560. }
  561.