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 DEFAULT_DEBUG_CHANNEL(msvcrt
);
15 extern CRITICAL_SECTION MSVCRT_console_cs
;
16 #define LOCK_CONSOLE EnterCriticalSection(&MSVCRT_console_cs)
17 #define UNLOCK_CONSOLE LeaveCriticalSection(&MSVCRT_console_cs)
19 static HANDLE MSVCRT_console_in
= INVALID_HANDLE_VALUE
;
20 static HANDLE MSVCRT_console_out
= INVALID_HANDLE_VALUE
;
21 static int __MSVCRT_console_buffer
= MSVCRT_EOF
;
23 /* INTERNAL: Initialise console handles */
24 void MSVCRT_init_console(void)
26 TRACE(":Opening console handles\n");
28 MSVCRT_console_in
= GetStdHandle(STD_INPUT_HANDLE
);
30 /* FIXME: Should be initialised with:
31 * CreateFileA("CONIN$", GENERIC_READ, FILE_SHARE_READ,
32 * NULL, OPEN_EXISTING, 0, (HANDLE)NULL);
35 MSVCRT_console_out
= CreateFileA("CONOUT$", GENERIC_WRITE
, FILE_SHARE_WRITE
,
36 NULL
, OPEN_EXISTING
, 0, (HANDLE
)NULL
);
38 if ((MSVCRT_console_in
== INVALID_HANDLE_VALUE
) ||
39 (MSVCRT_console_out
== INVALID_HANDLE_VALUE
))
40 WARN(":Console handle Initialisation FAILED!\n");
43 /* INTERNAL: Free console handles */
44 void MSVCRT_free_console(void)
46 TRACE(":Closing console handles\n");
47 CloseHandle(MSVCRT_console_in
);
48 CloseHandle(MSVCRT_console_out
);
51 /*********************************************************************
54 int __cdecl
MSVCRT__cputs(const char * str
)
57 int retval
= MSVCRT_EOF
;
60 if (WriteConsoleA(MSVCRT_console_out
, str
, strlen(str
), &count
, NULL
)
67 /*********************************************************************
70 int __cdecl
MSVCRT__getch(void)
72 int retval
= MSVCRT_EOF
;
75 if (__MSVCRT_console_buffer
!= MSVCRT_EOF
)
77 retval
= __MSVCRT_console_buffer
;
78 __MSVCRT_console_buffer
= MSVCRT_EOF
;
86 GetConsoleMode(MSVCRT_console_in
, &mode
);
88 SetConsoleMode(MSVCRT_console_in
, 0);
91 if (ReadConsoleInputA(MSVCRT_console_in
, &ir
, 1, &count
))
93 /* Only interested in ASCII chars */
94 if (ir
.EventType
== KEY_EVENT
&&
95 ir
.Event
.KeyEvent
.bKeyDown
&&
96 ir
.Event
.KeyEvent
.uChar
.AsciiChar
)
98 retval
= ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
106 SetConsoleMode(MSVCRT_console_in
, mode
);
112 /*********************************************************************
115 int __cdecl
MSVCRT__putch(int c
)
117 int retval
= MSVCRT_EOF
;
120 if (WriteConsoleA(MSVCRT_console_out
, &c
, 1, &count
, NULL
) && count
== 1)
126 /*********************************************************************
129 int __cdecl
MSVCRT__getche(void)
133 retval
= MSVCRT__getch();
134 if (retval
!= MSVCRT_EOF
)
135 retval
= MSVCRT__putch(retval
);
140 /*********************************************************************
143 char *__cdecl
MSVCRT__cgets(char *str
)
147 str
[1] = 0; /* Length */
148 /* FIXME: No editing of string supported */
152 if (str
[1] >= str
[0] || (str
[1]++, c
= MSVCRT__getche()) == MSVCRT_EOF
|| c
== '\n')
161 /*********************************************************************
162 * _ungetch (MSVCRT.@)
164 int __cdecl
MSVCRT__ungetch(int c
)
166 int retval
= MSVCRT_EOF
;
168 if (c
!= MSVCRT_EOF
&& __MSVCRT_console_buffer
== MSVCRT_EOF
)
169 retval
= __MSVCRT_console_buffer
= c
;
174 /*********************************************************************
177 int __cdecl
MSVCRT__cscanf( const char * format
, ... )
179 /* NOTE: If you extend this function, extend MSVCRT_fscanf in file.c too */
183 if (!*format
) return 0;
184 WARN("\"%s\": semi-stub\n", format
);
185 va_start(ap
, format
);
187 nch
= MSVCRT__getch();
189 if (*format
== ' ') {
190 /* skip whitespace */
191 while ((nch
!=MSVCRT_EOF
) && isspace(nch
))
192 nch
= MSVCRT__getch();
194 else if (*format
== '%') {
198 case 'd': { /* read an integer */
199 int*val
= va_arg(ap
, int*);
201 /* skip initial whitespace */
202 while ((nch
!=MSVCRT_EOF
) && isspace(nch
))
203 nch
= MSVCRT__getch();
204 /* get sign and first digit */
206 nch
= MSVCRT__getch();
215 nch
= MSVCRT__getch();
216 /* read until no more digits */
217 while ((nch
!=MSVCRT_EOF
) && isdigit(nch
)) {
218 cur
= cur
*10 + (nch
- '0');
219 nch
= MSVCRT__getch();
225 case 'f': { /* read a float */
226 float*val
= va_arg(ap
, float*);
228 /* skip initial whitespace */
229 while ((nch
!=MSVCRT_EOF
) && isspace(nch
))
230 nch
= MSVCRT__getch();
231 /* get sign and first digit */
233 nch
= MSVCRT__getch();
242 /* read until no more digits */
243 while ((nch
!=MSVCRT_EOF
) && isdigit(nch
)) {
244 cur
= cur
*10 + (nch
- '0');
245 nch
= MSVCRT__getch();
248 /* handle decimals */
250 nch
= MSVCRT__getch();
251 while ((nch
!=MSVCRT_EOF
) && isdigit(nch
)) {
253 cur
+= dec
* (nch
- '0');
254 nch
= MSVCRT__getch();
261 case 's': { /* read a word */
262 char*str
= va_arg(ap
, char*);
264 /* skip initial whitespace */
265 while ((nch
!=MSVCRT_EOF
) && isspace(nch
))
266 nch
= MSVCRT__getch();
267 /* read until whitespace */
268 while ((nch
!=MSVCRT_EOF
) && !isspace(nch
)) {
270 nch
= MSVCRT__getch();
274 TRACE("read word: %s\n", str
);
277 default: FIXME("unhandled: %%%c\n", *format
);
283 /* check for character match */
285 nch
= MSVCRT__getch();
290 if (nch
!= MSVCRT_EOF
)
291 MSVCRT__ungetch(nch
);
294 TRACE("returning %d\n", rd
);
298 /*********************************************************************
301 int __cdecl
MSVCRT__kbhit(void)
306 if (__MSVCRT_console_buffer
!= MSVCRT_EOF
)
310 /* FIXME: There has to be a faster way than this in Win32.. */
311 INPUT_RECORD
*ir
= NULL
;
314 GetNumberOfConsoleInputEvents(MSVCRT_console_in
, &count
);
316 if (count
&& (ir
= MSVCRT_malloc(count
* sizeof(INPUT_RECORD
))) &&
317 PeekConsoleInputA(MSVCRT_console_in
, ir
, count
, &count
))
318 for(i
= 0; i
< count
- 1; i
++)
320 if (ir
[i
].EventType
== KEY_EVENT
&&
321 ir
[i
].Event
.KeyEvent
.bKeyDown
&&
322 ir
[i
].Event
.KeyEvent
.uChar
.AsciiChar
)
336 extern int snprintf(char *, int, const char *, ...);
338 /*********************************************************************
339 * _cprintf (MSVCRT.@)
341 int __cdecl
MSVCRT__cprintf( const char * format
, ... )
343 char buf
[2048], *mem
= buf
;
344 int written
, resize
= sizeof(buf
), retval
;
347 va_start( valist
, format
);
348 /* There are two conventions for snprintf failing:
349 * Return -1 if we truncated, or
350 * Return the number of bytes that would have been written
351 * The code below handles both cases
353 while ((written
= snprintf( mem
, resize
, format
, valist
)) == -1 ||
356 resize
= (written
== -1 ? resize
* 2 : written
+ 1);
359 if (!(mem
= (char *)MSVCRT_malloc(resize
)))
361 va_start( valist
, format
);
365 retval
= MSVCRT__cputs( mem
);