vt: don’t ignore extra private/intermediate characters

Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.

Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.

Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.

Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:

  switch (term->vt.private) {
  case ‘?’:
      ...
      break;
  }

Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:

  switch (term->vt.private) {
  case 0x243f:  /* ‘?$’ */
      ...
      break;
  }

The ‘clear’ action remains simple (and fast), with a single write
operation.

Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.

We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
This commit is contained in:
Daniel Eklöf 2020-12-16 14:30:49 +01:00
parent db097891f2
commit 2e137c0a7e
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
5 changed files with 80 additions and 58 deletions

6
dcs.c
View file

@ -31,15 +31,15 @@ esu(struct terminal *term)
void
dcs_hook(struct terminal *term, uint8_t final)
{
LOG_DBG("hook: %c (intermediate(s): %.2s, param=%d)", final, term->vt.private,
vt_param_get(term, 0, 0));
LOG_DBG("hook: %c (intermediate(s): %.2s, param=%d)", final,
(const char *)&term->vt.private, vt_param_get(term, 0, 0));
assert(term->vt.dcs.data == NULL);
assert(term->vt.dcs.size == 0);
assert(term->vt.dcs.put_handler == NULL);
assert(term->vt.dcs.unhook_handler == NULL);
switch (term->vt.private[0]) {
switch (term->vt.private) {
case 0:
switch (final) {
case 'q':