teken_subr.h revision 197520
133965Sjdp/*-
238889Sjdp * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
338889Sjdp * All rights reserved.
433965Sjdp *
533965Sjdp * Redistribution and use in source and binary forms, with or without
633965Sjdp * modification, are permitted provided that the following conditions
733965Sjdp * are met:
833965Sjdp * 1. Redistributions of source code must retain the above copyright
933965Sjdp *    notice, this list of conditions and the following disclaimer.
1033965Sjdp * 2. Redistributions in binary form must reproduce the above copyright
1133965Sjdp *    notice, this list of conditions and the following disclaimer in the
1233965Sjdp *    documentation and/or other materials provided with the distribution.
1333965Sjdp *
1433965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1533965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1633965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1733965Sjdp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1833965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1933965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2033965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2233965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2333965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2433965Sjdp * SUCH DAMAGE.
2533965Sjdp *
2633965Sjdp * $FreeBSD: head/sys/teken/teken_subr.h 197520 2009-09-26 15:03:42Z ed $
2733965Sjdp */
2833965Sjdp
2933965Sjdpstatic void teken_subr_cursor_up(teken_t *, unsigned int);
3033965Sjdpstatic void teken_subr_erase_line(teken_t *, unsigned int);
3133965Sjdpstatic void teken_subr_regular_character(teken_t *, teken_char_t);
3233965Sjdpstatic void teken_subr_reset_to_initial_state(teken_t *);
3333965Sjdpstatic void teken_subr_save_cursor(teken_t *);
3433965Sjdp
3533965Sjdpstatic inline int
3677298Sobrienteken_tab_isset(teken_t *t, unsigned int col)
3733965Sjdp{
3833965Sjdp	unsigned int b, o;
3933965Sjdp
4033965Sjdp	if (col >= T_NUMCOL)
4133965Sjdp		return ((col % 8) == 0);
4233965Sjdp
4333965Sjdp	b = col / (sizeof(unsigned int) * 8);
4433965Sjdp	o = col % (sizeof(unsigned int) * 8);
4533965Sjdp
4633965Sjdp	return (t->t_tabstops[b] & (1 << o));
4733965Sjdp}
4833965Sjdp
4933965Sjdpstatic inline void
5033965Sjdpteken_tab_clear(teken_t *t, unsigned int col)
5133965Sjdp{
5233965Sjdp	unsigned int b, o;
5333965Sjdp
5433965Sjdp	if (col >= T_NUMCOL)
5533965Sjdp		return;
5633965Sjdp
5733965Sjdp	b = col / (sizeof(unsigned int) * 8);
5833965Sjdp	o = col % (sizeof(unsigned int) * 8);
5933965Sjdp
6033965Sjdp	t->t_tabstops[b] &= ~(1 << o);
6133965Sjdp}
6233965Sjdp
6333965Sjdpstatic inline void
6433965Sjdpteken_tab_set(teken_t *t, unsigned int col)
6533965Sjdp{
6633965Sjdp	unsigned int b, o;
6733965Sjdp
6833965Sjdp	if (col >= T_NUMCOL)
6933965Sjdp		return;
7033965Sjdp
7133965Sjdp	b = col / (sizeof(unsigned int) * 8);
7233965Sjdp	o = col % (sizeof(unsigned int) * 8);
7333965Sjdp
7433965Sjdp	t->t_tabstops[b] |= 1 << o;
7533965Sjdp}
7633965Sjdp
7733965Sjdpstatic void
7833965Sjdpteken_tab_default(teken_t *t)
7933965Sjdp{
8033965Sjdp	unsigned int i;
8133965Sjdp
8233965Sjdp	memset(&t->t_tabstops, 0, T_NUMCOL / 8);
8333965Sjdp
8433965Sjdp	for (i = 8; i < T_NUMCOL; i += 8)
8533965Sjdp		teken_tab_set(t, i);
8633965Sjdp}
8733965Sjdp
8833965Sjdpstatic void
8933965Sjdpteken_subr_do_scroll(teken_t *t, int amount)
9033965Sjdp{
9133965Sjdp	teken_rect_t tr;
9233965Sjdp	teken_pos_t tp;
9333965Sjdp
9433965Sjdp	teken_assert(t->t_cursor.tp_row <= t->t_winsize.tp_row);
9533965Sjdp	teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
9633965Sjdp	teken_assert(amount != 0);
9733965Sjdp
9833965Sjdp	/* Copy existing data 1 line up. */
9933965Sjdp	if (amount > 0) {
10033965Sjdp		/* Scroll down. */
10133965Sjdp
10233965Sjdp		/* Copy existing data up. */
10333965Sjdp		if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
10433965Sjdp			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin + amount;
10533965Sjdp			tr.tr_begin.tp_col = 0;
10633965Sjdp			tr.tr_end.tp_row = t->t_scrollreg.ts_end;
10733965Sjdp			tr.tr_end.tp_col = t->t_winsize.tp_col;
10833965Sjdp			tp.tp_row = t->t_scrollreg.ts_begin;
10933965Sjdp			tp.tp_col = 0;
11033965Sjdp			teken_funcs_copy(t, &tr, &tp);
11133965Sjdp
11233965Sjdp			tr.tr_begin.tp_row = t->t_scrollreg.ts_end - amount;
11333965Sjdp		} else {
11433965Sjdp			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
11533965Sjdp		}
11633965Sjdp
11733965Sjdp		/* Clear the last lines. */
11833965Sjdp		tr.tr_begin.tp_col = 0;
11933965Sjdp		tr.tr_end.tp_row = t->t_scrollreg.ts_end;
12033965Sjdp		tr.tr_end.tp_col = t->t_winsize.tp_col;
12133965Sjdp		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
12233965Sjdp	} else {
12333965Sjdp		/* Scroll up. */
12433965Sjdp		amount = -amount;
12533965Sjdp
12677298Sobrien		/* Copy existing data down. */
12733965Sjdp		if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
12838889Sjdp			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
12933965Sjdp			tr.tr_begin.tp_col = 0;
13033965Sjdp			tr.tr_end.tp_row = t->t_scrollreg.ts_end - amount;
13133965Sjdp			tr.tr_end.tp_col = t->t_winsize.tp_col;
13233965Sjdp			tp.tp_row = t->t_scrollreg.ts_begin + amount;
13333965Sjdp			tp.tp_col = 0;
13438889Sjdp			teken_funcs_copy(t, &tr, &tp);
13533965Sjdp
13633965Sjdp			tr.tr_end.tp_row = t->t_scrollreg.ts_begin + amount;
13733965Sjdp		} else {
13833965Sjdp			tr.tr_end.tp_row = t->t_scrollreg.ts_end;
13933965Sjdp		}
14038889Sjdp
14133965Sjdp		/* Clear the first lines. */
14233965Sjdp		tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
14333965Sjdp		tr.tr_begin.tp_col = 0;
14433965Sjdp		tr.tr_end.tp_col = t->t_winsize.tp_col;
14533965Sjdp		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
14633965Sjdp	}
14733965Sjdp}
14833965Sjdp
14933965Sjdpstatic ssize_t
15033965Sjdpteken_subr_do_cpr(teken_t *t, unsigned int cmd, char response[16])
15133965Sjdp{
15233965Sjdp
15360484Sobrien	switch (cmd) {
15460484Sobrien	case 5: /* Operating status. */
15560484Sobrien		strcpy(response, "0n");
15660484Sobrien		return (2);
15760484Sobrien	case 6: { /* Cursor position. */
15833965Sjdp		int len;
15933965Sjdp
16033965Sjdp		len = snprintf(response, 16, "%u;%uR",
16133965Sjdp		    (t->t_cursor.tp_row - t->t_originreg.ts_begin) + 1,
16233965Sjdp		    t->t_cursor.tp_col + 1);
16333965Sjdp
16433965Sjdp		if (len >= 16)
16533965Sjdp			return (-1);
16633965Sjdp		return (len);
16733965Sjdp	}
16833965Sjdp	case 15: /* Printer status. */
16933965Sjdp		strcpy(response, "13n");
17033965Sjdp		return (3);
17133965Sjdp	case 25: /* UDK status. */
17233965Sjdp		strcpy(response, "20n");
17333965Sjdp		return (3);
17433965Sjdp	case 26: /* Keyboard status. */
17533965Sjdp		strcpy(response, "27;1n");
17633965Sjdp		return (5);
17733965Sjdp	default:
17833965Sjdp		teken_printf("Unknown DSR\n");
17933965Sjdp		return (-1);
18033965Sjdp	}
18133965Sjdp}
18233965Sjdp
18377298Sobrienstatic void
18433965Sjdpteken_subr_alignment_test(teken_t *t)
18533965Sjdp{
18633965Sjdp	teken_rect_t tr;
18733965Sjdp
18833965Sjdp	t->t_scrollreg.ts_begin = 0;
18933965Sjdp	t->t_scrollreg.ts_end = t->t_winsize.tp_row;
19033965Sjdp
19133965Sjdp	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
19233965Sjdp	t->t_stateflags &= ~TS_WRAPPED;
19333965Sjdp	teken_funcs_cursor(t);
19433965Sjdp
19533965Sjdp	tr.tr_begin.tp_row = 0;
19633965Sjdp	tr.tr_begin.tp_col = 0;
19733965Sjdp	tr.tr_end = t->t_winsize;
19833965Sjdp	teken_funcs_fill(t, &tr, 'E', &t->t_defattr);
19933965Sjdp}
20033965Sjdp
20133965Sjdpstatic void
20233965Sjdpteken_subr_backspace(teken_t *t)
20333965Sjdp{
20433965Sjdp
20533965Sjdp	if (t->t_stateflags & TS_CONS25) {
20633965Sjdp		if (t->t_cursor.tp_col == 0) {
20733965Sjdp			if (t->t_cursor.tp_row == t->t_originreg.ts_begin)
20833965Sjdp				return;
20933965Sjdp			t->t_cursor.tp_row--;
21033965Sjdp			t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
21133965Sjdp		} else {
21233965Sjdp			t->t_cursor.tp_col--;
21333965Sjdp		}
21433965Sjdp	} else {
21533965Sjdp		if (t->t_cursor.tp_col == 0)
21633965Sjdp			return;
21733965Sjdp
21833965Sjdp		t->t_cursor.tp_col--;
21933965Sjdp		t->t_stateflags &= ~TS_WRAPPED;
22033965Sjdp	}
22133965Sjdp
22238889Sjdp	teken_funcs_cursor(t);
22333965Sjdp}
22433965Sjdp
22538889Sjdpstatic void
22633965Sjdpteken_subr_bell(teken_t *t)
22733965Sjdp{
22833965Sjdp
22938889Sjdp	teken_funcs_bell(t);
23033965Sjdp}
23133965Sjdp
23233965Sjdpstatic void
23333965Sjdpteken_subr_carriage_return(teken_t *t)
23433965Sjdp{
23533965Sjdp
23633965Sjdp	t->t_cursor.tp_col = 0;
23733965Sjdp	t->t_stateflags &= ~TS_WRAPPED;
23833965Sjdp	teken_funcs_cursor(t);
23933965Sjdp}
24060484Sobrien
24160484Sobrienstatic void
24260484Sobrienteken_subr_cursor_backward(teken_t *t, unsigned int ncols)
24333965Sjdp{
24433965Sjdp
24533965Sjdp	if (ncols > t->t_cursor.tp_col)
24633965Sjdp		t->t_cursor.tp_col = 0;
24733965Sjdp	else
24833965Sjdp		t->t_cursor.tp_col -= ncols;
24933965Sjdp	t->t_stateflags &= ~TS_WRAPPED;
25033965Sjdp	teken_funcs_cursor(t);
25133965Sjdp}
25233965Sjdp
25333965Sjdpstatic void
25433965Sjdpteken_subr_cursor_backward_tabulation(teken_t *t, unsigned int ntabs)
25533965Sjdp{
25633965Sjdp
25733965Sjdp	do {
25833965Sjdp		/* Stop when we've reached the beginning of the line. */
25933965Sjdp		if (t->t_cursor.tp_col == 0)
26033965Sjdp			break;
26133965Sjdp
26233965Sjdp		t->t_cursor.tp_col--;
26333965Sjdp
26433965Sjdp		/* Tab marker set. */
26533965Sjdp		if (teken_tab_isset(t, t->t_cursor.tp_col))
26633965Sjdp			ntabs--;
26733965Sjdp	} while (ntabs > 0);
26833965Sjdp
26933965Sjdp	teken_funcs_cursor(t);
27033965Sjdp}
27133965Sjdp
27233965Sjdpstatic void
27333965Sjdpteken_subr_cursor_down(teken_t *t, unsigned int nrows)
27433965Sjdp{
27533965Sjdp
27633965Sjdp	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end)
27733965Sjdp		t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
27877298Sobrien	else
27933965Sjdp		t->t_cursor.tp_row += nrows;
28033965Sjdp	t->t_stateflags &= ~TS_WRAPPED;
28133965Sjdp	teken_funcs_cursor(t);
28277298Sobrien}
28333965Sjdp
28433965Sjdpstatic void
28533965Sjdpteken_subr_cursor_forward(teken_t *t, unsigned int ncols)
28633965Sjdp{
28733965Sjdp
28833965Sjdp	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
28933965Sjdp		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
29033965Sjdp	else
29133965Sjdp		t->t_cursor.tp_col += ncols;
29233965Sjdp	t->t_stateflags &= ~TS_WRAPPED;
29333965Sjdp	teken_funcs_cursor(t);
29433965Sjdp}
29533965Sjdp
29633965Sjdpstatic void
29733965Sjdpteken_subr_cursor_forward_tabulation(teken_t *t, unsigned int ntabs)
29833965Sjdp{
29933965Sjdp
30033965Sjdp	do {
30133965Sjdp		/* Stop when we've reached the end of the line. */
30233965Sjdp		if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1)
30333965Sjdp			break;
30433965Sjdp
30533965Sjdp		t->t_cursor.tp_col++;
30633965Sjdp
30733965Sjdp		/* Tab marker set. */
30833965Sjdp		if (teken_tab_isset(t, t->t_cursor.tp_col))
30933965Sjdp			ntabs--;
31033965Sjdp	} while (ntabs > 0);
31133965Sjdp
31233965Sjdp	teken_funcs_cursor(t);
31333965Sjdp}
31433965Sjdp
31533965Sjdpstatic void
31633965Sjdpteken_subr_cursor_next_line(teken_t *t, unsigned int ncols)
31733965Sjdp{
31833965Sjdp
31933965Sjdp	t->t_cursor.tp_col = 0;
32033965Sjdp	teken_subr_cursor_down(t, ncols);
32133965Sjdp}
32233965Sjdp
32333965Sjdpstatic void
32433965Sjdpteken_subr_cursor_position(teken_t *t, unsigned int row, unsigned int col)
32533965Sjdp{
32633965Sjdp
32733965Sjdp	t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
32833965Sjdp	if (row >= t->t_originreg.ts_end)
32933965Sjdp		t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
33033965Sjdp
33133965Sjdp	t->t_cursor.tp_col = col - 1;
33233965Sjdp	if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
33333965Sjdp		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
33433965Sjdp
33533965Sjdp	t->t_stateflags &= ~TS_WRAPPED;
33633965Sjdp	teken_funcs_cursor(t);
33733965Sjdp}
33833965Sjdp
33933965Sjdpstatic void
34033965Sjdpteken_subr_cursor_position_report(teken_t *t, unsigned int cmd)
34133965Sjdp{
34233965Sjdp	char response[18] = "\x1B[";
34333965Sjdp	ssize_t len;
34433965Sjdp
34533965Sjdp	len = teken_subr_do_cpr(t, cmd, response + 2);
34633965Sjdp	if (len < 0)
34733965Sjdp		return;
34833965Sjdp
34933965Sjdp	teken_funcs_respond(t, response, len + 2);
35033965Sjdp}
35133965Sjdp
35233965Sjdpstatic void
35333965Sjdpteken_subr_cursor_previous_line(teken_t *t, unsigned int ncols)
35433965Sjdp{
35533965Sjdp
35633965Sjdp	t->t_cursor.tp_col = 0;
35733965Sjdp	teken_subr_cursor_up(t, ncols);
35833965Sjdp}
35933965Sjdp
36033965Sjdpstatic void
36133965Sjdpteken_subr_cursor_up(teken_t *t, unsigned int nrows)
36233965Sjdp{
36333965Sjdp
36433965Sjdp	if (t->t_scrollreg.ts_begin + nrows >= t->t_cursor.tp_row)
36533965Sjdp		t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
36633965Sjdp	else
36733965Sjdp		t->t_cursor.tp_row -= nrows;
36833965Sjdp	t->t_stateflags &= ~TS_WRAPPED;
36933965Sjdp	teken_funcs_cursor(t);
37033965Sjdp}
37133965Sjdp
37233965Sjdpstatic void
37333965Sjdpteken_subr_delete_character(teken_t *t, unsigned int ncols)
37433965Sjdp{
37533965Sjdp	teken_rect_t tr;
37633965Sjdp
37733965Sjdp	tr.tr_begin.tp_row = t->t_cursor.tp_row;
37833965Sjdp	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
37933965Sjdp	tr.tr_end.tp_col = t->t_winsize.tp_col;
38033965Sjdp
38133965Sjdp	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
38233965Sjdp		tr.tr_begin.tp_col = t->t_cursor.tp_col;
38333965Sjdp	} else {
38433965Sjdp		/* Copy characters to the left. */
38533965Sjdp		tr.tr_begin.tp_col = t->t_cursor.tp_col + ncols;
38633965Sjdp		teken_funcs_copy(t, &tr, &t->t_cursor);
38733965Sjdp
38833965Sjdp		tr.tr_begin.tp_col = t->t_winsize.tp_col - ncols;
38933965Sjdp	}
39033965Sjdp
39133965Sjdp	/* Blank trailing columns. */
39233965Sjdp	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
39333965Sjdp}
39433965Sjdp
39533965Sjdpstatic void
39633965Sjdpteken_subr_delete_line(teken_t *t, unsigned int nrows)
39733965Sjdp{
39833965Sjdp	teken_rect_t tr;
39933965Sjdp
40033965Sjdp	/* Ignore if outside scrolling region. */
40133965Sjdp	if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin ||
40233965Sjdp	    t->t_cursor.tp_row >= t->t_scrollreg.ts_end)
40333965Sjdp		return;
40433965Sjdp
40533965Sjdp	tr.tr_begin.tp_col = 0;
40633965Sjdp	tr.tr_end.tp_row = t->t_scrollreg.ts_end;
40733965Sjdp	tr.tr_end.tp_col = t->t_winsize.tp_col;
40833965Sjdp
40933965Sjdp	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
41033965Sjdp		tr.tr_begin.tp_row = t->t_cursor.tp_row;
41133965Sjdp	} else {
41233965Sjdp		teken_pos_t tp;
41333965Sjdp
41433965Sjdp		/* Copy rows up. */
41533965Sjdp		tr.tr_begin.tp_row = t->t_cursor.tp_row + nrows;
41633965Sjdp		tp.tp_row = t->t_cursor.tp_row;
41733965Sjdp		tp.tp_col = 0;
41833965Sjdp		teken_funcs_copy(t, &tr, &tp);
41933965Sjdp
42033965Sjdp		tr.tr_begin.tp_row = t->t_scrollreg.ts_end - nrows;
42133965Sjdp	}
42233965Sjdp
42333965Sjdp	/* Blank trailing rows. */
42433965Sjdp	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
42533965Sjdp}
42633965Sjdp
42733965Sjdpstatic void
42833965Sjdpteken_subr_device_control_string(teken_t *t __unused)
42933965Sjdp{
43033965Sjdp
43133965Sjdp	teken_printf("device control string???\n");
43233965Sjdp}
43333965Sjdp
43433965Sjdpstatic void
43533965Sjdpteken_subr_device_status_report(teken_t *t, unsigned int cmd)
43633965Sjdp{
43733965Sjdp	char response[19] = "\x1B[?";
43833965Sjdp	ssize_t len;
43933965Sjdp
44033965Sjdp	len = teken_subr_do_cpr(t, cmd, response + 3);
44133965Sjdp	if (len < 0)
44277298Sobrien		return;
44333965Sjdp
44433965Sjdp	teken_funcs_respond(t, response, len + 3);
44533965Sjdp}
44633965Sjdp
44733965Sjdpstatic void
44833965Sjdpteken_subr_double_height_double_width_line_top(teken_t *t __unused)
44933965Sjdp{
45033965Sjdp
45133965Sjdp	teken_printf("double height double width top\n");
45233965Sjdp}
45333965Sjdp
45433965Sjdpstatic void
45533965Sjdpteken_subr_double_height_double_width_line_bottom(teken_t *t __unused)
45633965Sjdp{
45733965Sjdp
45833965Sjdp	teken_printf("double height double width bottom\n");
45933965Sjdp}
46033965Sjdp
46133965Sjdpstatic void
46233965Sjdpteken_subr_erase_character(teken_t *t, unsigned int ncols)
46333965Sjdp{
46433965Sjdp	teken_rect_t tr;
46533965Sjdp
46633965Sjdp	tr.tr_begin = t->t_cursor;
46733965Sjdp	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
46833965Sjdp
46933965Sjdp	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
47033965Sjdp		tr.tr_end.tp_col = t->t_winsize.tp_col;
47133965Sjdp	else
47233965Sjdp		tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
47333965Sjdp
47433965Sjdp	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
47533965Sjdp}
47633965Sjdp
47733965Sjdpstatic void
47877298Sobrienteken_subr_erase_display(teken_t *t, unsigned int mode)
47933965Sjdp{
48033965Sjdp	teken_rect_t r;
48133965Sjdp
48233965Sjdp	r.tr_begin.tp_col = 0;
48333965Sjdp	r.tr_end.tp_col = t->t_winsize.tp_col;
48433965Sjdp
48533965Sjdp	switch (mode) {
48633965Sjdp	case 1: /* Erase from the top to the cursor. */
48733965Sjdp		teken_subr_erase_line(t, 1);
48833965Sjdp
48933965Sjdp		/* Erase lines above. */
49033965Sjdp		if (t->t_cursor.tp_row == 0)
49133965Sjdp			return;
49233965Sjdp		r.tr_begin.tp_row = 0;
49333965Sjdp		r.tr_end.tp_row = t->t_cursor.tp_row;
49433965Sjdp		break;
49533965Sjdp	case 2: /* Erase entire display. */
49633965Sjdp		r.tr_begin.tp_row = 0;
49733965Sjdp		r.tr_end.tp_row = t->t_winsize.tp_row;
49833965Sjdp		break;
49933965Sjdp	default: /* Erase from cursor to the bottom. */
50033965Sjdp		teken_subr_erase_line(t, 0);
50133965Sjdp
50233965Sjdp		/* Erase lines below. */
50333965Sjdp		if (t->t_cursor.tp_row == t->t_winsize.tp_row - 1)
50433965Sjdp			return;
50533965Sjdp		r.tr_begin.tp_row = t->t_cursor.tp_row + 1;
50633965Sjdp		r.tr_end.tp_row = t->t_winsize.tp_row;
50733965Sjdp		break;
50833965Sjdp	}
50933965Sjdp
51033965Sjdp	teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
51133965Sjdp}
51233965Sjdp
51333965Sjdpstatic void
51433965Sjdpteken_subr_erase_line(teken_t *t, unsigned int mode)
51533965Sjdp{
51633965Sjdp	teken_rect_t r;
51733965Sjdp
51833965Sjdp	r.tr_begin.tp_row = t->t_cursor.tp_row;
51933965Sjdp	r.tr_end.tp_row = t->t_cursor.tp_row + 1;
52033965Sjdp
52133965Sjdp	switch (mode) {
52233965Sjdp	case 1: /* Erase from the beginning of the line to the cursor. */
52333965Sjdp		r.tr_begin.tp_col = 0;
52433965Sjdp		r.tr_end.tp_col = t->t_cursor.tp_col + 1;
52533965Sjdp		break;
52633965Sjdp	case 2: /* Erase entire line. */
52733965Sjdp		r.tr_begin.tp_col = 0;
52833965Sjdp		r.tr_end.tp_col = t->t_winsize.tp_col;
52933965Sjdp		break;
53033965Sjdp	default: /* Erase from cursor to the end of the line. */
53133965Sjdp		r.tr_begin.tp_col = t->t_cursor.tp_col;
53233965Sjdp		r.tr_end.tp_col = t->t_winsize.tp_col;
53333965Sjdp		break;
53433965Sjdp	}
53533965Sjdp
53633965Sjdp	teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
53733965Sjdp}
53833965Sjdp
53933965Sjdpstatic void
54033965Sjdpteken_subr_g0_scs_special_graphics(teken_t *t __unused)
54133965Sjdp{
54233965Sjdp
54333965Sjdp	t->t_scs[0] = teken_scs_special_graphics;
54433965Sjdp}
54533965Sjdp
54677298Sobrienstatic void
54733965Sjdpteken_subr_g0_scs_uk_national(teken_t *t __unused)
54833965Sjdp{
54933965Sjdp
55033965Sjdp	t->t_scs[0] = teken_scs_uk_national;
55133965Sjdp}
55233965Sjdp
55333965Sjdpstatic void
55433965Sjdpteken_subr_g0_scs_us_ascii(teken_t *t __unused)
55533965Sjdp{
55633965Sjdp
55733965Sjdp	t->t_scs[0] = teken_scs_us_ascii;
55833965Sjdp}
55933965Sjdp
56033965Sjdpstatic void
56133965Sjdpteken_subr_g1_scs_special_graphics(teken_t *t __unused)
56233965Sjdp{
56333965Sjdp
56433965Sjdp	t->t_scs[1] = teken_scs_special_graphics;
56533965Sjdp}
56633965Sjdp
56733965Sjdpstatic void
56833965Sjdpteken_subr_g1_scs_uk_national(teken_t *t __unused)
56933965Sjdp{
57033965Sjdp
57133965Sjdp	t->t_scs[1] = teken_scs_uk_national;
57233965Sjdp}
57333965Sjdp
57433965Sjdpstatic void
57533965Sjdpteken_subr_g1_scs_us_ascii(teken_t *t __unused)
57633965Sjdp{
57733965Sjdp
57833965Sjdp	t->t_scs[1] = teken_scs_us_ascii;
57933965Sjdp}
58033965Sjdp
58133965Sjdpstatic void
58233965Sjdpteken_subr_horizontal_position_absolute(teken_t *t, unsigned int col)
58333965Sjdp{
58433965Sjdp
58533965Sjdp	t->t_cursor.tp_col = col - 1;
58633965Sjdp	if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
58733965Sjdp		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
58833965Sjdp
58933965Sjdp	t->t_stateflags &= ~TS_WRAPPED;
59033965Sjdp	teken_funcs_cursor(t);
59133965Sjdp}
59233965Sjdp
59333965Sjdpstatic void
59433965Sjdpteken_subr_horizontal_tab(teken_t *t)
59533965Sjdp{
59633965Sjdp
59733965Sjdp	if (t->t_stateflags & TS_CONS25) {
59833965Sjdp		teken_subr_cursor_forward_tabulation(t, 1);
59933965Sjdp	} else {
60033965Sjdp		teken_rect_t tr;
60133965Sjdp
60233965Sjdp		tr.tr_begin = t->t_cursor;
60333965Sjdp		teken_subr_cursor_forward_tabulation(t, 1);
60433965Sjdp		tr.tr_end.tp_row = tr.tr_begin.tp_row + 1;
60533965Sjdp		tr.tr_end.tp_col = t->t_cursor.tp_col;
60633965Sjdp
60733965Sjdp		/* Blank region that we skipped. */
60833965Sjdp		if (tr.tr_end.tp_col > tr.tr_begin.tp_col)
60933965Sjdp			teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
61033965Sjdp	}
61133965Sjdp}
61233965Sjdp
61333965Sjdpstatic void
61433965Sjdpteken_subr_horizontal_tab_set(teken_t *t)
61533965Sjdp{
61633965Sjdp
61733965Sjdp	teken_tab_set(t, t->t_cursor.tp_col);
61833965Sjdp}
61933965Sjdp
62033965Sjdpstatic void
62133965Sjdpteken_subr_index(teken_t *t)
62233965Sjdp{
62333965Sjdp
62433965Sjdp	if (t->t_cursor.tp_row < t->t_scrollreg.ts_end - 1) {
62533965Sjdp		t->t_cursor.tp_row++;
62633965Sjdp		t->t_stateflags &= ~TS_WRAPPED;
62733965Sjdp		teken_funcs_cursor(t);
62833965Sjdp	} else {
62933965Sjdp		teken_subr_do_scroll(t, 1);
63033965Sjdp	}
63133965Sjdp}
63233965Sjdp
63333965Sjdpstatic void
63433965Sjdpteken_subr_insert_character(teken_t *t, unsigned int ncols)
63533965Sjdp{
63633965Sjdp	teken_rect_t tr;
63733965Sjdp
63833965Sjdp	tr.tr_begin = t->t_cursor;
63933965Sjdp	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
64033965Sjdp
64133965Sjdp	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
64233965Sjdp		tr.tr_end.tp_col = t->t_winsize.tp_col;
64333965Sjdp	} else {
64433965Sjdp		teken_pos_t tp;
64533965Sjdp
64633965Sjdp		/* Copy characters to the right. */
64733965Sjdp		tr.tr_end.tp_col = t->t_winsize.tp_col - ncols;
64833965Sjdp		tp.tp_row = t->t_cursor.tp_row;
64933965Sjdp		tp.tp_col = t->t_cursor.tp_col + ncols;
65033965Sjdp		teken_funcs_copy(t, &tr, &tp);
65133965Sjdp
65233965Sjdp		tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
65333965Sjdp	}
65433965Sjdp
65533965Sjdp	/* Blank current location. */
65633965Sjdp	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
65733965Sjdp}
65833965Sjdp
65933965Sjdpstatic void
66033965Sjdpteken_subr_insert_line(teken_t *t, unsigned int nrows)
66133965Sjdp{
66233965Sjdp	teken_rect_t tr;
66333965Sjdp
66433965Sjdp	/* Ignore if outside scrolling region. */
66533965Sjdp	if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin ||
66633965Sjdp	    t->t_cursor.tp_row >= t->t_scrollreg.ts_end)
66733965Sjdp		return;
66833965Sjdp
66933965Sjdp	tr.tr_begin.tp_row = t->t_cursor.tp_row;
67033965Sjdp	tr.tr_begin.tp_col = 0;
67133965Sjdp	tr.tr_end.tp_col = t->t_winsize.tp_col;
67233965Sjdp
67333965Sjdp	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
67433965Sjdp		tr.tr_end.tp_row = t->t_scrollreg.ts_end;
67533965Sjdp	} else {
67633965Sjdp		teken_pos_t tp;
67733965Sjdp
67833965Sjdp		/* Copy lines down. */
67933965Sjdp		tr.tr_end.tp_row = t->t_scrollreg.ts_end - nrows;
68033965Sjdp		tp.tp_row = t->t_cursor.tp_row + nrows;
68133965Sjdp		tp.tp_col = 0;
68233965Sjdp		teken_funcs_copy(t, &tr, &tp);
68333965Sjdp
68433965Sjdp		tr.tr_end.tp_row = t->t_cursor.tp_row + nrows;
68533965Sjdp	}
68633965Sjdp
68733965Sjdp	/* Blank current location. */
68833965Sjdp	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
68933965Sjdp}
69033965Sjdp
69133965Sjdpstatic void
69233965Sjdpteken_subr_keypad_application_mode(teken_t *t)
69333965Sjdp{
69433965Sjdp
69533965Sjdp	teken_funcs_param(t, TP_KEYPADAPP, 1);
69633965Sjdp}
69733965Sjdp
69833965Sjdpstatic void
69933965Sjdpteken_subr_keypad_numeric_mode(teken_t *t)
70033965Sjdp{
70133965Sjdp
70233965Sjdp	teken_funcs_param(t, TP_KEYPADAPP, 0);
70333965Sjdp}
70433965Sjdp
70533965Sjdpstatic void
70633965Sjdpteken_subr_newline(teken_t *t)
70733965Sjdp{
70833965Sjdp
70933965Sjdp	t->t_cursor.tp_row++;
71033965Sjdp
71133965Sjdp	if (t->t_cursor.tp_row >= t->t_scrollreg.ts_end) {
71233965Sjdp		teken_subr_do_scroll(t, 1);
71333965Sjdp		t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
71433965Sjdp	}
71533965Sjdp
71633965Sjdp	t->t_stateflags &= ~TS_WRAPPED;
71733965Sjdp	teken_funcs_cursor(t);
71833965Sjdp}
71933965Sjdp
72033965Sjdpstatic void
72133965Sjdpteken_subr_newpage(teken_t *t)
72233965Sjdp{
72333965Sjdp
72433965Sjdp	if (t->t_stateflags & TS_CONS25) {
72533965Sjdp		teken_rect_t tr;
72633965Sjdp
72733965Sjdp		tr.tr_begin.tp_row = tr.tr_begin.tp_col = 0;
72833965Sjdp		tr.tr_end = t->t_winsize;
72933965Sjdp		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
73033965Sjdp
73133965Sjdp		t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
73233965Sjdp		teken_funcs_cursor(t);
73333965Sjdp	} else {
73433965Sjdp		teken_subr_newline(t);
73533965Sjdp	}
73633965Sjdp}
73733965Sjdp
73833965Sjdpstatic void
73933965Sjdpteken_subr_next_line(teken_t *t)
74033965Sjdp{
74133965Sjdp
74233965Sjdp	t->t_cursor.tp_col = 0;
74333965Sjdp	teken_subr_newline(t);
74433965Sjdp}
74533965Sjdp
74633965Sjdpstatic void
74733965Sjdpteken_subr_pan_down(teken_t *t, unsigned int nrows)
74833965Sjdp{
74933965Sjdp
75033965Sjdp	teken_subr_do_scroll(t, (int)nrows);
75133965Sjdp}
75233965Sjdp
75333965Sjdpstatic void
75433965Sjdpteken_subr_pan_up(teken_t *t, unsigned int nrows)
75533965Sjdp{
75633965Sjdp
75733965Sjdp	teken_subr_do_scroll(t, -(int)nrows);
75833965Sjdp}
75933965Sjdp
76033965Sjdpstatic void
76133965Sjdpteken_subr_primary_device_attributes(teken_t *t, unsigned int request)
76233965Sjdp{
76333965Sjdp
76433965Sjdp	if (request == 0) {
76533965Sjdp		const char response[] = "\x1B[?1;2c";
76677298Sobrien
76733965Sjdp		teken_funcs_respond(t, response, sizeof response - 1);
76833965Sjdp	} else {
76933965Sjdp		teken_printf("Unknown DA1\n");
77033965Sjdp	}
77133965Sjdp}
77233965Sjdp
77333965Sjdpstatic void
77433965Sjdpteken_subr_do_putchar(teken_t *t, const teken_pos_t *tp, teken_char_t c,
77533965Sjdp    int width)
77633965Sjdp{
77733965Sjdp
77833965Sjdp	if (t->t_stateflags & TS_INSERT &&
77933965Sjdp	    tp->tp_col < t->t_winsize.tp_col - width) {
78033965Sjdp		teken_rect_t ctr;
78133965Sjdp		teken_pos_t ctp;
78233965Sjdp
78333965Sjdp		/* Insert mode. Move existing characters to the right. */
78433965Sjdp		ctr.tr_begin = *tp;
78533965Sjdp		ctr.tr_end.tp_row = tp->tp_row + 1;
78633965Sjdp		ctr.tr_end.tp_col = t->t_winsize.tp_col - width;
78733965Sjdp		ctp.tp_row = tp->tp_row;
78833965Sjdp		ctp.tp_col = tp->tp_col + width;
78933965Sjdp		teken_funcs_copy(t, &ctr, &ctp);
79033965Sjdp	}
79133965Sjdp
79233965Sjdp	if (width == 2 && tp->tp_col + 1 < t->t_winsize.tp_col) {
79333965Sjdp		teken_pos_t tp2;
79433965Sjdp
79533965Sjdp		/*
79633965Sjdp		 * Store a space behind double width characters before
79733965Sjdp		 * actually printing them. This prevents artifacts when
79833965Sjdp		 * the consumer doesn't render it using double width
79933965Sjdp		 * glyphs.
80033965Sjdp		 */
80133965Sjdp		tp2.tp_row = tp->tp_row;
80233965Sjdp		tp2.tp_col = tp->tp_col + 1;
80333965Sjdp		teken_funcs_putchar(t, &tp2, BLANK, &t->t_curattr);
80433965Sjdp	}
80533965Sjdp
80633965Sjdp	teken_funcs_putchar(t, tp, c, &t->t_curattr);
80733965Sjdp}
80833965Sjdp
80933965Sjdpstatic void
81033965Sjdpteken_subr_regular_character(teken_t *t, teken_char_t c)
81133965Sjdp{
81233965Sjdp	int width;
81333965Sjdp
81433965Sjdp	if (t->t_stateflags & TS_8BIT) {
81533965Sjdp		if (!(t->t_stateflags & TS_CONS25) && (c <= 0x1b || c == 0x7f))
81633965Sjdp			return;
81733965Sjdp		c = teken_scs_process(t, c);
81833965Sjdp		width = 1;
81933965Sjdp	} else {
82033965Sjdp		c = teken_scs_process(t, c);
82133965Sjdp		width = teken_wcwidth(c);
82233965Sjdp		/* XXX: Don't process zero-width characters yet. */
82333965Sjdp		if (width <= 0)
82433965Sjdp			return;
82533965Sjdp	}
82633965Sjdp
82733965Sjdp	if (t->t_stateflags & TS_CONS25) {
82833965Sjdp		teken_subr_do_putchar(t, &t->t_cursor, c, width);
82933965Sjdp		t->t_cursor.tp_col += width;
83033965Sjdp
83133965Sjdp		if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
83233965Sjdp			if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
83333965Sjdp				/* Perform scrolling. */
83433965Sjdp				teken_subr_do_scroll(t, 1);
83533965Sjdp			} else {
83633965Sjdp				/* No scrolling needed. */
83733965Sjdp				if (t->t_cursor.tp_row <
83833965Sjdp				    t->t_winsize.tp_row - 1)
83933965Sjdp					t->t_cursor.tp_row++;
84033965Sjdp			}
84133965Sjdp			t->t_cursor.tp_col = 0;
84233965Sjdp		}
84333965Sjdp	} else if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1 &&
84433965Sjdp	    (t->t_stateflags & (TS_WRAPPED|TS_AUTOWRAP)) ==
84533965Sjdp	    (TS_WRAPPED|TS_AUTOWRAP)) {
84633965Sjdp		teken_pos_t tp;
84733965Sjdp
84833965Sjdp		/* Perform line wrapping. */
84933965Sjdp
85033965Sjdp		if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
85133965Sjdp			/* Perform scrolling. */
85233965Sjdp			teken_subr_do_scroll(t, 1);
85333965Sjdp			tp.tp_row = t->t_scrollreg.ts_end - 1;
85433965Sjdp		} else {
85533965Sjdp			/* No scrolling needed. */
85633965Sjdp			tp.tp_row = t->t_cursor.tp_row + 1;
85733965Sjdp			if (tp.tp_row == t->t_winsize.tp_row) {
85833965Sjdp				/*
859				 * Corner case: regular character
860				 * outside scrolling region, but at the
861				 * bottom of the screen.
862				 */
863				teken_subr_do_putchar(t, &t->t_cursor,
864				    c, width);
865				return;
866			}
867		}
868
869		tp.tp_col = 0;
870		teken_subr_do_putchar(t, &tp, c, width);
871
872		t->t_cursor.tp_row = tp.tp_row;
873		t->t_cursor.tp_col = width;
874		t->t_stateflags &= ~TS_WRAPPED;
875	} else {
876		/* No line wrapping needed. */
877		teken_subr_do_putchar(t, &t->t_cursor, c, width);
878		t->t_cursor.tp_col += width;
879
880		if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
881			t->t_stateflags |= TS_WRAPPED;
882			t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
883		} else {
884			t->t_stateflags &= ~TS_WRAPPED;
885		}
886	}
887
888	teken_funcs_cursor(t);
889}
890
891static void
892teken_subr_reset_dec_mode(teken_t *t, unsigned int cmd)
893{
894
895	switch (cmd) {
896	case 1: /* Cursor keys mode. */
897		teken_funcs_param(t, TP_CURSORKEYS, 0);
898		break;
899	case 2: /* DECANM: ANSI/VT52 mode. */
900		teken_printf("DECRST VT52\n");
901		break;
902	case 3: /* 132 column mode. */
903		teken_funcs_param(t, TP_132COLS, 0);
904		teken_subr_reset_to_initial_state(t);
905		break;
906	case 5: /* Inverse video. */
907		teken_printf("DECRST inverse video\n");
908		break;
909	case 6: /* Origin mode. */
910		t->t_stateflags &= ~TS_ORIGIN;
911		t->t_originreg.ts_begin = 0;
912		t->t_originreg.ts_end = t->t_winsize.tp_row;
913		t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
914		t->t_stateflags &= ~TS_WRAPPED;
915		teken_funcs_cursor(t);
916		break;
917	case 7: /* Autowrap mode. */
918		t->t_stateflags &= ~TS_AUTOWRAP;
919		break;
920	case 8: /* Autorepeat mode. */
921		teken_funcs_param(t, TP_AUTOREPEAT, 0);
922		break;
923	case 25: /* Hide cursor. */
924		teken_funcs_param(t, TP_SHOWCURSOR, 0);
925		break;
926	case 40: /* Disallow 132 columns. */
927		teken_printf("DECRST allow 132\n");
928		break;
929	case 45: /* Disable reverse wraparound. */
930		teken_printf("DECRST reverse wraparound\n");
931		break;
932	case 47: /* Switch to alternate buffer. */
933		teken_printf("Switch to alternate buffer\n");
934		break;
935	default:
936		teken_printf("Unknown DECRST: %u\n", cmd);
937	}
938}
939
940static void
941teken_subr_reset_mode(teken_t *t, unsigned int cmd)
942{
943
944	switch (cmd) {
945	case 4:
946		t->t_stateflags &= ~TS_INSERT;
947		break;
948	default:
949		teken_printf("Unknown reset mode: %u\n", cmd);
950	}
951}
952
953static void
954teken_subr_do_reset(teken_t *t)
955{
956
957	t->t_curattr = t->t_defattr;
958	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
959	t->t_scrollreg.ts_begin = 0;
960	t->t_scrollreg.ts_end = t->t_winsize.tp_row;
961	t->t_originreg = t->t_scrollreg;
962	t->t_stateflags &= TS_8BIT|TS_CONS25;
963	t->t_stateflags |= TS_AUTOWRAP;
964
965	t->t_scs[0] = teken_scs_us_ascii;
966	t->t_scs[1] = teken_scs_us_ascii;
967	t->t_curscs = 0;
968
969	teken_subr_save_cursor(t);
970	teken_tab_default(t);
971}
972
973static void
974teken_subr_reset_to_initial_state(teken_t *t)
975{
976
977	teken_subr_do_reset(t);
978	teken_subr_erase_display(t, 2);
979	teken_funcs_param(t, TP_SHOWCURSOR, 1);
980	teken_funcs_cursor(t);
981}
982
983static void
984teken_subr_restore_cursor(teken_t *t)
985{
986
987	t->t_cursor = t->t_saved_cursor;
988	t->t_curattr = t->t_saved_curattr;
989	t->t_scs[t->t_curscs] = t->t_saved_curscs;
990	t->t_stateflags &= ~TS_WRAPPED;
991	teken_funcs_cursor(t);
992}
993
994static void
995teken_subr_reverse_index(teken_t *t)
996{
997
998	if (t->t_cursor.tp_row > t->t_scrollreg.ts_begin) {
999		t->t_cursor.tp_row--;
1000		t->t_stateflags &= ~TS_WRAPPED;
1001		teken_funcs_cursor(t);
1002	} else {
1003		teken_subr_do_scroll(t, -1);
1004	}
1005}
1006
1007static void
1008teken_subr_save_cursor(teken_t *t)
1009{
1010
1011	t->t_saved_cursor = t->t_cursor;
1012	t->t_saved_curattr = t->t_curattr;
1013	t->t_saved_curscs = t->t_scs[t->t_curscs];
1014}
1015
1016static void
1017teken_subr_secondary_device_attributes(teken_t *t, unsigned int request)
1018{
1019
1020	if (request == 0) {
1021		const char response[] = "\x1B[>0;10;0c";
1022		teken_funcs_respond(t, response, sizeof response - 1);
1023	} else {
1024		teken_printf("Unknown DA2\n");
1025	}
1026}
1027
1028static void
1029teken_subr_set_dec_mode(teken_t *t, unsigned int cmd)
1030{
1031
1032	switch (cmd) {
1033	case 1: /* Cursor keys mode. */
1034		teken_funcs_param(t, TP_CURSORKEYS, 1);
1035		break;
1036	case 2: /* DECANM: ANSI/VT52 mode. */
1037		teken_printf("DECSET VT52\n");
1038		break;
1039	case 3: /* 132 column mode. */
1040		teken_funcs_param(t, TP_132COLS, 1);
1041		teken_subr_reset_to_initial_state(t);
1042		break;
1043	case 5: /* Inverse video. */
1044		teken_printf("DECSET inverse video\n");
1045		break;
1046	case 6: /* Origin mode. */
1047		t->t_stateflags |= TS_ORIGIN;
1048		t->t_originreg = t->t_scrollreg;
1049		t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
1050		t->t_cursor.tp_col = 0;
1051		t->t_stateflags &= ~TS_WRAPPED;
1052		teken_funcs_cursor(t);
1053		break;
1054	case 7: /* Autowrap mode. */
1055		t->t_stateflags |= TS_AUTOWRAP;
1056		break;
1057	case 8: /* Autorepeat mode. */
1058		teken_funcs_param(t, TP_AUTOREPEAT, 1);
1059		break;
1060	case 25: /* Display cursor. */
1061		teken_funcs_param(t, TP_SHOWCURSOR, 1);
1062		break;
1063	case 40: /* Allow 132 columns. */
1064		teken_printf("DECSET allow 132\n");
1065		break;
1066	case 45: /* Enable reverse wraparound. */
1067		teken_printf("DECSET reverse wraparound\n");
1068		break;
1069	case 47: /* Switch to alternate buffer. */
1070		teken_printf("Switch away from alternate buffer\n");
1071		break;
1072	default:
1073		teken_printf("Unknown DECSET: %u\n", cmd);
1074	}
1075}
1076
1077static void
1078teken_subr_set_mode(teken_t *t, unsigned int cmd)
1079{
1080
1081	switch (cmd) {
1082	case 4:
1083		teken_printf("Insert mode\n");
1084		t->t_stateflags |= TS_INSERT;
1085		break;
1086	default:
1087		teken_printf("Unknown set mode: %u\n", cmd);
1088	}
1089}
1090
1091static void
1092teken_subr_set_graphic_rendition(teken_t *t, unsigned int ncmds,
1093    unsigned int cmds[])
1094{
1095	unsigned int i, n;
1096
1097	/* No attributes means reset. */
1098	if (ncmds == 0) {
1099		t->t_curattr = t->t_defattr;
1100		return;
1101	}
1102
1103	for (i = 0; i < ncmds; i++) {
1104		n = cmds[i];
1105
1106		switch (n) {
1107		case 0: /* Reset. */
1108			t->t_curattr = t->t_defattr;
1109			break;
1110		case 1: /* Bold. */
1111			t->t_curattr.ta_format |= TF_BOLD;
1112			break;
1113		case 4: /* Underline. */
1114			t->t_curattr.ta_format |= TF_UNDERLINE;
1115			break;
1116		case 5: /* Blink. */
1117			t->t_curattr.ta_format |= TF_BLINK;
1118			break;
1119		case 7: /* Reverse. */
1120			t->t_curattr.ta_format |= TF_REVERSE;
1121			break;
1122		case 22: /* Remove bold. */
1123			t->t_curattr.ta_format &= ~TF_BOLD;
1124			break;
1125		case 24: /* Remove underline. */
1126			t->t_curattr.ta_format &= ~TF_UNDERLINE;
1127			break;
1128		case 25: /* Remove blink. */
1129			t->t_curattr.ta_format &= ~TF_BLINK;
1130			break;
1131		case 27: /* Remove reverse. */
1132			t->t_curattr.ta_format &= ~TF_REVERSE;
1133			break;
1134		case 30: /* Set foreground color: black */
1135		case 31: /* Set foreground color: red */
1136		case 32: /* Set foreground color: green */
1137		case 33: /* Set foreground color: brown */
1138		case 34: /* Set foreground color: blue */
1139		case 35: /* Set foreground color: magenta */
1140		case 36: /* Set foreground color: cyan */
1141		case 37: /* Set foreground color: white */
1142			t->t_curattr.ta_fgcolor = n - 30;
1143			break;
1144		case 39: /* Set default foreground color. */
1145			t->t_curattr.ta_fgcolor = t->t_defattr.ta_fgcolor;
1146			break;
1147		case 40: /* Set background color: black */
1148		case 41: /* Set background color: red */
1149		case 42: /* Set background color: green */
1150		case 43: /* Set background color: brown */
1151		case 44: /* Set background color: blue */
1152		case 45: /* Set background color: magenta */
1153		case 46: /* Set background color: cyan */
1154		case 47: /* Set background color: white */
1155			t->t_curattr.ta_bgcolor = n - 40;
1156			break;
1157		case 49: /* Set default background color. */
1158			t->t_curattr.ta_bgcolor = t->t_defattr.ta_bgcolor;
1159			break;
1160		default:
1161			teken_printf("unsupported attribute %u\n", n);
1162		}
1163	}
1164}
1165
1166static void
1167teken_subr_set_top_and_bottom_margins(teken_t *t, unsigned int top,
1168    unsigned int bottom)
1169{
1170
1171	/* Adjust top row number. */
1172	if (top > 0)
1173		top--;
1174	/* Adjust bottom row number. */
1175	if (bottom == 0 || bottom > t->t_winsize.tp_row)
1176		bottom = t->t_winsize.tp_row;
1177
1178	/* Invalid arguments. */
1179	if (top >= bottom - 1) {
1180		top = 0;
1181		bottom = t->t_winsize.tp_row;
1182	}
1183
1184	t->t_scrollreg.ts_begin = top;
1185	t->t_scrollreg.ts_end = bottom;
1186	if (t->t_stateflags & TS_ORIGIN) {
1187		/* XXX: home cursor? */
1188		t->t_originreg = t->t_scrollreg;
1189		t->t_cursor.tp_row = t->t_originreg.ts_begin;
1190		t->t_cursor.tp_col = 0;
1191		t->t_stateflags &= ~TS_WRAPPED;
1192		teken_funcs_cursor(t);
1193	}
1194}
1195
1196static void
1197teken_subr_single_height_double_width_line(teken_t *t __unused)
1198{
1199
1200	teken_printf("single height double width???\n");
1201}
1202
1203static void
1204teken_subr_single_height_single_width_line(teken_t *t __unused)
1205{
1206
1207	teken_printf("single height single width???\n");
1208}
1209
1210static void
1211teken_subr_string_terminator(teken_t *t __unused)
1212{
1213
1214	teken_printf("string terminator???\n");
1215}
1216
1217static void
1218teken_subr_tab_clear(teken_t *t, unsigned int cmd)
1219{
1220
1221	switch (cmd) {
1222	case 0:
1223		teken_tab_clear(t, t->t_cursor.tp_col);
1224		break;
1225	case 3:
1226		memset(&t->t_tabstops, 0, T_NUMCOL / 8);
1227		break;
1228	}
1229}
1230
1231static void
1232teken_subr_vertical_position_absolute(teken_t *t, unsigned int row)
1233{
1234
1235	t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
1236	if (row >= t->t_originreg.ts_end)
1237		t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
1238
1239
1240	t->t_stateflags &= ~TS_WRAPPED;
1241	teken_funcs_cursor(t);
1242}
1243