# Substitute (SUB)

> Display an error character in place of something that could not be received, abandoning any sequence in progress.

- **Sequence:** `SUB`
- **ECMA-48:** [§8.3.148 SUB – Substitute, p. 71](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n84/mode/1up)
- **DEC STD 070:** [§5.9 Substitute, p. 5-132](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n386/mode/1up)
- **VT510:** [4.2 Control Characters](https://vt100.net/docs/vt510-rm/chapter4.html#S4.2)

SUB stands in for a character that arrived damaged. ECMA-48 says it is "used
in the place of a character that has been found to be invalid or in error",
and does not say what a terminal shows. DEC STD 070 does: SUB places "a
reversed question mark" at the cursor, as an error character, which the
VT100 and its relatives drew as a checkerboard "blotch" instead. Unicode
encodes the reversed question mark as U+2426, SYMBOL FOR SUBSTITUTE FORM
TWO, `␦`.

Inside a sequence, SUB also abandons it, as [CAN](https://control-codes.page/c0/can/index.html.md) does. DEC STD
070 ([§3.5.1.2.2, p. 3-19](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n123/mode/1up)) says it ends any sequence in
progress "without execution", and that SUB and the characters after it are
then "interpreted normally": the error character is displayed. The VT510
manual says the same, and adds device control strings.

xterm, emulating a VT220 or later, displays U+2426 in
[`CASE_SUB`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L3646-L3678), and the checkerboard U+2592 when
emulating a VT100.

## Validation

### SUB-1: Displays the error character

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
AB
\x1a      # SUB
C
```

Expected screen:

```text
|AB␦C_|
cursor 1,5
```

libghostty-vt displays nothing for SUB, and the cursor does not move, so the
`C` lands where the error character should be. Its parser does abandon a
sequence on SUB, as on CAN, but `stream.zig` has no handling for the
character itself: a comment there says "We don't currently have any handling
for 0x18 or 0x1A", and its C0 dispatch logs SUB as an "invalid C0 character,
ignoring". DEC STD 070, the VT510 manual and xterm all display an error
character.

### SUB-2: Abandons a control sequence

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
A
\e[3      # CUF, unfinished
\x1a
C
```

Expected screen:

```text
|A␦C__|
```

libghostty-vt does abandon the sequence, so the `C` is printed rather than
taken as the final byte of CUF. It fails only because, as in SUB-1, no error
character is displayed.

---

This is the Markdown version of <https://control-codes.page/c0/sub/>. On that page every validation case runs live in libghostty-vt, the terminal emulation core of Ghostty, compiled to WebAssembly.

The validation cases are written in the notation described in <https://control-codes.page/notation/index.html.md>.
