include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / msvcrt / console.c
blob2c6b59d36c6346914a3861f4c8240e4d0f31da76
1 /*
2 * msvcrt.dll console functions
4 * Copyright 2000 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Note: init and free don't need MT locking since they are called at DLL
21 * (de)attachment time, which is synchronised for us
24 #include "msvcrt.h"
25 #include "winnls.h"
26 #include "wincon.h"
27 #include "mtdll.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
32 /* MT */
33 #define LOCK_CONSOLE _lock(_CONIO_LOCK)
34 #define UNLOCK_CONSOLE _unlock(_CONIO_LOCK)
36 static HANDLE MSVCRT_console_in;
37 static HANDLE MSVCRT_console_out;
38 static int __MSVCRT_console_buffer = EOF;
39 static wchar_t __MSVCRT_console_buffer_w = WEOF;
41 /* INTERNAL: Initialise console handles, _CONIO_LOCK must be held */
42 static HANDLE msvcrt_input_console(void)
44 if (!MSVCRT_console_in)
46 MSVCRT_console_in = CreateFileA("CONIN$", GENERIC_WRITE|GENERIC_READ,
47 FILE_SHARE_WRITE|FILE_SHARE_READ,
48 NULL, OPEN_EXISTING, 0, NULL);
49 if (MSVCRT_console_in == INVALID_HANDLE_VALUE)
50 WARN("Input console handle initialization failed!\n");
52 return MSVCRT_console_in;
55 static HANDLE msvcrt_output_console(void)
57 if (!MSVCRT_console_out)
59 MSVCRT_console_out = CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
60 NULL, OPEN_EXISTING, 0, NULL);
61 if (MSVCRT_console_out == INVALID_HANDLE_VALUE)
62 WARN("Output console handle initialization failed!\n");
64 return MSVCRT_console_out;
67 /* INTERNAL: Free console handles */
68 void msvcrt_free_console(void)
70 TRACE(":Closing console handles\n");
71 CloseHandle(MSVCRT_console_in);
72 CloseHandle(MSVCRT_console_out);
75 /*********************************************************************
76 * _cputs (MSVCRT.@)
78 int CDECL _cputs(const char* str)
80 DWORD count;
81 int len, retval = -1;
83 if (!MSVCRT_CHECK_PMT(str != NULL)) return -1;
84 len = strlen(str);
86 LOCK_CONSOLE;
87 if (WriteConsoleA(msvcrt_output_console(), str, len, &count, NULL)
88 && count == len)
89 retval = 0;
90 UNLOCK_CONSOLE;
91 return retval;
94 /*********************************************************************
95 * _cputws (MSVCRT.@)
97 int CDECL _cputws(const wchar_t* str)
99 DWORD count;
100 int len, retval = -1;
102 if (!MSVCRT_CHECK_PMT(str != NULL)) return -1;
103 len = wcslen(str);
105 LOCK_CONSOLE;
106 if (WriteConsoleW(msvcrt_output_console(), str, len, &count, NULL)
107 && count == len)
108 retval = 0;
109 UNLOCK_CONSOLE;
110 return retval;
113 #define NORMAL_CHAR 0
114 #define ALT_CHAR 1
115 #define CTRL_CHAR 2
116 #define SHIFT_CHAR 3
118 static const struct {unsigned short vk; unsigned char ch[4][2];} enh_map[] = {
119 {0x47, {{0xE0, 0x47}, {0x00, 0x97}, {0xE0, 0x77}, {0xE0, 0x47}}},
120 {0x48, {{0xE0, 0x48}, {0x00, 0x98}, {0xE0, 0x8D}, {0xE0, 0x48}}},
121 {0x49, {{0xE0, 0x49}, {0x00, 0x99}, {0xE0, 0x86}, {0xE0, 0x49}}},
122 {0x4B, {{0xE0, 0x4B}, {0x00, 0x9B}, {0xE0, 0x73}, {0xE0, 0x4B}}},
123 {0x4D, {{0xE0, 0x4D}, {0x00, 0x9D}, {0xE0, 0x74}, {0xE0, 0x4D}}},
124 {0x4F, {{0xE0, 0x4F}, {0x00, 0x9F}, {0xE0, 0x75}, {0xE0, 0x4F}}},
125 {0x50, {{0xE0, 0x50}, {0x00, 0xA0}, {0xE0, 0x91}, {0xE0, 0x50}}},
126 {0x51, {{0xE0, 0x51}, {0x00, 0xA1}, {0xE0, 0x76}, {0xE0, 0x51}}},
127 {0x52, {{0xE0, 0x52}, {0x00, 0xA2}, {0xE0, 0x92}, {0xE0, 0x52}}},
128 {0x53, {{0xE0, 0x53}, {0x00, 0xA3}, {0xE0, 0x93}, {0xE0, 0x53}}},
131 static BOOL handle_enhanced_keys(INPUT_RECORD *ir, unsigned char *ch1, unsigned char *ch2)
133 int i;
135 for (i = 0; i < ARRAY_SIZE(enh_map); i++)
137 if (ir->Event.KeyEvent.wVirtualScanCode == enh_map[i].vk)
139 unsigned idx;
141 if (ir->Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
142 idx = ALT_CHAR;
143 else if (ir->Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) )
144 idx = CTRL_CHAR;
145 else if (ir->Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
146 idx = SHIFT_CHAR;
147 else
148 idx = NORMAL_CHAR;
150 *ch1 = enh_map[i].ch[idx][0];
151 *ch2 = enh_map[i].ch[idx][1];
152 return TRUE;
156 WARN("Unmapped char keyState=%lx vk=%x\n",
157 ir->Event.KeyEvent.dwControlKeyState, ir->Event.KeyEvent.wVirtualScanCode);
158 return FALSE;
161 /*********************************************************************
162 * _getch_nolock (MSVCR80.@)
164 int CDECL _getch_nolock(void)
166 int retval = EOF;
168 if (__MSVCRT_console_buffer != EOF)
170 retval = __MSVCRT_console_buffer;
171 __MSVCRT_console_buffer = EOF;
173 else
175 INPUT_RECORD ir;
176 DWORD count;
177 DWORD mode = 0;
179 GetConsoleMode(msvcrt_input_console(), &mode);
180 if(mode)
181 SetConsoleMode(msvcrt_input_console(), 0);
183 do {
184 if (ReadConsoleInputA(msvcrt_input_console(), &ir, 1, &count))
186 /* Only interested in ASCII chars */
187 if (ir.EventType == KEY_EVENT &&
188 ir.Event.KeyEvent.bKeyDown)
190 unsigned char ch1, ch2;
192 if (ir.Event.KeyEvent.uChar.AsciiChar)
194 retval = ir.Event.KeyEvent.uChar.AsciiChar;
195 break;
198 if (handle_enhanced_keys(&ir, &ch1, &ch2))
200 retval = ch1;
201 __MSVCRT_console_buffer = ch2;
202 break;
206 else
207 break;
208 } while(1);
209 if (mode)
210 SetConsoleMode(msvcrt_input_console(), mode);
212 return retval;
215 /*********************************************************************
216 * _getch (MSVCRT.@)
218 int CDECL _getch(void)
220 int ret;
222 LOCK_CONSOLE;
223 ret = _getch_nolock();
224 UNLOCK_CONSOLE;
225 return ret;
228 /*********************************************************************
229 * _getwch_nolock (MSVCR80.@)
231 wchar_t CDECL _getwch_nolock(void)
233 wchar_t retval = WEOF;
235 if (__MSVCRT_console_buffer_w != WEOF)
237 retval = __MSVCRT_console_buffer_w;
238 __MSVCRT_console_buffer_w = WEOF;
240 else
242 INPUT_RECORD ir;
243 DWORD count;
244 DWORD mode = 0;
246 GetConsoleMode(msvcrt_input_console(), &mode);
247 if(mode)
248 SetConsoleMode(msvcrt_input_console(), 0);
250 do {
251 if (ReadConsoleInputW(msvcrt_input_console(), &ir, 1, &count))
253 /* Only interested in ASCII chars */
254 if (ir.EventType == KEY_EVENT &&
255 ir.Event.KeyEvent.bKeyDown)
257 unsigned char ch1, ch2;
259 if (ir.Event.KeyEvent.uChar.UnicodeChar)
261 retval = ir.Event.KeyEvent.uChar.UnicodeChar;
262 break;
265 if (handle_enhanced_keys(&ir, &ch1, &ch2))
267 retval = ch1;
268 __MSVCRT_console_buffer_w = ch2;
269 break;
273 else
274 break;
275 } while(1);
276 if (mode)
277 SetConsoleMode(msvcrt_input_console(), mode);
279 return retval;
282 /*********************************************************************
283 * _getwch (MSVCRT.@)
285 wchar_t CDECL _getwch(void)
287 wchar_t ret;
289 LOCK_CONSOLE;
290 ret = _getwch_nolock();
291 UNLOCK_CONSOLE;
292 return ret;
295 /*********************************************************************
296 * _putch_nolock (MSVCR80.@)
298 int CDECL _putch_nolock(int c)
300 DWORD count;
301 if (WriteConsoleA(msvcrt_output_console(), &c, 1, &count, NULL) && count == 1)
302 return c;
303 return EOF;
306 /*********************************************************************
307 * _putch (MSVCRT.@)
309 int CDECL _putch(int c)
311 LOCK_CONSOLE;
312 c = _putch_nolock(c);
313 UNLOCK_CONSOLE;
314 return c;
317 /*********************************************************************
318 * _putwch_nolock (MSVCR80.@)
320 wchar_t CDECL _putwch_nolock(wchar_t c)
322 DWORD count;
323 if (WriteConsoleW(msvcrt_output_console(), &c, 1, &count, NULL) && count==1)
324 return c;
325 return WEOF;
328 /*********************************************************************
329 * _putwch (MSVCRT.@)
331 wchar_t CDECL _putwch(wchar_t c)
333 LOCK_CONSOLE;
334 c = _putwch_nolock(c);
335 UNLOCK_CONSOLE;
336 return c;
339 /*********************************************************************
340 * _getche_nolock (MSVCR80.@)
342 int CDECL _getche_nolock(void)
344 int retval;
345 retval = _getch_nolock();
346 if (retval != EOF)
347 retval = _putch_nolock(retval);
348 return retval;
351 /*********************************************************************
352 * _getche (MSVCRT.@)
354 int CDECL _getche(void)
356 int ret;
358 LOCK_CONSOLE;
359 ret = _getche_nolock();
360 UNLOCK_CONSOLE;
361 return ret;
364 /*********************************************************************
365 * _getwche_nolock (MSVCR80.@)
367 wchar_t CDECL _getwche_nolock(void)
369 wchar_t wch;
370 wch = _getch_nolock();
371 if (wch == WEOF)
372 return wch;
373 return _putwch_nolock(wch);
376 /*********************************************************************
377 * _getwche (MSVCRT.@)
379 wchar_t CDECL _getwche(void)
381 wchar_t ret;
383 LOCK_CONSOLE;
384 ret = _getwche_nolock();
385 UNLOCK_CONSOLE;
386 return ret;
389 /*********************************************************************
390 * _cgets (MSVCRT.@)
392 char* CDECL _cgets(char* str)
394 char *buf = str + 2;
395 DWORD got;
396 DWORD conmode = 0;
398 TRACE("(%p)\n", str);
399 str[1] = 0; /* Length */
400 LOCK_CONSOLE;
401 GetConsoleMode(msvcrt_input_console(), &conmode);
402 SetConsoleMode(msvcrt_input_console(), ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT);
404 if(ReadConsoleA(msvcrt_input_console(), buf, str[0], &got, NULL)) {
405 if(buf[got-2] == '\r') {
406 buf[got-2] = 0;
407 str[1] = got-2;
409 else if(got == 1 && buf[got-1] == '\n') {
410 buf[0] = 0;
411 str[1] = 0;
413 else if(got == str[0] && buf[got-1] == '\r') {
414 buf[got-1] = 0;
415 str[1] = got-1;
417 else
418 str[1] = got;
420 else
421 buf = NULL;
422 SetConsoleMode(msvcrt_input_console(), conmode);
423 UNLOCK_CONSOLE;
424 return buf;
427 /*********************************************************************
428 * _ungetch_nolock (MSVCRT.@)
430 int CDECL _ungetch_nolock(int c)
432 int retval = EOF;
433 if (c != EOF && __MSVCRT_console_buffer == EOF)
434 retval = __MSVCRT_console_buffer = c;
435 return retval;
438 /*********************************************************************
439 * _ungetch (MSVCRT.@)
441 int CDECL _ungetch(int c)
443 LOCK_CONSOLE;
444 c = _ungetch_nolock(c);
445 UNLOCK_CONSOLE;
446 return c;
449 /*********************************************************************
450 * _ungetwch_nolock (MSVCR80.@)
452 wchar_t CDECL _ungetwch_nolock(wchar_t c)
454 wchar_t retval = WEOF;
455 if (c != WEOF && __MSVCRT_console_buffer_w == WEOF)
456 retval = __MSVCRT_console_buffer_w = c;
457 return retval;
460 /*********************************************************************
461 * _ungetwch (MSVCRT.@)
463 wchar_t CDECL _ungetwch(wchar_t c)
465 LOCK_CONSOLE;
466 c = _ungetwch_nolock(c);
467 UNLOCK_CONSOLE;
468 return c;
471 /*********************************************************************
472 * _kbhit (MSVCRT.@)
474 int CDECL _kbhit(void)
476 int retval = 0;
478 LOCK_CONSOLE;
479 if (__MSVCRT_console_buffer != EOF)
480 retval = 1;
481 else
483 /* FIXME: There has to be a faster way than this in Win32.. */
484 INPUT_RECORD *ir = NULL;
485 DWORD count = 0, i;
487 GetNumberOfConsoleInputEvents(msvcrt_input_console(), &count);
489 if (count && (ir = malloc(count * sizeof(INPUT_RECORD))) &&
490 PeekConsoleInputA(msvcrt_input_console(), ir, count, &count))
491 for(i = 0; i < count; i++)
493 if (ir[i].EventType == KEY_EVENT &&
494 ir[i].Event.KeyEvent.bKeyDown &&
495 ir[i].Event.KeyEvent.uChar.AsciiChar)
497 retval = 1;
498 break;
501 free(ir);
503 UNLOCK_CONSOLE;
504 return retval;
507 static int puts_clbk_console_a(void *ctx, int len, const char *str)
509 LOCK_CONSOLE;
510 if(!WriteConsoleA(msvcrt_output_console(), str, len, NULL, NULL))
511 len = -1;
512 UNLOCK_CONSOLE;
513 return len;
516 static int puts_clbk_console_w(void *ctx, int len, const wchar_t *str)
518 LOCK_CONSOLE;
519 if(!WriteConsoleW(msvcrt_output_console(), str, len, NULL, NULL))
520 len = -1;
521 UNLOCK_CONSOLE;
522 return len;
525 #if _MSVCR_VER<=120
526 /*********************************************************************
527 * _vcprintf_l (MSVCRT.@)
529 int CDECL _vcprintf_l(const char* format, _locale_t locale, va_list valist)
531 return pf_printf_a(puts_clbk_console_a, NULL, format, locale, 0, arg_clbk_valist, NULL, &valist);
533 #endif
535 /*********************************************************************
536 * _vcprintf (MSVCRT.@)
538 int CDECL _vcprintf(const char* format, va_list valist)
540 return pf_printf_a(puts_clbk_console_a, NULL, format, NULL, 0, arg_clbk_valist, NULL, &valist);
543 #if _MSVCR_VER<=120
544 /*********************************************************************
545 * _cprintf_l (MSVCRT.@)
547 int WINAPIV _cprintf_l(const char* format, _locale_t locale, ...)
549 int retval;
550 va_list valist;
552 va_start(valist, locale);
553 retval = _vcprintf_l(format, locale, valist);
554 va_end(valist);
556 return retval;
558 #endif
560 /*********************************************************************
561 * _cprintf (MSVCRT.@)
563 int WINAPIV _cprintf(const char* format, ...)
565 int retval;
566 va_list valist;
568 va_start( valist, format );
569 retval = _vcprintf(format, valist);
570 va_end(valist);
572 return retval;
575 #if _MSVCR_VER<=120
576 /*********************************************************************
577 * _vcwprintf_l (MSVCRT.@)
579 int CDECL _vcwprintf_l(const wchar_t* format, _locale_t locale, va_list valist)
581 return pf_printf_w(puts_clbk_console_w, NULL, format, locale, 0, arg_clbk_valist, NULL, &valist);
584 /*********************************************************************
585 * _vcwprintf (MSVCRT.@)
587 int CDECL _vcwprintf(const wchar_t* format, va_list valist)
589 return pf_printf_w(puts_clbk_console_w, NULL, format, NULL, 0, arg_clbk_valist, NULL, &valist);
592 /*********************************************************************
593 * _cwprintf_l (MSVCRT.@)
595 int WINAPIV _cwprintf_l(const wchar_t* format, _locale_t locale, ...)
597 int retval;
598 va_list valist;
600 va_start(valist, locale);
601 retval = _vcwprintf_l(format, locale, valist);
602 va_end(valist);
604 return retval;
607 /*********************************************************************
608 * _cwprintf (MSVCRT.@)
610 int WINAPIV _cwprintf(const wchar_t* format, ...)
612 int retval;
613 va_list valist;
615 va_start( valist, format );
616 retval = _vcwprintf(format, valist);
617 va_end(valist);
619 return retval;
621 #endif
623 #if _MSVCR_VER>=140
625 /*********************************************************************
626 * __conio_common_vcprintf (UCRTBASE.@)
628 int CDECL __conio_common_vcprintf(unsigned __int64 options, const char* format,
629 _locale_t locale, va_list valist)
631 if (options & ~UCRTBASE_PRINTF_MASK)
632 FIXME("options %#I64x not handled\n", options);
633 return pf_printf_a(puts_clbk_console_a, NULL, format, locale,
634 options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
637 /*********************************************************************
638 * __conio_common_vcwprintf (UCRTBASE.@)
640 int CDECL __conio_common_vcwprintf(unsigned __int64 options, const wchar_t* format,
641 _locale_t locale, va_list valist)
643 if (options & ~UCRTBASE_PRINTF_MASK)
644 FIXME("options %#I64x not handled\n", options);
645 return pf_printf_w(puts_clbk_console_w, NULL, format, locale,
646 options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
649 #endif /* _MSVCR_VER>=140 */