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