teken_subr.h revision 197117
190926Snectar/*-
255682Smarkm * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
390926Snectar * All rights reserved.
478527Sassar *
555682Smarkm * Redistribution and use in source and binary forms, with or without
655682Smarkm * modification, are permitted provided that the following conditions
755682Smarkm * are met:
855682Smarkm * 1. Redistributions of source code must retain the above copyright
955682Smarkm *    notice, this list of conditions and the following disclaimer.
1055682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer in the
1255682Smarkm *    documentation and/or other materials provided with the distribution.
1355682Smarkm *
1490926Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1590926Snectar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1690926Snectar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1790926Snectar * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1890926Snectar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1990926Snectar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2090926Snectar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2190926Snectar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2290926Snectar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2390926Snectar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2455682Smarkm * SUCH DAMAGE.
2555682Smarkm *
2655682Smarkm * $FreeBSD: head/sys/teken/teken_subr.h 197117 2009-09-12 12:44:21Z ed $
2755682Smarkm */
2855682Smarkm
2955682Smarkmstatic void teken_subr_cursor_up(teken_t *, unsigned int);
3055682Smarkmstatic void teken_subr_erase_line(teken_t *, unsigned int);
3155682Smarkmstatic void teken_subr_regular_character(teken_t *, teken_char_t);
3255682Smarkmstatic void teken_subr_reset_to_initial_state(teken_t *);
3355682Smarkmstatic void teken_subr_save_cursor(teken_t *);
3455682Smarkm
3555682Smarkmstatic inline int
3655682Smarkmteken_tab_isset(teken_t *t, unsigned int col)
3755682Smarkm{
3855682Smarkm	unsigned int b, o;
3955682Smarkm
4055682Smarkm	if (col >= T_NUMCOL)
4155682Smarkm		return ((col % 8) == 0);
4255682Smarkm
4355682Smarkm	b = col / (sizeof(unsigned int) * 8);
4455682Smarkm	o = col % (sizeof(unsigned int) * 8);
4555682Smarkm
4655682Smarkm	return (t->t_tabstops[b] & (1 << o));
4755682Smarkm}
4855682Smarkm
4955682Smarkmstatic inline void
5055682Smarkmteken_tab_clear(teken_t *t, unsigned int col)
5155682Smarkm{
5255682Smarkm	unsigned int b, o;
5355682Smarkm
5455682Smarkm	if (col >= T_NUMCOL)
5572445Sassar		return;
5655682Smarkm
5755682Smarkm	b = col / (sizeof(unsigned int) * 8);
5890926Snectar	o = col % (sizeof(unsigned int) * 8);
5955682Smarkm
6055682Smarkm	t->t_tabstops[b] &= ~(1 << o);
6155682Smarkm}
6255682Smarkm
6355682Smarkmstatic inline void
6455682Smarkmteken_tab_set(teken_t *t, unsigned int col)
6555682Smarkm{
6655682Smarkm	unsigned int b, o;
6755682Smarkm
6855682Smarkm	if (col >= T_NUMCOL)
6972445Sassar		return;
7072445Sassar
7155682Smarkm	b = col / (sizeof(unsigned int) * 8);
7255682Smarkm	o = col % (sizeof(unsigned int) * 8);
7355682Smarkm
7455682Smarkm	t->t_tabstops[b] |= 1 << o;
7555682Smarkm}
7690926Snectar
7772445Sassarstatic void
7855682Smarkmteken_tab_default(teken_t *t)
7972445Sassar{
8090926Snectar	unsigned int i;
8172445Sassar
8272445Sassar	memset(&t->t_tabstops, 0, T_NUMCOL / 8);
8372445Sassar
8455682Smarkm	for (i = 8; i < T_NUMCOL; i += 8)
8555682Smarkm		teken_tab_set(t, i);
8655682Smarkm}
8772445Sassar
8855682Smarkmstatic void
8990926Snectarteken_subr_do_scroll(teken_t *t, int amount)
9090926Snectar{
9155682Smarkm	teken_rect_t tr;
9255682Smarkm	teken_pos_t tp;
9355682Smarkm
9455682Smarkm	teken_assert(t->t_cursor.tp_row <= t->t_winsize.tp_row);
9555682Smarkm	teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
9690926Snectar	teken_assert(amount != 0);
9790926Snectar
9890926Snectar	/* Copy existing data 1 line up. */
9990926Snectar	if (amount > 0) {
10072445Sassar		/* Scroll down. */
10190926Snectar
10272445Sassar		/* Copy existing data up. */
10390926Snectar		if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
10455682Smarkm			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin + amount;
10555682Smarkm			tr.tr_begin.tp_col = 0;
10655682Smarkm			tr.tr_end.tp_row = t->t_scrollreg.ts_end;
10755682Smarkm			tr.tr_end.tp_col = t->t_winsize.tp_col;
10855682Smarkm			tp.tp_row = t->t_scrollreg.ts_begin;
10955682Smarkm			tp.tp_col = 0;
11055682Smarkm			teken_funcs_copy(t, &tr, &tp);
11155682Smarkm
11255682Smarkm			tr.tr_begin.tp_row = t->t_scrollreg.ts_end - amount;
11372445Sassar		} else {
11455682Smarkm			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
11555682Smarkm		}
11655682Smarkm
11755682Smarkm		/* Clear the last lines. */
11855682Smarkm		tr.tr_begin.tp_col = 0;
11955682Smarkm		tr.tr_end.tp_row = t->t_scrollreg.ts_end;
12055682Smarkm		tr.tr_end.tp_col = t->t_winsize.tp_col;
12155682Smarkm		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
12290926Snectar	} else {
12390926Snectar		/* Scroll up. */
12490926Snectar		amount = -amount;
12590926Snectar
12655682Smarkm		/* Copy existing data down. */
12790926Snectar		if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
12890926Snectar			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
12972445Sassar			tr.tr_begin.tp_col = 0;
13072445Sassar			tr.tr_end.tp_row = t->t_scrollreg.ts_end - amount;
13172445Sassar			tr.tr_end.tp_col = t->t_winsize.tp_col;
13255682Smarkm			tp.tp_row = t->t_scrollreg.ts_begin + amount;
13390926Snectar			tp.tp_col = 0;
13472445Sassar			teken_funcs_copy(t, &tr, &tp);
13555682Smarkm
13655682Smarkm			tr.tr_end.tp_row = t->t_scrollreg.ts_begin + amount;
13790926Snectar		} else {
13855682Smarkm			tr.tr_end.tp_row = t->t_scrollreg.ts_end;
13990926Snectar		}
14055682Smarkm
14172445Sassar		/* Clear the first lines. */
14272445Sassar		tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
14355682Smarkm		tr.tr_begin.tp_col = 0;
14455682Smarkm		tr.tr_end.tp_col = t->t_winsize.tp_col;
14555682Smarkm		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
14655682Smarkm	}
14755682Smarkm}
14855682Smarkm
14955682Smarkmstatic ssize_t
15055682Smarkmteken_subr_do_cpr(teken_t *t, unsigned int cmd, char response[16])
15155682Smarkm{
15255682Smarkm
15355682Smarkm	switch (cmd) {
15455682Smarkm	case 5: /* Operating status. */
15555682Smarkm		strcpy(response, "0n");
15655682Smarkm		return (2);
15755682Smarkm	case 6: { /* Cursor position. */
15855682Smarkm		int len;
15955682Smarkm
16090926Snectar		len = snprintf(response, 16, "%u;%uR",
16172445Sassar		    (t->t_cursor.tp_row - t->t_originreg.ts_begin) + 1,
16255682Smarkm		    t->t_cursor.tp_col + 1);
16355682Smarkm
16455682Smarkm		if (len >= 16)
16555682Smarkm			return (-1);
16655682Smarkm		return (len);
16755682Smarkm	}
16855682Smarkm	case 15: /* Printer status. */
16972445Sassar		strcpy(response, "13n");
17072445Sassar		return (3);
17155682Smarkm	case 25: /* UDK status. */
17255682Smarkm		strcpy(response, "20n");
17355682Smarkm		return (3);
17455682Smarkm	case 26: /* Keyboard status. */
17555682Smarkm		strcpy(response, "27;1n");
17655682Smarkm		return (5);
17755682Smarkm	default:
17855682Smarkm		teken_printf("Unknown DSR\n");
17972445Sassar		return (-1);
18072445Sassar	}
18172445Sassar}
18255682Smarkm
18390926Snectarstatic void
18455682Smarkmteken_subr_alignment_test(teken_t *t)
18555682Smarkm{
18655682Smarkm	teken_rect_t tr;
18755682Smarkm
18855682Smarkm	t->t_scrollreg.ts_begin = 0;
18990926Snectar	t->t_scrollreg.ts_end = t->t_winsize.tp_row;
19055682Smarkm
19190926Snectar	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
19272445Sassar	t->t_stateflags &= ~TS_WRAPPED;
19355682Smarkm	teken_funcs_cursor(t);
19490926Snectar
19578527Sassar	tr.tr_begin.tp_row = 0;
19690926Snectar	tr.tr_begin.tp_col = 0;
19790926Snectar	tr.tr_end = t->t_winsize;
19855682Smarkm	teken_funcs_fill(t, &tr, 'E', &t->t_defattr);
19955682Smarkm}
20055682Smarkm
20155682Smarkmstatic void
20255682Smarkmteken_subr_backspace(teken_t *t)
20355682Smarkm{
20455682Smarkm
20555682Smarkm	if (t->t_stateflags & TS_CONS25) {
20672445Sassar		if (t->t_cursor.tp_col == 0) {
20755682Smarkm			if (t->t_cursor.tp_row == t->t_originreg.ts_begin)
20872445Sassar				return;
20972445Sassar			t->t_cursor.tp_row--;
21055682Smarkm			t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
21155682Smarkm		} else {
21255682Smarkm			t->t_cursor.tp_col--;
21355682Smarkm		}
21455682Smarkm	} else {
21590926Snectar		if (t->t_cursor.tp_col == 0)
21690926Snectar			return;
21790926Snectar
21872445Sassar		t->t_cursor.tp_col--;
21972445Sassar		t->t_stateflags &= ~TS_WRAPPED;
22072445Sassar	}
22172445Sassar
22272445Sassar	teken_funcs_cursor(t);
22372445Sassar}
22472445Sassar
22572445Sassarstatic void
22690926Snectarteken_subr_bell(teken_t *t)
22755682Smarkm{
22855682Smarkm
22972445Sassar	teken_funcs_bell(t);
23072445Sassar}
23172445Sassar
23272445Sassarstatic void
23372445Sassarteken_subr_carriage_return(teken_t *t)
23472445Sassar{
23572445Sassar
23672445Sassar	t->t_cursor.tp_col = 0;
23772445Sassar	t->t_stateflags &= ~TS_WRAPPED;
23855682Smarkm	teken_funcs_cursor(t);
23955682Smarkm}
24072445Sassar
24172445Sassarstatic void
24272445Sassarteken_subr_cursor_backward(teken_t *t, unsigned int ncols)
24372445Sassar{
24472445Sassar
24572445Sassar	if (ncols > t->t_cursor.tp_col)
24672445Sassar		t->t_cursor.tp_col = 0;
24772445Sassar	else
24872445Sassar		t->t_cursor.tp_col -= ncols;
24955682Smarkm	t->t_stateflags &= ~TS_WRAPPED;
25055682Smarkm	teken_funcs_cursor(t);
25172445Sassar}
25272445Sassar
25372445Sassarstatic void
25472445Sassarteken_subr_cursor_backward_tabulation(teken_t *t, unsigned int ntabs)
25572445Sassar{
25672445Sassar
25772445Sassar	do {
25872445Sassar		/* Stop when we've reached the beginning of the line. */
25955682Smarkm		if (t->t_cursor.tp_col == 0)
26072445Sassar			break;
26172445Sassar
26272445Sassar		t->t_cursor.tp_col--;
26355682Smarkm
26490926Snectar		/* Tab marker set. */
26590926Snectar		if (teken_tab_isset(t, t->t_cursor.tp_col))
26690926Snectar			ntabs--;
26790926Snectar	} while (ntabs > 0);
26890926Snectar
26990926Snectar	teken_funcs_cursor(t);
27055682Smarkm}
27190926Snectar
27290926Snectarstatic void
27390926Snectarteken_subr_cursor_down(teken_t *t, unsigned int nrows)
27490926Snectar{
27590926Snectar
27690926Snectar	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end)
27790926Snectar		t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
27890926Snectar	else
27990926Snectar		t->t_cursor.tp_row += nrows;
28090926Snectar	t->t_stateflags &= ~TS_WRAPPED;
28190926Snectar	teken_funcs_cursor(t);
28290926Snectar}
28390926Snectar
28490926Snectarstatic void
28590926Snectarteken_subr_cursor_forward(teken_t *t, unsigned int ncols)
28690926Snectar{
28790926Snectar
28890926Snectar	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
28990926Snectar		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
29090926Snectar	else
29190926Snectar		t->t_cursor.tp_col += ncols;
29290926Snectar	t->t_stateflags &= ~TS_WRAPPED;
29390926Snectar	teken_funcs_cursor(t);
29490926Snectar}
29590926Snectar
29690926Snectarstatic void
29790926Snectarteken_subr_cursor_forward_tabulation(teken_t *t, unsigned int ntabs)
29890926Snectar{
29990926Snectar
30090926Snectar	do {
30190926Snectar		/* Stop when we've reached the end of the line. */
30290926Snectar		if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1)
30390926Snectar			break;
30490926Snectar
30590926Snectar		t->t_cursor.tp_col++;
30690926Snectar
30790926Snectar		/* Tab marker set. */
30890926Snectar		if (teken_tab_isset(t, t->t_cursor.tp_col))
30955682Smarkm			ntabs--;
31090926Snectar	} while (ntabs > 0);
31190926Snectar
31255682Smarkm	teken_funcs_cursor(t);
31355682Smarkm}
31490926Snectar
31590926Snectarstatic void
31690926Snectarteken_subr_cursor_next_line(teken_t *t, unsigned int ncols)
31790926Snectar{
31890926Snectar
31990926Snectar	t->t_cursor.tp_col = 0;
32090926Snectar	teken_subr_cursor_down(t, ncols);
32190926Snectar}
32272445Sassar
32390926Snectarstatic void
32490926Snectarteken_subr_cursor_position(teken_t *t, unsigned int row, unsigned int col)
32590926Snectar{
32690926Snectar
32755682Smarkm	t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
32890926Snectar	if (row >= t->t_originreg.ts_end)
32990926Snectar		t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
33055682Smarkm
33190926Snectar	t->t_cursor.tp_col = col - 1;
33255682Smarkm	if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
33355682Smarkm		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
33478527Sassar
33555682Smarkm	t->t_stateflags &= ~TS_WRAPPED;
33690926Snectar	teken_funcs_cursor(t);
33790926Snectar}
33855682Smarkm
33990926Snectarstatic void
34090926Snectarteken_subr_cursor_position_report(teken_t *t, unsigned int cmd)
34155682Smarkm{
34290926Snectar	char response[18] = "\x1B[";
34390926Snectar	ssize_t len;
34490926Snectar
34590926Snectar	len = teken_subr_do_cpr(t, cmd, response + 2);
34690926Snectar	if (len < 0)
34790926Snectar		return;
34890926Snectar
34990926Snectar	teken_funcs_respond(t, response, len + 2);
35090926Snectar}
35155682Smarkm
35255682Smarkmstatic void
35355682Smarkmteken_subr_cursor_previous_line(teken_t *t, unsigned int ncols)
35455682Smarkm{
35590926Snectar
35690926Snectar	t->t_cursor.tp_col = 0;
35790926Snectar	teken_subr_cursor_up(t, ncols);
35890926Snectar}
35990926Snectar
36090926Snectarstatic void
36190926Snectarteken_subr_cursor_up(teken_t *t, unsigned int nrows)
36255682Smarkm{
36355682Smarkm
36455682Smarkm	if (t->t_scrollreg.ts_begin + nrows >= t->t_cursor.tp_row)
36555682Smarkm		t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
36655682Smarkm	else
36772445Sassar		t->t_cursor.tp_row -= nrows;
36890926Snectar	t->t_stateflags &= ~TS_WRAPPED;
36972445Sassar	teken_funcs_cursor(t);
37072445Sassar}
37155682Smarkm
37255682Smarkmstatic void
37390926Snectarteken_subr_delete_character(teken_t *t, unsigned int ncols)
37490926Snectar{
37555682Smarkm	teken_rect_t tr;
37655682Smarkm
37755682Smarkm	tr.tr_begin.tp_row = t->t_cursor.tp_row;
37855682Smarkm	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
37990926Snectar	tr.tr_end.tp_col = t->t_winsize.tp_col;
38090926Snectar
38190926Snectar	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
38290926Snectar		tr.tr_begin.tp_col = t->t_cursor.tp_col;
38390926Snectar	} else {
38490926Snectar		/* Copy characters to the left. */
38590926Snectar		tr.tr_begin.tp_col = t->t_cursor.tp_col + ncols;
38655682Smarkm		teken_funcs_copy(t, &tr, &t->t_cursor);
38755682Smarkm
38855682Smarkm		tr.tr_begin.tp_col = t->t_winsize.tp_col - ncols;
38955682Smarkm	}
39055682Smarkm
39172445Sassar	/* Blank trailing columns. */
39290926Snectar	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
39372445Sassar}
39472445Sassar
39555682Smarkmstatic void
39655682Smarkmteken_subr_delete_line(teken_t *t, unsigned int nrows)
39790926Snectar{
39890926Snectar	teken_rect_t tr;
39955682Smarkm
40055682Smarkm	tr.tr_begin.tp_col = 0;
40155682Smarkm	tr.tr_end.tp_row = t->t_scrollreg.ts_end;
40255682Smarkm	tr.tr_end.tp_col = t->t_winsize.tp_col;
40390926Snectar
40490926Snectar	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
40590926Snectar		tr.tr_begin.tp_row = t->t_cursor.tp_row;
40690926Snectar	} else {
40790926Snectar		teken_pos_t tp;
40890926Snectar
40990926Snectar		/* Copy rows up. */
41055682Smarkm		tr.tr_begin.tp_row = t->t_cursor.tp_row + nrows;
41155682Smarkm		tp.tp_row = t->t_cursor.tp_row;
41255682Smarkm		tp.tp_col = 0;
41355682Smarkm		teken_funcs_copy(t, &tr, &tp);
41455682Smarkm
41572445Sassar		tr.tr_begin.tp_row = t->t_scrollreg.ts_end - nrows;
41690926Snectar	}
41772445Sassar
41872445Sassar	/* Blank trailing rows. */
41955682Smarkm	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
42055682Smarkm}
42190926Snectar
42290926Snectarstatic void
42390926Snectarteken_subr_device_control_string(teken_t *t __unused)
42455682Smarkm{
42555682Smarkm
42690926Snectar	teken_printf("device control string???\n");
42755682Smarkm}
42855682Smarkm
42990926Snectarstatic void
43055682Smarkmteken_subr_device_status_report(teken_t *t, unsigned int cmd)
43155682Smarkm{
43290926Snectar	char response[19] = "\x1B[?";
43355682Smarkm	ssize_t len;
43455682Smarkm
43590926Snectar	len = teken_subr_do_cpr(t, cmd, response + 3);
43672445Sassar	if (len < 0)
43772445Sassar		return;
43890926Snectar
43990926Snectar	teken_funcs_respond(t, response, len + 3);
44090926Snectar}
44190926Snectar
44290926Snectarstatic void
44390926Snectarteken_subr_double_height_double_width_line_top(teken_t *t __unused)
44490926Snectar{
44572445Sassar
44690926Snectar	teken_printf("double height double width top\n");
44790926Snectar}
44872445Sassar
44972445Sassarstatic void
45090926Snectarteken_subr_double_height_double_width_line_bottom(teken_t *t __unused)
45172445Sassar{
45290926Snectar
45390926Snectar	teken_printf("double height double width bottom\n");
45472445Sassar}
45590926Snectar
45690926Snectarstatic void
45790926Snectarteken_subr_erase_character(teken_t *t, unsigned int ncols)
45855682Smarkm{
45990926Snectar	teken_rect_t tr;
46090926Snectar
46190926Snectar	tr.tr_begin = t->t_cursor;
46255682Smarkm	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
46355682Smarkm
46455682Smarkm	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
46555682Smarkm		tr.tr_end.tp_col = t->t_winsize.tp_col;
46655682Smarkm	else
46755682Smarkm		tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
46855682Smarkm
46955682Smarkm	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
47055682Smarkm}
47172445Sassar
47255682Smarkmstatic void
47355682Smarkmteken_subr_erase_display(teken_t *t, unsigned int mode)
47455682Smarkm{
47555682Smarkm	teken_rect_t r;
47655682Smarkm
47790926Snectar	r.tr_begin.tp_col = 0;
47890926Snectar	r.tr_end.tp_col = t->t_winsize.tp_col;
47990926Snectar
48090926Snectar	switch (mode) {
48155682Smarkm	case 1: /* Erase from the top to the cursor. */
48255682Smarkm		teken_subr_erase_line(t, 1);
48355682Smarkm
48455682Smarkm		/* Erase lines above. */
48555682Smarkm		if (t->t_cursor.tp_row == 0)
48655682Smarkm			return;
48755682Smarkm		r.tr_begin.tp_row = 0;
48872445Sassar		r.tr_end.tp_row = t->t_cursor.tp_row;
48955682Smarkm		break;
49055682Smarkm	case 2: /* Erase entire display. */
49155682Smarkm		r.tr_begin.tp_row = 0;
49255682Smarkm		r.tr_end.tp_row = t->t_winsize.tp_row;
49355682Smarkm		break;
49455682Smarkm	default: /* Erase from cursor to the bottom. */
49555682Smarkm		teken_subr_erase_line(t, 0);
49672445Sassar
49772445Sassar		/* Erase lines below. */
49872445Sassar		if (t->t_cursor.tp_row == t->t_winsize.tp_row - 1)
49972445Sassar			return;
50072445Sassar		r.tr_begin.tp_row = t->t_cursor.tp_row + 1;
50172445Sassar		r.tr_end.tp_row = t->t_winsize.tp_row;
50255682Smarkm		break;
50372445Sassar	}
50455682Smarkm
50572445Sassar	teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
50672445Sassar}
50755682Smarkm
50855682Smarkmstatic void
50972445Sassarteken_subr_erase_line(teken_t *t, unsigned int mode)
51072445Sassar{
51172445Sassar	teken_rect_t r;
51272445Sassar
51372445Sassar	r.tr_begin.tp_row = t->t_cursor.tp_row;
51455682Smarkm	r.tr_end.tp_row = t->t_cursor.tp_row + 1;
51555682Smarkm
51672445Sassar	switch (mode) {
51755682Smarkm	case 1: /* Erase from the beginning of the line to the cursor. */
51878527Sassar		r.tr_begin.tp_col = 0;
51978527Sassar		r.tr_end.tp_col = t->t_cursor.tp_col + 1;
52078527Sassar		break;
52190926Snectar	case 2: /* Erase entire line. */
52278527Sassar		r.tr_begin.tp_col = 0;
52355682Smarkm		r.tr_end.tp_col = t->t_winsize.tp_col;
52490926Snectar		break;
52555682Smarkm	default: /* Erase from cursor to the end of the line. */
52690926Snectar		r.tr_begin.tp_col = t->t_cursor.tp_col;
52755682Smarkm		r.tr_end.tp_col = t->t_winsize.tp_col;
52890926Snectar		break;
52990926Snectar	}
53055682Smarkm
53155682Smarkm	teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
53255682Smarkm}
53390926Snectar
53490926Snectarstatic void
53590926Snectarteken_subr_g0_scs_special_graphics(teken_t *t __unused)
53690926Snectar{
53790926Snectar
53855682Smarkm	teken_scs_set(t, 0, teken_scs_special_graphics);
53972445Sassar}
54072445Sassar
54155682Smarkmstatic void
54255682Smarkmteken_subr_g0_scs_uk_national(teken_t *t __unused)
54372445Sassar{
54472445Sassar
54555682Smarkm	teken_scs_set(t, 0, teken_scs_uk_national);
54655682Smarkm}
54790926Snectar
54890926Snectarstatic void
54990926Snectarteken_subr_g0_scs_us_ascii(teken_t *t __unused)
55055682Smarkm{
55155682Smarkm
55255682Smarkm	teken_scs_set(t, 0, teken_scs_us_ascii);
55390926Snectar}
55490926Snectar
55590926Snectarstatic void
55690926Snectarteken_subr_g1_scs_special_graphics(teken_t *t __unused)
55790926Snectar{
55890926Snectar
55955682Smarkm	teken_scs_set(t, 1, teken_scs_special_graphics);
56055682Smarkm}
56190926Snectar
56255682Smarkmstatic void
56355682Smarkmteken_subr_g1_scs_uk_national(teken_t *t __unused)
56455682Smarkm{
56590926Snectar
56690926Snectar	teken_scs_set(t, 1, teken_scs_uk_national);
56755682Smarkm}
56890926Snectar
56990926Snectarstatic void
57090926Snectarteken_subr_g1_scs_us_ascii(teken_t *t __unused)
57155682Smarkm{
57255682Smarkm
57355682Smarkm	teken_scs_set(t, 1, teken_scs_us_ascii);
57455682Smarkm}
57555682Smarkm
57690926Snectarstatic void
57755682Smarkmteken_subr_horizontal_position_absolute(teken_t *t, unsigned int col)
57855682Smarkm{
57990926Snectar
58090926Snectar	t->t_cursor.tp_col = col - 1;
58190926Snectar	if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
58255682Smarkm		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
58390926Snectar
58490926Snectar	t->t_stateflags &= ~TS_WRAPPED;
58555682Smarkm	teken_funcs_cursor(t);
58690926Snectar}
58755682Smarkm
58890926Snectarstatic void
58990926Snectarteken_subr_horizontal_tab(teken_t *t)
59055682Smarkm{
59190926Snectar
59255682Smarkm	if (t->t_stateflags & TS_CONS25) {
59390926Snectar		teken_subr_cursor_forward_tabulation(t, 1);
59455682Smarkm	} else {
59590926Snectar		teken_rect_t tr;
59655682Smarkm
59790926Snectar		tr.tr_begin = t->t_cursor;
59890926Snectar		teken_subr_cursor_forward_tabulation(t, 1);
59990926Snectar		tr.tr_end.tp_row = tr.tr_begin.tp_row + 1;
60090926Snectar		tr.tr_end.tp_col = t->t_cursor.tp_col;
60190926Snectar
60290926Snectar		/* Blank region that we skipped. */
60390926Snectar		if (tr.tr_end.tp_col > tr.tr_begin.tp_col)
60490926Snectar			teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
60590926Snectar	}
60690926Snectar}
60790926Snectar
60890926Snectarstatic void
60990926Snectarteken_subr_horizontal_tab_set(teken_t *t)
61090926Snectar{
61190926Snectar
61255682Smarkm	teken_tab_set(t, t->t_cursor.tp_col);
61355682Smarkm}
61490926Snectar
61555682Smarkmstatic void
61690926Snectarteken_subr_index(teken_t *t)
61755682Smarkm{
61890926Snectar
61990926Snectar	if (t->t_cursor.tp_row < t->t_scrollreg.ts_end - 1) {
62090926Snectar		t->t_cursor.tp_row++;
62190926Snectar		t->t_stateflags &= ~TS_WRAPPED;
62290926Snectar		teken_funcs_cursor(t);
62390926Snectar	} else {
62490926Snectar		teken_subr_do_scroll(t, 1);
62590926Snectar	}
62690926Snectar}
62790926Snectar
62890926Snectarstatic void
62990926Snectarteken_subr_insert_character(teken_t *t, unsigned int ncols)
63090926Snectar{
63190926Snectar	teken_rect_t tr;
63290926Snectar
63390926Snectar	tr.tr_begin = t->t_cursor;
63490926Snectar	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
63590926Snectar
63690926Snectar	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
63790926Snectar		tr.tr_end.tp_col = t->t_winsize.tp_col;
63890926Snectar	} else {
63990926Snectar		teken_pos_t tp;
64090926Snectar
64190926Snectar		/* Copy characters to the right. */
64290926Snectar		tr.tr_end.tp_col = t->t_winsize.tp_col - ncols;
64355682Smarkm		tp.tp_row = t->t_cursor.tp_row;
64455682Smarkm		tp.tp_col = t->t_cursor.tp_col + ncols;
64555682Smarkm		teken_funcs_copy(t, &tr, &tp);
64655682Smarkm
64755682Smarkm		tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
64872445Sassar	}
64972445Sassar
65072445Sassar	/* Blank current location. */
65172445Sassar	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
65255682Smarkm}
65355682Smarkm
65455682Smarkmstatic void
65555682Smarkmteken_subr_insert_line(teken_t *t, unsigned int nrows)
65655682Smarkm{
65755682Smarkm	teken_rect_t tr;
65855682Smarkm
65955682Smarkm	tr.tr_begin.tp_row = t->t_cursor.tp_row;
66055682Smarkm	tr.tr_begin.tp_col = 0;
66155682Smarkm	tr.tr_end.tp_col = t->t_winsize.tp_col;
66255682Smarkm
66372445Sassar	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
66472445Sassar		tr.tr_end.tp_row = t->t_scrollreg.ts_end;
66555682Smarkm	} else {
66655682Smarkm		teken_pos_t tp;
66755682Smarkm
66855682Smarkm		/* Copy lines down. */
66955682Smarkm		tr.tr_end.tp_row = t->t_scrollreg.ts_end - nrows;
67055682Smarkm		tp.tp_row = t->t_cursor.tp_row + nrows;
67155682Smarkm		tp.tp_col = 0;
67255682Smarkm		teken_funcs_copy(t, &tr, &tp);
67355682Smarkm
67455682Smarkm		tr.tr_end.tp_row = t->t_cursor.tp_row + nrows;
67555682Smarkm	}
67655682Smarkm
67755682Smarkm	/* Blank current location. */
67855682Smarkm	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
67955682Smarkm}
68055682Smarkm
68155682Smarkmstatic void
68255682Smarkmteken_subr_keypad_application_mode(teken_t *t)
68355682Smarkm{
68455682Smarkm
68555682Smarkm	teken_funcs_param(t, TP_KEYPADAPP, 1);
68655682Smarkm}
68755682Smarkm
68855682Smarkmstatic void
68955682Smarkmteken_subr_keypad_numeric_mode(teken_t *t)
69055682Smarkm{
69155682Smarkm
69255682Smarkm	teken_funcs_param(t, TP_KEYPADAPP, 0);
69355682Smarkm}
69455682Smarkm
69555682Smarkmstatic void
69655682Smarkmteken_subr_newline(teken_t *t)
69755682Smarkm{
69855682Smarkm
69955682Smarkm	t->t_cursor.tp_row++;
70055682Smarkm
70155682Smarkm	if (t->t_cursor.tp_row >= t->t_scrollreg.ts_end) {
70255682Smarkm		teken_subr_do_scroll(t, 1);
70355682Smarkm		t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
70455682Smarkm	}
70555682Smarkm
70655682Smarkm	t->t_stateflags &= ~TS_WRAPPED;
70755682Smarkm	teken_funcs_cursor(t);
70855682Smarkm}
70955682Smarkm
71055682Smarkmstatic void
71155682Smarkmteken_subr_newpage(teken_t *t)
71255682Smarkm{
71355682Smarkm
71455682Smarkm	if (t->t_stateflags & TS_CONS25) {
71555682Smarkm		teken_rect_t tr;
71655682Smarkm
71755682Smarkm		tr.tr_begin.tp_row = tr.tr_begin.tp_col = 0;
71855682Smarkm		tr.tr_end = t->t_winsize;
71955682Smarkm		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
72055682Smarkm
72155682Smarkm		t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
72255682Smarkm		teken_funcs_cursor(t);
72355682Smarkm	} else {
72455682Smarkm		teken_subr_newline(t);
72555682Smarkm	}
72655682Smarkm}
72755682Smarkm
72855682Smarkmstatic void
72955682Smarkmteken_subr_next_line(teken_t *t)
73055682Smarkm{
73155682Smarkm
73255682Smarkm	t->t_cursor.tp_col = 0;
73372445Sassar	teken_subr_newline(t);
73472445Sassar}
73555682Smarkm
73655682Smarkmstatic void
73755682Smarkmteken_subr_pan_down(teken_t *t, unsigned int nrows)
73855682Smarkm{
73955682Smarkm
74055682Smarkm	teken_subr_do_scroll(t, (int)nrows);
74155682Smarkm}
74255682Smarkm
74355682Smarkmstatic void
74455682Smarkmteken_subr_pan_up(teken_t *t, unsigned int nrows)
74555682Smarkm{
74655682Smarkm
74755682Smarkm	teken_subr_do_scroll(t, -(int)nrows);
74855682Smarkm}
74955682Smarkm
75055682Smarkmstatic void
75155682Smarkmteken_subr_primary_device_attributes(teken_t *t, unsigned int request)
75255682Smarkm{
75355682Smarkm
75455682Smarkm	if (request == 0) {
75555682Smarkm		const char response[] = "\x1B[?1;2c";
75655682Smarkm
75755682Smarkm		teken_funcs_respond(t, response, sizeof response - 1);
75855682Smarkm	} else {
75955682Smarkm		teken_printf("Unknown DA1\n");
76055682Smarkm	}
76155682Smarkm}
76255682Smarkm
76355682Smarkmstatic void
76455682Smarkmteken_subr_do_putchar(teken_t *t, const teken_pos_t *tp, teken_char_t c,
76555682Smarkm    int width)
76655682Smarkm{
76755682Smarkm
76855682Smarkm	if (t->t_stateflags & TS_INSERT &&
76955682Smarkm	    tp->tp_col < t->t_winsize.tp_col - width) {
77055682Smarkm		teken_rect_t ctr;
77155682Smarkm		teken_pos_t ctp;
77255682Smarkm
773		/* Insert mode. Move existing characters to the right. */
774		ctr.tr_begin = *tp;
775		ctr.tr_end.tp_row = tp->tp_row + 1;
776		ctr.tr_end.tp_col = t->t_winsize.tp_col - width;
777		ctp.tp_row = tp->tp_row;
778		ctp.tp_col = tp->tp_col + width;
779		teken_funcs_copy(t, &ctr, &ctp);
780	}
781
782	if (width == 2 && tp->tp_col + 1 < t->t_winsize.tp_col) {
783		teken_pos_t tp2;
784
785		/*
786		 * Store a space behind double width characters before
787		 * actually printing them. This prevents artifacts when
788		 * the consumer doesn't render it using double width
789		 * glyphs.
790		 */
791		tp2.tp_row = tp->tp_row;
792		tp2.tp_col = tp->tp_col + 1;
793		teken_funcs_putchar(t, &tp2, BLANK, &t->t_curattr);
794	}
795
796	teken_funcs_putchar(t, tp, c, &t->t_curattr);
797}
798
799static void
800teken_subr_regular_character(teken_t *t, teken_char_t c)
801{
802	int width;
803
804	if (t->t_stateflags & TS_8BIT) {
805		if (!(t->t_stateflags & TS_CONS25) && c <= 0x1B)
806			return;
807		width = 1;
808	} else {
809		c = teken_scs_process(t, c);
810		width = teken_wcwidth(c);
811		/* XXX: Don't process zero-width characters yet. */
812		if (width <= 0)
813			return;
814	}
815
816	if (t->t_stateflags & TS_CONS25) {
817		teken_subr_do_putchar(t, &t->t_cursor, c, width);
818		t->t_cursor.tp_col += width;
819
820		if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
821			if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
822				/* Perform scrolling. */
823				teken_subr_do_scroll(t, 1);
824			} else {
825				/* No scrolling needed. */
826				if (t->t_cursor.tp_row <
827				    t->t_winsize.tp_row - 1)
828					t->t_cursor.tp_row++;
829			}
830			t->t_cursor.tp_col = 0;
831		}
832	} else if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1 &&
833	    (t->t_stateflags & (TS_WRAPPED|TS_AUTOWRAP)) ==
834	    (TS_WRAPPED|TS_AUTOWRAP)) {
835		teken_pos_t tp;
836
837		/* Perform line wrapping. */
838
839		if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
840			/* Perform scrolling. */
841			teken_subr_do_scroll(t, 1);
842			tp.tp_row = t->t_scrollreg.ts_end - 1;
843		} else {
844			/* No scrolling needed. */
845			tp.tp_row = t->t_cursor.tp_row + 1;
846			if (tp.tp_row == t->t_winsize.tp_row) {
847				/*
848				 * Corner case: regular character
849				 * outside scrolling region, but at the
850				 * bottom of the screen.
851				 */
852				teken_subr_do_putchar(t, &t->t_cursor,
853				    c, width);
854				return;
855			}
856		}
857
858		tp.tp_col = 0;
859		teken_subr_do_putchar(t, &tp, c, width);
860
861		t->t_cursor.tp_row = tp.tp_row;
862		t->t_cursor.tp_col = width;
863		t->t_stateflags &= ~TS_WRAPPED;
864	} else {
865		/* No line wrapping needed. */
866		teken_subr_do_putchar(t, &t->t_cursor, c, width);
867		t->t_cursor.tp_col += width;
868
869		if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
870			t->t_stateflags |= TS_WRAPPED;
871			t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
872		} else {
873			t->t_stateflags &= ~TS_WRAPPED;
874		}
875	}
876
877	teken_funcs_cursor(t);
878}
879
880static void
881teken_subr_reset_dec_mode(teken_t *t, unsigned int cmd)
882{
883
884	switch (cmd) {
885	case 1: /* Cursor keys mode. */
886		teken_funcs_param(t, TP_CURSORKEYS, 0);
887		break;
888	case 2: /* DECANM: ANSI/VT52 mode. */
889		teken_printf("DECRST VT52\n");
890		break;
891	case 3: /* 132 column mode. */
892		teken_funcs_param(t, TP_132COLS, 0);
893		teken_subr_reset_to_initial_state(t);
894		break;
895	case 5: /* Inverse video. */
896		teken_printf("DECRST inverse video\n");
897		break;
898	case 6: /* Origin mode. */
899		t->t_stateflags &= ~TS_ORIGIN;
900		t->t_originreg.ts_begin = 0;
901		t->t_originreg.ts_end = t->t_winsize.tp_row;
902		t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
903		t->t_stateflags &= ~TS_WRAPPED;
904		teken_funcs_cursor(t);
905		break;
906	case 7: /* Autowrap mode. */
907		t->t_stateflags &= ~TS_AUTOWRAP;
908		break;
909	case 8: /* Autorepeat mode. */
910		teken_funcs_param(t, TP_AUTOREPEAT, 0);
911		break;
912	case 25: /* Hide cursor. */
913		teken_funcs_param(t, TP_SHOWCURSOR, 0);
914		break;
915	case 40: /* Disallow 132 columns. */
916		teken_printf("DECRST allow 132\n");
917		break;
918	case 45: /* Disable reverse wraparound. */
919		teken_printf("DECRST reverse wraparound\n");
920		break;
921	case 47: /* Switch to alternate buffer. */
922		teken_printf("Switch to alternate buffer\n");
923		break;
924	default:
925		teken_printf("Unknown DECRST: %u\n", cmd);
926	}
927}
928
929static void
930teken_subr_reset_mode(teken_t *t, unsigned int cmd)
931{
932
933	switch (cmd) {
934	case 4:
935		t->t_stateflags &= ~TS_INSERT;
936		break;
937	default:
938		teken_printf("Unknown reset mode: %u\n", cmd);
939	}
940}
941
942static void
943teken_subr_do_reset(teken_t *t)
944{
945
946	t->t_curattr = t->t_defattr;
947	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
948	t->t_scrollreg.ts_begin = 0;
949	t->t_scrollreg.ts_end = t->t_winsize.tp_row;
950	t->t_originreg = t->t_scrollreg;
951	t->t_stateflags &= TS_8BIT|TS_CONS25;
952	t->t_stateflags |= TS_AUTOWRAP;
953
954	teken_scs_set(t, 0, teken_scs_us_ascii);
955	teken_scs_set(t, 1, teken_scs_us_ascii);
956	teken_scs_switch(t, 0);
957
958	teken_subr_save_cursor(t);
959	teken_tab_default(t);
960}
961
962static void
963teken_subr_reset_to_initial_state(teken_t *t)
964{
965
966	teken_subr_do_reset(t);
967	teken_subr_erase_display(t, 2);
968	teken_funcs_param(t, TP_SHOWCURSOR, 1);
969	teken_funcs_cursor(t);
970}
971
972static void
973teken_subr_restore_cursor(teken_t *t)
974{
975
976	t->t_cursor = t->t_saved_cursor;
977	t->t_curattr = t->t_saved_curattr;
978	t->t_stateflags &= ~TS_WRAPPED;
979	teken_scs_restore(t);
980	teken_funcs_cursor(t);
981}
982
983static void
984teken_subr_reverse_index(teken_t *t)
985{
986
987	if (t->t_cursor.tp_row > t->t_scrollreg.ts_begin) {
988		t->t_cursor.tp_row--;
989		t->t_stateflags &= ~TS_WRAPPED;
990		teken_funcs_cursor(t);
991	} else {
992		teken_subr_do_scroll(t, -1);
993	}
994}
995
996static void
997teken_subr_save_cursor(teken_t *t)
998{
999
1000	t->t_saved_cursor = t->t_cursor;
1001	t->t_saved_curattr = t->t_curattr;
1002	teken_scs_save(t);
1003}
1004
1005static void
1006teken_subr_secondary_device_attributes(teken_t *t, unsigned int request)
1007{
1008
1009	if (request == 0) {
1010		const char response[] = "\x1B[>0;10;0c";
1011		teken_funcs_respond(t, response, sizeof response - 1);
1012	} else {
1013		teken_printf("Unknown DA2\n");
1014	}
1015}
1016
1017static void
1018teken_subr_set_dec_mode(teken_t *t, unsigned int cmd)
1019{
1020
1021	switch (cmd) {
1022	case 1: /* Cursor keys mode. */
1023		teken_funcs_param(t, TP_CURSORKEYS, 1);
1024		break;
1025	case 2: /* DECANM: ANSI/VT52 mode. */
1026		teken_printf("DECSET VT52\n");
1027		break;
1028	case 3: /* 132 column mode. */
1029		teken_funcs_param(t, TP_132COLS, 1);
1030		teken_subr_reset_to_initial_state(t);
1031		break;
1032	case 5: /* Inverse video. */
1033		teken_printf("DECSET inverse video\n");
1034		break;
1035	case 6: /* Origin mode. */
1036		t->t_stateflags |= TS_ORIGIN;
1037		t->t_originreg = t->t_scrollreg;
1038		t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
1039		t->t_cursor.tp_col = 0;
1040		t->t_stateflags &= ~TS_WRAPPED;
1041		teken_funcs_cursor(t);
1042		break;
1043	case 7: /* Autowrap mode. */
1044		t->t_stateflags |= TS_AUTOWRAP;
1045		break;
1046	case 8: /* Autorepeat mode. */
1047		teken_funcs_param(t, TP_AUTOREPEAT, 1);
1048		break;
1049	case 25: /* Display cursor. */
1050		teken_funcs_param(t, TP_SHOWCURSOR, 1);
1051		break;
1052	case 40: /* Allow 132 columns. */
1053		teken_printf("DECSET allow 132\n");
1054		break;
1055	case 45: /* Enable reverse wraparound. */
1056		teken_printf("DECSET reverse wraparound\n");
1057		break;
1058	case 47: /* Switch to alternate buffer. */
1059		teken_printf("Switch away from alternate buffer\n");
1060		break;
1061	default:
1062		teken_printf("Unknown DECSET: %u\n", cmd);
1063	}
1064}
1065
1066static void
1067teken_subr_set_mode(teken_t *t, unsigned int cmd)
1068{
1069
1070	switch (cmd) {
1071	case 4:
1072		teken_printf("Insert mode\n");
1073		t->t_stateflags |= TS_INSERT;
1074		break;
1075	default:
1076		teken_printf("Unknown set mode: %u\n", cmd);
1077	}
1078}
1079
1080static void
1081teken_subr_set_graphic_rendition(teken_t *t, unsigned int ncmds,
1082    unsigned int cmds[])
1083{
1084	unsigned int i, n;
1085
1086	/* No attributes means reset. */
1087	if (ncmds == 0) {
1088		t->t_curattr = t->t_defattr;
1089		return;
1090	}
1091
1092	for (i = 0; i < ncmds; i++) {
1093		n = cmds[i];
1094
1095		switch (n) {
1096		case 0: /* Reset. */
1097			t->t_curattr = t->t_defattr;
1098			break;
1099		case 1: /* Bold. */
1100			t->t_curattr.ta_format |= TF_BOLD;
1101			break;
1102		case 4: /* Underline. */
1103			t->t_curattr.ta_format |= TF_UNDERLINE;
1104			break;
1105		case 5: /* Blink. */
1106			t->t_curattr.ta_format |= TF_BLINK;
1107			break;
1108		case 7: /* Reverse. */
1109			t->t_curattr.ta_format |= TF_REVERSE;
1110			break;
1111		case 22: /* Remove bold. */
1112			t->t_curattr.ta_format &= ~TF_BOLD;
1113			break;
1114		case 24: /* Remove underline. */
1115			t->t_curattr.ta_format &= ~TF_UNDERLINE;
1116			break;
1117		case 25: /* Remove blink. */
1118			t->t_curattr.ta_format &= ~TF_BLINK;
1119			break;
1120		case 27: /* Remove reverse. */
1121			t->t_curattr.ta_format &= ~TF_REVERSE;
1122			break;
1123		case 30: /* Set foreground color: black */
1124		case 31: /* Set foreground color: red */
1125		case 32: /* Set foreground color: green */
1126		case 33: /* Set foreground color: brown */
1127		case 34: /* Set foreground color: blue */
1128		case 35: /* Set foreground color: magenta */
1129		case 36: /* Set foreground color: cyan */
1130		case 37: /* Set foreground color: white */
1131			t->t_curattr.ta_fgcolor = n - 30;
1132			break;
1133		case 39: /* Set default foreground color. */
1134			t->t_curattr.ta_fgcolor = t->t_defattr.ta_fgcolor;
1135			break;
1136		case 40: /* Set background color: black */
1137		case 41: /* Set background color: red */
1138		case 42: /* Set background color: green */
1139		case 43: /* Set background color: brown */
1140		case 44: /* Set background color: blue */
1141		case 45: /* Set background color: magenta */
1142		case 46: /* Set background color: cyan */
1143		case 47: /* Set background color: white */
1144			t->t_curattr.ta_bgcolor = n - 40;
1145			break;
1146		case 49: /* Set default background color. */
1147			t->t_curattr.ta_bgcolor = t->t_defattr.ta_bgcolor;
1148			break;
1149		default:
1150			teken_printf("unsupported attribute %u\n", n);
1151		}
1152	}
1153}
1154
1155static void
1156teken_subr_set_top_and_bottom_margins(teken_t *t, unsigned int top,
1157    unsigned int bottom)
1158{
1159
1160	/* Adjust top row number. */
1161	if (top > 0)
1162		top--;
1163	/* Adjust bottom row number. */
1164	if (bottom == 0 || bottom > t->t_winsize.tp_row)
1165		bottom = t->t_winsize.tp_row;
1166
1167	/* Invalid arguments. */
1168	if (top >= bottom - 1) {
1169		top = 0;
1170		bottom = t->t_winsize.tp_row;
1171	}
1172
1173	t->t_scrollreg.ts_begin = top;
1174	t->t_scrollreg.ts_end = bottom;
1175	if (t->t_stateflags & TS_ORIGIN) {
1176		/* XXX: home cursor? */
1177		t->t_originreg = t->t_scrollreg;
1178		t->t_cursor.tp_row = t->t_originreg.ts_begin;
1179		t->t_cursor.tp_col = 0;
1180		t->t_stateflags &= ~TS_WRAPPED;
1181		teken_funcs_cursor(t);
1182	}
1183}
1184
1185static void
1186teken_subr_single_height_double_width_line(teken_t *t __unused)
1187{
1188
1189	teken_printf("single height double width???\n");
1190}
1191
1192static void
1193teken_subr_single_height_single_width_line(teken_t *t __unused)
1194{
1195
1196	teken_printf("single height single width???\n");
1197}
1198
1199static void
1200teken_subr_string_terminator(teken_t *t __unused)
1201{
1202
1203	teken_printf("string terminator???\n");
1204}
1205
1206static void
1207teken_subr_tab_clear(teken_t *t, unsigned int cmd)
1208{
1209
1210	switch (cmd) {
1211	case 0:
1212		teken_tab_clear(t, t->t_cursor.tp_col);
1213		break;
1214	case 3:
1215		memset(&t->t_tabstops, 0, T_NUMCOL / 8);
1216		break;
1217	}
1218}
1219
1220static void
1221teken_subr_vertical_position_absolute(teken_t *t, unsigned int row)
1222{
1223
1224	t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
1225	if (row >= t->t_originreg.ts_end)
1226		t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
1227
1228
1229	t->t_stateflags &= ~TS_WRAPPED;
1230	teken_funcs_cursor(t);
1231}
1232