GCC Code Coverage Report


Directory: src/gate/
File: src/gate/console.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 153 236 64.8%
Functions: 22 33 66.7%
Branches: 41 116 35.3%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, 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 static char const* gate_console_interface_name_impl(void* self)
55 {
56 (void)self;
57 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 48 static void gate_init_console_vtbl()
74 {
75
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 32 times.
48 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 16 gate_console_vtbl = vtbl_impl;
96 }
97 48 }
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 24 static void gate_console_release_impl(void* self)
689 {
690 (void)self;
691 24 }
692 8 static int gate_console_retain_impl(void* self)
693 {
694 (void)self;
695 8 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 2759 gate_result_t gate_console_write_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
724 {
725 2759 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
726 2759 ssize_t result = write(ptr->write_handle, buffer, (int)bufferlength);
727
1/2
✓ Branch 0 taken 2759 times.
✗ Branch 1 not taken.
2759 if (result >= 0)
728 {
729
1/2
✓ Branch 0 taken 2759 times.
✗ Branch 1 not taken.
2759 if (written != NULL)
730 {
731 2759 *written = (gate_size_t)result;
732 }
733 2759 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 8 gate_result_t gate_console_write_err_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
827 {
828 8 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
829 8 ssize_t result = write(ptr->error_handle, buffer, (int)bufferlength);
830
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (result >= 0)
831 {
832
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (written != NULL)
833 {
834 8 *written = (gate_size_t)result;
835 }
836 8 return GATE_RESULT_OK;
837 }
838 else
839 {
840 return GATE_RESULT_FAILED;
841 }
842 }
843 1 gate_result_t gate_console_flush_err_impl(void* stream)
844 {
845 1 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
846 1 fsync(ptr->error_handle);
847 1 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 48 gate_console_t* gate_console()
891 {
892 48 gate_init_console_vtbl();
893 48 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 #include <efilib.h>
1048
1049 typedef struct gate_console_class_impl
1050 {
1051 GATE_INTERFACE_VTBL(gate_console)* vtbl;
1052
1053 } gate_console_impl_t;
1054
1055 void gate_console_release_impl(void* self)
1056 {
1057 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1058 (void)impl;
1059 }
1060 int gate_console_retain_impl(void* self)
1061 {
1062 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1063 (void)impl;
1064 return 1;
1065 }
1066
1067 static gate_bool_t console_input_buffer_mode = true;
1068 static gate_bool_t console_input_echo_mode = true;
1069 static gate_char32_t console_input_buffer[256];
1070 static char console_buffer[1024];
1071 static gate_size_t console_buffer_length = 0;
1072 static gate_size_t console_buffer_offset = 0;
1073
1074 static gate_result_t gate_console_read_direct(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1075 {
1076 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1077 gate_result_t ret = GATE_RESULT_OK;
1078 gate_char32_t chr32;
1079 gate_size_t bytes_received = 0;
1080 gate_size_t chars_converted;
1081
1082 while (bufferlength > 0)
1083 {
1084 ret = gate_console_read_char_impl(self, &chr32);
1085 if (GATE_FAILED(ret))
1086 {
1087 if (bytes_received > 0)
1088 {
1089 /* we have already received something -> just return that */
1090 ret = GATE_RESULT_OK;
1091 }
1092 break;
1093 }
1094
1095 gate_platform_efi_console_write_char((gate_char16_t)chr32);
1096
1097 chars_converted = gate_char_write_utf8(chr32, buffer, bufferlength);
1098 buffer += chars_converted;
1099 bufferlength -= chars_converted;
1100 bytes_received += chars_converted;
1101 if (/*(chr32 == 13) ||*/ (chr32 == 10))
1102 {
1103 break;
1104 }
1105 };
1106
1107 if (returned)
1108 {
1109 *returned = bytes_received;
1110 }
1111
1112 return ret;
1113 }
1114
1115 static gate_result_t gate_console_read_buffered(void* self)
1116 {
1117 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1118 gate_result_t ret = GATE_RESULT_OK;
1119 gate_char32_t chr32;
1120 gate_size_t chars_converted;
1121
1122 do
1123 {
1124 if (console_buffer_length != 0)
1125 {
1126 /* there is already something in the buffer to be extracted */
1127 ret = GATE_RESULT_OK;
1128 break;
1129 }
1130
1131 console_buffer_offset = 0;
1132
1133 while (console_buffer_length < sizeof(console_buffer) - 8)
1134 {
1135 /* wait for next key */
1136 ret = gate_console_await_char_impl(self, 10);
1137 if (ret == GATE_RESULT_TIMEOUT)
1138 {
1139 continue;
1140 }
1141
1142 if (GATE_SUCCEEDED(ret))
1143 {
1144 /* extract next key */
1145 ret = gate_console_read_char_impl(self, &chr32);
1146 }
1147
1148 if (GATE_FAILED(ret))
1149 {
1150 /* error case */
1151 if (console_buffer_length > 0)
1152 {
1153 /* we have already received something -> just return that */
1154 ret = GATE_RESULT_OK;
1155 }
1156 break;
1157 }
1158
1159 if (chr32 == 8)
1160 {
1161 /* backspace */
1162 if (console_buffer_length > 0)
1163 {
1164 --console_buffer_length;
1165 if (console_input_echo_mode)
1166 {
1167 gate_platform_efi_console_write_char((gate_char16_t)8);
1168 }
1169 }
1170 continue;
1171 }
1172
1173 if (console_input_echo_mode)
1174 {
1175 gate_platform_efi_console_write_char((gate_char16_t)chr32);
1176 }
1177
1178 chars_converted = gate_char_write_utf8(chr32, &console_buffer[console_buffer_length],
1179 sizeof(console_buffer) - console_buffer_length);
1180 console_buffer_length += chars_converted;
1181
1182 if (chr32 == 10)
1183 {
1184 /* newline == ENTER */
1185 if (console_input_echo_mode)
1186 {
1187 gate_platform_efi_console_write_char(L'\r');
1188 }
1189 break;
1190 }
1191 };
1192
1193 } while (0);
1194
1195 return ret;
1196 }
1197
1198 gate_result_t gate_console_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1199 {
1200 gate_result_t ret;
1201 if (console_input_buffer_mode)
1202 {
1203 do
1204 {
1205 ret = gate_console_read_buffered(self);
1206 GATE_BREAK_IF_FAILED(ret);
1207
1208 if (bufferlength > console_buffer_length)
1209 {
1210 bufferlength = console_buffer_length;
1211 }
1212 gate_mem_copy(buffer, &console_buffer[console_buffer_offset], bufferlength);
1213 if (returned)
1214 {
1215 *returned = bufferlength;
1216 }
1217 ret = GATE_RESULT_OK;
1218
1219 console_buffer_length -= bufferlength;
1220 console_buffer_offset += bufferlength;
1221
1222 if (console_buffer_length == 0)
1223 {
1224 /* reset console buffer */
1225 gate_mem_clear(console_buffer, sizeof(console_buffer));
1226 console_buffer_offset = 0;
1227 }
1228 } while (0);
1229 }
1230 else
1231 {
1232 ret = gate_console_read_direct(self, buffer, bufferlength, returned);
1233 }
1234 return ret;
1235 }
1236 gate_result_t gate_console_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1237 {
1238 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1239 return GATE_RESULT_NOTSUPPORTED;
1240 }
1241 gate_result_t gate_console_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1242 {
1243 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1244 gate_result_t ret = GATE_RESULT_OK;
1245 gate_char32_t utf32_chr = 0;
1246 gate_char16_t utf16_chr[8] = { 0 };
1247 gate_size_t chars_read = 0;
1248 gate_size_t chars_converted;
1249 gate_size_t chars_written = 0;
1250 gate_size_t ndx;
1251
1252 while (bufferlength > 0)
1253 {
1254 chars_read = gate_char_read_utf8(buffer, bufferlength, &utf32_chr);
1255 if (chars_read == 0)
1256 {
1257 break;
1258 }
1259 buffer += chars_read;
1260 bufferlength -= chars_read;
1261 chars_converted = gate_char_write_utf16(utf32_chr, &utf16_chr[0], 4);
1262
1263 for (ndx = 0; ndx != chars_converted; ++ndx)
1264 {
1265 ret = gate_platform_efi_console_write_char(utf16_chr[ndx]);
1266 GATE_BREAK_IF_FAILED(ret);
1267 }
1268 GATE_BREAK_IF_FAILED(ret);
1269
1270 chars_written += chars_read;
1271 }
1272
1273 if (written)
1274 {
1275 *written = chars_written;
1276 }
1277 return ret;
1278 }
1279 gate_result_t gate_console_flush_impl(void* self)
1280 {
1281 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1282 return GATE_RESULT_OK;
1283 }
1284
1285 gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
1286 {
1287 return GATE_RESULT_NOTSUPPORTED;
1288 }
1289
1290
1291 gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
1292 {
1293 return gate_platform_efi_console_await_char(timeout_ms);
1294
1295 }
1296 gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
1297 {
1298 gate_result_t ret = GATE_RESULT_FAILED;
1299 gate_char16_t chr16;
1300
1301 do
1302 {
1303 ret = gate_platform_efi_console_read_char(&chr16, NULL, false);
1304 GATE_BREAK_IF_FAILED(ret);
1305
1306 if (ptr_char)
1307 {
1308 if (chr16 == 13)
1309 {
1310 *ptr_char = 10;
1311 }
1312 else
1313 {
1314 *ptr_char = (gate_char32_t)chr16;
1315 }
1316 }
1317 } while (0);
1318
1319 return ret;
1320 }
1321
1322
1323 gate_result_t gate_console_write_err_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1324 {
1325 return gate_console_write_impl(self, buffer, bufferlength, written);
1326 }
1327 gate_result_t gate_console_flush_err_impl(void* self)
1328 {
1329 return gate_console_flush_impl(self);
1330 }
1331
1332 gate_result_t gate_console_read_key(gate_console_t* con,
1333 gate_uint32_t timeout_ms,
1334 gate_input_keycode_t* out_ptr_keycode,
1335 gate_char32_t* out_ptr_chr,
1336 char* out_buffer, gate_size_t* out_buffer_len)
1337 {
1338 gate_result_t ret;
1339 gate_char16_t chr16 = 0;
1340 gate_uint16_t scan_code = 0;
1341
1342 do
1343 {
1344 ret = gate_console_await_char_impl(con, timeout_ms);
1345 GATE_BREAK_IF_FAILED(ret);
1346
1347 ret = gate_platform_efi_console_read_char(&chr16, &scan_code, false);
1348 GATE_BREAK_IF_FAILED(ret);
1349
1350 if (out_ptr_keycode)
1351 {
1352 *out_ptr_keycode = scan_code;
1353 }
1354 if (out_ptr_chr)
1355 {
1356 *out_ptr_chr = chr16;
1357 }
1358 if (out_buffer && out_buffer_len)
1359 {
1360 *out_buffer_len = gate_char_write_utf8(chr16, out_buffer, *out_buffer_len);
1361 }
1362 } while (0);
1363
1364 return ret;
1365 }
1366
1367
1368 static gate_console_impl_t gate_console_impl_instance = {
1369 &gate_console_vtbl
1370 };
1371
1372 gate_console_t* gate_console()
1373 {
1374 gate_init_console_vtbl();
1375 return (gate_console_t*)&gate_console_impl_instance;
1376 }
1377
1378 #endif /* GATE_CORE_CONSOLE_EFI */
1379
1380
1381 #if defined(GATE_CORE_CONSOLE_WASM_IMPL)
1382
1383
1384 #include "gate/platforms.h"
1385 #include "gate/platform/wasm/wasm_gate.h"
1386
1387 typedef struct gate_console_class_impl
1388 {
1389 GATE_INTERFACE_VTBL(gate_console)* vtbl;
1390
1391 gate_platform_stream_t read_handle;
1392 gate_platform_stream_t write_handle;
1393 gate_platform_stream_t error_handle;
1394 } gate_console_impl_t;
1395
1396
1397 static void gate_console_release_impl(void* self)
1398 {
1399 (void)self;
1400 }
1401 static int gate_console_retain_impl(void* self)
1402 {
1403 (void)self;
1404 return 1;
1405 }
1406
1407 gate_result_t gate_console_read_impl(void* stream, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1408 {
1409 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
1410 return gate_platform_stream_read(ptr->read_handle, buffer, bufferlength, returned);
1411 }
1412 gate_result_t gate_console_peek_impl(void* stream, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1413 {
1414 (void)stream;
1415 (void)buffer;
1416 (void)bufferlength;
1417 (void)returned;
1418 return GATE_RESULT_NOTSUPPORTED;
1419 }
1420 gate_result_t gate_console_write_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1421 {
1422 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
1423 return gate_platform_stream_write(ptr->write_handle, buffer, bufferlength, written);
1424 }
1425 gate_result_t gate_console_flush_impl(void* stream)
1426 {
1427 (void)stream;
1428 return GATE_RESULT_OK;
1429 }
1430 gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
1431 {
1432 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1433 return ret;
1434 }
1435 gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
1436 {
1437 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1438 return ret;
1439 }
1440
1441 gate_result_t gate_console_write_err_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1442 {
1443 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
1444 return gate_platform_stream_write(ptr->error_handle, buffer, bufferlength, written);
1445 }
1446 gate_result_t gate_console_flush_err_impl(void* stream)
1447 {
1448 (void)stream;
1449 return GATE_RESULT_OK;
1450 }
1451 static gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
1452 {
1453 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
1454 gate_result_t ret;
1455 switch (resource_type)
1456 {
1457 case GATE_STREAM_RESOURCE_INPUT:
1458 {
1459 *resource = (gate_uintptr_t)ptr->read_handle;
1460 ret = GATE_RESULT_OK;
1461 break;
1462 }
1463 case GATE_STREAM_RESOURCE_OUTPUT:
1464 {
1465 *resource = (gate_uintptr_t)ptr->write_handle;
1466 ret = GATE_RESULT_OK;
1467 break;
1468 }
1469 case GATE_STREAM_RESOURCE_ERROR:
1470 {
1471 *resource = (gate_uintptr_t)ptr->error_handle;
1472 ret = GATE_RESULT_OK;
1473 break;
1474 }
1475 default:
1476 {
1477 ret = GATE_RESULT_NOTSUPPORTED;
1478 break;
1479 }
1480 }
1481 return ret;
1482 }
1483
1484 gate_result_t gate_console_read_key(gate_console_t* con,
1485 gate_uint32_t timeout_ms,
1486 gate_input_keycode_t* out_ptr_keycode,
1487 gate_char32_t* out_ptr_chr,
1488 char* out_buffer, gate_size_t* out_buffer_len)
1489 {
1490 gate_result_t result;
1491 gate_console_impl_t* ptr = (gate_console_impl_t*)con;
1492 gate_char32_t chr32 = 0;
1493 gate_input_keycode_t keycode = 0;
1494
1495 do
1496 {
1497 result = gate_console_await_char(con, timeout_ms);
1498 GATE_BREAK_IF_FAILED(result);
1499
1500 result = gate_console_read_char(con, &chr32);
1501 GATE_BREAK_IF_FAILED(result);
1502 } while (0);
1503
1504 if (out_ptr_chr)
1505 {
1506 *out_ptr_chr = chr32;
1507 }
1508 if (out_ptr_keycode)
1509 {
1510 *out_ptr_keycode = keycode;
1511 }
1512 if (out_buffer && out_buffer_len)
1513 {
1514 *out_buffer_len = 0;
1515 }
1516
1517 return result;
1518 }
1519
1520 static gate_console_impl_t gate_console_impl_instance = {
1521 &gate_console_vtbl,
1522
1523 (gate_platform_stream_t)(gate_intptr_t)0,
1524 (gate_platform_stream_t)(gate_intptr_t)1,
1525 (gate_platform_stream_t)(gate_intptr_t)2
1526 };
1527
1528 gate_console_t* gate_console()
1529 {
1530 gate_init_console_vtbl();
1531 gate_wasm_console_init();
1532 return (gate_console_t*)&gate_console_impl_instance;
1533 }
1534
1535
1536 #endif /* GATE_CORE_CONSOLE_WASM_IMPL */
1537
1538
1539
1540
1541 #if defined(GATE_CORE_CONSOLE_NOIMPL)
1542
1543
1544 typedef struct gate_console_class_impl
1545 {
1546 GATE_INTERFACE_VTBL(gate_console)* vtbl;
1547 } gate_console_impl_t;
1548
1549 static gate_console_impl_t gate_console_impl_instance = {
1550 &gate_console_vtbl
1551 };
1552
1553 static gate_result_t gate_console_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1554 {
1555 GATE_UNUSED_ARG(self);
1556 GATE_UNUSED_ARG(buffer);
1557 GATE_UNUSED_ARG(bufferlength);
1558 GATE_UNUSED_ARG(returned);
1559 return GATE_RESULT_NOTIMPLEMENTED;
1560 }
1561 static gate_result_t gate_console_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1562 {
1563 GATE_UNUSED_ARG(self);
1564 GATE_UNUSED_ARG(buffer);
1565 GATE_UNUSED_ARG(bufferlength);
1566 GATE_UNUSED_ARG(returned);
1567 return GATE_RESULT_NOTIMPLEMENTED;
1568 }
1569 static gate_result_t gate_console_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1570 {
1571 GATE_UNUSED_ARG(self);
1572 GATE_UNUSED_ARG(buffer);
1573 GATE_UNUSED_ARG(bufferlength);
1574 GATE_UNUSED_ARG(written);
1575 return GATE_RESULT_NOTIMPLEMENTED;
1576 }
1577 static gate_result_t gate_console_flush_impl(void* self)
1578 {
1579 GATE_UNUSED_ARG(self);
1580 return GATE_RESULT_NOTIMPLEMENTED;
1581 }
1582
1583 static gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
1584 {
1585 GATE_UNUSED_ARG(self);
1586 GATE_UNUSED_ARG(resource_type);
1587 GATE_UNUSED_ARG(resource);
1588 return GATE_RESULT_NOTIMPLEMENTED;
1589 }
1590
1591 static gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
1592 {
1593 GATE_UNUSED_ARG(self);
1594 GATE_UNUSED_ARG(timeout_ms);
1595 return GATE_RESULT_NOTIMPLEMENTED;
1596 }
1597 static gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
1598 {
1599 GATE_UNUSED_ARG(self);
1600 GATE_UNUSED_ARG(ptr_char);
1601 return GATE_RESULT_NOTIMPLEMENTED;
1602 }
1603 static gate_result_t gate_console_write_err_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1604 {
1605 GATE_UNUSED_ARG(self);
1606 GATE_UNUSED_ARG(buffer);
1607 GATE_UNUSED_ARG(bufferlength);
1608 GATE_UNUSED_ARG(written);
1609 return GATE_RESULT_NOTIMPLEMENTED;
1610 }
1611 static gate_result_t gate_console_flush_err_impl(void* self)
1612 {
1613 GATE_UNUSED_ARG(self);
1614 return GATE_RESULT_NOTIMPLEMENTED;
1615 }
1616 static void gate_console_release_impl(void* self)
1617 {
1618 GATE_UNUSED_ARG(self);
1619
1620 }
1621 static int gate_console_retain_impl(void* self)
1622 {
1623 GATE_UNUSED_ARG(self);
1624 return 0;
1625 }
1626
1627 gate_console_t* gate_console()
1628 {
1629 gate_init_console_vtbl();
1630 return (gate_console_t*)&gate_console_impl_instance;
1631 }
1632
1633
1634 #endif /* GATE_CORE_CONSOLE_NOIMPL */
1635
1636
1637
1638 /****************************
1639 * Generic implementation *
1640 ****************************/
1641
1642 gate_stream_t* gate_console_stream()
1643 {
1644 return (gate_stream_t*)gate_console();
1645 }
1646
1647 8 static void gate_console_error_release_impl(void* self)
1648 {
1649 GATE_UNUSED_ARG(self);
1650 8 }
1651 static int gate_console_error_retain_impl(void* self)
1652 {
1653 GATE_UNUSED_ARG(self);
1654 return 1;
1655 }
1656 static char const* gate_console_error_interface_name_impl(void* self)
1657 {
1658 GATE_UNUSED_ARG(self);
1659 return GATE_INTERFACE_NAME_STREAM;
1660 }
1661 static gate_result_t gate_console_error_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1662 {
1663 GATE_UNUSED_ARG(self);
1664 GATE_UNUSED_ARG(buffer);
1665 GATE_UNUSED_ARG(bufferlength);
1666 GATE_UNUSED_ARG(returned);
1667 return GATE_RESULT_NOTSUPPORTED;
1668 }
1669 static gate_result_t gate_console_error_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1670 {
1671 GATE_UNUSED_ARG(self);
1672 GATE_UNUSED_ARG(buffer);
1673 GATE_UNUSED_ARG(bufferlength);
1674 GATE_UNUSED_ARG(returned);
1675 return GATE_RESULT_NOTSUPPORTED;
1676 }
1677 static gate_result_t gate_console_error_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1678 {
1679 gate_console_t* con = gate_console();
1680 GATE_UNUSED_ARG(self);
1681 return con->vtbl->write_err(con, buffer, bufferlength, written);
1682 }
1683 static gate_result_t gate_console_error_flush_impl(void* self)
1684 {
1685 gate_console_t* con = gate_console();
1686 GATE_UNUSED_ARG(self);
1687 return con->vtbl->flush_err(con);
1688 }
1689
1690 typedef struct
1691 {
1692 GATE_INTERFACE_VTBL(gate_stream) const* vtbl;
1693 } gate_console_error_stream_impl_t;
1694
1695 static gate_console_error_stream_impl_t gate_console_error_stream_impl;
1696
1697 8 gate_stream_t* gate_console_error_stream()
1698 {
1699 static GATE_INTERFACE_VTBL(gate_stream) gate_console_error_stream_vtbl_impl;
1700
1701
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (!gate_console_error_stream_impl.vtbl)
1702 {
1703 8 gate_console_error_stream_vtbl_impl.get_interface_name = &gate_console_error_interface_name_impl;
1704 8 gate_console_error_stream_vtbl_impl.release = &gate_console_error_release_impl;
1705 8 gate_console_error_stream_vtbl_impl.retain = &gate_console_error_retain_impl;
1706 8 gate_console_error_stream_vtbl_impl.read = &gate_console_error_read_impl;
1707 8 gate_console_error_stream_vtbl_impl.peek = &gate_console_error_peek_impl;
1708 8 gate_console_error_stream_vtbl_impl.write = &gate_console_error_write_impl;
1709 8 gate_console_error_stream_vtbl_impl.flush = &gate_console_error_flush_impl;
1710
1711 8 gate_console_error_stream_impl.vtbl = &gate_console_error_stream_vtbl_impl;
1712 }
1713 8 return (gate_stream_t*)&gate_console_error_stream_impl;
1714 }
1715
1716 6 gate_result_t gate_console_write_err(gate_console_t* con, char const* buffer, gate_size_t bufferlen)
1717 {
1718 6 gate_size_t lenwritten = 0;
1719 6 return con->vtbl->write_err(con, buffer, bufferlen, &lenwritten);
1720 }
1721 gate_result_t gate_console_print_err(gate_console_t* con, char const* buffer)
1722 {
1723 return gate_console_write_err(con, buffer, gate_str_length(buffer));
1724 }
1725 gate_result_t gate_console_print_err_num(gate_console_t* con, gate_int64_t num)
1726 {
1727 char buffer[128];
1728 gate_size_t len = gate_str_print_int64(buffer, sizeof(buffer), num);
1729 return gate_console_write_err(con, buffer, len);
1730 }
1731
1732 gate_result_t gate_console_println_err(gate_console_t* con, char const* buffer)
1733 {
1734 gate_result_t ret;
1735 ret = gate_console_print_err(con, buffer);
1736 if (GATE_SUCCEEDED(ret))
1737 {
1738 ret = gate_console_write_err(con, GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH);
1739 }
1740 return ret;
1741 }
1742
1743 1 gate_result_t gate_console_readln(gate_console_t* con, gate_string_t* line)
1744 {
1745 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
1746 1 gate_size_t retrieved = 0;
1747 1 gate_result_t result = gate_stream_read(con, &buffer[0], sizeof(buffer), &retrieved);
1748
1749
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(result))
1750 {
1751
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_string_create(line, buffer, retrieved))
1752 {
1753 result = GATE_RESULT_OUTOFMEMORY;
1754 }
1755 }
1756 1 return result;
1757 }
1758
1759 1 gate_result_t gate_console_readln_raw(gate_console_t* con, gate_string_t* line, gate_uint32_t timeout_ms)
1760 {
1761 1 gate_result_t ret = GATE_RESULT_FAILED;
1762 gate_char32_t chr32;
1763 char utf8_chars[16];
1764 gate_size_t utf8_chars_used;
1765 gate_strbuilder_t builder;
1766 1 gate_timecounter_t timeout_timepoint = 0;
1767 gate_timecounter_t now;
1768 1 gate_uint32_t next_timeout_ms = GATE_CONSOLE_TIMEOUT_NEVER;
1769 gate_int64_t diff;
1770
1771 do
1772 {
1773
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (timeout_ms != GATE_CONSOLE_TIMEOUT_NEVER)
1774 {
1775 1 ret = gate_timecounter_now(&timeout_timepoint);
1776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1777 1 timeout_timepoint = gate_timecounter_add(timeout_timepoint, (gate_int64_t)timeout_ms * 1000);
1778 }
1779 else
1780 {
1781 /* we have no timeout */
1782 next_timeout_ms = GATE_CONSOLE_TIMEOUT_NEVER;
1783 }
1784
1785 1 gate_strbuilder_create(&builder, 16);
1786
1787 for (;;)
1788 {
1789
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (timeout_ms != GATE_CONSOLE_TIMEOUT_NEVER)
1790 {
1791 /* calculate next character max timeout */
1792 1 gate_timecounter_now(&now);
1793 1 diff = gate_timecounter_diff(timeout_timepoint, now);
1794
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (diff < 0)
1795 {
1796 /* timeout reached */
1797 1 break;
1798 }
1799 else
1800 {
1801 next_timeout_ms = (gate_uint32_t)(diff / 1000);
1802 }
1803 }
1804
1805 ret = gate_console_timed_read_char(con, next_timeout_ms, &chr32);
1806 GATE_BREAK_IF_FAILED(ret);
1807 utf8_chars_used = gate_char_write_utf8(chr32, utf8_chars, sizeof(utf8_chars));
1808 gate_strbuilder_append_text(&builder, utf8_chars, utf8_chars_used);
1809 if ((chr32 == 13) || (chr32 == 10))
1810 {
1811 break;
1812 }
1813 }
1814
1815 1 ret = GATE_RESULT_OK;
1816
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (line != NULL)
1817 {
1818
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (gate_strbuilder_length(&builder) > 0)
1819 {
1820 if (NULL == gate_strbuilder_to_string(&builder, line))
1821 {
1822 ret = GATE_RESULT_OUTOFMEMORY;
1823 }
1824 }
1825 else
1826 {
1827 1 gate_string_create_empty(line);
1828 }
1829 }
1830 } while (0);
1831
1832 1 gate_strbuilder_release(&builder);
1833 1 return ret;
1834 }
1835
1836 2 gate_result_t gate_console_timed_read_char(gate_console_t* con, gate_uint32_t timeout_ms, gate_char32_t* ptr_chr)
1837 {
1838 2 gate_result_t result = gate_console_await_char(con, timeout_ms);
1839
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(result))
1840 {
1841 2 result = gate_console_read_char(con, ptr_chr);
1842 }
1843 2 return result;
1844 }
1845