teken_subr.h revision 186798
1/*-
2 * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/syscons/teken/teken_subr.h 186798 2009-01-05 22:09:46Z ed $
27 */
28
29static void teken_subr_cursor_up(teken_t *, unsigned int);
30static void teken_subr_erase_line(teken_t *, unsigned int);
31static void teken_subr_regular_character(teken_t *, teken_char_t);
32static void teken_subr_reset_to_initial_state(teken_t *);
33
34static inline int
35teken_tab_isset(teken_t *t, unsigned int col)
36{
37	unsigned int b, o;
38
39	teken_assert(col <= T_NUMCOL);
40
41	b = col / (sizeof(unsigned int) * 8);
42	o = col % (sizeof(unsigned int) * 8);
43
44	return (t->t_tabstops[b] & (1 << o));
45}
46
47static inline void
48teken_tab_clear(teken_t *t, unsigned int col)
49{
50	unsigned int b, o;
51
52	teken_assert(col <= T_NUMCOL);
53
54	b = col / (sizeof(unsigned int) * 8);
55	o = col % (sizeof(unsigned int) * 8);
56
57	t->t_tabstops[b] &= ~(1 << o);
58}
59
60static inline void
61teken_tab_set(teken_t *t, unsigned int col)
62{
63	unsigned int b, o;
64
65	teken_assert(col <= T_NUMCOL);
66
67	b = col / (sizeof(unsigned int) * 8);
68	o = col % (sizeof(unsigned int) * 8);
69
70	t->t_tabstops[b] |= 1 << o;
71}
72
73static void
74teken_tab_default(teken_t *t)
75{
76	unsigned int i;
77
78	memset(&t->t_tabstops, 0, T_NUMCOL / 8);
79
80	for (i = 8; i < T_NUMCOL; i += 8)
81		teken_tab_set(t, i);
82}
83
84static void
85teken_subr_do_scroll(teken_t *t, int amount)
86{
87	teken_rect_t tr;
88	teken_pos_t tp;
89
90	teken_assert(t->t_cursor.tp_row <= t->t_winsize.tp_row);
91	teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
92	teken_assert(amount != 0);
93
94	/* Copy existing data 1 line up. */
95	if (amount > 0) {
96		/* Scroll down. */
97
98		/* Copy existing data up. */
99		if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
100			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin + amount;
101			tr.tr_begin.tp_col = 0;
102			tr.tr_end.tp_row = t->t_scrollreg.ts_end;
103			tr.tr_end.tp_col = t->t_winsize.tp_col;
104			tp.tp_row = t->t_scrollreg.ts_begin;
105			tp.tp_col = 0;
106			teken_funcs_copy(t, &tr, &tp);
107
108			tr.tr_begin.tp_row = t->t_scrollreg.ts_end - amount;
109		} else {
110			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
111		}
112
113		/* Clear the last lines. */
114		tr.tr_begin.tp_col = 0;
115		tr.tr_end.tp_row = t->t_scrollreg.ts_end;
116		tr.tr_end.tp_col = t->t_winsize.tp_col;
117		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
118	} else {
119		/* Scroll up. */
120		amount = -amount;
121
122		/* Copy existing data down. */
123		if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) {
124			tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
125			tr.tr_begin.tp_col = 0;
126			tr.tr_end.tp_row = t->t_scrollreg.ts_end - amount;
127			tr.tr_end.tp_col = t->t_winsize.tp_col;
128			tp.tp_row = t->t_scrollreg.ts_begin + amount;
129			tp.tp_col = 0;
130			teken_funcs_copy(t, &tr, &tp);
131
132			tr.tr_end.tp_row = t->t_scrollreg.ts_begin + amount;
133		} else {
134			tr.tr_end.tp_row = t->t_scrollreg.ts_end;
135		}
136
137		/* Clear the first lines. */
138		tr.tr_begin.tp_row = t->t_scrollreg.ts_begin;
139		tr.tr_begin.tp_col = 0;
140		tr.tr_end.tp_col = t->t_winsize.tp_col;
141		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
142	}
143}
144
145static ssize_t
146teken_subr_do_cpr(teken_t *t, unsigned int cmd, char response[16])
147{
148
149	switch (cmd) {
150	case 5: /* Operating status. */
151		strcpy(response, "0n");
152		return (2);
153	case 6: { /* Cursor position. */
154		int len;
155
156		len = snprintf(response, 16, "%u;%uR",
157		    (t->t_cursor.tp_row - t->t_originreg.ts_begin) + 1,
158		    t->t_cursor.tp_col + 1);
159
160		if (len >= 16)
161			return (-1);
162		return (len);
163	}
164	case 15: /* Printer status. */
165		strcpy(response, "13n");
166		return (3);
167	case 25: /* UDK status. */
168		strcpy(response, "20n");
169		return (3);
170	case 26: /* Keyboard status. */
171		strcpy(response, "27;1n");
172		return (5);
173	default:
174		teken_printf("Unknown DSR\n");
175		return (-1);
176	}
177}
178
179static void
180teken_subr_alignment_test(teken_t *t)
181{
182	teken_rect_t tr;
183
184	t->t_scrollreg.ts_begin = 0;
185	t->t_scrollreg.ts_end = t->t_winsize.tp_row;
186
187	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
188	t->t_stateflags &= ~TS_WRAPPED;
189	teken_funcs_cursor(t);
190
191	tr.tr_begin.tp_row = 0;
192	tr.tr_begin.tp_col = 0;
193	tr.tr_end = t->t_winsize;
194	teken_funcs_fill(t, &tr, 'E', &t->t_defattr);
195}
196
197static void
198teken_subr_backspace(teken_t *t)
199{
200
201#ifdef TEKEN_CONS25
202	if (t->t_cursor.tp_col == 0) {
203		if (t->t_cursor.tp_row == t->t_originreg.ts_begin)
204			return;
205		t->t_cursor.tp_row--;
206		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
207	} else {
208		t->t_cursor.tp_col--;
209	}
210#else /* !TEKEN_CONS25 */
211	if (t->t_cursor.tp_col == 0)
212		return;
213
214	t->t_cursor.tp_col--;
215	t->t_stateflags &= ~TS_WRAPPED;
216#endif /* TEKEN_CONS25 */
217
218	teken_funcs_cursor(t);
219}
220
221static void
222teken_subr_bell(teken_t *t)
223{
224
225	teken_funcs_bell(t);
226}
227
228static void
229teken_subr_carriage_return(teken_t *t)
230{
231
232	t->t_cursor.tp_col = 0;
233	t->t_stateflags &= ~TS_WRAPPED;
234	teken_funcs_cursor(t);
235}
236
237static void
238teken_subr_cursor_backward(teken_t *t, unsigned int ncols)
239{
240
241	if (ncols > t->t_cursor.tp_col)
242		t->t_cursor.tp_col = 0;
243	else
244		t->t_cursor.tp_col -= ncols;
245	t->t_stateflags &= ~TS_WRAPPED;
246	teken_funcs_cursor(t);
247}
248
249static void
250teken_subr_cursor_backward_tabulation(teken_t *t, unsigned int ntabs)
251{
252
253	do {
254		/* Stop when we've reached the beginning of the line. */
255		if (t->t_cursor.tp_col == 0)
256			break;
257
258		t->t_cursor.tp_col--;
259
260		/* Tab marker set. */
261		if (teken_tab_isset(t, t->t_cursor.tp_col))
262			ntabs--;
263	} while (ntabs > 0);
264
265	teken_funcs_cursor(t);
266}
267
268static void
269teken_subr_cursor_down(teken_t *t, unsigned int nrows)
270{
271
272	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end)
273		t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
274	else
275		t->t_cursor.tp_row += nrows;
276	t->t_stateflags &= ~TS_WRAPPED;
277	teken_funcs_cursor(t);
278}
279
280static void
281teken_subr_cursor_forward(teken_t *t, unsigned int ncols)
282{
283
284	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
285		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
286	else
287		t->t_cursor.tp_col += ncols;
288	t->t_stateflags &= ~TS_WRAPPED;
289	teken_funcs_cursor(t);
290}
291
292static void
293teken_subr_cursor_forward_tabulation(teken_t *t, unsigned int ntabs)
294{
295
296	do {
297		/* Stop when we've reached the end of the line. */
298		if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1)
299			break;
300
301		t->t_cursor.tp_col++;
302
303		/* Tab marker set. */
304		if (teken_tab_isset(t, t->t_cursor.tp_col))
305			ntabs--;
306	} while (ntabs > 0);
307
308	teken_funcs_cursor(t);
309}
310
311static void
312teken_subr_cursor_next_line(teken_t *t, unsigned int ncols)
313{
314
315	t->t_cursor.tp_col = 0;
316	teken_subr_cursor_down(t, ncols);
317}
318
319static void
320teken_subr_cursor_position(teken_t *t, unsigned int row, unsigned int col)
321{
322
323	t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
324	if (row >= t->t_originreg.ts_end)
325		t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
326
327	t->t_cursor.tp_col = col - 1;
328	if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
329		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
330
331	t->t_stateflags &= ~TS_WRAPPED;
332	teken_funcs_cursor(t);
333}
334
335static void
336teken_subr_cursor_position_report(teken_t *t, unsigned int cmd)
337{
338	char response[18] = "\x1B[";
339	ssize_t len;
340
341	len = teken_subr_do_cpr(t, cmd, response + 2);
342	if (len < 0)
343		return;
344
345	teken_funcs_respond(t, response, len + 2);
346}
347
348static void
349teken_subr_cursor_previous_line(teken_t *t, unsigned int ncols)
350{
351
352	t->t_cursor.tp_col = 0;
353	teken_subr_cursor_up(t, ncols);
354}
355
356static void
357teken_subr_cursor_up(teken_t *t, unsigned int nrows)
358{
359
360	if (t->t_scrollreg.ts_begin + nrows >= t->t_cursor.tp_row)
361		t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
362	else
363		t->t_cursor.tp_row -= nrows;
364	t->t_stateflags &= ~TS_WRAPPED;
365	teken_funcs_cursor(t);
366}
367
368static void
369teken_subr_delete_character(teken_t *t, unsigned int ncols)
370{
371	teken_rect_t tr;
372
373	tr.tr_begin.tp_row = t->t_cursor.tp_row;
374	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
375	tr.tr_end.tp_col = t->t_winsize.tp_col;
376
377	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
378		tr.tr_begin.tp_col = t->t_cursor.tp_col;
379	} else {
380		/* Copy characters to the left. */
381		tr.tr_begin.tp_col = t->t_cursor.tp_col + ncols;
382		teken_funcs_copy(t, &tr, &t->t_cursor);
383
384		tr.tr_begin.tp_col = t->t_winsize.tp_col - ncols;
385	}
386
387	/* Blank trailing columns. */
388	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
389}
390
391static void
392teken_subr_delete_line(teken_t *t, unsigned int nrows)
393{
394	teken_rect_t tr;
395
396	tr.tr_begin.tp_col = 0;
397	tr.tr_end.tp_row = t->t_scrollreg.ts_end;
398	tr.tr_end.tp_col = t->t_winsize.tp_col;
399
400	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
401		tr.tr_begin.tp_row = t->t_cursor.tp_row;
402	} else {
403		teken_pos_t tp;
404
405		/* Copy rows up. */
406		tr.tr_begin.tp_row = t->t_cursor.tp_row + nrows;
407		tp.tp_row = t->t_cursor.tp_row;
408		tp.tp_col = 0;
409		teken_funcs_copy(t, &tr, &tp);
410
411		tr.tr_begin.tp_row = t->t_scrollreg.ts_end - nrows;
412	}
413
414	/* Blank trailing rows. */
415	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
416}
417
418static void
419teken_subr_device_control_string(teken_t *t __unused)
420{
421
422	teken_printf("device control string???\n");
423}
424
425static void
426teken_subr_device_status_report(teken_t *t, unsigned int cmd)
427{
428	char response[19] = "\x1B[?";
429	ssize_t len;
430
431	len = teken_subr_do_cpr(t, cmd, response + 3);
432	if (len < 0)
433		return;
434
435	teken_funcs_respond(t, response, len + 3);
436}
437
438static void
439teken_subr_double_height_double_width_line_top(teken_t *t __unused)
440{
441
442	teken_printf("double height double width top\n");
443}
444
445static void
446teken_subr_double_height_double_width_line_bottom(teken_t *t __unused)
447{
448
449	teken_printf("double height double width bottom\n");
450}
451
452static void
453teken_subr_erase_character(teken_t *t, unsigned int ncols)
454{
455	teken_rect_t tr;
456
457	tr.tr_begin = t->t_cursor;
458	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
459
460	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
461		tr.tr_end.tp_col = t->t_winsize.tp_col;
462	else
463		tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
464
465	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
466}
467
468static void
469teken_subr_erase_display(teken_t *t, unsigned int mode)
470{
471	teken_rect_t r;
472
473	r.tr_begin.tp_col = 0;
474	r.tr_end.tp_col = t->t_winsize.tp_col;
475
476	switch (mode) {
477	case 1: /* Erase from the top to the cursor. */
478		teken_subr_erase_line(t, 1);
479
480		/* Erase lines above. */
481		if (t->t_cursor.tp_row == 0)
482			return;
483		r.tr_begin.tp_row = 0;
484		r.tr_end.tp_row = t->t_cursor.tp_row;
485		break;
486	case 2: /* Erase entire display. */
487		r.tr_begin.tp_row = 0;
488		r.tr_end.tp_row = t->t_winsize.tp_row;
489		break;
490	default: /* Erase from cursor to the bottom. */
491		teken_subr_erase_line(t, 0);
492
493		/* Erase lines below. */
494		if (t->t_cursor.tp_row == t->t_winsize.tp_row - 1)
495			return;
496		r.tr_begin.tp_row = t->t_cursor.tp_row + 1;
497		r.tr_end.tp_row = t->t_winsize.tp_row;
498		break;
499	}
500
501	teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
502}
503
504static void
505teken_subr_erase_line(teken_t *t, unsigned int mode)
506{
507	teken_rect_t r;
508
509	r.tr_begin.tp_row = t->t_cursor.tp_row;
510	r.tr_end.tp_row = t->t_cursor.tp_row + 1;
511
512	switch (mode) {
513	case 1: /* Erase from the beginning of the line to the cursor. */
514		r.tr_begin.tp_col = 0;
515		r.tr_end.tp_col = t->t_cursor.tp_col + 1;
516		break;
517	case 2: /* Erase entire line. */
518		r.tr_begin.tp_col = 0;
519		r.tr_end.tp_col = t->t_winsize.tp_col;
520		break;
521	default: /* Erase from cursor to the end of the line. */
522		r.tr_begin.tp_col = t->t_cursor.tp_col;
523		r.tr_end.tp_col = t->t_winsize.tp_col;
524		break;
525	}
526
527	teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
528}
529
530static void
531teken_subr_horizontal_position_absolute(teken_t *t, unsigned int col)
532{
533
534	t->t_cursor.tp_col = col - 1;
535	if (t->t_cursor.tp_col >= t->t_winsize.tp_col)
536		t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
537
538	t->t_stateflags &= ~TS_WRAPPED;
539	teken_funcs_cursor(t);
540}
541
542static void
543teken_subr_horizontal_tab(teken_t *t)
544{
545#ifdef TEKEN_CONS25
546
547	teken_subr_cursor_forward_tabulation(t, 1);
548#else /* !TEKEN_CONS25 */
549	teken_rect_t tr;
550
551	tr.tr_begin = t->t_cursor;
552	teken_subr_cursor_forward_tabulation(t, 1);
553	tr.tr_end.tp_row = tr.tr_begin.tp_row + 1;
554	tr.tr_end.tp_col = t->t_cursor.tp_col;
555
556	/* Blank region that we skipped. */
557	if (tr.tr_end.tp_col > tr.tr_begin.tp_col)
558		teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
559#endif /* TEKEN_CONS25 */
560}
561
562static void
563teken_subr_horizontal_tab_set(teken_t *t)
564{
565
566	teken_tab_set(t, t->t_cursor.tp_col);
567}
568
569static void
570teken_subr_index(teken_t *t)
571{
572
573	if (t->t_cursor.tp_row < t->t_scrollreg.ts_end - 1) {
574		t->t_cursor.tp_row++;
575		t->t_stateflags &= ~TS_WRAPPED;
576		teken_funcs_cursor(t);
577	} else {
578		teken_subr_do_scroll(t, 1);
579	}
580}
581
582static void
583teken_subr_insert_character(teken_t *t, unsigned int ncols)
584{
585	teken_rect_t tr;
586
587	tr.tr_begin = t->t_cursor;
588	tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
589
590	if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
591		tr.tr_end.tp_col = t->t_winsize.tp_col;
592	} else {
593		teken_pos_t tp;
594
595		/* Copy characters to the right. */
596		tr.tr_end.tp_col = t->t_winsize.tp_col - ncols;
597		tp.tp_row = t->t_cursor.tp_row;
598		tp.tp_col = t->t_cursor.tp_col + ncols;
599		teken_funcs_copy(t, &tr, &tp);
600
601		tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
602	}
603
604	/* Blank current location. */
605	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
606}
607
608static void
609teken_subr_insert_line(teken_t *t, unsigned int nrows)
610{
611	teken_rect_t tr;
612
613	tr.tr_begin.tp_row = t->t_cursor.tp_row;
614	tr.tr_begin.tp_col = 0;
615	tr.tr_end.tp_col = t->t_winsize.tp_col;
616
617	if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
618		tr.tr_end.tp_row = t->t_scrollreg.ts_end;
619	} else {
620		teken_pos_t tp;
621
622		/* Copy lines down. */
623		tr.tr_end.tp_row = t->t_scrollreg.ts_end - nrows;
624		tp.tp_row = t->t_cursor.tp_row + nrows;
625		tp.tp_col = 0;
626		teken_funcs_copy(t, &tr, &tp);
627
628		tr.tr_end.tp_row = t->t_cursor.tp_row + nrows;
629	}
630
631	/* Blank current location. */
632	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
633}
634
635static void
636teken_subr_keypad_application_mode(teken_t *t)
637{
638
639	teken_funcs_param(t, TP_KEYPADAPP, 1);
640}
641
642static void
643teken_subr_keypad_numeric_mode(teken_t *t)
644{
645
646	teken_funcs_param(t, TP_KEYPADAPP, 0);
647}
648
649static void
650teken_subr_newline(teken_t *t)
651{
652
653	t->t_cursor.tp_row++;
654
655	if (t->t_cursor.tp_row >= t->t_scrollreg.ts_end) {
656		teken_subr_do_scroll(t, 1);
657		t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
658	}
659
660	t->t_stateflags &= ~TS_WRAPPED;
661	teken_funcs_cursor(t);
662}
663
664static void
665teken_subr_newpage(teken_t *t)
666{
667#ifdef TEKEN_CONS25
668	teken_rect_t tr;
669
670	tr.tr_begin.tp_row = tr.tr_begin.tp_col = 0;
671	tr.tr_end = t->t_winsize;
672	teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
673
674	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
675	teken_funcs_cursor(t);
676#else /* !TEKEN_CONS25 */
677
678	teken_subr_newline(t);
679#endif /* TEKEN_CONS25 */
680}
681
682static void
683teken_subr_next_line(teken_t *t)
684{
685
686	t->t_cursor.tp_col = 0;
687	teken_subr_newline(t);
688}
689
690static void
691teken_subr_pan_down(teken_t *t, unsigned int nrows)
692{
693
694	teken_subr_do_scroll(t, (int)nrows);
695}
696
697static void
698teken_subr_pan_up(teken_t *t, unsigned int nrows)
699{
700
701	teken_subr_do_scroll(t, -(int)nrows);
702}
703
704static void
705teken_subr_primary_device_attributes(teken_t *t, unsigned int request)
706{
707
708	if (request == 0) {
709		const char response[] = "\x1B[?1;2c";
710
711		teken_funcs_respond(t, response, sizeof response - 1);
712	} else {
713		teken_printf("Unknown DA1\n");
714	}
715}
716
717static void
718teken_subr_do_putchar(teken_t *t, const teken_pos_t *tp, teken_char_t c,
719    int width)
720{
721
722	if (t->t_stateflags & TS_INSERT &&
723	    tp->tp_col < t->t_winsize.tp_col - width) {
724		teken_rect_t ctr;
725		teken_pos_t ctp;
726
727		/* Insert mode. Move existing characters to the right. */
728		ctr.tr_begin = *tp;
729		ctr.tr_end.tp_row = tp->tp_row + 1;
730		ctr.tr_end.tp_col = t->t_winsize.tp_col - width;
731		ctp.tp_row = tp->tp_row;
732		ctp.tp_col = tp->tp_col + width;
733		teken_funcs_copy(t, &ctr, &ctp);
734	}
735
736	teken_funcs_putchar(t, tp, c, &t->t_curattr);
737}
738
739static void
740teken_subr_regular_character(teken_t *t, teken_char_t c)
741{
742	int width;
743
744	/* XXX: Don't process zero-width characters yet. */
745	width = teken_wcwidth(c);
746	if (width <= 0)
747		return;
748
749#ifdef TEKEN_CONS25
750	teken_subr_do_putchar(t, &t->t_cursor, c, width);
751	t->t_cursor.tp_col += width;
752
753	if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
754		if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
755			/* Perform scrolling. */
756			teken_subr_do_scroll(t, 1);
757		} else {
758			/* No scrolling needed. */
759			if (t->t_cursor.tp_row < t->t_winsize.tp_row - 1)
760				t->t_cursor.tp_row++;
761		}
762		t->t_cursor.tp_col = 0;
763	}
764#else /* !TEKEN_CONS25 */
765	if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1 &&
766	    (t->t_stateflags & (TS_WRAPPED|TS_AUTOWRAP)) ==
767	    (TS_WRAPPED|TS_AUTOWRAP)) {
768		teken_pos_t tp;
769
770		/* Perform line wrapping. */
771
772		if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
773			/* Perform scrolling. */
774			teken_subr_do_scroll(t, 1);
775			tp.tp_row = t->t_scrollreg.ts_end - 1;
776		} else {
777			/* No scrolling needed. */
778			tp.tp_row = t->t_cursor.tp_row + 1;
779			if (tp.tp_row == t->t_winsize.tp_row) {
780				/*
781				 * Corner case: regular character
782				 * outside scrolling region, but at the
783				 * bottom of the screen.
784				 */
785				teken_subr_do_putchar(t, &t->t_cursor,
786				    c, width);
787				return;
788			}
789		}
790
791		tp.tp_col = 0;
792		teken_subr_do_putchar(t, &tp, c, width);
793
794		t->t_cursor.tp_row = tp.tp_row;
795		t->t_cursor.tp_col = width;
796		t->t_stateflags &= ~TS_WRAPPED;
797	} else {
798		/* No line wrapping needed. */
799		teken_subr_do_putchar(t, &t->t_cursor, c, width);
800		t->t_cursor.tp_col += width;
801
802		if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
803			t->t_stateflags |= TS_WRAPPED;
804			t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
805		} else {
806			t->t_stateflags &= ~TS_WRAPPED;
807		}
808	}
809#endif /* TEKEN_CONS25 */
810
811	teken_funcs_cursor(t);
812}
813
814static void
815teken_subr_reset_dec_mode(teken_t *t, unsigned int cmd)
816{
817
818	switch (cmd) {
819	case 1: /* Cursor keys mode. */
820		teken_funcs_param(t, TP_CURSORKEYS, 0);
821		break;
822	case 2: /* DECANM: ANSI/VT52 mode. */
823		teken_printf("DECRST VT52\n");
824		break;
825	case 3: /* 132 column mode. */
826		teken_funcs_param(t, TP_132COLS, 0);
827		teken_subr_reset_to_initial_state(t);
828		break;
829	case 5: /* Inverse video. */
830		teken_printf("DECRST inverse video\n");
831		break;
832	case 6: /* Origin mode. */
833		t->t_stateflags &= ~TS_ORIGIN;
834		t->t_originreg.ts_begin = 0;
835		t->t_originreg.ts_end = t->t_winsize.tp_row;
836		t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
837		t->t_stateflags &= ~TS_WRAPPED;
838		teken_funcs_cursor(t);
839		break;
840	case 7: /* Autowrap mode. */
841		t->t_stateflags &= ~TS_AUTOWRAP;
842		break;
843	case 8: /* Autorepeat mode. */
844		teken_funcs_param(t, TP_AUTOREPEAT, 0);
845		break;
846	case 25: /* Hide cursor. */
847		teken_funcs_param(t, TP_SHOWCURSOR, 0);
848		break;
849	case 40: /* Disallow 132 columns. */
850		teken_printf("DECRST allow 132\n");
851		break;
852	case 45: /* Disable reverse wraparound. */
853		teken_printf("DECRST reverse wraparound\n");
854		break;
855	case 47: /* Switch to alternate buffer. */
856		teken_printf("Switch to alternate buffer\n");
857		break;
858	default:
859		teken_printf("Unknown DECRST: %u\n", cmd);
860	}
861}
862
863static void
864teken_subr_reset_mode(teken_t *t, unsigned int cmd)
865{
866
867	switch (cmd) {
868	case 4:
869		t->t_stateflags &= ~TS_INSERT;
870		break;
871	default:
872		teken_printf("Unknown reset mode: %u\n", cmd);
873	}
874}
875
876static void
877teken_subr_do_reset(teken_t *t)
878{
879
880	t->t_curattr = t->t_saved_curattr = t->t_defattr;
881	t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
882	t->t_saved_cursor = t->t_cursor;
883	t->t_stateflags = TS_AUTOWRAP;
884
885	teken_tab_default(t);
886}
887
888static void
889teken_subr_reset_to_initial_state(teken_t *t)
890{
891
892	teken_subr_do_reset(t);
893	teken_subr_erase_display(t, 2);
894	teken_funcs_param(t, TP_SHOWCURSOR, 1);
895	teken_funcs_cursor(t);
896}
897
898static void
899teken_subr_restore_cursor(teken_t *t)
900{
901
902	t->t_cursor = t->t_saved_cursor;
903	t->t_curattr = t->t_saved_curattr;
904	t->t_stateflags &= ~TS_WRAPPED;
905	teken_funcs_cursor(t);
906}
907
908static void
909teken_subr_reverse_index(teken_t *t)
910{
911
912	if (t->t_cursor.tp_row > t->t_scrollreg.ts_begin) {
913		t->t_cursor.tp_row--;
914		t->t_stateflags &= ~TS_WRAPPED;
915		teken_funcs_cursor(t);
916	} else {
917		teken_subr_do_scroll(t, -1);
918	}
919}
920
921static void
922teken_subr_save_cursor(teken_t *t)
923{
924
925	t->t_saved_cursor = t->t_cursor;
926	t->t_saved_curattr = t->t_curattr;
927}
928
929static void
930teken_subr_scs(teken_t *t __unused)
931{
932
933	teken_printf("scs???\n");
934}
935
936static void
937teken_subr_secondary_device_attributes(teken_t *t, unsigned int request)
938{
939
940	if (request == 0) {
941		const char response[] = "\x1B[>0;10;0c";
942		teken_funcs_respond(t, response, sizeof response - 1);
943	} else {
944		teken_printf("Unknown DA2\n");
945	}
946}
947
948static void
949teken_subr_set_dec_mode(teken_t *t, unsigned int cmd)
950{
951
952	switch (cmd) {
953	case 1: /* Cursor keys mode. */
954		teken_funcs_param(t, TP_CURSORKEYS, 1);
955		break;
956	case 2: /* DECANM: ANSI/VT52 mode. */
957		teken_printf("DECSET VT52\n");
958		break;
959	case 3: /* 132 column mode. */
960		teken_funcs_param(t, TP_132COLS, 1);
961		teken_subr_reset_to_initial_state(t);
962		break;
963	case 5: /* Inverse video. */
964		teken_printf("DECSET inverse video\n");
965		break;
966	case 6: /* Origin mode. */
967		t->t_stateflags |= TS_ORIGIN;
968		t->t_originreg = t->t_scrollreg;
969		t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
970		t->t_cursor.tp_col = 0;
971		t->t_stateflags &= ~TS_WRAPPED;
972		teken_funcs_cursor(t);
973		break;
974	case 7: /* Autowrap mode. */
975		t->t_stateflags |= TS_AUTOWRAP;
976		break;
977	case 8: /* Autorepeat mode. */
978		teken_funcs_param(t, TP_AUTOREPEAT, 1);
979		break;
980	case 25: /* Display cursor. */
981		teken_funcs_param(t, TP_SHOWCURSOR, 1);
982		break;
983	case 40: /* Allow 132 columns. */
984		teken_printf("DECSET allow 132\n");
985		break;
986	case 45: /* Enable reverse wraparound. */
987		teken_printf("DECSET reverse wraparound\n");
988		break;
989	case 47: /* Switch to alternate buffer. */
990		teken_printf("Switch away from alternate buffer\n");
991		break;
992	default:
993		teken_printf("Unknown DECSET: %u\n", cmd);
994	}
995}
996
997static void
998teken_subr_set_mode(teken_t *t, unsigned int cmd)
999{
1000
1001	switch (cmd) {
1002	case 4:
1003		teken_printf("Insert mode\n");
1004		t->t_stateflags |= TS_INSERT;
1005		break;
1006	default:
1007		teken_printf("Unknown set mode: %u\n", cmd);
1008	}
1009}
1010
1011static void
1012teken_subr_set_graphic_rendition(teken_t *t, unsigned int ncmds,
1013    unsigned int cmds[])
1014{
1015	unsigned int i, n;
1016
1017	/* No attributes means reset. */
1018	if (ncmds == 0) {
1019		t->t_curattr = t->t_defattr;
1020		return;
1021	}
1022
1023	for (i = 0; i < ncmds; i++) {
1024		n = cmds[i];
1025
1026		switch (n) {
1027		case 0: /* Reset. */
1028			t->t_curattr = t->t_defattr;
1029			break;
1030		case 1: /* Bold. */
1031			t->t_curattr.ta_format |= TF_BOLD;
1032			break;
1033		case 4: /* Underline. */
1034			t->t_curattr.ta_format |= TF_UNDERLINE;
1035			break;
1036		case 5: /* Blink. */
1037			t->t_curattr.ta_format |= TF_BLINK;
1038			break;
1039		case 7: /* Reverse. */
1040			t->t_curattr.ta_format |= TF_REVERSE;
1041			break;
1042		case 22: /* Remove bold. */
1043			t->t_curattr.ta_format &= ~TF_BOLD;
1044			break;
1045		case 24: /* Remove underline. */
1046			t->t_curattr.ta_format &= ~TF_UNDERLINE;
1047			break;
1048		case 25: /* Remove blink. */
1049			t->t_curattr.ta_format &= ~TF_BLINK;
1050			break;
1051		case 27: /* Remove reverse. */
1052			t->t_curattr.ta_format &= ~TF_REVERSE;
1053			break;
1054		case 30: /* Set foreground color: black */
1055		case 31: /* Set foreground color: red */
1056		case 32: /* Set foreground color: green */
1057		case 33: /* Set foreground color: brown */
1058		case 34: /* Set foreground color: blue */
1059		case 35: /* Set foreground color: magenta */
1060		case 36: /* Set foreground color: cyan */
1061		case 37: /* Set foreground color: white */
1062			t->t_curattr.ta_fgcolor = n - 30;
1063			break;
1064		case 39: /* Set default foreground color. */
1065			t->t_curattr.ta_fgcolor = t->t_defattr.ta_fgcolor;
1066			break;
1067		case 40: /* Set background color: black */
1068		case 41: /* Set background color: red */
1069		case 42: /* Set background color: green */
1070		case 43: /* Set background color: brown */
1071		case 44: /* Set background color: blue */
1072		case 45: /* Set background color: magenta */
1073		case 46: /* Set background color: cyan */
1074		case 47: /* Set background color: white */
1075			t->t_curattr.ta_bgcolor = n - 40;
1076			break;
1077		case 49: /* Set default background color. */
1078			t->t_curattr.ta_bgcolor = t->t_defattr.ta_bgcolor;
1079			break;
1080		default:
1081			teken_printf("unsupported attribute %u\n", n);
1082		}
1083	}
1084}
1085
1086static void
1087teken_subr_set_top_and_bottom_margins(teken_t *t, unsigned int top,
1088    unsigned int bottom)
1089{
1090
1091	/* Adjust top row number. */
1092	if (top > 0)
1093		top--;
1094	/* Adjust bottom row number. */
1095	if (bottom == 0 || bottom > t->t_winsize.tp_row)
1096		bottom = t->t_winsize.tp_row;
1097
1098	/* Invalid arguments. */
1099	if (top >= bottom - 1) {
1100		top = 0;
1101		bottom = t->t_winsize.tp_row;
1102	}
1103
1104	t->t_scrollreg.ts_begin = top;
1105	t->t_scrollreg.ts_end = bottom;
1106	if (t->t_stateflags & TS_ORIGIN) {
1107		/* XXX: home cursor? */
1108		t->t_originreg = t->t_scrollreg;
1109		t->t_cursor.tp_row = t->t_originreg.ts_begin;
1110		t->t_cursor.tp_col = 0;
1111		t->t_stateflags &= ~TS_WRAPPED;
1112		teken_funcs_cursor(t);
1113	}
1114}
1115
1116static void
1117teken_subr_single_height_double_width_line(teken_t *t __unused)
1118{
1119
1120	teken_printf("single height double width???\n");
1121}
1122
1123static void
1124teken_subr_single_height_single_width_line(teken_t *t __unused)
1125{
1126
1127	teken_printf("single height single width???\n");
1128}
1129
1130static void
1131teken_subr_string_terminator(teken_t *t __unused)
1132{
1133
1134	teken_printf("string terminator???\n");
1135}
1136
1137static void
1138teken_subr_tab_clear(teken_t *t, unsigned int cmd)
1139{
1140
1141	switch (cmd) {
1142	case 0:
1143		teken_tab_clear(t, t->t_cursor.tp_col);
1144		break;
1145	case 3:
1146		memset(&t->t_tabstops, 0, T_NUMCOL / 8);
1147		break;
1148	}
1149}
1150
1151static void
1152teken_subr_vertical_position_absolute(teken_t *t, unsigned int row)
1153{
1154
1155	t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1;
1156	if (row >= t->t_originreg.ts_end)
1157		t->t_cursor.tp_row = t->t_originreg.ts_end - 1;
1158
1159
1160	t->t_stateflags &= ~TS_WRAPPED;
1161	teken_funcs_cursor(t);
1162}
1163