mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
dcs: xtgettcap: always reply with tigetstr(3) formatted "strings"
That is, instead of sometimes replying with a "source" encoded string (where e.g. '\E' are returned just like that, and not as an actual ESC), always unescape all string values. This also includes \n \r \t \b \f \s, \^ \\ \ \:, as well as ^x-styled escapes. Closes #1701
This commit is contained in:
parent
4d4ef5eed5
commit
a3debf7741
3 changed files with 60 additions and 21 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -55,6 +55,21 @@
|
||||||
## Unreleased
|
## Unreleased
|
||||||
### Added
|
### Added
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
* All `XTGETTCAP` capabilities are now in the `tigetstr()` format:
|
||||||
|
|
||||||
|
- parameterized string capabilities were previously "source
|
||||||
|
encoded", meaning e.g. `\E` where not "decoded" into `\x1b`.
|
||||||
|
- Control characters were also "source encoded", meaning they were
|
||||||
|
returned as e.g. "^G" instead of `\x07` ([#1701][1701]).
|
||||||
|
|
||||||
|
In other words, if, after this change, `XTGETTCAP` returns a string
|
||||||
|
that is different compared to `tigetstr()`, then it is likely a bug
|
||||||
|
in foot's implementation of `XTGETTCAP`.
|
||||||
|
|
||||||
|
[1701]: https://codeberg.org/dnkl/foot/issues/1701
|
||||||
|
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
### Removed
|
### Removed
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
||||||
|
|
@ -50,27 +50,33 @@ class IntCapability(Capability):
|
||||||
|
|
||||||
class StringCapability(Capability):
|
class StringCapability(Capability):
|
||||||
def __init__(self, name: str, value: str):
|
def __init__(self, name: str, value: str):
|
||||||
# Expand \E to literal ESC in non-parameterized capabilities
|
# see terminfo(5) for valid escape sequences
|
||||||
if '%' not in value:
|
|
||||||
# Ensure e.g. \E7 doesn’t get translated to “\0337”, which
|
|
||||||
# would be interpreted as octal 337 by the C compiler
|
|
||||||
value = re.sub(r'\\E([0-7])', r'\\033" "\1', value)
|
|
||||||
|
|
||||||
# Replace \E with an actual escape
|
# Control characters
|
||||||
value = re.sub(r'\\E', r'\\033', value)
|
def translate_ctrl_chr(m):
|
||||||
|
ctrl = m.group(1)
|
||||||
|
if ctrl == '?':
|
||||||
|
return chr(0x7f)
|
||||||
|
return chr(ord(ctrl) - ord('@'))
|
||||||
|
value = re.sub('\^([@A-Z[\\\\\]^_?])', translate_ctrl_chr, value)
|
||||||
|
|
||||||
# Don’t escape ‘:’
|
# Ensure e.g. \E7 (or \e7) doesn’t get translated to “\0337”,
|
||||||
value = value.replace('\\:', ':')
|
# which would be interpreted as octal 337 by the C compiler
|
||||||
|
value = re.sub(r'(\\E|\\e)([0-7])', r'\\033" "\2', value)
|
||||||
|
|
||||||
else:
|
# Replace \E and \e with ESC
|
||||||
value = value.replace("\\", "\\\\")
|
value = re.sub(r'\\E|\\e', r'\\033', value)
|
||||||
# # Need to double-escape backslashes. These only occur in
|
|
||||||
# # ‘\E\’ combos. Note that \E itself is updated below
|
|
||||||
# value = value.replace('\\E\\\\', '\\E\\\\\\\\')
|
|
||||||
|
|
||||||
# # Need to double-escape \E in C string literals
|
# Unescape ,:^
|
||||||
# value = value.replace('\\E', '\\\\E')
|
value = re.sub(r'\\(,|:|\^)', r'\1', value)
|
||||||
|
|
||||||
|
# Replace \s with space
|
||||||
|
value = value.replace('\\s', ' ')
|
||||||
|
|
||||||
|
# Let \\, \n, \r, \t, \b and \f "fall through", to the C string literal
|
||||||
|
|
||||||
|
if re.search(r'\\l', value):
|
||||||
|
raise NotImplementedError('\\l escape sequence')
|
||||||
|
|
||||||
super().__init__(name, value)
|
super().__init__(name, value)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ main(int argc, const char *const *argv)
|
||||||
if (isprint(buf[i]))
|
if (isprint(buf[i]))
|
||||||
printf("%c", buf[i]);
|
printf("%c", buf[i]);
|
||||||
else if (buf[i] == '\033')
|
else if (buf[i] == '\033')
|
||||||
printf("\033[1;31m\\E\033[m");
|
printf("\033[1;31m<ESC>\033[m");
|
||||||
else
|
else
|
||||||
printf("%02x", (uint8_t)buf[i]);
|
printf("%02x", (uint8_t)buf[i]);
|
||||||
}
|
}
|
||||||
|
|
@ -158,12 +158,30 @@ main(int argc, const char *const *argv)
|
||||||
|
|
||||||
printf(" \033[%dm", color);
|
printf(" \033[%dm", color);
|
||||||
for (size_t i = 0 ; i < len; i++) {
|
for (size_t i = 0 ; i < len; i++) {
|
||||||
if (isprint(decoded[i]))
|
if (isprint(decoded[i])) {
|
||||||
|
/* All printable characters */
|
||||||
printf("%c", decoded[i]);
|
printf("%c", decoded[i]);
|
||||||
else if (decoded[i] == '\033')
|
}
|
||||||
printf("\033[1;31m\\E\033[22;%dm", color);
|
|
||||||
else
|
else if (decoded[i] == '\033') {
|
||||||
|
/* ESC */
|
||||||
|
printf("\033[1;31m<ESC>\033[22;%dm", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (decoded[i] >= '\x00' && decoded[i] <= '\x5f') {
|
||||||
|
/* Control characters, e.g. ^G etc */
|
||||||
|
printf("\033[1m^%c\033[22m", decoded[i] + '@');
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (decoded[i] == '\x7f') {
|
||||||
|
/* Control character ^? */
|
||||||
|
printf("\033[1m^?\033[22m");
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
/* Unknown: print hex representation */
|
||||||
printf("\033[1m%02x\033[22m", (uint8_t)decoded[i]);
|
printf("\033[1m%02x\033[22m", (uint8_t)decoded[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("\033[m\r\n");
|
printf("\033[m\r\n");
|
||||||
replies++;
|
replies++;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue