Mercurial > trustbridge > nss-cmake-static
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(", &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 |