2 * CONSOLE.C - console input/output functions.
7 * 20-Jan-1999 (Eric Kohl)
10 * 03-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
11 * Remove all hardcoded strings in En.rc
13 * 01-Jul-2005 (Brandon Turner <turnerb7@msu.edu>)
14 * Added ConPrintfPaging and ConOutPrintfPaging
16 * 02-Feb-2007 (Paolo Devoti <devotip at gmail.com>)
17 * Fixed ConPrintfPaging
22 #define OUTPUT_BUFFER_SIZE 4096
29 BOOL
IsConsoleHandle(HANDLE hHandle
)
33 /* Check whether the handle may be that of a console... */
34 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
38 * It may be. Perform another test... The idea comes from the
39 * MSDN description of the WriteConsole API:
41 * "WriteConsole fails if it is used with a standard handle
42 * that is redirected to a file. If an application processes
43 * multilingual output that can be redirected, determine whether
44 * the output handle is a console handle (one method is to call
45 * the GetConsoleMode function and check whether it succeeds).
46 * If the handle is a console handle, call WriteConsole. If the
47 * handle is not a console handle, the output is redirected and
48 * you should call WriteFile to perform the I/O."
50 return GetConsoleMode(hHandle
, &dwMode
);
53 VOID
ConInDisable(VOID
)
55 HANDLE hInput
= GetStdHandle(STD_INPUT_HANDLE
);
58 GetConsoleMode(hInput
, &dwMode
);
59 dwMode
&= ~ENABLE_PROCESSED_INPUT
;
60 SetConsoleMode(hInput
, dwMode
);
64 VOID
ConInEnable(VOID
)
66 HANDLE hInput
= GetStdHandle(STD_INPUT_HANDLE
);
69 GetConsoleMode(hInput
, &dwMode
);
70 dwMode
|= ENABLE_PROCESSED_INPUT
;
71 SetConsoleMode(hInput
, dwMode
);
75 VOID
ConInFlush (VOID
)
77 FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE
));
81 VOID
ConInKey(PINPUT_RECORD lpBuffer
)
83 HANDLE hInput
= GetStdHandle(STD_INPUT_HANDLE
);
86 if (hInput
== INVALID_HANDLE_VALUE
)
87 WARN ("Invalid input handle!!!\n");
91 ReadConsoleInput(hInput
, lpBuffer
, 1, &dwRead
);
92 if ((lpBuffer
->EventType
== KEY_EVENT
) &&
93 (lpBuffer
->Event
.KeyEvent
.bKeyDown
== TRUE
))
100 VOID
ConInString(LPTSTR lpInput
, DWORD dwLength
)
110 pBuf
= (PCHAR
)cmd_alloc(dwLength
- 1);
114 ZeroMemory(lpInput
, dwLength
* sizeof(TCHAR
));
115 hFile
= GetStdHandle(STD_INPUT_HANDLE
);
116 GetConsoleMode(hFile
, &dwOldMode
);
118 SetConsoleMode(hFile
, ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
);
120 ReadFile(hFile
, (PVOID
)pBuf
, dwLength
- 1, &dwRead
, NULL
);
123 MultiByteToWideChar(InputCodePage
, 0, pBuf
, dwRead
, lpInput
, dwLength
- 1);
126 for (p
= lpInput
; *p
; p
++)
128 if (*p
== _T('\x0d'))
135 SetConsoleMode(hFile
, dwOldMode
);
138 static VOID
ConWrite(TCHAR
*str
, DWORD len
, DWORD nStdHandle
)
140 DWORD dwNumBytes
= 0;
141 HANDLE hOutput
= GetStdHandle(nStdHandle
);
144 /* If we don't write anything, just return */
145 if (!str
|| len
== 0)
148 /* Check whether we are writing to a console and if so, write to it */
149 if (IsConsoleHandle(hOutput
))
151 WriteConsole(hOutput
, str
, len
, &dwNumBytes
, NULL
);
155 /* We're writing to a file or pipe instead of the console. Convert the
156 * string from TCHARs to the desired output format, if the two differ */
160 WCHAR
*buffer
= cmd_alloc(len
* sizeof(WCHAR
));
163 error_out_of_memory();
166 len
= (DWORD
)MultiByteToWideChar(OutputCodePage
, 0, str
, (INT
)len
, buffer
, (INT
)len
);
170 * Find any newline character in the buffer,
171 * write the part BEFORE the newline, then write
172 * a carriage-return + newline, and then write
173 * the remaining part of the buffer.
175 * This fixes output in files and serial console.
179 /* Loop until we find a \r or \n character */
180 // FIXME: What about the pair \r\n ?
182 while (len
> 0 && *(PWCHAR
)p
!= L
'\r' && *(PWCHAR
)p
!= L
'\n')
184 /* Advance one character */
185 p
= (PVOID
)((PWCHAR
)p
+ 1);
189 /* Write everything up to \r or \n */
190 dwNumBytes
= ((PWCHAR
)p
- (PWCHAR
)str
) * sizeof(WCHAR
);
191 WriteFile(hOutput
, str
, dwNumBytes
, &dwNumBytes
, NULL
);
193 /* If we hit \r or \n ... */
194 if (len
> 0 && (*(PWCHAR
)p
== L
'\r' || *(PWCHAR
)p
== L
'\n'))
196 /* ... send a carriage-return + newline sequence and skip \r or \n */
197 WriteFile(hOutput
, L
"\r\n", 2 * sizeof(WCHAR
), &dwNumBytes
, NULL
);
198 str
= (PVOID
)((PWCHAR
)p
+ 1);
210 CHAR
*buffer
= cmd_alloc(len
* MB_LEN_MAX
* sizeof(CHAR
));
213 error_out_of_memory();
216 len
= WideCharToMultiByte(OutputCodePage
, 0, str
, len
, buffer
, len
* MB_LEN_MAX
, NULL
, NULL
);
220 * Find any newline character in the buffer,
221 * write the part BEFORE the newline, then write
222 * a carriage-return + newline, and then write
223 * the remaining part of the buffer.
225 * This fixes output in files and serial console.
229 /* Loop until we find a \r or \n character */
230 // FIXME: What about the pair \r\n ?
232 while (len
> 0 && *(PCHAR
)p
!= '\r' && *(PCHAR
)p
!= '\n')
234 /* Advance one character */
235 p
= (PVOID
)((PCHAR
)p
+ 1);
239 /* Write everything up to \r or \n */
240 dwNumBytes
= ((PCHAR
)p
- (PCHAR
)str
) * sizeof(CHAR
);
241 WriteFile(hOutput
, str
, dwNumBytes
, &dwNumBytes
, NULL
);
243 /* If we hit \r or \n ... */
244 if (len
> 0 && (*(PCHAR
)p
== '\r' || *(PCHAR
)p
== '\n'))
246 /* ... send a carriage-return + newline sequence and skip \r or \n */
247 WriteFile(hOutput
, "\r\n", 2, &dwNumBytes
, NULL
);
248 str
= (PVOID
)((PCHAR
)p
+ 1);
259 VOID
ConOutChar(TCHAR c
)
261 ConWrite(&c
, 1, STD_OUTPUT_HANDLE
);
264 VOID
ConPuts(LPTSTR szText
, DWORD nStdHandle
)
266 ConWrite(szText
, (DWORD
)_tcslen(szText
), nStdHandle
);
269 VOID
ConOutResPaging(BOOL NewPage
, UINT resID
)
271 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
272 LoadString(CMD_ModuleHandle
, resID
, szMsg
, ARRAYSIZE(szMsg
));
273 ConOutPrintfPaging(NewPage
, szMsg
);
276 VOID
ConOutResPuts(UINT resID
)
278 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
279 LoadString(CMD_ModuleHandle
, resID
, szMsg
, ARRAYSIZE(szMsg
));
280 ConPuts(szMsg
, STD_OUTPUT_HANDLE
);
283 VOID
ConOutPuts(LPTSTR szText
)
285 ConPuts(szText
, STD_OUTPUT_HANDLE
);
289 VOID
ConPrintf(LPTSTR szFormat
, va_list arg_ptr
, DWORD nStdHandle
)
291 TCHAR szOut
[OUTPUT_BUFFER_SIZE
];
294 len
= (DWORD
)_vstprintf(szOut
, szFormat
, arg_ptr
);
295 ConWrite(szOut
, len
, nStdHandle
);
298 INT
ConPrintfPaging(BOOL NewPage
, LPTSTR szFormat
, va_list arg_ptr
, DWORD nStdHandle
)
301 CONSOLE_SCREEN_BUFFER_INFO csbi
;
302 TCHAR szOut
[OUTPUT_BUFFER_SIZE
];
304 HANDLE hOutput
= GetStdHandle(nStdHandle
);
306 /* Used to count number of lines since last pause */
307 static int LineCount
= 0;
309 /* Used to see how big the screen is */
312 /* Chars since start of line */
320 /* Reset LineCount and return if no string has been given */
321 if (szFormat
== NULL
)
324 /* Get the size of the visual screen that can be printed to */
325 if (!IsConsoleHandle(hOutput
) || !GetConsoleScreenBufferInfo(hOutput
, &csbi
))
327 /* We assume it's a file handle */
328 ConPrintf(szFormat
, arg_ptr
, nStdHandle
);
333 * Get the number of lines currently displayed on screen, minus 1
334 * to account for the "press any key..." prompt from PagePrompt().
336 ScreenLines
= (csbi
.srWindow
.Bottom
- csbi
.srWindow
.Top
);
337 CharSL
= csbi
.dwCursorPosition
.X
;
339 /* Make sure the user doesn't have the screen too small */
342 ConPrintf(szFormat
, arg_ptr
, nStdHandle
);
346 len
= _vstprintf(szOut
, szFormat
, arg_ptr
);
350 /* Search until the end of a line is reached */
351 if (szOut
[i
++] != _T('\n') && ++CharSL
< csbi
.dwSize
.X
)
357 if (LineCount
>= ScreenLines
)
359 WriteConsole(hOutput
, &szOut
[from
], i
-from
, &dwWritten
, NULL
);
362 /* Prompt the user */
363 if (PagePrompt() != PROMPT_YES
)
368 // TODO: Recalculate 'ScreenLines' in case the user redimensions
369 // the window during the prompt.
371 /* Reset the number of lines being printed */
376 WriteConsole(hOutput
, &szOut
[from
], i
-from
, &dwWritten
, NULL
);
381 VOID
ConErrFormatMessage(DWORD MessageId
, ...)
383 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
388 va_start(arg_ptr
, MessageId
);
389 ret
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
392 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
405 LoadString(CMD_ModuleHandle
, STRING_CONSOLE_ERROR
, szMsg
, ARRAYSIZE(szMsg
));
410 VOID
ConOutFormatMessage(DWORD MessageId
, ...)
412 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
417 va_start(arg_ptr
, MessageId
);
418 ret
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
421 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
434 LoadString(CMD_ModuleHandle
, STRING_CONSOLE_ERROR
, szMsg
, ARRAYSIZE(szMsg
));
439 VOID
ConOutResPrintf(UINT resID
, ...)
441 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
444 va_start(arg_ptr
, resID
);
445 LoadString(CMD_ModuleHandle
, resID
, szMsg
, ARRAYSIZE(szMsg
));
446 ConPrintf(szMsg
, arg_ptr
, STD_OUTPUT_HANDLE
);
450 VOID
ConOutPrintf(LPTSTR szFormat
, ...)
454 va_start(arg_ptr
, szFormat
);
455 ConPrintf(szFormat
, arg_ptr
, STD_OUTPUT_HANDLE
);
459 INT
ConOutPrintfPaging(BOOL NewPage
, LPTSTR szFormat
, ...)
464 va_start(arg_ptr
, szFormat
);
465 iReturn
= ConPrintfPaging(NewPage
, szFormat
, arg_ptr
, STD_OUTPUT_HANDLE
);
470 VOID
ConErrChar(TCHAR c
)
472 ConWrite(&c
, 1, STD_ERROR_HANDLE
);
476 VOID
ConErrResPuts(UINT resID
)
478 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
479 LoadString(CMD_ModuleHandle
, resID
, szMsg
, ARRAYSIZE(szMsg
));
480 ConPuts(szMsg
, STD_ERROR_HANDLE
);
483 VOID
ConErrPuts(LPTSTR szText
)
485 ConPuts(szText
, STD_ERROR_HANDLE
);
489 VOID
ConErrResPrintf(UINT resID
, ...)
491 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
494 va_start(arg_ptr
, resID
);
495 LoadString(CMD_ModuleHandle
, resID
, szMsg
, ARRAYSIZE(szMsg
));
496 ConPrintf(szMsg
, arg_ptr
, STD_ERROR_HANDLE
);
500 VOID
ConErrPrintf(LPTSTR szFormat
, ...)
504 va_start(arg_ptr
, szFormat
);
505 ConPrintf(szFormat
, arg_ptr
, STD_ERROR_HANDLE
);
510 VOID
SetCursorXY(SHORT x
, SHORT y
)
516 SetConsoleCursorPosition(GetStdHandle (STD_OUTPUT_HANDLE
), coPos
);
519 VOID
GetCursorXY(PSHORT x
, PSHORT y
)
521 CONSOLE_SCREEN_BUFFER_INFO csbi
;
523 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
);
525 *x
= csbi
.dwCursorPosition
.X
;
526 *y
= csbi
.dwCursorPosition
.Y
;
529 SHORT
GetCursorX(VOID
)
531 CONSOLE_SCREEN_BUFFER_INFO csbi
;
533 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
);
534 return csbi
.dwCursorPosition
.X
;
537 SHORT
GetCursorY(VOID
)
539 CONSOLE_SCREEN_BUFFER_INFO csbi
;
541 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
);
542 return csbi
.dwCursorPosition
.Y
;
545 VOID
SetCursorType(BOOL bInsert
, BOOL bVisible
)
547 CONSOLE_CURSOR_INFO cci
;
549 cci
.dwSize
= bInsert
? 10 : 99;
550 cci
.bVisible
= bVisible
;
552 SetConsoleCursorInfo(GetStdHandle (STD_OUTPUT_HANDLE
), &cci
);
555 VOID
GetScreenSize(PSHORT maxx
, PSHORT maxy
)
557 CONSOLE_SCREEN_BUFFER_INFO csbi
;
559 if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
))
565 if (maxx
) *maxx
= csbi
.dwSize
.X
;
566 if (maxy
) *maxy
= csbi
.dwSize
.Y
;