/* emul.c */ #include "windows.h" #include "screen.h" static int ScreenEmChars(SCREEN *pScr, char *c, int len) { /* * Function: Send a string of characters to the screen. Placement * continues as long as the stream of characters does not contain any * control chracters or cause wrapping to another line. When a control * character is encountered or wrapping occurs, display stops and a * count of the number of characters is returned. * * Parameters: * pScr - the screen to place the characters on. * c - the string of characters to place on the screen. * len - the number of characters contained in the string * * Returns: The number of characters actually placed on the screen. */ int insert; int ocount; int attrib; int extra; int nchars; char *acurrent; /* place to put attributes */ char *current; /* place to put characters */ char *start; SCREENLINE *pScrLine; if (len <= 0) return(0); if (pScr->x != pScr->width - 1) pScr->bWrapPending = FALSE; else { if (pScr->bWrapPending) { pScr->x = 0; pScr->bWrapPending = FALSE; ScreenIndex(pScr); } } pScrLine = GetScreenLineFromY(pScr, pScr->y); if (pScrLine == NULL) return(0); current = &pScrLine->text[pScr->x]; acurrent = &pScrLine->attrib[pScr->x]; start = current; ocount = pScr->x; extra = 0; attrib = pScr->attrib; insert = pScr->IRM; for (nchars = 0; nchars < len && *c >= 32; nchars++) { if (insert) ScreenInsChar(pScr, 1); *current = *c; *acurrent = (char) attrib; c++; if (pScr->x < pScr->width - 1) { acurrent++; current++; pScr->x++; } else { extra = 1; if (pScr->DECAWM) { pScr->bWrapPending = TRUE; nchars++; break; } } } ScreenDraw(pScr, ocount, pScr->y, pScr->attrib, pScr->x - ocount + extra, start); return(nchars); } void ScreenEm(LPSTR c, int len, SCREEN *pScr) { int escflg; /* vt100 escape level */ RECT rc; unsigned int ic; char stat[20]; int i; int nchars; if (pScr->screen_bottom != pScr->buffer_bottom) { ScreenUnscroll(pScr); InvalidateRect(pScr->hWnd, NULL, TRUE); SetScrollPos(pScr->hWnd, SB_VERT, pScr->numlines, TRUE); } ScreenCursorOff(pScr); escflg = pScr->escflg; #ifdef UM if (pScr->localprint && len > 0) { /* see if printer needs anything */ pcount = send_localprint(c, len); len -= pcount; c += pcount; } #endif while (len > 0) { /* * look at first character in the vt100 string, if it is a * non-printable ascii code */ while((*c < 32) && (escflg == 0) && (len > 0)) { switch(*c) { case 0x1b: /* ESC found (begin vt100 control sequence) */ escflg++; break; case -1: /* IAC from telnet session */ escflg = 6; break; #ifdef CISB case 0x05: /* CTRL-E found (answerback) */ bp_ENQ(); break; #endif case 0x07: /* CTRL-G found (bell) */ ScreenBell(pScr); break; case 0x08: /* CTRL-H found (backspace) */ ScreenBackspace(pScr); break; case 0x09: /* CTRL-I found (tab) */ ScreenTab(pScr); /* Later change for versatile tabbing */ break; case 0x0a: /* CTRL-J found (line feed) */ case 0x0b: /* CTRL-K found (treat as line feed) */ case 0x0c: /* CTRL-L found (treat as line feed) */ ScreenIndex(pScr); break; case 0x0d: /* CTRL-M found (carriage feed) */ ScreenCarriageFeed(pScr); break; #if 0 case 0x0e: /* CTRL-N found (invoke Graphics (G1) character set) */ if (pScr->G1) pScr->attrib = VSgraph(pScr->attrib); else pScr->attrib = VSnotgraph(pScr->attrib); pScr->charset = 1; break; case 0x0f: /* CTRL-O found (invoke 'normal' (G0) character set) */ if(pScr->G0) pScr->attrib = VSgraph(pScr->attrib); else pScr->attrib = VSnotgraph(pScr->attrib); pScr->charset = 0; break; #endif #ifdef CISB case 0x10: /* CTRL-P found (undocumented in vt100) */ bp_DLE(c, len); len = 0; break; #endif #if 0 case 0x11: /* CTRL-Q found (XON) (unused presently) */ case 0x13: /* CTRL-S found (XOFF) (unused presently) */ case 0x18: /* CTRL-X found (CAN) (unused presently) */ case 0x1a: /* CTRL-Z found (SUB) (unused presently) */ break; #endif } c++; /* advance to the next character in the string */ len--; /* decrement the counter */ } if (escflg == 0) { /* check for normal character to print */ nchars = ScreenEmChars(pScr, c, len); c += nchars; len -= nchars; } while ((len > 0) && (escflg == 1)) { /* ESC character was found */ switch(*c) { case 0x08: /* CTRL-H found (backspace) */ ScreenBackspace(pScr); break; /* * mostly cursor movement options, and DEC private stuff following */ case '[': ScreenApClear(pScr); escflg = 2; break; case '#': /* various screen adjustments */ escflg = 3; break; case '(': /* G0 character set options */ escflg = 4; break; case ')': /* G1 character set options */ escflg = 5; break; case '>': /* keypad numeric mode (DECKPAM) */ pScr->DECPAM = 0; escflg = 0; break; case '=': /* keypad application mode (DECKPAM) */ pScr->DECPAM = 1; escflg = 0; break; case '7': /* save cursor (DECSC) */ ScreenSaveCursor(pScr); escflg = 0; break; case '8': /* restore cursor (DECRC) */ ScreenRestoreCursor(pScr); escflg = 0; break; #if 0 case 'c': /* reset to initial state (RIS) */ ScreenReset(pScr); escflg = 0; break; #endif case 'D': /* index (move down one line) (IND) */ ScreenIndex(pScr); escflg = 0; break; case 'E': /* next line (move down one line and to first column) (NEL) */ pScr->x = 0; ScreenIndex(pScr); escflg = 0; break; case 'H': /* horizontal tab set (HTS) */ pScr->tabs[pScr->x] = 'x'; escflg = 0; break; #ifdef CISB case 'I': /* undoumented in vt100 */ bp_ESC_I(); break; #endif case 'M': /* reverse index (move up one line) (RI) */ ScreenRevIndex(pScr); escflg = 0; break; case 'Z': /* identify terminal (DECID) */ escflg = 0; break; default: /* put the ESC character into the Screen */ ScreenEmChars(pScr, "\033", 1); /* put the next character into the Screen */ ScreenEmChars(pScr, c, 1); escflg = 0; break; } /* end switch */ c++; len--; } while((escflg == 2) && (len > 0)) { /* '[' handling */ switch(*c) { case 0x08: /* backspace */ ScreenBackspace(pScr); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* numeric parameters */ if (pScr->parms[pScr->parmptr] < 0) pScr->parms[pScr->parmptr] = 0; pScr->parms[pScr->parmptr] *= 10; pScr->parms[pScr->parmptr] += *c - '0'; break; case '?': /* vt100 mode change */ pScr->parms[pScr->parmptr++] = -2; break; case ';': /* parameter divider */ pScr->parmptr++; break; case 'A': /* cursor up (CUU) */ pScr->bWrapPending = FALSE; rc.left = pScr->x * pScr->cxChar; rc.right = (pScr->x + 1) * pScr->cxChar; rc.top = pScr->cyChar * pScr->y; rc.bottom = pScr->cyChar * (pScr->y + 1); InvalidateRect(pScr->hWnd, &rc, TRUE); if (pScr->parms[0] < 1) pScr->y--; else pScr->y -= pScr->parms[0]; if(pScr->y < pScr->top) pScr->y = pScr->top; ScreenRange(pScr); escflg = 0; SendMessage(pScr->hWnd, WM_PAINT, 0, 0); break; case 'B': /* cursor down (CUD) */ pScr->bWrapPending = FALSE; rc.left = pScr->x * pScr->cxChar; rc.right = (pScr->x + 1) * pScr->cxChar; rc.top = pScr->cyChar * pScr->y; rc.bottom = pScr->cyChar * (pScr->y + 1); InvalidateRect(pScr->hWnd, &rc, TRUE); if (pScr->parms[0] < 1) pScr->y++; else pScr->y += pScr->parms[0]; if (pScr->y > pScr->bottom) pScr->y = pScr->bottom; ScreenRange(pScr); escflg = 0; SendMessage(pScr->hWnd, WM_PAINT, 0, 0); break; case 'C': /* cursor forward (right) (CUF) */ pScr->bWrapPending = FALSE; rc.left = pScr->x * pScr->cxChar; rc.right = (pScr->x + 1) * pScr->cxChar; rc.top = pScr->cyChar * pScr->y; rc.bottom = pScr->cyChar * (pScr->y +1); InvalidateRect(pScr->hWnd, &rc, TRUE); if(pScr->parms[0] < 1) pScr->x++; else pScr->x += pScr->parms[0]; ScreenRange(pScr); if (pScr->x > pScr->width) pScr->x = pScr->width; escflg = 0; SendMessage(pScr->hWnd, WM_PAINT, 0, 0); break; case 'D': /* cursor backward (left) (CUB) */ pScr->bWrapPending = FALSE; rc.left = pScr->x * pScr->cxChar; rc.right = (pScr->x + 1) * pScr->cxChar; rc.top = pScr->cyChar * pScr->y; rc.bottom = pScr->cyChar * (pScr->y + 1); InvalidateRect(pScr->hWnd, &rc, TRUE); if(pScr->parms[0] < 1) pScr->x--; else pScr->x -= pScr->parms[0]; ScreenRange(pScr); escflg = 0; SendMessage(pScr->hWnd, WM_PAINT, 0, 0); break; case 'f': /* horizontal & vertical position (HVP) */ case 'H': /* cursor position (CUP) */ pScr->bWrapPending = FALSE; rc.left = pScr->x * pScr->cxChar; rc.right = (pScr->x + 1) * pScr->cxChar; rc.top = pScr->cyChar * pScr->y; rc.bottom = pScr->cyChar * (pScr->y + 1); InvalidateRect(pScr->hWnd, &rc, TRUE); pScr->x = pScr->parms[1] - 1; pScr->y = pScr->parms[0] - 1; ScreenRange(pScr); /* make certain the cursor position is valid */ escflg = 0; SendMessage(pScr->hWnd, WM_PAINT, 0, 0); break; case 'J': /* erase in display (ED) */ switch(pScr->parms[0]) { case -1: case 0: /* erase from active position to end of screen */ ScreenEraseToEndOfScreen(pScr); break; case 1: /* erase from start of screen to active position */ #if 0 ScreenEraseToPosition(pScr); #endif break; case 2: /* erase whole screen */ ScreenEraseScreen(pScr); break; default: break; } escflg = 0; break; case 'K': /* erase in line (EL) */ switch(pScr->parms[0]) { case -1: case 0: /* erase to end of line */ ScreenEraseToEOL(pScr); break; case 1: /* erase to beginning of line */ ScreenEraseToBOL(pScr); break; case 2: /* erase whole line */ ScreenEraseLine(pScr, -1); break; default: break; } escflg = 0; break; case 'L': /* insert n lines preceding current line (IL) */ if (pScr->parms[0] < 1) pScr->parms[0] = 1; ScreenInsLines(pScr, pScr->parms[0], -1); escflg = 0; break; case 'M': /* delete n lines from current position downward (DL) */ if (pScr->parms[0] < 1) pScr->parms[0] = 1; ScreenDelLines(pScr, pScr->parms[0], -1); escflg = 0; break; case 'P': /* delete n chars from cursor to the left (DCH) */ if (pScr->parms[0] < 1) pScr->parms[0] = 1; ScreenDelChars(pScr, pScr->parms[0]); escflg = 0; break; #if 0 case 'R': /* receive cursor position status from host */ break; #endif #if 0 case 'c': /* device attributes (DA) */ ScreenSendIdent(); escflg = 0; break; #endif case 'g': /* tabulation clear (TBC) */ if (pScr->parms[0] == 3)/* clear all tabs */ ScreenTabClear(pScr); else if (pScr->parms[0] <= 0) /* clear tab stop at active position */ pScr->tabs[pScr->x] = ' '; escflg = 0; break; case 'h': /* set mode (SM) */ ScreenSetOption(pScr,1); escflg = 0; break; case 'i': /* toggle printer */ #if 0 if(pScr->parms[pScr->parmptr] == 5) pScr->localprint = 1; else if (pScr->parms[pScr->parmptr] == 4) pScr->localprint = 0; #endif escflg = 0; break; case 'l': /* reset mode (RM) */ ScreenSetOption(pScr,0); escflg = 0; break; case 'm': /* select graphics rendition (SGR) */ { int temp = 0; while (temp <= pScr->parmptr) { if (pScr->parms[temp] < 1) pScr->attrib &= 128; else pScr->attrib |= 1 << (pScr->parms[temp] - 1); temp++; } } escflg = 0; break; case 'n': /* device status report (DSR) */ switch (pScr->parms[0]) { #if 0 case 0: /* response from vt100; ready, no malfunctions */ case 3: /* response from vt100; malfunction, retry */ #endif case 5: /* send status */ case 6: /* send active position */ wsprintf(stat, "\033[%d;%dR", pScr->y + 1, pScr->x + 1); for (i = 0; stat[i]; i++) SendMessage(pScr->hwndTel, WM_MYSCREENCHAR, stat[i], (LPARAM) pScr); break; } /* end switch */ escflg = 0; break; case 'q': /* load LEDs (unsupported) (DECLL) */ escflg = 0; break; case 'r': /* set top & bottom margins (DECSTBM) */ if (pScr->parms[0] < 0) pScr->top = 0; else pScr->top = pScr->parms[0] - 1; if (pScr->parms[1] < 0) pScr->bottom = pScr->height - 1; else pScr->bottom = pScr->parms[1] - 1; if (pScr->top < 0) pScr->top = 0; if (pScr->top > pScr->height-1) pScr->top = pScr->height-1; if (pScr->bottom < 1) pScr->bottom = pScr->height; if (pScr->bottom >= pScr->height) pScr->bottom = pScr->height - 1; if (pScr->top >= pScr->bottom) {/* check for valid scrolling region */ if (pScr->bottom >= 1) /* * assume the bottom value has * precedence, unless it is as the * top of the screen */ pScr->top = pScr->bottom - 1; else /* totally psychotic case, bottom of screen set to the very top line, move the bottom to below the top */ pScr->bottom = pScr->top + 1; } pScr->x = 0; pScr->y = 0; #if 0 if (pScr->DECORG) pScr->y = pScr->top; /* origin mode relative */ #endif escflg = 0; break; #if 0 case 'x': /* request/report terminal parameters (DECREQTPARM/DECREPTPARM) */ case 'y': /* invoke confidence test (DECTST) */ break; #endif default: escflg = 0; break; } c++; len--; #if 0 if (pScr->localprint && (len > 0)) { /* see if printer needs anything */ pcount = send_localprint(c, len); len -= pcount; c += pcount; } #endif } while ((escflg == 3) && (len > 0)) { /* # Handling */ switch (*c) { case 0x08: /* backspace */ ScreenBackspace(pScr); break; #if 0 case '3': /* top half of double line (DECDHL) */ case '4': /* bottom half of double line (DECDHL) */ case '5': /* single width line (DECSWL) */ case '6': /* double width line (DECDWL) */ break; #endif case '8': /* screen alignment display (DECALN) */ ScreenAlign(pScr); escflg = 0; break; default: escflg = 0; break; } c++; len--; } while ((escflg == 4) && (len > 0)) { /* ( Handling (GO character set) */ switch (*c) { case 0x08: /* backspace */ ScreenBackspace(pScr); break; #if 0 case 'A': /* united kingdom character set (unsupported) */ case 'B': /* ASCII character set */ case '1': /* choose standard graphics (same as ASCII) */ pScr->G0 = 0; if (!pScr->charset) pScr->attrib = ScreenNotGraph(pScr->attrib); escflg = 0; break; case '0': /* choose special graphics set */ case '2': /* alternate character set (special graphics) */ pScr->G0 = 1; if(!pScr->charset) pScr->attrib = ScreenGraph(pScr->attrib); escflg = 0; break; #endif default: escflg = 0; break; } c++; len--; } /* end while */ while((escflg == 5) && (len > 0)) { /* ) Handling (G1 handling) */ switch (*c) { case 0x08: /* backspace */ ScreenBackspace(pScr); break; #if 0 case 'A': /* united kingdom character set (unsupported) */ case 'B': /* ASCII character set */ case '1': /* choose standard graphics (same as ASCII) */ pScr->G1 = 0; if (pScr->charset) pScr->attrib = ScreenNotGraph(pScr->attrib); escflg = 0; break; case '0': /* choose special graphics set */ case '2': /* alternate character set (special graphics) */ pScr->G1 = 1; if(pScr->charset) pScr->attrib = ScreenGraph(pScr->attrib); escflg = 0; break; #endif default: escflg = 0; break; } /* end switch */ c++; len--; } /* end while */ while ((escflg >= 6) && (escflg <= 10) && (len > 0)) { /* Handling IAC */ ic = (unsigned char) *c; switch (escflg) { case 6: /* Handling IAC xx */ if (ic == 255) /* if IAC */ escflg = 0; else if (ic == 250) /* if SB */ escflg = 7; else escflg = 9; break; case 7: /* Handling IAC SB xx */ if (ic == 255) /* if IAC */ escflg = 8; break; case 8: /* Handling IAC SB IAC xx */ if (ic == 255) /* if IAC IAC */ escflg = 7; else if (ic == 240) /* if IAC SE */ escflg = 0; break; case 9: /* IAC xx xx */ escflg = 0; break; } c++; /* advance to the next character in the string */ len--; /* decrement the counter */ } if (escflg > 2 && escflg < 6 && len > 0) { escflg = 0; c++; len--; } } pScr->escflg = escflg; ScreenCursorOn(pScr); }