Deleted Added
full compact
teken.c (186731) teken.c (186798)
1/*-
2 * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*-
2 * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/syscons/teken/teken.c 186731 2009-01-04 00:20:18Z ed $
26 * $FreeBSD: head/sys/dev/syscons/teken/teken.c 186798 2009-01-05 22:09:46Z ed $
27 */
28
29#include <sys/cdefs.h>
30#if defined(__FreeBSD__) && defined(_KERNEL)
31#include <sys/param.h>
32#include <sys/lock.h>
33#include <sys/systm.h>
34#define teken_assert(x) MPASS(x)
35#define teken_printf(x,...)
36#else /* !(__FreeBSD__ && _KERNEL) */
37#include <sys/types.h>
38#include <assert.h>
39#include <inttypes.h>
40#include <stdio.h>
41#include <string.h>
42#define teken_assert(x) assert(x)
43#define teken_printf(x,...) do { \
44 if (df != NULL) \
45 fprintf(df, x, ## __VA_ARGS__); \
46} while (0)
47/* debug messages */
48static FILE *df;
49#endif /* __FreeBSD__ && _KERNEL */
50
51#include "teken.h"
52#ifdef TEKEN_UTF8
53#include "teken_wcwidth.h"
54#else /* !TEKEN_UTF8 */
55static inline int
56teken_wcwidth(teken_char_t c __unused)
57{
58
59#ifdef TEKEN_CONS25
60 return (1);
61#else /* !TEKEN_CONS25 */
62 return (c <= 0x1B) ? -1 : 1;
63#endif /* TEKEN_CONS25 */
64}
65#endif /* TEKEN_UTF8 */
66
67/* Private flags for teken_format_t. */
68#define TF_REVERSE 0x08
69
70/* Private flags for t_stateflags. */
71#define TS_FIRSTDIGIT 0x01 /* First numeric digit in escape sequence. */
72#define TS_INSERT 0x02 /* Insert mode. */
73#define TS_AUTOWRAP 0x04 /* Autowrap. */
74#define TS_ORIGIN 0x08 /* Origin mode. */
75#ifdef TEKEN_CONS25
76#define TS_WRAPPED 0x00 /* Simple line wrapping. */
77#else /* !TEKEN_CONS25 */
78#define TS_WRAPPED 0x10 /* Next character should be printed on col 0. */
79#endif /* TEKEN_CONS25 */
80
81/* Character that blanks a cell. */
82#define BLANK ' '
83
84static teken_state_t teken_state_init;
85
86/*
87 * Wrappers for hooks.
88 */
89
90static inline void
91teken_funcs_bell(teken_t *t)
92{
93
94 t->t_funcs->tf_bell(t->t_softc);
95}
96
97static inline void
98teken_funcs_cursor(teken_t *t)
99{
100
101 teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
102 teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
103
104 t->t_funcs->tf_cursor(t->t_softc, &t->t_cursor);
105}
106
107static inline void
108teken_funcs_putchar(teken_t *t, const teken_pos_t *p, teken_char_t c,
109 const teken_attr_t *a)
110{
111 teken_attr_t ta;
112
113 teken_assert(p->tp_row < t->t_winsize.tp_row);
114 teken_assert(p->tp_col < t->t_winsize.tp_col);
115
116 /* Apply inversion. */
117 if (a->ta_format & TF_REVERSE) {
118 ta.ta_format = a->ta_format;
119 ta.ta_fgcolor = a->ta_bgcolor;
120 ta.ta_bgcolor = a->ta_fgcolor;
121 a = &ta;
122 }
123
124 t->t_funcs->tf_putchar(t->t_softc, p, c, a);
125}
126
127static inline void
128teken_funcs_fill(teken_t *t, const teken_rect_t *r,
129 const teken_char_t c, const teken_attr_t *a)
130{
131 teken_attr_t ta;
132
133 teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
134 teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
135 teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
136 teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
137
138 /* Apply inversion. */
139 if (a->ta_format & TF_REVERSE) {
140 ta.ta_format = a->ta_format;
141 ta.ta_fgcolor = a->ta_bgcolor;
142 ta.ta_bgcolor = a->ta_fgcolor;
143 a = &ta;
144 }
145
146 t->t_funcs->tf_fill(t->t_softc, r, c, a);
147}
148
149static inline void
150teken_funcs_copy(teken_t *t, const teken_rect_t *r, const teken_pos_t *p)
151{
152
153 teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
154 teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
155 teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
156 teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
157 teken_assert(p->tp_row + (r->tr_end.tp_row - r->tr_begin.tp_row) <= t->t_winsize.tp_row);
158 teken_assert(p->tp_col + (r->tr_end.tp_col - r->tr_begin.tp_col) <= t->t_winsize.tp_col);
159
160 t->t_funcs->tf_copy(t->t_softc, r, p);
161}
162
163static inline void
164teken_funcs_param(teken_t *t, int cmd, int value)
165{
166
167 t->t_funcs->tf_param(t->t_softc, cmd, value);
168}
169
170static inline void
171teken_funcs_respond(teken_t *t, const void *buf, size_t len)
172{
173
174 t->t_funcs->tf_respond(t->t_softc, buf, len);
175}
176
177#include "teken_subr.h"
178#include "teken_subr_compat.h"
179
180/*
181 * Programming interface.
182 */
183
184void
185teken_init(teken_t *t, const teken_funcs_t *tf, void *softc)
186{
187 teken_pos_t tp = { .tp_row = 24, .tp_col = 80 };
188
189#if !(defined(__FreeBSD__) && defined(_KERNEL))
190 df = fopen("teken.log", "w");
191 if (df != NULL)
192 setvbuf(df, NULL, _IOLBF, BUFSIZ);
193#endif /* !(__FreeBSD__ && _KERNEL) */
194
195 t->t_funcs = tf;
196 t->t_softc = softc;
197
198 t->t_nextstate = teken_state_init;
199
200 t->t_defattr.ta_format = 0;
201 t->t_defattr.ta_fgcolor = TC_WHITE;
202 t->t_defattr.ta_bgcolor = TC_BLACK;
203 teken_subr_do_reset(t);
204
205#ifdef TEKEN_UTF8
206 t->t_utf8_left = 0;
207#endif /* TEKEN_UTF8 */
208
209 teken_set_winsize(t, &tp);
210}
211
212static void
213teken_input_char(teken_t *t, teken_char_t c)
214{
215
216 switch (c) {
217 case '\0':
218 break;
219 case '\a':
220 teken_subr_bell(t);
221 break;
222 case '\b':
223 teken_subr_backspace(t);
224 break;
225 case '\n':
226 case '\x0B':
227 teken_subr_newline(t);
228 break;
27 */
28
29#include <sys/cdefs.h>
30#if defined(__FreeBSD__) && defined(_KERNEL)
31#include <sys/param.h>
32#include <sys/lock.h>
33#include <sys/systm.h>
34#define teken_assert(x) MPASS(x)
35#define teken_printf(x,...)
36#else /* !(__FreeBSD__ && _KERNEL) */
37#include <sys/types.h>
38#include <assert.h>
39#include <inttypes.h>
40#include <stdio.h>
41#include <string.h>
42#define teken_assert(x) assert(x)
43#define teken_printf(x,...) do { \
44 if (df != NULL) \
45 fprintf(df, x, ## __VA_ARGS__); \
46} while (0)
47/* debug messages */
48static FILE *df;
49#endif /* __FreeBSD__ && _KERNEL */
50
51#include "teken.h"
52#ifdef TEKEN_UTF8
53#include "teken_wcwidth.h"
54#else /* !TEKEN_UTF8 */
55static inline int
56teken_wcwidth(teken_char_t c __unused)
57{
58
59#ifdef TEKEN_CONS25
60 return (1);
61#else /* !TEKEN_CONS25 */
62 return (c <= 0x1B) ? -1 : 1;
63#endif /* TEKEN_CONS25 */
64}
65#endif /* TEKEN_UTF8 */
66
67/* Private flags for teken_format_t. */
68#define TF_REVERSE 0x08
69
70/* Private flags for t_stateflags. */
71#define TS_FIRSTDIGIT 0x01 /* First numeric digit in escape sequence. */
72#define TS_INSERT 0x02 /* Insert mode. */
73#define TS_AUTOWRAP 0x04 /* Autowrap. */
74#define TS_ORIGIN 0x08 /* Origin mode. */
75#ifdef TEKEN_CONS25
76#define TS_WRAPPED 0x00 /* Simple line wrapping. */
77#else /* !TEKEN_CONS25 */
78#define TS_WRAPPED 0x10 /* Next character should be printed on col 0. */
79#endif /* TEKEN_CONS25 */
80
81/* Character that blanks a cell. */
82#define BLANK ' '
83
84static teken_state_t teken_state_init;
85
86/*
87 * Wrappers for hooks.
88 */
89
90static inline void
91teken_funcs_bell(teken_t *t)
92{
93
94 t->t_funcs->tf_bell(t->t_softc);
95}
96
97static inline void
98teken_funcs_cursor(teken_t *t)
99{
100
101 teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
102 teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
103
104 t->t_funcs->tf_cursor(t->t_softc, &t->t_cursor);
105}
106
107static inline void
108teken_funcs_putchar(teken_t *t, const teken_pos_t *p, teken_char_t c,
109 const teken_attr_t *a)
110{
111 teken_attr_t ta;
112
113 teken_assert(p->tp_row < t->t_winsize.tp_row);
114 teken_assert(p->tp_col < t->t_winsize.tp_col);
115
116 /* Apply inversion. */
117 if (a->ta_format & TF_REVERSE) {
118 ta.ta_format = a->ta_format;
119 ta.ta_fgcolor = a->ta_bgcolor;
120 ta.ta_bgcolor = a->ta_fgcolor;
121 a = &ta;
122 }
123
124 t->t_funcs->tf_putchar(t->t_softc, p, c, a);
125}
126
127static inline void
128teken_funcs_fill(teken_t *t, const teken_rect_t *r,
129 const teken_char_t c, const teken_attr_t *a)
130{
131 teken_attr_t ta;
132
133 teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
134 teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
135 teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
136 teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
137
138 /* Apply inversion. */
139 if (a->ta_format & TF_REVERSE) {
140 ta.ta_format = a->ta_format;
141 ta.ta_fgcolor = a->ta_bgcolor;
142 ta.ta_bgcolor = a->ta_fgcolor;
143 a = &ta;
144 }
145
146 t->t_funcs->tf_fill(t->t_softc, r, c, a);
147}
148
149static inline void
150teken_funcs_copy(teken_t *t, const teken_rect_t *r, const teken_pos_t *p)
151{
152
153 teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
154 teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
155 teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
156 teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
157 teken_assert(p->tp_row + (r->tr_end.tp_row - r->tr_begin.tp_row) <= t->t_winsize.tp_row);
158 teken_assert(p->tp_col + (r->tr_end.tp_col - r->tr_begin.tp_col) <= t->t_winsize.tp_col);
159
160 t->t_funcs->tf_copy(t->t_softc, r, p);
161}
162
163static inline void
164teken_funcs_param(teken_t *t, int cmd, int value)
165{
166
167 t->t_funcs->tf_param(t->t_softc, cmd, value);
168}
169
170static inline void
171teken_funcs_respond(teken_t *t, const void *buf, size_t len)
172{
173
174 t->t_funcs->tf_respond(t->t_softc, buf, len);
175}
176
177#include "teken_subr.h"
178#include "teken_subr_compat.h"
179
180/*
181 * Programming interface.
182 */
183
184void
185teken_init(teken_t *t, const teken_funcs_t *tf, void *softc)
186{
187 teken_pos_t tp = { .tp_row = 24, .tp_col = 80 };
188
189#if !(defined(__FreeBSD__) && defined(_KERNEL))
190 df = fopen("teken.log", "w");
191 if (df != NULL)
192 setvbuf(df, NULL, _IOLBF, BUFSIZ);
193#endif /* !(__FreeBSD__ && _KERNEL) */
194
195 t->t_funcs = tf;
196 t->t_softc = softc;
197
198 t->t_nextstate = teken_state_init;
199
200 t->t_defattr.ta_format = 0;
201 t->t_defattr.ta_fgcolor = TC_WHITE;
202 t->t_defattr.ta_bgcolor = TC_BLACK;
203 teken_subr_do_reset(t);
204
205#ifdef TEKEN_UTF8
206 t->t_utf8_left = 0;
207#endif /* TEKEN_UTF8 */
208
209 teken_set_winsize(t, &tp);
210}
211
212static void
213teken_input_char(teken_t *t, teken_char_t c)
214{
215
216 switch (c) {
217 case '\0':
218 break;
219 case '\a':
220 teken_subr_bell(t);
221 break;
222 case '\b':
223 teken_subr_backspace(t);
224 break;
225 case '\n':
226 case '\x0B':
227 teken_subr_newline(t);
228 break;
229 case '\x0C':
230 teken_subr_newpage(t);
231 break;
229 case '\r':
230 teken_subr_carriage_return(t);
231 break;
232 case '\t':
233 teken_subr_horizontal_tab(t);
234 break;
235 default:
236 t->t_nextstate(t, c);
237 break;
238 }
239
240 /* Post-processing assertions. */
241 teken_assert(t->t_cursor.tp_row >= t->t_originreg.ts_begin);
242 teken_assert(t->t_cursor.tp_row < t->t_originreg.ts_end);
243 teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
244 teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
245 teken_assert(t->t_saved_cursor.tp_row < t->t_winsize.tp_row);
246 teken_assert(t->t_saved_cursor.tp_col < t->t_winsize.tp_col);
247 teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
248 teken_assert(t->t_scrollreg.ts_begin < t->t_scrollreg.ts_end);
249 /* Origin region has to be window size or the same as scrollreg. */
250 teken_assert((t->t_originreg.ts_begin == t->t_scrollreg.ts_begin &&
251 t->t_originreg.ts_end == t->t_scrollreg.ts_end) ||
252 (t->t_originreg.ts_begin == 0 &&
253 t->t_originreg.ts_end == t->t_winsize.tp_row));
254}
255
256static void
257teken_input_byte(teken_t *t, unsigned char c)
258{
259
260#ifdef TEKEN_UTF8
261 /*
262 * UTF-8 handling.
263 */
264 if ((c & 0x80) == 0x00) {
265 /* One-byte sequence. */
266 t->t_utf8_left = 0;
267 teken_input_char(t, c);
268 } else if ((c & 0xe0) == 0xc0) {
269 /* Two-byte sequence. */
270 t->t_utf8_left = 1;
271 t->t_utf8_partial = c & 0x1f;
272 } else if ((c & 0xf0) == 0xe0) {
273 /* Three-byte sequence. */
274 t->t_utf8_left = 2;
275 t->t_utf8_partial = c & 0x0f;
276 } else if ((c & 0xf8) == 0xf0) {
277 /* Four-byte sequence. */
278 t->t_utf8_left = 3;
279 t->t_utf8_partial = c & 0x07;
280 } else if ((c & 0xc0) == 0x80) {
281 if (t->t_utf8_left == 0)
282 return;
283 t->t_utf8_left--;
284 t->t_utf8_partial = (t->t_utf8_partial << 6) | (c & 0x3f);
285 if (t->t_utf8_left == 0) {
286 teken_printf("Got UTF-8 char %u\n", t->t_utf8_partial);
287 teken_input_char(t, t->t_utf8_partial);
288 }
289 }
290#else /* !TEKEN_UTF8 */
291 teken_input_char(t, c);
292#endif /* TEKEN_UTF8 */
293}
294
295void
296teken_input(teken_t *t, const void *buf, size_t len)
297{
298 const char *c = buf;
299
300 while (len-- > 0)
301 teken_input_byte(t, *c++);
302}
303
304void
305teken_set_cursor(teken_t *t, const teken_pos_t *p)
306{
307
308 /* XXX: bounds checking with originreg! */
309 teken_assert(p->tp_row < t->t_winsize.tp_row);
310 teken_assert(p->tp_col < t->t_winsize.tp_col);
311
312 t->t_cursor = *p;
313}
314
315void
316teken_set_defattr(teken_t *t, const teken_attr_t *a)
317{
318
319 t->t_curattr = t->t_saved_curattr = t->t_defattr = *a;
320}
321
322void
323teken_set_winsize(teken_t *t, const teken_pos_t *p)
324{
325
326 teken_assert(p->tp_col <= T_NUMCOL);
327
328 t->t_winsize = *p;
329 /* XXX: bounds checking with cursor/etc! */
330 t->t_scrollreg.ts_begin = 0;
331 t->t_scrollreg.ts_end = t->t_winsize.tp_row;
332 t->t_originreg = t->t_scrollreg;
333}
334
335/*
336 * State machine.
337 */
338
339static void
340teken_state_switch(teken_t *t, teken_state_t *s)
341{
342
343 t->t_nextstate = s;
344 t->t_curnum = 0;
345 t->t_stateflags |= TS_FIRSTDIGIT;
346}
347
348static int
349teken_state_numbers(teken_t *t, teken_char_t c)
350{
351
352 teken_assert(t->t_curnum < T_NUMSIZE);
353
354 if (c >= '0' && c <= '9') {
355 /*
356 * Don't do math with the default value of 1 when a
357 * custom number is inserted.
358 */
359 if (t->t_stateflags & TS_FIRSTDIGIT) {
360 t->t_stateflags &= ~TS_FIRSTDIGIT;
361 t->t_nums[t->t_curnum] = 0;
362 } else {
363 t->t_nums[t->t_curnum] *= 10;
364 }
365
366 t->t_nums[t->t_curnum] += c - '0';
367 return (1);
368 } else if (c == ';') {
369 if (t->t_stateflags & TS_FIRSTDIGIT)
370 t->t_nums[t->t_curnum] = 0;
371
372 /* Only allow a limited set of arguments. */
373 if (++t->t_curnum == T_NUMSIZE) {
374 teken_state_switch(t, teken_state_init);
375 return (1);
376 }
377
378 t->t_stateflags |= TS_FIRSTDIGIT;
379 return (1);
380 } else {
381 if (t->t_stateflags & TS_FIRSTDIGIT && t->t_curnum > 0) {
382 /* Finish off the last empty argument. */
383 t->t_nums[t->t_curnum] = 0;
384 t->t_curnum++;
385 } else if ((t->t_stateflags & TS_FIRSTDIGIT) == 0) {
386 /* Also count the last argument. */
387 t->t_curnum++;
388 }
389 }
390
391 return (0);
392}
393
394#include "teken_state.h"
232 case '\r':
233 teken_subr_carriage_return(t);
234 break;
235 case '\t':
236 teken_subr_horizontal_tab(t);
237 break;
238 default:
239 t->t_nextstate(t, c);
240 break;
241 }
242
243 /* Post-processing assertions. */
244 teken_assert(t->t_cursor.tp_row >= t->t_originreg.ts_begin);
245 teken_assert(t->t_cursor.tp_row < t->t_originreg.ts_end);
246 teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
247 teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
248 teken_assert(t->t_saved_cursor.tp_row < t->t_winsize.tp_row);
249 teken_assert(t->t_saved_cursor.tp_col < t->t_winsize.tp_col);
250 teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
251 teken_assert(t->t_scrollreg.ts_begin < t->t_scrollreg.ts_end);
252 /* Origin region has to be window size or the same as scrollreg. */
253 teken_assert((t->t_originreg.ts_begin == t->t_scrollreg.ts_begin &&
254 t->t_originreg.ts_end == t->t_scrollreg.ts_end) ||
255 (t->t_originreg.ts_begin == 0 &&
256 t->t_originreg.ts_end == t->t_winsize.tp_row));
257}
258
259static void
260teken_input_byte(teken_t *t, unsigned char c)
261{
262
263#ifdef TEKEN_UTF8
264 /*
265 * UTF-8 handling.
266 */
267 if ((c & 0x80) == 0x00) {
268 /* One-byte sequence. */
269 t->t_utf8_left = 0;
270 teken_input_char(t, c);
271 } else if ((c & 0xe0) == 0xc0) {
272 /* Two-byte sequence. */
273 t->t_utf8_left = 1;
274 t->t_utf8_partial = c & 0x1f;
275 } else if ((c & 0xf0) == 0xe0) {
276 /* Three-byte sequence. */
277 t->t_utf8_left = 2;
278 t->t_utf8_partial = c & 0x0f;
279 } else if ((c & 0xf8) == 0xf0) {
280 /* Four-byte sequence. */
281 t->t_utf8_left = 3;
282 t->t_utf8_partial = c & 0x07;
283 } else if ((c & 0xc0) == 0x80) {
284 if (t->t_utf8_left == 0)
285 return;
286 t->t_utf8_left--;
287 t->t_utf8_partial = (t->t_utf8_partial << 6) | (c & 0x3f);
288 if (t->t_utf8_left == 0) {
289 teken_printf("Got UTF-8 char %u\n", t->t_utf8_partial);
290 teken_input_char(t, t->t_utf8_partial);
291 }
292 }
293#else /* !TEKEN_UTF8 */
294 teken_input_char(t, c);
295#endif /* TEKEN_UTF8 */
296}
297
298void
299teken_input(teken_t *t, const void *buf, size_t len)
300{
301 const char *c = buf;
302
303 while (len-- > 0)
304 teken_input_byte(t, *c++);
305}
306
307void
308teken_set_cursor(teken_t *t, const teken_pos_t *p)
309{
310
311 /* XXX: bounds checking with originreg! */
312 teken_assert(p->tp_row < t->t_winsize.tp_row);
313 teken_assert(p->tp_col < t->t_winsize.tp_col);
314
315 t->t_cursor = *p;
316}
317
318void
319teken_set_defattr(teken_t *t, const teken_attr_t *a)
320{
321
322 t->t_curattr = t->t_saved_curattr = t->t_defattr = *a;
323}
324
325void
326teken_set_winsize(teken_t *t, const teken_pos_t *p)
327{
328
329 teken_assert(p->tp_col <= T_NUMCOL);
330
331 t->t_winsize = *p;
332 /* XXX: bounds checking with cursor/etc! */
333 t->t_scrollreg.ts_begin = 0;
334 t->t_scrollreg.ts_end = t->t_winsize.tp_row;
335 t->t_originreg = t->t_scrollreg;
336}
337
338/*
339 * State machine.
340 */
341
342static void
343teken_state_switch(teken_t *t, teken_state_t *s)
344{
345
346 t->t_nextstate = s;
347 t->t_curnum = 0;
348 t->t_stateflags |= TS_FIRSTDIGIT;
349}
350
351static int
352teken_state_numbers(teken_t *t, teken_char_t c)
353{
354
355 teken_assert(t->t_curnum < T_NUMSIZE);
356
357 if (c >= '0' && c <= '9') {
358 /*
359 * Don't do math with the default value of 1 when a
360 * custom number is inserted.
361 */
362 if (t->t_stateflags & TS_FIRSTDIGIT) {
363 t->t_stateflags &= ~TS_FIRSTDIGIT;
364 t->t_nums[t->t_curnum] = 0;
365 } else {
366 t->t_nums[t->t_curnum] *= 10;
367 }
368
369 t->t_nums[t->t_curnum] += c - '0';
370 return (1);
371 } else if (c == ';') {
372 if (t->t_stateflags & TS_FIRSTDIGIT)
373 t->t_nums[t->t_curnum] = 0;
374
375 /* Only allow a limited set of arguments. */
376 if (++t->t_curnum == T_NUMSIZE) {
377 teken_state_switch(t, teken_state_init);
378 return (1);
379 }
380
381 t->t_stateflags |= TS_FIRSTDIGIT;
382 return (1);
383 } else {
384 if (t->t_stateflags & TS_FIRSTDIGIT && t->t_curnum > 0) {
385 /* Finish off the last empty argument. */
386 t->t_nums[t->t_curnum] = 0;
387 t->t_curnum++;
388 } else if ((t->t_stateflags & TS_FIRSTDIGIT) == 0) {
389 /* Also count the last argument. */
390 t->t_curnum++;
391 }
392 }
393
394 return (0);
395}
396
397#include "teken_state.h"