LCOV - code coverage report
Current view: directory - js/src - jsprf.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 541 285 52.7 %
Date: 2012-06-02 Functions: 21 16 76.2 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code, released
      16                 :  * March 31, 1998.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : /*
      40                 : ** Portable safe sprintf code.
      41                 : **
      42                 : ** Author: Kipp E.B. Hickman
      43                 : */
      44                 : #include <stdarg.h>
      45                 : #include <stdio.h>
      46                 : #include <string.h>
      47                 : #include <stdlib.h>
      48                 : #include "jsprf.h"
      49                 : #include "jsutil.h"
      50                 : #include "jspubtd.h"
      51                 : #include "jsstr.h"
      52                 : 
      53                 : using namespace js;
      54                 : 
      55                 : /*
      56                 : ** Note: on some platforms va_list is defined as an array,
      57                 : ** and requires array notation.
      58                 : */
      59                 : #ifdef HAVE_VA_COPY
      60                 : #define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo,bar)
      61                 : #elif defined(HAVE_VA_LIST_AS_ARRAY)
      62                 : #define VARARGS_ASSIGN(foo, bar)        foo[0] = bar[0]
      63                 : #else
      64                 : #define VARARGS_ASSIGN(foo, bar)        (foo) = (bar)
      65                 : #endif
      66                 : 
      67                 : /*
      68                 : ** WARNING: This code may *NOT* call JS_LOG (because JS_LOG calls it)
      69                 : */
      70                 : 
      71                 : /*
      72                 : ** XXX This needs to be internationalized!
      73                 : */
      74                 : 
      75                 : typedef struct SprintfStateStr SprintfState;
      76                 : 
      77                 : struct SprintfStateStr {
      78                 :     int (*stuff)(SprintfState *ss, const char *sp, uint32_t len);
      79                 : 
      80                 :     char *base;
      81                 :     char *cur;
      82                 :     uint32_t maxlen;
      83                 : 
      84                 :     int (*func)(void *arg, const char *sp, uint32_t len);
      85                 :     void *arg;
      86                 : };
      87                 : 
      88                 : /*
      89                 : ** Numbered Arguement State
      90                 : */
      91                 : struct NumArgState{
      92                 :     int     type;               /* type of the current ap                    */
      93                 :     va_list ap;                 /* point to the corresponding position on ap */
      94                 : };
      95                 : 
      96                 : #define NAS_DEFAULT_NUM 20  /* default number of NumberedArgumentState array */
      97                 : 
      98                 : 
      99                 : #define TYPE_INT16      0
     100                 : #define TYPE_UINT16     1
     101                 : #define TYPE_INTN       2
     102                 : #define TYPE_UINTN      3
     103                 : #define TYPE_INT32      4
     104                 : #define TYPE_UINT32     5
     105                 : #define TYPE_INT64      6
     106                 : #define TYPE_UINT64     7
     107                 : #define TYPE_STRING     8
     108                 : #define TYPE_DOUBLE     9
     109                 : #define TYPE_INTSTR     10
     110                 : #define TYPE_WSTRING    11
     111                 : #define TYPE_UNKNOWN    20
     112                 : 
     113                 : #define FLAG_LEFT       0x1
     114                 : #define FLAG_SIGNED     0x2
     115                 : #define FLAG_SPACED     0x4
     116                 : #define FLAG_ZEROS      0x8
     117                 : #define FLAG_NEG        0x10
     118                 : 
     119                 : /*
     120                 : ** Fill into the buffer using the data in src
     121                 : */
     122          912552 : static int fill2(SprintfState *ss, const char *src, int srclen, int width,
     123                 :                 int flags)
     124                 : {
     125          912552 :     char space = ' ';
     126                 :     int rv;
     127                 : 
     128          912552 :     width -= srclen;
     129          912552 :     if ((width > 0) && ((flags & FLAG_LEFT) == 0)) {    /* Right adjusting */
     130            3007 :         if (flags & FLAG_ZEROS) {
     131               0 :             space = '0';
     132                 :         }
     133           19441 :         while (--width >= 0) {
     134           13427 :             rv = (*ss->stuff)(ss, &space, 1);
     135           13427 :             if (rv < 0) {
     136               0 :                 return rv;
     137                 :             }
     138                 :         }
     139                 :     }
     140                 : 
     141                 :     /* Copy out the source data */
     142          912552 :     rv = (*ss->stuff)(ss, src, uint32_t(srclen));
     143          912552 :     if (rv < 0) {
     144               0 :         return rv;
     145                 :     }
     146                 : 
     147          912552 :     if ((width > 0) && ((flags & FLAG_LEFT) != 0)) {    /* Left adjusting */
     148          479160 :         while (--width >= 0) {
     149          258012 :             rv = (*ss->stuff)(ss, &space, 1);
     150          258012 :             if (rv < 0) {
     151               0 :                 return rv;
     152                 :             }
     153                 :         }
     154                 :     }
     155          912552 :     return 0;
     156                 : }
     157                 : 
     158                 : /*
     159                 : ** Fill a number. The order is: optional-sign zero-filling conversion-digits
     160                 : */
     161        19725471 : static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
     162                 :                   int prec, int type, int flags)
     163                 : {
     164        19725471 :     int zerowidth = 0;
     165        19725471 :     int precwidth = 0;
     166        19725471 :     int signwidth = 0;
     167        19725471 :     int leftspaces = 0;
     168        19725471 :     int rightspaces = 0;
     169                 :     int cvtwidth;
     170                 :     int rv;
     171                 :     char sign;
     172                 : 
     173        19725471 :     if ((type & 1) == 0) {
     174          432224 :         if (flags & FLAG_NEG) {
     175             248 :             sign = '-';
     176             248 :             signwidth = 1;
     177          431976 :         } else if (flags & FLAG_SIGNED) {
     178           68319 :             sign = '+';
     179           68319 :             signwidth = 1;
     180          363657 :         } else if (flags & FLAG_SPACED) {
     181               0 :             sign = ' ';
     182               0 :             signwidth = 1;
     183                 :         }
     184                 :     }
     185        19725471 :     cvtwidth = signwidth + srclen;
     186                 : 
     187        19725471 :     if (prec > 0) {
     188            2869 :         if (prec > srclen) {
     189            1357 :             precwidth = prec - srclen;          /* Need zero filling */
     190            1357 :             cvtwidth += precwidth;
     191                 :         }
     192                 :     }
     193                 : 
     194        19725471 :     if ((flags & FLAG_ZEROS) && (prec < 0)) {
     195          147478 :         if (width > cvtwidth) {
     196           29961 :             zerowidth = width - cvtwidth;       /* Zero filling */
     197           29961 :             cvtwidth += zerowidth;
     198                 :         }
     199                 :     }
     200                 : 
     201        19725471 :     if (flags & FLAG_LEFT) {
     202               0 :         if (width > cvtwidth) {
     203                 :             /* Space filling on the right (i.e. left adjusting) */
     204               0 :             rightspaces = width - cvtwidth;
     205                 :         }
     206                 :     } else {
     207        19725471 :         if (width > cvtwidth) {
     208                 :             /* Space filling on the left (i.e. right adjusting) */
     209          299511 :             leftspaces = width - cvtwidth;
     210                 :         }
     211                 :     }
     212        40350843 :     while (--leftspaces >= 0) {
     213          899901 :         rv = (*ss->stuff)(ss, " ", 1);
     214          899901 :         if (rv < 0) {
     215               0 :             return rv;
     216                 :         }
     217                 :     }
     218        19725471 :     if (signwidth) {
     219           68567 :         rv = (*ss->stuff)(ss, &sign, 1);
     220           68567 :         if (rv < 0) {
     221               0 :             return rv;
     222                 :         }
     223                 :     }
     224        39452344 :     while (--precwidth >= 0) {
     225            1402 :         rv = (*ss->stuff)(ss, "0", 1);
     226            1402 :         if (rv < 0) {
     227               0 :             return rv;
     228                 :         }
     229                 :     }
     230        39484143 :     while (--zerowidth >= 0) {
     231           33201 :         rv = (*ss->stuff)(ss, "0", 1);
     232           33201 :         if (rv < 0) {
     233               0 :             return rv;
     234                 :         }
     235                 :     }
     236        19725471 :     rv = (*ss->stuff)(ss, src, uint32_t(srclen));
     237        19725471 :     if (rv < 0) {
     238               0 :         return rv;
     239                 :     }
     240        39450942 :     while (--rightspaces >= 0) {
     241               0 :         rv = (*ss->stuff)(ss, " ", 1);
     242               0 :         if (rv < 0) {
     243               0 :             return rv;
     244                 :         }
     245                 :     }
     246        19725471 :     return 0;
     247                 : }
     248                 : 
     249                 : /*
     250                 : ** Convert a long into its printable form
     251                 : */
     252        19725471 : static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
     253                 :                  int type, int flags, const char *hexp)
     254                 : {
     255                 :     char cvtbuf[100];
     256                 :     char *cvt;
     257                 :     int digits;
     258                 : 
     259                 :     /* according to the man page this needs to happen */
     260        19725471 :     if ((prec == 0) && (num == 0)) {
     261               0 :         return 0;
     262                 :     }
     263                 : 
     264                 :     /*
     265                 :     ** Converting decimal is a little tricky. In the unsigned case we
     266                 :     ** need to stop when we hit 10 digits. In the signed case, we can
     267                 :     ** stop when the number is zero.
     268                 :     */
     269        19725471 :     cvt = cvtbuf + sizeof(cvtbuf);
     270        19725471 :     digits = 0;
     271       190527481 :     while (num) {
     272       151076539 :         int digit = (((unsigned long)num) % radix) & 0xF;
     273       151076539 :         *--cvt = hexp[digit];
     274       151076539 :         digits++;
     275       151076539 :         num = (long)(((unsigned long)num) / radix);
     276                 :     }
     277        19725471 :     if (digits == 0) {
     278          191636 :         *--cvt = '0';
     279          191636 :         digits++;
     280                 :     }
     281                 : 
     282                 :     /*
     283                 :     ** Now that we have the number converted without its sign, deal with
     284                 :     ** the sign and zero padding.
     285                 :     */
     286        19725471 :     return fill_n(ss, cvt, digits, width, prec, type, flags);
     287                 : }
     288                 : 
     289                 : /*
     290                 : ** Convert a 64-bit integer into its printable form
     291                 : */
     292               0 : static int cvt_ll(SprintfState *ss, int64_t num, int width, int prec, int radix,
     293                 :                   int type, int flags, const char *hexp)
     294                 : {
     295                 :     /* according to the man page this needs to happen */
     296               0 :     if (prec == 0 && num == 0) {
     297               0 :         return 0;
     298                 :     }
     299                 : 
     300                 :     /*
     301                 :     ** Converting decimal is a little tricky. In the unsigned case we
     302                 :     ** need to stop when we hit 10 digits. In the signed case, we can
     303                 :     ** stop when the number is zero.
     304                 :     */
     305               0 :     int64_t rad = int64_t(radix);
     306                 :     char cvtbuf[100];
     307               0 :     char *cvt = cvtbuf + sizeof(cvtbuf);
     308               0 :     int digits = 0;
     309               0 :     while (num != 0) {
     310               0 :         int64_t quot = uint64_t(num) / rad;
     311               0 :         int64_t rem = uint64_t(num) % rad;
     312               0 :         int32_t digit = int32_t(rem);
     313               0 :         *--cvt = hexp[digit & 0xf];
     314               0 :         digits++;
     315               0 :         num = quot;
     316                 :     }
     317               0 :     if (digits == 0) {
     318               0 :         *--cvt = '0';
     319               0 :         digits++;
     320                 :     }
     321                 : 
     322                 :     /*
     323                 :     ** Now that we have the number converted without its sign, deal with
     324                 :     ** the sign and zero padding.
     325                 :     */
     326               0 :     return fill_n(ss, cvt, digits, width, prec, type, flags);
     327                 : }
     328                 : 
     329                 : /*
     330                 : ** Convert a double precision floating point number into its printable
     331                 : ** form.
     332                 : **
     333                 : ** XXX stop using sprintf to convert floating point
     334                 : */
     335           42840 : static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
     336                 : {
     337                 :     char fin[20];
     338                 :     char fout[300];
     339           42840 :     int amount = fmt1 - fmt0;
     340                 : 
     341           42840 :     JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin)));
     342           42840 :     if (amount >= (int)sizeof(fin)) {
     343                 :         /* Totally bogus % command to sprintf. Just ignore it */
     344               0 :         return 0;
     345                 :     }
     346           42840 :     js_memcpy(fin, fmt0, (size_t)amount);
     347           42840 :     fin[amount] = 0;
     348                 : 
     349                 :     /* Convert floating point using the native sprintf code */
     350                 : #ifdef DEBUG
     351                 :     {
     352           42840 :         const char *p = fin;
     353          256716 :         while (*p) {
     354          171036 :             JS_ASSERT(*p != 'L');
     355          171036 :             p++;
     356                 :         }
     357                 :     }
     358                 : #endif
     359           42840 :     sprintf(fout, fin, d);
     360                 : 
     361                 :     /*
     362                 :     ** This assert will catch overflow's of fout, when building with
     363                 :     ** debugging on. At least this way we can track down the evil piece
     364                 :     ** of calling code and fix it!
     365                 :     */
     366           42840 :     JS_ASSERT(strlen(fout) < sizeof(fout));
     367                 : 
     368           42840 :     return (*ss->stuff)(ss, fout, strlen(fout));
     369                 : }
     370                 : 
     371                 : /*
     372                 : ** Convert a string into its printable form.  "width" is the output
     373                 : ** width. "prec" is the maximum number of characters of "s" to output,
     374                 : ** where -1 means until NUL.
     375                 : */
     376          912552 : static int cvt_s(SprintfState *ss, const char *s, int width, int prec,
     377                 :                  int flags)
     378                 : {
     379                 :     int slen;
     380                 : 
     381          912552 :     if (prec == 0)
     382               0 :         return 0;
     383                 : 
     384                 :     /* Limit string length by precision value */
     385          912552 :     slen = s ? strlen(s) : 6;
     386          912552 :     if (prec > 0) {
     387               0 :         if (prec < slen) {
     388               0 :             slen = prec;
     389                 :         }
     390                 :     }
     391                 : 
     392                 :     /* and away we go */
     393          912552 :     return fill2(ss, s ? s : "(null)", slen, width, flags);
     394                 : }
     395                 : 
     396               0 : static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec,
     397                 :                   int flags)
     398                 : {
     399                 :     int result;
     400                 :     /*
     401                 :      * Supply NULL as the JSContext; errors are not reported,
     402                 :      * and malloc() is used to allocate the buffer buffer.
     403                 :      */
     404               0 :     if (ws) {
     405               0 :         int slen = js_strlen(ws);
     406               0 :         char *s = DeflateString(NULL, ws, slen);
     407               0 :         if (!s)
     408               0 :             return -1; /* JSStuffFunc error indicator. */
     409               0 :         result = cvt_s(ss, s, width, prec, flags);
     410               0 :         UnwantedForeground::free_(s);
     411                 :     } else {
     412               0 :         result = cvt_s(ss, NULL, width, prec, flags);
     413                 :     }
     414               0 :     return result;
     415                 : }
     416                 : 
     417                 : /*
     418                 : ** BuildArgArray stands for Numbered Argument list Sprintf
     419                 : ** for example,
     420                 : **      fmp = "%4$i, %2$d, %3s, %1d";
     421                 : ** the number must start from 1, and no gap among them
     422                 : */
     423                 : 
     424        19975350 : static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArgState* nasArray )
     425                 : {
     426        19975350 :     int number = 0, cn = 0, i;
     427                 :     const char *p;
     428                 :     char c;
     429                 :     struct NumArgState *nas;
     430                 : 
     431                 : 
     432                 :     /*
     433                 :     **  first pass:
     434                 :     **  detemine how many legal % I have got, then allocate space
     435                 :     */
     436                 : 
     437        19975350 :     p = fmt;
     438        19975350 :     *rv = 0;
     439        19975350 :     i = 0;
     440       256112164 :     while( ( c = *p++ ) != 0 ){
     441       216161464 :         if( c != '%' )
     442       195457039 :             continue;
     443        20704425 :         if( ( c = *p++ ) == '%' )       /* skip %% case */
     444            8892 :             continue;
     445                 : 
     446        42183587 :         while( c != 0 ){
     447        21488054 :             if( c > '9' || c < '0' ){
     448        20695533 :                 if( c == '$' ){         /* numbered argument csae */
     449               0 :                     if( i > 0 ){
     450               0 :                         *rv = -1;
     451               0 :                         return NULL;
     452                 :                     }
     453               0 :                     number++;
     454                 :                 } else {                /* non-numbered argument case */
     455        20695533 :                     if( number > 0 ){
     456               0 :                         *rv = -1;
     457               0 :                         return NULL;
     458                 :                     }
     459        20695533 :                     i = 1;
     460                 :                 }
     461        20695533 :                 break;
     462                 :             }
     463                 : 
     464          792521 :             c = *p++;
     465                 :         }
     466                 :     }
     467                 : 
     468        19975350 :     if( number == 0 ){
     469        19975350 :         return NULL;
     470                 :     }
     471                 : 
     472                 : 
     473               0 :     if( number > NAS_DEFAULT_NUM ){
     474               0 :         nas = (struct NumArgState*)malloc( number * sizeof( struct NumArgState ) );
     475               0 :         if( !nas ){
     476               0 :             *rv = -1;
     477               0 :             return NULL;
     478                 :         }
     479                 :     } else {
     480               0 :         nas = nasArray;
     481                 :     }
     482                 : 
     483               0 :     for( i = 0; i < number; i++ ){
     484               0 :         nas[i].type = TYPE_UNKNOWN;
     485                 :     }
     486                 : 
     487                 : 
     488                 :     /*
     489                 :     ** second pass:
     490                 :     ** set nas[].type
     491                 :     */
     492                 : 
     493               0 :     p = fmt;
     494               0 :     while( ( c = *p++ ) != 0 ){
     495               0 :         if( c != '%' )  continue;
     496               0 :             c = *p++;
     497               0 :         if( c == '%' )  continue;
     498                 : 
     499               0 :         cn = 0;
     500               0 :         while( c && c != '$' ){     /* should improve error check later */
     501               0 :             cn = cn*10 + c - '0';
     502               0 :             c = *p++;
     503                 :         }
     504                 : 
     505               0 :         if( !c || cn < 1 || cn > number ){
     506               0 :             *rv = -1;
     507               0 :             break;
     508                 :         }
     509                 : 
     510                 :         /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
     511               0 :         cn--;
     512               0 :         if( nas[cn].type != TYPE_UNKNOWN )
     513               0 :             continue;
     514                 : 
     515               0 :         c = *p++;
     516                 : 
     517                 :         /* width */
     518               0 :         if (c == '*') {
     519                 :             /* not supported feature, for the argument is not numbered */
     520               0 :             *rv = -1;
     521               0 :             break;
     522                 :         }
     523                 : 
     524               0 :         while ((c >= '0') && (c <= '9')) {
     525               0 :             c = *p++;
     526                 :         }
     527                 : 
     528                 :         /* precision */
     529               0 :         if (c == '.') {
     530               0 :             c = *p++;
     531               0 :             if (c == '*') {
     532                 :                 /* not supported feature, for the argument is not numbered */
     533               0 :                 *rv = -1;
     534               0 :                 break;
     535                 :             }
     536                 : 
     537               0 :             while ((c >= '0') && (c <= '9')) {
     538               0 :                 c = *p++;
     539                 :             }
     540                 :         }
     541                 : 
     542                 :         /* size */
     543               0 :         nas[cn].type = TYPE_INTN;
     544               0 :         if (c == 'h') {
     545               0 :             nas[cn].type = TYPE_INT16;
     546               0 :             c = *p++;
     547               0 :         } else if (c == 'L') {
     548                 :             /* XXX not quite sure here */
     549               0 :             nas[cn].type = TYPE_INT64;
     550               0 :             c = *p++;
     551               0 :         } else if (c == 'l') {
     552               0 :             nas[cn].type = TYPE_INT32;
     553               0 :             c = *p++;
     554               0 :             if (c == 'l') {
     555               0 :                 nas[cn].type = TYPE_INT64;
     556               0 :                 c = *p++;
     557                 :             }
     558                 :         }
     559                 : 
     560                 :         /* format */
     561               0 :         switch (c) {
     562                 :         case 'd':
     563                 :         case 'c':
     564                 :         case 'i':
     565                 :         case 'o':
     566                 :         case 'u':
     567                 :         case 'x':
     568                 :         case 'X':
     569               0 :             break;
     570                 : 
     571                 :         case 'e':
     572                 :         case 'f':
     573                 :         case 'g':
     574               0 :             nas[ cn ].type = TYPE_DOUBLE;
     575               0 :             break;
     576                 : 
     577                 :         case 'p':
     578                 :             /* XXX should use cpp */
     579                 :             if (sizeof(void *) == sizeof(int32_t)) {
     580               0 :                 nas[ cn ].type = TYPE_UINT32;
     581                 :             } else if (sizeof(void *) == sizeof(int64_t)) {
     582                 :                 nas[ cn ].type = TYPE_UINT64;
     583                 :             } else if (sizeof(void *) == sizeof(int)) {
     584                 :                 nas[ cn ].type = TYPE_UINTN;
     585                 :             } else {
     586                 :                 nas[ cn ].type = TYPE_UNKNOWN;
     587                 :             }
     588               0 :             break;
     589                 : 
     590                 :         case 'C':
     591                 :         case 'S':
     592                 :         case 'E':
     593                 :         case 'G':
     594                 :             /* XXX not supported I suppose */
     595               0 :             JS_ASSERT(0);
     596               0 :             nas[ cn ].type = TYPE_UNKNOWN;
     597               0 :             break;
     598                 : 
     599                 :         case 's':
     600               0 :             nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
     601               0 :             break;
     602                 : 
     603                 :         case 'n':
     604               0 :             nas[ cn ].type = TYPE_INTSTR;
     605               0 :             break;
     606                 : 
     607                 :         default:
     608               0 :             JS_ASSERT(0);
     609               0 :             nas[ cn ].type = TYPE_UNKNOWN;
     610               0 :             break;
     611                 :         }
     612                 : 
     613                 :         /* get a legal para. */
     614               0 :         if( nas[ cn ].type == TYPE_UNKNOWN ){
     615               0 :             *rv = -1;
     616               0 :             break;
     617                 :         }
     618                 :     }
     619                 : 
     620                 : 
     621                 :     /*
     622                 :     ** third pass
     623                 :     ** fill the nas[cn].ap
     624                 :     */
     625                 : 
     626               0 :     if( *rv < 0 ){
     627               0 :         if( nas != nasArray )
     628               0 :             UnwantedForeground::free_( nas );
     629               0 :         return NULL;
     630                 :     }
     631                 : 
     632               0 :     cn = 0;
     633               0 :     while( cn < number ){
     634               0 :         if( nas[cn].type == TYPE_UNKNOWN ){
     635               0 :             cn++;
     636               0 :             continue;
     637                 :         }
     638                 : 
     639               0 :         VARARGS_ASSIGN(nas[cn].ap, ap);
     640                 : 
     641               0 :         switch( nas[cn].type ){
     642                 :         case TYPE_INT16:
     643                 :         case TYPE_UINT16:
     644                 :         case TYPE_INTN:
     645               0 :         case TYPE_UINTN:                (void)va_arg( ap, int );             break;
     646                 : 
     647               0 :         case TYPE_INT32:                (void)va_arg( ap, int32_t );            break;
     648                 : 
     649               0 :         case TYPE_UINT32:       (void)va_arg( ap, uint32_t );   break;
     650                 : 
     651               0 :         case TYPE_INT64:        (void)va_arg( ap, int64_t );            break;
     652                 : 
     653               0 :         case TYPE_UINT64:       (void)va_arg( ap, uint64_t );           break;
     654                 : 
     655               0 :         case TYPE_STRING:       (void)va_arg( ap, char* );              break;
     656                 : 
     657               0 :         case TYPE_WSTRING:      (void)va_arg( ap, jschar* );            break;
     658                 : 
     659               0 :         case TYPE_INTSTR:       (void)va_arg( ap, int* );            break;
     660                 : 
     661               0 :         case TYPE_DOUBLE:       (void)va_arg( ap, double );             break;
     662                 : 
     663                 :         default:
     664               0 :             if( nas != nasArray )
     665               0 :                 UnwantedForeground::free_( nas );
     666               0 :             *rv = -1;
     667               0 :             return NULL;
     668                 :         }
     669                 : 
     670               0 :         cn++;
     671                 :     }
     672                 : 
     673                 : 
     674               0 :     return nas;
     675                 : }
     676                 : 
     677                 : /*
     678                 : ** The workhorse sprintf code.
     679                 : */
     680        19975350 : static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
     681                 : {
     682                 :     char c;
     683                 :     int flags, width, prec, radix, type;
     684                 :     union {
     685                 :         char ch;
     686                 :         jschar wch;
     687                 :         int i;
     688                 :         long l;
     689                 :         int64_t ll;
     690                 :         double d;
     691                 :         const char *s;
     692                 :         const jschar* ws;
     693                 :         int *ip;
     694                 :     } u;
     695                 :     const char *fmt0;
     696                 :     static const char hex[] = "0123456789abcdef";
     697                 :     static const char HEX[] = "0123456789ABCDEF";
     698                 :     const char *hexp;
     699                 :     int rv, i;
     700        19975350 :     struct NumArgState *nas = NULL;
     701                 :     struct NumArgState nasArray[ NAS_DEFAULT_NUM ];
     702                 :     char pattern[20];
     703        19975350 :     const char *dolPt = NULL;  /* in "%4$.2f", dolPt will poiont to . */
     704                 :     uint8_t utf8buf[6];
     705                 :     int utf8len;
     706                 : 
     707                 :     /*
     708                 :     ** build an argument array, IF the fmt is numbered argument
     709                 :     ** list style, to contain the Numbered Argument list pointers
     710                 :     */
     711                 : 
     712        19975350 :     nas = BuildArgArray( fmt, ap, &rv, nasArray );
     713        19975350 :     if( rv < 0 ){
     714                 :         /* the fmt contains error Numbered Argument format, jliu@netscape.com */
     715               0 :         JS_ASSERT(0);
     716               0 :         return rv;
     717                 :     }
     718                 : 
     719       255588963 :     while ((c = *fmt++) != 0) {
     720       215638263 :         if (c != '%') {
     721       194933838 :             rv = (*ss->stuff)(ss, fmt - 1, 1);
     722       194933838 :             if (rv < 0) {
     723               0 :                 return rv;
     724                 :             }
     725       194933838 :             continue;
     726                 :         }
     727        20704425 :         fmt0 = fmt - 1;
     728                 : 
     729                 :         /*
     730                 :         ** Gobble up the % format string. Hopefully we have handled all
     731                 :         ** of the strange cases!
     732                 :         */
     733        20704425 :         flags = 0;
     734        20704425 :         c = *fmt++;
     735        20704425 :         if (c == '%') {
     736                 :             /* quoting a % with %% */
     737            8892 :             rv = (*ss->stuff)(ss, fmt - 1, 1);
     738            8892 :             if (rv < 0) {
     739               0 :                 return rv;
     740                 :             }
     741            8892 :             continue;
     742                 :         }
     743                 : 
     744        20695533 :         if( nas != NULL ){
     745                 :             /* the fmt contains the Numbered Arguments feature */
     746               0 :             i = 0;
     747               0 :             while( c && c != '$' ){         /* should imporve error check later */
     748               0 :                 i = ( i * 10 ) + ( c - '0' );
     749               0 :                 c = *fmt++;
     750                 :             }
     751                 : 
     752               0 :             if( nas[i-1].type == TYPE_UNKNOWN ){
     753               0 :                 if( nas && ( nas != nasArray ) )
     754               0 :                     UnwantedForeground::free_( nas );
     755               0 :                 return -1;
     756                 :             }
     757                 : 
     758               0 :             ap = nas[i-1].ap;
     759               0 :             dolPt = fmt;
     760               0 :             c = *fmt++;
     761                 :         }
     762                 : 
     763                 :         /*
     764                 :          * Examine optional flags.  Note that we do not implement the
     765                 :          * '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
     766                 :          * somewhat ambiguous and not ideal, which is perhaps why
     767                 :          * the various sprintf() implementations are inconsistent
     768                 :          * on this feature.
     769                 :          */
     770        41736099 :         while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
     771          345033 :             if (c == '-') flags |= FLAG_LEFT;
     772          345033 :             if (c == '+') flags |= FLAG_SIGNED;
     773          345033 :             if (c == ' ') flags |= FLAG_SPACED;
     774          345033 :             if (c == '0') flags |= FLAG_ZEROS;
     775          345033 :             c = *fmt++;
     776                 :         }
     777        20695533 :         if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
     778        20695533 :         if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
     779                 : 
     780                 :         /* width */
     781        20695533 :         if (c == '*') {
     782            6953 :             c = *fmt++;
     783            6953 :             width = va_arg(ap, int);
     784                 :         } else {
     785        20688580 :             width = 0;
     786        42151200 :             while ((c >= '0') && (c <= '9')) {
     787          774040 :                 width = (width * 10) + (c - '0');
     788          774040 :                 c = *fmt++;
     789                 :             }
     790                 :         }
     791                 : 
     792                 :         /* precision */
     793        20695533 :         prec = -1;
     794        20695533 :         if (c == '.') {
     795           45547 :             c = *fmt++;
     796           45547 :             if (c == '*') {
     797               0 :                 c = *fmt++;
     798               0 :                 prec = va_arg(ap, int);
     799                 :             } else {
     800           45547 :                 prec = 0;
     801          136641 :                 while ((c >= '0') && (c <= '9')) {
     802           45547 :                     prec = (prec * 10) + (c - '0');
     803           45547 :                     c = *fmt++;
     804                 :                 }
     805                 :             }
     806                 :         }
     807                 : 
     808                 :         /* size */
     809        20695533 :         type = TYPE_INTN;
     810        20695533 :         if (c == 'h') {
     811               0 :             type = TYPE_INT16;
     812               0 :             c = *fmt++;
     813        20695533 :         } else if (c == 'L') {
     814                 :             /* XXX not quite sure here */
     815               0 :             type = TYPE_INT64;
     816               0 :             c = *fmt++;
     817        20695533 :         } else if (c == 'l') {
     818           98602 :             type = TYPE_INT32;
     819           98602 :             c = *fmt++;
     820           98602 :             if (c == 'l') {
     821               0 :                 type = TYPE_INT64;
     822               0 :                 c = *fmt++;
     823                 :             }
     824                 :         }
     825                 : 
     826                 :         /* format */
     827        20695533 :         hexp = hex;
     828        20695533 :         switch (c) {
     829                 :           case 'd': case 'i':                   /* decimal/integer */
     830          432224 :             radix = 10;
     831          432224 :             goto fetch_and_convert;
     832                 : 
     833                 :           case 'o':                             /* octal */
     834               0 :             radix = 8;
     835               0 :             type |= 1;
     836               0 :             goto fetch_and_convert;
     837                 : 
     838                 :           case 'u':                             /* unsigned decimal */
     839          764415 :             radix = 10;
     840          764415 :             type |= 1;
     841          764415 :             goto fetch_and_convert;
     842                 : 
     843                 :           case 'x':                             /* unsigned hex */
     844           39368 :             radix = 16;
     845           39368 :             type |= 1;
     846           39368 :             goto fetch_and_convert;
     847                 : 
     848                 :           case 'X':                             /* unsigned HEX */
     849              58 :             radix = 16;
     850              58 :             hexp = HEX;
     851              58 :             type |= 1;
     852              58 :             goto fetch_and_convert;
     853                 : 
     854                 :           fetch_and_convert:
     855        19725471 :             switch (type) {
     856                 :               case TYPE_INT16:
     857               0 :                 u.l = va_arg(ap, int);
     858               0 :                 if (u.l < 0) {
     859               0 :                     u.l = -u.l;
     860               0 :                     flags |= FLAG_NEG;
     861                 :                 }
     862               0 :                 goto do_long;
     863                 :               case TYPE_UINT16:
     864               0 :                 u.l = va_arg(ap, int) & 0xffff;
     865               0 :                 goto do_long;
     866                 :               case TYPE_INTN:
     867          359864 :                 u.l = va_arg(ap, int);
     868          359864 :                 if (u.l < 0) {
     869             248 :                     u.l = -u.l;
     870             248 :                     flags |= FLAG_NEG;
     871                 :                 }
     872          359864 :                 goto do_long;
     873                 :               case TYPE_UINTN:
     874          777599 :                 u.l = (long)va_arg(ap, unsigned int);
     875          777599 :                 goto do_long;
     876                 : 
     877                 :               case TYPE_INT32:
     878           72360 :                 u.l = va_arg(ap, int32_t);
     879           72360 :                 if (u.l < 0) {
     880               0 :                     u.l = -u.l;
     881               0 :                     flags |= FLAG_NEG;
     882                 :                 }
     883           72360 :                 goto do_long;
     884                 :               case TYPE_UINT32:
     885        18515648 :                 u.l = (long)va_arg(ap, uint32_t);
     886                 :               do_long:
     887        19725471 :                 rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
     888        19725471 :                 if (rv < 0) {
     889               0 :                     return rv;
     890                 :                 }
     891        19725471 :                 break;
     892                 : 
     893                 :               case TYPE_INT64:
     894               0 :                 u.ll = va_arg(ap, int64_t);
     895               0 :                 if (u.ll < 0) {
     896               0 :                     u.ll = -u.ll;
     897               0 :                     flags |= FLAG_NEG;
     898                 :                 }
     899               0 :                 goto do_longlong;
     900                 :               case TYPE_UINT64:
     901               0 :                 u.ll = va_arg(ap, uint64_t);
     902                 :               do_longlong:
     903               0 :                 rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
     904               0 :                 if (rv < 0) {
     905               0 :                     return rv;
     906                 :                 }
     907               0 :                 break;
     908                 :             }
     909        19725471 :             break;
     910                 : 
     911                 :           case 'e':
     912                 :           case 'E':
     913                 :           case 'f':
     914                 :           case 'g':
     915           42840 :             u.d = va_arg(ap, double);
     916           42840 :             if( nas != NULL ){
     917               0 :                 i = fmt - dolPt;
     918               0 :                 if( i < (int)sizeof( pattern ) ){
     919               0 :                     pattern[0] = '%';
     920               0 :                     js_memcpy( &pattern[1], dolPt, (size_t)i );
     921               0 :                     rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
     922                 :                 }
     923                 :             } else
     924           42840 :                 rv = cvt_f(ss, u.d, fmt0, fmt);
     925                 : 
     926           42840 :             if (rv < 0) {
     927               0 :                 return rv;
     928                 :             }
     929           42840 :             break;
     930                 : 
     931                 :           case 'c':
     932           14670 :             if ((flags & FLAG_LEFT) == 0) {
     933           29340 :                 while (width-- > 1) {
     934               0 :                     rv = (*ss->stuff)(ss, " ", 1);
     935               0 :                     if (rv < 0) {
     936               0 :                         return rv;
     937                 :                     }
     938                 :                 }
     939                 :             }
     940           14670 :             switch (type) {
     941                 :               case TYPE_INT16:
     942                 :                 /* Treat %hc as %c unless js_CStringsAreUTF8. */
     943               0 :                 if (js_CStringsAreUTF8) {
     944               0 :                     u.wch = va_arg(ap, int);
     945               0 :                     utf8len = js_OneUcs4ToUtf8Char (utf8buf, u.wch);
     946               0 :                     rv = (*ss->stuff)(ss, (char *)utf8buf, utf8len);
     947               0 :                     break;
     948                 :                 }
     949                 :               case TYPE_INTN:
     950           14670 :                 u.ch = va_arg(ap, int);
     951           14670 :                 rv = (*ss->stuff)(ss, &u.ch, 1);
     952           14670 :                 break;
     953                 :             }
     954           14670 :             if (rv < 0) {
     955               0 :                 return rv;
     956                 :             }
     957           14670 :             if (flags & FLAG_LEFT) {
     958               0 :                 while (width-- > 1) {
     959               0 :                     rv = (*ss->stuff)(ss, " ", 1);
     960               0 :                     if (rv < 0) {
     961               0 :                         return rv;
     962                 :                     }
     963                 :                 }
     964                 :             }
     965           14670 :             break;
     966                 : 
     967                 :           case 'p':
     968                 :             if (sizeof(void *) == sizeof(int32_t)) {
     969        18489406 :                 type = TYPE_UINT32;
     970                 :             } else if (sizeof(void *) == sizeof(int64_t)) {
     971                 :                 type = TYPE_UINT64;
     972                 :             } else if (sizeof(void *) == sizeof(int)) {
     973                 :                 type = TYPE_UINTN;
     974                 :             } else {
     975                 :                 JS_ASSERT(0);
     976                 :                 break;
     977                 :             }
     978        18489406 :             radix = 16;
     979        18489406 :             goto fetch_and_convert;
     980                 : 
     981                 : #if 0
     982                 :           case 'C':
     983                 :           case 'S':
     984                 :           case 'E':
     985                 :           case 'G':
     986                 :             /* XXX not supported I suppose */
     987                 :             JS_ASSERT(0);
     988                 :             break;
     989                 : #endif
     990                 : 
     991                 :           case 's':
     992          912552 :             if(type == TYPE_INT16) {
     993                 :                 /*
     994                 :                  * This would do a simple string/byte conversion
     995                 :                  * unless js_CStringsAreUTF8.
     996                 :                  */
     997               0 :                 u.ws = va_arg(ap, const jschar*);
     998               0 :                 rv = cvt_ws(ss, u.ws, width, prec, flags);
     999                 :             } else {
    1000          912552 :                 u.s = va_arg(ap, const char*);
    1001          912552 :                 rv = cvt_s(ss, u.s, width, prec, flags);
    1002                 :             }
    1003          912552 :             if (rv < 0) {
    1004               0 :                 return rv;
    1005                 :             }
    1006          912552 :             break;
    1007                 : 
    1008                 :           case 'n':
    1009               0 :             u.ip = va_arg(ap, int*);
    1010               0 :             if (u.ip) {
    1011               0 :                 *u.ip = ss->cur - ss->base;
    1012                 :             }
    1013               0 :             break;
    1014                 : 
    1015                 :           default:
    1016                 :             /* Not a % token after all... skip it */
    1017                 : #if 0
    1018                 :             JS_ASSERT(0);
    1019                 : #endif
    1020               0 :             rv = (*ss->stuff)(ss, "%", 1);
    1021               0 :             if (rv < 0) {
    1022               0 :                 return rv;
    1023                 :             }
    1024               0 :             rv = (*ss->stuff)(ss, fmt - 1, 1);
    1025               0 :             if (rv < 0) {
    1026               0 :                 return rv;
    1027                 :             }
    1028                 :         }
    1029                 :     }
    1030                 : 
    1031                 :     /* Stuff trailing NUL */
    1032        19975350 :     rv = (*ss->stuff)(ss, "\0", 1);
    1033                 : 
    1034        19975350 :     if( nas && ( nas != nasArray ) ){
    1035               0 :         UnwantedForeground::free_( nas );
    1036                 :     }
    1037                 : 
    1038        19975350 :     return rv;
    1039                 : }
    1040                 : 
    1041                 : /************************************************************************/
    1042                 : 
    1043               0 : static int FuncStuff(SprintfState *ss, const char *sp, uint32_t len)
    1044                 : {
    1045                 :     int rv;
    1046                 : 
    1047               0 :     rv = (*ss->func)(ss->arg, sp, len);
    1048               0 :     if (rv < 0) {
    1049               0 :         return rv;
    1050                 :     }
    1051               0 :     ss->maxlen += len;
    1052               0 :     return 0;
    1053                 : }
    1054                 : 
    1055               0 : JS_PUBLIC_API(uint32_t) JS_sxprintf(JSStuffFunc func, void *arg,
    1056                 :                                     const char *fmt, ...)
    1057                 : {
    1058                 :     va_list ap;
    1059                 :     int rv;
    1060                 : 
    1061               0 :     va_start(ap, fmt);
    1062               0 :     rv = JS_vsxprintf(func, arg, fmt, ap);
    1063               0 :     va_end(ap);
    1064               0 :     return rv;
    1065                 : }
    1066                 : 
    1067               0 : JS_PUBLIC_API(uint32_t) JS_vsxprintf(JSStuffFunc func, void *arg,
    1068                 :                                      const char *fmt, va_list ap)
    1069                 : {
    1070                 :     SprintfState ss;
    1071                 :     int rv;
    1072                 : 
    1073               0 :     ss.stuff = FuncStuff;
    1074               0 :     ss.func = func;
    1075               0 :     ss.arg = arg;
    1076               0 :     ss.maxlen = 0;
    1077               0 :     rv = dosprintf(&ss, fmt, ap);
    1078               0 :     return (rv < 0) ? UINT32_MAX : ss.maxlen;
    1079                 : }
    1080                 : 
    1081                 : /*
    1082                 : ** Stuff routine that automatically grows the malloc'd output buffer
    1083                 : ** before it overflows.
    1084                 : */
    1085         8101448 : static int GrowStuff(SprintfState *ss, const char *sp, uint32_t len)
    1086                 : {
    1087                 :     ptrdiff_t off;
    1088                 :     char *newbase;
    1089                 :     uint32_t newlen;
    1090                 : 
    1091         8101448 :     off = ss->cur - ss->base;
    1092         8101448 :     if (off + len >= ss->maxlen) {
    1093                 :         /* Grow the buffer */
    1094         1436450 :         newlen = ss->maxlen + ((len > 32) ? len : 32);
    1095         1436450 :         if (ss->base) {
    1096          419093 :             newbase = (char*) OffTheBooks::realloc_(ss->base, newlen);
    1097                 :         } else {
    1098         1017357 :             newbase = (char*) OffTheBooks::malloc_(newlen);
    1099                 :         }
    1100         1436450 :         if (!newbase) {
    1101                 :             /* Ran out of memory */
    1102               0 :             return -1;
    1103                 :         }
    1104         1436450 :         ss->base = newbase;
    1105         1436450 :         ss->maxlen = newlen;
    1106         1436450 :         ss->cur = ss->base + off;
    1107                 :     }
    1108                 : 
    1109                 :     /* Copy data */
    1110        38709535 :     while (len) {
    1111        22506639 :         --len;
    1112        22506639 :         *ss->cur++ = *sp++;
    1113                 :     }
    1114         8101448 :     JS_ASSERT(uint32_t(ss->cur - ss->base) <= ss->maxlen);
    1115         8101448 :     return 0;
    1116                 : }
    1117                 : 
    1118                 : /*
    1119                 : ** sprintf into a malloc'd buffer
    1120                 : */
    1121          122374 : JS_PUBLIC_API(char *) JS_smprintf(const char *fmt, ...)
    1122                 : {
    1123                 :     va_list ap;
    1124                 :     char *rv;
    1125                 : 
    1126          122374 :     va_start(ap, fmt);
    1127          122374 :     rv = JS_vsmprintf(fmt, ap);
    1128          122374 :     va_end(ap);
    1129          122374 :     return rv;
    1130                 : }
    1131                 : 
    1132                 : /*
    1133                 : ** Free memory allocated, for the caller, by JS_smprintf
    1134                 : */
    1135          121679 : JS_PUBLIC_API(void) JS_smprintf_free(char *mem)
    1136                 : {
    1137          121679 :         Foreground::free_(mem);
    1138          121679 : }
    1139                 : 
    1140          980590 : JS_PUBLIC_API(char *) JS_vsmprintf(const char *fmt, va_list ap)
    1141                 : {
    1142                 :     SprintfState ss;
    1143                 :     int rv;
    1144                 : 
    1145          980590 :     ss.stuff = GrowStuff;
    1146          980590 :     ss.base = 0;
    1147          980590 :     ss.cur = 0;
    1148          980590 :     ss.maxlen = 0;
    1149          980590 :     rv = dosprintf(&ss, fmt, ap);
    1150          980590 :     if (rv < 0) {
    1151               0 :         if (ss.base) {
    1152               0 :             Foreground::free_(ss.base);
    1153                 :         }
    1154               0 :         return 0;
    1155                 :     }
    1156          980590 :     return ss.base;
    1157                 : }
    1158                 : 
    1159                 : /*
    1160                 : ** Stuff routine that discards overflow data
    1161                 : */
    1162       228786675 : static int LimitStuff(SprintfState *ss, const char *sp, uint32_t len)
    1163                 : {
    1164       228786675 :     uint32_t limit = ss->maxlen - (ss->cur - ss->base);
    1165                 : 
    1166       228786675 :     if (len > limit) {
    1167               0 :         len = limit;
    1168                 :     }
    1169       816337724 :     while (len) {
    1170       358764374 :         --len;
    1171       358764374 :         *ss->cur++ = *sp++;
    1172                 :     }
    1173       228786675 :     return 0;
    1174                 : }
    1175                 : 
    1176                 : /*
    1177                 : ** sprintf into a fixed size buffer. Make sure there is a NUL at the end
    1178                 : ** when finished.
    1179                 : */
    1180        18771117 : JS_PUBLIC_API(uint32_t) JS_snprintf(char *out, uint32_t outlen, const char *fmt, ...)
    1181                 : {
    1182                 :     va_list ap;
    1183                 :     int rv;
    1184                 : 
    1185        18771117 :     JS_ASSERT(int32_t(outlen) > 0);
    1186        18771117 :     if (int32_t(outlen) <= 0) {
    1187               0 :         return 0;
    1188                 :     }
    1189                 : 
    1190        18771117 :     va_start(ap, fmt);
    1191        18771117 :     rv = JS_vsnprintf(out, outlen, fmt, ap);
    1192        18771117 :     va_end(ap);
    1193        18771117 :     return rv;
    1194                 : }
    1195                 : 
    1196        18869811 : JS_PUBLIC_API(uint32_t) JS_vsnprintf(char *out, uint32_t outlen,const char *fmt,
    1197                 :                                      va_list ap)
    1198                 : {
    1199                 :     SprintfState ss;
    1200                 :     uint32_t n;
    1201                 : 
    1202        18869811 :     JS_ASSERT(int32_t(outlen) > 0);
    1203        18869811 :     if (int32_t(outlen) <= 0) {
    1204               0 :         return 0;
    1205                 :     }
    1206                 : 
    1207        18869811 :     ss.stuff = LimitStuff;
    1208        18869811 :     ss.base = out;
    1209        18869811 :     ss.cur = out;
    1210        18869811 :     ss.maxlen = outlen;
    1211        18869811 :     (void) dosprintf(&ss, fmt, ap);
    1212                 : 
    1213                 :     /* If we added chars, and we didn't append a null, do it now. */
    1214        18869811 :     if( (ss.cur != ss.base) && (ss.cur[-1] != '\0') )
    1215               0 :         ss.cur[-1] = '\0';
    1216                 : 
    1217        18869811 :     n = ss.cur - ss.base;
    1218        18869811 :     return n ? n - 1 : n;
    1219                 : }
    1220                 : 
    1221          124949 : JS_PUBLIC_API(char *) JS_sprintf_append(char *last, const char *fmt, ...)
    1222                 : {
    1223                 :     va_list ap;
    1224                 :     char *rv;
    1225                 : 
    1226          124949 :     va_start(ap, fmt);
    1227          124949 :     rv = JS_vsprintf_append(last, fmt, ap);
    1228          124949 :     va_end(ap);
    1229          124949 :     return rv;
    1230                 : }
    1231                 : 
    1232          124949 : JS_PUBLIC_API(char *) JS_vsprintf_append(char *last, const char *fmt, va_list ap)
    1233                 : {
    1234                 :     SprintfState ss;
    1235                 :     int rv;
    1236                 : 
    1237          124949 :     ss.stuff = GrowStuff;
    1238          124949 :     if (last) {
    1239           88182 :         int lastlen = strlen(last);
    1240           88182 :         ss.base = last;
    1241           88182 :         ss.cur = last + lastlen;
    1242           88182 :         ss.maxlen = lastlen;
    1243                 :     } else {
    1244           36767 :         ss.base = 0;
    1245           36767 :         ss.cur = 0;
    1246           36767 :         ss.maxlen = 0;
    1247                 :     }
    1248          124949 :     rv = dosprintf(&ss, fmt, ap);
    1249          124949 :     if (rv < 0) {
    1250               0 :         if (ss.base) {
    1251               0 :             Foreground::free_(ss.base);
    1252                 :         }
    1253               0 :         return 0;
    1254                 :     }
    1255          124949 :     return ss.base;
    1256                 : }
    1257                 : 

Generated by: LCOV version 1.7