ReactOS  0.4.12-dev-375-g61fed54
outstream.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Console Utilities Library
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Provides basic abstraction wrappers around CRT streams or
5  * Win32 console API I/O functions, to deal with i18n + Unicode
6  * related problems.
7  * COPYRIGHT: Copyright 2017-2018 ReactOS Team
8  * Copyright 2017-2018 Hermes Belusca-Maito
9  */
10 
18 /*
19  * Enable this define if you want to only use CRT functions to output
20  * UNICODE stream to the console, as in the way explained by
21  * http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
22  */
24 // #define USE_CRT
25 
26 /* FIXME: Temporary HACK before we cleanly support UNICODE functions */
27 #define UNICODE
28 #define _UNICODE
29 
30 #ifdef USE_CRT
31 #include <fcntl.h>
32 #include <io.h>
33 #endif /* USE_CRT */
34 
35 #include <stdlib.h> // limits.h // For MB_LEN_MAX
36 
37 #include <windef.h>
38 #include <winbase.h>
39 #include <winnls.h>
40 #include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
41 #include <wincon.h> // Console APIs (only if kernel32 support included)
42 #include <strsafe.h>
43 
44 /* PSEH for SEH Support */
45 #include <pseh/pseh2.h>
46 
47 #include "conutils.h"
48 #include "stream.h"
49 #include "stream_private.h"
50 
51 
52 // Also known as: RC_STRING_MAX_SIZE, MAX_BUFFER_SIZE (some programs:
53 // wlanconf, shutdown, set it to 5024), OUTPUT_BUFFER_SIZE (name given
54 // in cmd/console.c), MAX_STRING_SIZE (name given in diskpart) or
55 // MAX_MESSAGE_SIZE (set to 512 in shutdown).
56 #define CON_RC_STRING_MAX_SIZE 4096
57 
58 
83 INT
87  IN PTCHAR szStr,
88  IN DWORD len)
89 {
90 #ifndef USE_CRT
91  DWORD TotalLen = len, dwNumBytes = 0;
92  PVOID p;
93 
94  /* If we do not write anything, just return */
95  if (!szStr || len == 0)
96  return 0;
97 
98  /* Check whether we are writing to a console */
99  // if (IsConsoleHandle(Stream->hHandle))
100  if (Stream->IsConsole)
101  {
102  // TODO: Check if (Stream->Mode == WideText or UTF16Text) ??
103 
104  /*
105  * This code is inspired from _cputws, in particular from the fact that,
106  * according to MSDN: https://msdn.microsoft.com/en-us/library/ms687401(v=vs.85).aspx
107  * the buffer size must be less than 64 KB.
108  *
109  * A similar code can be used for implementing _cputs too.
110  */
111 
112  DWORD cchWrite;
113  TotalLen = len, dwNumBytes = 0;
114 
115  while (len > 0)
116  {
117  cchWrite = min(len, 65535 / sizeof(WCHAR));
118 
119  // FIXME: Check return value!
120  WriteConsole(Stream->hHandle, szStr, cchWrite, &dwNumBytes, NULL);
121 
122  szStr += cchWrite;
123  len -= cchWrite;
124  }
125 
126  return (INT)TotalLen; // FIXME: Really return the number of chars written!
127  }
128 
129  /*
130  * We are redirected and writing to a file or pipe instead of the console.
131  * Convert the string from TCHARs to the desired output format, if the two differ.
132  *
133  * Implementation NOTE:
134  * MultiByteToWideChar (resp. WideCharToMultiByte) are equivalent to
135  * OemToCharBuffW (resp. CharToOemBuffW), but these latter functions
136  * uselessly depend on user32.dll, while MultiByteToWideChar and
137  * WideCharToMultiByte only need kernel32.dll.
138  */
139  if ((Stream->Mode == WideText) || (Stream->Mode == UTF16Text))
140  {
141 #ifndef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
142  /* Convert from the current process/thread's code page to UTF-16 */
144  if (!buffer)
145  {
147  return 0;
148  }
149  len = (DWORD)MultiByteToWideChar(CP_THREAD_ACP, // CP_ACP, CP_OEMCP
150  0, szStr, (INT)len, buffer, (INT)len);
151  szStr = (PVOID)buffer;
152 #else
153  /*
154  * Do not perform any conversion since we are already in UTF-16,
155  * that is the same encoding as the stream.
156  */
157 #endif
158 
159  /*
160  * Find any newline character in the buffer,
161  * write the part BEFORE the newline, then emit
162  * a carriage-return + newline sequence and finally
163  * write the remaining part of the buffer.
164  *
165  * This fixes output in files and serial console.
166  */
167  while (len > 0)
168  {
169  /* Loop until we find a newline character */
170  p = szStr;
171  while (len > 0 && *(PWCHAR)p != L'\n')
172  {
173  /* Advance one character */
174  p = (PVOID)((PWCHAR)p + 1);
175  --len;
176  }
177 
178  /* Write everything up to \n */
179  dwNumBytes = ((PWCHAR)p - (PWCHAR)szStr) * sizeof(WCHAR);
180  WriteFile(Stream->hHandle, szStr, dwNumBytes, &dwNumBytes, NULL);
181 
182  /*
183  * If we hit a newline and the previous character is not a carriage-return,
184  * emit a carriage-return + newline sequence, otherwise just emit the newline.
185  */
186  if (len > 0 && *(PWCHAR)p == L'\n')
187  {
188  if (p == (PVOID)szStr || (p > (PVOID)szStr && *((PWCHAR)p - 1) != L'\r'))
189  WriteFile(Stream->hHandle, L"\r\n", 2 * sizeof(WCHAR), &dwNumBytes, NULL);
190  else
191  WriteFile(Stream->hHandle, L"\n", sizeof(WCHAR), &dwNumBytes, NULL);
192 
193  /* Skip \n */
194  p = (PVOID)((PWCHAR)p + 1);
195  --len;
196  }
197  szStr = p;
198  }
199 
200 #ifndef _UNICODE
202 #endif
203  }
204  else if ((Stream->Mode == UTF8Text) || (Stream->Mode == AnsiText))
205  {
206  UINT CodePage;
207  PCHAR buffer;
208 
209  /*
210  * Resolve the current code page if it has not been assigned yet
211  * (we do this only if the stream is in ANSI mode; in UTF8 mode
212  * the code page is always set to CP_UTF8). Otherwise use the
213  * current stream's code page.
214  */
215  if (/*(Stream->Mode == AnsiText) &&*/ (Stream->CodePage == INVALID_CP))
216  CodePage = GetConsoleOutputCP(); // CP_ACP, CP_OEMCP
217  else
218  CodePage = Stream->CodePage;
219 
220 #ifdef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
221  /* Convert from UTF-16 to either UTF-8 or ANSI, using the stream code page */
222  // NOTE: MB_LEN_MAX defined either in limits.h or in stdlib.h .
224  if (!buffer)
225  {
227  return 0;
228  }
230  szStr, len, buffer, len * MB_LEN_MAX,
231  NULL, NULL);
232  szStr = (PVOID)buffer;
233 #else
234  /*
235  * Convert from the current process/thread's code page to either
236  * UTF-8 or ANSI, using the stream code page.
237  * We need to perform a double conversion, by going through UTF-16.
238  */
239  // TODO!
240  #error "Need to implement double conversion!"
241 #endif
242 
243  /*
244  * Find any newline character in the buffer,
245  * write the part BEFORE the newline, then emit
246  * a carriage-return + newline sequence and finally
247  * write the remaining part of the buffer.
248  *
249  * This fixes output in files and serial console.
250  */
251  while (len > 0)
252  {
253  /* Loop until we find a newline character */
254  p = szStr;
255  while (len > 0 && *(PCHAR)p != '\n')
256  {
257  /* Advance one character */
258  p = (PVOID)((PCHAR)p + 1);
259  --len;
260  }
261 
262  /* Write everything up to \n */
263  dwNumBytes = ((PCHAR)p - (PCHAR)szStr) * sizeof(CHAR);
264  WriteFile(Stream->hHandle, szStr, dwNumBytes, &dwNumBytes, NULL);
265 
266  /*
267  * If we hit a newline and the previous character is not a carriage-return,
268  * emit a carriage-return + newline sequence, otherwise just emit the newline.
269  */
270  if (len > 0 && *(PCHAR)p == '\n')
271  {
272  if (p == (PVOID)szStr || (p > (PVOID)szStr && *((PCHAR)p - 1) != '\r'))
273  WriteFile(Stream->hHandle, "\r\n", 2, &dwNumBytes, NULL);
274  else
275  WriteFile(Stream->hHandle, "\n", 1, &dwNumBytes, NULL);
276 
277  /* Skip \n */
278  p = (PVOID)((PCHAR)p + 1);
279  --len;
280  }
281  szStr = p;
282  }
283 
284 #ifdef _UNICODE
286 #else
287  // TODO!
288 #endif
289  }
290  else // if (Stream->Mode == Binary)
291  {
292  /* Directly output the string */
293  WriteFile(Stream->hHandle, szStr, len, &dwNumBytes, NULL);
294  }
295 
296  // FIXME!
297  return (INT)TotalLen;
298 
299 #else /* defined(USE_CRT) */
300 
301  DWORD total = len;
302  DWORD written = 0;
303 
304  /* If we do not write anything, just return */
305  if (!szStr || len == 0)
306  return 0;
307 
308 #if 1
309  /*
310  * There is no "counted" printf-to-stream or puts-like function, therefore
311  * we use this trick to output the counted string to the stream.
312  */
313  while (1)
314  {
315  written = fwprintf(Stream->fStream, L"%.*s", total, szStr);
316  if (written < total)
317  {
318  /*
319  * Some embedded NULL or special character
320  * was encountered, print it apart.
321  */
322  if (written == 0)
323  {
324  fputwc(*szStr, Stream->fStream);
325  written++;
326  }
327 
328  szStr += written;
329  total -= written;
330  }
331  else
332  {
333  break;
334  }
335  }
336  return (INT)len;
337 #else
338  /* ANSI text or Binary output only */
339  _setmode(_fileno(Stream->fStream), _O_TEXT); // _O_BINARY
340  return fwrite(szStr, sizeof(*szStr), len, Stream->fStream);
341 #endif
342 
343 #endif /* defined(USE_CRT) */
344 }
345 
346 
347 #define CON_STREAM_WRITE_CALL(Stream, Str, Len) \
348  (Stream)->WriteFunc((Stream), (Str), (Len))
349 
350 /* Lock the stream only in non-USE_CRT mode (otherwise use the CRT stream lock) */
351 #ifndef USE_CRT
352 
353 #define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
354 do { \
355  EnterCriticalSection(&(Stream)->Lock); \
356  (RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
357  LeaveCriticalSection(&(Stream)->Lock); \
358 } while(0)
359 
360 #define CON_STREAM_WRITE(Stream, Str, Len) \
361 do { \
362  EnterCriticalSection(&(Stream)->Lock); \
363  CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
364  LeaveCriticalSection(&(Stream)->Lock); \
365 } while(0)
366 
367 #else
368 
369 #define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
370 do { \
371  (RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
372 } while(0)
373 
374 #define CON_STREAM_WRITE(Stream, Str, Len) \
375  CON_STREAM_WRITE_CALL((Stream), (Str), (Len))
376 
377 #endif
378 
379 
397 INT
400  IN PTCHAR szStr,
401  IN DWORD len)
402 {
403  INT Len;
404  CON_STREAM_WRITE2(Stream, szStr, len, Len);
405  return Len;
406 }
407 
426 INT
429  IN LPWSTR szStr)
430 {
431  INT Len;
432 
433  Len = wcslen(szStr);
434  CON_STREAM_WRITE2(Stream, szStr, Len, Len);
435 
436  /* Fixup returned length in case of errors */
437  if (Len < 0)
438  Len = 0;
439 
440  return Len;
441 }
442 
465 INT
468  IN LPWSTR szStr,
469  IN va_list args)
470 {
471  INT Len;
473 
474  // Len = vfwprintf(Stream->fStream, szStr, args); // vfprintf for direct ANSI
475 
476  /*
477  * Reuse szStr as the pointer to end-of-string, to compute
478  * the string length instead of calling wcslen().
479  */
480  // StringCchVPrintfW(bufSrc, ARRAYSIZE(bufSrc), szStr, args);
481  // Len = wcslen(bufSrc);
482  StringCchVPrintfExW(bufSrc, ARRAYSIZE(bufSrc), &szStr, NULL, 0, szStr, args);
483  Len = szStr - bufSrc;
484 
485  CON_STREAM_WRITE2(Stream, bufSrc, Len, Len);
486 
487  /* Fixup returned length in case of errors */
488  if (Len < 0)
489  Len = 0;
490 
491  return Len;
492 }
493 
518 INT
519 __cdecl
522  IN LPWSTR szStr,
523  ...)
524 {
525  INT Len;
526  va_list args;
527 
528  // Len = vfwprintf(Stream->fStream, szMsgBuf, args); // vfprintf for direct ANSI
529 
530  // StringCchPrintfW
531  va_start(args, szStr);
532  Len = ConPrintfV(Stream, szStr, args);
533  va_end(args);
534 
535  return Len;
536 }
537 
568 INT
572  IN UINT uID,
573  IN LANGID LanguageId)
574 {
575  INT Len;
576  PWCHAR szStr = NULL;
577 
578  Len = K32LoadStringExW(hInstance, uID, LanguageId, (PWSTR)&szStr, 0);
579  if (szStr && Len)
580  // Len = ConPuts(Stream, szStr);
581  CON_STREAM_WRITE2(Stream, szStr, Len, Len);
582 
583  /* Fixup returned length in case of errors */
584  if (Len < 0)
585  Len = 0;
586 
587  return Len;
588 }
589 
609 INT
612  IN UINT uID)
613 {
614  return ConResPutsEx(Stream, NULL /*GetModuleHandleW(NULL)*/,
616 }
617 
652 INT
656  IN UINT uID,
657  IN LANGID LanguageId,
658  IN va_list args)
659 {
660  INT Len;
662 
663  // NOTE: We may use the special behaviour where nBufMaxSize == 0
664  Len = K32LoadStringExW(hInstance, uID, LanguageId, bufSrc, ARRAYSIZE(bufSrc));
665  if (Len)
666  Len = ConPrintfV(Stream, bufSrc, args);
667 
668  return Len;
669 }
670 
694 INT
697  IN UINT uID,
698  IN va_list args)
699 {
700  return ConResPrintfExV(Stream, NULL /*GetModuleHandleW(NULL)*/,
702  args);
703 }
704 
738 INT
739 __cdecl
743  IN UINT uID,
744  IN LANGID LanguageId,
745  ...)
746 {
747  INT Len;
748  va_list args;
749 
750  va_start(args, LanguageId);
751  Len = ConResPrintfExV(Stream, hInstance, uID, LanguageId, args);
752  va_end(args);
753 
754  return Len;
755 }
756 
779 INT
780 __cdecl
783  IN UINT uID,
784  ...)
785 {
786  INT Len;
787  va_list args;
788 
789  va_start(args, uID);
790  Len = ConResPrintfV(Stream, uID, args);
791  va_end(args);
792 
793  return Len;
794 }
795 
836 INT
839  IN DWORD dwFlags,
840  IN LPCVOID lpSource OPTIONAL,
841  IN DWORD dwMessageId,
842  IN DWORD dwLanguageId)
843 {
844  INT Len;
845  DWORD dwLength = 0;
846  LPWSTR lpMsgBuf = NULL;
847 
848  /*
849  * Sanitize dwFlags. This version always ignore explicitely the inserts
850  * as we emulate the behaviour of the (f)puts function.
851  */
852  dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
853  dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS; // Ignore inserts for FormatMessage.
855 
856  /*
857  * Retrieve the message string without appending extra newlines.
858  * Wrap in SEH to protect from invalid string parameters.
859  */
860  _SEH2_TRY
861  {
863  lpSource,
864  dwMessageId,
865  dwLanguageId,
866  (LPWSTR)&lpMsgBuf,
867  0,
868  NULL);
869  }
871  {
872  }
873  _SEH2_END;
874 
875  Len = (INT)dwLength;
876 
877  if (!lpMsgBuf)
878  {
879  // ASSERT(dwLength == 0);
880  }
881  else
882  {
883  // ASSERT(dwLength != 0);
884 
885  /* lpMsgBuf is NULL-terminated by FormatMessage */
886  // Len = ConPuts(Stream, lpMsgBuf);
887  CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
888 
889  /* Fixup returned length in case of errors */
890  if (Len < 0)
891  Len = 0;
892 
893  /* Free the buffer allocated by FormatMessage */
894  LocalFree(lpMsgBuf);
895  }
896 
897  return Len;
898 }
899 
908 INT
911  IN DWORD dwFlags,
912  IN LPCVOID lpSource OPTIONAL,
913  IN DWORD dwMessageId,
914  IN DWORD dwLanguageId,
915  IN va_list args)
916 {
917  INT Len;
918  DWORD dwLength = 0;
919  LPWSTR lpMsgBuf = NULL;
920 
921  /*
922  * Sanitize dwFlags. This version always ignore explicitely the inserts.
923  * The string that we will return to the user will not be pre-formatted.
924  */
925  dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
926  dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS; // Ignore inserts for FormatMessage.
928 
929  /*
930  * Retrieve the message string without appending extra newlines.
931  * Wrap in SEH to protect from invalid string parameters.
932  */
933  _SEH2_TRY
934  {
936  lpSource,
937  dwMessageId,
938  dwLanguageId,
939  (LPWSTR)&lpMsgBuf,
940  0,
941  NULL);
942  }
944  {
945  }
946  _SEH2_END;
947 
948  Len = (INT)dwLength;
949 
950  if (!lpMsgBuf)
951  {
952  // ASSERT(dwLength == 0);
953  }
954  else
955  {
956  // ASSERT(dwLength != 0);
957 
958  /* lpMsgBuf is NULL-terminated by FormatMessage */
959  Len = ConPrintfV(Stream, lpMsgBuf, args);
960  // CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
961 
962  /* Fixup returned length in case of errors */
963  if (Len < 0)
964  Len = 0;
965 
966  /* Free the buffer allocated by FormatMessage */
967  LocalFree(lpMsgBuf);
968  }
969 
970  return Len;
971 }
972 
1029 INT
1032  IN DWORD dwFlags,
1033  IN LPCVOID lpSource OPTIONAL,
1034  IN DWORD dwMessageId,
1035  IN DWORD dwLanguageId,
1036  IN va_list *Arguments OPTIONAL)
1037 {
1038  INT Len;
1039  DWORD dwLength = 0;
1040  LPWSTR lpMsgBuf = NULL;
1041 
1042  /* Sanitize dwFlags */
1043  dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
1044 
1045  /*
1046  * Retrieve the message string without appending extra newlines.
1047  * Use the "safe" FormatMessage version (SEH-protected) to protect
1048  * from invalid string parameters.
1049  */
1051  lpSource,
1052  dwMessageId,
1053  dwLanguageId,
1054  (LPWSTR)&lpMsgBuf,
1055  0,
1056  Arguments);
1057 
1058  Len = (INT)dwLength;
1059 
1060  if (!lpMsgBuf)
1061  {
1062  // ASSERT(dwLength == 0);
1063  }
1064  else
1065  {
1066  // ASSERT(dwLength != 0);
1067 
1068  CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
1069 
1070  /* Fixup returned length in case of errors */
1071  if (Len < 0)
1072  Len = 0;
1073 
1074  /* Free the buffer allocated by FormatMessage */
1075  LocalFree(lpMsgBuf);
1076  }
1077 
1078  return Len;
1079 }
1080 
1128 INT
1129 __cdecl
1132  IN DWORD dwFlags,
1133  IN LPCVOID lpSource OPTIONAL,
1134  IN DWORD dwMessageId,
1135  IN DWORD dwLanguageId,
1136  ...)
1137 {
1138  INT Len;
1139  va_list args;
1140 
1141  /* Sanitize dwFlags */
1143 
1144  va_start(args, dwLanguageId);
1146  dwFlags,
1147  lpSource,
1148  dwMessageId,
1149  dwLanguageId,
1150  &args);
1151  va_end(args);
1152 
1153  return Len;
1154 }
1155 
1217 INT
1221  IN DWORD dwFlags,
1222  IN UINT uID,
1223  IN LANGID LanguageId,
1224  IN va_list *Arguments OPTIONAL)
1225 {
1226  INT Len;
1227  DWORD dwLength = 0;
1228  LPWSTR lpMsgBuf = NULL;
1229  WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
1230 
1231  /* Retrieve the string from the resource string table */
1232  // NOTE: We may use the special behaviour where nBufMaxSize == 0
1233  Len = K32LoadStringExW(hInstance, uID, LanguageId, bufSrc, ARRAYSIZE(bufSrc));
1234  if (Len == 0)
1235  return Len;
1236 
1237  /* Sanitize dwFlags */
1238  dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
1239 
1240  /* The string has already been manually loaded */
1243 
1244  /*
1245  * Retrieve the message string without appending extra newlines.
1246  * Use the "safe" FormatMessage version (SEH-protected) to protect
1247  * from invalid string parameters.
1248  */
1250  bufSrc,
1251  0, 0,
1252  (LPWSTR)&lpMsgBuf,
1253  0,
1254  Arguments);
1255 
1256  Len = (INT)dwLength;
1257 
1258  if (!lpMsgBuf)
1259  {
1260  // ASSERT(dwLength == 0);
1261  }
1262  else
1263  {
1264  // ASSERT(dwLength != 0);
1265 
1266  CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
1267 
1268  /* Fixup returned length in case of errors */
1269  if (Len < 0)
1270  Len = 0;
1271 
1272  /* Free the buffer allocated by FormatMessage */
1273  LocalFree(lpMsgBuf);
1274  }
1275 
1276  return Len;
1277 }
1278 
1328 INT
1331  IN DWORD dwFlags,
1332  IN UINT uID,
1333  IN va_list *Arguments OPTIONAL)
1334 {
1335  return ConResMsgPrintfExV(Stream, NULL /*GetModuleHandleW(NULL)*/,
1336  dwFlags, uID,
1338  Arguments);
1339 }
1340 
1392 INT
1393 __cdecl
1397  IN DWORD dwFlags,
1398  IN UINT uID,
1399  IN LANGID LanguageId,
1400  ...)
1401 {
1402  INT Len;
1403  va_list args;
1404 
1405  /* Sanitize dwFlags */
1407 
1408  va_start(args, LanguageId);
1410  hInstance,
1411  dwFlags,
1412  uID,
1413  LanguageId,
1414  &args);
1415  va_end(args);
1416 
1417  return Len;
1418 }
1419 
1459 INT
1460 __cdecl
1463  IN DWORD dwFlags,
1464  IN UINT uID,
1465  ...)
1466 {
1467  INT Len;
1468  va_list args;
1469 
1470  /* Sanitize dwFlags */
1472 
1473  va_start(args, uID);
1474  Len = ConResMsgPrintfV(Stream, dwFlags, uID, &args);
1475  va_end(args);
1476 
1477  return Len;
1478 }
1479 
1480 
1481 
1482 VOID
1484 {
1485  HANDLE hOutput = ConStreamGetOSHandle(Stream);
1486 
1487  /*
1488  * Erase the full line where the cursor is, and move
1489  * the cursor back to the beginning of the line.
1490  */
1491 
1492  if (IsConsoleHandle(hOutput))
1493  {
1495  DWORD dwWritten;
1496 
1497  GetConsoleScreenBufferInfo(hOutput, &csbi);
1498 
1499  csbi.dwCursorPosition.X = 0;
1500  // csbi.dwCursorPosition.Y;
1501 
1502  FillConsoleOutputCharacterW(hOutput, L' ',
1503  csbi.dwSize.X,
1504  csbi.dwCursorPosition,
1505  &dwWritten);
1507  }
1508  else if (IsTTYHandle(hOutput))
1509  {
1510  ConPuts(Stream, L"\x1B[2K\x1B[1G"); // FIXME: Just use WriteFile
1511  }
1512  // else, do nothing for files
1513 }
1514 
1515 /* EOF */
signed char * PCHAR
Definition: retypes.h:7
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
#define IN
Definition: typedefs.h:38
#define _setmode(fd, mode)
Definition: cat.c:21
INT __cdecl ConResMsgPrintfEx(IN PCON_STREAM Stream, IN HINSTANCE hInstance OPTIONAL, IN DWORD dwFlags, IN UINT uID, IN LANGID LanguageId,...)
Definition: outstream.c:1394
INT ConResPrintfV(IN PCON_STREAM Stream, IN UINT uID, IN va_list args)
Definition: outstream.c:695
#define WideCharToMultiByte
Definition: compat.h:101
#define __cdecl
Definition: accygwin.h:79
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define DWORD
Definition: msvc.h:34
uint16_t * PWSTR
Definition: typedefs.h:54
#define LANG_NEUTRAL
Definition: nls.h:22
#define FORMAT_MESSAGE_ARGUMENT_ARRAY
Definition: winbase.h:405
#define FORMAT_MESSAGE_FROM_STRING
Definition: winbase.h:402
char CHAR
Definition: xmlstorage.h:175
VOID ConClearLine(IN PCON_STREAM Stream)
Definition: outstream.c:1483
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
GLuint buffer
Definition: glext.h:5915
WORD LANGID
Definition: typedefs.h:79
uint16_t * PWCHAR
Definition: typedefs.h:54
_Check_return_opt_ _CRTIMP size_t __cdecl fwrite(_In_reads_bytes_(_Size *_Count) const void *_Str, _In_ size_t _Size, _In_ size_t _Count, _Inout_ FILE *_File)
DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:583
#define SUBLANG_NEUTRAL
Definition: nls.h:167
Definition: match.c:390
int32_t INT
Definition: typedefs.h:56
_SEH2_TRY
Definition: create.c:4250
INT ConMsgPrintfV(IN PCON_STREAM Stream, IN DWORD dwFlags, IN LPCVOID lpSource OPTIONAL, IN DWORD dwMessageId, IN DWORD dwLanguageId, IN va_list *Arguments OPTIONAL)
Definition: outstream.c:1030
HINSTANCE hInstance
Definition: charmap.c:20
#define va_end(ap)
Definition: acmsvcex.h:90
_Check_return_opt_ _CRTIMP int __cdecl fwprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const wchar_t *_Format,...)
#define FORMAT_MESSAGE_ALLOCATE_BUFFER
Definition: winbase.h:400
#define INT(a)
Definition: assyntax.h:463
INT __cdecl ConPrintf(IN PCON_STREAM Stream, IN LPWSTR szStr,...)
Definition: outstream.c:520
UINT WINAPI DECLSPEC_HOTPATCH GetConsoleOutputCP(VOID)
Definition: console.c:2453
INT ConStreamWrite(IN PCON_STREAM Stream, IN PTCHAR szStr, IN DWORD len)
Definition: outstream.c:398
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
INT ConResMsgPrintfExV(IN PCON_STREAM Stream, IN HINSTANCE hInstance OPTIONAL, IN DWORD dwFlags, IN UINT uID, IN LANGID LanguageId, IN va_list *Arguments OPTIONAL)
Definition: outstream.c:1218
smooth NULL
Definition: ftsmooth.c:416
BOOL WINAPI SetConsoleCursorPosition(IN HANDLE hConsoleOutput, IN COORD dwCursorPosition)
Definition: console.c:590
char * va_list
Definition: acmsvcex.h:78
void * PVOID
Definition: retypes.h:9
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:404
BOOL WINAPI GetConsoleScreenBufferInfo(IN HANDLE hConsoleOutput, OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo)
Definition: console.c:544
#define FORMAT_MESSAGE_FROM_HMODULE
Definition: winbase.h:403
INT ConResPrintfExV(IN PCON_STREAM Stream, IN HINSTANCE hInstance OPTIONAL, IN UINT uID, IN LANGID LanguageId, IN va_list args)
Definition: outstream.c:653
#define PCHAR
Definition: match.c:90
INT __cdecl ConResPrintf(IN PCON_STREAM Stream, IN UINT uID,...)
Definition: outstream.c:781
ULONG X
Definition: bl.h:1340
BOOL IsTTYHandle(IN HANDLE hHandle)
Definition: utils.c:342
HANDLE ConStreamGetOSHandle(IN PCON_STREAM Stream)
Definition: stream.c:240
#define CON_STREAM_WRITE2(Stream, Str, Len, RetLen)
Definition: outstream.c:353
#define CON_RC_STRING_MAX_SIZE
Definition: outstream.c:56
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
static DWORD DWORD * dwLength
Definition: fusion.c:83
unsigned int UINT
Definition: ndis.h:50
unsigned long DWORD
Definition: ntddk_ex.h:95
INT ConMsgPrintf2V(IN PCON_STREAM Stream, IN DWORD dwFlags, IN LPCVOID lpSource OPTIONAL, IN DWORD dwMessageId, IN DWORD dwLanguageId, IN va_list args)
Definition: outstream.c:909
#define Len
Definition: deflate.h:82
#define SetLastError(x)
Definition: compat.h:409
#define __stdcall
Definition: typedefs.h:25
INT ConMsgPuts(IN PCON_STREAM Stream, IN DWORD dwFlags, IN LPCVOID lpSource OPTIONAL, IN DWORD dwMessageId, IN DWORD dwLanguageId)
Definition: outstream.c:837
#define IsConsoleHandle(h)
Definition: console.h:14
INT __stdcall ConWrite(IN PCON_STREAM Stream, IN PTCHAR szStr, IN DWORD len)
Definition: outstream.c:85
#define INVALID_CP
Definition: stream.h:53
INT ConResPuts(IN PCON_STREAM Stream, IN UINT uID)
Definition: outstream.c:610
static const WCHAR L[]
Definition: oid.c:1087
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
GLenum GLsizei len
Definition: glext.h:6722
#define FORMAT_MESSAGE_IGNORE_INSERTS
Definition: winbase.h:401
_SEH2_END
Definition: create.c:4424
STRSAFEAPI StringCchVPrintfExW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags, STRSAFE_LPCWSTR pszFormat, va_list argList)
Definition: strsafe.h:661
INT ConResMsgPrintfV(IN PCON_STREAM Stream, IN DWORD dwFlags, IN UINT uID, IN va_list *Arguments OPTIONAL)
Definition: outstream.c:1329
INT ConPrintfV(IN PCON_STREAM Stream, IN LPWSTR szStr, IN va_list args)
Definition: outstream.c:466
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1577
INT ConResPutsEx(IN PCON_STREAM Stream, IN HINSTANCE hInstance OPTIONAL, IN UINT uID, IN LANGID LanguageId)
Definition: outstream.c:569
#define _O_TEXT
Definition: cabinet.h:50
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define min(a, b)
Definition: monoChain.cc:55
INT __cdecl ConResPrintfEx(IN PCON_STREAM Stream, IN HINSTANCE hInstance OPTIONAL, IN UINT uID, IN LANGID LanguageId,...)
Definition: outstream.c:740
#define WriteConsole
Definition: wincon.h:772
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
INT ConPuts(IN PCON_STREAM Stream, IN LPWSTR szStr)
Definition: outstream.c:427
#define MultiByteToWideChar
Definition: compat.h:100
CONST void * LPCVOID
Definition: windef.h:191
INT __cdecl ConMsgPrintf(IN PCON_STREAM Stream, IN DWORD dwFlags, IN LPCVOID lpSource OPTIONAL, IN DWORD dwMessageId, IN DWORD dwLanguageId,...)
Definition: outstream.c:1130
#define MAKELANGID(p, s)
Definition: nls.h:15
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
_Check_return_ _CRTIMP int __cdecl _fileno(_In_ FILE *_File)
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define CP_THREAD_ACP
Definition: winnls.h:230
_Check_return_opt_ _CRTIMP wint_t __cdecl fputwc(_In_ wchar_t _Ch, _Inout_ FILE *_File)
DWORD WINAPI FormatMessageSafeW(IN DWORD dwFlags, IN LPCVOID lpSource OPTIONAL, IN DWORD dwMessageId, IN DWORD dwLanguageId, OUT LPWSTR lpBuffer, IN DWORD nSize, IN va_list *Arguments OPTIONAL)
Definition: utils.c:254
#define args
Definition: format.c:66
INT WINAPI K32LoadStringExW(IN HINSTANCE hInstance OPTIONAL, IN UINT uID, IN LANGID LanguageId, OUT LPWSTR lpBuffer, IN INT nBufferMax)
Definition: utils.c:99
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define HeapFree(x, y, z)
Definition: compat.h:394
_Inout_opt_ PUNICODE_STRING _Inout_opt_ PUNICODE_STRING Stream
Definition: fltkernel.h:1092
#define MB_LEN_MAX
Definition: limits.h:35
INT __cdecl ConResMsgPrintf(IN PCON_STREAM Stream, IN DWORD dwFlags, IN UINT uID,...)
Definition: outstream.c:1461
char * PTCHAR
Definition: ntbasedef.h:483
BOOL WINAPI DECLSPEC_HOTPATCH FillConsoleOutputCharacterW(IN HANDLE hConsoleOutput, IN WCHAR cCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten)
Definition: readwrite.c:1676
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68