Bug 1858509 add thread-safety annotations around MediaSourceDemuxer::mMonitor r=alwu
[gecko.git] / mozglue / misc / Printf.cpp
blob7313495612f1849dac5f92441ebe66b4a7f609dc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * Portable safe sprintf code.
10 * Author: Kipp E.B. Hickman
13 #include "double-conversion/double-to-string.h"
14 #include "mozilla/AllocPolicy.h"
15 #include "mozilla/Printf.h"
16 #include "mozilla/UniquePtrExtensions.h"
17 #include "mozilla/Vector.h"
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #if defined(XP_WIN)
25 # include <windows.h>
26 #endif
28 using double_conversion::DoubleToStringConverter;
29 using DTSC = DoubleToStringConverter;
32 * Numbered Argument State
34 struct NumArgState {
35 int type; // type of the current ap
36 va_list ap; // point to the corresponding position on ap
39 using NumArgStateVector =
40 mozilla::Vector<NumArgState, 20, mozilla::MallocAllocPolicy>;
42 // For values up to and including TYPE_DOUBLE, the lowest bit indicates
43 // whether the type is signed (0) or unsigned (1).
44 #define TYPE_SHORT 0
45 #define TYPE_USHORT 1
46 #define TYPE_INTN 2
47 #define TYPE_UINTN 3
48 #define TYPE_LONG 4
49 #define TYPE_ULONG 5
50 #define TYPE_LONGLONG 6
51 #define TYPE_ULONGLONG 7
52 #define TYPE_DOUBLE 8
53 #define TYPE_STRING 9
54 #define TYPE_INTSTR 10
55 #define TYPE_POINTER 11
56 #if defined(XP_WIN)
57 # define TYPE_WSTRING 12
58 #endif
59 #define TYPE_SCHAR 14
60 #define TYPE_UCHAR 15
61 #define TYPE_UNKNOWN 20
63 #define FLAG_LEFT 0x1
64 #define FLAG_SIGNED 0x2
65 #define FLAG_SPACED 0x4
66 #define FLAG_ZEROS 0x8
67 #define FLAG_NEG 0x10
69 static const char hex[] = "0123456789abcdef";
70 static const char HEX[] = "0123456789ABCDEF";
72 // Fill into the buffer using the data in src
73 bool mozilla::PrintfTarget::fill2(const char* src, int srclen, int width,
74 int flags) {
75 char space = ' ';
77 width -= srclen;
78 if (width > 0 && (flags & FLAG_LEFT) == 0) { // Right adjusting
79 if (flags & FLAG_ZEROS) {
80 space = '0';
82 while (--width >= 0) {
83 if (!emit(&space, 1)) {
84 return false;
89 // Copy out the source data
90 if (!emit(src, srclen)) {
91 return false;
94 if (width > 0 && (flags & FLAG_LEFT) != 0) { // Left adjusting
95 while (--width >= 0) {
96 if (!emit(&space, 1)) {
97 return false;
101 return true;
105 * Fill a number. The order is: optional-sign zero-filling conversion-digits
107 bool mozilla::PrintfTarget::fill_n(const char* src, int srclen, int width,
108 int prec, int type, int flags) {
109 int zerowidth = 0;
110 int precwidth = 0;
111 int leftspaces = 0;
112 int rightspaces = 0;
113 int cvtwidth;
114 char sign = 0;
116 if ((type & 1) == 0) {
117 if (flags & FLAG_NEG) {
118 sign = '-';
119 } else if (flags & FLAG_SIGNED) {
120 sign = '+';
121 } else if (flags & FLAG_SPACED) {
122 sign = ' ';
125 cvtwidth = (sign ? 1 : 0) + srclen;
127 if (prec > 0 && (type != TYPE_DOUBLE)) {
128 if (prec > srclen) {
129 precwidth = prec - srclen; // Need zero filling
130 cvtwidth += precwidth;
134 if ((flags & FLAG_ZEROS) && ((type == TYPE_DOUBLE) || (prec < 0))) {
135 if (width > cvtwidth) {
136 zerowidth = width - cvtwidth; // Zero filling
137 cvtwidth += zerowidth;
141 if (flags & FLAG_LEFT) {
142 if (width > cvtwidth) {
143 // Space filling on the right (i.e. left adjusting)
144 rightspaces = width - cvtwidth;
146 } else {
147 if (width > cvtwidth) {
148 // Space filling on the left (i.e. right adjusting)
149 leftspaces = width - cvtwidth;
152 while (--leftspaces >= 0) {
153 if (!emit(" ", 1)) {
154 return false;
157 if (sign) {
158 if (!emit(&sign, 1)) {
159 return false;
162 while (--precwidth >= 0) {
163 if (!emit("0", 1)) {
164 return false;
167 while (--zerowidth >= 0) {
168 if (!emit("0", 1)) {
169 return false;
172 if (!emit(src, uint32_t(srclen))) {
173 return false;
175 while (--rightspaces >= 0) {
176 if (!emit(" ", 1)) {
177 return false;
180 return true;
183 // All that the cvt_* functions care about as far as the TYPE_* constants is
184 // that the low bit is set to indicate unsigned, or unset to indicate signed.
185 // So we don't try to hard to ensure that the passed TYPE_* constant lines
186 // up with the actual size of the number being printed here. The main printf
187 // code, below, does have to care so that the correct bits are extracted from
188 // the varargs list.
189 bool mozilla::PrintfTarget::appendIntDec(int32_t num) {
190 int flags = 0;
191 long n = num;
192 if (n < 0) {
193 n = -n;
194 flags |= FLAG_NEG;
196 return cvt_l(n, -1, -1, 10, TYPE_INTN, flags, hex);
199 bool mozilla::PrintfTarget::appendIntDec(uint32_t num) {
200 return cvt_l(num, -1, -1, 10, TYPE_UINTN, 0, hex);
203 bool mozilla::PrintfTarget::appendIntOct(uint32_t num) {
204 return cvt_l(num, -1, -1, 8, TYPE_UINTN, 0, hex);
207 bool mozilla::PrintfTarget::appendIntHex(uint32_t num) {
208 return cvt_l(num, -1, -1, 16, TYPE_UINTN, 0, hex);
211 bool mozilla::PrintfTarget::appendIntDec(int64_t num) {
212 int flags = 0;
213 if (num < 0) {
214 num = -num;
215 flags |= FLAG_NEG;
217 return cvt_ll(num, -1, -1, 10, TYPE_INTN, flags, hex);
220 bool mozilla::PrintfTarget::appendIntDec(uint64_t num) {
221 return cvt_ll(num, -1, -1, 10, TYPE_UINTN, 0, hex);
224 bool mozilla::PrintfTarget::appendIntOct(uint64_t num) {
225 return cvt_ll(num, -1, -1, 8, TYPE_UINTN, 0, hex);
228 bool mozilla::PrintfTarget::appendIntHex(uint64_t num) {
229 return cvt_ll(num, -1, -1, 16, TYPE_UINTN, 0, hex);
232 /* Convert a long into its printable form. */
233 bool mozilla::PrintfTarget::cvt_l(long num, int width, int prec, int radix,
234 int type, int flags, const char* hexp) {
235 char cvtbuf[100];
236 char* cvt;
237 int digits;
239 // according to the man page this needs to happen
240 if ((prec == 0) && (num == 0)) {
241 return fill_n("", 0, width, prec, type, flags);
244 // Converting decimal is a little tricky. In the unsigned case we
245 // need to stop when we hit 10 digits. In the signed case, we can
246 // stop when the number is zero.
247 cvt = cvtbuf + sizeof(cvtbuf);
248 digits = 0;
249 while (num) {
250 int digit = (((unsigned long)num) % radix) & 0xF;
251 *--cvt = hexp[digit];
252 digits++;
253 num = (long)(((unsigned long)num) / radix);
255 if (digits == 0) {
256 *--cvt = '0';
257 digits++;
260 // Now that we have the number converted without its sign, deal with
261 // the sign and zero padding.
262 return fill_n(cvt, digits, width, prec, type, flags);
265 /* Convert a 64-bit integer into its printable form. */
266 bool mozilla::PrintfTarget::cvt_ll(int64_t num, int width, int prec, int radix,
267 int type, int flags, const char* hexp) {
268 // According to the man page, this needs to happen.
269 if (prec == 0 && num == 0) {
270 return fill_n("", 0, width, prec, type, flags);
273 // Converting decimal is a little tricky. In the unsigned case we
274 // need to stop when we hit 10 digits. In the signed case, we can
275 // stop when the number is zero.
276 int64_t rad = int64_t(radix);
277 char cvtbuf[100];
278 char* cvt = cvtbuf + sizeof(cvtbuf);
279 int digits = 0;
280 while (num != 0) {
281 int64_t quot = uint64_t(num) / rad;
282 int64_t rem = uint64_t(num) % rad;
283 int32_t digit = int32_t(rem);
284 *--cvt = hexp[digit & 0xf];
285 digits++;
286 num = quot;
288 if (digits == 0) {
289 *--cvt = '0';
290 digits++;
293 // Now that we have the number converted without its sign, deal with
294 // the sign and zero padding.
295 return fill_n(cvt, digits, width, prec, type, flags);
298 template <size_t N>
299 constexpr static size_t lengthof(const char (&)[N]) {
300 return N - 1;
303 // Longest possible output from ToFixed for positive numbers:
304 // [0-9]{kMaxFixedDigitsBeforePoint}\.[0-9]{kMaxFixedDigitsAfterPoint}?
305 constexpr int FIXED_MAX_CHARS =
306 DTSC::kMaxFixedDigitsBeforePoint + 1 + DTSC::kMaxFixedDigitsAfterPoint;
308 // Longest possible output from ToExponential:
309 // [1-9]\.[0-9]{kMaxExponentialDigits}e[+-][0-9]{1,3}
310 // (std::numeric_limits<double>::max() has exponent 308).
311 constexpr int EXPONENTIAL_MAX_CHARS =
312 lengthof("1.") + DTSC::kMaxExponentialDigits + lengthof("e+999");
314 // Longest possible output from ToPrecise:
315 // [0-9\.]{kMaxPrecisionDigits+1} or
316 // [1-9]\.[0-9]{kMaxPrecisionDigits-1}e[+-][0-9]{1,3}
317 constexpr int PRECISE_MAX_CHARS =
318 lengthof("1.") + DTSC::kMaxPrecisionDigits - 1 + lengthof("e+999");
320 constexpr int DTSC_MAX_CHARS =
321 std::max({FIXED_MAX_CHARS, EXPONENTIAL_MAX_CHARS, PRECISE_MAX_CHARS});
324 * Convert a double precision floating point number into its printable
325 * form.
327 bool mozilla::PrintfTarget::cvt_f(double d, char c, int width, int prec,
328 int flags) {
329 bool lower = islower(c);
330 const char* inf = lower ? "inf" : "INF";
331 const char* nan = lower ? "nan" : "NAN";
332 char e = lower ? 'e' : 'E';
333 DoubleToStringConverter converter(DTSC::UNIQUE_ZERO | DTSC::NO_TRAILING_ZERO |
334 DTSC::EMIT_POSITIVE_EXPONENT_SIGN,
335 inf, nan, e, 0, 0, 4, 0, 2);
336 // Longest of the above cases, plus space for a terminal nul character.
337 char buf[DTSC_MAX_CHARS + 1];
338 double_conversion::StringBuilder builder(buf, sizeof(buf));
339 bool success = false;
340 if (std::signbit(d)) {
341 d = std::abs(d);
342 flags |= FLAG_NEG;
344 if (!std::isfinite(d)) {
345 flags &= ~FLAG_ZEROS;
347 // "If the precision is missing, it shall be taken as 6."
348 if (prec < 0) {
349 prec = 6;
351 switch (c) {
352 case 'e':
353 case 'E':
354 success = converter.ToExponential(d, prec, &builder);
355 break;
356 case 'f':
357 case 'F':
358 success = converter.ToFixed(d, prec, &builder);
359 break;
360 case 'g':
361 case 'G':
362 // "If an explicit precision is zero, it shall be taken as 1."
363 success = converter.ToPrecision(d, prec ? prec : 1, &builder);
364 break;
366 if (!success) {
367 return false;
369 int len = builder.position();
370 char* cvt = builder.Finalize();
371 return fill_n(cvt, len, width, prec, TYPE_DOUBLE, flags);
375 * Convert a string into its printable form. "width" is the output
376 * width. "prec" is the maximum number of characters of "s" to output,
377 * where -1 means until NUL.
379 bool mozilla::PrintfTarget::cvt_s(const char* s, int width, int prec,
380 int flags) {
381 if (prec == 0) {
382 return true;
384 if (!s) {
385 s = "(null)";
388 // Limit string length by precision value
389 int slen = int(strlen(s));
390 if (0 < prec && prec < slen) {
391 slen = prec;
394 // and away we go
395 return fill2(s, slen, width, flags);
399 * BuildArgArray stands for Numbered Argument list Sprintf
400 * for example,
401 * fmp = "%4$i, %2$d, %3s, %1d";
402 * the number must start from 1, and no gap among them
404 static bool BuildArgArray(const char* fmt, va_list ap, NumArgStateVector& nas) {
405 size_t number = 0, cn = 0, i;
406 const char* p;
407 char c;
409 // First pass:
410 // Detemine how many legal % I have got, then allocate space.
412 p = fmt;
413 i = 0;
414 while ((c = *p++) != 0) {
415 if (c != '%') {
416 continue;
418 if ((c = *p++) == '%') { // skip %% case
419 continue;
422 while (c != 0) {
423 if (c > '9' || c < '0') {
424 if (c == '$') { // numbered argument case
425 if (i > 0) {
426 MOZ_CRASH("Bad format string");
428 number++;
429 } else { // non-numbered argument case
430 if (number > 0) {
431 MOZ_CRASH("Bad format string");
433 i = 1;
435 break;
438 c = *p++;
442 if (number == 0) {
443 return true;
446 // Only allow a limited number of arguments.
447 MOZ_RELEASE_ASSERT(number <= 20);
449 if (!nas.growByUninitialized(number)) {
450 return false;
453 for (i = 0; i < number; i++) {
454 nas[i].type = TYPE_UNKNOWN;
457 // Second pass:
458 // Set nas[].type.
460 p = fmt;
461 while ((c = *p++) != 0) {
462 if (c != '%') {
463 continue;
465 c = *p++;
466 if (c == '%') {
467 continue;
470 cn = 0;
471 while (c && c != '$') { // should improve error check later
472 cn = cn * 10 + c - '0';
473 c = *p++;
476 if (!c || cn < 1 || cn > number) {
477 MOZ_CRASH("Bad format string");
480 // nas[cn] starts from 0, and make sure nas[cn].type is not assigned.
481 cn--;
482 if (nas[cn].type != TYPE_UNKNOWN) {
483 continue;
486 c = *p++;
488 // flags
489 while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
490 c = *p++;
493 // width
494 if (c == '*') {
495 // not supported feature, for the argument is not numbered
496 MOZ_CRASH("Bad format string");
499 while ((c >= '0') && (c <= '9')) {
500 c = *p++;
503 // precision
504 if (c == '.') {
505 c = *p++;
506 if (c == '*') {
507 // not supported feature, for the argument is not numbered
508 MOZ_CRASH("Bad format string");
511 while ((c >= '0') && (c <= '9')) {
512 c = *p++;
516 // size
517 nas[cn].type = TYPE_INTN;
518 if (c == 'h') {
519 nas[cn].type = TYPE_SHORT;
520 c = *p++;
521 if (c == 'h') {
522 nas[cn].type = TYPE_SCHAR;
523 c = *p++;
525 } else if (c == 'L') {
526 nas[cn].type = TYPE_LONGLONG;
527 c = *p++;
528 } else if (c == 'l') {
529 nas[cn].type = TYPE_LONG;
530 c = *p++;
531 if (c == 'l') {
532 nas[cn].type = TYPE_LONGLONG;
533 c = *p++;
535 } else if (c == 'z' || c == 'I') {
536 static_assert(sizeof(size_t) == sizeof(int) ||
537 sizeof(size_t) == sizeof(long) ||
538 sizeof(size_t) == sizeof(long long),
539 "size_t is not one of the expected sizes");
540 nas[cn].type = sizeof(size_t) == sizeof(int) ? TYPE_INTN
541 : sizeof(size_t) == sizeof(long) ? TYPE_LONG
542 : TYPE_LONGLONG;
543 c = *p++;
544 } else if (c == 't') {
545 static_assert(sizeof(ptrdiff_t) == sizeof(int) ||
546 sizeof(ptrdiff_t) == sizeof(long) ||
547 sizeof(ptrdiff_t) == sizeof(long long),
548 "ptrdiff_t is not one of the expected sizes");
549 nas[cn].type = sizeof(ptrdiff_t) == sizeof(int) ? TYPE_INTN
550 : sizeof(ptrdiff_t) == sizeof(long) ? TYPE_LONG
551 : TYPE_LONGLONG;
552 c = *p++;
553 } else if (c == 'j') {
554 static_assert(sizeof(intmax_t) == sizeof(int) ||
555 sizeof(intmax_t) == sizeof(long) ||
556 sizeof(intmax_t) == sizeof(long long),
557 "intmax_t is not one of the expected sizes");
558 nas[cn].type = sizeof(intmax_t) == sizeof(int) ? TYPE_INTN
559 : sizeof(intmax_t) == sizeof(long) ? TYPE_LONG
560 : TYPE_LONGLONG;
561 c = *p++;
564 // format
565 switch (c) {
566 case 'd':
567 case 'c':
568 case 'i':
569 break;
571 case 'o':
572 case 'u':
573 case 'x':
574 case 'X':
575 // Mark as unsigned type.
576 nas[cn].type |= 1;
577 break;
579 case 'e':
580 case 'E':
581 case 'f':
582 case 'F':
583 case 'g':
584 case 'G':
585 nas[cn].type = TYPE_DOUBLE;
586 break;
588 case 'p':
589 nas[cn].type = TYPE_POINTER;
590 break;
592 case 'S':
593 #if defined(XP_WIN)
594 nas[cn].type = TYPE_WSTRING;
595 #else
596 MOZ_ASSERT(0);
597 nas[cn].type = TYPE_UNKNOWN;
598 #endif
599 break;
601 case 's':
602 #if defined(XP_WIN)
603 if (nas[cn].type == TYPE_LONG) {
604 nas[cn].type = TYPE_WSTRING;
605 break;
607 #endif
608 // Other type sizes are not supported here.
609 MOZ_ASSERT(nas[cn].type == TYPE_INTN);
610 nas[cn].type = TYPE_STRING;
611 break;
613 case 'n':
614 nas[cn].type = TYPE_INTSTR;
615 break;
617 default:
618 MOZ_ASSERT(0);
619 nas[cn].type = TYPE_UNKNOWN;
620 break;
623 // get a legal para.
624 if (nas[cn].type == TYPE_UNKNOWN) {
625 MOZ_CRASH("Bad format string");
629 // Third pass:
630 // Fill nas[].ap.
632 cn = 0;
633 while (cn < number) {
634 // A TYPE_UNKNOWN here means that the format asked for a
635 // positional argument without specifying the meaning of some
636 // earlier argument.
637 MOZ_ASSERT(nas[cn].type != TYPE_UNKNOWN);
639 va_copy(nas[cn].ap, ap);
641 switch (nas[cn].type) {
642 case TYPE_SCHAR:
643 case TYPE_UCHAR:
644 case TYPE_SHORT:
645 case TYPE_USHORT:
646 case TYPE_INTN:
647 case TYPE_UINTN:
648 (void)va_arg(ap, int);
649 break;
650 case TYPE_LONG:
651 (void)va_arg(ap, long);
652 break;
653 case TYPE_ULONG:
654 (void)va_arg(ap, unsigned long);
655 break;
656 case TYPE_LONGLONG:
657 (void)va_arg(ap, long long);
658 break;
659 case TYPE_ULONGLONG:
660 (void)va_arg(ap, unsigned long long);
661 break;
662 case TYPE_STRING:
663 (void)va_arg(ap, char*);
664 break;
665 case TYPE_INTSTR:
666 (void)va_arg(ap, int*);
667 break;
668 case TYPE_DOUBLE:
669 (void)va_arg(ap, double);
670 break;
671 case TYPE_POINTER:
672 (void)va_arg(ap, void*);
673 break;
674 #if defined(XP_WIN)
675 case TYPE_WSTRING:
676 (void)va_arg(ap, wchar_t*);
677 break;
678 #endif
680 default:
681 MOZ_CRASH();
684 cn++;
687 return true;
690 mozilla::PrintfTarget::PrintfTarget() : mEmitted(0) {}
692 bool mozilla::PrintfTarget::vprint(const char* fmt, va_list ap) {
693 char c;
694 int flags, width, prec, radix, type;
695 union {
696 char ch;
697 int i;
698 long l;
699 long long ll;
700 double d;
701 const char* s;
702 int* ip;
703 void* p;
704 #if defined(XP_WIN)
705 const wchar_t* ws;
706 #endif
707 } u{};
708 const char* hexp;
709 int i;
711 // Build an argument array, IF the fmt is numbered argument
712 // list style, to contain the Numbered Argument list pointers.
714 NumArgStateVector nas;
715 if (!BuildArgArray(fmt, ap, nas)) {
716 // the fmt contains error Numbered Argument format, jliu@netscape.com
717 MOZ_CRASH("Bad format string");
720 while ((c = *fmt++) != 0) {
721 if (c != '%') {
722 if (!emit(fmt - 1, 1)) {
723 return false;
726 continue;
729 // Gobble up the % format string. Hopefully we have handled all
730 // of the strange cases!
731 flags = 0;
732 c = *fmt++;
733 if (c == '%') {
734 // quoting a % with %%
735 if (!emit(fmt - 1, 1)) {
736 return false;
739 continue;
742 if (!nas.empty()) {
743 // the fmt contains the Numbered Arguments feature
744 i = 0;
745 while (c && c != '$') { // should improve error check later
746 i = (i * 10) + (c - '0');
747 c = *fmt++;
750 if (nas[i - 1].type == TYPE_UNKNOWN) {
751 MOZ_CRASH("Bad format string");
754 ap = nas[i - 1].ap;
755 c = *fmt++;
758 // Examine optional flags. Note that we do not implement the
759 // '#' flag of sprintf(). The ANSI C spec. of the '#' flag is
760 // somewhat ambiguous and not ideal, which is perhaps why
761 // the various sprintf() implementations are inconsistent
762 // on this feature.
763 while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
764 if (c == '-') {
765 flags |= FLAG_LEFT;
767 if (c == '+') {
768 flags |= FLAG_SIGNED;
770 if (c == ' ') {
771 flags |= FLAG_SPACED;
773 if (c == '0') {
774 flags |= FLAG_ZEROS;
776 c = *fmt++;
778 if (flags & FLAG_SIGNED) {
779 flags &= ~FLAG_SPACED;
781 if (flags & FLAG_LEFT) {
782 flags &= ~FLAG_ZEROS;
785 // width
786 if (c == '*') {
787 c = *fmt++;
788 width = va_arg(ap, int);
789 if (width < 0) {
790 width = -width;
791 flags |= FLAG_LEFT;
792 flags &= ~FLAG_ZEROS;
794 } else {
795 width = 0;
796 while ((c >= '0') && (c <= '9')) {
797 width = (width * 10) + (c - '0');
798 c = *fmt++;
802 // precision
803 prec = -1;
804 if (c == '.') {
805 c = *fmt++;
806 if (c == '*') {
807 c = *fmt++;
808 prec = va_arg(ap, int);
809 } else {
810 prec = 0;
811 while ((c >= '0') && (c <= '9')) {
812 prec = (prec * 10) + (c - '0');
813 c = *fmt++;
818 // size
819 type = TYPE_INTN;
820 if (c == 'h') {
821 type = TYPE_SHORT;
822 c = *fmt++;
823 if (c == 'h') {
824 type = TYPE_SCHAR;
825 c = *fmt++;
827 } else if (c == 'L') {
828 type = TYPE_LONGLONG;
829 c = *fmt++;
830 } else if (c == 'l') {
831 type = TYPE_LONG;
832 c = *fmt++;
833 if (c == 'l') {
834 type = TYPE_LONGLONG;
835 c = *fmt++;
837 } else if (c == 'z' || c == 'I') {
838 static_assert(sizeof(size_t) == sizeof(int) ||
839 sizeof(size_t) == sizeof(long) ||
840 sizeof(size_t) == sizeof(long long),
841 "size_t is not one of the expected sizes");
842 type = sizeof(size_t) == sizeof(int) ? TYPE_INTN
843 : sizeof(size_t) == sizeof(long) ? TYPE_LONG
844 : TYPE_LONGLONG;
845 c = *fmt++;
846 } else if (c == 't') {
847 static_assert(sizeof(ptrdiff_t) == sizeof(int) ||
848 sizeof(ptrdiff_t) == sizeof(long) ||
849 sizeof(ptrdiff_t) == sizeof(long long),
850 "ptrdiff_t is not one of the expected sizes");
851 type = sizeof(ptrdiff_t) == sizeof(int) ? TYPE_INTN
852 : sizeof(ptrdiff_t) == sizeof(long) ? TYPE_LONG
853 : TYPE_LONGLONG;
854 c = *fmt++;
855 } else if (c == 'j') {
856 static_assert(sizeof(intmax_t) == sizeof(int) ||
857 sizeof(intmax_t) == sizeof(long) ||
858 sizeof(intmax_t) == sizeof(long long),
859 "intmax_t is not one of the expected sizes");
860 type = sizeof(intmax_t) == sizeof(int) ? TYPE_INTN
861 : sizeof(intmax_t) == sizeof(long) ? TYPE_LONG
862 : TYPE_LONGLONG;
863 c = *fmt++;
866 // format
867 hexp = hex;
868 switch (c) {
869 case 'd':
870 case 'i': // decimal/integer
871 radix = 10;
872 goto fetch_and_convert;
874 case 'o': // octal
875 radix = 8;
876 type |= 1;
877 goto fetch_and_convert;
879 case 'u': // unsigned decimal
880 radix = 10;
881 type |= 1;
882 goto fetch_and_convert;
884 case 'x': // unsigned hex
885 radix = 16;
886 type |= 1;
887 goto fetch_and_convert;
889 case 'X': // unsigned HEX
890 radix = 16;
891 hexp = HEX;
892 type |= 1;
893 goto fetch_and_convert;
895 fetch_and_convert:
896 switch (type) {
897 case TYPE_SCHAR:
898 u.l = (signed char)va_arg(ap, int);
899 if (u.l < 0) {
900 u.l = -u.l;
901 flags |= FLAG_NEG;
903 goto do_long;
904 case TYPE_UCHAR:
905 u.l = (unsigned char)va_arg(ap, unsigned int);
906 goto do_long;
907 case TYPE_SHORT:
908 u.l = (short)va_arg(ap, int);
909 if (u.l < 0) {
910 u.l = -u.l;
911 flags |= FLAG_NEG;
913 goto do_long;
914 case TYPE_USHORT:
915 u.l = (unsigned short)va_arg(ap, unsigned int);
916 goto do_long;
917 case TYPE_INTN:
918 u.l = va_arg(ap, int);
919 if (u.l < 0) {
920 u.l = -u.l;
921 flags |= FLAG_NEG;
923 goto do_long;
924 case TYPE_UINTN:
925 u.l = (long)va_arg(ap, unsigned int);
926 goto do_long;
928 case TYPE_LONG:
929 u.l = va_arg(ap, long);
930 if (u.l < 0) {
931 u.l = -u.l;
932 flags |= FLAG_NEG;
934 goto do_long;
935 case TYPE_ULONG:
936 u.l = (long)va_arg(ap, unsigned long);
937 do_long:
938 if (!cvt_l(u.l, width, prec, radix, type, flags, hexp)) {
939 return false;
942 break;
944 case TYPE_LONGLONG:
945 u.ll = va_arg(ap, long long);
946 if (u.ll < 0) {
947 u.ll = -u.ll;
948 flags |= FLAG_NEG;
950 goto do_longlong;
951 case TYPE_POINTER:
952 u.ll = (uintptr_t)va_arg(ap, void*);
953 goto do_longlong;
954 case TYPE_ULONGLONG:
955 u.ll = va_arg(ap, unsigned long long);
956 do_longlong:
957 if (!cvt_ll(u.ll, width, prec, radix, type, flags, hexp)) {
958 return false;
961 break;
963 break;
965 case 'e':
966 case 'E':
967 case 'f':
968 case 'F':
969 case 'g':
970 case 'G':
971 u.d = va_arg(ap, double);
972 if (!cvt_f(u.d, c, width, prec, flags)) {
973 return false;
976 break;
978 case 'c':
979 if ((flags & FLAG_LEFT) == 0) {
980 while (width-- > 1) {
981 if (!emit(" ", 1)) {
982 return false;
986 switch (type) {
987 case TYPE_SHORT:
988 case TYPE_INTN:
989 u.ch = va_arg(ap, int);
990 if (!emit(&u.ch, 1)) {
991 return false;
993 break;
995 if (flags & FLAG_LEFT) {
996 while (width-- > 1) {
997 if (!emit(" ", 1)) {
998 return false;
1002 break;
1004 case 'p':
1005 type = TYPE_POINTER;
1006 radix = 16;
1007 goto fetch_and_convert;
1009 case 's':
1010 if (type == TYPE_INTN) {
1011 u.s = va_arg(ap, const char*);
1012 if (!cvt_s(u.s, width, prec, flags)) {
1013 return false;
1015 break;
1017 MOZ_ASSERT(type == TYPE_LONG);
1018 [[fallthrough]];
1019 case 'S':
1020 #if defined(XP_WIN)
1022 u.ws = va_arg(ap, const wchar_t*);
1024 int rv = WideCharToMultiByte(CP_ACP, 0, u.ws, -1, NULL, 0, NULL, NULL);
1025 if (rv == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
1026 if (!cvt_s("<unicode errors in string>", width, prec, flags)) {
1027 return false;
1029 } else {
1030 if (rv == 0) {
1031 rv = 1;
1033 UniqueFreePtr<char[]> buf((char*)malloc(rv));
1034 WideCharToMultiByte(CP_ACP, 0, u.ws, -1, buf.get(), rv, NULL, NULL);
1035 buf[rv - 1] = '\0';
1037 if (!cvt_s(buf.get(), width, prec, flags)) {
1038 return false;
1042 #else
1043 // Not supported here.
1044 MOZ_ASSERT(0);
1045 #endif
1046 break;
1048 case 'n':
1049 u.ip = va_arg(ap, int*);
1050 if (u.ip) {
1051 *u.ip = mEmitted;
1053 break;
1055 default:
1056 // Not a % token after all... skip it
1057 if (!emit("%", 1)) {
1058 return false;
1060 if (!emit(fmt - 1, 1)) {
1061 return false;
1066 return true;
1069 /************************************************************************/
1071 bool mozilla::PrintfTarget::print(const char* format, ...) {
1072 va_list ap;
1074 va_start(ap, format);
1075 bool result = vprint(format, ap);
1076 va_end(ap);
1077 return result;
1080 #undef TYPE_SHORT
1081 #undef TYPE_USHORT
1082 #undef TYPE_INTN
1083 #undef TYPE_UINTN
1084 #undef TYPE_LONG
1085 #undef TYPE_ULONG
1086 #undef TYPE_LONGLONG
1087 #undef TYPE_ULONGLONG
1088 #undef TYPE_STRING
1089 #undef TYPE_DOUBLE
1090 #undef TYPE_INTSTR
1091 #undef TYPE_POINTER
1092 #undef TYPE_WSTRING
1093 #undef TYPE_UNKNOWN
1094 #undef TYPE_SCHAR
1095 #undef TYPE_UCHAR
1097 #undef FLAG_LEFT
1098 #undef FLAG_SIGNED
1099 #undef FLAG_SPACED
1100 #undef FLAG_ZEROS
1101 #undef FLAG_NEG