2019-06-15 22:22:44 +02:00
|
|
|
#include "vt.h"
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2019-07-15 15:42:00 +02:00
|
|
|
#include <unistd.h>
|
2019-06-15 22:22:44 +02:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
#define LOG_MODULE "vt"
|
2019-07-03 20:21:03 +02:00
|
|
|
#define LOG_ENABLE_DBG 0
|
2019-06-15 22:22:44 +02:00
|
|
|
#include "log.h"
|
|
|
|
|
#include "csi.h"
|
2019-06-17 19:33:10 +02:00
|
|
|
#include "grid.h"
|
2019-07-19 09:55:07 +02:00
|
|
|
#include "osc.h"
|
2019-06-15 22:22:44 +02:00
|
|
|
|
2019-08-30 22:08:37 +02:00
|
|
|
#define max(x, y) ((x) > (y) ? (x) : (y))
|
|
|
|
|
|
2019-11-29 23:59:24 +01:00
|
|
|
#define UNHANDLED() LOG_DBG("unhandled: %s", esc_as_string(term, final))
|
2019-07-30 21:42:46 +02:00
|
|
|
|
2019-06-15 22:22:44 +02:00
|
|
|
/* https://vt100.net/emu/dec_ansi_parser */
|
|
|
|
|
|
|
|
|
|
enum state {
|
|
|
|
|
STATE_SAME, /* For state_transition */
|
|
|
|
|
|
|
|
|
|
STATE_GROUND,
|
2019-06-23 13:28:55 +02:00
|
|
|
STATE_ESCAPE,
|
|
|
|
|
STATE_ESCAPE_INTERMEDIATE,
|
|
|
|
|
|
|
|
|
|
STATE_CSI_ENTRY,
|
|
|
|
|
STATE_CSI_PARAM,
|
|
|
|
|
STATE_CSI_INTERMEDIATE,
|
|
|
|
|
STATE_CSI_IGNORE,
|
|
|
|
|
|
|
|
|
|
STATE_OSC_STRING,
|
|
|
|
|
|
|
|
|
|
STATE_DCS_ENTRY,
|
|
|
|
|
STATE_DCS_PARAM,
|
|
|
|
|
STATE_DCS_INTERMEDIATE,
|
|
|
|
|
STATE_DCS_IGNORE,
|
|
|
|
|
STATE_DCS_PASSTHROUGH,
|
2019-06-15 22:22:44 +02:00
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
STATE_SOS_PM_APC_STRING,
|
|
|
|
|
|
|
|
|
|
STATE_UTF8_COLLECT,
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum action {
|
|
|
|
|
ACTION_NONE, /* For state_transition */
|
|
|
|
|
|
|
|
|
|
ACTION_IGNORE,
|
|
|
|
|
ACTION_CLEAR,
|
|
|
|
|
ACTION_EXECUTE,
|
|
|
|
|
ACTION_PRINT,
|
|
|
|
|
ACTION_PARAM,
|
|
|
|
|
ACTION_COLLECT,
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
ACTION_ESC_DISPATCH,
|
|
|
|
|
ACTION_CSI_DISPATCH,
|
|
|
|
|
|
|
|
|
|
ACTION_OSC_START,
|
|
|
|
|
ACTION_OSC_END,
|
|
|
|
|
ACTION_OSC_PUT,
|
|
|
|
|
|
|
|
|
|
ACTION_HOOK,
|
|
|
|
|
ACTION_UNHOOK,
|
|
|
|
|
ACTION_PUT,
|
|
|
|
|
|
|
|
|
|
ACTION_UTF8_2_ENTRY,
|
|
|
|
|
ACTION_UTF8_3_ENTRY,
|
|
|
|
|
ACTION_UTF8_4_ENTRY,
|
|
|
|
|
ACTION_UTF8_COLLECT,
|
2019-07-07 16:32:18 +02:00
|
|
|
ACTION_UTF8_PRINT,
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
2019-11-05 13:55:43 +01:00
|
|
|
#if defined(_DEBUG) && defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG && 0
|
2019-06-15 22:22:44 +02:00
|
|
|
static const char *const state_names[] = {
|
|
|
|
|
[STATE_SAME] = "no change",
|
|
|
|
|
[STATE_GROUND] = "ground",
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
[STATE_ESCAPE] = "escape",
|
|
|
|
|
[STATE_ESCAPE_INTERMEDIATE] = "escape intermediate",
|
|
|
|
|
|
|
|
|
|
[STATE_CSI_ENTRY] = "CSI entry",
|
|
|
|
|
[STATE_CSI_PARAM] = "CSI param",
|
|
|
|
|
[STATE_CSI_INTERMEDIATE] = "CSI intermediate",
|
|
|
|
|
[STATE_CSI_IGNORE] = "CSI ignore",
|
|
|
|
|
|
|
|
|
|
[STATE_OSC_STRING] = "OSC string",
|
|
|
|
|
|
|
|
|
|
[STATE_DCS_ENTRY] = "DCS entry",
|
|
|
|
|
[STATE_DCS_PARAM] = "DCS param",
|
|
|
|
|
[STATE_DCS_INTERMEDIATE] = "DCS intermediate",
|
|
|
|
|
[STATE_DCS_IGNORE] = "DCS ignore",
|
|
|
|
|
[STATE_DCS_PASSTHROUGH] = "DCS passthrough",
|
|
|
|
|
|
|
|
|
|
[STATE_SOS_PM_APC_STRING] = "sos/pm/apc string",
|
|
|
|
|
|
|
|
|
|
[STATE_UTF8_COLLECT] = "UTF-8",
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
2019-07-07 16:32:18 +02:00
|
|
|
#endif
|
2019-06-15 22:22:44 +02:00
|
|
|
static const char *const action_names[] __attribute__((unused)) = {
|
|
|
|
|
[ACTION_NONE] = "no action",
|
|
|
|
|
[ACTION_IGNORE] = "ignore",
|
|
|
|
|
[ACTION_CLEAR] = "clear",
|
|
|
|
|
[ACTION_EXECUTE] = "execute",
|
|
|
|
|
[ACTION_PRINT] = "print",
|
|
|
|
|
[ACTION_PARAM] = "param",
|
|
|
|
|
[ACTION_COLLECT] = "collect",
|
2019-06-23 13:28:55 +02:00
|
|
|
[ACTION_ESC_DISPATCH] = "ESC dispatch",
|
|
|
|
|
[ACTION_CSI_DISPATCH] = "CSI dispatch",
|
|
|
|
|
[ACTION_OSC_START] = "OSC start",
|
|
|
|
|
[ACTION_OSC_END] = "OSC end",
|
|
|
|
|
[ACTION_OSC_PUT] = "OSC put",
|
|
|
|
|
[ACTION_HOOK] = "hook",
|
|
|
|
|
[ACTION_UNHOOK] = "unhook",
|
|
|
|
|
[ACTION_PUT] = "put",
|
|
|
|
|
|
|
|
|
|
[ACTION_UTF8_2_ENTRY] = "UTF-8 (2 chars) begin",
|
|
|
|
|
[ACTION_UTF8_3_ENTRY] = "UTF-8 (3 chars) begin",
|
|
|
|
|
[ACTION_UTF8_4_ENTRY] = "UTF-8 (4 chars) begin",
|
|
|
|
|
[ACTION_UTF8_COLLECT] = "UTF-8 collect",
|
2019-07-07 16:32:18 +02:00
|
|
|
[ACTION_UTF8_PRINT] = "UTF-8 print",
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct state_transition {
|
|
|
|
|
enum action action;
|
|
|
|
|
enum state state;
|
|
|
|
|
};
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
#if 0
|
2019-06-15 22:22:44 +02:00
|
|
|
static const struct state_transition state_anywhere[256] = {
|
2019-06-23 13:28:55 +02:00
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
2019-06-23 13:28:55 +02:00
|
|
|
#endif
|
2019-06-15 22:22:44 +02:00
|
|
|
|
|
|
|
|
static const struct state_transition state_ground[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_EXECUTE},
|
2019-06-23 13:28:55 +02:00
|
|
|
[0x19] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_EXECUTE},
|
2019-06-15 22:22:44 +02:00
|
|
|
[0x20 ... 0x7f] = {.action = ACTION_PRINT},
|
2019-06-23 13:28:55 +02:00
|
|
|
|
|
|
|
|
[0xc0 ... 0xdf] = {.action = ACTION_UTF8_2_ENTRY, .state = STATE_UTF8_COLLECT},
|
|
|
|
|
[0xe0 ... 0xef] = {.action = ACTION_UTF8_3_ENTRY, .state = STATE_UTF8_COLLECT},
|
|
|
|
|
[0xf0 ... 0xf7] = {.action = ACTION_UTF8_4_ENTRY, .state = STATE_UTF8_COLLECT},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition state_escape[256] = {
|
2019-06-23 13:28:55 +02:00
|
|
|
[0x00 ... 0x17] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x19] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x20 ... 0x2f] = {.action = ACTION_COLLECT, .state = STATE_ESCAPE_INTERMEDIATE},
|
|
|
|
|
[0x30 ... 0x4f] = {.action = ACTION_ESC_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x50] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x51 ... 0x57] = {.action = ACTION_ESC_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x58] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x59] = {.action = ACTION_ESC_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x5a] = {.action = ACTION_ESC_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x5b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x5c] = {.action = ACTION_ESC_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x5d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x5e ... 0x5f] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x60 ... 0x7e] = {.action = ACTION_ESC_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
static const struct state_transition state_escape_intermediate[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x19] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x20 ... 0x2f] = {.action = ACTION_COLLECT},
|
|
|
|
|
[0x30 ... 0x7e] = {.action = ACTION_ESC_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
static const struct state_transition state_csi_entry[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x19] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x20 ... 0x2f] = {.action = ACTION_COLLECT, .state = STATE_CSI_INTERMEDIATE},
|
|
|
|
|
[0x30 ... 0x39] = {.action = ACTION_PARAM, .state = STATE_CSI_PARAM},
|
2019-07-15 12:34:51 +02:00
|
|
|
[0x3a ... 0x3b] = { .state = STATE_CSI_PARAM},
|
2019-06-23 13:28:55 +02:00
|
|
|
[0x3c ... 0x3f] = {.action = ACTION_COLLECT, .state = STATE_CSI_PARAM},
|
|
|
|
|
[0x40 ... 0x7e] = {.action = ACTION_CSI_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition state_csi_param[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x19] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x20 ... 0x2f] = {.action = ACTION_COLLECT, .state = STATE_CSI_INTERMEDIATE},
|
2019-06-15 22:22:44 +02:00
|
|
|
[0x30 ... 0x39] = {.action = ACTION_PARAM},
|
2019-07-15 12:34:51 +02:00
|
|
|
[0x3a ... 0x3b] = {.action = ACTION_PARAM},
|
2019-06-23 13:28:55 +02:00
|
|
|
[0x3c ... 0x3f] = { .state = STATE_CSI_IGNORE},
|
|
|
|
|
[0x40 ... 0x7e] = {.action = ACTION_CSI_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition state_csi_intermediate[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x19] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x20 ... 0x2f] = {.action = ACTION_COLLECT},
|
|
|
|
|
[0x30 ... 0x3f] = { .state = STATE_CSI_IGNORE},
|
|
|
|
|
[0x40 ... 0x7e] = {.action = ACTION_CSI_DISPATCH, .state = STATE_GROUND},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition state_csi_ignore[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x19] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_EXECUTE},
|
|
|
|
|
[0x20 ... 0x3f] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x40 ... 0x7e] = { .state = STATE_GROUND},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
};
|
|
|
|
|
|
2019-07-09 09:59:32 +02:00
|
|
|
static const struct state_transition state_osc_string[256] = {
|
2019-06-23 13:28:55 +02:00
|
|
|
[0x00 ... 0x06] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x07] = { .state = STATE_GROUND},
|
|
|
|
|
[0x08 ... 0x17] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x19] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_IGNORE},
|
2019-07-09 11:06:20 +02:00
|
|
|
|
2019-07-09 09:59:32 +02:00
|
|
|
[0x20 ... 0xff] = {.action = ACTION_OSC_PUT},
|
2019-07-09 11:06:20 +02:00
|
|
|
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
2019-07-09 09:59:32 +02:00
|
|
|
#if 0
|
2019-06-23 13:28:55 +02:00
|
|
|
[0x20 ... 0x7f] = {.action = ACTION_OSC_PUT},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
|
2019-07-09 09:59:32 +02:00
|
|
|
[0xc0 ... 0xdf] = {.action = ACTION_OSC_PUT},
|
|
|
|
|
[0xe0 ... 0xef] = {.action = ACTION_OSC_PUT},
|
|
|
|
|
[0xf0 ... 0xf7] = {.action = ACTION_OSC_PUT},
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
2019-07-09 09:59:32 +02:00
|
|
|
#endif
|
2019-06-23 13:28:55 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition state_dcs_entry[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x19] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x20 ... 0x2f] = {.action = ACTION_COLLECT, .state = STATE_DCS_INTERMEDIATE},
|
|
|
|
|
[0x30 ... 0x39] = {.action = ACTION_PARAM, .state = STATE_DCS_PARAM},
|
|
|
|
|
[0x3a] = { .state = STATE_DCS_IGNORE},
|
|
|
|
|
[0x3b] = {.action = ACTION_PARAM, .state = STATE_DCS_PARAM},
|
|
|
|
|
[0x3c ... 0x3f] = {.action = ACTION_COLLECT, .state = STATE_DCS_PARAM},
|
|
|
|
|
[0x40 ... 0x7e] = { .state = STATE_DCS_PASSTHROUGH},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition state_dcs_param[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x19] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x20 ... 0x2f] = {.action = ACTION_COLLECT, .state = STATE_DCS_INTERMEDIATE},
|
|
|
|
|
[0x30 ... 0x39] = {.action = ACTION_PARAM},
|
|
|
|
|
[0x3a] = { .state = STATE_DCS_IGNORE},
|
|
|
|
|
[0x3b] = {.action = ACTION_PARAM},
|
|
|
|
|
[0x3c ... 0x3f] = { .state = STATE_DCS_IGNORE},
|
|
|
|
|
[0x40 ... 0x7e] = { .state = STATE_DCS_PASSTHROUGH},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition state_dcs_intermediate[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x19] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x20 ... 0x2f] = {.action = ACTION_COLLECT},
|
|
|
|
|
[0x30 ... 0x3f] = { .state = STATE_DCS_IGNORE},
|
|
|
|
|
[0x40 ... 0x7e] = { .state = STATE_DCS_PASSTHROUGH},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
static const struct state_transition state_dcs_ignore[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x19] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x1c ... 0x1f] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x20 ... 0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition state_dcs_passthrough[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_PUT},
|
|
|
|
|
[0x19] = {.action = ACTION_PUT},
|
|
|
|
|
[0x1c ... 0x7e] = {.action = ACTION_PUT},
|
|
|
|
|
[0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition state_sos_pm_apc_string[256] = {
|
|
|
|
|
[0x00 ... 0x17] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x19] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x1c ... 0x7f] = {.action = ACTION_IGNORE},
|
|
|
|
|
[0x9c] = { .state = STATE_GROUND},
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
|
|
|
|
[0x18] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x1b] = { .state = STATE_ESCAPE},
|
|
|
|
|
[0x80 ... 0x8f] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x90] = { .state = STATE_DCS_ENTRY},
|
|
|
|
|
[0x91 ... 0x97] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x98] = { .state = STATE_SOS_PM_APC_STRING},
|
|
|
|
|
[0x99] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9a] = {.action = ACTION_EXECUTE, .state = STATE_GROUND},
|
|
|
|
|
[0x9b] = { .state = STATE_CSI_ENTRY},
|
|
|
|
|
[0x9d] = { .state = STATE_OSC_STRING},
|
|
|
|
|
[0x9e ... 0x9f] = { .state = STATE_SOS_PM_APC_STRING},
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct state_transition* states[] = {
|
|
|
|
|
[STATE_GROUND] = state_ground,
|
2019-06-23 13:28:55 +02:00
|
|
|
[STATE_ESCAPE] = state_escape,
|
|
|
|
|
[STATE_ESCAPE_INTERMEDIATE] = state_escape_intermediate,
|
|
|
|
|
[STATE_CSI_ENTRY] = state_csi_entry,
|
|
|
|
|
[STATE_CSI_PARAM] = state_csi_param,
|
|
|
|
|
[STATE_CSI_INTERMEDIATE] = state_csi_intermediate,
|
|
|
|
|
[STATE_CSI_IGNORE] = state_csi_ignore,
|
2019-07-09 09:59:32 +02:00
|
|
|
[STATE_OSC_STRING] = state_osc_string,
|
2019-06-23 13:28:55 +02:00
|
|
|
[STATE_DCS_ENTRY] = state_dcs_entry,
|
|
|
|
|
[STATE_DCS_PARAM] = state_dcs_param,
|
|
|
|
|
[STATE_DCS_INTERMEDIATE] = state_dcs_intermediate,
|
|
|
|
|
[STATE_DCS_IGNORE] = state_dcs_ignore,
|
|
|
|
|
[STATE_DCS_PASSTHROUGH] = state_dcs_passthrough,
|
|
|
|
|
[STATE_SOS_PM_APC_STRING] = state_sos_pm_apc_string,
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const enum action entry_actions[] = {
|
|
|
|
|
[STATE_SAME] = ACTION_NONE,
|
|
|
|
|
[STATE_GROUND] = ACTION_NONE,
|
2019-06-23 13:28:55 +02:00
|
|
|
[STATE_ESCAPE] = ACTION_CLEAR,
|
|
|
|
|
[STATE_CSI_ENTRY] = ACTION_CLEAR,
|
|
|
|
|
[STATE_CSI_PARAM] = ACTION_NONE,
|
|
|
|
|
[STATE_CSI_INTERMEDIATE] = ACTION_NONE,
|
|
|
|
|
[STATE_CSI_IGNORE] = ACTION_NONE,
|
|
|
|
|
[STATE_OSC_STRING] = ACTION_OSC_START,
|
|
|
|
|
[STATE_UTF8_COLLECT] = ACTION_NONE,
|
|
|
|
|
[STATE_DCS_ENTRY] = ACTION_CLEAR,
|
|
|
|
|
[STATE_DCS_PARAM] = ACTION_NONE,
|
|
|
|
|
[STATE_DCS_INTERMEDIATE] = ACTION_NONE,
|
|
|
|
|
[STATE_DCS_IGNORE] = ACTION_NONE,
|
|
|
|
|
[STATE_DCS_PASSTHROUGH] = ACTION_HOOK,
|
|
|
|
|
[STATE_SOS_PM_APC_STRING] = ACTION_NONE,
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const enum action exit_actions[] = {
|
|
|
|
|
[STATE_SAME] = ACTION_NONE,
|
|
|
|
|
[STATE_GROUND] = ACTION_NONE,
|
2019-06-23 13:28:55 +02:00
|
|
|
[STATE_ESCAPE] = ACTION_NONE,
|
|
|
|
|
[STATE_CSI_ENTRY] = ACTION_NONE,
|
|
|
|
|
[STATE_CSI_PARAM] = ACTION_NONE,
|
|
|
|
|
[STATE_CSI_INTERMEDIATE] = ACTION_NONE,
|
|
|
|
|
[STATE_CSI_IGNORE] = ACTION_NONE,
|
|
|
|
|
[STATE_OSC_STRING] = ACTION_OSC_END,
|
|
|
|
|
[STATE_UTF8_COLLECT] = ACTION_NONE,
|
|
|
|
|
[STATE_DCS_ENTRY] = ACTION_NONE,
|
|
|
|
|
[STATE_DCS_PARAM] = ACTION_NONE,
|
|
|
|
|
[STATE_DCS_INTERMEDIATE] = ACTION_NONE,
|
|
|
|
|
[STATE_DCS_IGNORE] = ACTION_NONE,
|
|
|
|
|
[STATE_DCS_PASSTHROUGH] = ACTION_UNHOOK,
|
|
|
|
|
[STATE_SOS_PM_APC_STRING] = ACTION_NONE,
|
2019-06-15 22:22:44 +02:00
|
|
|
};
|
|
|
|
|
|
2019-11-30 00:02:19 +01:00
|
|
|
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
|
2019-07-04 19:35:01 +02:00
|
|
|
static const char *
|
|
|
|
|
esc_as_string(struct terminal *term, uint8_t final)
|
2019-06-23 13:36:20 +02:00
|
|
|
{
|
2019-07-04 19:35:01 +02:00
|
|
|
static char msg[1024];
|
2019-07-10 16:04:25 +02:00
|
|
|
int c = snprintf(msg, sizeof(msg), "\\E");
|
2019-06-23 13:36:20 +02:00
|
|
|
|
2019-07-19 09:56:59 +02:00
|
|
|
for (size_t i = 0; i < sizeof(term->vt.private) / sizeof(term->vt.private[0]); i++) {
|
|
|
|
|
if (term->vt.private[i] == 0)
|
|
|
|
|
break;
|
|
|
|
|
c += snprintf(&msg[c], sizeof(msg) - c, "%c", term->vt.private[i]);
|
|
|
|
|
}
|
2019-06-23 13:36:20 +02:00
|
|
|
|
2019-07-15 13:39:19 +02:00
|
|
|
assert(term->vt.params.idx == 0);
|
|
|
|
|
|
2019-11-05 10:39:36 +01:00
|
|
|
snprintf(&msg[c], sizeof(msg) - c, "%c", final);
|
2019-07-04 19:35:01 +02:00
|
|
|
return msg;
|
|
|
|
|
|
|
|
|
|
}
|
2019-11-30 00:02:19 +01:00
|
|
|
#endif
|
2019-07-04 19:35:01 +02:00
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
static void
|
2019-07-04 19:35:01 +02:00
|
|
|
esc_dispatch(struct terminal *term, uint8_t final)
|
|
|
|
|
{
|
|
|
|
|
LOG_DBG("ESC: %s", esc_as_string(term, final));
|
2019-06-23 13:36:20 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
switch (term->vt.private[0]) {
|
|
|
|
|
case 0:
|
|
|
|
|
switch (final) {
|
|
|
|
|
case '7':
|
|
|
|
|
term->saved_cursor = term->cursor;
|
|
|
|
|
term->vt.saved_attrs = term->vt.attrs;
|
2019-11-17 10:02:46 +01:00
|
|
|
term->saved_charsets = term->charsets;
|
2019-11-05 11:32:56 +01:00
|
|
|
break;
|
2019-07-17 10:39:38 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case '8':
|
|
|
|
|
term_restore_cursor(term);
|
|
|
|
|
term->vt.attrs = term->vt.saved_attrs;
|
2019-11-17 10:02:46 +01:00
|
|
|
term->charsets = term->saved_charsets;
|
2019-11-05 11:32:56 +01:00
|
|
|
break;
|
2019-06-29 20:49:00 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case 'c':
|
|
|
|
|
term_reset(term, true);
|
|
|
|
|
break;
|
2019-06-29 20:49:00 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case 'D':
|
|
|
|
|
term_linefeed(term);
|
|
|
|
|
break;
|
2019-07-10 16:05:19 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case 'E':
|
|
|
|
|
term_linefeed(term);
|
2019-11-17 09:44:31 +01:00
|
|
|
term_cursor_left(term, term->cursor.point.col);
|
2019-11-05 11:32:56 +01:00
|
|
|
break;
|
2019-07-18 19:25:53 +02:00
|
|
|
|
2019-11-16 10:57:11 +01:00
|
|
|
case 'H':
|
|
|
|
|
tll_foreach(term->tab_stops, it) {
|
2019-11-17 09:44:31 +01:00
|
|
|
if (it->item >= term->cursor.point.col) {
|
|
|
|
|
tll_insert_before(term->tab_stops, it, term->cursor.point.col);
|
2019-11-16 10:57:11 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-17 09:44:31 +01:00
|
|
|
tll_push_back(term->tab_stops, term->cursor.point.col);
|
2019-11-16 10:57:11 +01:00
|
|
|
break;
|
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case 'M':
|
|
|
|
|
term_reverse_index(term);
|
|
|
|
|
break;
|
2019-07-10 16:05:01 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case 'N':
|
|
|
|
|
/* SS2 - Single Shift 2 */
|
2019-11-17 09:59:12 +01:00
|
|
|
term->charsets.selected = 2; /* G2 */
|
2019-11-05 11:32:56 +01:00
|
|
|
break;
|
2019-07-18 19:25:53 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case 'O':
|
|
|
|
|
/* SS3 - Single Shift 3 */
|
2019-11-17 09:59:12 +01:00
|
|
|
term->charsets.selected = 3; /* G3 */
|
2019-11-05 11:32:56 +01:00
|
|
|
break;
|
2019-07-18 19:25:53 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case '\\':
|
|
|
|
|
/* ST - String Terminator */
|
|
|
|
|
break;
|
2019-07-10 16:05:19 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case '=':
|
|
|
|
|
term->keypad_keys_mode = KEYPAD_APPLICATION;
|
|
|
|
|
break;
|
2019-07-03 16:21:26 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case '>':
|
|
|
|
|
term->keypad_keys_mode = KEYPAD_NUMERICAL;
|
|
|
|
|
break;
|
2019-07-03 16:21:26 +02:00
|
|
|
|
|
|
|
|
default:
|
2019-07-30 21:42:46 +02:00
|
|
|
UNHANDLED();
|
2019-07-07 16:32:18 +02:00
|
|
|
break;
|
2019-07-03 16:21:26 +02:00
|
|
|
}
|
2019-11-05 11:32:56 +01:00
|
|
|
break; /* private[0] == 0 */
|
|
|
|
|
|
|
|
|
|
case '(':
|
|
|
|
|
case ')':
|
|
|
|
|
case '*':
|
|
|
|
|
case '+':
|
|
|
|
|
switch (final) {
|
|
|
|
|
case '0': {
|
|
|
|
|
char priv = term->vt.private[0];
|
|
|
|
|
ssize_t idx = priv ==
|
|
|
|
|
'(' ? 0 :
|
|
|
|
|
')' ? 1 :
|
|
|
|
|
'*' ? 2 :
|
|
|
|
|
'+' ? 3 : -1;
|
|
|
|
|
assert(idx != -1);
|
2019-11-17 09:59:12 +01:00
|
|
|
term->charsets.set[idx] = CHARSET_GRAPHIC;
|
2019-11-05 11:32:56 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2019-06-29 20:49:00 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case 'B': {
|
|
|
|
|
char priv = term->vt.private[0];
|
|
|
|
|
ssize_t idx = priv ==
|
|
|
|
|
'(' ? 0 :
|
|
|
|
|
')' ? 1 :
|
|
|
|
|
'*' ? 2 :
|
|
|
|
|
'+' ? 3 : -1;
|
|
|
|
|
assert(idx != -1);
|
2019-11-17 09:59:12 +01:00
|
|
|
term->charsets.set[idx] = CHARSET_ASCII;
|
2019-06-23 13:36:20 +02:00
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-23 13:36:20 +02:00
|
|
|
break;
|
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
case '#':
|
|
|
|
|
switch (final) {
|
|
|
|
|
case '8':
|
|
|
|
|
for (int r = 0; r < term->rows; r++) {
|
2019-11-14 11:08:49 +01:00
|
|
|
struct row *row = grid_row(term->grid, r);
|
2019-11-05 11:32:56 +01:00
|
|
|
for (int c = 0; c < term->cols; c++) {
|
|
|
|
|
row->cells[c].wc = L'E';
|
|
|
|
|
row->cells[c].attrs.clean = 0;
|
|
|
|
|
}
|
|
|
|
|
row->dirty = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break; /* private[0] == '#' */
|
|
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-17 17:22:16 +01:00
|
|
|
static inline void
|
|
|
|
|
pre_print(struct terminal *term)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(term->cursor.lcf) && term->auto_margin) {
|
|
|
|
|
if (term->cursor.point.row == term->scroll_region.end - 1) {
|
|
|
|
|
term_scroll(term, 1);
|
|
|
|
|
term_cursor_to(term, term->cursor.point.row, 0);
|
|
|
|
|
} else
|
|
|
|
|
term_cursor_to(term, term->cursor.point.row + 1, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
static inline void
|
|
|
|
|
post_print(struct terminal *term)
|
|
|
|
|
{
|
2019-11-17 09:44:31 +01:00
|
|
|
if (term->cursor.point.col < term->cols - 1)
|
2019-07-07 16:32:18 +02:00
|
|
|
term_cursor_right(term, 1);
|
|
|
|
|
else
|
2019-11-17 09:46:20 +01:00
|
|
|
term->cursor.lcf = true;
|
2019-07-07 16:32:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
2019-08-30 22:08:37 +02:00
|
|
|
print_insert(struct terminal *term, int width)
|
2019-07-07 16:32:18 +02:00
|
|
|
{
|
2019-11-30 00:15:05 +01:00
|
|
|
assert(width > 0);
|
|
|
|
|
if (unlikely(term->insert_mode)) {
|
|
|
|
|
struct row *row = term->grid->cur_row;
|
|
|
|
|
const size_t move_count = max(0, term->cols - term->cursor.point.col - width);
|
|
|
|
|
|
|
|
|
|
memmove(
|
|
|
|
|
&row->cells[term->cursor.point.col + width],
|
|
|
|
|
&row->cells[term->cursor.point.col],
|
|
|
|
|
move_count * sizeof(struct cell));
|
|
|
|
|
|
|
|
|
|
/* Mark moved cells as dirty */
|
|
|
|
|
for (size_t i = term->cursor.point.col + width; i < term->cols; i++)
|
|
|
|
|
row->cells[i].attrs.clean = 0;
|
|
|
|
|
}
|
2019-07-07 16:32:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
action_print_utf8(struct terminal *term)
|
|
|
|
|
{
|
2019-11-17 17:22:16 +01:00
|
|
|
pre_print(term);
|
2019-07-07 16:32:18 +02:00
|
|
|
|
2019-07-08 13:57:31 +02:00
|
|
|
struct row *row = term->grid->cur_row;
|
2019-11-17 09:44:31 +01:00
|
|
|
struct cell *cell = &row->cells[term->cursor.point.col];
|
font: initial support for double-width *and* color emoji glyphs
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
2019-07-31 18:03:35 +02:00
|
|
|
|
2019-08-30 22:08:37 +02:00
|
|
|
/* Convert to wchar */
|
|
|
|
|
mbstate_t ps = {0};
|
|
|
|
|
wchar_t wc;
|
|
|
|
|
if (mbrtowc(&wc, (const char *)term->vt.utf8.data, term->vt.utf8.idx, &ps) < 0)
|
|
|
|
|
wc = 0;
|
|
|
|
|
|
|
|
|
|
int width = wcwidth(wc);
|
2019-11-30 00:15:05 +01:00
|
|
|
if (width > 0)
|
|
|
|
|
print_insert(term, width);
|
2019-08-30 22:08:37 +02:00
|
|
|
|
2019-07-08 13:57:31 +02:00
|
|
|
row->dirty = true;
|
2019-08-30 22:08:37 +02:00
|
|
|
cell->wc = wc;
|
2019-07-30 18:03:03 +02:00
|
|
|
cell->attrs.clean = 0;
|
2019-08-30 22:08:37 +02:00
|
|
|
cell->attrs = term->vt.attrs;
|
2019-06-23 13:36:20 +02:00
|
|
|
|
2019-08-30 22:08:37 +02:00
|
|
|
/* Reset VT utf8 state */
|
2019-07-07 16:32:18 +02:00
|
|
|
term->vt.utf8.idx = 0;
|
|
|
|
|
|
2019-08-02 18:19:07 +02:00
|
|
|
if (width <= 0) {
|
|
|
|
|
/* Skip post_print() below - i.e. don't advance cursor */
|
|
|
|
|
return;
|
|
|
|
|
}
|
font: initial support for double-width *and* color emoji glyphs
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
2019-07-31 18:03:35 +02:00
|
|
|
|
2019-08-02 18:19:07 +02:00
|
|
|
/* Advance cursor the 'additional' columns (last step is done
|
|
|
|
|
* by post_print()) */
|
2019-11-17 09:44:31 +01:00
|
|
|
for (int i = 1; i < width && term->cursor.point.col < term->cols - 1; i++) {
|
2019-08-02 18:19:07 +02:00
|
|
|
term_cursor_right(term, 1);
|
font: initial support for double-width *and* color emoji glyphs
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
2019-07-31 18:03:35 +02:00
|
|
|
|
2019-11-17 09:44:31 +01:00
|
|
|
assert(term->cursor.point.col < term->cols);
|
|
|
|
|
struct cell *cell = &row->cells[term->cursor.point.col];
|
2019-08-02 18:19:07 +02:00
|
|
|
cell->wc = 0;
|
|
|
|
|
cell->attrs.clean = 0;
|
font: initial support for double-width *and* color emoji glyphs
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
2019-07-31 18:03:35 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
post_print(term);
|
2019-06-23 13:36:20 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
static void
|
|
|
|
|
action_print(struct terminal *term, uint8_t c)
|
2019-06-15 22:22:44 +02:00
|
|
|
{
|
2019-11-17 17:22:16 +01:00
|
|
|
pre_print(term);
|
2019-07-07 16:32:18 +02:00
|
|
|
|
2019-07-08 13:57:31 +02:00
|
|
|
struct row *row = term->grid->cur_row;
|
2019-11-17 09:44:31 +01:00
|
|
|
struct cell *cell = &row->cells[term->cursor.point.col];
|
font: initial support for double-width *and* color emoji glyphs
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
2019-07-31 18:03:35 +02:00
|
|
|
|
2019-07-08 13:57:31 +02:00
|
|
|
row->dirty = true;
|
2019-07-30 18:03:03 +02:00
|
|
|
cell->attrs.clean = 0;
|
2019-07-07 16:32:18 +02:00
|
|
|
|
2019-08-30 22:08:37 +02:00
|
|
|
print_insert(term, 1);
|
2019-07-07 16:32:18 +02:00
|
|
|
|
2019-08-16 18:04:03 +02:00
|
|
|
/* 0x60 - 0x7e */
|
2019-08-27 15:23:50 +02:00
|
|
|
static const wchar_t vt100_0[] = {
|
|
|
|
|
L'◆', L'▒', L'␉', L'␌', L'␍', L'␊', L'°', L'±', /* ` - g */
|
|
|
|
|
L'', L'␋', L'┘', L'┐', L'┌', L'└', L'┼', L'⎺', /* h - o */
|
|
|
|
|
L'⎻', L'─', L'⎼', L'⎽', L'├', L'┤', L'┴', L'┬', /* p - w */
|
|
|
|
|
L'│', L'≤', L'≥', L'π', L'≠', L'£', L'·', /* x - ~ */
|
2019-07-07 16:32:18 +02:00
|
|
|
};
|
|
|
|
|
|
2019-11-17 09:59:12 +01:00
|
|
|
if (unlikely(term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC) &&
|
2019-08-16 18:04:03 +02:00
|
|
|
c >= 0x60 && c <= 0x7e)
|
2019-07-07 16:32:18 +02:00
|
|
|
{
|
2019-08-27 15:23:50 +02:00
|
|
|
cell->wc = vt100_0[c - 0x60];
|
2019-07-07 16:32:18 +02:00
|
|
|
} else {
|
2019-11-05 13:56:25 +01:00
|
|
|
// LOG_DBG("print: ASCII: %c (0x%04x)", c, c);
|
2019-08-02 18:19:07 +02:00
|
|
|
cell->wc = c;
|
2019-07-07 16:32:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cell->attrs = term->vt.attrs;
|
|
|
|
|
post_print(term);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
action(struct terminal *term, enum action _action, uint8_t c)
|
|
|
|
|
{
|
|
|
|
|
switch (_action) {
|
2019-06-15 22:22:44 +02:00
|
|
|
case ACTION_NONE:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACTION_IGNORE:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACTION_EXECUTE:
|
|
|
|
|
LOG_DBG("execute: 0x%02x", c);
|
|
|
|
|
switch (c) {
|
2019-07-18 12:19:54 +02:00
|
|
|
case '\0':
|
|
|
|
|
break;
|
|
|
|
|
|
2019-06-19 10:04:47 +02:00
|
|
|
case '\n':
|
2019-06-26 19:58:37 +02:00
|
|
|
/* LF - line feed */
|
2019-07-10 16:04:46 +02:00
|
|
|
term_linefeed(term);
|
2019-06-19 10:04:47 +02:00
|
|
|
break;
|
|
|
|
|
|
2019-06-15 22:22:44 +02:00
|
|
|
case '\r':
|
2019-06-26 19:58:37 +02:00
|
|
|
/* FF - form feed */
|
2019-11-17 09:44:31 +01:00
|
|
|
term_cursor_left(term, term->cursor.point.col);
|
2019-06-17 18:57:12 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '\b':
|
2019-06-26 19:58:37 +02:00
|
|
|
/* backspace */
|
2019-06-29 21:03:28 +02:00
|
|
|
term_cursor_left(term, 1);
|
2019-06-15 22:22:44 +02:00
|
|
|
break;
|
2019-06-19 10:04:47 +02:00
|
|
|
|
|
|
|
|
case '\x07':
|
2019-06-26 19:58:37 +02:00
|
|
|
/* BEL */
|
2019-11-30 00:00:41 +01:00
|
|
|
// LOG_INFO("BELL");
|
|
|
|
|
// term_flash(term, 50);
|
2019-06-19 10:04:47 +02:00
|
|
|
break;
|
|
|
|
|
|
2019-06-26 19:58:37 +02:00
|
|
|
case '\x09': {
|
|
|
|
|
/* HT - horizontal tab */
|
2019-11-17 10:15:56 +01:00
|
|
|
int new_col = term->cols - 1;
|
2019-11-16 10:57:39 +01:00
|
|
|
tll_foreach(term->tab_stops, it) {
|
2019-11-17 10:15:56 +01:00
|
|
|
if (it->item > term->cursor.point.col) {
|
2019-11-16 10:57:39 +01:00
|
|
|
new_col = it->item;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-17 11:20:59 +01:00
|
|
|
assert(new_col >= term->cursor.point.col);
|
2019-11-17 09:44:31 +01:00
|
|
|
term_cursor_right(term, new_col - term->cursor.point.col);
|
2019-06-26 19:58:37 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-05 13:56:52 +01:00
|
|
|
case '\x0b':
|
|
|
|
|
/* VT - vertical tab */
|
|
|
|
|
term_cursor_down(term, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
2019-11-05 13:56:44 +01:00
|
|
|
case '\x0e':
|
2019-07-15 12:04:40 +02:00
|
|
|
/* SO - shift out */
|
2019-11-17 09:59:12 +01:00
|
|
|
term->charsets.selected = 1; /* G1 */
|
2019-07-15 12:04:40 +02:00
|
|
|
break;
|
|
|
|
|
|
2019-11-05 13:56:44 +01:00
|
|
|
case '\x0f':
|
2019-07-15 12:04:40 +02:00
|
|
|
/* SI - shift in */
|
2019-11-17 09:59:12 +01:00
|
|
|
term->charsets.selected = 0; /* G0 */
|
2019-07-15 12:04:40 +02:00
|
|
|
break;
|
|
|
|
|
|
2019-06-19 10:04:47 +02:00
|
|
|
default:
|
2019-07-07 16:32:18 +02:00
|
|
|
break;
|
2019-06-15 22:22:44 +02:00
|
|
|
}
|
2019-06-17 18:57:12 +02:00
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
break;
|
2019-06-15 22:22:44 +02:00
|
|
|
|
|
|
|
|
case ACTION_CLEAR:
|
2019-08-24 11:33:13 +02:00
|
|
|
term->vt.params.idx = 0;
|
2019-07-19 09:56:59 +02:00
|
|
|
term->vt.private[0] = 0;
|
|
|
|
|
term->vt.private[1] = 0;
|
2019-07-02 21:44:58 +02:00
|
|
|
term->vt.utf8.idx = 0;
|
2019-06-15 22:22:44 +02:00
|
|
|
break;
|
|
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
case ACTION_PRINT:
|
|
|
|
|
action_print(term, c);
|
|
|
|
|
break;
|
2019-06-17 20:53:05 +02:00
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
case ACTION_UTF8_PRINT:
|
|
|
|
|
action_print_utf8(term);
|
2019-06-15 22:22:44 +02:00
|
|
|
break;
|
|
|
|
|
|
2019-07-15 12:34:51 +02:00
|
|
|
case ACTION_PARAM:
|
2019-08-24 11:33:13 +02:00
|
|
|
if (term->vt.params.idx == 0) {
|
2019-08-27 15:24:49 +02:00
|
|
|
struct vt_param *param = &term->vt.params.v[0];
|
|
|
|
|
param->value = 0;
|
|
|
|
|
param->sub.idx = 0;
|
2019-06-15 22:22:44 +02:00
|
|
|
term->vt.params.idx = 1;
|
2019-08-24 11:33:13 +02:00
|
|
|
}
|
2019-06-15 22:22:44 +02:00
|
|
|
|
|
|
|
|
if (c == ';') {
|
2019-08-27 15:24:49 +02:00
|
|
|
struct vt_param *param = &term->vt.params.v[term->vt.params.idx++];
|
|
|
|
|
param->value = 0;
|
|
|
|
|
param->sub.idx = 0;
|
2019-06-15 22:22:44 +02:00
|
|
|
} else if (c == ':') {
|
2019-08-24 11:33:13 +02:00
|
|
|
struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1];
|
2019-08-24 11:39:28 +02:00
|
|
|
param->sub.value[param->sub.idx++] = 0;
|
2019-06-15 22:22:44 +02:00
|
|
|
} else {
|
2019-07-15 12:34:51 +02:00
|
|
|
assert(term->vt.params.idx >= 0);
|
|
|
|
|
struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1];
|
|
|
|
|
|
|
|
|
|
unsigned *value = param->sub.idx > 0
|
|
|
|
|
? ¶m->sub.value[param->sub.idx - 1]
|
|
|
|
|
: ¶m->value;
|
|
|
|
|
|
|
|
|
|
*value *= 10;
|
|
|
|
|
*value += c - '0';
|
2019-06-15 22:22:44 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACTION_COLLECT:
|
|
|
|
|
LOG_DBG("collect");
|
2019-07-19 09:56:59 +02:00
|
|
|
if (term->vt.private[0] == 0)
|
|
|
|
|
term->vt.private[0] = c;
|
|
|
|
|
else if (term->vt.private[1] == 0)
|
|
|
|
|
term->vt.private[1] = c;
|
2019-07-30 21:42:46 +02:00
|
|
|
else
|
2019-11-30 00:12:30 +01:00
|
|
|
LOG_DBG("only two private/intermediate characters supported");
|
2019-07-07 16:32:18 +02:00
|
|
|
break;
|
2019-06-23 13:28:55 +02:00
|
|
|
|
2019-06-23 13:36:20 +02:00
|
|
|
case ACTION_ESC_DISPATCH:
|
2019-07-07 16:32:18 +02:00
|
|
|
esc_dispatch(term, c);
|
2019-06-23 13:36:20 +02:00
|
|
|
break;
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
case ACTION_CSI_DISPATCH:
|
2019-07-07 16:32:18 +02:00
|
|
|
csi_dispatch(term, c);
|
|
|
|
|
break;
|
2019-06-15 22:22:44 +02:00
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
case ACTION_OSC_START:
|
2019-06-15 22:22:44 +02:00
|
|
|
term->vt.osc.idx = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
case ACTION_OSC_PUT:
|
2019-07-19 08:59:35 +02:00
|
|
|
if (!osc_ensure_size(term, term->vt.osc.idx + 1))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
term->vt.osc.data[term->vt.osc.idx++] = c;
|
2019-06-15 22:22:44 +02:00
|
|
|
break;
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
case ACTION_OSC_END:
|
2019-07-19 08:59:35 +02:00
|
|
|
if (!osc_ensure_size(term, term->vt.osc.idx + 1))
|
|
|
|
|
break;
|
2019-07-05 09:46:48 +02:00
|
|
|
term->vt.osc.data[term->vt.osc.idx] = '\0';
|
2019-07-07 16:32:18 +02:00
|
|
|
osc_dispatch(term);
|
|
|
|
|
break;
|
2019-06-15 22:22:44 +02:00
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
case ACTION_HOOK:
|
|
|
|
|
case ACTION_PUT:
|
2019-07-19 09:55:07 +02:00
|
|
|
case ACTION_UNHOOK:
|
2019-07-21 18:22:26 +02:00
|
|
|
/* We have no parent terminal to pass through to */
|
2019-07-19 09:55:07 +02:00
|
|
|
break;
|
2019-06-23 13:28:55 +02:00
|
|
|
|
|
|
|
|
case ACTION_UTF8_2_ENTRY:
|
2019-06-15 22:22:44 +02:00
|
|
|
term->vt.utf8.idx = 0;
|
2019-06-23 13:28:55 +02:00
|
|
|
term->vt.utf8.left = 2;
|
2019-06-15 22:22:44 +02:00
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
|
|
|
|
term->vt.utf8.left--;
|
|
|
|
|
break;
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
case ACTION_UTF8_3_ENTRY:
|
|
|
|
|
term->vt.utf8.idx = 0;
|
|
|
|
|
term->vt.utf8.left = 3;
|
|
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
|
|
|
|
term->vt.utf8.left--;
|
|
|
|
|
break;
|
2019-06-15 22:22:44 +02:00
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
case ACTION_UTF8_4_ENTRY:
|
|
|
|
|
term->vt.utf8.idx = 0;
|
|
|
|
|
term->vt.utf8.left = 4;
|
|
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
|
|
|
|
term->vt.utf8.left--;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACTION_UTF8_COLLECT:
|
|
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
2019-07-07 16:32:18 +02:00
|
|
|
if (--term->vt.utf8.left == 0) {
|
2019-06-23 13:28:55 +02:00
|
|
|
term->vt.state = STATE_GROUND;
|
2019-07-07 16:32:18 +02:00
|
|
|
action_print_utf8(term);
|
|
|
|
|
}
|
2019-06-23 13:28:55 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2019-06-15 22:22:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
vt_from_slave(struct terminal *term, const uint8_t *data, size_t len)
|
|
|
|
|
{
|
2019-07-07 16:32:18 +02:00
|
|
|
//LOG_DBG("input: 0x%02x", data[i]);
|
|
|
|
|
enum state current_state = term->vt.state;
|
|
|
|
|
|
2019-06-15 22:22:44 +02:00
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
if (current_state == STATE_UTF8_COLLECT) {
|
2019-07-07 16:32:18 +02:00
|
|
|
action(term, ACTION_UTF8_COLLECT, data[i]);
|
2019-06-18 21:55:18 +02:00
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
current_state = term->vt.state;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const struct state_transition *transition = &states[current_state][data[i]];
|
2019-06-15 22:22:44 +02:00
|
|
|
|
|
|
|
|
if (transition->state != STATE_SAME) {
|
|
|
|
|
enum action exit_action = exit_actions[current_state];
|
2019-07-07 16:32:18 +02:00
|
|
|
action(term, exit_action, data[i]);
|
2019-06-15 22:22:44 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
action(term, transition->action, data[i]);
|
2019-06-15 22:22:44 +02:00
|
|
|
|
|
|
|
|
if (transition->state != STATE_SAME) {
|
2019-06-17 18:57:12 +02:00
|
|
|
/*
|
|
|
|
|
* LOG_DBG("transition: %s -> %s", state_names[current_state],
|
|
|
|
|
* state_names[transition->state]);
|
|
|
|
|
*/
|
2019-06-15 22:22:44 +02:00
|
|
|
term->vt.state = transition->state;
|
2019-07-07 16:32:18 +02:00
|
|
|
current_state = transition->state;
|
2019-06-15 22:22:44 +02:00
|
|
|
|
|
|
|
|
enum action entry_action = entry_actions[transition->state];
|
2019-07-07 16:32:18 +02:00
|
|
|
action(term, entry_action, data[i]);
|
2019-06-15 22:22:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|