source: asp3_tinet_ecnl_rx/trunk/curl-7.57.0/lib/mprintf.c@ 364

Last change on this file since 364 was 364, checked in by coas-nagasima, 5 years ago

TINETとSocket APIなどを更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 32.9 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1999 - 2017, Daniel Stenberg, <daniel@haxx.se>, 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.haxx.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 <curl/mprintf.h>
40
41#include "curl_memory.h"
42/* The last #include file should be: */
43#include "memdebug.h"
44
45/*
46 * If SIZEOF_SIZE_T has not been defined, default to the size of long.
47 */
48
49#ifdef HAVE_LONGLONG
50# define LONG_LONG_TYPE long long
51# define HAVE_LONG_LONG_TYPE
52#else
53# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
54# define LONG_LONG_TYPE __int64
55# define HAVE_LONG_LONG_TYPE
56# else
57# undef LONG_LONG_TYPE
58# undef HAVE_LONG_LONG_TYPE
59# endif
60#endif
61
62/*
63 * Non-ANSI integer extensions
64 */
65
66#if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \
67 (defined(__WATCOMC__) && defined(__386__)) || \
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_FALSE
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
148typedef struct {
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} va_stack_t;
163
164struct nsprintf {
165 char *buffer;
166 size_t length;
167 size_t max;
168};
169
170struct asprintf {
171 char *buffer; /* allocated buffer */
172 size_t len; /* length of string */
173 size_t alloc; /* length of alloc */
174 int fail; /* (!= 0) if an alloc has failed and thus
175 the output is not the complete data */
176};
177
178static long dprintf_DollarString(char *input, char **end)
179{
180 int number = 0;
181 while(ISDIGIT(*input)) {
182 number *= 10;
183 number += *input-'0';
184 input++;
185 }
186 if(number && ('$'==*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#if 0
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, va_stack_t *vto, char **endpos,
228 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 default:
382 break;
383 }
384 } /* switch */
385
386 /* Handle the specifier */
387
388 i = this_param - 1;
389
390 if((i < 0) || (i >= MAX_PARAMETERS))
391 /* out of allowed range */
392 return 1;
393
394 switch (*fmt) {
395 case 'S':
396 flags |= FLAGS_ALT;
397 /* FALLTHROUGH */
398 case 's':
399 vto[i].type = FORMAT_STRING;
400 break;
401 case 'n':
402 vto[i].type = FORMAT_INTPTR;
403 break;
404 case 'p':
405 vto[i].type = FORMAT_PTR;
406 break;
407 case 'd': case 'i':
408 vto[i].type = FORMAT_INT;
409 break;
410 case 'u':
411 vto[i].type = FORMAT_INT;
412 flags |= FLAGS_UNSIGNED;
413 break;
414 case 'o':
415 vto[i].type = FORMAT_INT;
416 flags |= FLAGS_OCTAL;
417 break;
418 case 'x':
419 vto[i].type = FORMAT_INT;
420 flags |= FLAGS_HEX|FLAGS_UNSIGNED;
421 break;
422 case 'X':
423 vto[i].type = FORMAT_INT;
424 flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
425 break;
426 case 'c':
427 vto[i].type = FORMAT_INT;
428 flags |= FLAGS_CHAR;
429 break;
430 case 'f':
431 vto[i].type = FORMAT_DOUBLE;
432 break;
433 case 'e':
434 vto[i].type = FORMAT_DOUBLE;
435 flags |= FLAGS_FLOATE;
436 break;
437 case 'E':
438 vto[i].type = FORMAT_DOUBLE;
439 flags |= FLAGS_FLOATE|FLAGS_UPPER;
440 break;
441 case 'g':
442 vto[i].type = FORMAT_DOUBLE;
443 flags |= FLAGS_FLOATG;
444 break;
445 case 'G':
446 vto[i].type = FORMAT_DOUBLE;
447 flags |= FLAGS_FLOATG|FLAGS_UPPER;
448 break;
449 default:
450 vto[i].type = FORMAT_UNKNOWN;
451 break;
452 } /* switch */
453
454 vto[i].flags = flags;
455 vto[i].width = width;
456 vto[i].precision = precision;
457
458 if(flags & FLAGS_WIDTHPARAM) {
459 /* we have the width specified from a parameter, so we make that
460 parameter's info setup properly */
461 long k = width - 1;
462 vto[i].width = k;
463 vto[k].type = FORMAT_WIDTH;
464 vto[k].flags = FLAGS_NEW;
465 /* can't use width or precision of width! */
466 vto[k].width = 0;
467 vto[k].precision = 0;
468 }
469 if(flags & FLAGS_PRECPARAM) {
470 /* we have the precision specified from a parameter, so we make that
471 parameter's info setup properly */
472 long k = precision - 1;
473 vto[i].precision = k;
474 vto[k].type = FORMAT_WIDTH;
475 vto[k].flags = FLAGS_NEW;
476 /* can't use width or precision of width! */
477 vto[k].width = 0;
478 vto[k].precision = 0;
479 }
480 *endpos++ = fmt + 1; /* end of this sequence */
481 }
482 }
483
484 /* Read the arg list parameters into our data list */
485 for(i = 0; i<max_param; i++) {
486 /* Width/precision arguments must be read before the main argument
487 they are attached to */
488 if(vto[i].flags & FLAGS_WIDTHPARAM) {
489 vto[vto[i].width].data.num.as_signed =
490 (mp_intmax_t)va_arg(arglist, int);
491 }
492 if(vto[i].flags & FLAGS_PRECPARAM) {
493 vto[vto[i].precision].data.num.as_signed =
494 (mp_intmax_t)va_arg(arglist, int);
495 }
496
497 switch(vto[i].type) {
498 case FORMAT_STRING:
499 vto[i].data.str = va_arg(arglist, char *);
500 break;
501
502 case FORMAT_INTPTR:
503 case FORMAT_UNKNOWN:
504 case FORMAT_PTR:
505 vto[i].data.ptr = va_arg(arglist, void *);
506 break;
507
508 case FORMAT_INT:
509#ifdef HAVE_LONG_LONG_TYPE
510 if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED))
511 vto[i].data.num.as_unsigned =
512 (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
513 else if(vto[i].flags & FLAGS_LONGLONG)
514 vto[i].data.num.as_signed =
515 (mp_intmax_t)va_arg(arglist, mp_intmax_t);
516 else
517#endif
518 {
519 if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED))
520 vto[i].data.num.as_unsigned =
521 (mp_uintmax_t)va_arg(arglist, unsigned long);
522 else if(vto[i].flags & FLAGS_LONG)
523 vto[i].data.num.as_signed =
524 (mp_intmax_t)va_arg(arglist, long);
525 else if(vto[i].flags & FLAGS_UNSIGNED)
526 vto[i].data.num.as_unsigned =
527 (mp_uintmax_t)va_arg(arglist, unsigned int);
528 else
529 vto[i].data.num.as_signed =
530 (mp_intmax_t)va_arg(arglist, int);
531 }
532 break;
533
534 case FORMAT_DOUBLE:
535 vto[i].data.dnum = va_arg(arglist, double);
536 break;
537
538 case FORMAT_WIDTH:
539 /* Argument has been read. Silently convert it into an integer
540 * for later use
541 */
542 vto[i].type = FORMAT_INT;
543 break;
544
545 default:
546 break;
547 }
548 }
549
550 return 0;
551
552}
553
554static int dprintf_formatf(
555 void *data, /* untouched by format(), just sent to the stream() function in
556 the second argument */
557 /* function pointer called for each output character */
558 int (*stream)(int, FILE *),
559 const char *format, /* %-formatted string */
560 va_list ap_save) /* list of parameters */
561{
562 /* Base-36 digits for numbers. */
563 const char *digits = lower_digits;
564
565 /* Pointer into the format string. */
566 char *f;
567
568 /* Number of characters written. */
569 int done = 0;
570
571 long param; /* current parameter to read */
572 long param_num = 0; /* parameter counter */
573
574 va_stack_t vto[MAX_PARAMETERS];
575 char *endpos[MAX_PARAMETERS];
576 char **end;
577
578 char work[BUFFSIZE];
579
580 va_stack_t *p;
581
582 /* 'workend' points to the final buffer byte position, but with an extra
583 byte as margin to avoid the (false?) warning Coverity gives us
584 otherwise */
585 char *workend = &work[sizeof(work) - 2];
586
587 /* Do the actual %-code parsing */
588 if(dprintf_Pass1(format, vto, endpos, ap_save))
589 return -1;
590
591 end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
592 created for us */
593
594 f = (char *)format;
595 while(*f != '\0') {
596 /* Format spec modifiers. */
597 int is_alt;
598
599 /* Width of a field. */
600 long width;
601
602 /* Precision of a field. */
603 long prec;
604
605 /* Decimal integer is negative. */
606 int is_neg;
607
608 /* Base of a number to be written. */
609 unsigned long base;
610
611 /* Integral values to be written. */
612 mp_uintmax_t num;
613
614 /* Used to convert negative in positive. */
615 mp_intmax_t signed_num;
616
617 char *w;
618
619 if(*f != '%') {
620 /* This isn't a format spec, so write everything out until the next one
621 OR end of string is reached. */
622 do {
623 OUTCHAR(*f);
624 } while(*++f && ('%' != *f));
625 continue;
626 }
627
628 ++f;
629
630 /* Check for "%%". Note that although the ANSI standard lists
631 '%' as a conversion specifier, it says "The complete format
632 specification shall be `%%'," so we can avoid all the width
633 and precision processing. */
634 if(*f == '%') {
635 ++f;
636 OUTCHAR('%');
637 continue;
638 }
639
640 /* If this is a positional parameter, the position must follow immediately
641 after the %, thus create a %<num>$ sequence */
642 param = dprintf_DollarString(f, &f);
643
644 if(!param)
645 param = param_num;
646 else
647 --param;
648
649 param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
650 third %s will pick the 3rd argument */
651
652 p = &vto[param];
653
654 /* pick up the specified width */
655 if(p->flags & FLAGS_WIDTHPARAM) {
656 width = (long)vto[p->width].data.num.as_signed;
657 param_num++; /* since the width is extracted from a parameter, we
658 must skip that to get to the next one properly */
659 if(width < 0) {
660 /* "A negative field width is taken as a '-' flag followed by a
661 positive field width." */
662 width = -width;
663 p->flags |= FLAGS_LEFT;
664 p->flags &= ~FLAGS_PAD_NIL;
665 }
666 }
667 else
668 width = p->width;
669
670 /* pick up the specified precision */
671 if(p->flags & FLAGS_PRECPARAM) {
672 prec = (long)vto[p->precision].data.num.as_signed;
673 param_num++; /* since the precision is extracted from a parameter, we
674 must skip that to get to the next one properly */
675 if(prec < 0)
676 /* "A negative precision is taken as if the precision were
677 omitted." */
678 prec = -1;
679 }
680 else if(p->flags & FLAGS_PREC)
681 prec = p->precision;
682 else
683 prec = -1;
684
685 is_alt = (p->flags & FLAGS_ALT) ? 1 : 0;
686
687 switch(p->type) {
688 case FORMAT_INT:
689 num = p->data.num.as_unsigned;
690 if(p->flags & FLAGS_CHAR) {
691 /* Character. */
692 if(!(p->flags & FLAGS_LEFT))
693 while(--width > 0)
694 OUTCHAR(' ');
695 OUTCHAR((char) num);
696 if(p->flags & FLAGS_LEFT)
697 while(--width > 0)
698 OUTCHAR(' ');
699 break;
700 }
701 if(p->flags & FLAGS_OCTAL) {
702 /* Octal unsigned integer. */
703 base = 8;
704 goto unsigned_number;
705 }
706 else if(p->flags & FLAGS_HEX) {
707 /* Hexadecimal unsigned integer. */
708
709 digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
710 base = 16;
711 goto unsigned_number;
712 }
713 else if(p->flags & FLAGS_UNSIGNED) {
714 /* Decimal unsigned integer. */
715 base = 10;
716 goto unsigned_number;
717 }
718
719 /* Decimal integer. */
720 base = 10;
721
722 is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0;
723 if(is_neg) {
724 /* signed_num might fail to hold absolute negative minimum by 1 */
725 signed_num = p->data.num.as_signed + (mp_intmax_t)1;
726 signed_num = -signed_num;
727 num = (mp_uintmax_t)signed_num;
728 num += (mp_uintmax_t)1;
729 }
730
731 goto number;
732
733 unsigned_number:
734 /* Unsigned number of base BASE. */
735 is_neg = 0;
736
737 number:
738 /* Number of base BASE. */
739
740 /* Supply a default precision if none was given. */
741 if(prec == -1)
742 prec = 1;
743
744 /* Put the number in WORK. */
745 w = workend;
746 while(num > 0) {
747 *w-- = digits[num % base];
748 num /= base;
749 }
750 width -= (long)(workend - w);
751 prec -= (long)(workend - w);
752
753 if(is_alt && base == 8 && prec <= 0) {
754 *w-- = '0';
755 --width;
756 }
757
758 if(prec > 0) {
759 width -= prec;
760 while(prec-- > 0)
761 *w-- = '0';
762 }
763
764 if(is_alt && base == 16)
765 width -= 2;
766
767 if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
768 --width;
769
770 if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
771 while(width-- > 0)
772 OUTCHAR(' ');
773
774 if(is_neg)
775 OUTCHAR('-');
776 else if(p->flags & FLAGS_SHOWSIGN)
777 OUTCHAR('+');
778 else if(p->flags & FLAGS_SPACE)
779 OUTCHAR(' ');
780
781 if(is_alt && base == 16) {
782 OUTCHAR('0');
783 if(p->flags & FLAGS_UPPER)
784 OUTCHAR('X');
785 else
786 OUTCHAR('x');
787 }
788
789 if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
790 while(width-- > 0)
791 OUTCHAR('0');
792
793 /* Write the number. */
794 while(++w <= workend) {
795 OUTCHAR(*w);
796 }
797
798 if(p->flags & FLAGS_LEFT)
799 while(width-- > 0)
800 OUTCHAR(' ');
801 break;
802
803 case FORMAT_STRING:
804 /* String. */
805 {
806 static const char null[] = "(nil)";
807 const char *str;
808 size_t len;
809
810 str = (char *) p->data.str;
811 if(str == NULL) {
812 /* Write null[] if there's space. */
813 if(prec == -1 || prec >= (long) sizeof(null) - 1) {
814 str = null;
815 len = sizeof(null) - 1;
816 /* Disable quotes around (nil) */
817 p->flags &= (~FLAGS_ALT);
818 }
819 else {
820 str = "";
821 len = 0;
822 }
823 }
824 else if(prec != -1)
825 len = (size_t)prec;
826 else
827 len = strlen(str);
828
829 width -= (len > LONG_MAX) ? LONG_MAX : (long)len;
830
831 if(p->flags & FLAGS_ALT)
832 OUTCHAR('"');
833
834 if(!(p->flags&FLAGS_LEFT))
835 while(width-- > 0)
836 OUTCHAR(' ');
837
838 while((len-- > 0) && *str)
839 OUTCHAR(*str++);
840 if(p->flags&FLAGS_LEFT)
841 while(width-- > 0)
842 OUTCHAR(' ');
843
844 if(p->flags & FLAGS_ALT)
845 OUTCHAR('"');
846 }
847 break;
848
849 case FORMAT_PTR:
850 /* Generic pointer. */
851 {
852 void *ptr;
853 ptr = (void *) p->data.ptr;
854 if(ptr != NULL) {
855 /* If the pointer is not NULL, write it as a %#x spec. */
856 base = 16;
857 digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
858 is_alt = 1;
859 num = (size_t) ptr;
860 is_neg = 0;
861 goto number;
862 }
863 else {
864 /* Write "(nil)" for a nil pointer. */
865 static const char strnil[] = "(nil)";
866 const char *point;
867
868 width -= (long)(sizeof(strnil) - 1);
869 if(p->flags & FLAGS_LEFT)
870 while(width-- > 0)
871 OUTCHAR(' ');
872 for(point = strnil; *point != '\0'; ++point)
873 OUTCHAR(*point);
874 if(! (p->flags & FLAGS_LEFT))
875 while(width-- > 0)
876 OUTCHAR(' ');
877 }
878 }
879 break;
880
881 case FORMAT_DOUBLE:
882 {
883 char formatbuf[32]="%";
884 char *fptr = &formatbuf[1];
885 size_t left = sizeof(formatbuf)-strlen(formatbuf);
886 int len;
887
888 width = -1;
889 if(p->flags & FLAGS_WIDTH)
890 width = p->width;
891 else if(p->flags & FLAGS_WIDTHPARAM)
892 width = (long)vto[p->width].data.num.as_signed;
893
894 prec = -1;
895 if(p->flags & FLAGS_PREC)
896 prec = p->precision;
897 else if(p->flags & FLAGS_PRECPARAM)
898 prec = (long)vto[p->precision].data.num.as_signed;
899
900 if(p->flags & FLAGS_LEFT)
901 *fptr++ = '-';
902 if(p->flags & FLAGS_SHOWSIGN)
903 *fptr++ = '+';
904 if(p->flags & FLAGS_SPACE)
905 *fptr++ = ' ';
906 if(p->flags & FLAGS_ALT)
907 *fptr++ = '#';
908
909 *fptr = 0;
910
911 if(width >= 0) {
912 if(width >= (long)sizeof(work))
913 width = sizeof(work)-1;
914 /* RECURSIVE USAGE */
915 len = curl_msnprintf(fptr, left, "%ld", width);
916 fptr += len;
917 left -= len;
918 }
919 if(prec >= 0) {
920 /* for each digit in the integer part, we can have one less
921 precision */
922 size_t maxprec = sizeof(work) - 2;
923 double val = p->data.dnum;
924 while(val >= 10.0) {
925 val /= 10;
926 maxprec--;
927 }
928
929 if(prec > (long)maxprec)
930 prec = (long)maxprec-1;
931 /* RECURSIVE USAGE */
932 len = curl_msnprintf(fptr, left, ".%ld", prec);
933 fptr += len;
934 }
935 if(p->flags & FLAGS_LONG)
936 *fptr++ = 'l';
937
938 if(p->flags & FLAGS_FLOATE)
939 *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e');
940 else if(p->flags & FLAGS_FLOATG)
941 *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g');
942 else
943 *fptr++ = 'f';
944
945 *fptr = 0; /* and a final zero termination */
946
947 /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
948 output characters */
949 (sprintf)(work, formatbuf, p->data.dnum);
950 DEBUGASSERT(strlen(work) <= sizeof(work));
951 for(fptr = work; *fptr; fptr++)
952 OUTCHAR(*fptr);
953 }
954 break;
955
956 case FORMAT_INTPTR:
957 /* Answer the count of characters written. */
958#ifdef HAVE_LONG_LONG_TYPE
959 if(p->flags & FLAGS_LONGLONG)
960 *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done;
961 else
962#endif
963 if(p->flags & FLAGS_LONG)
964 *(long *) p->data.ptr = (long)done;
965 else if(!(p->flags & FLAGS_SHORT))
966 *(int *) p->data.ptr = (int)done;
967 else
968 *(short *) p->data.ptr = (short)done;
969 break;
970
971 default:
972 break;
973 }
974 f = *end++; /* goto end of %-code */
975
976 }
977 return done;
978}
979#else
980/*------------------------------------------------------------------------/
981/ Universal string handler for user console interface
982/-------------------------------------------------------------------------/
983/
984/ Copyright (C) 2011, ChaN, all right reserved.
985/
986/ * This software is a free software and there is NO WARRANTY.
987/ * No restriction on use. You can use, modify and redistribute it for
988/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
989/ * Redistributions of source code must retain the above copyright notice.
990/
991/-------------------------------------------------------------------------*/
992static int dprintf_formatf(
993 void *data,
994 int(*stream)(int, FILE *),
995 const char *fmt,
996 va_list arp)
997{
998 unsigned int r, i, j, w, f;
999 unsigned long long v;
1000 char s[16], c, d, *p;
1001
1002 /* Number of characters written. */
1003 int done = 0;
1004
1005 for (;;) {
1006 c = *fmt++; /* Get a char */
1007 if (!c) break; /* End of format? */
1008 if (c != '%') { /* Pass through it if not a % sequense */
1009 OUTCHAR(c); continue;
1010 }
1011 f = 0;
1012 c = *fmt++; /* Get first char of the sequense */
1013 if (c == '0') { /* Flag: '0' padded */
1014 f = 1; c = *fmt++;
1015 }
1016 else {
1017 if (c == '-') { /* Flag: left justified */
1018 f = 2; c = *fmt++;
1019 }
1020 }
1021 for (w = 0; c >= '0' && c <= '9'; c = *fmt++) /* Minimum width */
1022 w = w * 10 + c - '0';
1023 if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
1024 c = *fmt++;
1025 if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
1026 f |= 32; c = *fmt++;
1027 }
1028 else {
1029 f |= 4;
1030 }
1031 }
1032 else if (c == 'h') { /* Prefix: Size is short int */
1033 f |= 16; c = *fmt++;
1034 }
1035 if (!c) break; /* End of format? */
1036 d = c;
1037 if (d >= 'a') d -= 0x20;
1038 switch (d) { /* Type is... */
1039 case 'S': /* String */
1040 p = va_arg(arp, char*);
1041 for (j = 0; p[j]; j++);
1042 while (!(f & 2) && j++ < w) OUTCHAR(' ');
1043 for (; *p; p++)
1044 OUTCHAR(*p);
1045 while (j++ < w) OUTCHAR(' ');
1046 continue;
1047 case 'C': /* Character */
1048 OUTCHAR((char)va_arg(arp, int)); continue;
1049 case 'B': /* Binary */
1050 r = 2; break;
1051 case 'O': /* Octal */
1052 r = 8; break;
1053 case 'D': /* Signed decimal */
1054 case 'U': /* Unsigned decimal */
1055 r = 10; break;
1056 case 'X': /* Hexdecimal */
1057 r = 16; break;
1058 default: /* Unknown type (passthrough) */
1059 OUTCHAR(c); continue;
1060 }
1061
1062 /* Get an argument and put it in numeral */
1063 if (f & 4)
1064 v = (long long)va_arg(arp, long);
1065 else if (f & 16)
1066 v = (d == 'D') ? (long long)((short)va_arg(arp, int)) : (long long)((unsigned short)va_arg(arp, unsigned int));
1067 else if (f & 32)
1068 v = (d == 'D') ? (long long)(va_arg(arp, long long)) : (long long)(va_arg(arp, unsigned long long));
1069 else
1070 v = (d == 'D') ? (long long)va_arg(arp, int) : (long long)va_arg(arp, unsigned int);
1071 if (d == 'D' && (v & 0x8000000000000000ll)) {
1072 v = 0 - v;
1073 f |= 8;
1074 }
1075 i = 0;
1076 do {
1077 d = (char)(v % r); v /= r;
1078 if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
1079 s[i++] = d + '0';
1080 } while (v && i < sizeof(s));
1081 if (f & 8) s[i++] = '-';
1082 j = i; d = (f & 1) ? '0' : ' ';
1083 while (!(f & 2) && j++ < w) OUTCHAR(d);
1084 do OUTCHAR(s[--i]); while (i);
1085 while (j++ < w) OUTCHAR(' ');
1086 }
1087 return done;
1088}
1089#endif
1090/* fputc() look-alike */
1091static int addbyter(int output, FILE *data)
1092{
1093 struct nsprintf *infop = (struct nsprintf *)data;
1094 unsigned char outc = (unsigned char)output;
1095
1096 if(infop->length < infop->max) {
1097 /* only do this if we haven't reached max length yet */
1098 infop->buffer[0] = outc; /* store */
1099 infop->buffer++; /* increase pointer */
1100 infop->length++; /* we are now one byte larger */
1101 return outc; /* fputc() returns like this on success */
1102 }
1103 return -1;
1104}
1105
1106int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
1107 va_list ap_save)
1108{
1109 int retcode;
1110 struct nsprintf info;
1111
1112 info.buffer = buffer;
1113 info.length = 0;
1114 info.max = maxlength;
1115
1116 retcode = dprintf_formatf(&info, addbyter, format, ap_save);
1117 if((retcode != -1) && info.max) {
1118 /* we terminate this with a zero byte */
1119 if(info.max == info.length)
1120 /* we're at maximum, scrap the last letter */
1121 info.buffer[-1] = 0;
1122 else
1123 info.buffer[0] = 0;
1124 }
1125 return retcode;
1126}
1127
1128int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1129{
1130 int retcode;
1131 va_list ap_save; /* argument pointer */
1132 va_start(ap_save, format);
1133 retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1134 va_end(ap_save);
1135 return retcode;
1136}
1137
1138/* fputc() look-alike */
1139static int alloc_addbyter(int output, FILE *data)
1140{
1141 struct asprintf *infop = (struct asprintf *)data;
1142 unsigned char outc = (unsigned char)output;
1143
1144 if(!infop->buffer) {
1145 infop->buffer = malloc(32);
1146 if(!infop->buffer) {
1147 infop->fail = 1;
1148 return -1; /* fail */
1149 }
1150 infop->alloc = 32;
1151 infop->len = 0;
1152 }
1153 else if(infop->len + 1 >= infop->alloc) {
1154 char *newptr = NULL;
1155 size_t newsize = infop->alloc*2;
1156
1157 /* detect wrap-around or other overflow problems */
1158 if(newsize > infop->alloc)
1159 newptr = realloc(infop->buffer, newsize);
1160
1161 if(!newptr) {
1162 infop->fail = 1;
1163 return -1; /* fail */
1164 }
1165 infop->buffer = newptr;
1166 infop->alloc = newsize;
1167 }
1168
1169 infop->buffer[ infop->len ] = outc;
1170
1171 infop->len++;
1172
1173 return outc; /* fputc() returns like this on success */
1174}
1175
1176char *curl_maprintf(const char *format, ...)
1177{
1178 va_list ap_save; /* argument pointer */
1179 int retcode;
1180 struct asprintf info;
1181
1182 info.buffer = NULL;
1183 info.len = 0;
1184 info.alloc = 0;
1185 info.fail = 0;
1186
1187 va_start(ap_save, format);
1188 retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1189 va_end(ap_save);
1190 if((-1 == retcode) || info.fail) {
1191 if(info.alloc)
1192 free(info.buffer);
1193 return NULL;
1194 }
1195 if(info.alloc) {
1196 info.buffer[info.len] = 0; /* we terminate this with a zero byte */
1197 return info.buffer;
1198 }
1199 return strdup("");
1200}
1201
1202char *curl_mvaprintf(const char *format, va_list ap_save)
1203{
1204 int retcode;
1205 struct asprintf info;
1206
1207 info.buffer = NULL;
1208 info.len = 0;
1209 info.alloc = 0;
1210 info.fail = 0;
1211
1212 retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1213 if((-1 == retcode) || info.fail) {
1214 if(info.alloc)
1215 free(info.buffer);
1216 return NULL;
1217 }
1218
1219 if(info.alloc) {
1220 info.buffer[info.len] = 0; /* we terminate this with a zero byte */
1221 return info.buffer;
1222 }
1223 return strdup("");
1224}
1225
1226static int storebuffer(int output, FILE *data)
1227{
1228 char **buffer = (char **)data;
1229 unsigned char outc = (unsigned char)output;
1230 **buffer = outc;
1231 (*buffer)++;
1232 return outc; /* act like fputc() ! */
1233}
1234
1235int curl_msprintf(char *buffer, const char *format, ...)
1236{
1237 va_list ap_save; /* argument pointer */
1238 int retcode;
1239 va_start(ap_save, format);
1240 retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1241 va_end(ap_save);
1242 *buffer = 0; /* we terminate this with a zero byte */
1243 return retcode;
1244}
1245
1246int curl_mprintf(const char *format, ...)
1247{
1248 int retcode;
1249 va_list ap_save; /* argument pointer */
1250 va_start(ap_save, format);
1251
1252 retcode = dprintf_formatf(stdout, fputc, format, ap_save);
1253 va_end(ap_save);
1254 return retcode;
1255}
1256
1257int curl_mfprintf(FILE *whereto, const char *format, ...)
1258{
1259 int retcode;
1260 va_list ap_save; /* argument pointer */
1261 va_start(ap_save, format);
1262 retcode = dprintf_formatf(whereto, fputc, format, ap_save);
1263 va_end(ap_save);
1264 return retcode;
1265}
1266
1267int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
1268{
1269 int retcode;
1270 retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1271 *buffer = 0; /* we terminate this with a zero byte */
1272 return retcode;
1273}
1274
1275int curl_mvprintf(const char *format, va_list ap_save)
1276{
1277 return dprintf_formatf(stdout, fputc, format, ap_save);
1278}
1279
1280int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1281{
1282 return dprintf_formatf(whereto, fputc, format, ap_save);
1283}
Note: See TracBrowser for help on using the repository browser.