mirror of
https://github.com/tmate-io/tmate.git
synced 2024-11-27 18:43:11 +01:00
1145 lines
25 KiB
C
1145 lines
25 KiB
C
/* $Id: input.c,v 1.21 2007-10-05 17:51:56 nicm Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "tmux.h"
|
|
|
|
const struct {
|
|
u_char first;
|
|
u_char last;
|
|
enum input_class class;
|
|
} input_table[] = {
|
|
{ 0x00, 0x1f, INPUT_C0CONTROL },
|
|
{ 0x20, 0x20, INPUT_SPACE },
|
|
{ 0x21, 0x2F, INPUT_INTERMEDIATE }, /* also INPUT_SPACE */
|
|
{ 0x30, 0x3F, INPUT_PARAMETER },
|
|
{ 0x40, 0x5F, INPUT_UPPERCASE },
|
|
{ 0x60, 0x7E, INPUT_LOWERCASE },
|
|
{ 0x7F, 0x7F, INPUT_DELETE },
|
|
{ 0x80, 0x9F, INPUT_C1CONTROL },
|
|
{ 0xA0, 0xA0, INPUT_SPACE },
|
|
{ 0xA1, 0xFE, INPUT_G1DISPLAYABLE },
|
|
{ 0xFF, 0xFF, INPUT_SPECIAL },
|
|
};
|
|
#define NINPUTCLASS (sizeof input_table / sizeof input_table[0])
|
|
|
|
enum input_class input_lookup_class(u_char);
|
|
int input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t);
|
|
int input_new_argument(struct input_ctx *);
|
|
int input_add_argument(struct input_ctx *, u_char ch);
|
|
|
|
void *input_state_first(u_char, enum input_class, struct input_ctx *);
|
|
void *input_state_escape(u_char, enum input_class, struct input_ctx *);
|
|
void *input_state_intermediate(u_char, enum input_class, struct input_ctx *);
|
|
void *input_state_title_first(u_char, enum input_class, struct input_ctx *);
|
|
void *input_state_title_second(u_char, enum input_class, struct input_ctx *);
|
|
void *input_state_title_next(u_char, enum input_class, struct input_ctx *);
|
|
void *input_state_sequence_first(
|
|
u_char, enum input_class, struct input_ctx *);
|
|
void *input_state_sequence_next(
|
|
u_char, enum input_class, struct input_ctx *);
|
|
void *input_state_sequence_intermediate(
|
|
u_char, enum input_class, struct input_ctx *);
|
|
|
|
void input_handle_character(u_char, struct input_ctx *);
|
|
void input_handle_c0_control(u_char, struct input_ctx *);
|
|
void input_handle_c1_control(u_char, struct input_ctx *);
|
|
void input_handle_private_two(u_char, struct input_ctx *);
|
|
void input_handle_standard_two(u_char, struct input_ctx *);
|
|
void input_handle_sequence(u_char, struct input_ctx *);
|
|
|
|
void input_handle_sequence_cuu(struct input_ctx *);
|
|
void input_handle_sequence_cud(struct input_ctx *);
|
|
void input_handle_sequence_cuf(struct input_ctx *);
|
|
void input_handle_sequence_cub(struct input_ctx *);
|
|
void input_handle_sequence_dch(struct input_ctx *);
|
|
void input_handle_sequence_dl(struct input_ctx *);
|
|
void input_handle_sequence_ich(struct input_ctx *);
|
|
void input_handle_sequence_il(struct input_ctx *);
|
|
void input_handle_sequence_vpa(struct input_ctx *);
|
|
void input_handle_sequence_hpa(struct input_ctx *);
|
|
void input_handle_sequence_cup(struct input_ctx *);
|
|
void input_handle_sequence_cup(struct input_ctx *);
|
|
void input_handle_sequence_ed(struct input_ctx *);
|
|
void input_handle_sequence_el(struct input_ctx *);
|
|
void input_handle_sequence_sm(struct input_ctx *);
|
|
void input_handle_sequence_rm(struct input_ctx *);
|
|
void input_handle_sequence_decstbm(struct input_ctx *);
|
|
void input_handle_sequence_sgr(struct input_ctx *);
|
|
|
|
enum input_class
|
|
input_lookup_class(u_char ch)
|
|
{
|
|
enum input_class iclass;
|
|
u_int i;
|
|
|
|
iclass = INPUT_SPACE;
|
|
for (i = 0; i < NINPUTCLASS; i++) {
|
|
if (ch >= input_table[i].first && ch <= input_table[i].last) {
|
|
iclass = input_table[i].class;
|
|
break;
|
|
}
|
|
}
|
|
if (i == NINPUTCLASS)
|
|
fatalx("character without class");
|
|
|
|
return (iclass);
|
|
}
|
|
|
|
int
|
|
input_new_argument(struct input_ctx *ictx)
|
|
{
|
|
struct input_arg *arg;
|
|
|
|
ARRAY_EXPAND(&ictx->args, 1);
|
|
|
|
arg = &ARRAY_LAST(&ictx->args);
|
|
arg->used = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
input_add_argument(struct input_ctx *ictx, u_char ch)
|
|
{
|
|
struct input_arg *arg;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) == 0)
|
|
return (0);
|
|
|
|
arg = &ARRAY_LAST(&ictx->args);
|
|
if (arg->used > (sizeof arg->data) - 1)
|
|
return (-1);
|
|
arg->data[arg->used++] = ch;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
input_get_argument(struct input_ctx *ictx, u_int i, uint16_t *n, uint16_t d)
|
|
{
|
|
struct input_arg *arg;
|
|
const char *errstr;
|
|
|
|
*n = d;
|
|
if (i >= ARRAY_LENGTH(&ictx->args))
|
|
return (0);
|
|
|
|
arg = &ARRAY_ITEM(&ictx->args, i);
|
|
if (*arg->data == '\0')
|
|
return (0);
|
|
|
|
*n = strtonum(arg->data, 0, UINT16_MAX, &errstr);
|
|
if (errstr != NULL)
|
|
return (-1);
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
input_init(struct input_ctx *ictx, struct screen *s)
|
|
{
|
|
ictx->s = s;
|
|
|
|
ARRAY_INIT(&ictx->args);
|
|
|
|
ictx->state = input_state_first;
|
|
}
|
|
|
|
void
|
|
input_free(struct input_ctx *ictx)
|
|
{
|
|
ARRAY_FREE(&ictx->args);
|
|
}
|
|
|
|
void
|
|
input_parse(struct input_ctx *ictx, u_char *buf, size_t len, struct buffer *b)
|
|
{
|
|
enum input_class iclass;
|
|
u_char ch;
|
|
|
|
ictx->buf = buf;
|
|
ictx->len = len;
|
|
ictx->off = 0;
|
|
|
|
ictx->b = b;
|
|
ictx->flags = 0;
|
|
|
|
log_debug2("entry; buffer=%zu", ictx->len);
|
|
|
|
while (ictx->off < ictx->len) {
|
|
ch = ictx->buf[ictx->off++];
|
|
iclass = input_lookup_class(ch);
|
|
ictx->state = ictx->state(ch, iclass, ictx);
|
|
}
|
|
}
|
|
|
|
void *
|
|
input_state_first(u_char ch, enum input_class iclass, struct input_ctx *ictx)
|
|
{
|
|
switch (iclass) {
|
|
case INPUT_C0CONTROL:
|
|
if (ch == 0x1b)
|
|
return (input_state_escape);
|
|
input_handle_c0_control(ch, ictx);
|
|
break;
|
|
case INPUT_C1CONTROL:
|
|
ch -= 0x40;
|
|
if (ch == '[')
|
|
return (input_state_sequence_first);
|
|
if (ch == ']')
|
|
return (input_state_title_first);
|
|
input_handle_c1_control(ch, ictx);
|
|
break;
|
|
case INPUT_SPACE:
|
|
case INPUT_INTERMEDIATE:
|
|
case INPUT_PARAMETER:
|
|
case INPUT_UPPERCASE:
|
|
case INPUT_LOWERCASE:
|
|
case INPUT_DELETE:
|
|
case INPUT_G1DISPLAYABLE:
|
|
case INPUT_SPECIAL:
|
|
input_handle_character(ch, ictx);
|
|
break;
|
|
}
|
|
return (input_state_first);
|
|
}
|
|
|
|
void *
|
|
input_state_escape(u_char ch, enum input_class iclass, struct input_ctx *ictx)
|
|
{
|
|
if (iclass == INPUT_C1CONTROL || iclass == INPUT_G1DISPLAYABLE) {
|
|
/* Treat as 7-bit equivalent. */
|
|
ch &= 0x7f;
|
|
iclass = input_lookup_class(ch);
|
|
}
|
|
|
|
switch (iclass) {
|
|
case INPUT_C0CONTROL:
|
|
input_handle_c0_control(ch, ictx);
|
|
return (input_state_escape);
|
|
case INPUT_SPACE:
|
|
case INPUT_INTERMEDIATE:
|
|
return (input_state_intermediate);
|
|
case INPUT_PARAMETER:
|
|
input_handle_private_two(ch, ictx);
|
|
break;
|
|
case INPUT_UPPERCASE:
|
|
if (ch == '[')
|
|
return (input_state_sequence_first);
|
|
if (ch == ']')
|
|
return (input_state_title_first);
|
|
input_handle_c1_control(ch, ictx);
|
|
break;
|
|
case INPUT_LOWERCASE:
|
|
input_handle_standard_two(ch, ictx);
|
|
break;
|
|
case INPUT_DELETE:
|
|
case INPUT_SPECIAL:
|
|
case INPUT_C1CONTROL:
|
|
case INPUT_G1DISPLAYABLE:
|
|
break;
|
|
}
|
|
return (input_state_first);
|
|
}
|
|
|
|
void *
|
|
input_state_title_first(
|
|
u_char ch, unused enum input_class iclass, struct input_ctx *ictx)
|
|
{
|
|
if (ch >= '0' && ch <= '9') {
|
|
ictx->title_type = ch - '0';
|
|
return (input_state_title_second);
|
|
}
|
|
return (input_state_first);
|
|
}
|
|
|
|
void *
|
|
input_state_title_second(
|
|
u_char ch, unused enum input_class iclass, struct input_ctx *ictx)
|
|
{
|
|
if (ch == ';') {
|
|
ictx->title_len = 0;
|
|
return (input_state_title_next);
|
|
}
|
|
return (input_state_first);
|
|
}
|
|
|
|
void *
|
|
input_state_title_next(
|
|
u_char ch, unused enum input_class iclass, struct input_ctx *ictx)
|
|
{
|
|
if (ch == '\007') {
|
|
ictx->title_buf[ictx->title_len] = '\0';
|
|
switch (ictx->title_type) {
|
|
case 0:
|
|
strlcpy(ictx->s->title,
|
|
ictx->title_buf, sizeof ictx->s->title);
|
|
input_store_one(ictx->b, CODE_TITLE, ictx->title_len);
|
|
buffer_write(ictx->b, ictx->title_buf, ictx->title_len);
|
|
break;
|
|
}
|
|
} else if (ch >= 0x20) {
|
|
if (ictx->title_len < (sizeof ictx->title_buf) - 1) {
|
|
ictx->title_buf[ictx->title_len++] = ch;
|
|
return (input_state_title_next);
|
|
}
|
|
}
|
|
return (input_state_first);
|
|
}
|
|
|
|
void *
|
|
input_state_intermediate(
|
|
u_char ch, enum input_class iclass, struct input_ctx *ictx)
|
|
{
|
|
switch (iclass) {
|
|
case INPUT_SPACE:
|
|
case INPUT_INTERMEDIATE:
|
|
return (input_state_intermediate);
|
|
case INPUT_PARAMETER:
|
|
input_handle_private_two(ch, ictx);
|
|
break;
|
|
case INPUT_UPPERCASE:
|
|
case INPUT_LOWERCASE:
|
|
input_handle_standard_two(ch, ictx);
|
|
break;
|
|
case INPUT_C0CONTROL:
|
|
case INPUT_DELETE:
|
|
case INPUT_SPECIAL:
|
|
case INPUT_C1CONTROL:
|
|
case INPUT_G1DISPLAYABLE:
|
|
break;
|
|
}
|
|
return (input_state_first);
|
|
}
|
|
|
|
void *
|
|
input_state_sequence_first(
|
|
u_char ch, enum input_class iclass, struct input_ctx *ictx)
|
|
{
|
|
ictx->private = '\0';
|
|
ARRAY_CLEAR(&ictx->args);
|
|
|
|
switch (iclass) {
|
|
case INPUT_PARAMETER:
|
|
if (ch >= 0x3c && ch <= 0x3f) {
|
|
/* Private control sequence. */
|
|
ictx->private = ch;
|
|
return (input_state_sequence_next);
|
|
}
|
|
input_new_argument(ictx);
|
|
break;
|
|
case INPUT_SPACE:
|
|
case INPUT_INTERMEDIATE:
|
|
case INPUT_UPPERCASE:
|
|
case INPUT_LOWERCASE:
|
|
case INPUT_C0CONTROL:
|
|
case INPUT_C1CONTROL:
|
|
case INPUT_DELETE:
|
|
case INPUT_G1DISPLAYABLE:
|
|
case INPUT_SPECIAL:
|
|
break;
|
|
}
|
|
|
|
/* Pass character on directly. */
|
|
return (input_state_sequence_next(ch, iclass, ictx));
|
|
}
|
|
|
|
void *
|
|
input_state_sequence_next(
|
|
u_char ch, enum input_class iclass, struct input_ctx *ictx)
|
|
{
|
|
switch (iclass) {
|
|
case INPUT_SPACE:
|
|
case INPUT_INTERMEDIATE:
|
|
if (input_add_argument(ictx, '\0') != 0)
|
|
break;
|
|
return (input_state_sequence_intermediate);
|
|
case INPUT_PARAMETER:
|
|
if (ch == ';') {
|
|
if (input_add_argument(ictx, '\0') != 0)
|
|
break;
|
|
input_new_argument(ictx);
|
|
return (input_state_sequence_next);
|
|
}
|
|
if (input_add_argument(ictx, ch) != 0)
|
|
break;
|
|
return (input_state_sequence_next);
|
|
case INPUT_UPPERCASE:
|
|
case INPUT_LOWERCASE:
|
|
if (input_add_argument(ictx, '\0') != 0)
|
|
break;
|
|
input_handle_sequence(ch, ictx);
|
|
break;
|
|
case INPUT_C0CONTROL:
|
|
case INPUT_C1CONTROL:
|
|
case INPUT_DELETE:
|
|
case INPUT_SPECIAL:
|
|
case INPUT_G1DISPLAYABLE:
|
|
break;
|
|
}
|
|
return (input_state_first);
|
|
}
|
|
|
|
void *
|
|
input_state_sequence_intermediate(
|
|
u_char ch, enum input_class iclass, struct input_ctx *ictx)
|
|
{
|
|
switch (iclass) {
|
|
case INPUT_SPACE:
|
|
case INPUT_INTERMEDIATE:
|
|
return (input_state_sequence_intermediate);
|
|
case INPUT_UPPERCASE:
|
|
case INPUT_LOWERCASE:
|
|
input_handle_sequence(ch, ictx);
|
|
break;
|
|
case INPUT_PARAMETER:
|
|
case INPUT_C0CONTROL:
|
|
case INPUT_DELETE:
|
|
case INPUT_SPECIAL:
|
|
case INPUT_C1CONTROL:
|
|
case INPUT_G1DISPLAYABLE:
|
|
break;
|
|
}
|
|
return (input_state_first);
|
|
}
|
|
|
|
void
|
|
input_handle_character(u_char ch, struct input_ctx *ictx)
|
|
{
|
|
log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch);
|
|
|
|
if (ictx->s->cx > ictx->s->sx - 1 || ictx->s->cy > ictx->s->sy - 1)
|
|
return;
|
|
|
|
screen_write_character(ictx->s, ch);
|
|
input_store8(ictx->b, ch);
|
|
|
|
if (ictx->s->cx == ictx->s->sx - 1) {
|
|
ictx->s->cx = 0;
|
|
screen_cursor_down_scroll(ictx->s);
|
|
|
|
input_store8(ictx->b, '\r');
|
|
input_store8(ictx->b, '\n');
|
|
} else
|
|
ictx->s->cx++;
|
|
}
|
|
|
|
void
|
|
input_handle_c0_control(u_char ch, struct input_ctx *ictx)
|
|
{
|
|
log_debug2("-- c0 %zu: %hhu", ictx->off, ch);
|
|
|
|
switch (ch) {
|
|
case '\0': /* NUL */
|
|
break;
|
|
case '\n': /* LF */
|
|
screen_cursor_down_scroll(ictx->s);
|
|
break;
|
|
case '\r': /* CR */
|
|
ictx->s->cx = 0;
|
|
break;
|
|
case '\007': /* BELL */
|
|
ictx->flags |= INPUT_BELL;
|
|
break;
|
|
case '\010': /* BS */
|
|
if (ictx->s->cx > 0)
|
|
ictx->s->cx--;
|
|
break;
|
|
default:
|
|
log_debug("unknown c0: %hhu", ch);
|
|
return;
|
|
}
|
|
input_store8(ictx->b, ch);
|
|
}
|
|
|
|
void
|
|
input_handle_c1_control(u_char ch, struct input_ctx *ictx)
|
|
{
|
|
log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch);
|
|
|
|
switch (ch) {
|
|
case 'M': /* RI */
|
|
screen_cursor_up_scroll(ictx->s);
|
|
input_store_zero(ictx->b, CODE_REVERSEINDEX);
|
|
break;
|
|
default:
|
|
log_debug("unknown c1: %hhu", ch);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
input_handle_private_two(u_char ch, struct input_ctx *ictx)
|
|
{
|
|
log_debug2("-- p2 %zu: %hhu (%c)", ictx->off, ch, ch);
|
|
|
|
switch (ch) {
|
|
case '=': /* DECKPAM */
|
|
input_store_zero(ictx->b, CODE_KKEYPADON);
|
|
break;
|
|
case '>': /* DECKPNM*/
|
|
input_store_zero(ictx->b, CODE_KKEYPADOFF);
|
|
break;
|
|
default:
|
|
log_debug("unknown p2: %hhu", ch);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
input_handle_standard_two(u_char ch, struct input_ctx *ictx)
|
|
{
|
|
log_debug2("-- s2 %zu: %hhu (%c)", ictx->off, ch, ch);
|
|
|
|
log_debug("unknown s2: %hhu", ch);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence(u_char ch, struct input_ctx *ictx)
|
|
{
|
|
static const struct {
|
|
u_char ch;
|
|
void (*fn)(struct input_ctx *);
|
|
} table[] = {
|
|
{ '@', input_handle_sequence_ich },
|
|
{ 'A', input_handle_sequence_cuu },
|
|
{ 'B', input_handle_sequence_cud },
|
|
{ 'C', input_handle_sequence_cuf },
|
|
{ 'D', input_handle_sequence_cub },
|
|
{ 'G', input_handle_sequence_hpa },
|
|
{ 'H', input_handle_sequence_cup },
|
|
{ 'J', input_handle_sequence_ed },
|
|
{ 'K', input_handle_sequence_el },
|
|
{ 'L', input_handle_sequence_il },
|
|
{ 'M', input_handle_sequence_dl },
|
|
{ 'P', input_handle_sequence_dch },
|
|
{ 'd', input_handle_sequence_vpa },
|
|
{ 'f', input_handle_sequence_cup },
|
|
{ 'h', input_handle_sequence_sm },
|
|
{ 'l', input_handle_sequence_rm },
|
|
{ 'm', input_handle_sequence_sgr },
|
|
{ 'r', input_handle_sequence_decstbm },
|
|
};
|
|
u_int i;
|
|
struct input_arg *iarg;
|
|
|
|
log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u]",
|
|
ictx->off, ch, ch, ARRAY_LENGTH(&ictx->args),
|
|
ictx->s->sx, ictx->s->sy, ictx->s->cx, ictx->s->cy);
|
|
for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
|
|
iarg = &ARRAY_ITEM(&ictx->args, i);
|
|
if (*iarg->data != '\0')
|
|
log_debug2(" ++ %u: %s", i, iarg->data);
|
|
}
|
|
|
|
/* XXX bsearch? */
|
|
for (i = 0; i < (sizeof table / sizeof table[0]); i++) {
|
|
if (table[i].ch == ch) {
|
|
table[i].fn(ictx);
|
|
return;
|
|
}
|
|
}
|
|
|
|
log_debug("unknown sq: %c (%hhu %hhu)", ch, ch, ictx->private);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_cuu(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->cy) {
|
|
log_debug3("cuu: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
ictx->s->cy -= n;
|
|
input_store_one(ictx->b, CODE_CURSORUP, n);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_cud(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sy - ictx->s->cy - 1) {
|
|
log_debug3("cud: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
ictx->s->cy += n;
|
|
input_store_one(ictx->b, CODE_CURSORDOWN, n);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_cuf(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sx - ictx->s->cx - 1) {
|
|
log_debug3("cuf: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
ictx->s->cx += n;
|
|
input_store_one(ictx->b, CODE_CURSORRIGHT, n);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_cub(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->cx) {
|
|
log_debug3("cub: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
ictx->s->cx -= n;
|
|
input_store_one(ictx->b, CODE_CURSORLEFT, n);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_dch(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sx - ictx->s->cx - 1) {
|
|
log_debug3("dch: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
screen_delete_characters(ictx->s, ictx->s->cx, ictx->s->cy, n);
|
|
input_store_one(ictx->b, CODE_DELETECHARACTER, n);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_dl(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sy - ictx->s->cy - 1) {
|
|
log_debug3("dl: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
if (n < ictx->s->ry_upper || n > ictx->s->ry_lower)
|
|
screen_delete_lines(ictx->s, ictx->s->cy, n);
|
|
else
|
|
screen_delete_lines_region(ictx->s, ictx->s->cy, n);
|
|
input_store_one(ictx->b, CODE_DELETELINE, n);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_ich(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sx - ictx->s->cx - 1) {
|
|
log_debug3("ich: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
screen_insert_characters(ictx->s, ictx->s->cx, ictx->s->cy, n);
|
|
input_store_one(ictx->b, CODE_INSERTCHARACTER, n);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_il(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sy - ictx->s->cy - 1) {
|
|
log_debug3("il: out of range: %hu", n);
|
|
return;
|
|
}
|
|
if (n < ictx->s->ry_upper || n > ictx->s->ry_lower)
|
|
screen_insert_lines(ictx->s, ictx->s->cy, n);
|
|
else
|
|
screen_insert_lines_region(ictx->s, ictx->s->cy, n);
|
|
input_store_one(ictx->b, CODE_INSERTLINE, n);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_vpa(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sy) {
|
|
log_debug3("vpa: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
ictx->s->cy = n - 1;
|
|
input_store_two(ictx->b, CODE_CURSORMOVE, n, ictx->s->cx + 1);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_hpa(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sx) {
|
|
log_debug3("hpa: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
ictx->s->cx = n - 1;
|
|
input_store_two(ictx->b, CODE_CURSORMOVE, ictx->s->cy + 1, n);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_cup(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n, m;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 2)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
if (input_get_argument(ictx, 1, &m, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sy || m == 0 || m > ictx->s->sx) {
|
|
log_debug3("cup: out of range: %hu", n);
|
|
return;
|
|
}
|
|
|
|
ictx->s->cx = m - 1;
|
|
ictx->s->cy = n - 1;
|
|
input_store_two(ictx->b, CODE_CURSORMOVE, n, m);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_ed(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
u_int i;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 0) != 0)
|
|
return;
|
|
|
|
if (n > 2)
|
|
return;
|
|
|
|
switch (n) {
|
|
case 0:
|
|
screen_fill_end_of_screen(ictx->s, 0, ictx->s->cy,
|
|
SCREEN_DEFDATA, ictx->s->attr, ictx->s->colr);
|
|
input_store_zero(ictx->b, CODE_CLEARLINE);
|
|
for (i = ictx->s->cy + 1; i < ictx->s->sy; i++) {
|
|
input_store_two(ictx->b, CODE_CURSORMOVE, i + 1, 1);
|
|
input_store_zero(ictx->b, CODE_CLEARLINE);
|
|
}
|
|
input_store_two(
|
|
ictx->b, CODE_CURSORMOVE, ictx->s->cy + 1, ictx->s->cx + 1);
|
|
break;
|
|
case 2:
|
|
screen_fill_screen(
|
|
ictx->s, SCREEN_DEFDATA, ictx->s->attr, ictx->s->colr);
|
|
for (i = 0; i < ictx->s->sy; i++) {
|
|
input_store_two(ictx->b, CODE_CURSORMOVE, i + 1, 1);
|
|
input_store_zero(ictx->b, CODE_CLEARLINE);
|
|
}
|
|
input_store_two(
|
|
ictx->b, CODE_CURSORMOVE, ictx->s->cy + 1, ictx->s->cx + 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_el(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 0) != 0)
|
|
return;
|
|
|
|
if (n > 2)
|
|
return;
|
|
|
|
switch (n) {
|
|
case 0:
|
|
screen_fill_end_of_line(ictx->s, ictx->s->cx, ictx->s->cy,
|
|
SCREEN_DEFDATA, ictx->s->attr, ictx->s->colr);
|
|
input_store_zero(ictx->b, CODE_CLEARENDOFLINE);
|
|
break;
|
|
case 1:
|
|
screen_fill_start_of_line(ictx->s, ictx->s->cx, ictx->s->cy,
|
|
SCREEN_DEFDATA, ictx->s->attr, ictx->s->colr);
|
|
input_store_zero(ictx->b, CODE_CLEARSTARTOFLINE);
|
|
break;
|
|
case 2:
|
|
screen_fill_line(ictx->s, ictx->s->cy,
|
|
SCREEN_DEFDATA, ictx->s->attr, ictx->s->colr);
|
|
input_store_zero(ictx->b, CODE_CLEARLINE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_sm(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 0) != 0)
|
|
return;
|
|
|
|
if (ictx->private == '?') {
|
|
switch (n) {
|
|
case 1: /* GATM */
|
|
ictx->s->mode |= MODE_KCURSOR;
|
|
input_store_zero(ictx->b, CODE_KCURSORON);
|
|
break;
|
|
case 25: /* TCEM */
|
|
ictx->s->mode |= MODE_CURSOR;
|
|
input_store_zero(ictx->b, CODE_CURSORON);
|
|
break;
|
|
default:
|
|
log_debug("unknown SM [%hhu]: %u", ictx->private, n);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (n) {
|
|
case 4: /* IRM */
|
|
ictx->s->mode |= MODE_INSERT;
|
|
input_store_zero(ictx->b, CODE_INSERTON);
|
|
break;
|
|
case 34:
|
|
/* Cursor high visibility not supported. */
|
|
break;
|
|
default:
|
|
log_debug("unknown SM [%hhu]: %u", ictx->private, n);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_rm(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 1)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 0) != 0)
|
|
return;
|
|
|
|
if (ictx->private == '?') {
|
|
switch (n) {
|
|
case 1: /* GATM */
|
|
ictx->s->mode &= ~MODE_KCURSOR;
|
|
input_store_zero(ictx->b, CODE_KCURSOROFF);
|
|
break;
|
|
case 25: /* TCEM */
|
|
ictx->s->mode &= ~MODE_CURSOR;
|
|
input_store_zero(ictx->b, CODE_CURSOROFF);
|
|
break;
|
|
default:
|
|
log_debug("unknown RM [%hhu]: %u", ictx->private, n);
|
|
break;
|
|
}
|
|
} else if (ictx->private == '\0') {
|
|
switch (n) {
|
|
case 4: /* IRM */
|
|
ictx->s->mode &= ~MODE_INSERT;
|
|
input_store_zero(ictx->b, CODE_INSERTOFF);
|
|
break;
|
|
case 34:
|
|
/* Cursor high visibility not supported. */
|
|
break;
|
|
default:
|
|
log_debug("unknown RM [%hhu]: %u", ictx->private, n);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_decstbm(struct input_ctx *ictx)
|
|
{
|
|
uint16_t n, m;
|
|
|
|
if (ictx->private != '\0')
|
|
return;
|
|
|
|
if (ARRAY_LENGTH(&ictx->args) > 2)
|
|
return;
|
|
if (input_get_argument(ictx, 0, &n, 1) != 0)
|
|
return;
|
|
if (input_get_argument(ictx, 1, &m, 1) != 0)
|
|
return;
|
|
|
|
if (n == 0 || n > ictx->s->sy || m == 0 || m > ictx->s->sy) {
|
|
log_debug3("decstbm: out of range: %hu,%hu", n, m);
|
|
return;
|
|
}
|
|
if (n > m) {
|
|
log_debug3("decstbm: out of range: %hu,%hu", n, m);
|
|
return;
|
|
}
|
|
|
|
ictx->s->ry_upper = n - 1;
|
|
ictx->s->ry_lower = m - 1;
|
|
input_store_two(ictx->b, CODE_SCROLLREGION, n, m);
|
|
}
|
|
|
|
void
|
|
input_handle_sequence_sgr(struct input_ctx *ictx)
|
|
{
|
|
u_int i, n;
|
|
uint16_t m;
|
|
|
|
n = ARRAY_LENGTH(&ictx->args);
|
|
if (n == 0) {
|
|
ictx->s->attr = 0;
|
|
ictx->s->colr = SCREEN_DEFCOLR;
|
|
} else {
|
|
for (i = 0; i < n; i++) {
|
|
if (input_get_argument(ictx, i, &m, 0) != 0)
|
|
return;
|
|
switch (m) {
|
|
case 0:
|
|
case 10:
|
|
ictx->s->attr = 0;
|
|
ictx->s->colr = SCREEN_DEFCOLR;
|
|
break;
|
|
case 1:
|
|
ictx->s->attr |= ATTR_BRIGHT;
|
|
break;
|
|
case 2:
|
|
ictx->s->attr |= ATTR_DIM;
|
|
break;
|
|
case 3:
|
|
ictx->s->attr |= ATTR_ITALICS;
|
|
break;
|
|
case 4:
|
|
ictx->s->attr |= ATTR_UNDERSCORE;
|
|
break;
|
|
case 5:
|
|
ictx->s->attr |= ATTR_BLINK;
|
|
break;
|
|
case 7:
|
|
ictx->s->attr |= ATTR_REVERSE;
|
|
break;
|
|
case 8:
|
|
ictx->s->attr |= ATTR_HIDDEN;
|
|
break;
|
|
case 23:
|
|
ictx->s->attr &= ~ATTR_ITALICS;
|
|
break;
|
|
case 24:
|
|
ictx->s->attr &= ~ATTR_UNDERSCORE;
|
|
break;
|
|
case 30:
|
|
case 31:
|
|
case 32:
|
|
case 33:
|
|
case 34:
|
|
case 35:
|
|
case 36:
|
|
case 37:
|
|
ictx->s->colr &= 0x0f;
|
|
ictx->s->colr |= (m - 30) << 4;
|
|
break;
|
|
case 39:
|
|
ictx->s->colr &= 0x0f;
|
|
ictx->s->colr |= 0x80;
|
|
break;
|
|
case 40:
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47:
|
|
ictx->s->colr &= 0xf0;
|
|
ictx->s->colr |= m - 40;
|
|
break;
|
|
case 49:
|
|
ictx->s->colr &= 0xf0;
|
|
ictx->s->colr |= 0x08;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
input_store_two(ictx->b, CODE_ATTRIBUTES, ictx->s->attr, ictx->s->colr);
|
|
}
|
|
|
|
void
|
|
input_store_zero(struct buffer *b, u_char code)
|
|
{
|
|
input_store8(b, '\e');
|
|
input_store8(b, code);
|
|
}
|
|
|
|
void
|
|
input_store_one(struct buffer *b, u_char code, uint16_t ua)
|
|
{
|
|
input_store8(b, '\e');
|
|
input_store8(b, code);
|
|
input_store16(b, ua);
|
|
}
|
|
|
|
void
|
|
input_store_two(struct buffer *b, u_char code, uint16_t ua, uint16_t ub)
|
|
{
|
|
input_store8(b, '\e');
|
|
input_store8(b, code);
|
|
input_store16(b, ua);
|
|
input_store16(b, ub);
|
|
}
|
|
|
|
void
|
|
input_store8(struct buffer *b, uint8_t n)
|
|
{
|
|
buffer_ensure(b, 1);
|
|
BUFFER_IN(b)[0] = n;
|
|
buffer_add(b, 1);
|
|
}
|
|
|
|
void
|
|
input_store16(struct buffer *b, uint16_t n)
|
|
{
|
|
buffer_ensure(b, 2);
|
|
BUFFER_IN(b)[0] = n & 0xff;
|
|
BUFFER_IN(b)[1] = n >> 8;
|
|
buffer_add(b, 2);
|
|
}
|
|
|
|
uint8_t
|
|
input_extract8(struct buffer *b)
|
|
{
|
|
uint8_t n;
|
|
|
|
n = BUFFER_OUT(b)[0];
|
|
buffer_remove(b, 1);
|
|
return (n);
|
|
}
|
|
|
|
uint16_t
|
|
input_extract16(struct buffer *b)
|
|
{
|
|
uint16_t n;
|
|
|
|
n = BUFFER_OUT(b)[0] | (BUFFER_OUT(b)[1] << 8);
|
|
buffer_remove(b, 2);
|
|
return (n);
|
|
}
|