LCOV - app.info - nsprpub/pr/src/io/prprf.c

LCOV - code coverage report
| Current view: | directory - nsprpub/pr/src/io - prprf.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 529 | 0 | 0.0 %
| Date: | 2012-04-07 | Functions: | 20 | 0 | 0.0 %

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

Generated by: LCOV version 1.7