Annotation of embedaddon/curl/lib/mprintf.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1999 - 2019, 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. */
96: static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
97:
98: /* Upper-case digits. */
99: static 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 */
110: typedef 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 */
124: enum {
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:
148: typedef 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:
164: struct nsprintf {
165: char *buffer;
166: size_t length;
167: size_t max;
168: };
169:
170: struct 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:
178: static 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:
193: static 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:
227: static 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:
554: static 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: for(; len && *str; len--)
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:
980: /* fputc() look-alike */
981: static int addbyter(int output, FILE *data)
982: {
983: struct nsprintf *infop = (struct nsprintf *)data;
984: unsigned char outc = (unsigned char)output;
985:
986: if(infop->length < infop->max) {
987: /* only do this if we haven't reached max length yet */
988: infop->buffer[0] = outc; /* store */
989: infop->buffer++; /* increase pointer */
990: infop->length++; /* we are now one byte larger */
991: return outc; /* fputc() returns like this on success */
992: }
993: return -1;
994: }
995:
996: int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
997: va_list ap_save)
998: {
999: int retcode;
1000: struct nsprintf info;
1001:
1002: info.buffer = buffer;
1003: info.length = 0;
1004: info.max = maxlength;
1005:
1006: retcode = dprintf_formatf(&info, addbyter, format, ap_save);
1007: if((retcode != -1) && info.max) {
1008: /* we terminate this with a zero byte */
1009: if(info.max == info.length)
1010: /* we're at maximum, scrap the last letter */
1011: info.buffer[-1] = 0;
1012: else
1013: info.buffer[0] = 0;
1014: }
1015: return retcode;
1016: }
1017:
1018: int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1019: {
1020: int retcode;
1021: va_list ap_save; /* argument pointer */
1022: va_start(ap_save, format);
1023: retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1024: va_end(ap_save);
1025: return retcode;
1026: }
1027:
1028: /* fputc() look-alike */
1029: static int alloc_addbyter(int output, FILE *data)
1030: {
1031: struct asprintf *infop = (struct asprintf *)data;
1032: unsigned char outc = (unsigned char)output;
1033:
1034: if(!infop->buffer) {
1035: infop->buffer = malloc(32);
1036: if(!infop->buffer) {
1037: infop->fail = 1;
1038: return -1; /* fail */
1039: }
1040: infop->alloc = 32;
1041: infop->len = 0;
1042: }
1043: else if(infop->len + 1 >= infop->alloc) {
1044: char *newptr = NULL;
1045: size_t newsize = infop->alloc*2;
1046:
1047: /* detect wrap-around or other overflow problems */
1048: if(newsize > infop->alloc)
1049: newptr = realloc(infop->buffer, newsize);
1050:
1051: if(!newptr) {
1052: infop->fail = 1;
1053: return -1; /* fail */
1054: }
1055: infop->buffer = newptr;
1056: infop->alloc = newsize;
1057: }
1058:
1059: infop->buffer[ infop->len ] = outc;
1060:
1061: infop->len++;
1062:
1063: return outc; /* fputc() returns like this on success */
1064: }
1065:
1066: char *curl_maprintf(const char *format, ...)
1067: {
1068: va_list ap_save; /* argument pointer */
1069: int retcode;
1070: struct asprintf info;
1071:
1072: info.buffer = NULL;
1073: info.len = 0;
1074: info.alloc = 0;
1075: info.fail = 0;
1076:
1077: va_start(ap_save, format);
1078: retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1079: va_end(ap_save);
1080: if((-1 == retcode) || info.fail) {
1081: if(info.alloc)
1082: free(info.buffer);
1083: return NULL;
1084: }
1085: if(info.alloc) {
1086: info.buffer[info.len] = 0; /* we terminate this with a zero byte */
1087: return info.buffer;
1088: }
1089: return strdup("");
1090: }
1091:
1092: char *curl_mvaprintf(const char *format, va_list ap_save)
1093: {
1094: int retcode;
1095: struct asprintf info;
1096:
1097: info.buffer = NULL;
1098: info.len = 0;
1099: info.alloc = 0;
1100: info.fail = 0;
1101:
1102: retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1103: if((-1 == retcode) || info.fail) {
1104: if(info.alloc)
1105: free(info.buffer);
1106: return NULL;
1107: }
1108:
1109: if(info.alloc) {
1110: info.buffer[info.len] = 0; /* we terminate this with a zero byte */
1111: return info.buffer;
1112: }
1113: return strdup("");
1114: }
1115:
1116: static int storebuffer(int output, FILE *data)
1117: {
1118: char **buffer = (char **)data;
1119: unsigned char outc = (unsigned char)output;
1120: **buffer = outc;
1121: (*buffer)++;
1122: return outc; /* act like fputc() ! */
1123: }
1124:
1125: int curl_msprintf(char *buffer, const char *format, ...)
1126: {
1127: va_list ap_save; /* argument pointer */
1128: int retcode;
1129: va_start(ap_save, format);
1130: retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1131: va_end(ap_save);
1132: *buffer = 0; /* we terminate this with a zero byte */
1133: return retcode;
1134: }
1135:
1136: int curl_mprintf(const char *format, ...)
1137: {
1138: int retcode;
1139: va_list ap_save; /* argument pointer */
1140: va_start(ap_save, format);
1141:
1142: retcode = dprintf_formatf(stdout, fputc, format, ap_save);
1143: va_end(ap_save);
1144: return retcode;
1145: }
1146:
1147: int curl_mfprintf(FILE *whereto, const char *format, ...)
1148: {
1149: int retcode;
1150: va_list ap_save; /* argument pointer */
1151: va_start(ap_save, format);
1152: retcode = dprintf_formatf(whereto, fputc, format, ap_save);
1153: va_end(ap_save);
1154: return retcode;
1155: }
1156:
1157: int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
1158: {
1159: int retcode;
1160: retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1161: *buffer = 0; /* we terminate this with a zero byte */
1162: return retcode;
1163: }
1164:
1165: int curl_mvprintf(const char *format, va_list ap_save)
1166: {
1167: return dprintf_formatf(stdout, fputc, format, ap_save);
1168: }
1169:
1170: int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1171: {
1172: return dprintf_formatf(whereto, fputc, format, ap_save);
1173: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>