source: mainline/uspace/srv/hid/output/proto/vt100.c@ 417e1f6

ticket/834-toolchain-update
Last change on this file since 417e1f6 was 417e1f6, checked in by Vojtech Horky <vojtech.horky@…>, 2 years ago

Ensure buffer is really big enough

  • Property mode set to 100644
File size: 6.3 KB
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * Copyright (c) 2011 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup output
31 * @{
32 */
33
34#include <inttypes.h>
35#include <errno.h>
36#include <stddef.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <io/color.h>
40#include <types/common.h>
41#include "vt100.h"
42
43/** Buffer size when creating actual VT100 commands.
44 *
45 * This is absurdly large but since we accept numbers via sysarg_t,
46 * we make it big enough for the largest value to be on the safe side
47 * (and to silence compiler too).
48 *
49 * TODO: find out if VT100 has some hard limits or perhaps simply cut-out
50 * values larger than 16 bits or something.
51 */
52#define MAX_CONTROL 64
53
54typedef enum {
55 CI_BLACK = 0,
56 CI_RED = 1,
57 CI_GREEN = 2,
58 CI_BROWN = 3,
59 CI_BLUE = 4,
60 CI_MAGENTA = 5,
61 CI_CYAN = 6,
62 CI_WHITE = 7
63} sgr_color_index_t;
64
65typedef enum {
66 SGR_RESET = 0,
67 SGR_BOLD = 1,
68 SGR_UNDERLINE = 4,
69 SGR_BLINK = 5,
70 SGR_REVERSE = 7,
71 SGR_FGCOLOR = 30,
72 SGR_BGCOLOR = 40
73} sgr_command_t;
74
75static sgr_color_index_t color_map[] = {
76 [COLOR_BLACK] = CI_BLACK,
77 [COLOR_BLUE] = CI_BLUE,
78 [COLOR_GREEN] = CI_GREEN,
79 [COLOR_CYAN] = CI_CYAN,
80 [COLOR_RED] = CI_RED,
81 [COLOR_MAGENTA] = CI_MAGENTA,
82 [COLOR_YELLOW] = CI_BROWN,
83 [COLOR_WHITE] = CI_WHITE
84};
85
86/** ECMA-48 Set Graphics Rendition. */
87static void vt100_sgr(vt100_state_t *state, unsigned int mode)
88{
89 char control[MAX_CONTROL];
90
91 snprintf(control, MAX_CONTROL, "\033[%um", mode);
92 state->control_puts(control);
93}
94
95static void vt100_set_pos(vt100_state_t *state, sysarg_t col, sysarg_t row)
96{
97 char control[MAX_CONTROL];
98
99 snprintf(control, MAX_CONTROL, "\033[%" PRIun ";%" PRIun "f",
100 row + 1, col + 1);
101 state->control_puts(control);
102}
103
104static void vt100_set_sgr(vt100_state_t *state, char_attrs_t attrs)
105{
106 switch (attrs.type) {
107 case CHAR_ATTR_STYLE:
108 switch (attrs.val.style) {
109 case STYLE_NORMAL:
110 vt100_sgr(state, SGR_RESET);
111 vt100_sgr(state, SGR_BGCOLOR + CI_WHITE);
112 vt100_sgr(state, SGR_FGCOLOR + CI_BLACK);
113 break;
114 case STYLE_EMPHASIS:
115 vt100_sgr(state, SGR_RESET);
116 vt100_sgr(state, SGR_BGCOLOR + CI_WHITE);
117 vt100_sgr(state, SGR_FGCOLOR + CI_RED);
118 vt100_sgr(state, SGR_BOLD);
119 break;
120 case STYLE_INVERTED:
121 vt100_sgr(state, SGR_RESET);
122 vt100_sgr(state, SGR_BGCOLOR + CI_BLACK);
123 vt100_sgr(state, SGR_FGCOLOR + CI_WHITE);
124 break;
125 case STYLE_SELECTED:
126 vt100_sgr(state, SGR_RESET);
127 vt100_sgr(state, SGR_BGCOLOR + CI_RED);
128 vt100_sgr(state, SGR_FGCOLOR + CI_WHITE);
129 break;
130 }
131 break;
132 case CHAR_ATTR_INDEX:
133 vt100_sgr(state, SGR_RESET);
134 vt100_sgr(state, SGR_BGCOLOR + color_map[attrs.val.index.bgcolor & 7]);
135 vt100_sgr(state, SGR_FGCOLOR + color_map[attrs.val.index.fgcolor & 7]);
136
137 if (attrs.val.index.attr & CATTR_BRIGHT)
138 vt100_sgr(state, SGR_BOLD);
139
140 break;
141 case CHAR_ATTR_RGB:
142 vt100_sgr(state, SGR_RESET);
143
144 if (attrs.val.rgb.bgcolor <= attrs.val.rgb.fgcolor)
145 vt100_sgr(state, SGR_REVERSE);
146
147 break;
148 }
149}
150
151vt100_state_t *vt100_state_create(sysarg_t cols, sysarg_t rows,
152 vt100_putuchar_t putuchar_fn, vt100_control_puts_t control_puts_fn,
153 vt100_flush_t flush_fn)
154{
155 vt100_state_t *state = malloc(sizeof(vt100_state_t));
156 if (state == NULL)
157 return NULL;
158
159 state->putuchar = putuchar_fn;
160 state->control_puts = control_puts_fn;
161 state->flush = flush_fn;
162
163 state->cols = cols;
164 state->rows = rows;
165
166 state->cur_col = (sysarg_t) -1;
167 state->cur_row = (sysarg_t) -1;
168
169 state->cur_attrs.type = CHAR_ATTR_STYLE;
170 state->cur_attrs.val.style = STYLE_NORMAL;
171
172 /* Initialize graphic rendition attributes */
173 vt100_sgr(state, SGR_RESET);
174 vt100_sgr(state, SGR_FGCOLOR + CI_BLACK);
175 vt100_sgr(state, SGR_BGCOLOR + CI_WHITE);
176 state->control_puts("\033[2J");
177 state->control_puts("\033[?25l");
178
179 return state;
180}
181
182void vt100_state_destroy(vt100_state_t *state)
183{
184 free(state);
185}
186
187void vt100_get_dimensions(vt100_state_t *state, sysarg_t *cols,
188 sysarg_t *rows)
189{
190 *cols = state->cols;
191 *rows = state->rows;
192}
193
194errno_t vt100_yield(vt100_state_t *state)
195{
196 return EOK;
197}
198
199errno_t vt100_claim(vt100_state_t *state)
200{
201 return EOK;
202}
203
204void vt100_goto(vt100_state_t *state, sysarg_t col, sysarg_t row)
205{
206 if ((col >= state->cols) || (row >= state->rows))
207 return;
208
209 if ((col != state->cur_col) || (row != state->cur_row)) {
210 vt100_set_pos(state, col, row);
211 state->cur_col = col;
212 state->cur_row = row;
213 }
214}
215
216void vt100_set_attr(vt100_state_t *state, char_attrs_t attrs)
217{
218 if (!attrs_same(state->cur_attrs, attrs)) {
219 vt100_set_sgr(state, attrs);
220 state->cur_attrs = attrs;
221 }
222}
223
224void vt100_cursor_visibility(vt100_state_t *state, bool visible)
225{
226 if (visible)
227 state->control_puts("\033[?25h");
228 else
229 state->control_puts("\033[?25l");
230}
231
232void vt100_putuchar(vt100_state_t *state, char32_t ch)
233{
234 state->putuchar(ch == 0 ? ' ' : ch);
235 state->cur_col++;
236
237 if (state->cur_col >= state->cols) {
238 state->cur_row += state->cur_col / state->cols;
239 state->cur_col %= state->cols;
240 }
241}
242
243void vt100_flush(vt100_state_t *state)
244{
245 state->flush();
246}
247
248/** @}
249 */
Note: See TracBrowser for help on using the repository browser.