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