home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / CK5A188S.ZIP / ckocon.c < prev    next >
C/C++ Source or Header  |  1992-11-23  |  77KB  |  2,952 lines

  1. char *connv = "OS/2 CONNECT command, 25 Oct 92";
  2.  
  3. /* C K O C O N  --  Kermit connect command for OS/2 systems */
  4.  
  5. /*
  6.  * Author: Chris Adie (C.Adie@uk.ac.edinburgh) Copyright (C) 1988 Edinburgh
  7.  * University Computing Service Permission is granted to any individual or
  8.  * institution to use, copy, or redistribute this software so long as it is
  9.  * not sold for profit, provided this copyright notice is retained.
  10.  *
  11.  * Incorporates a VT102 emulator, together with its screen access routines.
  12.  * If the code looks a bit funny sometimes, it's because it was machine
  13.  * translated to 'C'.
  14.  *
  15.  * Many changes for 5A by Kai Uwe Rommel (rommel@informatik.tu-muenchen.de)
  16.  *
  17.  * And more by Frank da Cruz (fdc@columbia.edu), mostly bug fixes (tabs,
  18.  * cursor/attributes save/restore, keypad modes, etc), hooking into new
  19.  * SET TERMINAL commands, and cosmetic.
  20.  */
  21.  
  22. /*
  23.  *
  24.  * =============================#includes=====================================
  25.  */
  26.  
  27. #include "ckcdeb.h"        /* Typedefs, debug formats, etc */
  28. #include "ckcker.h"        /* Kermit definitions */
  29. #include "ckcasc.h"             /* ASCII character symbols */
  30. #include "ckcxla.h"        /* Character set translation */
  31. #include "ckcnet.h"             /* Network support */
  32. #include "ckuusr.h"        /* For terminal type definitions, etc. */
  33.  
  34. #include <ctype.h>        /* Character types */
  35. #include <io.h>            /* File io function declarations */
  36. #include <process.h>        /* Process-control function declarations */
  37. #include <stdlib.h>        /* Standard library declarations */
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <assert.h>
  43.  
  44. #ifndef __32BIT__
  45. #define far _far
  46. #define near _near
  47. #define pascal _pascal
  48. #endif
  49. #define    INCL_NOPM
  50. #define    INCL_VIO
  51. #define    INCL_DOSPROCESS
  52. #define    INCL_DOSSEMAPHORES
  53. #include <os2.h>
  54. #undef COMMENT
  55.  
  56. #ifndef min
  57. #define min(a,b) ((a) <= (b) ? (a) : (b))
  58. #endif
  59.  
  60. /*
  61.  *
  62.  * =============================#defines======================================
  63.  */
  64.  
  65. #ifdef TRUE
  66. #undef TRUE
  67. #endif /* TRUE */
  68. #define TRUE 1
  69.  
  70. #ifdef FALSE
  71. #undef FALSE
  72. #endif /* FALSE */
  73. #define FALSE 0
  74.  
  75. #define    UPWARD        6
  76. #define    DOWNWARD    7
  77. #define    LBUFSIZE    240    /* No of lines in extended buffer (was 144) */
  78.  
  79. #define DEFTABS        \
  80. "0T0000000T0000000T0000000T0000000T0000000T0000000T0000000T0000000T0000000\
  81. T0000000T0000000T0000000T0000000T0000000T0000000T0000000T000";
  82.  
  83. /*
  84.  *
  85.  * =============================typedefs======================================
  86.  */
  87.  
  88. typedef char    fulstring[256];
  89. typedef int     bool;
  90.  
  91. typedef struct ascreen_rec {    /* Structure for saving screen info */
  92.     unsigned char   ox;
  93.     unsigned char   oy;
  94.     unsigned char   att;
  95.     char            *scrncpy;
  96. } ascreen;
  97.  
  98. /*
  99.  *
  100.  * =============================externals=====================================
  101.  */
  102.  
  103. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR);  /* Character set xlate */
  104. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR);  /* functions. */
  105. extern int language;        /* Current language. */
  106. extern struct langinfo langs[];    /* Language info. */
  107. extern struct csinfo fcsinfo[]; /* File character set info */
  108. extern int tcsr, tcsl;        /* Terminal character sets, remote & local. */
  109.  
  110. extern int tnlm;        /* Terminal newline mode */
  111. extern int tt_crd;        /* Carriage-return display mode */
  112. extern long    speed;
  113. extern int      local, escape, duplex, parity, flow, seslog, sessft,
  114.                 cmdmsk, cmask, sosi, xitsta, debses, mdmtyp, carrier;
  115.  
  116. extern int      network, nettype, ttnproto;
  117.  
  118. extern KEY     *keymap;
  119. extern MACRO     *macrotab;
  120. extern char     ttname[], sesfil[];
  121. extern void    cc_trap();
  122.  
  123. /*
  124.  *
  125.  * =============================variables==============================
  126.  */
  127.  
  128. #ifdef MONO
  129. int     colornormal     = 0x07;
  130. int     colorunderline  = 0x01;
  131. int     colorreverse    = 0x70;
  132. int     colorstatus     = 0x70;
  133. int     colorhelp       = 0x70;
  134. #else
  135. int     colornormal     = 0x30;
  136. int     colorunderline  = 0x3E;
  137. int     colorreverse    = 0x70;
  138. int     colorstatus     = 0x74;
  139. int     colorhelp       = 0x27;
  140. #endif
  141. int    colorcmd;
  142. int     scrninitialised;
  143.  
  144. static long    twochartimes;
  145. static char    termessage[132];
  146. static FILE    *lst = NULL;
  147. static bool     lstclosed = TRUE;
  148. static int      xsize = -1, ysize = -1;
  149. static ascreen  vt100screen, commandscreen, savedscreen;
  150. static unsigned char
  151.   attribute = NUL,
  152.   savedattribute = NUL,
  153.   defaultattribute = NUL;
  154.  
  155. static struct {
  156.     unsigned        reversed:1;
  157.     unsigned        blinking:1;
  158.     unsigned        underlined:1;
  159.     unsigned        bold:1;
  160.     unsigned        invisible:1;
  161. }               attrib, savedattrib;
  162.  
  163. static struct paging_record {
  164.     unsigned char   numlines;    /* no. of lines in extended display buffer */
  165.     unsigned char   topline;
  166.     unsigned char   botline;
  167.     char           *buffer;
  168. }               paginginfo;
  169.  
  170. static int wherex;            /* X-coordinate, 1-based */
  171. static int wherey;            /* Y-coordinate, 1-based */
  172. static int margintop = 1;        /* Top of scrolling region */
  173. static int marginbot = 24;        /* Bottom of scrolling region */
  174.  
  175. static int      active, quitnow, hangnow, inshift, outshift, tcs, langsv;
  176.  
  177. static char    answerback[81] = "OS/2 C-Kermit\n";
  178. static char     usertext[(132) + 1];
  179. static char     exittext[(14) + 1];
  180. static char     helptext[(14) + 1];
  181. static char     filetext[(14) + 1];
  182. static char     hostname[(20) + 1];
  183.  
  184. static unsigned char graphicset[32] = {
  185.     0x20, 0x04, 0xB0, 0x1A, 0x17, 0x1B, 0x19, 0xF8,
  186.     0xF1, 0x15, 0x12, 0xD9, 0xBF, 0xDA, 0xC0, 0xC5,
  187.     0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC3, 0xB4, 0xC1,
  188.     0xC2, 0xB3, 0xF3, 0xF2, 0xE3, 0x9D, 0x9C, 0xFA
  189. };
  190.  
  191. static char     htab[133] = DEFTABS    /* Default tab settings */
  192.  
  193. static VIOCURSORINFO crsr_command;
  194. static VIOCURSORINFO crsr_info;
  195.  
  196. static int      row = 0;
  197. static int      column = 0;
  198. static int      achar;
  199.  
  200. static unsigned char g0 = 'B';
  201. static unsigned char g1 = 'B';
  202. static unsigned char *g0g1 = &g0;
  203.  
  204. static bool     printon        = FALSE;    /* Printer is on */
  205. static bool     turnonprinter  = FALSE;    /* Time to turn on printer */
  206. static bool     turnoffprinter = FALSE;    /* Time to turn it off */
  207.  
  208. static bool     wrapit;
  209. static bool     literal   = FALSE;
  210. static bool     screenon  = TRUE;
  211. static bool     cursoron  = TRUE;    /* For speed, turn off when busy */
  212. static bool     relcursor = FALSE;
  213. static bool     keylock   = FALSE;
  214. static bool     vt52graphics = FALSE;
  215.  
  216. static unsigned char saveg0, saveg1, *saveg0g1;
  217. static bool     saverelcursor, saved=FALSE;
  218.  
  219. static bool     dwl[60];
  220. static bool     dwls = FALSE;    /* For optimisation */
  221. static bool     deccolm = FALSE;
  222. static bool     decscnm = FALSE;
  223. static bool     linemode = FALSE;
  224. static bool     insertmode = FALSE;
  225. /*
  226.   Terminal parameters that can also be set externally by SET commands.
  227.   Formerly they were declared and initialized here, and had different
  228.   names, as shown in the comments.  Now they are declared and
  229.   initialized in ckuus7.c.  - fdc
  230. */
  231. extern int tt_arrow;            /* cursorkey  = TRUE; */
  232. extern int tt_keypad;            /* keypadnum  = FALSE; */
  233. extern int tt_wrap;            /* autowrap   = TRUE; */
  234. extern int tt_type;            /* ansi       = TRUE; */
  235. extern int tt_cursor;            /* cursormode = 0; */
  236.  
  237. /* Escape-sequence processing buffer */
  238.  
  239. static bool     escaping = FALSE;
  240. static int      escnext = 1;
  241. static int      esclast = 0;
  242. static unsigned char escbuffer[129];
  243.  
  244. static unsigned char sgrcols[8] = {0, 4, 2, 6, 1, 5, 3, 7};
  245.  
  246. /* Function prototypes */
  247.  
  248. static CHAR (*sxo)(CHAR); /* Local translation functions */
  249. static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */
  250. static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */
  251. static CHAR (*rxi)(CHAR);
  252.  
  253. int ttoci(char c);
  254. int line25(void);
  255. int lgotoxy(int x, int y);
  256. int scroll(int updown, int top, int bottom);
  257. int clearscreen(int all, int attr);
  258. int setmargins(int top, int bot);
  259. int sendstr(char *s);
  260. int wrtch(char ch);
  261. int bleep(void);
  262. int movetoscreen(char *source, int x, int y, int len);
  263. int savescreen(ascreen *scrn);
  264. int restorescreen(ascreen *scrn);
  265. int clrtoeoln(void);
  266. int killcursor(void);
  267. int newcursor(void);
  268. int cwrite(unsigned char ch);
  269. int toplinetocyclicbuffer(void);
  270. int setcursormode(void);
  271. int restorecursormode(void);
  272.  
  273. extern int concooked(void);
  274. extern int conraw(void);
  275. extern int xxesc(char **);
  276.  
  277. /* thread stuff */
  278. #ifdef __32BIT__
  279. HEV threadsem;
  280. ULONG semcount;
  281. #define THRDSTKSIZ    8192
  282. #else
  283. static long int threadsem;    /* Semaphore to show thread is running */
  284. #define THRDSTKSIZ    2048
  285. static char            stack[THRDSTKSIZ];    /* Stack for second thread */
  286. #endif
  287. static TID             threadid;
  288.  
  289. /* skip escape sequences */
  290.  
  291. /* for comments, see ckucon.c, where this code is copied from */
  292.  
  293. #define ES_NORMAL 0            /* Normal, not in escape sequence */
  294. #define ES_GOTESC 1            /* Current character is ESC */
  295. #define ES_ESCSEQ 2            /* Inside an escape sequence */
  296. #define ES_GOTCSI 3            /* Inside a control sequence */
  297. #define ES_STRING 4            /* Inside DCS,OSC,PM, or APC string */
  298. #define ES_TERMIN 5            /* 1st char of string terminator */
  299.  
  300. static int
  301.   iskipesc = 0,                /* Skip over ANSI escape sequences */
  302.   oskipesc = 0,
  303.   inesc = ES_NORMAL,            /* State of sequence recognizer */
  304.   outesc = ES_NORMAL;
  305.  
  306. int
  307. chkaes(int esc, char c) {
  308.     if (c == CAN || c == SUB)        /* CAN and SUB cancel any sequence */
  309.       esc = ES_NORMAL;
  310.     else                /* Otherwise */
  311.       switch (esc) {            /* enter state switcher */
  312.  
  313.     case ES_NORMAL:            /* NORMAL state */
  314.       if (c == ESC)            /* Got an ESC */
  315.         esc = ES_GOTESC;        /* Change state to GOTESC */
  316.       break;            /* Otherwise stay in NORMAL state */
  317.  
  318.     case ES_GOTESC:            /* GOTESC state */
  319.       if (c == '[')            /* Left bracket after ESC is CSI */
  320.         esc = ES_GOTCSI;        /* Change to GOTCSI state */
  321.       else if (c > 057 && c < 0177)    /* Final character '0' thru '~' */
  322.         esc = ES_NORMAL;        /* Back to normal */
  323.       else if (c == 'P' || (c > 0134 && c < 0140)) /* P, [, ^, or _ */
  324.         esc = ES_STRING;        /* Switch to STRING-absorption state */
  325.       else if (c != ESC)        /* ESC in an escape sequence... */
  326.         esc = ES_ESCSEQ;        /* starts a new escape sequence */
  327.       break;            /* Intermediate or ignored ctrl char */
  328.  
  329.     case ES_ESCSEQ:            /* ESCSEQ -- in an escape sequence */
  330.       if (c > 057 && c < 0177)    /* Final character '0' thru '~' */
  331.         esc = ES_NORMAL;        /* Return to NORMAL state. */
  332.       else if (c == ESC)        /* ESC ... */
  333.         esc = ES_GOTESC;        /* starts a new escape sequence */
  334.       break;            /* Intermediate or ignored ctrl char */
  335.  
  336.     case ES_GOTCSI:            /* GOTCSI -- In a control sequence */
  337.       if (c > 077 && c < 0177)    /* Final character '@' thru '~' */
  338.         esc = ES_NORMAL;        /* Return to NORMAL. */
  339.       else if (c == ESC)        /* ESC ... */
  340.         esc = ES_GOTESC;        /* starts over. */
  341.       break;            /* Intermediate or ignored ctrl char */
  342.  
  343.     case ES_STRING:            /* Inside a string */
  344.       if (c == ESC)            /* ESC may be 1st char of terminator */
  345.         esc = ES_TERMIN;        /* Go see. */
  346.       break;            /* Absorb all other characters. */
  347.  
  348.     case ES_TERMIN:            /* May have a string terminator */
  349.       if (c == '\\')        /* which must be backslash */
  350.         esc = ES_NORMAL;        /* If so, back to NORMAL */
  351.       else                /* Otherwise */
  352.         esc = ES_STRING;        /* Back to string absorption. */
  353.       }
  354.     return(esc);
  355. }
  356.  
  357. /* end code to skip escape sequences */
  358.  
  359. /*
  360.  * Send a character to the serial line in immediate mode, checking to avoid
  361.  * overwriting a character already waiting to be sent.
  362.  */
  363. sendchar(unsigned char c) {
  364.     int i=0;
  365.     while (ttoci(dopar(c))<0 && i++<10)
  366.       DosSleep(twochartimes);
  367.     if (i>=10) {
  368.     active = FALSE;
  369.     strcpy(termessage,network ? "Cannot transmit to network link.\n"
  370.            : "Cannot transmit to serial port.\n");
  371.     }
  372. }
  373.  
  374. /* ------------------------------------------------------------------ */
  375. /* ipadl25 -                                                          */
  376. /* ------------------------------------------------------------------ */
  377. ipadl25() {
  378.     int i, j, n;
  379.     char *s;
  380.     if (tt_type == TT_VT102)
  381.       strcpy(usertext, " C-Kermit VT-102");
  382.     else if (tt_type == TT_VT52)
  383.       strcpy(usertext, " C-Kermit VT-52");
  384.     else strcpy(usertext, " C-Kermit");
  385.     if ( !network )
  386.       sprintf(filetext, "Serial %ld", speed);
  387.     else
  388.       switch ( nettype ) {
  389.       case NET_DEC:
  390.         switch ( ttnproto ) {
  391.         case NP_LAT:
  392.           strcpy(filetext, "DECnet LAT");
  393.           break;
  394.         case NP_CTERM:
  395.           strcpy(filetext, "DECnet CTERM");
  396.           break;
  397.         default:
  398.           strcpy(filetext, "DECnet");
  399.           break;
  400.         }
  401.         break;
  402.       case NET_TCPB:
  403.         strcpy(filetext, "TCP/IP");
  404.         break;
  405.       case NET_PIPE:
  406.         strcpy(filetext, "Named Pipe");
  407.         break;
  408.       }
  409.     strcpy(helptext, "Help: Alt-?");
  410.     strcpy(exittext, "Return: Alt-X");
  411.     n = strlen(ttname);
  412.     i = j = (n < 14) ? (14 - n) / 2 : 0;
  413.     n = 14 - i;
  414.     while (i-- > 0) hostname[i] = ' ';
  415.     for (i = 0; i < n && ttname[i]; i++)
  416.       hostname[i+j] = islower(ttname[i]) ? toupper(ttname[i]) : ttname[i];
  417.     hostname[i+j] = '\0';
  418.     line25();
  419. }
  420.  
  421. /* ------------------------------------------------------------------ */
  422. /* CursorUp -                                                         */
  423. /* ------------------------------------------------------------------ */
  424. static void
  425. cursorup() {
  426.     if ((relcursor ? margintop : 1) != wherey)
  427.     lgotoxy(wherex, wherey - 1);
  428. }
  429.  
  430. /* ------------------------------------------------------------------ */
  431. /* CursorDown -                                                       */
  432. /* ------------------------------------------------------------------ */
  433. static void
  434. cursordown() {
  435.     if ((relcursor ? marginbot : ysize) != wherey)
  436.     lgotoxy(wherex, wherey + 1);
  437. }
  438.  
  439. /* ------------------------------------------------------------------ */
  440. /* CursorRight -                                                      */
  441. /* ------------------------------------------------------------------ */
  442. static void
  443. cursorright() {
  444.     if (wherex < (dwl[wherey - 1] ? xsize - 1 : xsize))
  445.     lgotoxy(wherex + 1, wherey);
  446. }
  447.  
  448. /* ------------------------------------------------------------------ */
  449. /* CursorLeft -                                                       */
  450. /* ------------------------------------------------------------------ */
  451. static void
  452. cursorleft() {
  453.     if (wherex > 1)
  454.     lgotoxy(wherex - 1, wherey);
  455. }
  456.  
  457. /* ------------------------------------------------------------------ */
  458. /* ReverseScreen                              */
  459. /* ------------------------------------------------------------------ */
  460. static void
  461. reversescreen() {
  462.     unsigned char   back;
  463.     unsigned char   fore;
  464.     int             i, r, c;
  465.     USHORT          n;
  466.     unsigned char   cell[132 * 2];
  467.  
  468.     n = sizeof(cell);
  469.     for (r = 0; r < ysize; r++) {    /* flip row */
  470.     VioReadCellStr(cell, &n, r, 0, 0);
  471.     for (c = 1; c < n; c += 2) {    /* do each cell in row */
  472.         back = (cell[c] & 0x70) >> 4;
  473.         fore = (cell[c] & 0x07);
  474.         if (cell[c] == colorunderline)
  475.         cell[c] ^= 0x70;
  476.         else
  477.         cell[c] = (cell[c] & 0x88) | fore << 4 | back;
  478.     }
  479.     VioWrtCellStr(cell, n, r, 0, 0);
  480.     }
  481. }
  482.  
  483. /* ----------------------------------------------------------------- */
  484. /* ClrScreen -                                                       */
  485. /* ----------------------------------------------------------------- */
  486. static void
  487. clrscreen() {
  488.     int             i, j;
  489.     int             nlines;
  490.     USHORT          n;
  491.     char            cells[132 * 2];
  492.  
  493.     /* copy lines on screen to extended display buffer */
  494.     n = xsize * 2;
  495.     for (i = ysize - 1; i >= 0; i--) {
  496.     VioReadCellStr((char *) cells, &n, i, 0, 0);
  497.     for (j = 0; j < xsize; j++) {
  498.         if (cells[j * 2] != ' ')
  499.         break;
  500.     }
  501.     if (j < xsize)
  502.         break;
  503.     }
  504.     nlines = i;            /* no. of nonblank lines-1 */
  505.     for (i = 0; i <= nlines; ++i) {
  506.     paginginfo.botline = (paginginfo.botline + 1) % LBUFSIZE;
  507.     if (paginginfo.numlines < LBUFSIZE)
  508.         paginginfo.numlines = paginginfo.numlines + 1;
  509.     else
  510.         paginginfo.topline = (paginginfo.topline + 1) % LBUFSIZE;
  511.     VioReadCellStr((paginginfo.buffer + xsize * 2 * paginginfo.botline),
  512.                &n, i, 0, 0);
  513.     }
  514.     for (i = 0; i < ysize; i++)
  515.     dwl[i] = FALSE;
  516.     dwls = FALSE;
  517.     clearscreen(0, attribute);
  518. }
  519.  
  520. static void
  521. readmchar_escape() {
  522.     /* Stores character in achar directly */
  523.     if (escnext <= esclast) {
  524.     achar = escbuffer[escnext];
  525.     escnext = escnext + 1;
  526.     } else
  527.     achar = 0;
  528. }
  529.  
  530. static int
  531. pnumber(int *achar) {
  532.     int num = 0;
  533.  
  534.     while (isdigit(*achar)) {    /* get number */
  535.     num = (num * 10) + (*achar) - 48;
  536.     readmchar_escape();
  537.     }
  538.     return (num);
  539. }
  540.  
  541. static void
  542. clreoscr_escape() {
  543.     char cell[2];
  544.     int i;
  545.  
  546.     if (wherex == 1 && wherey == 1) {
  547.     clrscreen();
  548.     return;
  549.     }
  550.     cell[0] = ' ';
  551.     cell[1] = attribute;
  552.     i = (xsize * ysize) - (((wherey - 1) * xsize) + (wherex - 1));
  553.     VioWrtNCell(cell, i, wherey - 1, wherex - 1, 0);
  554.     for (i = wherey - 1; i < ysize; i++)
  555.     dwl[i] = FALSE;
  556.     dwls = FALSE;
  557.     for (i = 0; i < ysize; i++)
  558.     if (dwl[i]) {
  559.         dwls = TRUE;
  560.         break;
  561.     }
  562. }
  563.  
  564. static void
  565. clrboscr_escape() {
  566.     char cell[2];
  567.     int i;
  568.  
  569.     cell[0] = ' ';
  570.     cell[1] = attribute;
  571.     i = ((wherey - 1) * xsize) + wherex;
  572.     VioWrtNCell(cell, i, 0, 0, 0);
  573.     for (i = 0; i < wherey; i++)
  574.     dwl[i] = FALSE;
  575.     dwls = FALSE;
  576.     for (i = 0; i < ysize; i++)
  577.     if (dwl[i]) {
  578.         dwls = TRUE;
  579.         break;
  580.     }
  581. }
  582.  
  583. static void
  584. clrbol_escape() {
  585.     char cell[2];
  586.  
  587.     cell[0] = ' ';
  588.     cell[1] = attribute;
  589.     VioWrtNCell(cell, wherex, wherey - 1, 0, 0);
  590. }
  591.  
  592. static void
  593. clrline_escape() {
  594.     char cell[2];
  595.  
  596.     cell[0] = ' ';
  597.     cell[1] = attribute;
  598.     VioWrtNCell(cell, xsize, wherey - 1, 0, 0);
  599. }
  600.  
  601. static void
  602. decdwl_escape(bool dwlflag) {
  603.     unsigned char   linenumber;
  604.     unsigned char   newx;
  605.     char            cells[132 * 2];
  606.     int             i;
  607.     USHORT          n;
  608.     /* Decdwl */
  609.     linenumber = wherey - 1;
  610.     if (dwlflag != dwl[linenumber]) {
  611.     /* change size */
  612.     n = xsize * 2;
  613.     VioReadCellStr((char *) cells, &n, linenumber, 0, 0);
  614.     if (dwlflag) {        /* make this line double size */
  615.         for (i = xsize / 2 - 1; i >= 0; --i) {    /* expand */
  616.         cells[4 * i] = cells[2 *i];
  617.         cells[4 * i + 2] = ' ';
  618.         }
  619.         newx = (wherex - 1) * 2 + 1;
  620.         dwls = TRUE;
  621.     } else {        /* make this line single size */
  622.         for (i = 0; i <= xsize / 2 - 1; ++i)
  623.         cells[2 * i] = cells[4 * i];
  624.         for (i = xsize / 2; i < xsize; ++i)
  625.         cells[2 * i] = ' ';
  626.         newx = (wherex - 1) / 2 + 1;
  627.         dwls = FALSE;
  628.         for (i = 0; i < ysize; i++)
  629.         if (dwl[i]) {
  630.             dwls = TRUE;
  631.             break;
  632.         }
  633.     }
  634.     VioWrtCellStr((char *) cells, n, linenumber, 0, 0);
  635.     dwl[linenumber] = dwlflag;
  636.     if (newx >= xsize)
  637.       newx = xsize - 1;
  638.     lgotoxy(newx, wherey);
  639.     }
  640. }
  641.  
  642. static void                /* Reset the terminal emulator */
  643. doreset() {
  644.     int i;
  645.     defaultattribute = colornormal;
  646.     attribute = defaultattribute;
  647.     attrib.blinking = FALSE;
  648.     attrib.bold = FALSE;
  649.     attrib.invisible = FALSE;
  650.     attrib.underlined = FALSE;
  651.     attrib.reversed = FALSE;
  652.     g0 = g1 = 'A';
  653.     g0g1 = &g0;
  654.     printon = FALSE;
  655.     screenon = TRUE;
  656.     vt52graphics = FALSE;
  657.     saved = FALSE;
  658.     linemode = FALSE;
  659.     insertmode = FALSE;
  660.     tt_arrow = TRUE;
  661.     tt_keypad = FALSE;
  662.     tt_wrap = TRUE;
  663.     tt_type = TT_VT102;
  664.     keylock = FALSE;
  665.     deccolm = decscnm = FALSE;
  666.     for (i = 0; i < ysize; i++)
  667.       dwl[i] = FALSE;
  668.     dwls = FALSE;
  669.     for (i = 1; i < xsize; i++)
  670.       htab[i] = (i % 8) == 1 ? 'T' : '0'; /* was "== 0" */
  671.     relcursor = FALSE;
  672.     setmargins(1, ysize);
  673.     clrscreen();
  674. }
  675.  
  676.  
  677. static void
  678. vtescape() {
  679.     unsigned char   j;
  680.     unsigned char   k;
  681.     unsigned char   l;
  682.     unsigned char   blankcell[2];
  683.     int             i;
  684.     int             pn[11];
  685.     bool            private;
  686.     char            tempstr[20];
  687.     int             fore, back;
  688.     escaping = FALSE;
  689.     escnext = 1;
  690.     readmchar_escape();
  691.     if (screenon || (achar == '[')) {
  692.     /* screen escape sequences  */
  693.     switch (achar) {        /* First Level */
  694.     case '[':
  695.         {                /* Left square bracket */
  696.         readmchar_escape();
  697.         switch (achar) {    /* Second level */
  698.         case 'A':
  699.             cursorup();
  700.             wrapit = FALSE;
  701.             break;
  702.         case 'B':
  703.             cursordown();
  704.             wrapit = FALSE;
  705.             break;
  706.         case 'C':
  707.             cursorright();
  708.             if (dwl[wherey - 1])
  709.               cursorright();
  710.             break;
  711.         case 'D':
  712.             cursorleft();
  713.             if (dwl[wherey - 1])
  714.               cursorleft();
  715.             break;
  716.         case 'J':    /* Erase End of Display */
  717.             clreoscr_escape();
  718.             break;
  719.         case 'K':
  720.             clrtoeoln();
  721.             break;
  722.         case '?':
  723.             private = TRUE;
  724.             readmchar_escape();
  725.             goto LB2001;
  726.         case 'f':
  727.         case 'H':    /* Cursor Home */
  728.             lgotoxy(1, relcursor ? margintop : 1);
  729.             break;
  730.         case 'g':    /* Tab Clear at this position */
  731.             htab[wherex] = '0';
  732.             break;
  733.         case '}':
  734.         case 'm':    /* Normal Video - Exit all attribute modes */
  735.             attribute = defaultattribute;
  736.             attrib.blinking = FALSE;
  737.             attrib.bold = FALSE;
  738.             attrib.invisible = FALSE;
  739.             attrib.underlined = FALSE;
  740.             attrib.reversed = FALSE;
  741.             break;
  742.         case 'r':    /* Reset Margin */
  743.             setmargins(1, ysize);
  744.             lgotoxy(1, 1);
  745.             break;
  746.         case 'c':
  747.         case 'h':
  748.         case 'l':
  749.         case 'n':
  750.         case 'x':
  751.             pn[1] = 0;
  752.             private = FALSE;
  753.             k = 1;
  754.             goto LB2003;
  755.         case ';':
  756.             pn[1] = 0;
  757.             private = FALSE;
  758.             k = 1;
  759.             goto LB2002;
  760.         case 'L':
  761.         case 'M':
  762.         case '@':
  763.         case 'P':
  764.             pn[1] = 1;
  765.             private = FALSE;
  766.             k = 1;
  767.             goto LB2002;
  768.         default:    /* Pn - got a number */
  769.             private = FALSE;
  770.         LB2001:
  771.             {        /* Esc [ Pn...Pn x   functions */
  772.             pn[1] = pnumber(&achar);
  773.             k = 1;
  774.         LB2002:
  775.             while (achar == ';') {    /* get Pn[k] */
  776.                 readmchar_escape();
  777.                 k++;
  778.                 if (achar == '?') {
  779.                 readmchar_escape();
  780.                 }
  781.                 pn[k] = pnumber(&achar);
  782.             }
  783.             pn[k + 1] = 1;
  784.         LB2003:
  785.             switch (achar) { /* Third level */
  786.             case 'A':
  787.                 do {
  788.                 cursorup();
  789.                 wrapit = FALSE;
  790.                 pn[1] = pn[1] - 1;
  791.                 }
  792.                 while (!(pn[1] <= 0));
  793.                 break;
  794.             case 'B':
  795.                 do {
  796.                 cursordown();
  797.                 wrapit = FALSE;
  798.                 pn[1] = pn[1] - 1;
  799.                 }
  800.                 while (!(pn[1] <= 0));
  801.                 break;
  802.             case 'C':
  803.                 do {
  804.                 cursorright();
  805.                 if (dwl[wherey - 1])
  806.                     cursorright();
  807.                 pn[1] = pn[1] - 1;
  808.                 }
  809.                 while (pn[1] > 0);
  810.                 break;
  811.             case 'D':
  812.                 do {
  813.                 cursorleft();
  814.                 if (dwl[wherey - 1])
  815.                     cursorleft();
  816.                 pn[1] = pn[1] - 1;
  817.                 } while (pn[1] > 0);
  818.                 break;
  819.             case 'f':
  820.             case 'H':
  821.                 /* Direct cursor address */
  822.                 if (pn[1] == 0)
  823.                 pn[1] = 1;
  824.                 if (relcursor)
  825.                 pn[1] += margintop - 1;
  826.                 if (pn[1] > ysize)
  827.                     pn[1] = ysize - 1;
  828.                 if (pn[2] == 0)
  829.                 pn[2] = 1;
  830.                 if (dwl[pn[1] - 1]) {
  831.                 pn[2] = 2 * pn[2] - 1;
  832.                 if (pn[2] > xsize)
  833.                     pn[2] = xsize - 1;
  834.                 } else if (pn[2] > xsize)
  835.                 pn[2] = xsize;
  836.                 wrapit = FALSE;
  837.                 lgotoxy(pn[2], pn[1]);
  838.                 break;
  839.             case 'c':    /* Device Attributes */
  840.                 if (pn[1] == 0)
  841.                 sendstr("[?6c");
  842.                 break;
  843.             case 'g':
  844.                 if (pn[1] == 3) {
  845.                 /* clear all tabs */
  846.                 for (j = 1; j <=xsize; ++j)
  847.                     htab[j] = '0';
  848.                 } else if (pn[1] == 0)
  849.                 /* clear tab at current position */
  850.                 htab[wherex] = '0';
  851.                 break;
  852.             case 'h':    /* Set Mode */
  853.                 for (j = 1; j <= k; ++j)
  854.                 if (private)
  855.                     switch (pn[j]) {    /* Field specs */
  856.                     case 1:    /* DECCKM  */
  857.                     tt_arrow = TRUE;
  858.                     break;
  859.                     case 2:    /* DECANM : ANSI/VT52 */
  860.                     tt_type = TT_VT102;
  861.                     vt52graphics = FALSE;
  862.                     break;
  863.                     case 3:    /* DECCOLM : Col = 132 */
  864.                     deccolm = TRUE;
  865.                     clrscreen();
  866.                     break;
  867.                     case 4:    /* DECSCLM */
  868.                     break;
  869.                     case 5:    /* DECSCNM */
  870.                     if (decscnm)
  871.                         break;    /* Already set */
  872.                     decscnm = TRUE;
  873.                     reversescreen();
  874.                     defaultattribute = colornormal;
  875.                     attribute = defaultattribute;
  876.                     if (attrib.underlined)
  877.                         attribute = colorunderline;
  878.                     if (attrib.reversed) {
  879.                         attribute = colorreverse;
  880.                         if (attrib.underlined)
  881.                         attribute = colorunderline &
  882.                           0x0F | colorreverse & 0xF0;
  883.                     }
  884.                     if (attrib.blinking)
  885.                         attribute |= 0x80;
  886.                     if (attrib.bold)
  887.                         attribute ^= 8;
  888.                     if (attrib.invisible) {
  889.                         i = (attribute & 0xF8);
  890.                         attribute = i | ((i >> 4) & 7);
  891.                     }
  892.                     break;
  893.                     case 6:    /* DECOM : Relative origin */
  894.                     relcursor = TRUE;
  895.                     lgotoxy(1, margintop);
  896.                     break;
  897.                     case 7:    /* DECAWM */
  898.                     tt_wrap = TRUE;
  899.                     break;
  900.                     case 8:    /* DECARM */
  901.                     break;
  902.                     case 9:    /* DECINLM */
  903.                     break;
  904.                     default:
  905.                     break;
  906.                 } else
  907.                     switch (pn[j]) {
  908.                     case 2:    /* Keyboard locked */
  909.                     keylock = TRUE;
  910.                     break;
  911.                     case 4:    /* Ansi insert mode */
  912.                     insertmode = TRUE;
  913.                     break;
  914.                     case 20:    /* Ansi linefeed mode */
  915.                     linemode = TRUE;
  916.                     break;
  917.                     default:
  918.                     break;
  919.                     }
  920.                 break;
  921.             case 'l':    /* Reset Mode */
  922.                 for (j = 1; j <= k; ++j)
  923.                 if (private)
  924.                     switch ((pn[j])) {    /* Field specs */
  925.                     case 1:    /* DECCKM  */
  926.                     tt_arrow = FALSE;
  927.                     break;
  928.                     case 2:    /* DECANM : ANSI/VT52 */
  929.                     tt_type = TT_VT52;
  930.                     vt52graphics = FALSE;
  931.                     break;
  932.                     case 3:    /* DECCOLM : 80 col */
  933.                     deccolm = FALSE;
  934.                     clrscreen();
  935.                     break;
  936.                     case 4:    /* DECSCLM */
  937.                     break;
  938.                     case 5:    /* DECSCNM */
  939.                     if (!decscnm)
  940.                         break;
  941.                     decscnm = !decscnm;
  942.                     reversescreen();
  943.                     defaultattribute = colornormal;
  944.                     attribute = defaultattribute;
  945.                     if (attrib.underlined)
  946.                         attribute = colorunderline;
  947.                     if (attrib.reversed) {
  948.                         attribute = colorreverse;
  949.                         if (attrib.underlined)
  950.                         attribute = colorunderline &
  951.                           0x0F | colorreverse & 0xF0;
  952.                     }
  953.                     if (attrib.blinking)
  954.                         attribute |= 0x80;
  955.                     if (attrib.bold)
  956.                         attribute ^= 8;
  957.                     if (attrib.invisible) {
  958.                         i = (attribute & 0xF8);
  959.                         attribute = i | ((i >> 4) & 7);
  960.                     }
  961.                     break;
  962.                     case 6:    /* DECOM : Relative origin */
  963.                     relcursor = FALSE;
  964.                     lgotoxy(1, 1);
  965.                     break;
  966.                     case 7:    /* DECAWM */
  967.                     tt_wrap = FALSE;
  968.                     break;
  969.                     case 8:    /* DECARM */
  970.                     break;
  971.                     case 9:    /* DECINLM */
  972.                     break;
  973.                     default:
  974.                     break;
  975.                 } else
  976.                     switch (pn[j]) {
  977.                     case 2:    /* Keyboard unlocked */
  978.                     keylock = FALSE;
  979.                     break;
  980.                     case 4:    /* Ansi insert mode */
  981.                     insertmode = FALSE;
  982.                     break;
  983.                     case 20:    /* Ansi linefeed mode */
  984.                     linemode = FALSE;
  985.                     break;
  986.                     default:
  987.                     break;
  988.                     }
  989.                 break;
  990.             case 'i':    /* Printer Screen  on / off */
  991. #ifndef M_I286
  992. /*
  993.   Not only does this not work, but it causes crashes ("stack overflow"), in
  994.   the 16-bit version, at least for me -- but maybe that's because I don't have
  995.   a printer.  For now, we'll leave it buggy in the 32-bit version and turn it
  996.   off completely in the 16-bit version.  NEEDS DEBUGGING BY SOMEBODY WHO HAS A
  997.   PRINTER.
  998. */
  999.                 if (pn[1] == 0)
  1000.                   /* Need code here to print whole screen */
  1001.                   break;
  1002.                 else if (pn[1] == 1)
  1003.                   /* Need code here to print current line */
  1004.                   /* But only if private == TRUE */
  1005.                   break;
  1006. /* 
  1007.   For pn = 4 or 5, we should differentiate here between transparent print
  1008.   (private == FALSE) and autoprint (private == TRUE).  As presently coded,
  1009.   we always do transparent print.
  1010. */
  1011.                 else if (pn[1] == 4)
  1012.                   turnoffprinter = TRUE;
  1013.                 else if (pn[1] == 5)
  1014.                   turnonprinter = TRUE;
  1015.  
  1016. /*  6 and 7 are not in the VT102 manual.  Maybe in the Scottish version?  */
  1017.  
  1018.                 else if (pn[1] == 6)
  1019.                   screenon = FALSE;
  1020.                 else if (pn[1] == 7)
  1021.                   screenon = TRUE;
  1022. #endif /* M_I286 */
  1023.                 break;
  1024.             case 'q':        /* Load LEDs */
  1025.                 break;        /* (nothing) */
  1026.             case 'n':
  1027.                 if (pn[1] == 5)     /* Terminal Status Report */
  1028.                   sendstr("[0n");     /* Terminal is OK */
  1029.                 else if (pn[1] == 6) { /* Cursor position report */
  1030. #ifdef M_I286
  1031. /*
  1032.   16-bit version must use a hand-coded in-line version of sprintf to avoid
  1033.   the function call that would crash the program with a stack overflow.
  1034.   Handles numbers 0 - 999.  No range checking.  - fdc
  1035. */
  1036.                 int i = 0, j;
  1037.                 tempstr[i++] = '[';
  1038.                 if ((j = wherey / 100) > 0)
  1039.                   tempstr[i++] = (char) (j + 48);
  1040.                 if ((j = (wherey % 100) / 10) > 0 ||
  1041.                     wherey > 99)
  1042.                   tempstr[i++] = (char) (j + 48);
  1043.                 if ((j = wherey % 10) > 0 ||
  1044.                     wherey > 9)
  1045.                   tempstr[i++] = (char) (j + 48);
  1046.                 tempstr[i++] = ';';
  1047.                 if ((j = wherex / 100) > 0)
  1048.                   tempstr[i++] = (char) (j + 48);
  1049.                 if ((j = (wherex % 100) / 10) > 0 ||
  1050.                     wherex > 99)
  1051.                   tempstr[i++] = (char) (j + 48);
  1052.                 if ((j = wherex % 10) > 0 ||
  1053.                     wherex > 9)
  1054.                   tempstr[i++] = (char) (j + 48);
  1055.                 tempstr[i++] = 'R';
  1056.                 tempstr[i] = '\0';
  1057.                 sendstr(tempstr);
  1058. #else
  1059. /* 32-bit version can call sprintf() here.  This is the original code. */
  1060.                 sendstr("[");
  1061.                 sprintf(tempstr,"%1d",(int) wherey); /* row */
  1062.                 sendchar(tempstr[0]);
  1063.                 if (tempstr[1])
  1064.                     sendchar(tempstr[1]);
  1065.                 sendchar(';');
  1066.                 sprintf(tempstr,"%1d",(int) wherex); /* col */
  1067.                 sendchar(tempstr[0]);
  1068.                 if (tempstr[1])
  1069.                     sendchar(tempstr[1]);
  1070.                 sendchar('R');
  1071. #endif /* M_286 */
  1072.                 }
  1073.                 break;
  1074.             case 'x':    /* Request terminal Parameters */
  1075.                 if (pn[1] > 1)
  1076.                 break;
  1077.                 tempstr[0] = '[';
  1078.                 tempstr[1] = (pn[1] == 0) ? '2' : '3';
  1079.                 tempstr[2] = ';';
  1080.                 switch (parity) {                
  1081.                 case 'e':
  1082.                 tempstr[3] = '5';
  1083.                 tempstr[5] = '2';
  1084.                 break;
  1085.                 case 'o':
  1086.                 tempstr[3] = '4';
  1087.                 tempstr[5] = '2';
  1088.                 break;
  1089.                 case 0:
  1090.                 tempstr[3] = '1';
  1091.                 tempstr[5] = '1';
  1092.                 break;
  1093.                 default:
  1094.                 tempstr[3] = '1';
  1095.                 tempstr[5] = '2';
  1096.                 break;
  1097.                 }
  1098.                 tempstr[4] = ';';
  1099.                 switch (speed) {
  1100.                 case 50:
  1101.                 i = 0;
  1102.                 break;
  1103.                 case 75:
  1104.                 i = 8;
  1105.                 break;
  1106.                 case 110:
  1107.                 i = 16;
  1108.                 break;
  1109.                 case 133:
  1110.                 i = 14;
  1111.                 break;
  1112.                 case 150:
  1113.                 i = 32;
  1114.                 break;
  1115.                 case 200:
  1116.                 i = 40;
  1117.                 break;
  1118.                 case 300:
  1119.                 i = 48;
  1120.                 break;
  1121.                 case 600:
  1122.                 i = 56;
  1123.                 break;
  1124.                 case 1200:
  1125.                 i = 64;
  1126.                 break;
  1127.                 case 1800:
  1128.                 i = 72;
  1129.                 break;
  1130.                 case 2000:
  1131.                 i = 80;
  1132.                 break;
  1133.                 case 2400:
  1134.                 i = 88;
  1135.                 break;
  1136.                 case 3600:
  1137.                 i = 96;
  1138.                 break;
  1139.                 case 4800:
  1140.                 i = 104;
  1141.                 break;
  1142.                 case 9600:
  1143.                 i = 112;
  1144.                 break;
  1145.                 case 19200:
  1146.                 i = 120;
  1147.                 break;
  1148.                 default:
  1149.                 i = 128;
  1150.                 break;
  1151.                 }
  1152. #ifdef M_I286
  1153. /*
  1154.   Hand-coded sprintf() again.  - fdc.
  1155. */
  1156.                 {
  1157.                 int x, j;
  1158.                 x = i;
  1159.                 i = 6;
  1160.                 tempstr[i++] = ';';
  1161.                 if ((j = x / 100) > 0)
  1162.                   tempstr[i++] = (char) (j + 48);
  1163.                 if ((j = (wherey % 100) / 10) > 0 ||
  1164.                     wherey > 99)
  1165.                   tempstr[i++] = (char) (j + 48);
  1166.                 if ((j = wherey % 10) > 0 ||
  1167.                     wherey > 9)
  1168.                   tempstr[i++] = (char) (j + 48);
  1169.                 tempstr[i++] = ';';
  1170.                 if ((j = x / 100) > 0)
  1171.                   tempstr[i++] = (char) (j + 48);
  1172.                 if ((j = (wherey % 100) / 10) > 0 ||
  1173.                     wherey > 99)
  1174.                   tempstr[i++] = (char) (j + 48);
  1175.                 if ((j = wherey % 10) > 0 ||
  1176.                     wherey > 9)
  1177.                   tempstr[i++] = (char) (j + 48);
  1178.                 tempstr[i++] = ';';
  1179.                 tempstr[i++] = '1';
  1180.                 tempstr[i++] = ';';
  1181.                 tempstr[i++] = '0';
  1182.                 tempstr[i++] = 'x';
  1183.                 tempstr[i++] = '\0';
  1184.                 }
  1185. #else
  1186.                 sprintf(&tempstr[6], ";%d;%d;1;0x", i, i);
  1187. #endif /* M_I286 */
  1188.                 sendstr(tempstr);
  1189.                 break;
  1190.             case 'm':    /* Select graphic rendition */
  1191.             case '}':
  1192.                 for (j = 1; j <= k; ++j)
  1193.                 switch ((pn[j])) {    /* Field specs */
  1194.                 case 0:    /* normal */
  1195.                     attribute = defaultattribute;
  1196.                     attrib.blinking = FALSE;
  1197.                     attrib.bold = FALSE;
  1198.                     attrib.invisible = FALSE;
  1199.                     attrib.underlined = FALSE;
  1200.                     attrib.reversed = FALSE;
  1201.                     break;
  1202.                 case 1:    /* bold */
  1203.                     attrib.bold = TRUE;
  1204.                     attribute ^= 8;
  1205.                     break;
  1206.                 case 4:    /* underline */
  1207.                     attrib.underlined = TRUE;
  1208.                     attribute = colorunderline;
  1209.                     break;
  1210.                 case 5:    /* blink */
  1211.                     attrib.blinking = TRUE;
  1212.                     attribute |= 0x80;
  1213.                     break;
  1214.                 case 7:    /* reverse video */
  1215.                     if (attrib.reversed)
  1216.                     break;
  1217.                     attrib.reversed = TRUE;
  1218.                     attribute = colorreverse;
  1219.                     if (attrib.underlined)
  1220.                         attribute = colorunderline &
  1221.                       0x0F |
  1222.                         colorreverse & 0xF0;
  1223.                     if (attrib.invisible)
  1224.                         attribute = attribute &
  1225.                       0xF0 |
  1226.                         (attribute >> 4) & 0x07;
  1227.                     break;
  1228.                 case 8:    /* invisible */
  1229.                     if (attrib.invisible)
  1230.                     break;
  1231.                     attrib.invisible = TRUE;
  1232.                     attribute = attribute &
  1233.                       0xF0 |
  1234.                     (attribute >> 4) & 0x07;
  1235.                     break;
  1236.                 case 30:
  1237.                 case 31:
  1238.                 case 32:
  1239.                 case 33:
  1240.                 case 34:
  1241.                 case 35:
  1242.                 case 36:
  1243.                 case 37:
  1244.                     /* select foreground */
  1245.                     i = (attribute & 0xF8);
  1246.                     attribute = (i | sgrcols[pn[j] - 30]);
  1247.                     break;
  1248.                 case 40:
  1249.                 case 41:
  1250.                 case 42:
  1251.                 case 43:
  1252.                 case 44:
  1253.                 case 45:
  1254.                 case 46:
  1255.                 case 47:
  1256.                     /* select back ground */
  1257.                     i = (attribute & 0x8F);
  1258.                     l = sgrcols[pn[j] - 40];
  1259.                     attribute = (i | ((l << 4)));
  1260.                     break;
  1261.                 default:
  1262.                     break;
  1263.                 }
  1264.                 break;
  1265.             case 'r':    /* set margin */
  1266.                 if ((k < 2) || (pn[2] == 0))
  1267.                 pn[2] = ysize;
  1268.                 if (pn[1] == 0)
  1269.                 pn[1] = 1;
  1270.                 if ((pn[1] > 0) &&
  1271.                 (pn[1] < pn[2]) &&
  1272.                 (pn[2] <= ysize)) {
  1273.                 setmargins(pn[1], pn[2]);
  1274.                 lgotoxy(1, relcursor ? margintop : 1);
  1275.                 }
  1276.                 break;
  1277.             case 'J':
  1278.                 switch ((pn[1])) {
  1279.                 case 0:    /* clear to end of screen */
  1280.                 clreoscr_escape();
  1281.                 break;
  1282.                 case 1:    /* clear to beginning */
  1283.                 clrboscr_escape();
  1284.                 break;
  1285.                 case 2:    /* clear all of screen */
  1286.                 clrscreen();
  1287.                 break;
  1288.                 default:
  1289.                 break;
  1290.                 }
  1291.                 break;
  1292.             case 'K':
  1293.                 switch ((pn[1])) {
  1294.                 case 0:    /* clear to end of line */
  1295.                 clrtoeoln();
  1296.                 break;
  1297.                 case 1:    /* clear to beginning */
  1298.                 clrbol_escape();
  1299.                 break;
  1300.                 case 2:    /* clear line */
  1301.                 clrline_escape();
  1302.                 break;
  1303.                 default:
  1304.                 break;
  1305.                 }
  1306.                 break;
  1307.             case 'L':    /* Insert lines */
  1308.                 for (i = 1; i <= pn[1]; ++i)
  1309.                 scroll(DOWNWARD, wherey - 1, marginbot - 1);
  1310.                 break;
  1311.             case 'M':    /* Delete lines */
  1312.                 for (i = 1; i <= pn[1]; ++i)
  1313.                 scroll(UPWARD, wherey - 1, marginbot - 1);
  1314.                 break;
  1315.             case '@':    /* Insert characters */
  1316.                 blankcell[0] = ' ';
  1317.                 blankcell[1] = attribute;
  1318.                 pn[1] *= dwl[wherey - 1] ? 2 : 1;
  1319.                 if (pn[1] > xsize + 1 - wherex)
  1320.                 pn[1] = xsize + 1 - wherex;
  1321.                 VioScrollRt(wherey - 1,
  1322.                     wherex - 1,
  1323.                     wherey - 1,
  1324.                     xsize - 1,
  1325.                     pn[1],
  1326.                     blankcell,
  1327.                     0
  1328.                     );
  1329.                 break;
  1330.             case 'P':    /* DeleteChar */
  1331.                 blankcell[0] = ' ';
  1332.                 blankcell[1] = attribute;
  1333.                 pn[1] *= dwl[wherey - 1] ? 2 : 1;
  1334.                 if (pn[1] > xsize + 1 - wherex)
  1335.                 pn[1] = xsize + 1 - wherex;
  1336.                 VioScrollLf(wherey - 1,
  1337.                     wherex - 1,
  1338.                     wherey - 1,
  1339.                     xsize - 1,
  1340.                     pn[1],
  1341.                     blankcell,
  1342.                     0
  1343.                     );
  1344.                 break;
  1345.             default:
  1346.                 break;
  1347.             }
  1348.             }
  1349.             break;
  1350.         }
  1351.         }            /* Left square bracket */
  1352.         break;
  1353.     case '7':        /* Save cursor position and attributes */
  1354.         saved = TRUE;        /* Remember they are saved */
  1355.         row = wherey;        /* Current row (absolute) */
  1356.         column = wherex;        /* Current column (absolute) */
  1357.         savedattribute = attribute;    /* Current attributes */
  1358.         savedattrib = attrib;    /* Character attributes structure */
  1359.         saverelcursor = relcursor;    /* Cursor addressing mode */
  1360.         saveg0 = g0;        /* Character sets */
  1361.         saveg1 = g1;
  1362.         saveg0g1 = g0g1;
  1363.         break;
  1364.     case '8':        /* Restore Cursor Position and attributes */
  1365.         if (saved == FALSE) {    /* Nothing saved, home the cursor */
  1366.         lgotoxy(1, relcursor ? margintop : 1);
  1367.             break;
  1368.         }
  1369. #ifdef COMMENT
  1370. /*
  1371.   Wrong!  Restoring the saved parameters does not unsave them.  -fdc
  1372. */
  1373.         saved = FALSE;
  1374. #endif /* COMMENT */
  1375.         lgotoxy(column, row);    /* Goto saved position */
  1376.         attribute = savedattribute;    /* Restore saved attributes */
  1377.         attrib = savedattrib;
  1378.         relcursor = saverelcursor;    /* Restore cursor addressing mode */
  1379.         g0 = saveg0;        /* Restore character sets */
  1380.         g1 = saveg1;
  1381.         g0g1 = saveg0g1;
  1382.         break;
  1383.     case 'A':
  1384.         if (tt_type == TT_VT52)    /* VT52 control */
  1385.         cursorup();
  1386.         break;
  1387.     case 'B':
  1388.         if (tt_type == TT_VT52)    /* VT52 control */
  1389.         cursordown();
  1390.         break;
  1391.     case 'C':
  1392.         if (tt_type == TT_VT52)    /* VT52 control */
  1393.         cursorright();
  1394.         break;
  1395.     case 'D':
  1396.         if (tt_type == TT_VT52)    /* VT52 control */
  1397.           cursorleft();
  1398.         else {
  1399.         /* Index */
  1400.         if (wherey == marginbot)
  1401.           scroll(UPWARD, margintop - 1, marginbot - 1);
  1402.         else
  1403.           cursordown();
  1404.         }
  1405.         break;
  1406.     case 'E':            /* Next Line */
  1407.         wrtch(13);
  1408.         wrtch(10);
  1409.         break;
  1410.     case 'F':
  1411.         if (tt_type == TT_VT52)    /* VT52 control */
  1412.         vt52graphics = TRUE;
  1413.         break;
  1414.     case 'G':
  1415.         if (tt_type == TT_VT52)    /* VT52 control */
  1416.         vt52graphics = FALSE;
  1417.         break;
  1418.     case 'H':
  1419.         if (tt_type == TT_VT102) {
  1420.         /* Set Tab Stop */
  1421.         htab[wherex] = 'T';
  1422.         }
  1423.         /* Set Tab Stop */
  1424.         else
  1425.         lgotoxy(1, 1);
  1426.         /* VT52 control */
  1427.         break;
  1428.     case 'I':
  1429.         if (tt_type == TT_VT52) {
  1430.         /* VT52 control */
  1431.         if ((margintop < wherey))
  1432.             cursorup();
  1433.         else
  1434.             scroll(DOWNWARD, margintop - 1, marginbot - 1);
  1435.         }
  1436.         break;
  1437.     case 'J':
  1438.         if (tt_type == TT_VT52)
  1439.         /* VT52 control */
  1440.         clreoscr_escape();
  1441.         break;
  1442.     case 'K':
  1443.         if (tt_type == TT_VT52)
  1444.         /* VT52 control */
  1445.         clrtoeoln();
  1446.         break;
  1447.     case 'M':
  1448.         /* Reverse Index */
  1449.         if (margintop == wherey)    /* "==", not ">="!  - fdc */
  1450.           scroll(DOWNWARD, margintop - 1, marginbot - 1);
  1451.         else
  1452.           cursorup();
  1453.         break;
  1454.     case 'Y':
  1455.         if (tt_type == TT_VT52) {    /* VT52 control */
  1456.         /* direct cursor address */
  1457.         readmchar_escape();
  1458.         row = achar - 31;
  1459.         readmchar_escape();
  1460.         column = achar - 31;
  1461.         lgotoxy(column, row);
  1462.         }
  1463.         /* direct cursor address */
  1464.         break;
  1465.     case 'Z':
  1466.         if (tt_type == TT_VT102) {
  1467.         /* Device Attributes */
  1468.         /* Send  Esc[?6c */ /* (was "ESC [ ? 6 ; 2 c"  - fdc) */
  1469.         sendstr("[?6c");
  1470.         }
  1471.         /* Device Attributes */
  1472.         else
  1473.         /* VT52 control */
  1474.         sendstr("/Z");
  1475.         break;
  1476.     case 'c':
  1477.         /* Reset */
  1478.         doreset();
  1479.         break;
  1480.     case '#':
  1481.         /* Esc # sequence */
  1482.         readmchar_escape();
  1483.         switch (achar) {
  1484.         case '3':
  1485.         decdwl_escape(TRUE);
  1486.         break;
  1487.         case '4':
  1488.         decdwl_escape(TRUE);
  1489.         break;
  1490.         case '5':
  1491.         decdwl_escape(FALSE);
  1492.         break;
  1493.         case '6':
  1494.         decdwl_escape(TRUE);
  1495.         break;
  1496.         case '8':
  1497.         {
  1498.             char            cell[2];
  1499.             cell[0] = 'E';
  1500.             cell[1] = 7;
  1501.             /* Self Test */
  1502.             VioWrtNCell(cell, 1920, 0, 0, 0);
  1503.             setmargins(1, ysize);
  1504.             lgotoxy(1, 1);
  1505.         }
  1506.         break;
  1507.         /* Self Test */
  1508.         default:
  1509.         break;
  1510.         }
  1511.         break;
  1512.         /* Esc # sequence */
  1513.     case '=':
  1514.         tt_keypad = FALSE;
  1515.         break;
  1516.     case '>':
  1517.         tt_keypad = TRUE;
  1518.         break;
  1519.     case '<':
  1520.         /* VT52 control */
  1521.         tt_type = TT_VT102;
  1522.         break;
  1523.     case '(':
  1524.         readmchar_escape();
  1525.         g0 = achar;
  1526.         break;
  1527.     case ')':
  1528.         readmchar_escape();
  1529.         g1 = achar;
  1530.         break;
  1531.     default:
  1532.         if (achar == 12) {
  1533.         lgotoxy(1, 1);
  1534.         clrscreen();
  1535.         }
  1536.         break;
  1537.     }
  1538.     /* First Level Case  */
  1539.     } /* Screen escape sequences  */
  1540.  
  1541. /* Host said to turn off the printer. */
  1542.  
  1543.   if (turnoffprinter) {
  1544.       turnoffprinter = FALSE;
  1545.       if (lst && !lstclosed)
  1546.     fclose(lst);
  1547.       lstclosed = TRUE;
  1548.       printon = FALSE;
  1549.   }
  1550.  
  1551. /* If printer is on, print this escape sequence. */
  1552.  
  1553.     if (printon) {
  1554.     fprintf(lst, "%c", 27);
  1555.     if (esclast > 0) {
  1556.         /* print esc sequence */
  1557.         for (i = 1; i <= esclast; ++i)
  1558.           fprintf(lst, "%c", escbuffer[i]);
  1559.     }
  1560.     }
  1561. /*
  1562.   If we just got a "printer on" directive, turn on the printer now.
  1563.   This way, the "printer on" directive itself is not printed.
  1564. */
  1565.     if (turnonprinter) {        /* Last command was "printer on" */
  1566.     turnonprinter = FALSE;
  1567.     if (lstclosed || !lst)        /* Open printer device */
  1568.       lst = fopen("prn", "w");
  1569.     if (lst) {            /* Open OK? */
  1570.         lstclosed = FALSE;        /* So not closed */
  1571.         printon = TRUE;        /* and printer is on. */
  1572.     }
  1573.     }
  1574. }
  1575.  
  1576. /* ================================================================== */
  1577. /* VT100 emulate a DEC VT100 terminal writing a character             */
  1578. /* ================================================================== */
  1579. static void
  1580. vt100(unsigned char vtch) {
  1581.     int             i, j;
  1582.     char           *s, str[2];
  1583.     /* vt100 */
  1584.     if (screenon) {
  1585.     if (vtch < 32) {    /* Control Character */
  1586.         achar = vtch;    /* Let the rest of this module see the value */
  1587.         switch (achar) {
  1588.         case LF:
  1589.             if (linemode) wherex=1;
  1590.         wrtch((char) achar);
  1591.         break;
  1592.         case CR:
  1593.         wrtch((char) achar);
  1594.         break;
  1595.         /* ESC */
  1596.         case 27:
  1597.         vtescape();
  1598.         break;
  1599.         case 14:        /* SO */
  1600.         g0g1 = &g1;
  1601.         break;
  1602.         /* SI */
  1603.         case 15:
  1604.         g0g1 = &g0;
  1605.         break;
  1606.         /* BS */
  1607.         case 8:
  1608.         wrtch((char) achar);
  1609.         break;
  1610.         case 12:        /* FF */
  1611.         case 11:        /* VT */
  1612.         /* take as lf */
  1613.         achar = 10;
  1614.         wrtch(10);
  1615.         break;
  1616.         case 7:        /* BEL */
  1617.         bleep();
  1618.         break;
  1619.         case 5:        /* ENQ */
  1620.         s = answerback;
  1621.         while (*s)
  1622.             sendchar(*s++);
  1623.         break;
  1624.         case 9:        /* tab character */
  1625.         j = dwl[wherey - 1] ? 2 : 1;
  1626.         i = wherex;
  1627.         if (j == 2 && htab[(i - 1) / j + 1] == 'T') {
  1628.             i++;
  1629.             cursorright();
  1630.         }
  1631.         if (i < xsize)
  1632.             do {
  1633.             i++;
  1634.             cursorright();
  1635.             } while ((htab[(i - 1) / j + 1] != 'T') &&
  1636.                  (i <= xsize - j));
  1637.         break;
  1638.         default:        /* ignore it */
  1639.         break;
  1640.         }
  1641.         /* end of Control Character */
  1642.     } else {
  1643.         if (vtch != DEL) {    /* Normal char */
  1644.         if (tt_type == TT_VT102) {
  1645.             if (*g0g1 == 'A') {    /* UK ascii set */
  1646.             /* if (vtch == 35)
  1647.                 vtch = 156; */
  1648.             } else if ((*g0g1 == '0') &&
  1649.                    (95 <= vtch) && (vtch <= 126)) {
  1650.             literal = TRUE;
  1651.             vtch = graphicset[vtch - 95];
  1652.             }
  1653.         } else {
  1654.             if (vt52graphics && (95 <= vtch) && (vtch <= 126)) {
  1655.             literal = TRUE;
  1656.             vtch = graphicset[vtch - 95];
  1657.             }
  1658.         }
  1659.         if (wherex != (dwl[wherey - 1] ? xsize - 1 : xsize)) {
  1660.             wrtch(vtch);
  1661.             if (dwl[wherey - 1])
  1662.             wrtch(' ');
  1663.             wrapit = FALSE;
  1664.         } else {
  1665.             if (wrapit) {    /* Next line  */
  1666.             if (marginbot <= wherey) {    /* Scroll up */
  1667.                 scroll(UPWARD, margintop - 1, marginbot - 1);
  1668.                 lgotoxy(1, wherey);
  1669.             } else
  1670.                 lgotoxy(1, wherey + 1);
  1671.             wrtch(vtch);
  1672.             if (dwl[wherey - 1])
  1673.                 wrtch(' ');
  1674.             wrapit = FALSE;
  1675.             } else {    /* put char on last column */
  1676.             i = dwl[wherey - 1] ? 2 : 1;
  1677.             str[0] = vtch;
  1678.             str[1] = ' ';
  1679.             VioWrtCharStrAtt(&vtch, i,
  1680.                      wherey - 1,
  1681.                      xsize - i,
  1682.                      &attribute,
  1683.                      0);
  1684.             literal = FALSE;
  1685.             if ((tt_wrap && !deccolm))
  1686.                 wrapit = TRUE;
  1687.             }
  1688.         }
  1689.         }            /* Normal char */
  1690.     }
  1691.     }
  1692.     if (printon && (vtch != 27))
  1693.       fprintf(lst, "%c", vtch);
  1694. }
  1695.  
  1696. /* save current status of screen */
  1697. savescreen(ascreen *scrn) {
  1698.     USHORT n = xsize * (ysize + 1) * 2;
  1699.     scrn->ox = wherex;
  1700.     scrn->oy = wherey;
  1701.     scrn->att = attribute;
  1702.     VioReadCellStr((char *) (scrn->scrncpy), &n, 0, 0, 0);
  1703. }
  1704.  
  1705. /* restore state of screen */
  1706. restorescreen(ascreen *scrn) {
  1707.     movetoscreen(scrn->scrncpy, 1, 1, xsize * (ysize + 1) * 2);
  1708.     attribute = scrn->att;
  1709.     wherey = scrn->oy;
  1710.     wherex = scrn->ox;
  1711.     lgotoxy(wherex, wherey);
  1712. }
  1713.  
  1714. #ifdef M_I286
  1715. /* Avoid 16-bit stack overflows */
  1716. #define logchar(c) zchout(ZSFILE,c)
  1717. #else
  1718. void
  1719. logchar(char c) {
  1720.     if (zchout(ZSFILE,c) < 0) {
  1721.     conoll("");
  1722.     conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
  1723.     seslog = 0;
  1724.     }
  1725. }
  1726. #endif /* M_I286 */
  1727.  
  1728. sendcharduplex(unsigned char key) {
  1729.     unsigned char csave;
  1730.  
  1731.     key &= cmdmsk;        /* Do any requested masking */
  1732.     csave = key;
  1733.  
  1734.     if (outesc == ES_NORMAL) { /* If not inside escape seq.. */
  1735.     /* Translate character sets */
  1736.     if (sxo) key = (*sxo)(key); /* Local to intermediate. */
  1737.     if (rxo) key = (*rxo)(key); /* Intermediate to remote. */
  1738.     }
  1739.     if (oskipesc) outesc = chkaes(outesc, key);
  1740.     /* Check escape sequence status */
  1741.  
  1742.     if (sosi) {                      /* Shift-In/Out selected? */
  1743.     if (cmask == 0177) {         /* In 7-bit environment? */
  1744.         if (key & 0200) {        /* 8-bit character? */
  1745.         if (outshift == 0) { /* If not shifted, */
  1746.             sendchar(SO);    /* shift. */
  1747.             outshift = 1;
  1748.         }
  1749.         } else {
  1750.         if (outshift == 1) { /* 7-bit character */
  1751.             sendchar(SI);    /* If shifted, */
  1752.             outshift = 0;    /* unshift. */
  1753.         }
  1754.         }
  1755.     }
  1756.     if (key == SO) outshift = 1;    /* User typed SO */
  1757.     if (key == SI) outshift = 0;    /* User typed SI */
  1758.     }
  1759.  
  1760.     key &= cmask;        /* Apply Kermit-to-host mask now. */
  1761.     if (tnlm && key == '\015') {   /* Handle TERMINAL NEWLINE */
  1762.         sendchar(dopar('\015'));   /* Send the CR */
  1763.         if (duplex) {              /* If local echoing... */
  1764.        cwrite('\015');         /*   echo to screen */
  1765.            if (seslog)             /*   and if logging */
  1766.          logchar(csave);       /*   log it */
  1767.         }
  1768.         csave = key = '\012';   /* Now insert a linefeed */
  1769.     }
  1770.     sendchar(key);
  1771.     if (duplex) {
  1772.     cwrite(csave);
  1773.     if (seslog) logchar(csave);
  1774.     }
  1775. }
  1776.  
  1777. sendstrduplex(unsigned char *s, int escape) {
  1778.     if (escape)
  1779.         sendcharduplex(27);
  1780.     for ( ; *s; s++ )
  1781.         sendcharduplex(*s);
  1782. }
  1783.  
  1784. void
  1785. vt100key(int key) {
  1786.     void doesc(int);
  1787.     int helpconnect(int);
  1788.     int             i;
  1789.     int             il;
  1790.     char            str[3];
  1791.     int             prt;
  1792.     int             st;
  1793.     unsigned char   nolblines;
  1794.     unsigned char   linesleft;
  1795.     unsigned char   nextline;
  1796.     unsigned char   nlines;
  1797.  
  1798.     if ( macrotab[key] ) {
  1799.       sendstrduplex(macrotab[key], 0);
  1800.       return;
  1801.     }
  1802.  
  1803.     key = keymap[key];
  1804.  
  1805.     if (key < 0x100) {
  1806.     sendcharduplex((char) key);
  1807.     if (key == CR && linemode)
  1808.         sendcharduplex(LF);
  1809.         return;
  1810.     }
  1811.  
  1812.     switch (key & 0xFF) {
  1813.     case 72:
  1814.         /* up */
  1815.         if (tt_type == TT_VT102) {
  1816.             if (tt_arrow)
  1817.                 sendstrduplex("OA", 1);
  1818.             else
  1819.                 sendstrduplex("[A", 1);
  1820.         } else
  1821.             sendstrduplex("A", 1);
  1822.         break;
  1823.     case 75:
  1824.         /* left */
  1825.         if (tt_type == TT_VT102) {
  1826.             if (tt_arrow)
  1827.                 sendstrduplex("OD", 1);
  1828.             else
  1829.                 sendstrduplex("[D", 1);
  1830.         } else
  1831.             sendstrduplex("D", 1);
  1832.         break;
  1833.     case 77:
  1834.         /* right */
  1835.         if (tt_type == TT_VT102) {
  1836.             if (tt_arrow)
  1837.                 sendstrduplex("OC", 1);
  1838.             else
  1839.                 sendstrduplex("[C", 1);
  1840.         } else
  1841.             sendstrduplex("C", 1);
  1842.         break;
  1843.     case 80:
  1844.         /* down */
  1845.         if (tt_type == TT_VT102) {
  1846.             if (tt_arrow)
  1847.                 sendstrduplex("OB", 1);
  1848.             else
  1849.                 sendstrduplex("[B", 1);
  1850.         } else
  1851.             sendstrduplex("B", 1);
  1852.         break;
  1853.     case 15:                /* Backtab */
  1854.         /* backspace */
  1855.         sendcharduplex(8);
  1856.         break;
  1857.     case 83:                /* DEL */
  1858.         /* delete */
  1859.         sendcharduplex(127);
  1860.         break;
  1861.     case 59:                /* F1 */
  1862.         /* PF1 */
  1863.         if (tt_type == TT_VT102)
  1864.             sendstrduplex("OP", 1);
  1865.         else
  1866.             sendstrduplex("P", 1);
  1867.         break;
  1868.     case 60:                /* F2 */
  1869.         /* PF2 */
  1870.         if (tt_type == TT_VT102)
  1871.             sendstrduplex("OQ", 1);
  1872.         else
  1873.             sendstrduplex("Q", 1);
  1874.         break;
  1875.     case 61:
  1876.         /* PF3 */           /* F3 */
  1877.         if (tt_type == TT_VT102)
  1878.             sendstrduplex("OR", 1);
  1879.         else
  1880.             sendstrduplex("R", 1);
  1881.         break;
  1882.     case 62:                /* F4 */
  1883.         /* PF4 */
  1884.         if (tt_type == TT_VT102)
  1885.             sendstrduplex("OS", 1);
  1886.         else
  1887.             sendstrduplex("S", 1);
  1888.         break;
  1889.     case 120:               /* Alt-1 ... Alt-9 */
  1890.     case 121:
  1891.     case 122:
  1892.     case 123:
  1893.     case 124:
  1894.     case 125:
  1895.     case 126:
  1896.     case 127:
  1897.     case 128:
  1898.     case 129:           /* This one is Alt-0 */
  1899.         /* numeric 1-9,0 */
  1900.     if (tt_keypad) {        /* Keypad digits in numeric mode*/
  1901.         if (key == 129) key = 48;    /* Watch out for zero */
  1902.         else key -= 71;
  1903.         sendcharduplex((unsigned char)key);    /* send digit */
  1904.         } else {
  1905.             key = 'q' + (key & 0xFF) - 120;
  1906.             if (key == 'z')
  1907.                 key = 'p';
  1908.             /* alt 0 */
  1909.             if (tt_type == TT_VT102)
  1910.                 strcpy(str, "O ");
  1911.             else
  1912.                 strcpy(str, "? ");
  1913.             str[1] = key;
  1914.             sendstrduplex(str, 1);
  1915.         }
  1916.         break;
  1917.     case 63:                /* Keypad minus = F5 or ... */
  1918.     case 64:                /* F6 */
  1919.     if (tt_keypad)            /* Keypad in numeric mode */
  1920.         sendcharduplex('-');
  1921.         else if (tt_type == TT_VT102)    /* Application mode, VT102 */
  1922.             sendstrduplex("Om", 1);
  1923.         else                /* Application mode, VT52 */
  1924.             sendstrduplex("?m", 1);
  1925.         break;
  1926.     case 65:                /* Keypad comma = F7 or ... */
  1927.     case 66:                /* F8 */
  1928.     if (tt_keypad)
  1929.         sendcharduplex(',');
  1930.         else if (tt_type == TT_VT102)
  1931.             sendstrduplex("Ol", 1);
  1932.         else
  1933.             sendstrduplex("?l", 1);
  1934.         break;
  1935.     case 67:                /* Keypad period = F9 */
  1936.     if (tt_keypad)
  1937.         sendcharduplex('.');
  1938.         else if (tt_type == TT_VT102)
  1939.             sendstrduplex("On", 1);
  1940.         else
  1941.             sendstrduplex("?n", 1);
  1942.         break;
  1943.     case 68:                /* Keypad Enter = F10 */
  1944.     if (tt_keypad) {
  1945.         sendcharduplex('\015');    /* Numeric mode, send CR */
  1946.         if (tnlm)
  1947.           sendcharduplex('\012');    /* Newline mode, send LF too */
  1948.         } else if (tt_type == TT_VT102)
  1949.       sendstrduplex("OM", 1);
  1950.         else
  1951.       sendstrduplex("?M", 1);
  1952.         break;
  1953.     case 255:                /* Scroll-Lock */
  1954.         {
  1955.             strcpy(usertext, " Scroll-Lock ");
  1956.             *exittext = '\0';
  1957.             *helptext = '\0';
  1958.             line25();
  1959.             while (keymap[congks(0)] != 0x1FF) ;
  1960.             ipadl25();
  1961.         }
  1962.         break;
  1963.     case 81:                /* Page-Down */
  1964.     case 118:               /* Control-Page-Down */
  1965.         bleep();
  1966.         /* since not in extended display mode */
  1967.         break;
  1968.     case 71:                /* Home           enter extended display mode */
  1969.     case 73:                /* Page-Up  */
  1970.     case 132:               /* Control-Page-Up */
  1971.         if (paginginfo.numlines == 0)
  1972.             bleep();
  1973.         else {
  1974.             savescreen(&savedscreen);
  1975.             killcursor();
  1976.             linesleft = paginginfo.numlines;
  1977.             nextline = paginginfo.botline;
  1978.             do {
  1979.                 if ((key & 0xFF) == 71 || (key & 0xFF) == 73 || 
  1980.             (key & 0xFF) == 132) {  /* Page Up or Home */
  1981.                     if (linesleft == 0)
  1982.                         bleep();
  1983.                     else {
  1984.                         /* scroll up a page */
  1985.                         nlines = (key & 0xFF) == 73 ? ysize
  1986.                    : (key & 0xFF) == 71 ? linesleft : 1;
  1987.                         if (nlines > linesleft)
  1988.                             nlines = linesleft;
  1989.             if (nlines > ysize) {
  1990.                 nextline = paginginfo.topline + ysize - 1;
  1991.                 for (il = ysize; il >= 1; --il) {
  1992.                                 movetoscreen(paginginfo.buffer + 
  1993.                          xsize * 2 * nextline, 
  1994.                          1, il, xsize * 2);
  1995.                 nextline--;
  1996.                             }
  1997.             }
  1998.             else
  1999.                 for (il = 1; il <= nlines; ++il) {
  2000.                                 scroll(DOWNWARD, 0, ysize - 1);
  2001.                                 movetoscreen(paginginfo.buffer + 
  2002.                          xsize * 2 * nextline, 
  2003.                          1, 1, xsize * 2);
  2004.                                 if (nextline == 0)
  2005.                                     nextline = LBUFSIZE - 1;
  2006.                                 else
  2007.                                     nextline--;
  2008.                             }
  2009.  
  2010.                         linesleft = linesleft - nlines;
  2011.                     }
  2012.                 } else if ((key & 0xFF) == 81 || (key & 0xFF) == 118) {
  2013.                     nlines = (key & 0xFF) == 81 ? ysize : 1;    /* Page Down */
  2014.                     do {
  2015.                         nextline = nextline + 1;
  2016.                         if (nextline >= LBUFSIZE)
  2017.                             nextline = 0;
  2018.                         linesleft = linesleft + 1;
  2019.                         /* lines of ext display above top of the screen */
  2020.                         nolblines = paginginfo.numlines - linesleft;
  2021.                         /* no. of ext disp buffer lines on screen */
  2022.                         scroll(UPWARD, 0, ysize - 1);
  2023.                         if (nolblines >= ysize) {
  2024.                             /* move from buffer */
  2025.                             i = nextline;
  2026.                             i = (i + ysize);
  2027.                             if (i >= LBUFSIZE)
  2028.                                 i = i - LBUFSIZE;
  2029.                             movetoscreen(paginginfo.buffer + xsize * 2 * i,
  2030.                      1, ysize, xsize * 2);
  2031.                         } else {
  2032.                             /* move from the screen copy */
  2033.     movetoscreen(&(savedscreen.scrncpy[(ysize - 1 - nolblines) * xsize * 2]),
  2034.          1, ysize, xsize * 2);
  2035.                         }
  2036.                         nlines = nlines - 1;
  2037.                     }
  2038.                     while (!(((nlines == 0) ||
  2039.                   (linesleft == paginginfo.numlines)))) ;
  2040.                 } else
  2041.                     linesleft = paginginfo.numlines;
  2042.                 if (linesleft != paginginfo.numlines) {
  2043.                     strcpy(helptext, "PageUp/Down");
  2044.                     strcpy(exittext, "Home/End");
  2045.                     strcpy(usertext, " Scrollback:");
  2046.                     line25();
  2047.                     if ( (key = keymap[congks(0)]) < 0x100 )
  2048.                         key = 32;
  2049.                 }
  2050.             }
  2051.             while (linesleft != paginginfo.numlines);
  2052.             restorescreen(&savedscreen);
  2053.             newcursor();
  2054.             ipadl25();
  2055.         }
  2056.         break;
  2057.     case 16:                /* Alt-Q = Quit */
  2058.       doesc('Q'); break;
  2059.     case 45:                /* Alt-X = Return to prompt */
  2060.       doesc('C'); break;
  2061.     case 48:                /* Alt-B = Send BREAK */
  2062.       doesc('B'); break;
  2063.     case 38:                /* Alt-L = Send Long BREAK */
  2064.       doesc('L'); break;
  2065.     case 35:                /* Alt-H = Hangup */
  2066.       doesc('H'); break;
  2067.     case 131:                /* Alt-= is Reset */
  2068.       doreset();
  2069. #ifdef COMMENT
  2070.       clearscreen(0, attribute);
  2071.       savescreen(&vt100screen);
  2072. #endif /* COMMENT */
  2073.       break;
  2074.     case 53:                /* Alt-? or Alt-/ = Help */
  2075.       strcpy(usertext, " Press any key to restore the screen");
  2076.       exittext[0] = '\0';
  2077.       helptext[0] = '\0';
  2078.       line25();
  2079.       helpconnect(1);
  2080.       ipadl25();
  2081.       break;
  2082.     default:                /* Others, ignore */
  2083.         break;
  2084.     }
  2085.     /* of case */
  2086. }
  2087.  
  2088. /* ------------------------------------------------------------------ */
  2089. /* cwrite                                                             */
  2090. /* ------------------------------------------------------------------ */
  2091. cwrite(unsigned char ch)
  2092. {
  2093.     {
  2094.     /* check and process escape sequence */
  2095.     /* escape */
  2096.     if (ch == 27) {
  2097.         escaping = TRUE;
  2098.         esclast = 0;
  2099.     } else {
  2100.         if (!(escaping)) {
  2101.         /* can send it to vt100 to be processed */
  2102.         vt100(ch);
  2103.         } else {
  2104.         /* in the middle of an escape sequence */
  2105.         if (((ch == 24) || (ch == 26)))
  2106.             /* cancelled */
  2107.             escaping = FALSE;
  2108.         else {
  2109.             if (ch < 32) {
  2110.             if (ch == 8) {    /* Backspace */
  2111.                 if (esclast >= 1)
  2112.                 esclast--;
  2113.             }
  2114.             } else {
  2115.             /* add to control string */
  2116.             if (esclast < 128) {
  2117.                 /* add to buffer */
  2118.                 esclast = esclast + 1;
  2119.                 escbuffer[esclast] = ch;
  2120.             }
  2121.             /* now check to see if sequence complete */
  2122.             {
  2123.                 if (tt_type == TT_VT102) {
  2124.                 if (escbuffer[1] != '[') {
  2125.                     char            c = escbuffer[1];
  2126.                     if ((c != '#' &&
  2127.                      c != '(' &&
  2128.                      c != ')' &&
  2129.                      c != 'O' &&
  2130.                      c != '?') ||
  2131.                     esclast >= 2) {
  2132.                     if ((escbuffer[1] != 'Y'))
  2133.                         vtescape();
  2134.                     else {
  2135.                         if ((esclast == 3))
  2136.                         vtescape();
  2137.                     }
  2138.                     }
  2139.                 } else {
  2140.                     /* check for terminating character */
  2141.                     if ((((64 <= ch) &&
  2142.                       (ch <= 126)) &&
  2143.                      (esclast > 1)))
  2144.                     vtescape();
  2145.                 }
  2146.                 } else {
  2147.                 /* vt52 mode */
  2148.                 if ((escbuffer[1] != 'Y'))
  2149.                     vtescape();
  2150.                 else {
  2151.                     if (esclast == 3)
  2152.                     vtescape();
  2153.                 }
  2154.                 }
  2155.             }
  2156.             }
  2157.         }
  2158.         }
  2159.     }
  2160.     }
  2161. }
  2162.  
  2163. /*---------------------------------------------------------------------------*/
  2164. /* scrninit                                                                  */
  2165. /*---------------------------------------------------------------------------*/
  2166. scrninit() {
  2167.     if (!scrninitialised) {
  2168.     scrninitialised = 1;
  2169.     defaultattribute = colornormal;
  2170.     attribute = defaultattribute;
  2171.     /* Initialise paging info */
  2172.         if ( paginginfo.buffer == NULL )
  2173.       paginginfo.buffer = malloc(LBUFSIZE * xsize * 2);
  2174.     assert(paginginfo.buffer != NULL);
  2175.     paginginfo.numlines = 0;
  2176.     paginginfo.topline = 0;
  2177.     paginginfo.botline = LBUFSIZE - 1;
  2178.     clearscreen(0, attribute);
  2179.     savescreen(&vt100screen);
  2180.     }
  2181. }
  2182.  
  2183. /*---------------------------------------------------------------------------*/
  2184. /* bleep                                                                     */
  2185. /*---------------------------------------------------------------------------*/
  2186. bleep() {
  2187.     DosBeep(880, 50);
  2188. }
  2189.  
  2190. /*---------------------------------------------------------------------------*/
  2191. /* wrtch                                                                     */
  2192. /*---------------------------------------------------------------------------*/
  2193. wrtch(char ch) {
  2194.     char cell[2];
  2195.     if (ch >= ' ' || literal) {    /* Normal character */
  2196.     if ((tt_type == TT_VT102) && insertmode) {
  2197.         cell[0] = ch;
  2198.         cell[1] = attribute;
  2199.         VioScrollRt(wherey - 1, wherex - 1, wherey - 1,
  2200.             xsize - 1, 1, cell, 0);
  2201.     } else
  2202.         VioWrtCharStrAtt(&ch, 1, wherey - 1, wherex - 1, &attribute, 0);
  2203.     literal = FALSE;
  2204.     if (++wherex > xsize) {
  2205.         wherex = 1;
  2206.         wrtch(LF);
  2207.     }
  2208.     } else {            /* Control character */
  2209.     switch (ch) {
  2210.     case LF:
  2211.         if (wherey == marginbot) {
  2212.         if (margintop == 1)
  2213.             toplinetocyclicbuffer();
  2214.         scroll(UPWARD, margintop - 1, marginbot - 1);
  2215.         } else {
  2216.         wherey++;
  2217.         if (wherey == ysize + 1)
  2218.             wherey--;
  2219.         }
  2220.         break;
  2221.     case CR:
  2222.         wherex = 1;
  2223.         break;
  2224.     case BS:
  2225.         if (wherex > 1)
  2226.         wherex--;
  2227.         break;
  2228.     case 12:
  2229.         if (wherex < xsize)
  2230.         wherex++;
  2231.         break;
  2232.     case BEL:
  2233.         DosBeep(440, 100);
  2234.         break;
  2235.     default:{        /* Ignore */
  2236.         }
  2237.     }
  2238.     }
  2239.     if (cursoron)
  2240.     VioSetCurPos(wherey - 1, wherex - 1, 0);
  2241. }
  2242.  
  2243. /*---------------------------------------------------------------------------*/
  2244. /* clearscreen                                                               */
  2245. /*---------------------------------------------------------------------------*/
  2246. clearscreen(int all, int attr) {
  2247.     char cell[2];
  2248.     cell[0] = ' ';
  2249.     cell[1] = attr;
  2250.     VioWrtNCell(cell, xsize * ysize + (all ? xsize : 0), 0, 0, 0);
  2251.     lgotoxy(1, 1);
  2252. }
  2253.  
  2254. /*---------------------------------------------------------------------------*/
  2255. /* lgotoxy                                                                   */
  2256. /*---------------------------------------------------------------------------*/
  2257. lgotoxy(int x, int y) {
  2258.     wherex = x;
  2259.     wherey = y;
  2260.     if (cursoron)
  2261.     VioSetCurPos(wherey - 1, wherex - 1, 0);
  2262. }
  2263.  
  2264. /*---------------------------------------------------------------------------*/
  2265. /* scroll                                                                    */
  2266. /*---------------------------------------------------------------------------*/
  2267. scroll(int updown, int top, int bottom) {
  2268.     char blankcell[2];
  2269.     int i;
  2270.  
  2271.     blankcell[0] = ' ';
  2272.     blankcell[1] = attribute;
  2273.     switch (updown) {
  2274.     case UPWARD:
  2275.     VioScrollUp(top, 0, bottom, xsize - 1, 1, blankcell, 0);
  2276.         VioShowBuf(0, xsize * 2, 0);
  2277.         /* There is a bug in the OS/2 2.0 8514/A PM driver that causes
  2278.          * wrong screen update after a scroll operation. We just force
  2279.          * a correct screen update of the line in question here. */
  2280.     if (dwls) {
  2281.         for (i = top; i < bottom; i++)
  2282.         dwl[i] = dwl[i + 1];
  2283.         dwl[bottom] = FALSE;
  2284.     }
  2285.     break;
  2286.     case DOWNWARD:
  2287.     VioScrollDn(top, 0, bottom, xsize - 1, 1, blankcell, 0);
  2288.         VioShowBuf(xsize * 2, xsize * 2, 0);
  2289.     if (dwls) {
  2290.         for (i = bottom; i > top; i--)
  2291.         dwl[i] = dwl[i - 1];
  2292.         dwl[top] = FALSE;
  2293.     }
  2294.     break;
  2295.     default: /* ignore */ ;
  2296.     }
  2297.     if (dwls) {
  2298.     dwls = FALSE;
  2299.     for (i = 0; i < ysize; i++)
  2300.         if (dwl[i]) {
  2301.         dwls = TRUE;
  2302.         break;
  2303.         }
  2304.     }
  2305. }
  2306.  
  2307. /*---------------------------------------------------------------------------*/
  2308. /* movetoscreen                                                              */
  2309. /*---------------------------------------------------------------------------*/
  2310. movetoscreen(char *source, int x, int y, int len) {
  2311.     VioWrtCellStr(source, len, y - 1, x - 1, 0);
  2312. }
  2313.  
  2314. /*---------------------------------------------------------------------------*/
  2315. /* toplinetocyclicbuffer                                                     */
  2316. /*---------------------------------------------------------------------------*/
  2317. toplinetocyclicbuffer() {
  2318.     USHORT n = xsize * 2;
  2319.     if (paginginfo.numlines == LBUFSIZE) {
  2320.     if (++paginginfo.topline == LBUFSIZE)
  2321.         paginginfo.topline = 0;
  2322.     } else
  2323.     paginginfo.numlines++;
  2324.     if (++paginginfo.botline == LBUFSIZE)
  2325.     paginginfo.botline = 0;
  2326.     VioReadCellStr((paginginfo.buffer + xsize * 2 * paginginfo.botline),
  2327.            &n, 0, 0, 0);
  2328. }
  2329.  
  2330. /*---------------------------------------------------------------------------*/
  2331. /* cleartoeol                                                                */
  2332. /*---------------------------------------------------------------------------*/
  2333. clrtoeoln() {
  2334.     char            cell[2];
  2335.  
  2336.     cell[0] = ' ';
  2337.     cell[1] = attribute;
  2338.     VioWrtNCell(cell, xsize + 1 - wherex, wherey - 1, wherex - 1, 0);
  2339. }
  2340.  
  2341. /*---------------------------------------------------------------------------*/
  2342. /* setmargins                                                                */
  2343. /*---------------------------------------------------------------------------*/
  2344. setmargins(int top, int bot) {
  2345.     margintop = top;
  2346.     marginbot = bot;
  2347. }
  2348.  
  2349. /*---------------------------------------------------------------------------*/
  2350. /* killcursor                                                                */
  2351. /*---------------------------------------------------------------------------*/
  2352. killcursor() {
  2353.     VIOCURSORINFO   nocursor;
  2354.     if (!cursoron)
  2355.     return 0;
  2356.     VioGetCurType(&crsr_info, 0);    /* Store current cursor type */
  2357.     nocursor = crsr_info;    /* MS C allows this */
  2358.     nocursor.attr = -1;
  2359.     VioSetCurType(&nocursor, 0);/* Hide cursor */
  2360. }
  2361.  
  2362. /*---------------------------------------------------------------------------*/
  2363. /* newcursor                                                                 */
  2364. /*---------------------------------------------------------------------------*/
  2365. newcursor() {
  2366.     VioSetCurType(&crsr_info, 0);
  2367.     VioSetCurPos(wherey - 1, wherex - 1, 0);
  2368.     cursoron = TRUE;
  2369. }
  2370.  
  2371. /*---------------------------------------------------------------------------*/
  2372. /* line25                                                                    */
  2373. /*---------------------------------------------------------------------------*/
  2374.  
  2375. strinsert(char *d, char *s) {
  2376.     while (*s)
  2377.     *d++ = *s++;
  2378. }
  2379.  
  2380. line25() {
  2381.     char s[132];
  2382.     int  i;
  2383.     char attr;
  2384.  
  2385.     for (i = 0; i < xsize; i++)
  2386.     s[i] = ' ';
  2387.     strinsert(&s[00], usertext);
  2388.     strinsert(&s[20], helptext);
  2389.     strinsert(&s[33], exittext);
  2390.     strinsert(&s[50], hostname);
  2391.     strinsert(&s[65], filetext);
  2392.     attr = colorstatus;
  2393.     VioWrtCharStrAtt(s, xsize, ysize, 0, &attr, 0);
  2394. }
  2395.  
  2396. sendstr(char * s) {
  2397.     sendchar(27);
  2398.     while (*s)
  2399.     sendchar(*s++);
  2400. }
  2401.  
  2402. /*
  2403.  * RDSERWRTSCR  --  Read the comms line and write to the screen.
  2404.  * This function is executed by a separate thread.
  2405.  */
  2406. #ifdef __32BIT__
  2407. long FAR
  2408. rdserwrtscr(long param)
  2409. #else
  2410. void FAR
  2411. rdserwrtscr()
  2412. #endif
  2413. {
  2414.     int c;
  2415.  
  2416.     DosSetPrty(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
  2417. #ifdef __32BIT__
  2418.     DosPostEventSem(threadsem);
  2419. #else
  2420.     DosSemClear(&threadsem);    /* Let him know we've started */
  2421. #endif
  2422.  
  2423.     while (active) {
  2424.         c = ttinc(-50);
  2425.     if (!active)
  2426.       break;
  2427.     if (c >= 0) {
  2428.         DosEnterCritSec();
  2429.  
  2430.         if (cursoron)
  2431.         if (ttchk() > 20) {
  2432.             killcursor();
  2433.             cursoron = FALSE;
  2434.         }
  2435.  
  2436.             c &= cmask;
  2437.  
  2438.         if (sosi) {        /* Handle SI/SO */
  2439.         if (c == SO) {    /* Shift Out */
  2440.             inshift = 1;
  2441.             goto cont;
  2442.         } else if (c == SI) { /* Shift In */
  2443.             inshift = 0;
  2444.             goto cont;
  2445.         }
  2446.         if (inshift) c |= 0200;
  2447.         }
  2448.  
  2449.         /* Translate character sets */
  2450.         if (inesc == ES_NORMAL) {
  2451.           /* Translate character sets */
  2452.           if (sxi) c = (*sxi)((CHAR)c);
  2453.           if (rxi) c = (*rxi)((CHAR)c);
  2454.         }
  2455.         if (iskipesc) inesc = chkaes(inesc, (CHAR)c);
  2456.         /* Adjust escape sequence status */
  2457.  
  2458.         c &= cmdmsk;    /* Apply command mask. */
  2459.         if (c == CR && tt_crd) { /* SET TERM CR-DISPLAY CRLF ? */
  2460.         cwrite((char) c);    /* Yes, output CR */
  2461.         if (seslog) logchar((char) c);
  2462.         c = LF;             /* and insert a linefeed */
  2463.         }
  2464.         cwrite((char) c);
  2465.         if (seslog) logchar((char) c);
  2466.  
  2467. cont:        DosExitCritSec();
  2468.     } else if (c == -2) {
  2469.             active = FALSE;
  2470.         strcpy(termessage, "Connection closed.\n");
  2471.             /* link broken */
  2472.     } else if (!cursoron) {
  2473.         DosEnterCritSec();
  2474.         newcursor();
  2475.         DosExitCritSec();
  2476.     }
  2477.     }
  2478.  
  2479. #ifndef __32BIT__
  2480.     DosEnterCritSec();        /* Stop thread 1 discarding our stack before
  2481.                  * we've gone */
  2482.     DosSemClear(&threadsem);    /* Tell him we're going to die */
  2483. #endif
  2484.     DosExit(EXIT_THREAD, 0);
  2485. }
  2486.  
  2487. /* HELPCONNECT  --  Give help message for connect.  */
  2488.  
  2489. static int helpcol, helprow;
  2490. static int helpwidth;
  2491.  
  2492. void helpstart(int w, int h)
  2493. {
  2494.     unsigned char   cell[2];
  2495.  
  2496.     cell[1] = colorhelp;
  2497.     helpwidth = w;
  2498.     helpcol = (xsize - w) / 2;
  2499.     helprow = (ysize - h) / 2 - 1;
  2500.     cell[0] = 201;        /* Top left corner */
  2501.     VioWrtNCell(cell, 1, helprow, helpcol, 0);
  2502.     cell[0] = 205;        /* Horizontal */
  2503.     VioWrtNCell(cell, helpwidth, helprow, helpcol + 1, 0);
  2504.     cell[0] = 187;        /* Top right corner */
  2505.     VioWrtNCell(cell, 1, helprow, helpcol + helpwidth + 1, 0);
  2506. }
  2507.  
  2508. void
  2509. helpline(char *s) {
  2510.     unsigned char   cell[2];
  2511.     int             i;
  2512.  
  2513.     i = strlen(s);
  2514.     helprow++;
  2515.     cell[1] = colorhelp;
  2516.     cell[0] = 186;        /* Vertical */
  2517.     VioWrtNCell(cell, 1, helprow, helpcol, 0);
  2518.     VioWrtCharStrAtt(s, i, helprow, helpcol + 1, &cell[1], 0);
  2519.     cell[0] = ' ';
  2520.     VioWrtNCell(cell, helpwidth - i, helprow, helpcol + 1 + i, 0);
  2521.     cell[0] = 186;        /* Vertical */
  2522.     VioWrtNCell(cell, 1, helprow, helpcol + helpwidth + 1, 0);
  2523. }
  2524.  
  2525. void
  2526. helpend() {
  2527.     unsigned char   cell[2];
  2528.  
  2529.     helprow++;
  2530.     cell[1] = colorhelp;
  2531.     cell[0] = 200;        /* Bottom left corner */
  2532.     VioWrtNCell(cell, 1, helprow, helpcol, 0);
  2533.     cell[0] = 205;        /* Horizontal */
  2534.     VioWrtNCell(cell, helpwidth, helprow, helpcol + 1, 0);
  2535.     cell[0] = 188;        /* Bottom right corner */
  2536.     VioWrtNCell(cell, 1, helprow, helpcol + helpwidth + 1, 0);
  2537. }
  2538.  
  2539. int
  2540. helpconnect(int x) {
  2541.     int c, n;
  2542.     char line[80];
  2543.     static char    *hlpmsg[] = {
  2544.   "",
  2545.   " Command:   (SPACE to cancel)",
  2546.   "",
  2547.   "    C    to return to the C-Kermit prompt",
  2548.   "    H    to hangup and return to the prompt",
  2549.   "    Q    to hangup and quit C-Kermit",
  2550.   "    !    to enter an OS/2 command processor",
  2551.   "",
  2552.   "    0    (zero) to send a null",
  2553.   "   ^%c    to send the escape character",
  2554.   "    B    to send a BREAK",
  2555.   "    L    to send a LONG BREAK",
  2556.   "",
  2557.   "    \\    backslash escape (end with ENTER):",
  2558.   "         \\nnn   decimal code",
  2559.   "         \\Onnn  octal code",
  2560.   "         \\Xhh   hexadecimal code",
  2561.   ""};
  2562. #define HELPSIZE (sizeof(hlpmsg)/sizeof(char *))
  2563.  
  2564.     static char *altmsg[] = {
  2565.   "",
  2566.   " Alt-X to return to the C-Kermit prompt",
  2567.   " Alt-H to hangup and return to the prompt",
  2568.   " Alt-Q to hangup and quit Kermit",
  2569.   " Alt-B to send a BREAK",
  2570.   " Alt-L to send a Long BREAK",
  2571.   " Alt-= to reset terminal emulator",
  2572.   "",
  2573.   " or the CONNECT-mode escape character Ctrl-%c",
  2574.   " followed by ? for additional commands",
  2575.   ""};
  2576. #define ALTSIZE (sizeof(altmsg)/sizeof(char *))
  2577.  
  2578.     n = x ? ALTSIZE : HELPSIZE;
  2579.  
  2580.     savescreen(&savedscreen);
  2581.     killcursor();
  2582.     helpstart(47, n);
  2583.     for (c = 0; c < n; c++)
  2584.       if (strchr(x ? altmsg[c] : hlpmsg[c], '%')) {
  2585.     sprintf(line, x ? altmsg[c] : hlpmsg[c], ctl(escape));
  2586.     helpline(line);
  2587.       }
  2588.       else
  2589.     helpline(x ? altmsg[c] : hlpmsg[c]);
  2590.     helpend();
  2591.     c = keymap[congks(0)];
  2592.     newcursor();
  2593.     restorescreen(&savedscreen);
  2594.     return (c);
  2595. }
  2596.  
  2597. /* CHSTR  --  Make a printable string out of a character  */
  2598.  
  2599. char*
  2600. chstr(int c) {
  2601.     static char     s[8];
  2602.     char           *cp = s;
  2603.  
  2604.     if (c < SP) {
  2605.     sprintf(cp, "CTRL-%c", ctl(c));
  2606.     } else
  2607.     sprintf(cp, "'%c'\n", c);
  2608.     cp = s;
  2609.     return (cp);
  2610. }
  2611.  
  2612. /* DOESC  --  Process an escape character argument  */
  2613.  
  2614. void
  2615. esc25(int h) {
  2616.     strcpy(usertext, " Command:");
  2617.     strcpy(exittext, h ? "" : "Return: c");
  2618.     strcpy(helptext, h ? "" : "Help: ?");
  2619.     line25();
  2620. }
  2621.  
  2622. void
  2623. doesc(int c) {
  2624.     CHAR d;
  2625.     VIOMODEINFO mi;
  2626.  
  2627.     while (1) {
  2628.     if (c == escape) {    /* Send escape character */
  2629.         sendchar((char)c);
  2630.         return;
  2631.     } else
  2632.      /* Or else look it up below. */ if (isupper(c))
  2633.         c = tolower(c);
  2634.  
  2635.     switch (c) {
  2636.  
  2637.     case 'c':        /* return to command mode */
  2638.     case '\03':
  2639.         active = 0;
  2640.         return;
  2641.  
  2642.     case 'h':        /* Hangup and return to command mode */
  2643.     case '\010':
  2644.         hangnow = 1;
  2645.         active = 0;
  2646.         strcpy(termessage, "Hangup.\n");
  2647.         return;
  2648.  
  2649.     case 'q':               /* Hangup and quit */
  2650.     case '\021':
  2651.         active = 0;
  2652.         hangnow = 1;
  2653.         quitnow = 1;
  2654.         strcpy(termessage, "Hangup and quit.\n");
  2655.         return;
  2656.  
  2657.     case '!':
  2658.             savescreen(&savedscreen);
  2659.             mi.cb = sizeof(mi);
  2660.             VioGetMode(&mi, 0);
  2661.             concooked();
  2662.             clearscreen(1, colorcmd);
  2663.             restorecursormode();
  2664.             puts("Enter EXIT to return to C-Kermit.");
  2665.         zshcmd("");
  2666.         conraw();
  2667.             connoi();
  2668.             VioSetMode(&mi, 0);
  2669.             setcursormode();
  2670.             restorescreen(&savedscreen);
  2671.         return;
  2672.  
  2673.     case 'b':        /* Send a BREAK signal */
  2674.     case '\02':
  2675.         ttsndb();
  2676.         return;
  2677.  
  2678.     case 'l':        /* Send a LONG BREAK signal */
  2679.     case '\014':
  2680.         ttsndlb();
  2681.         return;
  2682.  
  2683.     case '0':        /* Send a null */
  2684.         c = '\0';
  2685.         sendchar((char)c);
  2686.         return;
  2687.  
  2688.         case '\\':
  2689.             {
  2690.                 char kbuf[32];
  2691.         char *kbp = kbuf, *text = usertext + 2;
  2692.  
  2693.         *kbp++ = c;
  2694.  
  2695.                 strcpy(usertext, " \\");
  2696.                 strcpy(exittext,"Exit: ENTER");
  2697.                 helptext[0] = 0;
  2698.                 line25();
  2699.  
  2700.         while (((c = (coninc(0) & cmdmsk)) != '\r') && (c != '\n')) {
  2701.                   if ( c == '\b' ) {
  2702.                     if ( kbp > kbuf + 1 ) {
  2703.               *--kbp = 0;
  2704.                       *--text = 0;
  2705.                     }
  2706.                   } else if ( kbp - kbuf < sizeof(kbuf) - 2 ) {
  2707.             *kbp++ = c;
  2708.                     *text++ = c;
  2709.                     *text = 0;
  2710.                   }
  2711.                   line25();
  2712.                 }
  2713.  
  2714.         *kbp = 0; kbp = kbuf;
  2715.         c = xxesc(&kbp);    /* Interpret it */
  2716.  
  2717.         if (c >= 0) {
  2718.                 sendcharduplex((char)c);
  2719.             return;
  2720.         } else {        /* Invalid backslash code. */
  2721.             conoc(BEL);
  2722.             return;
  2723.         }
  2724.         }
  2725.             return;
  2726.  
  2727.     case SP:        /* Space, ignore */
  2728.         return;
  2729.  
  2730.     default:        /* Other */
  2731.         conoc(BEL);
  2732.         return;        /* Invalid esc arg, beep */
  2733.     }
  2734.     }
  2735. }
  2736.  
  2737. /* CHECKSCREENMODE  --  Make sure we are in a usable mode */
  2738. checkscreenmode() {
  2739.     VIOMODEINFO     m;
  2740.     VIOINTENSITY vi;
  2741.  
  2742.     vi.cb = sizeof(vi);
  2743.     vi.type = 2;
  2744.     vi.fs = 1;
  2745.     VioSetState(&vi, 0);
  2746.     
  2747.     m.cb = sizeof(m);
  2748.     assert(VioGetMode(&m, 0) == 0);
  2749.  
  2750.     if ( xsize != min(132, m.col) || ysize != min(60, m.row) - 1 ) {
  2751.       scrninitialised = 0;
  2752.       if ( paginginfo.buffer )
  2753.         free(paginginfo.buffer);
  2754.       paginginfo.buffer = NULL;
  2755.       if ( vt100screen.scrncpy )
  2756.         free(vt100screen.scrncpy);
  2757.       vt100screen.scrncpy = NULL;
  2758.       if ( commandscreen.scrncpy )
  2759.         free(commandscreen.scrncpy);
  2760.       commandscreen.scrncpy = NULL;
  2761.       if ( savedscreen.scrncpy )
  2762.         free(savedscreen.scrncpy);
  2763.       savedscreen.scrncpy = NULL;
  2764.     }
  2765.  
  2766.     xsize = min(132, m.col);
  2767.     ysize = min(60, m.row) - 1;
  2768.     marginbot = ysize;
  2769.  
  2770.     if ( !vt100screen.scrncpy )
  2771.       vt100screen.scrncpy = malloc(xsize * (ysize + 1) * 2);
  2772.     assert(vt100screen.scrncpy != NULL);
  2773.     if ( !commandscreen.scrncpy )
  2774.       commandscreen.scrncpy = malloc(xsize * (ysize + 1) * 2);
  2775.     assert(commandscreen.scrncpy != NULL);
  2776.     if ( !savedscreen.scrncpy )
  2777.       savedscreen.scrncpy = malloc(xsize * (ysize + 1) * 2);
  2778.     assert(savedscreen.scrncpy != NULL);
  2779. }
  2780.  
  2781. setcursormode() {
  2782.     VIOMODEINFO vmi;
  2783.     VIOCURSORINFO vci;
  2784.     int cell, bottom, top;
  2785.  
  2786.     vmi.cb = sizeof(vmi);
  2787.     VioGetMode(&vmi, 0);
  2788.     cell   = vmi.vres / vmi.row;
  2789.  
  2790.     VioGetCurType(&vci, 0);
  2791.     crsr_command = vci;
  2792.  
  2793.     vci.cEnd   = cell - 1;
  2794.     vci.yStart = (tt_cursor == 0) ? cell - 2 :
  2795.                  cell - 1 - (cell - 2) * tt_cursor / 2;
  2796.  
  2797.     VioSetCurType(&vci, 0);
  2798. }
  2799.  
  2800. restorecursormode() {
  2801.     VioSetCurType(&crsr_command, 0);
  2802. }
  2803.  
  2804. /* CONECT  --  Perform terminal connection  */
  2805. int
  2806. conect() {
  2807.     USHORT          len, x, y;
  2808.     int             c, cm;    /* c is a character, but must be signed
  2809.                  * integer to pass thru -1, which is the
  2810.                  * modem disconnection signal, and is
  2811.                  * different from the character 0377 */
  2812.     char            errmsg[50], *erp, ac, bc, ss[132];
  2813.  
  2814.     if (!network && speed < 0) {
  2815.     printf("Sorry, you must set speed first.\n");
  2816.     return (0);
  2817.     }
  2818.     twochartimes = network ? 1 : 22000L / speed;
  2819.  
  2820.     if ((escape < 0) || (escape > 0177)) {
  2821.     printf("Your escape character is not ASCII - %d\n", escape);
  2822.     return (0);
  2823.     }
  2824.     if (ttopen(ttname, &local, network ? -nettype : mdmtyp, 0) < 0) {
  2825.     erp = errmsg;
  2826.     sprintf(erp, "Sorry, can't open %s", ttname);
  2827.     perror(errmsg);
  2828.     return (0);
  2829.     }
  2830.  
  2831.     /* Condition console terminal and communication line */
  2832.     if (ttvt(speed, flow) < 0) {
  2833.     printf("Sorry, Can't condition communication line\n");
  2834.     return (0);
  2835.     }
  2836.  
  2837.     if (!network && carrier != CAR_OFF && (ttgmdm() & BM_DCD) == 0) {
  2838.         printf("No carrier detected.\n");
  2839.     return (0);
  2840.     }
  2841.  
  2842.     outshift = inshift = 0;        /* Initial shift state. */
  2843.  
  2844.     tcs = TC_1LATIN;
  2845.     langsv = language;
  2846.     language = L_USASCII;
  2847.  
  2848.     if (tcsr == tcsl) {            /* Remote and local sets the same? */
  2849.     sxo = rxo = NULL;        /* If so, no translation. */
  2850.     sxi = rxi = NULL;
  2851.     } else {                /* Otherwise, set up */
  2852.     sxo = xls[tcs][tcsl];        /* translation function */
  2853.     rxo = xlr[tcs][tcsr];        /* pointers for output functions */
  2854.     sxi = xls[tcs][tcsr];        /* and for input functions. */
  2855.     rxi = xlr[tcs][tcsl];
  2856.     }
  2857.  
  2858.     iskipesc = oskipesc = (tcs != TC_TRANSP) &&    /* Not transparent */
  2859.       (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
  2860.     (fcsinfo[tcsl].code != FC_USASCII);
  2861.     inesc = outesc = ES_NORMAL;        /* Initial state of recognizer */
  2862.  
  2863.     checkscreenmode();
  2864.     setcursormode();
  2865.     VioGetCurPos(&y, &x, 0);
  2866.     wherex = x + 1;
  2867.     wherey = y + 1;
  2868.     savescreen(&commandscreen);
  2869.     colorcmd = commandscreen.scrncpy[(x + y * xsize) * 2 + 1];
  2870.     scrninit();
  2871.     restorescreen(&vt100screen);
  2872.     conraw();
  2873.     connoi();
  2874.     ipadl25();
  2875.  
  2876.     /* Create a thread to read the comms line and write to the screen */
  2877.  
  2878.     active = 1;            /* So thread 2 doesn't end at once */
  2879.     quitnow = 0;
  2880.     hangnow = 0;
  2881.     termessage[0] = 0;
  2882. #ifdef __32BIT__
  2883.     DosOpenEventSem(NULL, &threadsem);
  2884.     DosResetEventSem(threadsem, &semcount);
  2885.     if (DosCreateThread(&threadid, (PFNTHREAD)rdserwrtscr, 0, 0, THRDSTKSIZ)) {
  2886.     printf("Sorry, can't create thread\n");
  2887.     return (0);
  2888.     }
  2889.     DosWaitEventSem(threadsem, -1L);
  2890. #else
  2891.     DosSemSet(&threadsem);    /* Thread 2 will clear this when it starts */
  2892.     if (DosCreateThread(rdserwrtscr, &threadid,
  2893.             (PBYTE)(stack + THRDSTKSIZ))) {
  2894.     printf("Sorry, can't create thread\n");
  2895.     return (0);
  2896.     }
  2897.     DosSemWait(&threadsem, -1L);/* Wait for thread to start */
  2898.     DosSemSet(&threadsem);    /* Thread 2 will clear this on termination */
  2899. #endif
  2900.  
  2901.     while (active) {        /* Read the keyboard and write to comms line */
  2902.     c = congks(2);
  2903.     if (!active)
  2904.       break;
  2905.     if (c == -1) {
  2906.       active = network || (carrier == CAR_OFF) || (ttgmdm() & BM_DCD) != 0;
  2907.       if (!active)
  2908.         strcpy(termessage, "Carrier lost.\n");
  2909.       continue;
  2910.     }
  2911.     cm = keymap[c];
  2912.     DosEnterCritSec();    /* Protect the run time library */
  2913.     if (cm == escape) {    /* Look for escape char */
  2914.         esc25(0);
  2915.         c = keymap[congks(0)];    /* Got esc, get its arg */
  2916.         if (c == '?') {
  2917.             esc25(1);
  2918.         c = helpconnect(0);
  2919.         }
  2920.         doesc(c);        /* And process it */
  2921.         ipadl25();
  2922.     } else {        /* Ordinary character */
  2923.         if (!keylock)
  2924.         vt100key(c);
  2925.     }
  2926.     DosExitCritSec();    /* Let other guy use run time library */
  2927.     }                /* while (active) */
  2928.  
  2929. #ifdef __32BIT__
  2930.     DosWaitThread(&threadid, 0);
  2931.     DosCloseEventSem(threadsem);
  2932. #else
  2933.     DosSemWait(&threadsem, -1L);/* Wait for other thread to terminate */
  2934. #endif
  2935.  
  2936.     language = langsv;        /* Restore language */
  2937.  
  2938.     concooked();
  2939.     savescreen(&vt100screen);
  2940.     restorescreen(&commandscreen);
  2941.     restorecursormode();
  2942.     if (termessage[0]!='\0') printf(termessage);
  2943.     if (hangnow) {
  2944. #ifndef NODIAL
  2945.       if (mdmhup() < 1)
  2946. #endif /* NODIAL */
  2947.     tthang();
  2948.     }
  2949.     if (quitnow) doexit(GOOD_EXIT,0);
  2950.     return (1);
  2951. }
  2952.