2 * msvcrt.dll console functions
4 * Copyright 2000 Jon Griffiths
6 * Note: init and free don't need MT locking since they are called at DLL
7 * (de)attachment time, which is syncronised for us
12 #include "msvcrt/conio.h"
13 #include "msvcrt/malloc.h"
14 #include "msvcrt/stdio.h"
16 #include "wine/debug.h"
18 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
23 extern CRITICAL_SECTION MSVCRT_console_cs
;
24 #define LOCK_CONSOLE EnterCriticalSection(&MSVCRT_console_cs)
25 #define UNLOCK_CONSOLE LeaveCriticalSection(&MSVCRT_console_cs)
27 static HANDLE MSVCRT_console_in
= INVALID_HANDLE_VALUE
;
28 static HANDLE MSVCRT_console_out
= INVALID_HANDLE_VALUE
;
29 static int __MSVCRT_console_buffer
= MSVCRT_EOF
;
31 /* INTERNAL: Initialise console handles */
32 void msvcrt_init_console(void)
34 TRACE(":Opening console handles\n");
36 MSVCRT_console_in
= GetStdHandle(STD_INPUT_HANDLE
);
38 /* FIXME: Should be initialised with:
39 * CreateFileA("CONIN$", GENERIC_READ, FILE_SHARE_READ,
40 * NULL, OPEN_EXISTING, 0, (HANDLE)NULL);
43 MSVCRT_console_out
= CreateFileA("CONOUT$", GENERIC_WRITE
, FILE_SHARE_WRITE
,
44 NULL
, OPEN_EXISTING
, 0, (HANDLE
)NULL
);
46 if ((MSVCRT_console_in
== INVALID_HANDLE_VALUE
) ||
47 (MSVCRT_console_out
== INVALID_HANDLE_VALUE
))
48 WARN(":Console handle Initialisation FAILED!\n");
51 /* INTERNAL: Free console handles */
52 void msvcrt_free_console(void)
54 TRACE(":Closing console handles\n");
55 CloseHandle(MSVCRT_console_in
);
56 CloseHandle(MSVCRT_console_out
);
59 /*********************************************************************
62 int _cputs(const char* str
)
65 int retval
= MSVCRT_EOF
;
68 if (WriteConsoleA(MSVCRT_console_out
, str
, strlen(str
), &count
, NULL
)
75 /*********************************************************************
80 int retval
= MSVCRT_EOF
;
83 if (__MSVCRT_console_buffer
!= MSVCRT_EOF
)
85 retval
= __MSVCRT_console_buffer
;
86 __MSVCRT_console_buffer
= MSVCRT_EOF
;
94 GetConsoleMode(MSVCRT_console_in
, &mode
);
96 SetConsoleMode(MSVCRT_console_in
, 0);
99 if (ReadConsoleInputA(MSVCRT_console_in
, &ir
, 1, &count
))
101 /* Only interested in ASCII chars */
102 if (ir
.EventType
== KEY_EVENT
&&
103 ir
.Event
.KeyEvent
.bKeyDown
&&
104 ir
.Event
.KeyEvent
.uChar
.AsciiChar
)
106 retval
= ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
114 SetConsoleMode(MSVCRT_console_in
, mode
);
120 /*********************************************************************
125 int retval
= MSVCRT_EOF
;
128 if (WriteConsoleA(MSVCRT_console_out
, &c
, 1, &count
, NULL
) && count
== 1)
134 /*********************************************************************
142 if (retval
!= MSVCRT_EOF
)
143 retval
= _putch(retval
);
148 /*********************************************************************
151 char* _cgets(char* str
)
155 str
[1] = 0; /* Length */
156 /* FIXME: No editing of string supported */
160 if (str
[1] >= str
[0] || (str
[1]++, c
= _getche()) == MSVCRT_EOF
|| c
== '\n')
169 /*********************************************************************
170 * _ungetch (MSVCRT.@)
174 int retval
= MSVCRT_EOF
;
176 if (c
!= MSVCRT_EOF
&& __MSVCRT_console_buffer
== MSVCRT_EOF
)
177 retval
= __MSVCRT_console_buffer
= c
;
182 /*********************************************************************
185 int _cscanf(const char* format
, ...)
187 /* NOTE: If you extend this function, extend MSVCRT_fscanf in file.c too */
191 if (!*format
) return 0;
192 WARN("\"%s\": semi-stub\n", format
);
193 va_start(ap
, format
);
197 if (*format
== ' ') {
198 /* skip whitespace */
199 while ((nch
!=MSVCRT_EOF
) && isspace(nch
))
202 else if (*format
== '%') {
206 case 'd': { /* read an integer */
207 int*val
= va_arg(ap
, int*);
209 /* skip initial whitespace */
210 while ((nch
!=MSVCRT_EOF
) && isspace(nch
))
212 /* get sign and first digit */
224 /* read until no more digits */
225 while ((nch
!=MSVCRT_EOF
) && isdigit(nch
)) {
226 cur
= cur
*10 + (nch
- '0');
233 case 'f': { /* read a float */
234 float*val
= va_arg(ap
, float*);
236 /* skip initial whitespace */
237 while ((nch
!=MSVCRT_EOF
) && isspace(nch
))
239 /* get sign and first digit */
250 /* read until no more digits */
251 while ((nch
!=MSVCRT_EOF
) && isdigit(nch
)) {
252 cur
= cur
*10 + (nch
- '0');
256 /* handle decimals */
259 while ((nch
!=MSVCRT_EOF
) && isdigit(nch
)) {
261 cur
+= dec
* (nch
- '0');
269 case 's': { /* read a word */
270 char*str
= va_arg(ap
, char*);
272 /* skip initial whitespace */
273 while ((nch
!=MSVCRT_EOF
) && isspace(nch
))
275 /* read until whitespace */
276 while ((nch
!=MSVCRT_EOF
) && !isspace(nch
)) {
282 TRACE("read word: %s\n", str
);
285 default: FIXME("unhandled: %%%c\n", *format
);
291 /* check for character match */
298 if (nch
!= MSVCRT_EOF
)
302 TRACE("returning %d\n", rd
);
306 /*********************************************************************
314 if (__MSVCRT_console_buffer
!= MSVCRT_EOF
)
318 /* FIXME: There has to be a faster way than this in Win32.. */
319 INPUT_RECORD
*ir
= NULL
;
322 GetNumberOfConsoleInputEvents(MSVCRT_console_in
, &count
);
324 if (count
&& (ir
= MSVCRT_malloc(count
* sizeof(INPUT_RECORD
))) &&
325 PeekConsoleInputA(MSVCRT_console_in
, ir
, count
, &count
))
326 for(i
= 0; i
< count
- 1; i
++)
328 if (ir
[i
].EventType
== KEY_EVENT
&&
329 ir
[i
].Event
.KeyEvent
.bKeyDown
&&
330 ir
[i
].Event
.KeyEvent
.uChar
.AsciiChar
)
344 /*********************************************************************
345 * _cprintf (MSVCRT.@)
347 int _cprintf(const char* format
, ...)
349 char buf
[2048], *mem
= buf
;
350 int written
, resize
= sizeof(buf
), retval
;
353 va_start( valist
, format
);
354 /* There are two conventions for snprintf failing:
355 * Return -1 if we truncated, or
356 * Return the number of bytes that would have been written
357 * The code below handles both cases
359 while ((written
= _snprintf( mem
, resize
, format
, valist
)) == -1 ||
362 resize
= (written
== -1 ? resize
* 2 : written
+ 1);
365 if (!(mem
= (char *)MSVCRT_malloc(resize
)))
367 va_start( valist
, format
);
371 retval
= _cputs( mem
);