GCC Code Coverage Report


Directory: src/gate/
File: src/gate/console.c
Date: 2025-12-12 23:40:09
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-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 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 82 static void gate_init_console_vtbl()
74 {
75
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 52 times.
82 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 82 }
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 3339 gate_result_t gate_console_write_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
724 {
725 3339 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
726 3339 ssize_t result = write(ptr->write_handle, buffer, (int)bufferlength);
727
1/2
✓ Branch 0 taken 3339 times.
✗ Branch 1 not taken.
3339 if (result >= 0)
728 {
729
1/2
✓ Branch 0 taken 3339 times.
✗ Branch 1 not taken.
3339 if (written != NULL)
730 {
731 3339 *written = (gate_size_t)result;
732 }
733 3339 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 23 gate_result_t gate_console_write_err_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
827 {
828 23 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
829 23 ssize_t result = write(ptr->error_handle, buffer, (int)bufferlength);
830
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (result >= 0)
831 {
832
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (written != NULL)
833 {
834 23 *written = (gate_size_t)result;
835 }
836 23 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 82 gate_console_t* gate_console()
891 {
892 82 gate_init_console_vtbl();
893 82 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_UNUSED_ARG(self);
1239 GATE_UNUSED_ARG(buffer);
1240 GATE_UNUSED_ARG(bufferlength);
1241 GATE_UNUSED_ARG(returned);
1242 return GATE_RESULT_NOTSUPPORTED;
1243 }
1244 gate_result_t gate_console_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1245 {
1246 gate_console_impl_t* impl = (gate_console_impl_t*)self;
1247 gate_result_t ret = GATE_RESULT_OK;
1248 gate_char32_t utf32_chr = 0;
1249 gate_char16_t utf16_chr[8] = { 0 };
1250 gate_size_t chars_read = 0;
1251 gate_size_t chars_converted;
1252 gate_size_t chars_written = 0;
1253 gate_size_t ndx;
1254
1255 while (bufferlength > 0)
1256 {
1257 chars_read = gate_char_read_utf8(buffer, bufferlength, &utf32_chr);
1258 if (chars_read == 0)
1259 {
1260 break;
1261 }
1262 buffer += chars_read;
1263 bufferlength -= chars_read;
1264 chars_converted = gate_char_write_utf16(utf32_chr, &utf16_chr[0], 4);
1265
1266 for (ndx = 0; ndx != chars_converted; ++ndx)
1267 {
1268 ret = gate_platform_efi_console_write_char(utf16_chr[ndx]);
1269 GATE_BREAK_IF_FAILED(ret);
1270 }
1271 GATE_BREAK_IF_FAILED(ret);
1272
1273 chars_written += chars_read;
1274 }
1275
1276 if (written)
1277 {
1278 *written = chars_written;
1279 }
1280 return ret;
1281 }
1282 gate_result_t gate_console_flush_impl(void* self)
1283 {
1284 GATE_UNUSED_ARG(self);
1285 return GATE_RESULT_OK;
1286 }
1287
1288 gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
1289 {
1290 return GATE_RESULT_NOTSUPPORTED;
1291 }
1292
1293
1294 gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
1295 {
1296 return gate_platform_efi_console_await_char(timeout_ms);
1297
1298 }
1299 gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
1300 {
1301 gate_result_t ret = GATE_RESULT_FAILED;
1302 gate_char16_t chr16;
1303
1304 do
1305 {
1306 ret = gate_platform_efi_console_read_char(&chr16, NULL, false);
1307 GATE_BREAK_IF_FAILED(ret);
1308
1309 if (ptr_char)
1310 {
1311 if (chr16 == 13)
1312 {
1313 *ptr_char = 10;
1314 }
1315 else
1316 {
1317 *ptr_char = (gate_char32_t)chr16;
1318 }
1319 }
1320 } while (0);
1321
1322 return ret;
1323 }
1324
1325
1326 gate_result_t gate_console_write_err_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1327 {
1328 return gate_console_write_impl(self, buffer, bufferlength, written);
1329 }
1330 gate_result_t gate_console_flush_err_impl(void* self)
1331 {
1332 return gate_console_flush_impl(self);
1333 }
1334
1335 gate_result_t gate_console_read_key(gate_console_t* con,
1336 gate_uint32_t timeout_ms,
1337 gate_input_keycode_t* out_ptr_keycode,
1338 gate_char32_t* out_ptr_chr,
1339 char* out_buffer, gate_size_t* out_buffer_len)
1340 {
1341 gate_result_t ret;
1342 gate_char16_t chr16 = 0;
1343 gate_uint16_t scan_code = 0;
1344
1345 do
1346 {
1347 ret = gate_console_await_char_impl(con, timeout_ms);
1348 GATE_BREAK_IF_FAILED(ret);
1349
1350 ret = gate_platform_efi_console_read_char(&chr16, &scan_code, false);
1351 GATE_BREAK_IF_FAILED(ret);
1352
1353 if (out_ptr_keycode)
1354 {
1355 *out_ptr_keycode = scan_code;
1356 }
1357 if (out_ptr_chr)
1358 {
1359 *out_ptr_chr = chr16;
1360 }
1361 if (out_buffer && out_buffer_len)
1362 {
1363 *out_buffer_len = gate_char_write_utf8(chr16, out_buffer, *out_buffer_len);
1364 }
1365 } while (0);
1366
1367 return ret;
1368 }
1369
1370
1371 static gate_console_impl_t gate_console_impl_instance = {
1372 &gate_console_vtbl
1373 };
1374
1375 gate_console_t* gate_console()
1376 {
1377 gate_init_console_vtbl();
1378 return (gate_console_t*)&gate_console_impl_instance;
1379 }
1380
1381 #endif /* GATE_CORE_CONSOLE_EFI */
1382
1383
1384 #if defined(GATE_CORE_CONSOLE_WASM_IMPL)
1385
1386
1387 #include "gate/platforms.h"
1388 #include "gate/platform/wasm/wasm_gate.h"
1389
1390 typedef struct gate_console_class_impl
1391 {
1392 GATE_INTERFACE_VTBL(gate_console)* vtbl;
1393
1394 gate_platform_stream_t read_handle;
1395 gate_platform_stream_t write_handle;
1396 gate_platform_stream_t error_handle;
1397 } gate_console_impl_t;
1398
1399
1400 static void gate_console_release_impl(void* self)
1401 {
1402 (void)self;
1403 }
1404 static int gate_console_retain_impl(void* self)
1405 {
1406 (void)self;
1407 return 1;
1408 }
1409
1410 gate_result_t gate_console_read_impl(void* stream, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1411 {
1412 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
1413 return gate_platform_stream_read(ptr->read_handle, buffer, bufferlength, returned);
1414 }
1415 gate_result_t gate_console_peek_impl(void* stream, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1416 {
1417 (void)stream;
1418 (void)buffer;
1419 (void)bufferlength;
1420 (void)returned;
1421 return GATE_RESULT_NOTSUPPORTED;
1422 }
1423 gate_result_t gate_console_write_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1424 {
1425 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
1426 return gate_platform_stream_write(ptr->write_handle, buffer, bufferlength, written);
1427 }
1428 gate_result_t gate_console_flush_impl(void* stream)
1429 {
1430 (void)stream;
1431 return GATE_RESULT_OK;
1432 }
1433 gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
1434 {
1435 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1436 return ret;
1437 }
1438 gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
1439 {
1440 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1441 return ret;
1442 }
1443
1444 gate_result_t gate_console_write_err_impl(void* stream, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1445 {
1446 gate_console_impl_t* ptr = (gate_console_impl_t*)stream;
1447 return gate_platform_stream_write(ptr->error_handle, buffer, bufferlength, written);
1448 }
1449 gate_result_t gate_console_flush_err_impl(void* stream)
1450 {
1451 (void)stream;
1452 return GATE_RESULT_OK;
1453 }
1454 static gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
1455 {
1456 gate_console_impl_t* ptr = (gate_console_impl_t*)self;
1457 gate_result_t ret;
1458 switch (resource_type)
1459 {
1460 case GATE_STREAM_RESOURCE_INPUT:
1461 {
1462 *resource = (gate_uintptr_t)ptr->read_handle;
1463 ret = GATE_RESULT_OK;
1464 break;
1465 }
1466 case GATE_STREAM_RESOURCE_OUTPUT:
1467 {
1468 *resource = (gate_uintptr_t)ptr->write_handle;
1469 ret = GATE_RESULT_OK;
1470 break;
1471 }
1472 case GATE_STREAM_RESOURCE_ERROR:
1473 {
1474 *resource = (gate_uintptr_t)ptr->error_handle;
1475 ret = GATE_RESULT_OK;
1476 break;
1477 }
1478 default:
1479 {
1480 ret = GATE_RESULT_NOTSUPPORTED;
1481 break;
1482 }
1483 }
1484 return ret;
1485 }
1486
1487 gate_result_t gate_console_read_key(gate_console_t* con,
1488 gate_uint32_t timeout_ms,
1489 gate_input_keycode_t* out_ptr_keycode,
1490 gate_char32_t* out_ptr_chr,
1491 char* out_buffer, gate_size_t* out_buffer_len)
1492 {
1493 gate_result_t result;
1494 gate_char32_t chr32 = 0;
1495 gate_input_keycode_t keycode = 0;
1496
1497 do
1498 {
1499 result = gate_console_await_char(con, timeout_ms);
1500 GATE_BREAK_IF_FAILED(result);
1501
1502 result = gate_console_read_char(con, &chr32);
1503 GATE_BREAK_IF_FAILED(result);
1504 } while (0);
1505
1506 if (out_ptr_chr)
1507 {
1508 *out_ptr_chr = chr32;
1509 }
1510 if (out_ptr_keycode)
1511 {
1512 *out_ptr_keycode = keycode;
1513 }
1514 if (out_buffer && out_buffer_len)
1515 {
1516 *out_buffer_len = 0;
1517 }
1518
1519 return result;
1520 }
1521
1522 static gate_console_impl_t gate_console_impl_instance = {
1523 &gate_console_vtbl,
1524
1525 (gate_platform_stream_t)(gate_intptr_t)0,
1526 (gate_platform_stream_t)(gate_intptr_t)1,
1527 (gate_platform_stream_t)(gate_intptr_t)2
1528 };
1529
1530 gate_console_t* gate_console()
1531 {
1532 gate_init_console_vtbl();
1533 gate_wasm_console_init();
1534 return (gate_console_t*)&gate_console_impl_instance;
1535 }
1536
1537
1538 #endif /* GATE_CORE_CONSOLE_WASM_IMPL */
1539
1540
1541
1542
1543 #if defined(GATE_CORE_CONSOLE_NOIMPL)
1544
1545
1546 typedef struct gate_console_class_impl
1547 {
1548 GATE_INTERFACE_VTBL(gate_console)* vtbl;
1549 } gate_console_impl_t;
1550
1551 static gate_console_impl_t gate_console_impl_instance = {
1552 &gate_console_vtbl
1553 };
1554
1555 static gate_result_t gate_console_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1556 {
1557 GATE_UNUSED_ARG(self);
1558 GATE_UNUSED_ARG(buffer);
1559 GATE_UNUSED_ARG(bufferlength);
1560 GATE_UNUSED_ARG(returned);
1561 return GATE_RESULT_NOTIMPLEMENTED;
1562 }
1563 static gate_result_t gate_console_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1564 {
1565 GATE_UNUSED_ARG(self);
1566 GATE_UNUSED_ARG(buffer);
1567 GATE_UNUSED_ARG(bufferlength);
1568 GATE_UNUSED_ARG(returned);
1569 return GATE_RESULT_NOTIMPLEMENTED;
1570 }
1571 static gate_result_t gate_console_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1572 {
1573 GATE_UNUSED_ARG(self);
1574 GATE_UNUSED_ARG(buffer);
1575 GATE_UNUSED_ARG(bufferlength);
1576 GATE_UNUSED_ARG(written);
1577 return GATE_RESULT_NOTIMPLEMENTED;
1578 }
1579 static gate_result_t gate_console_flush_impl(void* self)
1580 {
1581 GATE_UNUSED_ARG(self);
1582 return GATE_RESULT_NOTIMPLEMENTED;
1583 }
1584
1585 static gate_result_t gate_console_get_resource_impl(void* self, gate_enumint_t resource_type, gate_uintptr_t* resource)
1586 {
1587 GATE_UNUSED_ARG(self);
1588 GATE_UNUSED_ARG(resource_type);
1589 GATE_UNUSED_ARG(resource);
1590 return GATE_RESULT_NOTIMPLEMENTED;
1591 }
1592
1593 static gate_result_t gate_console_await_char_impl(void* self, gate_uint32_t timeout_ms)
1594 {
1595 GATE_UNUSED_ARG(self);
1596 GATE_UNUSED_ARG(timeout_ms);
1597 return GATE_RESULT_NOTIMPLEMENTED;
1598 }
1599 static gate_result_t gate_console_read_char_impl(void* self, gate_char32_t* ptr_char)
1600 {
1601 GATE_UNUSED_ARG(self);
1602 GATE_UNUSED_ARG(ptr_char);
1603 return GATE_RESULT_NOTIMPLEMENTED;
1604 }
1605 static gate_result_t gate_console_write_err_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1606 {
1607 GATE_UNUSED_ARG(self);
1608 GATE_UNUSED_ARG(buffer);
1609 GATE_UNUSED_ARG(bufferlength);
1610 GATE_UNUSED_ARG(written);
1611 return GATE_RESULT_NOTIMPLEMENTED;
1612 }
1613 static gate_result_t gate_console_flush_err_impl(void* self)
1614 {
1615 GATE_UNUSED_ARG(self);
1616 return GATE_RESULT_NOTIMPLEMENTED;
1617 }
1618 static void gate_console_release_impl(void* self)
1619 {
1620 GATE_UNUSED_ARG(self);
1621
1622 }
1623 static int gate_console_retain_impl(void* self)
1624 {
1625 GATE_UNUSED_ARG(self);
1626 return 0;
1627 }
1628
1629 gate_console_t* gate_console()
1630 {
1631 gate_init_console_vtbl();
1632 return (gate_console_t*)&gate_console_impl_instance;
1633 }
1634
1635
1636 #endif /* GATE_CORE_CONSOLE_NOIMPL */
1637
1638
1639
1640 /****************************
1641 * Generic implementation *
1642 ****************************/
1643
1644 1 gate_stream_t* gate_console_stream()
1645 {
1646 1 return (gate_stream_t*)gate_console();
1647 }
1648
1649 12 static void gate_console_error_release_impl(void* self)
1650 {
1651 GATE_UNUSED_ARG(self);
1652 12 }
1653 static int gate_console_error_retain_impl(void* self)
1654 {
1655 GATE_UNUSED_ARG(self);
1656 return 1;
1657 }
1658 1 static char const* gate_console_error_interface_name_impl(void* self)
1659 {
1660 GATE_UNUSED_ARG(self);
1661 1 return GATE_INTERFACE_NAME_STREAM;
1662 }
1663 1 static gate_result_t gate_console_error_read_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1664 {
1665 GATE_UNUSED_ARG(self);
1666 GATE_UNUSED_ARG(buffer);
1667 GATE_UNUSED_ARG(bufferlength);
1668 GATE_UNUSED_ARG(returned);
1669 1 return GATE_RESULT_NOTSUPPORTED;
1670 }
1671 1 static gate_result_t gate_console_error_peek_impl(void* self, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1672 {
1673 GATE_UNUSED_ARG(self);
1674 GATE_UNUSED_ARG(buffer);
1675 GATE_UNUSED_ARG(bufferlength);
1676 GATE_UNUSED_ARG(returned);
1677 1 return GATE_RESULT_NOTSUPPORTED;
1678 }
1679 11 static gate_result_t gate_console_error_write_impl(void* self, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1680 {
1681 11 gate_console_t* con = gate_console();
1682 GATE_UNUSED_ARG(self);
1683 11 return con->vtbl->write_err(con, buffer, bufferlength, written);
1684 }
1685 1 static gate_result_t gate_console_error_flush_impl(void* self)
1686 {
1687 1 gate_console_t* con = gate_console();
1688 GATE_UNUSED_ARG(self);
1689 1 return con->vtbl->flush_err(con);
1690 }
1691
1692 typedef struct
1693 {
1694 GATE_INTERFACE_VTBL(gate_stream) const* vtbl;
1695 } gate_console_error_stream_impl_t;
1696
1697 static gate_console_error_stream_impl_t gate_console_error_stream_impl;
1698
1699 16 gate_stream_t* gate_console_error_stream()
1700 {
1701 static GATE_INTERFACE_VTBL(gate_stream) gate_console_error_stream_vtbl_impl;
1702
1703
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16 if (!gate_console_error_stream_impl.vtbl)
1704 {
1705 14 gate_console_error_stream_vtbl_impl.get_interface_name = &gate_console_error_interface_name_impl;
1706 14 gate_console_error_stream_vtbl_impl.release = &gate_console_error_release_impl;
1707 14 gate_console_error_stream_vtbl_impl.retain = &gate_console_error_retain_impl;
1708 14 gate_console_error_stream_vtbl_impl.read = &gate_console_error_read_impl;
1709 14 gate_console_error_stream_vtbl_impl.peek = &gate_console_error_peek_impl;
1710 14 gate_console_error_stream_vtbl_impl.write = &gate_console_error_write_impl;
1711 14 gate_console_error_stream_vtbl_impl.flush = &gate_console_error_flush_impl;
1712
1713 14 gate_console_error_stream_impl.vtbl = &gate_console_error_stream_vtbl_impl;
1714 }
1715 16 return (gate_stream_t*)&gate_console_error_stream_impl;
1716 }
1717
1718 10 gate_result_t gate_console_write_err(gate_console_t* con, char const* buffer, gate_size_t bufferlen)
1719 {
1720 10 gate_size_t lenwritten = 0;
1721 10 return con->vtbl->write_err(con, buffer, bufferlen, &lenwritten);
1722 }
1723 2 gate_result_t gate_console_print_err(gate_console_t* con, char const* buffer)
1724 {
1725 2 return gate_console_write_err(con, buffer, gate_str_length(buffer));
1726 }
1727 1 gate_result_t gate_console_print_err_num(gate_console_t* con, gate_int64_t num)
1728 {
1729 char buffer[128];
1730 1 gate_size_t len = gate_str_print_int64(buffer, sizeof(buffer), num);
1731 1 return gate_console_write_err(con, buffer, len);
1732 }
1733
1734 1 gate_result_t gate_console_println_err(gate_console_t* con, char const* buffer)
1735 {
1736 gate_result_t ret;
1737 1 ret = gate_console_print_err(con, buffer);
1738
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(ret))
1739 {
1740 1 ret = gate_console_write_err(con, GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH);
1741 }
1742 1 return ret;
1743 }
1744
1745 1 gate_result_t gate_console_readln(gate_console_t* con, gate_string_t* line)
1746 {
1747 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
1748 1 gate_size_t retrieved = 0;
1749 1 gate_result_t result = gate_stream_read(con, &buffer[0], sizeof(buffer), &retrieved);
1750
1751
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(result))
1752 {
1753
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_string_create(line, buffer, retrieved))
1754 {
1755 result = GATE_RESULT_OUTOFMEMORY;
1756 }
1757 }
1758 1 return result;
1759 }
1760
1761 1 gate_result_t gate_console_readln_raw(gate_console_t* con, gate_string_t* line, gate_uint32_t timeout_ms)
1762 {
1763 1 gate_result_t ret = GATE_RESULT_FAILED;
1764 gate_char32_t chr32;
1765 char utf8_chars[16];
1766 gate_size_t utf8_chars_used;
1767 gate_strbuilder_t builder;
1768 1 gate_timecounter_t timeout_timepoint = 0;
1769 gate_timecounter_t now;
1770 1 gate_uint32_t next_timeout_ms = GATE_CONSOLE_TIMEOUT_NEVER;
1771 gate_int64_t diff;
1772
1773 do
1774 {
1775
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (timeout_ms != GATE_CONSOLE_TIMEOUT_NEVER)
1776 {
1777 1 ret = gate_timecounter_now(&timeout_timepoint);
1778
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1779 1 timeout_timepoint = gate_timecounter_add(timeout_timepoint, (gate_int64_t)timeout_ms * 1000);
1780 }
1781 else
1782 {
1783 /* we have no timeout */
1784 next_timeout_ms = GATE_CONSOLE_TIMEOUT_NEVER;
1785 }
1786
1787 1 gate_strbuilder_create(&builder, 16);
1788
1789 for (;;)
1790 {
1791
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (timeout_ms != GATE_CONSOLE_TIMEOUT_NEVER)
1792 {
1793 /* calculate next character max timeout */
1794 1 gate_timecounter_now(&now);
1795 1 diff = gate_timecounter_diff(timeout_timepoint, now);
1796
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (diff < 0)
1797 {
1798 /* timeout reached */
1799 1 break;
1800 }
1801 else
1802 {
1803 next_timeout_ms = (gate_uint32_t)(diff / 1000);
1804 }
1805 }
1806
1807 ret = gate_console_timed_read_char(con, next_timeout_ms, &chr32);
1808 GATE_BREAK_IF_FAILED(ret);
1809 utf8_chars_used = gate_char_write_utf8(chr32, utf8_chars, sizeof(utf8_chars));
1810 gate_strbuilder_append_text(&builder, utf8_chars, utf8_chars_used);
1811 if ((chr32 == 13) || (chr32 == 10))
1812 {
1813 break;
1814 }
1815 }
1816
1817 1 ret = GATE_RESULT_OK;
1818
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (line != NULL)
1819 {
1820
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (gate_strbuilder_length(&builder) > 0)
1821 {
1822 if (NULL == gate_strbuilder_to_string(&builder, line))
1823 {
1824 ret = GATE_RESULT_OUTOFMEMORY;
1825 }
1826 }
1827 else
1828 {
1829 1 gate_string_create_empty(line);
1830 }
1831 }
1832 } while (0);
1833
1834 1 gate_strbuilder_release(&builder);
1835 1 return ret;
1836 }
1837
1838 2 gate_result_t gate_console_timed_read_char(gate_console_t* con, gate_uint32_t timeout_ms, gate_char32_t* ptr_chr)
1839 {
1840 2 gate_result_t result = gate_console_await_char(con, timeout_ms);
1841
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(result))
1842 {
1843 2 result = gate_console_read_char(con, ptr_chr);
1844 }
1845 2 return result;
1846 }
1847