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