LCOV - code coverage report
Current view: directory - objdir/xpcom/build - nsTextFormatter.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 609 241 39.6 %
Date: 2012-06-02 Functions: 19 14 73.7 %

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

Generated by: LCOV version 1.7