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_CHAR
) == 0) return FALSE
;
37 * It may be. Perform another test... The idea comes from the
38 * MSDN description of the WriteConsole API:
40 * "WriteConsole fails if it is used with a standard handle
41 * that is redirected to a file. If an application processes
42 * multilingual output that can be redirected, determine whether
43 * the output handle is a console handle (one method is to call
44 * the GetConsoleMode function and check whether it succeeds).
45 * If the handle is a console handle, call WriteConsole. If the
46 * handle is not a console handle, the output is redirected and
47 * you should call WriteFile to perform the I/O."
49 return GetConsoleMode(hHandle
, &dwMode
);
52 VOID
ConInDisable(VOID
)
54 HANDLE hInput
= GetStdHandle(STD_INPUT_HANDLE
);
57 GetConsoleMode(hInput
, &dwMode
);
58 dwMode
&= ~ENABLE_PROCESSED_INPUT
;
59 SetConsoleMode(hInput
, dwMode
);
63 VOID
ConInEnable(VOID
)
65 HANDLE hInput
= GetStdHandle(STD_INPUT_HANDLE
);
68 GetConsoleMode(hInput
, &dwMode
);
69 dwMode
|= ENABLE_PROCESSED_INPUT
;
70 SetConsoleMode(hInput
, dwMode
);
74 VOID
ConInFlush (VOID
)
76 FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE
));
80 VOID
ConInKey(PINPUT_RECORD lpBuffer
)
82 HANDLE hInput
= GetStdHandle(STD_INPUT_HANDLE
);
85 if (hInput
== INVALID_HANDLE_VALUE
)
86 WARN ("Invalid input handle!!!\n");
90 ReadConsoleInput(hInput
, lpBuffer
, 1, &dwRead
);
91 if ((lpBuffer
->EventType
== KEY_EVENT
) &&
92 (lpBuffer
->Event
.KeyEvent
.bKeyDown
== TRUE
))
99 VOID
ConInString(LPTSTR lpInput
, DWORD dwLength
)
109 pBuf
= (PCHAR
)cmd_alloc(dwLength
- 1);
113 ZeroMemory(lpInput
, dwLength
* sizeof(TCHAR
));
114 hFile
= GetStdHandle(STD_INPUT_HANDLE
);
115 GetConsoleMode(hFile
, &dwOldMode
);
117 SetConsoleMode(hFile
, ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
);
119 ReadFile(hFile
, (PVOID
)pBuf
, dwLength
- 1, &dwRead
, NULL
);
122 MultiByteToWideChar(InputCodePage
, 0, pBuf
, dwRead
, lpInput
, dwLength
- 1);
125 for (p
= lpInput
; *p
; p
++)
127 if (*p
== _T('\x0d'))
134 SetConsoleMode(hFile
, dwOldMode
);
137 static VOID
ConWrite(TCHAR
*str
, DWORD len
, DWORD nStdHandle
)
140 HANDLE hOutput
= GetStdHandle(nStdHandle
);
143 /* Check whether we are writing to a console and if so, write to it */
144 if (IsConsoleHandle(hOutput
))
146 if (WriteConsole(hOutput
, str
, len
, &dwWritten
, NULL
))
150 /* We're writing to a file or pipe instead of the console. Convert the
151 * string from TCHARs to the desired output format, if the two differ */
155 WCHAR
*buffer
= cmd_alloc(len
* sizeof(WCHAR
));
158 error_out_of_memory();
161 len
= (DWORD
)MultiByteToWideChar(OutputCodePage
, 0, str
, (INT
)len
, buffer
, (INT
)len
);
165 * Find any newline character in the buffer,
166 * send the part BEFORE the newline, then send
167 * a carriage-return + newline, and then send
168 * the remaining part of the buffer.
170 * This fixes output in files and serial console.
172 while (str
&& *(PWCHAR
)str
&& len
> 0)
174 p
= wcspbrk((PWCHAR
)str
, L
"\r\n");
177 len
-= ((PWCHAR
)p
- (PWCHAR
)str
) + 1;
178 WriteFile(hOutput
, str
, ((PWCHAR
)p
- (PWCHAR
)str
) * sizeof(WCHAR
), &dwWritten
, NULL
);
179 WriteFile(hOutput
, L
"\r\n", 2 * sizeof(WCHAR
), &dwWritten
, NULL
);
180 str
= (PVOID
)((PWCHAR
)p
+ 1);
184 WriteFile(hOutput
, str
, len
* sizeof(WCHAR
), &dwWritten
, NULL
);
189 // WriteFile(hOutput, str, len * sizeof(WCHAR), &dwWritten, NULL);
197 CHAR
*buffer
= cmd_alloc(len
* MB_LEN_MAX
* sizeof(CHAR
));
200 error_out_of_memory();
203 len
= WideCharToMultiByte(OutputCodePage
, 0, str
, len
, buffer
, len
* MB_LEN_MAX
, NULL
, NULL
);
207 * Find any newline character in the buffer,
208 * send the part BEFORE the newline, then send
209 * a carriage-return + newline, and then send
210 * the remaining part of the buffer.
212 * This fixes output in files and serial console.
214 while (str
&& *(PCHAR
)str
&& len
> 0)
216 p
= strpbrk((PCHAR
)str
, "\r\n");
219 len
-= ((PCHAR
)p
- (PCHAR
)str
) + 1;
220 WriteFile(hOutput
, str
, ((PCHAR
)p
- (PCHAR
)str
), &dwWritten
, NULL
);
221 WriteFile(hOutput
, "\r\n", 2, &dwWritten
, NULL
);
222 str
= (PVOID
)((PCHAR
)p
+ 1);
226 WriteFile(hOutput
, str
, len
, &dwWritten
, NULL
);
231 // WriteFile(hOutput, str, len, &dwWritten, NULL);
238 VOID
ConOutChar(TCHAR c
)
240 ConWrite(&c
, 1, STD_OUTPUT_HANDLE
);
243 VOID
ConPuts(LPTSTR szText
, DWORD nStdHandle
)
245 ConWrite(szText
, (DWORD
)_tcslen(szText
), nStdHandle
);
248 VOID
ConOutResPaging(BOOL NewPage
, UINT resID
)
250 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
251 LoadString(CMD_ModuleHandle
, resID
, szMsg
, RC_STRING_MAX_SIZE
);
252 ConOutPrintfPaging(NewPage
, szMsg
);
255 VOID
ConOutResPuts(UINT resID
)
257 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
258 LoadString(CMD_ModuleHandle
, resID
, szMsg
, RC_STRING_MAX_SIZE
);
259 ConPuts(szMsg
, STD_OUTPUT_HANDLE
);
262 VOID
ConOutPuts(LPTSTR szText
)
264 ConPuts(szText
, STD_OUTPUT_HANDLE
);
268 VOID
ConPrintf(LPTSTR szFormat
, va_list arg_ptr
, DWORD nStdHandle
)
270 TCHAR szOut
[OUTPUT_BUFFER_SIZE
];
273 len
= (DWORD
)_vstprintf(szOut
, szFormat
, arg_ptr
);
274 ConWrite(szOut
, len
, nStdHandle
);
277 INT
ConPrintfPaging(BOOL NewPage
, LPTSTR szFormat
, va_list arg_ptr
, DWORD nStdHandle
)
280 CONSOLE_SCREEN_BUFFER_INFO csbi
;
281 TCHAR szOut
[OUTPUT_BUFFER_SIZE
];
283 HANDLE hOutput
= GetStdHandle(nStdHandle
);
285 /* used to count number of lines since last pause */
286 static int LineCount
= 0;
288 /* used to see how big the screen is */
291 /* chars since start of line */
299 /* rest LineCount and return if no string have been given */
300 if (szFormat
== NULL
)
303 /* Get the size of the visual screen that can be printed too */
304 if (!IsConsoleHandle(hOutput
) || !GetConsoleScreenBufferInfo(hOutput
, &csbi
))
306 /* We assume it's a file handle */
307 ConPrintf(szFormat
, arg_ptr
, nStdHandle
);
310 /* Subtract 2 to account for "press any key..." and for the blank line at the end of PagePrompt() */
311 ScreenLines
= (csbi
.srWindow
.Bottom
- csbi
.srWindow
.Top
) - 4;
312 CharSL
= csbi
.dwCursorPosition
.X
;
314 /* Make sure they didn't make the screen to small */
317 ConPrintf(szFormat
, arg_ptr
, nStdHandle
);
321 len
= _vstprintf(szOut
, szFormat
, arg_ptr
);
325 /* Search until the end of a line is reached */
326 if (szOut
[i
++] != _T('\n') && ++CharSL
< csbi
.dwSize
.X
)
332 if (LineCount
>= ScreenLines
)
334 WriteConsole(hOutput
, &szOut
[from
], i
-from
, &dwWritten
, NULL
);
337 if (PagePrompt() != PROMPT_YES
)
341 /* Reset the number of lines being printed */
346 WriteConsole(hOutput
, &szOut
[from
], i
-from
, &dwWritten
, NULL
);
351 VOID
ConErrFormatMessage(DWORD MessageId
, ...)
353 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
358 va_start(arg_ptr
, MessageId
);
359 ret
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
362 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
375 LoadString(CMD_ModuleHandle
, STRING_CONSOLE_ERROR
, szMsg
, RC_STRING_MAX_SIZE
);
380 VOID
ConOutFormatMessage(DWORD MessageId
, ...)
382 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
387 va_start(arg_ptr
, MessageId
);
388 ret
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
391 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
404 LoadString(CMD_ModuleHandle
, STRING_CONSOLE_ERROR
, szMsg
, RC_STRING_MAX_SIZE
);
409 VOID
ConOutResPrintf(UINT resID
, ...)
411 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
414 va_start(arg_ptr
, resID
);
415 LoadString(CMD_ModuleHandle
, resID
, szMsg
, RC_STRING_MAX_SIZE
);
416 ConPrintf(szMsg
, arg_ptr
, STD_OUTPUT_HANDLE
);
420 VOID
ConOutPrintf(LPTSTR szFormat
, ...)
424 va_start(arg_ptr
, szFormat
);
425 ConPrintf(szFormat
, arg_ptr
, STD_OUTPUT_HANDLE
);
429 INT
ConOutPrintfPaging(BOOL NewPage
, LPTSTR szFormat
, ...)
434 va_start(arg_ptr
, szFormat
);
435 iReturn
= ConPrintfPaging(NewPage
, szFormat
, arg_ptr
, STD_OUTPUT_HANDLE
);
440 VOID
ConErrChar(TCHAR c
)
442 ConWrite(&c
, 1, STD_ERROR_HANDLE
);
446 VOID
ConErrResPuts(UINT resID
)
448 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
449 LoadString(CMD_ModuleHandle
, resID
, szMsg
, RC_STRING_MAX_SIZE
);
450 ConPuts(szMsg
, STD_ERROR_HANDLE
);
453 VOID
ConErrPuts(LPTSTR szText
)
455 ConPuts(szText
, STD_ERROR_HANDLE
);
459 VOID
ConErrResPrintf(UINT resID
, ...)
461 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
464 va_start(arg_ptr
, resID
);
465 LoadString(CMD_ModuleHandle
, resID
, szMsg
, RC_STRING_MAX_SIZE
);
466 ConPrintf(szMsg
, arg_ptr
, STD_ERROR_HANDLE
);
470 VOID
ConErrPrintf(LPTSTR szFormat
, ...)
474 va_start(arg_ptr
, szFormat
);
475 ConPrintf(szFormat
, arg_ptr
, STD_ERROR_HANDLE
);
480 VOID
SetCursorXY(SHORT x
, SHORT y
)
486 SetConsoleCursorPosition(GetStdHandle (STD_OUTPUT_HANDLE
), coPos
);
489 VOID
GetCursorXY(PSHORT x
, PSHORT y
)
491 CONSOLE_SCREEN_BUFFER_INFO csbi
;
493 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
);
495 *x
= csbi
.dwCursorPosition
.X
;
496 *y
= csbi
.dwCursorPosition
.Y
;
499 SHORT
GetCursorX(VOID
)
501 CONSOLE_SCREEN_BUFFER_INFO csbi
;
503 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
);
504 return csbi
.dwCursorPosition
.X
;
507 SHORT
GetCursorY(VOID
)
509 CONSOLE_SCREEN_BUFFER_INFO csbi
;
511 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
);
512 return csbi
.dwCursorPosition
.Y
;
515 VOID
SetCursorType(BOOL bInsert
, BOOL bVisible
)
517 CONSOLE_CURSOR_INFO cci
;
519 cci
.dwSize
= bInsert
? 10 : 99;
520 cci
.bVisible
= bVisible
;
522 SetConsoleCursorInfo(GetStdHandle (STD_OUTPUT_HANDLE
), &cci
);
525 VOID
GetScreenSize(PSHORT maxx
, PSHORT maxy
)
527 CONSOLE_SCREEN_BUFFER_INFO csbi
;
529 if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
))
535 if (maxx
) *maxx
= csbi
.dwSize
.X
;
536 if (maxy
) *maxy
= csbi
.dwSize
.Y
;