LCOV - code coverage report
Current view: top level - mozglue/misc - Printf.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 188 401 46.9 %
Date: 2017-07-14 16:53:18 Functions: 9 10 90.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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 "mozilla/AllocPolicy.h"
      14             : #include "mozilla/Printf.h"
      15             : #include "mozilla/Sprintf.h"
      16             : #include "mozilla/UniquePtrExtensions.h"
      17             : #include "mozilla/Vector.h"
      18             : 
      19             : #include <stdarg.h>
      20             : #include <stdio.h>
      21             : #include <stdlib.h>
      22             : #include <string.h>
      23             : 
      24             : #if defined(XP_WIN)
      25             : #include <windows.h>
      26             : #endif
      27             : 
      28             : /*
      29             :  * Note: on some platforms va_list is defined as an array,
      30             :  * and requires array notation.
      31             :  */
      32             : #ifdef HAVE_VA_COPY
      33             : #define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo, bar)
      34             : #elif defined(HAVE_VA_LIST_AS_ARRAY)
      35             : #define VARARGS_ASSIGN(foo, bar)        foo[0] = bar[0]
      36             : #else
      37             : #define VARARGS_ASSIGN(foo, bar)        (foo) = (bar)
      38             : #endif
      39             : 
      40             : /*
      41             :  * Numbered Argument State
      42             :  */
      43             : struct NumArgState
      44             : {
      45             :     int type;       // type of the current ap
      46             :     va_list ap;     // point to the corresponding position on ap
      47             : };
      48             : 
      49             : typedef mozilla::Vector<NumArgState, 20, mozilla::MallocAllocPolicy> NumArgStateVector;
      50             : 
      51             : 
      52             : #define TYPE_SHORT      0
      53             : #define TYPE_USHORT     1
      54             : #define TYPE_INTN       2
      55             : #define TYPE_UINTN      3
      56             : #define TYPE_LONG       4
      57             : #define TYPE_ULONG      5
      58             : #define TYPE_LONGLONG   6
      59             : #define TYPE_ULONGLONG  7
      60             : #define TYPE_STRING     8
      61             : #define TYPE_DOUBLE     9
      62             : #define TYPE_INTSTR     10
      63             : #define TYPE_POINTER    11
      64             : #if defined(XP_WIN)
      65             : #define TYPE_WSTRING    12
      66             : #endif
      67             : #define TYPE_UNKNOWN    20
      68             : 
      69             : #define FLAG_LEFT       0x1
      70             : #define FLAG_SIGNED     0x2
      71             : #define FLAG_SPACED     0x4
      72             : #define FLAG_ZEROS      0x8
      73             : #define FLAG_NEG        0x10
      74             : 
      75             : // Fill into the buffer using the data in src
      76             : bool
      77        8436 : mozilla::PrintfTarget::fill2(const char* src, int srclen, int width, int flags)
      78             : {
      79        8436 :     char space = ' ';
      80             : 
      81        8436 :     width -= srclen;
      82        8436 :     if (width > 0 && (flags & FLAG_LEFT) == 0) {    // Right adjusting
      83           0 :         if (flags & FLAG_ZEROS)
      84           0 :             space = '0';
      85           0 :         while (--width >= 0) {
      86           0 :             if (!emit(&space, 1))
      87           0 :                 return false;
      88             :         }
      89             :     }
      90             : 
      91             :     // Copy out the source data
      92        8436 :     if (!emit(src, srclen))
      93           0 :         return false;
      94             : 
      95        8436 :     if (width > 0 && (flags & FLAG_LEFT) != 0) {    // Left adjusting
      96           0 :         while (--width >= 0) {
      97           0 :             if (!emit(&space, 1))
      98           0 :                 return false;
      99             :         }
     100             :     }
     101        8436 :     return true;
     102             : }
     103             : 
     104             : /*
     105             :  * Fill a number. The order is: optional-sign zero-filling conversion-digits
     106             :  */
     107             : bool
     108       15184 : mozilla::PrintfTarget::fill_n(const char* src, int srclen, int width, int prec, int type, int flags)
     109             : {
     110       15184 :     int zerowidth = 0;
     111       15184 :     int precwidth = 0;
     112       15184 :     int signwidth = 0;
     113       15184 :     int leftspaces = 0;
     114       15184 :     int rightspaces = 0;
     115             :     int cvtwidth;
     116             :     char sign;
     117             : 
     118       15184 :     if ((type & 1) == 0) {
     119         733 :         if (flags & FLAG_NEG) {
     120          13 :             sign = '-';
     121          13 :             signwidth = 1;
     122         720 :         } else if (flags & FLAG_SIGNED) {
     123           0 :             sign = '+';
     124           0 :             signwidth = 1;
     125         720 :         } else if (flags & FLAG_SPACED) {
     126           0 :             sign = ' ';
     127           0 :             signwidth = 1;
     128             :         }
     129             :     }
     130       15184 :     cvtwidth = signwidth + srclen;
     131             : 
     132       15184 :     if (prec > 0) {
     133           1 :         if (prec > srclen) {
     134           0 :             precwidth = prec - srclen;          // Need zero filling
     135           0 :             cvtwidth += precwidth;
     136             :         }
     137             :     }
     138             : 
     139       15184 :     if ((flags & FLAG_ZEROS) && (prec < 0)) {
     140          18 :         if (width > cvtwidth) {
     141           8 :             zerowidth = width - cvtwidth;       // Zero filling
     142           8 :             cvtwidth += zerowidth;
     143             :         }
     144             :     }
     145             : 
     146       15184 :     if (flags & FLAG_LEFT) {
     147           0 :         if (width > cvtwidth) {
     148             :             // Space filling on the right (i.e. left adjusting)
     149           0 :             rightspaces = width - cvtwidth;
     150             :         }
     151             :     } else {
     152       15184 :         if (width > cvtwidth) {
     153             :             // Space filling on the left (i.e. right adjusting)
     154           0 :             leftspaces = width - cvtwidth;
     155             :         }
     156             :     }
     157       15184 :     while (--leftspaces >= 0) {
     158           0 :         if (!emit(" ", 1))
     159           0 :             return false;
     160             :     }
     161       15184 :     if (signwidth) {
     162          13 :         if (!emit(&sign, 1))
     163           0 :             return false;
     164             :     }
     165       15184 :     while (--precwidth >= 0) {
     166           0 :         if (!emit("0", 1))
     167           0 :             return false;
     168             :     }
     169       15200 :     while (--zerowidth >= 0) {
     170           8 :         if (!emit("0", 1))
     171           0 :             return false;
     172             :     }
     173       15184 :     if (!emit(src, uint32_t(srclen)))
     174           0 :         return false;
     175       15184 :     while (--rightspaces >= 0) {
     176           0 :         if (!emit(" ", 1))
     177           0 :             return false;
     178             :     }
     179       15184 :     return true;
     180             : }
     181             : 
     182             : /* Convert a long into its printable form. */
     183             : bool
     184       15116 : mozilla::PrintfTarget::cvt_l(long num, int width, int prec, int radix,
     185             :                              int type, int flags, const char* hexp)
     186             : {
     187             :     char cvtbuf[100];
     188             :     char* cvt;
     189             :     int digits;
     190             : 
     191             :     // according to the man page this needs to happen
     192       15116 :     if ((prec == 0) && (num == 0))
     193           0 :         return true;
     194             : 
     195             :     // Converting decimal is a little tricky. In the unsigned case we
     196             :     // need to stop when we hit 10 digits. In the signed case, we can
     197             :     // stop when the number is zero.
     198       15116 :     cvt = cvtbuf + sizeof(cvtbuf);
     199       15116 :     digits = 0;
     200       96834 :     while (num) {
     201       40859 :         int digit = (((unsigned long)num) % radix) & 0xF;
     202       40859 :         *--cvt = hexp[digit];
     203       40859 :         digits++;
     204       40859 :         num = (long)(((unsigned long)num) / radix);
     205             :     }
     206       15116 :     if (digits == 0) {
     207        4253 :         *--cvt = '0';
     208        4253 :         digits++;
     209             :     }
     210             : 
     211             :     // Now that we have the number converted without its sign, deal with
     212             :     // the sign and zero padding.
     213       15116 :     return fill_n(cvt, digits, width, prec, type, flags);
     214             : }
     215             : 
     216             : /* Convert a 64-bit integer into its printable form. */
     217             : bool
     218          68 : mozilla::PrintfTarget::cvt_ll(int64_t num, int width, int prec, int radix,
     219             :                               int type, int flags, const char* hexp)
     220             : {
     221             :     // According to the man page, this needs to happen.
     222          68 :     if (prec == 0 && num == 0)
     223           0 :         return true;
     224             : 
     225             :     // Converting decimal is a little tricky. In the unsigned case we
     226             :     // need to stop when we hit 10 digits. In the signed case, we can
     227             :     // stop when the number is zero.
     228          68 :     int64_t rad = int64_t(radix);
     229             :     char cvtbuf[100];
     230          68 :     char* cvt = cvtbuf + sizeof(cvtbuf);
     231          68 :     int digits = 0;
     232         620 :     while (num != 0) {
     233         276 :         int64_t quot = uint64_t(num) / rad;
     234         276 :         int64_t rem = uint64_t(num) % rad;
     235         276 :         int32_t digit = int32_t(rem);
     236         276 :         *--cvt = hexp[digit & 0xf];
     237         276 :         digits++;
     238         276 :         num = quot;
     239             :     }
     240          68 :     if (digits == 0) {
     241          45 :         *--cvt = '0';
     242          45 :         digits++;
     243             :     }
     244             : 
     245             :     // Now that we have the number converted without its sign, deal with
     246             :     // the sign and zero padding.
     247          68 :     return fill_n(cvt, digits, width, prec, type, flags);
     248             : }
     249             : 
     250             : /*
     251             :  * Convert a double precision floating point number into its printable
     252             :  * form.
     253             :  */
     254             : bool
     255           0 : mozilla::PrintfTarget::cvt_f(double d, const char* fmt0, const char* fmt1)
     256             : {
     257             :     char fin[20];
     258             :     // The size is chosen such that we can print DBL_MAX.  See bug#1350097.
     259             :     char fout[320];
     260           0 :     int amount = fmt1 - fmt0;
     261             : 
     262           0 :     MOZ_ASSERT((amount > 0) && (amount < (int)sizeof(fin)));
     263           0 :     if (amount >= (int)sizeof(fin)) {
     264             :         // Totally bogus % command to sprintf. Just ignore it
     265           0 :         return true;
     266             :     }
     267           0 :     memcpy(fin, fmt0, (size_t)amount);
     268           0 :     fin[amount] = 0;
     269             : 
     270             :     // Convert floating point using the native snprintf code
     271             : #ifdef DEBUG
     272             :     {
     273           0 :         const char* p = fin;
     274           0 :         while (*p) {
     275           0 :             MOZ_ASSERT(*p != 'L');
     276           0 :             p++;
     277             :         }
     278             :     }
     279             : #endif
     280           0 :     size_t len = SprintfLiteral(fout, fin, d);
     281           0 :     MOZ_RELEASE_ASSERT(len <= sizeof(fout));
     282             : 
     283           0 :     return emit(fout, len);
     284             : }
     285             : 
     286             : /*
     287             :  * Convert a string into its printable form.  "width" is the output
     288             :  * width. "prec" is the maximum number of characters of "s" to output,
     289             :  * where -1 means until NUL.
     290             :  */
     291             : bool
     292        8436 : mozilla::PrintfTarget::cvt_s(const char* s, int width, int prec, int flags)
     293             : {
     294        8436 :     if (prec == 0)
     295           0 :         return true;
     296        8436 :     if (!s)
     297           0 :         s = "(null)";
     298             : 
     299             :     // Limit string length by precision value
     300        8436 :     int slen = int(strlen(s));
     301        8436 :     if (0 < prec && prec < slen)
     302           0 :         slen = prec;
     303             : 
     304             :     // and away we go
     305        8436 :     return fill2(s, slen, width, flags);
     306             : }
     307             : 
     308             : /*
     309             :  * BuildArgArray stands for Numbered Argument list Sprintf
     310             :  * for example,
     311             :  *      fmp = "%4$i, %2$d, %3s, %1d";
     312             :  * the number must start from 1, and no gap among them
     313             :  */
     314             : static bool
     315        9199 : BuildArgArray(const char* fmt, va_list ap, NumArgStateVector& nas)
     316             : {
     317        9199 :     size_t number = 0, cn = 0, i;
     318             :     const char* p;
     319             :     char c;
     320             : 
     321             : 
     322             :     // First pass:
     323             :     // Detemine how many legal % I have got, then allocate space.
     324             : 
     325        9199 :     p = fmt;
     326        9199 :     i = 0;
     327      136689 :     while ((c = *p++) != 0) {
     328       63745 :         if (c != '%')
     329       40113 :             continue;
     330       23632 :         if ((c = *p++) == '%')          // skip %% case
     331           0 :             continue;
     332             : 
     333       23704 :         while (c != 0) {
     334       23668 :             if (c > '9' || c < '0') {
     335       23632 :                 if (c == '$') {         // numbered argument case
     336           0 :                     if (i > 0)
     337           0 :                         MOZ_CRASH("Bad format string");
     338           0 :                     number++;
     339             :                 } else {                // non-numbered argument case
     340       23632 :                     if (number > 0)
     341           0 :                         MOZ_CRASH("Bad format string");
     342       23632 :                     i = 1;
     343             :                 }
     344       23632 :                 break;
     345             :             }
     346             : 
     347          36 :             c = *p++;
     348             :         }
     349             :     }
     350             : 
     351        9199 :     if (number == 0)
     352        9199 :         return true;
     353             : 
     354             :     // Only allow a limited number of arguments.
     355           0 :     MOZ_RELEASE_ASSERT(number <= 20);
     356             : 
     357           0 :     if (!nas.growByUninitialized(number))
     358           0 :         return false;
     359             : 
     360           0 :     for (i = 0; i < number; i++)
     361           0 :         nas[i].type = TYPE_UNKNOWN;
     362             : 
     363             : 
     364             :     // Second pass:
     365             :     // Set nas[].type.
     366             : 
     367           0 :     p = fmt;
     368           0 :     while ((c = *p++) != 0) {
     369           0 :         if (c != '%')
     370           0 :             continue;
     371           0 :         c = *p++;
     372           0 :         if (c == '%')
     373           0 :             continue;
     374             : 
     375           0 :         cn = 0;
     376           0 :         while (c && c != '$') {     // should improve error check later
     377           0 :             cn = cn*10 + c - '0';
     378           0 :             c = *p++;
     379             :         }
     380             : 
     381           0 :         if (!c || cn < 1 || cn > number)
     382           0 :             MOZ_CRASH("Bad format string");
     383             : 
     384             :         // nas[cn] starts from 0, and make sure nas[cn].type is not assigned.
     385           0 :         cn--;
     386           0 :         if (nas[cn].type != TYPE_UNKNOWN)
     387           0 :             continue;
     388             : 
     389           0 :         c = *p++;
     390             : 
     391             :         // flags
     392           0 :         while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
     393           0 :             c = *p++;
     394             :         }
     395             : 
     396             :         // width
     397           0 :         if (c == '*') {
     398             :             // not supported feature, for the argument is not numbered
     399           0 :             MOZ_CRASH("Bad format string");
     400             :         }
     401             : 
     402           0 :         while ((c >= '0') && (c <= '9')) {
     403           0 :             c = *p++;
     404             :         }
     405             : 
     406             :         // precision
     407           0 :         if (c == '.') {
     408           0 :             c = *p++;
     409           0 :             if (c == '*') {
     410             :                 // not supported feature, for the argument is not numbered
     411           0 :                 MOZ_CRASH("Bad format string");
     412             :             }
     413             : 
     414           0 :             while ((c >= '0') && (c <= '9')) {
     415           0 :                 c = *p++;
     416             :             }
     417             :         }
     418             : 
     419             :         // size
     420           0 :         nas[cn].type = TYPE_INTN;
     421           0 :         if (c == 'h') {
     422           0 :             nas[cn].type = TYPE_SHORT;
     423           0 :             c = *p++;
     424           0 :         } else if (c == 'L') {
     425           0 :             nas[cn].type = TYPE_LONGLONG;
     426           0 :             c = *p++;
     427           0 :         } else if (c == 'l') {
     428           0 :             nas[cn].type = TYPE_LONG;
     429           0 :             c = *p++;
     430           0 :             if (c == 'l') {
     431           0 :                 nas[cn].type = TYPE_LONGLONG;
     432           0 :                 c = *p++;
     433             :             }
     434           0 :         } else if (c == 'z' || c == 'I') {
     435             :             static_assert(sizeof(size_t) == sizeof(int) || sizeof(size_t) == sizeof(long) ||
     436             :                           sizeof(size_t) == sizeof(long long),
     437             :                           "size_t is not one of the expected sizes");
     438           0 :             nas[cn].type = sizeof(size_t) == sizeof(int) ? TYPE_INTN :
     439             :                 sizeof(size_t) == sizeof(long) ? TYPE_LONG : TYPE_LONGLONG;
     440           0 :             c = *p++;
     441             :         }
     442             : 
     443             :         // format
     444           0 :         switch (c) {
     445             :         case 'd':
     446             :         case 'c':
     447             :         case 'i':
     448           0 :             break;
     449             : 
     450             :         case 'o':
     451             :         case 'u':
     452             :         case 'x':
     453             :         case 'X':
     454             :             // Mark as unsigned type.
     455           0 :             nas[cn].type |= 1;
     456           0 :             break;
     457             : 
     458             :         case 'e':
     459             :         case 'f':
     460             :         case 'g':
     461           0 :             nas[cn].type = TYPE_DOUBLE;
     462           0 :             break;
     463             : 
     464             :         case 'p':
     465           0 :             nas[cn].type = TYPE_POINTER;
     466           0 :             break;
     467             : 
     468             :         case 'S':
     469             : #if defined(XP_WIN)
     470             :             nas[cn].type = TYPE_WSTRING;
     471             : #else
     472           0 :             MOZ_ASSERT(0);
     473             :             nas[cn].type = TYPE_UNKNOWN;
     474             : #endif
     475             :             break;
     476             : 
     477             :         case 's':
     478             : #if defined(XP_WIN)
     479             :             if (nas[cn].type == TYPE_LONG) {
     480             :                 nas[cn].type = TYPE_WSTRING;
     481             :                 break;
     482             :             }
     483             : #endif
     484             :             // Other type sizes are not supported here.
     485           0 :             MOZ_ASSERT (nas[cn].type == TYPE_INTN);
     486           0 :             nas[cn].type = TYPE_STRING;
     487           0 :             break;
     488             : 
     489             :         case 'n':
     490           0 :             nas[cn].type = TYPE_INTSTR;
     491           0 :             break;
     492             : 
     493             :         default:
     494           0 :             MOZ_ASSERT(0);
     495             :             nas[cn].type = TYPE_UNKNOWN;
     496             :             break;
     497             :         }
     498             : 
     499             :         // get a legal para.
     500           0 :         if (nas[cn].type == TYPE_UNKNOWN)
     501           0 :             MOZ_CRASH("Bad format string");
     502             :     }
     503             : 
     504             : 
     505             :     // Third pass:
     506             :     // Fill nas[].ap.
     507             : 
     508           0 :     cn = 0;
     509           0 :     while (cn < number) {
     510             :         // A TYPE_UNKNOWN here means that the format asked for a
     511             :         // positional argument without specifying the meaning of some
     512             :         // earlier argument.
     513           0 :         MOZ_ASSERT (nas[cn].type != TYPE_UNKNOWN);
     514             : 
     515           0 :         VARARGS_ASSIGN(nas[cn].ap, ap);
     516             : 
     517           0 :         switch (nas[cn].type) {
     518             :         case TYPE_SHORT:
     519             :         case TYPE_USHORT:
     520             :         case TYPE_INTN:
     521           0 :         case TYPE_UINTN:        (void) va_arg(ap, int);         break;
     522           0 :         case TYPE_LONG:         (void) va_arg(ap, long);        break;
     523           0 :         case TYPE_ULONG:        (void) va_arg(ap, unsigned long); break;
     524           0 :         case TYPE_LONGLONG:     (void) va_arg(ap, long long);   break;
     525           0 :         case TYPE_ULONGLONG:    (void) va_arg(ap, unsigned long long); break;
     526           0 :         case TYPE_STRING:       (void) va_arg(ap, char*);       break;
     527           0 :         case TYPE_INTSTR:       (void) va_arg(ap, int*);        break;
     528           0 :         case TYPE_DOUBLE:       (void) va_arg(ap, double);      break;
     529           0 :         case TYPE_POINTER:      (void) va_arg(ap, void*);       break;
     530             : #if defined(XP_WIN)
     531             :         case TYPE_WSTRING:      (void) va_arg(ap, wchar_t*);    break;
     532             : #endif
     533             : 
     534           0 :         default: MOZ_CRASH();
     535             :         }
     536             : 
     537           0 :         cn++;
     538             :     }
     539             : 
     540           0 :     return true;
     541             : }
     542             : 
     543        9146 : mozilla::PrintfTarget::PrintfTarget()
     544        9146 :   : mEmitted(0)
     545             : {
     546        9146 : }
     547             : 
     548             : bool
     549        9198 : mozilla::PrintfTarget::vprint(const char* fmt, va_list ap)
     550             : {
     551             :     char c;
     552             :     int flags, width, prec, radix, type;
     553             :     union {
     554             :         char ch;
     555             :         int i;
     556             :         long l;
     557             :         long long ll;
     558             :         double d;
     559             :         const char* s;
     560             :         int* ip;
     561             :         void* p;
     562             : #if defined(XP_WIN)
     563             :         const wchar_t* ws;
     564             : #endif
     565             :     } u;
     566             :     const char* fmt0;
     567             :     static const char hex[] = "0123456789abcdef";
     568             :     static const char HEX[] = "0123456789ABCDEF";
     569             :     const char* hexp;
     570             :     int i;
     571             :     char pattern[20];
     572        9198 :     const char* dolPt = nullptr;  // in "%4$.2f", dolPt will point to '.'
     573             : 
     574             :     // Build an argument array, IF the fmt is numbered argument
     575             :     // list style, to contain the Numbered Argument list pointers.
     576             : 
     577       18397 :     NumArgStateVector nas;
     578        9198 :     if (!BuildArgArray(fmt, ap, nas)) {
     579             :         // the fmt contains error Numbered Argument format, jliu@netscape.com
     580           0 :         MOZ_CRASH("Bad format string");
     581             :     }
     582             : 
     583      136630 :     while ((c = *fmt++) != 0) {
     584       63716 :         if (c != '%') {
     585       40083 :             if (!emit(fmt - 1, 1))
     586           0 :                 return false;
     587             : 
     588       40081 :             continue;
     589             :         }
     590       23633 :         fmt0 = fmt - 1;
     591             : 
     592             :         // Gobble up the % format string. Hopefully we have handled all
     593             :         // of the strange cases!
     594       23633 :         flags = 0;
     595       23633 :         c = *fmt++;
     596       23633 :         if (c == '%') {
     597             :             // quoting a % with %%
     598           0 :             if (!emit(fmt - 1, 1))
     599           0 :                 return false;
     600             : 
     601           0 :             continue;
     602             :         }
     603             : 
     604       23633 :         if (!nas.empty()) {
     605             :             // the fmt contains the Numbered Arguments feature
     606           0 :             i = 0;
     607           0 :             while (c && c != '$') {         // should improve error check later
     608           0 :                 i = (i * 10) + (c - '0');
     609           0 :                 c = *fmt++;
     610             :             }
     611             : 
     612           0 :             if (nas[i - 1].type == TYPE_UNKNOWN)
     613           0 :                 MOZ_CRASH("Bad format string");
     614             : 
     615           0 :             ap = nas[i - 1].ap;
     616           0 :             dolPt = fmt;
     617           0 :             c = *fmt++;
     618             :         }
     619             : 
     620             :         // Examine optional flags.  Note that we do not implement the
     621             :         // '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
     622             :         // somewhat ambiguous and not ideal, which is perhaps why
     623             :         // the various sprintf() implementations are inconsistent
     624             :         // on this feature.
     625       23669 :         while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
     626          18 :             if (c == '-') flags |= FLAG_LEFT;
     627          18 :             if (c == '+') flags |= FLAG_SIGNED;
     628          18 :             if (c == ' ') flags |= FLAG_SPACED;
     629          18 :             if (c == '0') flags |= FLAG_ZEROS;
     630          18 :             c = *fmt++;
     631             :         }
     632       23633 :         if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
     633       23633 :         if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
     634             : 
     635             :         // width
     636       23633 :         if (c == '*') {
     637           0 :             c = *fmt++;
     638           0 :             width = va_arg(ap, int);
     639           0 :             if (width < 0) {
     640           0 :                 width = -width;
     641           0 :                 flags |= FLAG_LEFT;
     642           0 :                 flags &= ~FLAG_ZEROS;
     643             :             }
     644             :         } else {
     645       23633 :             width = 0;
     646       23669 :             while ((c >= '0') && (c <= '9')) {
     647          18 :                 width = (width * 10) + (c - '0');
     648          18 :                 c = *fmt++;
     649             :             }
     650             :         }
     651             : 
     652             :         // precision
     653       23633 :         prec = -1;
     654       23633 :         if (c == '.') {
     655           1 :             c = *fmt++;
     656           1 :             if (c == '*') {
     657           0 :                 c = *fmt++;
     658           0 :                 prec = va_arg(ap, int);
     659             :             } else {
     660           1 :                 prec = 0;
     661           5 :                 while ((c >= '0') && (c <= '9')) {
     662           2 :                     prec = (prec * 10) + (c - '0');
     663           2 :                     c = *fmt++;
     664             :                 }
     665             :             }
     666             :         }
     667             : 
     668             :         // size
     669       23633 :         type = TYPE_INTN;
     670       23633 :         if (c == 'h') {
     671           0 :             type = TYPE_SHORT;
     672           0 :             c = *fmt++;
     673       23633 :         } else if (c == 'L') {
     674           0 :             type = TYPE_LONGLONG;
     675           0 :             c = *fmt++;
     676       23633 :         } else if (c == 'l') {
     677          22 :             type = TYPE_LONG;
     678          22 :             c = *fmt++;
     679          22 :             if (c == 'l') {
     680           0 :                 type = TYPE_LONGLONG;
     681           0 :                 c = *fmt++;
     682             :             }
     683       23611 :         } else if (c == 'z' || c == 'I') {
     684             :             static_assert(sizeof(size_t) == sizeof(int) || sizeof(size_t) == sizeof(long) ||
     685             :                           sizeof(size_t) == sizeof(long long),
     686             :                           "size_t is not one of the expected sizes");
     687           0 :             type = sizeof(size_t) == sizeof(int) ? TYPE_INTN :
     688             :                 sizeof(size_t) == sizeof(long) ? TYPE_LONG : TYPE_LONGLONG;
     689           0 :             c = *fmt++;
     690             :         }
     691             : 
     692             :         // format
     693       23633 :         hexp = hex;
     694       23633 :         switch (c) {
     695             :           case 'd': case 'i':                   // decimal/integer
     696         733 :             radix = 10;
     697         733 :             goto fetch_and_convert;
     698             : 
     699             :           case 'o':                             // octal
     700           0 :             radix = 8;
     701           0 :             type |= 1;
     702           0 :             goto fetch_and_convert;
     703             : 
     704             :           case 'u':                             // unsigned decimal
     705       12385 :             radix = 10;
     706       12385 :             type |= 1;
     707       12385 :             goto fetch_and_convert;
     708             : 
     709             :           case 'x':                             // unsigned hex
     710        1997 :             radix = 16;
     711        1997 :             type |= 1;
     712        1997 :             goto fetch_and_convert;
     713             : 
     714             :           case 'X':                             // unsigned HEX
     715           1 :             radix = 16;
     716           1 :             hexp = HEX;
     717           1 :             type |= 1;
     718           1 :             goto fetch_and_convert;
     719             : 
     720             :           fetch_and_convert:
     721       15184 :             switch (type) {
     722             :               case TYPE_SHORT:
     723           0 :                 u.l = va_arg(ap, int);
     724           0 :                 if (u.l < 0) {
     725           0 :                     u.l = -u.l;
     726           0 :                     flags |= FLAG_NEG;
     727             :                 }
     728           0 :                 goto do_long;
     729             :               case TYPE_USHORT:
     730           0 :                 u.l = (unsigned short) va_arg(ap, unsigned int);
     731           0 :                 goto do_long;
     732             :               case TYPE_INTN:
     733         723 :                 u.l = va_arg(ap, int);
     734         723 :                 if (u.l < 0) {
     735          13 :                     u.l = -u.l;
     736          13 :                     flags |= FLAG_NEG;
     737             :                 }
     738         723 :                 goto do_long;
     739             :               case TYPE_UINTN:
     740       14371 :                 u.l = (long)va_arg(ap, unsigned int);
     741       14371 :                 goto do_long;
     742             : 
     743             :               case TYPE_LONG:
     744          10 :                 u.l = va_arg(ap, long);
     745          10 :                 if (u.l < 0) {
     746           0 :                     u.l = -u.l;
     747           0 :                     flags |= FLAG_NEG;
     748             :                 }
     749          10 :                 goto do_long;
     750             :               case TYPE_ULONG:
     751          12 :                 u.l = (long)va_arg(ap, unsigned long);
     752             :               do_long:
     753       15116 :                 if (!cvt_l(u.l, width, prec, radix, type, flags, hexp))
     754           0 :                     return false;
     755             : 
     756       15116 :                 break;
     757             : 
     758             :               case TYPE_LONGLONG:
     759           0 :                 u.ll = va_arg(ap, long long);
     760           0 :                 if (u.ll < 0) {
     761           0 :                     u.ll = -u.ll;
     762           0 :                     flags |= FLAG_NEG;
     763             :                 }
     764           0 :                 goto do_longlong;
     765             :               case TYPE_POINTER:
     766          68 :                 u.ll = (uintptr_t)va_arg(ap, void*);
     767          68 :                 goto do_longlong;
     768             :               case TYPE_ULONGLONG:
     769           0 :                 u.ll = va_arg(ap, unsigned long long);
     770             :               do_longlong:
     771          68 :                 if (!cvt_ll(u.ll, width, prec, radix, type, flags, hexp))
     772           0 :                     return false;
     773             : 
     774          68 :                 break;
     775             :             }
     776       15184 :             break;
     777             : 
     778             :           case 'e':
     779             :           case 'E':
     780             :           case 'f':
     781             :           case 'g':
     782           0 :             u.d = va_arg(ap, double);
     783           0 :             if (!nas.empty()) {
     784           0 :                 i = fmt - dolPt;
     785           0 :                 if (i < int(sizeof(pattern))) {
     786           0 :                     pattern[0] = '%';
     787           0 :                     memcpy(&pattern[1], dolPt, size_t(i));
     788           0 :                     if (!cvt_f(u.d, pattern, &pattern[i + 1]))
     789           0 :                         return false;
     790             :                 }
     791             :             } else {
     792           0 :                 if (!cvt_f(u.d, fmt0, fmt))
     793           0 :                     return false;
     794             :             }
     795             : 
     796           0 :             break;
     797             : 
     798             :           case 'c':
     799          14 :             if ((flags & FLAG_LEFT) == 0) {
     800          14 :                 while (width-- > 1) {
     801           0 :                     if (!emit(" ", 1))
     802           0 :                         return false;
     803             :                 }
     804             :             }
     805          14 :             switch (type) {
     806             :               case TYPE_SHORT:
     807             :               case TYPE_INTN:
     808          14 :                 u.ch = va_arg(ap, int);
     809          14 :                 if (!emit(&u.ch, 1))
     810           0 :                     return false;
     811          14 :                 break;
     812             :             }
     813          14 :             if (flags & FLAG_LEFT) {
     814           0 :                 while (width-- > 1) {
     815           0 :                     if (!emit(" ", 1))
     816           0 :                         return false;
     817             :                 }
     818             :             }
     819          14 :             break;
     820             : 
     821             :           case 'p':
     822          68 :             type = TYPE_POINTER;
     823          68 :             radix = 16;
     824          68 :             goto fetch_and_convert;
     825             : 
     826             :           case 's':
     827        8436 :             if (type == TYPE_INTN) {
     828        8436 :                 u.s = va_arg(ap, const char*);
     829        8436 :                 if (!cvt_s(u.s, width, prec, flags))
     830           0 :                     return false;
     831        8436 :                 break;
     832             :             }
     833           0 :             MOZ_ASSERT(type == TYPE_LONG);
     834             :             MOZ_FALLTHROUGH;
     835             :           case 'S':
     836             : #if defined(XP_WIN)
     837             :             {
     838             :                 u.ws = va_arg(ap, const wchar_t*);
     839             : 
     840             :                 int rv = WideCharToMultiByte(CP_ACP, 0, u.ws, -1, NULL, 0, NULL, NULL);
     841             :                 if (rv == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
     842             :                     if (!cvt_s("<unicode errors in string>", width, prec, flags)) {
     843             :                         return false;
     844             :                     }
     845             :                 } else {
     846             :                     if (rv == 0) {
     847             :                         rv = 1;
     848             :                     }
     849             :                     UniqueFreePtr<char[]> buf((char*)malloc(rv));
     850             :                     WideCharToMultiByte(CP_ACP, 0, u.ws, -1, buf.get(), rv, NULL, NULL);
     851             :                     buf[rv - 1] = '\0';
     852             : 
     853             :                     if (!cvt_s(buf.get(), width, prec, flags)) {
     854             :                         return false;
     855             :                     }
     856             :                 }
     857             :             }
     858             : #else
     859             :             // Not supported here.
     860           0 :             MOZ_ASSERT(0);
     861             : #endif
     862             :             break;
     863             : 
     864             :           case 'n':
     865           0 :             u.ip = va_arg(ap, int*);
     866           0 :             if (u.ip) {
     867           0 :                 *u.ip = mEmitted;
     868             :             }
     869           0 :             break;
     870             : 
     871             :           default:
     872             :             // Not a % token after all... skip it
     873           0 :             if (!emit("%", 1))
     874           0 :                 return false;
     875           0 :             if (!emit(fmt - 1, 1))
     876           0 :                 return false;
     877             :         }
     878             :     }
     879             : 
     880        9199 :     return true;
     881             : }
     882             : 
     883             : /************************************************************************/
     884             : 
     885             : bool
     886          74 : mozilla::PrintfTarget::print(const char* format, ...)
     887             : {
     888             :     va_list ap;
     889             : 
     890          74 :     va_start(ap, format);
     891          74 :     bool result = vprint(format, ap);
     892          74 :     va_end(ap);
     893          74 :     return result;
     894             : }
     895             : 
     896             : #undef TYPE_SHORT
     897             : #undef TYPE_USHORT
     898             : #undef TYPE_INTN
     899             : #undef TYPE_UINTN
     900             : #undef TYPE_LONG
     901             : #undef TYPE_ULONG
     902             : #undef TYPE_LONGLONG
     903             : #undef TYPE_ULONGLONG
     904             : #undef TYPE_STRING
     905             : #undef TYPE_DOUBLE
     906             : #undef TYPE_INTSTR
     907             : #undef TYPE_POINTER
     908             : #undef TYPE_WSTRING
     909             : #undef TYPE_UNKNOWN
     910             : 
     911             : #undef FLAG_LEFT
     912             : #undef FLAG_SIGNED
     913             : #undef FLAG_SPACED
     914             : #undef FLAG_ZEROS
     915             : #undef FLAG_NEG

Generated by: LCOV version 1.13