GCC Code Coverage Report


Directory: src/gate/
File: src/gate/console.c
Date: 2026-02-03 22:06:38
Exec Total Coverage
Lines: 179 236 75.8%
Functions: 32 33 97.0%
Branches: 43 116 37.1%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
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 are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/console.h"
30 #include "gate/results.h"
31 #include "gate/times.h"
32 #include "gate/debugging.h"
33 #include "gate/inputs.h"
34
35
36 #if defined(GATE_SYS_WIN) && !defined(GATE_SYS_WIN16)
37 # define GATE_CORE_CONSOLE_WINAPI 1
38 #elif defined(GATE_SYS_WASM)
39 # define GATE_CORE_CONSOLE_WASM_IMPL 1
40 #elif defined(GATE_SYS_EFI)
41 # define GATE_CORE_CONSOLE_EFI 1
42 #elif defined(GATE_SYS_BEOS)
43 # define GATE_CORE_CONSOLE_POSIX 1
44 #elif defined(GATE_SYS_DOS)
45 # define GATE_CORE_CONSOLE_POSIX 1
46 #elif defined(GATE_SYS_POSIX)
47 # define GATE_CORE_CONSOLE_POSIX 1
48 #else
49 # define GATE_CORE_CONSOLE_NOIMPL 1
50 #endif
51
52 static void gate_console_release_impl(void* self);
53 static int gate_console_retain_impl(void* self);
54 1 static char const* gate_console_interface_name_impl(void* self)
55 {
56 (void)self;
57 1 return GATE_INTERFACE_NAME_CONSOLE;
58 }
59 static gate_result_t gate_console_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
60 static gate_result_t gate_console_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned);
61 static gate_result_t gate_console_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
62 static gate_result_t gate_console_flush_impl(void* self);
63
64 static gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource);
65
66 static gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms);
67 static gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char);
68 static gate_result_t gate_console_write_err_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written);
69 static gate_result_t gate_console_flush_err_impl(void* self);
70
71 static GATE_INTERFACE_VTBL(gate_console) gate_console_vtbl;
72
73 81 static void gate_init_console_vtbl()
74 {
75
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 51 times.
81 if (!gate_console_vtbl.get_interface_name)
76 {
77 GATE_INTERFACE_VTBL(gate_console) const vtbl_impl =
78 {
79 &gate_console_interface_name_impl,
80 &gate_console_release_impl,
81 &gate_console_retain_impl,
82
83 &gate_console_read_impl,
84 &gate_console_peek_impl,
85 &gate_console_write_impl,
86 &gate_console_flush_impl,
87
88 &gate_console_get_resource_impl,
89
90 &gate_console_await_char_impl,
91 &gate_console_read_char_impl,
92 &gate_console_write_err_impl,
93 &gate_console_flush_err_impl
94 };
95 30 gate_console_vtbl = vtbl_impl;
96 }
97 81 }
98
99
100 1 static gate_input_keycode_t keycode_from_char32(gate_char32_t chr)
101 {
102 1 gate_input_keycode_t key_code = 0;
103
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (chr >= 'A' && chr <= 'Z')
104 {
105 key_code = (gate_input_keycode_t)(GATE_KBD_KEY_A + chr - 'A');
106 }
107
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 else if (chr >= 'a' && chr <= 'z')
108 {
109 key_code = (gate_input_keycode_t)(GATE_KBD_KEY_A + chr - 'a');
110 }
111
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 else if (chr >= '0' && chr <= '9')
112 {
113 key_code = (gate_input_keycode_t)(GATE_KBD_KEY_0 + chr - '0');
114 }
115 else
116 {
117
1/20
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
1 switch (chr)
118 {
119 case 0x08: key_code = GATE_KBD_KEY_BACKSPACE; break;
120 case 0x09: key_code = GATE_KBD_KEY_TAB; break;
121 case 0x0d: key_code = GATE_KBD_KEY_RETURN; break;
122 case 0x0a: key_code = GATE_KBD_KEY_RETURN; break;
123 case 0x1b: key_code = GATE_KBD_KEY_ESCAPE; break;
124 case 0x2b: key_code = GATE_KBD_KEY_ADD; break;
125 case 0x2d: key_code = GATE_KBD_KEY_SUBTRACT; break;
126 case 0x2a: key_code = GATE_KBD_KEY_MULTIPLY; break;
127 case 0x2f: key_code = GATE_KBD_KEY_DEVIDE; break;
128 case 0x5c: key_code = GATE_KBD_KEY_BACKSLASH; break;
129 case 0x7f: key_code = GATE_KBD_KEY_BACKSPACE; break;
130 case 0x2c: key_code = GATE_KBD_KEY_SEPARATOR; break;
131 case 0x2e: key_code = GATE_KBD_KEY_DECIMAL; break;
132 case 0x3d: key_code = GATE_KBD_KEY_EQUAL; break;
133 case 0x5b: key_code = GATE_KBD_KEY_BRACE_LEFT; break;
134 case 0x5d: key_code = GATE_KBD_KEY_BRACE_RIGHT; break;
135 case 0x22: key_code = GATE_KBD_KEY_QUOTE; break;
136 case 0x7e: key_code = GATE_KBD_KEY_TILDE; break;
137 case 0x20: key_code = GATE_KBD_KEY_SPACEBAR; break;
138 1 default: break;
139 }
140 }
141 1 return key_code;
142 }
143
144
145 #if defined(GATE_CORE_CONSOLE_WINAPI)
146
147 /****************************
148 * Windows implementation *
149 ****************************/
150
151 #include "gate/platforms.h"
152
153 typedef struct gate_console_class_impl
154 {
155 GATE_INTERFACE_VTBL(gate_console)* vtbl;
156
157 HANDLE read_handle;
158 HANDLE write_handle;
159 HANDLE error_handle;
160
161 } gate_console_impl_t;
162
163 static void gate_console_release_impl(void* self)
164 {
165 GATE_UNUSED_ARG(self);
166 }
167 static int gate_console_retain_impl(void* self)
168 {
169 GATE_UNUSED_ARG(self);
170 return 1;
171 }
172 static gate_result_t gate_console_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
173 {
174 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
175 gate_result_t ret = GATE_RESULT_FAILED;
176 DWORD dwread;
177 if (ptr->read_handle == NULL)
178 {
179 if (returned != NULL)
180 {
181 *returned = 0;
182 }
183 ret = GATE_RESULT_OK;
184 }
185 else
186 {
187 if (FALSE == gate_win32_readfile(ptr->read_handle, buffer, (DWORD)bufferlength, &dwread, NULL))
188 {
189 GATE_DEBUG_TRACE("ReadFile() failed");
190 GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror());
191 gate_win32_print_lasterror(&ret, NULL, 0);
192 }
193 else
194 {
195 if (returned != NULL)
196 {
197 *returned = (gate_size_t)dwread;
198 }
199 ret = GATE_RESULT_OK;
200 }
201 }
202 return ret;
203 }
204 static gate_result_t gate_console_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
205 {
206 GATE_UNUSED_ARG(self);
207 GATE_UNUSED_ARG(buffer);
208 GATE_UNUSED_ARG(bufferlength);
209 GATE_UNUSED_ARG(returned);
210 return GATE_RESULT_NOTSUPPORTED;
211 }
212 static gate_result_t gate_console_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
213 {
214 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
215 gate_result_t ret = GATE_RESULT_FAILED;
216 DWORD dwwrite = 0;
217 if (ptr->write_handle == NULL)
218 {
219 if (written != NULL)
220 {
221 *written = (gate_result_t)bufferlength;
222 }
223 ret = GATE_RESULT_OK;
224 }
225 else
226 {
227 if (FALSE == gate_win32_writefile(ptr->write_handle, buffer, (DWORD)bufferlength, &dwwrite, NULL))
228 {
229 GATE_DEBUG_TRACE("WriteFile() failed");
230 GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror());
231 gate_win32_print_lasterror(&ret, NULL, 0);
232 }
233 else
234 {
235 if (written != NULL)
236 {
237 *written = (gate_result_t)dwwrite;
238 }
239 ret = GATE_RESULT_OK;
240 }
241 }
242 return ret;
243 }
244 static gate_result_t gate_console_flush_impl(void* self)
245 {
246 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
247 gate_win32_flushfilebuffers(ptr->write_handle);
248 return GATE_RESULT_OK;
249 }
250
251 static gate_bool_t is_control_key(WORD keyCode)
252 {
253 switch (keyCode)
254 {
255 case VK_SHIFT:
256 case VK_CONTROL:
257 case VK_MENU:
258 case VK_LSHIFT:
259 case VK_RSHIFT:
260 case VK_LCONTROL:
261 case VK_RCONTROL:
262 case VK_LMENU:
263 case VK_RMENU:
264 return true;
265 default:
266 return false;
267 }
268 }
269
270 static gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
271 {
272 gate_result_t ret = GATE_RESULT_FAILED;
273 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
274 #ifdef GATE_SYS_WINCE
275 ret = GATE_RESULT_NOTSUPPORTED;
276 #else
277 gate_timecounter_t tc_start;
278 gate_timecounter_t tc_now;
279 gate_int64_t time_diff;
280 DWORD next_timeout = (timeout_ms == GATE_CONSOLE_TIMEOUT_NEVER) ? INFINITE : (DWORD)timeout_ms;
281 INPUT_RECORD input_record = GATE_INIT_EMPTY;
282 DWORD event_count;
283 DWORD wait_result;
284
285 do
286 {
287 ret = gate_timecounter_now(&tc_start);
288 GATE_BREAK_IF_FAILED(ret);
289
290 ret = GATE_RESULT_FAILED;
291 while (WAIT_OBJECT_0 == (wait_result = WaitForSingleObject(ptr->read_handle, next_timeout)))
292 {
293 event_count = 0;
294 if (PeekConsoleInput(ptr->read_handle, &input_record, 1, &event_count))
295 {
296 if (input_record.EventType != KEY_EVENT)
297 {
298 /* not interested in out events -> remove event from buffer */
299 ReadConsoleInput(ptr->read_handle, &input_record, 1, &event_count);
300 }
301 else if (!input_record.Event.KeyEvent.bKeyDown)
302 {
303 /* not interested in key_up -> remove event */
304 ReadConsoleInput(ptr->read_handle, &input_record, 1, &event_count);
305 }
306 else if (is_control_key(input_record.Event.KeyEvent.wVirtualKeyCode))
307 {
308 /* ignore control keys -> remove event */
309 ReadConsoleInput(ptr->read_handle, &input_record, 1, &event_count);
310 }
311 else
312 {
313 /* next event is a readable key */
314 ret = GATE_RESULT_OK;
315 break;
316 }
317 }
318
319 ret = gate_timecounter_now(&tc_now);
320 GATE_BREAK_IF_FAILED(ret);
321
322 time_diff = gate_timecounter_diff(tc_now, tc_start) / 1000;
323 if (time_diff >= timeout_ms)
324 {
325 ret = GATE_RESULT_TIMEOUT;
326 break;
327 }
328 next_timeout = (DWORD)(timeout_ms - time_diff);
329 }
330 if (wait_result == WAIT_TIMEOUT)
331 {
332 ret = GATE_RESULT_TIMEOUT;
333 }
334 else if (wait_result != WAIT_OBJECT_0)
335 {
336 ret = GATE_RESULT_FAILED;
337 }
338 } while (0);
339 #endif
340 return ret;
341 }
342
343
344 static gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
345 {
346 gate_result_t ret = GATE_RESULT_FAILED;
347 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
348 #ifdef GATE_SYS_WINCE
349 ret = GATE_RESULT_NOTSUPPORTED;
350 #else
351 INPUT_RECORD input_record = GATE_INIT_EMPTY;
352 DWORD event_count = 0;
353 gate_char32_t chr;
354
355 do
356 {
357 ret = gate_console_await_char_impl(self, GATE_CONSOLE_TIMEOUT_NEVER);
358 GATE_BREAK_IF_FAILED(ret);
359
360 event_count = 0;
361 if (!ReadConsoleInput(ptr->read_handle, &input_record, 1, &event_count))
362 {
363 ret = GATE_RESULT_FAILED;
364 break;
365 }
366 if (input_record.EventType != KEY_EVENT)
367 {
368 ret = GATE_RESULT_FAILED;
369 break;
370 }
371 if (!input_record.Event.KeyEvent.bKeyDown)
372 {
373 ret = GATE_RESULT_FAILED;
374 break;
375 }
376
377 #if defined(GATE_WIN32_UNICODE)
378 chr = input_record.Event.KeyEvent.uChar.UnicodeChar;
379 #else
380 chr = input_record.Event.KeyEvent.uChar.AsciiChar;
381 #endif
382 if (chr == 0)
383 {
384 gate_keyboard_native_key_to_unicode(input_record.Event.KeyEvent.wVirtualKeyCode, &chr);
385 }
386 *ptr_char = chr;
387
388 } while (0);
389 #endif
390 return ret;
391 }
392 static gate_result_t gate_console_write_err_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
393 {
394 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
395 gate_result_t ret = GATE_RESULT_FAILED;
396 DWORD dwwrite = 0;
397 if (ptr->error_handle == NULL)
398 {
399 if (written != NULL)
400 {
401 *written = bufferlength;
402 }
403 ret = GATE_RESULT_OK;
404 }
405 else
406 {
407 if (FALSE == gate_win32_writefile(ptr->error_handle, buffer, (DWORD)bufferlength, &dwwrite, NULL))
408 {
409 GATE_DEBUG_TRACE("WriteFile() failed");
410 GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror());
411 gate_win32_print_lasterror(&ret, NULL, 0);
412 }
413 else
414 {
415 if (written != NULL)
416 {
417 *written = (gate_result_t)dwwrite;
418 }
419 ret = GATE_RESULT_OK;
420 }
421 }
422 return ret;
423 }
424 static gate_result_t gate_console_flush_err_impl(void* self)
425 {
426 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
427 gate_win32_flushfilebuffers(ptr->error_handle);
428 return GATE_RESULT_OK;
429 }
430
431 static gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
432 {
433 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
434 gate_result_t ret;
435 switch (resource_type)
436 {
437 case GATE_STREAM_RESOURCE_INPUT:
438 {
439 *resource = (gate_uintptr_t)ptr->read_handle;
440 ret = GATE_RESULT_OK;
441 break;
442 }
443 case GATE_STREAM_RESOURCE_OUTPUT:
444 {
445 *resource = (gate_uintptr_t)ptr->write_handle;
446 ret = GATE_RESULT_OK;
447 break;
448 }
449 case GATE_STREAM_RESOURCE_ERROR:
450 {
451 *resource = (gate_uintptr_t)ptr->error_handle;
452 ret = GATE_RESULT_OK;
453 break;
454 }
455 default:
456 {
457 ret = GATE_RESULT_NOTSUPPORTED;
458 break;
459 }
460 }
461 return ret;
462 }
463
464
465
466 static gate_console_impl_t gate_console_impl_instance = {
467 &gate_console_vtbl,
468
469 0,
470 0,
471 0
472 };
473
474
475 static gate_console_t* gate_console_constructor(void);
476
477 static gate_console_t* (*gate_console_function)(void) = &gate_console_constructor;
478
479 static gate_console_t* gate_console_default(void)
480 {
481 return (gate_console_t*)&gate_console_impl_instance;
482 }
483
484 #if defined(GATE_SYS_WINCE)
485
486 typedef FILE* (__cdecl* getstdfilex_func)(int);
487 typedef void* (__cdecl* fileno_func)(FILE*);
488
489 static getstdfilex_func getstdfilex_impl = NULL;
490 static fileno_func fileno_impl = NULL;
491
492 static gate_bool_t load_coredll_cfile_functions()
493 {
494 HMODULE hmod;
495
496 if ((getstdfilex_impl != NULL) && (fileno_impl != NULL))
497 {
498 return true;
499 }
500
501 hmod = gate_win32_get_ntdll_module();
502 if (hmod == NULL)
503 {
504 return false;
505 }
506 if (getstdfilex_impl == NULL)
507 {
508 if (!gate_win32_get_proc_address(hmod, "_getstdfilex", &getstdfilex_impl))
509 {
510 return false;
511 }
512 }
513
514 if (fileno_impl == NULL)
515 {
516 if (!gate_win32_get_proc_address(hmod, "_fileno", &fileno_impl))
517 {
518 return false;
519 }
520 }
521 return true;
522 }
523
524 static HANDLE open_ce_console()
525 {
526 static HANDLE hcon = INVALID_HANDLE_VALUE;
527 if (hcon == INVALID_HANDLE_VALUE)
528 {
529 hcon = CreateFile(_T("CON0:"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
530 }
531 return hcon;
532 }
533
534 #endif
535
536 static gate_console_t* gate_console_constructor(void)
537 {
538 #if defined(GATE_SYS_WINCE)
539 #if defined(GATE_COMPILER_MSVC)
540 gate_console_impl_instance.read_handle = fileno(stdin);
541 gate_console_impl_instance.write_handle = fileno(stdout);
542 gate_console_impl_instance.error_handle = fileno(stderr);
543 #else
544 if (!load_coredll_cfile_functions())
545 {
546 gate_console_impl_instance.read_handle = open_ce_console();
547 gate_console_impl_instance.write_handle = open_ce_console();
548 gate_console_impl_instance.error_handle = open_ce_console();
549 }
550 else
551 {
552 gate_console_impl_instance.read_handle = fileno_impl(getstdfilex_impl(0));
553 gate_console_impl_instance.write_handle = fileno_impl(getstdfilex_impl(1));
554 gate_console_impl_instance.error_handle = fileno_impl(getstdfilex_impl(2));
555 }
556 #endif
557 #else
558 gate_console_impl_instance.read_handle = GetStdHandle(STD_INPUT_HANDLE);
559 gate_console_impl_instance.write_handle = GetStdHandle(STD_OUTPUT_HANDLE);
560 gate_console_impl_instance.error_handle = GetStdHandle(STD_ERROR_HANDLE);
561 #endif
562 gate_init_console_vtbl();
563 gate_console_function = &gate_console_default;
564 return (gate_console_t*)&gate_console_impl_instance;
565 }
566
567
568 gate_console_t* gate_console()
569 {
570 return gate_console_function();
571 }
572
573 gate_result_t gate_console_read_key(gate_console_t* con,
574 gate_uint32_t timeout_ms,
575 gate_input_keycode_t* out_ptr_keycode,
576 gate_char32_t* out_ptr_chr,
577 char* out_buffer, gate_size_t* out_buffer_len)
578 {
579 gate_result_t result;
580 gate_char32_t chr = 0;
581 WORD vkey = 0;
582 gate_input_nativekeycode_t native_key;
583
584 result = gate_console_timed_read_char(con, timeout_ms, &chr);
585 if (GATE_SUCCEEDED(result))
586 {
587 result = gate_keyboard_unicode_to_native_key(chr, &native_key);
588 if (GATE_SUCCEEDED(result))
589 {
590 vkey = (WORD)native_key;
591 }
592 else
593 {
594 result = GATE_RESULT_OK;
595 }
596
597 if (out_ptr_keycode)
598 {
599 *out_ptr_keycode = 0;
600 if (vkey)
601 {
602 gate_keyboard_parse_native_key(vkey, out_ptr_keycode, NULL);
603 }
604 else
605 {
606 *out_ptr_keycode = keycode_from_char32(chr);
607 }
608 }
609
610 if (out_ptr_chr)
611 {
612 *out_ptr_chr = chr;
613 }
614
615 if (out_buffer && out_buffer_len)
616 {
617 *out_buffer_len = gate_char_write_utf8(chr, out_buffer, *out_buffer_len);
618 }
619 }
620 return result;
621 }
622
623
624 #endif /* GATE_CORE_CONSOLE_WINAPI */
625
626
627
628 #if defined(GATE_CORE_CONSOLE_POSIX)
629
630 #include "gate/platforms.h"
631 #if defined(GATE_SYS_BEOS)
632 # include <termios.h>
633 # include <sys/select.h>
634 #elif defined(GATE_SYS_DOS)
635 # include <io.h>
636 #else
637 # include <termios.h>
638 #endif
639
640 #if defined(GATE_SYS_BEOS)
641
642 gate_result_t gate_posix_await_read(int fd, gate_uint32_t timeout_ms)
643 {
644 fd_set read_set;
645 struct timeval timeout;
646
647 if (timeout_ms != 0xffffffff)
648 {
649 timeout.tv_sec = timeout_ms / 1000;
650 timeout.tv_usec = (timeout_ms % 1000) * 1000;
651 }
652 else
653 {
654 timeout.tv_sec = 0x7fffffff;
655 timeout.tv_usec = 0;
656 }
657
658 FD_ZERO(&read_set);
659 FD_SET(fd, &read_set);
660 if (-1 == select(fd + 1, &read_set, NULL, NULL, &timeout))
661 {
662 return GATE_RESULT_FAILED;
663 }
664
665 if (!FD_ISSET(fd, &read_set))
666 {
667 return GATE_RESULT_TIMEOUT;
668 }
669 else
670 {
671 return GATE_RESULT_OK;
672 }
673 }
674
675 #endif
676
677
678 typedef struct gate_console_class_impl
679 {
680 GATE_INTERFACE_VTBL(gate_console)* vtbl;
681
682 int read_handle;
683 int write_handle;
684 int error_handle;
685 } gate_console_impl_t;
686
687
688 37 static void gate_console_release_impl(void* self)
689 {
690 (void)self;
691 37 }
692 12 static int gate_console_retain_impl(void* self)
693 {
694 (void)self;
695 12 return 1;
696 }
697
698 3 gate_result_t gate_console_read_impl(void* stream, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
699 {
700 3 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
701 3 ssize_t result = read(ptr->read_handle, buffer, (int)bufferlength);
702
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (result >= 0)
703 {
704
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (returned != NULL)
705 {
706 1 *returned = (gate_size_t)result;
707 }
708 3 return GATE_RESULT_OK;
709 }
710 else
711 {
712 return GATE_RESULT_FAILED;
713 }
714 }
715 1 gate_result_t gate_console_peek_impl(void* stream, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
716 {
717 GATE_UNUSED_ARG(stream);
718 GATE_UNUSED_ARG(buffer);
719 GATE_UNUSED_ARG(bufferlength);
720 GATE_UNUSED_ARG(returned);
721 1 return GATE_RESULT_NOTSUPPORTED;
722 }
723 3512 gate_result_t gate_console_write_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
724 {
725 3512 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
726 3512 ssize_t result = write(ptr->write_handle, buffer, (int)bufferlength);
727
1/2
✓ Branch 0 taken 3512 times.
✗ Branch 1 not taken.
3512 if (result >= 0)
728 {
729
1/2
✓ Branch 0 taken 3512 times.
✗ Branch 1 not taken.
3512 if (written != NULL)
730 {
731 3512 *written = (gate_size_t)result;
732 }
733 3512 return GATE_RESULT_OK;
734 }
735 else
736 {
737 return GATE_RESULT_FAILED;
738 }
739 }
740 2 gate_result_t gate_console_flush_impl(void* stream)
741 {
742 2 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
743 2 fsync(ptr->error_handle);
744 2 return GATE_RESULT_OK;
745 }
746
747 #if defined(GATE_SYS_DOS)
748
749 static gate_result_t gate_console_await_and_read_char(void* self, gate_char32_t* ptr_char, gate_uint32_t timeout_ms)
750 {
751 GATE_UNUSED_ARG(self);
752 return gate_dos_await_and_read_kbd(ptr_char, timeout_ms);
753 }
754
755
756 #else /* GATE_SYS_DOS */
757
758 5 static gate_result_t gate_console_await_and_read_char(void* self, gate_char32_t* ptr_char, gate_uint32_t timeout_ms)
759 {
760 5 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
761 5 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
762
763 struct termios termios_attrs_orig;
764 struct termios termios_attrs;
765 5 gate_bool_t reset_termios_attrs = false;
766
767 5 char buffer[8] = { 0 };
768
769 do
770 {
771
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (0 == tcgetattr(ptr->read_handle, &termios_attrs_orig))
772 {
773 //if(GATE_FLAG_ENABLED(termios_attrs_orig.c_lflag, ICANON))
774 {
775 gate_mem_copy(&termios_attrs, &termios_attrs_orig, sizeof(termios_attrs));
776 GATE_FLAG_SET(termios_attrs.c_lflag, ICANON, false);
777 GATE_FLAG_SET(termios_attrs.c_lflag, ECHO, false);
778 GATE_FLAG_SET(termios_attrs.c_lflag, ECHONL, false);
779 GATE_FLAG_SET(termios_attrs.c_lflag, ISIG, false);
780 GATE_FLAG_SET(termios_attrs.c_lflag, IEXTEN, false);
781 if (0 == tcsetattr(ptr->read_handle, TCSANOW, &termios_attrs))
782 {
783
784 reset_termios_attrs = true;
785 }
786 }
787 }
788
789 5 ret = gate_posix_await_read(ptr->read_handle, timeout_ms);
790
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 GATE_BREAK_IF_FAILED(ret);
791
792
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (ptr_char)
793 {
794 /* read character */
795 2 ret = gate_console_read_impl(self, buffer, 1, NULL);
796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
797 2 *ptr_char = (gate_char32_t)buffer[0];
798 }
799 else
800 {
801 /* only return available status */
802 3 ret = GATE_RESULT_OK;
803 }
804 } while (0);
805
806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (reset_termios_attrs)
807 {
808 tcsetattr(ptr->read_handle, TCSANOW, &termios_attrs_orig);
809 }
810
811 5 return ret;
812 }
813 #endif /* GATE_SYS_DOS */
814
815 3 gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
816 {
817 3 return gate_console_await_and_read_char(self, NULL, timeout_ms);
818 }
819
820 2 gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
821 {
822 2 return gate_console_await_and_read_char(self, ptr_char, GATE_CONSOLE_TIMEOUT_NEVER);
823 }
824
825
826 22 gate_result_t gate_console_write_err_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
827 {
828 22 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
829 22 ssize_t result = write(ptr->error_handle, buffer, (int)bufferlength);
830
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (result >= 0)
831 {
832
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (written != NULL)
833 {
834 22 *written = (gate_size_t)result;
835 }
836 22 return GATE_RESULT_OK;
837 }
838 else
839 {
840 return GATE_RESULT_FAILED;
841 }
842 }
843 2 gate_result_t gate_console_flush_err_impl(void* stream)
844 {
845 2 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
846 2 fsync(ptr->error_handle);
847 2 return GATE_RESULT_OK;
848 }
849 3 static gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
850 {
851 3 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
852 gate_result_t ret;
853
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 switch (resource_type)
854 {
855 1 case GATE_STREAM_RESOURCE_INPUT:
856 {
857 1 *resource = (gate_uintptr_t)ptr->read_handle;
858 1 ret = GATE_RESULT_OK;
859 1 break;
860 }
861 1 case GATE_STREAM_RESOURCE_OUTPUT:
862 {
863 1 *resource = (gate_uintptr_t)ptr->write_handle;
864 1 ret = GATE_RESULT_OK;
865 1 break;
866 }
867 1 case GATE_STREAM_RESOURCE_ERROR:
868 {
869 1 *resource = (gate_uintptr_t)ptr->error_handle;
870 1 ret = GATE_RESULT_OK;
871 1 break;
872 }
873 default:
874 {
875 ret = GATE_RESULT_NOTSUPPORTED;
876 break;
877 }
878 }
879 3 return ret;
880 }
881
882 static gate_console_impl_t gate_console_impl_instance = {
883 &gate_console_vtbl,
884
885 STDIN_FILENO,
886 STDOUT_FILENO,
887 STDERR_FILENO
888 };
889
890 81 gate_console_t* gate_console()
891 {
892 81 gate_init_console_vtbl();
893 81 return (gate_console_t*)&gate_console_impl_instance;
894 }
895
896
897 #if defined(GATE_SYS_DOS)
898
899 gate_result_t gate_console_read_key(gate_console_t* con,
900 gate_uint32_t timeout_ms,
901 gate_input_keycode_t* out_ptr_keycode,
902 gate_char32_t* out_ptr_chr,
903 char* out_buffer, gate_size_t* out_buffer_len)
904 {
905 gate_result_t ret;
906 char buffer[32];
907 gate_size_t buffer_len = 0;
908 gate_char32_t chr = 0;
909 gate_input_keycode_t key_code = 0;
910
911 do
912 {
913 ret = gate_console_timed_read_char(con, timeout_ms, &chr);
914 GATE_BREAK_IF_FAILED(ret);
915
916 buffer[buffer_len] = (char)chr;
917 ++buffer_len;
918
919 if (chr == 0x00)
920 {
921 /* BIOS extended codes: */
922 while (GATE_RESULT_OK == (ret = gate_console_timed_read_char(con, 1, &chr)))
923 {
924 buffer[buffer_len] = (char)chr;
925 ++buffer_len;
926
927 key_code = gate_dos_kbd_scan_code_to_input_code((unsigned)chr);
928 break;
929 }
930 }
931 else
932 {
933 if (out_ptr_keycode)
934 {
935 key_code = keycode_from_char32(chr);
936 }
937 }
938 if (out_ptr_keycode)
939 {
940 *out_ptr_keycode = key_code;
941 }
942 if (out_ptr_chr)
943 {
944 *out_ptr_chr = chr;
945 }
946 } while (0);
947
948 if (out_buffer && out_buffer_len)
949 {
950 if (buffer_len > *out_buffer_len)
951 {
952 buffer_len = *out_buffer_len;
953 }
954 gate_mem_copy(out_buffer, &buffer[0], buffer_len);
955 }
956
957 return ret;
958 }
959
960 #else /* GATE_SYS_DOS */
961
962 1 gate_result_t gate_console_read_key(gate_console_t* con,
963 gate_uint32_t timeout_ms,
964 gate_input_keycode_t* out_ptr_keycode,
965 gate_char32_t* out_ptr_chr,
966 char* out_buffer, gate_size_t* out_buffer_len)
967 {
968 gate_result_t ret;
969 char buffer[32];
970 1 gate_size_t buffer_len = 0;
971 1 gate_char32_t chr = 0;
972 gate_size_t parsed;
973 1 gate_input_keycode_t key_code = 0;
974 1 gate_input_keystates_t key_states = 0;
975
976 do
977 {
978 1 ret = gate_console_timed_read_char(con, timeout_ms, &chr);
979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
980
981 1 buffer[buffer_len] = (char)chr;
982 1 ++buffer_len;
983
984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (chr == 0x1b)
985 {
986 /* VT 100 escape code: */
987 while (GATE_RESULT_OK == (ret = gate_console_timed_read_char(con, 1, &chr)))
988 {
989 buffer[buffer_len] = (char)chr;
990 ++buffer_len;
991
992 key_code = 0;
993 parsed = gate_keyboard_parse_vt100_symbols(buffer, buffer_len, &key_code, &key_states, &chr);
994 if ((parsed != 0) && (key_code != 0))
995 {
996 break;
997 }
998 }
999 }
1000 else
1001 {
1002
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (out_ptr_keycode)
1003 {
1004 1 key_code = keycode_from_char32(chr);
1005 }
1006 }
1007
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (out_ptr_keycode)
1008 {
1009 1 *out_ptr_keycode = key_code;
1010 }
1011
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (out_ptr_chr)
1012 {
1013 1 *out_ptr_chr = chr;
1014 }
1015 } while (0);
1016
1017
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (out_buffer && out_buffer_len)
1018 {
1019
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (buffer_len > *out_buffer_len)
1020 {
1021 buffer_len = *out_buffer_len;
1022 }
1023
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (buffer_len > 0)
1024 {
1025 1 gate_mem_copy(out_buffer, &buffer[0], buffer_len);
1026 }
1027 }
1028
1029 1 return ret;
1030 }
1031
1032 #endif
1033
1034 #endif /* GATE_CORE_CONSOLE_POSIX */
1035
1036
1037
1038 #if defined(GATE_CORE_CONSOLE_EFI)
1039
1040 /***********************
1041 * EFI implementation *
1042 ************************/
1043
1044 #include "gate/platform/efi/efi_gate.h"
1045
1046 #include <efi.h>
1047
1048 typedef struct gate_console_class_impl
1049 {
1050 GATE_INTERFACE_VTBL(gate_console)* vtbl;
1051
1052 } gate_console_impl_t;
1053
1054 void gate_console_release_impl(void* self)
1055 {
1056 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1057 (void)impl;
1058 }
1059 int gate_console_retain_impl(void* self)
1060 {
1061 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1062 (void)impl;
1063 return 1;
1064 }
1065
1066 static gate_bool_t console_input_buffer_mode = true;
1067 static gate_bool_t console_input_echo_mode = true;
1068 static gate_char32_t console_input_buffer[256];
1069 static char console_buffer[1024];
1070 static gate_size_t console_buffer_length = 0;
1071 static gate_size_t console_buffer_offset = 0;
1072
1073 static gate_result_t gate_console_read_direct(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1074 {
1075 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1076 gate_result_t ret = GATE_RESULT_OK;
1077 gate_char32_t chr32;
1078 gate_size_t bytes_received = 0;
1079 gate_size_t chars_converted;
1080
1081 while (bufferlength > 0)
1082 {
1083 ret = gate_console_read_char_impl(self, &chr32);
1084 if (GATE_FAILED(ret))
1085 {
1086 if (bytes_received > 0)
1087 {
1088 /* we have already received something -> just return that */
1089 ret = GATE_RESULT_OK;
1090 }
1091 break;
1092 }
1093
1094 gate_platform_efi_console_write_char((gate_char16_t)chr32);
1095
1096 chars_converted = gate_char_write_utf8(chr32, buffer, bufferlength);
1097 buffer += chars_converted;
1098 bufferlength -= chars_converted;
1099 bytes_received += chars_converted;
1100 if (/*(chr32 == 13) ||*/ (chr32 == 10))
1101 {
1102 break;
1103 }
1104 };
1105
1106 if (returned)
1107 {
1108 *returned = bytes_received;
1109 }
1110
1111 return ret;
1112 }
1113
1114 static gate_result_t gate_console_read_buffered(void* self)
1115 {
1116 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1117 gate_result_t ret = GATE_RESULT_OK;
1118 gate_char32_t chr32;
1119 gate_size_t chars_converted;
1120
1121 do
1122 {
1123 if (console_buffer_length != 0)
1124 {
1125 /* there is already something in the buffer to be extracted */
1126 ret = GATE_RESULT_OK;
1127 break;
1128 }
1129
1130 console_buffer_offset = 0;
1131
1132 while (console_buffer_length < sizeof(console_buffer) - 8)
1133 {
1134 /* wait for next key */
1135 ret = gate_console_await_char_impl(self, 10);
1136 if (ret == GATE_RESULT_TIMEOUT)
1137 {
1138 continue;
1139 }
1140
1141 if (GATE_SUCCEEDED(ret))
1142 {
1143 /* extract next key */
1144 ret = gate_console_read_char_impl(self, &chr32);
1145 }
1146
1147 if (GATE_FAILED(ret))
1148 {
1149 /* error case */
1150 if (console_buffer_length > 0)
1151 {
1152 /* we have already received something -> just return that */
1153 ret = GATE_RESULT_OK;
1154 }
1155 break;
1156 }
1157
1158 if (chr32 == 8)
1159 {
1160 /* backspace */
1161 if (console_buffer_length > 0)
1162 {
1163 --console_buffer_length;
1164 if (console_input_echo_mode)
1165 {
1166 gate_platform_efi_console_write_char((gate_char16_t)8);
1167 }
1168 }
1169 continue;
1170 }
1171
1172 if (console_input_echo_mode)
1173 {
1174 gate_platform_efi_console_write_char((gate_char16_t)chr32);
1175 }
1176
1177 chars_converted = gate_char_write_utf8(chr32, &console_buffer[console_buffer_length],
1178 sizeof(console_buffer) - console_buffer_length);
1179 console_buffer_length += chars_converted;
1180
1181 if (chr32 == 10)
1182 {
1183 /* newline == ENTER */
1184 if (console_input_echo_mode)
1185 {
1186 gate_platform_efi_console_write_char(L'\r');
1187 }
1188 break;
1189 }
1190 };
1191
1192 } while (0);
1193
1194 return ret;
1195 }
1196
1197 gate_result_t gate_console_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1198 {
1199 gate_result_t ret;
1200 if (console_input_buffer_mode)
1201 {
1202 do
1203 {
1204 ret = gate_console_read_buffered(self);
1205 GATE_BREAK_IF_FAILED(ret);
1206
1207 if (bufferlength > console_buffer_length)
1208 {
1209 bufferlength = console_buffer_length;
1210 }
1211 gate_mem_copy(buffer, &console_buffer[console_buffer_offset], bufferlength);
1212 if (returned)
1213 {
1214 *returned = bufferlength;
1215 }
1216 ret = GATE_RESULT_OK;
1217
1218 console_buffer_length -= bufferlength;
1219 console_buffer_offset += bufferlength;
1220
1221 if (console_buffer_length == 0)
1222 {
1223 /* reset console buffer */
1224 gate_mem_clear(console_buffer, sizeof(console_buffer));
1225 console_buffer_offset = 0;
1226 }
1227 } while (0);
1228 }
1229 else
1230 {
1231 ret = gate_console_read_direct(self, buffer, bufferlength, returned);
1232 }
1233 return ret;
1234 }
1235 gate_result_t gate_console_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1236 {
1237 GATE_UNUSED_ARG(self);
1238 GATE_UNUSED_ARG(buffer);
1239 GATE_UNUSED_ARG(bufferlength);
1240 GATE_UNUSED_ARG(returned);
1241 return GATE_RESULT_NOTSUPPORTED;
1242 }
1243 gate_result_t gate_console_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1244 {
1245 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1246 gate_result_t ret = GATE_RESULT_OK;
1247 gate_char32_t utf32_chr = 0;
1248 gate_char16_t utf16_chr[8] = { 0 };
1249 gate_size_t chars_read = 0;
1250 gate_size_t chars_converted;
1251 gate_size_t chars_written = 0;
1252 gate_size_t ndx;
1253
1254 while (bufferlength > 0)
1255 {
1256 chars_read = gate_char_read_utf8(buffer, bufferlength, &utf32_chr);
1257 if (chars_read == 0)
1258 {
1259 break;
1260 }
1261 buffer += chars_read;
1262 bufferlength -= chars_read;
1263 chars_converted = gate_char_write_utf16(utf32_chr, &utf16_chr[0], 4);
1264
1265 for (ndx = 0; ndx != chars_converted; ++ndx)
1266 {
1267 ret = gate_platform_efi_console_write_char(utf16_chr[ndx]);
1268 GATE_BREAK_IF_FAILED(ret);
1269 }
1270 GATE_BREAK_IF_FAILED(ret);
1271
1272 chars_written += chars_read;
1273 }
1274
1275 if (written)
1276 {
1277 *written = chars_written;
1278 }
1279 return ret;
1280 }
1281 gate_result_t gate_console_flush_impl(void* self)
1282 {
1283 GATE_UNUSED_ARG(self);
1284 return GATE_RESULT_OK;
1285 }
1286
1287 gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
1288 {
1289 return GATE_RESULT_NOTSUPPORTED;
1290 }
1291
1292
1293 gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
1294 {
1295 return gate_platform_efi_console_await_char(timeout_ms);
1296 }
1297
1298 gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
1299 {
1300 gate_result_t ret = GATE_RESULT_FAILED;
1301 gate_char16_t chr16;
1302
1303 do
1304 {
1305 ret = gate_platform_efi_console_read_char(&chr16, NULL, false);
1306 GATE_BREAK_IF_FAILED(ret);
1307
1308 if (ptr_char)
1309 {
1310 if (chr16 == 13)
1311 {
1312 *ptr_char = 10;
1313 }
1314 else
1315 {
1316 *ptr_char = (gate_char32_t)chr16;
1317 }
1318 }
1319 } while (0);
1320
1321 return ret;
1322 }
1323
1324
1325 gate_result_t gate_console_write_err_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1326 {
1327 return gate_console_write_impl(self, buffer, bufferlength, written);
1328 }
1329 gate_result_t gate_console_flush_err_impl(void* self)
1330 {
1331 return gate_console_flush_impl(self);
1332 }
1333
1334 gate_result_t gate_console_read_key(gate_console_t* con,
1335 gate_uint32_t timeout_ms,
1336 gate_input_keycode_t* out_ptr_keycode,
1337 gate_char32_t* out_ptr_chr,
1338 char* out_buffer, gate_size_t* out_buffer_len)
1339 {
1340 gate_result_t ret;
1341 gate_char16_t chr16 = 0;
1342 gate_uint16_t scan_code = 0;
1343
1344 do
1345 {
1346 ret = gate_console_await_char_impl(con, timeout_ms);
1347 GATE_BREAK_IF_FAILED(ret);
1348
1349 ret = gate_platform_efi_console_read_char(&chr16, &scan_code, false);
1350 GATE_BREAK_IF_FAILED(ret);
1351
1352 if (out_ptr_keycode)
1353 {
1354 *out_ptr_keycode = scan_code;
1355 }
1356 if (out_ptr_chr)
1357 {
1358 *out_ptr_chr = chr16;
1359 }
1360 if (out_buffer && out_buffer_len)
1361 {
1362 *out_buffer_len = gate_char_write_utf8(chr16, out_buffer, *out_buffer_len);
1363 }
1364 } while (0);
1365
1366 return ret;
1367 }
1368
1369
1370 static gate_console_impl_t gate_console_impl_instance = {
1371 &gate_console_vtbl
1372 };
1373
1374 gate_console_t* gate_console()
1375 {
1376 gate_init_console_vtbl();
1377 return (gate_console_t*)&gate_console_impl_instance;
1378 }
1379
1380 #endif /* GATE_CORE_CONSOLE_EFI */
1381
1382
1383 #if defined(GATE_CORE_CONSOLE_WASM_IMPL)
1384
1385
1386 #include "gate/platforms.h"
1387 #include "gate/platform/wasm/wasm_gate.h"
1388
1389 typedef struct gate_console_class_impl
1390 {
1391 GATE_INTERFACE_VTBL(gate_console)* vtbl;
1392
1393 gate_platform_stream_t read_handle;
1394 gate_platform_stream_t write_handle;
1395 gate_platform_stream_t error_handle;
1396 } gate_console_impl_t;
1397
1398
1399 static void gate_console_release_impl(void* self)
1400 {
1401 (void)self;
1402 }
1403 static int gate_console_retain_impl(void* self)
1404 {
1405 (void)self;
1406 return 1;
1407 }
1408
1409 gate_result_t gate_console_read_impl(void* stream, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1410 {
1411 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
1412 return gate_platform_stream_read(ptr->read_handle, buffer, bufferlength, returned);
1413 }
1414 gate_result_t gate_console_peek_impl(void* stream, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1415 {
1416 (void)stream;
1417 (void)buffer;
1418 (void)bufferlength;
1419 (void)returned;
1420 return GATE_RESULT_NOTSUPPORTED;
1421 }
1422 gate_result_t gate_console_write_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1423 {
1424 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
1425 return gate_platform_stream_write(ptr->write_handle, buffer, bufferlength, written);
1426 }
1427 gate_result_t gate_console_flush_impl(void* stream)
1428 {
1429 (void)stream;
1430 return GATE_RESULT_OK;
1431 }
1432 gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
1433 {
1434 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1435 return ret;
1436 }
1437 gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
1438 {
1439 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1440 return ret;
1441 }
1442
1443 gate_result_t gate_console_write_err_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1444 {
1445 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
1446 return gate_platform_stream_write(ptr->error_handle, buffer, bufferlength, written);
1447 }
1448 gate_result_t gate_console_flush_err_impl(void* stream)
1449 {
1450 (void)stream;
1451 return GATE_RESULT_OK;
1452 }
1453 static gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
1454 {
1455 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
1456 gate_result_t ret;
1457 switch (resource_type)
1458 {
1459 case GATE_STREAM_RESOURCE_INPUT:
1460 {
1461 *resource = (gate_uintptr_t)ptr->read_handle;
1462 ret = GATE_RESULT_OK;
1463 break;
1464 }
1465 case GATE_STREAM_RESOURCE_OUTPUT:
1466 {
1467 *resource = (gate_uintptr_t)ptr->write_handle;
1468 ret = GATE_RESULT_OK;
1469 break;
1470 }
1471 case GATE_STREAM_RESOURCE_ERROR:
1472 {
1473 *resource = (gate_uintptr_t)ptr->error_handle;
1474 ret = GATE_RESULT_OK;
1475 break;
1476 }
1477 default:
1478 {
1479 ret = GATE_RESULT_NOTSUPPORTED;
1480 break;
1481 }
1482 }
1483 return ret;
1484 }
1485
1486 gate_result_t gate_console_read_key(gate_console_t* con,
1487 gate_uint32_t timeout_ms,
1488 gate_input_keycode_t* out_ptr_keycode,
1489 gate_char32_t* out_ptr_chr,
1490 char* out_buffer, gate_size_t* out_buffer_len)
1491 {
1492 gate_result_t result;
1493 gate_char32_t chr32 = 0;
1494 gate_input_keycode_t keycode = 0;
1495
1496 do
1497 {
1498 result = gate_console_await_char(con, timeout_ms);
1499 GATE_BREAK_IF_FAILED(result);
1500
1501 result = gate_console_read_char(con, &chr32);
1502 GATE_BREAK_IF_FAILED(result);
1503 } while (0);
1504
1505 if (out_ptr_chr)
1506 {
1507 *out_ptr_chr = chr32;
1508 }
1509 if (out_ptr_keycode)
1510 {
1511 *out_ptr_keycode = keycode;
1512 }
1513 if (out_buffer && out_buffer_len)
1514 {
1515 *out_buffer_len = 0;
1516 }
1517
1518 return result;
1519 }
1520
1521 static gate_console_impl_t gate_console_impl_instance = {
1522 &gate_console_vtbl,
1523
1524 (gate_platform_stream_t)(gate_intptr_t)0,
1525 (gate_platform_stream_t)(gate_intptr_t)1,
1526 (gate_platform_stream_t)(gate_intptr_t)2
1527 };
1528
1529 gate_console_t* gate_console()
1530 {
1531 gate_init_console_vtbl();
1532 gate_wasm_console_init();
1533 return (gate_console_t*)&gate_console_impl_instance;
1534 }
1535
1536
1537 #endif /* GATE_CORE_CONSOLE_WASM_IMPL */
1538
1539
1540
1541
1542 #if defined(GATE_CORE_CONSOLE_NOIMPL)
1543
1544
1545 typedef struct gate_console_class_impl
1546 {
1547 GATE_INTERFACE_VTBL(gate_console)* vtbl;
1548 } gate_console_impl_t;
1549
1550 static gate_console_impl_t gate_console_impl_instance = {
1551 &gate_console_vtbl
1552 };
1553
1554 static gate_result_t gate_console_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1555 {
1556 GATE_UNUSED_ARG(self);
1557 GATE_UNUSED_ARG(buffer);
1558 GATE_UNUSED_ARG(bufferlength);
1559 GATE_UNUSED_ARG(returned);
1560 return GATE_RESULT_NOTIMPLEMENTED;
1561 }
1562 static gate_result_t gate_console_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1563 {
1564 GATE_UNUSED_ARG(self);
1565 GATE_UNUSED_ARG(buffer);
1566 GATE_UNUSED_ARG(bufferlength);
1567 GATE_UNUSED_ARG(returned);
1568 return GATE_RESULT_NOTIMPLEMENTED;
1569 }
1570 static gate_result_t gate_console_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1571 {
1572 GATE_UNUSED_ARG(self);
1573 GATE_UNUSED_ARG(buffer);
1574 GATE_UNUSED_ARG(bufferlength);
1575 GATE_UNUSED_ARG(written);
1576 return GATE_RESULT_NOTIMPLEMENTED;
1577 }
1578 static gate_result_t gate_console_flush_impl(void* self)
1579 {
1580 GATE_UNUSED_ARG(self);
1581 return GATE_RESULT_NOTIMPLEMENTED;
1582 }
1583
1584 static gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
1585 {
1586 GATE_UNUSED_ARG(self);
1587 GATE_UNUSED_ARG(resource_type);
1588 GATE_UNUSED_ARG(resource);
1589 return GATE_RESULT_NOTIMPLEMENTED;
1590 }
1591
1592 static gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
1593 {
1594 GATE_UNUSED_ARG(self);
1595 GATE_UNUSED_ARG(timeout_ms);
1596 return GATE_RESULT_NOTIMPLEMENTED;
1597 }
1598 static gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
1599 {
1600 GATE_UNUSED_ARG(self);
1601 GATE_UNUSED_ARG(ptr_char);
1602 return GATE_RESULT_NOTIMPLEMENTED;
1603 }
1604 static gate_result_t gate_console_write_err_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1605 {
1606 GATE_UNUSED_ARG(self);
1607 GATE_UNUSED_ARG(buffer);
1608 GATE_UNUSED_ARG(bufferlength);
1609 GATE_UNUSED_ARG(written);
1610 return GATE_RESULT_NOTIMPLEMENTED;
1611 }
1612 static gate_result_t gate_console_flush_err_impl(void* self)
1613 {
1614 GATE_UNUSED_ARG(self);
1615 return GATE_RESULT_NOTIMPLEMENTED;
1616 }
1617 static void gate_console_release_impl(void* self)
1618 {
1619 GATE_UNUSED_ARG(self);
1620
1621 }
1622 static int gate_console_retain_impl(void* self)
1623 {
1624 GATE_UNUSED_ARG(self);
1625 return 0;
1626 }
1627
1628 gate_result_t gate_console_read_key(gate_console_t* con,
1629 gate_uint32_t timeout_ms,
1630 gate_input_keycode_t* out_ptr_keycode,
1631 gate_char32_t* out_ptr_chr,
1632 char* out_buffer, gate_size_t* out_buffer_len)
1633 {
1634 GATE_UNUSED_ARG(con);
1635 GATE_UNUSED_ARG(timeout_ms);
1636 GATE_UNUSED_ARG(out_ptr_keycode);
1637 GATE_UNUSED_ARG(out_ptr_chr);
1638 GATE_UNUSED_ARG(out_buffer);
1639 GATE_UNUSED_ARG(out_buffer_len);
1640 return GATE_RESULT_NOTIMPLEMENTED;
1641 }
1642
1643 gate_console_t* gate_console()
1644 {
1645 gate_init_console_vtbl();
1646 return (gate_console_t*)&gate_console_impl_instance;
1647 }
1648
1649
1650 #endif /* GATE_CORE_CONSOLE_NOIMPL */
1651
1652
1653
1654 /****************************
1655 * Generic implementation *
1656 ****************************/
1657
1658 1 gate_stream_t* gate_console_stream()
1659 {
1660 1 return (gate_stream_t*)gate_console();
1661 }
1662
1663 12 static void gate_console_error_release_impl(void* self)
1664 {
1665 GATE_UNUSED_ARG(self);
1666 12 }
1667 static int gate_console_error_retain_impl(void* self)
1668 {
1669 GATE_UNUSED_ARG(self);
1670 return 1;
1671 }
1672 1 static char const* gate_console_error_interface_name_impl(void* self)
1673 {
1674 GATE_UNUSED_ARG(self);
1675 1 return GATE_INTERFACE_NAME_STREAM;
1676 }
1677 1 static gate_result_t gate_console_error_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1678 {
1679 GATE_UNUSED_ARG(self);
1680 GATE_UNUSED_ARG(buffer);
1681 GATE_UNUSED_ARG(bufferlength);
1682 GATE_UNUSED_ARG(returned);
1683 1 return GATE_RESULT_NOTSUPPORTED;
1684 }
1685 1 static gate_result_t gate_console_error_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1686 {
1687 GATE_UNUSED_ARG(self);
1688 GATE_UNUSED_ARG(buffer);
1689 GATE_UNUSED_ARG(bufferlength);
1690 GATE_UNUSED_ARG(returned);
1691 1 return GATE_RESULT_NOTSUPPORTED;
1692 }
1693 11 static gate_result_t gate_console_error_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1694 {
1695 11 gate_console_t* con = gate_console();
1696 GATE_UNUSED_ARG(self);
1697 11 return con->vtbl->write_err(con, buffer, bufferlength, written);
1698 }
1699 1 static gate_result_t gate_console_error_flush_impl(void* self)
1700 {
1701 1 gate_console_t* con = gate_console();
1702 GATE_UNUSED_ARG(self);
1703 1 return con->vtbl->flush_err(con);
1704 }
1705
1706 typedef struct
1707 {
1708 GATE_INTERFACE_VTBL(gate_stream) const* vtbl;
1709 } gate_console_error_stream_impl_t;
1710
1711 static gate_console_error_stream_impl_t gate_console_error_stream_impl;
1712
1713 16 gate_stream_t* gate_console_error_stream()
1714 {
1715 static GATE_INTERFACE_VTBL(gate_stream) gate_console_error_stream_vtbl_impl;
1716
1717
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16 if (!gate_console_error_stream_impl.vtbl)
1718 {
1719 14 gate_console_error_stream_vtbl_impl.get_interface_name = &gate_console_error_interface_name_impl;
1720 14 gate_console_error_stream_vtbl_impl.release = &gate_console_error_release_impl;
1721 14 gate_console_error_stream_vtbl_impl.retain = &gate_console_error_retain_impl;
1722 14 gate_console_error_stream_vtbl_impl.read = &gate_console_error_read_impl;
1723 14 gate_console_error_stream_vtbl_impl.peek = &gate_console_error_peek_impl;
1724 14 gate_console_error_stream_vtbl_impl.write = &gate_console_error_write_impl;
1725 14 gate_console_error_stream_vtbl_impl.flush = &gate_console_error_flush_impl;
1726
1727 14 gate_console_error_stream_impl.vtbl = &gate_console_error_stream_vtbl_impl;
1728 }
1729 16 return (gate_stream_t*)&gate_console_error_stream_impl;
1730 }
1731
1732 9 gate_result_t gate_console_write_err(gate_console_t* con, char const* buffer, gate_size_t bufferlen)
1733 {
1734 9 gate_size_t lenwritten = 0;
1735 9 return con->vtbl->write_err(con, buffer, bufferlen, &lenwritten);
1736 }
1737 2 gate_result_t gate_console_print_err(gate_console_t* con, char const* buffer)
1738 {
1739 2 return gate_console_write_err(con, buffer, gate_str_length(buffer));
1740 }
1741 1 gate_result_t gate_console_print_err_num(gate_console_t* con, gate_int64_t num)
1742 {
1743 char buffer[128];
1744 1 gate_size_t len = gate_str_print_int64(buffer, sizeof(buffer), num);
1745 1 return gate_console_write_err(con, buffer, len);
1746 }
1747
1748 1 gate_result_t gate_console_println_err(gate_console_t* con, char const* buffer)
1749 {
1750 gate_result_t ret;
1751 1 ret = gate_console_print_err(con, buffer);
1752
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(ret))
1753 {
1754 1 ret = gate_console_write_err(con, GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH);
1755 }
1756 1 return ret;
1757 }
1758
1759 1 gate_result_t gate_console_readln(gate_console_t* con, gate_string_t* line)
1760 {
1761 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
1762 1 gate_size_t retrieved = 0;
1763 1 gate_result_t result = gate_stream_read(con, &buffer[0], sizeof(buffer), &retrieved);
1764
1765
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(result))
1766 {
1767
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_string_create(line, buffer, retrieved))
1768 {
1769 result = GATE_RESULT_OUTOFMEMORY;
1770 }
1771 }
1772 1 return result;
1773 }
1774
1775 1 gate_result_t gate_console_readln_raw(gate_console_t* con, gate_string_t* line, gate_uint32_t timeout_ms)
1776 {
1777 1 gate_result_t ret = GATE_RESULT_FAILED;
1778 gate_char32_t chr32;
1779 char utf8_chars[16];
1780 gate_size_t utf8_chars_used;
1781 gate_strbuilder_t builder;
1782 1 gate_timecounter_t timeout_timepoint = 0;
1783 gate_timecounter_t now;
1784 1 gate_uint32_t next_timeout_ms = GATE_CONSOLE_TIMEOUT_NEVER;
1785 gate_int64_t diff;
1786
1787 do
1788 {
1789
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (timeout_ms != GATE_CONSOLE_TIMEOUT_NEVER)
1790 {
1791 1 ret = gate_timecounter_now(&timeout_timepoint);
1792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1793 1 timeout_timepoint = gate_timecounter_add(timeout_timepoint, (gate_int64_t)timeout_ms * 1000);
1794 }
1795 else
1796 {
1797 /* we have no timeout */
1798 next_timeout_ms = GATE_CONSOLE_TIMEOUT_NEVER;
1799 }
1800
1801 1 gate_strbuilder_create(&builder, 16);
1802
1803 for (;;)
1804 {
1805
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (timeout_ms != GATE_CONSOLE_TIMEOUT_NEVER)
1806 {
1807 /* calculate next character max timeout */
1808 1 gate_timecounter_now(&now);
1809 1 diff = gate_timecounter_diff(timeout_timepoint, now);
1810
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (diff < 0)
1811 {
1812 /* timeout reached */
1813 1 break;
1814 }
1815 else
1816 {
1817 next_timeout_ms = (gate_uint32_t)(diff / 1000);
1818 }
1819 }
1820
1821 ret = gate_console_timed_read_char(con, next_timeout_ms, &chr32);
1822 GATE_BREAK_IF_FAILED(ret);
1823 utf8_chars_used = gate_char_write_utf8(chr32, utf8_chars, sizeof(utf8_chars));
1824 gate_strbuilder_append_text(&builder, utf8_chars, utf8_chars_used);
1825 if ((chr32 == 13) || (chr32 == 10))
1826 {
1827 break;
1828 }
1829 }
1830
1831 1 ret = GATE_RESULT_OK;
1832
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (line != NULL)
1833 {
1834
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (gate_strbuilder_length(&builder) > 0)
1835 {
1836 if (NULL == gate_strbuilder_to_string(&builder, line))
1837 {
1838 ret = GATE_RESULT_OUTOFMEMORY;
1839 }
1840 }
1841 else
1842 {
1843 1 gate_string_create_empty(line);
1844 }
1845 }
1846 } while (0);
1847
1848 1 gate_strbuilder_release(&builder);
1849 1 return ret;
1850 }
1851
1852 2 gate_result_t gate_console_timed_read_char(gate_console_t* con, gate_uint32_t timeout_ms, gate_char32_t* ptr_chr)
1853 {
1854 2 gate_result_t result = gate_console_await_char(con, timeout_ms);
1855
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(result))
1856 {
1857 2 result = gate_console_read_char(con, ptr_chr);
1858 }
1859 2 return result;
1860 }
1861