xpcom/glue/nsTextFormatter.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/glue/nsTextFormatter.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1326 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/* 
    1.10 + * Portable safe sprintf code.
    1.11 + *
    1.12 + * Code based on mozilla/nsprpub/src/io/prprf.c rev 3.7 
    1.13 + *
    1.14 + * Contributor(s):
    1.15 + *   Kipp E.B. Hickman  <kipp@netscape.com>  (original author)
    1.16 + *   Frank Yung-Fong Tang  <ftang@netscape.com>
    1.17 + *   Daniele Nicolodi  <daniele@grinta.net>
    1.18 + */
    1.19 +
    1.20 +/*
    1.21 + * Copied from xpcom/ds/nsTextFormatter.cpp r1.22
    1.22 + *     Changed to use nsMemory and Frozen linkage
    1.23 + *                  -- Prasad <prasad@medhas.org>
    1.24 + */
    1.25 +
    1.26 +#include <stdarg.h>
    1.27 +#include <stddef.h>
    1.28 +#include <stdio.h>
    1.29 +#include <string.h>
    1.30 +#include "prdtoa.h"
    1.31 +#include "prlog.h"
    1.32 +#include "prprf.h"
    1.33 +#include "prmem.h"
    1.34 +#include "nsCRTGlue.h"
    1.35 +#include "nsTextFormatter.h"
    1.36 +#include "nsMemory.h"
    1.37 +
    1.38 +/*
    1.39 +** Note: on some platforms va_list is defined as an array,
    1.40 +** and requires array notation.
    1.41 +*/
    1.42 +
    1.43 +#ifdef HAVE_VA_COPY
    1.44 +#define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo,bar)
    1.45 +#elif defined(HAVE_VA_LIST_AS_ARRAY)
    1.46 +#define VARARGS_ASSIGN(foo, bar)	foo[0] = bar[0]
    1.47 +#else
    1.48 +#define VARARGS_ASSIGN(foo, bar)	(foo) = (bar)
    1.49 +#endif
    1.50 +
    1.51 +typedef struct SprintfStateStr SprintfState;
    1.52 +
    1.53 +struct SprintfStateStr {
    1.54 +    int (*stuff)(SprintfState *ss, const char16_t *sp, uint32_t len);
    1.55 +
    1.56 +    char16_t *base;
    1.57 +    char16_t *cur;
    1.58 +    uint32_t maxlen;
    1.59 +
    1.60 +    void *stuffclosure;
    1.61 +};
    1.62 +
    1.63 +/*
    1.64 +** Numbered Arguement State
    1.65 +*/
    1.66 +struct NumArgState{
    1.67 +    int	    type;		/* type of the current ap                    */
    1.68 +    va_list ap;			/* point to the corresponding position on ap */
    1.69 +
    1.70 +    enum Type {
    1.71 +        INT16,
    1.72 +        UINT16,
    1.73 +        INTN,
    1.74 +        UINTN,
    1.75 +        INT32,
    1.76 +        UINT32,
    1.77 +        INT64,
    1.78 +        UINT64,
    1.79 +        STRING,
    1.80 +        DOUBLE,
    1.81 +        INTSTR,
    1.82 +        UNISTRING,
    1.83 +        UNKNOWN
    1.84 +    };
    1.85 +};
    1.86 +
    1.87 +#define NAS_DEFAULT_NUM 20  /* default number of NumberedArgumentState array */
    1.88 +
    1.89 +#define _LEFT		0x1
    1.90 +#define _SIGNED		0x2
    1.91 +#define _SPACED		0x4
    1.92 +#define _ZEROS		0x8
    1.93 +#define _NEG		0x10
    1.94 +
    1.95 +#define ELEMENTS_OF(array_) (sizeof(array_) / sizeof(array_[0]))
    1.96 +
    1.97 +/*
    1.98 +** Fill into the buffer using the data in src
    1.99 +*/
   1.100 +static int fill2(SprintfState *ss, const char16_t *src, int srclen, 
   1.101 +                 int width, int flags)
   1.102 +{
   1.103 +    char16_t space = ' ';
   1.104 +    int rv;
   1.105 +    
   1.106 +    width -= srclen;
   1.107 +    /* Right adjusting */
   1.108 +    if ((width > 0) && ((flags & _LEFT) == 0)) {
   1.109 +	if (flags & _ZEROS) {
   1.110 +	    space = '0';
   1.111 +	}
   1.112 +	while (--width >= 0) {
   1.113 +	    rv = (*ss->stuff)(ss, &space, 1);
   1.114 +	    if (rv < 0) {
   1.115 +		return rv;
   1.116 +	    }
   1.117 +	}
   1.118 +    }
   1.119 +
   1.120 +    /* Copy out the source data */
   1.121 +    rv = (*ss->stuff)(ss, src, srclen);
   1.122 +    if (rv < 0) {
   1.123 +	return rv;
   1.124 +    }
   1.125 +    
   1.126 +    /* Left adjusting */
   1.127 +    if ((width > 0) && ((flags & _LEFT) != 0)) {
   1.128 +	while (--width >= 0) {
   1.129 +	    rv = (*ss->stuff)(ss, &space, 1);
   1.130 +	    if (rv < 0) {
   1.131 +		return rv;
   1.132 +	    }
   1.133 +	}
   1.134 +    }
   1.135 +    return 0;
   1.136 +}
   1.137 +
   1.138 +/*
   1.139 +** Fill a number. The order is: optional-sign zero-filling conversion-digits
   1.140 +*/
   1.141 +static int fill_n(SprintfState *ss, const char16_t *src, int srclen, 
   1.142 +                  int width, int prec, int type, int flags)
   1.143 +{
   1.144 +    int zerowidth   = 0;
   1.145 +    int precwidth   = 0;
   1.146 +    int signwidth   = 0;
   1.147 +    int leftspaces  = 0;
   1.148 +    int rightspaces = 0;
   1.149 +    int cvtwidth;
   1.150 +    int rv;
   1.151 +    char16_t sign;
   1.152 +    char16_t space = ' ';
   1.153 +    char16_t zero = '0';
   1.154 +
   1.155 +    if ((type & 1) == 0) {
   1.156 +	if (flags & _NEG) {
   1.157 +	    sign = '-';
   1.158 +	    signwidth = 1;
   1.159 +	} else if (flags & _SIGNED) {
   1.160 +	    sign = '+';
   1.161 +	    signwidth = 1;
   1.162 +	} else if (flags & _SPACED) {
   1.163 +	    sign = ' ';
   1.164 +	    signwidth = 1;
   1.165 +	}
   1.166 +    }
   1.167 +    cvtwidth = signwidth + srclen;
   1.168 +
   1.169 +    if (prec > 0) {
   1.170 +	if (prec > srclen) {
   1.171 +            /* Need zero filling */
   1.172 +	    precwidth = prec - srclen;
   1.173 +	    cvtwidth += precwidth;
   1.174 +	}
   1.175 +    }
   1.176 +
   1.177 +    if ((flags & _ZEROS) && (prec < 0)) {
   1.178 +	if (width > cvtwidth) {
   1.179 +            /* Zero filling */
   1.180 +	    zerowidth = width - cvtwidth;
   1.181 +	    cvtwidth += zerowidth;
   1.182 +	}
   1.183 +    }
   1.184 +
   1.185 +    if (flags & _LEFT) {
   1.186 +	if (width > cvtwidth) {
   1.187 +	    /* Space filling on the right (i.e. left adjusting) */
   1.188 +	    rightspaces = width - cvtwidth;
   1.189 +	}
   1.190 +    } else {
   1.191 +	if (width > cvtwidth) {
   1.192 +	    /* Space filling on the left (i.e. right adjusting) */
   1.193 +	    leftspaces = width - cvtwidth;
   1.194 +	}
   1.195 +    }
   1.196 +    while (--leftspaces >= 0) {
   1.197 +	rv = (*ss->stuff)(ss, &space, 1);
   1.198 +	if (rv < 0) {
   1.199 +	    return rv;
   1.200 +	}
   1.201 +    }
   1.202 +    if (signwidth) {
   1.203 +	rv = (*ss->stuff)(ss, &sign, 1);
   1.204 +	if (rv < 0) {
   1.205 +	    return rv;
   1.206 +	}
   1.207 +    }
   1.208 +    while (--precwidth >= 0) {
   1.209 +	rv = (*ss->stuff)(ss,  &space, 1);
   1.210 +	if (rv < 0) {
   1.211 +	    return rv;
   1.212 +	}
   1.213 +    }
   1.214 +    while (--zerowidth >= 0) {
   1.215 +	rv = (*ss->stuff)(ss,  &zero, 1);
   1.216 +	if (rv < 0) {
   1.217 +	    return rv;
   1.218 +	}
   1.219 +    }
   1.220 +    rv = (*ss->stuff)(ss, src, srclen);
   1.221 +    if (rv < 0) {
   1.222 +	return rv;
   1.223 +    }
   1.224 +    while (--rightspaces >= 0) {
   1.225 +	rv = (*ss->stuff)(ss,  &space, 1);
   1.226 +	if (rv < 0) {
   1.227 +	    return rv;
   1.228 +	}
   1.229 +    }
   1.230 +    return 0;
   1.231 +}
   1.232 +
   1.233 +/*
   1.234 +** Convert a long into its printable form
   1.235 +*/
   1.236 +static int cvt_l(SprintfState *ss, long num, int width, int prec,
   1.237 +                 int radix, int type, int flags, const char16_t *hexp)
   1.238 +{
   1.239 +    char16_t cvtbuf[100];
   1.240 +    char16_t *cvt;
   1.241 +    int digits;
   1.242 +
   1.243 +    /* according to the man page this needs to happen */
   1.244 +    if ((prec == 0) && (num == 0)) {
   1.245 +	return 0;
   1.246 +    }
   1.247 +
   1.248 +    /*
   1.249 +    ** Converting decimal is a little tricky. In the unsigned case we
   1.250 +    ** need to stop when we hit 10 digits. In the signed case, we can
   1.251 +    ** stop when the number is zero.
   1.252 +    */
   1.253 +    cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf);
   1.254 +    digits = 0;
   1.255 +    while (num) {
   1.256 +	int digit = (((unsigned long)num) % radix) & 0xF;
   1.257 +	*--cvt = hexp[digit];
   1.258 +	digits++;
   1.259 +	num = (long)(((unsigned long)num) / radix);
   1.260 +    }
   1.261 +    if (digits == 0) {
   1.262 +	*--cvt = '0';
   1.263 +	digits++;
   1.264 +    }
   1.265 +
   1.266 +    /*
   1.267 +    ** Now that we have the number converted without its sign, deal with
   1.268 +    ** the sign and zero padding.
   1.269 +    */
   1.270 +    return fill_n(ss, cvt, digits, width, prec, type, flags);
   1.271 +}
   1.272 +
   1.273 +/*
   1.274 +** Convert a 64-bit integer into its printable form
   1.275 +*/
   1.276 +static int cvt_ll(SprintfState *ss, int64_t num, int width, int prec,
   1.277 +                  int radix, int type, int flags, const char16_t *hexp)
   1.278 +{
   1.279 +    char16_t cvtbuf[100];
   1.280 +    char16_t *cvt;
   1.281 +    int digits;
   1.282 +    int64_t rad;
   1.283 +
   1.284 +    /* according to the man page this needs to happen */
   1.285 +    if (prec == 0 && num == 0) {
   1.286 +	return 0;
   1.287 +    }
   1.288 +
   1.289 +    /*
   1.290 +    ** Converting decimal is a little tricky. In the unsigned case we
   1.291 +    ** need to stop when we hit 10 digits. In the signed case, we can
   1.292 +    ** stop when the number is zero.
   1.293 +    */
   1.294 +    rad = radix;
   1.295 +    cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf);
   1.296 +    digits = 0;
   1.297 +    while (num != 0) {
   1.298 +	*--cvt = hexp[int32_t(num % rad) & 0xf];
   1.299 +	digits++;
   1.300 +	num /= rad;
   1.301 +    }
   1.302 +    if (digits == 0) {
   1.303 +	*--cvt = '0';
   1.304 +	digits++;
   1.305 +    }
   1.306 +
   1.307 +    /*
   1.308 +    ** Now that we have the number converted without its sign, deal with
   1.309 +    ** the sign and zero padding.
   1.310 +    */
   1.311 +    return fill_n(ss, cvt, digits, width, prec, type, flags);
   1.312 +}
   1.313 +
   1.314 +/*
   1.315 +** Convert a double precision floating point number into its printable
   1.316 +** form.
   1.317 +*/
   1.318 +static int cvt_f(SprintfState *ss, double d, int width, int prec, 
   1.319 +                 const char16_t type, int flags)
   1.320 +{
   1.321 +    int    mode = 2;
   1.322 +    int    decpt;
   1.323 +    int    sign;
   1.324 +    char   buf[256];
   1.325 +    char * bufp = buf;
   1.326 +    int    bufsz = 256;
   1.327 +    char   num[256];
   1.328 +    char * nump;
   1.329 +    char * endnum;
   1.330 +    int    numdigits = 0;
   1.331 +    char   exp = 'e';
   1.332 +
   1.333 +    if (prec == -1) {
   1.334 +        prec = 6;
   1.335 +    } else if (prec > 50) {
   1.336 +        // limit precision to avoid PR_dtoa bug 108335
   1.337 +        // and to prevent buffers overflows
   1.338 +        prec = 50;
   1.339 +    }
   1.340 +
   1.341 +    switch (type) {
   1.342 +    case 'f':  
   1.343 +        numdigits = prec;
   1.344 +        mode = 3;
   1.345 +        break;
   1.346 +    case 'E':
   1.347 +        exp = 'E';
   1.348 +        // no break
   1.349 +    case 'e':
   1.350 +        numdigits = prec + 1;
   1.351 +        mode = 2;
   1.352 +        break;
   1.353 +    case 'G':
   1.354 +        exp = 'E';
   1.355 +        // no break
   1.356 +    case 'g':
   1.357 +        if (prec == 0) {
   1.358 +            prec = 1;
   1.359 +        }
   1.360 +        numdigits = prec;
   1.361 +        mode = 2;
   1.362 +        break;
   1.363 +    default:
   1.364 +        NS_ERROR("invalid type passed to cvt_f");
   1.365 +    }
   1.366 +    
   1.367 +    if (PR_dtoa(d, mode, numdigits, &decpt, &sign, &endnum, num, bufsz) == PR_FAILURE) {
   1.368 +        buf[0] = '\0';
   1.369 +        return -1;
   1.370 +    }
   1.371 +    numdigits = endnum - num;
   1.372 +    nump = num;
   1.373 +
   1.374 +    if (sign) {
   1.375 +        *bufp++ = '-';
   1.376 +    } else if (flags & _SIGNED) {
   1.377 +        *bufp++ = '+';
   1.378 +    }
   1.379 +
   1.380 +    if (decpt == 9999) {
   1.381 +        while ((*bufp++ = *nump++)) { }
   1.382 +    } else {
   1.383 +
   1.384 +        switch (type) {
   1.385 +
   1.386 +        case 'E':
   1.387 +        case 'e':
   1.388 +
   1.389 +            *bufp++ = *nump++;                
   1.390 +            if (prec > 0) {
   1.391 +                *bufp++ = '.';
   1.392 +                while (*nump) {
   1.393 +                    *bufp++ = *nump++;
   1.394 +                    prec--;
   1.395 +                }
   1.396 +                while (prec-- > 0) {
   1.397 +                    *bufp++ = '0';
   1.398 +                }
   1.399 +            }
   1.400 +            *bufp++ = exp;
   1.401 +            PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1);
   1.402 +            break;
   1.403 +
   1.404 +        case 'f':
   1.405 +
   1.406 +            if (decpt < 1) {
   1.407 +                *bufp++ = '0';
   1.408 +                if (prec > 0) {
   1.409 +                    *bufp++ = '.';
   1.410 +                    while (decpt++ && prec-- > 0) {
   1.411 +                        *bufp++ = '0';
   1.412 +                    }
   1.413 +                    while (*nump && prec-- > 0) {
   1.414 +                        *bufp++ = *nump++;
   1.415 +                    }
   1.416 +                    while (prec-- > 0) {
   1.417 +                        *bufp++ = '0';
   1.418 +                    }
   1.419 +                }
   1.420 +            } else {
   1.421 +                while (*nump && decpt-- > 0) {
   1.422 +                    *bufp++ = *nump++;
   1.423 +                }
   1.424 +                while (decpt-- > 0) {
   1.425 +                    *bufp++ = '0';
   1.426 +                }
   1.427 +                if (prec > 0) {
   1.428 +                    *bufp++ = '.';
   1.429 +                    while (*nump && prec-- > 0) {
   1.430 +                        *bufp++ = *nump++;
   1.431 +                    }
   1.432 +                    while (prec-- > 0) {
   1.433 +                        *bufp++ = '0';
   1.434 +                    }
   1.435 +                }
   1.436 +            }
   1.437 +            *bufp = '\0';
   1.438 +            break;
   1.439 +
   1.440 +        case 'G':
   1.441 +        case 'g':
   1.442 +
   1.443 +            if ((decpt < -3) || ((decpt - 1) >= prec)) {
   1.444 +                *bufp++ = *nump++;
   1.445 +                numdigits--;
   1.446 +                if (numdigits > 0) {
   1.447 +                    *bufp++ = '.';
   1.448 +                    while (*nump) {
   1.449 +                        *bufp++ = *nump++;
   1.450 +                    }
   1.451 +                }
   1.452 +                *bufp++ = exp;
   1.453 +                PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1);
   1.454 +            } else {
   1.455 +                if (decpt < 1) {
   1.456 +                    *bufp++ = '0';
   1.457 +                    if (prec > 0) {
   1.458 +                        *bufp++ = '.';
   1.459 +                        while (decpt++) {
   1.460 +                            *bufp++ = '0';
   1.461 +                        }
   1.462 +                        while (*nump) {
   1.463 +                            *bufp++ = *nump++;
   1.464 +                        }
   1.465 +                    }
   1.466 +                } else {
   1.467 +                    while (*nump && decpt-- > 0) {
   1.468 +                        *bufp++ = *nump++;
   1.469 +                        numdigits--;
   1.470 +                    }
   1.471 +                    while (decpt-- > 0) {
   1.472 +                        *bufp++ = '0';
   1.473 +                    }
   1.474 +                    if (numdigits > 0) {
   1.475 +                        *bufp++ = '.';
   1.476 +                        while (*nump) {
   1.477 +                            *bufp++ = *nump++;
   1.478 +                        }
   1.479 +                    }
   1.480 +                }
   1.481 +                *bufp = '\0';
   1.482 +            }
   1.483 +        }
   1.484 +    }
   1.485 +
   1.486 +    char16_t rbuf[256];
   1.487 +    char16_t *rbufp = rbuf;
   1.488 +    bufp = buf;
   1.489 +    // cast to char16_t
   1.490 +    while ((*rbufp++ = *bufp++)) { }
   1.491 +    *rbufp = '\0';
   1.492 +
   1.493 +    return fill2(ss, rbuf, NS_strlen(rbuf), width, flags);
   1.494 +}
   1.495 +
   1.496 +/*
   1.497 +** Convert a string into its printable form. "width" is the output
   1.498 +** width. "prec" is the maximum number of characters of "s" to output,
   1.499 +** where -1 means until NUL.
   1.500 +*/
   1.501 +static int cvt_S(SprintfState *ss, const char16_t *s, int width,
   1.502 +                 int prec, int flags)
   1.503 +{
   1.504 +    int slen;
   1.505 +
   1.506 +    if (prec == 0) {
   1.507 +	return 0;
   1.508 +    }
   1.509 +
   1.510 +    /* Limit string length by precision value */
   1.511 +    slen = s ? NS_strlen(s) : 6;
   1.512 +    if (prec > 0) {
   1.513 +	if (prec < slen) {
   1.514 +	    slen = prec;
   1.515 +	}
   1.516 +    }
   1.517 +
   1.518 +    /* and away we go */
   1.519 +    return fill2(ss, s ? s : MOZ_UTF16("(null)"), slen, width, flags);
   1.520 +}
   1.521 +
   1.522 +/*
   1.523 +** Convert a string into its printable form.  "width" is the output
   1.524 +** width. "prec" is the maximum number of characters of "s" to output,
   1.525 +** where -1 means until NUL.
   1.526 +*/
   1.527 +static int cvt_s(SprintfState *ss, const char *s, int width,
   1.528 +                 int prec, int flags)
   1.529 +{
   1.530 +    NS_ConvertUTF8toUTF16 utf16Val(s);
   1.531 +    return cvt_S(ss, utf16Val.get(), width, prec, flags);
   1.532 +}
   1.533 +
   1.534 +/*
   1.535 +** BuildArgArray stands for Numbered Argument list Sprintf
   1.536 +** for example,  
   1.537 +**	fmp = "%4$i, %2$d, %3s, %1d";
   1.538 +** the number must start from 1, and no gap among them
   1.539 +*/
   1.540 +
   1.541 +static struct NumArgState* BuildArgArray(const char16_t *fmt, 
   1.542 +                                         va_list ap, int * rv, 
   1.543 +                                         struct NumArgState * nasArray)
   1.544 +{
   1.545 +    int number = 0, cn = 0, i;
   1.546 +    const char16_t* p;
   1.547 +    char16_t  c;
   1.548 +    struct NumArgState* nas;
   1.549 +
   1.550 +    /*
   1.551 +    **	first pass:
   1.552 +    **	detemine how many legal % I have got, then allocate space
   1.553 +    */
   1.554 +    p = fmt;
   1.555 +    *rv = 0;
   1.556 +    i = 0;
   1.557 +    while ((c = *p++) != 0) {
   1.558 +	if (c != '%') {
   1.559 +	    continue;
   1.560 +        }
   1.561 +        /* skip %% case */
   1.562 +	if ((c = *p++) == '%') {
   1.563 +	    continue;
   1.564 +        }
   1.565 +
   1.566 +	while( c != 0 ){
   1.567 +	    if (c > '9' || c < '0') {
   1.568 +                /* numbered argument csae */
   1.569 +		if (c == '$') {
   1.570 +		    if (i > 0) {
   1.571 +			*rv = -1;
   1.572 +			return nullptr;
   1.573 +		    }
   1.574 +		    number++;
   1.575 +		    break;
   1.576 +
   1.577 +		} else {
   1.578 +                    /* non-numbered argument case */
   1.579 +		    if (number > 0) {
   1.580 +			*rv = -1;
   1.581 +			return nullptr;
   1.582 +		    }
   1.583 +		    i = 1;
   1.584 +		    break;
   1.585 +		}
   1.586 +	    }
   1.587 +	    c = *p++;
   1.588 +	}
   1.589 +    }
   1.590 +
   1.591 +    if (number == 0) {
   1.592 +	return nullptr;
   1.593 +    }
   1.594 +    
   1.595 +    if (number > NAS_DEFAULT_NUM) {
   1.596 +	nas = (struct NumArgState*)nsMemory::Alloc(number * sizeof(struct NumArgState));
   1.597 +	if (!nas) {
   1.598 +	    *rv = -1;
   1.599 +	    return nullptr;
   1.600 +	}
   1.601 +    } else {
   1.602 +	nas = nasArray;
   1.603 +    }
   1.604 +
   1.605 +    for (i = 0; i < number; i++) {
   1.606 +	nas[i].type = NumArgState::UNKNOWN;
   1.607 +    }
   1.608 +
   1.609 +    /*
   1.610 +    ** second pass:
   1.611 +    ** set nas[].type
   1.612 +    */
   1.613 +    p = fmt;
   1.614 +    while ((c = *p++) != 0) {
   1.615 +    	if (c != '%') {
   1.616 +            continue;
   1.617 +        }
   1.618 +        c = *p++;
   1.619 +	if (c == '%') {
   1.620 +            continue;
   1.621 +        }
   1.622 +	cn = 0;
   1.623 +        /* should imporve error check later */
   1.624 +	while (c && c != '$') {
   1.625 +	    cn = cn*10 + c - '0';
   1.626 +	    c = *p++;
   1.627 +	}
   1.628 +
   1.629 +	if (!c || cn < 1 || cn > number) {
   1.630 +	    *rv = -1;
   1.631 +	    break;
   1.632 +        }
   1.633 +
   1.634 +	/* nas[cn] starts from 0, and make sure 
   1.635 +           nas[cn].type is not assigned */
   1.636 +        cn--;
   1.637 +	if (nas[cn].type != NumArgState::UNKNOWN) {
   1.638 +	    continue;
   1.639 +        }
   1.640 +
   1.641 +        c = *p++;
   1.642 +
   1.643 +        /* width */
   1.644 +        if (c == '*') {
   1.645 +	    /* not supported feature, for the argument is not numbered */
   1.646 +	    *rv = -1;
   1.647 +	    break;
   1.648 +	} else {
   1.649 +	    while ((c >= '0') && (c <= '9')) {
   1.650 +	        c = *p++;
   1.651 +	    }
   1.652 +	}
   1.653 +
   1.654 +	/* precision */
   1.655 +	if (c == '.') {
   1.656 +	    c = *p++;
   1.657 +	    if (c == '*') {
   1.658 +	        /* not supported feature, for the argument is not numbered */
   1.659 +	        *rv = -1;
   1.660 +	        break;
   1.661 +	    } else {
   1.662 +	        while ((c >= '0') && (c <= '9')) {
   1.663 +		    c = *p++;
   1.664 +		}
   1.665 +	    }
   1.666 +	}
   1.667 +
   1.668 +	/* size */
   1.669 +	nas[cn].type = NumArgState::INTN;
   1.670 +	if (c == 'h') {
   1.671 +	    nas[cn].type = NumArgState::INT16;
   1.672 +	    c = *p++;
   1.673 +	} else if (c == 'L') {
   1.674 +	    /* XXX not quite sure here */
   1.675 +	    nas[cn].type = NumArgState::INT64;
   1.676 +	    c = *p++;
   1.677 +	} else if (c == 'l') {
   1.678 +	    nas[cn].type = NumArgState::INT32;
   1.679 +	    c = *p++;
   1.680 +	    if (c == 'l') {
   1.681 +	        nas[cn].type = NumArgState::INT64;
   1.682 +	        c = *p++;
   1.683 +	    }
   1.684 +	}
   1.685 +
   1.686 +	/* format */
   1.687 +	switch (c) {
   1.688 +	case 'd':
   1.689 +	case 'c':
   1.690 +	case 'i':
   1.691 +	case 'o':
   1.692 +	case 'u':
   1.693 +	case 'x':
   1.694 +	case 'X':
   1.695 +	    break;
   1.696 +
   1.697 +	case 'e':
   1.698 +	case 'f':
   1.699 +	case 'g':
   1.700 +	    nas[cn].type = NumArgState::DOUBLE;
   1.701 +	    break;
   1.702 +
   1.703 +	case 'p':
   1.704 +	    /* XXX should use cpp */
   1.705 +	    if (sizeof(void *) == sizeof(int32_t)) {
   1.706 +		nas[cn].type = NumArgState::UINT32;
   1.707 +	    } else if (sizeof(void *) == sizeof(int64_t)) {
   1.708 +	        nas[cn].type = NumArgState::UINT64;
   1.709 +	    } else if (sizeof(void *) == sizeof(int)) {
   1.710 +	        nas[cn].type = NumArgState::UINTN;
   1.711 +	    } else {
   1.712 +	        nas[cn].type = NumArgState::UNKNOWN;
   1.713 +	    }
   1.714 +	    break;
   1.715 +
   1.716 +	case 'C':
   1.717 +	    /* XXX not supported I suppose */
   1.718 +	    PR_ASSERT(0);
   1.719 +	    nas[cn].type = NumArgState::UNKNOWN;
   1.720 +	    break;
   1.721 +
   1.722 +	case 'S':
   1.723 +	    nas[cn].type = NumArgState::UNISTRING;
   1.724 +	    break;
   1.725 +
   1.726 +	case 's':
   1.727 +	    nas[cn].type = NumArgState::STRING;
   1.728 +	    break;
   1.729 +
   1.730 +	case 'n':
   1.731 +	    nas[cn].type = NumArgState::INTSTR;
   1.732 +	    break;
   1.733 +
   1.734 +	default:
   1.735 +	    PR_ASSERT(0);
   1.736 +	    nas[cn].type = NumArgState::UNKNOWN;
   1.737 +	    break;
   1.738 +	}
   1.739 +
   1.740 +	/* get a legal para. */
   1.741 +	if (nas[cn].type == NumArgState::UNKNOWN) {
   1.742 +	    *rv = -1;
   1.743 +	    break;
   1.744 +	}
   1.745 +    }
   1.746 +
   1.747 +
   1.748 +    /*
   1.749 +    ** third pass
   1.750 +    ** fill the nas[cn].ap
   1.751 +    */
   1.752 +    if (*rv < 0) {
   1.753 +	if( nas != nasArray ) {
   1.754 +	    PR_DELETE(nas);
   1.755 +        }
   1.756 +	return nullptr;
   1.757 +    }
   1.758 +
   1.759 +    cn = 0;
   1.760 +    while (cn < number) {
   1.761 +	if (nas[cn].type == NumArgState::UNKNOWN) {
   1.762 +	    cn++;
   1.763 +	    continue;
   1.764 +	}
   1.765 +
   1.766 +	VARARGS_ASSIGN(nas[cn].ap, ap);
   1.767 +
   1.768 +	switch (nas[cn].type) {
   1.769 +	case NumArgState::INT16:
   1.770 +	case NumArgState::UINT16:
   1.771 +	case NumArgState::INTN:
   1.772 +	case NumArgState::UINTN:     (void)va_arg(ap, int);         break;
   1.773 +
   1.774 +	case NumArgState::INT32:     (void)va_arg(ap, int32_t);     break;
   1.775 +
   1.776 +	case NumArgState::UINT32:    (void)va_arg(ap, uint32_t);    break;
   1.777 +
   1.778 +	case NumArgState::INT64:     (void)va_arg(ap, int64_t);     break;
   1.779 +
   1.780 +	case NumArgState::UINT64:    (void)va_arg(ap, uint64_t);    break;
   1.781 +
   1.782 +	case NumArgState::STRING:    (void)va_arg(ap, char*);       break;
   1.783 +
   1.784 +	case NumArgState::INTSTR:    (void)va_arg(ap, int*);        break;
   1.785 +
   1.786 +	case NumArgState::DOUBLE:    (void)va_arg(ap, double);      break;
   1.787 +
   1.788 +	case NumArgState::UNISTRING: (void)va_arg(ap, char16_t*);  break;
   1.789 +
   1.790 +	default:
   1.791 +	    if( nas != nasArray ) {
   1.792 +		PR_DELETE( nas );
   1.793 +            }
   1.794 +	    *rv = -1;
   1.795 +	    return nullptr;
   1.796 +	}
   1.797 +	cn++;
   1.798 +    }
   1.799 +    return nas;
   1.800 +}
   1.801 +
   1.802 +/*
   1.803 +** The workhorse sprintf code.
   1.804 +*/
   1.805 +static int dosprintf(SprintfState *ss, const char16_t *fmt, va_list ap)
   1.806 +{
   1.807 +    char16_t c;
   1.808 +    int flags, width, prec, radix, type;
   1.809 +    union {
   1.810 +	char16_t ch;
   1.811 +	int i;
   1.812 +	long l;
   1.813 +	int64_t ll;
   1.814 +	double d;
   1.815 +	const char *s;
   1.816 +	const char16_t *S;
   1.817 +	int *ip;
   1.818 +    } u;
   1.819 +    char16_t space = ' ';
   1.820 +
   1.821 +    nsAutoString hex;
   1.822 +    hex.AssignLiteral("0123456789abcdef");
   1.823 +
   1.824 +    nsAutoString HEX;
   1.825 +    HEX.AssignLiteral("0123456789ABCDEF");
   1.826 +
   1.827 +    const char16_t *hexp;
   1.828 +    int rv, i;
   1.829 +    struct NumArgState* nas = nullptr;
   1.830 +    struct NumArgState  nasArray[NAS_DEFAULT_NUM];
   1.831 +
   1.832 +
   1.833 +    /*
   1.834 +    ** build an argument array, IF the fmt is numbered argument
   1.835 +    ** list style, to contain the Numbered Argument list pointers
   1.836 +    */
   1.837 +    nas = BuildArgArray (fmt, ap, &rv, nasArray);
   1.838 +    if (rv < 0) {
   1.839 +	/* the fmt contains error Numbered Argument format, jliu@netscape.com */
   1.840 +	PR_ASSERT(0);
   1.841 +	return rv;
   1.842 +    }
   1.843 +
   1.844 +    while ((c = *fmt++) != 0) {
   1.845 +	if (c != '%') {
   1.846 +	    rv = (*ss->stuff)(ss, fmt - 1, 1);
   1.847 +	    if (rv < 0) {
   1.848 +		return rv;
   1.849 +	    }
   1.850 +	    continue;
   1.851 +	}
   1.852 +
   1.853 +	/*
   1.854 +	** Gobble up the % format string. Hopefully we have handled all
   1.855 +	** of the strange cases!
   1.856 +	*/
   1.857 +	flags = 0;
   1.858 +	c = *fmt++;
   1.859 +	if (c == '%') {
   1.860 +	    /* quoting a % with %% */
   1.861 +	    rv = (*ss->stuff)(ss, fmt - 1, 1);
   1.862 +	    if (rv < 0) {
   1.863 +		return rv;
   1.864 +	    }
   1.865 +	    continue;
   1.866 +	}
   1.867 +
   1.868 +	if (nas != nullptr) {
   1.869 +	    /* the fmt contains the Numbered Arguments feature */
   1.870 +	    i = 0;
   1.871 +	    /* should imporve error check later */
   1.872 +	    while (c && c != '$') {
   1.873 +		i = (i * 10) + (c - '0');
   1.874 +		c = *fmt++;
   1.875 +	    }
   1.876 +
   1.877 +	    if (nas[i-1].type == NumArgState::UNKNOWN) {
   1.878 +		if (nas && (nas != nasArray)) {
   1.879 +		    PR_DELETE(nas);
   1.880 +                }
   1.881 +		return -1;
   1.882 +	    }
   1.883 +
   1.884 +	    VARARGS_ASSIGN(ap, nas[i-1].ap);
   1.885 +	    c = *fmt++;
   1.886 +	}
   1.887 +
   1.888 +	/*
   1.889 +	 * Examine optional flags.  Note that we do not implement the
   1.890 +	 * '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
   1.891 +	 * somewhat ambiguous and not ideal, which is perhaps why
   1.892 +	 * the various sprintf() implementations are inconsistent
   1.893 +	 * on this feature.
   1.894 +	 */
   1.895 +	while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
   1.896 +	    if (c == '-') flags |= _LEFT;
   1.897 +	    if (c == '+') flags |= _SIGNED;
   1.898 +	    if (c == ' ') flags |= _SPACED;
   1.899 +	    if (c == '0') flags |= _ZEROS;
   1.900 +	    c = *fmt++;
   1.901 +	}
   1.902 +	if (flags & _SIGNED) flags &= ~_SPACED;
   1.903 +	if (flags & _LEFT) flags &= ~_ZEROS;
   1.904 +
   1.905 +	/* width */
   1.906 +	if (c == '*') {
   1.907 +	    c = *fmt++;
   1.908 +	    width = va_arg(ap, int);
   1.909 +	} else {
   1.910 +	    width = 0;
   1.911 +	    while ((c >= '0') && (c <= '9')) {
   1.912 +		width = (width * 10) + (c - '0');
   1.913 +		c = *fmt++;
   1.914 +	    }
   1.915 +	}
   1.916 +
   1.917 +	/* precision */
   1.918 +	prec = -1;
   1.919 +	if (c == '.') {
   1.920 +	    c = *fmt++;
   1.921 +	    if (c == '*') {
   1.922 +		c = *fmt++;
   1.923 +		prec = va_arg(ap, int);
   1.924 +	    } else {
   1.925 +		prec = 0;
   1.926 +		while ((c >= '0') && (c <= '9')) {
   1.927 +		    prec = (prec * 10) + (c - '0');
   1.928 +		    c = *fmt++;
   1.929 +		}
   1.930 +	    }
   1.931 +	}
   1.932 +
   1.933 +	/* size */
   1.934 +	type = NumArgState::INTN;
   1.935 +	if (c == 'h') {
   1.936 +	    type = NumArgState::INT16;
   1.937 +	    c = *fmt++;
   1.938 +	} else if (c == 'L') {
   1.939 +	    /* XXX not quite sure here */
   1.940 +	    type = NumArgState::INT64;
   1.941 +	    c = *fmt++;
   1.942 +	} else if (c == 'l') {
   1.943 +	    type = NumArgState::INT32;
   1.944 +	    c = *fmt++;
   1.945 +	    if (c == 'l') {
   1.946 +		type = NumArgState::INT64;
   1.947 +		c = *fmt++;
   1.948 +	    }
   1.949 +	}
   1.950 +
   1.951 +	/* format */
   1.952 +	hexp = hex.get();
   1.953 +	switch (c) {
   1.954 +        case 'd': 
   1.955 +        case 'i':                               /* decimal/integer */
   1.956 +	    radix = 10;
   1.957 +	    goto fetch_and_convert;
   1.958 +
   1.959 +        case 'o':                               /* octal */
   1.960 +	    radix = 8;
   1.961 +	    type |= 1;
   1.962 +	    goto fetch_and_convert;
   1.963 +
   1.964 +        case 'u':                               /* unsigned decimal */
   1.965 +	    radix = 10;
   1.966 +	    type |= 1;
   1.967 +	    goto fetch_and_convert;
   1.968 +
   1.969 +        case 'x':                               /* unsigned hex */
   1.970 +	    radix = 16;
   1.971 +	    type |= 1;
   1.972 +	    goto fetch_and_convert;
   1.973 +
   1.974 +        case 'X':                               /* unsigned HEX */
   1.975 +	    radix = 16;
   1.976 +	    hexp = HEX.get();
   1.977 +	    type |= 1;
   1.978 +	    goto fetch_and_convert;
   1.979 +
   1.980 +        fetch_and_convert:
   1.981 +	    switch (type) {
   1.982 +            case NumArgState::INT16:
   1.983 +		u.l = va_arg(ap, int);
   1.984 +		if (u.l < 0) {
   1.985 +		    u.l = -u.l;
   1.986 +		    flags |= _NEG;
   1.987 +		}
   1.988 +		goto do_long;
   1.989 +            case NumArgState::UINT16:
   1.990 +		u.l = va_arg(ap, int) & 0xffff;
   1.991 +		goto do_long;
   1.992 +            case NumArgState::INTN:
   1.993 +		u.l = va_arg(ap, int);
   1.994 +		if (u.l < 0) {
   1.995 +		    u.l = -u.l;
   1.996 +		    flags |= _NEG;
   1.997 +		}
   1.998 +		goto do_long;
   1.999 +            case NumArgState::UINTN:
  1.1000 +		u.l = (long)va_arg(ap, unsigned int);
  1.1001 +		goto do_long;
  1.1002 +
  1.1003 +            case NumArgState::INT32:
  1.1004 +		u.l = va_arg(ap, int32_t);
  1.1005 +		if (u.l < 0) {
  1.1006 +		    u.l = -u.l;
  1.1007 +		    flags |= _NEG;
  1.1008 +		}
  1.1009 +		goto do_long;
  1.1010 +            case NumArgState::UINT32:
  1.1011 +		u.l = (long)va_arg(ap, uint32_t);
  1.1012 +            do_long:
  1.1013 +		rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
  1.1014 +		if (rv < 0) {
  1.1015 +		    return rv;
  1.1016 +		}
  1.1017 +		break;
  1.1018 +
  1.1019 +            case NumArgState::INT64:
  1.1020 +		u.ll = va_arg(ap, int64_t);
  1.1021 +		if (u.ll < 0) {
  1.1022 +		    u.ll = -u.ll;
  1.1023 +		    flags |= _NEG;
  1.1024 +		}
  1.1025 +		goto do_longlong;
  1.1026 +            case NumArgState::UINT64:
  1.1027 +		u.ll = va_arg(ap, uint64_t);
  1.1028 +            do_longlong:
  1.1029 +		rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
  1.1030 +		if (rv < 0) {
  1.1031 +		    return rv;
  1.1032 +		}
  1.1033 +		break;
  1.1034 +	    }
  1.1035 +	    break;
  1.1036 +
  1.1037 +        case 'e':
  1.1038 +        case 'E':
  1.1039 +        case 'f':
  1.1040 +        case 'g':
  1.1041 +        case 'G':
  1.1042 +	    u.d = va_arg(ap, double);
  1.1043 +            rv = cvt_f(ss, u.d, width, prec, c, flags);
  1.1044 +	    if (rv < 0) {
  1.1045 +		return rv;
  1.1046 +	    }
  1.1047 +	    break;
  1.1048 +
  1.1049 +        case 'c':
  1.1050 +	    u.ch = va_arg(ap, int);
  1.1051 +            if ((flags & _LEFT) == 0) {
  1.1052 +                while (width-- > 1) {
  1.1053 +                    rv = (*ss->stuff)(ss, &space, 1);
  1.1054 +                    if (rv < 0) {
  1.1055 +                        return rv;
  1.1056 +                    }
  1.1057 +                }
  1.1058 +            }
  1.1059 +	    rv = (*ss->stuff)(ss, &u.ch, 1);
  1.1060 +	    if (rv < 0) {
  1.1061 +		return rv;
  1.1062 +	    }
  1.1063 +            if (flags & _LEFT) {
  1.1064 +                while (width-- > 1) {
  1.1065 +                    rv = (*ss->stuff)(ss, &space, 1);
  1.1066 +                    if (rv < 0) {
  1.1067 +                        return rv;
  1.1068 +                    }
  1.1069 +                }
  1.1070 +            }
  1.1071 +	    break;
  1.1072 +
  1.1073 +        case 'p':
  1.1074 +	    if (sizeof(void *) == sizeof(int32_t)) {
  1.1075 +	    	type = NumArgState::UINT32;
  1.1076 +	    } else if (sizeof(void *) == sizeof(int64_t)) {
  1.1077 +	    	type = NumArgState::UINT64;
  1.1078 +	    } else if (sizeof(void *) == sizeof(int)) {
  1.1079 +		type = NumArgState::UINTN;
  1.1080 +	    } else {
  1.1081 +		PR_ASSERT(0);
  1.1082 +		break;
  1.1083 +	    }
  1.1084 +	    radix = 16;
  1.1085 +	    goto fetch_and_convert;
  1.1086 +
  1.1087 +#if 0
  1.1088 +        case 'C':
  1.1089 +	    /* XXX not supported I suppose */
  1.1090 +	    PR_ASSERT(0);
  1.1091 +	    break;
  1.1092 +#endif
  1.1093 +
  1.1094 +        case 'S':
  1.1095 +	    u.S = va_arg(ap, const char16_t*);
  1.1096 +	    rv = cvt_S(ss, u.S, width, prec, flags);
  1.1097 +	    if (rv < 0) {
  1.1098 +		return rv;
  1.1099 +	    }
  1.1100 +	    break;
  1.1101 +
  1.1102 +        case 's':
  1.1103 +	    u.s = va_arg(ap, const char*);
  1.1104 +	    rv = cvt_s(ss, u.s, width, prec, flags);
  1.1105 +	    if (rv < 0) {
  1.1106 +		return rv;
  1.1107 +	    }
  1.1108 +	    break;
  1.1109 +
  1.1110 +        case 'n':
  1.1111 +	    u.ip = va_arg(ap, int*);
  1.1112 +	    if (u.ip) {
  1.1113 +		*u.ip = ss->cur - ss->base;
  1.1114 +	    }
  1.1115 +	    break;
  1.1116 +
  1.1117 +        default:
  1.1118 +	    /* Not a % token after all... skip it */
  1.1119 +#if 0
  1.1120 +	    PR_ASSERT(0);
  1.1121 +#endif
  1.1122 +            char16_t perct = '%'; 
  1.1123 +	    rv = (*ss->stuff)(ss, &perct, 1);
  1.1124 +	    if (rv < 0) {
  1.1125 +		return rv;
  1.1126 +	    }
  1.1127 +	    rv = (*ss->stuff)(ss, fmt - 1, 1);
  1.1128 +	    if (rv < 0) {
  1.1129 +		return rv;
  1.1130 +	    }
  1.1131 +	}
  1.1132 +    }
  1.1133 +
  1.1134 +    /* Stuff trailing NUL */
  1.1135 +    char16_t null = '\0';
  1.1136 +
  1.1137 +    rv = (*ss->stuff)(ss, &null, 1);
  1.1138 +
  1.1139 +    if( nas && ( nas != nasArray ) ){
  1.1140 +	PR_DELETE( nas );
  1.1141 +    }
  1.1142 +
  1.1143 +    return rv;
  1.1144 +}
  1.1145 +
  1.1146 +/************************************************************************/
  1.1147 +
  1.1148 +static int
  1.1149 +StringStuff(SprintfState* ss, const char16_t* sp, uint32_t len)
  1.1150 +{
  1.1151 +    if (*sp == '\0')
  1.1152 +      return 0;
  1.1153 +
  1.1154 +    ptrdiff_t off = ss->cur - ss->base;
  1.1155 +    
  1.1156 +    nsAString* str = static_cast<nsAString*>(ss->stuffclosure);
  1.1157 +    str->Append(sp, len);
  1.1158 +
  1.1159 +    ss->base = str->BeginWriting();
  1.1160 +    ss->cur = ss->base + off;
  1.1161 +
  1.1162 +    return 0;
  1.1163 +}
  1.1164 +
  1.1165 +/*
  1.1166 +** Stuff routine that automatically grows the malloc'd output buffer
  1.1167 +** before it overflows.
  1.1168 +*/
  1.1169 +static int GrowStuff(SprintfState *ss, const char16_t *sp, uint32_t len)
  1.1170 +{
  1.1171 +    ptrdiff_t off;
  1.1172 +    char16_t *newbase;
  1.1173 +    uint32_t newlen;
  1.1174 +
  1.1175 +    off = ss->cur - ss->base;
  1.1176 +    if (off + len >= ss->maxlen) {
  1.1177 +	/* Grow the buffer */
  1.1178 +	newlen = ss->maxlen + ((len > 32) ? len : 32);
  1.1179 +	if (ss->base) {
  1.1180 +	    newbase = (char16_t*) nsMemory::Realloc(ss->base, newlen*sizeof(char16_t));
  1.1181 +	} else {
  1.1182 +	    newbase = (char16_t*) nsMemory::Alloc(newlen*sizeof(char16_t));
  1.1183 +	}
  1.1184 +	if (!newbase) {
  1.1185 +	    /* Ran out of memory */
  1.1186 +	    return -1;
  1.1187 +	}
  1.1188 +	ss->base = newbase;
  1.1189 +	ss->maxlen = newlen;
  1.1190 +	ss->cur = ss->base + off;
  1.1191 +    }
  1.1192 +
  1.1193 +    /* Copy data */
  1.1194 +    while (len) {
  1.1195 +	--len;
  1.1196 +	*ss->cur++ = *sp++;
  1.1197 +    }
  1.1198 +    PR_ASSERT((uint32_t)(ss->cur - ss->base) <= ss->maxlen);
  1.1199 +    return 0;
  1.1200 +}
  1.1201 +
  1.1202 +/*
  1.1203 +** sprintf into a malloc'd buffer
  1.1204 +*/
  1.1205 +char16_t * nsTextFormatter::smprintf(const char16_t *fmt, ...)
  1.1206 +{
  1.1207 +    va_list ap;
  1.1208 +    char16_t *rv;
  1.1209 +
  1.1210 +    va_start(ap, fmt);
  1.1211 +    rv = nsTextFormatter::vsmprintf(fmt, ap);
  1.1212 +    va_end(ap);
  1.1213 +    return rv;
  1.1214 +}
  1.1215 +
  1.1216 +uint32_t nsTextFormatter::ssprintf(nsAString& out, const char16_t* fmt, ...)
  1.1217 +{
  1.1218 +    va_list ap;
  1.1219 +    uint32_t rv;
  1.1220 +
  1.1221 +    va_start(ap, fmt);
  1.1222 +    rv = nsTextFormatter::vssprintf(out, fmt, ap);
  1.1223 +    va_end(ap);
  1.1224 +    return rv;
  1.1225 +}
  1.1226 +
  1.1227 +uint32_t nsTextFormatter::vssprintf(nsAString& out, const char16_t* fmt, va_list ap)
  1.1228 +{
  1.1229 +    SprintfState ss;
  1.1230 +    ss.stuff = StringStuff;
  1.1231 +    ss.base = 0;
  1.1232 +    ss.cur = 0;
  1.1233 +    ss.maxlen = 0;
  1.1234 +    ss.stuffclosure = &out;
  1.1235 +
  1.1236 +    out.Truncate();
  1.1237 +    int n = dosprintf(&ss, fmt, ap);
  1.1238 +    return n ? n - 1 : n;
  1.1239 +}
  1.1240 +
  1.1241 +char16_t * nsTextFormatter::vsmprintf(const char16_t *fmt, va_list ap)
  1.1242 +{
  1.1243 +    SprintfState ss;
  1.1244 +    int rv;
  1.1245 +
  1.1246 +    ss.stuff = GrowStuff;
  1.1247 +    ss.base = 0;
  1.1248 +    ss.cur = 0;
  1.1249 +    ss.maxlen = 0;
  1.1250 +    rv = dosprintf(&ss, fmt, ap);
  1.1251 +    if (rv < 0) {
  1.1252 +	if (ss.base) {
  1.1253 +	    PR_DELETE(ss.base);
  1.1254 +	}
  1.1255 +	return 0;
  1.1256 +    }
  1.1257 +    return ss.base;
  1.1258 +}
  1.1259 +
  1.1260 +/*
  1.1261 +** Stuff routine that discards overflow data
  1.1262 +*/
  1.1263 +static int LimitStuff(SprintfState *ss, const char16_t *sp, uint32_t len)
  1.1264 +{
  1.1265 +    uint32_t limit = ss->maxlen - (ss->cur - ss->base);
  1.1266 +
  1.1267 +    if (len > limit) {
  1.1268 +	len = limit;
  1.1269 +    }
  1.1270 +    while (len) {
  1.1271 +	--len;
  1.1272 +	*ss->cur++ = *sp++;
  1.1273 +    }
  1.1274 +    return 0;
  1.1275 +}
  1.1276 +
  1.1277 +/*
  1.1278 +** sprintf into a fixed size buffer. Make sure there is a NUL at the end
  1.1279 +** when finished.
  1.1280 +*/
  1.1281 +uint32_t nsTextFormatter::snprintf(char16_t *out, uint32_t outlen, const char16_t *fmt, ...)
  1.1282 +{
  1.1283 +    va_list ap;
  1.1284 +    uint32_t rv;
  1.1285 +
  1.1286 +    PR_ASSERT((int32_t)outlen > 0);
  1.1287 +    if ((int32_t)outlen <= 0) {
  1.1288 +	return 0;
  1.1289 +    }
  1.1290 +
  1.1291 +    va_start(ap, fmt);
  1.1292 +    rv = nsTextFormatter::vsnprintf(out, outlen, fmt, ap);
  1.1293 +    va_end(ap);
  1.1294 +    return rv;
  1.1295 +}
  1.1296 +
  1.1297 +uint32_t nsTextFormatter::vsnprintf(char16_t *out, uint32_t outlen,const char16_t *fmt,
  1.1298 +                                    va_list ap)
  1.1299 +{
  1.1300 +    SprintfState ss;
  1.1301 +    uint32_t n;
  1.1302 +
  1.1303 +    PR_ASSERT((int32_t)outlen > 0);
  1.1304 +    if ((int32_t)outlen <= 0) {
  1.1305 +	return 0;
  1.1306 +    }
  1.1307 +
  1.1308 +    ss.stuff = LimitStuff;
  1.1309 +    ss.base = out;
  1.1310 +    ss.cur = out;
  1.1311 +    ss.maxlen = outlen;
  1.1312 +    (void) dosprintf(&ss, fmt, ap);
  1.1313 +
  1.1314 +    /* If we added chars, and we didn't append a null, do it now. */
  1.1315 +    if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') )
  1.1316 +        *(--ss.cur) = '\0';
  1.1317 +
  1.1318 +    n = ss.cur - ss.base;
  1.1319 +    return n ? n - 1 : n;
  1.1320 +}
  1.1321 +
  1.1322 +/*
  1.1323 + * Free memory allocated, for the caller, by smprintf
  1.1324 + */
  1.1325 +void nsTextFormatter::smprintf_free(char16_t *mem)
  1.1326 +{
  1.1327 +    nsMemory::Free(mem);
  1.1328 +}
  1.1329 +

mercurial