2 * CRTDLL console functions
4 * Copyright 2000 Jon Griffiths
7 * Only a one byte ungetch buffer is implemented, as per MS docs.
8 * Output is not redirectable using these functions, as per MS docs.
11 * There are several problems with the console input mechanism as
12 * currently implemented in Wine. When these are ironed out the
13 * getch() function will work correctly (gets() is currently fine).
14 * The problem is that opening CONIN$ does not work, and
15 * reading from STD_INPUT_HANDLE is line buffered.
21 DEFAULT_DEBUG_CHANNEL(crtdll);
23 static HANDLE __CRTDLL_console_in = INVALID_HANDLE_VALUE;
24 static HANDLE __CRTDLL_console_out = INVALID_HANDLE_VALUE;
25 static int __CRTDLL_console_buffer = CRTDLL_EOF;
28 /* INTERNAL: Initialise console handles */
29 VOID __CRTDLL_init_console(VOID)
31 TRACE(":Opening console handles\n");
33 __CRTDLL_console_in = GetStdHandle(STD_INPUT_HANDLE);
35 /* FIXME: Should be initialised with:
36 * CreateFileA("CONIN$", GENERIC_READ, FILE_SHARE_READ,
37 * NULL, OPEN_EXISTING, 0, (HANDLE)NULL);
40 __CRTDLL_console_out = CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
41 NULL, OPEN_EXISTING, 0, (HANDLE)NULL);
43 if ((__CRTDLL_console_in == INVALID_HANDLE_VALUE) ||
44 (__CRTDLL_console_out == INVALID_HANDLE_VALUE))
45 WARN(":Console handle Initialisation FAILED!\n");
48 /* INTERNAL: Free console handles */
49 void __CRTDLL_free_console(void)
51 TRACE(":Closing console handles\n");
52 CloseHandle(__CRTDLL_console_in);
53 CloseHandle(__CRTDLL_console_out);
57 /*********************************************************************
60 * Get a string from CONIN$.
62 LPSTR __cdecl CRTDLL__cgets(LPSTR str)
66 str[1] = 0; /* Length */
67 /* FIXME: No editing of string supported */
70 if (str[1] >= str[0] || (str[1]++, c = CRTDLL__getche()) == CRTDLL_EOF || c == '\n')
80 /*********************************************************************
81 * _cprintf (CRTDLL.064)
83 * Write a formatted string to CONOUT$.
85 INT __cdecl CRTDLL__cprintf( LPCSTR format, ... )
90 va_start( valist, format );
91 if (snprintf( buffer, sizeof(buffer), format, valist ) == -1)
92 ERR("Format too large for internal buffer!\n");
94 return CRTDLL__cputs( buffer );
98 /*********************************************************************
101 * Write a string to CONOUT$.
103 INT __cdecl CRTDLL__cputs(LPCSTR str)
106 if (WriteConsoleA(__CRTDLL_console_out, str, strlen(str), &count, NULL)
113 /*********************************************************************
114 * _cscanf (CRTDLL.067)
116 * Read formatted input from CONIN$.
118 INT __cdecl CRTDLL__cscanf( LPCSTR format, ... )
120 /* NOTE: If you extend this function, extend CRTDLL_fscanf in file.c too */
124 if (!*format) return 0;
125 WARN("\"%s\": semi-stub\n", format);
126 nch = CRTDLL__getch();
127 va_start(ap, format);
129 if (*format == ' ') {
130 /* skip whitespace */
131 while ((nch!=CRTDLL_EOF) && isspace(nch))
132 nch = CRTDLL__getch();
134 else if (*format == '%') {
138 case 'd': { /* read an integer */
139 int*val = va_arg(ap, int*);
141 /* skip initial whitespace */
142 while ((nch!=CRTDLL_EOF) && isspace(nch))
143 nch = CRTDLL__getch();
144 /* get sign and first digit */
146 nch = CRTDLL__getch();
155 nch = CRTDLL__getch();
156 /* read until no more digits */
157 while ((nch!=CRTDLL_EOF) && isdigit(nch)) {
158 cur = cur*10 + (nch - '0');
159 nch = CRTDLL__getch();
165 case 'f': { /* read a float */
166 float*val = va_arg(ap, float*);
168 /* skip initial whitespace */
169 while ((nch!=CRTDLL_EOF) && isspace(nch))
170 nch = CRTDLL__getch();
171 /* get sign and first digit */
173 nch = CRTDLL__getch();
182 /* read until no more digits */
183 while ((nch!=CRTDLL_EOF) && isdigit(nch)) {
184 cur = cur*10 + (nch - '0');
185 nch = CRTDLL__getch();
188 /* handle decimals */
190 nch = CRTDLL__getch();
191 while ((nch!=CRTDLL_EOF) && isdigit(nch)) {
193 cur += dec * (nch - '0');
194 nch = CRTDLL__getch();
201 case 's': { /* read a word */
202 char*str = va_arg(ap, char*);
204 /* skip initial whitespace */
205 while ((nch!=CRTDLL_EOF) && isspace(nch))
206 nch = CRTDLL__getch();
207 /* read until whitespace */
208 while ((nch!=CRTDLL_EOF) && !isspace(nch)) {
210 nch = CRTDLL__getch();
214 TRACE("read word: %s\n", str);
217 default: FIXME("unhandled: %%%c\n", *format);
223 /* check for character match */
225 nch = CRTDLL__getch();
231 if (nch != CRTDLL_EOF)
232 CRTDLL__ungetch(nch);
234 TRACE("returning %d\n", rd);
239 /*********************************************************************
240 * _getch (CRTDLL.118)
242 * Get a character from CONIN$.
244 INT __cdecl CRTDLL__getch(VOID)
246 if (__CRTDLL_console_buffer != CRTDLL_EOF)
248 INT retVal = __CRTDLL_console_buffer;
249 __CRTDLL_console_buffer = CRTDLL_EOF;
258 GetConsoleMode(__CRTDLL_console_in, &mode);
259 if(mode) SetConsoleMode(__CRTDLL_console_in, 0);
262 if (ReadConsoleInputA(__CRTDLL_console_in, &ir, 1, &count))
264 /* Only interested in ASCII chars */
265 if (ir.EventType == KEY_EVENT &&
266 ir.Event.KeyEvent.bKeyDown &&
267 ir.Event.KeyEvent.uChar.AsciiChar)
269 if(mode) SetConsoleMode(__CRTDLL_console_in, mode);
270 return ir.Event.KeyEvent.uChar.AsciiChar;
276 if (mode) SetConsoleMode(__CRTDLL_console_in, mode);
282 /*********************************************************************
283 * _getche (CRTDLL.119)
285 * Get a character from CONIN$ and echo it to CONOUT$.
287 INT __cdecl CRTDLL__getche(VOID)
289 INT res = CRTDLL__getch();
290 if (res != CRTDLL_EOF && CRTDLL__putch(res) != CRTDLL_EOF)
296 /*********************************************************************
297 * _kbhit (CRTDLL.169)
299 * Check if a character is waiting in CONIN$.
301 INT __cdecl CRTDLL__kbhit(VOID)
303 if (__CRTDLL_console_buffer != CRTDLL_EOF)
307 /* FIXME: There has to be a faster way than this in Win32.. */
312 GetNumberOfConsoleInputEvents(__CRTDLL_console_in, &count);
316 if (!(ir = CRTDLL_malloc(count * sizeof(INPUT_RECORD))))
319 if (!PeekConsoleInputA(__CRTDLL_console_in, ir, count, &count))
322 for(i = 0; i < count - 1; i++)
324 if (ir[i].EventType == KEY_EVENT &&
325 ir[i].Event.KeyEvent.bKeyDown &&
326 ir[i].Event.KeyEvent.uChar.AsciiChar)
338 /*********************************************************************
339 * _putch (CRTDLL.250)
341 * Write a character to CONOUT$.
343 INT __cdecl CRTDLL__putch(INT c)
346 if (WriteConsoleA(__CRTDLL_console_out, &c, 1, &count, NULL) &&
353 /*********************************************************************
354 * _ungetch (CRTDLL.311)
356 * Un-get a character from CONIN$.
358 INT __cdecl CRTDLL__ungetch(INT c)
360 if (c == CRTDLL_EOF || __CRTDLL_console_buffer != CRTDLL_EOF)
363 return __CRTDLL_console_buffer = c;