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

  1. /*
  2.  * Windows H19 Terminal Emulator
  3.  * 
  4.  * Written by William S. Hall
  5.  *          3665 Benton Street, #66
  6.  *          Santa Clara, CA 95051
  7.  *
  8.  * Terminal and status window module
  9.  */
  10.  
  11. #define NOKANJI
  12. #define NOATOM
  13. #include <string.h>
  14. #include <windows.h>
  15.  
  16. #include "winasc.h"
  17. #include "winh19.h"
  18. #include "win19d.h"
  19.  
  20. /* local functions */
  21. static void NEAR MoveCursorLeft(PTWND pTW, WORD count);
  22. static void NEAR MoveCursorRight(PTWND pTW, WORD count);
  23. static void NEAR SetScroll(void);
  24. static void NEAR MoveCursorUp(PTWND pTW, WORD count);
  25. static void NEAR MoveCursorDown(PTWND pTW, WORD count);
  26. static void NEAR PositionCursorRow(PTWND, short);
  27. static void NEAR PositionCursorCol(PTWND, short);
  28. static void NEAR CursorHome(PTWND);
  29. static void NEAR DeleteChar(PTWND, WORD);
  30. static void NEAR ClearStatusLine(PTWND);
  31. static void NEAR ClearTermWindow(PTWND);
  32. static void NEAR SlapScreenToClip(PTWND);
  33. static void NEAR SetAttrib(HDC, int);
  34. static void NEAR H19HideCaret(HWND hWnd);
  35. static void NEAR H19ShowCaret(HWND hWnd);
  36. static void NEAR SaveCursor(short line, short column);
  37. static void NEAR GetCursor(short lines, short cols, LONG lParam);
  38. static int NEAR H19TerminalDisplay(PTWND, BYTE *, short);
  39. static void NEAR DoCR(PTWND);
  40. static void NEAR DoBS(PTWND);
  41. static void NEAR MakeCaret(PTWND);
  42. static void NEAR DoHT(PTWND);
  43. static void NEAR ClearToEndOfLine(PTWND);
  44. static void NEAR ClearToEndOfScreen(PTWND);
  45. static void NEAR StatWndPaint(PTWND, LPPAINTSTRUCT);
  46. static void NEAR ClearToScreenTop(PTWND);
  47. static void NEAR ClearToLineStart(PTWND);
  48. static void NEAR EraseEntireLine(PTWND);
  49. static void NEAR TermWndPaint(PTWND, LPPAINTSTRUCT);
  50. static void NEAR AdjustWindowToCursor(PTWND);
  51. static void NEAR ShowLineOfText(HDC, short, short, BYTE *, short, short);
  52. static void NEAR InsertLine(PTWND, WORD);
  53. static void NEAR DeleteLine(PTWND, WORD);
  54. static void NEAR ReverseLF(PTWND);
  55. static void NEAR DoLF(PTWND);
  56.  
  57. /* status window proc */
  58. long FAR PASCAL StatWndProc(hWnd,message,wParam,lParam)
  59. HWND hWnd;
  60. unsigned message;
  61. WORD wParam;
  62. LONG lParam;
  63. {
  64.  
  65.     PAINTSTRUCT ps;
  66.     int count;
  67.  
  68.     register PTWND pSW = (PTWND)GetWindowWord(hWnd, 0);
  69.  
  70.     switch(message) {
  71.     case WH19_COMMAND:
  72.         if (CD.StatOpen) {
  73.             H19HideCaret(hWnd);
  74.             switch (wParam) {
  75.             case H19_MOVECURSORRIGHT:
  76.             MoveCursorRight(pSW, LOWORD(lParam));
  77.                 break;
  78.             case H19_MOVECURSORLEFT:
  79.                         MoveCursorLeft(pSW, LOWORD(lParam));
  80.                 break;
  81.             case H19_POSITIONCURSORCOL:
  82.                 PositionCursorCol(pSW, (short)LOWORD(lParam));
  83.                 break;
  84.             case H19_DELETECHAR:
  85.                 DeleteChar(pSW, LOWORD(lParam));
  86.                 break;
  87.             case H19_CLRSCREEN:
  88.                 ClearStatusLine(pSW);
  89.                 break;
  90.             case H19_CLRTOENDOFLINE:
  91.             case H19_CLRTOENDOFSCREEN:
  92.                 ClearToEndOfLine(pSW);
  93.                 break;
  94.             case H19_CLRTOSTARTOFLINE:
  95.             case H19_CLRTOTOPOFSCREEN:
  96.                 ClearToLineStart(pSW);
  97.             break;
  98.             case H19_INSERTLINE:
  99.             case H19_DELETELINE:
  100.                 pSW->Xpos = pSW->CurLineOffset = 0;
  101.             case H19_ERASELINE:
  102.                 EraseEntireLine(pSW);
  103.                 break;
  104.             }
  105.             SetCaretPos(pSW->Xpos, pSW->CharHeight);
  106.             H19ShowCaret(hWnd);
  107.         }
  108.         break;
  109.  
  110.     case WH19_CARETFUNCTION:
  111.         switch(wParam) {    
  112.         case H19_SHOWCARET:
  113.                 H19ShowCaret(hWnd);
  114.             break;
  115.  
  116.             case H19_HIDECARET:
  117.             H19HideCaret(hWnd);
  118.                 break;
  119.  
  120.         case H19_CREATECARET:
  121.             if (lParam) {
  122.                     MakeCaret(pSW);
  123.             SetCaretPos(pSW->Xpos, pSW->Ypos + pSW->CharHeight);
  124.             if (CD.StatOpen)
  125.                 H19ShowCaret(hWnd);
  126.                 }
  127.                 break;
  128.  
  129.         case H19_DESTROYCARET:
  130.             if (lParam) {
  131.             H19HideCaret(hWnd);
  132.             DestroyCaret();
  133.             }
  134.             break;
  135.         }
  136.         break;
  137.  
  138.     case WH19_STRINGINPUT:
  139.         count = 0;
  140.         if (CD.StatOpen) {
  141.             H19HideCaret(hWnd);
  142.         count = H19TerminalDisplay(pSW, (BYTE *)LOWORD(lParam),
  143.                             (short)wParam);
  144.         SetCaretPos(pSW->Xpos, pSW->CharHeight);
  145.         H19ShowCaret(hWnd);
  146.         }
  147.         return((LONG)count);
  148.         
  149.         case WH19_CURSORPOSITION:
  150.         if (wParam == H19_SAVECURSOR)
  151.             SaveCursor(TW.MaxLines, pSW->CurLineOffset);
  152.         else
  153.         GetCursor(TW.MaxLines, pSW->CurLineOffset, lParam);
  154.         break;
  155.  
  156.     case WM_CREATE:
  157.         TermWndCreate(hWnd, lParam);
  158.         break;
  159.  
  160.     case WM_PAINT:
  161.         BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
  162.             if (!IsRectEmpty((LPRECT)&ps.rcPaint))
  163.             StatWndPaint(pSW, (LPPAINTSTRUCT)&ps);
  164.         EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
  165.         break;
  166.  
  167.     default:
  168.         return ((long)DefWindowProc(hWnd,message,wParam,lParam));
  169.     }
  170.     return(0L);
  171. }
  172.  
  173. /* terminal window procedure */
  174. long FAR PASCAL TermWndProc(HWND hWnd,unsigned message,WORD wParam,LONG lParam)
  175. {
  176.  
  177.     PAINTSTRUCT ps;
  178.     short lines;
  179.     int count;
  180.  
  181.     register PTWND pTW = (PTWND)GetWindowWord(hWnd, 0);
  182.  
  183.     switch(message) {
  184.  
  185.     case WH19_COMMAND:
  186.         H19HideCaret(hWnd);
  187.         switch (wParam) {
  188.         case H19_MOVECURSORRIGHT:
  189.             MoveCursorRight(pTW, LOWORD(lParam));
  190.             break;
  191.         case H19_MOVECURSORLEFT:
  192.                     MoveCursorLeft(pTW, LOWORD(lParam));
  193.             break;
  194.         case H19_MOVECURSORUP:
  195.             MoveCursorUp(pTW, LOWORD(lParam));
  196.             break;
  197.         case H19_MOVECURSORDOWN:
  198.             MoveCursorDown(pTW, LOWORD(lParam));
  199.             break;
  200.         case H19_POSITIONCURSORROW:
  201.             PositionCursorRow(pTW, (short)LOWORD(lParam));
  202.             break;
  203.         case H19_POSITIONCURSORCOL:
  204.             PositionCursorCol(pTW, (short)LOWORD(lParam));
  205.             break;
  206.         case H19_ADJUSTWINDOW:
  207.             AdjustWindowToCursor(pTW);
  208.             break;
  209.         case H19_CURSORHOME:
  210.             CursorHome(pTW);
  211.             break;
  212.         case H19_DELETECHAR:
  213.             DeleteChar(pTW, LOWORD(lParam));
  214.             break;
  215.         case H19_CLRSCREEN:
  216.             ClearTermWindow(pTW);
  217.             break;
  218.         case H19_CLRTOENDOFSCREEN:
  219.             ClearToEndOfScreen(pTW);
  220.         case H19_CLRTOENDOFLINE:
  221.             ClearToEndOfLine(pTW);
  222.             break;
  223.         case H19_CLRTOTOPOFSCREEN:
  224.             ClearToScreenTop(pTW);
  225.         case H19_CLRTOSTARTOFLINE:
  226.             ClearToLineStart(pTW);
  227.             break;
  228.         case H19_ERASELINE:
  229.             EraseEntireLine(pTW);
  230.             break;
  231.         case H19_REVERSELINEFEED:
  232.             ReverseLF(pTW);
  233.             break;
  234.         case H19_INSERTLINE:
  235.             InsertLine(pTW, LOWORD(lParam));
  236.             break;
  237.         case H19_DELETELINE:
  238.             DeleteLine(pTW, LOWORD(lParam));
  239.             break;
  240.         }
  241.         SetCaretPos(pTW->Xpos, pTW->Ypos + pTW->CharHeight);
  242.         H19ShowCaret(hWnd);
  243.         break;
  244.  
  245.     case WH19_CARETFUNCTION:
  246.         switch(wParam) {    
  247.         case H19_SHOWCARET:
  248.                 H19ShowCaret(hWnd);
  249.             break;
  250.  
  251.             case H19_HIDECARET:
  252.             H19HideCaret(hWnd);
  253.                 break;
  254.  
  255.         case H19_CREATECARET:
  256.             if (lParam) {
  257.             AdjustWindowToCursor(pTW);
  258.             MakeCaret(pTW);
  259.             SetCaretPos(pTW->Xpos, pTW->Ypos + pTW->CharHeight);
  260.             H19ShowCaret(hWnd);
  261.             }
  262.             break;
  263.  
  264.         case H19_DESTROYCARET:
  265.             if (lParam) {
  266.             H19HideCaret(hWnd);
  267.             DestroyCaret();
  268.             }
  269.             break;
  270.         }
  271.         break;
  272.  
  273.     case WH19_STRINGINPUT:
  274.         H19HideCaret(hWnd);
  275.         count = H19TerminalDisplay(pTW, (BYTE *)LOWORD(lParam),
  276.                             (short)wParam);
  277.         SetCaretPos(pTW->Xpos, pTW->Ypos + pTW->CharHeight);
  278.         H19ShowCaret(hWnd);
  279.         return((LONG)count);
  280.         
  281.         case WH19_CURSORPOSITION:
  282.         lines = (pTW->oCurrentLine - pTW->oTopLine) / pTW->MaxCols;
  283.         if (lines < 0)
  284.         lines += pTW->MaxLines;
  285.         if (wParam == H19_SAVECURSOR)
  286.             SaveCursor(lines, pTW->CurLineOffset);
  287.         else
  288.             GetCursor(lines, pTW->CurLineOffset, lParam);
  289.         break;
  290.  
  291.     case WH19_SLAPSCREEN:
  292.         SlapScreenToClip(pTW);
  293.         break;
  294.  
  295.     case WM_CREATE:
  296.         TermWndCreate(hWnd, lParam);
  297.         break;
  298.  
  299.     case WM_PAINT:
  300.         BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
  301.             if (!IsRectEmpty((LPRECT)&ps.rcPaint))
  302.             TermWndPaint(pTW, (LPPAINTSTRUCT)&ps);
  303.         EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
  304.         break;
  305.  
  306.     default:
  307.         return ((long)DefWindowProc(hWnd,message,wParam,lParam));
  308.     }
  309.     return(0L);
  310. }
  311.  
  312. /* copy screen to clipboard */
  313. static void NEAR SlapScreenToClip(PTWND pTW)
  314. {
  315.  
  316.     short cols = pTW->MaxCols;
  317.     short lines = pTW->MaxLines;
  318.     HANDLE hGlob = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, 
  319.                     (LONG)((cols + 2) * lines + 2));
  320.  
  321.     if (hGlob != NULL) {
  322.     RECT rect;
  323.     BYTE *pTop = pTW->pVidBuffer;
  324.     BYTE *lineptr = pTop + pTW->oTopLine;
  325.     BYTE *pEnd = pTop + pTW->oVidLastLine;
  326.     BYTE FAR *pGlob = GlobalLock(hGlob);
  327.         short count;
  328.     register int i, j;
  329.         BYTE ch;
  330.     BYTE *pSource;
  331.  
  332.     GetClientRect(pTW->hWnd, &rect);
  333.     InvertRect(pTW->hDC, &rect);
  334.         for (i = 0; i < lines; i++) {
  335.         count = cols;
  336.         while ((*(lineptr + count - 1) == SP) && (count > 0))
  337.         count--;
  338.             pSource = lineptr;
  339.             for (j = 0; j < count; j++) {
  340.         ch = (*pSource++) & 0x7f;
  341.         if (ch == DEL)
  342.             ch -= 1;
  343.         else if (ch < SP)
  344.             ch += '^';
  345.         *pGlob++ =  ch;
  346.         }
  347.         *pGlob++ = '\r';
  348.         *pGlob++ = '\n';
  349.         if ((lineptr += cols) > pEnd)
  350.                 lineptr = pTop;
  351.         }
  352.     *pGlob = NUL;
  353.     GlobalUnlock(hGlob);
  354.     if (OpenClipboard(pTW->hWnd)) {
  355.         EmptyClipboard();
  356.         SetClipboardData(CF_TEXT, hGlob);
  357.         CloseClipboard();
  358.     }
  359.     else
  360.            GlobalFree(hGlob);
  361.     InvertRect(pTW->hDC, &rect);
  362.     }
  363. }
  364.  
  365. /* update the status window */
  366. static void NEAR StatWndPaint(PTWND pSW, LPPAINTSTRUCT ps)
  367. {
  368.  
  369.     BYTE *pBuf = pSW->pVidBuffer;
  370.     short xpos = 0;
  371.     short count = pSW->MaxCols;
  372.     register short left = ps->rcPaint.left;
  373.     register short right = pSW->Width - ps->rcPaint.right;
  374.     short cwidth = pSW->CharWidth;
  375.     short countchange;
  376.  
  377.     if (ps->rcPaint.top < pSW->CharHeight) {
  378.     if (left >= cwidth) {
  379.         xpos = left - left % cwidth;
  380.         countchange = left / cwidth;
  381.         pBuf += countchange;
  382.         count -= countchange;
  383.     }
  384.     if (right >= cwidth)
  385.         count -= right / cwidth;
  386.     ShowLineOfText(ps->hdc,xpos,0,pBuf,count,cwidth);
  387.     }
  388. }
  389.  
  390. /* update the terminal window */
  391. static void NEAR TermWndPaint(PTWND pTW, LPPAINTSTRUCT ps)
  392. {
  393.  
  394.     register int i;
  395.     BYTE *pTop = pTW->pVidBuffer;
  396.     BYTE *lineptr = pTop + pTW->oTopLine;
  397.     BYTE *pEnd = pTop + pTW->oVidLastLine;
  398.     short cwidth = pTW->CharWidth;
  399.     short cheight = pTW->CharHeight;
  400.     short line1 = 0;
  401.     short line2 = pTW->MaxLines;
  402.     short cols = pTW->MaxCols;
  403.     short count = cols;
  404.     register short base = 0;
  405.     short left = ps->rcPaint.left;
  406.     short right = pTW->Width - ps->rcPaint.right;
  407.     short top = ps->rcPaint.top;
  408.     short bottom = pTW->Height - ps->rcPaint.bottom;
  409.  
  410.     short xpos = 0;
  411.     short offset = 0;
  412.     short countchange;
  413.  
  414.     if (left >= cwidth) {
  415.         xpos = left - left % cwidth;
  416.     countchange = left / cwidth;
  417.     offset += countchange;
  418.     count -= countchange;
  419.     }
  420.  
  421.     if (right >= cwidth) 
  422.         count -= right / cwidth;
  423.  
  424.     if (top >= cheight) {
  425.     line1 = top / cheight;
  426.     base += line1 * cheight;
  427.     lineptr += line1 * cols;
  428.     if (lineptr > pEnd)
  429.         lineptr = pTop + (lineptr - pEnd) - cols;
  430.     }
  431.  
  432.     if (bottom >= cheight)
  433.     line2 -= bottom / cheight;
  434.  
  435.     for (i = line1; i < line2; i++) {
  436.     ShowLineOfText(ps->hdc,xpos,base,lineptr+offset,count,cwidth);
  437.         base += cheight;
  438.     if ((lineptr += cols) > pEnd)
  439.             lineptr = pTop;
  440.     }
  441. }
  442.  
  443. /* display a line of text on terminal or status window */
  444. static void NEAR ShowLineOfText(hDC, Xpos, Ypos, lineptr, linewidth, charwidth)
  445. HDC hDC;
  446. short Xpos, Ypos;
  447. BYTE *lineptr;
  448. short linewidth, charwidth;
  449. {
  450.  
  451.     register int i,j;
  452.     short X;
  453.     BYTE *sptr, *eptr, ch;
  454.     BYTE pBuf[TERMMAXCOLS];
  455.  
  456.     i = 0;
  457.     X = Xpos;
  458.     sptr = eptr = lineptr;
  459.  
  460.     while (i < linewidth) {
  461.     for (j = 0; j < linewidth - i; j++)
  462.         if (*eptr++ > DEL)
  463.         break;
  464.     SetAttrib(hDC, NORMAL);
  465.     TextOut(hDC,X,Ypos,(LPSTR)sptr, j);
  466.     if ((i += j) >= linewidth)
  467.         break;
  468.     sptr = --eptr;
  469.     X += j * charwidth;
  470.     for (j = 0; j < linewidth - i; j++)
  471.         if ((ch = *eptr++) <= DEL)
  472.         break;
  473.         else
  474.         pBuf[j] = ch & 0x7f;
  475.     SetAttrib(hDC, REVERSE);
  476.     TextOut(hDC,X,Ypos,(LPSTR)pBuf,j);
  477.     if ((i += j) < linewidth) {
  478.         X += j * charwidth;
  479.         sptr = --eptr;
  480.     }
  481.     }
  482. }
  483.  
  484. /* cursor support routines */
  485. static void NEAR MoveCursorRight(PTWND pTW, WORD count)
  486. {
  487.  
  488.     register short *offset = &pTW->CurLineOffset;
  489.     register short *xpos = &pTW->Xpos;
  490.     short cols = pTW->MaxCols - 1;
  491.     short width = pTW->CharWidth;
  492.  
  493.     while ((*offset < cols) && (count--)) {
  494.     *offset += 1;
  495.     *xpos += width;
  496.     }
  497. }
  498.  
  499. static void NEAR MoveCursorLeft(PTWND pTW, WORD count)
  500. {
  501.  
  502.     register short *offset = &pTW->CurLineOffset;
  503.     register short *xpos = &pTW->Xpos;
  504.     short width = pTW->CharWidth;
  505.  
  506.     while((*offset > 0) && (count--)) {
  507.         *offset -= 1;
  508.         *xpos -= width;
  509.     }
  510. }
  511.  
  512. static void NEAR MoveCursorUp(PTWND pTW, WORD count)
  513. {
  514.     register short *oCurLine = &pTW->oCurrentLine;
  515.     short top = pTW->oTopLine;
  516.  
  517.     if (*oCurLine != top) {
  518.         register short *ypos = &pTW->Ypos;
  519.         short cols  = pTW->MaxCols;
  520.     short cheight  = pTW->CharHeight;
  521.  
  522.     while ((*oCurLine != top) && (count--)) {
  523.         *ypos -= cheight;
  524.         if ((*oCurLine -= cols) < 0)
  525.             *oCurLine = pTW->oVidLastLine;
  526.         }
  527.         AdjustWindowToCursor(pTW);
  528.     }
  529. }
  530.  
  531. static void NEAR MoveCursorDown(PTWND pTW, WORD count)
  532. {
  533.     register short *oCurLine = &pTW->oCurrentLine;
  534.     short bottom = pTW->oBottomLine;
  535.  
  536.     if (*oCurLine != bottom) {
  537.     register short *ypos = &pTW->Ypos;
  538.     short cols  = pTW->MaxCols;
  539.     short cheight  = pTW->CharHeight;
  540.     short last =  pTW->oVidLastLine;
  541.  
  542.     while ((*oCurLine != bottom) && (count--)) {
  543.         *ypos += cheight;
  544.         if ((*oCurLine += cols) > last)
  545.             *oCurLine = 0;
  546.     }
  547.         AdjustWindowToCursor(pTW);
  548.     }
  549. }
  550.  
  551. /* position window so that cursor is visible */
  552. static void NEAR AdjustWindowToCursor(PTWND pTW)
  553. {
  554.  
  555.     POINT point;
  556.     HWND hWnd = pTW->hWnd;
  557.     short ypos = pTW->Ypos;
  558.     short width = pTW->Width;
  559.     short cheight = pTW->CharHeight;
  560.     register short Y1 = MW.SCTopTextLine;
  561.     register short Y2 = MW.SCBottomTextLine;
  562.     short Y;
  563.  
  564.     if ((CD.StatOpen) && (CD.StatOverlayTerm))
  565.     Y2 -= cheight;
  566.  
  567.     point.x = pTW->Xpos;
  568.     point.y = ypos;
  569.  
  570.     ClientToScreen(hWnd, (POINT FAR *)&point);
  571.     Y = point.y;
  572.  
  573.     if (Y < Y1) {
  574.     MoveWindow(hWnd,0,-ypos, width, pTW->Height, FALSE);
  575.     ScrollWindow(hWnd,0,Y1-Y, (LPRECT)NULL, (LPRECT)NULL);
  576.     UpdateWindow(hWnd);
  577.     }
  578.     else if (Y > Y2) {
  579.     MoveWindow(hWnd, 0, Y2-Y1-ypos, width, pTW->Height, FALSE);
  580.     ScrollWindow(hWnd,0,Y2-Y, (LPRECT)NULL, (LPRECT)NULL);
  581.     UpdateWindow(hWnd);
  582.     }   
  583. }
  584.  
  585. /* display a string */
  586. static int NEAR H19TerminalDisplay(PTWND pTW, BYTE *str, short len)
  587. {
  588.  
  589.     register BYTE *ptr;
  590.     register short ctr;
  591.     short toff, txpos;
  592.     BYTE *tBuf;
  593.     BYTE savebuf[TERMMAXCOLS];
  594.  
  595.     HWND hWnd = pTW->hWnd;
  596.     HDC hDC = pTW->hDC;
  597.     short cols = pTW->MaxCols;
  598.     short cwidth = pTW->CharWidth;
  599.     short width = pTW->Width;
  600.     BYTE *pBuf = pTW->pVidBuffer;
  601.     short more_than_one_line = pTW->MaxLines - 1;
  602.  
  603.     while (len) {
  604.     ptr = str;
  605.     ctr = 0;
  606.     tBuf = pBuf + pTW->oCurrentLine;
  607.         toff = pTW->CurLineOffset;
  608.         txpos = pTW->Xpos;
  609.  
  610.     while ((*ptr >= SP) && (*ptr < DEL)) {
  611.         if ((len) && (toff < cols)) {
  612.             if (CD.GraphicsMode)
  613.             if (*ptr == '~')
  614.                 *ptr += 1;        
  615.             else if (*ptr >= '^')
  616.                 *ptr -= '^';
  617.         if (CD.ICToggle)
  618.             savebuf[ctr] = *(tBuf + toff);
  619.         *(tBuf + toff++) = *ptr++ | CD.CharAttribute;
  620.             ctr += 1;
  621.         txpos += cwidth;
  622.             len -= 1;
  623.         }
  624.         else
  625.         break;
  626.     }
  627.         if (ctr) {
  628.         if (CD.ICToggle) {
  629.         RECT rect;
  630.         short ypos = pTW->Ypos;
  631.         short xpos = pTW->Xpos;
  632.         short tomove, tocopy;
  633.         tomove =  cols - toff -ctr;
  634.         tocopy = min (ctr, cols - toff);
  635.         if (tomove > 0) {        
  636.             memmove(tBuf + toff + ctr, tBuf + toff, tomove);
  637.         if (tocopy > 0)
  638.             strncpy(tBuf + toff, savebuf, tocopy);
  639.         }
  640.         SetRect(&rect, xpos, ypos, width, ypos + pTW->CharHeight);
  641.         ScrollWindow(hWnd, txpos - xpos, 0, &rect, &rect);
  642.         UpdateWindow(hWnd);
  643.         }
  644.         else {
  645.             if (CD.InverseVideo)
  646.             SetAttrib(hDC, REVERSE);
  647.             else
  648.             SetAttrib(hDC, NORMAL);
  649.                 TextOut(hDC, pTW->Xpos, pTW->Ypos, (LPSTR)str, ctr);
  650.         }
  651.         if (toff < cols) {
  652.         pTW->CurLineOffset = toff;
  653.         pTW->Xpos = txpos;
  654.         }
  655.         else {
  656.         if (CD.WrapAround) {
  657.             DoCR(pTW);
  658.             if (more_than_one_line)
  659.             DoLF(pTW);
  660.         }
  661.         else {
  662.             pTW->CurLineOffset = cols - 1;
  663.             pTW->Xpos = width - cwidth;
  664.         }
  665.         }
  666.     }
  667.     while ((*ptr < SP) || (*ptr >= DEL)) {
  668.         if (len) {
  669.             switch (*ptr) {
  670.             case BEL:
  671.                 MessageBeep(0);
  672.                 break;
  673.             case HT:
  674.             DoHT(pTW);
  675.             break;
  676.             case BS:
  677.             DoBS(pTW);
  678.             break;
  679.             case LF:
  680.             if (CD.CRonLF)
  681.                 DoCR(pTW);
  682.             if (more_than_one_line)
  683.                 DoLF(pTW);
  684.                 break;
  685.             case CR:
  686.             DoCR(pTW);
  687.             if (CD.HoldScreen && 
  688.                 (pTW->oCurrentLine == pTW->oBottomLine)) {
  689.                 if (CD.ReleaseCount == 0) {
  690.                     SetScroll();
  691.                     return(len > 0 ? len - 1 : 0);
  692.                 }
  693.                 else
  694.                 CD.ReleaseCount -= 1;
  695.             }
  696.             if (CD.LFonCR)
  697.                 if (more_than_one_line)
  698.                     DoLF(pTW);
  699.                 break;
  700.             }
  701.             len -= 1;
  702.             ptr++;
  703.         }
  704.         else
  705.         break;
  706.     }
  707.         str = ptr;
  708.     }
  709.     return(len);
  710. }
  711.  
  712. /* hold screen support */
  713. static void NEAR SetScroll()
  714. {
  715.  
  716.     BYTE keystate[256];
  717.  
  718.     GetKeyboardState((LPSTR)keystate);
  719.     keystate[VK_SCROLL] |= 1;
  720.     SetKeyboardState((LPSTR)keystate);
  721.     CD.ScrollLock = TRUE;
  722.  
  723. }
  724.  
  725. /* control character modules */
  726. static void NEAR DoLF(PTWND pTW)
  727. {
  728.  
  729.     HWND hWnd = pTW->hWnd;
  730.     register short cols = pTW->MaxCols;
  731.     register oEnd = pTW->oVidLastLine;
  732.  
  733.     if ( (pTW->oCurrentLine += cols) > oEnd)
  734.     pTW->oCurrentLine = 0;
  735.  
  736.     if (pTW->oCurrentLine == pTW->oTopLine) {
  737.     if ((pTW->oTopLine += cols) > oEnd)
  738.         pTW->oTopLine = 0;
  739.     if ((pTW->oBottomLine += cols) > oEnd)
  740.         pTW->oBottomLine = 0;
  741.     memset(pTW->pVidBuffer + pTW->oCurrentLine, SP, cols);
  742.     ScrollWindow(hWnd,0,-pTW->CharHeight, (LPRECT)NULL, (LPRECT)NULL);
  743.     UpdateWindow(hWnd);
  744.     }
  745.     else
  746.     pTW->Ypos += pTW->CharHeight;
  747.  
  748.     AdjustWindowToCursor(pTW);
  749.  
  750. }
  751.  
  752. static void NEAR DoCR(PTWND pTW)
  753. {
  754.  
  755.     pTW->Xpos = pTW->CurLineOffset = 0;
  756. }
  757.  
  758. static void NEAR DoBS(PTWND pTW)
  759. {
  760.     if (pTW->CurLineOffset) {
  761.     pTW->CurLineOffset -= 1;
  762.     pTW->Xpos -= pTW->CharWidth;
  763.     }
  764. }
  765.  
  766. static void NEAR DoHT(PTWND pTW)
  767. {
  768.  
  769.     register short offset = pTW->CurLineOffset;
  770.  
  771.     if (offset < pTW->MaxCols - 1) {
  772.     short charwidth = pTW->CharWidth;
  773.     short limit = pTW->TabLimit;
  774.     register short xpos = pTW->Xpos;
  775.         do {
  776.         xpos += charwidth;
  777.         } while((++offset % DEF_TABSTOP != 0) && (offset < limit));
  778.         pTW->Xpos = xpos;
  779.     pTW->CurLineOffset = offset;
  780.     }
  781. }
  782.  
  783. /* caret creation and deletion routines */
  784. static void NEAR MakeCaret(PTWND pTW)
  785. {
  786.  
  787.     register short height;
  788.  
  789.     if (CD.BlockCursor)
  790.     height = -pTW->CharHeight;
  791.     else
  792.     height = -2;
  793.  
  794.     CreateCaret(pTW->hWnd, (HBITMAP)NULL, pTW->CharWidth, height);
  795. }
  796.  
  797. static void NEAR H19ShowCaret(HWND hWnd)
  798. {
  799.  
  800.     if (!CD.CursorOff)
  801.     ShowCaret(hWnd);
  802. }
  803.  
  804. static void NEAR H19HideCaret(HWND hWnd)
  805. {
  806.  
  807.     if (!CD.CursorOff)
  808.     HideCaret(hWnd);
  809.  
  810. }
  811.  
  812. /* set text attributes */
  813. static void NEAR SetAttrib(HDC hDC, int type)
  814. {
  815.  
  816.     switch (type) {
  817.         case NORMAL:
  818.         SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  819.         SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
  820.         break;
  821.     case REVERSE:
  822.             SetTextColor(hDC, GetSysColor(COLOR_WINDOW));
  823.         SetBkColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  824.         break;
  825.     }
  826. }
  827.  
  828. /* cursor positioning routines */
  829. static void NEAR PositionCursorRow(PTWND pTW, short y)
  830. {
  831.  
  832.     register short cols = pTW->MaxCols;
  833.     register short oCurr = pTW->oTopLine;
  834.  
  835.     pTW->Ypos = y * pTW->CharHeight;
  836.     oCurr += y * cols;
  837.     if (oCurr > pTW->oVidLastLine)
  838.         oCurr -= pTW->ScreenSize;
  839.     pTW->oCurrentLine = oCurr;
  840.     AdjustWindowToCursor(pTW);
  841. }
  842.  
  843. static void NEAR PositionCursorCol(PTWND pTW, short x)
  844. {
  845. /*    
  846.     if (x >= pTW->MaxCols)
  847.     x = pTW->MaxCols - 1;
  848. */
  849.     pTW->Xpos = x * pTW->CharWidth;
  850.     pTW->CurLineOffset = x;
  851.  
  852. }
  853.  
  854. static void NEAR CursorHome(PTWND pTW)
  855. {
  856.  
  857.     pTW->Xpos = pTW->Ypos = pTW->CurLineOffset = 0;
  858.     pTW->oCurrentLine = pTW->oTopLine;
  859.     AdjustWindowToCursor(pTW);
  860.  
  861. }
  862.  
  863. /* character deletion */
  864. static void NEAR DeleteChar(PTWND pTW, WORD count)
  865. {
  866.  
  867.     RECT rect;
  868.     short cols = pTW->MaxCols;
  869.     short offset = pTW->CurLineOffset;
  870.     BYTE *dest = pTW->pVidBuffer + pTW->oCurrentLine + offset;
  871.     HWND hWnd = pTW->hWnd;
  872.     short ypos = pTW->Ypos;
  873.  
  874.     register short copycount;
  875.     register short maxdelchars;
  876.  
  877.     if (count > (maxdelchars = cols - offset))
  878.     count = maxdelchars;
  879.     copycount = maxdelchars - count;
  880.     memmove(dest, dest + count, copycount);
  881.     memset(dest+copycount, SP, count);
  882.  
  883.     SetRect(&rect, pTW->Xpos, ypos, pTW->Width, ypos + pTW->CharHeight);
  884.     ScrollWindow(hWnd,-pTW->CharWidth * count,0, &rect, &rect);
  885.     UpdateWindow(hWnd);
  886. }
  887.  
  888. /* clear screen routines */
  889. static void NEAR ClearStatusLine(PTWND pSW)
  890. {
  891.  
  892.     RECT rect;
  893.     register HWND hWnd = pSW->hWnd;
  894.  
  895.     memset(pSW->pVidBuffer, SP, pSW->MaxCols);
  896.     SetRect((LPRECT)&rect,0,0,pSW->Width,pSW->CharHeight);
  897.     InvalidateRect(hWnd, (LPRECT)&rect, TRUE);
  898.     UpdateWindow(hWnd);
  899. }
  900.  
  901. static void NEAR ClearTermWindow(PTWND pTW)
  902. {
  903.  
  904.     RECT rect;
  905.     register HWND hWnd = pTW->hWnd;
  906.  
  907.     memset(pTW->pVidBuffer, SP, pTW->ScreenSize);
  908.     pTW->Xpos = pTW->Ypos = pTW->CurLineOffset = 0;
  909.     pTW->oCurrentLine = pTW->oTopLine = 0;
  910.     pTW->oBottomLine = pTW->oVidLastLine;
  911.  
  912.     SetRect((LPRECT)&rect,0,0,pTW->Width,pTW->Height);
  913.     InvalidateRect(hWnd, (LPRECT)&rect, TRUE);
  914.     UpdateWindow(hWnd);
  915.  
  916.     AdjustWindowToCursor(pTW);
  917.  
  918. }
  919.  
  920. static void NEAR ClearToEndOfLine(PTWND pTW)
  921. {
  922.  
  923.     RECT rect;
  924.     HWND hWnd = pTW->hWnd;
  925.     register offset = pTW->CurLineOffset;
  926.     register char *src = pTW->pVidBuffer + pTW->oCurrentLine + offset;
  927.  
  928.     memset(src, SP, pTW->MaxCols - offset);
  929.     SetRect(&rect, pTW->Xpos, pTW->Ypos, pTW->Width, pTW->Ypos+pTW->CharHeight);
  930.     InvalidateRect(hWnd, (LPRECT)&rect, TRUE);
  931.     UpdateWindow(hWnd);
  932.  
  933. }
  934.  
  935. static void NEAR ClearToEndOfScreen(PTWND pTW)
  936. {
  937.  
  938.     RECT rect;
  939.  
  940.     char *pBuf = pTW->pVidBuffer;
  941.     char *pEnd = pBuf + pTW->oVidLastLine;
  942.     char *pBottom = pBuf + pTW->oBottomLine;
  943.     register char *base = pBuf + pTW->oCurrentLine;
  944.     register short cols = pTW->MaxCols;
  945.  
  946.     do {
  947.         if ((base += cols) > pEnd)
  948.         base = pBuf;
  949.     memset(base, SP, cols);
  950.     } while (base != pBottom);
  951.  
  952.     SetRect(&rect, 0, pTW->Ypos + pTW->CharHeight, pTW->Width, pTW->Height);
  953.     InvalidateRect(pTW->hWnd, (LPRECT)&rect, TRUE);
  954.     UpdateWindow(pTW->hWnd);
  955.  
  956. }
  957.  
  958. static void NEAR ClearToLineStart(PTWND pTW)
  959. {
  960.  
  961.     HWND hWnd = pTW->hWnd;
  962.     BYTE *pCurr = pTW->pVidBuffer + pTW->oCurrentLine;
  963.     RECT rect;
  964.     register short ypos = pTW->Ypos;
  965.     register offset = pTW->CurLineOffset + 1;
  966.  
  967.     memset(pCurr, SP, offset);
  968.  
  969.     SetRect(&rect, 0, ypos, offset * pTW->CharWidth, ypos + pTW->CharHeight); 
  970.     InvalidateRect(hWnd, (LPRECT)&rect, TRUE);
  971.     UpdateWindow(hWnd);
  972. }
  973.  
  974. static void NEAR ClearToScreenTop(PTWND pTW)
  975. {
  976.  
  977.     RECT rect;
  978.     HWND hWnd = pTW->hWnd;
  979.     BYTE *pBuf = pTW->pVidBuffer;
  980.     BYTE *pTop = pBuf + pTW->oTopLine;
  981.     BYTE *pEnd = pBuf + pTW->oVidLastLine;
  982.     register BYTE *base = pBuf + pTW->oCurrentLine;
  983.     register short cols = pTW->MaxCols;
  984.  
  985.     do {
  986.         if ((base -= cols) < pBuf)
  987.         base = pEnd;
  988.     memset(base, SP, cols);
  989.     } while (base != pTop);
  990.     SetRect((LPRECT)&rect, 0, 0, pTW->Width, pTW->Ypos);
  991.     InvalidateRect(hWnd, (LPRECT)&rect, TRUE);
  992.     UpdateWindow(hWnd);
  993. }
  994.  
  995. static void NEAR EraseEntireLine(PTWND pTW)
  996. {
  997.  
  998.     RECT rect;
  999.     register HWND hWnd = pTW->hWnd;
  1000.     register short ypos = pTW->Ypos;
  1001.     
  1002.     memset(pTW->pVidBuffer + pTW->oCurrentLine, SP, pTW->MaxCols);
  1003.     SetRect((LPRECT)&rect, 0, ypos, pTW->Width, ypos + pTW->CharHeight);
  1004.     InvalidateRect(hWnd, (LPRECT)&rect, TRUE);
  1005.     UpdateWindow(hWnd);
  1006.  
  1007. }
  1008.  
  1009. /* reverse index */
  1010. static void NEAR ReverseLF(PTWND pTW)
  1011. {
  1012.  
  1013.     register short cols = pTW->MaxCols;
  1014.     register short oEnd = pTW->oVidLastLine;
  1015.  
  1016.     if ((pTW->oCurrentLine -= cols) < 0)
  1017.     pTW->oCurrentLine = oEnd;
  1018.  
  1019.     if (pTW->oCurrentLine == pTW->oBottomLine) {
  1020.     if ((pTW->oTopLine -= cols) < 0)
  1021.         pTW->oTopLine = oEnd;
  1022.     if ((pTW->oBottomLine -= cols) < 0)
  1023.         pTW->oBottomLine = oEnd;
  1024.     memset(pTW->pVidBuffer + pTW->oCurrentLine, SP, cols);
  1025.         ScrollWindow(pTW->hWnd,0,pTW->CharHeight,(LPRECT)NULL,(LPRECT)NULL);
  1026.         UpdateWindow(pTW->hWnd);
  1027.     }
  1028.     else 
  1029.     pTW->Ypos -= pTW->CharHeight;
  1030.  
  1031.     AdjustWindowToCursor(pTW);
  1032. }
  1033.  
  1034. /* line insertion and deletion routines */
  1035. static void NEAR InsertLine(PTWND pTW, WORD count)
  1036. {
  1037.  
  1038.     RECT rect;
  1039.     int i;
  1040.     HWND hWnd = pTW->hWnd;
  1041.     short cols = pTW->MaxCols;
  1042.     short lines = pTW->MaxLines;
  1043.     BYTE *pBuf = pTW->pVidBuffer;
  1044.     BYTE *pCurr = pBuf + pTW->oCurrentLine;
  1045.     BYTE *pEnd = pBuf + pTW->oVidLastLine;
  1046.     register BYTE *dest = pBuf + pTW->oBottomLine;
  1047.     register BYTE *src;
  1048.  
  1049.     if (count > lines)
  1050.     count = lines;
  1051.     if ((src = dest - count * cols) < pBuf)
  1052.     src += pTW->ScreenSize;
  1053.     while (dest != pCurr) {
  1054.     memmove(dest, src, cols);
  1055.     if ((src -= cols) < pBuf)
  1056.         src = pEnd;
  1057.     if ((dest -= cols) < pBuf)
  1058.         dest = pEnd;
  1059.     }
  1060.     src = pCurr;
  1061.     for (i = 0; i < count; i++) {
  1062.         memset(src, SP, cols);
  1063.     if ((src += cols) > pEnd)
  1064.             src = pBuf;
  1065.     }
  1066.  
  1067.     pTW->CurLineOffset = pTW->Xpos = 0;
  1068.  
  1069.     SetRect((LPRECT)&rect, 0, pTW->Ypos, pTW->Width, pTW->Height);
  1070.     ScrollWindow(hWnd, 0, count * pTW->CharHeight, &rect, &rect);
  1071.     UpdateWindow(hWnd);
  1072.  
  1073. }
  1074.  
  1075. static void NEAR DeleteLine(PTWND pTW, WORD count)
  1076. {
  1077.  
  1078.     RECT rect;
  1079.     HWND hWnd = pTW->hWnd;
  1080.     short cols = pTW->MaxCols;
  1081.     BYTE *pBuf = pTW->pVidBuffer;
  1082.     BYTE *dest = pBuf + pTW->oCurrentLine;
  1083.     BYTE *pBottom = pBuf + pTW->oBottomLine;
  1084.     register BYTE *pEnd = pBuf + pTW->oVidLastLine;
  1085.     register BYTE *src;
  1086.     int i;
  1087.  
  1088.     if (count > pTW->MaxLines)
  1089.     count = pTW->MaxLines;
  1090.  
  1091.     if ((src = dest + count * cols) > pEnd)
  1092.     src -= pTW->ScreenSize;
  1093.     while (dest != pBottom) {
  1094.     memmove(dest, src, cols);
  1095.         if ((src += cols) > pEnd)
  1096.         src = pBuf;
  1097.         if ((dest += cols) > pEnd)
  1098.         dest = pBuf;
  1099.     }
  1100.     src = pBottom;
  1101.     for (i = 0; i < count; i++) {
  1102.         memset(src, SP, cols);
  1103.     if ((src -= cols) < pBuf)
  1104.             src = pEnd;
  1105.     }
  1106.  
  1107.     pTW->CurLineOffset = pTW->Xpos = 0;
  1108.  
  1109.     SetRect((LPRECT)&rect,0,pTW->Ypos,pTW->Width,pTW->Height);
  1110.     ScrollWindow(hWnd,0, -count * pTW->CharHeight, &rect, &rect);
  1111.     UpdateWindow(hWnd);
  1112. }
  1113.  
  1114. /* cursor save and restore */
  1115. static void NEAR SaveCursor(short line, short column)
  1116. {
  1117.  
  1118.     CD.CurSaveRow =  line;
  1119.     CD.CurSaveCol =  column;
  1120. }
  1121.  
  1122. static void NEAR GetCursor(short lines, short cols, LONG lParam)
  1123. {
  1124.  
  1125.     short *x, *y;
  1126.  
  1127.     x = (short *)LOWORD(lParam);
  1128.     y = (short *)HIWORD(lParam);
  1129.  
  1130.     *x = lines;
  1131.     *y = cols;
  1132.  
  1133. }
  1134.