VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/mprintf.c@ 97138

最後變更 在這個檔案從97138是 95312,由 vboxsync 提交於 3 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • 屬性 svn:eol-style 設為 native
檔案大小: 29.8 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1999 - 2022, Daniel Stenberg, <[email protected]>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 *
22 * Purpose:
23 * A merge of Bjorn Reese's format() function and Daniel's dsprintf()
24 * 1.0. A full blooded printf() clone with full support for <num>$
25 * everywhere (parameters, widths and precisions) including variabled
26 * sized parameters (like doubles, long longs, long doubles and even
27 * void * in 64-bit architectures).
28 *
29 * Current restrictions:
30 * - Max 128 parameters
31 * - No 'long double' support.
32 *
33 * If you ever want truly portable and good *printf() clones, the project that
34 * took on from here is named 'Trio' and you find more details on the trio web
35 * page at https://daniel.haxx.se/projects/trio/
36 */
37
38#include "curl_setup.h"
39#include "dynbuf.h"
40#include <curl/mprintf.h>
41
42#include "curl_memory.h"
43/* The last #include file should be: */
44#include "memdebug.h"
45
46/*
47 * If SIZEOF_SIZE_T has not been defined, default to the size of long.
48 */
49
50#ifdef HAVE_LONGLONG
51# define LONG_LONG_TYPE long long
52# define HAVE_LONG_LONG_TYPE
53#else
54# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
55# define LONG_LONG_TYPE __int64
56# define HAVE_LONG_LONG_TYPE
57# else
58# undef LONG_LONG_TYPE
59# undef HAVE_LONG_LONG_TYPE
60# endif
61#endif
62
63/*
64 * Non-ANSI integer extensions
65 */
66
67#if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \
68 (defined(__POCC__) && defined(_MSC_VER)) || \
69 (defined(_WIN32_WCE)) || \
70 (defined(__MINGW32__)) || \
71 (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64))
72# define MP_HAVE_INT_EXTENSIONS
73#endif
74
75/*
76 * Max integer data types that mprintf.c is capable
77 */
78
79#ifdef HAVE_LONG_LONG_TYPE
80# define mp_intmax_t LONG_LONG_TYPE
81# define mp_uintmax_t unsigned LONG_LONG_TYPE
82#else
83# define mp_intmax_t long
84# define mp_uintmax_t unsigned long
85#endif
86
87#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should
88 fit negative DBL_MAX (317 letters) */
89#define MAX_PARAMETERS 128 /* lame static limit */
90
91#ifdef __AMIGA__
92# undef FORMAT_INT
93#endif
94
95/* Lower-case digits. */
96static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
97
98/* Upper-case digits. */
99static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
100
101#define OUTCHAR(x) \
102 do { \
103 if(stream((unsigned char)(x), (FILE *)data) != -1) \
104 done++; \
105 else \
106 return done; /* return immediately on failure */ \
107 } while(0)
108
109/* Data type to read from the arglist */
110typedef enum {
111 FORMAT_UNKNOWN = 0,
112 FORMAT_STRING,
113 FORMAT_PTR,
114 FORMAT_INT,
115 FORMAT_INTPTR,
116 FORMAT_LONG,
117 FORMAT_LONGLONG,
118 FORMAT_DOUBLE,
119 FORMAT_LONGDOUBLE,
120 FORMAT_WIDTH /* For internal use */
121} FormatType;
122
123/* conversion and display flags */
124enum {
125 FLAGS_NEW = 0,
126 FLAGS_SPACE = 1<<0,
127 FLAGS_SHOWSIGN = 1<<1,
128 FLAGS_LEFT = 1<<2,
129 FLAGS_ALT = 1<<3,
130 FLAGS_SHORT = 1<<4,
131 FLAGS_LONG = 1<<5,
132 FLAGS_LONGLONG = 1<<6,
133 FLAGS_LONGDOUBLE = 1<<7,
134 FLAGS_PAD_NIL = 1<<8,
135 FLAGS_UNSIGNED = 1<<9,
136 FLAGS_OCTAL = 1<<10,
137 FLAGS_HEX = 1<<11,
138 FLAGS_UPPER = 1<<12,
139 FLAGS_WIDTH = 1<<13, /* '*' or '*<num>$' used */
140 FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
141 FLAGS_PREC = 1<<15, /* precision was specified */
142 FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */
143 FLAGS_CHAR = 1<<17, /* %c story */
144 FLAGS_FLOATE = 1<<18, /* %e or %E */
145 FLAGS_FLOATG = 1<<19 /* %g or %G */
146};
147
148struct va_stack {
149 FormatType type;
150 int flags;
151 long width; /* width OR width parameter number */
152 long precision; /* precision OR precision parameter number */
153 union {
154 char *str;
155 void *ptr;
156 union {
157 mp_intmax_t as_signed;
158 mp_uintmax_t as_unsigned;
159 } num;
160 double dnum;
161 } data;
162};
163
164struct nsprintf {
165 char *buffer;
166 size_t length;
167 size_t max;
168};
169
170struct asprintf {
171 struct dynbuf *b;
172 bool fail; /* if an alloc has failed and thus the output is not the complete
173 data */
174};
175
176static long dprintf_DollarString(char *input, char **end)
177{
178 int number = 0;
179 while(ISDIGIT(*input)) {
180 if(number < MAX_PARAMETERS) {
181 number *= 10;
182 number += *input - '0';
183 }
184 input++;
185 }
186 if(number <= MAX_PARAMETERS && ('$' == *input)) {
187 *end = ++input;
188 return number;
189 }
190 return 0;
191}
192
193static bool dprintf_IsQualifierNoDollar(const char *fmt)
194{
195#if defined(MP_HAVE_INT_EXTENSIONS)
196 if(!strncmp(fmt, "I32", 3) || !strncmp(fmt, "I64", 3)) {
197 return TRUE;
198 }
199#endif
200
201 switch(*fmt) {
202 case '-': case '+': case ' ': case '#': case '.':
203 case '0': case '1': case '2': case '3': case '4':
204 case '5': case '6': case '7': case '8': case '9':
205 case 'h': case 'l': case 'L': case 'z': case 'q':
206 case '*': case 'O':
207#if defined(MP_HAVE_INT_EXTENSIONS)
208 case 'I':
209#endif
210 return TRUE;
211
212 default:
213 return FALSE;
214 }
215}
216
217/******************************************************************
218 *
219 * Pass 1:
220 * Create an index with the type of each parameter entry and its
221 * value (may vary in size)
222 *
223 * Returns zero on success.
224 *
225 ******************************************************************/
226
227static int dprintf_Pass1(const char *format, struct va_stack *vto,
228 char **endpos, va_list arglist)
229{
230 char *fmt = (char *)format;
231 int param_num = 0;
232 long this_param;
233 long width;
234 long precision;
235 int flags;
236 long max_param = 0;
237 long i;
238
239 while(*fmt) {
240 if(*fmt++ == '%') {
241 if(*fmt == '%') {
242 fmt++;
243 continue; /* while */
244 }
245
246 flags = FLAGS_NEW;
247
248 /* Handle the positional case (N$) */
249
250 param_num++;
251
252 this_param = dprintf_DollarString(fmt, &fmt);
253 if(0 == this_param)
254 /* we got no positional, get the next counter */
255 this_param = param_num;
256
257 if(this_param > max_param)
258 max_param = this_param;
259
260 /*
261 * The parameter with number 'i' should be used. Next, we need
262 * to get SIZE and TYPE of the parameter. Add the information
263 * to our array.
264 */
265
266 width = 0;
267 precision = 0;
268
269 /* Handle the flags */
270
271 while(dprintf_IsQualifierNoDollar(fmt)) {
272#if defined(MP_HAVE_INT_EXTENSIONS)
273 if(!strncmp(fmt, "I32", 3)) {
274 flags |= FLAGS_LONG;
275 fmt += 3;
276 }
277 else if(!strncmp(fmt, "I64", 3)) {
278 flags |= FLAGS_LONGLONG;
279 fmt += 3;
280 }
281 else
282#endif
283
284 switch(*fmt++) {
285 case ' ':
286 flags |= FLAGS_SPACE;
287 break;
288 case '+':
289 flags |= FLAGS_SHOWSIGN;
290 break;
291 case '-':
292 flags |= FLAGS_LEFT;
293 flags &= ~FLAGS_PAD_NIL;
294 break;
295 case '#':
296 flags |= FLAGS_ALT;
297 break;
298 case '.':
299 if('*' == *fmt) {
300 /* The precision is picked from a specified parameter */
301
302 flags |= FLAGS_PRECPARAM;
303 fmt++;
304 param_num++;
305
306 i = dprintf_DollarString(fmt, &fmt);
307 if(i)
308 precision = i;
309 else
310 precision = param_num;
311
312 if(precision > max_param)
313 max_param = precision;
314 }
315 else {
316 flags |= FLAGS_PREC;
317 precision = strtol(fmt, &fmt, 10);
318 }
319 break;
320 case 'h':
321 flags |= FLAGS_SHORT;
322 break;
323#if defined(MP_HAVE_INT_EXTENSIONS)
324 case 'I':
325#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
326 flags |= FLAGS_LONGLONG;
327#else
328 flags |= FLAGS_LONG;
329#endif
330 break;
331#endif
332 case 'l':
333 if(flags & FLAGS_LONG)
334 flags |= FLAGS_LONGLONG;
335 else
336 flags |= FLAGS_LONG;
337 break;
338 case 'L':
339 flags |= FLAGS_LONGDOUBLE;
340 break;
341 case 'q':
342 flags |= FLAGS_LONGLONG;
343 break;
344 case 'z':
345 /* the code below generates a warning if -Wunreachable-code is
346 used */
347#if (SIZEOF_SIZE_T > SIZEOF_LONG)
348 flags |= FLAGS_LONGLONG;
349#else
350 flags |= FLAGS_LONG;
351#endif
352 break;
353 case 'O':
354#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
355 flags |= FLAGS_LONGLONG;
356#else
357 flags |= FLAGS_LONG;
358#endif
359 break;
360 case '0':
361 if(!(flags & FLAGS_LEFT))
362 flags |= FLAGS_PAD_NIL;
363 /* FALLTHROUGH */
364 case '1': case '2': case '3': case '4':
365 case '5': case '6': case '7': case '8': case '9':
366 flags |= FLAGS_WIDTH;
367 width = strtol(fmt-1, &fmt, 10);
368 break;
369 case '*': /* Special case */
370 flags |= FLAGS_WIDTHPARAM;
371 param_num++;
372
373 i = dprintf_DollarString(fmt, &fmt);
374 if(i)
375 width = i;
376 else
377 width = param_num;
378 if(width > max_param)
379 max_param = width;
380 break;
381 case '\0':
382 fmt--;
383 default:
384 break;
385 }
386 } /* switch */
387
388 /* Handle the specifier */
389
390 i = this_param - 1;
391
392 if((i < 0) || (i >= MAX_PARAMETERS))
393 /* out of allowed range */
394 return 1;
395
396 switch (*fmt) {
397 case 'S':
398 flags |= FLAGS_ALT;
399 /* FALLTHROUGH */
400 case 's':
401 vto[i].type = FORMAT_STRING;
402 break;
403 case 'n':
404 vto[i].type = FORMAT_INTPTR;
405 break;
406 case 'p':
407 vto[i].type = FORMAT_PTR;
408 break;
409 case 'd': case 'i':
410 vto[i].type = FORMAT_INT;
411 break;
412 case 'u':
413 vto[i].type = FORMAT_INT;
414 flags |= FLAGS_UNSIGNED;
415 break;
416 case 'o':
417 vto[i].type = FORMAT_INT;
418 flags |= FLAGS_OCTAL;
419 break;
420 case 'x':
421 vto[i].type = FORMAT_INT;
422 flags |= FLAGS_HEX|FLAGS_UNSIGNED;
423 break;
424 case 'X':
425 vto[i].type = FORMAT_INT;
426 flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
427 break;
428 case 'c':
429 vto[i].type = FORMAT_INT;
430 flags |= FLAGS_CHAR;
431 break;
432 case 'f':
433 vto[i].type = FORMAT_DOUBLE;
434 break;
435 case 'e':
436 vto[i].type = FORMAT_DOUBLE;
437 flags |= FLAGS_FLOATE;
438 break;
439 case 'E':
440 vto[i].type = FORMAT_DOUBLE;
441 flags |= FLAGS_FLOATE|FLAGS_UPPER;
442 break;
443 case 'g':
444 vto[i].type = FORMAT_DOUBLE;
445 flags |= FLAGS_FLOATG;
446 break;
447 case 'G':
448 vto[i].type = FORMAT_DOUBLE;
449 flags |= FLAGS_FLOATG|FLAGS_UPPER;
450 break;
451 default:
452 vto[i].type = FORMAT_UNKNOWN;
453 break;
454 } /* switch */
455
456 vto[i].flags = flags;
457 vto[i].width = width;
458 vto[i].precision = precision;
459
460 if(flags & FLAGS_WIDTHPARAM) {
461 /* we have the width specified from a parameter, so we make that
462 parameter's info setup properly */
463 long k = width - 1;
464 if((k < 0) || (k >= MAX_PARAMETERS))
465 /* out of allowed range */
466 return 1;
467 vto[i].width = k;
468 vto[k].type = FORMAT_WIDTH;
469 vto[k].flags = FLAGS_NEW;
470 /* can't use width or precision of width! */
471 vto[k].width = 0;
472 vto[k].precision = 0;
473 }
474 if(flags & FLAGS_PRECPARAM) {
475 /* we have the precision specified from a parameter, so we make that
476 parameter's info setup properly */
477 long k = precision - 1;
478 if((k < 0) || (k >= MAX_PARAMETERS))
479 /* out of allowed range */
480 return 1;
481 vto[i].precision = k;
482 vto[k].type = FORMAT_WIDTH;
483 vto[k].flags = FLAGS_NEW;
484 /* can't use width or precision of width! */
485 vto[k].width = 0;
486 vto[k].precision = 0;
487 }
488 *endpos++ = fmt + ((*fmt == '\0') ? 0 : 1); /* end of this sequence */
489 }
490 }
491
492 /* Read the arg list parameters into our data list */
493 for(i = 0; i<max_param; i++) {
494 /* Width/precision arguments must be read before the main argument
495 they are attached to */
496 if(vto[i].flags & FLAGS_WIDTHPARAM) {
497 vto[vto[i].width].data.num.as_signed =
498 (mp_intmax_t)va_arg(arglist, int);
499 }
500 if(vto[i].flags & FLAGS_PRECPARAM) {
501 vto[vto[i].precision].data.num.as_signed =
502 (mp_intmax_t)va_arg(arglist, int);
503 }
504
505 switch(vto[i].type) {
506 case FORMAT_STRING:
507 vto[i].data.str = va_arg(arglist, char *);
508 break;
509
510 case FORMAT_INTPTR:
511 case FORMAT_UNKNOWN:
512 case FORMAT_PTR:
513 vto[i].data.ptr = va_arg(arglist, void *);
514 break;
515
516 case FORMAT_INT:
517#ifdef HAVE_LONG_LONG_TYPE
518 if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED))
519 vto[i].data.num.as_unsigned =
520 (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
521 else if(vto[i].flags & FLAGS_LONGLONG)
522 vto[i].data.num.as_signed =
523 (mp_intmax_t)va_arg(arglist, mp_intmax_t);
524 else
525#endif
526 {
527 if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED))
528 vto[i].data.num.as_unsigned =
529 (mp_uintmax_t)va_arg(arglist, unsigned long);
530 else if(vto[i].flags & FLAGS_LONG)
531 vto[i].data.num.as_signed =
532 (mp_intmax_t)va_arg(arglist, long);
533 else if(vto[i].flags & FLAGS_UNSIGNED)
534 vto[i].data.num.as_unsigned =
535 (mp_uintmax_t)va_arg(arglist, unsigned int);
536 else
537 vto[i].data.num.as_signed =
538 (mp_intmax_t)va_arg(arglist, int);
539 }
540 break;
541
542 case FORMAT_DOUBLE:
543 vto[i].data.dnum = va_arg(arglist, double);
544 break;
545
546 case FORMAT_WIDTH:
547 /* Argument has been read. Silently convert it into an integer
548 * for later use
549 */
550 vto[i].type = FORMAT_INT;
551 break;
552
553 default:
554 break;
555 }
556 }
557
558 return 0;
559
560}
561
562static int dprintf_formatf(
563 void *data, /* untouched by format(), just sent to the stream() function in
564 the second argument */
565 /* function pointer called for each output character */
566 int (*stream)(int, FILE *),
567 const char *format, /* %-formatted string */
568 va_list ap_save) /* list of parameters */
569{
570 /* Base-36 digits for numbers. */
571 const char *digits = lower_digits;
572
573 /* Pointer into the format string. */
574 char *f;
575
576 /* Number of characters written. */
577 int done = 0;
578
579 long param; /* current parameter to read */
580 long param_num = 0; /* parameter counter */
581
582 struct va_stack vto[MAX_PARAMETERS];
583 char *endpos[MAX_PARAMETERS];
584 char **end;
585 char work[BUFFSIZE];
586 struct va_stack *p;
587
588 /* 'workend' points to the final buffer byte position, but with an extra
589 byte as margin to avoid the (false?) warning Coverity gives us
590 otherwise */
591 char *workend = &work[sizeof(work) - 2];
592
593 /* Do the actual %-code parsing */
594 if(dprintf_Pass1(format, vto, endpos, ap_save))
595 return -1;
596
597 end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
598 created for us */
599
600 f = (char *)format;
601 while(*f != '\0') {
602 /* Format spec modifiers. */
603 int is_alt;
604
605 /* Width of a field. */
606 long width;
607
608 /* Precision of a field. */
609 long prec;
610
611 /* Decimal integer is negative. */
612 int is_neg;
613
614 /* Base of a number to be written. */
615 unsigned long base;
616
617 /* Integral values to be written. */
618 mp_uintmax_t num;
619
620 /* Used to convert negative in positive. */
621 mp_intmax_t signed_num;
622
623 char *w;
624
625 if(*f != '%') {
626 /* This isn't a format spec, so write everything out until the next one
627 OR end of string is reached. */
628 do {
629 OUTCHAR(*f);
630 } while(*++f && ('%' != *f));
631 continue;
632 }
633
634 ++f;
635
636 /* Check for "%%". Note that although the ANSI standard lists
637 '%' as a conversion specifier, it says "The complete format
638 specification shall be `%%'," so we can avoid all the width
639 and precision processing. */
640 if(*f == '%') {
641 ++f;
642 OUTCHAR('%');
643 continue;
644 }
645
646 /* If this is a positional parameter, the position must follow immediately
647 after the %, thus create a %<num>$ sequence */
648 param = dprintf_DollarString(f, &f);
649
650 if(!param)
651 param = param_num;
652 else
653 --param;
654
655 param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
656 third %s will pick the 3rd argument */
657
658 p = &vto[param];
659
660 /* pick up the specified width */
661 if(p->flags & FLAGS_WIDTHPARAM) {
662 width = (long)vto[p->width].data.num.as_signed;
663 param_num++; /* since the width is extracted from a parameter, we
664 must skip that to get to the next one properly */
665 if(width < 0) {
666 /* "A negative field width is taken as a '-' flag followed by a
667 positive field width." */
668 width = -width;
669 p->flags |= FLAGS_LEFT;
670 p->flags &= ~FLAGS_PAD_NIL;
671 }
672 }
673 else
674 width = p->width;
675
676 /* pick up the specified precision */
677 if(p->flags & FLAGS_PRECPARAM) {
678 prec = (long)vto[p->precision].data.num.as_signed;
679 param_num++; /* since the precision is extracted from a parameter, we
680 must skip that to get to the next one properly */
681 if(prec < 0)
682 /* "A negative precision is taken as if the precision were
683 omitted." */
684 prec = -1;
685 }
686 else if(p->flags & FLAGS_PREC)
687 prec = p->precision;
688 else
689 prec = -1;
690
691 is_alt = (p->flags & FLAGS_ALT) ? 1 : 0;
692
693 switch(p->type) {
694 case FORMAT_INT:
695 num = p->data.num.as_unsigned;
696 if(p->flags & FLAGS_CHAR) {
697 /* Character. */
698 if(!(p->flags & FLAGS_LEFT))
699 while(--width > 0)
700 OUTCHAR(' ');
701 OUTCHAR((char) num);
702 if(p->flags & FLAGS_LEFT)
703 while(--width > 0)
704 OUTCHAR(' ');
705 break;
706 }
707 if(p->flags & FLAGS_OCTAL) {
708 /* Octal unsigned integer. */
709 base = 8;
710 goto unsigned_number;
711 }
712 else if(p->flags & FLAGS_HEX) {
713 /* Hexadecimal unsigned integer. */
714
715 digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
716 base = 16;
717 goto unsigned_number;
718 }
719 else if(p->flags & FLAGS_UNSIGNED) {
720 /* Decimal unsigned integer. */
721 base = 10;
722 goto unsigned_number;
723 }
724
725 /* Decimal integer. */
726 base = 10;
727
728 is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0;
729 if(is_neg) {
730 /* signed_num might fail to hold absolute negative minimum by 1 */
731 signed_num = p->data.num.as_signed + (mp_intmax_t)1;
732 signed_num = -signed_num;
733 num = (mp_uintmax_t)signed_num;
734 num += (mp_uintmax_t)1;
735 }
736
737 goto number;
738
739 unsigned_number:
740 /* Unsigned number of base BASE. */
741 is_neg = 0;
742
743 number:
744 /* Number of base BASE. */
745
746 /* Supply a default precision if none was given. */
747 if(prec == -1)
748 prec = 1;
749
750 /* Put the number in WORK. */
751 w = workend;
752 while(num > 0) {
753 *w-- = digits[num % base];
754 num /= base;
755 }
756 width -= (long)(workend - w);
757 prec -= (long)(workend - w);
758
759 if(is_alt && base == 8 && prec <= 0) {
760 *w-- = '0';
761 --width;
762 }
763
764 if(prec > 0) {
765 width -= prec;
766 while(prec-- > 0 && w >= work)
767 *w-- = '0';
768 }
769
770 if(is_alt && base == 16)
771 width -= 2;
772
773 if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
774 --width;
775
776 if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
777 while(width-- > 0)
778 OUTCHAR(' ');
779
780 if(is_neg)
781 OUTCHAR('-');
782 else if(p->flags & FLAGS_SHOWSIGN)
783 OUTCHAR('+');
784 else if(p->flags & FLAGS_SPACE)
785 OUTCHAR(' ');
786
787 if(is_alt && base == 16) {
788 OUTCHAR('0');
789 if(p->flags & FLAGS_UPPER)
790 OUTCHAR('X');
791 else
792 OUTCHAR('x');
793 }
794
795 if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
796 while(width-- > 0)
797 OUTCHAR('0');
798
799 /* Write the number. */
800 while(++w <= workend) {
801 OUTCHAR(*w);
802 }
803
804 if(p->flags & FLAGS_LEFT)
805 while(width-- > 0)
806 OUTCHAR(' ');
807 break;
808
809 case FORMAT_STRING:
810 /* String. */
811 {
812 static const char null[] = "(nil)";
813 const char *str;
814 size_t len;
815
816 str = (char *) p->data.str;
817 if(!str) {
818 /* Write null[] if there's space. */
819 if(prec == -1 || prec >= (long) sizeof(null) - 1) {
820 str = null;
821 len = sizeof(null) - 1;
822 /* Disable quotes around (nil) */
823 p->flags &= (~FLAGS_ALT);
824 }
825 else {
826 str = "";
827 len = 0;
828 }
829 }
830 else if(prec != -1)
831 len = (size_t)prec;
832 else if(*str == '\0')
833 len = 0;
834 else
835 len = strlen(str);
836
837 width -= (len > LONG_MAX) ? LONG_MAX : (long)len;
838
839 if(p->flags & FLAGS_ALT)
840 OUTCHAR('"');
841
842 if(!(p->flags&FLAGS_LEFT))
843 while(width-- > 0)
844 OUTCHAR(' ');
845
846 for(; len && *str; len--)
847 OUTCHAR(*str++);
848 if(p->flags&FLAGS_LEFT)
849 while(width-- > 0)
850 OUTCHAR(' ');
851
852 if(p->flags & FLAGS_ALT)
853 OUTCHAR('"');
854 }
855 break;
856
857 case FORMAT_PTR:
858 /* Generic pointer. */
859 {
860 void *ptr;
861 ptr = (void *) p->data.ptr;
862 if(ptr) {
863 /* If the pointer is not NULL, write it as a %#x spec. */
864 base = 16;
865 digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
866 is_alt = 1;
867 num = (size_t) ptr;
868 is_neg = 0;
869 goto number;
870 }
871 else {
872 /* Write "(nil)" for a nil pointer. */
873 static const char strnil[] = "(nil)";
874 const char *point;
875
876 width -= (long)(sizeof(strnil) - 1);
877 if(p->flags & FLAGS_LEFT)
878 while(width-- > 0)
879 OUTCHAR(' ');
880 for(point = strnil; *point != '\0'; ++point)
881 OUTCHAR(*point);
882 if(!(p->flags & FLAGS_LEFT))
883 while(width-- > 0)
884 OUTCHAR(' ');
885 }
886 }
887 break;
888
889 case FORMAT_DOUBLE:
890 {
891 char formatbuf[32]="%";
892 char *fptr = &formatbuf[1];
893 size_t left = sizeof(formatbuf)-strlen(formatbuf);
894 int len;
895
896 width = -1;
897 if(p->flags & FLAGS_WIDTH)
898 width = p->width;
899 else if(p->flags & FLAGS_WIDTHPARAM)
900 width = (long)vto[p->width].data.num.as_signed;
901
902 prec = -1;
903 if(p->flags & FLAGS_PREC)
904 prec = p->precision;
905 else if(p->flags & FLAGS_PRECPARAM)
906 prec = (long)vto[p->precision].data.num.as_signed;
907
908 if(p->flags & FLAGS_LEFT)
909 *fptr++ = '-';
910 if(p->flags & FLAGS_SHOWSIGN)
911 *fptr++ = '+';
912 if(p->flags & FLAGS_SPACE)
913 *fptr++ = ' ';
914 if(p->flags & FLAGS_ALT)
915 *fptr++ = '#';
916
917 *fptr = 0;
918
919 if(width >= 0) {
920 if(width >= (long)sizeof(work))
921 width = sizeof(work)-1;
922 /* RECURSIVE USAGE */
923 len = curl_msnprintf(fptr, left, "%ld", width);
924 fptr += len;
925 left -= len;
926 }
927 if(prec >= 0) {
928 /* for each digit in the integer part, we can have one less
929 precision */
930 size_t maxprec = sizeof(work) - 2;
931 double val = p->data.dnum;
932 if(width > 0 && prec <= width)
933 maxprec -= width;
934 while(val >= 10.0) {
935 val /= 10;
936 maxprec--;
937 }
938
939 if(prec > (long)maxprec)
940 prec = (long)maxprec-1;
941 if(prec < 0)
942 prec = 0;
943 /* RECURSIVE USAGE */
944 len = curl_msnprintf(fptr, left, ".%ld", prec);
945 fptr += len;
946 }
947 if(p->flags & FLAGS_LONG)
948 *fptr++ = 'l';
949
950 if(p->flags & FLAGS_FLOATE)
951 *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e');
952 else if(p->flags & FLAGS_FLOATG)
953 *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g');
954 else
955 *fptr++ = 'f';
956
957 *fptr = 0; /* and a final zero termination */
958
959 /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
960 output characters */
961 (sprintf)(work, formatbuf, p->data.dnum);
962 DEBUGASSERT(strlen(work) <= sizeof(work));
963 for(fptr = work; *fptr; fptr++)
964 OUTCHAR(*fptr);
965 }
966 break;
967
968 case FORMAT_INTPTR:
969 /* Answer the count of characters written. */
970#ifdef HAVE_LONG_LONG_TYPE
971 if(p->flags & FLAGS_LONGLONG)
972 *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done;
973 else
974#endif
975 if(p->flags & FLAGS_LONG)
976 *(long *) p->data.ptr = (long)done;
977 else if(!(p->flags & FLAGS_SHORT))
978 *(int *) p->data.ptr = (int)done;
979 else
980 *(short *) p->data.ptr = (short)done;
981 break;
982
983 default:
984 break;
985 }
986 f = *end++; /* goto end of %-code */
987
988 }
989 return done;
990}
991
992/* fputc() look-alike */
993static int addbyter(int output, FILE *data)
994{
995 struct nsprintf *infop = (struct nsprintf *)data;
996 unsigned char outc = (unsigned char)output;
997
998 if(infop->length < infop->max) {
999 /* only do this if we haven't reached max length yet */
1000 infop->buffer[0] = outc; /* store */
1001 infop->buffer++; /* increase pointer */
1002 infop->length++; /* we are now one byte larger */
1003 return outc; /* fputc() returns like this on success */
1004 }
1005 return -1;
1006}
1007
1008int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
1009 va_list ap_save)
1010{
1011 int retcode;
1012 struct nsprintf info;
1013
1014 info.buffer = buffer;
1015 info.length = 0;
1016 info.max = maxlength;
1017
1018 retcode = dprintf_formatf(&info, addbyter, format, ap_save);
1019 if((retcode != -1) && info.max) {
1020 /* we terminate this with a zero byte */
1021 if(info.max == info.length) {
1022 /* we're at maximum, scrap the last letter */
1023 info.buffer[-1] = 0;
1024 retcode--; /* don't count the nul byte */
1025 }
1026 else
1027 info.buffer[0] = 0;
1028 }
1029 return retcode;
1030}
1031
1032int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1033{
1034 int retcode;
1035 va_list ap_save; /* argument pointer */
1036 va_start(ap_save, format);
1037 retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1038 va_end(ap_save);
1039 return retcode;
1040}
1041
1042/* fputc() look-alike */
1043static int alloc_addbyter(int output, FILE *data)
1044{
1045 struct asprintf *infop = (struct asprintf *)data;
1046 unsigned char outc = (unsigned char)output;
1047
1048 if(Curl_dyn_addn(infop->b, &outc, 1)) {
1049 infop->fail = 1;
1050 return -1; /* fail */
1051 }
1052 return outc; /* fputc() returns like this on success */
1053}
1054
1055extern int Curl_dyn_vprintf(struct dynbuf *dyn,
1056 const char *format, va_list ap_save);
1057
1058/* appends the formatted string, returns 0 on success, 1 on error */
1059int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
1060{
1061 int retcode;
1062 struct asprintf info;
1063 info.b = dyn;
1064 info.fail = 0;
1065
1066 retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1067 if((-1 == retcode) || info.fail) {
1068 Curl_dyn_free(info.b);
1069 return 1;
1070 }
1071 return 0;
1072}
1073
1074char *curl_mvaprintf(const char *format, va_list ap_save)
1075{
1076 int retcode;
1077 struct asprintf info;
1078 struct dynbuf dyn;
1079 info.b = &dyn;
1080 Curl_dyn_init(info.b, DYN_APRINTF);
1081 info.fail = 0;
1082
1083 retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1084 if((-1 == retcode) || info.fail) {
1085 Curl_dyn_free(info.b);
1086 return NULL;
1087 }
1088 if(Curl_dyn_len(info.b))
1089 return Curl_dyn_ptr(info.b);
1090 return strdup("");
1091}
1092
1093char *curl_maprintf(const char *format, ...)
1094{
1095 va_list ap_save;
1096 char *s;
1097 va_start(ap_save, format);
1098 s = curl_mvaprintf(format, ap_save);
1099 va_end(ap_save);
1100 return s;
1101}
1102
1103static int storebuffer(int output, FILE *data)
1104{
1105 char **buffer = (char **)data;
1106 unsigned char outc = (unsigned char)output;
1107 **buffer = outc;
1108 (*buffer)++;
1109 return outc; /* act like fputc() ! */
1110}
1111
1112int curl_msprintf(char *buffer, const char *format, ...)
1113{
1114 va_list ap_save; /* argument pointer */
1115 int retcode;
1116 va_start(ap_save, format);
1117 retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1118 va_end(ap_save);
1119 *buffer = 0; /* we terminate this with a zero byte */
1120 return retcode;
1121}
1122
1123int curl_mprintf(const char *format, ...)
1124{
1125 int retcode;
1126 va_list ap_save; /* argument pointer */
1127 va_start(ap_save, format);
1128
1129 retcode = dprintf_formatf(stdout, fputc, format, ap_save);
1130 va_end(ap_save);
1131 return retcode;
1132}
1133
1134int curl_mfprintf(FILE *whereto, const char *format, ...)
1135{
1136 int retcode;
1137 va_list ap_save; /* argument pointer */
1138 va_start(ap_save, format);
1139 retcode = dprintf_formatf(whereto, fputc, format, ap_save);
1140 va_end(ap_save);
1141 return retcode;
1142}
1143
1144int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
1145{
1146 int retcode;
1147 retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1148 *buffer = 0; /* we terminate this with a zero byte */
1149 return retcode;
1150}
1151
1152int curl_mvprintf(const char *format, va_list ap_save)
1153{
1154 return dprintf_formatf(stdout, fputc, format, ap_save);
1155}
1156
1157int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1158{
1159 return dprintf_formatf(whereto, fputc, format, ap_save);
1160}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette