Partial merge of condrv_restructure branch r65657.
[reactos.git] / reactos / base / shell / cmd / console.c
1 /*
2 * CONSOLE.C - console input/output functions.
3 *
4 *
5 * History:
6 *
7 * 20-Jan-1999 (Eric Kohl)
8 * started
9 *
10 * 03-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
11 * Remove all hardcoded strings in En.rc
12 *
13 * 01-Jul-2005 (Brandon Turner <turnerb7@msu.edu>)
14 * Added ConPrintfPaging and ConOutPrintfPaging
15 *
16 * 02-Feb-2007 (Paolo Devoti <devotip at gmail.com>)
17 * Fixed ConPrintfPaging
18 */
19
20 #include "precomp.h"
21
22 #define OUTPUT_BUFFER_SIZE 4096
23
24
25 UINT InputCodePage;
26 UINT OutputCodePage;
27
28
29 BOOL IsConsoleHandle(HANDLE hHandle)
30 {
31 DWORD dwMode;
32
33 /* Check whether the handle may be that of a console... */
34 if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
35 return FALSE;
36
37 /*
38 * It may be. Perform another test... The idea comes from the
39 * MSDN description of the WriteConsole API:
40 *
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."
49 */
50 return GetConsoleMode(hHandle, &dwMode);
51 }
52
53 VOID ConInDisable(VOID)
54 {
55 HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
56 DWORD dwMode;
57
58 GetConsoleMode(hInput, &dwMode);
59 dwMode &= ~ENABLE_PROCESSED_INPUT;
60 SetConsoleMode(hInput, dwMode);
61 }
62
63
64 VOID ConInEnable(VOID)
65 {
66 HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
67 DWORD dwMode;
68
69 GetConsoleMode(hInput, &dwMode);
70 dwMode |= ENABLE_PROCESSED_INPUT;
71 SetConsoleMode(hInput, dwMode);
72 }
73
74
75 VOID ConInFlush (VOID)
76 {
77 FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
78 }
79
80
81 VOID ConInKey(PINPUT_RECORD lpBuffer)
82 {
83 HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
84 DWORD dwRead;
85
86 if (hInput == INVALID_HANDLE_VALUE)
87 WARN ("Invalid input handle!!!\n");
88
89 do
90 {
91 ReadConsoleInput(hInput, lpBuffer, 1, &dwRead);
92 if ((lpBuffer->EventType == KEY_EVENT) &&
93 (lpBuffer->Event.KeyEvent.bKeyDown == TRUE))
94 break;
95 }
96 while (TRUE);
97 }
98
99
100 VOID ConInString(LPTSTR lpInput, DWORD dwLength)
101 {
102 DWORD dwOldMode;
103 DWORD dwRead = 0;
104 HANDLE hFile;
105
106 LPTSTR p;
107 PCHAR pBuf;
108
109 #ifdef _UNICODE
110 pBuf = (PCHAR)cmd_alloc(dwLength - 1);
111 #else
112 pBuf = lpInput;
113 #endif
114 ZeroMemory(lpInput, dwLength * sizeof(TCHAR));
115 hFile = GetStdHandle(STD_INPUT_HANDLE);
116 GetConsoleMode(hFile, &dwOldMode);
117
118 SetConsoleMode(hFile, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
119
120 ReadFile(hFile, (PVOID)pBuf, dwLength - 1, &dwRead, NULL);
121
122 #ifdef _UNICODE
123 MultiByteToWideChar(InputCodePage, 0, pBuf, dwRead, lpInput, dwLength - 1);
124 cmd_free(pBuf);
125 #endif
126 for (p = lpInput; *p; p++)
127 {
128 if (*p == _T('\x0d'))
129 {
130 *p = _T('\0');
131 break;
132 }
133 }
134
135 SetConsoleMode(hFile, dwOldMode);
136 }
137
138 static VOID ConWrite(TCHAR *str, DWORD len, DWORD nStdHandle)
139 {
140 DWORD dwWritten;
141 HANDLE hOutput = GetStdHandle(nStdHandle);
142 PVOID p;
143
144 /* Check whether we are writing to a console and if so, write to it */
145 if (IsConsoleHandle(hOutput))
146 {
147 if (WriteConsole(hOutput, str, len, &dwWritten, NULL))
148 return;
149 }
150
151 /* We're writing to a file or pipe instead of the console. Convert the
152 * string from TCHARs to the desired output format, if the two differ */
153 if (bUnicodeOutput)
154 {
155 #ifndef _UNICODE
156 WCHAR *buffer = cmd_alloc(len * sizeof(WCHAR));
157 if (!buffer)
158 {
159 error_out_of_memory();
160 return;
161 }
162 len = (DWORD)MultiByteToWideChar(OutputCodePage, 0, str, (INT)len, buffer, (INT)len);
163 str = (PVOID)buffer;
164 #endif
165 /*
166 * Find any newline character in the buffer,
167 * send the part BEFORE the newline, then send
168 * a carriage-return + newline, and then send
169 * the remaining part of the buffer.
170 *
171 * This fixes output in files and serial console.
172 */
173 while (str && *(PWCHAR)str && len > 0)
174 {
175 p = wcspbrk((PWCHAR)str, L"\r\n");
176 if (p)
177 {
178 len -= ((PWCHAR)p - (PWCHAR)str) + 1;
179 WriteFile(hOutput, str, ((PWCHAR)p - (PWCHAR)str) * sizeof(WCHAR), &dwWritten, NULL);
180 WriteFile(hOutput, L"\r\n", 2 * sizeof(WCHAR), &dwWritten, NULL);
181 str = (PVOID)((PWCHAR)p + 1);
182 }
183 else
184 {
185 WriteFile(hOutput, str, len * sizeof(WCHAR), &dwWritten, NULL);
186 break;
187 }
188 }
189
190 // WriteFile(hOutput, str, len * sizeof(WCHAR), &dwWritten, NULL);
191 #ifndef _UNICODE
192 cmd_free(buffer);
193 #endif
194 }
195 else
196 {
197 #ifdef _UNICODE
198 CHAR *buffer = cmd_alloc(len * MB_LEN_MAX * sizeof(CHAR));
199 if (!buffer)
200 {
201 error_out_of_memory();
202 return;
203 }
204 len = WideCharToMultiByte(OutputCodePage, 0, str, len, buffer, len * MB_LEN_MAX, NULL, NULL);
205 str = (PVOID)buffer;
206 #endif
207 /*
208 * Find any newline character in the buffer,
209 * send the part BEFORE the newline, then send
210 * a carriage-return + newline, and then send
211 * the remaining part of the buffer.
212 *
213 * This fixes output in files and serial console.
214 */
215 while (str && *(PCHAR)str && len > 0)
216 {
217 p = strpbrk((PCHAR)str, "\r\n");
218 if (p)
219 {
220 len -= ((PCHAR)p - (PCHAR)str) + 1;
221 WriteFile(hOutput, str, ((PCHAR)p - (PCHAR)str), &dwWritten, NULL);
222 WriteFile(hOutput, "\r\n", 2, &dwWritten, NULL);
223 str = (PVOID)((PCHAR)p + 1);
224 }
225 else
226 {
227 WriteFile(hOutput, str, len, &dwWritten, NULL);
228 break;
229 }
230 }
231
232 // WriteFile(hOutput, str, len, &dwWritten, NULL);
233 #ifdef _UNICODE
234 cmd_free(buffer);
235 #endif
236 }
237 }
238
239 VOID ConOutChar(TCHAR c)
240 {
241 ConWrite(&c, 1, STD_OUTPUT_HANDLE);
242 }
243
244 VOID ConPuts(LPTSTR szText, DWORD nStdHandle)
245 {
246 ConWrite(szText, (DWORD)_tcslen(szText), nStdHandle);
247 }
248
249 VOID ConOutResPaging(BOOL NewPage, UINT resID)
250 {
251 TCHAR szMsg[RC_STRING_MAX_SIZE];
252 LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
253 ConOutPrintfPaging(NewPage, szMsg);
254 }
255
256 VOID ConOutResPuts(UINT resID)
257 {
258 TCHAR szMsg[RC_STRING_MAX_SIZE];
259 LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
260 ConPuts(szMsg, STD_OUTPUT_HANDLE);
261 }
262
263 VOID ConOutPuts(LPTSTR szText)
264 {
265 ConPuts(szText, STD_OUTPUT_HANDLE);
266 }
267
268
269 VOID ConPrintf(LPTSTR szFormat, va_list arg_ptr, DWORD nStdHandle)
270 {
271 TCHAR szOut[OUTPUT_BUFFER_SIZE];
272 DWORD len;
273
274 len = (DWORD)_vstprintf(szOut, szFormat, arg_ptr);
275 ConWrite(szOut, len, nStdHandle);
276 }
277
278 INT ConPrintfPaging(BOOL NewPage, LPTSTR szFormat, va_list arg_ptr, DWORD nStdHandle)
279 {
280 INT len;
281 CONSOLE_SCREEN_BUFFER_INFO csbi;
282 TCHAR szOut[OUTPUT_BUFFER_SIZE];
283 DWORD dwWritten;
284 HANDLE hOutput = GetStdHandle(nStdHandle);
285
286 /* used to count number of lines since last pause */
287 static int LineCount = 0;
288
289 /* used to see how big the screen is */
290 int ScreenLines = 0;
291
292 /* chars since start of line */
293 int CharSL;
294
295 int from = 0, i = 0;
296
297 if (NewPage == TRUE)
298 LineCount = 0;
299
300 /* rest LineCount and return if no string have been given */
301 if (szFormat == NULL)
302 return 0;
303
304 /* Get the size of the visual screen that can be printed too */
305 if (!IsConsoleHandle(hOutput) || !GetConsoleScreenBufferInfo(hOutput, &csbi))
306 {
307 /* We assume it's a file handle */
308 ConPrintf(szFormat, arg_ptr, nStdHandle);
309 return 0;
310 }
311 /* Subtract 2 to account for "press any key..." and for the blank line at the end of PagePrompt() */
312 ScreenLines = (csbi.srWindow.Bottom - csbi.srWindow.Top) - 4;
313 CharSL = csbi.dwCursorPosition.X;
314
315 /* Make sure they didn't make the screen to small */
316 if (ScreenLines < 4)
317 {
318 ConPrintf(szFormat, arg_ptr, nStdHandle);
319 return 0;
320 }
321
322 len = _vstprintf(szOut, szFormat, arg_ptr);
323
324 while (i < len)
325 {
326 /* Search until the end of a line is reached */
327 if (szOut[i++] != _T('\n') && ++CharSL < csbi.dwSize.X)
328 continue;
329
330 LineCount++;
331 CharSL=0;
332
333 if (LineCount >= ScreenLines)
334 {
335 WriteConsole(hOutput, &szOut[from], i-from, &dwWritten, NULL);
336 from = i;
337
338 if (PagePrompt() != PROMPT_YES)
339 {
340 return 1;
341 }
342 /* Reset the number of lines being printed */
343 LineCount = 0;
344 }
345 }
346
347 WriteConsole(hOutput, &szOut[from], i-from, &dwWritten, NULL);
348
349 return 0;
350 }
351
352 VOID ConErrFormatMessage(DWORD MessageId, ...)
353 {
354 TCHAR szMsg[RC_STRING_MAX_SIZE];
355 DWORD ret;
356 LPTSTR text;
357 va_list arg_ptr;
358
359 va_start(arg_ptr, MessageId);
360 ret = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
361 NULL,
362 MessageId,
363 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
364 (LPTSTR) &text,
365 0,
366 &arg_ptr);
367
368 va_end(arg_ptr);
369 if (ret > 0)
370 {
371 ConErrPuts(text);
372 LocalFree(text);
373 }
374 else
375 {
376 LoadString(CMD_ModuleHandle, STRING_CONSOLE_ERROR, szMsg, RC_STRING_MAX_SIZE);
377 ConErrPrintf(szMsg);
378 }
379 }
380
381 VOID ConOutFormatMessage(DWORD MessageId, ...)
382 {
383 TCHAR szMsg[RC_STRING_MAX_SIZE];
384 DWORD ret;
385 LPTSTR text;
386 va_list arg_ptr;
387
388 va_start(arg_ptr, MessageId);
389 ret = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
390 NULL,
391 MessageId,
392 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
393 (LPTSTR) &text,
394 0,
395 &arg_ptr);
396
397 va_end(arg_ptr);
398 if (ret > 0)
399 {
400 ConErrPuts(text);
401 LocalFree(text);
402 }
403 else
404 {
405 LoadString(CMD_ModuleHandle, STRING_CONSOLE_ERROR, szMsg, RC_STRING_MAX_SIZE);
406 ConErrPrintf(szMsg);
407 }
408 }
409
410 VOID ConOutResPrintf(UINT resID, ...)
411 {
412 TCHAR szMsg[RC_STRING_MAX_SIZE];
413 va_list arg_ptr;
414
415 va_start(arg_ptr, resID);
416 LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
417 ConPrintf(szMsg, arg_ptr, STD_OUTPUT_HANDLE);
418 va_end(arg_ptr);
419 }
420
421 VOID ConOutPrintf(LPTSTR szFormat, ...)
422 {
423 va_list arg_ptr;
424
425 va_start(arg_ptr, szFormat);
426 ConPrintf(szFormat, arg_ptr, STD_OUTPUT_HANDLE);
427 va_end(arg_ptr);
428 }
429
430 INT ConOutPrintfPaging(BOOL NewPage, LPTSTR szFormat, ...)
431 {
432 INT iReturn;
433 va_list arg_ptr;
434
435 va_start(arg_ptr, szFormat);
436 iReturn = ConPrintfPaging(NewPage, szFormat, arg_ptr, STD_OUTPUT_HANDLE);
437 va_end(arg_ptr);
438 return iReturn;
439 }
440
441 VOID ConErrChar(TCHAR c)
442 {
443 ConWrite(&c, 1, STD_ERROR_HANDLE);
444 }
445
446
447 VOID ConErrResPuts(UINT resID)
448 {
449 TCHAR szMsg[RC_STRING_MAX_SIZE];
450 LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
451 ConPuts(szMsg, STD_ERROR_HANDLE);
452 }
453
454 VOID ConErrPuts(LPTSTR szText)
455 {
456 ConPuts(szText, STD_ERROR_HANDLE);
457 }
458
459
460 VOID ConErrResPrintf(UINT resID, ...)
461 {
462 TCHAR szMsg[RC_STRING_MAX_SIZE];
463 va_list arg_ptr;
464
465 va_start(arg_ptr, resID);
466 LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
467 ConPrintf(szMsg, arg_ptr, STD_ERROR_HANDLE);
468 va_end(arg_ptr);
469 }
470
471 VOID ConErrPrintf(LPTSTR szFormat, ...)
472 {
473 va_list arg_ptr;
474
475 va_start(arg_ptr, szFormat);
476 ConPrintf(szFormat, arg_ptr, STD_ERROR_HANDLE);
477 va_end(arg_ptr);
478 }
479
480
481 VOID SetCursorXY(SHORT x, SHORT y)
482 {
483 COORD coPos;
484
485 coPos.X = x;
486 coPos.Y = y;
487 SetConsoleCursorPosition(GetStdHandle (STD_OUTPUT_HANDLE), coPos);
488 }
489
490 VOID GetCursorXY(PSHORT x, PSHORT y)
491 {
492 CONSOLE_SCREEN_BUFFER_INFO csbi;
493
494 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
495
496 *x = csbi.dwCursorPosition.X;
497 *y = csbi.dwCursorPosition.Y;
498 }
499
500 SHORT GetCursorX(VOID)
501 {
502 CONSOLE_SCREEN_BUFFER_INFO csbi;
503
504 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
505 return csbi.dwCursorPosition.X;
506 }
507
508 SHORT GetCursorY(VOID)
509 {
510 CONSOLE_SCREEN_BUFFER_INFO csbi;
511
512 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
513 return csbi.dwCursorPosition.Y;
514 }
515
516 VOID SetCursorType(BOOL bInsert, BOOL bVisible)
517 {
518 CONSOLE_CURSOR_INFO cci;
519
520 cci.dwSize = bInsert ? 10 : 99;
521 cci.bVisible = bVisible;
522
523 SetConsoleCursorInfo(GetStdHandle (STD_OUTPUT_HANDLE), &cci);
524 }
525
526 VOID GetScreenSize(PSHORT maxx, PSHORT maxy)
527 {
528 CONSOLE_SCREEN_BUFFER_INFO csbi;
529
530 if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
531 {
532 csbi.dwSize.X = 80;
533 csbi.dwSize.Y = 25;
534 }
535
536 if (maxx) *maxx = csbi.dwSize.X;
537 if (maxy) *maxy = csbi.dwSize.Y;
538 }
539
540 /* EOF */