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/. */
6 
7 /*
8  * Portable safe sprintf code.
9  *
10  * Author: Kipp E.B. Hickman
11  */
12 
13 #include "double-conversion/double-conversion.h"
14 #include "mozilla/AllocPolicy.h"
15 #include "mozilla/Likely.h"
16 #include "mozilla/Printf.h"
17 #include "mozilla/Sprintf.h"
18 #include "mozilla/UniquePtrExtensions.h"
19 #include "mozilla/Vector.h"
20 
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #if defined(XP_WIN)
27 #  include <windows.h>
28 #endif
29 
30 using double_conversion::DoubleToStringConverter;
31 using DTSC = DoubleToStringConverter;
32 
33 /*
34  * Note: on some platforms va_list is defined as an array,
35  * and requires array notation.
36  */
37 #ifdef HAVE_VA_COPY
38 #  define VARARGS_ASSIGN(foo, bar) VA_COPY(foo, bar)
39 #elif defined(HAVE_VA_LIST_AS_ARRAY)
40 #  define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]
41 #else
42 #  define VARARGS_ASSIGN(foo, bar) (foo) = (bar)
43 #endif
44 
45 /*
46  * Numbered Argument State
47  */
48 struct NumArgState {
49   int type;    // type of the current ap
50   va_list ap;  // point to the corresponding position on ap
51 };
52 
53 using NumArgStateVector =
54     mozilla::Vector<NumArgState, 20, mozilla::MallocAllocPolicy>;
55 
56 // For values up to and including TYPE_DOUBLE, the lowest bit indicates
57 // whether the type is signed (0) or unsigned (1).
58 #define TYPE_SHORT 0
59 #define TYPE_USHORT 1
60 #define TYPE_INTN 2
61 #define TYPE_UINTN 3
62 #define TYPE_LONG 4
63 #define TYPE_ULONG 5
64 #define TYPE_LONGLONG 6
65 #define TYPE_ULONGLONG 7
66 #define TYPE_DOUBLE 8
67 #define TYPE_STRING 9
68 #define TYPE_INTSTR 10
69 #define TYPE_POINTER 11
70 #if defined(XP_WIN)
71 #  define TYPE_WSTRING 12
72 #endif
73 #define TYPE_SCHAR 14
74 #define TYPE_UCHAR 15
75 #define TYPE_UNKNOWN 20
76 
77 #define FLAG_LEFT 0x1
78 #define FLAG_SIGNED 0x2
79 #define FLAG_SPACED 0x4
80 #define FLAG_ZEROS 0x8
81 #define FLAG_NEG 0x10
82 
83 static const char hex[] = "0123456789abcdef";
84 static const char HEX[] = "0123456789ABCDEF";
85 
86 // Fill into the buffer using the data in src
fill2(const char * src,int srclen,int width,int flags)87 bool mozilla::PrintfTarget::fill2(const char* src, int srclen, int width,
88                                   int flags) {
89   char space = ' ';
90 
91   width -= srclen;
92   if (width > 0 && (flags & FLAG_LEFT) == 0) {  // Right adjusting
93     if (flags & FLAG_ZEROS) {
94       space = '0';
95     }
96     while (--width >= 0) {
97       if (!emit(&space, 1)) {
98         return false;
99       }
100     }
101   }
102 
103   // Copy out the source data
104   if (!emit(src, srclen)) {
105     return false;
106   }
107 
108   if (width > 0 && (flags & FLAG_LEFT) != 0) {  // Left adjusting
109     while (--width >= 0) {
110       if (!emit(&space, 1)) {
111         return false;
112       }
113     }
114   }
115   return true;
116 }
117 
118 /*
119  * Fill a number. The order is: optional-sign zero-filling conversion-digits
120  */
fill_n(const char * src,int srclen,int width,int prec,int type,int flags)121 bool mozilla::PrintfTarget::fill_n(const char* src, int srclen, int width,
122                                    int prec, int type, int flags) {
123   int zerowidth = 0;
124   int precwidth = 0;
125   int signwidth = 0;
126   int leftspaces = 0;
127   int rightspaces = 0;
128   int cvtwidth;
129   char sign;
130 
131   if ((type & 1) == 0) {
132     if (flags & FLAG_NEG) {
133       sign = '-';
134       signwidth = 1;
135     } else if (flags & FLAG_SIGNED) {
136       sign = '+';
137       signwidth = 1;
138     } else if (flags & FLAG_SPACED) {
139       sign = ' ';
140       signwidth = 1;
141     }
142   }
143   cvtwidth = signwidth + srclen;
144 
145   if (prec > 0 && (type != TYPE_DOUBLE)) {
146     if (prec > srclen) {
147       precwidth = prec - srclen;  // Need zero filling
148       cvtwidth += precwidth;
149     }
150   }
151 
152   if ((flags & FLAG_ZEROS) && ((type == TYPE_DOUBLE) || (prec < 0))) {
153     if (width > cvtwidth) {
154       zerowidth = width - cvtwidth;  // Zero filling
155       cvtwidth += zerowidth;
156     }
157   }
158 
159   if (flags & FLAG_LEFT) {
160     if (width > cvtwidth) {
161       // Space filling on the right (i.e. left adjusting)
162       rightspaces = width - cvtwidth;
163     }
164   } else {
165     if (width > cvtwidth) {
166       // Space filling on the left (i.e. right adjusting)
167       leftspaces = width - cvtwidth;
168     }
169   }
170   while (--leftspaces >= 0) {
171     if (!emit(" ", 1)) {
172       return false;
173     }
174   }
175   if (signwidth) {
176     if (!emit(&sign, 1)) {
177       return false;
178     }
179   }
180   while (--precwidth >= 0) {
181     if (!emit("0", 1)) {
182       return false;
183     }
184   }
185   while (--zerowidth >= 0) {
186     if (!emit("0", 1)) {
187       return false;
188     }
189   }
190   if (!emit(src, uint32_t(srclen))) {
191     return false;
192   }
193   while (--rightspaces >= 0) {
194     if (!emit(" ", 1)) {
195       return false;
196     }
197   }
198   return true;
199 }
200 
201 // All that the cvt_* functions care about as far as the TYPE_* constants is
202 // that the low bit is set to indicate unsigned, or unset to indicate signed.
203 // So we don't try to hard to ensure that the passed TYPE_* constant lines
204 // up with the actual size of the number being printed here.  The main printf
205 // code, below, does have to care so that the correct bits are extracted from
206 // the varargs list.
appendIntDec(int32_t num)207 bool mozilla::PrintfTarget::appendIntDec(int32_t num) {
208   int flags = 0;
209   long n = num;
210   if (n < 0) {
211     n = -n;
212     flags |= FLAG_NEG;
213   }
214   return cvt_l(n, -1, -1, 10, TYPE_INTN, flags, hex);
215 }
216 
appendIntDec(uint32_t num)217 bool mozilla::PrintfTarget::appendIntDec(uint32_t num) {
218   return cvt_l(num, -1, -1, 10, TYPE_UINTN, 0, hex);
219 }
220 
appendIntOct(uint32_t num)221 bool mozilla::PrintfTarget::appendIntOct(uint32_t num) {
222   return cvt_l(num, -1, -1, 8, TYPE_UINTN, 0, hex);
223 }
224 
appendIntHex(uint32_t num)225 bool mozilla::PrintfTarget::appendIntHex(uint32_t num) {
226   return cvt_l(num, -1, -1, 16, TYPE_UINTN, 0, hex);
227 }
228 
appendIntDec(int64_t num)229 bool mozilla::PrintfTarget::appendIntDec(int64_t num) {
230   int flags = 0;
231   if (num < 0) {
232     num = -num;
233     flags |= FLAG_NEG;
234   }
235   return cvt_ll(num, -1, -1, 10, TYPE_INTN, flags, hex);
236 }
237 
appendIntDec(uint64_t num)238 bool mozilla::PrintfTarget::appendIntDec(uint64_t num) {
239   return cvt_ll(num, -1, -1, 10, TYPE_UINTN, 0, hex);
240 }
241 
appendIntOct(uint64_t num)242 bool mozilla::PrintfTarget::appendIntOct(uint64_t num) {
243   return cvt_ll(num, -1, -1, 8, TYPE_UINTN, 0, hex);
244 }
245 
appendIntHex(uint64_t num)246 bool mozilla::PrintfTarget::appendIntHex(uint64_t num) {
247   return cvt_ll(num, -1, -1, 16, TYPE_UINTN, 0, hex);
248 }
249 
250 /* Convert a long into its printable form. */
cvt_l(long num,int width,int prec,int radix,int type,int flags,const char * hexp)251 bool mozilla::PrintfTarget::cvt_l(long num, int width, int prec, int radix,
252                                   int type, int flags, const char* hexp) {
253   char cvtbuf[100];
254   char* cvt;
255   int digits;
256 
257   // according to the man page this needs to happen
258   if ((prec == 0) && (num == 0)) {
259     return fill_n("", 0, width, prec, type, flags);
260   }
261 
262   // Converting decimal is a little tricky. In the unsigned case we
263   // need to stop when we hit 10 digits. In the signed case, we can
264   // stop when the number is zero.
265   cvt = cvtbuf + sizeof(cvtbuf);
266   digits = 0;
267   while (num) {
268     int digit = (((unsigned long)num) % radix) & 0xF;
269     *--cvt = hexp[digit];
270     digits++;
271     num = (long)(((unsigned long)num) / radix);
272   }
273   if (digits == 0) {
274     *--cvt = '0';
275     digits++;
276   }
277 
278   // Now that we have the number converted without its sign, deal with
279   // the sign and zero padding.
280   return fill_n(cvt, digits, width, prec, type, flags);
281 }
282 
283 /* Convert a 64-bit integer into its printable form. */
cvt_ll(int64_t num,int width,int prec,int radix,int type,int flags,const char * hexp)284 bool mozilla::PrintfTarget::cvt_ll(int64_t num, int width, int prec, int radix,
285                                    int type, int flags, const char* hexp) {
286   // According to the man page, this needs to happen.
287   if (prec == 0 && num == 0) {
288     return fill_n("", 0, width, prec, type, flags);
289   }
290 
291   // Converting decimal is a little tricky. In the unsigned case we
292   // need to stop when we hit 10 digits. In the signed case, we can
293   // stop when the number is zero.
294   int64_t rad = int64_t(radix);
295   char cvtbuf[100];
296   char* cvt = cvtbuf + sizeof(cvtbuf);
297   int digits = 0;
298   while (num != 0) {
299     int64_t quot = uint64_t(num) / rad;
300     int64_t rem = uint64_t(num) % rad;
301     int32_t digit = int32_t(rem);
302     *--cvt = hexp[digit & 0xf];
303     digits++;
304     num = quot;
305   }
306   if (digits == 0) {
307     *--cvt = '0';
308     digits++;
309   }
310 
311   // Now that we have the number converted without its sign, deal with
312   // the sign and zero padding.
313   return fill_n(cvt, digits, width, prec, type, flags);
314 }
315 
316 template <size_t N>
lengthof(const char (&)[N])317 constexpr static size_t lengthof(const char (&)[N]) {
318   return N - 1;
319 }
320 
321 // Longest possible output from ToFixed for positive numbers:
322 // [0-9]{kMaxFixedDigitsBeforePoint}\.[0-9]{kMaxFixedDigitsAfterPoint}?
323 constexpr int FIXED_MAX_CHARS =
324     DTSC::kMaxFixedDigitsBeforePoint + 1 + DTSC::kMaxFixedDigitsAfterPoint;
325 
326 // Longest possible output from ToExponential:
327 // [1-9]\.[0-9]{kMaxExponentialDigits}e[+-][0-9]{1,3}
328 // (std::numeric_limits<double>::max() has exponent 308).
329 constexpr int EXPONENTIAL_MAX_CHARS =
330     lengthof("1.") + DTSC::kMaxExponentialDigits + lengthof("e+999");
331 
332 // Longest possible output from ToPrecise:
333 // [0-9\.]{kMaxPrecisionDigits+1} or
334 // [1-9]\.[0-9]{kMaxPrecisionDigits-1}e[+-][0-9]{1,3}
335 constexpr int PRECISE_MAX_CHARS =
336     lengthof("1.") + DTSC::kMaxPrecisionDigits - 1 + lengthof("e+999");
337 
338 constexpr int DTSC_MAX_CHARS =
339     std::max({FIXED_MAX_CHARS, EXPONENTIAL_MAX_CHARS, PRECISE_MAX_CHARS});
340 
341 /*
342  * Convert a double precision floating point number into its printable
343  * form.
344  */
cvt_f(double d,char c,int width,int prec,int flags)345 bool mozilla::PrintfTarget::cvt_f(double d, char c, int width, int prec,
346                                   int flags) {
347   bool lower = islower(c);
348   const char* inf = lower ? "inf" : "INF";
349   const char* nan = lower ? "nan" : "NAN";
350   char e = lower ? 'e' : 'E';
351   DoubleToStringConverter converter(DTSC::UNIQUE_ZERO | DTSC::NO_TRAILING_ZERO |
352                                         DTSC::EMIT_POSITIVE_EXPONENT_SIGN,
353                                     inf, nan, e, 0, 0, 4, 0, 2);
354   // Longest of the above cases, plus space for a terminal nul character.
355   char buf[DTSC_MAX_CHARS + 1];
356   double_conversion::StringBuilder builder(buf, sizeof(buf));
357   bool success = false;
358   if (std::signbit(d)) {
359     d = std::abs(d);
360     flags |= FLAG_NEG;
361   }
362   if (!std::isfinite(d)) {
363     flags &= ~FLAG_ZEROS;
364   }
365   // "If the precision is missing, it shall be taken as 6."
366   if (prec < 0) {
367     prec = 6;
368   }
369   switch (c) {
370     case 'e':
371     case 'E':
372       success = converter.ToExponential(d, prec, &builder);
373       break;
374     case 'f':
375     case 'F':
376       success = converter.ToFixed(d, prec, &builder);
377       break;
378     case 'g':
379     case 'G':
380       // "If an explicit precision is zero, it shall be taken as 1."
381       success = converter.ToPrecision(d, prec ? prec : 1, &builder);
382       break;
383   }
384   if (!success) {
385     return false;
386   }
387   int len = builder.position();
388   char* cvt = builder.Finalize();
389   return fill_n(cvt, len, width, prec, TYPE_DOUBLE, flags);
390 }
391 
392 /*
393  * Convert a string into its printable form.  "width" is the output
394  * width. "prec" is the maximum number of characters of "s" to output,
395  * where -1 means until NUL.
396  */
cvt_s(const char * s,int width,int prec,int flags)397 bool mozilla::PrintfTarget::cvt_s(const char* s, int width, int prec,
398                                   int flags) {
399   if (prec == 0) {
400     return true;
401   }
402   if (!s) {
403     s = "(null)";
404   }
405 
406   // Limit string length by precision value
407   int slen = int(strlen(s));
408   if (0 < prec && prec < slen) {
409     slen = prec;
410   }
411 
412   // and away we go
413   return fill2(s, slen, width, flags);
414 }
415 
416 /*
417  * BuildArgArray stands for Numbered Argument list Sprintf
418  * for example,
419  *      fmp = "%4$i, %2$d, %3s, %1d";
420  * the number must start from 1, and no gap among them
421  */
BuildArgArray(const char * fmt,va_list ap,NumArgStateVector & nas)422 static bool BuildArgArray(const char* fmt, va_list ap, NumArgStateVector& nas) {
423   size_t number = 0, cn = 0, i;
424   const char* p;
425   char c;
426 
427   // First pass:
428   // Detemine how many legal % I have got, then allocate space.
429 
430   p = fmt;
431   i = 0;
432   while ((c = *p++) != 0) {
433     if (c != '%') {
434       continue;
435     }
436     if ((c = *p++) == '%') {  // skip %% case
437       continue;
438     }
439 
440     while (c != 0) {
441       if (c > '9' || c < '0') {
442         if (c == '$') {  // numbered argument case
443           if (i > 0) {
444             MOZ_CRASH("Bad format string");
445           }
446           number++;
447         } else {  // non-numbered argument case
448           if (number > 0) {
449             MOZ_CRASH("Bad format string");
450           }
451           i = 1;
452         }
453         break;
454       }
455 
456       c = *p++;
457     }
458   }
459 
460   if (number == 0) {
461     return true;
462   }
463 
464   // Only allow a limited number of arguments.
465   MOZ_RELEASE_ASSERT(number <= 20);
466 
467   if (!nas.growByUninitialized(number)) {
468     return false;
469   }
470 
471   for (i = 0; i < number; i++) {
472     nas[i].type = TYPE_UNKNOWN;
473   }
474 
475   // Second pass:
476   // Set nas[].type.
477 
478   p = fmt;
479   while ((c = *p++) != 0) {
480     if (c != '%') {
481       continue;
482     }
483     c = *p++;
484     if (c == '%') {
485       continue;
486     }
487 
488     cn = 0;
489     while (c && c != '$') {  // should improve error check later
490       cn = cn * 10 + c - '0';
491       c = *p++;
492     }
493 
494     if (!c || cn < 1 || cn > number) {
495       MOZ_CRASH("Bad format string");
496     }
497 
498     // nas[cn] starts from 0, and make sure nas[cn].type is not assigned.
499     cn--;
500     if (nas[cn].type != TYPE_UNKNOWN) {
501       continue;
502     }
503 
504     c = *p++;
505 
506     // flags
507     while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
508       c = *p++;
509     }
510 
511     // width
512     if (c == '*') {
513       // not supported feature, for the argument is not numbered
514       MOZ_CRASH("Bad format string");
515     }
516 
517     while ((c >= '0') && (c <= '9')) {
518       c = *p++;
519     }
520 
521     // precision
522     if (c == '.') {
523       c = *p++;
524       if (c == '*') {
525         // not supported feature, for the argument is not numbered
526         MOZ_CRASH("Bad format string");
527       }
528 
529       while ((c >= '0') && (c <= '9')) {
530         c = *p++;
531       }
532     }
533 
534     // size
535     nas[cn].type = TYPE_INTN;
536     if (c == 'h') {
537       nas[cn].type = TYPE_SHORT;
538       c = *p++;
539       if (c == 'h') {
540         nas[cn].type = TYPE_SCHAR;
541         c = *p++;
542       }
543     } else if (c == 'L') {
544       nas[cn].type = TYPE_LONGLONG;
545       c = *p++;
546     } else if (c == 'l') {
547       nas[cn].type = TYPE_LONG;
548       c = *p++;
549       if (c == 'l') {
550         nas[cn].type = TYPE_LONGLONG;
551         c = *p++;
552       }
553     } else if (c == 'z' || c == 'I') {
554       static_assert(sizeof(size_t) == sizeof(int) ||
555                         sizeof(size_t) == sizeof(long) ||
556                         sizeof(size_t) == sizeof(long long),
557                     "size_t is not one of the expected sizes");
558       nas[cn].type = sizeof(size_t) == sizeof(int)    ? TYPE_INTN
559                      : sizeof(size_t) == sizeof(long) ? TYPE_LONG
560                                                       : TYPE_LONGLONG;
561       c = *p++;
562     } else if (c == 't') {
563       static_assert(sizeof(ptrdiff_t) == sizeof(int) ||
564                         sizeof(ptrdiff_t) == sizeof(long) ||
565                         sizeof(ptrdiff_t) == sizeof(long long),
566                     "ptrdiff_t is not one of the expected sizes");
567       nas[cn].type = sizeof(ptrdiff_t) == sizeof(int)    ? TYPE_INTN
568                      : sizeof(ptrdiff_t) == sizeof(long) ? TYPE_LONG
569                                                          : TYPE_LONGLONG;
570       c = *p++;
571     } else if (c == 'j') {
572       static_assert(sizeof(intmax_t) == sizeof(int) ||
573                         sizeof(intmax_t) == sizeof(long) ||
574                         sizeof(intmax_t) == sizeof(long long),
575                     "intmax_t is not one of the expected sizes");
576       nas[cn].type = sizeof(intmax_t) == sizeof(int)    ? TYPE_INTN
577                      : sizeof(intmax_t) == sizeof(long) ? TYPE_LONG
578                                                         : TYPE_LONGLONG;
579       c = *p++;
580     }
581 
582     // format
583     switch (c) {
584       case 'd':
585       case 'c':
586       case 'i':
587         break;
588 
589       case 'o':
590       case 'u':
591       case 'x':
592       case 'X':
593         // Mark as unsigned type.
594         nas[cn].type |= 1;
595         break;
596 
597       case 'e':
598       case 'E':
599       case 'f':
600       case 'F':
601       case 'g':
602       case 'G':
603         nas[cn].type = TYPE_DOUBLE;
604         break;
605 
606       case 'p':
607         nas[cn].type = TYPE_POINTER;
608         break;
609 
610       case 'S':
611 #if defined(XP_WIN)
612         nas[cn].type = TYPE_WSTRING;
613 #else
614         MOZ_ASSERT(0);
615         nas[cn].type = TYPE_UNKNOWN;
616 #endif
617         break;
618 
619       case 's':
620 #if defined(XP_WIN)
621         if (nas[cn].type == TYPE_LONG) {
622           nas[cn].type = TYPE_WSTRING;
623           break;
624         }
625 #endif
626         // Other type sizes are not supported here.
627         MOZ_ASSERT(nas[cn].type == TYPE_INTN);
628         nas[cn].type = TYPE_STRING;
629         break;
630 
631       case 'n':
632         nas[cn].type = TYPE_INTSTR;
633         break;
634 
635       default:
636         MOZ_ASSERT(0);
637         nas[cn].type = TYPE_UNKNOWN;
638         break;
639     }
640 
641     // get a legal para.
642     if (nas[cn].type == TYPE_UNKNOWN) {
643       MOZ_CRASH("Bad format string");
644     }
645   }
646 
647   // Third pass:
648   // Fill nas[].ap.
649 
650   cn = 0;
651   while (cn < number) {
652     // A TYPE_UNKNOWN here means that the format asked for a
653     // positional argument without specifying the meaning of some
654     // earlier argument.
655     MOZ_ASSERT(nas[cn].type != TYPE_UNKNOWN);
656 
657     VARARGS_ASSIGN(nas[cn].ap, ap);
658 
659     switch (nas[cn].type) {
660       case TYPE_SCHAR:
661       case TYPE_UCHAR:
662       case TYPE_SHORT:
663       case TYPE_USHORT:
664       case TYPE_INTN:
665       case TYPE_UINTN:
666         (void)va_arg(ap, int);
667         break;
668       case TYPE_LONG:
669         (void)va_arg(ap, long);
670         break;
671       case TYPE_ULONG:
672         (void)va_arg(ap, unsigned long);
673         break;
674       case TYPE_LONGLONG:
675         (void)va_arg(ap, long long);
676         break;
677       case TYPE_ULONGLONG:
678         (void)va_arg(ap, unsigned long long);
679         break;
680       case TYPE_STRING:
681         (void)va_arg(ap, char*);
682         break;
683       case TYPE_INTSTR:
684         (void)va_arg(ap, int*);
685         break;
686       case TYPE_DOUBLE:
687         (void)va_arg(ap, double);
688         break;
689       case TYPE_POINTER:
690         (void)va_arg(ap, void*);
691         break;
692 #if defined(XP_WIN)
693       case TYPE_WSTRING:
694         (void)va_arg(ap, wchar_t*);
695         break;
696 #endif
697 
698       default:
699         MOZ_CRASH();
700     }
701 
702     cn++;
703   }
704 
705   return true;
706 }
707 
PrintfTarget()708 mozilla::PrintfTarget::PrintfTarget() : mEmitted(0) {}
709 
vprint(const char * fmt,va_list ap)710 bool mozilla::PrintfTarget::vprint(const char* fmt, va_list ap) {
711   char c;
712   int flags, width, prec, radix, type;
713   union {
714     char ch;
715     int i;
716     long l;
717     long long ll;
718     double d;
719     const char* s;
720     int* ip;
721     void* p;
722 #if defined(XP_WIN)
723     const wchar_t* ws;
724 #endif
725   } u{};
726   const char* hexp;
727   int i;
728 
729   // Build an argument array, IF the fmt is numbered argument
730   // list style, to contain the Numbered Argument list pointers.
731 
732   NumArgStateVector nas;
733   if (!BuildArgArray(fmt, ap, nas)) {
734     // the fmt contains error Numbered Argument format, jliu@netscape.com
735     MOZ_CRASH("Bad format string");
736   }
737 
738   while ((c = *fmt++) != 0) {
739     if (c != '%') {
740       if (!emit(fmt - 1, 1)) {
741         return false;
742       }
743 
744       continue;
745     }
746 
747     // Gobble up the % format string. Hopefully we have handled all
748     // of the strange cases!
749     flags = 0;
750     c = *fmt++;
751     if (c == '%') {
752       // quoting a % with %%
753       if (!emit(fmt - 1, 1)) {
754         return false;
755       }
756 
757       continue;
758     }
759 
760     if (!nas.empty()) {
761       // the fmt contains the Numbered Arguments feature
762       i = 0;
763       while (c && c != '$') {  // should improve error check later
764         i = (i * 10) + (c - '0');
765         c = *fmt++;
766       }
767 
768       if (nas[i - 1].type == TYPE_UNKNOWN) {
769         MOZ_CRASH("Bad format string");
770       }
771 
772       ap = nas[i - 1].ap;
773       c = *fmt++;
774     }
775 
776     // Examine optional flags.  Note that we do not implement the
777     // '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
778     // somewhat ambiguous and not ideal, which is perhaps why
779     // the various sprintf() implementations are inconsistent
780     // on this feature.
781     while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
782       if (c == '-') {
783         flags |= FLAG_LEFT;
784       }
785       if (c == '+') {
786         flags |= FLAG_SIGNED;
787       }
788       if (c == ' ') {
789         flags |= FLAG_SPACED;
790       }
791       if (c == '0') {
792         flags |= FLAG_ZEROS;
793       }
794       c = *fmt++;
795     }
796     if (flags & FLAG_SIGNED) {
797       flags &= ~FLAG_SPACED;
798     }
799     if (flags & FLAG_LEFT) {
800       flags &= ~FLAG_ZEROS;
801     }
802 
803     // width
804     if (c == '*') {
805       c = *fmt++;
806       width = va_arg(ap, int);
807       if (width < 0) {
808         width = -width;
809         flags |= FLAG_LEFT;
810         flags &= ~FLAG_ZEROS;
811       }
812     } else {
813       width = 0;
814       while ((c >= '0') && (c <= '9')) {
815         width = (width * 10) + (c - '0');
816         c = *fmt++;
817       }
818     }
819 
820     // precision
821     prec = -1;
822     if (c == '.') {
823       c = *fmt++;
824       if (c == '*') {
825         c = *fmt++;
826         prec = va_arg(ap, int);
827       } else {
828         prec = 0;
829         while ((c >= '0') && (c <= '9')) {
830           prec = (prec * 10) + (c - '0');
831           c = *fmt++;
832         }
833       }
834     }
835 
836     // size
837     type = TYPE_INTN;
838     if (c == 'h') {
839       type = TYPE_SHORT;
840       c = *fmt++;
841       if (c == 'h') {
842         type = TYPE_SCHAR;
843         c = *fmt++;
844       }
845     } else if (c == 'L') {
846       type = TYPE_LONGLONG;
847       c = *fmt++;
848     } else if (c == 'l') {
849       type = TYPE_LONG;
850       c = *fmt++;
851       if (c == 'l') {
852         type = TYPE_LONGLONG;
853         c = *fmt++;
854       }
855     } else if (c == 'z' || c == 'I') {
856       static_assert(sizeof(size_t) == sizeof(int) ||
857                         sizeof(size_t) == sizeof(long) ||
858                         sizeof(size_t) == sizeof(long long),
859                     "size_t is not one of the expected sizes");
860       type = sizeof(size_t) == sizeof(int)    ? TYPE_INTN
861              : sizeof(size_t) == sizeof(long) ? TYPE_LONG
862                                               : TYPE_LONGLONG;
863       c = *fmt++;
864     } else if (c == 't') {
865       static_assert(sizeof(ptrdiff_t) == sizeof(int) ||
866                         sizeof(ptrdiff_t) == sizeof(long) ||
867                         sizeof(ptrdiff_t) == sizeof(long long),
868                     "ptrdiff_t is not one of the expected sizes");
869       type = sizeof(ptrdiff_t) == sizeof(int)    ? TYPE_INTN
870              : sizeof(ptrdiff_t) == sizeof(long) ? TYPE_LONG
871                                                  : TYPE_LONGLONG;
872       c = *fmt++;
873     } else if (c == 'j') {
874       static_assert(sizeof(intmax_t) == sizeof(int) ||
875                         sizeof(intmax_t) == sizeof(long) ||
876                         sizeof(intmax_t) == sizeof(long long),
877                     "intmax_t is not one of the expected sizes");
878       type = sizeof(intmax_t) == sizeof(int)    ? TYPE_INTN
879              : sizeof(intmax_t) == sizeof(long) ? TYPE_LONG
880                                                 : TYPE_LONGLONG;
881       c = *fmt++;
882     }
883 
884     // format
885     hexp = hex;
886     switch (c) {
887       case 'd':
888       case 'i':  // decimal/integer
889         radix = 10;
890         goto fetch_and_convert;
891 
892       case 'o':  // octal
893         radix = 8;
894         type |= 1;
895         goto fetch_and_convert;
896 
897       case 'u':  // unsigned decimal
898         radix = 10;
899         type |= 1;
900         goto fetch_and_convert;
901 
902       case 'x':  // unsigned hex
903         radix = 16;
904         type |= 1;
905         goto fetch_and_convert;
906 
907       case 'X':  // unsigned HEX
908         radix = 16;
909         hexp = HEX;
910         type |= 1;
911         goto fetch_and_convert;
912 
913       fetch_and_convert:
914         switch (type) {
915           case TYPE_SCHAR:
916             u.l = (signed char)va_arg(ap, int);
917             if (u.l < 0) {
918               u.l = -u.l;
919               flags |= FLAG_NEG;
920             }
921             goto do_long;
922           case TYPE_UCHAR:
923             u.l = (unsigned char)va_arg(ap, unsigned int);
924             goto do_long;
925           case TYPE_SHORT:
926             u.l = (short)va_arg(ap, int);
927             if (u.l < 0) {
928               u.l = -u.l;
929               flags |= FLAG_NEG;
930             }
931             goto do_long;
932           case TYPE_USHORT:
933             u.l = (unsigned short)va_arg(ap, unsigned int);
934             goto do_long;
935           case TYPE_INTN:
936             u.l = va_arg(ap, int);
937             if (u.l < 0) {
938               u.l = -u.l;
939               flags |= FLAG_NEG;
940             }
941             goto do_long;
942           case TYPE_UINTN:
943             u.l = (long)va_arg(ap, unsigned int);
944             goto do_long;
945 
946           case TYPE_LONG:
947             u.l = va_arg(ap, long);
948             if (u.l < 0) {
949               u.l = -u.l;
950               flags |= FLAG_NEG;
951             }
952             goto do_long;
953           case TYPE_ULONG:
954             u.l = (long)va_arg(ap, unsigned long);
955           do_long:
956             if (!cvt_l(u.l, width, prec, radix, type, flags, hexp)) {
957               return false;
958             }
959 
960             break;
961 
962           case TYPE_LONGLONG:
963             u.ll = va_arg(ap, long long);
964             if (u.ll < 0) {
965               u.ll = -u.ll;
966               flags |= FLAG_NEG;
967             }
968             goto do_longlong;
969           case TYPE_POINTER:
970             u.ll = (uintptr_t)va_arg(ap, void*);
971             goto do_longlong;
972           case TYPE_ULONGLONG:
973             u.ll = va_arg(ap, unsigned long long);
974           do_longlong:
975             if (!cvt_ll(u.ll, width, prec, radix, type, flags, hexp)) {
976               return false;
977             }
978 
979             break;
980         }
981         break;
982 
983       case 'e':
984       case 'E':
985       case 'f':
986       case 'F':
987       case 'g':
988       case 'G':
989         u.d = va_arg(ap, double);
990         if (!cvt_f(u.d, c, width, prec, flags)) {
991           return false;
992         }
993 
994         break;
995 
996       case 'c':
997         if ((flags & FLAG_LEFT) == 0) {
998           while (width-- > 1) {
999             if (!emit(" ", 1)) {
1000               return false;
1001             }
1002           }
1003         }
1004         switch (type) {
1005           case TYPE_SHORT:
1006           case TYPE_INTN:
1007             u.ch = va_arg(ap, int);
1008             if (!emit(&u.ch, 1)) {
1009               return false;
1010             }
1011             break;
1012         }
1013         if (flags & FLAG_LEFT) {
1014           while (width-- > 1) {
1015             if (!emit(" ", 1)) {
1016               return false;
1017             }
1018           }
1019         }
1020         break;
1021 
1022       case 'p':
1023         type = TYPE_POINTER;
1024         radix = 16;
1025         goto fetch_and_convert;
1026 
1027       case 's':
1028         if (type == TYPE_INTN) {
1029           u.s = va_arg(ap, const char*);
1030           if (!cvt_s(u.s, width, prec, flags)) {
1031             return false;
1032           }
1033           break;
1034         }
1035         MOZ_ASSERT(type == TYPE_LONG);
1036         [[fallthrough]];
1037       case 'S':
1038 #if defined(XP_WIN)
1039       {
1040         u.ws = va_arg(ap, const wchar_t*);
1041 
1042         int rv = WideCharToMultiByte(CP_ACP, 0, u.ws, -1, NULL, 0, NULL, NULL);
1043         if (rv == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
1044           if (!cvt_s("<unicode errors in string>", width, prec, flags)) {
1045             return false;
1046           }
1047         } else {
1048           if (rv == 0) {
1049             rv = 1;
1050           }
1051           UniqueFreePtr<char[]> buf((char*)malloc(rv));
1052           WideCharToMultiByte(CP_ACP, 0, u.ws, -1, buf.get(), rv, NULL, NULL);
1053           buf[rv - 1] = '\0';
1054 
1055           if (!cvt_s(buf.get(), width, prec, flags)) {
1056             return false;
1057           }
1058         }
1059       }
1060 #else
1061         // Not supported here.
1062         MOZ_ASSERT(0);
1063 #endif
1064       break;
1065 
1066       case 'n':
1067         u.ip = va_arg(ap, int*);
1068         if (u.ip) {
1069           *u.ip = mEmitted;
1070         }
1071         break;
1072 
1073       default:
1074         // Not a % token after all... skip it
1075         if (!emit("%", 1)) {
1076           return false;
1077         }
1078         if (!emit(fmt - 1, 1)) {
1079           return false;
1080         }
1081     }
1082   }
1083 
1084   return true;
1085 }
1086 
1087 /************************************************************************/
1088 
print(const char * format,...)1089 bool mozilla::PrintfTarget::print(const char* format, ...) {
1090   va_list ap;
1091 
1092   va_start(ap, format);
1093   bool result = vprint(format, ap);
1094   va_end(ap);
1095   return result;
1096 }
1097 
1098 #undef TYPE_SHORT
1099 #undef TYPE_USHORT
1100 #undef TYPE_INTN
1101 #undef TYPE_UINTN
1102 #undef TYPE_LONG
1103 #undef TYPE_ULONG
1104 #undef TYPE_LONGLONG
1105 #undef TYPE_ULONGLONG
1106 #undef TYPE_STRING
1107 #undef TYPE_DOUBLE
1108 #undef TYPE_INTSTR
1109 #undef TYPE_POINTER
1110 #undef TYPE_WSTRING
1111 #undef TYPE_UNKNOWN
1112 #undef TYPE_SCHAR
1113 #undef TYPE_UCHAR
1114 
1115 #undef FLAG_LEFT
1116 #undef FLAG_SIGNED
1117 #undef FLAG_SPACED
1118 #undef FLAG_ZEROS
1119 #undef FLAG_NEG
1120