nsprpub/pr/src/io/prprf.c

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

mercurial