Index: head/sys/teken/libteken/teken.3 =================================================================== --- head/sys/teken/libteken/teken.3 (revision 332296) +++ head/sys/teken/libteken/teken.3 (revision 332297) @@ -1,234 +1,234 @@ .\" Copyright (c) 2011 Ed Schouten .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd Mar 13, 2017 .Dt TEKEN 3 .Os .Sh NAME .Nm teken .Nd xterm-like terminal emulation interface .Sh LIBRARY .Lb libteken .Sh SYNOPSIS .In teken.h .Ft void .Fn teken_init "teken_t *t" "const teken_funcs_t *funcs" "void *thunk" .Ft void .Fn teken_input "teken_t *t" "const void *buf" "size_t nbytes" .Ft const teken_pos_t * .Fn teken_get_winsize "teken_t *t" .Ft void .Fn teken_set_winsize "teken_t *t" "const teken_pos_t *size" .Ft const teken_pos_t * -.Fn teken_get_cursor "teken_t *t" +.Fn teken_get_cursor "const teken_t *t" .Ft void .Fn teken_set_cursor "teken_t *t" "const teken_pos_t *pos" .Ft const teken_attr_t * -.Fn teken_get_curattr "teken_t *t" +.Fn teken_get_curattr "const teken_t *t" .Ft void .Fn teken_set_curattr "teken_t *t" "const teken_attr_t *attr" .Ft const teken_attr_t * -.Fn teken_get_defattr "teken_t *t" +.Fn teken_get_defattr "const teken_t *t" .Ft void .Fn teken_set_defattr "teken_t *t" "const teken_attr_t *attr" .Ft const char * -.Fn teken_get_sequence "teken_t *t" "unsigned int id" +.Fn teken_get_sequence "const teken_t *t" "unsigned int id" .Ft teken_color_t .Fn teken_256to16 "teken_color_t color" .Ft teken_color_t .Fn teken_256to8 "teken_color_t color" .Ft void -.Fn teken_get_defattr_cons25 "teken_t *t" "int *fg" "int *bg" +.Fn teken_get_defattr_cons25 "const teken_t *t" "int *fg" "int *bg" .Ft void .Fn teken_set_8bit "teken_t *t" .Ft void .Fn teken_set_cons25 "teken_t *t" .Sh DESCRIPTION The .Nm library implements the input parser of a 256-color xterm-like terminal. It converts a stream of UTF-8 encoded characters into a series of primitive drawing instructions that can be used by a console driver or terminal emulator to render a terminal application. .Pp The .Fn teken_init function is used to initialize terminal state object .Fa t , having type .Vt teken_t . The supplied .Vt teken_funcs_t structure .Fa funcs contains a set of callback functions, which are called when supplying data to .Fn teken_input . The .Fa thunk argument stores an arbitrary pointer, which is passed to each invocation of the callback functions. .Pp The .Vt teken_funcs_t structure stores the following callbacks: .Bd -literal -offset indent typedef struct { tf_bell_t *tf_bell; /* Audible/visible bell. */ tf_cursor_t *tf_cursor; /* Move cursor to x/y. */ tf_putchar_t *tf_putchar; /* Put Unicode character at x/y. */ tf_fill_t *tf_fill; /* Fill rectangle with character. */ tf_copy_t *tf_copy; /* Copy rectangle to new location. */ tf_param_t *tf_param; /* Miscellaneous options. */ tf_respond_t *tf_respond; /* Send response string to user. */ } teken_funcs_t; .Ed .Pp All callbacks must be provided, though unimplemented callbacks may some times be sufficient. The actual types of these callbacks can be found in .In teken.h . .Pp By default, .Fn teken_init initializes the .Vt teken_t structure to emulate a terminal having 24 rows and 80 columns. The .Fn teken_get_winsize and .Fn teken_set_winsize functions can be used to obtain and modify the dimensions of the terminal. .Pp Even though the cursor position is normally controlled by input of data through .Fn teken_input and returned by the .Fn tf_cursor callback, it can be obtained and modified manually using the .Fn teken_get_cursor and .Fn teken_set_cursor functions. The same holds for .Fn teken_get_curattr and .Fn teken_set_curattr , which can be used to change the currently selected font attributes and foreground and background color. .Pp By default, .Nm emulates a white-on-black terminal, which means the default foreground color is white, while the background color is black. These defaults can be modified using .Fn teken_get_defattr and .Fn teken_set_defattr . .Pp The .Fn teken_get_sequence function is a utility function that can be used to obtain escape sequences of special keyboard keys, generated by user input. The .Fa id parameter must be one of the .Dv TKEY_* parameters listed in .In teken.h . .Sh LEGACY FEATURES This library also provides a set of functions that shouldn't be used in any modern applications. .Pp The .Fn teken_256to16 function converts an xterm-256 256-color code to an xterm 16-color code whose color with default palettes is as similar as possible (not very similar). The lower 3 bits of the result are the ANSI color and the next lowest bit is brightness. Other layers (hardare and software) that only support 16 colors can use this to avoid knowing the details of 256-color codes. .Pp The .Fn teken_256to8 function is similar to .Fn teken_256to16 except it converts to an ANSI 8-color code. This is more accurate than discarding the brigtness bit in the result of .Fn teken_256to16 . .Pp The .Fn teken_get_defattr_cons25 function obtains the default terminal attributes as a pair of foreground and background colors, using ANSI color numbering. .Pp The .Fn teken_set_8bit function disables UTF-8 processing and switches to 8-bit character mode, which can be used to support character sets like CP437 and ISO-8859-1. .Pp The .Fn teken_set_cons25 function switches terminal emulation to .Dv cons25 , which is used by versions of .Fx prior to 9.0. .Sh SEE ALSO .Xr ncurses 3 , .Xr termcap 3 , .Xr syscons 4 .Sh HISTORY The .Nm library appeared in .Fx 8.0 , though it was only available and used inside the kernel. In .Fx 9.0 , the .Nm library appeared in userspace. .Sh AUTHORS .An Ed Schouten Aq ed@FreeBSD.org .Sh SECURITY CONSIDERATIONS The .Fn tf_respond callback is used to respond to device status requests commands generated by an application. In the past, there have been various security issues, where a malicious application sends a device status request before termination, causing the generated response to be interpreted by applications such as .Xr sh 1 . .Pp .Nm only implements a small subset of responses which are unlikely to cause any harm. Still, it is advised to leave .Fn tf_respond unimplemented. Index: head/sys/teken/teken.c =================================================================== --- head/sys/teken/teken.c (revision 332296) +++ head/sys/teken/teken.c (revision 332297) @@ -1,716 +1,723 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2008-2009 Ed Schouten * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #if defined(__FreeBSD__) && defined(_KERNEL) #include #include #include #include #define teken_assert(x) MPASS(x) #else /* !(__FreeBSD__ && _KERNEL) */ #include #include #include #include #include #include #define teken_assert(x) assert(x) #endif /* __FreeBSD__ && _KERNEL */ /* debug messages */ #define teken_printf(x,...) /* Private flags for t_stateflags. */ #define TS_FIRSTDIGIT 0x0001 /* First numeric digit in escape sequence. */ #define TS_INSERT 0x0002 /* Insert mode. */ #define TS_AUTOWRAP 0x0004 /* Autowrap. */ #define TS_ORIGIN 0x0008 /* Origin mode. */ #define TS_WRAPPED 0x0010 /* Next character should be printed on col 0. */ #define TS_8BIT 0x0020 /* UTF-8 disabled. */ #define TS_CONS25 0x0040 /* cons25 emulation. */ #define TS_INSTRING 0x0080 /* Inside string. */ #define TS_CURSORKEYS 0x0100 /* Cursor keys mode. */ /* Character that blanks a cell. */ #define BLANK ' ' #include "teken.h" #include "teken_wcwidth.h" #include "teken_scs.h" static teken_state_t teken_state_init; /* * Wrappers for hooks. */ static inline void -teken_funcs_bell(teken_t *t) +teken_funcs_bell(const teken_t *t) { + teken_assert(t->t_funcs->tf_bell != NULL); t->t_funcs->tf_bell(t->t_softc); } static inline void -teken_funcs_cursor(teken_t *t) +teken_funcs_cursor(const teken_t *t) { teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row); teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col); + teken_assert(t->t_funcs->tf_cursor != NULL); t->t_funcs->tf_cursor(t->t_softc, &t->t_cursor); } static inline void -teken_funcs_putchar(teken_t *t, const teken_pos_t *p, teken_char_t c, +teken_funcs_putchar(const teken_t *t, const teken_pos_t *p, teken_char_t c, const teken_attr_t *a) { teken_assert(p->tp_row < t->t_winsize.tp_row); teken_assert(p->tp_col < t->t_winsize.tp_col); + teken_assert(t->t_funcs->tf_putchar != NULL); t->t_funcs->tf_putchar(t->t_softc, p, c, a); } static inline void -teken_funcs_fill(teken_t *t, const teken_rect_t *r, +teken_funcs_fill(const teken_t *t, const teken_rect_t *r, const teken_char_t c, const teken_attr_t *a) { teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row); teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row); teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col); teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col); + teken_assert(t->t_funcs->tf_fill != NULL); t->t_funcs->tf_fill(t->t_softc, r, c, a); } static inline void -teken_funcs_copy(teken_t *t, const teken_rect_t *r, const teken_pos_t *p) +teken_funcs_copy(const teken_t *t, const teken_rect_t *r, const teken_pos_t *p) { teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row); teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row); teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col); teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col); teken_assert(p->tp_row + (r->tr_end.tp_row - r->tr_begin.tp_row) <= t->t_winsize.tp_row); teken_assert(p->tp_col + (r->tr_end.tp_col - r->tr_begin.tp_col) <= t->t_winsize.tp_col); + teken_assert(t->t_funcs->tf_copy != NULL); t->t_funcs->tf_copy(t->t_softc, r, p); } static inline void -teken_funcs_param(teken_t *t, int cmd, unsigned int value) +teken_funcs_param(const teken_t *t, int cmd, unsigned int value) { + teken_assert(t->t_funcs->tf_param != NULL); t->t_funcs->tf_param(t->t_softc, cmd, value); } static inline void -teken_funcs_respond(teken_t *t, const void *buf, size_t len) +teken_funcs_respond(const teken_t *t, const void *buf, size_t len) { + teken_assert(t->t_funcs->tf_respond != NULL); t->t_funcs->tf_respond(t->t_softc, buf, len); } #include "teken_subr.h" #include "teken_subr_compat.h" /* * Programming interface. */ void teken_init(teken_t *t, const teken_funcs_t *tf, void *softc) { teken_pos_t tp = { .tp_row = 24, .tp_col = 80 }; t->t_funcs = tf; t->t_softc = softc; t->t_nextstate = teken_state_init; t->t_stateflags = 0; t->t_utf8_left = 0; t->t_defattr.ta_format = 0; t->t_defattr.ta_fgcolor = TC_WHITE; t->t_defattr.ta_bgcolor = TC_BLACK; teken_subr_do_reset(t); teken_set_winsize(t, &tp); } static void teken_input_char(teken_t *t, teken_char_t c) { /* * There is no support for DCS and OSC. Just discard strings * until we receive characters that may indicate string * termination. */ if (t->t_stateflags & TS_INSTRING) { switch (c) { case '\x1B': t->t_stateflags &= ~TS_INSTRING; break; case '\a': t->t_stateflags &= ~TS_INSTRING; return; default: return; } } switch (c) { case '\0': break; case '\a': teken_subr_bell(t); break; case '\b': teken_subr_backspace(t); break; case '\n': case '\x0B': teken_subr_newline(t); break; case '\x0C': teken_subr_newpage(t); break; case '\x0E': if (t->t_stateflags & TS_CONS25) t->t_nextstate(t, c); else t->t_curscs = 1; break; case '\x0F': if (t->t_stateflags & TS_CONS25) t->t_nextstate(t, c); else t->t_curscs = 0; break; case '\r': teken_subr_carriage_return(t); break; case '\t': teken_subr_horizontal_tab(t); break; default: t->t_nextstate(t, c); break; } /* Post-processing assertions. */ teken_assert(t->t_cursor.tp_row >= t->t_originreg.ts_begin); teken_assert(t->t_cursor.tp_row < t->t_originreg.ts_end); teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row); teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col); teken_assert(t->t_saved_cursor.tp_row < t->t_winsize.tp_row); teken_assert(t->t_saved_cursor.tp_col < t->t_winsize.tp_col); teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row); teken_assert(t->t_scrollreg.ts_begin < t->t_scrollreg.ts_end); /* Origin region has to be window size or the same as scrollreg. */ teken_assert((t->t_originreg.ts_begin == t->t_scrollreg.ts_begin && t->t_originreg.ts_end == t->t_scrollreg.ts_end) || (t->t_originreg.ts_begin == 0 && t->t_originreg.ts_end == t->t_winsize.tp_row)); } static void teken_input_byte(teken_t *t, unsigned char c) { /* * UTF-8 handling. */ if ((c & 0x80) == 0x00 || t->t_stateflags & TS_8BIT) { /* One-byte sequence. */ t->t_utf8_left = 0; teken_input_char(t, c); } else if ((c & 0xe0) == 0xc0) { /* Two-byte sequence. */ t->t_utf8_left = 1; t->t_utf8_partial = c & 0x1f; } else if ((c & 0xf0) == 0xe0) { /* Three-byte sequence. */ t->t_utf8_left = 2; t->t_utf8_partial = c & 0x0f; } else if ((c & 0xf8) == 0xf0) { /* Four-byte sequence. */ t->t_utf8_left = 3; t->t_utf8_partial = c & 0x07; } else if ((c & 0xc0) == 0x80) { if (t->t_utf8_left == 0) return; t->t_utf8_left--; t->t_utf8_partial = (t->t_utf8_partial << 6) | (c & 0x3f); if (t->t_utf8_left == 0) { teken_printf("Got UTF-8 char %x\n", t->t_utf8_partial); teken_input_char(t, t->t_utf8_partial); } } } void teken_input(teken_t *t, const void *buf, size_t len) { const char *c = buf; while (len-- > 0) teken_input_byte(t, *c++); } const teken_pos_t * -teken_get_cursor(teken_t *t) +teken_get_cursor(const teken_t *t) { return (&t->t_cursor); } void teken_set_cursor(teken_t *t, const teken_pos_t *p) { /* XXX: bounds checking with originreg! */ teken_assert(p->tp_row < t->t_winsize.tp_row); teken_assert(p->tp_col < t->t_winsize.tp_col); t->t_cursor = *p; } const teken_attr_t * -teken_get_curattr(teken_t *t) +teken_get_curattr(const teken_t *t) { return (&t->t_curattr); } void teken_set_curattr(teken_t *t, const teken_attr_t *a) { t->t_curattr = *a; } const teken_attr_t * -teken_get_defattr(teken_t *t) +teken_get_defattr(const teken_t *t) { return (&t->t_defattr); } void teken_set_defattr(teken_t *t, const teken_attr_t *a) { t->t_curattr = t->t_saved_curattr = t->t_defattr = *a; } const teken_pos_t * -teken_get_winsize(teken_t *t) +teken_get_winsize(const teken_t *t) { return (&t->t_winsize); } static void teken_trim_cursor_pos(teken_t *t, const teken_pos_t *new) { const teken_pos_t *cur; cur = &t->t_winsize; if (cur->tp_row < new->tp_row || cur->tp_col < new->tp_col) return; if (t->t_cursor.tp_row >= new->tp_row) t->t_cursor.tp_row = new->tp_row - 1; if (t->t_cursor.tp_col >= new->tp_col) t->t_cursor.tp_col = new->tp_col - 1; } void teken_set_winsize(teken_t *t, const teken_pos_t *p) { teken_trim_cursor_pos(t, p); t->t_winsize = *p; teken_subr_do_reset(t); } void teken_set_winsize_noreset(teken_t *t, const teken_pos_t *p) { teken_trim_cursor_pos(t, p); t->t_winsize = *p; teken_subr_do_resize(t); } void teken_set_8bit(teken_t *t) { t->t_stateflags |= TS_8BIT; } void teken_set_cons25(teken_t *t) { t->t_stateflags |= TS_CONS25; } /* * State machine. */ static void teken_state_switch(teken_t *t, teken_state_t *s) { t->t_nextstate = s; t->t_curnum = 0; t->t_stateflags |= TS_FIRSTDIGIT; } static int teken_state_numbers(teken_t *t, teken_char_t c) { teken_assert(t->t_curnum < T_NUMSIZE); if (c >= '0' && c <= '9') { if (t->t_stateflags & TS_FIRSTDIGIT) { /* First digit. */ t->t_stateflags &= ~TS_FIRSTDIGIT; t->t_nums[t->t_curnum] = c - '0'; } else if (t->t_nums[t->t_curnum] < UINT_MAX / 100) { /* * There is no need to continue parsing input * once the value exceeds the size of the * terminal. It would only allow for integer * overflows when performing arithmetic on the * cursor position. * * Ignore any further digits if the value is * already UINT_MAX / 100. */ t->t_nums[t->t_curnum] = t->t_nums[t->t_curnum] * 10 + c - '0'; } return (1); } else if (c == ';') { if (t->t_stateflags & TS_FIRSTDIGIT) t->t_nums[t->t_curnum] = 0; /* Only allow a limited set of arguments. */ if (++t->t_curnum == T_NUMSIZE) { teken_state_switch(t, teken_state_init); return (1); } t->t_stateflags |= TS_FIRSTDIGIT; return (1); } else { if (t->t_stateflags & TS_FIRSTDIGIT && t->t_curnum > 0) { /* Finish off the last empty argument. */ t->t_nums[t->t_curnum] = 0; t->t_curnum++; } else if ((t->t_stateflags & TS_FIRSTDIGIT) == 0) { /* Also count the last argument. */ t->t_curnum++; } } return (0); } #define k TC_BLACK #define b TC_BLUE #define y TC_BROWN #define c TC_CYAN #define g TC_GREEN #define m TC_MAGENTA #define r TC_RED #define w TC_WHITE #define K (TC_BLACK | TC_LIGHT) #define B (TC_BLUE | TC_LIGHT) #define Y (TC_BROWN | TC_LIGHT) #define C (TC_CYAN | TC_LIGHT) #define G (TC_GREEN | TC_LIGHT) #define M (TC_MAGENTA | TC_LIGHT) #define R (TC_RED | TC_LIGHT) #define W (TC_WHITE | TC_LIGHT) /** * The xterm-256 color map has steps of 0x28 (in the range 0-0xff), except * for the first step which is 0x5f. Scale to the range 0-6 by dividing * by 0x28 and rounding down. The range of 0-5 cannot represent the * larger first step. * * This table is generated by the follow rules: * - if all components are equal, the result is black for (0, 0, 0) and * (2, 2, 2), else white; otherwise: * - subtract the smallest component from all components * - if this gives only one nonzero component, then that is the color * - else if one component is 2 or more larger than the other nonzero one, * then that component gives the color * - else there are 2 nonzero components. The color is that of a small * equal mixture of these components (cyan, yellow or magenta). E.g., * (0, 5, 6) (Turquoise2) is a much purer cyan than (0, 2, 3) * (DeepSkyBlue4), but we map both to cyan since we can't represent * delicate shades of either blue or cyan and blue would be worse. * Here it is important that components of 1 never occur. Blue would * be twice as large as green in (0, 1, 2). */ static const teken_color_t teken_256to8tab[] = { /* xterm normal colors: */ k, r, g, y, b, m, c, w, /* xterm bright colors: */ k, r, g, y, b, m, c, w, /* Red0 submap. */ k, b, b, b, b, b, g, c, c, b, b, b, g, c, c, c, b, b, g, g, c, c, c, b, g, g, g, c, c, c, g, g, g, g, c, c, /* Red2 submap. */ r, m, m, b, b, b, y, k, b, b, b, b, y, g, c, c, b, b, g, g, c, c, c, b, g, g, g, c, c, c, g, g, g, g, c, c, /* Red3 submap. */ r, m, m, m, b, b, y, r, m, m, b, b, y, y, w, b, b, b, y, y, g, c, c, b, g, g, g, c, c, c, g, g, g, g, c, c, /* Red4 submap. */ r, r, m, m, m, b, r, r, m, m, m, b, y, y, r, m, m, b, y, y, y, w, b, b, y, y, y, g, c, c, g, g, g, g, c, c, /* Red5 submap. */ r, r, r, m, m, m, r, r, r, m, m, m, r, r, r, m, m, m, y, y, y, r, m, m, y, y, y, y, w, b, y, y, y, y, g, c, /* Red6 submap. */ r, r, r, r, m, m, r, r, r, r, m, m, r, r, r, r, m, m, r, r, r, r, m, m, y, y, y, y, r, m, y, y, y, y, y, w, /* Grey submap. */ k, k, k, k, k, k, k, k, k, k, k, k, w, w, w, w, w, w, w, w, w, w, w, w, }; /* * This table is generated from the previous one by setting TC_LIGHT for * entries whose luminosity in the xterm256 color map is 60% or larger. * Thus the previous table is currently not really needed. It will be * used for different fine tuning of the tables. */ static const teken_color_t teken_256to16tab[] = { /* xterm normal colors: */ k, r, g, y, b, m, c, w, /* xterm bright colors: */ K, R, G, Y, B, M, C, W, /* Red0 submap. */ k, b, b, b, b, b, g, c, c, b, b, b, g, c, c, c, b, b, g, g, c, c, c, b, g, g, g, c, c, c, g, g, g, g, c, c, /* Red2 submap. */ r, m, m, b, b, b, y, K, b, b, B, B, y, g, c, c, B, B, g, g, c, c, C, B, g, G, G, C, C, C, g, G, G, G, C, C, /* Red3 submap. */ r, m, m, m, b, b, y, r, m, m, B, B, y, y, w, B, B, B, y, y, G, C, C, B, g, G, G, C, C, C, g, G, G, G, C, C, /* Red4 submap. */ r, r, m, m, m, b, r, r, m, m, M, B, y, y, R, M, M, B, y, y, Y, W, B, B, y, Y, Y, G, C, C, g, G, G, G, C, C, /* Red5 submap. */ r, r, r, m, m, m, r, R, R, M, M, M, r, R, R, M, M, M, y, Y, Y, R, M, M, y, Y, Y, Y, W, B, y, Y, Y, Y, G, C, /* Red6 submap. */ r, r, r, r, m, m, r, R, R, R, M, M, r, R, R, R, M, M, r, R, R, R, M, M, y, Y, Y, Y, R, M, y, Y, Y, Y, Y, W, /* Grey submap. */ k, k, k, k, k, k, K, K, K, K, K, K, w, w, w, w, w, w, W, W, W, W, W, W, }; #undef k #undef b #undef y #undef c #undef g #undef m #undef r #undef w #undef K #undef B #undef Y #undef C #undef G #undef M #undef R #undef W teken_color_t teken_256to8(teken_color_t c) { return (teken_256to8tab[c % 256]); } teken_color_t teken_256to16(teken_color_t c) { return (teken_256to16tab[c % 256]); } static const char * const special_strings_cons25[] = { [TKEY_UP] = "\x1B[A", [TKEY_DOWN] = "\x1B[B", [TKEY_LEFT] = "\x1B[D", [TKEY_RIGHT] = "\x1B[C", [TKEY_HOME] = "\x1B[H", [TKEY_END] = "\x1B[F", [TKEY_INSERT] = "\x1B[L", [TKEY_DELETE] = "\x7F", [TKEY_PAGE_UP] = "\x1B[I", [TKEY_PAGE_DOWN] = "\x1B[G", [TKEY_F1] = "\x1B[M", [TKEY_F2] = "\x1B[N", [TKEY_F3] = "\x1B[O", [TKEY_F4] = "\x1B[P", [TKEY_F5] = "\x1B[Q", [TKEY_F6] = "\x1B[R", [TKEY_F7] = "\x1B[S", [TKEY_F8] = "\x1B[T", [TKEY_F9] = "\x1B[U", [TKEY_F10] = "\x1B[V", [TKEY_F11] = "\x1B[W", [TKEY_F12] = "\x1B[X", }; static const char * const special_strings_ckeys[] = { [TKEY_UP] = "\x1BOA", [TKEY_DOWN] = "\x1BOB", [TKEY_LEFT] = "\x1BOD", [TKEY_RIGHT] = "\x1BOC", [TKEY_HOME] = "\x1BOH", [TKEY_END] = "\x1BOF", }; static const char * const special_strings_normal[] = { [TKEY_UP] = "\x1B[A", [TKEY_DOWN] = "\x1B[B", [TKEY_LEFT] = "\x1B[D", [TKEY_RIGHT] = "\x1B[C", [TKEY_HOME] = "\x1B[H", [TKEY_END] = "\x1B[F", [TKEY_INSERT] = "\x1B[2~", [TKEY_DELETE] = "\x1B[3~", [TKEY_PAGE_UP] = "\x1B[5~", [TKEY_PAGE_DOWN] = "\x1B[6~", [TKEY_F1] = "\x1BOP", [TKEY_F2] = "\x1BOQ", [TKEY_F3] = "\x1BOR", [TKEY_F4] = "\x1BOS", [TKEY_F5] = "\x1B[15~", [TKEY_F6] = "\x1B[17~", [TKEY_F7] = "\x1B[18~", [TKEY_F8] = "\x1B[19~", [TKEY_F9] = "\x1B[20~", [TKEY_F10] = "\x1B[21~", [TKEY_F11] = "\x1B[23~", [TKEY_F12] = "\x1B[24~", }; const char * -teken_get_sequence(teken_t *t, unsigned int k) +teken_get_sequence(const teken_t *t, unsigned int k) { /* Cons25 mode. */ if (t->t_stateflags & TS_CONS25 && k < sizeof special_strings_cons25 / sizeof(char *)) return (special_strings_cons25[k]); /* Cursor keys mode. */ if (t->t_stateflags & TS_CURSORKEYS && k < sizeof special_strings_ckeys / sizeof(char *)) return (special_strings_ckeys[k]); /* Default xterm sequences. */ if (k < sizeof special_strings_normal / sizeof(char *)) return (special_strings_normal[k]); return (NULL); } #include "teken_state.h" Index: head/sys/teken/teken.h =================================================================== --- head/sys/teken/teken.h (revision 332296) +++ head/sys/teken/teken.h (revision 332297) @@ -1,215 +1,215 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2008-2009 Ed Schouten * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _TEKEN_H_ #define _TEKEN_H_ #include /* * libteken: terminal emulation library. * * This library converts an UTF-8 stream of bytes to terminal drawing * commands. */ typedef uint32_t teken_char_t; typedef unsigned short teken_unit_t; typedef unsigned char teken_format_t; #define TF_BOLD 0x01 /* Bold character. */ #define TF_UNDERLINE 0x02 /* Underline character. */ #define TF_BLINK 0x04 /* Blinking character. */ #define TF_REVERSE 0x08 /* Reverse rendered character. */ #define TF_CJK_RIGHT 0x10 /* Right-hand side of CJK character. */ typedef unsigned char teken_color_t; #define TC_BLACK 0 #define TC_RED 1 #define TC_GREEN 2 #define TC_BROWN 3 #define TC_BLUE 4 #define TC_MAGENTA 5 #define TC_CYAN 6 #define TC_WHITE 7 #define TC_NCOLORS 8 #define TC_LIGHT 8 /* ORed with the others. */ typedef struct { teken_unit_t tp_row; teken_unit_t tp_col; } teken_pos_t; typedef struct { teken_pos_t tr_begin; teken_pos_t tr_end; } teken_rect_t; typedef struct { teken_format_t ta_format; teken_color_t ta_fgcolor; teken_color_t ta_bgcolor; } teken_attr_t; typedef struct { teken_unit_t ts_begin; teken_unit_t ts_end; } teken_span_t; typedef struct __teken teken_t; typedef void teken_state_t(teken_t *, teken_char_t); /* * Drawing routines supplied by the user. */ typedef void tf_bell_t(void *); typedef void tf_cursor_t(void *, const teken_pos_t *); typedef void tf_putchar_t(void *, const teken_pos_t *, teken_char_t, const teken_attr_t *); typedef void tf_fill_t(void *, const teken_rect_t *, teken_char_t, const teken_attr_t *); typedef void tf_copy_t(void *, const teken_rect_t *, const teken_pos_t *); typedef void tf_param_t(void *, int, unsigned int); #define TP_SHOWCURSOR 0 #define TP_KEYPADAPP 1 #define TP_AUTOREPEAT 2 #define TP_SWITCHVT 3 #define TP_132COLS 4 #define TP_SETBELLPD 5 #define TP_SETBELLPD_PITCH(pd) ((pd) >> 16) #define TP_SETBELLPD_DURATION(pd) ((pd) & 0xffff) #define TP_MOUSE 6 #define TP_SETBORDER 7 #define TP_SETLOCALCURSOR 8 #define TP_SETGLOBALCURSOR 9 typedef void tf_respond_t(void *, const void *, size_t); typedef struct { tf_bell_t *tf_bell; tf_cursor_t *tf_cursor; tf_putchar_t *tf_putchar; tf_fill_t *tf_fill; tf_copy_t *tf_copy; tf_param_t *tf_param; tf_respond_t *tf_respond; } teken_funcs_t; -typedef teken_char_t teken_scs_t(teken_t *, teken_char_t); +typedef teken_char_t teken_scs_t(const teken_t *, teken_char_t); /* * Terminal state. */ struct __teken { const teken_funcs_t *t_funcs; void *t_softc; teken_state_t *t_nextstate; unsigned int t_stateflags; #define T_NUMSIZE 8 unsigned int t_nums[T_NUMSIZE]; unsigned int t_curnum; teken_pos_t t_cursor; teken_attr_t t_curattr; teken_pos_t t_saved_cursor; teken_attr_t t_saved_curattr; teken_attr_t t_defattr; teken_pos_t t_winsize; /* For DECSTBM. */ teken_span_t t_scrollreg; /* For DECOM. */ teken_span_t t_originreg; #define T_NUMCOL 160 unsigned int t_tabstops[T_NUMCOL / (sizeof(unsigned int) * 8)]; unsigned int t_utf8_left; teken_char_t t_utf8_partial; unsigned int t_curscs; teken_scs_t *t_saved_curscs; teken_scs_t *t_scs[2]; }; /* Initialize teken structure. */ void teken_init(teken_t *, const teken_funcs_t *, void *); /* Deliver character input. */ void teken_input(teken_t *, const void *, size_t); /* Get/set teken attributes. */ -const teken_pos_t *teken_get_cursor(teken_t *); -const teken_attr_t *teken_get_curattr(teken_t *); -const teken_attr_t *teken_get_defattr(teken_t *); -void teken_get_defattr_cons25(teken_t *, int *, int *); -const teken_pos_t *teken_get_winsize(teken_t *); +const teken_pos_t *teken_get_cursor(const teken_t *); +const teken_attr_t *teken_get_curattr(const teken_t *); +const teken_attr_t *teken_get_defattr(const teken_t *); +void teken_get_defattr_cons25(const teken_t *, int *, int *); +const teken_pos_t *teken_get_winsize(const teken_t *); void teken_set_cursor(teken_t *, const teken_pos_t *); void teken_set_curattr(teken_t *, const teken_attr_t *); void teken_set_defattr(teken_t *, const teken_attr_t *); void teken_set_winsize(teken_t *, const teken_pos_t *); void teken_set_winsize_noreset(teken_t *, const teken_pos_t *); /* Key input escape sequences. */ #define TKEY_UP 0x00 #define TKEY_DOWN 0x01 #define TKEY_LEFT 0x02 #define TKEY_RIGHT 0x03 #define TKEY_HOME 0x04 #define TKEY_END 0x05 #define TKEY_INSERT 0x06 #define TKEY_DELETE 0x07 #define TKEY_PAGE_UP 0x08 #define TKEY_PAGE_DOWN 0x09 #define TKEY_F1 0x0a #define TKEY_F2 0x0b #define TKEY_F3 0x0c #define TKEY_F4 0x0d #define TKEY_F5 0x0e #define TKEY_F6 0x0f #define TKEY_F7 0x10 #define TKEY_F8 0x11 #define TKEY_F9 0x12 #define TKEY_F10 0x13 #define TKEY_F11 0x14 #define TKEY_F12 0x15 -const char *teken_get_sequence(teken_t *, unsigned int); +const char *teken_get_sequence(const teken_t *, unsigned int); /* Legacy features. */ void teken_set_8bit(teken_t *); void teken_set_cons25(teken_t *); /* Color conversion. */ teken_color_t teken_256to16(teken_color_t); teken_color_t teken_256to8(teken_color_t); #endif /* !_TEKEN_H_ */ Index: head/sys/teken/teken_scs.h =================================================================== --- head/sys/teken/teken_scs.h (revision 332296) +++ head/sys/teken/teken_scs.h (revision 332297) @@ -1,82 +1,83 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2009 Ed Schouten * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ static inline teken_char_t -teken_scs_process(teken_t *t, teken_char_t c) +teken_scs_process(const teken_t *t, teken_char_t c) { return (t->t_scs[t->t_curscs](t, c)); } /* Unicode points for VT100 box drawing. */ static const uint16_t teken_boxdrawing_unicode[31] = { 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7 }; /* ASCII points for VT100 box drawing. */ static const uint8_t teken_boxdrawing_8bit[31] = { '?', '?', 'H', 'F', 'C', 'L', '?', '?', 'N', 'V', '+', '+', '+', '+', '+', '-', '-', '-', '-', '-', '+', '+', '+', '+', '|', '?', '?', '?', '?', '?', '?', }; static teken_char_t -teken_scs_special_graphics(teken_t *t, teken_char_t c) +teken_scs_special_graphics(const teken_t *t, teken_char_t c) { /* Box drawing. */ if (c >= '`' && c <= '~') return (t->t_stateflags & TS_8BIT ? teken_boxdrawing_8bit[c - '`'] : teken_boxdrawing_unicode[c - '`']); return (c); } static teken_char_t -teken_scs_uk_national(teken_t *t, teken_char_t c) +teken_scs_uk_national(const teken_t *t, teken_char_t c) { /* Pound sign. */ if (c == '#') return (t->t_stateflags & TS_8BIT ? 0x9c : 0xa3); return (c); } static teken_char_t -teken_scs_us_ascii(teken_t *t __unused, teken_char_t c) +teken_scs_us_ascii(const teken_t *t, teken_char_t c) { /* No processing. */ + (void)t; return (c); } Index: head/sys/teken/teken_subr.h =================================================================== --- head/sys/teken/teken_subr.h (revision 332296) +++ head/sys/teken/teken_subr.h (revision 332297) @@ -1,1308 +1,1315 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2008-2009 Ed Schouten * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ static void teken_subr_cursor_up(teken_t *, unsigned int); -static void teken_subr_erase_line(teken_t *, unsigned int); +static void teken_subr_erase_line(const teken_t *, unsigned int); static void teken_subr_regular_character(teken_t *, teken_char_t); static void teken_subr_reset_to_initial_state(teken_t *); static void teken_subr_save_cursor(teken_t *); static inline int -teken_tab_isset(teken_t *t, unsigned int col) +teken_tab_isset(const teken_t *t, unsigned int col) { unsigned int b, o; if (col >= T_NUMCOL) return ((col % 8) == 0); b = col / (sizeof(unsigned int) * 8); o = col % (sizeof(unsigned int) * 8); - return (t->t_tabstops[b] & (1 << o)); + return (t->t_tabstops[b] & (1U << o)); } static inline void teken_tab_clear(teken_t *t, unsigned int col) { unsigned int b, o; if (col >= T_NUMCOL) return; b = col / (sizeof(unsigned int) * 8); o = col % (sizeof(unsigned int) * 8); - t->t_tabstops[b] &= ~(1 << o); + t->t_tabstops[b] &= ~(1U << o); } static inline void teken_tab_set(teken_t *t, unsigned int col) { unsigned int b, o; if (col >= T_NUMCOL) return; b = col / (sizeof(unsigned int) * 8); o = col % (sizeof(unsigned int) * 8); - t->t_tabstops[b] |= 1 << o; + t->t_tabstops[b] |= 1U << o; } static void teken_tab_default(teken_t *t) { unsigned int i; - memset(&t->t_tabstops, 0, T_NUMCOL / 8); + memset(t->t_tabstops, 0, T_NUMCOL / 8); for (i = 8; i < T_NUMCOL; i += 8) teken_tab_set(t, i); } static void -teken_subr_do_scroll(teken_t *t, int amount) +teken_subr_do_scroll(const teken_t *t, int amount) { teken_rect_t tr; teken_pos_t tp; teken_assert(t->t_cursor.tp_row <= t->t_winsize.tp_row); teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row); teken_assert(amount != 0); /* Copy existing data 1 line up. */ if (amount > 0) { /* Scroll down. */ /* Copy existing data up. */ if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) { tr.tr_begin.tp_row = t->t_scrollreg.ts_begin + amount; tr.tr_begin.tp_col = 0; tr.tr_end.tp_row = t->t_scrollreg.ts_end; tr.tr_end.tp_col = t->t_winsize.tp_col; tp.tp_row = t->t_scrollreg.ts_begin; tp.tp_col = 0; teken_funcs_copy(t, &tr, &tp); tr.tr_begin.tp_row = t->t_scrollreg.ts_end - amount; } else { tr.tr_begin.tp_row = t->t_scrollreg.ts_begin; } /* Clear the last lines. */ tr.tr_begin.tp_col = 0; tr.tr_end.tp_row = t->t_scrollreg.ts_end; tr.tr_end.tp_col = t->t_winsize.tp_col; teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); } else { /* Scroll up. */ amount = -amount; /* Copy existing data down. */ if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) { tr.tr_begin.tp_row = t->t_scrollreg.ts_begin; tr.tr_begin.tp_col = 0; tr.tr_end.tp_row = t->t_scrollreg.ts_end - amount; tr.tr_end.tp_col = t->t_winsize.tp_col; tp.tp_row = t->t_scrollreg.ts_begin + amount; tp.tp_col = 0; teken_funcs_copy(t, &tr, &tp); tr.tr_end.tp_row = t->t_scrollreg.ts_begin + amount; } else { tr.tr_end.tp_row = t->t_scrollreg.ts_end; } /* Clear the first lines. */ tr.tr_begin.tp_row = t->t_scrollreg.ts_begin; tr.tr_begin.tp_col = 0; tr.tr_end.tp_col = t->t_winsize.tp_col; teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); } } static ssize_t -teken_subr_do_cpr(teken_t *t, unsigned int cmd, char response[16]) +teken_subr_do_cpr(const teken_t *t, unsigned int cmd, char response[16]) { switch (cmd) { case 5: /* Operating status. */ strcpy(response, "0n"); return (2); case 6: { /* Cursor position. */ int len; len = snprintf(response, 16, "%u;%uR", (t->t_cursor.tp_row - t->t_originreg.ts_begin) + 1, t->t_cursor.tp_col + 1); if (len >= 16) return (-1); return (len); } case 15: /* Printer status. */ strcpy(response, "13n"); return (3); case 25: /* UDK status. */ strcpy(response, "20n"); return (3); case 26: /* Keyboard status. */ strcpy(response, "27;1n"); return (5); default: teken_printf("Unknown DSR\n"); return (-1); } } static void teken_subr_alignment_test(teken_t *t) { teken_rect_t tr; t->t_cursor.tp_row = t->t_cursor.tp_col = 0; t->t_scrollreg.ts_begin = 0; t->t_scrollreg.ts_end = t->t_winsize.tp_row; t->t_originreg = t->t_scrollreg; t->t_stateflags &= ~(TS_WRAPPED|TS_ORIGIN); teken_funcs_cursor(t); tr.tr_begin.tp_row = 0; tr.tr_begin.tp_col = 0; tr.tr_end = t->t_winsize; teken_funcs_fill(t, &tr, 'E', &t->t_defattr); } static void teken_subr_backspace(teken_t *t) { if (t->t_stateflags & TS_CONS25) { if (t->t_cursor.tp_col == 0) { if (t->t_cursor.tp_row == t->t_originreg.ts_begin) return; t->t_cursor.tp_row--; t->t_cursor.tp_col = t->t_winsize.tp_col - 1; } else { t->t_cursor.tp_col--; } } else { if (t->t_cursor.tp_col == 0) return; t->t_cursor.tp_col--; t->t_stateflags &= ~TS_WRAPPED; } teken_funcs_cursor(t); } static void -teken_subr_bell(teken_t *t) +teken_subr_bell(const teken_t *t) { teken_funcs_bell(t); } static void teken_subr_carriage_return(teken_t *t) { t->t_cursor.tp_col = 0; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } static void teken_subr_cursor_backward(teken_t *t, unsigned int ncols) { if (ncols > t->t_cursor.tp_col) t->t_cursor.tp_col = 0; else t->t_cursor.tp_col -= ncols; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } static void teken_subr_cursor_backward_tabulation(teken_t *t, unsigned int ntabs) { do { /* Stop when we've reached the beginning of the line. */ if (t->t_cursor.tp_col == 0) break; t->t_cursor.tp_col--; /* Tab marker set. */ if (teken_tab_isset(t, t->t_cursor.tp_col)) ntabs--; } while (ntabs > 0); teken_funcs_cursor(t); } static void teken_subr_cursor_down(teken_t *t, unsigned int nrows) { if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1; else t->t_cursor.tp_row += nrows; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } static void teken_subr_cursor_forward(teken_t *t, unsigned int ncols) { if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) t->t_cursor.tp_col = t->t_winsize.tp_col - 1; else t->t_cursor.tp_col += ncols; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } static void teken_subr_cursor_forward_tabulation(teken_t *t, unsigned int ntabs) { do { /* Stop when we've reached the end of the line. */ if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1) break; t->t_cursor.tp_col++; /* Tab marker set. */ if (teken_tab_isset(t, t->t_cursor.tp_col)) ntabs--; } while (ntabs > 0); teken_funcs_cursor(t); } static void teken_subr_cursor_next_line(teken_t *t, unsigned int ncols) { t->t_cursor.tp_col = 0; teken_subr_cursor_down(t, ncols); } static void teken_subr_cursor_position(teken_t *t, unsigned int row, unsigned int col) { - row = row - 1 + t->t_originreg.ts_begin; + row = (row - 1) + t->t_originreg.ts_begin; t->t_cursor.tp_row = row < t->t_originreg.ts_end ? row : t->t_originreg.ts_end - 1; col--; t->t_cursor.tp_col = col < t->t_winsize.tp_col ? col : t->t_winsize.tp_col - 1; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } static void -teken_subr_cursor_position_report(teken_t *t, unsigned int cmd) +teken_subr_cursor_position_report(const teken_t *t, unsigned int cmd) { char response[18] = "\x1B["; ssize_t len; len = teken_subr_do_cpr(t, cmd, response + 2); if (len < 0) return; teken_funcs_respond(t, response, len + 2); } static void teken_subr_cursor_previous_line(teken_t *t, unsigned int ncols) { t->t_cursor.tp_col = 0; teken_subr_cursor_up(t, ncols); } static void teken_subr_cursor_up(teken_t *t, unsigned int nrows) { if (t->t_scrollreg.ts_begin + nrows >= t->t_cursor.tp_row) t->t_cursor.tp_row = t->t_scrollreg.ts_begin; else t->t_cursor.tp_row -= nrows; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } static void -teken_subr_delete_character(teken_t *t, unsigned int ncols) +teken_subr_delete_character(const teken_t *t, unsigned int ncols) { teken_rect_t tr; tr.tr_begin.tp_row = t->t_cursor.tp_row; tr.tr_end.tp_row = t->t_cursor.tp_row + 1; tr.tr_end.tp_col = t->t_winsize.tp_col; if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) { tr.tr_begin.tp_col = t->t_cursor.tp_col; } else { /* Copy characters to the left. */ tr.tr_begin.tp_col = t->t_cursor.tp_col + ncols; teken_funcs_copy(t, &tr, &t->t_cursor); tr.tr_begin.tp_col = t->t_winsize.tp_col - ncols; } /* Blank trailing columns. */ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); } static void -teken_subr_delete_line(teken_t *t, unsigned int nrows) +teken_subr_delete_line(const teken_t *t, unsigned int nrows) { teken_rect_t tr; /* Ignore if outside scrolling region. */ if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin || t->t_cursor.tp_row >= t->t_scrollreg.ts_end) return; tr.tr_begin.tp_col = 0; tr.tr_end.tp_row = t->t_scrollreg.ts_end; tr.tr_end.tp_col = t->t_winsize.tp_col; if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) { tr.tr_begin.tp_row = t->t_cursor.tp_row; } else { teken_pos_t tp; /* Copy rows up. */ tr.tr_begin.tp_row = t->t_cursor.tp_row + nrows; tp.tp_row = t->t_cursor.tp_row; tp.tp_col = 0; teken_funcs_copy(t, &tr, &tp); tr.tr_begin.tp_row = t->t_scrollreg.ts_end - nrows; } /* Blank trailing rows. */ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); } static void teken_subr_device_control_string(teken_t *t) { teken_printf("Unsupported device control string\n"); t->t_stateflags |= TS_INSTRING; } static void -teken_subr_device_status_report(teken_t *t, unsigned int cmd) +teken_subr_device_status_report(const teken_t *t, unsigned int cmd) { char response[19] = "\x1B[?"; ssize_t len; len = teken_subr_do_cpr(t, cmd, response + 3); if (len < 0) return; teken_funcs_respond(t, response, len + 3); } static void -teken_subr_double_height_double_width_line_top(teken_t *t __unused) +teken_subr_double_height_double_width_line_top(const teken_t *t) { + (void)t; teken_printf("double height double width top\n"); } static void -teken_subr_double_height_double_width_line_bottom(teken_t *t __unused) +teken_subr_double_height_double_width_line_bottom(const teken_t *t) { + (void)t; teken_printf("double height double width bottom\n"); } static void -teken_subr_erase_character(teken_t *t, unsigned int ncols) +teken_subr_erase_character(const teken_t *t, unsigned int ncols) { teken_rect_t tr; tr.tr_begin = t->t_cursor; tr.tr_end.tp_row = t->t_cursor.tp_row + 1; if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) tr.tr_end.tp_col = t->t_winsize.tp_col; else tr.tr_end.tp_col = t->t_cursor.tp_col + ncols; teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); } static void -teken_subr_erase_display(teken_t *t, unsigned int mode) +teken_subr_erase_display(const teken_t *t, unsigned int mode) { teken_rect_t r; r.tr_begin.tp_col = 0; r.tr_end.tp_col = t->t_winsize.tp_col; switch (mode) { case 1: /* Erase from the top to the cursor. */ teken_subr_erase_line(t, 1); /* Erase lines above. */ if (t->t_cursor.tp_row == 0) return; r.tr_begin.tp_row = 0; r.tr_end.tp_row = t->t_cursor.tp_row; break; case 2: /* Erase entire display. */ r.tr_begin.tp_row = 0; r.tr_end.tp_row = t->t_winsize.tp_row; break; default: /* Erase from cursor to the bottom. */ teken_subr_erase_line(t, 0); /* Erase lines below. */ if (t->t_cursor.tp_row == t->t_winsize.tp_row - 1) return; r.tr_begin.tp_row = t->t_cursor.tp_row + 1; r.tr_end.tp_row = t->t_winsize.tp_row; break; } teken_funcs_fill(t, &r, BLANK, &t->t_curattr); } static void -teken_subr_erase_line(teken_t *t, unsigned int mode) +teken_subr_erase_line(const teken_t *t, unsigned int mode) { teken_rect_t r; r.tr_begin.tp_row = t->t_cursor.tp_row; r.tr_end.tp_row = t->t_cursor.tp_row + 1; switch (mode) { case 1: /* Erase from the beginning of the line to the cursor. */ r.tr_begin.tp_col = 0; r.tr_end.tp_col = t->t_cursor.tp_col + 1; break; case 2: /* Erase entire line. */ r.tr_begin.tp_col = 0; r.tr_end.tp_col = t->t_winsize.tp_col; break; default: /* Erase from cursor to the end of the line. */ r.tr_begin.tp_col = t->t_cursor.tp_col; r.tr_end.tp_col = t->t_winsize.tp_col; break; } teken_funcs_fill(t, &r, BLANK, &t->t_curattr); } static void -teken_subr_g0_scs_special_graphics(teken_t *t __unused) +teken_subr_g0_scs_special_graphics(teken_t *t) { t->t_scs[0] = teken_scs_special_graphics; } static void -teken_subr_g0_scs_uk_national(teken_t *t __unused) +teken_subr_g0_scs_uk_national(teken_t *t) { t->t_scs[0] = teken_scs_uk_national; } static void -teken_subr_g0_scs_us_ascii(teken_t *t __unused) +teken_subr_g0_scs_us_ascii(teken_t *t) { t->t_scs[0] = teken_scs_us_ascii; } static void -teken_subr_g1_scs_special_graphics(teken_t *t __unused) +teken_subr_g1_scs_special_graphics(teken_t *t) { t->t_scs[1] = teken_scs_special_graphics; } static void -teken_subr_g1_scs_uk_national(teken_t *t __unused) +teken_subr_g1_scs_uk_national(teken_t *t) { t->t_scs[1] = teken_scs_uk_national; } static void -teken_subr_g1_scs_us_ascii(teken_t *t __unused) +teken_subr_g1_scs_us_ascii(teken_t *t) { t->t_scs[1] = teken_scs_us_ascii; } static void teken_subr_horizontal_position_absolute(teken_t *t, unsigned int col) { col--; t->t_cursor.tp_col = col < t->t_winsize.tp_col ? col : t->t_winsize.tp_col - 1; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } static void teken_subr_horizontal_tab(teken_t *t) { teken_subr_cursor_forward_tabulation(t, 1); } static void teken_subr_horizontal_tab_set(teken_t *t) { teken_tab_set(t, t->t_cursor.tp_col); } static void teken_subr_index(teken_t *t) { if (t->t_cursor.tp_row < t->t_scrollreg.ts_end - 1) { t->t_cursor.tp_row++; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } else { teken_subr_do_scroll(t, 1); } } static void -teken_subr_insert_character(teken_t *t, unsigned int ncols) +teken_subr_insert_character(const teken_t *t, unsigned int ncols) { teken_rect_t tr; tr.tr_begin = t->t_cursor; tr.tr_end.tp_row = t->t_cursor.tp_row + 1; if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) { tr.tr_end.tp_col = t->t_winsize.tp_col; } else { teken_pos_t tp; /* Copy characters to the right. */ tr.tr_end.tp_col = t->t_winsize.tp_col - ncols; tp.tp_row = t->t_cursor.tp_row; tp.tp_col = t->t_cursor.tp_col + ncols; teken_funcs_copy(t, &tr, &tp); tr.tr_end.tp_col = t->t_cursor.tp_col + ncols; } /* Blank current location. */ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); } static void -teken_subr_insert_line(teken_t *t, unsigned int nrows) +teken_subr_insert_line(const teken_t *t, unsigned int nrows) { teken_rect_t tr; /* Ignore if outside scrolling region. */ if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin || t->t_cursor.tp_row >= t->t_scrollreg.ts_end) return; tr.tr_begin.tp_row = t->t_cursor.tp_row; tr.tr_begin.tp_col = 0; tr.tr_end.tp_col = t->t_winsize.tp_col; if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) { tr.tr_end.tp_row = t->t_scrollreg.ts_end; } else { teken_pos_t tp; /* Copy lines down. */ tr.tr_end.tp_row = t->t_scrollreg.ts_end - nrows; tp.tp_row = t->t_cursor.tp_row + nrows; tp.tp_col = 0; teken_funcs_copy(t, &tr, &tp); tr.tr_end.tp_row = t->t_cursor.tp_row + nrows; } /* Blank current location. */ teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); } static void -teken_subr_keypad_application_mode(teken_t *t) +teken_subr_keypad_application_mode(const teken_t *t) { teken_funcs_param(t, TP_KEYPADAPP, 1); } static void -teken_subr_keypad_numeric_mode(teken_t *t) +teken_subr_keypad_numeric_mode(const teken_t *t) { teken_funcs_param(t, TP_KEYPADAPP, 0); } static void teken_subr_newline(teken_t *t) { t->t_cursor.tp_row++; if (t->t_cursor.tp_row >= t->t_scrollreg.ts_end) { teken_subr_do_scroll(t, 1); t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1; } t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } static void teken_subr_newpage(teken_t *t) { if (t->t_stateflags & TS_CONS25) { teken_rect_t tr; /* Clear screen. */ tr.tr_begin.tp_row = t->t_originreg.ts_begin; tr.tr_begin.tp_col = 0; tr.tr_end.tp_row = t->t_originreg.ts_end; tr.tr_end.tp_col = t->t_winsize.tp_col; teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); /* Cursor at top left. */ t->t_cursor.tp_row = t->t_originreg.ts_begin; t->t_cursor.tp_col = 0; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } else { teken_subr_newline(t); } } static void teken_subr_next_line(teken_t *t) { t->t_cursor.tp_col = 0; teken_subr_newline(t); } static void teken_subr_operating_system_command(teken_t *t) { teken_printf("Unsupported operating system command\n"); t->t_stateflags |= TS_INSTRING; } static void -teken_subr_pan_down(teken_t *t, unsigned int nrows) +teken_subr_pan_down(const teken_t *t, unsigned int nrows) { teken_subr_do_scroll(t, (int)nrows); } static void -teken_subr_pan_up(teken_t *t, unsigned int nrows) +teken_subr_pan_up(const teken_t *t, unsigned int nrows) { teken_subr_do_scroll(t, -(int)nrows); } static void -teken_subr_primary_device_attributes(teken_t *t, unsigned int request) +teken_subr_primary_device_attributes(const teken_t *t, unsigned int request) { if (request == 0) { const char response[] = "\x1B[?1;2c"; teken_funcs_respond(t, response, sizeof response - 1); } else { teken_printf("Unknown DA1\n"); } } static void -teken_subr_do_putchar(teken_t *t, const teken_pos_t *tp, teken_char_t c, +teken_subr_do_putchar(const teken_t *t, const teken_pos_t *tp, teken_char_t c, int width) { if (t->t_stateflags & TS_INSERT && tp->tp_col < t->t_winsize.tp_col - width) { teken_rect_t ctr; teken_pos_t ctp; /* Insert mode. Move existing characters to the right. */ ctr.tr_begin = *tp; ctr.tr_end.tp_row = tp->tp_row + 1; ctr.tr_end.tp_col = t->t_winsize.tp_col - width; ctp.tp_row = tp->tp_row; ctp.tp_col = tp->tp_col + width; teken_funcs_copy(t, &ctr, &ctp); } teken_funcs_putchar(t, tp, c, &t->t_curattr); if (width == 2 && tp->tp_col + 1 < t->t_winsize.tp_col) { teken_pos_t tp2; teken_attr_t attr; /* Print second half of CJK fullwidth character. */ tp2.tp_row = tp->tp_row; tp2.tp_col = tp->tp_col + 1; attr = t->t_curattr; attr.ta_format |= TF_CJK_RIGHT; teken_funcs_putchar(t, &tp2, c, &attr); } } static void teken_subr_regular_character(teken_t *t, teken_char_t c) { int width; if (t->t_stateflags & TS_8BIT) { if (!(t->t_stateflags & TS_CONS25) && (c <= 0x1b || c == 0x7f)) return; c = teken_scs_process(t, c); width = 1; } else { c = teken_scs_process(t, c); width = teken_wcwidth(c); /* XXX: Don't process zero-width characters yet. */ if (width <= 0) return; } if (t->t_stateflags & TS_CONS25) { teken_subr_do_putchar(t, &t->t_cursor, c, width); t->t_cursor.tp_col += width; if (t->t_cursor.tp_col >= t->t_winsize.tp_col) { if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) { /* Perform scrolling. */ teken_subr_do_scroll(t, 1); } else { /* No scrolling needed. */ if (t->t_cursor.tp_row < t->t_winsize.tp_row - 1) t->t_cursor.tp_row++; } t->t_cursor.tp_col = 0; } } else if (t->t_stateflags & TS_AUTOWRAP && ((t->t_stateflags & TS_WRAPPED && t->t_cursor.tp_col + 1 == t->t_winsize.tp_col) || t->t_cursor.tp_col + width > t->t_winsize.tp_col)) { teken_pos_t tp; /* * Perform line wrapping, if: * - Autowrapping is enabled, and * - We're in the wrapped state at the last column, or * - The character to be printed does not fit anymore. */ if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) { /* Perform scrolling. */ teken_subr_do_scroll(t, 1); tp.tp_row = t->t_scrollreg.ts_end - 1; } else { /* No scrolling needed. */ tp.tp_row = t->t_cursor.tp_row + 1; if (tp.tp_row == t->t_winsize.tp_row) { /* * Corner case: regular character * outside scrolling region, but at the * bottom of the screen. */ teken_subr_do_putchar(t, &t->t_cursor, c, width); return; } } tp.tp_col = 0; teken_subr_do_putchar(t, &tp, c, width); t->t_cursor.tp_row = tp.tp_row; t->t_cursor.tp_col = width; t->t_stateflags &= ~TS_WRAPPED; } else { /* No line wrapping needed. */ teken_subr_do_putchar(t, &t->t_cursor, c, width); t->t_cursor.tp_col += width; if (t->t_cursor.tp_col >= t->t_winsize.tp_col) { t->t_stateflags |= TS_WRAPPED; t->t_cursor.tp_col = t->t_winsize.tp_col - 1; } else { t->t_stateflags &= ~TS_WRAPPED; } } teken_funcs_cursor(t); } static void teken_subr_reset_dec_mode(teken_t *t, unsigned int cmd) { switch (cmd) { case 1: /* Cursor keys mode. */ t->t_stateflags &= ~TS_CURSORKEYS; break; case 2: /* DECANM: ANSI/VT52 mode. */ teken_printf("DECRST VT52\n"); break; case 3: /* 132 column mode. */ teken_funcs_param(t, TP_132COLS, 0); teken_subr_reset_to_initial_state(t); break; case 5: /* Inverse video. */ teken_printf("DECRST inverse video\n"); break; case 6: /* Origin mode. */ t->t_stateflags &= ~TS_ORIGIN; t->t_originreg.ts_begin = 0; t->t_originreg.ts_end = t->t_winsize.tp_row; t->t_cursor.tp_row = t->t_cursor.tp_col = 0; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); break; case 7: /* Autowrap mode. */ t->t_stateflags &= ~TS_AUTOWRAP; break; case 8: /* Autorepeat mode. */ teken_funcs_param(t, TP_AUTOREPEAT, 0); break; case 25: /* Hide cursor. */ teken_funcs_param(t, TP_SHOWCURSOR, 0); break; case 40: /* Disallow 132 columns. */ teken_printf("DECRST allow 132\n"); break; case 45: /* Disable reverse wraparound. */ teken_printf("DECRST reverse wraparound\n"); break; case 47: /* Switch to alternate buffer. */ teken_printf("Switch to alternate buffer\n"); break; case 1000: /* Mouse input. */ teken_funcs_param(t, TP_MOUSE, 0); break; default: teken_printf("Unknown DECRST: %u\n", cmd); } } static void teken_subr_reset_mode(teken_t *t, unsigned int cmd) { switch (cmd) { case 4: t->t_stateflags &= ~TS_INSERT; break; default: teken_printf("Unknown reset mode: %u\n", cmd); } } static void teken_subr_do_resize(teken_t *t) { t->t_scrollreg.ts_begin = 0; t->t_scrollreg.ts_end = t->t_winsize.tp_row; t->t_originreg = t->t_scrollreg; } static void teken_subr_do_reset(teken_t *t) { t->t_curattr = t->t_defattr; t->t_cursor.tp_row = t->t_cursor.tp_col = 0; t->t_scrollreg.ts_begin = 0; t->t_scrollreg.ts_end = t->t_winsize.tp_row; t->t_originreg = t->t_scrollreg; t->t_stateflags &= TS_8BIT|TS_CONS25; t->t_stateflags |= TS_AUTOWRAP; t->t_scs[0] = teken_scs_us_ascii; t->t_scs[1] = teken_scs_us_ascii; t->t_curscs = 0; teken_subr_save_cursor(t); teken_tab_default(t); } static void teken_subr_reset_to_initial_state(teken_t *t) { teken_subr_do_reset(t); teken_subr_erase_display(t, 2); teken_funcs_param(t, TP_SHOWCURSOR, 1); teken_funcs_cursor(t); } static void teken_subr_restore_cursor(teken_t *t) { t->t_cursor = t->t_saved_cursor; t->t_curattr = t->t_saved_curattr; t->t_scs[t->t_curscs] = t->t_saved_curscs; t->t_stateflags &= ~TS_WRAPPED; /* Get out of origin mode when the cursor is moved outside. */ if (t->t_cursor.tp_row < t->t_originreg.ts_begin || t->t_cursor.tp_row >= t->t_originreg.ts_end) { t->t_stateflags &= ~TS_ORIGIN; t->t_originreg.ts_begin = 0; t->t_originreg.ts_end = t->t_winsize.tp_row; } teken_funcs_cursor(t); } static void teken_subr_reverse_index(teken_t *t) { if (t->t_cursor.tp_row > t->t_scrollreg.ts_begin) { t->t_cursor.tp_row--; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } else { teken_subr_do_scroll(t, -1); } } static void teken_subr_save_cursor(teken_t *t) { t->t_saved_cursor = t->t_cursor; t->t_saved_curattr = t->t_curattr; t->t_saved_curscs = t->t_scs[t->t_curscs]; } static void -teken_subr_secondary_device_attributes(teken_t *t, unsigned int request) +teken_subr_secondary_device_attributes(const teken_t *t, unsigned int request) { if (request == 0) { const char response[] = "\x1B[>0;10;0c"; teken_funcs_respond(t, response, sizeof response - 1); } else { teken_printf("Unknown DA2\n"); } } static void teken_subr_set_dec_mode(teken_t *t, unsigned int cmd) { switch (cmd) { case 1: /* Cursor keys mode. */ t->t_stateflags |= TS_CURSORKEYS; break; case 2: /* DECANM: ANSI/VT52 mode. */ teken_printf("DECSET VT52\n"); break; case 3: /* 132 column mode. */ teken_funcs_param(t, TP_132COLS, 1); teken_subr_reset_to_initial_state(t); break; case 5: /* Inverse video. */ teken_printf("DECSET inverse video\n"); break; case 6: /* Origin mode. */ t->t_stateflags |= TS_ORIGIN; t->t_originreg = t->t_scrollreg; t->t_cursor.tp_row = t->t_scrollreg.ts_begin; t->t_cursor.tp_col = 0; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); break; case 7: /* Autowrap mode. */ t->t_stateflags |= TS_AUTOWRAP; break; case 8: /* Autorepeat mode. */ teken_funcs_param(t, TP_AUTOREPEAT, 1); break; case 25: /* Display cursor. */ teken_funcs_param(t, TP_SHOWCURSOR, 1); break; case 40: /* Allow 132 columns. */ teken_printf("DECSET allow 132\n"); break; case 45: /* Enable reverse wraparound. */ teken_printf("DECSET reverse wraparound\n"); break; case 47: /* Switch to alternate buffer. */ teken_printf("Switch away from alternate buffer\n"); break; case 1000: /* Mouse input. */ teken_funcs_param(t, TP_MOUSE, 1); break; default: teken_printf("Unknown DECSET: %u\n", cmd); } } static void teken_subr_set_mode(teken_t *t, unsigned int cmd) { switch (cmd) { case 4: teken_printf("Insert mode\n"); t->t_stateflags |= TS_INSERT; break; default: teken_printf("Unknown set mode: %u\n", cmd); } } static void teken_subr_set_graphic_rendition(teken_t *t, unsigned int ncmds, - unsigned int cmds[]) + const unsigned int cmds[]) { unsigned int i, n; /* No attributes means reset. */ if (ncmds == 0) { t->t_curattr = t->t_defattr; return; } for (i = 0; i < ncmds; i++) { n = cmds[i]; switch (n) { case 0: /* Reset. */ t->t_curattr = t->t_defattr; break; case 1: /* Bold. */ t->t_curattr.ta_format |= TF_BOLD; break; case 4: /* Underline. */ t->t_curattr.ta_format |= TF_UNDERLINE; break; case 5: /* Blink. */ t->t_curattr.ta_format |= TF_BLINK; break; case 7: /* Reverse. */ t->t_curattr.ta_format |= TF_REVERSE; break; case 22: /* Remove bold. */ t->t_curattr.ta_format &= ~TF_BOLD; break; case 24: /* Remove underline. */ t->t_curattr.ta_format &= ~TF_UNDERLINE; break; case 25: /* Remove blink. */ t->t_curattr.ta_format &= ~TF_BLINK; break; case 27: /* Remove reverse. */ t->t_curattr.ta_format &= ~TF_REVERSE; break; case 30: /* Set foreground color: black */ case 31: /* Set foreground color: red */ case 32: /* Set foreground color: green */ case 33: /* Set foreground color: brown */ case 34: /* Set foreground color: blue */ case 35: /* Set foreground color: magenta */ case 36: /* Set foreground color: cyan */ case 37: /* Set foreground color: white */ t->t_curattr.ta_fgcolor = n - 30; break; case 38: /* Set foreground color: 256 color mode */ if (i + 2 >= ncmds || cmds[i + 1] != 5) continue; t->t_curattr.ta_fgcolor = cmds[i + 2]; i += 2; break; case 39: /* Set default foreground color. */ t->t_curattr.ta_fgcolor = t->t_defattr.ta_fgcolor; break; case 40: /* Set background color: black */ case 41: /* Set background color: red */ case 42: /* Set background color: green */ case 43: /* Set background color: brown */ case 44: /* Set background color: blue */ case 45: /* Set background color: magenta */ case 46: /* Set background color: cyan */ case 47: /* Set background color: white */ t->t_curattr.ta_bgcolor = n - 40; break; case 48: /* Set background color: 256 color mode */ if (i + 2 >= ncmds || cmds[i + 1] != 5) continue; t->t_curattr.ta_bgcolor = cmds[i + 2]; i += 2; break; case 49: /* Set default background color. */ t->t_curattr.ta_bgcolor = t->t_defattr.ta_bgcolor; break; case 90: /* Set bright foreground color: black */ case 91: /* Set bright foreground color: red */ case 92: /* Set bright foreground color: green */ case 93: /* Set bright foreground color: brown */ case 94: /* Set bright foreground color: blue */ case 95: /* Set bright foreground color: magenta */ case 96: /* Set bright foreground color: cyan */ case 97: /* Set bright foreground color: white */ - t->t_curattr.ta_fgcolor = n - 90 + 8; + t->t_curattr.ta_fgcolor = (n - 90) + 8; break; case 100: /* Set bright background color: black */ case 101: /* Set bright background color: red */ case 102: /* Set bright background color: green */ case 103: /* Set bright background color: brown */ case 104: /* Set bright background color: blue */ case 105: /* Set bright background color: magenta */ case 106: /* Set bright background color: cyan */ case 107: /* Set bright background color: white */ - t->t_curattr.ta_bgcolor = n - 100 + 8; + t->t_curattr.ta_bgcolor = (n - 100) + 8; break; default: teken_printf("unsupported attribute %u\n", n); } } } static void teken_subr_set_top_and_bottom_margins(teken_t *t, unsigned int top, unsigned int bottom) { /* Adjust top row number. */ if (top > 0) top--; /* Adjust bottom row number. */ if (bottom == 0 || bottom > t->t_winsize.tp_row) bottom = t->t_winsize.tp_row; /* Invalid arguments. */ if (top >= bottom - 1) { top = 0; bottom = t->t_winsize.tp_row; } /* Apply scrolling region. */ t->t_scrollreg.ts_begin = top; t->t_scrollreg.ts_end = bottom; if (t->t_stateflags & TS_ORIGIN) t->t_originreg = t->t_scrollreg; /* Home cursor to the top left of the scrolling region. */ t->t_cursor.tp_row = t->t_originreg.ts_begin; t->t_cursor.tp_col = 0; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } static void -teken_subr_single_height_double_width_line(teken_t *t __unused) +teken_subr_single_height_double_width_line(const teken_t *t) { + (void)t; teken_printf("single height double width???\n"); } static void -teken_subr_single_height_single_width_line(teken_t *t __unused) +teken_subr_single_height_single_width_line(const teken_t *t) { + (void)t; teken_printf("single height single width???\n"); } static void -teken_subr_string_terminator(teken_t *t __unused) +teken_subr_string_terminator(const teken_t *t) { + (void)t; /* * Strings are already terminated in teken_input_char() when ^[ * is inserted. */ } static void teken_subr_tab_clear(teken_t *t, unsigned int cmd) { switch (cmd) { case 0: teken_tab_clear(t, t->t_cursor.tp_col); break; case 3: - memset(&t->t_tabstops, 0, T_NUMCOL / 8); + memset(t->t_tabstops, 0, T_NUMCOL / 8); break; + default: + break; } } static void teken_subr_vertical_position_absolute(teken_t *t, unsigned int row) { - row = row - 1 + t->t_originreg.ts_begin; + row = (row - 1) + t->t_originreg.ts_begin; t->t_cursor.tp_row = row < t->t_originreg.ts_end ? row : t->t_originreg.ts_end - 1; t->t_stateflags &= ~TS_WRAPPED; teken_funcs_cursor(t); } Index: head/sys/teken/teken_subr_compat.h =================================================================== --- head/sys/teken/teken_subr_compat.h (revision 332296) +++ head/sys/teken/teken_subr_compat.h (revision 332297) @@ -1,150 +1,153 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2008-2009 Ed Schouten * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ static void -teken_subr_cons25_set_border(teken_t *t, unsigned int c) +teken_subr_cons25_set_border(const teken_t *t, unsigned int c) { teken_funcs_param(t, TP_SETBORDER, c); } static void -teken_subr_cons25_set_global_cursor_shape(teken_t *t, unsigned int ncmds, - unsigned int cmds[]) +teken_subr_cons25_set_global_cursor_shape(const teken_t *t, unsigned int ncmds, + const unsigned int cmds[]) { unsigned int code, i; /* * Pack the args to work around API deficiencies. This requires * knowing too much about the low level to be fully compatible. * Returning when ncmds > 3 is necessary and happens to be * compatible. Discarding high bits is necessary and happens to * be incompatible only for invalid args when ncmds == 3. */ if (ncmds > 3) return; code = 0; for (i = ncmds; i > 0; i--) code = (code << 8) | (cmds[i - 1] & 0xff); code = (code << 8) | ncmds; teken_funcs_param(t, TP_SETGLOBALCURSOR, code); } static void -teken_subr_cons25_set_local_cursor_type(teken_t *t, unsigned int type) +teken_subr_cons25_set_local_cursor_type(const teken_t *t, unsigned int type) { teken_funcs_param(t, TP_SETLOCALCURSOR, type); } static const teken_color_t cons25_colors[8] = { TC_BLACK, TC_BLUE, TC_GREEN, TC_CYAN, TC_RED, TC_MAGENTA, TC_BROWN, TC_WHITE }; static void teken_subr_cons25_set_default_background(teken_t *t, unsigned int c) { t->t_defattr.ta_bgcolor = cons25_colors[c % 8] | (c & 8); t->t_curattr.ta_bgcolor = cons25_colors[c % 8] | (c & 8); } static void teken_subr_cons25_set_default_foreground(teken_t *t, unsigned int c) { t->t_defattr.ta_fgcolor = cons25_colors[c % 8] | (c & 8); t->t_curattr.ta_fgcolor = cons25_colors[c % 8] | (c & 8); } static const teken_color_t cons25_revcolors[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; void -teken_get_defattr_cons25(teken_t *t, int *fg, int *bg) +teken_get_defattr_cons25(const teken_t *t, int *fg, int *bg) { *fg = cons25_revcolors[teken_256to8(t->t_defattr.ta_fgcolor)]; if (t->t_defattr.ta_format & TF_BOLD) *fg += 8; *bg = cons25_revcolors[teken_256to8(t->t_defattr.ta_bgcolor)]; } static void -teken_subr_cons25_switch_virtual_terminal(teken_t *t, unsigned int vt) +teken_subr_cons25_switch_virtual_terminal(const teken_t *t, unsigned int vt) { teken_funcs_param(t, TP_SWITCHVT, vt); } static void -teken_subr_cons25_set_bell_pitch_duration(teken_t *t, unsigned int pitch, +teken_subr_cons25_set_bell_pitch_duration(const teken_t *t, unsigned int pitch, unsigned int duration) { teken_funcs_param(t, TP_SETBELLPD, (pitch << 16) | (duration & 0xffff)); } static void teken_subr_cons25_set_graphic_rendition(teken_t *t, unsigned int cmd, - unsigned int param __unused) + unsigned int param) { + (void)param; switch (cmd) { case 0: /* Reset. */ t->t_curattr = t->t_defattr; break; default: teken_printf("unsupported attribute %u\n", cmd); } } static void teken_subr_cons25_set_terminal_mode(teken_t *t, unsigned int mode) { switch (mode) { case 0: /* Switch terminal to xterm. */ t->t_stateflags &= ~TS_CONS25; break; case 1: /* Switch terminal to cons25. */ t->t_stateflags |= TS_CONS25; + break; + default: break; } } #if 0 static void teken_subr_vt52_decid(teken_t *t) { const char response[] = "\x1B/Z"; teken_funcs_respond(t, response, sizeof response - 1); } #endif Index: head/sys/teken/teken_wcwidth.h =================================================================== --- head/sys/teken/teken_wcwidth.h (revision 332296) +++ head/sys/teken/teken_wcwidth.h (revision 332297) @@ -1,120 +1,120 @@ /* * Markus Kuhn -- 2007-05-26 (Unicode 5.0) * * Permission to use, copy, modify, and distribute this software * for any purpose and without fee is hereby granted. The author * disclaims all warranties with regard to this software. * * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c * * $FreeBSD$ */ struct interval { teken_char_t first; teken_char_t last; }; /* auxiliary function for binary search in interval table */ static int bisearch(teken_char_t ucs, const struct interval *table, int max) { int min = 0; int mid; if (ucs < table[0].first || ucs > table[max].last) return 0; while (max >= min) { mid = (min + max) / 2; if (ucs > table[mid].last) min = mid + 1; else if (ucs < table[mid].first) max = mid - 1; else return 1; } return 0; } static int teken_wcwidth(teken_char_t ucs) { /* sorted list of non-overlapping intervals of non-spacing characters */ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ static const struct interval combining[] = { { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, { 0xE0100, 0xE01EF } }; /* test for 8-bit control characters */ if (ucs == 0) return 0; if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) return -1; /* binary search in table of non-spacing characters */ if (bisearch(ucs, combining, sizeof(combining) / sizeof(struct interval) - 1)) return 0; /* if we arrive here, ucs is not a combining or C0/C1 control character */ - return 1 + + return 1 + (ucs >= 0x1100 && (ucs <= 0x115f || /* Hangul Jamo init. consonants */ ucs == 0x2329 || ucs == 0x232a || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ (ucs >= 0xffe0 && ucs <= 0xffe6) || (ucs >= 0x20000 && ucs <= 0x2fffd) || (ucs >= 0x30000 && ucs <= 0x3fffd))); }