xref: /reactos/base/shell/cmd/console.c (revision 84344399)
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 /* Cache codepage for text streams */
25 UINT InputCodePage;
26 UINT OutputCodePage;
27 
28 /* Global console Screen and Pager */
29 CON_SCREEN StdOutScreen = INIT_CON_SCREEN(StdOut);
30 CON_PAGER  StdOutPager  = INIT_CON_PAGER(&StdOutScreen);
31 
32 
33 
34 /********************* Console STREAM IN utility functions ********************/
35 
36 VOID ConInDisable(VOID)
37 {
38     HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
39     DWORD dwMode;
40 
41     GetConsoleMode(hInput, &dwMode);
42     dwMode &= ~ENABLE_PROCESSED_INPUT;
43     SetConsoleMode(hInput, dwMode);
44 }
45 
46 VOID ConInEnable(VOID)
47 {
48     HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
49     DWORD dwMode;
50 
51     GetConsoleMode(hInput, &dwMode);
52     dwMode |= ENABLE_PROCESSED_INPUT;
53     SetConsoleMode(hInput, dwMode);
54 }
55 
56 VOID ConInFlush(VOID)
57 {
58     FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
59 }
60 
61 VOID ConInKey(PINPUT_RECORD lpBuffer)
62 {
63     HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
64     DWORD  dwRead;
65 
66     if (hInput == INVALID_HANDLE_VALUE)
67         WARN ("Invalid input handle!!!\n");
68 
69     do
70     {
71         ReadConsoleInput(hInput, lpBuffer, 1, &dwRead);
72         if (lpBuffer->EventType == KEY_EVENT &&
73             lpBuffer->Event.KeyEvent.bKeyDown)
74         {
75             break;
76         }
77     }
78     while (TRUE);
79 }
80 
81 VOID ConInString(LPWSTR lpInput, DWORD dwLength)
82 {
83     DWORD dwOldMode;
84     DWORD dwRead = 0;
85     HANDLE hFile;
86 
87     LPWSTR p;
88     PCHAR pBuf;
89 
90     pBuf = (PCHAR)cmd_alloc(dwLength - 1);
91 
92     ZeroMemory(lpInput, dwLength * sizeof(WCHAR));
93     hFile = GetStdHandle(STD_INPUT_HANDLE);
94     GetConsoleMode(hFile, &dwOldMode);
95 
96     SetConsoleMode(hFile, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
97 
98     ReadFile(hFile, (PVOID)pBuf, dwLength - 1, &dwRead, NULL);
99 
100     MultiByteToWideChar(InputCodePage, 0, pBuf, dwRead, lpInput, dwLength - 1);
101     cmd_free(pBuf);
102 
103     for (p = lpInput; *p; p++)
104     {
105         if (*p == L'\r') // Terminate at the carriage-return.
106         {
107             *p = L'\0';
108             break;
109         }
110     }
111 
112     SetConsoleMode(hFile, dwOldMode);
113 }
114 
115 
116 
117 /******************** Console STREAM OUT utility functions ********************/
118 
119 VOID ConOutChar(WCHAR c)
120 {
121     ConWrite(StdOut, &c, 1);
122 }
123 
124 VOID ConErrChar(WCHAR c)
125 {
126     ConWrite(StdErr, &c, 1);
127 }
128 
129 VOID __cdecl ConFormatMessage(PCON_STREAM Stream, DWORD MessageId, ...)
130 {
131     INT Len;
132     va_list arg_ptr;
133 
134     va_start(arg_ptr, MessageId);
135     Len = ConMsgPrintfV(Stream,
136                         FORMAT_MESSAGE_FROM_SYSTEM,
137                         NULL,
138                         MessageId,
139                         LANG_USER_DEFAULT,
140                         &arg_ptr);
141     va_end(arg_ptr);
142 
143     if (Len <= 0)
144         ConResPrintf(Stream, STRING_CONSOLE_ERROR, MessageId);
145 }
146 
147 
148 
149 /************************** Console PAGER functions ***************************/
150 
151 BOOL ConPrintfVPaging(PCON_PAGER Pager, BOOL StartPaging, LPWSTR szFormat, va_list arg_ptr)
152 {
153     // INT len;
154     WCHAR szOut[OUTPUT_BUFFER_SIZE];
155 
156     /* Return if no string has been given */
157     if (szFormat == NULL)
158         return TRUE;
159 
160     /*len =*/ vswprintf(szOut, szFormat, arg_ptr);
161 
162     // return ConPutsPaging(Pager, PagePrompt, StartPaging, szOut);
163     return ConWritePaging(Pager, PagePrompt, StartPaging,
164                           szOut, wcslen(szOut));
165 }
166 
167 BOOL __cdecl ConOutPrintfPaging(BOOL StartPaging, LPWSTR szFormat, ...)
168 {
169     BOOL bRet;
170     va_list arg_ptr;
171 
172     va_start(arg_ptr, szFormat);
173     bRet = ConPrintfVPaging(&StdOutPager, StartPaging, szFormat, arg_ptr);
174     va_end(arg_ptr);
175     return bRet;
176 }
177 
178 VOID ConOutResPaging(BOOL StartPaging, UINT resID)
179 {
180     ConResPaging(&StdOutPager, PagePrompt, StartPaging, resID);
181 }
182 
183 
184 
185 /************************** Console SCREEN functions **************************/
186 
187 VOID SetCursorXY(SHORT x, SHORT y)
188 {
189     COORD coPos;
190 
191     coPos.X = x;
192     coPos.Y = y;
193     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coPos);
194 }
195 
196 VOID GetCursorXY(PSHORT x, PSHORT y)
197 {
198     CONSOLE_SCREEN_BUFFER_INFO csbi;
199 
200     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
201 
202     *x = csbi.dwCursorPosition.X;
203     *y = csbi.dwCursorPosition.Y;
204 }
205 
206 SHORT GetCursorX(VOID)
207 {
208     CONSOLE_SCREEN_BUFFER_INFO csbi;
209 
210     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
211     return csbi.dwCursorPosition.X;
212 }
213 
214 SHORT GetCursorY(VOID)
215 {
216     CONSOLE_SCREEN_BUFFER_INFO csbi;
217 
218     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
219     return csbi.dwCursorPosition.Y;
220 }
221 
222 VOID SetCursorType(BOOL bInsert, BOOL bVisible)
223 {
224     CONSOLE_CURSOR_INFO cci;
225 
226     cci.dwSize = bInsert ? 10 : 99;
227     cci.bVisible = bVisible;
228 
229     SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
230 }
231 
232 VOID GetScreenSize(PSHORT maxx, PSHORT maxy)
233 {
234     CONSOLE_SCREEN_BUFFER_INFO csbi;
235 
236     if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
237     {
238         csbi.dwSize.X = 80;
239         csbi.dwSize.Y = 25;
240     }
241 
242     if (maxx) *maxx = csbi.dwSize.X;
243     if (maxy) *maxy = csbi.dwSize.Y;
244 }
245 
246 
247 
248 
249 #ifdef INCLUDE_CMD_COLOR
250 
251 BOOL ConGetDefaultAttributes(PWORD pwDefAttr)
252 {
253     BOOL Success;
254     HANDLE hConsole;
255     CONSOLE_SCREEN_BUFFER_INFO csbi;
256 
257     /* Do not modify *pwDefAttr if we fail, in which case use default attributes */
258 
259     hConsole = CreateFile(_T("CONOUT$"), GENERIC_READ|GENERIC_WRITE,
260                           FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
261                           OPEN_EXISTING, 0, NULL);
262     if (hConsole == INVALID_HANDLE_VALUE)
263         return FALSE; // No default console
264 
265     Success = GetConsoleScreenBufferInfo(hConsole, &csbi);
266     if (Success)
267         *pwDefAttr = csbi.wAttributes;
268 
269     CloseHandle(hConsole);
270     return Success;
271 }
272 
273 #endif
274 
275 
276 BOOL ConSetTitle(IN LPCWSTR lpConsoleTitle)
277 {
278     /* Now really set the console title */
279     return SetConsoleTitle(lpConsoleTitle);
280 }
281 
282 #ifdef INCLUDE_CMD_BEEP
283 VOID ConRingBell(HANDLE hOutput)
284 {
285 #if 0
286     /* Emit an error beep sound */
287     if (IsConsoleHandle(hOutput))
288         Beep(800, 200);
289     else if (IsTTYHandle(hOutput))
290         ConOutPuts(_T("\a")); // BEL character 0x07
291     else
292 #endif
293         MessageBeep(-1);
294 }
295 #endif
296 
297 #ifdef INCLUDE_CMD_COLOR
298 BOOL ConSetScreenColor(HANDLE hOutput, WORD wColor, BOOL bFill)
299 {
300     DWORD dwWritten;
301     CONSOLE_SCREEN_BUFFER_INFO csbi;
302     COORD coPos;
303 
304     /* Foreground and Background colors can't be the same */
305     if ((wColor & 0x0F) == (wColor & 0xF0) >> 4)
306         return FALSE;
307 
308     /* Fill the whole background if needed */
309     if (bFill)
310     {
311         GetConsoleScreenBufferInfo(hOutput, &csbi);
312 
313         coPos.X = 0;
314         coPos.Y = 0;
315         FillConsoleOutputAttribute(hOutput,
316                                    wColor & 0x00FF,
317                                    csbi.dwSize.X * csbi.dwSize.Y,
318                                    coPos,
319                                    &dwWritten);
320     }
321 
322     /* Set the text attribute */
323     SetConsoleTextAttribute(hOutput, wColor & 0x00FF);
324     return TRUE;
325 }
326 #endif
327 
328 #include <cjkcode.h>
329 #include "wcwidth.c"
330 
331 // NOTE: The check against 0x80 is to avoid calling the helper function
332 // for characters that we already know are not full-width.
333 #define IS_FULL_WIDTH(wch)  \
334     (((USHORT)(wch) >= 0x0080) && (mk_wcwidth_cjk(wch) == 2))
335 
336 SIZE_T ConGetTextWidthW(PCWSTR pszText)
337 {
338     SIZE_T ich, cxWidth;
339 
340     if (!IsCJKCodePage(OutputCodePage))
341         return _tcslen(pszText);
342 
343     for (ich = cxWidth = 0; pszText[ich]; ++ich)
344     {
345         if (IS_FULL_WIDTH(pszText[ich]))
346             cxWidth += 2;
347         else
348             ++cxWidth;
349     }
350 
351     return cxWidth;
352 }
353 
354 SIZE_T ConGetTextWidthA(PCSTR pszText)
355 {
356     int cchMax;
357     PWSTR pszWide;
358     SIZE_T cxWidth;
359 
360     cchMax = MultiByteToWideChar(OutputCodePage, 0, pszText, -1, NULL, 0);
361     pszWide = cmd_alloc(cchMax * sizeof(WCHAR));
362     MultiByteToWideChar(OutputCodePage, 0, pszText, -1, pszWide, cchMax);
363     cxWidth = ConGetTextWidthW(pszWide);
364     cmd_free(pszWide);
365     return cxWidth;
366 }
367 
368 /* EOF */
369