XTGETTCAP
Latest update:
When the authors of a new terminal emulator (TE) decide which
capabilities to support, they inevitably end up with a subset of
XTerm's features. Then, much like a non-mainstream web browser hiding
its true identity behind a fake User-Agent
request header, the new
TE often claims to be a variant of xterm
. This frustrates the
current XTerm maintainer & the maintainers of the terminfo database,
who insist that every TE should have its own entry in terminfo, and
that it's always better to esse quam videri. So far, TE authors have
largely ignored this prudent advice.
Sometimes, the ability to deceive programs that rely on the TERM
environment variable can be useful. Suppose you want to display an
infobox to a user via dialog(1), but you want it to use a monochrome
palette. The dialog program doesn't have a flag for this, but we can
trick it into thinking it's running in a terminal that doesn't support
colours:
$ TERM=vt100 dialog --infobox 'ну шо ти малá' 0 0
This works because the dialog(1) program uses the ncurses library,
which in turn relies on the terminfo database. The latter includes an
entry for the vt100
terminal, that, according to terminfo, is fairly
unsophisticated:
$ TERM=vt100 tput colors
-1
To get a full list of such simpletons, run:
$ find /usr/share/terminfo -type f |
xargs -n1 basename |
while read line; do [ `tput -T $line colors` = -1 ] && echo $line; done
In general, CLI programs that use terminal features beyond simply
deleting the previous character fall into 2 categories--those that:
- consult terminfo for supported capabilities;
- include their own little database of compatible TE.
Both rely on $TERM
, hence, both can be easily lead astray.
There is a 3rd way: ask the terminal emulator (TE) to report its
capabilities using escape sequences. This mechanism, called
XTGETTCAP, is slowly gaining popularity among TEs. Obviously, it
"works over ssh" & doesn't require terminfo to be installed on the
remote machine. XTGETTCAP was first introduced by XTerm and is now
supported by Kitty and iTerm2. With this mechanism, the value of
$TERM
becomes less relevant:
$ echo $TERM
xterm-256color
$ TERM=vt100 ./XTGETTCAP TN
xterm-256color
$ ./XTGETTCAP colors
256
Alas, there is no widely known CLI utility named XTGETTCAP
--in the
example above, it's just a ~small shell script. Even more unfortunate
is that doing a proper XTGETTCAP query & reading the response is a
tricky business. You need to:
Construct a query using an escape sequence & hexify the capability
name, e.g., colors
becomes 636f6c6f7273
.
Switch the TE from canonical to raw mode.
Handle raw mode correctly. In this mode, the TE doesn't assemble
characters into lines, so we can't rely on it to return everything
up to one line at a time. Instead, we must either request a
response of a known size (we don't know the size!) or read an
unknown-length response with a timeout. If you royally screw this
up, your read operation may block ∞.
Restore canonical mode.
Unpack the reply.
#!/bin/sh
set -e
eh() { echo "Error: $*" 1>&2; trap - 0; exit 1; }
text2hex() { od -A n -t x1 | tr -d ' \n'; }
hex2text() { sed 's/../0x& /g' | xargs printf '\\\\%03o\n' | xargs printf %b; }
stty_orig=`stty -g`
stty_restore() { stty "$stty_orig"; }
[ -n "$1" ] || eh Usage: XTGETTCAP capability
capablity=`printf '%s' "$1" | text2hex`
trap stty_restore 0
stty -echo raw time 1 min 0
printf '\033P+q%s\033'\\ "$capablity" > /dev/tty
buf=`dd status=none count=1`
stty_restore
[ -n "$buf" ] || eh unsupported terminal
[ "$V" ] && printf %s "$buf" | xxd
buf=`printf %s "$buf" | sed 's/[^a-zA-Z0-9+=]//g'`
[ P1 = "${buf%+*}" ] || eh unknown capabilitah
printf %s "${buf#*=}" | hex2text | xargs
A couple of notes:
the script doesn't work under screen/tmux, even if an underline TE
supports the XTGETTCAP mechanism.
if you decide to fiddle with time
and min
settings, think twice;
here's a matrix from APUE, ch. 18:
hex2text()
may look silly, but it works even under FreeBSD (unless
the source contains encoded null bytes) & doesn't rely on
non-standard utilities like xxd;
in principle, dd ...
call can be replaced with a simple cat
.
$ ./XTGETTCAP TN
xterm-kitty
$ VERBOSE=1 ./XTGETTCAP colors
00000000: 1b50 312b 7236 3336 6636 6336 6637 3237 .P1+r636f6c6f727
00000010: 333d 3332 3335 3336 1b5c 3=323536.\
256
$ ./XTGETTCAP шо?
Error: unknown capabilitah
- Requires
allowTcapOps
resource to be
true. By default, it's off on all IBM distros due to security
concerns (e.g., see CVE-2022-45063).
Tags: ойті
Authors: ag