Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/teken/teken_subr.h
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2008-2009 Ed Schouten <[email protected]>
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
29
static void teken_subr_cursor_up(teken_t *, unsigned int);
30
static void teken_subr_erase_line(const teken_t *, unsigned int);
31
static void teken_subr_regular_character(teken_t *, teken_char_t);
32
static void teken_subr_reset_to_initial_state(teken_t *);
33
static void teken_subr_save_cursor(teken_t *);
34
35
static inline int
36
teken_tab_isset(const 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] & (1U << o));
47
}
48
49
static inline void
50
teken_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] &= ~(1U << o);
61
}
62
63
static inline void
64
teken_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] |= 1U << o;
75
}
76
77
static void
78
teken_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
88
static void
89
teken_subr_do_scroll(const 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
149
static ssize_t
150
teken_subr_do_cpr(const 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
183
static void
184
teken_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
201
static void
202
teken_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
225
static void
226
teken_subr_bell(const teken_t *t)
227
{
228
229
teken_funcs_bell(t);
230
}
231
232
static void
233
teken_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
241
static void
242
teken_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
253
static void
254
teken_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
272
static void
273
teken_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
284
static void
285
teken_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
296
static void
297
teken_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
315
static void
316
teken_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
323
static void
324
teken_subr_cursor_position(teken_t *t, unsigned int row, unsigned int col)
325
{
326
327
row = (row - 1) + t->t_originreg.ts_begin;
328
t->t_cursor.tp_row = row < t->t_originreg.ts_end ?
329
row : t->t_originreg.ts_end - 1;
330
331
col--;
332
t->t_cursor.tp_col = col < t->t_winsize.tp_col ?
333
col : t->t_winsize.tp_col - 1;
334
335
t->t_stateflags &= ~TS_WRAPPED;
336
teken_funcs_cursor(t);
337
}
338
339
static void
340
teken_subr_cursor_position_report(const 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
352
static void
353
teken_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
360
static void
361
teken_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
372
static void
373
teken_subr_set_cursor_style(teken_t *t __unused, unsigned int style __unused)
374
{
375
376
/* TODO */
377
378
/*
379
* CSI Ps SP q
380
* Set cursor style (DECSCUSR), VT520.
381
* Ps = 0 -> blinking block.
382
* Ps = 1 -> blinking block (default).
383
* Ps = 2 -> steady block.
384
* Ps = 3 -> blinking underline.
385
* Ps = 4 -> steady underline.
386
* Ps = 5 -> blinking bar (xterm).
387
* Ps = 6 -> steady bar (xterm).
388
*/
389
}
390
391
static void
392
teken_subr_delete_character(const teken_t *t, unsigned int ncols)
393
{
394
teken_rect_t tr;
395
396
tr.tr_begin.tp_row = t->t_cursor.tp_row;
397
tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
398
tr.tr_end.tp_col = t->t_winsize.tp_col;
399
400
if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
401
tr.tr_begin.tp_col = t->t_cursor.tp_col;
402
} else {
403
/* Copy characters to the left. */
404
tr.tr_begin.tp_col = t->t_cursor.tp_col + ncols;
405
teken_funcs_copy(t, &tr, &t->t_cursor);
406
407
tr.tr_begin.tp_col = t->t_winsize.tp_col - ncols;
408
}
409
410
/* Blank trailing columns. */
411
teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
412
}
413
414
static void
415
teken_subr_delete_line(const teken_t *t, unsigned int nrows)
416
{
417
teken_rect_t tr;
418
419
/* Ignore if outside scrolling region. */
420
if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin ||
421
t->t_cursor.tp_row >= t->t_scrollreg.ts_end)
422
return;
423
424
tr.tr_begin.tp_col = 0;
425
tr.tr_end.tp_row = t->t_scrollreg.ts_end;
426
tr.tr_end.tp_col = t->t_winsize.tp_col;
427
428
if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
429
tr.tr_begin.tp_row = t->t_cursor.tp_row;
430
} else {
431
teken_pos_t tp;
432
433
/* Copy rows up. */
434
tr.tr_begin.tp_row = t->t_cursor.tp_row + nrows;
435
tp.tp_row = t->t_cursor.tp_row;
436
tp.tp_col = 0;
437
teken_funcs_copy(t, &tr, &tp);
438
439
tr.tr_begin.tp_row = t->t_scrollreg.ts_end - nrows;
440
}
441
442
/* Blank trailing rows. */
443
teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
444
}
445
446
static void
447
teken_subr_device_control_string(teken_t *t)
448
{
449
450
teken_printf("Unsupported device control string\n");
451
t->t_stateflags |= TS_INSTRING;
452
}
453
454
static void
455
teken_subr_device_status_report(const teken_t *t, unsigned int cmd)
456
{
457
char response[19] = "\x1B[?";
458
ssize_t len;
459
460
len = teken_subr_do_cpr(t, cmd, response + 3);
461
if (len < 0)
462
return;
463
464
teken_funcs_respond(t, response, len + 3);
465
}
466
467
static void
468
teken_subr_double_height_double_width_line_top(const teken_t *t)
469
{
470
471
(void)t;
472
teken_printf("double height double width top\n");
473
}
474
475
static void
476
teken_subr_double_height_double_width_line_bottom(const teken_t *t)
477
{
478
479
(void)t;
480
teken_printf("double height double width bottom\n");
481
}
482
483
static void
484
teken_subr_erase_character(const teken_t *t, unsigned int ncols)
485
{
486
teken_rect_t tr;
487
488
tr.tr_begin = t->t_cursor;
489
tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
490
491
if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col)
492
tr.tr_end.tp_col = t->t_winsize.tp_col;
493
else
494
tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
495
496
teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
497
}
498
499
static void
500
teken_subr_erase_display(const teken_t *t, unsigned int mode)
501
{
502
teken_rect_t r;
503
504
r.tr_begin.tp_col = 0;
505
r.tr_end.tp_col = t->t_winsize.tp_col;
506
507
switch (mode) {
508
case 1: /* Erase from the top to the cursor. */
509
teken_subr_erase_line(t, 1);
510
511
/* Erase lines above. */
512
if (t->t_cursor.tp_row == 0)
513
return;
514
r.tr_begin.tp_row = 0;
515
r.tr_end.tp_row = t->t_cursor.tp_row;
516
break;
517
case 2: /* Erase entire display. */
518
r.tr_begin.tp_row = 0;
519
r.tr_end.tp_row = t->t_winsize.tp_row;
520
break;
521
default: /* Erase from cursor to the bottom. */
522
teken_subr_erase_line(t, 0);
523
524
/* Erase lines below. */
525
if (t->t_cursor.tp_row == t->t_winsize.tp_row - 1)
526
return;
527
r.tr_begin.tp_row = t->t_cursor.tp_row + 1;
528
r.tr_end.tp_row = t->t_winsize.tp_row;
529
break;
530
}
531
532
teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
533
}
534
535
static void
536
teken_subr_erase_line(const teken_t *t, unsigned int mode)
537
{
538
teken_rect_t r;
539
540
r.tr_begin.tp_row = t->t_cursor.tp_row;
541
r.tr_end.tp_row = t->t_cursor.tp_row + 1;
542
543
switch (mode) {
544
case 1: /* Erase from the beginning of the line to the cursor. */
545
r.tr_begin.tp_col = 0;
546
r.tr_end.tp_col = t->t_cursor.tp_col + 1;
547
break;
548
case 2: /* Erase entire line. */
549
r.tr_begin.tp_col = 0;
550
r.tr_end.tp_col = t->t_winsize.tp_col;
551
break;
552
default: /* Erase from cursor to the end of the line. */
553
r.tr_begin.tp_col = t->t_cursor.tp_col;
554
r.tr_end.tp_col = t->t_winsize.tp_col;
555
break;
556
}
557
558
teken_funcs_fill(t, &r, BLANK, &t->t_curattr);
559
}
560
561
static void
562
teken_subr_g0_scs_special_graphics(teken_t *t)
563
{
564
565
t->t_scs[0] = teken_scs_special_graphics;
566
}
567
568
static void
569
teken_subr_g0_scs_uk_national(teken_t *t)
570
{
571
572
t->t_scs[0] = teken_scs_uk_national;
573
}
574
575
static void
576
teken_subr_g0_scs_us_ascii(teken_t *t)
577
{
578
579
t->t_scs[0] = teken_scs_us_ascii;
580
}
581
582
static void
583
teken_subr_g1_scs_special_graphics(teken_t *t)
584
{
585
586
t->t_scs[1] = teken_scs_special_graphics;
587
}
588
589
static void
590
teken_subr_g1_scs_uk_national(teken_t *t)
591
{
592
593
t->t_scs[1] = teken_scs_uk_national;
594
}
595
596
static void
597
teken_subr_g1_scs_us_ascii(teken_t *t)
598
{
599
600
t->t_scs[1] = teken_scs_us_ascii;
601
}
602
603
static void
604
teken_subr_horizontal_position_absolute(teken_t *t, unsigned int col)
605
{
606
607
col--;
608
t->t_cursor.tp_col = col < t->t_winsize.tp_col ?
609
col : t->t_winsize.tp_col - 1;
610
611
t->t_stateflags &= ~TS_WRAPPED;
612
teken_funcs_cursor(t);
613
}
614
615
static void
616
teken_subr_horizontal_tab(teken_t *t)
617
{
618
619
teken_subr_cursor_forward_tabulation(t, 1);
620
}
621
622
static void
623
teken_subr_horizontal_tab_set(teken_t *t)
624
{
625
626
teken_tab_set(t, t->t_cursor.tp_col);
627
}
628
629
static void
630
teken_subr_index(teken_t *t)
631
{
632
633
if (t->t_cursor.tp_row < t->t_scrollreg.ts_end - 1) {
634
t->t_cursor.tp_row++;
635
t->t_stateflags &= ~TS_WRAPPED;
636
teken_funcs_cursor(t);
637
} else {
638
teken_subr_do_scroll(t, 1);
639
}
640
}
641
642
static void
643
teken_subr_insert_character(const teken_t *t, unsigned int ncols)
644
{
645
teken_rect_t tr;
646
647
tr.tr_begin = t->t_cursor;
648
tr.tr_end.tp_row = t->t_cursor.tp_row + 1;
649
650
if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) {
651
tr.tr_end.tp_col = t->t_winsize.tp_col;
652
} else {
653
teken_pos_t tp;
654
655
/* Copy characters to the right. */
656
tr.tr_end.tp_col = t->t_winsize.tp_col - ncols;
657
tp.tp_row = t->t_cursor.tp_row;
658
tp.tp_col = t->t_cursor.tp_col + ncols;
659
teken_funcs_copy(t, &tr, &tp);
660
661
tr.tr_end.tp_col = t->t_cursor.tp_col + ncols;
662
}
663
664
/* Blank current location. */
665
teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
666
}
667
668
static void
669
teken_subr_insert_line(const teken_t *t, unsigned int nrows)
670
{
671
teken_rect_t tr;
672
673
/* Ignore if outside scrolling region. */
674
if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin ||
675
t->t_cursor.tp_row >= t->t_scrollreg.ts_end)
676
return;
677
678
tr.tr_begin.tp_row = t->t_cursor.tp_row;
679
tr.tr_begin.tp_col = 0;
680
tr.tr_end.tp_col = t->t_winsize.tp_col;
681
682
if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) {
683
tr.tr_end.tp_row = t->t_scrollreg.ts_end;
684
} else {
685
teken_pos_t tp;
686
687
/* Copy lines down. */
688
tr.tr_end.tp_row = t->t_scrollreg.ts_end - nrows;
689
tp.tp_row = t->t_cursor.tp_row + nrows;
690
tp.tp_col = 0;
691
teken_funcs_copy(t, &tr, &tp);
692
693
tr.tr_end.tp_row = t->t_cursor.tp_row + nrows;
694
}
695
696
/* Blank current location. */
697
teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
698
}
699
700
static void
701
teken_subr_keypad_application_mode(const teken_t *t)
702
{
703
704
teken_funcs_param(t, TP_KEYPADAPP, 1);
705
}
706
707
static void
708
teken_subr_keypad_numeric_mode(const teken_t *t)
709
{
710
711
teken_funcs_param(t, TP_KEYPADAPP, 0);
712
}
713
714
static void
715
teken_subr_newline(teken_t *t)
716
{
717
718
t->t_cursor.tp_row++;
719
720
if (t->t_cursor.tp_row >= t->t_scrollreg.ts_end) {
721
teken_subr_do_scroll(t, 1);
722
t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1;
723
}
724
725
t->t_stateflags &= ~TS_WRAPPED;
726
teken_funcs_cursor(t);
727
}
728
729
static void
730
teken_subr_newpage(teken_t *t)
731
{
732
733
if (t->t_stateflags & TS_CONS25) {
734
teken_rect_t tr;
735
736
/* Clear screen. */
737
tr.tr_begin.tp_row = t->t_originreg.ts_begin;
738
tr.tr_begin.tp_col = 0;
739
tr.tr_end.tp_row = t->t_originreg.ts_end;
740
tr.tr_end.tp_col = t->t_winsize.tp_col;
741
teken_funcs_fill(t, &tr, BLANK, &t->t_curattr);
742
743
/* Cursor at top left. */
744
t->t_cursor.tp_row = t->t_originreg.ts_begin;
745
t->t_cursor.tp_col = 0;
746
t->t_stateflags &= ~TS_WRAPPED;
747
teken_funcs_cursor(t);
748
} else {
749
teken_subr_newline(t);
750
}
751
}
752
753
static void
754
teken_subr_next_line(teken_t *t)
755
{
756
757
t->t_cursor.tp_col = 0;
758
teken_subr_newline(t);
759
}
760
761
static void
762
teken_subr_operating_system_command(teken_t *t)
763
{
764
765
teken_printf("Unsupported operating system command\n");
766
t->t_stateflags |= TS_INSTRING;
767
}
768
769
static void
770
teken_subr_pan_down(const teken_t *t, unsigned int nrows)
771
{
772
773
teken_subr_do_scroll(t, (int)nrows);
774
}
775
776
static void
777
teken_subr_pan_up(const teken_t *t, unsigned int nrows)
778
{
779
780
teken_subr_do_scroll(t, -(int)nrows);
781
}
782
783
static void
784
teken_subr_primary_device_attributes(const teken_t *t, unsigned int request)
785
{
786
787
if (request == 0) {
788
const char response[] = "\x1B[?1;2c";
789
790
teken_funcs_respond(t, response, sizeof response - 1);
791
} else {
792
teken_printf("Unknown DA1\n");
793
}
794
}
795
796
static void
797
teken_subr_do_putchar(teken_t *t, const teken_pos_t *tp, teken_char_t c,
798
int width)
799
{
800
801
t->t_last = c;
802
if (t->t_stateflags & TS_INSERT &&
803
tp->tp_col < t->t_winsize.tp_col - width) {
804
teken_rect_t ctr;
805
teken_pos_t ctp;
806
807
/* Insert mode. Move existing characters to the right. */
808
ctr.tr_begin = *tp;
809
ctr.tr_end.tp_row = tp->tp_row + 1;
810
ctr.tr_end.tp_col = t->t_winsize.tp_col - width;
811
ctp.tp_row = tp->tp_row;
812
ctp.tp_col = tp->tp_col + width;
813
teken_funcs_copy(t, &ctr, &ctp);
814
}
815
816
teken_funcs_putchar(t, tp, c, &t->t_curattr);
817
818
if (width == 2 && tp->tp_col + 1 < t->t_winsize.tp_col) {
819
teken_pos_t tp2;
820
teken_attr_t attr;
821
822
/* Print second half of CJK fullwidth character. */
823
tp2.tp_row = tp->tp_row;
824
tp2.tp_col = tp->tp_col + 1;
825
attr = t->t_curattr;
826
attr.ta_format |= TF_CJK_RIGHT;
827
teken_funcs_putchar(t, &tp2, c, &attr);
828
}
829
}
830
831
static void
832
teken_subr_regular_character(teken_t *t, teken_char_t c)
833
{
834
int width;
835
836
if (t->t_stateflags & TS_8BIT) {
837
if (!(t->t_stateflags & TS_CONS25) && (c <= 0x1b || c == 0x7f))
838
return;
839
c = teken_scs_process(t, c);
840
width = 1;
841
} else {
842
c = teken_scs_process(t, c);
843
width = teken_wcwidth(c);
844
/* XXX: Don't process zero-width characters yet. */
845
if (width <= 0)
846
return;
847
}
848
849
if (t->t_stateflags & TS_CONS25) {
850
teken_subr_do_putchar(t, &t->t_cursor, c, width);
851
t->t_cursor.tp_col += width;
852
853
if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
854
if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
855
/* Perform scrolling. */
856
teken_subr_do_scroll(t, 1);
857
} else {
858
/* No scrolling needed. */
859
if (t->t_cursor.tp_row <
860
t->t_winsize.tp_row - 1)
861
t->t_cursor.tp_row++;
862
}
863
t->t_cursor.tp_col = 0;
864
}
865
} else if (t->t_stateflags & TS_AUTOWRAP &&
866
((t->t_stateflags & TS_WRAPPED &&
867
t->t_cursor.tp_col + 1 == t->t_winsize.tp_col) ||
868
t->t_cursor.tp_col + width > t->t_winsize.tp_col)) {
869
teken_pos_t tp;
870
871
/*
872
* Perform line wrapping, if:
873
* - Autowrapping is enabled, and
874
* - We're in the wrapped state at the last column, or
875
* - The character to be printed does not fit anymore.
876
*/
877
if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) {
878
/* Perform scrolling. */
879
teken_subr_do_scroll(t, 1);
880
tp.tp_row = t->t_scrollreg.ts_end - 1;
881
} else {
882
/* No scrolling needed. */
883
tp.tp_row = t->t_cursor.tp_row + 1;
884
if (tp.tp_row == t->t_winsize.tp_row) {
885
/*
886
* Corner case: regular character
887
* outside scrolling region, but at the
888
* bottom of the screen.
889
*/
890
teken_subr_do_putchar(t, &t->t_cursor,
891
c, width);
892
return;
893
}
894
}
895
896
tp.tp_col = 0;
897
teken_subr_do_putchar(t, &tp, c, width);
898
899
t->t_cursor.tp_row = tp.tp_row;
900
t->t_cursor.tp_col = width;
901
t->t_stateflags &= ~TS_WRAPPED;
902
} else {
903
/* No line wrapping needed. */
904
teken_subr_do_putchar(t, &t->t_cursor, c, width);
905
t->t_cursor.tp_col += width;
906
907
if (t->t_cursor.tp_col >= t->t_winsize.tp_col) {
908
t->t_stateflags |= TS_WRAPPED;
909
t->t_cursor.tp_col = t->t_winsize.tp_col - 1;
910
} else {
911
t->t_stateflags &= ~TS_WRAPPED;
912
}
913
}
914
915
teken_funcs_cursor(t);
916
}
917
918
static void
919
teken_subr_reset_dec_mode(teken_t *t, unsigned int cmd)
920
{
921
922
switch (cmd) {
923
case 1: /* Cursor keys mode. */
924
t->t_stateflags &= ~TS_CURSORKEYS;
925
break;
926
case 2: /* DECANM: ANSI/VT52 mode. */
927
teken_printf("DECRST VT52\n");
928
break;
929
case 3: /* 132 column mode. */
930
teken_funcs_param(t, TP_132COLS, 0);
931
teken_subr_reset_to_initial_state(t);
932
break;
933
case 5: /* Inverse video. */
934
teken_printf("DECRST inverse video\n");
935
break;
936
case 6: /* Origin mode. */
937
t->t_stateflags &= ~TS_ORIGIN;
938
t->t_originreg.ts_begin = 0;
939
t->t_originreg.ts_end = t->t_winsize.tp_row;
940
t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
941
t->t_stateflags &= ~TS_WRAPPED;
942
teken_funcs_cursor(t);
943
break;
944
case 7: /* Autowrap mode. */
945
t->t_stateflags &= ~TS_AUTOWRAP;
946
break;
947
case 8: /* Autorepeat mode. */
948
teken_funcs_param(t, TP_AUTOREPEAT, 0);
949
break;
950
case 25: /* Hide cursor. */
951
teken_funcs_param(t, TP_SHOWCURSOR, 0);
952
break;
953
case 40: /* Disallow 132 columns. */
954
teken_printf("DECRST allow 132\n");
955
break;
956
case 45: /* Disable reverse wraparound. */
957
teken_printf("DECRST reverse wraparound\n");
958
break;
959
case 47: /* Switch to alternate buffer. */
960
teken_printf("Switch to alternate buffer\n");
961
break;
962
case 1000: /* Mouse input. */
963
teken_funcs_param(t, TP_MOUSE, 0);
964
break;
965
default:
966
teken_printf("Unknown DECRST: %u\n", cmd);
967
}
968
}
969
970
static void
971
teken_subr_reset_mode(teken_t *t, unsigned int cmd)
972
{
973
974
switch (cmd) {
975
case 4:
976
t->t_stateflags &= ~TS_INSERT;
977
break;
978
default:
979
teken_printf("Unknown reset mode: %u\n", cmd);
980
}
981
}
982
983
static void
984
teken_subr_do_resize(teken_t *t)
985
{
986
987
t->t_scrollreg.ts_begin = 0;
988
t->t_scrollreg.ts_end = t->t_winsize.tp_row;
989
t->t_originreg = t->t_scrollreg;
990
}
991
992
static void
993
teken_subr_do_reset(teken_t *t)
994
{
995
996
t->t_curattr = t->t_defattr;
997
t->t_cursor.tp_row = t->t_cursor.tp_col = 0;
998
t->t_scrollreg.ts_begin = 0;
999
t->t_scrollreg.ts_end = t->t_winsize.tp_row;
1000
t->t_originreg = t->t_scrollreg;
1001
t->t_stateflags &= TS_8BIT | TS_CONS25 | TS_CONS25KEYS;
1002
t->t_stateflags |= TS_AUTOWRAP;
1003
1004
t->t_scs[0] = teken_scs_us_ascii;
1005
t->t_scs[1] = teken_scs_us_ascii;
1006
t->t_curscs = 0;
1007
1008
teken_subr_save_cursor(t);
1009
teken_tab_default(t);
1010
}
1011
1012
static void
1013
teken_subr_reset_to_initial_state(teken_t *t)
1014
{
1015
1016
teken_subr_do_reset(t);
1017
teken_subr_erase_display(t, 2);
1018
teken_funcs_param(t, TP_SHOWCURSOR, 1);
1019
teken_funcs_cursor(t);
1020
}
1021
1022
static void
1023
teken_subr_restore_cursor(teken_t *t)
1024
{
1025
1026
t->t_cursor = t->t_saved_cursor;
1027
t->t_curattr = t->t_saved_curattr;
1028
t->t_scs[t->t_curscs] = t->t_saved_curscs;
1029
t->t_stateflags &= ~TS_WRAPPED;
1030
1031
/* Get out of origin mode when the cursor is moved outside. */
1032
if (t->t_cursor.tp_row < t->t_originreg.ts_begin ||
1033
t->t_cursor.tp_row >= t->t_originreg.ts_end) {
1034
t->t_stateflags &= ~TS_ORIGIN;
1035
t->t_originreg.ts_begin = 0;
1036
t->t_originreg.ts_end = t->t_winsize.tp_row;
1037
}
1038
1039
teken_funcs_cursor(t);
1040
}
1041
1042
static void
1043
teken_subr_reverse_index(teken_t *t)
1044
{
1045
1046
if (t->t_cursor.tp_row > t->t_scrollreg.ts_begin) {
1047
t->t_cursor.tp_row--;
1048
t->t_stateflags &= ~TS_WRAPPED;
1049
teken_funcs_cursor(t);
1050
} else {
1051
teken_subr_do_scroll(t, -1);
1052
}
1053
}
1054
1055
static void
1056
teken_subr_save_cursor(teken_t *t)
1057
{
1058
1059
t->t_saved_cursor = t->t_cursor;
1060
t->t_saved_curattr = t->t_curattr;
1061
t->t_saved_curscs = t->t_scs[t->t_curscs];
1062
}
1063
1064
static void
1065
teken_subr_secondary_device_attributes(const teken_t *t, unsigned int request)
1066
{
1067
1068
if (request == 0) {
1069
const char response[] = "\x1B[>0;10;0c";
1070
teken_funcs_respond(t, response, sizeof response - 1);
1071
} else {
1072
teken_printf("Unknown DA2\n");
1073
}
1074
}
1075
1076
static void
1077
teken_subr_set_dec_mode(teken_t *t, unsigned int cmd)
1078
{
1079
1080
switch (cmd) {
1081
case 1: /* Cursor keys mode. */
1082
t->t_stateflags |= TS_CURSORKEYS;
1083
break;
1084
case 2: /* DECANM: ANSI/VT52 mode. */
1085
teken_printf("DECSET VT52\n");
1086
break;
1087
case 3: /* 132 column mode. */
1088
teken_funcs_param(t, TP_132COLS, 1);
1089
teken_subr_reset_to_initial_state(t);
1090
break;
1091
case 5: /* Inverse video. */
1092
teken_printf("DECSET inverse video\n");
1093
break;
1094
case 6: /* Origin mode. */
1095
t->t_stateflags |= TS_ORIGIN;
1096
t->t_originreg = t->t_scrollreg;
1097
t->t_cursor.tp_row = t->t_scrollreg.ts_begin;
1098
t->t_cursor.tp_col = 0;
1099
t->t_stateflags &= ~TS_WRAPPED;
1100
teken_funcs_cursor(t);
1101
break;
1102
case 7: /* Autowrap mode. */
1103
t->t_stateflags |= TS_AUTOWRAP;
1104
break;
1105
case 8: /* Autorepeat mode. */
1106
teken_funcs_param(t, TP_AUTOREPEAT, 1);
1107
break;
1108
case 25: /* Display cursor. */
1109
teken_funcs_param(t, TP_SHOWCURSOR, 1);
1110
break;
1111
case 40: /* Allow 132 columns. */
1112
teken_printf("DECSET allow 132\n");
1113
break;
1114
case 45: /* Enable reverse wraparound. */
1115
teken_printf("DECSET reverse wraparound\n");
1116
break;
1117
case 47: /* Switch to alternate buffer. */
1118
teken_printf("Switch away from alternate buffer\n");
1119
break;
1120
case 1000: /* Mouse input. */
1121
teken_funcs_param(t, TP_MOUSE, 1);
1122
break;
1123
default:
1124
teken_printf("Unknown DECSET: %u\n", cmd);
1125
}
1126
}
1127
1128
static void
1129
teken_subr_set_mode(teken_t *t, unsigned int cmd)
1130
{
1131
1132
switch (cmd) {
1133
case 4:
1134
teken_printf("Insert mode\n");
1135
t->t_stateflags |= TS_INSERT;
1136
break;
1137
default:
1138
teken_printf("Unknown set mode: %u\n", cmd);
1139
}
1140
}
1141
1142
static void
1143
teken_subr_set_graphic_rendition(teken_t *t, unsigned int ncmds,
1144
const unsigned int cmds[])
1145
{
1146
unsigned int i, n;
1147
1148
/* No attributes means reset. */
1149
if (ncmds == 0) {
1150
t->t_curattr = t->t_defattr;
1151
return;
1152
}
1153
1154
for (i = 0; i < ncmds; i++) {
1155
n = cmds[i];
1156
1157
switch (n) {
1158
case 0: /* Reset. */
1159
t->t_curattr = t->t_defattr;
1160
break;
1161
case 1: /* Bold. */
1162
t->t_curattr.ta_format |= TF_BOLD;
1163
break;
1164
case 4: /* Underline. */
1165
t->t_curattr.ta_format |= TF_UNDERLINE;
1166
break;
1167
case 5: /* Blink. */
1168
t->t_curattr.ta_format |= TF_BLINK;
1169
break;
1170
case 7: /* Reverse. */
1171
t->t_curattr.ta_format |= TF_REVERSE;
1172
break;
1173
case 22: /* Remove bold. */
1174
t->t_curattr.ta_format &= ~TF_BOLD;
1175
break;
1176
case 24: /* Remove underline. */
1177
t->t_curattr.ta_format &= ~TF_UNDERLINE;
1178
break;
1179
case 25: /* Remove blink. */
1180
t->t_curattr.ta_format &= ~TF_BLINK;
1181
break;
1182
case 27: /* Remove reverse. */
1183
t->t_curattr.ta_format &= ~TF_REVERSE;
1184
break;
1185
case 30: /* Set foreground color: black */
1186
case 31: /* Set foreground color: red */
1187
case 32: /* Set foreground color: green */
1188
case 33: /* Set foreground color: brown */
1189
case 34: /* Set foreground color: blue */
1190
case 35: /* Set foreground color: magenta */
1191
case 36: /* Set foreground color: cyan */
1192
case 37: /* Set foreground color: white */
1193
t->t_curattr.ta_fgcolor = n - 30;
1194
break;
1195
case 38: /* Set foreground color: 256 color mode */
1196
if (i + 2 >= ncmds || cmds[i + 1] != 5)
1197
continue;
1198
t->t_curattr.ta_fgcolor = cmds[i + 2];
1199
i += 2;
1200
break;
1201
case 39: /* Set default foreground color. */
1202
t->t_curattr.ta_fgcolor = t->t_defattr.ta_fgcolor;
1203
break;
1204
case 40: /* Set background color: black */
1205
case 41: /* Set background color: red */
1206
case 42: /* Set background color: green */
1207
case 43: /* Set background color: brown */
1208
case 44: /* Set background color: blue */
1209
case 45: /* Set background color: magenta */
1210
case 46: /* Set background color: cyan */
1211
case 47: /* Set background color: white */
1212
t->t_curattr.ta_bgcolor = n - 40;
1213
break;
1214
case 48: /* Set background color: 256 color mode */
1215
if (i + 2 >= ncmds || cmds[i + 1] != 5)
1216
continue;
1217
t->t_curattr.ta_bgcolor = cmds[i + 2];
1218
i += 2;
1219
break;
1220
case 49: /* Set default background color. */
1221
t->t_curattr.ta_bgcolor = t->t_defattr.ta_bgcolor;
1222
break;
1223
case 90: /* Set bright foreground color: black */
1224
case 91: /* Set bright foreground color: red */
1225
case 92: /* Set bright foreground color: green */
1226
case 93: /* Set bright foreground color: brown */
1227
case 94: /* Set bright foreground color: blue */
1228
case 95: /* Set bright foreground color: magenta */
1229
case 96: /* Set bright foreground color: cyan */
1230
case 97: /* Set bright foreground color: white */
1231
t->t_curattr.ta_fgcolor = (n - 90) + 8;
1232
break;
1233
case 100: /* Set bright background color: black */
1234
case 101: /* Set bright background color: red */
1235
case 102: /* Set bright background color: green */
1236
case 103: /* Set bright background color: brown */
1237
case 104: /* Set bright background color: blue */
1238
case 105: /* Set bright background color: magenta */
1239
case 106: /* Set bright background color: cyan */
1240
case 107: /* Set bright background color: white */
1241
t->t_curattr.ta_bgcolor = (n - 100) + 8;
1242
break;
1243
default:
1244
teken_printf("unsupported attribute %u\n", n);
1245
}
1246
}
1247
}
1248
1249
static void
1250
teken_subr_set_top_and_bottom_margins(teken_t *t, unsigned int top,
1251
unsigned int bottom)
1252
{
1253
1254
/* Adjust top row number. */
1255
if (top > 0)
1256
top--;
1257
/* Adjust bottom row number. */
1258
if (bottom == 0 || bottom > t->t_winsize.tp_row)
1259
bottom = t->t_winsize.tp_row;
1260
1261
/* Invalid arguments. */
1262
if (top >= bottom - 1) {
1263
top = 0;
1264
bottom = t->t_winsize.tp_row;
1265
}
1266
1267
/* Apply scrolling region. */
1268
t->t_scrollreg.ts_begin = top;
1269
t->t_scrollreg.ts_end = bottom;
1270
if (t->t_stateflags & TS_ORIGIN)
1271
t->t_originreg = t->t_scrollreg;
1272
1273
/* Home cursor to the top left of the scrolling region. */
1274
t->t_cursor.tp_row = t->t_originreg.ts_begin;
1275
t->t_cursor.tp_col = 0;
1276
t->t_stateflags &= ~TS_WRAPPED;
1277
teken_funcs_cursor(t);
1278
}
1279
1280
static void
1281
teken_subr_single_height_double_width_line(const teken_t *t)
1282
{
1283
1284
(void)t;
1285
teken_printf("single height double width???\n");
1286
}
1287
1288
static void
1289
teken_subr_single_height_single_width_line(const teken_t *t)
1290
{
1291
1292
(void)t;
1293
teken_printf("single height single width???\n");
1294
}
1295
1296
static void
1297
teken_subr_string_terminator(const teken_t *t)
1298
{
1299
1300
(void)t;
1301
/*
1302
* Strings are already terminated in teken_input_char() when ^[
1303
* is inserted.
1304
*/
1305
}
1306
1307
static void
1308
teken_subr_tab_clear(teken_t *t, unsigned int cmd)
1309
{
1310
1311
switch (cmd) {
1312
case 0:
1313
teken_tab_clear(t, t->t_cursor.tp_col);
1314
break;
1315
case 3:
1316
memset(t->t_tabstops, 0, T_NUMCOL / 8);
1317
break;
1318
default:
1319
break;
1320
}
1321
}
1322
1323
static void
1324
teken_subr_vertical_position_absolute(teken_t *t, unsigned int row)
1325
{
1326
1327
row = (row - 1) + t->t_originreg.ts_begin;
1328
t->t_cursor.tp_row = row < t->t_originreg.ts_end ?
1329
row : t->t_originreg.ts_end - 1;
1330
1331
t->t_stateflags &= ~TS_WRAPPED;
1332
teken_funcs_cursor(t);
1333
}
1334
1335
static void
1336
teken_subr_repeat_last_graphic_char(teken_t *t, unsigned int rpts)
1337
{
1338
unsigned int max_repetitions;
1339
1340
max_repetitions = t->t_winsize.tp_row * t->t_winsize.tp_col;
1341
if (rpts > max_repetitions)
1342
rpts = max_repetitions;
1343
for (; t->t_last != 0 && rpts > 0; rpts--)
1344
teken_subr_regular_character(t, t->t_last);
1345
}
1346
1347