LCOV - app.info - js/src/jsprf.cpp

LCOV - code coverage report
| Current view: | directory - js/src - jsprf.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 541 | 271 | 50.1 %
| Date: | 2012-04-07 | Functions: | 21 | 15 | 71.4 %

           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          519058 : static int fill2(SprintfState *ss, const char *src, int srclen, int width,
         123                 :                 int flags)
         124                 : {
         125          519058 :     char space = ' ';
         126                 :     int rv;
         127                 :
         128          519058 :     width -= srclen;
         129          519058 :     if ((width > 0) && ((flags & FLAG_LEFT) == 0)) {    /* Right adjusting */
         130            1404 :         if (flags & FLAG_ZEROS) {
         131               0 :             space = '0';
         132                 :         }
         133            9576 :         while (--width >= 0) {
         134            6768 :             rv = (*ss->stuff)(ss, &space, 1);
         135            6768 :             if (rv < 0) {
         136               0 :                 return rv;
         137                 :             }
         138                 :         }
         139                 :     }
         140                 :
         141                 :     /* Copy out the source data */
         142          519058 :     rv = (*ss->stuff)(ss, src, uint32_t(srclen));
         143          519058 :     if (rv < 0) {
         144               0 :         return rv;
         145                 :     }
         146                 :
         147          519058 :     if ((width > 0) && ((flags & FLAG_LEFT) != 0)) {    /* Left adjusting */
         148          479529 :         while (--width >= 0) {
         149          258201 :             rv = (*ss->stuff)(ss, &space, 1);
         150          258201 :             if (rv < 0) {
         151               0 :                 return rv;
         152                 :             }
         153                 :         }
         154                 :     }
         155          519058 :     return 0;
         156                 : }
         157                 :
         158                 : /*
         159                 : ** Fill a number. The order is: optional-sign zero-filling conversion-digits
         160                 : */
         161        19110403 : static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
         162                 :                   int prec, int type, int flags)
         163                 : {
         164        19110403 :     int zerowidth = 0;
         165        19110403 :     int precwidth = 0;
         166        19110403 :     int signwidth = 0;
         167        19110403 :     int leftspaces = 0;
         168        19110403 :     int rightspaces = 0;
         169                 :     int cvtwidth;
         170                 :     int rv;
         171                 :     char sign;
         172                 :
         173        19110403 :     if ((type & 1) == 0) {
         174          352256 :         if (flags & FLAG_NEG) {
         175              63 :             sign = '-';
         176              63 :             signwidth = 1;
         177          352193 :         } else if (flags & FLAG_SIGNED) {
         178           68319 :             sign = '+';
         179           68319 :             signwidth = 1;
         180          283874 :         } else if (flags & FLAG_SPACED) {
         181               0 :             sign = ' ';
         182               0 :             signwidth = 1;
         183                 :         }
         184                 :     }
         185        19110403 :     cvtwidth = signwidth + srclen;
         186                 :
         187        19110403 :     if (prec > 0) {
         188            1089 :         if (prec > srclen) {
         189             498 :             precwidth = prec - srclen;          /* Need zero filling */
         190             498 :             cvtwidth += precwidth;
         191                 :         }
         192                 :     }
         193                 :
         194        19110403 :     if ((flags & FLAG_ZEROS) && (prec < 0)) {
         195          165951 :         if (width > cvtwidth) {
         196           32472 :             zerowidth = width - cvtwidth;       /* Zero filling */
         197           32472 :             cvtwidth += zerowidth;
         198                 :         }
         199                 :     }
         200                 :
         201        19110403 :     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        19110403 :         if (width > cvtwidth) {
         208                 :             /* Space filling on the left (i.e. right adjusting) */
         209          298944 :             leftspaces = width - cvtwidth;
         210                 :         }
         211                 :     }
         212        39101798 :     while (--leftspaces >= 0) {
         213          880992 :         rv = (*ss->stuff)(ss, " ", 1);
         214          880992 :         if (rv < 0) {
         215               0 :             return rv;
         216                 :         }
         217                 :     }
         218        19110403 :     if (signwidth) {
         219           68382 :         rv = (*ss->stuff)(ss, &sign, 1);
         220           68382 :         if (rv < 0) {
         221               0 :             return rv;
         222                 :         }
         223                 :     }
         224        38221349 :     while (--precwidth >= 0) {
         225             543 :         rv = (*ss->stuff)(ss, "0", 1);
         226             543 :         if (rv < 0) {
         227               0 :             return rv;
         228                 :         }
         229                 :     }
         230        38257022 :     while (--zerowidth >= 0) {
         231           36216 :         rv = (*ss->stuff)(ss, "0", 1);
         232           36216 :         if (rv < 0) {
         233               0 :             return rv;
         234                 :         }
         235                 :     }
         236        19110403 :     rv = (*ss->stuff)(ss, src, uint32_t(srclen));
         237        19110403 :     if (rv < 0) {
         238               0 :         return rv;
         239                 :     }
         240        38220806 :     while (--rightspaces >= 0) {
         241               0 :         rv = (*ss->stuff)(ss, " ", 1);
         242               0 :         if (rv < 0) {
         243               0 :             return rv;
         244                 :         }
         245                 :     }
         246        19110403 :     return 0;
         247                 : }
         248                 :
         249                 : /*
         250                 : ** Convert a long into its printable form
         251                 : */
         252        19110403 : 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        19110403 :     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        19110403 :     cvt = cvtbuf + sizeof(cvtbuf);
         270        19110403 :     digits = 0;
         271       184923474 :     while (num) {
         272       146702668 :         int digit = (((unsigned long)num) % radix) & 0xF;
         273       146702668 :         *--cvt = hexp[digit];
         274       146702668 :         digits++;
         275       146702668 :         num = (long)(((unsigned long)num) / radix);
         276                 :     }
         277        19110403 :     if (digits == 0) {
         278          165662 :         *--cvt = '0';
         279          165662 :         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        19110403 :     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             162 : static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
         336                 : {
         337                 :     char fin[20];
         338                 :     char fout[300];
         339             162 :     int amount = fmt1 - fmt0;
         340                 :
         341             162 :     JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin)));
         342             162 :     if (amount >= (int)sizeof(fin)) {
         343                 :         /* Totally bogus % command to sprintf. Just ignore it */
         344               0 :         return 0;
         345                 :     }
         346             162 :     js_memcpy(fin, fmt0, (size_t)amount);
         347             162 :     fin[amount] = 0;
         348                 :
         349                 :     /* Convert floating point using the native sprintf code */
         350                 : #ifdef DEBUG
         351                 :     {
         352             162 :         const char *p = fin;
         353             648 :         while (*p) {
         354             324 :             JS_ASSERT(*p != 'L');
         355             324 :             p++;
         356                 :         }
         357                 :     }
         358                 : #endif
         359             162 :     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             162 :     JS_ASSERT(strlen(fout) < sizeof(fout));
         367                 :
         368             162 :     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          519058 : static int cvt_s(SprintfState *ss, const char *s, int width, int prec,
         377                 :                  int flags)
         378                 : {
         379                 :     int slen;
         380                 :
         381          519058 :     if (prec == 0)
         382               0 :         return 0;
         383                 :
         384                 :     /* Limit string length by precision value */
         385          519058 :     slen = s ? strlen(s) : 6;
         386          519058 :     if (prec > 0) {
         387               0 :         if (prec < slen) {
         388               0 :             slen = prec;
         389                 :         }
         390                 :     }
         391                 :
         392                 :     /* and away we go */
         393          519058 :     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        19171408 : static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArgState* nasArray )
         425                 : {
         426        19171408 :     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        19171408 :     p = fmt;
         438        19171408 :     *rv = 0;
         439        19171408 :     i = 0;
         440       246470647 :     while( ( c = *p++ ) != 0 ){
         441       208127831 :         if( c != '%' )
         442       188484852 :             continue;
         443        19642979 :         if( ( c = *p++ ) == '%' )       /* skip %% case */
         444               0 :             continue;
         445                 :
         446        40115785 :         while( c != 0 ){
         447        20472806 :             if( c > '9' || c < '0' ){
         448        19642979 :                 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        19642979 :                     if( number > 0 ){
         456               0 :                         *rv = -1;
         457               0 :                         return NULL;
         458                 :                     }
         459        19642979 :                     i = 1;
         460                 :                 }
         461        19642979 :                 break;
         462                 :             }
         463                 :
         464          829827 :             c = *p++;
         465                 :         }
         466                 :     }
         467                 :
         468        19171408 :     if( number == 0 ){
         469        19171408 :         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        19171408 : 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        19171408 :     struct NumArgState *nas = NULL;
         701                 :     struct NumArgState nasArray[ NAS_DEFAULT_NUM ];
         702                 :     char pattern[20];
         703        19171408 :     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        19171408 :     nas = BuildArgArray( fmt, ap, &rv, nasArray );
         713        19171408 :     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       246038949 :     while ((c = *fmt++) != 0) {
         720       207696133 :         if (c != '%') {
         721       188053154 :             rv = (*ss->stuff)(ss, fmt - 1, 1);
         722       188053154 :             if (rv < 0) {
         723               0 :                 return rv;
         724                 :             }
         725       188053154 :             continue;
         726                 :         }
         727        19642979 :         fmt0 = fmt - 1;
         728                 :
         729                 :         /*
         730                 :         ** Gobble up the % format string. Hopefully we have handled all
         731                 :         ** of the strange cases!
         732                 :         */
         733        19642979 :         flags = 0;
         734        19642979 :         c = *fmt++;
         735        19642979 :         if (c == '%') {
         736                 :             /* quoting a % with %% */
         737               0 :             rv = (*ss->stuff)(ss, fmt - 1, 1);
         738               0 :             if (rv < 0) {
         739               0 :                 return rv;
         740                 :             }
         741               0 :             continue;
         742                 :         }
         743                 :
         744        19642979 :         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        39649369 :         while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
         771          363411 :             if (c == '-') flags |= FLAG_LEFT;
         772          363411 :             if (c == '+') flags |= FLAG_SIGNED;
         773          363411 :             if (c == ' ') flags |= FLAG_SPACED;
         774          363411 :             if (c == '0') flags |= FLAG_ZEROS;
         775          363411 :             c = *fmt++;
         776                 :         }
         777        19642979 :         if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
         778        19642979 :         if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
         779                 :
         780                 :         /* width */
         781        19642979 :         if (c == '*') {
         782            2889 :             c = *fmt++;
         783            2889 :             width = va_arg(ap, int);
         784                 :         } else {
         785        19640090 :             width = 0;
         786        40073143 :             while ((c >= '0') && (c <= '9')) {
         787          792963 :                 width = (width * 10) + (c - '0');
         788          792963 :                 c = *fmt++;
         789                 :             }
         790                 :         }
         791                 :
         792                 :         /* precision */
         793        19642979 :         prec = -1;
         794        19642979 :         if (c == '.') {
         795            1089 :             c = *fmt++;
         796            1089 :             if (c == '*') {
         797               0 :                 c = *fmt++;
         798               0 :                 prec = va_arg(ap, int);
         799                 :             } else {
         800            1089 :                 prec = 0;
         801            3267 :                 while ((c >= '0') && (c <= '9')) {
         802            1089 :                     prec = (prec * 10) + (c - '0');
         803            1089 :                     c = *fmt++;
         804                 :                 }
         805                 :             }
         806                 :         }
         807                 :
         808                 :         /* size */
         809        19642979 :         type = TYPE_INTN;
         810        19642979 :         if (c == 'h') {
         811               0 :             type = TYPE_INT16;
         812               0 :             c = *fmt++;
         813        19642979 :         } else if (c == 'L') {
         814                 :             /* XXX not quite sure here */
         815               0 :             type = TYPE_INT64;
         816               0 :             c = *fmt++;
         817        19642979 :         } else if (c == 'l') {
         818          100084 :             type = TYPE_INT32;
         819          100084 :             c = *fmt++;
         820          100084 :             if (c == 'l') {
         821               0 :                 type = TYPE_INT64;
         822               0 :                 c = *fmt++;
         823                 :             }
         824                 :         }
         825                 :
         826                 :         /* format */
         827        19642979 :         hexp = hex;
         828        19642979 :         switch (c) {
         829                 :           case 'd': case 'i':                   /* decimal/integer */
         830          352256 :             radix = 10;
         831          352256 :             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          781789 :             radix = 10;
         840          781789 :             type |= 1;
         841          781789 :             goto fetch_and_convert;
         842                 :
         843                 :           case 'x':                             /* unsigned hex */
         844               0 :             radix = 16;
         845               0 :             type |= 1;
         846               0 :             goto fetch_and_convert;
         847                 :
         848                 :           case 'X':                             /* unsigned HEX */
         849               0 :             radix = 16;
         850               0 :             hexp = HEX;
         851               0 :             type |= 1;
         852               0 :             goto fetch_and_convert;
         853                 :
         854                 :           fetch_and_convert:
         855        19110403 :             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          277196 :                 u.l = va_arg(ap, int);
         868          277196 :                 if (u.l < 0) {
         869              63 :                     u.l = -u.l;
         870              63 :                     flags |= FLAG_NEG;
         871                 :                 }
         872          277196 :                 goto do_long;
         873                 :               case TYPE_UINTN:
         874          756765 :                 u.l = (long)va_arg(ap, unsigned int);
         875          756765 :                 goto do_long;
         876                 :
         877                 :               case TYPE_INT32:
         878           75060 :                 u.l = va_arg(ap, int32_t);
         879           75060 :                 if (u.l < 0) {
         880               0 :                     u.l = -u.l;
         881               0 :                     flags |= FLAG_NEG;
         882                 :                 }
         883           75060 :                 goto do_long;
         884                 :               case TYPE_UINT32:
         885        18001382 :                 u.l = (long)va_arg(ap, uint32_t);
         886                 :               do_long:
         887        19110403 :                 rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
         888        19110403 :                 if (rv < 0) {
         889               0 :                     return rv;
         890                 :                 }
         891        19110403 :                 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        19110403 :             break;
         910                 :
         911                 :           case 'e':
         912                 :           case 'E':
         913                 :           case 'f':
         914                 :           case 'g':
         915             162 :             u.d = va_arg(ap, double);
         916             162 :             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             162 :                 rv = cvt_f(ss, u.d, fmt0, fmt);
         925                 :
         926             162 :             if (rv < 0) {
         927               0 :                 return rv;
         928                 :             }
         929             162 :             break;
         930                 :
         931                 :           case 'c':
         932           13356 :             if ((flags & FLAG_LEFT) == 0) {
         933           26712 :                 while (width-- > 1) {
         934               0 :                     rv = (*ss->stuff)(ss, " ", 1);
         935               0 :                     if (rv < 0) {
         936               0 :                         return rv;
         937                 :                     }
         938                 :                 }
         939                 :             }
         940           13356 :             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           13356 :                 u.ch = va_arg(ap, int);
         951           13356 :                 rv = (*ss->stuff)(ss, &u.ch, 1);
         952           13356 :                 break;
         953                 :             }
         954           13356 :             if (rv < 0) {
         955               0 :                 return rv;
         956                 :             }
         957           13356 :             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           13356 :             break;
         966                 :
         967                 :           case 'p':
         968                 :             if (sizeof(void *) == sizeof(int32_t)) {
         969        17976358 :                 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        17976358 :             radix = 16;
         979        17976358 :             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          519058 :             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          519058 :                 u.s = va_arg(ap, const char*);
        1001          519058 :                 rv = cvt_s(ss, u.s, width, prec, flags);
        1002                 :             }
        1003          519058 :             if (rv < 0) {
        1004               0 :                 return rv;
        1005                 :             }
        1006          519058 :             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        19171408 :     rv = (*ss->stuff)(ss, "\0", 1);
        1033                 :
        1034        19171408 :     if( nas && ( nas != nasArray ) ){
        1035               0 :         UnwantedForeground::free_( nas );
        1036                 :     }
        1037                 :
        1038        19171408 :     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         6024219 : 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         6024219 :     off = ss->cur - ss->base;
        1092         6024219 :     if (off + len >= ss->maxlen) {
        1093                 :         /* Grow the buffer */
        1094         1071869 :         newlen = ss->maxlen + ((len > 32) ? len : 32);
        1095         1071869 :         if (ss->base) {
        1096          171723 :             newbase = (char*) OffTheBooks::realloc_(ss->base, newlen);
        1097                 :         } else {
        1098          900146 :             newbase = (char*) OffTheBooks::malloc_(newlen);
        1099                 :         }
        1100         1071869 :         if (!newbase) {
        1101                 :             /* Ran out of memory */
        1102               0 :             return -1;
        1103                 :         }
        1104         1071869 :         ss->base = newbase;
        1105         1071869 :         ss->maxlen = newlen;
        1106         1071869 :         ss->cur = ss->base + off;
        1107                 :     }
        1108                 :
        1109                 :     /* Copy data */
        1110        22176505 :     while (len) {
        1111        10128067 :         --len;
        1112        10128067 :         *ss->cur++ = *sp++;
        1113                 :     }
        1114         6024219 :     JS_ASSERT(uint32_t(ss->cur - ss->base) <= ss->maxlen);
        1115         6024219 :     return 0;
        1116                 : }
        1117                 :
        1118                 : /*
        1119                 : ** sprintf into a malloc'd buffer
        1120                 : */
        1121            1638 : JS_PUBLIC_API(char *) JS_smprintf(const char *fmt, ...)
        1122                 : {
        1123                 :     va_list ap;
        1124                 :     char *rv;
        1125                 :
        1126            1638 :     va_start(ap, fmt);
        1127            1638 :     rv = JS_vsmprintf(fmt, ap);
        1128            1638 :     va_end(ap);
        1129            1638 :     return rv;
        1130                 : }
        1131                 :
        1132                 : /*
        1133                 : ** Free memory allocated, for the caller, by JS_smprintf
        1134                 : */
        1135               0 : JS_PUBLIC_API(void) JS_smprintf_free(char *mem)
        1136                 : {
        1137               0 :         Foreground::free_(mem);
        1138               0 : }
        1139                 :
        1140          881654 : JS_PUBLIC_API(char *) JS_vsmprintf(const char *fmt, va_list ap)
        1141                 : {
        1142                 :     SprintfState ss;
        1143                 :     int rv;
        1144                 :
        1145          881654 :     ss.stuff = GrowStuff;
        1146          881654 :     ss.base = 0;
        1147          881654 :     ss.cur = 0;
        1148          881654 :     ss.maxlen = 0;
        1149          881654 :     rv = dosprintf(&ss, fmt, ap);
        1150          881654 :     if (rv < 0) {
        1151               0 :         if (ss.base) {
        1152               0 :             Foreground::free_(ss.base);
        1153                 :         }
        1154               0 :         return 0;
        1155                 :     }
        1156          881654 :     return ss.base;
        1157                 : }
        1158                 :
        1159                 : /*
        1160                 : ** Stuff routine that discards overflow data
        1161                 : */
        1162       222094424 : static int LimitStuff(SprintfState *ss, const char *sp, uint32_t len)
        1163                 : {
        1164       222094424 :     uint32_t limit = ss->maxlen - (ss->cur - ss->base);
        1165                 :
        1166       222094424 :     if (len > limit) {
        1167               0 :         len = limit;
        1168                 :     }
        1169       792324494 :     while (len) {
        1170       348135646 :         --len;
        1171       348135646 :         *ss->cur++ = *sp++;
        1172                 :     }
        1173       222094424 :     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        18234350 : 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        18234350 :     JS_ASSERT(int32_t(outlen) > 0);
        1186        18234350 :     if (int32_t(outlen) <= 0) {
        1187               0 :         return 0;
        1188                 :     }
        1189                 :
        1190        18234350 :     va_start(ap, fmt);
        1191        18234350 :     rv = JS_vsnprintf(out, outlen, fmt, ap);
        1192        18234350 :     va_end(ap);
        1193        18234350 :     return rv;
        1194                 : }
        1195                 :
        1196        18234350 : 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        18234350 :     JS_ASSERT(int32_t(outlen) > 0);
        1203        18234350 :     if (int32_t(outlen) <= 0) {
        1204               0 :         return 0;
        1205                 :     }
        1206                 :
        1207        18234350 :     ss.stuff = LimitStuff;
        1208        18234350 :     ss.base = out;
        1209        18234350 :     ss.cur = out;
        1210        18234350 :     ss.maxlen = outlen;
        1211        18234350 :     (void) dosprintf(&ss, fmt, ap);
        1212                 :
        1213                 :     /* If we added chars, and we didn't append a null, do it now. */
        1214        18234350 :     if( (ss.cur != ss.base) && (ss.cur[-1] != '\0') )
        1215               0 :         ss.cur[-1] = '\0';
        1216                 :
        1217        18234350 :     n = ss.cur - ss.base;
        1218        18234350 :     return n ? n - 1 : n;
        1219                 : }
        1220                 :
        1221           55404 : JS_PUBLIC_API(char *) JS_sprintf_append(char *last, const char *fmt, ...)
        1222                 : {
        1223                 :     va_list ap;
        1224                 :     char *rv;
        1225                 :
        1226           55404 :     va_start(ap, fmt);
        1227           55404 :     rv = JS_vsprintf_append(last, fmt, ap);
        1228           55404 :     va_end(ap);
        1229           55404 :     return rv;
        1230                 : }
        1231                 :
        1232           55404 : JS_PUBLIC_API(char *) JS_vsprintf_append(char *last, const char *fmt, va_list ap)
        1233                 : {
        1234                 :     SprintfState ss;
        1235                 :     int rv;
        1236                 :
        1237           55404 :     ss.stuff = GrowStuff;
        1238           55404 :     if (last) {
        1239           36912 :         int lastlen = strlen(last);
        1240           36912 :         ss.base = last;
        1241           36912 :         ss.cur = last + lastlen;
        1242           36912 :         ss.maxlen = lastlen;
        1243                 :     } else {
        1244           18492 :         ss.base = 0;
        1245           18492 :         ss.cur = 0;
        1246           18492 :         ss.maxlen = 0;
        1247                 :     }
        1248           55404 :     rv = dosprintf(&ss, fmt, ap);
        1249           55404 :     if (rv < 0) {
        1250               0 :         if (ss.base) {
        1251               0 :             Foreground::free_(ss.base);
        1252                 :         }
        1253               0 :         return 0;
        1254                 :     }
        1255           55404 :     return ss.base;
        1256                 : }
        1257                 :

Generated by: LCOV version 1.7