source: UsbWattMeter/trunk/curl-7.47.1/lib/mprintf.c@ 164

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

TOPPERS/ECNLサンプルアプリ「USB充電器電力計」を追加

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