LCOV - code coverage report
Current view: directory - nsprpub/pr/src/io - prprf.c (source / functions) Found Hit Coverage
Test: app.info Lines: 529 293 55.4 %
Date: 2012-06-02 Functions: 20 19 95.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           69544 : static int fill2(SprintfState *ss, const char *src, int srclen, int width,
     124                 :                 int flags)
     125                 : {
     126           69544 :     char space = ' ';
     127                 :     int rv;
     128                 : 
     129           69544 :     width -= srclen;
     130           69544 :     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           69544 :     rv = (*ss->stuff)(ss, src, srclen);
     144           69544 :     if (rv < 0) {
     145               0 :         return rv;
     146                 :     }
     147                 : 
     148           69544 :     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           69544 :     return 0;
     157                 : }
     158                 : 
     159                 : /*
     160                 : ** Fill a number. The order is: optional-sign zero-filling conversion-digits
     161                 : */
     162          212434 : static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
     163                 :                   int prec, int type, int flags)
     164                 : {
     165          212434 :     int zerowidth = 0;
     166          212434 :     int precwidth = 0;
     167          212434 :     int signwidth = 0;
     168          212434 :     int leftspaces = 0;
     169          212434 :     int rightspaces = 0;
     170                 :     int cvtwidth;
     171                 :     int rv;
     172                 :     char sign;
     173                 : 
     174          212434 :     if ((type & 1) == 0) {
     175           72944 :         if (flags & FLAG_NEG) {
     176             509 :             sign = '-';
     177             509 :             signwidth = 1;
     178           72435 :         } else if (flags & FLAG_SIGNED) {
     179               0 :             sign = '+';
     180               0 :             signwidth = 1;
     181           72435 :         } else if (flags & FLAG_SPACED) {
     182               0 :             sign = ' ';
     183               0 :             signwidth = 1;
     184                 :         }
     185                 :     }
     186          212434 :     cvtwidth = signwidth + srclen;
     187                 : 
     188          212434 :     if (prec > 0) {
     189            1210 :         if (prec > srclen) {
     190             535 :             precwidth = prec - srclen;          /* Need zero filling */
     191             535 :             cvtwidth += precwidth;
     192                 :         }
     193                 :     }
     194                 : 
     195          212434 :     if ((flags & FLAG_ZEROS) && (prec < 0)) {
     196          134126 :         if (width > cvtwidth) {
     197            8330 :             zerowidth = width - cvtwidth;       /* Zero filling */
     198            8330 :             cvtwidth += zerowidth;
     199                 :         }
     200                 :     }
     201                 : 
     202          212434 :     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          212434 :         if (width > cvtwidth) {
     209                 :             /* Space filling on the left (i.e. right adjusting) */
     210               0 :             leftspaces = width - cvtwidth;
     211                 :         }
     212                 :     }
     213          424868 :     while (--leftspaces >= 0) {
     214               0 :         rv = (*ss->stuff)(ss, " ", 1);
     215               0 :         if (rv < 0) {
     216               0 :             return rv;
     217                 :         }
     218                 :     }
     219          212434 :     if (signwidth) {
     220             509 :         rv = (*ss->stuff)(ss, &sign, 1);
     221             509 :         if (rv < 0) {
     222               0 :             return rv;
     223                 :         }
     224                 :     }
     225          425403 :     while (--precwidth >= 0) {
     226             535 :         rv = (*ss->stuff)(ss, "0", 1);
     227             535 :         if (rv < 0) {
     228               0 :             return rv;
     229                 :         }
     230                 :     }
     231          434057 :     while (--zerowidth >= 0) {
     232            9189 :         rv = (*ss->stuff)(ss, "0", 1);
     233            9189 :         if (rv < 0) {
     234               0 :             return rv;
     235                 :         }
     236                 :     }
     237          212434 :     rv = (*ss->stuff)(ss, src, srclen);
     238          212434 :     if (rv < 0) {
     239               0 :         return rv;
     240                 :     }
     241          424868 :     while (--rightspaces >= 0) {
     242               0 :         rv = (*ss->stuff)(ss, " ", 1);
     243               0 :         if (rv < 0) {
     244               0 :             return rv;
     245                 :         }
     246                 :     }
     247          212434 :     return 0;
     248                 : }
     249                 : 
     250                 : /*
     251                 : ** Convert a long into its printable form
     252                 : */
     253          203035 : 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          203035 :     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          203035 :     cvt = cvtbuf + sizeof(cvtbuf);
     271          203035 :     digits = 0;
     272          947215 :     while (num) {
     273          541145 :         int digit = (((unsigned long)num) % radix) & 0xF;
     274          541145 :         *--cvt = hexp[digit];
     275          541145 :         digits++;
     276          541145 :         num = (long)(((unsigned long)num) / radix);
     277                 :     }
     278          203035 :     if (digits == 0) {
     279            3316 :         *--cvt = '0';
     280            3316 :         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          203035 :     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            9399 : 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            9399 :     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            9399 :     LL_I2L(rad, radix);
     312            9399 :     cvt = cvtbuf + sizeof(cvtbuf);
     313            9399 :     digits = 0;
     314          101740 :     while (!LL_IS_ZERO(num)) {
     315                 :         PRInt32 digit;
     316                 :         PRInt64 quot, rem;
     317           82942 :         LL_UDIVMOD(&quot, &rem, num, rad);
     318           82942 :         LL_L2I(digit, rem);
     319           82942 :         *--cvt = hexp[digit & 0xf];
     320           82942 :         digits++;
     321           82942 :         num = quot;
     322                 :     }
     323            9399 :     if (digits == 0) {
     324              80 :         *--cvt = '0';
     325              80 :         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            9399 :     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           69544 : static int cvt_s(SprintfState *ss, const char *str, int width, int prec,
     383                 :                  int flags)
     384                 : {
     385                 :     int slen;
     386                 : 
     387           69544 :     if (prec == 0)
     388               0 :         return 0;
     389                 : 
     390                 :     /* Limit string length by precision value */
     391           69544 :     if (!str) {
     392               0 :         str = "(null)";
     393                 :     } 
     394           69544 :     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           69544 :         slen = strlen(str);
     403                 :     }
     404                 : 
     405                 :     /* and away we go */
     406           69544 :     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          120831 : static struct NumArg* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArg* nasArray )
     417                 : {
     418          120831 :     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          120831 :     p = fmt;
     430          120831 :     *rv = 0;
     431          120831 :     i = 0;
     432         1521220 :     while( ( c = *p++ ) != 0 ){
     433         1279558 :         if( c != '%' )
     434          992562 :             continue;
     435          286996 :         if( ( c = *p++ ) == '%' )       /* skip %% case */
     436               0 :             continue;
     437                 : 
     438          842284 :         while( c != 0 ){
     439          555288 :             if( c > '9' || c < '0' ){
     440          286996 :                 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          286996 :                     if( number > 0 ){
     448               0 :                         *rv = -1;
     449               0 :                         return NULL;
     450                 :                     }
     451          286996 :                     i = 1;
     452                 :                 }
     453          286996 :                 break;
     454                 :             }
     455                 : 
     456          268292 :             c = *p++;
     457                 :         }
     458                 :     }
     459                 : 
     460          120831 :     if( number == 0 ){
     461          120831 :         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          120831 : 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          120831 :     struct NumArg* nas = NULL;
     719                 :     struct NumArg* nap;
     720                 :     struct NumArg  nasArray[ NAS_DEFAULT_NUM ];
     721                 :     char  pattern[20];
     722          120831 :     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          120831 :     nas = BuildArgArray( fmt, ap, &rv, nasArray );
     733          120831 :     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         1490543 :     while ((c = *fmt++) != 0) {
     740         1248881 :         if (c != '%') {
     741          961885 :             rv = (*ss->stuff)(ss, fmt - 1, 1);
     742          961885 :             if (rv < 0) {
     743               0 :                 return rv;
     744                 :             }
     745          961885 :             continue;
     746                 :         }
     747          286996 :         fmt0 = fmt - 1;
     748                 : 
     749                 :         /*
     750                 :         ** Gobble up the % format string. Hopefully we have handled all
     751                 :         ** of the strange cases!
     752                 :         */
     753          286996 :         flags = 0;
     754          286996 :         c = *fmt++;
     755          286996 :         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          286996 :         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          708118 :         while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
     791          134126 :             if (c == '-') flags |= FLAG_LEFT;
     792          134126 :             if (c == '+') flags |= FLAG_SIGNED;
     793          134126 :             if (c == ' ') flags |= FLAG_SPACED;
     794          134126 :             if (c == '0') flags |= FLAG_ZEROS;
     795          134126 :             c = *fmt++;
     796                 :         }
     797          286996 :         if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
     798          286996 :         if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
     799                 : 
     800                 :         /* width */
     801          286996 :         if (c == '*') {
     802               0 :             c = *fmt++;
     803               0 :             width = va_arg(ap, int);
     804                 :         } else {
     805          286996 :             width = 0;
     806          708158 :             while ((c >= '0') && (c <= '9')) {
     807          134166 :                 width = (width * 10) + (c - '0');
     808          134166 :                 c = *fmt++;
     809                 :             }
     810                 :         }
     811                 : 
     812                 :         /* precision */
     813          286996 :         prec = -1;
     814          286996 :         if (c == '.') {
     815            1210 :             c = *fmt++;
     816            1210 :             if (c == '*') {
     817               0 :                 c = *fmt++;
     818               0 :                 prec = va_arg(ap, int);
     819                 :             } else {
     820            1210 :                 prec = 0;
     821            3630 :                 while ((c >= '0') && (c <= '9')) {
     822            1210 :                     prec = (prec * 10) + (c - '0');
     823            1210 :                     c = *fmt++;
     824                 :                 }
     825                 :             }
     826                 :         }
     827                 : 
     828                 :         /* size */
     829          286996 :         type = TYPE_INTN;
     830          286996 :         if (c == 'h') {
     831            1038 :             type = TYPE_INT16;
     832            1038 :             c = *fmt++;
     833          285958 :         } else if (c == 'L') {
     834                 :             /* XXX not quite sure here */
     835               0 :             type = TYPE_INT64;
     836               0 :             c = *fmt++;
     837          285958 :         } else if (c == 'l') {
     838           17820 :             type = TYPE_INT32;
     839           17820 :             c = *fmt++;
     840           17820 :             if (c == 'l') {
     841            9399 :                 type = TYPE_INT64;
     842            9399 :                 c = *fmt++;
     843                 :             }
     844                 :         }
     845                 : 
     846                 :         /* format */
     847          286996 :         hexp = hex;
     848          286996 :         switch (c) {
     849                 :           case 'd': case 'i':                   /* decimal/integer */
     850           72944 :             radix = 10;
     851           72944 :             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            5417 :             radix = 10;
     860            5417 :             type |= 1;
     861            5417 :             goto fetch_and_convert;
     862                 : 
     863                 :           case 'x':                             /* unsigned hex */
     864          127921 :             radix = 16;
     865          127921 :             type |= 1;
     866          127921 :             goto fetch_and_convert;
     867                 : 
     868                 :           case 'X':                             /* unsigned HEX */
     869            5619 :             radix = 16;
     870            5619 :             hexp = HEX;
     871            5619 :             type |= 1;
     872            5619 :             goto fetch_and_convert;
     873                 : 
     874                 :           fetch_and_convert:
     875          212434 :             switch (type) {
     876                 :               case TYPE_INT16:
     877            1038 :                 u.l = nas ? nap->u.i : va_arg(ap, int);
     878            1038 :                 if (u.l < 0) {
     879               0 :                     u.l = -u.l;
     880               0 :                     flags |= FLAG_NEG;
     881                 :                 }
     882            1038 :                 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           55867 :                 u.l = nas ? nap->u.i : va_arg(ap, int);
     888           55867 :                 if (u.l < 0) {
     889             509 :                     u.l = -u.l;
     890             509 :                     flags |= FLAG_NEG;
     891                 :                 }
     892           55867 :                 goto do_long;
     893                 :               case TYPE_UINTN:
     894          137176 :                 u.l = (long)(nas ? nap->u.ui : va_arg(ap, unsigned int));
     895          137176 :                 goto do_long;
     896                 : 
     897                 :               case TYPE_INT32:
     898            6783 :                 u.l = nas ? nap->u.i32 : va_arg(ap, PRInt32);
     899            6783 :                 if (u.l < 0) {
     900               0 :                     u.l = -u.l;
     901               0 :                     flags |= FLAG_NEG;
     902                 :                 }
     903            6783 :                 goto do_long;
     904                 :               case TYPE_UINT32:
     905            2171 :                 u.l = (long)(nas ? nap->u.ui32 : va_arg(ap, PRUint32));
     906                 :               do_long:
     907          203035 :                 rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
     908          203035 :                 if (rv < 0) {
     909               0 :                     return rv;
     910                 :                 }
     911          203035 :                 break;
     912                 : 
     913                 :               case TYPE_INT64:
     914            9256 :                 u.ll = nas ? nap->u.ll : va_arg(ap, PRInt64);
     915            9256 :                 if (!LL_GE_ZERO(u.ll)) {
     916               0 :                     LL_NEG(u.ll, u.ll);
     917               0 :                     flags |= FLAG_NEG;
     918                 :                 }
     919            9256 :                 goto do_longlong;
     920                 :               case TYPE_UINT64:
     921             143 :                 u.ll = nas ? nap->u.ull : va_arg(ap, PRUint64);
     922                 :               do_longlong:
     923            9399 :                 rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
     924            9399 :                 if (rv < 0) {
     925               0 :                     return rv;
     926                 :                 }
     927            9399 :                 break;
     928                 :             }
     929          212434 :             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            5018 :             u.ch = nas ? nap->u.i : va_arg(ap, int);
     953            5018 :             if ((flags & FLAG_LEFT) == 0) {
     954           10036 :                 while (width-- > 1) {
     955               0 :                     rv = (*ss->stuff)(ss, " ", 1);
     956               0 :                     if (rv < 0) {
     957               0 :                         return rv;
     958                 :                     }
     959                 :                 }
     960                 :             }
     961            5018 :             rv = (*ss->stuff)(ss, &u.ch, 1);
     962            5018 :             if (rv < 0) {
     963               0 :                 return rv;
     964                 :             }
     965            5018 :             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            5018 :             break;
     974                 : 
     975                 :           case 'p':
     976                 :             if (sizeof(void *) == sizeof(PRInt32)) {
     977             533 :                 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             533 :             radix = 16;
     987             533 :             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           69544 :             u.s = nas ? nap->u.s : va_arg(ap, const char*);
    1030           69544 :             rv = cvt_s(ss, u.s, width, prec, flags);
    1031           69544 :             if (rv < 0) {
    1032               0 :                 return rv;
    1033                 :             }
    1034           69544 :             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          120831 :     rv = (*ss->stuff)(ss, "\0", 1);
    1061                 : 
    1062          120831 :     if( nas && ( nas != nasArray ) ){
    1063               0 :         PR_DELETE( nas );
    1064                 :     }
    1065                 : 
    1066          120831 :     return rv;
    1067                 : }
    1068                 : 
    1069                 : /************************************************************************/
    1070                 : 
    1071          144288 : static int FuncStuff(SprintfState *ss, const char *sp, PRUint32 len)
    1072                 : {
    1073                 :     int rv;
    1074                 : 
    1075          144288 :     rv = (*ss->func)(ss->arg, sp, len);
    1076          144288 :     if (rv < 0) {
    1077               0 :         return rv;
    1078                 :     }
    1079          144288 :     ss->maxlen += len;
    1080          144288 :     return 0;
    1081                 : }
    1082                 : 
    1083           24048 : PR_IMPLEMENT(PRUint32) PR_sxprintf(PRStuffFunc func, void *arg, 
    1084                 :                                  const char *fmt, ...)
    1085                 : {
    1086                 :     va_list ap;
    1087                 :     PRUint32 rv;
    1088                 : 
    1089           24048 :     va_start(ap, fmt);
    1090           24048 :     rv = PR_vsxprintf(func, arg, fmt, ap);
    1091           24048 :     va_end(ap);
    1092           24048 :     return rv;
    1093                 : }
    1094                 : 
    1095           24048 : 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           24048 :     ss.stuff = FuncStuff;
    1102           24048 :     ss.func = func;
    1103           24048 :     ss.arg = arg;
    1104           24048 :     ss.maxlen = 0;
    1105           24048 :     rv = dosprintf(&ss, fmt, ap);
    1106           24048 :     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          587154 : static int GrowStuff(SprintfState *ss, const char *sp, PRUint32 len)
    1114                 : {
    1115                 :     ptrdiff_t off;
    1116                 :     char *newbase;
    1117                 :     PRUint32 newlen;
    1118                 : 
    1119          587154 :     off = ss->cur - ss->base;
    1120          587154 :     if (off + len >= ss->maxlen) {
    1121                 :         /* Grow the buffer */
    1122           47210 :         newlen = ss->maxlen + ((len > 32) ? len : 32);
    1123           47210 :         if (ss->base) {
    1124           25792 :             newbase = (char*) PR_REALLOC(ss->base, newlen);
    1125                 :         } else {
    1126           21418 :             newbase = (char*) PR_MALLOC(newlen);
    1127                 :         }
    1128           47210 :         if (!newbase) {
    1129                 :             /* Ran out of memory */
    1130               0 :             return -1;
    1131                 :         }
    1132           47210 :         ss->base = newbase;
    1133           47210 :         ss->maxlen = newlen;
    1134           47210 :         ss->cur = ss->base + off;
    1135                 :     }
    1136                 : 
    1137                 :     /* Copy data */
    1138         3637299 :     while (len) {
    1139         2462991 :         --len;
    1140         2462991 :         *ss->cur++ = *sp++;
    1141                 :     }
    1142          587154 :     PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen);
    1143          587154 :     return 0;
    1144                 : }
    1145                 : 
    1146                 : /*
    1147                 : ** sprintf into a malloc'd buffer
    1148                 : */
    1149           16407 : PR_IMPLEMENT(char *) PR_smprintf(const char *fmt, ...)
    1150                 : {
    1151                 :     va_list ap;
    1152                 :     char *rv;
    1153                 : 
    1154           16407 :     va_start(ap, fmt);
    1155           16407 :     rv = PR_vsmprintf(fmt, ap);
    1156           16407 :     va_end(ap);
    1157           16407 :     return rv;
    1158                 : }
    1159                 : 
    1160                 : /*
    1161                 : ** Free memory allocated, for the caller, by PR_smprintf
    1162                 : */
    1163           19714 : PR_IMPLEMENT(void) PR_smprintf_free(char *mem)
    1164                 : {
    1165           19714 :         PR_DELETE(mem);
    1166           19714 : }
    1167                 : 
    1168           21417 : PR_IMPLEMENT(char *) PR_vsmprintf(const char *fmt, va_list ap)
    1169                 : {
    1170                 :     SprintfState ss;
    1171                 :     int rv;
    1172                 : 
    1173           21417 :     ss.stuff = GrowStuff;
    1174           21417 :     ss.base = 0;
    1175           21417 :     ss.cur = 0;
    1176           21417 :     ss.maxlen = 0;
    1177           21417 :     rv = dosprintf(&ss, fmt, ap);
    1178           21417 :     if (rv < 0) {
    1179               0 :         if (ss.base) {
    1180               0 :             PR_DELETE(ss.base);
    1181                 :         }
    1182               0 :         return 0;
    1183                 :     }
    1184           21417 :     return ss.base;
    1185                 : }
    1186                 : 
    1187                 : /*
    1188                 : ** Stuff routine that discards overflow data
    1189                 : */
    1190          648503 : static int LimitStuff(SprintfState *ss, const char *sp, PRUint32 len)
    1191                 : {
    1192          648503 :     PRUint32 limit = ss->maxlen - (ss->cur - ss->base);
    1193                 : 
    1194          648503 :     if (len > limit) {
    1195              85 :         len = limit;
    1196                 :     }
    1197         2539556 :     while (len) {
    1198         1242550 :         --len;
    1199         1242550 :         *ss->cur++ = *sp++;
    1200                 :     }
    1201          648503 :     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           16931 : PR_IMPLEMENT(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...)
    1209                 : {
    1210                 :     va_list ap;
    1211                 :     PRUint32 rv;
    1212                 : 
    1213           16931 :     va_start(ap, fmt);
    1214           16931 :     rv = PR_vsnprintf(out, outlen, fmt, ap);
    1215           16931 :     va_end(ap);
    1216           16931 :     return rv;
    1217                 : }
    1218                 : 
    1219           74913 : 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           74913 :     PR_ASSERT((PRInt32)outlen > 0);
    1226           74913 :     if ((PRInt32)outlen <= 0) {
    1227               0 :         return 0;
    1228                 :     }
    1229                 : 
    1230           74913 :     ss.stuff = LimitStuff;
    1231           74913 :     ss.base = out;
    1232           74913 :     ss.cur = out;
    1233           74913 :     ss.maxlen = outlen;
    1234           74913 :     (void) dosprintf(&ss, fmt, ap);
    1235                 : 
    1236                 :     /* If we added chars, and we didn't append a null, do it now. */
    1237           74913 :     if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') )
    1238               1 :         *(ss.cur - 1) = '\0';
    1239                 : 
    1240           74913 :     n = ss.cur - ss.base;
    1241           74913 :     return n ? n - 1 : n;
    1242                 : }
    1243                 : 
    1244             453 : PR_IMPLEMENT(char *) PR_sprintf_append(char *last, const char *fmt, ...)
    1245                 : {
    1246                 :     va_list ap;
    1247                 :     char *rv;
    1248                 : 
    1249             453 :     va_start(ap, fmt);
    1250             453 :     rv = PR_vsprintf_append(last, fmt, ap);
    1251             453 :     va_end(ap);
    1252             453 :     return rv;
    1253                 : }
    1254                 : 
    1255             453 : PR_IMPLEMENT(char *) PR_vsprintf_append(char *last, const char *fmt, va_list ap)
    1256                 : {
    1257                 :     SprintfState ss;
    1258                 :     int rv;
    1259                 : 
    1260             453 :     ss.stuff = GrowStuff;
    1261             453 :     if (last) {
    1262             452 :         int lastlen = strlen(last);
    1263             452 :         ss.base = last;
    1264             452 :         ss.cur = last + lastlen;
    1265             452 :         ss.maxlen = lastlen;
    1266                 :     } else {
    1267               1 :         ss.base = 0;
    1268               1 :         ss.cur = 0;
    1269               1 :         ss.maxlen = 0;
    1270                 :     }
    1271             453 :     rv = dosprintf(&ss, fmt, ap);
    1272             453 :     if (rv < 0) {
    1273               0 :         if (ss.base) {
    1274               0 :             PR_DELETE(ss.base);
    1275                 :         }
    1276               0 :         return 0;
    1277                 :     }
    1278             453 :     return ss.base;
    1279                 : }
    1280                 : 

Generated by: LCOV version 1.7