dcs: initial handling of DCS in general

Add data structure to term->vt. This structure tracks the free-form
data that is passed-through, and the handler to call at the end.

Intermediates and parameters are collected by the normal VT
parser. Then, when we enter the passthrough state, we call dcs_hook().

This function checks the intermediate(s) and parameters, and selects
the appropriate unhook handler (and optionally does some execution
already).

In passthrough mode, we simply append strings to an internal
buffer. This might have to be changed in the future, if we need to
support a DCS that needs to execute as we go.

In unhook (i.e. when the DCS is terminated), we execute the unhook
handler.

As a proof-of-concept, handlers for BSU/ESU (Begin/End Synchronized
Update) has been added (but are left unimplemented).
This commit is contained in:
Daniel Eklöf 2020-01-12 11:55:22 +01:00
parent 0b30316261
commit 5a6cbb8c3e
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
5 changed files with 106 additions and 0 deletions

87
dcs.c Normal file
View file

@ -0,0 +1,87 @@
#include "dcs.h"
#define LOG_MODULE "dcs"
#define LOG_ENABLE_DBG 0
#include "log.h"
#include "vt.h"
static void
bsu(struct terminal *term)
{
LOG_WARN("unimplemented: BSU - Begin Synchronized Update (params: %.*s)",
(int)term->vt.dcs.idx, term->vt.dcs.data);
}
static void
esu(struct terminal *term)
{
LOG_WARN("unimplemented: ESU - Begin Synchronized Update (params: %.*s)",
(int)term->vt.dcs.idx, term->vt.dcs.data);
}
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, 127));
assert(term->vt.dcs.data == NULL);
assert(term->vt.dcs.size == 0);
assert(term->vt.dcs.unhook_handler == NULL);
switch (term->vt.private[0]) {
case '=':
switch (final) {
case 's':
switch (vt_param_get(term, 0, 0)) {
case 1: term->vt.dcs.unhook_handler = &bsu; return;
case 2: term->vt.dcs.unhook_handler = &esu; return;
}
break;
}
break;
}
}
static bool
ensure_size(struct terminal *term, size_t required_size)
{
if (required_size <= term->vt.dcs.size)
return true;
size_t new_size = (required_size + 127) / 128 * 128;
assert(new_size > 0);
uint8_t *new_data = realloc(term->vt.dcs.data, new_size);
if (new_data == NULL) {
LOG_ERRNO("failed to increase size of DCS buffer");
return false;
}
term->vt.dcs.data = new_data;
term->vt.dcs.size = new_size;
return true;
}
void
dcs_put(struct terminal *term, uint8_t c)
{
LOG_DBG("PUT: %c", c);
ensure_size(term, term->vt.dcs.idx + 1);
term->vt.dcs.data[term->vt.dcs.idx++] = c;
}
void
dcs_unhook(struct terminal *term)
{
assert(term->vt.dcs.unhook_handler != NULL);
if (term->vt.dcs.unhook_handler != NULL)
term->vt.dcs.unhook_handler(term);
term->vt.dcs.unhook_handler = NULL;
free(term->vt.dcs.data);
term->vt.dcs.data = NULL;
term->vt.dcs.size = 0;
term->vt.dcs.idx = 0;
}

8
dcs.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
#include <stdbool.h>
#include "terminal.h"
void dcs_hook(struct terminal *term, uint8_t final);
void dcs_put(struct terminal *term, uint8_t c);
void dcs_unhook(struct terminal *term);

View file

@ -70,6 +70,7 @@ executable(
'config.c', 'config.h', 'config.c', 'config.h',
'commands.c', 'commands.h', 'commands.c', 'commands.h',
'csi.c', 'csi.h', 'csi.c', 'csi.h',
'dcs.c', 'dcs.h',
'fdm.c', 'fdm.h', 'fdm.c', 'fdm.h',
'grid.c', 'grid.h', 'grid.c', 'grid.h',
'input.c', 'input.h', 'input.c', 'input.h',

View file

@ -125,6 +125,12 @@ struct vt {
size_t idx; size_t idx;
size_t left; size_t left;
} utf8; } utf8;
struct {
uint8_t *data;
size_t size;
size_t idx;
void (*unhook_handler)(struct terminal *term);
} dcs;
struct attributes attrs; struct attributes attrs;
struct attributes saved_attrs; struct attributes saved_attrs;
}; };

4
vt.c
View file

@ -9,6 +9,7 @@
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "csi.h" #include "csi.h"
#include "dcs.h"
#include "grid.h" #include "grid.h"
#include "osc.h" #include "osc.h"
@ -482,16 +483,19 @@ action_osc_put(struct terminal *term, uint8_t c)
static void static void
action_hook(struct terminal *term, uint8_t c) action_hook(struct terminal *term, uint8_t c)
{ {
dcs_hook(term, c);
} }
static void static void
action_unhook(struct terminal *term, uint8_t c) action_unhook(struct terminal *term, uint8_t c)
{ {
dcs_unhook(term);
} }
static void static void
action_put(struct terminal *term, uint8_t c) action_put(struct terminal *term, uint8_t c)
{ {
dcs_put(term, c);
} }
static void static void