xpcom/glue/nsTextFormatter.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial