XMLterm changes only. Major restructuring of the xmlterm build process. Split lineterm from xmlterm. IDLified all interfaces (bug 69002). Eliminated printing to console in opt builds (bug 78641)
879 lines
26 KiB
C
879 lines
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;
|
|
}
|