/* * Windows H19 Terminal Emulator * * Written by William S. Hall * 3665 Benton Street, #66 * Santa Clara, CA 95051 * * Terminal and status window module */ #define NOKANJI #define NOATOM #include #include #include "winasc.h" #include "winh19.h" #include "win19d.h" /* local functions */ static void NEAR MoveCursorLeft(PTWND pTW, WORD count); static void NEAR MoveCursorRight(PTWND pTW, WORD count); static void NEAR SetScroll(void); static void NEAR MoveCursorUp(PTWND pTW, WORD count); static void NEAR MoveCursorDown(PTWND pTW, WORD count); static void NEAR PositionCursorRow(PTWND, short); static void NEAR PositionCursorCol(PTWND, short); static void NEAR CursorHome(PTWND); static void NEAR DeleteChar(PTWND, WORD); static void NEAR ClearStatusLine(PTWND); static void NEAR ClearTermWindow(PTWND); static void NEAR SlapScreenToClip(PTWND); static void NEAR SetAttrib(HDC, int); static void NEAR H19HideCaret(HWND hWnd); static void NEAR H19ShowCaret(HWND hWnd); static void NEAR SaveCursor(short line, short column); static void NEAR GetCursor(short lines, short cols, LONG lParam); static int NEAR H19TerminalDisplay(PTWND, BYTE *, short); static void NEAR DoCR(PTWND); static void NEAR DoBS(PTWND); static void NEAR MakeCaret(PTWND); static void NEAR DoHT(PTWND); static void NEAR ClearToEndOfLine(PTWND); static void NEAR ClearToEndOfScreen(PTWND); static void NEAR StatWndPaint(PTWND, LPPAINTSTRUCT); static void NEAR ClearToScreenTop(PTWND); static void NEAR ClearToLineStart(PTWND); static void NEAR EraseEntireLine(PTWND); static void NEAR TermWndPaint(PTWND, LPPAINTSTRUCT); static void NEAR AdjustWindowToCursor(PTWND); static void NEAR ShowLineOfText(HDC, short, short, BYTE *, short, short); static void NEAR InsertLine(PTWND, WORD); static void NEAR DeleteLine(PTWND, WORD); static void NEAR ReverseLF(PTWND); static void NEAR DoLF(PTWND); /* status window proc */ long FAR PASCAL StatWndProc(hWnd,message,wParam,lParam) HWND hWnd; unsigned message; WORD wParam; LONG lParam; { PAINTSTRUCT ps; int count; register PTWND pSW = (PTWND)GetWindowWord(hWnd, 0); switch(message) { case WH19_COMMAND: if (CD.StatOpen) { H19HideCaret(hWnd); switch (wParam) { case H19_MOVECURSORRIGHT: MoveCursorRight(pSW, LOWORD(lParam)); break; case H19_MOVECURSORLEFT: MoveCursorLeft(pSW, LOWORD(lParam)); break; case H19_POSITIONCURSORCOL: PositionCursorCol(pSW, (short)LOWORD(lParam)); break; case H19_DELETECHAR: DeleteChar(pSW, LOWORD(lParam)); break; case H19_CLRSCREEN: ClearStatusLine(pSW); break; case H19_CLRTOENDOFLINE: case H19_CLRTOENDOFSCREEN: ClearToEndOfLine(pSW); break; case H19_CLRTOSTARTOFLINE: case H19_CLRTOTOPOFSCREEN: ClearToLineStart(pSW); break; case H19_INSERTLINE: case H19_DELETELINE: pSW->Xpos = pSW->CurLineOffset = 0; case H19_ERASELINE: EraseEntireLine(pSW); break; } SetCaretPos(pSW->Xpos, pSW->CharHeight); H19ShowCaret(hWnd); } break; case WH19_CARETFUNCTION: switch(wParam) { case H19_SHOWCARET: H19ShowCaret(hWnd); break; case H19_HIDECARET: H19HideCaret(hWnd); break; case H19_CREATECARET: if (lParam) { MakeCaret(pSW); SetCaretPos(pSW->Xpos, pSW->Ypos + pSW->CharHeight); if (CD.StatOpen) H19ShowCaret(hWnd); } break; case H19_DESTROYCARET: if (lParam) { H19HideCaret(hWnd); DestroyCaret(); } break; } break; case WH19_STRINGINPUT: count = 0; if (CD.StatOpen) { H19HideCaret(hWnd); count = H19TerminalDisplay(pSW, (BYTE *)LOWORD(lParam), (short)wParam); SetCaretPos(pSW->Xpos, pSW->CharHeight); H19ShowCaret(hWnd); } return((LONG)count); case WH19_CURSORPOSITION: if (wParam == H19_SAVECURSOR) SaveCursor(TW.MaxLines, pSW->CurLineOffset); else GetCursor(TW.MaxLines, pSW->CurLineOffset, lParam); break; case WM_CREATE: TermWndCreate(hWnd, lParam); break; case WM_PAINT: BeginPaint(hWnd, (LPPAINTSTRUCT)&ps); if (!IsRectEmpty((LPRECT)&ps.rcPaint)) StatWndPaint(pSW, (LPPAINTSTRUCT)&ps); EndPaint(hWnd, (LPPAINTSTRUCT)&ps); break; default: return ((long)DefWindowProc(hWnd,message,wParam,lParam)); } return(0L); } /* terminal window procedure */ long FAR PASCAL TermWndProc(HWND hWnd,unsigned message,WORD wParam,LONG lParam) { PAINTSTRUCT ps; short lines; int count; register PTWND pTW = (PTWND)GetWindowWord(hWnd, 0); switch(message) { case WH19_COMMAND: H19HideCaret(hWnd); switch (wParam) { case H19_MOVECURSORRIGHT: MoveCursorRight(pTW, LOWORD(lParam)); break; case H19_MOVECURSORLEFT: MoveCursorLeft(pTW, LOWORD(lParam)); break; case H19_MOVECURSORUP: MoveCursorUp(pTW, LOWORD(lParam)); break; case H19_MOVECURSORDOWN: MoveCursorDown(pTW, LOWORD(lParam)); break; case H19_POSITIONCURSORROW: PositionCursorRow(pTW, (short)LOWORD(lParam)); break; case H19_POSITIONCURSORCOL: PositionCursorCol(pTW, (short)LOWORD(lParam)); break; case H19_ADJUSTWINDOW: AdjustWindowToCursor(pTW); break; case H19_CURSORHOME: CursorHome(pTW); break; case H19_DELETECHAR: DeleteChar(pTW, LOWORD(lParam)); break; case H19_CLRSCREEN: ClearTermWindow(pTW); break; case H19_CLRTOENDOFSCREEN: ClearToEndOfScreen(pTW); case H19_CLRTOENDOFLINE: ClearToEndOfLine(pTW); break; case H19_CLRTOTOPOFSCREEN: ClearToScreenTop(pTW); case H19_CLRTOSTARTOFLINE: ClearToLineStart(pTW); break; case H19_ERASELINE: EraseEntireLine(pTW); break; case H19_REVERSELINEFEED: ReverseLF(pTW); break; case H19_INSERTLINE: InsertLine(pTW, LOWORD(lParam)); break; case H19_DELETELINE: DeleteLine(pTW, LOWORD(lParam)); break; } SetCaretPos(pTW->Xpos, pTW->Ypos + pTW->CharHeight); H19ShowCaret(hWnd); break; case WH19_CARETFUNCTION: switch(wParam) { case H19_SHOWCARET: H19ShowCaret(hWnd); break; case H19_HIDECARET: H19HideCaret(hWnd); break; case H19_CREATECARET: if (lParam) { AdjustWindowToCursor(pTW); MakeCaret(pTW); SetCaretPos(pTW->Xpos, pTW->Ypos + pTW->CharHeight); H19ShowCaret(hWnd); } break; case H19_DESTROYCARET: if (lParam) { H19HideCaret(hWnd); DestroyCaret(); } break; } break; case WH19_STRINGINPUT: H19HideCaret(hWnd); count = H19TerminalDisplay(pTW, (BYTE *)LOWORD(lParam), (short)wParam); SetCaretPos(pTW->Xpos, pTW->Ypos + pTW->CharHeight); H19ShowCaret(hWnd); return((LONG)count); case WH19_CURSORPOSITION: lines = (pTW->oCurrentLine - pTW->oTopLine) / pTW->MaxCols; if (lines < 0) lines += pTW->MaxLines; if (wParam == H19_SAVECURSOR) SaveCursor(lines, pTW->CurLineOffset); else GetCursor(lines, pTW->CurLineOffset, lParam); break; case WH19_SLAPSCREEN: SlapScreenToClip(pTW); break; case WM_CREATE: TermWndCreate(hWnd, lParam); break; case WM_PAINT: BeginPaint(hWnd, (LPPAINTSTRUCT)&ps); if (!IsRectEmpty((LPRECT)&ps.rcPaint)) TermWndPaint(pTW, (LPPAINTSTRUCT)&ps); EndPaint(hWnd, (LPPAINTSTRUCT)&ps); break; default: return ((long)DefWindowProc(hWnd,message,wParam,lParam)); } return(0L); } /* copy screen to clipboard */ static void NEAR SlapScreenToClip(PTWND pTW) { short cols = pTW->MaxCols; short lines = pTW->MaxLines; HANDLE hGlob = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (LONG)((cols + 2) * lines + 2)); if (hGlob != NULL) { RECT rect; BYTE *pTop = pTW->pVidBuffer; BYTE *lineptr = pTop + pTW->oTopLine; BYTE *pEnd = pTop + pTW->oVidLastLine; BYTE FAR *pGlob = GlobalLock(hGlob); short count; register int i, j; BYTE ch; BYTE *pSource; GetClientRect(pTW->hWnd, &rect); InvertRect(pTW->hDC, &rect); for (i = 0; i < lines; i++) { count = cols; while ((*(lineptr + count - 1) == SP) && (count > 0)) count--; pSource = lineptr; for (j = 0; j < count; j++) { ch = (*pSource++) & 0x7f; if (ch == DEL) ch -= 1; else if (ch < SP) ch += '^'; *pGlob++ = ch; } *pGlob++ = '\r'; *pGlob++ = '\n'; if ((lineptr += cols) > pEnd) lineptr = pTop; } *pGlob = NUL; GlobalUnlock(hGlob); if (OpenClipboard(pTW->hWnd)) { EmptyClipboard(); SetClipboardData(CF_TEXT, hGlob); CloseClipboard(); } else GlobalFree(hGlob); InvertRect(pTW->hDC, &rect); } } /* update the status window */ static void NEAR StatWndPaint(PTWND pSW, LPPAINTSTRUCT ps) { BYTE *pBuf = pSW->pVidBuffer; short xpos = 0; short count = pSW->MaxCols; register short left = ps->rcPaint.left; register short right = pSW->Width - ps->rcPaint.right; short cwidth = pSW->CharWidth; short countchange; if (ps->rcPaint.top < pSW->CharHeight) { if (left >= cwidth) { xpos = left - left % cwidth; countchange = left / cwidth; pBuf += countchange; count -= countchange; } if (right >= cwidth) count -= right / cwidth; ShowLineOfText(ps->hdc,xpos,0,pBuf,count,cwidth); } } /* update the terminal window */ static void NEAR TermWndPaint(PTWND pTW, LPPAINTSTRUCT ps) { register int i; BYTE *pTop = pTW->pVidBuffer; BYTE *lineptr = pTop + pTW->oTopLine; BYTE *pEnd = pTop + pTW->oVidLastLine; short cwidth = pTW->CharWidth; short cheight = pTW->CharHeight; short line1 = 0; short line2 = pTW->MaxLines; short cols = pTW->MaxCols; short count = cols; register short base = 0; short left = ps->rcPaint.left; short right = pTW->Width - ps->rcPaint.right; short top = ps->rcPaint.top; short bottom = pTW->Height - ps->rcPaint.bottom; short xpos = 0; short offset = 0; short countchange; if (left >= cwidth) { xpos = left - left % cwidth; countchange = left / cwidth; offset += countchange; count -= countchange; } if (right >= cwidth) count -= right / cwidth; if (top >= cheight) { line1 = top / cheight; base += line1 * cheight; lineptr += line1 * cols; if (lineptr > pEnd) lineptr = pTop + (lineptr - pEnd) - cols; } if (bottom >= cheight) line2 -= bottom / cheight; for (i = line1; i < line2; i++) { ShowLineOfText(ps->hdc,xpos,base,lineptr+offset,count,cwidth); base += cheight; if ((lineptr += cols) > pEnd) lineptr = pTop; } } /* display a line of text on terminal or status window */ static void NEAR ShowLineOfText(hDC, Xpos, Ypos, lineptr, linewidth, charwidth) HDC hDC; short Xpos, Ypos; BYTE *lineptr; short linewidth, charwidth; { register int i,j; short X; BYTE *sptr, *eptr, ch; BYTE pBuf[TERMMAXCOLS]; i = 0; X = Xpos; sptr = eptr = lineptr; while (i < linewidth) { for (j = 0; j < linewidth - i; j++) if (*eptr++ > DEL) break; SetAttrib(hDC, NORMAL); TextOut(hDC,X,Ypos,(LPSTR)sptr, j); if ((i += j) >= linewidth) break; sptr = --eptr; X += j * charwidth; for (j = 0; j < linewidth - i; j++) if ((ch = *eptr++) <= DEL) break; else pBuf[j] = ch & 0x7f; SetAttrib(hDC, REVERSE); TextOut(hDC,X,Ypos,(LPSTR)pBuf,j); if ((i += j) < linewidth) { X += j * charwidth; sptr = --eptr; } } } /* cursor support routines */ static void NEAR MoveCursorRight(PTWND pTW, WORD count) { register short *offset = &pTW->CurLineOffset; register short *xpos = &pTW->Xpos; short cols = pTW->MaxCols - 1; short width = pTW->CharWidth; while ((*offset < cols) && (count--)) { *offset += 1; *xpos += width; } } static void NEAR MoveCursorLeft(PTWND pTW, WORD count) { register short *offset = &pTW->CurLineOffset; register short *xpos = &pTW->Xpos; short width = pTW->CharWidth; while((*offset > 0) && (count--)) { *offset -= 1; *xpos -= width; } } static void NEAR MoveCursorUp(PTWND pTW, WORD count) { register short *oCurLine = &pTW->oCurrentLine; short top = pTW->oTopLine; if (*oCurLine != top) { register short *ypos = &pTW->Ypos; short cols = pTW->MaxCols; short cheight = pTW->CharHeight; while ((*oCurLine != top) && (count--)) { *ypos -= cheight; if ((*oCurLine -= cols) < 0) *oCurLine = pTW->oVidLastLine; } AdjustWindowToCursor(pTW); } } static void NEAR MoveCursorDown(PTWND pTW, WORD count) { register short *oCurLine = &pTW->oCurrentLine; short bottom = pTW->oBottomLine; if (*oCurLine != bottom) { register short *ypos = &pTW->Ypos; short cols = pTW->MaxCols; short cheight = pTW->CharHeight; short last = pTW->oVidLastLine; while ((*oCurLine != bottom) && (count--)) { *ypos += cheight; if ((*oCurLine += cols) > last) *oCurLine = 0; } AdjustWindowToCursor(pTW); } } /* position window so that cursor is visible */ static void NEAR AdjustWindowToCursor(PTWND pTW) { POINT point; HWND hWnd = pTW->hWnd; short ypos = pTW->Ypos; short width = pTW->Width; short cheight = pTW->CharHeight; register short Y1 = MW.SCTopTextLine; register short Y2 = MW.SCBottomTextLine; short Y; if ((CD.StatOpen) && (CD.StatOverlayTerm)) Y2 -= cheight; point.x = pTW->Xpos; point.y = ypos; ClientToScreen(hWnd, (POINT FAR *)&point); Y = point.y; if (Y < Y1) { MoveWindow(hWnd,0,-ypos, width, pTW->Height, FALSE); ScrollWindow(hWnd,0,Y1-Y, (LPRECT)NULL, (LPRECT)NULL); UpdateWindow(hWnd); } else if (Y > Y2) { MoveWindow(hWnd, 0, Y2-Y1-ypos, width, pTW->Height, FALSE); ScrollWindow(hWnd,0,Y2-Y, (LPRECT)NULL, (LPRECT)NULL); UpdateWindow(hWnd); } } /* display a string */ static int NEAR H19TerminalDisplay(PTWND pTW, BYTE *str, short len) { register BYTE *ptr; register short ctr; short toff, txpos; BYTE *tBuf; BYTE savebuf[TERMMAXCOLS]; HWND hWnd = pTW->hWnd; HDC hDC = pTW->hDC; short cols = pTW->MaxCols; short cwidth = pTW->CharWidth; short width = pTW->Width; BYTE *pBuf = pTW->pVidBuffer; short more_than_one_line = pTW->MaxLines - 1; while (len) { ptr = str; ctr = 0; tBuf = pBuf + pTW->oCurrentLine; toff = pTW->CurLineOffset; txpos = pTW->Xpos; while ((*ptr >= SP) && (*ptr < DEL)) { if ((len) && (toff < cols)) { if (CD.GraphicsMode) if (*ptr == '~') *ptr += 1; else if (*ptr >= '^') *ptr -= '^'; if (CD.ICToggle) savebuf[ctr] = *(tBuf + toff); *(tBuf + toff++) = *ptr++ | CD.CharAttribute; ctr += 1; txpos += cwidth; len -= 1; } else break; } if (ctr) { if (CD.ICToggle) { RECT rect; short ypos = pTW->Ypos; short xpos = pTW->Xpos; short tomove, tocopy; tomove = cols - toff -ctr; tocopy = min (ctr, cols - toff); if (tomove > 0) { memmove(tBuf + toff + ctr, tBuf + toff, tomove); if (tocopy > 0) strncpy(tBuf + toff, savebuf, tocopy); } SetRect(&rect, xpos, ypos, width, ypos + pTW->CharHeight); ScrollWindow(hWnd, txpos - xpos, 0, &rect, &rect); UpdateWindow(hWnd); } else { if (CD.InverseVideo) SetAttrib(hDC, REVERSE); else SetAttrib(hDC, NORMAL); TextOut(hDC, pTW->Xpos, pTW->Ypos, (LPSTR)str, ctr); } if (toff < cols) { pTW->CurLineOffset = toff; pTW->Xpos = txpos; } else { if (CD.WrapAround) { DoCR(pTW); if (more_than_one_line) DoLF(pTW); } else { pTW->CurLineOffset = cols - 1; pTW->Xpos = width - cwidth; } } } while ((*ptr < SP) || (*ptr >= DEL)) { if (len) { switch (*ptr) { case BEL: MessageBeep(0); break; case HT: DoHT(pTW); break; case BS: DoBS(pTW); break; case LF: if (CD.CRonLF) DoCR(pTW); if (more_than_one_line) DoLF(pTW); break; case CR: DoCR(pTW); if (CD.HoldScreen && (pTW->oCurrentLine == pTW->oBottomLine)) { if (CD.ReleaseCount == 0) { SetScroll(); return(len > 0 ? len - 1 : 0); } else CD.ReleaseCount -= 1; } if (CD.LFonCR) if (more_than_one_line) DoLF(pTW); break; } len -= 1; ptr++; } else break; } str = ptr; } return(len); } /* hold screen support */ static void NEAR SetScroll() { BYTE keystate[256]; GetKeyboardState((LPSTR)keystate); keystate[VK_SCROLL] |= 1; SetKeyboardState((LPSTR)keystate); CD.ScrollLock = TRUE; } /* control character modules */ static void NEAR DoLF(PTWND pTW) { HWND hWnd = pTW->hWnd; register short cols = pTW->MaxCols; register oEnd = pTW->oVidLastLine; if ( (pTW->oCurrentLine += cols) > oEnd) pTW->oCurrentLine = 0; if (pTW->oCurrentLine == pTW->oTopLine) { if ((pTW->oTopLine += cols) > oEnd) pTW->oTopLine = 0; if ((pTW->oBottomLine += cols) > oEnd) pTW->oBottomLine = 0; memset(pTW->pVidBuffer + pTW->oCurrentLine, SP, cols); ScrollWindow(hWnd,0,-pTW->CharHeight, (LPRECT)NULL, (LPRECT)NULL); UpdateWindow(hWnd); } else pTW->Ypos += pTW->CharHeight; AdjustWindowToCursor(pTW); } static void NEAR DoCR(PTWND pTW) { pTW->Xpos = pTW->CurLineOffset = 0; } static void NEAR DoBS(PTWND pTW) { if (pTW->CurLineOffset) { pTW->CurLineOffset -= 1; pTW->Xpos -= pTW->CharWidth; } } static void NEAR DoHT(PTWND pTW) { register short offset = pTW->CurLineOffset; if (offset < pTW->MaxCols - 1) { short charwidth = pTW->CharWidth; short limit = pTW->TabLimit; register short xpos = pTW->Xpos; do { xpos += charwidth; } while((++offset % DEF_TABSTOP != 0) && (offset < limit)); pTW->Xpos = xpos; pTW->CurLineOffset = offset; } } /* caret creation and deletion routines */ static void NEAR MakeCaret(PTWND pTW) { register short height; if (CD.BlockCursor) height = -pTW->CharHeight; else height = -2; CreateCaret(pTW->hWnd, (HBITMAP)NULL, pTW->CharWidth, height); } static void NEAR H19ShowCaret(HWND hWnd) { if (!CD.CursorOff) ShowCaret(hWnd); } static void NEAR H19HideCaret(HWND hWnd) { if (!CD.CursorOff) HideCaret(hWnd); } /* set text attributes */ static void NEAR SetAttrib(HDC hDC, int type) { switch (type) { case NORMAL: SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(hDC, GetSysColor(COLOR_WINDOW)); break; case REVERSE: SetTextColor(hDC, GetSysColor(COLOR_WINDOW)); SetBkColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); break; } } /* cursor positioning routines */ static void NEAR PositionCursorRow(PTWND pTW, short y) { register short cols = pTW->MaxCols; register short oCurr = pTW->oTopLine; pTW->Ypos = y * pTW->CharHeight; oCurr += y * cols; if (oCurr > pTW->oVidLastLine) oCurr -= pTW->ScreenSize; pTW->oCurrentLine = oCurr; AdjustWindowToCursor(pTW); } static void NEAR PositionCursorCol(PTWND pTW, short x) { /* if (x >= pTW->MaxCols) x = pTW->MaxCols - 1; */ pTW->Xpos = x * pTW->CharWidth; pTW->CurLineOffset = x; } static void NEAR CursorHome(PTWND pTW) { pTW->Xpos = pTW->Ypos = pTW->CurLineOffset = 0; pTW->oCurrentLine = pTW->oTopLine; AdjustWindowToCursor(pTW); } /* character deletion */ static void NEAR DeleteChar(PTWND pTW, WORD count) { RECT rect; short cols = pTW->MaxCols; short offset = pTW->CurLineOffset; BYTE *dest = pTW->pVidBuffer + pTW->oCurrentLine + offset; HWND hWnd = pTW->hWnd; short ypos = pTW->Ypos; register short copycount; register short maxdelchars; if (count > (maxdelchars = cols - offset)) count = maxdelchars; copycount = maxdelchars - count; memmove(dest, dest + count, copycount); memset(dest+copycount, SP, count); SetRect(&rect, pTW->Xpos, ypos, pTW->Width, ypos + pTW->CharHeight); ScrollWindow(hWnd,-pTW->CharWidth * count,0, &rect, &rect); UpdateWindow(hWnd); } /* clear screen routines */ static void NEAR ClearStatusLine(PTWND pSW) { RECT rect; register HWND hWnd = pSW->hWnd; memset(pSW->pVidBuffer, SP, pSW->MaxCols); SetRect((LPRECT)&rect,0,0,pSW->Width,pSW->CharHeight); InvalidateRect(hWnd, (LPRECT)&rect, TRUE); UpdateWindow(hWnd); } static void NEAR ClearTermWindow(PTWND pTW) { RECT rect; register HWND hWnd = pTW->hWnd; memset(pTW->pVidBuffer, SP, pTW->ScreenSize); pTW->Xpos = pTW->Ypos = pTW->CurLineOffset = 0; pTW->oCurrentLine = pTW->oTopLine = 0; pTW->oBottomLine = pTW->oVidLastLine; SetRect((LPRECT)&rect,0,0,pTW->Width,pTW->Height); InvalidateRect(hWnd, (LPRECT)&rect, TRUE); UpdateWindow(hWnd); AdjustWindowToCursor(pTW); } static void NEAR ClearToEndOfLine(PTWND pTW) { RECT rect; HWND hWnd = pTW->hWnd; register offset = pTW->CurLineOffset; register char *src = pTW->pVidBuffer + pTW->oCurrentLine + offset; memset(src, SP, pTW->MaxCols - offset); SetRect(&rect, pTW->Xpos, pTW->Ypos, pTW->Width, pTW->Ypos+pTW->CharHeight); InvalidateRect(hWnd, (LPRECT)&rect, TRUE); UpdateWindow(hWnd); } static void NEAR ClearToEndOfScreen(PTWND pTW) { RECT rect; char *pBuf = pTW->pVidBuffer; char *pEnd = pBuf + pTW->oVidLastLine; char *pBottom = pBuf + pTW->oBottomLine; register char *base = pBuf + pTW->oCurrentLine; register short cols = pTW->MaxCols; do { if ((base += cols) > pEnd) base = pBuf; memset(base, SP, cols); } while (base != pBottom); SetRect(&rect, 0, pTW->Ypos + pTW->CharHeight, pTW->Width, pTW->Height); InvalidateRect(pTW->hWnd, (LPRECT)&rect, TRUE); UpdateWindow(pTW->hWnd); } static void NEAR ClearToLineStart(PTWND pTW) { HWND hWnd = pTW->hWnd; BYTE *pCurr = pTW->pVidBuffer + pTW->oCurrentLine; RECT rect; register short ypos = pTW->Ypos; register offset = pTW->CurLineOffset + 1; memset(pCurr, SP, offset); SetRect(&rect, 0, ypos, offset * pTW->CharWidth, ypos + pTW->CharHeight); InvalidateRect(hWnd, (LPRECT)&rect, TRUE); UpdateWindow(hWnd); } static void NEAR ClearToScreenTop(PTWND pTW) { RECT rect; HWND hWnd = pTW->hWnd; BYTE *pBuf = pTW->pVidBuffer; BYTE *pTop = pBuf + pTW->oTopLine; BYTE *pEnd = pBuf + pTW->oVidLastLine; register BYTE *base = pBuf + pTW->oCurrentLine; register short cols = pTW->MaxCols; do { if ((base -= cols) < pBuf) base = pEnd; memset(base, SP, cols); } while (base != pTop); SetRect((LPRECT)&rect, 0, 0, pTW->Width, pTW->Ypos); InvalidateRect(hWnd, (LPRECT)&rect, TRUE); UpdateWindow(hWnd); } static void NEAR EraseEntireLine(PTWND pTW) { RECT rect; register HWND hWnd = pTW->hWnd; register short ypos = pTW->Ypos; memset(pTW->pVidBuffer + pTW->oCurrentLine, SP, pTW->MaxCols); SetRect((LPRECT)&rect, 0, ypos, pTW->Width, ypos + pTW->CharHeight); InvalidateRect(hWnd, (LPRECT)&rect, TRUE); UpdateWindow(hWnd); } /* reverse index */ static void NEAR ReverseLF(PTWND pTW) { register short cols = pTW->MaxCols; register short oEnd = pTW->oVidLastLine; if ((pTW->oCurrentLine -= cols) < 0) pTW->oCurrentLine = oEnd; if (pTW->oCurrentLine == pTW->oBottomLine) { if ((pTW->oTopLine -= cols) < 0) pTW->oTopLine = oEnd; if ((pTW->oBottomLine -= cols) < 0) pTW->oBottomLine = oEnd; memset(pTW->pVidBuffer + pTW->oCurrentLine, SP, cols); ScrollWindow(pTW->hWnd,0,pTW->CharHeight,(LPRECT)NULL,(LPRECT)NULL); UpdateWindow(pTW->hWnd); } else pTW->Ypos -= pTW->CharHeight; AdjustWindowToCursor(pTW); } /* line insertion and deletion routines */ static void NEAR InsertLine(PTWND pTW, WORD count) { RECT rect; int i; HWND hWnd = pTW->hWnd; short cols = pTW->MaxCols; short lines = pTW->MaxLines; BYTE *pBuf = pTW->pVidBuffer; BYTE *pCurr = pBuf + pTW->oCurrentLine; BYTE *pEnd = pBuf + pTW->oVidLastLine; register BYTE *dest = pBuf + pTW->oBottomLine; register BYTE *src; if (count > lines) count = lines; if ((src = dest - count * cols) < pBuf) src += pTW->ScreenSize; while (dest != pCurr) { memmove(dest, src, cols); if ((src -= cols) < pBuf) src = pEnd; if ((dest -= cols) < pBuf) dest = pEnd; } src = pCurr; for (i = 0; i < count; i++) { memset(src, SP, cols); if ((src += cols) > pEnd) src = pBuf; } pTW->CurLineOffset = pTW->Xpos = 0; SetRect((LPRECT)&rect, 0, pTW->Ypos, pTW->Width, pTW->Height); ScrollWindow(hWnd, 0, count * pTW->CharHeight, &rect, &rect); UpdateWindow(hWnd); } static void NEAR DeleteLine(PTWND pTW, WORD count) { RECT rect; HWND hWnd = pTW->hWnd; short cols = pTW->MaxCols; BYTE *pBuf = pTW->pVidBuffer; BYTE *dest = pBuf + pTW->oCurrentLine; BYTE *pBottom = pBuf + pTW->oBottomLine; register BYTE *pEnd = pBuf + pTW->oVidLastLine; register BYTE *src; int i; if (count > pTW->MaxLines) count = pTW->MaxLines; if ((src = dest + count * cols) > pEnd) src -= pTW->ScreenSize; while (dest != pBottom) { memmove(dest, src, cols); if ((src += cols) > pEnd) src = pBuf; if ((dest += cols) > pEnd) dest = pBuf; } src = pBottom; for (i = 0; i < count; i++) { memset(src, SP, cols); if ((src -= cols) < pBuf) src = pEnd; } pTW->CurLineOffset = pTW->Xpos = 0; SetRect((LPRECT)&rect,0,pTW->Ypos,pTW->Width,pTW->Height); ScrollWindow(hWnd,0, -count * pTW->CharHeight, &rect, &rect); UpdateWindow(hWnd); } /* cursor save and restore */ static void NEAR SaveCursor(short line, short column) { CD.CurSaveRow = line; CD.CurSaveCol = column; } static void NEAR GetCursor(short lines, short cols, LONG lParam) { short *x, *y; x = (short *)LOWORD(lParam); y = (short *)HIWORD(lParam); *x = lines; *y = cols; }