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