init version.
[bush.git] / lib / sh / snprintf.c
blob5748341d7e332fd24d514ff18b7b81047555668e
1 /* snprintf - formatted output to strings, with bounds checking and allocation */
3 /*
4 build a test version with
5 gcc -g -DDRIVER -I../.. -I../../include -o test-snprintf snprintf.c fmtu*long.o
6 */
8 /*
9 Unix snprintf implementation.
10 derived from inetutils/libinetutils/snprintf.c Version 1.1
12 Copyright (C) 2001-2020 Free Software Foundation, Inc.
14 This file is part of GNU Bush, the Bourne Again SHell.
16 Bush is free software: you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
21 Bush is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with Bush. If not, see <http://www.gnu.org/licenses/>.
29 Original (pre-bush) Revision History:
31 1.1:
32 * added changes from Miles Bader
33 * corrected a bug with %f
34 * added support for %#g
35 * added more comments :-)
36 1.0:
37 * supporting must ANSI syntaxic_sugars
38 0.0:
39 * support %s %c %d
41 THANKS(for the patches and ideas):
42 Miles Bader
43 Cyrille Rustom
44 Jacek Slabocewiz
45 Mike Parker(mouse)
50 * Currently doesn't handle (and bush/readline doesn't use):
51 * * *M$ width, precision specifications
52 * * %N$ numbered argument conversions
53 * * support for `F' is imperfect with ldfallback(), since underlying
54 * printf may not handle it -- should ideally have another autoconf test
57 #define FLOATING_POINT
59 #ifdef HAVE_CONFIG_H
60 # include <config.h>
61 #endif
63 /* GCC 4.2 on Snow Leopard doesn't like the snprintf prototype */
64 #if defined(DEBUG) && !defined (MACOSX)
65 # undef HAVE_SNPRINTF
66 # undef HAVE_ASPRINTF
68 # define HAVE_SNPRINTF 0
69 # define HAVE_ASPRINTF 0
70 #endif
72 #if defined(DRIVER) && !defined(HAVE_CONFIG_H)
73 #define HAVE_LONG_LONG
74 #define HAVE_LONG_DOUBLE
75 #ifdef __linux__
76 #define HAVE_PRINTF_A_FORMAT
77 #endif
78 #define HAVE_ISINF_IN_LIBC
79 #define HAVE_ISNAN_IN_LIBC
80 #define PREFER_STDARG
81 #define HAVE_STRINGIZE
82 #define HAVE_LIMITS_H
83 #define HAVE_STDDEF_H
84 #define HAVE_LOCALE_H
85 #define intmax_t long
86 #endif
88 #if !HAVE_SNPRINTF || !HAVE_ASPRINTF
90 #include <bushtypes.h>
92 #if defined(PREFER_STDARG)
93 # include <stdarg.h>
94 #else
95 # include <varargs.h>
96 #endif
98 #ifdef HAVE_LIMITS_H
99 # include <limits.h>
100 #endif
101 #include <bushansi.h>
102 #ifdef HAVE_STDDEF_H
103 # include <stddef.h>
104 #endif
105 #include <chartypes.h>
107 #ifdef HAVE_STDINT_H
108 # include <stdint.h>
109 #endif
111 #ifdef FLOATING_POINT
112 # include <float.h> /* for manifest constants */
113 # include <stdio.h> /* for sprintf */
114 #endif
116 #include <typemax.h>
118 #ifdef HAVE_LOCALE_H
119 # include <locale.h>
120 #endif
122 #include "stdc.h"
123 #include <shmbutil.h>
125 #ifndef DRIVER
126 # include "shell.h"
127 #else
128 # define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */
129 # define FL_ADDBASE 0x02 /* add base# prefix to converted value */
130 # define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */
131 # define FL_UNSIGNED 0x08 /* don't add any sign */
132 extern char *fmtulong PARAMS((unsigned long int, int, char *, size_t, int));
133 extern char *fmtullong PARAMS((unsigned long long int, int, char *, size_t, int));
134 #endif
136 #ifndef FREE
137 # define FREE(x) if (x) free (x)
138 #endif
140 /* Bound on length of the string representing an integer value of type T.
141 Subtract one for the sign bit if T is signed;
142 302 / 1000 is log10 (2) rounded up;
143 add one for integer division truncation;
144 add one more for a minus sign if t is signed. */
145 #ifndef INT_STRLEN_BOUND
146 #define INT_STRLEN_BOUND(t) \
147 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
148 + 1 + TYPE_SIGNED (t))
149 #endif
151 /* conversion flags */
152 #define PF_ALTFORM 0x00001 /* # */
153 #define PF_HEXPREFIX 0x00002 /* 0[Xx] */
154 #define PF_LADJUST 0x00004 /* - */
155 #define PF_ZEROPAD 0x00008 /* 0 */
156 #define PF_PLUS 0x00010 /* + */
157 #define PF_SPACE 0x00020 /* ' ' */
158 #define PF_THOUSANDS 0x00040 /* ' */
160 #define PF_DOT 0x00080 /* `.precision' */
161 #define PF_STAR_P 0x00100 /* `*' after precision */
162 #define PF_STAR_W 0x00200 /* `*' before or without precision */
164 /* length modifiers */
165 #define PF_SIGNEDCHAR 0x00400 /* hh */
166 #define PF_SHORTINT 0x00800 /* h */
167 #define PF_LONGINT 0x01000 /* l */
168 #define PF_LONGLONG 0x02000 /* ll */
169 #define PF_LONGDBL 0x04000 /* L */
170 #define PF_INTMAX_T 0x08000 /* j */
171 #define PF_SIZE_T 0x10000 /* z */
172 #define PF_PTRDIFF_T 0x20000 /* t */
174 #define PF_ALLOCBUF 0x40000 /* for asprintf, vasprintf */
176 #define PFM_SN 0x01 /* snprintf, vsnprintf */
177 #define PFM_AS 0x02 /* asprintf, vasprintf */
179 #define ASBUFSIZE 128
181 #define x_digs "0123456789abcdef"
182 #define X_digs "0123456789ABCDEF"
184 static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1];
186 static int decpoint;
187 static int thoussep;
188 static char *grouping;
191 * For the FLOATING POINT FORMAT :
192 * the challenge was finding a way to
193 * manipulate the Real numbers without having
194 * to resort to mathematical function(it
195 * would require to link with -lm) and not
196 * going down to the bit pattern(not portable)
198 * so a number, a real is:
200 real = integral + fraction
202 integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
203 fraction = b(1)*10^-1 + b(2)*10^-2 + ...
205 where:
206 0 <= a(i) => 9
207 0 <= b(i) => 9
209 from then it was simple math
213 * size of the buffer for the integral part
214 * and the fraction part
216 #define MAX_INT 99 + 1 /* 1 for the null */
217 #define MAX_FRACT 307 + 1
220 * These functions use static buffers to store the results,
221 * and so are not reentrant
223 #define itoa(n) fmtulong(n, 10, intbuf, sizeof(intbuf), 0);
224 #define dtoa(n, p, f) numtoa(n, 10, p, f)
226 #define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
228 #define GETARG(type) (va_arg(args, type))
230 /* Macros that do proper sign extension and handle length modifiers. Used
231 for the integer conversion specifiers. */
232 #define GETSIGNED(p) \
233 (((p)->flags & PF_LONGINT) \
234 ? GETARG (long) \
235 : (((p)->flags & PF_SHORTINT) ? (long)(short)GETARG (int) \
236 : (long)GETARG (int)))
238 #define GETUNSIGNED(p) \
239 (((p)->flags & PF_LONGINT) \
240 ? GETARG (unsigned long) \
241 : (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)GETARG (int) \
242 : (unsigned long)GETARG (unsigned int)))
245 #ifdef HAVE_LONG_DOUBLE
246 #define GETLDOUBLE(p) GETARG (long double)
247 #endif
248 #define GETDOUBLE(p) GETARG (double)
250 #define SET_SIZE_FLAGS(p, type) \
251 if (sizeof (type) > sizeof (int)) \
252 (p)->flags |= PF_LONGINT; \
253 if (sizeof (type) > sizeof (long)) \
254 (p)->flags |= PF_LONGLONG;
256 /* this struct holds everything we need */
257 struct DATA
259 int length;
260 char *base; /* needed for [v]asprintf */
261 char *holder;
262 int counter;
263 const char *pf;
265 /* FLAGS */
266 int flags;
267 int justify;
268 int width, precision;
269 char pad;
272 /* the floating point stuff */
273 #ifdef FLOATING_POINT
274 static double pow_10 PARAMS((int));
275 static int log_10 PARAMS((double));
276 static double integral PARAMS((double, double *));
277 static char *numtoa PARAMS((double, int, int, char **));
278 #endif
280 static void init_data PARAMS((struct DATA *, char *, size_t, const char *, int));
281 static void init_conv_flag PARAMS((struct DATA *));
283 /* for the format */
284 #ifdef FLOATING_POINT
285 static void floating PARAMS((struct DATA *, double));
286 static void exponent PARAMS((struct DATA *, double));
287 #endif
288 static void number PARAMS((struct DATA *, unsigned long, int));
289 #ifdef HAVE_LONG_LONG
290 static void lnumber PARAMS((struct DATA *, unsigned long long, int));
291 #endif
292 static void pointer PARAMS((struct DATA *, unsigned long));
293 static void strings PARAMS((struct DATA *, char *));
295 #ifdef FLOATING_POINT
296 # define FALLBACK_FMTSIZE 32
297 # define FALLBACK_BASE 4096
298 # define LFALLBACK_BASE 5120
299 # ifdef HAVE_LONG_DOUBLE
300 static void ldfallback PARAMS((struct DATA *, const char *, const char *, long double));
301 # endif
302 static void dfallback PARAMS((struct DATA *, const char *, const char *, double));
303 #endif
305 static char *groupnum PARAMS((char *));
307 #if defined (HAVE_LONG_DOUBLE)
308 # define LONGDOUBLE long double
309 #else
310 # define LONGDOUBLE double
311 #endif
313 #ifndef isnan
314 static inline int isnan_f (float x) { return x != x; }
315 static inline int isnan_d (double x) { return x != x; }
316 static inline int isnan_ld (LONGDOUBLE x) { return x != x; }
317 # define isnan(x) \
318 (sizeof (x) == sizeof (LONGDOUBLE) ? isnan_ld (x) \
319 : sizeof (x) == sizeof (double) ? isnan_d (x) \
320 : isnan_f (x))
321 #endif
323 #ifndef isinf
324 static inline int isinf_f (float x) { return !isnan (x) && isnan (x - x); }
325 static inline int isinf_d (double x) { return !isnan (x) && isnan (x - x); }
326 static inline int isinf_ld (LONGDOUBLE x) { return !isnan (x) && isnan (x - x); }
327 # define isinf(x) \
328 (sizeof (x) == sizeof (LONGDOUBLE) ? isinf_ld (x) \
329 : sizeof (x) == sizeof (double) ? isinf_d (x) \
330 : isinf_f (x))
331 #endif
333 #ifdef DRIVER
334 static void memory_error_and_abort ();
335 static void *xmalloc PARAMS((size_t));
336 static void *xrealloc PARAMS((void *, size_t));
337 static void xfree PARAMS((void *));
338 #else
339 # include <xmalloc.h>
340 #endif
342 /* those are defines specific to snprintf to hopefully
343 * make the code clearer :-)
345 #define RIGHT 1
346 #define LEFT 0
347 #define NOT_FOUND -1
348 #define FOUND 1
349 #define MAX_FIELD 15
351 /* round off to the precision */
352 #define ROUND(d, p) \
353 (d < 0.) ? \
354 d - pow_10(-(p)->precision) * 0.5 : \
355 d + pow_10(-(p)->precision) * 0.5
357 /* set default precision */
358 #define DEF_PREC(p) \
359 if ((p)->precision == NOT_FOUND) \
360 (p)->precision = 6
362 /* put a char. increment the number of chars written even if we've exceeded
363 the vsnprintf/snprintf buffer size (for the return value) */
364 #define PUT_CHAR(c, p) \
365 do \
367 if (((p)->flags & PF_ALLOCBUF) && ((p)->counter >= (p)->length - 1)) \
369 (p)->length += ASBUFSIZE; \
370 (p)->base = (char *)xrealloc((p)->base, (p)->length); \
371 (p)->holder = (p)->base + (p)->counter; /* in case reallocated */ \
373 if ((p)->counter < (p)->length) \
374 *(p)->holder++ = (c); \
375 (p)->counter++; \
377 while (0)
379 /* Output a string. P->WIDTH has already been adjusted for padding. */
380 #define PUT_STRING(string, len, p) \
381 do \
383 PAD_RIGHT (p); \
384 while ((len)-- > 0) \
386 PUT_CHAR (*(string), (p)); \
387 (string)++; \
389 PAD_LEFT (p); \
391 while (0)
393 #define PUT_PLUS(d, p, zero) \
394 if (((p)->flags & PF_PLUS) && (d) > zero) \
395 PUT_CHAR('+', p)
397 #define PUT_SPACE(d, p, zero) \
398 if (((p)->flags & PF_SPACE) && (d) > zero) \
399 PUT_CHAR(' ', p)
401 /* pad right */
402 #define PAD_RIGHT(p) \
403 if ((p)->width > 0 && (p)->justify != LEFT) \
404 for (; (p)->width > 0; (p)->width--) \
405 PUT_CHAR((p)->pad, p)
407 /* pad left */
408 #define PAD_LEFT(p) \
409 if ((p)->width > 0 && (p)->justify == LEFT) \
410 for (; (p)->width > 0; (p)->width--) \
411 PUT_CHAR((p)->pad, p)
413 /* pad with zeros from decimal precision */
414 #define PAD_ZERO(p) \
415 if ((p)->precision > 0) \
416 for (; (p)->precision > 0; (p)->precision--) \
417 PUT_CHAR('0', p)
419 /* if width and prec. in the args */
420 #define STAR_ARGS(p) \
421 do { \
422 if ((p)->flags & PF_STAR_W) \
424 (p)->width = GETARG (int); \
425 if ((p)->width < 0) \
427 (p)->flags |= PF_LADJUST; \
428 (p)->justify = LEFT; \
429 (p)->width = -(p)->width; \
432 if ((p)->flags & PF_STAR_P) \
434 (p)->precision = GETARG (int); \
435 if ((p)->precision < 0) \
437 (p)->flags &= ~PF_STAR_P; \
438 (p)->precision = NOT_FOUND; \
441 } while (0)
443 #if defined (HAVE_LOCALE_H) && defined (HAVE_LOCALECONV)
444 # define GETLOCALEDATA(d, t, g) \
445 do \
447 struct lconv *lv; \
448 if ((d) == 0) { \
449 (d) = '.'; (t) = -1; (g) = 0; /* defaults */ \
450 lv = localeconv(); \
451 if (lv) \
453 if (lv->decimal_point && lv->decimal_point[0]) \
454 (d) = lv->decimal_point[0]; \
455 if (lv->thousands_sep && lv->thousands_sep[0]) \
456 (t) = lv->thousands_sep[0]; \
457 (g) = lv->grouping ? lv->grouping : ""; \
458 if (*(g) == '\0' || *(g) == CHAR_MAX || (t) == -1) (g) = 0; \
462 while (0);
463 #else
464 # define GETLOCALEDATA(d, t, g) \
465 ( (d) = '.', (t) = ',', g = "\003" )
466 #endif
468 #ifdef FLOATING_POINT
470 * Find the nth power of 10
472 static double
473 pow_10(n)
474 int n;
476 double P;
478 /* handle common cases with fast switch statement. */
479 switch (n)
481 case -3: return .001;
482 case -2: return .01;
483 case -1: return .1;
484 case 0: return 1.;
485 case 1: return 10.;
486 case 2: return 100.;
487 case 3: return 1000.;
490 if (n < 0)
492 P = .0001;
493 for (n += 4; n < 0; n++)
494 P /= 10.;
496 else
498 P = 10000.;
499 for (n -= 4; n > 0; n--)
500 P *= 10.;
503 return P;
507 * Find the integral part of the log in base 10
508 * Note: this not a real log10()
509 I just need and approximation(integerpart) of x in:
510 10^x ~= r
511 * log_10(200) = 2;
512 * log_10(250) = 2;
514 * NOTE: do not call this with r == 0 -- an infinite loop results.
516 static int
517 log_10(r)
518 double r;
520 int i = 0;
521 double result = 1.;
523 if (r < 0.)
524 r = -r;
526 if (r < 1.)
528 while (result >= r)
530 result /= 10.;
531 i++;
533 return (-i);
535 else
537 while (result <= r)
539 result *= 10.;
540 i++;
542 return (i - 1);
547 * This function return the fraction part of a double
548 * and set in ip the integral part.
549 * In many ways it resemble the modf() found on most Un*x
551 static double
552 integral(real, ip)
553 double real;
554 double *ip;
556 int j;
557 double i, s, p;
558 double real_integral = 0.;
560 /* take care of the obvious */
561 /* equal to zero ? */
562 if (real == 0.)
564 *ip = 0.;
565 return (0.);
568 /* negative number ? */
569 if (real < 0.)
570 real = -real;
572 /* a fraction ? */
573 if ( real < 1.)
575 *ip = 0.;
576 return real;
579 /* the real work :-) */
580 for (j = log_10(real); j >= 0; j--)
582 p = pow_10(j);
583 s = (real - real_integral)/p;
584 i = 0.;
585 while (i + 1. <= s)
586 i++;
587 real_integral += i*p;
589 *ip = real_integral;
590 return (real - real_integral);
593 #define PRECISION 1.e-6
595 * return an ascii representation of the integral part of the number
596 * and set fract to be an ascii representation of the fraction part
597 * the container for the fraction and the integral part or statically
598 * declare with fix size
600 static char *
601 numtoa(number, base, precision, fract)
602 double number;
603 int base, precision;
604 char **fract;
606 register int i, j;
607 double ip, fp; /* integer and fraction part */
608 double fraction;
609 int digits, sign;
610 static char integral_part[MAX_INT];
611 static char fraction_part[MAX_FRACT];
612 int ch;
614 /* taking care of the obvious case: 0.0 */
615 if (number == 0.)
617 integral_part[0] = '0';
618 integral_part[1] = '\0';
619 /* The fractional part has to take the precision into account */
620 for (ch = 0; ch < precision-1; ch++)
621 fraction_part[ch] = '0';
622 fraction_part[ch] = '0';
623 fraction_part[ch+1] = '\0';
624 if (fract)
625 *fract = fraction_part;
626 return integral_part;
629 /* -0 is tricky */
630 sign = (number == -0.) ? '-' : ((number < 0.) ? '-' : '+');
631 digits = MAX_INT - 1;
633 /* for negative numbers */
634 if (sign == '-')
636 number = -number;
637 digits--; /* sign consume one digit */
640 fraction = integral(number, &ip);
641 number = ip;
643 /* do the integral part */
644 if (ip == 0.)
646 integral_part[0] = '0';
647 i = 1;
649 else
651 for ( i = 0; i < digits && number != 0.; ++i)
653 number /= base;
654 fp = integral(number, &ip);
655 ch = (int)((fp + PRECISION)*base); /* force to round */
656 integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
657 if (! ISXDIGIT((unsigned char)integral_part[i]))
658 break; /* bail out overflow !! */
659 number = ip;
663 /* Oh No !! out of bound, ho well fill it up ! */
664 if (number != 0.)
665 for (i = 0; i < digits; ++i)
666 integral_part[i] = '9';
668 /* put the sign ? */
669 if (sign == '-')
670 integral_part[i++] = '-';
672 integral_part[i] = '\0';
674 /* reverse every thing */
675 for ( i--, j = 0; j < i; j++, i--)
676 SWAP_INT(integral_part[i], integral_part[j]);
678 /* the fractional part */
679 for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision--)
681 fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
682 if (! DIGIT(fraction_part[i])) /* underflow ? */
683 break;
684 fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
686 fraction_part[i] = '\0';
688 if (fract != (char **)0)
689 *fract = fraction_part;
691 return integral_part;
693 #endif
695 /* for %d and friends, it puts in holder
696 * the representation with the right padding
698 static void
699 number(p, d, base)
700 struct DATA *p;
701 unsigned long d;
702 int base;
704 char *tmp, *t;
705 long sd;
706 int flags;
708 /* An explicit precision turns off the zero-padding flag and sets the
709 pad character back to space. */
710 if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT))
712 p->flags &= ~PF_ZEROPAD;
713 p->pad = ' ';
716 sd = d; /* signed for ' ' padding in base 10 */
717 flags = 0;
718 flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
719 if (*p->pf == 'X')
720 flags |= FL_HEXUPPER;
722 tmp = fmtulong (d, base, intbuf, sizeof(intbuf), flags);
723 t = 0;
724 if ((p->flags & PF_THOUSANDS))
726 GETLOCALEDATA(decpoint, thoussep, grouping);
727 if (grouping && (t = groupnum (tmp)))
728 tmp = t;
731 /* need to add one for any `+', but we only add one in base 10 */
732 p->width -= strlen(tmp) + (base == 10 && d > 0 && (p->flags & PF_PLUS));
733 PAD_RIGHT(p);
735 if ((p->flags & PF_DOT) && p->precision > 0)
737 p->precision -= strlen(tmp);
738 PAD_ZERO(p);
741 switch (base)
743 case 10:
744 PUT_PLUS(sd, p, 0);
745 PUT_SPACE(sd, p, 0);
746 break;
747 case 8:
748 if (p->flags & PF_ALTFORM)
749 PUT_CHAR('0', p);
750 break;
751 case 16:
752 if (p->flags & PF_ALTFORM)
754 PUT_CHAR('0', p);
755 PUT_CHAR(*p->pf, p);
757 break;
760 while (*tmp)
762 PUT_CHAR(*tmp, p);
763 tmp++;
766 PAD_LEFT(p);
767 FREE (t);
770 #ifdef HAVE_LONG_LONG
772 * identical to number() but works for `long long'
774 static void
775 lnumber(p, d, base)
776 struct DATA *p;
777 unsigned long long d;
778 int base;
780 char *tmp, *t;
781 long long sd;
782 int flags;
784 /* An explicit precision turns off the zero-padding flag and sets the
785 pad character back to space. */
786 if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT))
788 p->flags &= ~PF_ZEROPAD;
789 p->pad = ' ';
792 sd = d; /* signed for ' ' padding in base 10 */
793 flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
794 if (*p->pf == 'X')
795 flags |= FL_HEXUPPER;
797 tmp = fmtullong (d, base, intbuf, sizeof(intbuf), flags);
798 t = 0;
799 if ((p->flags & PF_THOUSANDS))
801 GETLOCALEDATA(decpoint, thoussep, grouping);
802 if (grouping && (t = groupnum (tmp)))
803 tmp = t;
806 /* need to add one for any `+', but we only add one in base 10 */
807 p->width -= strlen(tmp) + (base == 10 && d > 0 && (p->flags & PF_PLUS));
808 PAD_RIGHT(p);
810 if ((p->flags & PF_DOT) && p->precision > 0)
812 p->precision -= strlen(tmp);
813 PAD_ZERO(p);
816 switch (base)
818 case 10:
819 PUT_PLUS(sd, p, 0);
820 PUT_SPACE(sd, p, 0);
821 break;
822 case 8:
823 if (p->flags & PF_ALTFORM)
824 PUT_CHAR('0', p);
825 break;
826 case 16:
827 if (p->flags & PF_ALTFORM)
829 PUT_CHAR('0', p);
830 PUT_CHAR(*p->pf, p);
832 break;
835 while (*tmp)
837 PUT_CHAR(*tmp, p);
838 tmp++;
841 PAD_LEFT(p);
842 FREE (t);
844 #endif
846 static void
847 pointer(p, d)
848 struct DATA *p;
849 unsigned long d;
851 char *tmp;
853 tmp = fmtulong(d, 16, intbuf, sizeof(intbuf), 0);
854 p->width -= strlen(tmp);
855 PAD_RIGHT(p);
857 /* prefix '0x' for pointers */
858 PUT_CHAR('0', p);
859 PUT_CHAR('x', p);
861 while (*tmp)
863 PUT_CHAR(*tmp, p);
864 tmp++;
867 PAD_LEFT(p);
870 /* %s strings */
871 static void
872 strings(p, tmp)
873 struct DATA *p;
874 char *tmp;
876 size_t len;
878 len = strlen(tmp);
879 if (p->precision != NOT_FOUND) /* the smallest number */
880 len = (len < p->precision ? len : p->precision);
881 p->width -= len;
883 PUT_STRING (tmp, len, p);
886 #if HANDLE_MULTIBYTE
887 /* %ls wide-character strings */
888 static void
889 wstrings(p, tmp)
890 struct DATA *p;
891 wchar_t *tmp;
893 size_t len;
894 mbstate_t mbs;
895 char *os;
896 const wchar_t *ws;
898 memset (&mbs, '\0', sizeof (mbstate_t));
899 ws = (const wchar_t *)tmp;
901 os = (char *)NULL;
902 if (p->precision != NOT_FOUND)
904 os = (char *)xmalloc (p->precision + 1);
905 len = wcsrtombs (os, &ws, p->precision, &mbs);
907 else
909 len = wcsrtombs (NULL, &ws, 0, &mbs);
910 if (len != (size_t)-1)
912 memset (&mbs, '\0', sizeof (mbstate_t));
913 os = (char *)xmalloc (len + 1);
914 (void)wcsrtombs (os, &ws, len + 1, &mbs);
917 if (len == (size_t)-1)
919 /* invalid multibyte sequence; bail now. */
920 FREE (os);
921 return;
924 p->width -= len;
925 PUT_STRING (os, len, p);
926 free (os);
929 static void
930 wchars (p, wc)
931 struct DATA *p;
932 wint_t wc;
934 char *lbuf, *l;
935 mbstate_t mbs;
936 size_t len;
938 lbuf = (char *)malloc (MB_CUR_MAX+1);
939 if (lbuf == 0)
940 return;
941 memset (&mbs, '\0', sizeof (mbstate_t));
942 len = wcrtomb (lbuf, wc, &mbs);
943 if (len == (size_t)-1)
944 /* conversion failed; bail now. */
945 return;
946 p->width -= len;
947 l = lbuf;
948 PUT_STRING (l, len, p);
949 free (lbuf);
951 #endif /* HANDLE_MULTIBYTE */
953 #ifdef FLOATING_POINT
955 /* Check for [+-]infinity and NaN. If MODE == 1, we check for Infinity, else
956 (mode == 2) we check for NaN. This does the necessary printing. Returns
957 1 if Inf or Nan, 0 if not. */
958 static int
959 chkinfnan(p, d, mode)
960 struct DATA *p;
961 double d;
962 int mode; /* == 1 for inf, == 2 for nan */
964 int i;
965 char *tmp;
966 char *big, *small;
968 i = (mode == 1) ? isinf(d) : isnan(d);
969 if (i == 0)
970 return 0;
971 big = (mode == 1) ? "INF" : "NAN";
972 small = (mode == 1) ? "inf" : "nan";
974 tmp = (*p->pf == 'F' || *p->pf == 'G' || *p->pf == 'E') ? big : small;
976 if (i < 0)
977 PUT_CHAR('-', p);
979 while (*tmp)
981 PUT_CHAR (*tmp, p);
982 tmp++;
985 return 1;
988 /* %f %F %g %G floating point representation */
989 static void
990 floating(p, d)
991 struct DATA *p;
992 double d;
994 char *tmp, *tmp2, *t;
995 int i;
997 if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)))
998 return; /* already printed nan or inf */
1000 GETLOCALEDATA(decpoint, thoussep, grouping);
1001 DEF_PREC(p);
1002 d = ROUND(d, p);
1003 tmp = dtoa(d, p->precision, &tmp2);
1004 t = 0;
1005 if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp)))
1006 tmp = t;
1008 if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
1010 /* smash the trailing zeros unless altform */
1011 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
1012 tmp2[i] = '\0';
1013 if (tmp2[0] == '\0')
1014 p->precision = 0;
1017 /* calculate the padding. 1 for the dot */
1018 p->width = p->width -
1019 /* XXX - should this be d>0. && (p->flags & PF_PLUS) ? */
1020 #if 0
1021 ((d > 0. && p->justify == RIGHT) ? 1:0) -
1022 #else
1023 ((d > 0. && (p->flags & PF_PLUS)) ? 1:0) -
1024 #endif
1025 ((p->flags & PF_SPACE) ? 1:0) -
1026 strlen(tmp) - p->precision -
1027 ((p->precision != 0 || (p->flags & PF_ALTFORM)) ? 1 : 0); /* radix char */
1029 if (p->pad == ' ')
1031 PAD_RIGHT(p);
1032 PUT_PLUS(d, p, 0.);
1034 else
1036 if (*tmp == '-')
1037 PUT_CHAR(*tmp++, p);
1038 PUT_PLUS(d, p, 0.);
1039 PAD_RIGHT(p);
1041 PUT_SPACE(d, p, 0.);
1043 while (*tmp)
1045 PUT_CHAR(*tmp, p); /* the integral */
1046 tmp++;
1048 FREE (t);
1050 if (p->precision != 0 || (p->flags & PF_ALTFORM))
1051 PUT_CHAR(decpoint, p); /* put the '.' */
1053 for (; *tmp2; tmp2++)
1054 PUT_CHAR(*tmp2, p); /* the fraction */
1056 PAD_LEFT(p);
1059 /* %e %E %g %G exponent representation */
1060 static void
1061 exponent(p, d)
1062 struct DATA *p;
1063 double d;
1065 char *tmp, *tmp2;
1066 int j, i;
1068 if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)))
1069 return; /* already printed nan or inf */
1071 GETLOCALEDATA(decpoint, thoussep, grouping);
1072 DEF_PREC(p);
1073 if (d == 0.)
1074 j = 0;
1075 else
1077 j = log_10(d);
1078 d = d / pow_10(j); /* get the Mantissa */
1079 d = ROUND(d, p);
1081 tmp = dtoa(d, p->precision, &tmp2);
1083 /* 1 for unit, 1 for the '.', 1 for 'e|E',
1084 * 1 for '+|-', 2 for 'exp' (but no `.' if precision == 0 */
1085 /* calculate how much padding need */
1086 p->width = p->width -
1087 /* XXX - should this be d>0. && (p->flags & PF_PLUS) ? */
1088 #if 0
1089 ((d > 0. && p->justify == RIGHT) ? 1:0) -
1090 #else
1091 ((d > 0. && (p->flags & PF_PLUS)) ? 1:0) -
1092 #endif
1093 (p->precision != 0 || (p->flags & PF_ALTFORM)) -
1094 ((p->flags & PF_SPACE) ? 1:0) - p->precision - 5;
1096 if (p->pad == ' ')
1098 PAD_RIGHT(p);
1099 PUT_PLUS(d, p, 0.);
1101 else
1103 if (*tmp == '-')
1104 PUT_CHAR(*tmp++, p);
1105 PUT_PLUS(d, p, 0.);
1106 PAD_RIGHT(p);
1108 PUT_SPACE(d, p, 0.);
1110 while (*tmp)
1112 PUT_CHAR(*tmp, p);
1113 tmp++;
1116 if (p->precision != 0 || (p->flags & PF_ALTFORM))
1117 PUT_CHAR(decpoint, p); /* the '.' */
1119 if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
1120 /* smash the trailing zeros unless altform */
1121 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
1122 tmp2[i] = '\0';
1124 for (; *tmp2; tmp2++)
1125 PUT_CHAR(*tmp2, p); /* the fraction */
1127 /* the exponent put the 'e|E' */
1128 if (*p->pf == 'g' || *p->pf == 'e')
1129 PUT_CHAR('e', p);
1130 else
1131 PUT_CHAR('E', p);
1133 /* the sign of the exp */
1134 if (j >= 0)
1135 PUT_CHAR('+', p);
1136 else
1138 PUT_CHAR('-', p);
1139 j = -j;
1142 tmp = itoa(j);
1143 /* pad out to at least two spaces. pad with `0' if the exponent is a
1144 single digit. */
1145 if (j <= 9)
1146 PUT_CHAR('0', p);
1148 /* the exponent */
1149 while (*tmp)
1151 PUT_CHAR(*tmp, p);
1152 tmp++;
1155 PAD_LEFT(p);
1157 #endif
1159 /* Return a new string with the digits in S grouped according to the locale's
1160 grouping info and thousands separator. If no grouping should be performed,
1161 this returns NULL; the caller needs to check for it. */
1162 static char *
1163 groupnum (s)
1164 char *s;
1166 char *se, *ret, *re, *g;
1167 int len, slen;
1169 if (grouping == 0 || *grouping <= 0 || *grouping == CHAR_MAX)
1170 return ((char *)NULL);
1172 /* find min grouping to size returned string */
1173 for (len = *grouping, g = grouping; *g; g++)
1174 if (*g > 0 && *g < len)
1175 len = *g;
1177 slen = strlen (s);
1178 len = slen / len + 1;
1179 ret = (char *)xmalloc (slen + len + 1);
1180 re = ret + slen + len;
1181 *re = '\0';
1183 g = grouping;
1184 se = s + slen;
1185 len = *g;
1187 while (se > s)
1189 *--re = *--se;
1191 /* handle `-' inserted by numtoa() and the fmtu* family here. */
1192 if (se > s && se[-1] == '-')
1193 continue;
1195 /* begin new group. */
1196 if (--len == 0 && se > s)
1198 *--re = thoussep;
1199 len = *++g; /* was g++, but that uses first char twice (glibc bug, too) */
1200 if (*g == '\0')
1201 len = *--g; /* use previous grouping */
1202 else if (*g == CHAR_MAX)
1205 *--re = *--se;
1206 while (se > s);
1207 break;
1212 if (re > ret)
1213 #ifdef HAVE_MEMMOVE
1214 memmove (ret, re, strlen (re) + 1);
1215 #else
1216 strcpy (ret, re);
1217 #endif
1219 return ret;
1222 /* initialize the conversion specifiers */
1223 static void
1224 init_conv_flag (p)
1225 struct DATA *p;
1227 p->flags &= PF_ALLOCBUF; /* preserve PF_ALLOCBUF flag */
1228 p->precision = p->width = NOT_FOUND;
1229 p->justify = NOT_FOUND;
1230 p->pad = ' ';
1233 static void
1234 init_data (p, string, length, format, mode)
1235 struct DATA *p;
1236 char *string;
1237 size_t length;
1238 const char *format;
1239 int mode;
1241 p->length = length - 1; /* leave room for '\0' */
1242 p->holder = p->base = string;
1243 p->pf = format;
1244 p->counter = 0;
1245 p->flags = (mode == PFM_AS) ? PF_ALLOCBUF : 0;
1248 static int
1249 #if defined (__STDC__)
1250 vsnprintf_internal(struct DATA *data, char *string, size_t length, const char *format, va_list args)
1251 #else
1252 vsnprintf_internal(data, string, length, format, args)
1253 struct DATA *data;
1254 char *string;
1255 size_t length;
1256 const char *format;
1257 va_list args;
1258 #endif
1260 double d; /* temporary holder */
1261 #ifdef HAVE_LONG_DOUBLE
1262 long double ld; /* for later */
1263 #endif
1264 unsigned long ul;
1265 #ifdef HAVE_LONG_LONG
1266 unsigned long long ull;
1267 #endif
1268 int state, i, c, n;
1269 char *s;
1270 #if HANDLE_MULTIBYTE
1271 wchar_t *ws;
1272 wint_t wc;
1273 #endif
1274 const char *convstart;
1275 int negprec;
1277 /* Sanity check, the string length must be >= 0. C99 actually says that
1278 LENGTH can be zero here, in the case of snprintf/vsnprintf (it's never
1279 0 in the case of asprintf/vasprintf), and the return value is the number
1280 of characters that would have been written. */
1281 if (length < 0)
1282 return -1;
1284 if (format == 0)
1285 return 0;
1287 /* Reset these for each call because the locale might have changed. */
1288 decpoint = thoussep = 0;
1289 grouping = 0;
1291 negprec = 0;
1292 for (; c = *(data->pf); data->pf++)
1294 if (c != '%')
1296 PUT_CHAR (c, data);
1297 continue;
1300 convstart = data->pf;
1301 init_conv_flag (data); /* initialise format flags */
1303 state = 1;
1304 for (state = 1; state && *data->pf; )
1306 c = *(++data->pf);
1307 /* fmtend = data->pf */
1308 #if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE)
1309 if (data->flags & PF_LONGDBL)
1311 switch (c)
1313 case 'f': case 'F':
1314 case 'e': case 'E':
1315 case 'g': case 'G':
1316 # ifdef HAVE_PRINTF_A_FORMAT
1317 case 'a': case 'A':
1318 # endif
1319 STAR_ARGS (data);
1320 ld = GETLDOUBLE (data);
1321 ldfallback (data, convstart, data->pf, ld);
1322 goto conv_break;
1325 #endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */
1327 switch (c)
1329 /* Parse format flags */
1330 case '\0': /* a NULL here ? ? bail out */
1331 *data->holder = '\0';
1332 return data->counter;
1333 break;
1334 case '#':
1335 data->flags |= PF_ALTFORM;
1336 continue;
1337 case '*':
1338 if (data->flags & PF_DOT)
1339 data->flags |= PF_STAR_P;
1340 else
1341 data->flags |= PF_STAR_W;
1342 continue;
1343 case '-':
1344 if ((data->flags & PF_DOT) == 0)
1346 data->flags |= PF_LADJUST;
1347 data->justify = LEFT;
1349 else
1350 negprec = 1;
1351 continue;
1352 case ' ':
1353 if ((data->flags & PF_PLUS) == 0)
1354 data->flags |= PF_SPACE;
1355 continue;
1356 case '+':
1357 if ((data->flags & PF_DOT) == 0)
1359 data->flags |= PF_PLUS;
1360 if ((data->flags & PF_LADJUST) == 0)
1361 data->justify = RIGHT;
1363 continue;
1364 case '\'':
1365 data->flags |= PF_THOUSANDS;
1366 continue;
1368 case '0':
1369 /* If we're not specifying precision (in which case we've seen
1370 a `.') and we're not performing left-adjustment (in which
1371 case the `0' is ignored), a `0' is taken as the zero-padding
1372 flag. */
1373 if ((data->flags & (PF_DOT|PF_LADJUST)) == 0)
1375 data->flags |= PF_ZEROPAD;
1376 data->pad = '0';
1377 continue;
1379 case '1': case '2': case '3':
1380 case '4': case '5': case '6':
1381 case '7': case '8': case '9':
1382 n = 0;
1385 n = n * 10 + TODIGIT(c);
1386 c = *(++data->pf);
1388 while (DIGIT(c));
1389 data->pf--; /* went too far */
1390 if (n < 0)
1391 n = 0;
1392 if (data->flags & PF_DOT)
1393 data->precision = negprec ? NOT_FOUND : n;
1394 else
1395 data->width = n;
1396 continue;
1398 /* optional precision */
1399 case '.':
1400 data->flags |= PF_DOT;
1401 data->precision = 0;
1402 continue;
1404 /* length modifiers */
1405 case 'h':
1406 data->flags |= (data->flags & PF_SHORTINT) ? PF_SIGNEDCHAR : PF_SHORTINT;
1407 continue;
1408 case 'l':
1409 data->flags |= (data->flags & PF_LONGINT) ? PF_LONGLONG : PF_LONGINT;
1410 continue;
1411 case 'L':
1412 data->flags |= PF_LONGDBL;
1413 continue;
1414 case 'q':
1415 data->flags |= PF_LONGLONG;
1416 continue;
1417 case 'j':
1418 data->flags |= PF_INTMAX_T;
1419 SET_SIZE_FLAGS(data, intmax_t);
1420 continue;
1421 case 'z':
1422 data->flags |= PF_SIZE_T;
1423 SET_SIZE_FLAGS(data, size_t);
1424 continue;
1425 case 't':
1426 data->flags |= PF_PTRDIFF_T;
1427 SET_SIZE_FLAGS(data, ptrdiff_t);
1428 continue;
1430 /* Conversion specifiers */
1431 #ifdef FLOATING_POINT
1432 case 'f': /* float, double */
1433 case 'F':
1434 STAR_ARGS(data);
1435 d = GETDOUBLE(data);
1436 floating(data, d);
1437 conv_break:
1438 state = 0;
1439 break;
1440 case 'g':
1441 case 'G':
1442 STAR_ARGS(data);
1443 DEF_PREC(data);
1444 d = GETDOUBLE(data);
1445 i = (d != 0.) ? log_10(d) : -1;
1447 * for '%g|%G' ANSI: use f if exponent
1448 * is in the range or [-4,p] exclusively
1449 * else use %e|%E
1451 if (-4 < i && i < data->precision)
1453 /* reset precision */
1454 data->precision -= i + 1;
1455 floating(data, d);
1457 else
1459 /* reduce precision by 1 because of leading digit before
1460 decimal point in e format, unless specified as 0. */
1461 if (data->precision > 0)
1462 data->precision--;
1463 exponent(data, d);
1465 state = 0;
1466 break;
1467 case 'e':
1468 case 'E': /* Exponent double */
1469 STAR_ARGS(data);
1470 d = GETDOUBLE(data);
1471 exponent(data, d);
1472 state = 0;
1473 break;
1474 # ifdef HAVE_PRINTF_A_FORMAT
1475 case 'a':
1476 case 'A':
1477 STAR_ARGS(data);
1478 d = GETDOUBLE(data);
1479 dfallback(data, convstart, data->pf, d);
1480 state = 0;
1481 break;
1482 # endif /* HAVE_PRINTF_A_FORMAT */
1483 #endif /* FLOATING_POINT */
1484 case 'U':
1485 data->flags |= PF_LONGINT;
1486 /* FALLTHROUGH */
1487 case 'u':
1488 STAR_ARGS(data);
1489 #ifdef HAVE_LONG_LONG
1490 if (data->flags & PF_LONGLONG)
1492 ull = GETARG (unsigned long long);
1493 lnumber(data, ull, 10);
1495 else
1496 #endif
1498 ul = GETUNSIGNED(data);
1499 number(data, ul, 10);
1501 state = 0;
1502 break;
1503 case 'D':
1504 data->flags |= PF_LONGINT;
1505 /* FALLTHROUGH */
1506 case 'd': /* decimal */
1507 case 'i':
1508 STAR_ARGS(data);
1509 #ifdef HAVE_LONG_LONG
1510 if (data->flags & PF_LONGLONG)
1512 ull = GETARG (long long);
1513 lnumber(data, ull, 10);
1515 else
1516 #endif
1518 ul = GETSIGNED(data);
1519 number(data, ul, 10);
1521 state = 0;
1522 break;
1523 case 'o': /* octal */
1524 STAR_ARGS(data);
1525 #ifdef HAVE_LONG_LONG
1526 if (data->flags & PF_LONGLONG)
1528 ull = GETARG (unsigned long long);
1529 lnumber(data, ull, 8);
1531 else
1532 #endif
1534 ul = GETUNSIGNED(data);
1535 number(data, ul, 8);
1537 state = 0;
1538 break;
1539 case 'x':
1540 case 'X': /* hexadecimal */
1541 STAR_ARGS(data);
1542 #ifdef HAVE_LONG_LONG
1543 if (data->flags & PF_LONGLONG)
1545 ull = GETARG (unsigned long long);
1546 lnumber(data, ull, 16);
1548 else
1549 #endif
1551 ul = GETUNSIGNED(data);
1552 number(data, ul, 16);
1554 state = 0;
1555 break;
1556 case 'p':
1557 STAR_ARGS(data);
1558 ul = (unsigned long)GETARG (void *);
1559 pointer(data, ul);
1560 state = 0;
1561 break;
1562 #if HANDLE_MULTIBYTE
1563 case 'C':
1564 data->flags |= PF_LONGINT;
1565 /* FALLTHROUGH */
1566 #endif
1567 case 'c': /* character */
1568 STAR_ARGS(data);
1569 #if HANDLE_MULTIBYTE
1570 if (data->flags & PF_LONGINT)
1572 wc = GETARG (wint_t);
1573 wchars (data, wc);
1575 else
1576 #endif
1578 ul = GETARG (int);
1579 PUT_CHAR(ul, data);
1581 state = 0;
1582 break;
1583 #if HANDLE_MULTIBYTE
1584 case 'S':
1585 data->flags |= PF_LONGINT;
1586 /* FALLTHROUGH */
1587 #endif
1588 case 's': /* string */
1589 STAR_ARGS(data);
1590 #if HANDLE_MULTIBYTE
1591 if (data->flags & PF_LONGINT)
1593 ws = GETARG (wchar_t *);
1594 wstrings (data, ws);
1596 else
1597 #endif
1599 s = GETARG (char *);
1600 strings(data, s);
1602 state = 0;
1603 break;
1604 case 'n':
1605 #ifdef HAVE_LONG_LONG
1606 if (data->flags & PF_LONGLONG)
1607 *(GETARG (long long *)) = data->counter;
1608 else
1609 #endif
1610 if (data->flags & PF_LONGINT)
1611 *(GETARG (long *)) = data->counter;
1612 else if (data->flags & PF_SHORTINT)
1613 *(GETARG (short *)) = data->counter;
1614 else
1615 *(GETARG (int *)) = data->counter;
1616 state = 0;
1617 break;
1618 case '%': /* nothing just % */
1619 PUT_CHAR('%', data);
1620 state = 0;
1621 break;
1622 default:
1623 /* is this an error ? maybe bail out */
1624 state = 0;
1625 break;
1626 } /* end switch */
1627 } /* end of `%' for loop */
1628 } /* end of format string for loop */
1630 if (data->length >= 0)
1631 *data->holder = '\0'; /* the end ye ! */
1633 return data->counter;
1636 #if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE)
1638 * Printing floating point numbers accurately is an art. I'm not good
1639 * at it. Fall back to sprintf for long double formats.
1641 static void
1642 ldfallback (data, fs, fe, ld)
1643 struct DATA *data;
1644 const char *fs, *fe;
1645 long double ld;
1647 register char *x;
1648 char fmtbuf[FALLBACK_FMTSIZE], *obuf;
1649 int fl;
1651 fl = LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2;
1652 obuf = (char *)xmalloc (fl);
1653 fl = fe - fs + 1;
1654 strncpy (fmtbuf, fs, fl);
1655 fmtbuf[fl] = '\0';
1657 if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P))
1658 sprintf (obuf, fmtbuf, data->width, data->precision, ld);
1659 else if (data->flags & PF_STAR_W)
1660 sprintf (obuf, fmtbuf, data->width, ld);
1661 else if (data->flags & PF_STAR_P)
1662 sprintf (obuf, fmtbuf, data->precision, ld);
1663 else
1664 sprintf (obuf, fmtbuf, ld);
1666 for (x = obuf; *x; x++)
1667 PUT_CHAR (*x, data);
1668 xfree (obuf);
1670 #endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */
1672 #ifdef FLOATING_POINT
1673 /* Used for %a, %A if the libc printf supports them. */
1674 static void
1675 dfallback (data, fs, fe, d)
1676 struct DATA *data;
1677 const char *fs, *fe;
1678 double d;
1680 register char *x;
1681 char fmtbuf[FALLBACK_FMTSIZE], obuf[FALLBACK_BASE];
1682 int fl;
1684 fl = fe - fs + 1;
1685 strncpy (fmtbuf, fs, fl);
1686 fmtbuf[fl] = '\0';
1688 if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P))
1689 sprintf (obuf, fmtbuf, data->width, data->precision, d);
1690 else if (data->flags & PF_STAR_W)
1691 sprintf (obuf, fmtbuf, data->width, d);
1692 else if (data->flags & PF_STAR_P)
1693 sprintf (obuf, fmtbuf, data->precision, d);
1694 else
1695 sprintf (obuf, fmtbuf, d);
1697 for (x = obuf; *x; x++)
1698 PUT_CHAR (*x, data);
1700 #endif /* FLOATING_POINT */
1702 #if !HAVE_SNPRINTF
1705 #if defined (__STDC__)
1706 vsnprintf(char *string, size_t length, const char *format, va_list args)
1707 #else
1708 vsnprintf(string, length, format, args)
1709 char *string;
1710 size_t length;
1711 const char *format;
1712 va_list args;
1713 #endif
1715 struct DATA data;
1717 if (string == 0 && length != 0)
1718 return 0;
1719 init_data (&data, string, length, format, PFM_SN);
1720 return (vsnprintf_internal(&data, string, length, format, args));
1724 #if defined(PREFER_STDARG)
1725 snprintf(char *string, size_t length, const char * format, ...)
1726 #else
1727 snprintf(string, length, format, va_alist)
1728 char *string;
1729 size_t length;
1730 const char *format;
1731 va_dcl
1732 #endif
1734 struct DATA data;
1735 int rval;
1736 va_list args;
1738 SH_VA_START(args, format);
1740 if (string == 0 && length != 0)
1741 return 0;
1742 init_data (&data, string, length, format, PFM_SN);
1743 rval = vsnprintf_internal (&data, string, length, format, args);
1745 va_end(args);
1747 return rval;
1750 #endif /* HAVE_SNPRINTF */
1752 #if !HAVE_ASPRINTF
1755 #if defined (__STDC__)
1756 vasprintf(char **stringp, const char *format, va_list args)
1757 #else
1758 vasprintf(stringp, format, args)
1759 char **stringp;
1760 const char *format;
1761 va_list args;
1762 #endif
1764 struct DATA data;
1765 char *string;
1766 int r;
1768 string = (char *)xmalloc(ASBUFSIZE);
1769 init_data (&data, string, ASBUFSIZE, format, PFM_AS);
1770 r = vsnprintf_internal(&data, string, ASBUFSIZE, format, args);
1771 *stringp = data.base; /* not string in case reallocated */
1772 return r;
1776 #if defined(PREFER_STDARG)
1777 asprintf(char **stringp, const char * format, ...)
1778 #else
1779 asprintf(stringp, format, va_alist)
1780 char **stringp;
1781 const char *format;
1782 va_dcl
1783 #endif
1785 int rval;
1786 va_list args;
1788 SH_VA_START(args, format);
1790 rval = vasprintf (stringp, format, args);
1792 va_end(args);
1794 return rval;
1797 #endif /* !HAVE_ASPRINTF */
1799 #endif /* !HAVE_SNPRINTF || !HAVE_ASPRINTF */
1801 #ifdef DRIVER
1803 static void
1804 memory_error_and_abort ()
1806 write (2, "out of virtual memory\n", 22);
1807 abort ();
1810 static void *
1811 xmalloc(bytes)
1812 size_t bytes;
1814 void *ret;
1816 ret = malloc(bytes);
1817 if (ret == 0)
1818 memory_error_and_abort ();
1819 return ret;
1822 static void *
1823 xrealloc (pointer, bytes)
1824 void *pointer;
1825 size_t bytes;
1827 void *ret;
1829 ret = pointer ? realloc(pointer, bytes) : malloc(bytes);
1830 if (ret == 0)
1831 memory_error_and_abort ();
1832 return ret;
1835 static void
1836 xfree(x)
1837 void *x;
1839 if (x)
1840 free (x);
1843 /* set of small tests for snprintf() */
1844 main()
1846 char holder[100];
1847 char *h;
1848 int i, si, ai;
1850 #ifdef HAVE_LOCALE_H
1851 setlocale(LC_ALL, "");
1852 #endif
1854 #if 1
1855 si = snprintf((char *)NULL, 0, "abcde\n");
1856 printf("snprintf returns %d with NULL first argument and size of 0\n", si);
1857 si = snprintf(holder, 0, "abcde\n");
1858 printf("snprintf returns %d with non-NULL first argument and size of 0\n", si);
1859 si = snprintf((char *)NULL, 16, "abcde\n");
1860 printf("snprintf returns %d with NULL first argument and non-zero size\n", si);
1863 printf("Suite of test for snprintf:\n");
1864 printf("a_format\n");
1865 printf("printf() format\n");
1866 printf("snprintf() format\n\n");
1868 /* Checking the field widths */
1870 printf("/%%ld %%ld/, 336, 336\n");
1871 snprintf(holder, sizeof holder, "/%ld %ld/\n", 336, 336);
1872 asprintf(&h, "/%ld %ld/\n", 336, 336);
1873 printf("/%ld %ld/\n", 336, 336);
1874 printf("%s", holder);
1875 printf("%s\n", h);
1877 printf("/%%d/, 336\n");
1878 snprintf(holder, sizeof holder, "/%d/\n", 336);
1879 asprintf(&h, "/%d/\n", 336);
1880 printf("/%d/\n", 336);
1881 printf("%s", holder);
1882 printf("%s\n", h);
1884 printf("/%%2d/, 336\n");
1885 snprintf(holder, sizeof holder, "/%2d/\n", 336);
1886 asprintf(&h, "/%2d/\n", 336);
1887 printf("/%2d/\n", 336);
1888 printf("%s", holder);
1889 printf("%s\n", h);
1891 printf("/%%10d/, 336\n");
1892 snprintf(holder, sizeof holder, "/%10d/\n", 336);
1893 asprintf(&h, "/%10d/\n", 336);
1894 printf("/%10d/\n", 336);
1895 printf("%s", holder);
1896 printf("%s\n", h);
1898 printf("/%%-10d/, 336\n");
1899 snprintf(holder, sizeof holder, "/%-10d/\n", 336);
1900 asprintf(&h, "/%-10d/\n", 336);
1901 printf("/%-10d/\n", 336);
1902 printf("%s", holder);
1903 printf("%s\n", h);
1906 /* floating points */
1908 printf("/%%f/, 1234.56\n");
1909 snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
1910 asprintf(&h, "/%f/\n", 1234.56);
1911 printf("/%f/\n", 1234.56);
1912 printf("%s", holder);
1913 printf("%s\n", h);
1915 printf("/%%e/, 1234.56\n");
1916 snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
1917 asprintf(&h, "/%e/\n", 1234.56);
1918 printf("/%e/\n", 1234.56);
1919 printf("%s", holder);
1920 printf("%s\n", h);
1922 printf("/%%4.2f/, 1234.56\n");
1923 snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
1924 asprintf(&h, "/%4.2f/\n", 1234.56);
1925 printf("/%4.2f/\n", 1234.56);
1926 printf("%s", holder);
1927 printf("%s\n", h);
1929 printf("/%%3.1f/, 1234.56\n");
1930 snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
1931 asprintf(&h, "/%3.1f/\n", 1234.56);
1932 printf("/%3.1f/\n", 1234.56);
1933 printf("%s", holder);
1934 printf("%s\n", h);
1936 printf("/%%10.3f/, 1234.56\n");
1937 snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
1938 asprintf(&h, "/%10.3f/\n", 1234.56);
1939 printf("/%10.3f/\n", 1234.56);
1940 printf("%s", holder);
1941 printf("%s\n", h);
1943 printf("/%%10.3e/, 1234.56\n");
1944 snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
1945 asprintf(&h, "/%10.3e/\n", 1234.56);
1946 printf("/%10.3e/\n", 1234.56);
1947 printf("%s", holder);
1948 printf("%s\n", h);
1950 printf("/%%+4.2f/, 1234.56\n");
1951 snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
1952 asprintf(&h, "/%+4.2f/\n", 1234.56);
1953 printf("/%+4.2f/\n", 1234.56);
1954 printf("%s", holder);
1955 printf("%s\n", h);
1957 printf("/%%010.2f/, 1234.56\n");
1958 snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
1959 asprintf(&h, "/%010.2f/\n", 1234.56);
1960 printf("/%010.2f/\n", 1234.56);
1961 printf("%s", holder);
1962 printf("%s\n", h);
1964 #define BLURB "Outstanding acting !"
1965 /* strings precisions */
1967 printf("/%%2s/, \"%s\"\n", BLURB);
1968 snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
1969 asprintf(&h, "/%2s/\n", BLURB);
1970 printf("/%2s/\n", BLURB);
1971 printf("%s", holder);
1972 printf("%s\n", h);
1974 printf("/%%22s/ %s\n", BLURB);
1975 snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
1976 asprintf(&h, "/%22s/\n", BLURB);
1977 printf("/%22s/\n", BLURB);
1978 printf("%s", holder);
1979 printf("%s\n", h);
1981 printf("/%%22.5s/ %s\n", BLURB);
1982 snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
1983 asprintf(&h, "/%22.5s/\n", BLURB);
1984 printf("/%22.5s/\n", BLURB);
1985 printf("%s", holder);
1986 printf("%s\n", h);
1988 printf("/%%-22.5s/ %s\n", BLURB);
1989 snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
1990 asprintf(&h, "/%-22.5s/\n", BLURB);
1991 printf("/%-22.5s/\n", BLURB);
1992 printf("%s", holder);
1993 printf("%s\n", h);
1995 /* see some flags */
1997 printf("%%x %%X %%#x, 31, 31, 31\n");
1998 snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
1999 asprintf(&h, "%x %X %#x\n", 31, 31, 31);
2000 printf("%x %X %#x\n", 31, 31, 31);
2001 printf("%s", holder);
2002 printf("%s\n", h);
2004 printf("**%%d**%% d**%% d**, 42, 42, -42\n");
2005 snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
2006 asprintf(&h, "**%d**% d**% d**\n", 42, 42, -42);
2007 printf("**%d**% d**% d**\n", 42, 42, -42);
2008 printf("%s", holder);
2009 printf("%s\n", h);
2011 /* other flags */
2013 printf("/%%g/, 31.4\n");
2014 snprintf(holder, sizeof holder, "/%g/\n", 31.4);
2015 asprintf(&h, "/%g/\n", 31.4);
2016 printf("/%g/\n", 31.4);
2017 printf("%s", holder);
2018 printf("%s\n", h);
2020 printf("/%%.6g/, 31.4\n");
2021 snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
2022 asprintf(&h, "/%.6g/\n", 31.4);
2023 printf("/%.6g/\n", 31.4);
2024 printf("%s", holder);
2025 printf("%s\n", h);
2027 printf("/%%.1G/, 31.4\n");
2028 snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
2029 asprintf(&h, "/%.1G/\n", 31.4);
2030 printf("/%.1G/\n", 31.4);
2031 printf("%s", holder);
2032 printf("%s\n", h);
2034 printf("/%%.1G/, 3100000000.4\n");
2035 snprintf(holder, sizeof holder, "/%.1G/\n", 3100000000.4);
2036 asprintf(&h, "/%.1G/\n", 3100000000.4);
2037 printf("/%.1G/\n", 3100000000.4);
2038 printf("%s", holder);
2039 printf("%s\n", h);
2041 printf("abc%%n\n");
2042 printf("abc%n", &i); printf("%d\n", i);
2043 snprintf(holder, sizeof holder, "abc%n", &i);
2044 printf("%s", holder); printf("%d\n\n", i);
2045 asprintf(&h, "abc%n", &i);
2046 printf("%s", h); printf("%d\n\n", i);
2048 printf("%%*.*s --> 10.10\n");
2049 snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
2050 asprintf(&h, "%*.*s\n", 10, 10, BLURB);
2051 printf("%*.*s\n", 10, 10, BLURB);
2052 printf("%s", holder);
2053 printf("%s\n", h);
2055 printf("%%%%%%%%\n");
2056 snprintf(holder, sizeof holder, "%%%%\n");
2057 asprintf(&h, "%%%%\n");
2058 printf("%%%%\n");
2059 printf("%s", holder);
2060 printf("%s\n", h);
2062 #define BIG "Hello this is a too big string for the buffer"
2063 /* printf("A buffer to small of 10, trying to put this:\n");*/
2064 printf("<%%>, %s\n", BIG);
2065 i = snprintf(holder, 10, "%s\n", BIG);
2066 i = asprintf(&h, "%s", BIG);
2067 printf("<%s>\n", BIG);
2068 printf("<%s>\n", holder);
2069 printf("<%s>\n\n", h);
2071 printf ("<%%p> vsnprintf\n");
2072 i = snprintf(holder, 100, "%p", vsnprintf);
2073 i = asprintf(&h, "%p", vsnprintf);
2074 printf("<%p>\n", vsnprintf);
2075 printf("<%s>\n", holder);
2076 printf("<%s>\n\n", h);
2078 printf ("<%%lu> LONG_MAX+1\n");
2079 i = snprintf(holder, 100, "%lu", (unsigned long)(LONG_MAX)+1);
2080 i = asprintf(&h, "%lu", (unsigned long)(LONG_MAX)+1);
2081 printf("<%lu>\n", (unsigned long)(LONG_MAX)+1);
2082 printf("<%s>\n", holder);
2083 printf("<%s>\n\n", h);
2085 #ifdef HAVE_LONG_LONG
2086 printf ("<%%llu> LLONG_MAX+1\n");
2087 i = snprintf(holder, 100, "%llu", (unsigned long long)(LLONG_MAX)+1);
2088 i = asprintf(&h, "%llu", (unsigned long long)(LLONG_MAX)+1);
2089 printf("<%llu>\n", (unsigned long long)(LLONG_MAX)+1);
2090 printf("<%s>\n", holder);
2091 printf("<%s>\n\n", h);
2092 #endif
2094 #ifdef HAVE_LONG_DOUBLE
2095 printf ("<%%6.2LE> 42.42\n");
2096 i = snprintf(holder, 100, "%6.2LE", (long double)42.42);
2097 i = asprintf(&h, "%6.2LE", (long double)42.42);
2098 printf ("<%6.2LE>\n", (long double)42.42);
2099 printf ("<%s>\n", holder);
2100 printf ("<%s>\n\n", h);
2101 #endif
2103 #ifdef HAVE_PRINTF_A_FORMAT
2104 printf ("<%%6.2A> 42.42\n");
2105 i = snprintf(holder, 100, "%6.2A", 42.42);
2106 i = asprintf(&h, "%6.2A", 42.42);
2107 printf ("<%6.2A>\n", 42.42);
2108 printf ("<%s>\n", holder);
2109 printf ("<%s>\n\n", h);
2111 printf ("<%%6.2LA> 42.42\n");
2112 i = snprintf(holder, 100, "%6.2LA", (long double)42.42);
2113 i = asprintf(&h, "%6.2LA", (long double)42.42);
2114 printf ("<%6.2LA>\n", (long double)42.42);
2115 printf ("<%s>\n", holder);
2116 printf ("<%s>\n\n", h);
2117 #endif
2119 printf ("<%%.10240f> DBL_MAX\n");
2120 si = snprintf(holder, 100, "%.10240f", DBL_MAX);
2121 ai = asprintf(&h, "%.10240f", DBL_MAX);
2122 printf ("<%.10240f>\n", DBL_MAX);
2123 printf ("<%d> <%s>\n", si, holder);
2124 printf ("<%d> <%s>\n\n", ai, h);
2126 printf ("<%%.10240Lf> LDBL_MAX\n");
2127 si = snprintf(holder, 100, "%.10240Lf", (long double)LDBL_MAX);
2128 ai = asprintf(&h, "%.10240Lf", (long double)LDBL_MAX);
2129 printf ("<%.10240Lf>\n", (long double)LDBL_MAX);
2130 printf ("<%d> <%s>\n", si, holder);
2131 printf ("<%d> <%s>\n\n", ai, h);
2133 /* huh? */
2134 printf("/%%g/, 421.2345\n");
2135 snprintf(holder, sizeof holder, "/%g/\n", 421.2345);
2136 asprintf(&h, "/%g/\n", 421.2345);
2137 printf("/%g/\n", 421.2345);
2138 printf("%s", holder);
2139 printf("%s\n", h);
2141 printf("/%%g/, 4214.2345\n");
2142 snprintf(holder, sizeof holder, "/%g/\n", 4214.2345);
2143 asprintf(&h, "/%g/\n", 4214.2345);
2144 printf("/%g/\n", 4214.2345);
2145 printf("%s", holder);
2146 printf("%s\n", h);
2148 printf("/%%.5g/, 4214.2345\n");
2149 snprintf(holder, sizeof holder, "/%.5g/\n", 4214.2345);
2150 asprintf(&h, "/%.5g/\n", 4214.2345);
2151 printf("/%.5g/\n", 4214.2345);
2152 printf("%s", holder);
2153 printf("%s\n", h);
2155 printf("/%%.4g/, 4214.2345\n");
2156 snprintf(holder, sizeof holder, "/%.4g/\n", 4214.2345);
2157 asprintf(&h, "/%.4g/\n", 4214.2345);
2158 printf("/%.4g/\n", 4214.2345);
2159 printf("%s", holder);
2160 printf("%s\n", h);
2162 printf("/%%'ld %%'ld/, 12345, 1234567\n");
2163 snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 12345, 1234567);
2164 asprintf(&h, "/%'ld %'ld/\n", 12345, 1234567);
2165 printf("/%'ld %'ld/\n", 12345, 1234567);
2166 printf("%s", holder);
2167 printf("%s\n", h);
2169 printf("/%%'ld %%'ld/, 336, 3336\n");
2170 snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 336, 3336);
2171 asprintf(&h, "/%'ld %'ld/\n", 336, 3336);
2172 printf("/%'ld %'ld/\n", 336, 3336);
2173 printf("%s", holder);
2174 printf("%s\n", h);
2176 printf("/%%'ld %%'ld/, -42786, -142786\n");
2177 snprintf(holder, sizeof holder, "/%'ld %'ld/\n", -42786, -142786);
2178 asprintf(&h, "/%'ld %'ld/\n", -42786, -142786);
2179 printf("/%'ld %'ld/\n", -42786, -142786);
2180 printf("%s", holder);
2181 printf("%s\n", h);
2183 printf("/%%'f %%'f/, 421.2345, 421234.56789\n");
2184 snprintf(holder, sizeof holder, "/%'f %'f/\n", 421.2345, 421234.56789);
2185 asprintf(&h, "/%'f %'f/\n", 421.2345, 421234.56789);
2186 printf("/%'f %'f/\n", 421.2345, 421234.56789);
2187 printf("%s", holder);
2188 printf("%s\n", h);
2190 printf("/%%'f %%'f/, -421.2345, -421234.56789\n");
2191 snprintf(holder, sizeof holder, "/%'f %'f/\n", -421.2345, -421234.56789);
2192 asprintf(&h, "/%'f %'f/\n", -421.2345, -421234.56789);
2193 printf("/%'f %'f/\n", -421.2345, -421234.56789);
2194 printf("%s", holder);
2195 printf("%s\n", h);
2197 printf("/%%'g %%'g/, 421.2345, 421234.56789\n");
2198 snprintf(holder, sizeof holder, "/%'g %'g/\n", 421.2345, 421234.56789);
2199 asprintf(&h, "/%'g %'g/\n", 421.2345, 421234.56789);
2200 printf("/%'g %'g/\n", 421.2345, 421234.56789);
2201 printf("%s", holder);
2202 printf("%s\n", h);
2204 printf("/%%'g %%'g/, -421.2345, -421234.56789\n");
2205 snprintf(holder, sizeof holder, "/%'g %'g/\n", -421.2345, -421234.56789);
2206 asprintf(&h, "/%'g %'g/\n", -421.2345, -421234.56789);
2207 printf("/%'g %'g/\n", -421.2345, -421234.56789);
2208 printf("%s", holder);
2209 printf("%s\n", h);
2210 #endif
2212 printf("/%%'g/, 4213455.8392\n");
2213 snprintf(holder, sizeof holder, "/%'g/\n", 4213455.8392);
2214 asprintf(&h, "/%'g/\n", 4213455.8392);
2215 printf("/%'g/\n", 4213455.8392);
2216 printf("%s", holder);
2217 printf("%s\n", h);
2219 exit (0);
2221 #endif