home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / mincom15.zip / vt100.c < prev    next >
C/C++ Source or Header  |  1993-10-09  |  16KB  |  784 lines

  1. /*
  2.  * VT100.C    ANSI/VT102 emulator code.
  3.  *        This code was integrated to the Minicom communications
  4.  *        package, but has been reworked to allow usage as a separate
  5.  *        module.
  6.  *
  7.  *        (C) 1993 Miquel van Smoorenburg.
  8.  */
  9. #include <sys/types.h>
  10. #if defined (_POSIX_SOURCE) || defined(_BSD43)
  11. #  include <stdlib.h>
  12. #  include <unistd.h>
  13. #  undef NULL
  14. #endif
  15. #include <time.h>
  16. #include <stdio.h>
  17. #include <signal.h>
  18. #include <setjmp.h>
  19. #include <string.h>
  20. #include "window.h"
  21. #include "vt100.h"
  22.  
  23. /*
  24.  * The global variable esc_s holds the escape sequence status:
  25.  * 0 - normal
  26.  * 1 - ESC
  27.  * 2 - ESC [
  28.  * 3 - ESC [ ?
  29.  * 4 - ESC (
  30.  * 5 - ESC )
  31.  * 6 - ESC #
  32.  * 7 - ESC P
  33.  */
  34. static int esc_s = 0;
  35.  
  36. #define ESC 27
  37.  
  38. /* Structure to hold escape sequences. */
  39. struct escseq {
  40.   int code;
  41.   char *vt100_st;
  42.   char *vt100_app;
  43.   char *ansi;
  44. };
  45.  
  46. /* Escape sequences for different terminal types. */
  47. static struct escseq vt_keys[] = {
  48.   { K_F1,    "OP",    "OP",    "OP" },
  49.   { K_F2,    "OQ",    "OQ",    "OQ" },
  50.   { K_F3,    "OR",    "OR",    "OR" },
  51.   { K_F4,    "OS",    "OS",    "OS" },
  52.   { K_F5,    "",    "",    "OT" },
  53.   { K_F6,    "",    "",    "OU" },
  54.   { K_F7,    "",    "",    "OV" },
  55.   { K_F8,    "",    "",    "OW" },
  56.   { K_F9,    "",    "",    "OX" },
  57.   { K_F10,    "",    "",    "OY" },
  58.   { K_HOME,    "[H",    "[H",    "[H" },
  59.   { K_PGUP,    "",    "",    "[V" },
  60.   { K_UP,    "[A",    "OA",    "[A" },
  61.   { K_LT,    "[D",    "OD",    "[D" },
  62.   { K_RT,    "[C",    "OC",    "[C" },
  63.   { K_DN,    "[B",    "OB",    "[B" },
  64.   { K_END,    "[K",    "[K",    "[Y" },
  65.   { K_PGDN,    "",    "",    "[U" },
  66.   { K_INS,    "",    "",    "0"  },
  67.   { K_DEL,    "\177",    "\177",    "\177" },
  68.   { 0,        NULL,    NULL,    NULL },
  69. };
  70.  
  71. #ifndef _SELECT
  72. /* This is cheaper. */
  73. #  define v_termout termout
  74. #endif
  75.  
  76. #ifdef _SELECT
  77. static int vt_echo;        /* Local echo on/off. */
  78. #endif
  79. static int vt_type   = ANSI;    /* Terminal type. */
  80. static int vt_wrap   = 0;    /* Line wrap on/off */
  81. static int vt_addlf  = 0;    /* Add linefeed on/off */
  82. static int vt_fg;        /* Standard foreground color. */
  83. static int vt_bg;        /* Standard background color. */
  84. static int vt_keypad;        /* Keypad mode. */
  85. static int vt_cursor;        /* cursor key mode. */
  86. static int vt_bs = 8;        /* Code that backspace key sends. */
  87. WIN *vt_win          = NIL_WIN;    /* Output window. */
  88. static int vt_docap;        /* Capture on/off. */
  89. static FILE *vt_capfp;        /* Capture file. */
  90. static void (*vt_keyb)();    /* Gets called for NORMAL/APPL switch. */
  91. static void (*termout)();    /* Gets called to output a string. */
  92.  
  93. static int escparms[8];        /* Cumulated escape sequence. */
  94. static int ptr = -2;        /* Index into escparms array. */
  95.  
  96. short newy1 = 0;        /* Current size of scrolling region. */
  97. short newy2 = 23;
  98.  
  99. /* Saved color and posistions */
  100. static short savex = 0, savey = 0, saveattr = A_NORMAL, savecol = 112;
  101.  
  102. /*
  103.  * Initialize the emulator once.
  104.  */
  105. void vt_install(fun1, fun2, win)
  106. void (*fun1)();
  107. void (*fun2)();
  108. WIN *win;
  109. {
  110.   termout = fun1;
  111.   vt_keyb = fun2;
  112.   vt_win = win;
  113. }
  114.  
  115. /* Set characteristics of emulator. */
  116. void vt_init(type, fg, bg, wrap, add)
  117. int type;
  118. int fg;
  119. int bg;
  120. int wrap;
  121. int add;
  122. {
  123.   vt_type = type;
  124.   vt_fg = fg;
  125.   vt_bg = bg;
  126.   if (wrap >= 0) vt_win->wrap = vt_wrap = wrap;
  127.   vt_addlf = add;
  128.  
  129.   newy1 = 0;
  130.   newy2 = vt_win->ys - 1;
  131.   wresetregion(vt_win);
  132.   vt_keypad = NORMAL;
  133.   vt_cursor = NORMAL;
  134.   vt_echo = 0;
  135.   ptr = -2;
  136.   esc_s = 0;
  137.  
  138.   if (vt_keyb) vt_keyb(vt_keypad, vt_cursor);
  139.   wsetfgcol(vt_win, vt_fg);
  140.   wsetbgcol(vt_win, vt_bg);
  141. }
  142.  
  143. /* Change some things on the fly. */
  144. void vt_set(addlf, wrap, capfp, docap, bscode, echo, cursor)
  145. int addlf;
  146. int wrap;
  147. FILE *capfp;
  148. int docap;
  149. int bscode;
  150. int echo;
  151. int cursor;
  152. {
  153.   if (addlf >= 0) vt_addlf = addlf;
  154.   if (wrap >= 0)  vt_win->wrap = vt_wrap = wrap;
  155.   if (capfp != (FILE *)0) vt_capfp = capfp;
  156.   if (docap >= 0) vt_docap = docap;
  157.   if (bscode >= 0) vt_bs = bscode;
  158.   if (echo >= 0) vt_echo = echo;
  159.   if (cursor >= 0) vt_cursor = cursor;
  160. }
  161.  
  162. /* Output a string to the modem. */
  163. #ifdef _SELECT
  164. static void v_termout(s)
  165. char *s;
  166. {
  167.   char *p;
  168.  
  169.   if (vt_echo) {
  170.     for(p = s; *p; p++) vt_out(*p);
  171.     wflush();
  172.   }
  173.   termout(s);
  174. }
  175. #endif
  176.  
  177. /*
  178.  * Escape code handling.
  179.  */
  180.  
  181. /*
  182.  * ESC was seen the last time. Process the next character.
  183.  */
  184. static void state1(c)
  185. int c;
  186. {
  187.   short x, y, f;
  188.  
  189.   switch(c) {
  190.     case '[': /* ESC [ */
  191.         esc_s = 2;
  192.         return;
  193.     case '(': /* ESC ( */
  194.         esc_s = 4;
  195.         return;
  196.     case ')': /* ESC ) */
  197.         esc_s = 5;
  198.         return;
  199.     case '#': /* ESC # */
  200.         esc_s = 6;
  201.         return;
  202.     case 'P': /* ESC P (DCS, Device Control String) */
  203.         esc_s = 7;
  204.         return;
  205.     case 'D': /* Cursor down */
  206.     case 'M': /* Cursor up */
  207.         x = vt_win->curx;
  208.         if (c == 'D')  { /* Down. */
  209.             y = vt_win->cury + 1;
  210.             if (y == newy2 + 1)
  211.                 wscroll(vt_win, S_UP);
  212.             else if (vt_win->cury < vt_win->ys)
  213.                 wlocate(vt_win, x, y);
  214.         }        
  215.         if (c == 'M')  { /* Up. */
  216.             y = vt_win->cury - 1;
  217.             if (y == newy1 - 1)
  218.                 wscroll(vt_win, S_DOWN);
  219.             else if (y >= 0)
  220.                 wlocate(vt_win, x, y);
  221.         }
  222.         break;
  223.     case 'E': /* CR + NL */
  224.          wputs(vt_win, "\r\n");
  225.          break;
  226.      case '7': /* Save attributes and cursor position */
  227.      case 's':
  228.          savex = vt_win->curx;
  229.          savey = vt_win->cury;
  230.          saveattr = vt_win->attr;
  231.          savecol = vt_win->color;
  232.          break;
  233.      case '8': /* Restore them */
  234.      case 'u':    
  235.          vt_win->color = savecol; /* HACK should use wsetfgcol etc */
  236.          wsetattr(vt_win, saveattr);
  237.          wlocate(vt_win, savex, savey);
  238.          break;
  239.      case '=': /* Keypad into applications mode */
  240.         vt_keypad = APPL;
  241.         if (vt_keyb) vt_keyb(vt_keypad, vt_cursor);
  242.          break;
  243.      case '>': /* Keypad into numeric mode */
  244.          vt_keypad = NORMAL;
  245.         if (vt_keyb) vt_keyb(vt_keypad, vt_cursor);
  246.          break;
  247.      case 'Z': /* Report terminal type */
  248.         if (vt_type == VT100)
  249.             v_termout("\033[?1;0c");
  250.          else    
  251.              v_termout("\033[?c");
  252.          break;    
  253.      case 'c': /* Reset to initial state */
  254.          f = A_NORMAL;
  255.          wsetattr(vt_win, f);
  256.          wlocate(vt_win, 0, 0);
  257.         vt_win->wrap = (vt_type != VT100);
  258.         if (vt_wrap != -1) vt_win->wrap = vt_wrap;
  259.         vt_init(vt_type, vt_fg, vt_bg, vt_win->wrap, 0);
  260.          break;
  261.      case 'N': /* G2 character set for next character only*/
  262.      case 'O': /* G3 "                "    */
  263.      case 'H': /* Set tab in current position */
  264.      case '<': /* Exit vt52 mode */
  265.      default:
  266.          /* ALL IGNORED */
  267.          break;
  268.   }
  269.   esc_s = 0;
  270.   return;
  271. }
  272.  
  273. /*
  274.  * ESC [ ... was seen the last time. Process next character.
  275.  */
  276. static void state2(c)
  277. int c;
  278. {
  279.   short x, y, attr, f;
  280.   char temp[16];
  281.   char did_esc = 1;
  282.  
  283.   /* See if a number follows */
  284.   if (c >= '0' && c <= '9') {
  285.     if (ptr < 0) ptr = 0;
  286.     escparms[ptr] = 10*(escparms[ptr]) + c - '0';
  287.     return;
  288.   }
  289.   /* Separation between numbers ? */
  290.   if (c == ';') {
  291.     if (ptr < 15 && ptr >= 0) ptr++;
  292.     return;
  293.   }
  294.   /* ESC [ something-without-argument? */
  295.   if (ptr < 0) switch(c) {
  296.     case '?': /* ESC [ ? */
  297.         esc_s = 3;
  298.         return;
  299.     case 'K': /* Clear to end of line */
  300.         wclreol(vt_win);
  301.         break;
  302.     case 'J': /* Clear to end of screen */
  303.         wclreos(vt_win);
  304.         break;
  305.     case 'c': /* Identify Terminal Type */
  306.         if (vt_type == VT100)
  307.             v_termout("\033[?1;0c");
  308.         else    
  309.             v_termout("\033[?c");
  310.         break;    
  311.     case 'i': /* print page */
  312.     case 'g': /* clear tab stop */
  313.         /* IGNORED */
  314.         break;
  315.      case 's': /* Save attributes and cursor position */
  316.          savex = vt_win->curx;
  317.          savey = vt_win->cury;
  318.          saveattr = vt_win->attr;
  319.          savecol = vt_win->color;
  320.          break;
  321.      case 'u': /* Restore them */
  322.          vt_win->color = savecol; /* HACK should use wsetfgcol etc */
  323.          wsetattr(vt_win, saveattr);
  324.          wlocate(vt_win, savex, savey);
  325.          break;
  326.     default: /* We did not find it. Maybe it's a variable-argument func. */
  327.         did_esc = 0;
  328.         break;
  329.   }
  330.   if (ptr < 0 && did_esc) {
  331.     esc_s = 0;
  332.     return;
  333.   }
  334.   /* ESC [ one-argument-only something ? */
  335.   if (ptr == 0) switch(c) {
  336.     case 'K': /* Line erasing */
  337.         switch(escparms[0]) {
  338.             case 0:
  339.                 wclreol(vt_win);
  340.                 break;
  341.             case 1:
  342.                 wclrbol(vt_win);
  343.                 break;
  344.             case 2:
  345.                 wclrel(vt_win);
  346.                 break;
  347.         }
  348.         break;
  349.     case 'J': /* Screen erasing */
  350.         x = vt_win->color;
  351.         y = vt_win->attr;
  352.         if (vt_type == ANSI) {
  353.             wsetattr(vt_win, A_NORMAL);
  354.             wsetfgcol(vt_win, WHITE);
  355.             wsetbgcol(vt_win, BLACK);
  356.         }
  357.         switch(escparms[0]) {
  358.             case 0:
  359.                 wclreos(vt_win);
  360.                 break;
  361.             case 1:
  362.                 wclrbos(vt_win);
  363.                 break;
  364.             case 2:
  365.                 winclr(vt_win);
  366.                 break;
  367.         }
  368.         if (vt_type == ANSI) {
  369.             vt_win->color = x;
  370.             vt_win->attr = y;
  371.         }
  372.         break;
  373.     case 'n': /* Requests / Reports */
  374.         switch(escparms[0]) {
  375.             case 5: /* Status */
  376.                 v_termout("\033[0n");
  377.                 break;
  378.             case 6:    /* Cursor Position */
  379.                 sprintf(temp, "\033[%d;%dR", 
  380.                     vt_win->cury + 1, vt_win->curx + 1);
  381.                 v_termout(temp);
  382.                 break;
  383.         }
  384.         break;
  385.     case 'c': /* Identify Terminal Type */
  386.         if (vt_type == VT100) {
  387.             v_termout("\033[?1;0c");
  388.             break;
  389.         }
  390.         v_termout("\033[?c");
  391.         break;
  392.     case 'g': /* Tabulation */
  393.     case 'i': /* Printing */
  394.     default:
  395.         /* IGNORED */
  396.         break;
  397.   }
  398.  
  399.   /* Process functions with zero, one, two or more arguments */
  400.   switch(c) {
  401.     case 'A':
  402.     case 'B':
  403.     case 'C':
  404.     case 'D': /* Cursor motion */
  405.         if ((f = escparms[0]) == 0) f = 1;
  406.         x = vt_win->curx;
  407.         y = vt_win->cury;
  408.         x += f * ((c == 'C') - (c == 'D'));
  409.         if (x < 0) x = 0;
  410.         if (x >= vt_win->xs) x = vt_win->xs - 1;
  411.         if (c == 'B') { /* Down. */
  412.             y += f;
  413.             if (y >= vt_win->ys) y = vt_win->ys - 1;
  414.             if (y == newy2 + 1) y = newy2;
  415.         }
  416.         if (c == 'A') { /* Up. */
  417.             y -= f;
  418.              if (y < 0) y = 0;
  419.             if (y == newy1 - 1) y = newy1;
  420.         }    
  421.         wlocate(vt_win, x, y);
  422.         break;
  423.     case 'H':
  424.     case 'f': /* Set cursor position */
  425.         if ((y = escparms[0]) == 0) y = 1;
  426.         if ((x = escparms[1]) == 0) x = 1;
  427.         wlocate(vt_win, x - 1, y - 1);
  428.         break;
  429.     case 'm': /* Set attributes */
  430.           /* Without argument, esc-parms[0] is 0 */
  431.         if (ptr < 0) ptr = 0;  
  432.         attr = wgetattr((vt_win));
  433.         for (f = 0; f <= ptr; f++) {
  434.             if (escparms[f] >= 30 && escparms[f] <= 37)
  435.             wsetfgcol(vt_win, escparms[f] - 30);
  436.             if (escparms[f] >= 40 && escparms[f] <= 47)
  437.             wsetbgcol(vt_win, escparms[f] - 40);
  438.             switch(escparms[f]) {
  439.             case 0:
  440.                 attr = A_NORMAL;
  441.                 wsetfgcol(vt_win, vt_fg);
  442.                 wsetbgcol(vt_win, vt_bg);
  443.                 break;
  444.             case 4:
  445.                 attr |= A_UNDERLINE;
  446.                 break;
  447.             case 7:
  448.                 attr |= A_REVERSE;
  449.                 break;
  450.             case 1:
  451.                 attr |= A_BOLD;
  452.                 break;
  453.             case 5:
  454.                 attr |= A_BLINK;
  455.                 break;
  456.             case 22: /* Bold off */
  457.                 attr &= ~A_BOLD;
  458.                 break;
  459.             case 24: /* Not underlined */
  460.                 attr &=~A_UNDERLINE;
  461.                 break;
  462.             case 25: /* Not blinking */
  463.                 attr &= ~A_BLINK;
  464.                 break;
  465.             case 27: /* Not reverse */
  466.                 attr &= ~A_REVERSE;
  467.                 break;
  468.             case 39: /* Default fg color */
  469.                 wsetfgcol(vt_win, vt_fg);
  470.                 break;
  471.             case 49: /* Default bg color */
  472.                 wsetbgcol(vt_win, vt_bg);
  473.                 break;
  474.                 
  475.             }
  476.         }
  477.         wsetattr(vt_win, attr);
  478.         break;
  479.     case 'L': /* Insert lines */
  480.         if ((x = escparms[0]) == 0) x = 1;
  481.         for(f = 0; f < x; f++)
  482.             winsline(vt_win);
  483.         break;    
  484.     case 'M': /* Delete lines */
  485.         if ((x = escparms[0]) == 0) x = 1;
  486.         for(f = 0; f < x; f++)
  487.             wdelline(vt_win);
  488.         break;    
  489.     case 'P': /* Delete Characters */
  490.         if ((x = escparms[0]) == 0) x = 1;
  491.         for(f = 0; f < x; f++)
  492.             wdelchar(vt_win);
  493.         break;    
  494.     case '@': /* Insert Characters */        
  495.         if ((x = escparms[0]) == 0) x = 1;
  496.         for(f = 0; f < x; f++)
  497.             winschar(vt_win);
  498.         break;    
  499.     case 'r': /* Set scroll region */
  500.         if ((newy1 = escparms[0]) == 0) newy1 = 1;
  501.         if ((newy2 = escparms[1]) == 0) newy2 = vt_win->ys;
  502.         newy1-- ; newy2--;
  503.         if (newy1 < 0) newy1 = 0;
  504.         if (newy2 < 0) newy2 = 0;
  505.         if (newy1 >= vt_win->ys) newy1 = vt_win->ys - 1;
  506.         if (newy2 >= vt_win->ys) newy2 = vt_win->ys - 1;
  507.         wsetregion(vt_win, newy1, newy2);
  508.         break;
  509.     case 'y': /* Self test modes */
  510.     default:
  511.         /* IGNORED */
  512.         break;
  513.   }
  514.   /* Ok, our escape sequence is all done */
  515.   esc_s = 0;
  516.   ptr = -2;
  517.   return;        
  518. }
  519.   
  520. /*
  521.  * ESC [ ? ... seen.
  522.  */
  523. static void state3(c)
  524. int c;
  525. {
  526.   /* See if a number follows */
  527.   if (c >= '0' && c <= '9') {
  528.     if (ptr < 0) ptr = 0;
  529.     escparms[ptr] = 10*(escparms[ptr]) + c - '0';
  530.     return;
  531.   }
  532.   /* ESC [ ? number seen */
  533.   if (ptr < 0) {
  534.     esc_s = 0;
  535.     return;
  536.   }
  537.   switch(c) {
  538.     case 'h':
  539.         switch(escparms[0]) {
  540.             case 7: /* Auto wrap on (automatic margins) */
  541.                 vt_win->wrap = 1;
  542.                 break;
  543.             case 6: /* Set scroll region */
  544.                 if (newy1 < 0) newy1 = 0;
  545.                 if (newy2 < 0) newy2 = 0;
  546.                 if (newy1 >= vt_win->ys) newy1 = vt_win->ys - 1;
  547.                 if (newy2 >= vt_win->ys) newy2 = vt_win->ys - 1;
  548.                 wsetregion(vt_win, newy1, newy2);
  549.                 break;
  550.             case 1: /* Cursor keys in appl. mode */
  551.                 vt_cursor = APPL;
  552.                 if (vt_keyb) vt_keyb(vt_keypad, vt_cursor);
  553.                 break;
  554.             case 25: /* Cursor on */
  555.                 wcursor(vt_win, CNORMAL);
  556.                 break;    
  557.             default: /* Mostly set up functions */
  558.                 /* IGNORED */
  559.                 break;
  560.         }
  561.         break;
  562.     case 'l':
  563.         switch(escparms[0]) {
  564.             case 7: /* Auto wrap off */
  565.                 vt_win->wrap = 0;
  566.                 break;
  567.             case 6: /* Whole screen mode */
  568.                 newy1 = 0;
  569.                 newy2 = vt_win->ys - 1;
  570.                 wresetregion(vt_win);
  571.                 break;
  572.             case 1: /* Cursor keys in cursor pos. mode */
  573.                 vt_cursor = NORMAL;
  574.                 if (vt_keyb) vt_keyb(vt_keypad, vt_cursor);
  575.                 break;
  576.             case 25: /* Cursor off */
  577.                 wcursor(vt_win, CNONE);
  578.                 break;
  579.             default: /* Mostly set up functions */
  580.                 /* IGNORED */
  581.                 break;
  582.         }
  583.         break;
  584.     case 'i': /* Printing */
  585.     case 'n': /* Request printer status */
  586.     default:
  587.         /* IGNORED */
  588.         break;
  589.   }
  590.   esc_s = 0;
  591.   ptr = -2;
  592.   return;
  593. }
  594.  
  595. /*
  596.  * ESC ( Seen.
  597.  */
  598. static void state4(c)
  599. int c;
  600. {
  601.   /* Switch Character Sets. */
  602.   /* IGNORED */
  603.   esc_s = 0;
  604. }
  605.  
  606. /*
  607.  * ESC ) Seen.
  608.  */
  609. static void state5(c)
  610. int c;
  611. {
  612.   /* Switch Character Sets. */
  613.   /* IGNORED */
  614.   esc_s = 0;
  615. }
  616.  
  617. /*
  618.  * ESC # Seen.
  619.  */
  620. static void state6(c)
  621. int c;
  622. {
  623.   /* Double Height and Double width character sets */
  624.   /* IGNORED */
  625.   esc_s = 0;
  626. }
  627.  
  628. /*
  629.  * ESC P Seen.
  630.  */
  631. static void state7(c)
  632. int c;
  633. {
  634.   /*
  635.    * Device dependant control strings. The Minix virtual console package
  636.    * uses these sequences. We can only turn cursor on or off, because
  637.    * that's the only one supported in termcap. The rest is ignored.
  638.    */
  639.   static char buf[17];
  640.   static int pos = 0;
  641.   static int state = 0;
  642.  
  643.   if (c == ESC) {
  644.       state = 1;
  645.       return;
  646.   }
  647.   if (state == 1) {
  648.       buf[pos] = 0;
  649.       pos = 0;
  650.       state = 0;
  651.       esc_s = 0;
  652.       if (c != '\\') return;
  653.       /* Process string here! */
  654.       if (!strcmp(buf, "cursor.on")) wcursor(vt_win, CNORMAL);
  655.       if (!strcmp(buf, "cursor.off")) wcursor(vt_win, CNONE);
  656.       if (!strcmp(buf, "linewrap.on")) {
  657.           vt_wrap = -1;
  658.           vt_win->wrap = 1;
  659.       }
  660.       if (!strcmp(buf, "linewrap.off")) {
  661.           vt_wrap = -1;
  662.           vt_win->wrap = 0;
  663.       }
  664.       return;
  665.   }
  666.   if (pos > 15) return;
  667.   buf[pos++] = c;
  668. }
  669.  
  670. void vt_out(ch)
  671. int ch;
  672. {
  673.   int f;
  674.   short x;
  675.   unsigned char c;
  676.  
  677.   if (!ch) return;
  678.  
  679.   if (ptr == -2) { /* Initialize */
  680.     ptr = -1;
  681.     for(f = 0; f < 8; f++) escparms[f] = 0;
  682.   }
  683.  
  684.   c = (unsigned char)ch;
  685.   
  686.   if (vt_docap == 2) /* Literal. */
  687.     fputc(c, vt_capfp);
  688.  
  689.   switch(esc_s) {
  690.     case 0: /* Normal character */
  691.         switch(c) {
  692.             case '\r': /* Carriage return */
  693.                 wputc(vt_win, c);
  694.                 if (vt_addlf) {
  695.                     wputc(vt_win, '\n');
  696.                     if (vt_docap == 1)
  697.                         fputc('\n', vt_capfp);
  698.                 }
  699.                 break;
  700.             case '\t': /* Non - destructive TAB */
  701.                 x = ((vt_win->curx / 8) + 1) * 8;
  702.                 wlocate(vt_win, x, vt_win->cury);
  703.                 if (vt_docap == 1) fputc(c, vt_capfp);
  704.                 break;
  705.             case 013: /* Old Minix: CTRL-K = up */
  706.                 wlocate(vt_win, vt_win->curx, vt_win->cury - 1);
  707.                 break;
  708.             case '\f': /* Form feed: clear screen. */
  709.                 winclr(vt_win);
  710.                 wlocate(vt_win, 0, 0);
  711.                 break;
  712.             case 14:
  713.             case 15:  /* Change character set. Not supported. */
  714.                 break;
  715.             case ESC: /* Begin escape sequence */
  716.                 esc_s = 1;
  717.                 break;
  718.             case '\n': /* Printable by wputc too */
  719.             case '\b':
  720.             case 7: /* Bell */
  721.             default: /* Printable character */
  722.                 wputc(vt_win, c);
  723.                 if (vt_docap == 1)
  724.                     fputc(c, vt_capfp);
  725.                 break;
  726.         }
  727.         break;
  728.     case 1: /* ESC seen */
  729.         state1(c);
  730.         break;
  731.     case 2: /* ESC [ ... seen */
  732.         state2(c);
  733.         break;
  734.     case 3:
  735.         state3(c);
  736.         break;
  737.     case 4:
  738.         state4(c);
  739.         break;
  740.     case 5:
  741.         state5(c);
  742.         break;
  743.     case 6:
  744.         state6(c);
  745.         break;
  746.     case 7:
  747.         state7(c);
  748.         break;    
  749.   }
  750. }
  751.  
  752. /* Translate keycode to escape sequence. */
  753. void vt_send(c)
  754. int c;
  755. {
  756.   char s[2];
  757.   int f;
  758.  
  759.   /* Special key? */
  760.   if (c < 256) {
  761.     /* Translate backapce key? */
  762.     if (c == K_ERA) c = vt_bs;
  763.     s[0] = c;
  764.     s[1] = 0;
  765.     v_termout(s);
  766.     return;
  767.   }
  768.  
  769.   /* Look up code in translation table. */
  770.   for(f = 0; vt_keys[f].code; f++)
  771.     if (vt_keys[f].code == c) break;
  772.   if (vt_keys[f].code == 0) return;
  773.  
  774.   /* Now send appropriate escape code. */
  775.   v_termout("\033");
  776.   if (vt_type == VT100) {
  777.     if (vt_cursor == NORMAL)
  778.         v_termout(vt_keys[f].vt100_st);
  779.     else
  780.         v_termout(vt_keys[f].vt100_app);
  781.   } else
  782.     v_termout(vt_keys[f].ansi);
  783. }
  784.