teken_subr.h revision 196775
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes *
141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241590Srgrimes * SUCH DAMAGE.
251590Srgrimes *
261590Srgrimes * $FreeBSD: head/sys/teken/teken_subr.h 190158 2009-03-20 14:32:51Z ed $
271590Srgrimes */
281590Srgrimes
291590Srgrimesstatic void teken_subr_cursor_up(teken_t *, unsigned int);
301590Srgrimesstatic void teken_subr_erase_line(teken_t *, unsigned int);
3191792Smikestatic void teken_subr_regular_character(teken_t *, teken_char_t);
321590Srgrimesstatic void teken_subr_reset_to_initial_state(teken_t *);
331590Srgrimesstatic void teken_subr_save_cursor(teken_t *);
341590Srgrimes
351590Srgrimesstatic inline int
3691792Smiketeken_tab_isset(teken_t *t, unsigned int col)
371590Srgrimes{
381590Srgrimes	unsigned int b, o;
3990131Smike
4028792Scharnier	if (col >= T_NUMCOL)
411590Srgrimes		return ((col % 8) == 0);
4290131Smike
4390131Smike	b = col / (sizeof(unsigned int) * 8);
4490131Smike	o = col % (sizeof(unsigned int) * 8);
451590Srgrimes
461590Srgrimes	return (t->t_tabstops[b] & (1 << o));
471590Srgrimes}
4836913Speter
4977368Sphkstatic inline void
5028792Scharnierteken_tab_clear(teken_t *t, unsigned int col)
511590Srgrimes{
5280050Smike	unsigned int b, o;
531590Srgrimes
5453291Sache	if (col >= T_NUMCOL)
5528792Scharnier		return;
5633626Swollman
5728792Scharnier	b = col / (sizeof(unsigned int) * 8);
581590Srgrimes	o = col % (sizeof(unsigned int) * 8);
59130479Sbms
6053291Sache	t->t_tabstops[b] &= ~(1 << o);
6154088Sache}
6243506Swollman
6333626Swollmanstatic inline void
64106735Smiketeken_tab_set(teken_t *t, unsigned int col)
65138681Sceri{
6633626Swollman	unsigned int b, o;
6733626Swollman
6853291Sache	if (col >= T_NUMCOL)
6953291Sache		return;
7087536Smike
71112617Seivind	b = col / (sizeof(unsigned int) * 8);
72130466Sbms	o = col % (sizeof(unsigned int) * 8);
73134294Smbr
74154710Sjhay	t->t_tabstops[b] |= 1 << o;
7581165Smike}
7678581Sdes
77110159Srobertostatic void
781590Srgrimesteken_tab_default(teken_t *t)
7953291Sache{
8084852Smike	unsigned int i;
8153291Sache
8284852Smike	memset(&t->t_tabstops, 0, T_NUMCOL / 8);
8384852Smike
84227246Sed	for (i = 8; i < T_NUMCOL; i += 8)
85227246Sed		teken_tab_set(t, i);
86227246Sed}
8778900Sdd
8879835Smikestatic void
8980050Smiketeken_subr_do_scroll(teken_t *t, int amount)
9090163Skris{
9178581Sdes	teken_rect_t tr;
9290131Smike	teken_pos_t tp;
9328792Scharnier
9428792Scharnier	teken_assert(t->t_cursor.tp_row <= t->t_winsize.tp_row);
9578581Sdes	teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
961590Srgrimes	teken_assert(amount != 0);
9781165Smike
9853291Sache	/* Copy existing data 1 line up. */
9980050Smike	if (amount > 0) {
1001590Srgrimes		/* Scroll down. */
10115359Spst
10215359Spst		/* Copy existing data up. */
10315359Spst		if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
10415359Spst			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin + amount;
10581165Smike			tr.tr_begin.tp_col = 0;
10681165Smike			tr.tr_end.tp_row = t->t_scrollreg.ts_end;
107202280Sedwin			tr.tr_end.tp_col = t->t_winsize.tp_col;
10878581Sdes			tp.tp_row = t->t_scrollreg.ts_begin;
10933626Swollman			tp.tp_col = 0;
11033626Swollman			teken_funcs_copy(t, &tr, &tp);
11133626Swollman
11281165Smike			tr.tr_begin.tp_row = t->t_scrollreg.ts_end - amount;
11381165Smike		} else {
11481165Smike			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
115130479Sbms		}
116130479Sbms
117130479Sbms		/* Clear the last lines. */
11881165Smike		tr.tr_begin.tp_col = 0;
11981165Smike		tr.tr_end.tp_row = t->t_scrollreg.ts_end;
12085067Smike		tr.tr_end.tp_col = t->t_winsize.tp_col;
121154710Sjhay		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
122154710Sjhay	} else {
123154710Sjhay		/* Scroll up. */
12443506Swollman		amount = -amount;
12543506Swollman
12643506Swollman		/* Copy existing data down. */
1271590Srgrimes		if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
1281590Srgrimes			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
1291590Srgrimes			tr.tr_begin.tp_col = 0;
13053048Sache			tr.tr_end.tp_row = t->t_scrollreg.ts_end - amount;
13153048Sache			tr.tr_end.tp_col = t->t_winsize.tp_col;
13253048Sache			tp.tp_row = t->t_scrollreg.ts_begin + amount;
133130466Sbms			tp.tp_col = 0;
134130466Sbms			teken_funcs_copy(t, &tr, &tp);
135130466Sbms
136138681Sceri			tr.tr_end.tp_row = t->t_scrollreg.ts_begin + amount;
137138681Sceri		} else {
138138681Sceri			tr.tr_end.tp_row = t->t_scrollreg.ts_end;
139106735Smike		}
140106735Smike
141106735Smike		/* Clear the first lines. */
14253291Sache		tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
14353291Sache		tr.tr_begin.tp_col = 0;
14453291Sache		tr.tr_end.tp_col = t->t_winsize.tp_col;
14533626Swollman		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
14681165Smike	}
14733626Swollman}
14853291Sache
14953291Sachestatic ssize_t
15053291Sacheteken_subr_do_cpr(teken_t *t, unsigned int cmd, char response[16])
15133626Swollman{
15233626Swollman
15333626Swollman	switch (cmd) {
15443520Sache	case 5: /* Operating status. */
15581165Smike		strcpy(response, "0n");
15681165Smike		return (2);
15743520Sache	case 6: { /* Cursor position. */
158197725Sdougb		int len;
15954172Sjoe
160197725Sdougb		len = snprintf(response, 16, "%u;%uR",
161197725Sdougb		    (t->t_cursor.tp_row - t->t_originreg.ts_begin) + 1,
16254172Sjoe		    t->t_cursor.tp_col + 1);
1631590Srgrimes
1641590Srgrimes		if (len >= 16)
1651590Srgrimes			return (-1);
16678581Sdes		return (len);
1671590Srgrimes	}
16854227Sjoe	case 15: /* Printer status. */
1691590Srgrimes		strcpy(response, "13n");
1701590Srgrimes		return (3);
1711590Srgrimes	case 25: /* UDK status. */
17281165Smike		strcpy(response, "20n");
1731590Srgrimes		return (3);
1741590Srgrimes	case 26: /* Keyboard status. */
17553291Sache		strcpy(response, "27;1n");
17681165Smike		return (5);
17781165Smike	default:
17878581Sdes		teken_printf("Unknown DSR\n");
17978581Sdes		return (-1);
18053291Sache	}
18181165Smike}
182268154Sume
183268154Sumestatic void
184268154Sumeteken_subr_alignment_test(teken_t *t)
185268154Sume{
186268154Sume	teken_rect_t tr;
187268154Sume
18853291Sache	t->t_scrollreg.ts_begin = 0;
18990131Smike	t->t_scrollreg.ts_end = t->t_winsize.tp_row;
19081165Smike
19181165Smike	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
19290131Smike	t->t_stateflags &= ~TS_WRAPPED;
19385067Smike	teken_funcs_cursor(t);
19480050Smike
19590131Smike	tr.tr_begin.tp_row = 0;
19680050Smike	tr.tr_begin.tp_col = 0;
19790131Smike	tr.tr_end = t->t_winsize;
19878581Sdes	teken_funcs_fill(t, &tr, 'E', &t->t_defattr);
19978581Sdes}
20090131Smike
20153291Sachestatic void
20253291Sacheteken_subr_backspace(teken_t *t)
20353291Sache{
20453291Sache
20579835Smike#ifdef TEKEN_XTERM
20679835Smike	if (t->t_cursor.tp_col == 0)
20779835Smike		return;
20879835Smike
20979835Smike	t->t_cursor.tp_col--;
21079835Smike	t->t_stateflags &= ~TS_WRAPPED;
21179835Smike#else /* !TEKEN_XTERM */
21279835Smike	if (t->t_cursor.tp_col == 0) {
21379835Smike		if (t->t_cursor.tp_row == t->t_originreg.ts_begin)
21479835Smike			return;
21579835Smike		t->t_cursor.tp_row--;
216202281Sedwin		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
217202281Sedwin	} else {
218202281Sedwin		t->t_cursor.tp_col--;
219202281Sedwin	}
22079835Smike#endif /* TEKEN_XTERM */
22179835Smike
22279835Smike	teken_funcs_cursor(t);
22379835Smike}
224112617Seivind
225112617Seivindstatic void
226112617Seivindteken_subr_bell(teken_t *t)
227112617Seivind{
228112617Seivind
229112617Seivind	teken_funcs_bell(t);
23079835Smike}
23179835Smike
23280155Smikestatic void
23380155Smiketeken_subr_carriage_return(teken_t *t)
23480050Smike{
23580050Smike
236117050Sache	t->t_cursor.tp_col = 0;
23780050Smike	t->t_stateflags &= ~TS_WRAPPED;
23879835Smike	teken_funcs_cursor(t);
23979835Smike}
24079835Smike
24185067Smikestatic void
24280050Smiketeken_subr_cursor_backward(teken_t *t, unsigned int ncols)
24380050Smike{
24480050Smike
24580050Smike	if (ncols > t->t_cursor.tp_col)
24680050Smike		t->t_cursor.tp_col = 0;
24780050Smike	else
24880050Smike		t->t_cursor.tp_col -= ncols;
24980050Smike	t->t_stateflags &= ~TS_WRAPPED;
25080050Smike	teken_funcs_cursor(t);
25181165Smike}
25280050Smike
25380050Smikestatic void
25480050Smiketeken_subr_cursor_backward_tabulation(teken_t *t, unsigned int ntabs)
25580050Smike{
25680050Smike
25780050Smike	do {
25880050Smike		/* Stop when we've reached the beginning of the line. */
25985067Smike		if (t->t_cursor.tp_col == 0)
26080050Smike			break;
26180050Smike
26280050Smike		t->t_cursor.tp_col--;
26380050Smike
26453291Sache		/* Tab marker set. */
26580050Smike		if (teken_tab_isset(t, t->t_cursor.tp_col))
26680050Smike			ntabs--;
26780050Smike	} while (ntabs > 0);
26880050Smike
26980050Smike	teken_funcs_cursor(t);
27080050Smike}
27180050Smike
27280050Smikestatic void
27380050Smiketeken_subr_cursor_down(teken_t *t, unsigned int nrows)
27480050Smike{
27580050Smike
27680050Smike	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end)
27780050Smike		t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
27890131Smike	else
27953291Sache		t->t_cursor.tp_row += nrows;
28053291Sache	t->t_stateflags &= ~TS_WRAPPED;
28190131Smike	teken_funcs_cursor(t);
28284852Smike}
28384852Smike
284103530Smikestatic void
28553291Sacheteken_subr_cursor_forward(teken_t *t, unsigned int ncols)
286146752Scharnier{
28790131Smike
28890131Smike	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
28977585Sume		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
29078581Sdes	else
29177585Sume		t->t_cursor.tp_col += ncols;
29278581Sdes	t->t_stateflags &= ~TS_WRAPPED;
29377585Sume	teken_funcs_cursor(t);
29477585Sume}
29554227Sjoe
29690131Smikestatic void
29778581Sdesteken_subr_cursor_forward_tabulation(teken_t *t, unsigned int ntabs)
29878581Sdes{
29933626Swollman
3001590Srgrimes	do {
3011590Srgrimes		/* Stop when we've reached the end of the line. */
30278581Sdes		if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1)
30378581Sdes			break;
304134294Smbr
305134294Smbr		t->t_cursor.tp_col++;
306166103Sphk
307166103Sphk		/* Tab marker set. */
308134294Smbr		if (teken_tab_isset(t, t->t_cursor.tp_col))
309134294Smbr			ntabs--;
310134294Smbr	} while (ntabs > 0);
31178581Sdes
31253291Sache	teken_funcs_cursor(t);
31378581Sdes}
31484852Smike
31578581Sdesstatic void
31684852Smiketeken_subr_cursor_next_line(teken_t *t, unsigned int ncols)
31753291Sache{
31878900Sdd
31984852Smike	t->t_cursor.tp_col = 0;
32084852Smike	teken_subr_cursor_down(t, ncols);
32184852Smike}
32284852Smike
32384852Smikestatic void
32484852Smiketeken_subr_cursor_position(teken_t *t, unsigned int row, unsigned int col)
32584852Smike{
32684852Smike
32778900Sdd	t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
32884852Smike	if (row >= t->t_originreg.ts_end)
32984852Smike		t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
330111430Smike
331111430Smike	t->t_cursor.tp_col = col - 1;
332111430Smike	if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
333110159Sroberto		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
334110159Sroberto
335110159Sroberto	t->t_stateflags &= ~TS_WRAPPED;
336110159Sroberto	teken_funcs_cursor(t);
337110159Sroberto}
338110159Sroberto
339110159Srobertostatic void
340111430Smiketeken_subr_cursor_position_report(teken_t *t, unsigned int cmd)
341111430Smike{
342103530Smike	char response[18] = "\x1B[";
343168721Sache	ssize_t len;
34478900Sdd
34584852Smike	len = teken_subr_do_cpr(t, cmd, response + 2);
34684852Smike	if (len < 0)
34784852Smike		return;
34884852Smike
34984852Smike	teken_funcs_respond(t, response, len + 2);
35084852Smike}
35178900Sdd
35253291Sachestatic void
35353291Sacheteken_subr_cursor_previous_line(teken_t *t, unsigned int ncols)
35453291Sache{
35578581Sdes
35690131Smike	t->t_cursor.tp_col = 0;
35778581Sdes	teken_subr_cursor_up(t, ncols);
35853291Sache}
3591590Srgrimes
3601590Srgrimesstatic void
36128792Scharnierteken_subr_cursor_up(teken_t *t, unsigned int nrows)
36278581Sdes{
3631590Srgrimes
36478581Sdes	if (t->t_scrollreg.ts_begin + nrows >= t->t_cursor.tp_row)
365202280Sedwin		t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
36681165Smike	else
36733626Swollman		t->t_cursor.tp_row -= nrows;
3681590Srgrimes	t->t_stateflags &= ~TS_WRAPPED;
369	teken_funcs_cursor(t);
370}
371
372static void
373teken_subr_delete_character(teken_t *t, unsigned int ncols)
374{
375	teken_rect_t tr;
376
377	tr.tr_begin.tp_row = t->t_cursor.tp_row;
378	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
379	tr.tr_end.tp_col = t->t_winsize.tp_col;
380
381	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
382		tr.tr_begin.tp_col = t->t_cursor.tp_col;
383	} else {
384		/* Copy characters to the left. */
385		tr.tr_begin.tp_col = t->t_cursor.tp_col + ncols;
386		teken_funcs_copy(t, &tr, &t->t_cursor);
387
388		tr.tr_begin.tp_col = t->t_winsize.tp_col - ncols;
389	}
390
391	/* Blank trailing columns. */
392	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
393}
394
395static void
396teken_subr_delete_line(teken_t *t, unsigned int nrows)
397{
398	teken_rect_t tr;
399
400	tr.tr_begin.tp_col = 0;
401	tr.tr_end.tp_row = t->t_scrollreg.ts_end;
402	tr.tr_end.tp_col = t->t_winsize.tp_col;
403
404	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
405		tr.tr_begin.tp_row = t->t_cursor.tp_row;
406	} else {
407		teken_pos_t tp;
408
409		/* Copy rows up. */
410		tr.tr_begin.tp_row = t->t_cursor.tp_row + nrows;
411		tp.tp_row = t->t_cursor.tp_row;
412		tp.tp_col = 0;
413		teken_funcs_copy(t, &tr, &tp);
414
415		tr.tr_begin.tp_row = t->t_scrollreg.ts_end - nrows;
416	}
417
418	/* Blank trailing rows. */
419	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
420}
421
422static void
423teken_subr_device_control_string(teken_t *t __unused)
424{
425
426	teken_printf("device control string???\n");
427}
428
429static void
430teken_subr_device_status_report(teken_t *t, unsigned int cmd)
431{
432	char response[19] = "\x1B[?";
433	ssize_t len;
434
435	len = teken_subr_do_cpr(t, cmd, response + 3);
436	if (len < 0)
437		return;
438
439	teken_funcs_respond(t, response, len + 3);
440}
441
442static void
443teken_subr_double_height_double_width_line_top(teken_t *t __unused)
444{
445
446	teken_printf("double height double width top\n");
447}
448
449static void
450teken_subr_double_height_double_width_line_bottom(teken_t *t __unused)
451{
452
453	teken_printf("double height double width bottom\n");
454}
455
456static void
457teken_subr_erase_character(teken_t *t, unsigned int ncols)
458{
459	teken_rect_t tr;
460
461	tr.tr_begin = t->t_cursor;
462	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
463
464	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
465		tr.tr_end.tp_col = t->t_winsize.tp_col;
466	else
467		tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
468
469	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
470}
471
472static void
473teken_subr_erase_display(teken_t *t, unsigned int mode)
474{
475	teken_rect_t r;
476
477	r.tr_begin.tp_col = 0;
478	r.tr_end.tp_col = t->t_winsize.tp_col;
479
480	switch (mode) {
481	case 1: /* Erase from the top to the cursor. */
482		teken_subr_erase_line(t, 1);
483
484		/* Erase lines above. */
485		if (t->t_cursor.tp_row == 0)
486			return;
487		r.tr_begin.tp_row = 0;
488		r.tr_end.tp_row = t->t_cursor.tp_row;
489		break;
490	case 2: /* Erase entire display. */
491		r.tr_begin.tp_row = 0;
492		r.tr_end.tp_row = t->t_winsize.tp_row;
493		break;
494	default: /* Erase from cursor to the bottom. */
495		teken_subr_erase_line(t, 0);
496
497		/* Erase lines below. */
498		if (t->t_cursor.tp_row == t->t_winsize.tp_row - 1)
499			return;
500		r.tr_begin.tp_row = t->t_cursor.tp_row + 1;
501		r.tr_end.tp_row = t->t_winsize.tp_row;
502		break;
503	}
504
505	teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
506}
507
508static void
509teken_subr_erase_line(teken_t *t, unsigned int mode)
510{
511	teken_rect_t r;
512
513	r.tr_begin.tp_row = t->t_cursor.tp_row;
514	r.tr_end.tp_row = t->t_cursor.tp_row + 1;
515
516	switch (mode) {
517	case 1: /* Erase from the beginning of the line to the cursor. */
518		r.tr_begin.tp_col = 0;
519		r.tr_end.tp_col = t->t_cursor.tp_col + 1;
520		break;
521	case 2: /* Erase entire line. */
522		r.tr_begin.tp_col = 0;
523		r.tr_end.tp_col = t->t_winsize.tp_col;
524		break;
525	default: /* Erase from cursor to the end of the line. */
526		r.tr_begin.tp_col = t->t_cursor.tp_col;
527		r.tr_end.tp_col = t->t_winsize.tp_col;
528		break;
529	}
530
531	teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
532}
533
534static void
535teken_subr_g0_scs_special_graphics(teken_t *t __unused)
536{
537
538	teken_scs_set(t, 0, teken_scs_special_graphics);
539}
540
541static void
542teken_subr_g0_scs_uk_national(teken_t *t __unused)
543{
544
545	teken_scs_set(t, 0, teken_scs_uk_national);
546}
547
548static void
549teken_subr_g0_scs_us_ascii(teken_t *t __unused)
550{
551
552	teken_scs_set(t, 0, teken_scs_us_ascii);
553}
554
555static void
556teken_subr_g1_scs_special_graphics(teken_t *t __unused)
557{
558
559	teken_scs_set(t, 1, teken_scs_special_graphics);
560}
561
562static void
563teken_subr_g1_scs_uk_national(teken_t *t __unused)
564{
565
566	teken_scs_set(t, 1, teken_scs_uk_national);
567}
568
569static void
570teken_subr_g1_scs_us_ascii(teken_t *t __unused)
571{
572
573	teken_scs_set(t, 1, teken_scs_us_ascii);
574}
575
576static void
577teken_subr_horizontal_position_absolute(teken_t *t, unsigned int col)
578{
579
580	t->t_cursor.tp_col = col - 1;
581	if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
582		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
583
584	t->t_stateflags &= ~TS_WRAPPED;
585	teken_funcs_cursor(t);
586}
587
588static void
589teken_subr_horizontal_tab(teken_t *t)
590{
591#ifdef TEKEN_XTERM
592	teken_rect_t tr;
593
594	tr.tr_begin = t->t_cursor;
595	teken_subr_cursor_forward_tabulation(t, 1);
596	tr.tr_end.tp_row = tr.tr_begin.tp_row + 1;
597	tr.tr_end.tp_col = t->t_cursor.tp_col;
598
599	/* Blank region that we skipped. */
600	if (tr.tr_end.tp_col > tr.tr_begin.tp_col)
601		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
602#else /* !TEKEN_XTERM */
603
604	teken_subr_cursor_forward_tabulation(t, 1);
605#endif /* TEKEN_XTERM */
606}
607
608static void
609teken_subr_horizontal_tab_set(teken_t *t)
610{
611
612	teken_tab_set(t, t->t_cursor.tp_col);
613}
614
615static void
616teken_subr_index(teken_t *t)
617{
618
619	if (t->t_cursor.tp_row < t->t_scrollreg.ts_end - 1) {
620		t->t_cursor.tp_row++;
621		t->t_stateflags &= ~TS_WRAPPED;
622		teken_funcs_cursor(t);
623	} else {
624		teken_subr_do_scroll(t, 1);
625	}
626}
627
628static void
629teken_subr_insert_character(teken_t *t, unsigned int ncols)
630{
631	teken_rect_t tr;
632
633	tr.tr_begin = t->t_cursor;
634	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
635
636	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
637		tr.tr_end.tp_col = t->t_winsize.tp_col;
638	} else {
639		teken_pos_t tp;
640
641		/* Copy characters to the right. */
642		tr.tr_end.tp_col = t->t_winsize.tp_col - ncols;
643		tp.tp_row = t->t_cursor.tp_row;
644		tp.tp_col = t->t_cursor.tp_col + ncols;
645		teken_funcs_copy(t, &tr, &tp);
646
647		tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
648	}
649
650	/* Blank current location. */
651	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
652}
653
654static void
655teken_subr_insert_line(teken_t *t, unsigned int nrows)
656{
657	teken_rect_t tr;
658
659	tr.tr_begin.tp_row = t->t_cursor.tp_row;
660	tr.tr_begin.tp_col = 0;
661	tr.tr_end.tp_col = t->t_winsize.tp_col;
662
663	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
664		tr.tr_end.tp_row = t->t_scrollreg.ts_end;
665	} else {
666		teken_pos_t tp;
667
668		/* Copy lines down. */
669		tr.tr_end.tp_row = t->t_scrollreg.ts_end - nrows;
670		tp.tp_row = t->t_cursor.tp_row + nrows;
671		tp.tp_col = 0;
672		teken_funcs_copy(t, &tr, &tp);
673
674		tr.tr_end.tp_row = t->t_cursor.tp_row + nrows;
675	}
676
677	/* Blank current location. */
678	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
679}
680
681static void
682teken_subr_keypad_application_mode(teken_t *t)
683{
684
685	teken_funcs_param(t, TP_KEYPADAPP, 1);
686}
687
688static void
689teken_subr_keypad_numeric_mode(teken_t *t)
690{
691
692	teken_funcs_param(t, TP_KEYPADAPP, 0);
693}
694
695static void
696teken_subr_newline(teken_t *t)
697{
698
699	t->t_cursor.tp_row++;
700
701	if (t->t_cursor.tp_row >= t->t_scrollreg.ts_end) {
702		teken_subr_do_scroll(t, 1);
703		t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
704	}
705
706	t->t_stateflags &= ~TS_WRAPPED;
707	teken_funcs_cursor(t);
708}
709
710static void
711teken_subr_newpage(teken_t *t)
712{
713#ifdef TEKEN_XTERM
714
715	teken_subr_newline(t);
716#else /* !TEKEN_XTERM */
717	teken_rect_t tr;
718
719	tr.tr_begin.tp_row = tr.tr_begin.tp_col = 0;
720	tr.tr_end = t->t_winsize;
721	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
722
723	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
724	teken_funcs_cursor(t);
725#endif /* TEKEN_XTERM */
726}
727
728static void
729teken_subr_next_line(teken_t *t)
730{
731
732	t->t_cursor.tp_col = 0;
733	teken_subr_newline(t);
734}
735
736static void
737teken_subr_pan_down(teken_t *t, unsigned int nrows)
738{
739
740	teken_subr_do_scroll(t, (int)nrows);
741}
742
743static void
744teken_subr_pan_up(teken_t *t, unsigned int nrows)
745{
746
747	teken_subr_do_scroll(t, -(int)nrows);
748}
749
750static void
751teken_subr_primary_device_attributes(teken_t *t, unsigned int request)
752{
753
754	if (request == 0) {
755		const char response[] = "\x1B[?1;2c";
756
757		teken_funcs_respond(t, response, sizeof response - 1);
758	} else {
759		teken_printf("Unknown DA1\n");
760	}
761}
762
763static void
764teken_subr_do_putchar(teken_t *t, const teken_pos_t *tp, teken_char_t c,
765    int width)
766{
767
768	if (t->t_stateflags & TS_INSERT &&
769	    tp->tp_col < t->t_winsize.tp_col - width) {
770		teken_rect_t ctr;
771		teken_pos_t ctp;
772
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	teken_funcs_putchar(t, tp, c, &t->t_curattr);
783}
784
785static void
786teken_subr_regular_character(teken_t *t, teken_char_t c)
787{
788	int width;
789
790	c = teken_scs_process(t, c);
791
792	/* XXX: Don't process zero-width characters yet. */
793	width = teken_wcwidth(c);
794	if (width <= 0)
795		return;
796
797#ifdef TEKEN_XTERM
798	if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1 &&
799	    (t->t_stateflags & (TS_WRAPPED|TS_AUTOWRAP)) ==
800	    (TS_WRAPPED|TS_AUTOWRAP)) {
801		teken_pos_t tp;
802
803		/* Perform line wrapping. */
804
805		if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
806			/* Perform scrolling. */
807			teken_subr_do_scroll(t, 1);
808			tp.tp_row = t->t_scrollreg.ts_end - 1;
809		} else {
810			/* No scrolling needed. */
811			tp.tp_row = t->t_cursor.tp_row + 1;
812			if (tp.tp_row == t->t_winsize.tp_row) {
813				/*
814				 * Corner case: regular character
815				 * outside scrolling region, but at the
816				 * bottom of the screen.
817				 */
818				teken_subr_do_putchar(t, &t->t_cursor,
819				    c, width);
820				return;
821			}
822		}
823
824		tp.tp_col = 0;
825		teken_subr_do_putchar(t, &tp, c, width);
826
827		t->t_cursor.tp_row = tp.tp_row;
828		t->t_cursor.tp_col = width;
829		t->t_stateflags &= ~TS_WRAPPED;
830	} else {
831		/* No line wrapping needed. */
832		teken_subr_do_putchar(t, &t->t_cursor, c, width);
833		t->t_cursor.tp_col += width;
834
835		if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
836			t->t_stateflags |= TS_WRAPPED;
837			t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
838		} else {
839			t->t_stateflags &= ~TS_WRAPPED;
840		}
841	}
842#else /* !TEKEN_XTERM */
843	teken_subr_do_putchar(t, &t->t_cursor, c, width);
844	t->t_cursor.tp_col += width;
845
846	if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
847		if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
848			/* Perform scrolling. */
849			teken_subr_do_scroll(t, 1);
850		} else {
851			/* No scrolling needed. */
852			if (t->t_cursor.tp_row < t->t_winsize.tp_row - 1)
853				t->t_cursor.tp_row++;
854		}
855		t->t_cursor.tp_col = 0;
856	}
857#endif /* TEKEN_XTERM */
858
859	teken_funcs_cursor(t);
860}
861
862static void
863teken_subr_reset_dec_mode(teken_t *t, unsigned int cmd)
864{
865
866	switch (cmd) {
867	case 1: /* Cursor keys mode. */
868		teken_funcs_param(t, TP_CURSORKEYS, 0);
869		break;
870	case 2: /* DECANM: ANSI/VT52 mode. */
871		teken_printf("DECRST VT52\n");
872		break;
873	case 3: /* 132 column mode. */
874		teken_funcs_param(t, TP_132COLS, 0);
875		teken_subr_reset_to_initial_state(t);
876		break;
877	case 5: /* Inverse video. */
878		teken_printf("DECRST inverse video\n");
879		break;
880	case 6: /* Origin mode. */
881		t->t_stateflags &= ~TS_ORIGIN;
882		t->t_originreg.ts_begin = 0;
883		t->t_originreg.ts_end = t->t_winsize.tp_row;
884		t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
885		t->t_stateflags &= ~TS_WRAPPED;
886		teken_funcs_cursor(t);
887		break;
888	case 7: /* Autowrap mode. */
889		t->t_stateflags &= ~TS_AUTOWRAP;
890		break;
891	case 8: /* Autorepeat mode. */
892		teken_funcs_param(t, TP_AUTOREPEAT, 0);
893		break;
894	case 25: /* Hide cursor. */
895		teken_funcs_param(t, TP_SHOWCURSOR, 0);
896		break;
897	case 40: /* Disallow 132 columns. */
898		teken_printf("DECRST allow 132\n");
899		break;
900	case 45: /* Disable reverse wraparound. */
901		teken_printf("DECRST reverse wraparound\n");
902		break;
903	case 47: /* Switch to alternate buffer. */
904		teken_printf("Switch to alternate buffer\n");
905		break;
906	default:
907		teken_printf("Unknown DECRST: %u\n", cmd);
908	}
909}
910
911static void
912teken_subr_reset_mode(teken_t *t, unsigned int cmd)
913{
914
915	switch (cmd) {
916	case 4:
917		t->t_stateflags &= ~TS_INSERT;
918		break;
919	default:
920		teken_printf("Unknown reset mode: %u\n", cmd);
921	}
922}
923
924static void
925teken_subr_do_reset(teken_t *t)
926{
927
928	t->t_curattr = t->t_defattr;
929	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
930	t->t_stateflags = TS_AUTOWRAP;
931
932	teken_scs_set(t, 0, teken_scs_us_ascii);
933	teken_scs_set(t, 1, teken_scs_us_ascii);
934	teken_scs_switch(t, 0);
935
936	teken_subr_save_cursor(t);
937	teken_tab_default(t);
938}
939
940static void
941teken_subr_reset_to_initial_state(teken_t *t)
942{
943
944	teken_subr_do_reset(t);
945	teken_subr_erase_display(t, 2);
946	teken_funcs_param(t, TP_SHOWCURSOR, 1);
947	teken_funcs_cursor(t);
948}
949
950static void
951teken_subr_restore_cursor(teken_t *t)
952{
953
954	t->t_cursor = t->t_saved_cursor;
955	t->t_curattr = t->t_saved_curattr;
956	t->t_stateflags &= ~TS_WRAPPED;
957	teken_scs_restore(t);
958	teken_funcs_cursor(t);
959}
960
961static void
962teken_subr_reverse_index(teken_t *t)
963{
964
965	if (t->t_cursor.tp_row > t->t_scrollreg.ts_begin) {
966		t->t_cursor.tp_row--;
967		t->t_stateflags &= ~TS_WRAPPED;
968		teken_funcs_cursor(t);
969	} else {
970		teken_subr_do_scroll(t, -1);
971	}
972}
973
974static void
975teken_subr_save_cursor(teken_t *t)
976{
977
978	t->t_saved_cursor = t->t_cursor;
979	t->t_saved_curattr = t->t_curattr;
980	teken_scs_save(t);
981}
982
983static void
984teken_subr_secondary_device_attributes(teken_t *t, unsigned int request)
985{
986
987	if (request == 0) {
988		const char response[] = "\x1B[>0;10;0c";
989		teken_funcs_respond(t, response, sizeof response - 1);
990	} else {
991		teken_printf("Unknown DA2\n");
992	}
993}
994
995static void
996teken_subr_set_dec_mode(teken_t *t, unsigned int cmd)
997{
998
999	switch (cmd) {
1000	case 1: /* Cursor keys mode. */
1001		teken_funcs_param(t, TP_CURSORKEYS, 1);
1002		break;
1003	case 2: /* DECANM: ANSI/VT52 mode. */
1004		teken_printf("DECSET VT52\n");
1005		break;
1006	case 3: /* 132 column mode. */
1007		teken_funcs_param(t, TP_132COLS, 1);
1008		teken_subr_reset_to_initial_state(t);
1009		break;
1010	case 5: /* Inverse video. */
1011		teken_printf("DECSET inverse video\n");
1012		break;
1013	case 6: /* Origin mode. */
1014		t->t_stateflags |= TS_ORIGIN;
1015		t->t_originreg = t->t_scrollreg;
1016		t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
1017		t->t_cursor.tp_col = 0;
1018		t->t_stateflags &= ~TS_WRAPPED;
1019		teken_funcs_cursor(t);
1020		break;
1021	case 7: /* Autowrap mode. */
1022		t->t_stateflags |= TS_AUTOWRAP;
1023		break;
1024	case 8: /* Autorepeat mode. */
1025		teken_funcs_param(t, TP_AUTOREPEAT, 1);
1026		break;
1027	case 25: /* Display cursor. */
1028		teken_funcs_param(t, TP_SHOWCURSOR, 1);
1029		break;
1030	case 40: /* Allow 132 columns. */
1031		teken_printf("DECSET allow 132\n");
1032		break;
1033	case 45: /* Enable reverse wraparound. */
1034		teken_printf("DECSET reverse wraparound\n");
1035		break;
1036	case 47: /* Switch to alternate buffer. */
1037		teken_printf("Switch away from alternate buffer\n");
1038		break;
1039	default:
1040		teken_printf("Unknown DECSET: %u\n", cmd);
1041	}
1042}
1043
1044static void
1045teken_subr_set_mode(teken_t *t, unsigned int cmd)
1046{
1047
1048	switch (cmd) {
1049	case 4:
1050		teken_printf("Insert mode\n");
1051		t->t_stateflags |= TS_INSERT;
1052		break;
1053	default:
1054		teken_printf("Unknown set mode: %u\n", cmd);
1055	}
1056}
1057
1058static void
1059teken_subr_set_graphic_rendition(teken_t *t, unsigned int ncmds,
1060    unsigned int cmds[])
1061{
1062	unsigned int i, n;
1063
1064	/* No attributes means reset. */
1065	if (ncmds == 0) {
1066		t->t_curattr = t->t_defattr;
1067		return;
1068	}
1069
1070	for (i = 0; i < ncmds; i++) {
1071		n = cmds[i];
1072
1073		switch (n) {
1074		case 0: /* Reset. */
1075			t->t_curattr = t->t_defattr;
1076			break;
1077		case 1: /* Bold. */
1078			t->t_curattr.ta_format |= TF_BOLD;
1079			break;
1080		case 4: /* Underline. */
1081			t->t_curattr.ta_format |= TF_UNDERLINE;
1082			break;
1083		case 5: /* Blink. */
1084			t->t_curattr.ta_format |= TF_BLINK;
1085			break;
1086		case 7: /* Reverse. */
1087			t->t_curattr.ta_format |= TF_REVERSE;
1088			break;
1089		case 22: /* Remove bold. */
1090			t->t_curattr.ta_format &= ~TF_BOLD;
1091			break;
1092		case 24: /* Remove underline. */
1093			t->t_curattr.ta_format &= ~TF_UNDERLINE;
1094			break;
1095		case 25: /* Remove blink. */
1096			t->t_curattr.ta_format &= ~TF_BLINK;
1097			break;
1098		case 27: /* Remove reverse. */
1099			t->t_curattr.ta_format &= ~TF_REVERSE;
1100			break;
1101		case 30: /* Set foreground color: black */
1102		case 31: /* Set foreground color: red */
1103		case 32: /* Set foreground color: green */
1104		case 33: /* Set foreground color: brown */
1105		case 34: /* Set foreground color: blue */
1106		case 35: /* Set foreground color: magenta */
1107		case 36: /* Set foreground color: cyan */
1108		case 37: /* Set foreground color: white */
1109			t->t_curattr.ta_fgcolor = n - 30;
1110			break;
1111		case 39: /* Set default foreground color. */
1112			t->t_curattr.ta_fgcolor = t->t_defattr.ta_fgcolor;
1113			break;
1114		case 40: /* Set background color: black */
1115		case 41: /* Set background color: red */
1116		case 42: /* Set background color: green */
1117		case 43: /* Set background color: brown */
1118		case 44: /* Set background color: blue */
1119		case 45: /* Set background color: magenta */
1120		case 46: /* Set background color: cyan */
1121		case 47: /* Set background color: white */
1122			t->t_curattr.ta_bgcolor = n - 40;
1123			break;
1124		case 49: /* Set default background color. */
1125			t->t_curattr.ta_bgcolor = t->t_defattr.ta_bgcolor;
1126			break;
1127		default:
1128			teken_printf("unsupported attribute %u\n", n);
1129		}
1130	}
1131}
1132
1133static void
1134teken_subr_set_top_and_bottom_margins(teken_t *t, unsigned int top,
1135    unsigned int bottom)
1136{
1137
1138	/* Adjust top row number. */
1139	if (top > 0)
1140		top--;
1141	/* Adjust bottom row number. */
1142	if (bottom == 0 || bottom > t->t_winsize.tp_row)
1143		bottom = t->t_winsize.tp_row;
1144
1145	/* Invalid arguments. */
1146	if (top >= bottom - 1) {
1147		top = 0;
1148		bottom = t->t_winsize.tp_row;
1149	}
1150
1151	t->t_scrollreg.ts_begin = top;
1152	t->t_scrollreg.ts_end = bottom;
1153	if (t->t_stateflags & TS_ORIGIN) {
1154		/* XXX: home cursor? */
1155		t->t_originreg = t->t_scrollreg;
1156		t->t_cursor.tp_row = t->t_originreg.ts_begin;
1157		t->t_cursor.tp_col = 0;
1158		t->t_stateflags &= ~TS_WRAPPED;
1159		teken_funcs_cursor(t);
1160	}
1161}
1162
1163static void
1164teken_subr_single_height_double_width_line(teken_t *t __unused)
1165{
1166
1167	teken_printf("single height double width???\n");
1168}
1169
1170static void
1171teken_subr_single_height_single_width_line(teken_t *t __unused)
1172{
1173
1174	teken_printf("single height single width???\n");
1175}
1176
1177static void
1178teken_subr_string_terminator(teken_t *t __unused)
1179{
1180
1181	teken_printf("string terminator???\n");
1182}
1183
1184static void
1185teken_subr_tab_clear(teken_t *t, unsigned int cmd)
1186{
1187
1188	switch (cmd) {
1189	case 0:
1190		teken_tab_clear(t, t->t_cursor.tp_col);
1191		break;
1192	case 3:
1193		memset(&t->t_tabstops, 0, T_NUMCOL / 8);
1194		break;
1195	}
1196}
1197
1198static void
1199teken_subr_vertical_position_absolute(teken_t *t, unsigned int row)
1200{
1201
1202	t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
1203	if (row >= t->t_originreg.ts_end)
1204		t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
1205
1206
1207	t->t_stateflags &= ~TS_WRAPPED;
1208	teken_funcs_cursor(t);
1209}
1210