/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is lineterm. * * The Initial Developer of the Original Code is * Ramalingam Saravanan. * Portions created by the Initial Developer are Copyright (C) 1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* ltermEscape.c: LTERM escape sequence processing */ /* public declarations */ #include "lineterm.h" /* private declarations */ #include "ltermPrivate.h" static int ltermProcessCSISequence(struct lterms *lts, const UNICHAR *buf, int count, const UNISTYLE *style, int *consumed, int *opcodes, int *opvals, int *oprow); static int ltermProcessDECPrivateMode(struct lterms *lts, const int *paramValues, int paramCount, UNICHAR uch, int *opcodes); static int ltermProcessXTERMSequence(struct lterms *lts, const UNICHAR *buf, int count, const UNISTYLE *style,int *consumed,int *opcodes); static int ltermProcessXMLTermSequence(struct lterms *lts, const UNICHAR *buf, int count, const UNISTYLE *style,int *consumed,int *opcodes); /** Processes ESCAPE sequence in string BUF containing COUNT characters, * returning the number of characters CONSUMED and the OPCODES. * Using Extended Backus-Naur Form notation: * OPCODES ::= 0 if the sequence was processed without any change of * outputMode or terminating condition. * OPCODES ::= LINEDATA OUTPUT if a switch from LineMode to ScreenMode * or StreamMode was triggered by the ESCAPE sqeuence. * OPCODES ::= SCREENDATA ( CLEAR | INSERT | DELETE | SCROLL )? * for screenMode escape sequences or if a switch from ScreenMode to StreamMode * was triggered by the ESCAPE sequence. * (A switch from ScreenMode to LineMode is not considered a terminating * condition and occurs transparently.) * OPVALS contains return value(s) for specific screen operations * such as INSERT, DELETE, and SCROLL. * OPROW contains the row value for specific screen operations such as * INSERT, DELETE, and SCROLL (or -1, cursor row is to be used). * * OPVALS contains return value(s) for specific screen operations * such as INSERT and DELETE. * OPROW contains the row value for specific screen operations such as * INSERT and DELETE (or -1, cursor row is to be used). * * @return 0 on successful processing of the ESCAPE sequence, * 1 if BUF contains an incomplete ESCAPE sequence, * -1 if error an error occurred. */ int ltermProcessEscape(struct lterms *lts, const UNICHAR *buf, int count, const UNISTYLE *style, int *consumed, int *opcodes, int *opvals, int *oprow) { struct LtermOutput *lto = &(lts->ltermOutput); LTERM_LOG(ltermProcessEscape,50,("count=%d, buf[1]=0x%x, cursorChar=%d, Chars=%d\n", count, buf[1], lto->outputCursorChar, lto->outputChars)); if (count < 2) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } if (buf[1] == U_LBRACKET) { /* ESC [ Process CSI sequence */ return ltermProcessCSISequence(lts, buf, count, style, consumed, opcodes, opvals, oprow); } if (buf[1] == U_RBRACKET) { /* ESC ] Process XTERM sequence */ return ltermProcessXTERMSequence(lts, buf, count, style, consumed, opcodes); } if (buf[1] == U_LCURLY) { /* ESC { Process XMLTerm sequence */ return ltermProcessXMLTermSequence(lts, buf, count, style, consumed, opcodes); } /* Assume two characters will be consumed at this point */ *consumed = 2; switch (buf[1]) { /* Three character sequences */ case U_NUMBER: /* ESC # 8 DEC Screen Alignment Test */ case U_LPAREN: /* ESC ( C Designate G0 Character Set */ case U_RPAREN: /* ESC ) C Designate G1 Character Set */ case U_STAR: /* ESC * C Designate G2 Character Set */ case U_PLUS: /* ESC + C Designate G3 Character Set */ case U_DOLLAR: /* ESC $ C Designate Kanji Character Set */ LTERM_LOG(ltermProcessEscape,51,("3 char sequence, buf[1:2]=0x%x,0x%x\n", buf[1], buf[2])); if (count < 3) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } *consumed = 3; if (buf[1] == U_NUMBER) { /* ESC # 8 DEC Screen Alignment Test */ } else { /* ESC ()*+$ C Designate Character Set */ } return 0; /* Two character sequences */ case U_SEVEN: /* ESC 7 Save Cursor */ LTERM_LOG(ltermProcessEscape,2,("Unimplemented 0x%x\n", buf[1])); return 0; case U_EIGHT: /* ESC 8 Restore Cursor */ LTERM_LOG(ltermProcessEscape,2,("Unimplemented 0x%x\n", buf[1])); return 0; case U_EQUALS: /* ESC = Application Keypad */ LTERM_LOG(ltermProcessEscape,52,("Application Keypad\n")); if (lto->outputMode == LTERM2_LINE_MODE) { ltermSwitchToScreenMode(lts); *opcodes = LTERM_LINEDATA_CODE | LTERM_OUTPUT_CODE; } return 0; case U_GREATERTHAN: /* ESC > Normal Keypad */ LTERM_LOG(ltermProcessEscape,52,("Normal Keypad\n")); if (lto->outputMode == LTERM1_SCREEN_MODE) { ltermSwitchToLineMode(lts); *opcodes = LTERM_SCREENDATA_CODE | LTERM_CLEAR_CODE; } return 0; case U_D_CHAR: /* ESC D Index (IND) */ LTERM_LOG(ltermProcessEscape,52,("Index\n")); if (lto->outputMode == LTERM1_SCREEN_MODE) { /* Scroll up */ if (ltermInsDelEraseLine(lts, 1, lto->topScrollRow, LTERM_DELETE_ACTION) != 0) return -1; *opcodes = LTERM_SCREENDATA_CODE | LTERM_DELETE_CODE; *opvals = 1; *oprow = lto->topScrollRow; } return 0; case U_E_CHAR: /* ESC E Next Line (NEL) */ if (lto->outputMode == LTERM1_SCREEN_MODE) { if (lto->cursorRow > 0) lto->cursorRow--; } return 0; case U_H_CHAR: /* ESC H Tab Set (HTS) */ LTERM_LOG(ltermProcessEscape,2,("Unimplemented 0x%x\n", buf[1])); return 0; case U_M_CHAR: /* ESC M Reverse Index (TI) */ LTERM_LOG(ltermProcessEscape,52,("Reverse Index\n")); if (lto->outputMode == LTERM1_SCREEN_MODE) { /* Scroll down */ if (ltermInsDelEraseLine(lts, 1, lto->topScrollRow, LTERM_INSERT_ACTION) != 0) return -1; *opcodes = LTERM_SCREENDATA_CODE | LTERM_INSERT_CODE; *opvals = 1; *oprow = lto->topScrollRow; } return 0; case U_N_CHAR: /* ESC N Single Shift Select of G2 Character Set */ LTERM_LOG(ltermProcessEscape,2,("Unimplemented 0x%x\n", buf[1])); return 0; case U_O_CHAR: /* ESC O Single Shift Select of G3 Character Set */ LTERM_LOG(ltermProcessEscape,2,("Unimplemented 0x%x\n", buf[1])); return 0; case U_Z_CHAR: /* ESC Z Obsolete form of ESC[c */ LTERM_LOG(ltermProcessEscape,2,("Unimplemented 0x%x\n", buf[1])); return 0; case U_c_CHAR: /* ESC c Full reset (RIS) */ LTERM_LOG(ltermProcessEscape,2,("Unimplemented 0x%x\n", buf[1])); return 0; case U_n_CHAR: /* ESC n Invoke the G2 Character Set */ LTERM_LOG(ltermProcessEscape,2,("Unimplemented 0x%x\n", buf[1])); return 0; case U_o_CHAR: /* ESC o Invoke the G3 Character Set */ LTERM_LOG(ltermProcessEscape,2,("Unimplemented 0x%x\n", buf[1])); return 0; default: LTERM_WARNING("ltermProcessEscape: Warning - unknown sequence 0x%x\n", buf[1]); return 0; } } /** Processes CSI sequence (a special case of Escape sequence processing) * @return 0 on success and -1 on error. */ static int ltermProcessCSISequence(struct lterms *lts, const UNICHAR *buf, int count, const UNISTYLE *style, int *consumed, int *opcodes, int *opvals, int *oprow) { struct LtermOutput *lto = &(lts->ltermOutput); int offset, value, privateMode; int paramCount, paramValues[MAXESCAPEPARAMS], param1, param2; if (count < 3) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } LTERM_LOG(ltermProcessCSISequence,50,("buf[2]=0x%x, cursorChar=%d, Chars=%d\n", buf[2], lto->outputCursorChar, lto->outputChars)); privateMode = 0; offset = 2; if (buf[2] == U_QUERYMARK) { /* ESC [ ? Process DEC Private Mode */ privateMode = 1; offset = 3; } /* Process numerical parameters */ paramCount = 0; while ((offset < count) && ((buf[offset] >= (UNICHAR)U_ZERO) && (buf[offset] <= (UNICHAR)U_NINE)) ) { /* Starts with a digit */ value = buf[offset] - U_ZERO; offset++; /* Process all contiguous digits */ while ((offset < count) && ((buf[offset] >= (UNICHAR)U_ZERO) && (buf[offset] <= (UNICHAR)U_NINE)) ) { value = value * 10 + buf[offset] - U_ZERO; offset++; } if (offset == count) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } if (paramCount < MAXESCAPEPARAMS) { /* Store numerical parameter */ paramValues[paramCount++] = value; } else { /* Numeric parameter buffer overflow */ LTERM_WARNING("ltermProcessCSISequence: Warning - numeric parameter buffer overflow\n"); } /* If next character not semicolon, stop processing */ if (buf[offset] != U_SEMICOLON) break; /* Process next argument */ offset++; } if (offset == count) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } /* Assume that all parsed characters will be consumed at this point */ *consumed = offset+1; LTERM_LOG(ltermProcessCSISequence,51,("paramCount=%d, offset=%d, buf[offset]='%d'\n", paramCount, offset, buf[offset])); if (privateMode) { /* ESC [ ? Process DEC Private Mode */ return ltermProcessDECPrivateMode( lts, paramValues, paramCount, buf[offset], opcodes); } /* Set returned opcodes to zero */ *opcodes = 0; /* Default parameter values: 1, 1 */ param1 = (paramCount > 0) ? paramValues[0] : 1; param2 = (paramCount > 1) ? paramValues[1] : 1; switch (buf[offset]) { case U_ATSIGN: /* Insert Ps (Blank) Character(s) [default: 1] (ICH) */ if (ltermInsDelEraseChar(lts, param1, LTERM_INSERT_ACTION) != 0) return -1; return 0; case U_e_CHAR: case U_A_CHAR: /* Cursor Up Ps Times [default: 1] (CUU) */ LTERM_LOG(ltermProcessCSISequence,52,("Cursor Up Count = %d\n", param1)); if (lto->outputMode == LTERM1_SCREEN_MODE) { lto->cursorRow += param1; if (lto->cursorRow >= lts->nRows) lto->cursorRow = lts->nRows - 1; } return 0; case U_B_CHAR: /* Cursor Down Ps Times [default: 1] (CUD) */ LTERM_LOG(ltermProcessCSISequence,52,("Cursor Down Count = %d\n", param1)); if (lto->outputMode == LTERM1_SCREEN_MODE) { lto->cursorRow -= param1; if (lto->cursorRow < 0) lto->cursorRow = 0; } return 0; case U_a_CHAR: case U_C_CHAR: /* Cursor Forward Ps Times [default: 1] (CUF) */ LTERM_LOG(ltermProcessCSISequence,52,("Cursor Forward Count = %d\n", param1)); if (lto->outputMode == LTERM2_LINE_MODE) { if (param1 <= (lto->outputChars - lto->outputCursorChar)) { lto->outputCursorChar += param1; } else { lto->outputCursorChar = lto->outputChars; } } else { lto->cursorCol += param1; if (lto->cursorCol >= lts->nCols) lto->cursorCol = lts->nCols-1; } return 0; case U_D_CHAR: /* Cursor Backward Ps Times [default: 1] (CUB) */ LTERM_LOG(ltermProcessCSISequence,52,("Cursor Back Count = %d\n", param1)); if (lto->outputMode == LTERM2_LINE_MODE) { if (param1 <= lto->outputCursorChar) { lto->outputCursorChar -= param1; } else { lto->outputCursorChar = 0; } } else { lto->cursorCol -= param1; if (lto->cursorCol < 0) lto->cursorCol = 0; } return 0; case U_E_CHAR: /* Cursor Down Ps Times [default: 1] and to first column */ LTERM_LOG(ltermProcessCSISequence,52,("Cursor Down and First Count = %d\n", param1)); if (lto->outputMode == LTERM1_SCREEN_MODE) { lto->cursorCol = 0; lto->cursorRow -= param1; if (lto->cursorRow < 0) lto->cursorRow = 0; } return 0; case U_F_CHAR: /* Cursor Up Ps Times [default: 1] and to first column */ LTERM_LOG(ltermProcessCSISequence,52,("Cursor Up and First Count = %d\n", param1)); if (lto->outputMode == LTERM1_SCREEN_MODE) { lto->cursorCol = 0; lto->cursorRow += param1; if (lto->cursorRow >= lts->nRows) lto->cursorRow = lts->nRows - 1; } return 0; case U_SNGLQUOTE: case U_G_CHAR: /* Cursor to Column Ps (HPA) */ LTERM_LOG(ltermProcessCSISequence,52,("Cursor to Column = %d\n", param1)); if (lto->outputMode == LTERM1_SCREEN_MODE) { lto->cursorCol = param1-1; if (lto->cursorCol < 0) { lto->cursorCol = 0; } else if (lto->cursorCol >= lts->nCols) { lto->cursorCol = lts->nCols - 1; } } return 0; case U_H_CHAR: /* Cursor Position [row;column] [default: 1;1] (CUP) */ LTERM_LOG(ltermProcessCSISequence,52,("Cursor Position = (%d, %d)\n", param1, param2)); if (lto->outputMode == LTERM2_LINE_MODE) { /* Line mode */ if ((param1 > 0) && ((param1-1) <= lto->outputChars)) { lto->outputCursorChar = param1-1; } else { lto->outputCursorChar = 0; } } else { /* Screen mode */ lto->cursorRow = lts->nRows - param1; if (lto->cursorRow < 0) { lto->cursorRow = 0; } else if (lto->cursorRow >= lts->nRows) { lto->cursorRow = lts->nRows - 1; } lto->cursorCol = param2 - 1; if (lto->cursorCol < 0) { lto->cursorCol = 0; } else if (lto->cursorCol >= lts->nCols) { lto->cursorCol = lts->nCols - 1; } } return 0; case U_I_CHAR: /* Move forward Ps tab stops [default: 1] */ LTERM_LOG(ltermProcessCSISequence,2,("Unimplemented 0x%x\n", buf[offset])); return 0; case U_J_CHAR: /* Erase in Display (ED) * Ps = 0 Clear Below (default) * Ps = 1 Clear Above * Ps = 2 Clear All */ param1 = (paramCount > 0) ? paramValues[0] : 0; LTERM_LOG(ltermProcessCSISequence,52,("Erase display code %d\n", param1)); if (lto->outputMode == LTERM2_LINE_MODE) { /* Clear line */ ltermClearOutputLine(lts); /* Set opcodes to return incomplete line */ *opcodes = LTERM_LINEDATA_CODE; } else { /* Screen mode */ int eraseLines, j; if ((param1 == 0) && (lto->cursorRow == lts->nRows-1)) param1 = 2; switch (param1) { case 0: /* Clear below */ eraseLines = lto->cursorRow + 1; if (ltermInsDelEraseLine(lts, eraseLines, lto->cursorRow, LTERM_ERASE_ACTION) != 0) return -1; /* Set line modification flags */ for (j=0; j<=lto->cursorRow; j++) { lto->modifiedCol[j] = lts->nCols-1; } break; case 1: /* Clear above */ eraseLines = lts->nRows - lto->cursorRow - 1; if (ltermInsDelEraseLine(lts, eraseLines, lts->nRows-1, LTERM_ERASE_ACTION) != 0) return -1; /* Set line modification flags */ for (j=lto->cursorRow; jnRows; j++) { lto->modifiedCol[j] = lts->nCols-1; } break; case 2: /* Clear all */ eraseLines = lts->nRows; if (ltermInsDelEraseLine(lts, eraseLines, lts->nRows-1, LTERM_ERASE_ACTION) != 0) return -1; /* Clear screen */ *opcodes = LTERM_SCREENDATA_CODE|LTERM_CLEAR_CODE; break; default: /* Invalid line erase code */ LTERM_WARNING("ltermProcessCSISequence: Warning - invalid line erase code %d\n", param1); } } return 0; case U_K_CHAR: /* Erase in Line (EL) * Ps = 0 Clear to Right (default) * Ps = 1 Clear to Left * Ps = 2 Clear All */ param1 = (paramCount > 0) ? paramValues[0] : 0; LTERM_LOG(ltermProcessCSISequence,52,("Line erase code %d\n", param1)); if (lto->outputMode == LTERM2_LINE_MODE) { /* Line mode */ switch(param1) { case 0: /* Clear to Right */ lto->outputChars = lto->outputCursorChar; lto->outputModifiedChar = lto->outputCursorChar; break; case 1: /* Clear to Left */ lto->outputChars -= lto->outputCursorChar; lto->outputCursorChar = 0; lto->outputModifiedChar = 0; break; case 2: /* Clear All */ lto->outputChars = 0; lto->outputCursorChar = 0; lto->outputModifiedChar = 0; break; default: /* Invalid char erase code */ LTERM_WARNING("ltermProcessCSISequence: Warning - invalid char erase code %d\n", param1); } } else { /* Screen mode */ int eraseCount = 0; switch(param1) { case 0: /* Clear to Right */ eraseCount = lts->nCols - lto->cursorCol; if (ltermInsDelEraseChar(lts, eraseCount, LTERM_ERASE_ACTION) != 0) return -1; break; case 1: /* Clear to Left */ eraseCount = lto->cursorCol; lto->cursorCol = 0; if (ltermInsDelEraseChar(lts, eraseCount, LTERM_ERASE_ACTION) != 0) return -1; lto->cursorCol = eraseCount; break; case 2: /* Clear All */ eraseCount = lts->nCols; lto->cursorCol = 0; if (ltermInsDelEraseChar(lts, eraseCount, LTERM_ERASE_ACTION) != 0) return -1; lto->cursorCol = eraseCount; break; default: /* Invalid erase code */ LTERM_WARNING("ltermProcessCSISequence: Warning - invalid erase code %d\n", param1); } } return 0; case U_L_CHAR: /* Insert Ps Line(s) [default: 1] (IL) */ LTERM_LOG(ltermProcessCSISequence,52,("Insert Line Count = %d\n", param1)); if (lto->outputMode == LTERM1_SCREEN_MODE) { if (ltermInsDelEraseLine(lts, param1, lto->cursorRow, LTERM_INSERT_ACTION) != 0) return -1; *opcodes = LTERM_SCREENDATA_CODE|LTERM_INSERT_CODE; *opvals = param1; *oprow = lto->cursorRow; } return 0; case U_M_CHAR: /* Delete Ps Line(s) [default: 1] (DL) */ LTERM_LOG(ltermProcessCSISequence,52,("Delete Line Count = %d\n", param1)); if (lto->outputMode == LTERM1_SCREEN_MODE) { if (ltermInsDelEraseLine(lts, param1, lto->cursorRow, LTERM_DELETE_ACTION) != 0) return -1; *opcodes = LTERM_SCREENDATA_CODE|LTERM_DELETE_CODE; *opvals = param1; *oprow = lto->cursorRow; } return 0; case U_P_CHAR: /* Delete Ps Character(s) [default: 1] (DCH) */ if (ltermInsDelEraseChar(lts, param1, LTERM_DELETE_ACTION) != 0) return -1; return 0; case U_T_CHAR: /* Initiate hilite mouse tracking. Parameters * [func;startx;starty;firstrow;lastrow]. */ LTERM_LOG(ltermProcessCSISequence,2,("Unimplemented 0x%x\n", buf[offset])); return 0; case U_W_CHAR: /* Tabulator functions: * Ps = 0 Tab Set (HTS) * Ps = 2 Tab Clear (TBC), Clear Current Column (default) * Ps = 5 Tab Clear (TBC), Clear All */ LTERM_LOG(ltermProcessCSISequence,2,("Unimplemented 0x%x\n", buf[offset])); return 0; case U_X_CHAR: /* Erase Ps Character(s) [default: 1] (ECH) */ if (ltermInsDelEraseChar(lts, param1, LTERM_ERASE_ACTION) != 0) return -1; return 0; case U_Z_CHAR: /* Move backward Ps [default: 1] tab stops */ LTERM_LOG(ltermProcessCSISequence,2,("Unimplemented 0x%x\n", buf[offset])); return 0; case U_c_CHAR: /* Send Device Attributes (DA) * Ps = 0 (or omitted) : request attributes from terminal * returns: ESC[?1;2c * (``I am a VT100 with Advanced Video Option'') */ LTERM_LOG(ltermProcessCSISequence,52,("Device Attr %d\n", param1)); { char deviceAttr[] = "\033[?1;2c"; if (ltermSendChar(lts, deviceAttr, strlen(deviceAttr)) != 0) return -1; } return 0; case U_d_CHAR: /* Cursor to Line Ps (VPA) */ LTERM_LOG(ltermProcessCSISequence,52,("Cursor to Line = %d\n", param1)); if (lto->outputMode == LTERM1_SCREEN_MODE) { lto->cursorRow = lts->nRows - param1; if (lto->cursorRow < 0) { lto->cursorRow = 0; } else if (lto->cursorRow >= lts->nRows) { lto->cursorRow = lts->nRows - 1; } } return 0; case U_f_CHAR: /* Horizontal and Vertical Position [row;column] (HVP) * [default: 1;1] */ LTERM_LOG(ltermProcessCSISequence,2,("Unimplemented 0x%x\n", buf[offset])); return 0; case U_g_CHAR: /* Tab Clear (TBC) * Ps = 0 Clear Current Column (default) * Ps = 3 Clear All (TBC) */ LTERM_LOG(ltermProcessCSISequence,2,("Unimplemented 0x%x\n", buf[offset])); return 0; case U_i_CHAR: /* Printing * Ps = 4 disable transparent print mode (MC4) * Ps = 5 enable transparent print mode (MC5) */ LTERM_LOG(ltermProcessCSISequence,2,("Unimplemented 0x%x\n", buf[offset])); return 0; case U_h_CHAR: /* Set Mode (SM) * Ps = 4 Insert Mode (SMIR) * Ps = 20 Automatic Newline (LNM) */ LTERM_LOG(ltermProcessCSISequence,52,("Set Mode %d\n", param1)); if (param1 == 4) { lto->insertMode = 1; } else if (param1 == 4) { lto->automaticNewline = 1; } if ((param1 % 100) == 47) { /* Switch to alternate buffer */ if (lto->outputMode == LTERM2_LINE_MODE) { ltermSwitchToScreenMode(lts); *opcodes = LTERM_LINEDATA_CODE | LTERM_OUTPUT_CODE; } } return 0; case U_l_CHAR: /* Reset Mode (RM) * Ps = 4 Replace Mode (RMIR) * Ps = 20 Normal Linefeed (LNM) */ LTERM_LOG(ltermProcessCSISequence,52,("Reset Mode %d\n", param1)); if (param1 == 4) { lto->insertMode = 0; } else if (param1 == 4) { lto->automaticNewline = 0; } if ((param1 % 100) == 47) { /* Switch to regular buffer */ if (lto->outputMode == LTERM1_SCREEN_MODE) { ltermSwitchToLineMode(lts); *opcodes = LTERM_SCREENDATA_CODE | LTERM_CLEAR_CODE; } } return 0; case U_m_CHAR: /* Character Attributes (SGR) * Ps = 0 Normal (default) * Ps = 1 / 22 On / Off Bold (bright fg) * Ps = 4 / 24 On / Off Underline * Ps = 5 / 25 On / Off Blink (bright bg) * Ps = 7 / 27 On / Off Inverse * Ps = 30 / 40 fg/bg Black * Ps = 31 / 41 fg/bg Red * Ps = 32 / 42 fg/bg Green * Ps = 33 / 43 fg/bg Yellow * Ps = 34 / 44 fg/bg Blue * Ps = 35 / 45 fg/bg Magenta * Ps = 36 / 46 fg/bg Cyan * Ps = 37 / 47 fg/bg White * Ps = 39 / 49 fg/bg Default */ /* Enforce default value for parameter (hack!) */ if (paramCount == 0) param1 = 0; LTERM_LOG(ltermProcessCSISequence,52,("Character Attr %d\n", param1)); switch (param1) { case 0: lto->styleMask = 0; break; case 1: lto->styleMask |= LTERM_BOLD_STYLE; break; case 22: lto->styleMask &= ~LTERM_BOLD_STYLE; break; case 4: lto->styleMask |= LTERM_ULINE_STYLE; break; case 24: lto->styleMask &= ~LTERM_ULINE_STYLE; break; case 5: lto->styleMask |= LTERM_BLINK_STYLE; break; case 25: lto->styleMask &= ~LTERM_BLINK_STYLE; break; case 7: lto->styleMask |= LTERM_INVERSE_STYLE; break; case 27: lto->styleMask &= ~LTERM_INVERSE_STYLE; break; default: break; } return 0; case U_n_CHAR: /* Device Status Report (DSR) * Ps = 5 Status Report ESC [ 0 n (``OK'') * Ps = 6 Report Cursor Position (CPR) [row;column] * as ESC [ r ; c R * Ps = 7 Request Display Name * Ps = 8 Request Version Number (place in window title) */ LTERM_LOG(ltermProcessCSISequence,52,("Status Report %d\n", param1)); switch (param1) { case 5: { char statusReport[] = "\033[01"; if (ltermSendChar(lts, statusReport, strlen(statusReport)) != 0) return -1; } break; case 6: if (lto->outputMode == LTERM1_SCREEN_MODE) { int iRow = lts->nRows-lto->cursorRow; int iCol = lto->cursorCol+1; char cursorPos[13]; if ((iRow > 0) && (iRow < 10000) && (iCol > 0) && (iCol < 10000)) { if (sprintf(cursorPos, "\033[%d;%dR", iRow, iCol) > 12) { LTERM_ERROR("ltermProcessCSISequence: Error - DSR buffer overflow\n"); } if (ltermSendChar(lts, cursorPos, strlen(cursorPos)) != 0) return -1; } } break; default: break; } return 0; case U_r_CHAR: /* Set Scrolling Region [top;bottom] * [default: full size of window] (CSR) */ if (lto->outputMode == LTERM1_SCREEN_MODE) { if (paramCount == 0) { param1 = 1; param2 = lts->nRows; } LTERM_LOG(ltermProcessCSISequence,52,("Scrolling Region (%d, %d)\n", param1, param2)); lto->topScrollRow = (param1 > 0) ? lts->nRows - param1 : lts->nRows - 1; if (lto->topScrollRow < 0) lto->topScrollRow = 0; lto->botScrollRow = (param2 > 0) ? lts->nRows - param2 : lts->nRows - 1; if (lto->botScrollRow < 0) lto->botScrollRow = 0; if (lto->topScrollRow < lto->botScrollRow) { int temRow = lto->topScrollRow; lto->topScrollRow = lto->botScrollRow; lto->botScrollRow = temRow; } *opcodes = LTERM_SCREENDATA_CODE|LTERM_SCROLL_CODE; *opvals = lto->topScrollRow; *oprow = lto->botScrollRow; } return 0; case U_x_CHAR: /* Request Terminal Parameters (DECREQTPARM) */ LTERM_LOG(ltermProcessCSISequence,2,("Unimplemented 0x%x\n", buf[offset])); return 0; default: /* Unknown Escape sequence */ LTERM_WARNING("ltermProcessCSISequence: Warning - unknown sequence 0x%x\n", buf[offset]); return 0; } } /** Processes DEC Private Modes (a special case of CSI sequence processing) * ESC [ ? Pm h * @return 0 on success and -1 on error. */ static int ltermProcessDECPrivateMode(struct lterms *lts, const int *paramValues, int paramCount, UNICHAR uch, int *opcodes) { struct LtermOutput *lto = &(lts->ltermOutput); int param1, param2; LTERM_LOG(ltermProcessDECPrivateMode,50,("ch=0x%x, cursorChar=%d, Chars=%d\n", uch, lto->outputCursorChar, lto->outputChars)); /* Set returned opcodes to zero */ *opcodes = 0; /* Default parameter values: 1, 1 */ param1 = (paramCount > 0) ? paramValues[0] : 1; param2 = (paramCount > 1) ? paramValues[1] : 1; switch (uch) { case U_h_CHAR: /* DEC Private Mode Set (DECSET) */ LTERM_LOG(ltermProcessDECPrivateMode,2,("Unimplemented 0x%x\n", uch)); if ((param1 % 100) == 47) { /* Switch to screen mode */ if (lto->outputMode == LTERM2_LINE_MODE) { ltermSwitchToScreenMode(lts); *opcodes = LTERM_LINEDATA_CODE | LTERM_OUTPUT_CODE; } } return 0; case U_l_CHAR: /* DEC Private Mode Reset (DECRST) */ LTERM_LOG(ltermProcessDECPrivateMode,2,("Unimplemented 0x%x\n", uch)); if ((param1 % 100) == 47) { /* Switch to line mode */ if (lto->outputMode == LTERM1_SCREEN_MODE) { ltermSwitchToLineMode(lts); *opcodes = LTERM_SCREENDATA_CODE | LTERM_CLEAR_CODE; } } return 0; case U_r_CHAR: /* Restore previously saved DEC Private Mode Values */ LTERM_LOG(ltermProcessDECPrivateMode,2,("Unimplemented 0x%x\n", uch)); return 0; case U_s_CHAR: /* Save DEC Private Mode Values */ LTERM_LOG(ltermProcessDECPrivateMode,2,("Unimplemented 0x%x\n", uch)); return 0; case U_t_CHAR: /* Toggle DEC Private Mode Values */ LTERM_LOG(ltermProcessDECPrivateMode,2,("Unimplemented 0x%x\n", uch)); return 0; default: /* Unknown escape sequence */ LTERM_WARNING("ltermProcessDECPrivateMode: Warning - unknown sequence 0x%x\n", uch); return 0; } } /** Processes XTERM sequence (a special case of Escape sequence processing) * ESC ] Ps;Pt BEL * @return 0 on success and -1 on error. */ static int ltermProcessXTERMSequence(struct lterms *lts, const UNICHAR *buf, int count, const UNISTYLE *style,int *consumed,int *opcodes) { struct LtermOutput *lto = &(lts->ltermOutput); int offset, paramValue, strLength; UNICHAR paramString[MAXSTRINGPARAM+1]; if (count < 3) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } LTERM_LOG(ltermProcessXTERMSequence,50,("cursorChar=%d, Chars=%d\n", lto->outputCursorChar, lto->outputChars)); offset = 2; /* Set returned opcodes to zero */ *opcodes = 0; /* Process numerical parameter */ paramValue = 0; while ((offset < count) && ((buf[offset] >= (UNICHAR)U_ZERO) && (buf[offset] <= (UNICHAR)U_NINE)) ) { paramValue = paramValue * 10 + buf[offset] - U_ZERO; offset++; } if (offset == count) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } if (buf[offset] != U_SEMICOLON) { /* If next character not semicolon, return */ *consumed = offset; return 0; } LTERM_LOG(ltermProcessXTERMSequence,51,("paramValue=%d, offset=%d, buf[offset]=0x%x\n", paramValue, offset, buf[offset])); /* Skip the semicolon */ offset++; /* Process string parameter */ strLength = 0; while ((offset < count) && (buf[offset] != U_BEL)) { if (strLength < MAXSTRINGPARAM) { paramString[strLength++] = buf[offset]; offset++; } else { LTERM_WARNING("ltermProcessXTERMSequence: Warning - string parameter too long; truncated\n"); break; } } if (offset == count) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } /* Insert terminating NULL character in string */ paramString[strLength] = U_NUL; LTERM_LOGUNICODE(ltermProcessXTERMSequence,52,(paramString, strLength)); /* All parsed characters have been consumed at this point */ *consumed = offset+1; LTERM_WARNING("ltermProcessXTERMSequence: Warning - unimplemented 0x%x\n", buf[offset]); return 0; } /** Processes XMLTerm sequence (a special case of Escape sequence processing) * XMLterm escape sequences are of the form * ESC { Pm C Pt LF * where Pm denotes multiple numeric arguments separated by semicolons, * character C is a not a digit and not a semicolon, * text parameter Pt may be a null string, and * LF is the linefeed character. * Omitted numeric parameters are assumed to be zero. * Any carriage return character preceding the terminating LF is discarded. * @return 0 on success and -1 on error. */ static int ltermProcessXMLTermSequence(struct lterms *lts, const UNICHAR *buf, int count, const UNISTYLE *style,int *consumed,int *opcodes) { struct LtermOutput *lto = &(lts->ltermOutput); int offset, value, strLength; int paramCount, paramValues[MAXESCAPEPARAMS], param1, param2, param3; UNICHAR termChar, paramString[MAXSTRINGPARAM+1]; char paramCString[MAXSTRINGPARAM+1]; if (count < 4) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } LTERM_LOG(ltermProcessXMLTermSequence,50,("cursorChar=%d, Chars=%d\n", lto->outputCursorChar, lto->outputChars)); offset = 2; /* Set returned opcodes to zero */ *opcodes = 0; /* Process numerical parameters */ paramCount = 0; while ((offset < count) && ((buf[offset] >= (UNICHAR)U_ZERO) && (buf[offset] <= (UNICHAR)U_NINE)) ) { /* Starts with a digit */ value = buf[offset] - U_ZERO; offset++; /* Process all contiguous digits */ while ((offset < count) && ((buf[offset] >= (UNICHAR)U_ZERO) && (buf[offset] <= (UNICHAR)U_NINE)) ) { value = value * 10 + buf[offset] - U_ZERO; offset++; } if (offset == count) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } if (paramCount < MAXESCAPEPARAMS) { /* Store numerical parameter */ paramValues[paramCount++] = value; } else { /* Numeric parameter buffer overflow */ LTERM_WARNING("ltermProcessXMLTermSequence: Warning - numeric parameter buffer overflow\n"); } /* If next character not semicolon, stop processing */ if (buf[offset] != U_SEMICOLON) break; /* Process next argument */ offset++; } if (offset == count) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } /* Terminating character */ termChar = buf[offset]; /* Skip terminating character */ offset++; LTERM_LOG(ltermProcessXMLTermSequence,51,("paramCount=%d, offset=%d, termChar=0x%x\n", paramCount, offset, termChar)); /* Process string parameter */ strLength = 0; while ((offset < count) && (buf[offset] != U_LINEFEED)) { if (strLength < MAXSTRINGPARAM) { paramCString[strLength] = buf[offset]; paramString[strLength++] = buf[offset]; offset++; } else { LTERM_WARNING("ltermProcessXMLTermSequence: Warning - string parameter too long; truncated\n"); break; } } if (offset == count) { /* Incomplete Escape sequence */ *consumed = 0; return 1; } /* Discard any CR character preceding the terminating LF character */ if ((strLength > 0) && (paramString[strLength-1] == U_CRETURN)) strLength--; /* Insert terminating NULL character in string */ paramCString[strLength] = U_NUL; paramString[strLength] = U_NUL; LTERM_LOGUNICODE(ltermProcessXMLTermSequence,52,(paramString, strLength)); /* All parsed characters have been consumed at this point (including BEL) */ *consumed = offset+1; /* Default parameter values: 0, 0, 0 */ param1 = (paramCount > 0) ? paramValues[0] : 0; param2 = (paramCount > 1) ? paramValues[1] : 0; param3 = (paramCount > 2) ? paramValues[2] : 0; switch (termChar) { int streamOpcodes, nRows, nCols, sprint_len; char sprint_buf[81]; case U_A_CHAR: /* Send XMLterm device attributes */ case U_B_CHAR: /* Send XMLterm device attributes (Bourne shell format) */ case U_C_CHAR: /* Send XMLterm device attributes (C shell format) */ LTERM_LOG(ltermProcessXMLTermSequence,52,("Sending device attributes\n")); nRows = lts->nRows; nCols = lts->nCols; if ((nRows >= 0) && (nRows < 10000) && (nCols >= 0) && (nCols < 10000)) { if (termChar == U_C_CHAR) { /* C shell format */ sprint_len = sprintf(sprint_buf, "setenv LINES %d;setenv COLUMNS %d;setenv LTERM_COOKIE ", nRows, nCols); } else { sprint_len = sprintf(sprint_buf, "LINES=%d;COLUMNS=%d;LTERM_COOKIE=", nRows, nCols); } if (sprint_len > 80) { LTERM_ERROR("ltermProcessXMLTermSequence: Error - sprintf buffer overflow\n"); } if (ltermSendChar(lts, sprint_buf, strlen(sprint_buf)) != 0) return -1; } if (*lts->cookie) { if (ltermSendChar(lts, lts->cookie, strlen(lts->cookie)) != 0) return -1; } if (termChar == U_B_CHAR) { const char exportStr[] = ";export LINES COLUMNS LTERM_COOKIE"; if (ltermSendChar(lts, exportStr, strlen(exportStr)) != 0) return -1; } if (ltermSendChar(lts, "\n", 1) != 0) return -1; return 0; case U_D_CHAR: /* Set debugging messageLevel/search-string */ LTERM_LOG(ltermProcessXMLTermSequence,52,("Setting message level etc.\n")); if (strLength == 0) { tlog_set_level(param1, param2, NULL); } else { tlog_set_level(param1, param2, paramCString); } return 0; case U_E_CHAR: /* Enable/disable input echo setting */ if (param1) { /* Enable input echo */ lts->disabledInputEcho = 0; LTERM_LOG(ltermProcessXMLTermSequence,52,("Enabled input echo\n")); } else { /* Disable input echo */ lts->disabledInputEcho = 1; LTERM_LOG(ltermProcessXMLTermSequence,52,("Disabled input echo\n")); } return 0; case U_F_CHAR: /* Enable/disable full screen mode */ if (param1) { /* Enable full screen mode */ if (lto->outputMode == LTERM2_LINE_MODE) { ltermSwitchToScreenMode(lts); *opcodes = LTERM_LINEDATA_CODE | LTERM_OUTPUT_CODE; } LTERM_LOG(ltermProcessXMLTermSequence,52,("Enabled full screen mode\n")); } else { /* Disable full screen mode */ if (lto->outputMode == LTERM1_SCREEN_MODE) { ltermSwitchToLineMode(lts); *opcodes = LTERM_SCREENDATA_CODE | LTERM_CLEAR_CODE; } LTERM_LOG(ltermProcessXMLTermSequence,52,("Disabled full screen mode\n")); } return 0; case U_R_CHAR: /* Enable/disable raw input mode */ if (param1) { /* Switch to raw input mode */ ltermSwitchToRawMode(lts); LTERM_LOG(ltermProcessXMLTermSequence,52,("Raw input mode\n")); } else { /* Switch to regular input mode */ ltermClearInputLine(lts); LTERM_LOG(ltermProcessXMLTermSequence,52,("Line input mode\n")); } return 0; case U_J_CHAR: /* Switch to null-terminated Javascript stream mode */ case U_S_CHAR: /* Switch to null-terminated stream mode, with cookie */ if (lto->outputMode == LTERM1_SCREEN_MODE) { *opcodes = LTERM_SCREENDATA_CODE; } else if (lto->outputMode == LTERM2_LINE_MODE) { *opcodes = LTERM_LINEDATA_CODE | LTERM_OUTPUT_CODE; } assert(lto->outputMode != LTERM0_STREAM_MODE); /* Set stream codes */ streamOpcodes = 0; if (termChar == U_J_CHAR) { /* Javascript stream */ streamOpcodes |= LTERM_JSSTREAM_CODE; } else { /* HTML/XML stream */ if (param1) streamOpcodes |= LTERM_DOCSTREAM_CODE; if (param2) streamOpcodes |= LTERM_XMLSTREAM_CODE; if (param3) streamOpcodes |= LTERM_WINSTREAM_CODE; } /* Check if cookie matches */ if ((strLength > 0) && (strcmp(paramCString, lts->cookie) == 0)) { streamOpcodes |= LTERM_COOKIESTR_CODE; } LTERM_LOG(ltermProcessXMLTermSequence,52, ("Switching to stream mode, codes=0x%x\n", streamOpcodes)); if (0 != ltermSwitchToStreamMode(lts, streamOpcodes, NULL)) return -1; return 0; default: /* Unknown escape sequence */ LTERM_WARNING("ltermProcessXMLTermSequence: Warning - unknown sequence 0x%x\n", termChar); return 0; } return 0; } /** Insert/delete/erase COUNT characters at current output cursor position. * @param action = LTERM_INSERT_ACTION (insert) * LTERM_DELETE_ACTION (delete) * LTERM_ERASE_ACTION (erase) * @return 0 on success and -1 on error. */ int ltermInsDelEraseChar(struct lterms *lts, int count, int action) { struct LtermOutput *lto = &(lts->ltermOutput); int charCount = count; int j; assert(count >= 0); LTERM_LOG(ltermInsDelEraseChar,60,("count=%d, action=%d\n", count, action)); if (lto->outputMode == LTERM2_LINE_MODE) { /* Line mode */ switch (action) { case LTERM_INSERT_ACTION: if (lto->outputChars + charCount > MAXCOLM1) { /* Output buffer overflow; ignore extra inserts */ LTERM_WARNING("ltermInsDelEraseChar: Warning - output line buffer overflow\n"); charCount = MAXCOLM1 - lto->outputChars; } LTERM_LOG(ltermInsDelEraseChar,62,("Line insert %d blank chars\n", charCount)); /* Shift characters to the right to make room for insertion */ for (j=lto->outputChars-1; j>=lto->outputCursorChar; j--) { lto->outputLine[j+charCount] = lto->outputLine[j]; lto->outputStyle[j+charCount] = lto->outputStyle[j]; } /* Insert blank characters */ for (j=lto->outputCursorChar; joutputCursorChar+charCount; j++) { lto->outputLine[j] = U_SPACE; lto->outputStyle[j] = LTERM_STDOUT_STYLE | lto->styleMask; } /* Increment character count */ lto->outputChars += charCount; break; case LTERM_DELETE_ACTION: if (lto->outputCursorChar+charCount > lto->outputChars) charCount = lto->outputChars - lto->outputCursorChar; LTERM_LOG(ltermInsDelEraseChar,62,("Line delete %d chars\n", charCount)); /* Shift characters to the left */ for (j=lto->outputCursorChar; joutputChars-charCount; j++) { lto->outputLine[j] = lto->outputLine[j+charCount]; lto->outputStyle[j] = lto->outputStyle[j+charCount]; } /* Decrement character count */ lto->outputChars -= charCount; break; case LTERM_ERASE_ACTION: if (lto->outputCursorChar+charCount > lto->outputChars) charCount = lto->outputChars - lto->outputCursorChar; LTERM_LOG(ltermInsDelEraseChar,62,("Line erase %d chars\n", charCount)); /* Erase characters */ for (j=lto->outputCursorChar; joutputCursorChar+charCount; j++) { lto->outputLine[j] = U_SPACE; lto->outputStyle[j] = LTERM_STDOUT_STYLE | lto->styleMask; } break; } /* Note modifications */ if (lto->outputCursorChar < lto->outputModifiedChar) lto->outputModifiedChar = lto->outputCursorChar; } else if (lto->outputMode == LTERM1_SCREEN_MODE) { /* Screen mode */ int j0 = lto->cursorRow*lts->nCols; switch (action) { case LTERM_INSERT_ACTION: if (lto->cursorCol+charCount > lts->nCols) { /* Ignore inserts beyond screen width */ LTERM_WARNING("ltermInsDelEraseChar: Warning - screen insert overflow\n"); charCount = lts->nCols - lto->cursorCol; } LTERM_LOG(ltermInsDelEraseChar,62, ("Screen insert %d blank chars at column %d\n", charCount, lto->cursorCol)); if (charCount > 0) { /* Shift characters to the right to make room for insertion */ for (j=lts->nCols-1+j0; j>=lto->cursorCol+charCount+j0; j--) { lto->screenChar[j] = lto->screenChar[j-charCount]; lto->screenStyle[j] = lto->screenStyle[j-charCount]; } /* Insert blank characters */ for (j=lto->cursorCol+j0; jcursorCol+charCount+j0; j++) { lto->screenChar[j] = U_SPACE; lto->screenStyle[j] = LTERM_STDOUT_STYLE | lto->styleMask; } /* Note modified column */ lto->modifiedCol[lto->cursorRow] = lts->nCols-1; } break; case LTERM_DELETE_ACTION: if (lto->cursorCol+charCount > lts->nCols) charCount = lts->nCols - lto->cursorCol; LTERM_LOG(ltermInsDelEraseChar,62, ("Screen delete %d chars at column %d\n", charCount, lto->cursorCol)); if (charCount > 0) { /* Shift characters to the left */ for (j=lto->cursorCol+j0; jnCols-charCount+j0; j++) { lto->screenChar[j] = lto->screenChar[j+charCount]; lto->screenStyle[j] = lto->screenStyle[j+charCount]; } /* Note modified column */ lto->modifiedCol[lto->cursorRow] = lts->nCols-1; } break; case LTERM_ERASE_ACTION: if (lto->cursorCol+charCount > lts->nCols) charCount = lts->nCols - lto->cursorCol; LTERM_LOG(ltermInsDelEraseChar,62, ("Screen erase %d chars at column %d\n", charCount, lto->cursorCol)); if (charCount > 0) { /* Erase characters */ for (j=lto->cursorCol+j0; jcursorCol+charCount+j0; j++) { lto->screenChar[j] = U_SPACE; lto->screenStyle[j] = LTERM_STDOUT_STYLE | lto->styleMask; } /* Note modified column */ if (lto->modifiedCol[lto->cursorRow] < lto->cursorCol+charCount-1) lto->modifiedCol[lto->cursorRow] = lto->cursorCol+charCount-1; } break; } } return 0; } /** Insert COUNT blank lines about current current line, scrolling down, or * delete COUNT lines at and below current line, scrolling up remaining lines, * or erase COUNT lines at and below current line. * Displayed lines above the current line are unaffected, * cursor is not moved and no new modification flags are set. * @param count no. of lines to be inserted/deleted/erased * @param row row for insertion/deletion/erasure * @param action = LTERM_INSERT_ACTION (insert) * LTERM_DELETE_ACTION (delete) * LTERM_ERASE_ACTION (erase) * @return 0 on success and -1 on error. */ int ltermInsDelEraseLine(struct lterms *lts, int count, int row, int action) { struct LtermOutput *lto = &(lts->ltermOutput); int lineCount, kblank1, kblank2; int joffset, jscroll, j, k; LTERM_LOG(ltermInsDelEraseLine,60, ("count=%d, row=%d, action=%d\n", count, row, action)); lineCount = count; switch (action) { case LTERM_ERASE_ACTION: /* Erase lines down; no scrolling */ if (lineCount > row + 1) lineCount = row + 1; kblank1 = row-lineCount+1; kblank2 = row; break; case LTERM_INSERT_ACTION: /* Scroll down for insertion */ if ( (row < lto->botScrollRow) || (row > lto->topScrollRow) ) { /* Cursor located outside scrollable region */ return 0; } if (lineCount > row - lto->botScrollRow + 1) lineCount = row - lto->botScrollRow + 1; kblank1 = row-lineCount+1; kblank2 = row; for (k=lto->botScrollRow; k<=row-lineCount; k++) { joffset = k*lts->nCols; jscroll = lineCount*lts->nCols; lto->modifiedCol[k] = lto->modifiedCol[k+lineCount]; for (j=0+joffset; j<=lts->nCols-1+joffset; j++) { lto->screenChar[j] = lto->screenChar[j+jscroll]; lto->screenStyle[j] = lto->screenStyle[j+jscroll]; } } break; case LTERM_DELETE_ACTION: /* Scroll up for deletion */ if ( (row < lto->botScrollRow) || (row > lto->topScrollRow) ) { /* Cursor located outside scrollable region */ return 0; } if (lineCount > row - lto->botScrollRow + 1) lineCount = row - lto->botScrollRow + 1; kblank1 = lto->botScrollRow; kblank2 = lto->botScrollRow + lineCount-1; /* Scroll up */ for (k=row; k>=lto->botScrollRow+lineCount; k--) { joffset = k*lts->nCols; jscroll = lineCount*lts->nCols; lto->modifiedCol[k] = lto->modifiedCol[k-lineCount]; for (j=0+joffset; j<=lts->nCols-1+joffset; j++) { lto->screenChar[j] = lto->screenChar[j-jscroll]; lto->screenStyle[j] = lto->screenStyle[j-jscroll]; } } break; default: kblank1 = 0; kblank2 = -1; break; } /* Blank out lines (assumed to be displayed already) */ for (k=kblank1; k<=kblank2; k++) { joffset = k*lts->nCols; lto->modifiedCol[k] = -1; for (j=0+joffset; j<=lts->nCols-1+joffset; j++) { lto->screenChar[j] = U_SPACE; lto->screenStyle[j] = LTERM_STDOUT_STYLE; } } return 0; }