- Minor fixes to work more like WinXP's cmd
[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 hardcode string to 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
23 #define OUTPUT_BUFFER_SIZE 4096
24
25
26 UINT InputCodePage;
27 UINT OutputCodePage;
28
29
30 VOID ConInDisable (VOID)
31 {
32 HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
33 DWORD dwMode;
34
35 GetConsoleMode (hInput, &dwMode);
36 dwMode &= ~ENABLE_PROCESSED_INPUT;
37 SetConsoleMode (hInput, dwMode);
38 }
39
40
41 VOID ConInEnable (VOID)
42 {
43 HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
44 DWORD dwMode;
45
46 GetConsoleMode (hInput, &dwMode);
47 dwMode |= ENABLE_PROCESSED_INPUT;
48 SetConsoleMode (hInput, dwMode);
49 }
50
51
52 VOID ConInDummy (VOID)
53 {
54 HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
55 INPUT_RECORD dummy;
56 DWORD dwRead;
57
58 if (hInput == INVALID_HANDLE_VALUE)
59 WARN ("Invalid input handle!!!\n");
60 ReadConsoleInput (hInput, &dummy, 1, &dwRead);
61 }
62
63 VOID ConInFlush (VOID)
64 {
65 FlushConsoleInputBuffer (GetStdHandle (STD_INPUT_HANDLE));
66 }
67
68
69 VOID ConInKey (PINPUT_RECORD lpBuffer)
70 {
71 HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
72 DWORD dwRead;
73
74 if (hInput == INVALID_HANDLE_VALUE)
75 WARN ("Invalid input handle!!!\n");
76
77 do
78 {
79 ReadConsoleInput (hInput, lpBuffer, 1, &dwRead);
80 if ((lpBuffer->EventType == KEY_EVENT) &&
81 (lpBuffer->Event.KeyEvent.bKeyDown == TRUE))
82 break;
83 }
84 while (TRUE);
85 }
86
87
88 VOID ConInString (LPTSTR lpInput, DWORD dwLength)
89 {
90 DWORD dwOldMode;
91 DWORD dwRead;
92 HANDLE hFile;
93
94 LPTSTR p;
95 DWORD i;
96 PCHAR pBuf;
97
98 #ifdef _UNICODE
99 pBuf = (PCHAR)cmd_alloc(dwLength);
100 #else
101 pBuf = lpInput;
102 #endif
103 ZeroMemory (lpInput, dwLength * sizeof(TCHAR));
104 hFile = GetStdHandle (STD_INPUT_HANDLE);
105 GetConsoleMode (hFile, &dwOldMode);
106
107 SetConsoleMode (hFile, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
108
109 ReadFile (hFile, (PVOID)pBuf, dwLength, &dwRead, NULL);
110
111 #ifdef _UNICODE
112 MultiByteToWideChar( InputCodePage, 0, pBuf, dwLength + 1, lpInput, dwLength + 1);
113 #endif
114 p = lpInput;
115 for (i = 0; i < dwRead; i++, p++)
116 {
117 if (*p == _T('\x0d'))
118 {
119 *p = _T('\0');
120 break;
121 }
122 }
123
124 #ifdef _UNICODE
125 cmd_free(pBuf);
126 #endif
127
128 SetConsoleMode (hFile, dwOldMode);
129 }
130
131 static VOID ConChar(TCHAR c, DWORD nStdHandle)
132 {
133 DWORD dwWritten;
134 CHAR cc;
135 #ifdef _UNICODE
136 CHAR as[2];
137 WCHAR ws[2];
138 ws[0] = c;
139 ws[1] = 0;
140 WideCharToMultiByte( OutputCodePage, 0, ws, 2, as, 2, NULL, NULL);
141 cc = as[0];
142 #else
143 cc = c;
144 #endif
145 WriteFile (GetStdHandle (nStdHandle),
146 &cc,
147 1,
148 &dwWritten,
149 NULL);
150 }
151
152 VOID ConOutChar (TCHAR c)
153 {
154 ConChar(c, STD_OUTPUT_HANDLE);
155 }
156
157 VOID ConPuts(LPTSTR szText, DWORD nStdHandle)
158 {
159 DWORD dwWritten;
160 HANDLE hStdHandle;
161 PCHAR pBuf;
162 INT len;
163
164 len = _tcslen(szText);
165 #ifdef _UNICODE
166 pBuf = cmd_alloc(len + 1);
167 len = WideCharToMultiByte( OutputCodePage, 0, szText, len + 1, pBuf, len + 1, NULL, NULL) - 1;
168 #else
169 pBuf = szText;
170 #endif
171 hStdHandle = GetStdHandle(nStdHandle);
172
173 WriteFile (hStdHandle,
174 pBuf,
175 len,
176 &dwWritten,
177 NULL);
178 WriteFile (hStdHandle,
179 _T("\n"),
180 1,
181 &dwWritten,
182 NULL);
183 #ifdef _UNICODE
184 cmd_free(pBuf);
185 #endif
186 }
187
188 VOID ConOutResPaging(BOOL NewPage, UINT resID)
189 {
190 TCHAR szMsg[RC_STRING_MAX_SIZE];
191 LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
192 ConOutPrintfPaging(NewPage, szMsg);
193 }
194
195 VOID ConOutResPuts (UINT resID)
196 {
197 TCHAR szMsg[RC_STRING_MAX_SIZE];
198 LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
199
200 ConPuts(szMsg, STD_OUTPUT_HANDLE);
201 }
202
203 VOID ConOutPuts (LPTSTR szText)
204 {
205 ConPuts(szText, STD_OUTPUT_HANDLE);
206 }
207
208
209 VOID ConPrintf(LPTSTR szFormat, va_list arg_ptr, DWORD nStdHandle)
210 {
211 INT len;
212 PCHAR pBuf;
213 TCHAR szOut[OUTPUT_BUFFER_SIZE];
214 DWORD dwWritten;
215
216 len = _vstprintf (szOut, szFormat, arg_ptr);
217 #ifdef _UNICODE
218 pBuf = cmd_alloc(len + 1);
219 len = WideCharToMultiByte( OutputCodePage, 0, szOut, len + 1, pBuf, len + 1, NULL, NULL) - 1;
220 #else
221 pBuf = szOut;
222 #endif
223
224 WriteFile (GetStdHandle (nStdHandle),
225 pBuf,
226 len,
227 &dwWritten,
228 NULL);
229
230
231 #ifdef _UNICODE
232 cmd_free(pBuf);
233 #endif
234 }
235
236 INT ConPrintfPaging(BOOL NewPage, LPTSTR szFormat, va_list arg_ptr, DWORD nStdHandle)
237 {
238 INT len;
239 PCHAR pBuf;
240 CONSOLE_SCREEN_BUFFER_INFO csbi;
241 TCHAR szOut[OUTPUT_BUFFER_SIZE];
242 DWORD dwWritten;
243
244 /* used to count number of lines since last pause */
245 static int LineCount = 0;
246
247 /* used to see how big the screen is */
248 int ScreenLines = 0;
249
250 /* the number of chars in a roow */
251 int ScreenCol = 0;
252
253 /* chars since start of line */
254 int CharSL = 0;
255
256 int i = 0;
257
258 if(NewPage == TRUE)
259 LineCount = 0;
260
261 /* rest LineCount and return if no string have been given */
262 if (szFormat == NULL)
263 return 0;
264
265
266 //get the size of the visual screen that can be printed too
267 if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
268 {
269 // we assuming its a file handle
270 ConPrintf(szFormat, arg_ptr, nStdHandle);
271 return 0;
272 }
273 //subtract 2 to account for "press any key..." and for the blank line at the end of PagePrompt()
274 ScreenLines = (csbi.srWindow.Bottom - csbi.srWindow.Top) - 4;
275 ScreenCol = (csbi.srWindow.Right - csbi.srWindow.Left) + 1;
276
277 //make sure they didnt make the screen to small
278 if(ScreenLines<4)
279 {
280 ConPrintf(szFormat, arg_ptr, nStdHandle);
281 return 0;
282 }
283
284 len = _vstprintf (szOut, szFormat, arg_ptr);
285 #ifdef _UNICODE
286 pBuf = cmd_alloc(len + 1);
287 len = WideCharToMultiByte( OutputCodePage, 0, szOut, len + 1, pBuf, len + 1, NULL, NULL) - 1;
288 #else
289 pBuf = szOut;
290 #endif
291
292 for(i = 0; i < len; i++)
293 {
294 // search 'end of string' '\n' or 'end of screen line'
295 for(; (i < len) && (pBuf[i] != _T('\n') && (CharSL<ScreenCol)) ; i++)
296 CharSL++;
297
298 WriteFile (GetStdHandle (nStdHandle),&pBuf[i-CharSL],sizeof(CHAR)*(CharSL+1),&dwWritten,NULL);
299 LineCount++;
300 CharSL=0;
301
302 if(LineCount >= ScreenLines)
303 {
304 if(_strnicmp(&pBuf[i], "\n", 2)!=0)
305 WriteFile (GetStdHandle (nStdHandle),_T("\n"),sizeof(CHAR),&dwWritten,NULL);
306
307 if(PagePrompt() != PROMPT_YES)
308 {
309 #ifdef _UNICODE
310 cmd_free(pBuf);
311 #endif
312 return 1;
313 }
314 //reset the number of lines being printed
315 LineCount = 0;
316 CharSL=0;
317 }
318
319 }
320
321 #ifdef _UNICODE
322 cmd_free(pBuf);
323 #endif
324 return 0;
325 }
326
327 VOID ConErrFormatMessage (DWORD MessageId, ...)
328 {
329 TCHAR szMsg[RC_STRING_MAX_SIZE];
330 DWORD ret;
331 LPTSTR text;
332 va_list arg_ptr;
333
334 va_start (arg_ptr, MessageId);
335 ret = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
336 NULL,
337 MessageId,
338 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
339 (LPTSTR) &text,
340 0,
341 &arg_ptr);
342
343 va_end (arg_ptr);
344 if(ret > 0)
345 {
346 ConErrPuts (text);
347 LocalFree(text);
348 }
349 else
350 {
351 LoadString(CMD_ModuleHandle, STRING_CONSOLE_ERROR, szMsg, RC_STRING_MAX_SIZE);
352 ConErrPrintf(szMsg);
353 }
354 }
355
356 VOID ConOutFormatMessage (DWORD MessageId, ...)
357 {
358 TCHAR szMsg[RC_STRING_MAX_SIZE];
359 DWORD ret;
360 LPTSTR text;
361 va_list arg_ptr;
362
363 va_start (arg_ptr, MessageId);
364 ret = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
365 NULL,
366 MessageId,
367 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
368 (LPTSTR) &text,
369 0,
370 &arg_ptr);
371
372 va_end (arg_ptr);
373 if(ret > 0)
374 {
375 ConErrPuts (text);
376 LocalFree(text);
377 }
378 else
379 {
380 LoadString(CMD_ModuleHandle, STRING_CONSOLE_ERROR, szMsg, RC_STRING_MAX_SIZE);
381 ConErrPrintf(szMsg);
382 }
383 }
384
385 VOID ConOutPrintf (LPTSTR szFormat, ...)
386 {
387 va_list arg_ptr;
388
389 va_start (arg_ptr, szFormat);
390 ConPrintf(szFormat, arg_ptr, STD_OUTPUT_HANDLE);
391 va_end (arg_ptr);
392 }
393
394 INT ConOutPrintfPaging (BOOL NewPage, LPTSTR szFormat, ...)
395 {
396 INT iReturn;
397 va_list arg_ptr;
398
399 va_start (arg_ptr, szFormat);
400 iReturn = ConPrintfPaging(NewPage, szFormat, arg_ptr, STD_OUTPUT_HANDLE);
401 va_end (arg_ptr);
402 return iReturn;
403 }
404
405 VOID ConErrChar (TCHAR c)
406 {
407 ConChar(c, STD_ERROR_HANDLE);
408 }
409
410
411 VOID ConErrResPuts (UINT resID)
412 {
413 TCHAR szMsg[RC_STRING_MAX_SIZE];
414 LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
415 ConPuts(szMsg, STD_ERROR_HANDLE);
416 }
417
418 VOID ConErrPuts (LPTSTR szText)
419 {
420 ConPuts(szText, STD_ERROR_HANDLE);
421 }
422
423
424 VOID ConErrPrintf (LPTSTR szFormat, ...)
425 {
426 va_list arg_ptr;
427
428 va_start (arg_ptr, szFormat);
429 ConPrintf(szFormat, arg_ptr, STD_ERROR_HANDLE);
430 va_end (arg_ptr);
431 }
432
433 VOID SetCursorXY (SHORT x, SHORT y)
434 {
435 COORD coPos;
436
437 coPos.X = x;
438 coPos.Y = y;
439 SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), coPos);
440 }
441
442
443 VOID GetCursorXY (PSHORT x, PSHORT y)
444 {
445 CONSOLE_SCREEN_BUFFER_INFO csbi;
446
447 GetConsoleScreenBufferInfo (hConsole, &csbi);
448
449 *x = csbi.dwCursorPosition.X;
450 *y = csbi.dwCursorPosition.Y;
451 }
452
453
454 SHORT GetCursorX (VOID)
455 {
456 CONSOLE_SCREEN_BUFFER_INFO csbi;
457
458 GetConsoleScreenBufferInfo (hConsole, &csbi);
459
460 return csbi.dwCursorPosition.X;
461 }
462
463
464 SHORT GetCursorY (VOID)
465 {
466 CONSOLE_SCREEN_BUFFER_INFO csbi;
467
468 GetConsoleScreenBufferInfo (hConsole, &csbi);
469
470 return csbi.dwCursorPosition.Y;
471 }
472
473
474 VOID GetScreenSize (PSHORT maxx, PSHORT maxy)
475 {
476 CONSOLE_SCREEN_BUFFER_INFO csbi;
477
478 GetConsoleScreenBufferInfo (hConsole, &csbi);
479
480 if (maxx)
481 *maxx = csbi.dwSize.X;
482 if (maxy)
483 *maxy = csbi.dwSize.Y;
484 }
485
486
487 VOID SetCursorType (BOOL bInsert, BOOL bVisible)
488 {
489 CONSOLE_CURSOR_INFO cci;
490
491 cci.dwSize = bInsert ? 10 : 99;
492 cci.bVisible = bVisible;
493
494 SetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cci);
495 }
496
497 /* EOF */