msvcrt: Keep FILE critical section initialized after closing file.
[wine] / dlls / msvcrt / console.c
1 /*
2  * msvcrt.dll console functions
3  *
4  * Copyright 2000 Jon Griffiths
5  *
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.
10  *
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.
15  *
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
19  *
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
22  */
23
24 #include "msvcrt.h"
25 #include "winnls.h"
26 #include "wincon.h"
27 #include "mtdll.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
31
32
33
34 /* MT */
35 #define LOCK_CONSOLE   _mlock(_CONIO_LOCK)
36 #define UNLOCK_CONSOLE _munlock(_CONIO_LOCK)
37
38 static HANDLE MSVCRT_console_in = INVALID_HANDLE_VALUE;
39 static HANDLE MSVCRT_console_out= INVALID_HANDLE_VALUE;
40 static int __MSVCRT_console_buffer = MSVCRT_EOF;
41
42 /* INTERNAL: Initialise console handles */
43 void msvcrt_init_console(void)
44 {
45   TRACE(":Opening console handles\n");
46
47   MSVCRT_console_in = CreateFileA("CONIN$", GENERIC_READ, FILE_SHARE_READ,
48                                   NULL, OPEN_EXISTING, 0, NULL);
49   MSVCRT_console_out= CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
50                                     NULL, OPEN_EXISTING, 0, NULL);
51
52   if ((MSVCRT_console_in == INVALID_HANDLE_VALUE) ||
53       (MSVCRT_console_out== INVALID_HANDLE_VALUE))
54     WARN(":Console handle Initialisation FAILED!\n");
55 }
56
57 /* INTERNAL: Free console handles */
58 void msvcrt_free_console(void)
59 {
60   TRACE(":Closing console handles\n");
61   CloseHandle(MSVCRT_console_in);
62   CloseHandle(MSVCRT_console_out);
63 }
64
65 /*********************************************************************
66  *              _cputs (MSVCRT.@)
67  */
68 int CDECL _cputs(const char* str)
69 {
70   DWORD count;
71   int retval = MSVCRT_EOF;
72
73   LOCK_CONSOLE;
74   if (WriteConsoleA(MSVCRT_console_out, str, strlen(str), &count, NULL)
75       && count == 1)
76     retval = 0;
77   UNLOCK_CONSOLE;
78   return retval;
79 }
80
81 /*********************************************************************
82  *              _cputws (MSVCRT.@)
83  */
84 int CDECL _cputws(const MSVCRT_wchar_t* str)
85 {
86   DWORD count;
87   int retval = MSVCRT_EOF;
88
89   LOCK_CONSOLE;
90   if (WriteConsoleW(MSVCRT_console_out, str, lstrlenW(str), &count, NULL)
91       && count == 1)
92     retval = 0;
93   UNLOCK_CONSOLE;
94   return retval;
95 }
96
97 #define NORMAL_CHAR     0
98 #define ALT_CHAR        1
99 #define CTRL_CHAR       2
100 #define SHIFT_CHAR      3
101
102 static const struct {unsigned vk; unsigned ch[4][2];} enh_map[] = {
103     {0x47, {{0xE0, 0x47}, {0x00, 0x97}, {0xE0, 0x77}, {0xE0, 0x47}}},
104     {0x48, {{0xE0, 0x48}, {0x00, 0x98}, {0xE0, 0x8D}, {0xE0, 0x48}}},
105     {0x49, {{0xE0, 0x49}, {0x00, 0x99}, {0xE0, 0x86}, {0xE0, 0x49}}},
106     {0x4B, {{0xE0, 0x4B}, {0x00, 0x9B}, {0xE0, 0x73}, {0xE0, 0x4B}}},
107     {0x4D, {{0xE0, 0x4D}, {0x00, 0x9D}, {0xE0, 0x74}, {0xE0, 0x4D}}},
108     {0x4F, {{0xE0, 0x4F}, {0x00, 0x9F}, {0xE0, 0x75}, {0xE0, 0x4F}}},
109     {0x50, {{0xE0, 0x50}, {0x00, 0xA0}, {0xE0, 0x91}, {0xE0, 0x50}}},
110     {0x51, {{0xE0, 0x51}, {0x00, 0xA1}, {0xE0, 0x76}, {0xE0, 0x51}}},
111     {0x52, {{0xE0, 0x52}, {0x00, 0xA2}, {0xE0, 0x92}, {0xE0, 0x52}}},
112     {0x53, {{0xE0, 0x53}, {0x00, 0xA3}, {0xE0, 0x93}, {0xE0, 0x53}}},
113 };
114
115 /*********************************************************************
116  *              _getch (MSVCRT.@)
117  */
118 int CDECL _getch(void)
119 {
120   int retval = MSVCRT_EOF;
121
122   LOCK_CONSOLE;
123   if (__MSVCRT_console_buffer != MSVCRT_EOF)
124   {
125     retval = __MSVCRT_console_buffer;
126     __MSVCRT_console_buffer = MSVCRT_EOF;
127   }
128   else
129   {
130     INPUT_RECORD ir;
131     DWORD count;
132     DWORD mode = 0;
133
134     GetConsoleMode(MSVCRT_console_in, &mode);
135     if(mode)
136       SetConsoleMode(MSVCRT_console_in, 0);
137
138     do {
139       if (ReadConsoleInputA(MSVCRT_console_in, &ir, 1, &count))
140       {
141           unsigned int i;
142         /* Only interested in ASCII chars */
143         if (ir.EventType == KEY_EVENT &&
144             ir.Event.KeyEvent.bKeyDown)
145         {
146             if (ir.Event.KeyEvent.uChar.AsciiChar)
147             {
148                 retval = ir.Event.KeyEvent.uChar.AsciiChar;
149                 break;
150             }
151             for (i = 0; i < sizeof(enh_map) / sizeof(enh_map[0]); i++)
152             {
153                 if (ir.Event.KeyEvent.wVirtualScanCode == enh_map[i].vk) break;
154             }
155             if (i < sizeof(enh_map) / sizeof(enh_map[0]))
156             {
157                 unsigned idx;
158
159                 if (ir.Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
160                     idx = ALT_CHAR;
161                 else if (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) )
162                     idx = CTRL_CHAR;
163                 else if (ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
164                     idx = SHIFT_CHAR;
165                 else
166                     idx = NORMAL_CHAR;
167
168                 retval = enh_map[i].ch[idx][0];
169                 __MSVCRT_console_buffer = enh_map[i].ch[idx][1];
170                 break;
171             }
172             WARN("Unmapped char keyState=%x vk=%x\n",
173                  ir.Event.KeyEvent.dwControlKeyState, ir.Event.KeyEvent.wVirtualScanCode);
174         }
175       }
176       else
177         break;
178     } while(1);
179     if (mode)
180       SetConsoleMode(MSVCRT_console_in, mode);
181   }
182   UNLOCK_CONSOLE;
183   return retval;
184 }
185
186 /*********************************************************************
187  *              _putch (MSVCRT.@)
188  */
189 int CDECL _putch(int c)
190 {
191   int retval = MSVCRT_EOF;
192   DWORD count;
193   LOCK_CONSOLE;
194   if (WriteConsoleA(MSVCRT_console_out, &c, 1, &count, NULL) && count == 1)
195     retval = c;
196   UNLOCK_CONSOLE;
197   return retval;
198 }
199
200 /*********************************************************************
201  *              _getche (MSVCRT.@)
202  */
203 int CDECL _getche(void)
204 {
205   int retval;
206   LOCK_CONSOLE;
207   retval = _getch();
208   if (retval != MSVCRT_EOF)
209     retval = _putch(retval);
210   UNLOCK_CONSOLE;
211   return retval;
212 }
213
214 /*********************************************************************
215  *              _cgets (MSVCRT.@)
216  */
217 char* CDECL _cgets(char* str)
218 {
219   char *buf = str + 2;
220   DWORD got;
221   DWORD conmode = 0;
222
223   TRACE("(%p)\n", str);
224   str[1] = 0; /* Length */
225   LOCK_CONSOLE;
226   GetConsoleMode(MSVCRT_console_in, &conmode);
227   SetConsoleMode(MSVCRT_console_in, ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT);
228
229   if(ReadConsoleA(MSVCRT_console_in, buf, str[0], &got, NULL)) {
230     if(buf[got-2] == '\r') {
231       buf[got-2] = 0;
232       str[1] = got-2;
233     }
234     else if(got == 1 && buf[got-1] == '\n') {
235       buf[0] = 0;
236       str[1] = 0;
237     }
238     else if(got == str[0] && buf[got-1] == '\r') {
239       buf[got-1] = 0;
240       str[1] = got-1;
241     }
242     else
243       str[1] = got;
244   }
245   else
246     buf = NULL;
247   SetConsoleMode(MSVCRT_console_in, conmode);
248   UNLOCK_CONSOLE;
249   return buf;
250 }
251
252 /*********************************************************************
253  *              _ungetch (MSVCRT.@)
254  */
255 int CDECL _ungetch(int c)
256 {
257   int retval = MSVCRT_EOF;
258   LOCK_CONSOLE;
259   if (c != MSVCRT_EOF && __MSVCRT_console_buffer == MSVCRT_EOF)
260     retval = __MSVCRT_console_buffer = c;
261   UNLOCK_CONSOLE;
262   return retval;
263 }
264
265 /*********************************************************************
266  *              _kbhit (MSVCRT.@)
267  */
268 int CDECL _kbhit(void)
269 {
270   int retval = 0;
271
272   LOCK_CONSOLE;
273   if (__MSVCRT_console_buffer != MSVCRT_EOF)
274     retval = 1;
275   else
276   {
277     /* FIXME: There has to be a faster way than this in Win32.. */
278     INPUT_RECORD *ir = NULL;
279     DWORD count = 0, i;
280
281     GetNumberOfConsoleInputEvents(MSVCRT_console_in, &count);
282
283     if (count && (ir = MSVCRT_malloc(count * sizeof(INPUT_RECORD))) &&
284         PeekConsoleInputA(MSVCRT_console_in, ir, count, &count))
285       for(i = 0; i < count - 1; i++)
286       {
287         if (ir[i].EventType == KEY_EVENT &&
288             ir[i].Event.KeyEvent.bKeyDown &&
289             ir[i].Event.KeyEvent.uChar.AsciiChar)
290         {
291           retval = 1;
292           break;
293         }
294       }
295     MSVCRT_free(ir);
296   }
297   UNLOCK_CONSOLE;
298   return retval;
299 }
300
301 static int puts_clbk_console_a(void *ctx, int len, const char *str)
302 {
303     LOCK_CONSOLE;
304     if(!WriteConsoleA(MSVCRT_console_out, str, len, NULL, NULL))
305         len = -1;
306     UNLOCK_CONSOLE;
307     return len;
308 }
309
310 static int puts_clbk_console_w(void *ctx, int len, const MSVCRT_wchar_t *str)
311 {
312     LOCK_CONSOLE;
313     if(!WriteConsoleW(MSVCRT_console_out, str, len, NULL, NULL))
314         len = -1;
315     UNLOCK_CONSOLE;
316     return len;
317 }
318
319 /*********************************************************************
320  *              _vcprintf (MSVCRT.@)
321  */
322 int CDECL _vcprintf(const char* format, __ms_va_list valist)
323 {
324     return pf_printf_a(puts_clbk_console_a, NULL, format, NULL, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
325 }
326
327 /*********************************************************************
328  *              _cprintf (MSVCRT.@)
329  */
330 int CDECL _cprintf(const char* format, ...)
331 {
332   int retval;
333   __ms_va_list valist;
334
335   __ms_va_start( valist, format );
336   retval = _vcprintf(format, valist);
337   __ms_va_end(valist);
338
339   return retval;
340 }
341
342
343 /*********************************************************************
344  *              _vcwprintf (MSVCRT.@)
345  */
346 int CDECL _vcwprintf(const MSVCRT_wchar_t* format, __ms_va_list valist)
347 {
348     return pf_printf_w(puts_clbk_console_w, NULL, format, NULL, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
349 }
350
351 /*********************************************************************
352  *              _cwprintf (MSVCRT.@)
353  */
354 int CDECL _cwprintf(const MSVCRT_wchar_t* format, ...)
355 {
356   int retval;
357   __ms_va_list valist;
358
359   __ms_va_start( valist, format );
360   retval = _vcwprintf(format, valist);
361   __ms_va_end(valist);
362
363   return retval;
364 }