LCOV - app.info - objdir/xpcom/build/nsTextFormatter.cpp

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