1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Netscape Portable Runtime (NSPR).
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : ** Portable safe sprintf code.
40 : **
41 : ** Author: Kipp E.B. Hickman
42 : */
43 : #include <stdarg.h>
44 : #include <stddef.h>
45 : #include <stdio.h>
46 : #include <string.h>
47 : #include "primpl.h"
48 : #include "prprf.h"
49 : #include "prlong.h"
50 : #include "prlog.h"
51 : #include "prmem.h"
52 :
53 : /*
54 : ** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it)
55 : */
56 :
57 : /*
58 : ** XXX This needs to be internationalized!
59 : */
60 :
61 : typedef struct SprintfStateStr SprintfState;
62 :
63 : struct SprintfStateStr {
64 : int (*stuff)(SprintfState *ss, const char *sp, PRUint32 len);
65 :
66 : char *base;
67 : char *cur;
68 : PRUint32 maxlen;
69 :
70 : int (*func)(void *arg, const char *sp, PRUint32 len);
71 : void *arg;
72 : };
73 :
74 : /*
75 : ** Numbered Argument
76 : */
77 : struct NumArg {
78 : int type; /* type of the numbered argument */
79 : union { /* the numbered argument */
80 : int i;
81 : unsigned int ui;
82 : PRInt32 i32;
83 : PRUint32 ui32;
84 : PRInt64 ll;
85 : PRUint64 ull;
86 : double d;
87 : const char *s;
88 : int *ip;
89 : #ifdef WIN32
90 : const WCHAR *ws;
91 : #endif
92 : } u;
93 : };
94 :
95 : #define NAS_DEFAULT_NUM 20 /* default number of NumberedArgument array */
96 :
97 :
98 : #define TYPE_INT16 0
99 : #define TYPE_UINT16 1
100 : #define TYPE_INTN 2
101 : #define TYPE_UINTN 3
102 : #define TYPE_INT32 4
103 : #define TYPE_UINT32 5
104 : #define TYPE_INT64 6
105 : #define TYPE_UINT64 7
106 : #define TYPE_STRING 8
107 : #define TYPE_DOUBLE 9
108 : #define TYPE_INTSTR 10
109 : #ifdef WIN32
110 : #define TYPE_WSTRING 11
111 : #endif
112 : #define TYPE_UNKNOWN 20
113 :
114 : #define FLAG_LEFT 0x1
115 : #define FLAG_SIGNED 0x2
116 : #define FLAG_SPACED 0x4
117 : #define FLAG_ZEROS 0x8
118 : #define FLAG_NEG 0x10
119 :
120 : /*
121 : ** Fill into the buffer using the data in src
122 : */
123 69544 : static int fill2(SprintfState *ss, const char *src, int srclen, int width,
124 : int flags)
125 : {
126 69544 : char space = ' ';
127 : int rv;
128 :
129 69544 : width -= srclen;
130 69544 : if ((width > 0) && ((flags & FLAG_LEFT) == 0)) { /* Right adjusting */
131 0 : if (flags & FLAG_ZEROS) {
132 0 : space = '0';
133 : }
134 0 : while (--width >= 0) {
135 0 : rv = (*ss->stuff)(ss, &space, 1);
136 0 : if (rv < 0) {
137 0 : return rv;
138 : }
139 : }
140 : }
141 :
142 : /* Copy out the source data */
143 69544 : rv = (*ss->stuff)(ss, src, srclen);
144 69544 : if (rv < 0) {
145 0 : return rv;
146 : }
147 :
148 69544 : if ((width > 0) && ((flags & FLAG_LEFT) != 0)) { /* Left adjusting */
149 0 : while (--width >= 0) {
150 0 : rv = (*ss->stuff)(ss, &space, 1);
151 0 : if (rv < 0) {
152 0 : return rv;
153 : }
154 : }
155 : }
156 69544 : return 0;
157 : }
158 :
159 : /*
160 : ** Fill a number. The order is: optional-sign zero-filling conversion-digits
161 : */
162 212434 : static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
163 : int prec, int type, int flags)
164 : {
165 212434 : int zerowidth = 0;
166 212434 : int precwidth = 0;
167 212434 : int signwidth = 0;
168 212434 : int leftspaces = 0;
169 212434 : int rightspaces = 0;
170 : int cvtwidth;
171 : int rv;
172 : char sign;
173 :
174 212434 : if ((type & 1) == 0) {
175 72944 : if (flags & FLAG_NEG) {
176 509 : sign = '-';
177 509 : signwidth = 1;
178 72435 : } else if (flags & FLAG_SIGNED) {
179 0 : sign = '+';
180 0 : signwidth = 1;
181 72435 : } else if (flags & FLAG_SPACED) {
182 0 : sign = ' ';
183 0 : signwidth = 1;
184 : }
185 : }
186 212434 : cvtwidth = signwidth + srclen;
187 :
188 212434 : if (prec > 0) {
189 1210 : if (prec > srclen) {
190 535 : precwidth = prec - srclen; /* Need zero filling */
191 535 : cvtwidth += precwidth;
192 : }
193 : }
194 :
195 212434 : if ((flags & FLAG_ZEROS) && (prec < 0)) {
196 134126 : if (width > cvtwidth) {
197 8330 : zerowidth = width - cvtwidth; /* Zero filling */
198 8330 : cvtwidth += zerowidth;
199 : }
200 : }
201 :
202 212434 : if (flags & FLAG_LEFT) {
203 0 : if (width > cvtwidth) {
204 : /* Space filling on the right (i.e. left adjusting) */
205 0 : rightspaces = width - cvtwidth;
206 : }
207 : } else {
208 212434 : if (width > cvtwidth) {
209 : /* Space filling on the left (i.e. right adjusting) */
210 0 : leftspaces = width - cvtwidth;
211 : }
212 : }
213 424868 : while (--leftspaces >= 0) {
214 0 : rv = (*ss->stuff)(ss, " ", 1);
215 0 : if (rv < 0) {
216 0 : return rv;
217 : }
218 : }
219 212434 : if (signwidth) {
220 509 : rv = (*ss->stuff)(ss, &sign, 1);
221 509 : if (rv < 0) {
222 0 : return rv;
223 : }
224 : }
225 425403 : while (--precwidth >= 0) {
226 535 : rv = (*ss->stuff)(ss, "0", 1);
227 535 : if (rv < 0) {
228 0 : return rv;
229 : }
230 : }
231 434057 : while (--zerowidth >= 0) {
232 9189 : rv = (*ss->stuff)(ss, "0", 1);
233 9189 : if (rv < 0) {
234 0 : return rv;
235 : }
236 : }
237 212434 : rv = (*ss->stuff)(ss, src, srclen);
238 212434 : if (rv < 0) {
239 0 : return rv;
240 : }
241 424868 : while (--rightspaces >= 0) {
242 0 : rv = (*ss->stuff)(ss, " ", 1);
243 0 : if (rv < 0) {
244 0 : return rv;
245 : }
246 : }
247 212434 : return 0;
248 : }
249 :
250 : /*
251 : ** Convert a long into its printable form
252 : */
253 203035 : static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
254 : int type, int flags, const char *hexp)
255 : {
256 : char cvtbuf[100];
257 : char *cvt;
258 : int digits;
259 :
260 : /* according to the man page this needs to happen */
261 203035 : if ((prec == 0) && (num == 0)) {
262 0 : return 0;
263 : }
264 :
265 : /*
266 : ** Converting decimal is a little tricky. In the unsigned case we
267 : ** need to stop when we hit 10 digits. In the signed case, we can
268 : ** stop when the number is zero.
269 : */
270 203035 : cvt = cvtbuf + sizeof(cvtbuf);
271 203035 : digits = 0;
272 947215 : while (num) {
273 541145 : int digit = (((unsigned long)num) % radix) & 0xF;
274 541145 : *--cvt = hexp[digit];
275 541145 : digits++;
276 541145 : num = (long)(((unsigned long)num) / radix);
277 : }
278 203035 : if (digits == 0) {
279 3316 : *--cvt = '0';
280 3316 : digits++;
281 : }
282 :
283 : /*
284 : ** Now that we have the number converted without its sign, deal with
285 : ** the sign and zero padding.
286 : */
287 203035 : return fill_n(ss, cvt, digits, width, prec, type, flags);
288 : }
289 :
290 : /*
291 : ** Convert a 64-bit integer into its printable form
292 : */
293 9399 : static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, int radix,
294 : int type, int flags, const char *hexp)
295 : {
296 : char cvtbuf[100];
297 : char *cvt;
298 : int digits;
299 : PRInt64 rad;
300 :
301 : /* according to the man page this needs to happen */
302 9399 : if ((prec == 0) && (LL_IS_ZERO(num))) {
303 0 : return 0;
304 : }
305 :
306 : /*
307 : ** Converting decimal is a little tricky. In the unsigned case we
308 : ** need to stop when we hit 10 digits. In the signed case, we can
309 : ** stop when the number is zero.
310 : */
311 9399 : LL_I2L(rad, radix);
312 9399 : cvt = cvtbuf + sizeof(cvtbuf);
313 9399 : digits = 0;
314 101740 : while (!LL_IS_ZERO(num)) {
315 : PRInt32 digit;
316 : PRInt64 quot, rem;
317 82942 : LL_UDIVMOD(", &rem, num, rad);
318 82942 : LL_L2I(digit, rem);
319 82942 : *--cvt = hexp[digit & 0xf];
320 82942 : digits++;
321 82942 : num = quot;
322 : }
323 9399 : if (digits == 0) {
324 80 : *--cvt = '0';
325 80 : digits++;
326 : }
327 :
328 : /*
329 : ** Now that we have the number converted without its sign, deal with
330 : ** the sign and zero padding.
331 : */
332 9399 : return fill_n(ss, cvt, digits, width, prec, type, flags);
333 : }
334 :
335 : /*
336 : ** Convert a double precision floating point number into its printable
337 : ** form.
338 : **
339 : ** XXX stop using sprintf to convert floating point
340 : */
341 0 : static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
342 : {
343 : char fin[20];
344 : char fout[300];
345 0 : int amount = fmt1 - fmt0;
346 :
347 0 : PR_ASSERT((amount > 0) && (amount < sizeof(fin)));
348 0 : if (amount >= sizeof(fin)) {
349 : /* Totally bogus % command to sprintf. Just ignore it */
350 0 : return 0;
351 : }
352 0 : memcpy(fin, fmt0, amount);
353 0 : fin[amount] = 0;
354 :
355 : /* Convert floating point using the native sprintf code */
356 : #ifdef DEBUG
357 : {
358 0 : const char *p = fin;
359 0 : while (*p) {
360 0 : PR_ASSERT(*p != 'L');
361 0 : p++;
362 : }
363 : }
364 : #endif
365 0 : sprintf(fout, fin, d);
366 :
367 : /*
368 : ** This assert will catch overflow's of fout, when building with
369 : ** debugging on. At least this way we can track down the evil piece
370 : ** of calling code and fix it!
371 : */
372 0 : PR_ASSERT(strlen(fout) < sizeof(fout));
373 :
374 0 : return (*ss->stuff)(ss, fout, strlen(fout));
375 : }
376 :
377 : /*
378 : ** Convert a string into its printable form. "width" is the output
379 : ** width. "prec" is the maximum number of characters of "s" to output,
380 : ** where -1 means until NUL.
381 : */
382 69544 : static int cvt_s(SprintfState *ss, const char *str, int width, int prec,
383 : int flags)
384 : {
385 : int slen;
386 :
387 69544 : if (prec == 0)
388 0 : return 0;
389 :
390 : /* Limit string length by precision value */
391 69544 : if (!str) {
392 0 : str = "(null)";
393 : }
394 69544 : if (prec > 0) {
395 : /* this is: slen = strnlen(str, prec); */
396 : register const char *s;
397 :
398 0 : for(s = str; prec && *s; s++, prec-- )
399 : ;
400 0 : slen = s - str;
401 : } else {
402 69544 : slen = strlen(str);
403 : }
404 :
405 : /* and away we go */
406 69544 : return fill2(ss, str, slen, width, flags);
407 : }
408 :
409 : /*
410 : ** BuildArgArray stands for Numbered Argument list Sprintf
411 : ** for example,
412 : ** fmp = "%4$i, %2$d, %3s, %1d";
413 : ** the number must start from 1, and no gap among them
414 : */
415 :
416 120831 : static struct NumArg* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArg* nasArray )
417 : {
418 120831 : int number = 0, cn = 0, i;
419 : const char* p;
420 : char c;
421 : struct NumArg* nas;
422 :
423 :
424 : /*
425 : ** first pass:
426 : ** determine how many legal % I have got, then allocate space
427 : */
428 :
429 120831 : p = fmt;
430 120831 : *rv = 0;
431 120831 : i = 0;
432 1521220 : while( ( c = *p++ ) != 0 ){
433 1279558 : if( c != '%' )
434 992562 : continue;
435 286996 : if( ( c = *p++ ) == '%' ) /* skip %% case */
436 0 : continue;
437 :
438 842284 : while( c != 0 ){
439 555288 : if( c > '9' || c < '0' ){
440 286996 : if( c == '$' ){ /* numbered argument case */
441 0 : if( i > 0 ){
442 0 : *rv = -1;
443 0 : return NULL;
444 : }
445 0 : number++;
446 : } else{ /* non-numbered argument case */
447 286996 : if( number > 0 ){
448 0 : *rv = -1;
449 0 : return NULL;
450 : }
451 286996 : i = 1;
452 : }
453 286996 : break;
454 : }
455 :
456 268292 : c = *p++;
457 : }
458 : }
459 :
460 120831 : if( number == 0 ){
461 120831 : return NULL;
462 : }
463 :
464 :
465 0 : if( number > NAS_DEFAULT_NUM ){
466 0 : nas = (struct NumArg*)PR_MALLOC( number * sizeof( struct NumArg ) );
467 0 : if( !nas ){
468 0 : *rv = -1;
469 0 : return NULL;
470 : }
471 : } else {
472 0 : nas = nasArray;
473 : }
474 :
475 0 : for( i = 0; i < number; i++ ){
476 0 : nas[i].type = TYPE_UNKNOWN;
477 : }
478 :
479 :
480 : /*
481 : ** second pass:
482 : ** set nas[].type
483 : */
484 :
485 0 : p = fmt;
486 0 : while( ( c = *p++ ) != 0 ){
487 0 : if( c != '%' ) continue;
488 0 : c = *p++;
489 0 : if( c == '%' ) continue;
490 :
491 0 : cn = 0;
492 0 : while( c && c != '$' ){ /* should imporve error check later */
493 0 : cn = cn*10 + c - '0';
494 0 : c = *p++;
495 : }
496 :
497 0 : if( !c || cn < 1 || cn > number ){
498 0 : *rv = -1;
499 0 : break;
500 : }
501 :
502 : /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
503 0 : cn--;
504 0 : if( nas[cn].type != TYPE_UNKNOWN )
505 0 : continue;
506 :
507 0 : c = *p++;
508 :
509 : /* width */
510 0 : if (c == '*') {
511 : /* not supported feature, for the argument is not numbered */
512 0 : *rv = -1;
513 0 : break;
514 : }
515 :
516 0 : while ((c >= '0') && (c <= '9')) {
517 0 : c = *p++;
518 : }
519 :
520 : /* precision */
521 0 : if (c == '.') {
522 0 : c = *p++;
523 0 : if (c == '*') {
524 : /* not supported feature, for the argument is not numbered */
525 0 : *rv = -1;
526 0 : break;
527 : }
528 :
529 0 : while ((c >= '0') && (c <= '9')) {
530 0 : c = *p++;
531 : }
532 : }
533 :
534 : /* size */
535 0 : nas[cn].type = TYPE_INTN;
536 0 : if (c == 'h') {
537 0 : nas[cn].type = TYPE_INT16;
538 0 : c = *p++;
539 0 : } else if (c == 'L') {
540 : /* XXX not quite sure here */
541 0 : nas[cn].type = TYPE_INT64;
542 0 : c = *p++;
543 0 : } else if (c == 'l') {
544 0 : nas[cn].type = TYPE_INT32;
545 0 : c = *p++;
546 0 : if (c == 'l') {
547 0 : nas[cn].type = TYPE_INT64;
548 0 : c = *p++;
549 : }
550 : }
551 :
552 : /* format */
553 0 : switch (c) {
554 : case 'd':
555 : case 'c':
556 : case 'i':
557 : case 'o':
558 : case 'u':
559 : case 'x':
560 : case 'X':
561 0 : break;
562 :
563 : case 'e':
564 : case 'f':
565 : case 'g':
566 0 : nas[ cn ].type = TYPE_DOUBLE;
567 0 : break;
568 :
569 : case 'p':
570 : /* XXX should use cpp */
571 : if (sizeof(void *) == sizeof(PRInt32)) {
572 0 : nas[ cn ].type = TYPE_UINT32;
573 : } else if (sizeof(void *) == sizeof(PRInt64)) {
574 : nas[ cn ].type = TYPE_UINT64;
575 : } else if (sizeof(void *) == sizeof(PRIntn)) {
576 : nas[ cn ].type = TYPE_UINTN;
577 : } else {
578 : nas[ cn ].type = TYPE_UNKNOWN;
579 : }
580 0 : break;
581 :
582 : case 'S':
583 : #ifdef WIN32
584 : nas[ cn ].type = TYPE_WSTRING;
585 : break;
586 : #endif
587 : case 'C':
588 : case 'E':
589 : case 'G':
590 : /* XXX not supported I suppose */
591 0 : PR_ASSERT(0);
592 0 : nas[ cn ].type = TYPE_UNKNOWN;
593 0 : break;
594 :
595 : case 's':
596 0 : nas[ cn ].type = TYPE_STRING;
597 0 : break;
598 :
599 : case 'n':
600 0 : nas[ cn ].type = TYPE_INTSTR;
601 0 : break;
602 :
603 : default:
604 0 : PR_ASSERT(0);
605 0 : nas[ cn ].type = TYPE_UNKNOWN;
606 0 : break;
607 : }
608 :
609 : /* get a legal para. */
610 0 : if( nas[ cn ].type == TYPE_UNKNOWN ){
611 0 : *rv = -1;
612 0 : break;
613 : }
614 : }
615 :
616 :
617 : /*
618 : ** third pass
619 : ** fill the nas[cn].ap
620 : */
621 :
622 0 : if( *rv < 0 ){
623 0 : if( nas != nasArray )
624 0 : PR_DELETE( nas );
625 0 : return NULL;
626 : }
627 :
628 0 : cn = 0;
629 0 : while( cn < number ){
630 0 : if( nas[cn].type == TYPE_UNKNOWN ){
631 0 : cn++;
632 0 : continue;
633 : }
634 :
635 0 : switch( nas[cn].type ){
636 : case TYPE_INT16:
637 : case TYPE_UINT16:
638 : case TYPE_INTN:
639 0 : nas[cn].u.i = va_arg( ap, int );
640 0 : break;
641 :
642 : case TYPE_UINTN:
643 0 : nas[cn].u.ui = va_arg( ap, unsigned int );
644 0 : break;
645 :
646 : case TYPE_INT32:
647 0 : nas[cn].u.i32 = va_arg( ap, PRInt32 );
648 0 : break;
649 :
650 : case TYPE_UINT32:
651 0 : nas[cn].u.ui32 = va_arg( ap, PRUint32 );
652 0 : break;
653 :
654 : case TYPE_INT64:
655 0 : nas[cn].u.ll = va_arg( ap, PRInt64 );
656 0 : break;
657 :
658 : case TYPE_UINT64:
659 0 : nas[cn].u.ull = va_arg( ap, PRUint64 );
660 0 : break;
661 :
662 : case TYPE_STRING:
663 0 : nas[cn].u.s = va_arg( ap, char* );
664 0 : break;
665 :
666 : #ifdef WIN32
667 : case TYPE_WSTRING:
668 : nas[cn].u.s = va_arg( ap, WCHAR* );
669 : break;
670 : #endif
671 :
672 : case TYPE_INTSTR:
673 0 : nas[cn].u.ip = va_arg( ap, int* );
674 0 : break;
675 :
676 : case TYPE_DOUBLE:
677 0 : nas[cn].u.d = va_arg( ap, double );
678 0 : break;
679 :
680 : default:
681 0 : if( nas != nasArray )
682 0 : PR_DELETE( nas );
683 0 : *rv = -1;
684 0 : return NULL;
685 : }
686 :
687 0 : cn++;
688 : }
689 :
690 :
691 0 : return nas;
692 : }
693 :
694 : /*
695 : ** The workhorse sprintf code.
696 : */
697 120831 : static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
698 : {
699 : char c;
700 : int flags, width, prec, radix, type;
701 : union {
702 : char ch;
703 : int i;
704 : long l;
705 : PRInt64 ll;
706 : double d;
707 : const char *s;
708 : int *ip;
709 : #ifdef WIN32
710 : WCHAR *ws;
711 : #endif
712 : } u;
713 : const char *fmt0;
714 : static char *hex = "0123456789abcdef";
715 : static char *HEX = "0123456789ABCDEF";
716 : char *hexp;
717 : int rv, i;
718 120831 : struct NumArg* nas = NULL;
719 : struct NumArg* nap;
720 : struct NumArg nasArray[ NAS_DEFAULT_NUM ];
721 : char pattern[20];
722 120831 : const char* dolPt = NULL; /* in "%4$.2f", dolPt will point to . */
723 : #ifdef WIN32
724 : char *pBuf = NULL;
725 : #endif
726 :
727 : /*
728 : ** build an argument array, IF the fmt is numbered argument
729 : ** list style, to contain the Numbered Argument list pointers
730 : */
731 :
732 120831 : nas = BuildArgArray( fmt, ap, &rv, nasArray );
733 120831 : if( rv < 0 ){
734 : /* the fmt contains error Numbered Argument format, jliu@netscape.com */
735 0 : PR_ASSERT(0);
736 0 : return rv;
737 : }
738 :
739 1490543 : while ((c = *fmt++) != 0) {
740 1248881 : if (c != '%') {
741 961885 : rv = (*ss->stuff)(ss, fmt - 1, 1);
742 961885 : if (rv < 0) {
743 0 : return rv;
744 : }
745 961885 : continue;
746 : }
747 286996 : fmt0 = fmt - 1;
748 :
749 : /*
750 : ** Gobble up the % format string. Hopefully we have handled all
751 : ** of the strange cases!
752 : */
753 286996 : flags = 0;
754 286996 : c = *fmt++;
755 286996 : if (c == '%') {
756 : /* quoting a % with %% */
757 0 : rv = (*ss->stuff)(ss, fmt - 1, 1);
758 0 : if (rv < 0) {
759 0 : return rv;
760 : }
761 0 : continue;
762 : }
763 :
764 286996 : if( nas != NULL ){
765 : /* the fmt contains the Numbered Arguments feature */
766 0 : i = 0;
767 0 : while( c && c != '$' ){ /* should imporve error check later */
768 0 : i = ( i * 10 ) + ( c - '0' );
769 0 : c = *fmt++;
770 : }
771 :
772 0 : if( nas[i-1].type == TYPE_UNKNOWN ){
773 0 : if( nas && ( nas != nasArray ) )
774 0 : PR_DELETE( nas );
775 0 : return -1;
776 : }
777 :
778 0 : nap = &nas[i-1];
779 0 : dolPt = fmt;
780 0 : c = *fmt++;
781 : }
782 :
783 : /*
784 : * Examine optional flags. Note that we do not implement the
785 : * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is
786 : * somewhat ambiguous and not ideal, which is perhaps why
787 : * the various sprintf() implementations are inconsistent
788 : * on this feature.
789 : */
790 708118 : while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
791 134126 : if (c == '-') flags |= FLAG_LEFT;
792 134126 : if (c == '+') flags |= FLAG_SIGNED;
793 134126 : if (c == ' ') flags |= FLAG_SPACED;
794 134126 : if (c == '0') flags |= FLAG_ZEROS;
795 134126 : c = *fmt++;
796 : }
797 286996 : if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
798 286996 : if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
799 :
800 : /* width */
801 286996 : if (c == '*') {
802 0 : c = *fmt++;
803 0 : width = va_arg(ap, int);
804 : } else {
805 286996 : width = 0;
806 708158 : while ((c >= '0') && (c <= '9')) {
807 134166 : width = (width * 10) + (c - '0');
808 134166 : c = *fmt++;
809 : }
810 : }
811 :
812 : /* precision */
813 286996 : prec = -1;
814 286996 : if (c == '.') {
815 1210 : c = *fmt++;
816 1210 : if (c == '*') {
817 0 : c = *fmt++;
818 0 : prec = va_arg(ap, int);
819 : } else {
820 1210 : prec = 0;
821 3630 : while ((c >= '0') && (c <= '9')) {
822 1210 : prec = (prec * 10) + (c - '0');
823 1210 : c = *fmt++;
824 : }
825 : }
826 : }
827 :
828 : /* size */
829 286996 : type = TYPE_INTN;
830 286996 : if (c == 'h') {
831 1038 : type = TYPE_INT16;
832 1038 : c = *fmt++;
833 285958 : } else if (c == 'L') {
834 : /* XXX not quite sure here */
835 0 : type = TYPE_INT64;
836 0 : c = *fmt++;
837 285958 : } else if (c == 'l') {
838 17820 : type = TYPE_INT32;
839 17820 : c = *fmt++;
840 17820 : if (c == 'l') {
841 9399 : type = TYPE_INT64;
842 9399 : c = *fmt++;
843 : }
844 : }
845 :
846 : /* format */
847 286996 : hexp = hex;
848 286996 : switch (c) {
849 : case 'd': case 'i': /* decimal/integer */
850 72944 : radix = 10;
851 72944 : goto fetch_and_convert;
852 :
853 : case 'o': /* octal */
854 0 : radix = 8;
855 0 : type |= 1;
856 0 : goto fetch_and_convert;
857 :
858 : case 'u': /* unsigned decimal */
859 5417 : radix = 10;
860 5417 : type |= 1;
861 5417 : goto fetch_and_convert;
862 :
863 : case 'x': /* unsigned hex */
864 127921 : radix = 16;
865 127921 : type |= 1;
866 127921 : goto fetch_and_convert;
867 :
868 : case 'X': /* unsigned HEX */
869 5619 : radix = 16;
870 5619 : hexp = HEX;
871 5619 : type |= 1;
872 5619 : goto fetch_and_convert;
873 :
874 : fetch_and_convert:
875 212434 : switch (type) {
876 : case TYPE_INT16:
877 1038 : u.l = nas ? nap->u.i : va_arg(ap, int);
878 1038 : if (u.l < 0) {
879 0 : u.l = -u.l;
880 0 : flags |= FLAG_NEG;
881 : }
882 1038 : goto do_long;
883 : case TYPE_UINT16:
884 0 : u.l = (nas ? nap->u.i : va_arg(ap, int)) & 0xffff;
885 0 : goto do_long;
886 : case TYPE_INTN:
887 55867 : u.l = nas ? nap->u.i : va_arg(ap, int);
888 55867 : if (u.l < 0) {
889 509 : u.l = -u.l;
890 509 : flags |= FLAG_NEG;
891 : }
892 55867 : goto do_long;
893 : case TYPE_UINTN:
894 137176 : u.l = (long)(nas ? nap->u.ui : va_arg(ap, unsigned int));
895 137176 : goto do_long;
896 :
897 : case TYPE_INT32:
898 6783 : u.l = nas ? nap->u.i32 : va_arg(ap, PRInt32);
899 6783 : if (u.l < 0) {
900 0 : u.l = -u.l;
901 0 : flags |= FLAG_NEG;
902 : }
903 6783 : goto do_long;
904 : case TYPE_UINT32:
905 2171 : u.l = (long)(nas ? nap->u.ui32 : va_arg(ap, PRUint32));
906 : do_long:
907 203035 : rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
908 203035 : if (rv < 0) {
909 0 : return rv;
910 : }
911 203035 : break;
912 :
913 : case TYPE_INT64:
914 9256 : u.ll = nas ? nap->u.ll : va_arg(ap, PRInt64);
915 9256 : if (!LL_GE_ZERO(u.ll)) {
916 0 : LL_NEG(u.ll, u.ll);
917 0 : flags |= FLAG_NEG;
918 : }
919 9256 : goto do_longlong;
920 : case TYPE_UINT64:
921 143 : u.ll = nas ? nap->u.ull : va_arg(ap, PRUint64);
922 : do_longlong:
923 9399 : rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
924 9399 : if (rv < 0) {
925 0 : return rv;
926 : }
927 9399 : break;
928 : }
929 212434 : break;
930 :
931 : case 'e':
932 : case 'E':
933 : case 'f':
934 : case 'g':
935 0 : u.d = nas ? nap->u.d : va_arg(ap, double);
936 0 : if( nas != NULL ){
937 0 : i = fmt - dolPt;
938 0 : if( i < sizeof( pattern ) ){
939 0 : pattern[0] = '%';
940 0 : memcpy( &pattern[1], dolPt, i );
941 0 : rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
942 : }
943 : } else
944 0 : rv = cvt_f(ss, u.d, fmt0, fmt);
945 :
946 0 : if (rv < 0) {
947 0 : return rv;
948 : }
949 0 : break;
950 :
951 : case 'c':
952 5018 : u.ch = nas ? nap->u.i : va_arg(ap, int);
953 5018 : if ((flags & FLAG_LEFT) == 0) {
954 10036 : while (width-- > 1) {
955 0 : rv = (*ss->stuff)(ss, " ", 1);
956 0 : if (rv < 0) {
957 0 : return rv;
958 : }
959 : }
960 : }
961 5018 : rv = (*ss->stuff)(ss, &u.ch, 1);
962 5018 : if (rv < 0) {
963 0 : return rv;
964 : }
965 5018 : if (flags & FLAG_LEFT) {
966 0 : while (width-- > 1) {
967 0 : rv = (*ss->stuff)(ss, " ", 1);
968 0 : if (rv < 0) {
969 0 : return rv;
970 : }
971 : }
972 : }
973 5018 : break;
974 :
975 : case 'p':
976 : if (sizeof(void *) == sizeof(PRInt32)) {
977 533 : type = TYPE_UINT32;
978 : } else if (sizeof(void *) == sizeof(PRInt64)) {
979 : type = TYPE_UINT64;
980 : } else if (sizeof(void *) == sizeof(int)) {
981 : type = TYPE_UINTN;
982 : } else {
983 : PR_ASSERT(0);
984 : break;
985 : }
986 533 : radix = 16;
987 533 : goto fetch_and_convert;
988 :
989 : #ifndef WIN32
990 : case 'S':
991 : /* XXX not supported I suppose */
992 0 : PR_ASSERT(0);
993 0 : break;
994 : #endif
995 :
996 : #if 0
997 : case 'C':
998 : case 'E':
999 : case 'G':
1000 : /* XXX not supported I suppose */
1001 : PR_ASSERT(0);
1002 : break;
1003 : #endif
1004 :
1005 : #ifdef WIN32
1006 : case 'S':
1007 : u.ws = nas ? nap->u.ws : va_arg(ap, const WCHAR*);
1008 :
1009 : /* Get the required size in rv */
1010 : rv = WideCharToMultiByte(CP_ACP, 0, u.ws, -1, NULL, 0, NULL, NULL);
1011 : if (rv == 0)
1012 : rv = 1;
1013 : pBuf = PR_MALLOC(rv);
1014 : WideCharToMultiByte(CP_ACP, 0, u.ws, -1, pBuf, (int)rv, NULL, NULL);
1015 : pBuf[rv-1] = '\0';
1016 :
1017 : rv = cvt_s(ss, pBuf, width, prec, flags);
1018 :
1019 : /* We don't need the allocated buffer anymore */
1020 : PR_Free(pBuf);
1021 : if (rv < 0) {
1022 : return rv;
1023 : }
1024 : break;
1025 :
1026 : #endif
1027 :
1028 : case 's':
1029 69544 : u.s = nas ? nap->u.s : va_arg(ap, const char*);
1030 69544 : rv = cvt_s(ss, u.s, width, prec, flags);
1031 69544 : if (rv < 0) {
1032 0 : return rv;
1033 : }
1034 69544 : break;
1035 :
1036 : case 'n':
1037 0 : u.ip = nas ? nap->u.ip : va_arg(ap, int*);
1038 0 : if (u.ip) {
1039 0 : *u.ip = ss->cur - ss->base;
1040 : }
1041 0 : break;
1042 :
1043 : default:
1044 : /* Not a % token after all... skip it */
1045 : #if 0
1046 : PR_ASSERT(0);
1047 : #endif
1048 0 : rv = (*ss->stuff)(ss, "%", 1);
1049 0 : if (rv < 0) {
1050 0 : return rv;
1051 : }
1052 0 : rv = (*ss->stuff)(ss, fmt - 1, 1);
1053 0 : if (rv < 0) {
1054 0 : return rv;
1055 : }
1056 : }
1057 : }
1058 :
1059 : /* Stuff trailing NUL */
1060 120831 : rv = (*ss->stuff)(ss, "\0", 1);
1061 :
1062 120831 : if( nas && ( nas != nasArray ) ){
1063 0 : PR_DELETE( nas );
1064 : }
1065 :
1066 120831 : return rv;
1067 : }
1068 :
1069 : /************************************************************************/
1070 :
1071 144288 : static int FuncStuff(SprintfState *ss, const char *sp, PRUint32 len)
1072 : {
1073 : int rv;
1074 :
1075 144288 : rv = (*ss->func)(ss->arg, sp, len);
1076 144288 : if (rv < 0) {
1077 0 : return rv;
1078 : }
1079 144288 : ss->maxlen += len;
1080 144288 : return 0;
1081 : }
1082 :
1083 24048 : PR_IMPLEMENT(PRUint32) PR_sxprintf(PRStuffFunc func, void *arg,
1084 : const char *fmt, ...)
1085 : {
1086 : va_list ap;
1087 : PRUint32 rv;
1088 :
1089 24048 : va_start(ap, fmt);
1090 24048 : rv = PR_vsxprintf(func, arg, fmt, ap);
1091 24048 : va_end(ap);
1092 24048 : return rv;
1093 : }
1094 :
1095 24048 : PR_IMPLEMENT(PRUint32) PR_vsxprintf(PRStuffFunc func, void *arg,
1096 : const char *fmt, va_list ap)
1097 : {
1098 : SprintfState ss;
1099 : int rv;
1100 :
1101 24048 : ss.stuff = FuncStuff;
1102 24048 : ss.func = func;
1103 24048 : ss.arg = arg;
1104 24048 : ss.maxlen = 0;
1105 24048 : rv = dosprintf(&ss, fmt, ap);
1106 24048 : return (rv < 0) ? (PRUint32)-1 : ss.maxlen;
1107 : }
1108 :
1109 : /*
1110 : ** Stuff routine that automatically grows the malloc'd output buffer
1111 : ** before it overflows.
1112 : */
1113 587154 : static int GrowStuff(SprintfState *ss, const char *sp, PRUint32 len)
1114 : {
1115 : ptrdiff_t off;
1116 : char *newbase;
1117 : PRUint32 newlen;
1118 :
1119 587154 : off = ss->cur - ss->base;
1120 587154 : if (off + len >= ss->maxlen) {
1121 : /* Grow the buffer */
1122 47210 : newlen = ss->maxlen + ((len > 32) ? len : 32);
1123 47210 : if (ss->base) {
1124 25792 : newbase = (char*) PR_REALLOC(ss->base, newlen);
1125 : } else {
1126 21418 : newbase = (char*) PR_MALLOC(newlen);
1127 : }
1128 47210 : if (!newbase) {
1129 : /* Ran out of memory */
1130 0 : return -1;
1131 : }
1132 47210 : ss->base = newbase;
1133 47210 : ss->maxlen = newlen;
1134 47210 : ss->cur = ss->base + off;
1135 : }
1136 :
1137 : /* Copy data */
1138 3637299 : while (len) {
1139 2462991 : --len;
1140 2462991 : *ss->cur++ = *sp++;
1141 : }
1142 587154 : PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen);
1143 587154 : return 0;
1144 : }
1145 :
1146 : /*
1147 : ** sprintf into a malloc'd buffer
1148 : */
1149 16407 : PR_IMPLEMENT(char *) PR_smprintf(const char *fmt, ...)
1150 : {
1151 : va_list ap;
1152 : char *rv;
1153 :
1154 16407 : va_start(ap, fmt);
1155 16407 : rv = PR_vsmprintf(fmt, ap);
1156 16407 : va_end(ap);
1157 16407 : return rv;
1158 : }
1159 :
1160 : /*
1161 : ** Free memory allocated, for the caller, by PR_smprintf
1162 : */
1163 19714 : PR_IMPLEMENT(void) PR_smprintf_free(char *mem)
1164 : {
1165 19714 : PR_DELETE(mem);
1166 19714 : }
1167 :
1168 21417 : PR_IMPLEMENT(char *) PR_vsmprintf(const char *fmt, va_list ap)
1169 : {
1170 : SprintfState ss;
1171 : int rv;
1172 :
1173 21417 : ss.stuff = GrowStuff;
1174 21417 : ss.base = 0;
1175 21417 : ss.cur = 0;
1176 21417 : ss.maxlen = 0;
1177 21417 : rv = dosprintf(&ss, fmt, ap);
1178 21417 : if (rv < 0) {
1179 0 : if (ss.base) {
1180 0 : PR_DELETE(ss.base);
1181 : }
1182 0 : return 0;
1183 : }
1184 21417 : return ss.base;
1185 : }
1186 :
1187 : /*
1188 : ** Stuff routine that discards overflow data
1189 : */
1190 648503 : static int LimitStuff(SprintfState *ss, const char *sp, PRUint32 len)
1191 : {
1192 648503 : PRUint32 limit = ss->maxlen - (ss->cur - ss->base);
1193 :
1194 648503 : if (len > limit) {
1195 85 : len = limit;
1196 : }
1197 2539556 : while (len) {
1198 1242550 : --len;
1199 1242550 : *ss->cur++ = *sp++;
1200 : }
1201 648503 : return 0;
1202 : }
1203 :
1204 : /*
1205 : ** sprintf into a fixed size buffer. Make sure there is a NUL at the end
1206 : ** when finished.
1207 : */
1208 16931 : PR_IMPLEMENT(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...)
1209 : {
1210 : va_list ap;
1211 : PRUint32 rv;
1212 :
1213 16931 : va_start(ap, fmt);
1214 16931 : rv = PR_vsnprintf(out, outlen, fmt, ap);
1215 16931 : va_end(ap);
1216 16931 : return rv;
1217 : }
1218 :
1219 74913 : PR_IMPLEMENT(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen,const char *fmt,
1220 : va_list ap)
1221 : {
1222 : SprintfState ss;
1223 : PRUint32 n;
1224 :
1225 74913 : PR_ASSERT((PRInt32)outlen > 0);
1226 74913 : if ((PRInt32)outlen <= 0) {
1227 0 : return 0;
1228 : }
1229 :
1230 74913 : ss.stuff = LimitStuff;
1231 74913 : ss.base = out;
1232 74913 : ss.cur = out;
1233 74913 : ss.maxlen = outlen;
1234 74913 : (void) dosprintf(&ss, fmt, ap);
1235 :
1236 : /* If we added chars, and we didn't append a null, do it now. */
1237 74913 : if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') )
1238 1 : *(ss.cur - 1) = '\0';
1239 :
1240 74913 : n = ss.cur - ss.base;
1241 74913 : return n ? n - 1 : n;
1242 : }
1243 :
1244 453 : PR_IMPLEMENT(char *) PR_sprintf_append(char *last, const char *fmt, ...)
1245 : {
1246 : va_list ap;
1247 : char *rv;
1248 :
1249 453 : va_start(ap, fmt);
1250 453 : rv = PR_vsprintf_append(last, fmt, ap);
1251 453 : va_end(ap);
1252 453 : return rv;
1253 : }
1254 :
1255 453 : PR_IMPLEMENT(char *) PR_vsprintf_append(char *last, const char *fmt, va_list ap)
1256 : {
1257 : SprintfState ss;
1258 : int rv;
1259 :
1260 453 : ss.stuff = GrowStuff;
1261 453 : if (last) {
1262 452 : int lastlen = strlen(last);
1263 452 : ss.base = last;
1264 452 : ss.cur = last + lastlen;
1265 452 : ss.maxlen = lastlen;
1266 : } else {
1267 1 : ss.base = 0;
1268 1 : ss.cur = 0;
1269 1 : ss.maxlen = 0;
1270 : }
1271 453 : rv = dosprintf(&ss, fmt, ap);
1272 453 : if (rv < 0) {
1273 0 : if (ss.base) {
1274 0 : PR_DELETE(ss.base);
1275 : }
1276 0 : return 0;
1277 : }
1278 453 : return ss.base;
1279 : }
1280 :
|