GCC Code Coverage Report


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

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