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