Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(557)

Side by Side Diff: nspr/pr/src/io/prprf.c

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

Powered by Google App Engine
This is Rietveld 408576698