Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / smallprint.cc
blob1e89f1ce0c3762c69e249966b92d374ec01fa698
1 /* smallprint.cc: small print routines for WIN32
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include "ntdll.h"
11 #include "sync.h"
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include <wchar.h>
17 Meaning of format conversion specifiers. If 'l' isn't explicitely mentioned,
18 it's ignored!
20 0 modifier: pad with zero instead of spaces
21 0-9 modifier: field length
22 + modifier: always add sign
23 l modifier to d, o, R, u, x, y: 4 byte on 32 bit, 8 byte on 64 bit
24 l modifier to s, S, W: non-ASCII tweaking
25 _ modifier: print lower case hex chars a-f instead of A-F
27 c char
28 C WCHAR/wchar_t
29 d signed int, 4 byte
30 D signed long long, 8 byte
31 E GetLastError
32 o octal unsigned int, 4 byte
33 O octal unsigned long long, 8 byte
34 p address
35 P process name
36 R return value, 4 byte.
37 s char *
38 S PUNICODE_STRING
39 u unsigned int, 4 byte
40 U unsigned long long, 8 byte
41 W PWCHAR/wchar_t *
42 x hex unsigned int, 4 byte
43 X hex unsigned long long, 8 byte
44 y 0x hex unsigned int, 4 byte
45 Y 0x hex unsigned long long, 8 byte
48 #define LLMASK (0xffffffffffffffffULL)
49 #define LMASK (0xffffffff)
51 #define rnarg(dst, base, dosign, len, pad) __rn ((dst), (base), (dosign), va_arg (ap, int32_t), len, pad, LMASK)
52 #define rnargLL(dst, base, dosign, len, pad) __rn ((dst), (base), (dosign), va_arg (ap, uint64_t), len, pad, LLMASK)
54 static const char hex_str_upper[] = "0123456789ABCDEF";
55 static const char hex_str_lower[] = "0123456789abcdef";
57 class tmpbuf
59 PWCHAR buf;
61 public:
62 operator WCHAR * ()
64 if (!buf)
65 buf = (PWCHAR) HeapAlloc (GetProcessHeap (), 0,
66 NT_MAX_PATH * sizeof (WCHAR));
67 return buf;
69 operator char * () { return (char *) ((WCHAR *) *this); }
71 tmpbuf () : buf (NULL) {}
72 ~tmpbuf ()
74 if (buf)
75 HeapFree (GetProcessHeap (), 0, buf);
79 static char *
80 __rn (char *dst, int base, int dosign, long long val, int len, int pad, unsigned long long mask)
82 /* longest number is ULLONG_MAX, 18446744073709551615, 20 digits */
83 unsigned long long uval = 0;
84 char res[20];
85 int l = 0;
86 const char *hex_str;
88 if (base < 0)
90 base = -base;
91 hex_str = hex_str_lower;
93 else
94 hex_str = hex_str_upper;
96 if (dosign && val < 0)
98 *dst++ = '-';
99 uval = -val;
101 else if (dosign > 0 && val > 0)
103 *dst++ = '+';
104 uval = val;
106 else
107 uval = val;
109 uval &= mask;
113 res[l++] = hex_str[uval % base];
114 uval /= base;
116 while (uval);
118 while (len-- > l)
119 *dst++ = pad;
121 while (l > 0)
122 *dst++ = res[--l];
124 return dst;
127 extern "C" int
128 __small_vsprintf (char *dst, const char *fmt, va_list ap)
130 tmpbuf tmp;
131 char *orig = dst;
132 const char *s;
133 PWCHAR w;
134 UNICODE_STRING uw, *us;
135 int base = 0;
137 DWORD err = GetLastError ();
139 intptr_t Rval = 0;
140 while (*fmt)
142 int i, n = 0x7fff;
143 bool l_opt = false;
144 /* set to -1 on '_', indicates upper (1)/lower(-1) case */
145 int h_opt = 1;
146 const char *hex_str = hex_str_upper;
147 if (*fmt != '%')
148 *dst++ = *fmt++;
149 else
151 int len = 0;
152 char pad = ' ';
153 int addsign = -1;
155 switch (*++fmt)
157 case '+':
158 addsign = 1;
159 fmt++;
160 break;
161 case '%':
162 *dst++ = *fmt++;
163 continue;
166 for (;;)
168 char c = *fmt++;
169 switch (c)
171 case '0':
172 if (len == 0)
174 pad = '0';
175 continue;
177 fallthrough;
178 case '1' ... '9':
179 len = len * 10 + (c - '0');
180 continue;
181 case 'l':
182 l_opt = true;
183 continue;
184 case '_':
185 h_opt = -1;
186 hex_str = hex_str_lower;
187 continue;
188 case 'c':
190 unsigned char c = (va_arg (ap, int) & 0xff);
191 if (isprint (c) || pad != '0')
192 *dst++ = c;
193 else
195 *dst++ = '0';
196 *dst++ = 'x';
197 dst = __rn (dst, h_opt * 16, 0, c, len, pad, LMASK);
200 break;
201 case 'C':
203 WCHAR wc = (WCHAR) va_arg (ap, int);
204 char buf[MB_LEN_MAX+1] = "", *c;
205 sys_wcstombs (buf, MB_LEN_MAX+1, &wc, 1);
206 for (c = buf; *c; ++c)
207 *dst++ = *c;
209 break;
210 case 'E':
211 strcpy (dst, "Win32 error ");
212 dst = __rn (dst + sizeof ("Win32 error"), 10, 0, err, len, pad, LMASK);
213 break;
214 case 'R':
216 if (l_opt)
217 Rval = va_arg (ap, int64_t);
218 else
219 Rval = va_arg (ap, int32_t);
220 dst = __rn (dst, 10, addsign, Rval, len, pad, LMASK);
222 break;
223 case 'd':
224 base = 10;
225 if (l_opt)
226 goto gen_decimalLL;
227 goto gen_decimal;
228 case 'u':
229 base = 10;
230 addsign = 0;
231 if (l_opt)
232 goto gen_decimalLL;
233 goto gen_decimal;
234 case 'o':
235 base = 8;
236 addsign = 0;
237 if (l_opt)
238 goto gen_decimalLL;
239 goto gen_decimal;
240 case 'y':
241 *dst++ = '0';
242 *dst++ = 'x';
243 fallthrough;
244 case 'x':
245 base = 16;
246 addsign = 0;
247 if (l_opt)
248 goto gen_decimalLL;
249 gen_decimal:
250 dst = rnarg (dst, h_opt * base, addsign, len, pad);
251 break;
252 case 'D':
253 base = 10;
254 goto gen_decimalLL;
255 case 'U':
256 base = 10;
257 addsign = 0;
258 goto gen_decimalLL;
259 case 'O':
260 base = 8;
261 addsign = 0;
262 goto gen_decimalLL;
263 case 'Y':
264 *dst++ = '0';
265 *dst++ = 'x';
266 fallthrough;
267 case 'X':
268 base = 16;
269 addsign = 0;
270 gen_decimalLL:
271 dst = rnargLL (dst, h_opt * base, addsign, len, pad);
272 break;
273 case 'p':
274 *dst++ = '0';
275 *dst++ = 'x';
276 dst = rnargLL (dst, h_opt * 16, 0, len, pad);
277 break;
278 case '.':
279 n = strtol (fmt, (char **) &fmt, 10);
280 if (*fmt++ != 's')
281 goto endfor;
282 fallthrough;
283 case 's':
284 s = va_arg (ap, char *);
285 if (s == NULL)
286 s = "(null)";
287 fillin:
288 for (i = 0; *s && i < n; i++)
289 if (l_opt && ((*(unsigned char *)s <= 0x1f && *s != '\n')
290 || *(unsigned char *)s >= 0x7f))
292 *dst++ = '\\';
293 *dst++ = 'x';
294 *dst++ = hex_str[*(unsigned char *)s >> 4];
295 *dst++ = hex_str[*(unsigned char *)s++ & 0xf];
297 else
298 *dst++ = *s++;
299 break;
300 case 'P':
301 RtlInitUnicodeString (us = &uw, global_progname);
302 goto wfillin;
303 case 'W':
304 w = va_arg (ap, PWCHAR);
305 RtlInitUnicodeString (us = &uw, w ?: L"(null)");
306 goto wfillin;
307 case 'S':
308 us = va_arg (ap, PUNICODE_STRING);
309 if (!us)
310 RtlInitUnicodeString (us = &uw, L"(null)");
311 wfillin:
312 if (l_opt)
314 for (USHORT i = 0; i < us->Length / sizeof (WCHAR); ++i)
316 WCHAR w = us->Buffer[i];
317 if ((w <= 0x1f && w != '\n') || w >= 0x7f)
319 *dst++ = '\\';
320 *dst++ = 'x';
321 *dst++ = hex_str[(w >> 12) & 0xf];
322 *dst++ = hex_str[(w >> 8) & 0xf];
323 *dst++ = hex_str[(w >> 4) & 0xf];
324 *dst++ = hex_str[w & 0xf];
326 else
327 *dst++ = w;
330 else if (sys_wcstombs (tmp, NT_MAX_PATH, us->Buffer,
331 us->Length / sizeof (WCHAR)))
333 s = tmp;
334 goto fillin;
336 break;
337 default:
338 *dst++ = '?';
339 *dst++ = fmt[-1];
341 endfor:
342 break;
346 if (Rval < 0)
348 dst = stpcpy (dst, ", errno ");
349 dst = __rn (dst, 10, false, get_errno (), 0, 0, LMASK);
351 *dst = 0;
352 SetLastError (err);
353 return dst - orig;
356 extern "C" int
357 __small_sprintf (char *dst, const char *fmt, ...)
359 int r;
360 va_list ap;
361 va_start (ap, fmt);
362 r = __small_vsprintf (dst, fmt, ap);
363 va_end (ap);
364 return r;
367 void
368 small_printf (const char *fmt, ...)
370 char buf[16384];
371 va_list ap;
372 DWORD done;
373 int count;
375 #if 0 /* Turn on to force console errors */
376 extern SECURITY_ATTRIBUTES sec_none;
377 HANDLE h = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE,
378 FILE_SHARE_WRITE | FILE_SHARE_WRITE, &sec_none,
379 OPEN_EXISTING, 0, 0);
380 if (h)
381 SetStdHandle (STD_ERROR_HANDLE, h);
382 #endif
384 va_start (ap, fmt);
385 count = __small_vsprintf (buf, fmt, ap);
386 va_end (ap);
388 WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
389 FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
392 #ifdef DEBUGGING
393 static HANDLE NO_COPY console_handle = NULL;
394 void
395 console_printf (const char *fmt, ...)
397 char buf[16384];
398 va_list ap;
399 DWORD done;
400 int count;
402 if (!console_handle)
403 console_handle = CreateFileA ("CON", GENERIC_WRITE,
404 FILE_SHARE_READ | FILE_SHARE_WRITE,
405 NULL, OPEN_EXISTING, 0, 0);
407 if (console_handle == INVALID_HANDLE_VALUE)
408 console_handle = GetStdHandle (STD_ERROR_HANDLE);
410 va_start (ap, fmt);
411 count = __small_vsprintf (buf, fmt, ap);
412 va_end (ap);
414 WriteFile (console_handle, buf, count, &done, NULL);
415 FlushFileBuffers (console_handle);
417 #endif
419 #define wrnarg(dst, base, dosign, len, pad) __wrn ((dst), (base), (dosign), va_arg (ap, long), len, pad, LMASK)
420 #define wrnargLL(dst, base, dosign, len, pad) __wrn ((dst), (base), (dosign), va_arg (ap, unsigned long long), len, pad, LLMASK)
422 static PWCHAR
423 __wrn (PWCHAR dst, int base, int dosign, long long val, int len, int pad, unsigned long long mask)
425 /* longest number is ULLONG_MAX, 18446744073709551615, 20 digits */
426 unsigned long long uval = 0;
427 WCHAR res[20];
428 int l = 0;
429 const char *hex_str;
431 if (base < 0)
433 base = -base;
434 hex_str = hex_str_lower;
436 else
437 hex_str = hex_str_upper;
439 if (dosign && val < 0)
441 *dst++ = L'-';
442 uval = -val;
444 else if (dosign > 0 && val > 0)
446 *dst++ = L'+';
447 uval = val;
449 else
450 uval = val;
452 uval &= mask;
456 res[l++] = hex_str[uval % base];
457 uval /= base;
459 while (uval);
461 while (len-- > l)
462 *dst++ = pad;
464 while (l > 0)
465 *dst++ = res[--l];
467 return dst;
471 __small_vswprintf (PWCHAR dst, const WCHAR *fmt, va_list ap)
473 tmpbuf tmp;
474 PWCHAR orig = dst;
475 const char *s;
476 PWCHAR w;
477 UNICODE_STRING uw, *us;
478 int base = 0;
480 DWORD err = GetLastError ();
482 intptr_t Rval = 0;
483 while (*fmt)
485 unsigned int n = 0x7fff;
486 bool l_opt = false;
487 /* set to -1 on '_', indicates upper (1)/lower(-1) case */
488 int h_opt = 1;
489 if (*fmt != L'%')
490 *dst++ = *fmt++;
491 else
493 int len = 0;
494 WCHAR pad = L' ';
495 int addsign = -1;
497 switch (*++fmt)
499 case L'+':
500 addsign = 1;
501 fmt++;
502 break;
503 case L'%':
504 *dst++ = *fmt++;
505 continue;
508 for (;;)
510 char c = *fmt++;
511 switch (c)
513 case L'0':
514 if (len == 0)
516 pad = L'0';
517 continue;
519 fallthrough;
520 case L'1' ... L'9':
521 len = len * 10 + (c - L'0');
522 continue;
523 case L'l':
524 l_opt = true;
525 continue;
526 case '_':
527 h_opt = -1;
528 continue;
529 case L'c':
530 case L'C':
531 *dst++ = va_arg (ap, unsigned);
532 break;
533 case L'E':
534 wcscpy (dst, L"Win32 error ");
535 dst = __wrn (dst + sizeof ("Win32 error"), 10, 0, err, len, pad, LMASK);
536 break;
537 case 'R':
539 if (l_opt)
540 Rval = va_arg (ap, int64_t);
541 else
542 Rval = va_arg (ap, int32_t);
543 dst = __wrn (dst, 10, addsign, Rval, len, pad, LMASK);
545 break;
546 case L'd':
547 base = 10;
548 if (l_opt)
549 goto gen_decimalLL;
550 goto gen_decimal;
551 case 'u':
552 base = 10;
553 addsign = 0;
554 if (l_opt)
555 goto gen_decimalLL;
556 goto gen_decimal;
557 case 'o':
558 base = 8;
559 addsign = 0;
560 if (l_opt)
561 goto gen_decimalLL;
562 goto gen_decimal;
563 case 'y':
564 *dst++ = '0';
565 *dst++ = 'x';
566 fallthrough;
567 case 'x':
568 base = 16;
569 addsign = 0;
570 if (l_opt)
571 goto gen_decimalLL;
572 gen_decimal:
573 dst = wrnarg (dst, h_opt * base, addsign, len, pad);
574 break;
575 case 'D':
576 base = 10;
577 goto gen_decimalLL;
578 case 'U':
579 base = 10;
580 addsign = 0;
581 goto gen_decimalLL;
582 case 'O':
583 base = 8;
584 addsign = 0;
585 goto gen_decimalLL;
586 case 'Y':
587 *dst++ = '0';
588 *dst++ = 'x';
589 fallthrough;
590 case 'X':
591 base = 16;
592 addsign = 0;
593 gen_decimalLL:
594 dst = wrnargLL (dst, h_opt * base, addsign, len, pad);
595 break;
596 case L'p':
597 *dst++ = L'0';
598 *dst++ = L'x';
599 dst = wrnargLL (dst, h_opt * 16, 0, len, pad);
600 break;
601 case L'P':
602 RtlInitUnicodeString (us = &uw, global_progname);
603 goto fillin;
604 case L'.':
605 n = wcstoul (fmt, (wchar_t **) &fmt, 10);
606 if (*fmt++ != L's')
607 goto endfor;
608 fallthrough;
609 case L's':
610 s = va_arg (ap, char *);
611 if (s == NULL)
612 s = "(null)";
613 sys_mbstowcs (tmp, NT_MAX_PATH, s, n < 0x7fff ? (int) n : -1);
614 RtlInitUnicodeString (us = &uw, tmp);
615 goto fillin;
616 break;
617 case L'W':
618 w = va_arg (ap, PWCHAR);
619 RtlInitUnicodeString (us = &uw, w ?: L"(null)");
620 goto fillin;
621 case L'S':
622 us = va_arg (ap, PUNICODE_STRING);
623 if (!us)
624 RtlInitUnicodeString (us = &uw, L"(null)");
625 fillin:
626 if (us->Length / sizeof (WCHAR) < n)
627 n = us->Length / sizeof (WCHAR);
628 w = us->Buffer;
629 for (unsigned int i = 0; i < n; i++)
630 *dst++ = *w++;
631 break;
632 default:
633 *dst++ = L'?';
634 *dst++ = fmt[-1];
636 endfor:
637 break;
641 if (Rval < 0)
643 dst = wcpcpy (dst, L", errno ");
644 dst = __wrn (dst, 10, false, get_errno (), 0, 0, LMASK);
646 *dst = L'\0';
647 SetLastError (err);
648 return dst - orig;
652 __small_swprintf (PWCHAR dst, const WCHAR *fmt, ...)
654 int r;
655 va_list ap;
656 va_start (ap, fmt);
657 r = __small_vswprintf (dst, fmt, ap);
658 va_end (ap);
659 return r;