js/src/jsprf.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     7 /*
     8  * Portable safe sprintf code.
     9  *
    10  * Author: Kipp E.B. Hickman
    11  */
    13 #include "jsprf.h"
    15 #include <stdarg.h>
    16 #include <stdio.h>
    17 #include <stdlib.h>
    18 #include <string.h>
    20 #include "jspubtd.h"
    21 #include "jsstr.h"
    22 #include "jsutil.h"
    24 using namespace js;
    26 /*
    27  * Note: on some platforms va_list is defined as an array,
    28  * and requires array notation.
    29  */
    30 #ifdef HAVE_VA_COPY
    31 #define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo, bar)
    32 #elif defined(HAVE_VA_LIST_AS_ARRAY)
    33 #define VARARGS_ASSIGN(foo, bar)        foo[0] = bar[0]
    34 #else
    35 #define VARARGS_ASSIGN(foo, bar)        (foo) = (bar)
    36 #endif
    38 struct SprintfState
    39 {
    40     int (*stuff)(SprintfState *ss, const char *sp, size_t len);
    42     char *base;
    43     char *cur;
    44     size_t maxlen;
    46     int (*func)(void *arg, const char *sp, uint32_t len);
    47     void *arg;
    48 };
    50 /*
    51  * Numbered Argument State
    52  */
    53 struct NumArgState
    54 {
    55     int type;       // type of the current ap
    56     va_list ap;     // point to the corresponding position on ap
    57 };
    59 const size_t NAS_DEFAULT_NUM = 20;  // default number of NumberedArgumentState array
    62 #define TYPE_INT16      0
    63 #define TYPE_UINT16     1
    64 #define TYPE_INTN       2
    65 #define TYPE_UINTN      3
    66 #define TYPE_INT32      4
    67 #define TYPE_UINT32     5
    68 #define TYPE_INT64      6
    69 #define TYPE_UINT64     7
    70 #define TYPE_STRING     8
    71 #define TYPE_DOUBLE     9
    72 #define TYPE_INTSTR     10
    73 #define TYPE_WSTRING    11
    74 #define TYPE_UNKNOWN    20
    76 #define FLAG_LEFT       0x1
    77 #define FLAG_SIGNED     0x2
    78 #define FLAG_SPACED     0x4
    79 #define FLAG_ZEROS      0x8
    80 #define FLAG_NEG        0x10
    82 inline int
    83 generic_write(SprintfState *ss, const char *src, size_t srclen)
    84 {
    85     return (*ss->stuff)(ss, src, srclen);
    86 }
    88 inline int
    89 generic_write(SprintfState *ss, const jschar *src, size_t srclen)
    90 {
    91     const size_t CHUNK_SIZE = 64;
    92     char chunk[CHUNK_SIZE];
    94     int rv = 0;
    95     size_t j = 0;
    96     size_t i = 0;
    97     while (i < srclen) {
    98         // FIXME: truncates characters to 8 bits
    99         chunk[j++] = char(src[i++]);
   101         if (j == CHUNK_SIZE || i == srclen) {
   102             rv = (*ss->stuff)(ss, chunk, j);
   103             if (rv != 0)
   104                 return rv;
   105             j = 0;
   106         }
   107     }
   108     return 0;
   109 }
   111 // Fill into the buffer using the data in src
   112 template <typename Char>
   113 static int
   114 fill2(SprintfState *ss, const Char *src, int srclen, int width, int flags)
   115 {
   116     char space = ' ';
   117     int rv;
   119     width -= srclen;
   120     if (width > 0 && (flags & FLAG_LEFT) == 0) {    // Right adjusting
   121         if (flags & FLAG_ZEROS)
   122             space = '0';
   123         while (--width >= 0) {
   124             rv = (*ss->stuff)(ss, &space, 1);
   125             if (rv < 0)
   126                 return rv;
   127         }
   128     }
   130     // Copy out the source data
   131     rv = generic_write(ss, src, srclen);
   132     if (rv < 0)
   133         return rv;
   135     if (width > 0 && (flags & FLAG_LEFT) != 0) {    // Left adjusting
   136         while (--width >= 0) {
   137             rv = (*ss->stuff)(ss, &space, 1);
   138             if (rv < 0)
   139                 return rv;
   140         }
   141     }
   142     return 0;
   143 }
   145 /*
   146  * Fill a number. The order is: optional-sign zero-filling conversion-digits
   147  */
   148 static int
   149 fill_n(SprintfState *ss, const char *src, int srclen, int width, int prec, int type, int flags)
   150 {
   151     int zerowidth = 0;
   152     int precwidth = 0;
   153     int signwidth = 0;
   154     int leftspaces = 0;
   155     int rightspaces = 0;
   156     int cvtwidth;
   157     int rv;
   158     char sign;
   160     if ((type & 1) == 0) {
   161         if (flags & FLAG_NEG) {
   162             sign = '-';
   163             signwidth = 1;
   164         } else if (flags & FLAG_SIGNED) {
   165             sign = '+';
   166             signwidth = 1;
   167         } else if (flags & FLAG_SPACED) {
   168             sign = ' ';
   169             signwidth = 1;
   170         }
   171     }
   172     cvtwidth = signwidth + srclen;
   174     if (prec > 0) {
   175         if (prec > srclen) {
   176             precwidth = prec - srclen;          // Need zero filling
   177             cvtwidth += precwidth;
   178         }
   179     }
   181     if ((flags & FLAG_ZEROS) && (prec < 0)) {
   182         if (width > cvtwidth) {
   183             zerowidth = width - cvtwidth;       // Zero filling
   184             cvtwidth += zerowidth;
   185         }
   186     }
   188     if (flags & FLAG_LEFT) {
   189         if (width > cvtwidth) {
   190             // Space filling on the right (i.e. left adjusting)
   191             rightspaces = width - cvtwidth;
   192         }
   193     } else {
   194         if (width > cvtwidth) {
   195             // Space filling on the left (i.e. right adjusting)
   196             leftspaces = width - cvtwidth;
   197         }
   198     }
   199     while (--leftspaces >= 0) {
   200         rv = (*ss->stuff)(ss, " ", 1);
   201         if (rv < 0) {
   202             return rv;
   203         }
   204     }
   205     if (signwidth) {
   206         rv = (*ss->stuff)(ss, &sign, 1);
   207         if (rv < 0) {
   208             return rv;
   209         }
   210     }
   211     while (--precwidth >= 0) {
   212         rv = (*ss->stuff)(ss, "0", 1);
   213         if (rv < 0) {
   214             return rv;
   215         }
   216     }
   217     while (--zerowidth >= 0) {
   218         rv = (*ss->stuff)(ss, "0", 1);
   219         if (rv < 0) {
   220             return rv;
   221         }
   222     }
   223     rv = (*ss->stuff)(ss, src, uint32_t(srclen));
   224     if (rv < 0) {
   225         return rv;
   226     }
   227     while (--rightspaces >= 0) {
   228         rv = (*ss->stuff)(ss, " ", 1);
   229         if (rv < 0) {
   230             return rv;
   231         }
   232     }
   233     return 0;
   234 }
   236 /* Convert a long into its printable form. */
   237 static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
   238                  int type, int flags, const char *hexp)
   239 {
   240     char cvtbuf[100];
   241     char *cvt;
   242     int digits;
   244     // according to the man page this needs to happen
   245     if ((prec == 0) && (num == 0)) {
   246         return 0;
   247     }
   249     // Converting decimal is a little tricky. In the unsigned case we
   250     // need to stop when we hit 10 digits. In the signed case, we can
   251     // stop when the number is zero.
   252     cvt = cvtbuf + sizeof(cvtbuf);
   253     digits = 0;
   254     while (num) {
   255         int digit = (((unsigned long)num) % radix) & 0xF;
   256         *--cvt = hexp[digit];
   257         digits++;
   258         num = (long)(((unsigned long)num) / radix);
   259     }
   260     if (digits == 0) {
   261         *--cvt = '0';
   262         digits++;
   263     }
   265     // Now that we have the number converted without its sign, deal with
   266     // the sign and zero padding.
   267     return fill_n(ss, cvt, digits, width, prec, type, flags);
   268 }
   270 /* Convert a 64-bit integer into its printable form. */
   271 static int cvt_ll(SprintfState *ss, int64_t num, int width, int prec, int radix,
   272                   int type, int flags, const char *hexp)
   273 {
   274     // According to the man page, this needs to happen.
   275     if (prec == 0 && num == 0)
   276         return 0;
   278     // Converting decimal is a little tricky. In the unsigned case we
   279     // need to stop when we hit 10 digits. In the signed case, we can
   280     // stop when the number is zero.
   281     int64_t rad = int64_t(radix);
   282     char cvtbuf[100];
   283     char *cvt = cvtbuf + sizeof(cvtbuf);
   284     int digits = 0;
   285     while (num != 0) {
   286         int64_t quot = uint64_t(num) / rad;
   287         int64_t rem = uint64_t(num) % rad;
   288         int32_t digit = int32_t(rem);
   289         *--cvt = hexp[digit & 0xf];
   290         digits++;
   291         num = quot;
   292     }
   293     if (digits == 0) {
   294         *--cvt = '0';
   295         digits++;
   296     }
   298     // Now that we have the number converted without its sign, deal with
   299     // the sign and zero padding.
   300     return fill_n(ss, cvt, digits, width, prec, type, flags);
   301 }
   303 /*
   304  * Convert a double precision floating point number into its printable
   305  * form.
   306  *
   307  * XXX stop using sprintf to convert floating point
   308  */
   309 static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
   310 {
   311     char fin[20];
   312     char fout[300];
   313     int amount = fmt1 - fmt0;
   315     JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin)));
   316     if (amount >= (int)sizeof(fin)) {
   317         // Totally bogus % command to sprintf. Just ignore it
   318         return 0;
   319     }
   320     js_memcpy(fin, fmt0, (size_t)amount);
   321     fin[amount] = 0;
   323     // Convert floating point using the native sprintf code
   324 #ifdef DEBUG
   325     {
   326         const char *p = fin;
   327         while (*p) {
   328             JS_ASSERT(*p != 'L');
   329             p++;
   330         }
   331     }
   332 #endif
   333     sprintf(fout, fin, d);
   335     // This assert will catch overflow's of fout, when building with
   336     // debugging on. At least this way we can track down the evil piece
   337     // of calling code and fix it!
   338     JS_ASSERT(strlen(fout) < sizeof(fout));
   340     return (*ss->stuff)(ss, fout, strlen(fout));
   341 }
   343 static inline const char *generic_null_str(const char *) { return "(null)"; }
   344 static inline const jschar *generic_null_str(const jschar *) { return MOZ_UTF16("(null)"); }
   346 static inline size_t generic_strlen(const char *s) { return strlen(s); }
   347 static inline size_t generic_strlen(const jschar *s) { return js_strlen(s); }
   349 /*
   350  * Convert a string into its printable form.  "width" is the output
   351  * width. "prec" is the maximum number of characters of "s" to output,
   352  * where -1 means until NUL.
   353  */
   354 template <typename Char>
   355 static int
   356 cvt_s(SprintfState *ss, const Char *s, int width, int prec, int flags)
   357 {
   358     if (prec == 0)
   359         return 0;
   360     if (!s)
   361         s = generic_null_str(s);
   363     // Limit string length by precision value
   364     int slen = int(generic_strlen(s));
   365     if (0 < prec && prec < slen)
   366         slen = prec;
   368     // and away we go
   369     return fill2(ss, s, slen, width, flags);
   370 }
   372 /*
   373  * BuildArgArray stands for Numbered Argument list Sprintf
   374  * for example,
   375  *      fmp = "%4$i, %2$d, %3s, %1d";
   376  * the number must start from 1, and no gap among them
   377  */
   378 static NumArgState *
   379 BuildArgArray(const char *fmt, va_list ap, int *rv, NumArgState *nasArray)
   380 {
   381     size_t number = 0, cn = 0, i;
   382     const char *p;
   383     char c;
   384     NumArgState *nas;
   387     // First pass:
   388     // Detemine how many legal % I have got, then allocate space.
   390     p = fmt;
   391     *rv = 0;
   392     i = 0;
   393     while ((c = *p++) != 0) {
   394         if (c != '%')
   395             continue;
   396         if ((c = *p++) == '%')          // skip %% case
   397             continue;
   399         while (c != 0) {
   400             if (c > '9' || c < '0') {
   401                 if (c == '$') {         // numbered argument case
   402                     if (i > 0) {
   403                         *rv = -1;
   404                         return nullptr;
   405                     }
   406                     number++;
   407                 } else {                // non-numbered argument case
   408                     if (number > 0) {
   409                         *rv = -1;
   410                         return nullptr;
   411                     }
   412                     i = 1;
   413                 }
   414                 break;
   415             }
   417             c = *p++;
   418         }
   419     }
   421     if (number == 0)
   422         return nullptr;
   424     if (number > NAS_DEFAULT_NUM) {
   425         nas = (NumArgState *) js_malloc(number * sizeof(NumArgState));
   426         if (!nas) {
   427             *rv = -1;
   428             return nullptr;
   429         }
   430     } else {
   431         nas = nasArray;
   432     }
   434     for (i = 0; i < number; i++)
   435         nas[i].type = TYPE_UNKNOWN;
   438     // Second pass:
   439     // Set nas[].type.
   441     p = fmt;
   442     while ((c = *p++) != 0) {
   443         if (c != '%')
   444             continue;
   445         c = *p++;
   446         if (c == '%')
   447             continue;
   449         cn = 0;
   450         while (c && c != '$') {     // should improve error check later
   451             cn = cn*10 + c - '0';
   452             c = *p++;
   453         }
   455         if (!c || cn < 1 || cn > number) {
   456             *rv = -1;
   457             break;
   458         }
   460         // nas[cn] starts from 0, and make sure nas[cn].type is not assigned.
   461         cn--;
   462         if (nas[cn].type != TYPE_UNKNOWN)
   463             continue;
   465         c = *p++;
   467         // width
   468         if (c == '*') {
   469             // not supported feature, for the argument is not numbered
   470             *rv = -1;
   471             break;
   472         }
   474         while ((c >= '0') && (c <= '9')) {
   475             c = *p++;
   476         }
   478         // precision
   479         if (c == '.') {
   480             c = *p++;
   481             if (c == '*') {
   482                 // not supported feature, for the argument is not numbered
   483                 *rv = -1;
   484                 break;
   485             }
   487             while ((c >= '0') && (c <= '9')) {
   488                 c = *p++;
   489             }
   490         }
   492         // size
   493         nas[cn].type = TYPE_INTN;
   494         if (c == 'h') {
   495             nas[cn].type = TYPE_INT16;
   496             c = *p++;
   497         } else if (c == 'L') {
   498             // XXX not quite sure here
   499             nas[cn].type = TYPE_INT64;
   500             c = *p++;
   501         } else if (c == 'l') {
   502             nas[cn].type = TYPE_INT32;
   503             c = *p++;
   504             if (c == 'l') {
   505                 nas[cn].type = TYPE_INT64;
   506                 c = *p++;
   507             }
   508         }
   510         // format
   511         switch (c) {
   512         case 'd':
   513         case 'c':
   514         case 'i':
   515         case 'o':
   516         case 'u':
   517         case 'x':
   518         case 'X':
   519             break;
   521         case 'e':
   522         case 'f':
   523         case 'g':
   524             nas[cn].type = TYPE_DOUBLE;
   525             break;
   527         case 'p':
   528             // XXX should use cpp
   529             if (sizeof(void *) == sizeof(int32_t)) {
   530                 nas[cn].type = TYPE_UINT32;
   531             } else if (sizeof(void *) == sizeof(int64_t)) {
   532                 nas[cn].type = TYPE_UINT64;
   533             } else if (sizeof(void *) == sizeof(int)) {
   534                 nas[cn].type = TYPE_UINTN;
   535             } else {
   536                 nas[cn].type = TYPE_UNKNOWN;
   537             }
   538             break;
   540         case 'C':
   541         case 'S':
   542         case 'E':
   543         case 'G':
   544             // XXX not supported I suppose
   545             JS_ASSERT(0);
   546             nas[cn].type = TYPE_UNKNOWN;
   547             break;
   549         case 's':
   550             nas[cn].type = (nas[cn].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
   551             break;
   553         case 'n':
   554             nas[cn].type = TYPE_INTSTR;
   555             break;
   557         default:
   558             JS_ASSERT(0);
   559             nas[cn].type = TYPE_UNKNOWN;
   560             break;
   561         }
   563         // get a legal para.
   564         if (nas[cn].type == TYPE_UNKNOWN) {
   565             *rv = -1;
   566             break;
   567         }
   568     }
   571     // Third pass:
   572     // Fill nas[].ap.
   574     if (*rv < 0) {
   575         if (nas != nasArray)
   576             js_free(nas);
   577         return nullptr;
   578     }
   580     cn = 0;
   581     while (cn < number) {
   582         if (nas[cn].type == TYPE_UNKNOWN) {
   583             cn++;
   584             continue;
   585         }
   587         VARARGS_ASSIGN(nas[cn].ap, ap);
   589         switch (nas[cn].type) {
   590         case TYPE_INT16:
   591         case TYPE_UINT16:
   592         case TYPE_INTN:
   593         case TYPE_UINTN:        (void) va_arg(ap, int);         break;
   594         case TYPE_INT32:        (void) va_arg(ap, int32_t);     break;
   595         case TYPE_UINT32:       (void) va_arg(ap, uint32_t);    break;
   596         case TYPE_INT64:        (void) va_arg(ap, int64_t);     break;
   597         case TYPE_UINT64:       (void) va_arg(ap, uint64_t);    break;
   598         case TYPE_STRING:       (void) va_arg(ap, char*);       break;
   599         case TYPE_WSTRING:      (void) va_arg(ap, jschar*);     break;
   600         case TYPE_INTSTR:       (void) va_arg(ap, int*);        break;
   601         case TYPE_DOUBLE:       (void) va_arg(ap, double);      break;
   603         default:
   604             if (nas != nasArray)
   605                 js_free(nas);
   606             *rv = -1;
   607             return nullptr;
   608         }
   610         cn++;
   611     }
   614     return nas;
   615 }
   617 /*
   618  * The workhorse sprintf code.
   619  */
   620 static int
   621 dosprintf(SprintfState *ss, const char *fmt, va_list ap)
   622 {
   623     char c;
   624     int flags, width, prec, radix, type;
   625     union {
   626         char ch;
   627         jschar wch;
   628         int i;
   629         long l;
   630         int64_t ll;
   631         double d;
   632         const char *s;
   633         const jschar* ws;
   634         int *ip;
   635     } u;
   636     const char *fmt0;
   637     static const char hex[] = "0123456789abcdef";
   638     static const char HEX[] = "0123456789ABCDEF";
   639     const char *hexp;
   640     int rv, i;
   641     NumArgState *nas = nullptr;
   642     NumArgState nasArray[NAS_DEFAULT_NUM];
   643     char pattern[20];
   644     const char *dolPt = nullptr;  // in "%4$.2f", dolPt will point to '.'
   646     // Build an argument array, IF the fmt is numbered argument
   647     // list style, to contain the Numbered Argument list pointers.
   649     nas = BuildArgArray(fmt, ap, &rv, nasArray);
   650     if (rv < 0) {
   651         // the fmt contains error Numbered Argument format, jliu@netscape.com
   652         JS_ASSERT(0);
   653         return rv;
   654     }
   656     while ((c = *fmt++) != 0) {
   657         if (c != '%') {
   658             rv = (*ss->stuff)(ss, fmt - 1, 1);
   659             if (rv < 0) {
   660                 return rv;
   661             }
   662             continue;
   663         }
   664         fmt0 = fmt - 1;
   666         // Gobble up the % format string. Hopefully we have handled all
   667         // of the strange cases!
   668         flags = 0;
   669         c = *fmt++;
   670         if (c == '%') {
   671             // quoting a % with %%
   672             rv = (*ss->stuff)(ss, fmt - 1, 1);
   673             if (rv < 0) {
   674                 return rv;
   675             }
   676             continue;
   677         }
   679         if (nas != nullptr) {
   680             // the fmt contains the Numbered Arguments feature
   681             i = 0;
   682             while (c && c != '$') {         // should improve error check later
   683                 i = (i * 10) + (c - '0');
   684                 c = *fmt++;
   685             }
   687             if (nas[i-1].type == TYPE_UNKNOWN) {
   688                 if (nas && nas != nasArray)
   689                     js_free(nas);
   690                 return -1;
   691             }
   693             ap = nas[i-1].ap;
   694             dolPt = fmt;
   695             c = *fmt++;
   696         }
   698         // Examine optional flags.  Note that we do not implement the
   699         // '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
   700         // somewhat ambiguous and not ideal, which is perhaps why
   701         // the various sprintf() implementations are inconsistent
   702         // on this feature.
   703         while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
   704             if (c == '-') flags |= FLAG_LEFT;
   705             if (c == '+') flags |= FLAG_SIGNED;
   706             if (c == ' ') flags |= FLAG_SPACED;
   707             if (c == '0') flags |= FLAG_ZEROS;
   708             c = *fmt++;
   709         }
   710         if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
   711         if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
   713         // width
   714         if (c == '*') {
   715             c = *fmt++;
   716             width = va_arg(ap, int);
   717         } else {
   718             width = 0;
   719             while ((c >= '0') && (c <= '9')) {
   720                 width = (width * 10) + (c - '0');
   721                 c = *fmt++;
   722             }
   723         }
   725         // precision
   726         prec = -1;
   727         if (c == '.') {
   728             c = *fmt++;
   729             if (c == '*') {
   730                 c = *fmt++;
   731                 prec = va_arg(ap, int);
   732             } else {
   733                 prec = 0;
   734                 while ((c >= '0') && (c <= '9')) {
   735                     prec = (prec * 10) + (c - '0');
   736                     c = *fmt++;
   737                 }
   738             }
   739         }
   741         // size
   742         type = TYPE_INTN;
   743         if (c == 'h') {
   744             type = TYPE_INT16;
   745             c = *fmt++;
   746         } else if (c == 'L') {
   747             // XXX not quite sure here
   748             type = TYPE_INT64;
   749             c = *fmt++;
   750         } else if (c == 'l') {
   751             type = TYPE_INT32;
   752             c = *fmt++;
   753             if (c == 'l') {
   754                 type = TYPE_INT64;
   755                 c = *fmt++;
   756             }
   757         }
   759         // format
   760         hexp = hex;
   761         switch (c) {
   762           case 'd': case 'i':                   // decimal/integer
   763             radix = 10;
   764             goto fetch_and_convert;
   766           case 'o':                             // octal
   767             radix = 8;
   768             type |= 1;
   769             goto fetch_and_convert;
   771           case 'u':                             // unsigned decimal
   772             radix = 10;
   773             type |= 1;
   774             goto fetch_and_convert;
   776           case 'x':                             // unsigned hex
   777             radix = 16;
   778             type |= 1;
   779             goto fetch_and_convert;
   781           case 'X':                             // unsigned HEX
   782             radix = 16;
   783             hexp = HEX;
   784             type |= 1;
   785             goto fetch_and_convert;
   787           fetch_and_convert:
   788             switch (type) {
   789               case TYPE_INT16:
   790                 u.l = va_arg(ap, int);
   791                 if (u.l < 0) {
   792                     u.l = -u.l;
   793                     flags |= FLAG_NEG;
   794                 }
   795                 goto do_long;
   796               case TYPE_UINT16:
   797                 u.l = va_arg(ap, int) & 0xffff;
   798                 goto do_long;
   799               case TYPE_INTN:
   800                 u.l = va_arg(ap, int);
   801                 if (u.l < 0) {
   802                     u.l = -u.l;
   803                     flags |= FLAG_NEG;
   804                 }
   805                 goto do_long;
   806               case TYPE_UINTN:
   807                 u.l = (long)va_arg(ap, unsigned int);
   808                 goto do_long;
   810               case TYPE_INT32:
   811                 u.l = va_arg(ap, int32_t);
   812                 if (u.l < 0) {
   813                     u.l = -u.l;
   814                     flags |= FLAG_NEG;
   815                 }
   816                 goto do_long;
   817               case TYPE_UINT32:
   818                 u.l = (long)va_arg(ap, uint32_t);
   819               do_long:
   820                 rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
   821                 if (rv < 0) {
   822                     return rv;
   823                 }
   824                 break;
   826               case TYPE_INT64:
   827                 u.ll = va_arg(ap, int64_t);
   828                 if (u.ll < 0) {
   829                     u.ll = -u.ll;
   830                     flags |= FLAG_NEG;
   831                 }
   832                 goto do_longlong;
   833               case TYPE_UINT64:
   834                 u.ll = va_arg(ap, uint64_t);
   835               do_longlong:
   836                 rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
   837                 if (rv < 0) {
   838                     return rv;
   839                 }
   840                 break;
   841             }
   842             break;
   844           case 'e':
   845           case 'E':
   846           case 'f':
   847           case 'g':
   848             u.d = va_arg(ap, double);
   849             if (nas != nullptr) {
   850                 i = fmt - dolPt;
   851                 if (i < int(sizeof(pattern))) {
   852                     pattern[0] = '%';
   853                     js_memcpy(&pattern[1], dolPt, size_t(i));
   854                     rv = cvt_f(ss, u.d, pattern, &pattern[i + 1]);
   855                 }
   856             } else
   857                 rv = cvt_f(ss, u.d, fmt0, fmt);
   859             if (rv < 0) {
   860                 return rv;
   861             }
   862             break;
   864           case 'c':
   865             if ((flags & FLAG_LEFT) == 0) {
   866                 while (width-- > 1) {
   867                     rv = (*ss->stuff)(ss, " ", 1);
   868                     if (rv < 0) {
   869                         return rv;
   870                     }
   871                 }
   872             }
   873             switch (type) {
   874               case TYPE_INT16:
   875               case TYPE_INTN:
   876                 u.ch = va_arg(ap, int);
   877                 rv = (*ss->stuff)(ss, &u.ch, 1);
   878                 break;
   879             }
   880             if (rv < 0) {
   881                 return rv;
   882             }
   883             if (flags & FLAG_LEFT) {
   884                 while (width-- > 1) {
   885                     rv = (*ss->stuff)(ss, " ", 1);
   886                     if (rv < 0) {
   887                         return rv;
   888                     }
   889                 }
   890             }
   891             break;
   893           case 'p':
   894             if (sizeof(void *) == sizeof(int32_t)) {
   895                 type = TYPE_UINT32;
   896             } else if (sizeof(void *) == sizeof(int64_t)) {
   897                 type = TYPE_UINT64;
   898             } else if (sizeof(void *) == sizeof(int)) {
   899                 type = TYPE_UINTN;
   900             } else {
   901                 JS_ASSERT(0);
   902                 break;
   903             }
   904             radix = 16;
   905             goto fetch_and_convert;
   907 #if 0
   908           case 'C':
   909           case 'S':
   910           case 'E':
   911           case 'G':
   912             // XXX not supported I suppose
   913             JS_ASSERT(0);
   914             break;
   915 #endif
   917           case 's':
   918             if(type == TYPE_INT16) {
   919                 u.ws = va_arg(ap, const jschar*);
   920                 rv = cvt_s(ss, u.ws, width, prec, flags);
   921             } else {
   922                 u.s = va_arg(ap, const char*);
   923                 rv = cvt_s(ss, u.s, width, prec, flags);
   924             }
   925             if (rv < 0) {
   926                 return rv;
   927             }
   928             break;
   930           case 'n':
   931             u.ip = va_arg(ap, int*);
   932             if (u.ip) {
   933                 *u.ip = ss->cur - ss->base;
   934             }
   935             break;
   937           default:
   938             // Not a % token after all... skip it
   939 #if 0
   940             JS_ASSERT(0);
   941 #endif
   942             rv = (*ss->stuff)(ss, "%", 1);
   943             if (rv < 0) {
   944                 return rv;
   945             }
   946             rv = (*ss->stuff)(ss, fmt - 1, 1);
   947             if (rv < 0) {
   948                 return rv;
   949             }
   950         }
   951     }
   953     // Stuff trailing NUL
   954     rv = (*ss->stuff)(ss, "\0", 1);
   956     if (nas && nas != nasArray)
   957         js_free(nas);
   959     return rv;
   960 }
   962 /************************************************************************/
   964 /*
   965  * Stuff routine that automatically grows the js_malloc'd output buffer
   966  * before it overflows.
   967  */
   968 static int
   969 GrowStuff(SprintfState *ss, const char *sp, size_t len)
   970 {
   971     ptrdiff_t off;
   972     char *newbase;
   973     size_t newlen;
   975     off = ss->cur - ss->base;
   976     if (off + len >= ss->maxlen) {
   977         /* Grow the buffer */
   978         newlen = ss->maxlen + ((len > 32) ? len : 32);
   979         newbase = static_cast<char *>(js_realloc(ss->base, newlen));
   980         if (!newbase) {
   981             /* Ran out of memory */
   982             return -1;
   983         }
   984         ss->base = newbase;
   985         ss->maxlen = newlen;
   986         ss->cur = ss->base + off;
   987     }
   989     /* Copy data */
   990     while (len) {
   991         --len;
   992         *ss->cur++ = *sp++;
   993     }
   994     MOZ_ASSERT(size_t(ss->cur - ss->base) <= ss->maxlen);
   995     return 0;
   996 }
   998 /*
   999  * sprintf into a js_malloc'd buffer
  1000  */
  1001 JS_PUBLIC_API(char *)
  1002 JS_smprintf(const char *fmt, ...)
  1004     va_list ap;
  1005     char *rv;
  1007     va_start(ap, fmt);
  1008     rv = JS_vsmprintf(fmt, ap);
  1009     va_end(ap);
  1010     return rv;
  1013 /*
  1014  * Free memory allocated, for the caller, by JS_smprintf
  1015  */
  1016 JS_PUBLIC_API(void)
  1017 JS_smprintf_free(char *mem)
  1019     js_free(mem);
  1022 JS_PUBLIC_API(char *)
  1023 JS_vsmprintf(const char *fmt, va_list ap)
  1025     SprintfState ss;
  1026     int rv;
  1028     ss.stuff = GrowStuff;
  1029     ss.base = 0;
  1030     ss.cur = 0;
  1031     ss.maxlen = 0;
  1032     rv = dosprintf(&ss, fmt, ap);
  1033     if (rv < 0) {
  1034         js_free(ss.base);
  1035         return 0;
  1037     return ss.base;
  1040 /*
  1041  * Stuff routine that discards overflow data
  1042  */
  1043 static int
  1044 LimitStuff(SprintfState *ss, const char *sp, size_t len)
  1046     size_t limit = ss->maxlen - (ss->cur - ss->base);
  1048     if (len > limit)
  1049         len = limit;
  1050     while (len) {
  1051         --len;
  1052         *ss->cur++ = *sp++;
  1054     return 0;
  1057 /*
  1058  * sprintf into a fixed size buffer. Make sure there is a NUL at the end
  1059  * when finished.
  1060  */
  1061 JS_PUBLIC_API(uint32_t)
  1062 JS_snprintf(char *out, uint32_t outlen, const char *fmt, ...)
  1064     va_list ap;
  1065     int rv;
  1067     JS_ASSERT(int32_t(outlen) > 0);
  1068     if (int32_t(outlen) <= 0)
  1069         return 0;
  1071     va_start(ap, fmt);
  1072     rv = JS_vsnprintf(out, outlen, fmt, ap);
  1073     va_end(ap);
  1074     return rv;
  1077 JS_PUBLIC_API(uint32_t)
  1078 JS_vsnprintf(char *out, uint32_t outlen, const char *fmt, va_list ap)
  1080     SprintfState ss;
  1081     uint32_t n;
  1083     JS_ASSERT(int32_t(outlen) > 0);
  1084     if (int32_t(outlen) <= 0) {
  1085         return 0;
  1088     ss.stuff = LimitStuff;
  1089     ss.base = out;
  1090     ss.cur = out;
  1091     ss.maxlen = outlen;
  1092     (void) dosprintf(&ss, fmt, ap);
  1094     /* If we added chars, and we didn't append a null, do it now. */
  1095     if (ss.cur != ss.base && ss.cur[-1] != '\0')
  1096         ss.cur[-1] = '\0';
  1098     n = ss.cur - ss.base;
  1099     return n ? n - 1 : n;
  1102 JS_PUBLIC_API(char *)
  1103 JS_sprintf_append(char *last, const char *fmt, ...)
  1105     va_list ap;
  1106     char *rv;
  1108     va_start(ap, fmt);
  1109     rv = JS_vsprintf_append(last, fmt, ap);
  1110     va_end(ap);
  1111     return rv;
  1114 JS_PUBLIC_API(char *)
  1115 JS_vsprintf_append(char *last, const char *fmt, va_list ap)
  1117     SprintfState ss;
  1118     int rv;
  1120     ss.stuff = GrowStuff;
  1121     if (last) {
  1122         size_t lastlen = strlen(last);
  1123         ss.base = last;
  1124         ss.cur = last + lastlen;
  1125         ss.maxlen = lastlen;
  1126     } else {
  1127         ss.base = 0;
  1128         ss.cur = 0;
  1129         ss.maxlen = 0;
  1131     rv = dosprintf(&ss, fmt, ap);
  1132     if (rv < 0) {
  1133         js_free(ss.base);
  1134         return 0;
  1136     return ss.base;
  1139 #undef TYPE_INT16
  1140 #undef TYPE_UINT16
  1141 #undef TYPE_INTN
  1142 #undef TYPE_UINTN
  1143 #undef TYPE_INT32
  1144 #undef TYPE_UINT32
  1145 #undef TYPE_INT64
  1146 #undef TYPE_UINT64
  1147 #undef TYPE_STRING
  1148 #undef TYPE_DOUBLE
  1149 #undef TYPE_INTSTR
  1150 #undef TYPE_WSTRING
  1151 #undef TYPE_UNKNOWN
  1153 #undef FLAG_LEFT
  1154 #undef FLAG_SIGNED
  1155 #undef FLAG_SPACED
  1156 #undef FLAG_ZEROS
  1157 #undef FLAG_NEG

mercurial