home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / win100.zip / win19f.c < prev    next >
C/C++ Source or Header  |  1991-10-20  |  33KB  |  1,387 lines

  1. /*
  2.  * Windows H19 Terminal Emulator Function Support Module
  3.  * 
  4.  * Written by William S. Hall
  5.  *          3665 Benton Street, #66
  6.  *          Santa Clara, CA 95051
  7.  */
  8.  
  9. #define NOKANJI
  10. #define NOATOM
  11. #define NOMINMAX
  12. #include <windows.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <limits.h>
  16. #include <ctype.h>
  17.  
  18. #include "winasc.h"
  19. #include "winh19.h"
  20. #include "win19d.h"
  21.  
  22. #if defined(KERMIT)
  23. #include "winkpf.h"
  24. extern krmState;
  25. #endif
  26.  
  27. /* ansi emulation manifests */
  28. #define MAX_PARAM_LIST    32
  29. #define BEGIN_ANSI_COMMAND    10
  30. #define ANSI_INDIGIT        11
  31. #define ANSI_ENDDIGIT        12
  32. #define ANSI_MODE        13
  33. #define ANSI_SET        14
  34. #define ANSI_MODE_INDIGIT    15
  35. #define ANSI_SET_INDIGIT    16
  36. #define ANSI_MODE_ENDDIGIT    17
  37. #define ANSI_SET_ENDDIGIT    18
  38.  
  39. /* ansi emulation local parameters */
  40. static int ParamListIndex;
  41. static int ANSIParam;
  42. static int ANSIParamList[MAX_PARAM_LIST + 1];
  43. static int NEAR InDigitTransition(BYTE ch, unsigned instate, unsigned endstate, 
  44.                     void (NEAR *action)(BYTE));
  45. static void NEAR PositionRow(BYTE y);
  46. static void NEAR PositionCol(BYTE x);
  47. static void NEAR SwitchActiveWindow(HWND hWnd);
  48. static void NEAR ProcessESCCommand(BYTE ch);
  49. static void NEAR MoveStatWindow(short height);
  50. static void NEAR ProcessBaudChange(int);
  51. static void NEAR IdentifyTerm(void);
  52. static void NEAR ReportCursorPosition(short line, short col);
  53. static BOOL NEAR DoKeyTranslation(unsigned message, WORD *wparam);
  54. static void NEAR DoANSICommand(int state, BYTE ch);
  55. static void NEAR ANSISetCommand(BYTE ch);
  56. static void NEAR ANSIModeCommand(BYTE ch);
  57. static void NEAR PlaceInList(int val);
  58. static void NEAR ANSICommand(BYTE ch);
  59. static void NEAR DoHeathCommand(int state, BYTE ch);
  60. static BOOL NEAR InNumpadSet(unsigned val);
  61. static WORD NEAR EditToNumpadShort(unsigned val);
  62. static WORD NEAR NumpadToEdit(unsigned val);
  63. static WORD NEAR EditToNumpadLong(unsigned val);
  64.  
  65. /* special key handler when off-line */
  66. void NEAR H19LocalKeyDown(WORD keycode)
  67. {
  68.  
  69.     switch (keycode) {
  70.     case VK_UP:
  71.         SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORUP,1L);
  72.         break;
  73.     case VK_DOWN:
  74.         SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORDOWN,1L);
  75.         break;
  76.     case VK_RIGHT:
  77.         SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORRIGHT,1L);
  78.         break;
  79.     case VK_LEFT:
  80.         SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORLEFT,1L);
  81.         break;
  82.     case VK_HOME:
  83.         CD.ICToggle = (CD.ICToggle ? FALSE : TRUE);
  84.         break;
  85.     case VK_END:
  86.         SendMessage(hWndActive, WH19_COMMAND, H19_INSERTLINE,1L);
  87.         break;
  88.     case VK_PRIOR:
  89.         SendMessage(hWndActive, WH19_COMMAND,H19_DELETECHAR,1L);
  90.         break;
  91.     case VK_NEXT:
  92.         SendMessage(hWndActive, WH19_COMMAND, H19_DELETELINE,1L);
  93.         break;
  94.     case VK_CLEAR:
  95.         SwitchActiveWindow(TW.hWnd);
  96.         SendMessage(hWndActive, WH19_COMMAND, H19_CURSORHOME,0L);
  97.         break;
  98.     case VK_F6:
  99.         if (GetKeyState(VK_SHIFT) & 0x8000)
  100.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRSCREEN,0L);
  101.         else
  102.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFSCREEN,0L);
  103.         break;
  104.  
  105.     }
  106. }
  107.  
  108. /* communications processor */
  109. BOOL NEAR DoMessage()
  110. {
  111.  
  112.     MSG msg;
  113.  
  114.     if (PeekMessage((LPMSG)&msg,NULL,0,0,PM_REMOVE)) {
  115.         if (msg.message == WM_QUIT)
  116.         exit((int)msg.wParam);
  117.     if (TranslateAccelerator(MW.hWnd,hAccel,(LPMSG)&msg) == 0) {
  118.         if (DoKeyTranslation(msg.message, &msg.wParam))
  119.                 TranslateMessage((LPMSG)&msg);
  120.             DispatchMessage((LPMSG)&msg);
  121.     }
  122.     return TRUE;
  123.     }
  124.     return FALSE;
  125. }
  126.  
  127. /* return TRUE if key is to be translated */
  128. static BOOL NEAR DoKeyTranslation(unsigned message, WORD *wparam)
  129. {
  130.  
  131.     register unsigned shiftstate, numstate;
  132.     int retval = TRUE;
  133.  
  134.     if ((message == WM_KEYDOWN) || (message == WM_KEYUP)) {
  135.     if (*wparam == VK_CANCEL)
  136.          return FALSE;
  137.  
  138.     if (*wparam == VK_BACK) {
  139.         if (GetKeyState(VK_CONTROL) & 0x8000)
  140.         return FALSE;
  141.         return TRUE;
  142.     }
  143.  
  144.         numstate = GetKeyState(VK_NUMLOCK);
  145.         shiftstate = (GetKeyState(VK_SHIFT) & 0x8000) >> 15;
  146.  
  147.     if (CD.ShiftedKeypad) {
  148.         if (numstate | shiftstate) {
  149.             if (InNumpadSet(*wparam))
  150.             *wparam = NumpadToEdit(*wparam);
  151.         else
  152.             *wparam = EditToNumpadLong(*wparam);
  153.         }        
  154.         else
  155.             *wparam = EditToNumpadShort(*wparam);
  156.     }
  157.     else {
  158.         if (!(numstate | shiftstate))
  159.             *wparam = EditToNumpadLong(*wparam);
  160.         else
  161.             *wparam = EditToNumpadShort(*wparam);
  162.     }
  163.     if (CD.AltKeypad)
  164.         if (InNumpadSet(*wparam))
  165.             retval = FALSE;
  166.     }
  167.     return retval;
  168. }
  169.  
  170. /* support modules for key translation */
  171. static BOOL NEAR InNumpadSet(unsigned val)
  172. {
  173.  
  174.     return(((val >= VK_NUMPAD0) && (val <= VK_NUMPAD9)) || (val == VK_DECIMAL));
  175.  
  176. }
  177.  
  178. static WORD NEAR NumpadToEdit(unsigned val)
  179. {
  180.  
  181.     switch (val) {
  182.     case VK_NUMPAD1:
  183.         val = VK_END;
  184.         break;
  185.     case VK_NUMPAD2:
  186.         val = VK_DOWN;
  187.         break;
  188.     case VK_NUMPAD3:
  189.         val = VK_NEXT;
  190.         break;
  191.     case VK_NUMPAD4:
  192.         val = VK_LEFT;
  193.         break;
  194.     case VK_NUMPAD5:
  195.         val = VK_CLEAR;
  196.         break;
  197.     case VK_NUMPAD6:
  198.         val = VK_RIGHT;
  199.         break;
  200.     case VK_NUMPAD7:
  201.         val = VK_HOME;
  202.         break;
  203.     case VK_NUMPAD8:
  204.         val = VK_UP;
  205.         break;
  206.     case VK_NUMPAD9:
  207.         val = VK_PRIOR;
  208.         break;
  209.     }
  210.     return val;
  211. }
  212.  
  213. static WORD NEAR EditToNumpadShort(unsigned val)
  214. {
  215.     switch (val) {
  216.     case VK_DELETE:
  217.         val = VK_DECIMAL;
  218.         break;
  219.     case VK_INSERT:
  220.         val = VK_NUMPAD0;
  221.         break;
  222.     }
  223.     return val;
  224. }
  225.  
  226. static WORD NEAR EditToNumpadLong(unsigned val)
  227. {
  228.  
  229.     switch (val) {
  230.     case VK_DELETE:
  231.         val = VK_DECIMAL;
  232.         break;
  233.     case VK_INSERT:
  234.         val = VK_NUMPAD0;
  235.         break;
  236.     case VK_END:
  237.         val = VK_NUMPAD1;
  238.         break;
  239.     case VK_DOWN:
  240.         val = VK_NUMPAD2;
  241.         break;
  242.     case VK_NEXT:
  243.         val = VK_NUMPAD3;
  244.         break;
  245.     case VK_LEFT:
  246.         val = VK_NUMPAD4;
  247.         break;
  248.     case VK_CLEAR:
  249.         val = VK_NUMPAD5;
  250.         break;
  251.     case VK_RIGHT:
  252.         val = VK_NUMPAD6;
  253.         break;
  254.     case VK_HOME:
  255.         val = VK_NUMPAD7;
  256.         break;
  257.     case VK_UP:
  258.         val = VK_NUMPAD8;
  259.         break;
  260.     case VK_PRIOR:
  261.         val = VK_NUMPAD9;
  262.         break;
  263.     }
  264.     return val;
  265. }
  266.  
  267. /* process string from comm port */
  268. int NEAR H19StringInput(BYTE *str, short len)
  269. {
  270.  
  271.     register BYTE *ptr;
  272.     register short ctr;
  273.     short state;
  274.     BYTE ch;
  275.     int numrem;
  276.  
  277.     while (len) {
  278.     if (state = CD.CommandState) {
  279.         ch = *str & 0x7f;
  280.         if (CD.ANSIMode)
  281.         DoANSICommand(state, ch);
  282.         else
  283.         DoHeathCommand(state, ch);
  284.         str++;
  285.         len -= 1;
  286.     }
  287.     else {
  288.         ctr = 0;
  289.         ptr = str;
  290.         while (len) {
  291.             if ((*ptr &= 0x7f) != ESC) {
  292.             ctr += 1;
  293.             ptr++;
  294.             len -= 1;
  295.         }
  296.         else {
  297.             ptr++;
  298.             len -= 1;
  299.             CD.CommandState = ESC_COMMAND;
  300.             break;
  301.         }
  302.         }
  303.         if (ctr) {
  304.             numrem = (int)SendMessage(hWndActive,WH19_STRINGINPUT,(WORD)ctr,
  305.                     (LONG)(LPSTR)str);
  306.             if (numrem)
  307.             return(len + numrem);        
  308.         }
  309.         str = ptr;
  310.     }
  311.     }
  312.     return (len);
  313. }
  314.  
  315. /* start ansi processing */
  316. static void NEAR DoANSICommand(int state, BYTE ch)
  317. {
  318.  
  319.     register int newstate;
  320.  
  321.     if (ch == CAN)
  322.     newstate = NO_COMMAND;
  323.     else if (ch == ESC)
  324.     newstate = ESC_COMMAND;
  325.     else {
  326.         switch(state) {
  327.         case ESC_COMMAND:
  328.         switch (ch) {
  329.             case '[':
  330.             ParamListIndex = 0;
  331.             ANSIParam = 0;
  332.             ANSIParamList[0] = 0;
  333.             newstate = BEGIN_ANSI_COMMAND;
  334.             break;
  335.             case 'M':
  336.             SendMessage(hWndActive, WH19_COMMAND,
  337.                      H19_REVERSELINEFEED,0L);
  338.             newstate = NO_COMMAND;
  339.             break;
  340.             case '=' :        /* enter alternate keypad */
  341.             CD.AltKeypad = TRUE;
  342.             newstate = NO_COMMAND;
  343.             break;
  344.             case '>' :        /* exit alternate keypad */
  345.             CD.AltKeypad = FALSE;
  346.             newstate = NO_COMMAND;
  347.             break;
  348.             default:
  349.             newstate = NO_COMMAND;
  350.             break;
  351.         }
  352.         break;
  353.  
  354.         case BEGIN_ANSI_COMMAND:
  355.         switch(ch) {
  356.             case '?':
  357.             newstate = ANSI_MODE;
  358.             break;
  359.             case '>':
  360.             newstate = ANSI_SET;
  361.             break;
  362.             default:
  363.             newstate = InDigitTransition(ch, ANSI_INDIGIT,
  364.                     ANSI_ENDDIGIT, ANSICommand);
  365.             break;
  366.         }
  367.         break;
  368.  
  369.         case ANSI_INDIGIT:
  370.         case ANSI_ENDDIGIT:
  371.             newstate = InDigitTransition(ch, ANSI_INDIGIT,
  372.                 ANSI_ENDDIGIT, ANSICommand);
  373.         break;    
  374.  
  375.         case ANSI_MODE:
  376.         case ANSI_MODE_INDIGIT:
  377.         case ANSI_MODE_ENDDIGIT:
  378.         newstate = InDigitTransition(ch, ANSI_MODE_INDIGIT, 
  379.                 ANSI_MODE_ENDDIGIT,ANSIModeCommand);
  380.         break;
  381.  
  382.         case ANSI_SET:
  383.         case ANSI_SET_INDIGIT:
  384.         case ANSI_SET_ENDDIGIT:
  385.         newstate = InDigitTransition(ch, ANSI_SET_INDIGIT, 
  386.                 ANSI_SET_ENDDIGIT,ANSISetCommand);
  387.         break;
  388.     }
  389.     }
  390.     CD.CommandState = newstate;
  391. }
  392.  
  393. /* support modules for ansi emulation */
  394. static int NEAR InDigitTransition(BYTE ch, unsigned instate, unsigned endstate, 
  395.                     void (NEAR *action)(BYTE))
  396. {
  397.     register int state;
  398.  
  399.     if (isdigit(ch)) {
  400.         ANSIParam = 10 * ANSIParam + ch - '0';
  401.     state = instate;
  402.     }
  403.     else if (ch == ';') {
  404.         PlaceInList(ANSIParam);
  405.     state = endstate;
  406.     }
  407.     else {
  408.         PlaceInList(ANSIParam);
  409.     (*action)(ch);
  410.     state = NO_COMMAND;
  411.     }
  412.     return state;
  413. }
  414.  
  415. static void NEAR ANSISetCommand(BYTE ch)
  416. {
  417.  
  418.     register int i;
  419.  
  420.     if (ch == 'h')
  421.     for (i = 0; i < ParamListIndex; i++)
  422.         ProcessSetCommand(ANSIParamList[i]);
  423.     else if (ch == 'l')
  424.     for (i = 0; i < ParamListIndex; i++)
  425.         ProcessResetCommand(ANSIParamList[i]);
  426.  
  427. }
  428.  
  429. static void NEAR ANSIModeCommand(BYTE ch)
  430. {
  431.  
  432.     register int i;
  433.     
  434.     if (ch == 'h') {
  435.     for (i = 0; i < ParamListIndex; i++) {
  436.         switch (ANSIParamList[i]) {
  437.             case 2:
  438.             CD.ANSIMode = FALSE;
  439.             return;
  440.             case 7:
  441.                 CD.WrapAround = TRUE;
  442.             break;
  443.         }
  444.     }
  445.     }
  446.     else if (ch == 'l') {
  447.     for (i = 0; i < ParamListIndex; i++) {
  448.         switch (ANSIParamList[i]) {
  449.             case 7:
  450.                 CD.WrapAround = FALSE;
  451.                 break;
  452.         }
  453.         }
  454.     }
  455. }
  456.  
  457. static void NEAR PlaceInList(int val)
  458. {
  459.  
  460.     if (ParamListIndex < MAX_PARAM_LIST)
  461.     ANSIParamList[ParamListIndex++] = val;
  462.     ANSIParam = 0;
  463.  
  464. }
  465.  
  466. static void NEAR ANSICommand(BYTE ch)
  467. {
  468.  
  469.     register int val1 = ANSIParamList[0]; 
  470.     register int val2 = ANSIParamList[1];
  471.     int i;
  472.     
  473.     switch(ch) {
  474.     case 'A' :        /* move cursor up */
  475.         if (val1 == 0)
  476.         val1 = 1;
  477.         SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORUP,(LONG)val1);
  478.         break;
  479.     case 'B' :        /* move cursor down */
  480.         if (val1 == 0)
  481.         val1 = 1;
  482.         SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORDOWN,(LONG)val1);
  483.         break;
  484.     case 'C' :
  485.         if (val1 == 0)
  486.         val1 = 1;
  487.             SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORRIGHT,(LONG)val1);
  488.         break;
  489.     case 'D' :
  490.         if (val1 == 0)
  491.         val1 = 1;
  492.         SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORLEFT,(LONG)val1);
  493.         break;
  494.     case 'f':
  495.     case 'H':
  496.         switch(ParamListIndex) {
  497.         case 0:
  498.             PositionRow(0);
  499.             PositionCol(0);
  500.             break;
  501.         case 1:
  502.             if (val1 == 0)
  503.             val1 = 1;
  504.             PositionRow(LOBYTE(val1 - 1));
  505.             PositionCol(0);
  506.             break;
  507.         default:
  508.             if (val1 == 0)
  509.             val1 = 1;
  510.             if (val2 == 0)
  511.             val2 = 1;
  512.             PositionRow(LOBYTE(val1 - 1));
  513.             PositionCol(LOBYTE(val2 - 1));
  514.             break;
  515.         }
  516.         break;
  517.     case 'J':
  518.         if (ParamListIndex == 0)
  519.         SendMessage(hWndActive,WH19_COMMAND,H19_CLRTOENDOFSCREEN,0L);
  520.         else {
  521.             switch(val1) {
  522.             case 0:
  523.                 SendMessage(hWndActive,WH19_COMMAND,H19_CLRTOENDOFSCREEN,0L);
  524.             break;
  525.             case 1:
  526.                 SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOTOPOFSCREEN,0L);
  527.                 break;
  528.             case 2:
  529.             SendMessage(hWndActive, WH19_COMMAND, H19_CLRSCREEN,0L);
  530.             break;
  531.         }
  532.         }
  533.         break;
  534.     case 'K':
  535.         if (ParamListIndex == 0)
  536.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFLINE,0L);
  537.         else {
  538.             switch(val1) {
  539.             case 0:
  540.                 SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFLINE,0L);
  541.             break;
  542.             case 1:
  543.                 SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOSTARTOFLINE,0L);
  544.             break;
  545.             case 2:
  546.             SendMessage(hWndActive, WH19_COMMAND, H19_ERASELINE,0L);
  547.             break;
  548.         }
  549.         }
  550.         break;
  551.     case 'L' :        /* insert line */
  552.         if (val1 == 0)
  553.         val1 = 1;
  554.         SendMessage(hWndActive, WH19_COMMAND, H19_INSERTLINE,(LONG)val1);
  555.         break;
  556.     case 'M' :        /* delete line */
  557.         if (val1 == 0)
  558.         val1 = 1;
  559.         SendMessage(hWndActive, WH19_COMMAND, H19_DELETELINE,(LONG)val1);
  560.         break;
  561.  
  562.     case 'P' :        /* delete char */
  563.         if (val1 == 0)
  564.         val1 = 1;
  565.         SendMessage(hWndActive, WH19_COMMAND,H19_DELETECHAR,(LONG)val1);
  566.         break;
  567.     case 'h' :
  568.         for (i = 0; i < ParamListIndex; i++) {
  569.             switch (ANSIParamList[i]) {
  570.             case 2:
  571.                 CD.KeyboardDisabled = TRUE;
  572.                 break;
  573.             case 4:
  574.                 CD.ICToggle = TRUE;
  575.                 break;
  576.             case 20:
  577.                 CD.CRonLF = TRUE;
  578.                 break;
  579.         }
  580.         }
  581.         break;
  582.     case 'l' :
  583.         for (i = 0; i < ParamListIndex; i++) {
  584.             switch (ANSIParamList[i]) {
  585.             case 2:
  586.                 CD.KeyboardDisabled = FALSE;
  587.                 break;
  588.             case 4:
  589.                 CD.ICToggle = FALSE;
  590.                 break;
  591.             case 20:
  592.                 CD.CRonLF = FALSE;
  593.                 break;
  594.         }
  595.         }
  596.         break;
  597.     case 'm':
  598.         for (i = 0; i < ParamListIndex; i++) {
  599.             switch (ANSIParamList[i]) {
  600.             case 0:
  601.                 CD.InverseVideo = FALSE;
  602.                 CD.CharAttribute = 0;
  603.                 break;
  604.             case 7:
  605.                 CD.InverseVideo = TRUE;
  606.                 CD.CharAttribute = 0x80;
  607.                 break;
  608.             case 10:
  609.                 CD.GraphicsMode = TRUE;
  610.                 break;
  611.             case 11:
  612.                 CD.GraphicsMode = FALSE;
  613.                 break;
  614.         }
  615.         }
  616.         break;
  617.     case 'n' :
  618.         switch(val1) {
  619.         case 6:
  620.             if (CD.LineState == IDM_ONLINE) {
  621.             short currow, curcol;
  622.             SendMessage(hWndActive, WH19_CURSORPOSITION,
  623.                     H19_GETCURSOR,MAKELONG(&currow, &curcol));
  624.             ReportCursorPosition(currow,curcol);
  625.             }
  626.         }
  627.         break;
  628.     case 'p':
  629.         SendScreen(&TW);
  630.         break;
  631.     case 'q':
  632.         SendStatusLine(&SW);
  633.         break;
  634.     case 'r':
  635.         ProcessBaudChange(val1 - 1);
  636.         break;
  637.     case 's' :
  638.         SendMessage(hWndActive, WH19_CURSORPOSITION,H19_SAVECURSOR, 0L);
  639.         break;
  640.     case 'u' :
  641.         PositionRow((BYTE)CD.CurSaveRow);
  642.         PositionCol((BYTE)CD.CurSaveCol);
  643.         break;
  644.     case 'z':
  645.         ResetTerminal();
  646.         break;
  647.     }
  648. }
  649.  
  650. /* Heath emulation modules */
  651. static void NEAR DoHeathCommand(int state, BYTE ch)
  652. {
  653.  
  654.     if (ch == CAN)
  655.     CD.CommandState = NO_COMMAND;
  656.     else if (ch == ESC)
  657.     CD.CommandState = ESC_COMMAND;
  658.     else {
  659.         switch(state) {
  660.             case ESC_COMMAND:
  661.         ProcessESCCommand(ch);
  662.         break;
  663.         case YPOS_COMMAND:
  664.         PositionRow((BYTE)(ch - SP));
  665.         break;
  666.         case XPOS_COMMAND:
  667.         PositionCol((BYTE)(ch - SP));
  668.         break;
  669.         case SET_COMMAND:
  670.         ProcessSetCommand((int)(ch - '0'));
  671.         break;
  672.         case RESET_COMMAND:
  673.         ProcessResetCommand((int)(ch - '0'));
  674.         break;
  675.         case SETBAUD_COMMAND:
  676.         ProcessBaudChange((int)(ch - 'A'));
  677.         break;
  678.     }
  679.     }
  680. }
  681.  
  682. static void NEAR PositionRow(BYTE y)
  683. {
  684.  
  685.     register short maxlines = TW.MaxLines;
  686.  
  687.     CD.CommandState = XPOS_COMMAND;
  688.  
  689.     if ((y >= 0) && (y < (BYTE)maxlines)) {
  690.     SwitchActiveWindow(TW.hWnd);
  691.     SendMessage(TW.hWnd,WH19_COMMAND,H19_POSITIONCURSORROW,(LONG)y);
  692.     }
  693.     else if (y == (BYTE)maxlines)
  694.     if (CD.StatOpen)
  695.         SwitchActiveWindow(SW.hWnd);
  696.  
  697. }
  698.  
  699. static void NEAR PositionCol(BYTE x)
  700. {
  701.  
  702.     register short cols = TW.MaxCols;
  703.  
  704.     CD.CommandState = NO_COMMAND;
  705.  
  706.     if ((x < 0) || (x >= (BYTE)cols))
  707.     x = (BYTE)(cols - 1);
  708.  
  709.     SendMessage(hWndActive, WH19_COMMAND, H19_POSITIONCURSORCOL, (LONG)x);
  710.  
  711. }
  712.  
  713. static void NEAR SwitchActiveWindow(HWND hWnd)
  714. {
  715.  
  716.     if (hWndActive != hWnd) {
  717.     SendMessage(hWndActive, WH19_CARETFUNCTION, H19_DESTROYCARET, 
  718.             (LONG)CD.OwnCaret);
  719.     hWndActive = hWnd;
  720.     SendMessage(hWndActive, WH19_CARETFUNCTION, H19_CREATECARET,
  721.             (LONG)CD.OwnCaret);
  722.     }    
  723. }
  724.  
  725. void ProcessSetCommand(int ch)
  726. {
  727.  
  728.     CD.CommandState = NO_COMMAND;
  729.  
  730.     switch(ch) {
  731.     case 1 :        /* enable status line */
  732.         if (!CD.StatOpen) {
  733.         CD.StatOpen = TRUE;
  734.         memset(SW.pVidBuffer, SP, TW.MaxCols);
  735.                 MoveStatWindow(MW.Height);
  736.         InvalidateRect(SW.hWnd, (LPRECT)NULL, TRUE);
  737.         UpdateWindow(SW.hWnd);
  738.         if (hWndActive == SW.hWnd)
  739.             SendMessage(hWndActive,WH19_CARETFUNCTION,H19_SHOWCARET,0L);
  740.         SendMessage(hWndActive, WH19_COMMAND, H19_ADJUSTWINDOW,0L);
  741.         }
  742.         break;
  743.  
  744.     case 2 :        /* no key click */
  745.         CD.KeyClick = FALSE;
  746.         break;
  747.  
  748.     case 3 :        /* hold screen mode */
  749.         CD.HoldScreen = TRUE;
  750.         break;
  751.  
  752.     case 4 :        /* block cursor */
  753.         if (!CD.BlockCursor) {
  754.         CD.BlockCursor = TRUE;
  755.             SendMessage(hWndActive,WH19_CARETFUNCTION,H19_DESTROYCARET,
  756.                 (LONG)CD.OwnCaret);
  757.             SendMessage(hWndActive,WH19_CARETFUNCTION,H19_CREATECARET,
  758.                 (LONG)CD.OwnCaret);
  759.         }
  760.         break;
  761.  
  762.     case 5 :        /* cursor off */
  763.         SendMessage(hWndActive,WH19_CARETFUNCTION,H19_HIDECARET,0L);
  764.         CD.CursorOff = TRUE;
  765.         break;
  766.  
  767.     case 6 :        /* keypad shifted */
  768.         CD.ShiftedKeypad = TRUE;
  769.         break;
  770.  
  771.     case 7 :        /* alternate keypad */
  772.         CD.AltKeypad = TRUE;
  773.         break;        
  774.  
  775.     case 8 :        /* auto lf on cr */
  776.         CD.LFonCR = TRUE;
  777.         break;
  778.  
  779.     case 9 :        /* auto cr on lf */
  780.         CD.CRonLF = TRUE;    
  781.         break;
  782.     }
  783. }
  784.  
  785. void ProcessResetCommand(int ch)
  786. {
  787.  
  788.     CD.CommandState = NO_COMMAND;
  789.  
  790.     switch(ch) {
  791.     case 1 :
  792.         if (CD.StatOpen) {
  793.         CD.StatOpen = FALSE;
  794.         memset(SW.pVidBuffer, SP, TW.MaxCols);
  795.             InvalidateRect(SW.hWnd, (LPRECT)NULL, TRUE);
  796.         UpdateWindow(SW.hWnd);
  797.                 MoveStatWindow(MW.Height);
  798.         if (hWndActive == SW.hWnd)
  799.             SendMessage(hWndActive,WH19_CARETFUNCTION,H19_HIDECARET,0L);
  800.         }
  801.         break;
  802.  
  803.     case 2 :        /* enable key click */
  804.         CD.KeyClick = TRUE;
  805.         break;
  806.  
  807.     case 3 :        /* exit hold screen mode */
  808.         CD.HoldScreen = FALSE;
  809.         break;
  810.  
  811.     case 4 :
  812.         if (CD.BlockCursor) {
  813.         CD.BlockCursor = FALSE;
  814.             SendMessage(hWndActive, WH19_CARETFUNCTION,H19_DESTROYCARET, 
  815.                 (LONG)CD.OwnCaret);
  816.             SendMessage(hWndActive, WH19_CARETFUNCTION,H19_CREATECARET,
  817.                 (LONG)CD.OwnCaret);
  818.         }
  819.         break;
  820.  
  821.     case 5 :        /* cursor on */
  822.         CD.CursorOff = FALSE;
  823.         SendMessage(hWndActive,WH19_CARETFUNCTION,H19_SHOWCARET,0L);
  824.         break;
  825.  
  826.     case 6 :        /* keypad unshifted */
  827.         CD.ShiftedKeypad = FALSE;
  828.         break;
  829.  
  830.     case 7 :        /* exit alternate keypad */
  831.         CD.AltKeypad = FALSE;
  832.         break;
  833.         
  834.     case 8 :        /* no auto lf on cr */
  835.         CD.LFonCR = FALSE;
  836.         break;
  837.  
  838.     case 9 :        /* no auto cr on lf */
  839.         CD.CRonLF = FALSE;
  840.         break;
  841.     }
  842. }
  843.  
  844. static void NEAR ProcessESCCommand(BYTE ch)
  845. {
  846.  
  847.     CD.CommandState = NO_COMMAND;
  848.  
  849.     switch(ch) {
  850.     case '#' :        /* transmit page */
  851.         SendScreen(&TW);
  852.         break;
  853.  
  854.     case '<' :        /* enter ansi mode */
  855.         CD.ANSIMode = TRUE;
  856.         break;
  857.  
  858.     case '=' :        /* enter alternate keypad */
  859.         CD.AltKeypad = TRUE;
  860.         break;
  861.  
  862.     case '>' :        /* exit alternate keypad */
  863.         CD.AltKeypad = FALSE;
  864.         break;
  865.  
  866.     case '@' :        /* enter insert char mode */
  867.         CD.ICToggle = TRUE;
  868.         break;
  869.  
  870.     case 'A' :        /* move cursor up */
  871.         SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORUP,1L);
  872.         break;
  873.  
  874.     case 'B' :        /* move cursor down */
  875.         SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORDOWN,1L);
  876.         break;
  877.  
  878.     case 'C' :        /* move cursor right */
  879.         SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORRIGHT,1L);
  880.         break;
  881.  
  882.     case 'D' :        /* move curosr left */
  883.         SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORLEFT,1L);
  884.         break;
  885.  
  886.     case 'E' :        /* home and clear */
  887.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRSCREEN,0L);
  888.         break;
  889.  
  890.     case 'F' :        /* enter graphics mode */
  891.         CD.GraphicsMode = TRUE;
  892.         break;
  893.  
  894.     case 'G' :        /* exit graphics mode */
  895.         CD.GraphicsMode = FALSE;
  896.         break;
  897.  
  898.     case 'H' :        /* home cursor */
  899.         SwitchActiveWindow(TW.hWnd);
  900.         SendMessage(hWndActive, WH19_COMMAND, H19_CURSORHOME,0L);
  901.         break;
  902.  
  903.     case 'I' :        /* reverse line feed */
  904.         SendMessage(hWndActive, WH19_COMMAND, H19_REVERSELINEFEED,0L);
  905.         break;
  906.     
  907.     case 'J' :        /* clear to end of screen */
  908.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFSCREEN,0L);
  909.         break;
  910.  
  911.     case 'K' :        /* clear to end of line */
  912.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFLINE,0L);
  913.         break;
  914.         
  915.     case 'L' :        /* insert line */
  916.         SendMessage(hWndActive, WH19_COMMAND, H19_INSERTLINE,1L);
  917.         break;
  918.  
  919.     case 'M' :        /* delete line */
  920.         SendMessage(hWndActive, WH19_COMMAND, H19_DELETELINE,1L);
  921.         break;
  922.  
  923.     case 'N' :        /* delete char */
  924.         SendMessage(hWndActive, WH19_COMMAND,H19_DELETECHAR,1L);
  925.         break;
  926.  
  927.     case 'O' :        /* exit insert char mode */
  928.         CD.ICToggle = FALSE;
  929.         break;
  930.  
  931.     case 'Y' :        /* position cursor */
  932.         CD.CommandState = YPOS_COMMAND;
  933.         break;
  934.  
  935.     case 'Z' :        /* identify as VT52 */
  936.         if (CD.LineState == IDM_ONLINE)
  937.             IdentifyTerm();    
  938.         break;
  939.  
  940.     case '[' :        /* enter hold screen mode */
  941.         CD.HoldScreen = TRUE;
  942.         break;
  943.  
  944.     case '\\' :        /* exit hold screen mode */
  945.         CD.HoldScreen = FALSE;
  946.         break;
  947.  
  948.     case ']' :        /* transmit status line */
  949.         SendStatusLine(&SW);
  950.         break;
  951.         
  952.     case 'b' :        /* clear to screen top */
  953.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOTOPOFSCREEN,0L);
  954.         break;
  955.  
  956.     case 'j' :        /* save cursor position */
  957.         SendMessage(hWndActive, WH19_CURSORPOSITION,H19_SAVECURSOR, 0L);
  958.         break;
  959.  
  960.     case 'k' :        /* set to saved position */
  961.         PositionRow((BYTE)CD.CurSaveRow);
  962.         PositionCol((BYTE)CD.CurSaveCol);
  963.         break;
  964.  
  965.     case 'l' :        /* erase entire line */
  966.         SendMessage(hWndActive, WH19_COMMAND, H19_ERASELINE,0L);
  967.         break;
  968.  
  969.     case 'n' :        /* report cursor position */
  970.         if (CD.LineState == IDM_ONLINE) {
  971.         short currow, curcol;
  972.             SendMessage(hWndActive, WH19_CURSORPOSITION,H19_GETCURSOR,
  973.                 MAKELONG(&currow, &curcol));
  974.         ReportCursorPosition(currow,curcol);
  975.         }
  976.         break;
  977.  
  978.     case 'o' :        /* clear to start of line */
  979.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOSTARTOFLINE,0L);
  980.         break;
  981.         
  982.     case 'p' :        /* enter inverse video */
  983.         CD.InverseVideo = TRUE;
  984.         CD.CharAttribute = 0x80;
  985.         break;
  986.  
  987.     case 'q' :        /* exit inverse video */
  988.         CD.CharAttribute = 0;
  989.         CD.InverseVideo = FALSE;
  990.         break;
  991.  
  992.     case 'r' :        /* set baud rate */
  993.         CD.CommandState = SETBAUD_COMMAND;
  994.         break;
  995.  
  996.     case 't' :        /* enter shifted keypad */
  997.         CD.ShiftedKeypad = TRUE;
  998.         break;
  999.  
  1000.     case 'u' :        /* exit shifted keypad */
  1001.         CD.ShiftedKeypad = FALSE;
  1002.         break;
  1003.  
  1004.     case 'v' :        /* set wraparound */
  1005.         CD.WrapAround = TRUE;
  1006.         break;
  1007.  
  1008.     case 'w':        /* no wrap */
  1009.         CD.WrapAround = FALSE;
  1010.         break;
  1011.  
  1012.     case 'x' :        /* set command */
  1013.         CD.CommandState = SET_COMMAND;
  1014.         break;
  1015.  
  1016.     case 'y' :        /* reset command */
  1017.         CD.CommandState = RESET_COMMAND;
  1018.         break;    
  1019.  
  1020.     case 'z' :        /* reset to power up conditions */
  1021.         ResetTerminal();
  1022.         break;
  1023.  
  1024.     case '}' :        /* disable keyboard */
  1025.         CD.KeyboardDisabled = TRUE;
  1026.         break;
  1027.  
  1028.     case '{' :        /* enable keyboard */
  1029.         CD.KeyboardDisabled = FALSE;
  1030.         break;
  1031.     }
  1032. }
  1033.  
  1034. /* paint command */
  1035. void NEAR MainWndPaint(hWnd, hDC)
  1036. HWND hWnd;
  1037. HDC hDC;
  1038. {
  1039.     register BOOL iconic = IsIconic(hWnd);
  1040.     char *ptr;
  1041.     RECT prect;
  1042.  
  1043. #if defined(KERMIT)
  1044.     if (krmState)
  1045.         krmShowTransferData(hWnd, hDC, iconic);
  1046.     else
  1047. #endif
  1048.  
  1049.         if (iconic) {
  1050.         GetClientRect(hWnd, (LPRECT)&prect);
  1051.         ptr = szWinTitle;
  1052.         Rectangle(hDC,prect.left,prect.top,prect.right,prect.bottom);
  1053.         prect.top += 1;
  1054.         DrawText(hDC, (LPSTR)ptr,4,(LPRECT)&prect,
  1055.             DT_CENTER | DT_NOCLIP | DT_EXTERNALLEADING);
  1056.         prect.top = prect.bottom/2;
  1057.         ptr += strlen(szWinTitle) - 5;
  1058.         DrawText(hDC, (LPSTR)ptr,4,(LPRECT)&prect,
  1059.             DT_CENTER | DT_NOCLIP);
  1060.     }
  1061. }
  1062.  
  1063. /* called when a system key is activated */
  1064. long NEAR MainSysCommand(hWnd,message,wParam,lParam)
  1065. HWND hWnd;
  1066. unsigned message;
  1067. WORD wParam;
  1068. LONG lParam;
  1069. {
  1070.  
  1071.     FARPROC fp;
  1072.  
  1073.     switch (wParam) {
  1074.     case IDM_ABOUT:
  1075.         fp = MakeProcInstance((FARPROC)AboutBoxProc, hInst);
  1076.         DialogBox(hInst, MAKEINTRESOURCE(DT_ABOUT),hWnd,fp);
  1077.         FreeProcInstance(fp);
  1078.         return TRUE;
  1079.     default:
  1080.         return(DefWindowProc(hWnd,message,wParam,lParam));
  1081.     }
  1082.     return (0L);
  1083. }
  1084.  
  1085. /* window has been resized */
  1086. void NEAR SizeWindow(width, height, code)
  1087. WORD width;
  1088. WORD height;
  1089. WORD code;
  1090. {
  1091.  
  1092. #if defined(KERMIT)
  1093.     if (krmState)
  1094.     krmAdjustHeight((short)width, (short)height);
  1095. #endif
  1096.     
  1097.     switch (code) {
  1098.     case SIZEICONIC:
  1099.         break;
  1100.     default:
  1101.         MW.Height = height;
  1102.         MW.Width = width;
  1103.         MW.BottomTextLine = height / TW.CharHeight * TW.CharHeight - 
  1104.                     TW.CharHeight;
  1105.         MW.SCBottomTextLine = MW.SCTopTextLine + MW.BottomTextLine;
  1106.         if (IsWindow(hWndActive))
  1107.         SendMessage(hWndActive, WH19_CARETFUNCTION,H19_DESTROYCARET,
  1108.                 (LONG)CD.OwnCaret);
  1109.         if (IsWindow(TW.hWnd)) {
  1110.             MoveWindow(TW.hWnd,0,0,TW.Width,TW.Height,TRUE);
  1111.             if (IsWindow(SW.hWnd))
  1112.                 MoveStatWindow(MW.Height);
  1113.         }
  1114.         if (IsWindow(hWndActive))
  1115.         SendMessage(hWndActive, WH19_CARETFUNCTION,H19_CREATECARET,
  1116.                 (LONG)CD.OwnCaret);
  1117.         break;
  1118.     }
  1119. }
  1120.  
  1121. /* move status window */
  1122. static void NEAR MoveStatWindow(short height)
  1123. {
  1124.  
  1125.     register short statpos = TW.Height;
  1126.     register short statheight = TW.CharHeight;
  1127.  
  1128.     CD.StatOverlayTerm = FALSE;
  1129.  
  1130.     if ((statpos + statheight) > height) {
  1131.         if (CD.StatOpen) {
  1132.         statpos = MW.BottomTextLine;
  1133.         statheight = MW.Height - MW.BottomTextLine;
  1134.         CD.StatOverlayTerm = TRUE;
  1135.     }
  1136.     else {
  1137.         statpos = MW.BottomTextLine + TW.CharHeight;
  1138.         statheight = height - statpos;
  1139.     }
  1140.     }
  1141.     MoveWindow(SW.hWnd,0,statpos,TW.Width,statheight,TRUE);
  1142. }
  1143.  
  1144. /* menu handler */
  1145. void NEAR WndCommand(hWnd, wparam, lparam)
  1146. HWND hWnd;
  1147. WORD wparam;
  1148. LONG lparam;
  1149. {
  1150.  
  1151.     register HMENU hMenu = GetMenu(hWnd);
  1152.     HCURSOR hCurOld;
  1153.     FARPROC fp;
  1154.     
  1155.     switch (wparam) {
  1156.  
  1157.     case IDM_CLEARCOM:
  1158.         FlushComm(cid,0);
  1159.         FlushComm(cid,1);
  1160.         EscapeCommFunction(cid,SETXON);
  1161.         if (CD.LineState == IDM_ONLINE)
  1162.         TransmitCommChar(cid, XON);
  1163.         break;
  1164.  
  1165.     case IDM_RESET:
  1166.             ResetTerminal();
  1167.         break;
  1168.  
  1169.         case IDM_OFFLINE:
  1170.             SetWindowLong(MW.hWnd, GWL_WNDPROC, (LONG)MainWndSubclassProc);
  1171.         hCurOld = SetCursor(LoadCursor((HANDLE)NULL,IDC_WAIT));
  1172.         SendMessage(hWndActive, WH19_CARETFUNCTION, H19_HIDECARET, 0L);
  1173.         ChangeMenu(hMenu,IDM_OFFLINE,(LPSTR)szOnline,IDM_ONLINE,
  1174.                 MF_BYCOMMAND | MF_CHANGE);
  1175.         DrawMenuBar(hWnd);
  1176.         CD.LineState = IDM_ONLINE;
  1177.         SendMessage(hWndActive, WH19_CARETFUNCTION, H19_SHOWCARET, 0L);
  1178.         SetCursor(hCurOld);
  1179.         break;
  1180.     case IDM_ONLINE:
  1181.         SetWindowLong(MW.hWnd, GWL_WNDPROC, (LONG)fpTerminal);
  1182.         hCurOld = SetCursor(LoadCursor((HANDLE)NULL,IDC_WAIT));
  1183.         SendMessage(hWndActive, WH19_CARETFUNCTION, H19_HIDECARET, 0L);
  1184.         ChangeMenu(hMenu,IDM_ONLINE,(LPSTR)szOffline,IDM_OFFLINE,
  1185.                     MF_BYCOMMAND | MF_CHANGE);
  1186.         DrawMenuBar(hWnd);
  1187.         CD.LineState = IDM_OFFLINE;
  1188.         SendMessage(hWndActive, WH19_CARETFUNCTION, H19_SHOWCARET, 0L);
  1189.         SetCursor(hCurOld);
  1190.         break;
  1191.     case IDM_COMM:
  1192.         fp = MakeProcInstance((FARPROC)SetCommParams, hInst);
  1193.         DialogBox(hInst, MAKEINTRESOURCE(DT_COMM),hWnd,fp);
  1194.         FreeProcInstance(fp);
  1195.         break;
  1196.     case IDM_TERM:
  1197.         fp = MakeProcInstance((FARPROC)SetTermParams, hInst);
  1198.         DialogBox(hInst, MAKEINTRESOURCE(DT_TERM),hWnd,fp);
  1199.         FreeProcInstance(fp);
  1200.         break;
  1201.     case IDM_SPECIALKEYS:
  1202.         fp = MakeProcInstance((FARPROC)SetStringParams, hInst);
  1203.         DialogBox(hInst, MAKEINTRESOURCE(DT_STRING),hWnd,fp);
  1204.         FreeProcInstance(fp);
  1205.         break;
  1206.     case IDM_COPY:
  1207.         SendMessage(TW.hWnd, WH19_SLAPSCREEN, 0, 0L);
  1208.         break;                
  1209.     case IDM_PASTE:
  1210.         if (OpenClipboard(hWnd)) {
  1211.             LPSTR lpClip, lpDest;
  1212.         BYTE ch;
  1213.  
  1214.         hClipData = GetClipboardData(CF_TEXT);
  1215.         GB.lBufSize = GlobalSize(hClipData);
  1216.         if (GB.hBuf == NULL) {
  1217.                 GB.hBuf = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
  1218.                                 GB.lBufSize);
  1219.             if (GB.hBuf != NULL) {
  1220.                 GB.lBufHead = GB.lBufTail = 0;
  1221.                 lpClip = GlobalLock(hClipData);
  1222.                 lpDest = GlobalLock(GB.hBuf);                
  1223.                 while(ch = *lpClip++) {
  1224.                 if (ch != LF) {
  1225.                     *lpDest++ = ch;
  1226.                     GB.lBufTail += 1;
  1227.                 }
  1228.             }
  1229.             GlobalUnlock(hClipData);
  1230.             GlobalUnlock(GB.hBuf);
  1231.                 }
  1232.         }
  1233.          CloseClipboard();
  1234.         }
  1235.         break;
  1236. #if defined(KERMIT)
  1237.     default:
  1238.         krmProcessKermitMenu(hWnd, wparam);
  1239.         break;
  1240. #endif    
  1241.     }
  1242. }
  1243.  
  1244. /* communications processor */
  1245. void NEAR ProcessComm()
  1246. {
  1247.  
  1248.     COMSTAT ComStatus;
  1249.     int num;
  1250.     register int retresult = 0;
  1251.     register int result = 0;
  1252.     
  1253.     static char Buffer[RXQUESIZE];
  1254.     static int bufsize = 0;
  1255.  
  1256.     if ((CD.LineState == IDM_ONLINE) && !CD.ScrollLock) {
  1257.     if (bufsize == 0) {
  1258.             GetCommError(cid, (COMSTAT FAR *)&ComStatus);
  1259.             if (num = ComStatus.cbInQue) {
  1260.         num = min(num, BUFSIZE);
  1261.             if ((result = ReadComm(cid, (LPSTR)Buffer, num)) < 0) {
  1262.             result = -result;
  1263.             Buffer[result] = NUL;
  1264.         }
  1265.         }
  1266.     }
  1267.     else
  1268.         result = bufsize;
  1269.  
  1270. #if defined(KERMIT)
  1271.     if (krmState)
  1272.         krmKermitDispatch(MW.hWnd, Buffer, result);
  1273.         else 
  1274. #endif
  1275.  
  1276.     if (result) {
  1277.         retresult = H19StringInput(Buffer, result);
  1278.  
  1279.         if (retresult) {
  1280.         bufsize = retresult;
  1281.         memmove(Buffer, Buffer+result-retresult,retresult);
  1282.         Buffer[bufsize] = 0;
  1283.         }
  1284.         else
  1285.         bufsize = 0;
  1286.     }
  1287.     else if (GB.hBuf) {
  1288.         BYTE FAR *tbuf;
  1289.         LONG BufBytesRemaining;
  1290.         int count;
  1291.  
  1292.         BufBytesRemaining = GB.lBufTail - GB.lBufHead;
  1293.         if (BufBytesRemaining > 0) {
  1294.             tbuf = GlobalLock(GB.hBuf) + GB.lBufHead;
  1295.         if (BufBytesRemaining > INT_MAX)
  1296.             count = TW.MaxCols;
  1297.         else
  1298.             count = min(TW.MaxCols, (int)LOWORD(BufBytesRemaining));
  1299.         WriteToPort(cid, tbuf, count);
  1300.         GB.lBufHead += count;
  1301.         BufBytesRemaining = GB.lBufTail - GB.lBufHead;
  1302.             GlobalUnlock(GB.hBuf);
  1303.         }
  1304.         if (BufBytesRemaining <= 0) 
  1305.             GB.hBuf = GlobalFree(GB.hBuf);
  1306.     }        
  1307.     }
  1308. }
  1309.  
  1310. /* write to comm port */
  1311. void NEAR WriteToPort(cid, buf, len)
  1312. short cid;
  1313. BYTE FAR *buf;
  1314. int len;
  1315. {
  1316.  
  1317.     COMSTAT mystat;
  1318.     register int room;
  1319.  
  1320.     GetCommError(cid, (COMSTAT FAR *)&mystat);
  1321.     room = TXQUESIZE - mystat.cbOutQue;
  1322.     
  1323.     while (room < len) {
  1324.     if (!DoMessage()) {
  1325.             GetCommError(cid, (COMSTAT FAR *)&mystat);
  1326.         room = TXQUESIZE - mystat.cbOutQue;
  1327.     }
  1328.     }
  1329.     WriteComm(cid, (LPSTR)buf, len);
  1330. }
  1331.  
  1332. /* change baud rate */
  1333. static void NEAR ProcessBaudChange(int ch)
  1334. {
  1335.  
  1336.     WORD rate;
  1337.      
  1338.     CD.CommandState = NO_COMMAND;
  1339.  
  1340.     if ((ch >= 0) && (ch < BAUDTABLESIZE)) {
  1341.     CommData.BaudRate = rate = BaudRateTable[ch];
  1342.     CommData.StopBits = ONESTOPBIT;
  1343.     if (rate == 110)
  1344.         CommData.StopBits = TWOSTOPBITS;
  1345.     SetCommState((DCB FAR *)&CommData);
  1346.     }
  1347. }
  1348.  
  1349. /* report vt52 */
  1350. static void NEAR IdentifyTerm()
  1351. {
  1352.     BYTE outstr[5];
  1353.  
  1354.     outstr[0] = ESC;
  1355.     outstr[1] = '/';
  1356.     outstr[2] = 'K';
  1357.     
  1358.     WriteToPort(cid, (BYTE FAR *)outstr, 3);
  1359. }
  1360.  
  1361. /* report cursor position */
  1362. static void NEAR ReportCursorPosition(short line, short col)
  1363. {
  1364.  
  1365.     BYTE outstr[20];
  1366.     register BYTE *outstrptr = outstr;
  1367.  
  1368.     *outstrptr++ = ESC;
  1369.  
  1370.     if (CD.ANSIMode) {
  1371.     *outstrptr++ = '[';
  1372.     itoa(line+1, outstrptr,10);
  1373.     outstrptr += strlen(outstrptr);
  1374.     *outstrptr++ = ';';
  1375.     itoa(col+1, outstrptr,10);
  1376.     outstrptr += strlen(outstrptr);
  1377.     *outstrptr++ = 'R';
  1378.     }
  1379.     else {
  1380.         *outstrptr++ = 'Y';
  1381.         *outstrptr++ = (BYTE)(SP + line);
  1382.         *outstrptr++ = (BYTE)(SP + col);
  1383.     }
  1384.     *outstrptr = NUL;
  1385.     WriteToPort(cid, (BYTE FAR *)outstr, strlen(outstr));
  1386. }
  1387.