comparison nspr/pr/src/io/prprf.c @ 0:1e5118fa0cb1

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