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(", &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 +