Allow specifying multiple graphics drivers and use the first one that
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Note: init and free don't need MT locking since they are called at DLL
21  * (de)attachment time, which is syncronised for us
22  */
23
24 #include "msvcrt.h"
25 #include "wincon.h"
26 #include "mtdll.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
30
31
32
33 /* MT */
34 #define LOCK_CONSOLE   _mlock(_CONIO_LOCK)
35 #define UNLOCK_CONSOLE _munlock(_CONIO_LOCK)
36
37 static HANDLE MSVCRT_console_in = INVALID_HANDLE_VALUE;
38 static HANDLE MSVCRT_console_out= INVALID_HANDLE_VALUE;
39 static int __MSVCRT_console_buffer = MSVCRT_EOF;
40
41 /* INTERNAL: Initialise console handles */
42 void msvcrt_init_console(void)
43 {
44   TRACE(":Opening console handles\n");
45
46   DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE),
47     GetCurrentProcess(), &MSVCRT_console_in, 0, FALSE, DUPLICATE_SAME_ACCESS);
48
49   /* FIXME: Should be initialised with:
50    * CreateFileA("CONIN$", GENERIC_READ, FILE_SHARE_READ,
51    * NULL, OPEN_EXISTING, 0, NULL);
52    */
53
54   MSVCRT_console_out= CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
55                                     NULL, OPEN_EXISTING, 0, NULL);
56
57   if ((MSVCRT_console_in == INVALID_HANDLE_VALUE) ||
58       (MSVCRT_console_out== INVALID_HANDLE_VALUE))
59     WARN(":Console handle Initialisation FAILED!\n");
60 }
61
62 /* INTERNAL: Free console handles */
63 void msvcrt_free_console(void)
64 {
65   TRACE(":Closing console handles\n");
66   CloseHandle(MSVCRT_console_in);
67   CloseHandle(MSVCRT_console_out);
68 }
69
70 /*********************************************************************
71  *              _cputs (MSVCRT.@)
72  */
73 int _cputs(const char* str)
74 {
75   DWORD count;
76   int retval = MSVCRT_EOF;
77
78   LOCK_CONSOLE;
79   if (WriteConsoleA(MSVCRT_console_out, str, strlen(str), &count, NULL)
80       && count == 1)
81     retval = 0;
82   UNLOCK_CONSOLE;
83   return retval;
84 }
85
86 /*********************************************************************
87  *              _getch (MSVCRT.@)
88  */
89 int _getch(void)
90 {
91   int retval = MSVCRT_EOF;
92
93   LOCK_CONSOLE;
94   if (__MSVCRT_console_buffer != MSVCRT_EOF)
95   {
96     retval = __MSVCRT_console_buffer;
97     __MSVCRT_console_buffer = MSVCRT_EOF;
98   }
99   else
100   {
101     INPUT_RECORD ir;
102     DWORD count;
103     DWORD mode = 0;
104
105     GetConsoleMode(MSVCRT_console_in, &mode);
106     if(mode)
107       SetConsoleMode(MSVCRT_console_in, 0);
108
109     do {
110       if (ReadConsoleInputA(MSVCRT_console_in, &ir, 1, &count))
111       {
112         /* Only interested in ASCII chars */
113         if (ir.EventType == KEY_EVENT &&
114             ir.Event.KeyEvent.bKeyDown &&
115             ir.Event.KeyEvent.uChar.AsciiChar)
116         {
117           retval = ir.Event.KeyEvent.uChar.AsciiChar;
118           break;
119         }
120       }
121       else
122         break;
123     } while(1);
124     if (mode)
125       SetConsoleMode(MSVCRT_console_in, mode);
126   }
127   UNLOCK_CONSOLE;
128   return retval;
129 }
130
131 /*********************************************************************
132  *              _putch (MSVCRT.@)
133  */
134 int _putch(int c)
135 {
136   int retval = MSVCRT_EOF;
137   DWORD count;
138   LOCK_CONSOLE;
139   if (WriteConsoleA(MSVCRT_console_out, &c, 1, &count, NULL) && count == 1)
140     retval = c;
141   UNLOCK_CONSOLE;
142   return retval;
143 }
144
145 /*********************************************************************
146  *              _getche (MSVCRT.@)
147  */
148 int _getche(void)
149 {
150   int retval;
151   LOCK_CONSOLE;
152   retval = _getch();
153   if (retval != MSVCRT_EOF)
154     retval = _putch(retval);
155   UNLOCK_CONSOLE;
156   return retval;
157 }
158
159 /*********************************************************************
160  *              _cgets (MSVCRT.@)
161  */
162 char* _cgets(char* str)
163 {
164   char *buf = str + 2;
165   int c;
166   str[1] = 0; /* Length */
167   /* FIXME: No editing of string supported */
168   LOCK_CONSOLE;
169   do
170   {
171     if (str[1] >= str[0] || (str[1]++, c = _getche()) == MSVCRT_EOF || c == '\n')
172       break;
173     *buf++ = c & 0xff;
174   } while (1);
175   UNLOCK_CONSOLE;
176   *buf = '\0';
177   return str + 2;
178 }
179
180 /*********************************************************************
181  *              _ungetch (MSVCRT.@)
182  */
183 int _ungetch(int c)
184 {
185   int retval = MSVCRT_EOF;
186   LOCK_CONSOLE;
187   if (c != MSVCRT_EOF && __MSVCRT_console_buffer == MSVCRT_EOF)
188     retval = __MSVCRT_console_buffer = c;
189   UNLOCK_CONSOLE;
190   return retval;
191 }
192
193 /*********************************************************************
194  *              _kbhit (MSVCRT.@)
195  */
196 int _kbhit(void)
197 {
198   int retval = 0;
199
200   LOCK_CONSOLE;
201   if (__MSVCRT_console_buffer != MSVCRT_EOF)
202     retval = 1;
203   else
204   {
205     /* FIXME: There has to be a faster way than this in Win32.. */
206     INPUT_RECORD *ir = NULL;
207     DWORD count = 0, i;
208
209     GetNumberOfConsoleInputEvents(MSVCRT_console_in, &count);
210
211     if (count && (ir = MSVCRT_malloc(count * sizeof(INPUT_RECORD))) &&
212         PeekConsoleInputA(MSVCRT_console_in, ir, count, &count))
213       for(i = 0; i < count - 1; i++)
214       {
215         if (ir[i].EventType == KEY_EVENT &&
216             ir[i].Event.KeyEvent.bKeyDown &&
217             ir[i].Event.KeyEvent.uChar.AsciiChar)
218         {
219           retval = 1;
220           break;
221         }
222       }
223     if (ir)
224       MSVCRT_free(ir);
225   }
226   UNLOCK_CONSOLE;
227   return retval;
228 }
229
230
231 /*********************************************************************
232  *              _cprintf (MSVCRT.@)
233  */
234 int _cprintf(const char* format, ...)
235 {
236   char buf[2048], *mem = buf;
237   int written, resize = sizeof(buf), retval;
238   va_list valist;
239
240   va_start( valist, format );
241   /* There are two conventions for snprintf failing:
242    * Return -1 if we truncated, or
243    * Return the number of bytes that would have been written
244    * The code below handles both cases
245    */
246   while ((written = _snprintf( mem, resize, format, valist )) == -1 ||
247           written > resize)
248   {
249     resize = (written == -1 ? resize * 2 : written + 1);
250     if (mem != buf)
251       MSVCRT_free (mem);
252     if (!(mem = (char *)MSVCRT_malloc(resize)))
253       return MSVCRT_EOF;
254     va_start( valist, format );
255   }
256   va_end(valist);
257   LOCK_CONSOLE;
258   retval = _cputs( mem );
259   UNLOCK_CONSOLE;
260   if (mem != buf)
261     MSVCRT_free (mem);
262   return retval;
263 }