Skip to content

Commit a988383

Browse files
Fixed: Fully consume unknown CSI sequences containing unsupported parameter and intermediate bytes
Standard ECMA-48: Control Functions for Coded Character Sets specifies the format of CSI commands. - https://en.wikipedia.org/wiki/ANSI_escape_code#Control_Sequence_Introducer_commands - https://invisible-island.net/xterm/ecma-48-parameter-format.html#section5.4 Previously unsupported bytes would be echoed to the terminal. ```shell $ printf '\x1b[=u' # PF u $ printf '\x1b[=5u' # PPF 5u $ printf '\x1b[=5!u' # PPIF 5!u $ printf '\x1b[=5!%u' # PPIIF 5!0 $ printf '\x1b[=?5!%u' # PPPIIF ?5!0 ``` This fixes a problem with fish shell 4.0.0 which uses that sequence. Closes #4338 Co-authored-by: @krobelus <[email protected]> Co-authored-by: @agnostic-apollo <[email protected]>
1 parent d2cd6ac commit a988383

File tree

1 file changed

+45
-2
lines changed

1 file changed

+45
-2
lines changed

terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java

+45-2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ public final class TerminalEmulator {
8383
private static final int ESC_APC = 20;
8484
/** Escape processing: "ESC _" or Application Program Command (APC), followed by Escape. */
8585
private static final int ESC_APC_ESCAPE = 21;
86+
/** Escape processing: ESC [ <parameter bytes> */
87+
private static final int ESC_CSI_UNSUPPORTED_PARAMETER_BYTE = 22;
88+
/** Escape processing: ESC [ <parameter bytes> <intermediate bytes> */
89+
private static final int ESC_CSI_UNSUPPORTED_INTERMEDIATE_BYTE = 23;
8690

8791
/** The number of parameter arguments including colon separated sub-parameters. */
8892
private static final int MAX_ESCAPE_PARAMETERS = 32;
@@ -658,6 +662,10 @@ public void processCodePoint(int b) {
658662
case ESC_CSI:
659663
doCsi(b);
660664
break;
665+
case ESC_CSI_UNSUPPORTED_PARAMETER_BYTE:
666+
case ESC_CSI_UNSUPPORTED_INTERMEDIATE_BYTE:
667+
doCsiUnsupportedParameterOrIntermediateByte(b);
668+
break;
661669
case ESC_CSI_EXCLAMATION:
662670
if (b == 'p') { // Soft terminal reset (DECSTR, http://vt100.net/docs/vt510-rm/DECSTR).
663671
reset();
@@ -1059,6 +1067,37 @@ private int nextTabStop(int numTabs) {
10591067
return mRightMargin - 1;
10601068
}
10611069

1070+
/**
1071+
* Process byte while in the {@link #ESC_CSI_UNSUPPORTED_PARAMETER_BYTE} or
1072+
* {@link #ESC_CSI_UNSUPPORTED_INTERMEDIATE_BYTE} escape state.
1073+
*
1074+
* Parse unsupported parameter, intermediate and final bytes but ignore them.
1075+
*
1076+
* > For Control Sequence Introducer, ... the ESC [ is followed by
1077+
* > - any number (including none) of "parameter bytes" in the range 0x30–0x3F (ASCII 0–9:;<=>?),
1078+
* > - then by any number of "intermediate bytes" in the range 0x20–0x2F (ASCII space and !"#$%&'()*+,-./),
1079+
* > - then finally by a single "final byte" in the range 0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~).
1080+
*
1081+
* - https://en.wikipedia.org/wiki/ANSI_escape_code#Control_Sequence_Introducer_commands
1082+
* - https://invisible-island.net/xterm/ecma-48-parameter-format.html#section5.4
1083+
*/
1084+
private void doCsiUnsupportedParameterOrIntermediateByte(int b) {
1085+
if (mEscapeState == ESC_CSI_UNSUPPORTED_PARAMETER_BYTE && b >= 0x30 && b <= 0x3F) {
1086+
// Supported `0–9:;>?` or unsupported `<=` parameter byte after an
1087+
// initial unsupported parameter byte in `doCsi()`, or a sequential parameter byte.
1088+
continueSequence(ESC_CSI_UNSUPPORTED_PARAMETER_BYTE);
1089+
} else if (b >= 0x20 && b <= 0x2F) {
1090+
// Optional intermediate byte `!"#$%&'()*+,-./` after parameter or intermediate byte.
1091+
continueSequence(ESC_CSI_UNSUPPORTED_INTERMEDIATE_BYTE);
1092+
} else if (b >= 0x40 && b <= 0x7E) {
1093+
// Final byte `@A–Z[\]^_`a–z{|}~` after parameter or intermediate byte.
1094+
// Calling `unknownSequence()` would log an error with only a final byte, so ignore it for now.
1095+
finishSequence();
1096+
} else {
1097+
unknownSequence(b);
1098+
}
1099+
}
1100+
10621101
/** Process byte while in the {@link #ESC_CSI_QUESTIONMARK} escape state. */
10631102
private void doCsiQuestionMark(int b) {
10641103
switch (b) {
@@ -1656,12 +1695,16 @@ private void doCsi(int b) {
16561695
}
16571696
mCursorCol = newCol;
16581697
break;
1659-
case '?': // Esc [ ? -- start of a private mode set
1698+
case '?': // Esc [ ? -- start of a private parameter byte
16601699
continueSequence(ESC_CSI_QUESTIONMARK);
16611700
break;
1662-
case '>': // "Esc [ >" --
1701+
case '>': // "Esc [ >" -- start of a private parameter byte
16631702
continueSequence(ESC_CSI_BIGGERTHAN);
16641703
break;
1704+
case '<': // "Esc [ <" -- start of a private parameter byte
1705+
case '=': // "Esc [ =" -- start of a private parameter byte
1706+
continueSequence(ESC_CSI_UNSUPPORTED_PARAMETER_BYTE);
1707+
break;
16651708
case '`': // Horizontal position absolute (HPA - http://www.vt100.net/docs/vt510-rm/HPA).
16661709
setCursorColRespectingOriginMode(getArg0(1) - 1);
16671710
break;

0 commit comments

Comments
 (0)