pjs/extensions/xmlterm/lineterm/ltermInput.c

879 строки
26 KiB
C

/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "MPL"); you may not use this file
* except in compliance with the MPL. You may obtain a copy of
* the MPL at http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the MPL for the specific language governing
* rights and limitations under the MPL.
*
* The Original Code is lineterm.
*
* The Initial Developer of the Original Code is Ramalingam Saravanan.
* Portions created by Ramalingam Saravanan <svn@xmlterm.org> are
* Copyright (C) 1999 Ramalingam Saravanan. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License (the "GPL"), in which case
* the provisions of the GPL are applicable instead of
* those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow
* others to use your version of this file under the MPL, indicate
* your decision by deleting the provisions above and replace them
* with the notice and other provisions required by the GPL.
* If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
/* ltermInput.c: LTERM PTY input data processing
*/
/* public declarations */
#include "lineterm.h"
/* private declarations */
#include "ltermPrivate.h"
static int ltermLineInput(struct lterms *lts, const UNICHAR *buf, int count,
int *opcodes);
static int ltermMetaInput(struct lterms *lts);
static int ltermRequestCompletion(struct lterms *lts, UNICHAR uch);
/** Processes plain text input data and returns
* OPCODES ::= LINEDATA ( INPUT ( NEWLINE HIDE? )?
* | INPUT META ( COMPLETION | NEWLINE HIDE? ) )
* if echoable input data was processed.
* (OPCODES is set to zero if raw input data was processed)
* Called from ltermWrite
* @return 0 on success,
* -1 on error, and
* -2 if pseudo-TTY has been closed.
*/
int ltermPlainTextInput(struct lterms *lts,
const UNICHAR *buf, int count, int *opcodes)
{
struct LtermInput *lti = &(lts->ltermInput);
int returnCode;
LTERM_LOG(ltermPlainTextInput,20,
("count=%d, lti->inputMode=%d\n", count, lti->inputMode));
if (lti->inputMode == LTERM0_RAW_MODE) {
/* Transmit characters immediately to child process; no buffering */
LTERM_LOG(ltermPlainTextInput,29,
("Raw mode, transmitting %d characters\n",
count));
if (ltermSendData(lts, buf, count) != 0)
return -1;
*opcodes = 0;
} else {
/* Not raw input mode; process line mode input */
int processTrailingTab = 0;
LTERM_LOG(ltermPlainTextInput,21,
("Line mode, lts->commandNumber=%d, inputMode=%d\n",
lts->commandNumber, lti->inputMode));
if ((lti->inputMode >= LTERM3_COMPLETION_MODE) &&
(lts->commandNumber == 0)) {
/* Downgrade input mode */
lti->inputMode = LTERM2_EDIT_MODE;
LTERM_LOG(ltermPlainTextInput,21,
("------------ Downgraded input mode=%d\n\n",
lti->inputMode));
} else if ((lti->inputMode < lts->maxInputMode) &&
(lts->commandNumber != 0)) {
/* Upgrade input mode */
int priorInputMode = lti->inputMode;
/* Set input mode (possibly allowing completion) */
lti->inputMode = lts->maxInputMode;
/* Do not allow command completion without TTY echo */
if ( (lts->disabledInputEcho || lts->noTTYEcho) &&
(lti->inputMode > LTERM2_EDIT_MODE) )
lti->inputMode = LTERM2_EDIT_MODE;
if ((lti->inputChars > 0) &&
(priorInputMode < LTERM3_COMPLETION_MODE) &&
(lti->inputMode >= LTERM3_COMPLETION_MODE)) {
/* Process prior input TABs before switching to completion mode */
int j;
if ((count == 0) &&
(lti->inputCursorGlyph == lti->inputGlyphs) &&
(lti->inputGlyphColIndex[lti->inputGlyphs] == lti->inputCols) &&
(lti->inputColCharIndex[lti->inputCols] == lti->inputChars) &&
(lti->inputLine[lti->inputChars] == U_TAB)) {
/* Trailing TAB in prior input; delete it, and process it later */
if (ltermDeleteGlyphs(lti, 1) != 0)
return -1;
processTrailingTab = 1;
}
/* Replace all input TABs with spaces */
for (j=0; j < lti->inputChars; j++) {
if (lti->inputLine[j] == U_TAB)
lti->inputLine[j] = U_SPACE;
}
}
LTERM_LOG(ltermPlainTextInput,21,
("------------ Upgraded input mode=%d, trailingTab=%d\n\n",
lti->inputMode, processTrailingTab));
}
if (processTrailingTab) {
/* Re-process trailing TAB */
UNICHAR uch = U_TAB;
assert(count == 0);
LTERM_LOG(ltermPlainTextInput,21,("Reprocessing trailing TAB\n"));
returnCode= ltermLineInput(lts, &uch, 1, opcodes);
if (returnCode < 0)
return returnCode;
} else {
/* Process new input characters */
returnCode = ltermLineInput(lts, buf, count, opcodes) != 0;
if (returnCode < 0)
return returnCode;
}
}
return 0;
}
/** Cancels a prior command line completion request
* @return 0 on success,
* -1 on error
*/
int ltermCancelCompletion(struct lterms *lts)
{
LTERM_LOG(ltermCancelCompletion,40,
("++++++++++++ CANCELED COMPLETION REQUEST\n\n"));
if (lts->completionRequest != LTERM_NO_COMPLETION) {
/* Kill input line transmitted to process */
if (ltermSendData(lts, lts->control+TTYKILL, 1) != 0)
return -1;
lts->completionRequest = LTERM_NO_COMPLETION;
}
return 0;
}
/** Inserts plain text character UCH as a single-column glyph at the
* current input cursor location, translating to escape sequence if needed.
* @return 0 on success, -1 on error.
*/
int ltermInsertChar(struct LtermInput *lti, UNICHAR uch)
{
UNICHAR* escapeSequence;
int insChars, insertColIndex, insertCharIndex, j;
LTERM_LOG(ltermInsertChar,40,("inserting character 0x%x at glyph %d\n",
uch, lti->inputCursorGlyph));
/* Ignore null character */
if (uch == 0)
return 0;
escapeSequence = NULL;
insChars = 1;
#if 0
/* COMMENTED OUT: Plain text not escaped; use code later in HTML insert */
/* Check if plain text character needs to be escaped for XML/HTML */
for (j=0; j<LTERM_PLAIN_ESCAPES; j++) {
if (uch == ltermGlobal.escapeChars[j]) {
/* Insert escape sequence rather than character */
escapeSequence = ltermGlobal.escapeSeq[j];
insChars = ltermGlobal.escapeLen[j];
LTERM_LOG(ltermInsertChar,42,("escape index=%d\n", j));
break;
}
}
#endif /* 0 */
if (lti->inputChars+insChars > MAXCOLM1) {
/* Input buffer overflow; ignore insert character */
LTERM_WARNING("ltermInsertChar: Warning - input line buffer overflow\n");
return 0;
}
assert(lti->inputChars >= 0);
assert(lti->inputCols >= 0);
assert(lti->inputGlyphs >= 0);
assert(lti->inputCursorGlyph >= 0);
assert(lti->inputCols <= lti->inputChars);
assert(lti->inputGlyphs <= lti->inputCols);
insertColIndex = lti->inputGlyphColIndex[lti->inputCursorGlyph];
insertCharIndex = lti->inputColCharIndex[insertColIndex];
LTERM_LOG(ltermInsertChar,41,("insertColIndex=%d, insertCharIndex=%d, insChars=%d\n",
insertColIndex, insertCharIndex, insChars));
/* Shift portion of input line to the right;
remember that the column/glyph index arrays have an extra element */
for (j=lti->inputChars - 1; j >= insertCharIndex; j--)
lti->inputLine[j+insChars] = lti->inputLine[j];
for (j=lti->inputCols; j >= insertColIndex; j--)
lti->inputColCharIndex[j+1] = lti->inputColCharIndex[j]+insChars;
for (j=lti->inputGlyphs; j >= lti->inputCursorGlyph; j--) {
lti->inputGlyphCharIndex[j+1] = lti->inputGlyphCharIndex[j]+insChars;
lti->inputGlyphColIndex[j+1] = lti->inputGlyphColIndex[j]+1;
}
/* Insert character(s) in input line */
if (escapeSequence == NULL) {
lti->inputLine[insertCharIndex] = uch;
} else {
for (j=0; j < insChars; j++)
lti->inputLine[j+insertCharIndex] = escapeSequence[j];
}
/* Insert column/glyph */
lti->inputColCharIndex[insertColIndex] = insertCharIndex;
lti->inputGlyphCharIndex[lti->inputCursorGlyph] = insertCharIndex;
lti->inputGlyphColIndex[lti->inputCursorGlyph] = insertColIndex;
lti->inputChars += insChars; /* Increment character count */
lti->inputCols++; /* Increment column count */
lti->inputGlyphs++; /* Increment glyph count */
lti->inputCursorGlyph++; /* Reposition cursor */
return 0;
}
/** switches to raw input mode */
void ltermSwitchToRawMode(struct lterms *lts)
{
struct LtermInput *lti = &(lts->ltermInput);
LTERM_LOG(ltermSwitchToRawMode,40,("\n"));
if (lti->inputMode != LTERM0_RAW_MODE) {
/* Do other things ... */
lti->inputMode = LTERM0_RAW_MODE;
}
}
/** clears input line buffer and switches to regular input mode */
void ltermClearInputLine(struct lterms *lts)
{
struct LtermInput *lti = &(lts->ltermInput);
LTERM_LOG(ltermClearInputLine,40,("\n"));
lti->inputChars = 0;
lti->inputCols = 0;
lti->inputColCharIndex[0] = 0;
lti->inputGlyphs = 0;
lti->inputGlyphCharIndex[0] = 0;
lti->inputGlyphColIndex[0] = 0;
lti->inputCursorGlyph = 0;
if (lts->maxInputMode >= LTERM2_EDIT_MODE)
lti->inputMode = LTERM2_EDIT_MODE;
else
lti->inputMode = lts->maxInputMode;
lti->escapeFlag = 0;
lti->escapeCSIFlag = 0;
lti->escapeCSIArg = 0;
}
/** Processes an input string in canonical or higher mode and returns
* OPCODES ::= LINEDATA ( INPUT (NEWLINE HIDE?)?
* | INPUT META (COMPLETION|NEWLINE HIDE?) )
* if echoable input data was processed.
* (OPCODES is set to zero if raw input data was processed)
* Called from ltermPlainTextInput
* @return 0 on success,
* -1 on error, and
* -2 if pseudo-TTY has been closed.
*/
static int ltermLineInput(struct lterms *lts,
const UNICHAR *buf, int count, int *opcodes)
{
struct LtermInput *lti = &(lts->ltermInput);
UNICHAR uch;
int charIndex, metaInput;
/* Default returned opcodes (maybe overridden) */
*opcodes = LTERM_LINEDATA_CODE | LTERM_INPUT_CODE;
charIndex = 0;
LTERM_LOG(ltermLineInput,30,
("count=%d, lti->inputMode=%d, inputCursorGlyph=%d\n",
count, lti->inputMode, lti->inputCursorGlyph));
LTERM_LOGUNICODE(ltermLineInput,31,(buf, count));
LTERM_LOG(ltermLineInput,31,("Glyphs=%d,Cols=%d,Chars=%d\n",
lti->inputGlyphs, lti->inputCols, lti->inputChars));
while (charIndex < count) {
uch = buf[charIndex];
if (uch == U_ESCAPE) {
/* Escape */
lti->escapeFlag = 1;
uch = U_NUL;
} else if (lti->escapeFlag) {
/* Escaped character */
lti->escapeFlag = 0;
switch (uch) {
case U_LBRACKET:
/* Start of escape code sequence */
lti->escapeCSIFlag = 1;
lti->escapeCSIArg = 0;
uch = U_NUL;
break;
default:
uch = U_NUL;
}
} else if (lti->escapeCSIFlag) {
/* Character part of escape code sequence */
LTERM_LOG(ltermLineInput,38,("Escape code sequence - 0x%x\n", uch));
if ((uch >= (UNICHAR)U_ZERO && uch <= (UNICHAR)U_NINE)) {
/* Process numerical argument to escape code sequence */
lti->escapeCSIArg = lti->escapeCSIArg*10 + (uch - U_ZERO);
uch = U_NUL;
} else {
/* End of escape code sequence */
lti->escapeCSIFlag = 0;
/* NOTE: Input CSI escape sequence; may not be portable */
/* SUN arrow key bindings */
switch (uch) {
case U_A_CHAR:
uch = U_CTL_P;
break;
case U_B_CHAR:
uch = U_CTL_N;
break;
case U_C_CHAR:
uch = U_CTL_F;
break;
case U_D_CHAR:
uch = U_CTL_B;
break;
default:
uch = U_NUL;
}
}
}
if ( ((uch >= (UNICHAR)U_SPACE) && (uch != (UNICHAR)U_DEL)) ||
((uch == (UNICHAR)U_TAB) && (lti->inputMode <= LTERM2_EDIT_MODE)) ) {
/* printable character or non-completion mode TAB; insert in buffer */
/* (NEED TO UPDATE THIS CHECK FOR UNICODE PRINTABILITY) */
LTERM_LOG(ltermLineInput,39,("inserting printable character - %c\n",
(char) uch));
/* Insert character */
if (ltermInsertChar(lti, uch) != 0)
return -1;
} else {
/* Control character */
/* Translate carriage returns to linefeeds in line mode
(***NOTE*** may not be portable out of *nix) */
if (uch == U_CRETURN)
uch = U_LINEFEED;
/* Line break control characters */
if ( (uch == U_LINEFEED) ||
(uch == lts->control[TTYDISCARD]) ||
(uch == lts->control[TTYSUSPEND]) ||
(uch == lts->control[TTYINTERRUPT])) {
/* Newline/TTYdiscard/TTYsuspend/TTYinterrupt character */
/* Assert that linebreak character occurs at end of buffer;
* enforced by lterm_write.
*/
assert(charIndex == count-1);
/* Check if meta input line */
metaInput = ltermMetaInput(lts);
if ((uch == lts->control[TTYDISCARD]) && !metaInput
&& (lts->commandNumber == 0)) {
/* Not meta/command line; simply transmit discard character */
if (ltermSendData(lts, lts->control+TTYDISCARD, 1) != 0)
return -1;
} else {
/* Newline behaviour, with hide option */
LTERM_LOG(ltermLineInput,31,("------------ NEWLINE (0x%x)\n\n",
uch));
LTERM_LOGUNICODE(ltermLineInput,31,( lti->inputLine,
lti->inputChars));
/* The NEWLINE code tells ltermReturnInputLine to clear
* the input line buffer after copying it
*/
*opcodes = LTERM_LINEDATA_CODE | LTERM_INPUT_CODE
| LTERM_NEWLINE_CODE;
if (uch == lts->control[TTYDISCARD]) {
*opcodes |= LTERM_HIDE_CODE;
uch = U_LINEFEED; /* essentially newline behaviour otherwise */
}
if (uch == lts->control[TTYINTERRUPT]) {
/* Interrupt output operations, if necessary */
if (ltermInterruptOutput(lts) != 0)
return -1;
}
if (metaInput) {
/* meta input; do not send line */
*opcodes |= LTERM_META_CODE;
} else {
/* Send line and copy to echo buffer */
if (ltermSendLine(lts, uch, (uch != U_LINEFEED),
LTERM_NO_COMPLETION) != 0)
return -1;
}
}
} else if (uch == lts->control[TTYKILL]) {
/* kill line */
ltermClearInputLine(lts);
LTERM_LOG(ltermLineInput,31,("TTYKILL\n"));
} else if ((uch == U_BACKSPACE) || (uch == U_DEL) ||
(uch == lts->control[TTYERASE])) {
/* erase glyph */
if (ltermDeleteGlyphs(lti, 1) != 0)
return -1;
LTERM_LOG(ltermLineInput,39,("TTYERASE=0x%x/0x%x\n",
lts->control[TTYERASE], uch ));
} else {
/* other control characters */
LTERM_LOG(ltermLineInput,32,("^%c\n", uch+U_ATSIGN));
if (lti->inputMode < LTERM2_EDIT_MODE) {
/* Non-edit mode; simply transmit control character */
if (ltermSendData(lts, &uch, 1) != 0)
return -1;
} else {
/* Edit input mode */
if (uch == U_CTL_D) {
/* Special handling for ^D */
if (lti->inputChars == 0) {
/* Lone ^D in input line, simply transmit it */
if (ltermSendData(lts, &uch, 1) != 0)
return -1;
uch = U_NUL;
} else if (lti->inputCursorGlyph < lti->inputGlyphs) {
/* Cursor not at end of line; delete to right */
if (ltermDeleteGlyphs(lti, -1) != 0)
return -1;
uch = U_NUL;
}
}
switch (uch) {
case U_NUL: /* Null character; ignore */
break;
case U_CTL_B: /* move cursor backward */
if (lti->inputCursorGlyph > 0) {
lti->inputCursorGlyph--;
}
break;
case U_CTL_F: /* move cursor forward */
if (lti->inputCursorGlyph < lti->inputGlyphs) {
lti->inputCursorGlyph++;
}
break;
case U_CTL_A: /* position cursor at beginning of line */
lti->inputCursorGlyph = 0;
break;
case U_CTL_E: /* position cursor at end of line */
lti->inputCursorGlyph = lti->inputGlyphs;
break;
case U_CTL_K: /* delete to end of line */
if (ltermDeleteGlyphs(lti,-(lti->inputGlyphs-lti->inputCursorGlyph))
!= 0)
return -1;
break;
case U_CTL_L: /* form feed */
case U_CTL_R: /* redisplay */
break;
case U_CTL_D: /* ^D at end of non-null input line */
case U_CTL_N: /* dowN history */
case U_CTL_P: /* uP history */
case U_CTL_Y: /* yank */
case U_TAB: /* command completion */
/* Assert that completion character occurs at end of buffer;
* enforced by lterm_write.
*/
assert(charIndex == count-1);
metaInput = ltermMetaInput(lts);
if (metaInput) {
/* Meta input command completion */
LTERM_LOG(ltermLineInput,40,
("++++++++++++ meta COMPLETION uch=0x%X\n\n", uch));
if (uch == U_TAB) {
*opcodes = LTERM_LINEDATA_CODE | LTERM_INPUT_CODE
| LTERM_META_CODE
| LTERM_COMPLETION_CODE;
} else {
LTERM_WARNING("ltermLineInput: Warning - meta command completion not yet implemented for uch=0x%x\n", uch);
}
} else if (lti->inputMode >= LTERM3_COMPLETION_MODE) {
/* Completion mode; non-completion TABs already processed */
if (ltermRequestCompletion(lts, uch) != 0)
return -1;
}
break;
default: /* Transmit any other control character */
if (ltermSendData(lts, &uch, 1) != 0)
return -1;
}
}
}
}
/* Increment character index */
charIndex++;
}
return 0;
}
/** Check if input line contains a meta delimiter;
* @return 1 if it does, 0 otherwise.
*/
static int ltermMetaInput(struct lterms *lts)
{
struct LtermInput *lti = &(lts->ltermInput);
UNICHAR *delimLoc, *ustr, *ustr2;
LTERM_LOG(ltermMetaInput,40,("\n"));
if (lts->options & LTERM_NOMETA_FLAG)
return 0;
/* Assert that there is at least one free character position in the buffer */
assert(lti->inputChars < MAXCOL);
/* Insert null character at the end of the input buffer */
lti->inputLine[lti->inputChars] = U_NUL;
/* Locate first occurrence of meta delimiter in input line */
delimLoc = ucschr(lti->inputLine, ltermGlobal.metaDelimiter);
if (delimLoc == NULL)
return 0;
for (ustr=lti->inputLine; ustr<delimLoc; ustr++) /* skip spaces/TABs */
if ((*ustr != U_SPACE) && (*ustr != U_TAB)) break;
if (ustr == delimLoc) {
/* Nameless meta command */
LTERM_LOG(ltermMetaInput,41,("Nameless meta command\n"));
return 1;
}
if (!IS_ASCII_LETTER(*ustr)) /* meta command must start with a letter */
return 0;
for (ustr2=ustr+1; ustr2<delimLoc; ustr2++)
if (!IS_ASCII_LETTER(*ustr2) && !IS_ASCII_DIGIT(*ustr2))
return 0;
LTERM_LOG(ltermMetaInput,41,("Named meta command\n"));
return 1;
}
/** Requests command line completion from process corresponding to
* control character UCH.
* @return 0 on success,
* -1 on error
*/
static int ltermRequestCompletion(struct lterms *lts, UNICHAR uch)
{
LTERM_LOG(ltermRequestCompletion,40,
("++++++++++++ COMPLETION REQUEST uch=0x%X\n\n", uch));
switch (uch) {
case U_TAB:
/* Send line and copy to echo buffer */
if (ltermSendLine(lts, uch, 0, LTERM_TAB_COMPLETION) != 0)
return -1;
break;
case U_CTL_P:
case U_CTL_N:
/* Send line and copy to echo buffer */
if (ltermSendLine(lts, uch, 0, LTERM_HISTORY_COMPLETION) != 0)
return -1;
break;
default:
LTERM_WARNING("ltermCompletionRequest: Warning - command completion not yet implemented for uch=0x%x\n", uch);
}
return 0;
}
/** Deletes glyphs from the input line.
* If COUNT > 0, glyphs are deleted to the left of the cursor.
* If COUNT < 0, glyphs are deleted to the right of the cursor.
* Called from ltermLineInput.
* @return 0 on success, -1 on error.
*/
int ltermDeleteGlyphs(struct LtermInput *lti, int count)
{
int leftGlyph, leftColIndex, leftCharIndex;
int rightGlyph, rightColIndex, rightCharIndex;
int deleteGlyphs, deleteCols, deleteChars, j;
LTERM_LOG(ltermDeleteGlyphs,40,("deleting %d glyphs from glyph %d\n",
count, lti->inputCursorGlyph));
if (count >= 0) {
/* Delete to the left */
deleteGlyphs = count;
/* Limit the number of glyphs deleted to that present to the left */
if (deleteGlyphs > lti->inputCursorGlyph)
deleteGlyphs = lti->inputCursorGlyph;
rightGlyph = lti->inputCursorGlyph;
leftGlyph = rightGlyph - deleteGlyphs;
} else {
/* Delete to the right */
deleteGlyphs = -count;
/* Limit the number of glyphs deleted to that present to the right */
if (deleteGlyphs > (lti->inputGlyphs - lti->inputCursorGlyph))
deleteGlyphs = lti->inputGlyphs - lti->inputCursorGlyph;
leftGlyph = lti->inputCursorGlyph;
rightGlyph = leftGlyph + deleteGlyphs;
}
leftColIndex = lti->inputGlyphColIndex[leftGlyph];
leftCharIndex = lti->inputGlyphCharIndex[leftGlyph];
rightColIndex = lti->inputGlyphColIndex[rightGlyph];
rightCharIndex = lti->inputGlyphCharIndex[rightGlyph];
deleteCols = rightColIndex - leftColIndex;
deleteChars = rightCharIndex - leftCharIndex;
LTERM_LOG(ltermDeleteGlyphs,41,("deleteCols=%d, deleteChars=%d\n",
deleteCols, deleteChars));
LTERM_LOG(ltermDeleteGlyphs,42,("leftGlyph=%d, leftCol=%d, leftChar=%d\n",
leftGlyph, leftColIndex, leftCharIndex));
LTERM_LOG(ltermDeleteGlyphs,42,("rightGlyph=%d, rightCol=%d, rightChar=%d\n",
rightGlyph, rightColIndex, rightCharIndex));
/* Shift portion of input line to the left;
remember that the column/glyph index arrays have an extra element */
for (j = leftCharIndex; j < lti->inputChars-deleteChars; j++)
lti->inputLine[j] = lti->inputLine[j+deleteChars];
for (j = leftColIndex; j <= lti->inputCols-deleteCols; j++)
lti->inputColCharIndex[j] = lti->inputColCharIndex[j+deleteCols]
- deleteChars;
for (j = leftGlyph; j <= lti->inputGlyphs-deleteGlyphs; j++)
lti->inputGlyphColIndex[j] = lti->inputGlyphColIndex[j+deleteGlyphs]
- deleteCols;
lti->inputChars -= deleteChars; /* Decrement character count */
lti->inputCols -= deleteCols; /* Decrement column count */
lti->inputGlyphs -= deleteGlyphs; /* Decrement glyph count */
if (count > 0)
lti->inputCursorGlyph -= deleteGlyphs; /* Reposition glyph cursor */
return 0;
}
/** Transmits COUNT Unicode characters from BUF to child process
* after translating Unicode to UTF8 or Latin1, as appropriate.
* The data is transmitted in smallish chunks so as not to overflow the
* PTY input buffer.
* @return 0 on successful write, -1 on error.
*/
int ltermSendData(struct lterms *lts, const UNICHAR *buf, int count)
{
char ch, ptyBuf[MAXPTYIN];
int remainingChars, chunkSize, success;
assert(lts != NULL);
assert(count >= 0);
LTERM_LOG(ltermSendData,40,("count=%d\n", count));
LTERM_LOGUNICODE(ltermSendData,41,(buf, count));
if ((count == 1) && (*buf < 0x80)) {
/* Optimized code to transmit single ASCII character */
ch = (char) *buf;
if (lts->ptyMode)
#ifndef USE_NSPR_IO
success = (write(lts->pty.ptyFD, &ch, 1) == 1);
#else
assert(0);
#endif
else
success = (WRITE(lts->ltermProcess.processIN, &ch, 1) == 1);
if (!success) {
#if defined(DEBUG_LTERM) && !defined(USE_NSPR_IO)
int errcode = errno;
perror("ltermSendData");
#else
int errcode = 0;
#endif
LTERM_ERROR("ltermSendData: Error %d in writing to child STDIN\n",
errcode);
return -1;
}
return 0;
}
remainingChars = count;
while (remainingChars > 0) {
/* Convert Unicode to UTF8 */
ucstoutf8(&buf[count-remainingChars], remainingChars,
ptyBuf, MAXPTYIN,
&remainingChars, &chunkSize);
assert(chunkSize > 0);
LTERM_LOG(ltermSendData,42,("remainingChars=%d, chunkSize=%d\n",
remainingChars, chunkSize));
/* Send UTF8 to process */
if (ltermSendChar(lts, ptyBuf, chunkSize) != 0)
return -1;
}
return 0;
}
/** Transmits COUNT characters from BUF to child process.
* @return 0 on successful write, -1 on error.
*/
int ltermSendChar(struct lterms *lts, const char *buf, int count)
{
int success;
LTERM_LOG(ltermSendChar,50,("count=%d\n", count));
if (lts->ptyMode)
#ifndef USE_NSPR_IO
success = (write(lts->pty.ptyFD, buf,
(SIZE_T) count) == count);
#else
assert(0);
#endif
else
success = (WRITE(lts->ltermProcess.processIN, buf,
(SIZE_T) count) == count);
if (!success) {
#if defined(DEBUG_LTERM) && !defined(USE_NSPR_IO)
int errcode = errno;
perror("ltermSendChar");
#else
int errcode = 0;
#endif
LTERM_ERROR("ltermSendChar: Error %d in writing to child STDIN\n",
errcode);
return -1;
}
return 0;
}