]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/sh/snprintf.c
Imported from ../bash-3.2.48.tar.gz.
[thirdparty/bash.git] / lib / sh / snprintf.c
1 /*
2 build a test version with
3 gcc -g -DDRIVER -I../.. -I../../include -o test-snprintf snprintf.c fmtu*long.o
4 */
5
6 /*
7 Unix snprintf implementation.
8 derived from inetutils/libinetutils/snprintf.c Version 1.1
9
10 Copyright (C) 2001 Free Software Foundation, Inc.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General License for more details.
21
22 You should have received a copy of the GNU General License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26 Revision History:
27
28 1.1:
29 * added changes from Miles Bader
30 * corrected a bug with %f
31 * added support for %#g
32 * added more comments :-)
33 1.0:
34 * supporting must ANSI syntaxic_sugars
35 0.0:
36 * support %s %c %d
37
38 THANKS(for the patches and ideas):
39 Miles Bader
40 Cyrille Rustom
41 Jacek Slabocewiz
42 Mike Parker(mouse)
43
44 */
45
46 /*
47 * Currently doesn't handle (and bash/readline doesn't use):
48 * * *M$ width, precision specifications
49 * * %N$ numbered argument conversions
50 * * inf, nan floating values imperfect (if isinf(), isnan() not in libc)
51 * * support for `F' is imperfect with ldfallback(), since underlying
52 * printf may not handle it -- should ideally have another autoconf test
53 */
54
55 #define FLOATING_POINT
56
57 #ifdef HAVE_CONFIG_H
58 # include <config.h>
59 #endif
60
61 #if defined(DRIVER) && !defined(HAVE_CONFIG_H)
62 #define HAVE_LONG_LONG
63 #define HAVE_LONG_DOUBLE
64 #ifdef __linux__
65 #define HAVE_PRINTF_A_FORMAT
66 #endif
67 #define HAVE_ISINF_IN_LIBC
68 #define HAVE_ISNAN_IN_LIBC
69 #define PREFER_STDARG
70 #define HAVE_STRINGIZE
71 #define HAVE_LIMITS_H
72 #define HAVE_STDDEF_H
73 #define HAVE_LOCALE_H
74 #define intmax_t long
75 #endif
76
77 #if !defined (HAVE_SNPRINTF) || !defined (HAVE_ASPRINTF)
78
79 #include <bashtypes.h>
80
81 #if defined(PREFER_STDARG)
82 # include <stdarg.h>
83 #else
84 # include <varargs.h>
85 #endif
86
87 #ifdef HAVE_LIMITS_H
88 # include <limits.h>
89 #endif
90 #include <bashansi.h>
91 #ifdef HAVE_STDDEF_H
92 # include <stddef.h>
93 #endif
94 #include <chartypes.h>
95
96 #ifdef HAVE_STDINT_H
97 # include <stdint.h>
98 #endif
99
100 #ifdef FLOATING_POINT
101 # include <float.h> /* for manifest constants */
102 # include <stdio.h> /* for sprintf */
103 #endif
104
105 #include <typemax.h>
106
107 #ifdef HAVE_LOCALE_H
108 # include <locale.h>
109 #endif
110
111 #include "stdc.h"
112 #include <shmbutil.h>
113
114 #ifndef DRIVER
115 # include "shell.h"
116 #else
117 # define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */
118 # define FL_ADDBASE 0x02 /* add base# prefix to converted value */
119 # define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */
120 # define FL_UNSIGNED 0x08 /* don't add any sign */
121 extern char *fmtulong __P((unsigned long int, int, char *, size_t, int));
122 extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
123 #endif
124
125 #ifndef FREE
126 # define FREE(x) if (x) free (x)
127 #endif
128
129 /* Bound on length of the string representing an integer value of type T.
130 Subtract one for the sign bit if T is signed;
131 302 / 1000 is log10 (2) rounded up;
132 add one for integer division truncation;
133 add one more for a minus sign if t is signed. */
134 #define INT_STRLEN_BOUND(t) \
135 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
136 + 1 + TYPE_SIGNED (t))
137
138 /* conversion flags */
139 #define PF_ALTFORM 0x00001 /* # */
140 #define PF_HEXPREFIX 0x00002 /* 0[Xx] */
141 #define PF_LADJUST 0x00004 /* - */
142 #define PF_ZEROPAD 0x00008 /* 0 */
143 #define PF_PLUS 0x00010 /* + */
144 #define PF_SPACE 0x00020 /* ' ' */
145 #define PF_THOUSANDS 0x00040 /* ' */
146
147 #define PF_DOT 0x00080 /* `.precision' */
148 #define PF_STAR_P 0x00100 /* `*' after precision */
149 #define PF_STAR_W 0x00200 /* `*' before or without precision */
150
151 /* length modifiers */
152 #define PF_SIGNEDCHAR 0x00400 /* hh */
153 #define PF_SHORTINT 0x00800 /* h */
154 #define PF_LONGINT 0x01000 /* l */
155 #define PF_LONGLONG 0x02000 /* ll */
156 #define PF_LONGDBL 0x04000 /* L */
157 #define PF_INTMAX_T 0x08000 /* j */
158 #define PF_SIZE_T 0x10000 /* z */
159 #define PF_PTRDIFF_T 0x20000 /* t */
160
161 #define PF_ALLOCBUF 0x40000 /* for asprintf, vasprintf */
162
163 #define PFM_SN 0x01 /* snprintf, vsnprintf */
164 #define PFM_AS 0x02 /* asprintf, vasprintf */
165
166 #define ASBUFSIZE 128
167
168 #define x_digs "0123456789abcdef"
169 #define X_digs "0123456789ABCDEF"
170
171 static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1];
172
173 static int decpoint;
174 static int thoussep;
175 static char *grouping;
176
177 /*
178 * For the FLOATING POINT FORMAT :
179 * the challenge was finding a way to
180 * manipulate the Real numbers without having
181 * to resort to mathematical function(it
182 * would require to link with -lm) and not
183 * going down to the bit pattern(not portable)
184 *
185 * so a number, a real is:
186
187 real = integral + fraction
188
189 integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
190 fraction = b(1)*10^-1 + b(2)*10^-2 + ...
191
192 where:
193 0 <= a(i) => 9
194 0 <= b(i) => 9
195
196 from then it was simple math
197 */
198
199 /*
200 * size of the buffer for the integral part
201 * and the fraction part
202 */
203 #define MAX_INT 99 + 1 /* 1 for the null */
204 #define MAX_FRACT 307 + 1
205
206 /*
207 * These functions use static buffers to store the results,
208 * and so are not reentrant
209 */
210 #define itoa(n) fmtulong(n, 10, intbuf, sizeof(intbuf), 0);
211 #define dtoa(n, p, f) numtoa(n, 10, p, f)
212
213 #define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
214
215 #define GETARG(type) (va_arg(args, type))
216
217 /* Macros that do proper sign extension and handle length modifiers. Used
218 for the integer conversion specifiers. */
219 #define GETSIGNED(p) \
220 (((p)->flags & PF_LONGINT) \
221 ? GETARG (long) \
222 : (((p)->flags & PF_SHORTINT) ? (long)(short)GETARG (int) \
223 : (long)GETARG (int)))
224
225 #define GETUNSIGNED(p) \
226 (((p)->flags & PF_LONGINT) \
227 ? GETARG (unsigned long) \
228 : (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)GETARG (int) \
229 : (unsigned long)GETARG (unsigned int)))
230
231
232 #ifdef HAVE_LONG_DOUBLE
233 #define GETLDOUBLE(p) GETARG (long double)
234 #endif
235 #define GETDOUBLE(p) GETARG (double)
236
237 #define SET_SIZE_FLAGS(p, type) \
238 if (sizeof (type) > sizeof (int)) \
239 (p)->flags |= PF_LONGINT; \
240 if (sizeof (type) > sizeof (long)) \
241 (p)->flags |= PF_LONGLONG;
242
243 /* this struct holds everything we need */
244 struct DATA
245 {
246 int length;
247 char *base; /* needed for [v]asprintf */
248 char *holder;
249 int counter;
250 const char *pf;
251
252 /* FLAGS */
253 int flags;
254 int justify;
255 int width, precision;
256 char pad;
257 };
258
259 /* the floating point stuff */
260 #ifdef FLOATING_POINT
261 static double pow_10 __P((int));
262 static int log_10 __P((double));
263 static double integral __P((double, double *));
264 static char *numtoa __P((double, int, int, char **));
265 #endif
266
267 static void init_data __P((struct DATA *, char *, size_t, const char *, int));
268 static void init_conv_flag __P((struct DATA *));
269
270 /* for the format */
271 #ifdef FLOATING_POINT
272 static void floating __P((struct DATA *, double));
273 static void exponent __P((struct DATA *, double));
274 #endif
275 static void number __P((struct DATA *, unsigned long, int));
276 #ifdef HAVE_LONG_LONG
277 static void lnumber __P((struct DATA *, unsigned long long, int));
278 #endif
279 static void pointer __P((struct DATA *, unsigned long));
280 static void strings __P((struct DATA *, char *));
281
282 #ifdef FLOATING_POINT
283 # define FALLBACK_FMTSIZE 32
284 # define FALLBACK_BASE 4096
285 # define LFALLBACK_BASE 5120
286 # ifdef HAVE_LONG_DOUBLE
287 static void ldfallback __P((struct DATA *, const char *, const char *, long double));
288 # endif
289 static void dfallback __P((struct DATA *, const char *, const char *, double));
290 #endif
291
292 static char *groupnum __P((char *));
293
294 #ifdef DRIVER
295 static void memory_error_and_abort ();
296 static void *xmalloc __P((size_t));
297 static void *xrealloc __P((void *, size_t));
298 static void xfree __P((void *));
299 #else
300 # include <xmalloc.h>
301 #endif
302
303 /* those are defines specific to snprintf to hopefully
304 * make the code clearer :-)
305 */
306 #define RIGHT 1
307 #define LEFT 0
308 #define NOT_FOUND -1
309 #define FOUND 1
310 #define MAX_FIELD 15
311
312 /* round off to the precision */
313 #define ROUND(d, p) \
314 (d < 0.) ? \
315 d - pow_10(-(p)->precision) * 0.5 : \
316 d + pow_10(-(p)->precision) * 0.5
317
318 /* set default precision */
319 #define DEF_PREC(p) \
320 if ((p)->precision == NOT_FOUND) \
321 (p)->precision = 6
322
323 /* put a char. increment the number of chars written even if we've exceeded
324 the vsnprintf/snprintf buffer size (for the return value) */
325 #define PUT_CHAR(c, p) \
326 do \
327 { \
328 if (((p)->flags & PF_ALLOCBUF) && ((p)->counter >= (p)->length - 1)) \
329 { \
330 (p)->length += ASBUFSIZE; \
331 (p)->base = (char *)xrealloc((p)->base, (p)->length); \
332 (p)->holder = (p)->base + (p)->counter; /* in case reallocated */ \
333 } \
334 if ((p)->counter < (p)->length) \
335 *(p)->holder++ = (c); \
336 (p)->counter++; \
337 } \
338 while (0)
339
340 /* Output a string. P->WIDTH has already been adjusted for padding. */
341 #define PUT_STRING(string, len, p) \
342 do \
343 { \
344 PAD_RIGHT (p); \
345 while ((len)-- > 0) \
346 { \
347 PUT_CHAR (*(string), (p)); \
348 (string)++; \
349 } \
350 PAD_LEFT (p); \
351 } \
352 while (0)
353
354 #define PUT_PLUS(d, p, zero) \
355 if ((d) > zero && (p)->justify == RIGHT) \
356 PUT_CHAR('+', p)
357
358 #define PUT_SPACE(d, p, zero) \
359 if (((p)->flags & PF_SPACE) && (d) > zero) \
360 PUT_CHAR(' ', p)
361
362 /* pad right */
363 #define PAD_RIGHT(p) \
364 if ((p)->width > 0 && (p)->justify != LEFT) \
365 for (; (p)->width > 0; (p)->width--) \
366 PUT_CHAR((p)->pad, p)
367
368 /* pad left */
369 #define PAD_LEFT(p) \
370 if ((p)->width > 0 && (p)->justify == LEFT) \
371 for (; (p)->width > 0; (p)->width--) \
372 PUT_CHAR((p)->pad, p)
373
374 /* pad with zeros from decimal precision */
375 #define PAD_ZERO(p) \
376 if ((p)->precision > 0) \
377 for (; (p)->precision > 0; (p)->precision--) \
378 PUT_CHAR('0', p)
379
380 /* if width and prec. in the args */
381 #define STAR_ARGS(p) \
382 do { \
383 if ((p)->flags & PF_STAR_W) \
384 { \
385 (p)->width = GETARG (int); \
386 if ((p)->width < 0) \
387 { \
388 (p)->flags |= PF_LADJUST; \
389 (p)->justify = LEFT; \
390 (p)->width = -(p)->width; \
391 } \
392 } \
393 if ((p)->flags & PF_STAR_P) \
394 { \
395 (p)->precision = GETARG (int); \
396 if ((p)->precision < 0) \
397 { \
398 (p)->flags &= ~PF_STAR_P; \
399 (p)->precision = NOT_FOUND; \
400 } \
401 } \
402 } while (0)
403
404 #if defined (HAVE_LOCALE_H)
405 # define GETLOCALEDATA(d, t, g) \
406 do \
407 { \
408 struct lconv *lv; \
409 if ((d) == 0) { \
410 (d) = '.'; (t) = -1; (g) = 0; /* defaults */ \
411 lv = localeconv(); \
412 if (lv) \
413 { \
414 if (lv->decimal_point && lv->decimal_point[0]) \
415 (d) = lv->decimal_point[0]; \
416 if (lv->thousands_sep && lv->thousands_sep[0]) \
417 (t) = lv->thousands_sep[0]; \
418 (g) = lv->grouping ? lv->grouping : ""; \
419 if (*(g) == '\0' || *(g) == CHAR_MAX || (t) == -1) (g) = 0; \
420 } \
421 } \
422 } \
423 while (0);
424 #else
425 # define GETLOCALEDATA(d, t, g) \
426 ( (d) = '.', (t) = ',', g = "\003" )
427 #endif
428
429 #ifdef FLOATING_POINT
430 /*
431 * Find the nth power of 10
432 */
433 static double
434 pow_10(n)
435 int n;
436 {
437 double P;
438
439 /* handle common cases with fast switch statement. */
440 switch (n)
441 {
442 case -3: return .001;
443 case -2: return .01;
444 case -1: return .1;
445 case 0: return 1.;
446 case 1: return 10.;
447 case 2: return 100.;
448 case 3: return 1000.;
449 }
450
451 if (n < 0)
452 {
453 P = .0001;
454 for (n += 4; n < 0; n++)
455 P /= 10.;
456 }
457 else
458 {
459 P = 10000.;
460 for (n -= 4; n > 0; n--)
461 P *= 10.;
462 }
463
464 return P;
465 }
466
467 /*
468 * Find the integral part of the log in base 10
469 * Note: this not a real log10()
470 I just need and approximation(integerpart) of x in:
471 10^x ~= r
472 * log_10(200) = 2;
473 * log_10(250) = 2;
474 *
475 * NOTE: do not call this with r == 0 -- an infinite loop results.
476 */
477 static int
478 log_10(r)
479 double r;
480 {
481 int i = 0;
482 double result = 1.;
483
484 if (r < 0.)
485 r = -r;
486
487 if (r < 1.)
488 {
489 while (result >= r)
490 {
491 result /= 10.;
492 i++;
493 }
494 return (-i);
495 }
496 else
497 {
498 while (result <= r)
499 {
500 result *= 10.;
501 i++;
502 }
503 return (i - 1);
504 }
505 }
506
507 /*
508 * This function return the fraction part of a double
509 * and set in ip the integral part.
510 * In many ways it resemble the modf() found on most Un*x
511 */
512 static double
513 integral(real, ip)
514 double real;
515 double *ip;
516 {
517 int j;
518 double i, s, p;
519 double real_integral = 0.;
520
521 /* take care of the obvious */
522 /* equal to zero ? */
523 if (real == 0.)
524 {
525 *ip = 0.;
526 return (0.);
527 }
528
529 /* negative number ? */
530 if (real < 0.)
531 real = -real;
532
533 /* a fraction ? */
534 if ( real < 1.)
535 {
536 *ip = 0.;
537 return real;
538 }
539
540 /* the real work :-) */
541 for (j = log_10(real); j >= 0; j--)
542 {
543 p = pow_10(j);
544 s = (real - real_integral)/p;
545 i = 0.;
546 while (i + 1. <= s)
547 i++;
548 real_integral += i*p;
549 }
550 *ip = real_integral;
551 return (real - real_integral);
552 }
553
554 #define PRECISION 1.e-6
555 /*
556 * return an ascii representation of the integral part of the number
557 * and set fract to be an ascii representation of the fraction part
558 * the container for the fraction and the integral part or staticly
559 * declare with fix size
560 */
561 static char *
562 numtoa(number, base, precision, fract)
563 double number;
564 int base, precision;
565 char **fract;
566 {
567 register int i, j;
568 double ip, fp; /* integer and fraction part */
569 double fraction;
570 int digits = MAX_INT - 1;
571 static char integral_part[MAX_INT];
572 static char fraction_part[MAX_FRACT];
573 double sign;
574 int ch;
575
576 /* taking care of the obvious case: 0.0 */
577 if (number == 0.)
578 {
579 integral_part[0] = '0';
580 integral_part[1] = '\0';
581 /* The fractional part has to take the precision into account */
582 for (ch = 0; ch < precision-1; ch++)
583 fraction_part[ch] = '0';
584 fraction_part[ch] = '0';
585 fraction_part[ch+1] = '\0';
586 if (fract)
587 *fract = fraction_part;
588 return integral_part;
589 }
590
591 /* for negative numbers */
592 if ((sign = number) < 0.)
593 {
594 number = -number;
595 digits--; /* sign consume one digit */
596 }
597
598 fraction = integral(number, &ip);
599 number = ip;
600
601 /* do the integral part */
602 if (ip == 0.)
603 {
604 integral_part[0] = '0';
605 i = 1;
606 }
607 else
608 {
609 for ( i = 0; i < digits && number != 0.; ++i)
610 {
611 number /= base;
612 fp = integral(number, &ip);
613 ch = (int)((fp + PRECISION)*base); /* force to round */
614 integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
615 if (! ISXDIGIT((unsigned char)integral_part[i]))
616 break; /* bail out overflow !! */
617 number = ip;
618 }
619 }
620
621 /* Oh No !! out of bound, ho well fill it up ! */
622 if (number != 0.)
623 for (i = 0; i < digits; ++i)
624 integral_part[i] = '9';
625
626 /* put the sign ? */
627 if (sign < 0.)
628 integral_part[i++] = '-';
629
630 integral_part[i] = '\0';
631
632 /* reverse every thing */
633 for ( i--, j = 0; j < i; j++, i--)
634 SWAP_INT(integral_part[i], integral_part[j]);
635
636 /* the fractional part */
637 for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision--)
638 {
639 fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
640 if (! DIGIT(fraction_part[i])) /* underflow ? */
641 break;
642 fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
643 }
644 fraction_part[i] = '\0';
645
646 if (fract != (char **)0)
647 *fract = fraction_part;
648
649 return integral_part;
650 }
651 #endif
652
653 /* for %d and friends, it puts in holder
654 * the representation with the right padding
655 */
656 static void
657 number(p, d, base)
658 struct DATA *p;
659 unsigned long d;
660 int base;
661 {
662 char *tmp, *t;
663 long sd;
664 int flags;
665
666 /* An explicit precision turns off the zero-padding flag. */
667 if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT))
668 p->flags &= ~PF_ZEROPAD;
669
670 sd = d; /* signed for ' ' padding in base 10 */
671 flags = 0;
672 flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
673 if (*p->pf == 'X')
674 flags |= FL_HEXUPPER;
675
676 tmp = fmtulong (d, base, intbuf, sizeof(intbuf), flags);
677 t = 0;
678 if ((p->flags & PF_THOUSANDS))
679 {
680 GETLOCALEDATA(decpoint, thoussep, grouping);
681 if (grouping && (t = groupnum (tmp)))
682 tmp = t;
683 }
684
685 p->width -= strlen(tmp);
686 PAD_RIGHT(p);
687
688 if ((p->flags & PF_DOT) && p->precision > 0)
689 {
690 p->precision -= strlen(tmp);
691 PAD_ZERO(p);
692 }
693
694 switch (base)
695 {
696 case 10:
697 PUT_PLUS(sd, p, 0);
698 PUT_SPACE(sd, p, 0);
699 break;
700 case 8:
701 if (p->flags & PF_ALTFORM)
702 PUT_CHAR('0', p);
703 break;
704 case 16:
705 if (p->flags & PF_ALTFORM)
706 {
707 PUT_CHAR('0', p);
708 PUT_CHAR(*p->pf, p);
709 }
710 break;
711 }
712
713 while (*tmp)
714 {
715 PUT_CHAR(*tmp, p);
716 tmp++;
717 }
718
719 PAD_LEFT(p);
720 FREE (t);
721 }
722
723 #ifdef HAVE_LONG_LONG
724 /*
725 * identical to number() but works for `long long'
726 */
727 static void
728 lnumber(p, d, base)
729 struct DATA *p;
730 unsigned long long d;
731 int base;
732 {
733 char *tmp, *t;
734 long long sd;
735 int flags;
736
737 /* An explicit precision turns off the zero-padding flag. */
738 if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT))
739 p->flags &= ~PF_ZEROPAD;
740
741 sd = d; /* signed for ' ' padding in base 10 */
742 flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
743 if (*p->pf == 'X')
744 flags |= FL_HEXUPPER;
745
746 tmp = fmtullong (d, base, intbuf, sizeof(intbuf), flags);
747 t = 0;
748 if ((p->flags & PF_THOUSANDS))
749 {
750 GETLOCALEDATA(decpoint, thoussep, grouping);
751 if (grouping && (t = groupnum (tmp)))
752 tmp = t;
753 }
754
755 p->width -= strlen(tmp);
756 PAD_RIGHT(p);
757
758 if ((p->flags & PF_DOT) && p->precision > 0)
759 {
760 p->precision -= strlen(tmp);
761 PAD_ZERO(p);
762 }
763
764 switch (base)
765 {
766 case 10:
767 PUT_PLUS(sd, p, 0);
768 PUT_SPACE(sd, p, 0);
769 break;
770 case 8:
771 if (p->flags & PF_ALTFORM)
772 PUT_CHAR('0', p);
773 break;
774 case 16:
775 if (p->flags & PF_ALTFORM)
776 {
777 PUT_CHAR('0', p);
778 PUT_CHAR(*p->pf, p);
779 }
780 break;
781 }
782
783 while (*tmp)
784 {
785 PUT_CHAR(*tmp, p);
786 tmp++;
787 }
788
789 PAD_LEFT(p);
790 FREE (t);
791 }
792 #endif
793
794 static void
795 pointer(p, d)
796 struct DATA *p;
797 unsigned long d;
798 {
799 char *tmp;
800
801 tmp = fmtulong(d, 16, intbuf, sizeof(intbuf), 0);
802 p->width -= strlen(tmp);
803 PAD_RIGHT(p);
804
805 /* prefix '0x' for pointers */
806 PUT_CHAR('0', p);
807 PUT_CHAR('x', p);
808
809 while (*tmp)
810 {
811 PUT_CHAR(*tmp, p);
812 tmp++;
813 }
814
815 PAD_LEFT(p);
816 }
817
818 /* %s strings */
819 static void
820 strings(p, tmp)
821 struct DATA *p;
822 char *tmp;
823 {
824 size_t len;
825
826 len = strlen(tmp);
827 if (p->precision != NOT_FOUND) /* the smallest number */
828 len = (len < p->precision ? len : p->precision);
829 p->width -= len;
830
831 PUT_STRING (tmp, len, p);
832 }
833
834 #if HANDLE_MULTIBYTE
835 /* %ls wide-character strings */
836 static void
837 wstrings(p, tmp)
838 struct DATA *p;
839 wchar_t *tmp;
840 {
841 size_t len;
842 mbstate_t mbs;
843 char *os;
844 const wchar_t *ws;
845
846 memset (&mbs, '\0', sizeof (mbstate_t));
847 ws = (const wchar_t *)tmp;
848
849 os = (char *)NULL;
850 if (p->precision != NOT_FOUND)
851 {
852 os = (char *)xmalloc (p->precision + 1);
853 len = wcsrtombs (os, &ws, p->precision, &mbs);
854 }
855 else
856 {
857 len = wcsrtombs (NULL, &ws, 0, &mbs);
858 if (len != (size_t)-1)
859 {
860 memset (&mbs, '\0', sizeof (mbstate_t));
861 os = (char *)xmalloc (len + 1);
862 (void)wcsrtombs (os, &ws, len + 1, &mbs);
863 }
864 }
865 if (len == (size_t)-1)
866 {
867 /* invalid multibyte sequence; bail now. */
868 FREE (os);
869 return;
870 }
871
872 p->width -= len;
873 PUT_STRING (os, len, p);
874 free (os);
875 }
876
877 static void
878 wchars (p, wc)
879 struct DATA *p;
880 wint_t wc;
881 {
882 char *lbuf, *l;
883 mbstate_t mbs;
884 size_t len;
885
886 lbuf = (char *)malloc (MB_CUR_MAX+1);
887 if (lbuf == 0)
888 return;
889 memset (&mbs, '\0', sizeof (mbstate_t));
890 len = wcrtomb (lbuf, wc, &mbs);
891 if (len == (size_t)-1)
892 /* conversion failed; bail now. */
893 return;
894 p->width -= len;
895 l = lbuf;
896 PUT_STRING (l, len, p);
897 free (lbuf);
898 }
899 #endif /* HANDLE_MULTIBYTE */
900
901 #ifdef FLOATING_POINT
902
903 #ifndef HAVE_ISINF_IN_LIBC
904 /* Half-assed versions, since we don't want to link with libm. */
905 static int
906 isinf(d)
907 double d;
908 {
909 #ifdef DBL_MAX
910 if (d < DBL_MIN)
911 return -1;
912 else if (d > DBL_MAX)
913 return 1;
914 else
915 #endif
916 return 0;
917 }
918 #endif
919
920 #ifndef HAVE_ISNAN_IN_LIBC
921 static int
922 isnan(d)
923 double d;
924 {
925 return 0;
926 }
927 #endif
928
929 /* Check for [+-]infinity and NaN. If MODE == 1, we check for Infinity, else
930 (mode == 2) we check for NaN. This does the necessary printing. Returns
931 1 if Inf or Nan, 0 if not. */
932 static int
933 chkinfnan(p, d, mode)
934 struct DATA *p;
935 double d;
936 int mode; /* == 1 for inf, == 2 for nan */
937 {
938 int i;
939 char *tmp;
940 char *big, *small;
941
942 i = (mode == 1) ? isinf(d) : isnan(d);
943 if (i == 0)
944 return 0;
945 big = (mode == 1) ? "INF" : "NAN";
946 small = (mode == 1) ? "inf" : "nan";
947
948 tmp = (*p->pf == 'F' || *p->pf == 'G' || *p->pf == 'E') ? big : small;
949
950 if (i < 0)
951 PUT_CHAR('-', p);
952
953 while (*tmp)
954 {
955 PUT_CHAR (*tmp, p);
956 tmp++;
957 }
958
959 return 1;
960 }
961
962 /* %f %F %g %G floating point representation */
963 static void
964 floating(p, d)
965 struct DATA *p;
966 double d;
967 {
968 char *tmp, *tmp2, *t;
969 int i;
970
971 if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)))
972 return; /* already printed nan or inf */
973
974 GETLOCALEDATA(decpoint, thoussep, grouping);
975 DEF_PREC(p);
976 d = ROUND(d, p);
977 tmp = dtoa(d, p->precision, &tmp2);
978 t = 0;
979 if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp)))
980 tmp = t;
981
982 if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
983 {
984 /* smash the trailing zeros unless altform */
985 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
986 tmp2[i] = '\0';
987 if (tmp2[0] == '\0')
988 p->precision = 0;
989 }
990
991 /* calculate the padding. 1 for the dot */
992 p->width = p->width -
993 ((d > 0. && p->justify == RIGHT) ? 1:0) -
994 ((p->flags & PF_SPACE) ? 1:0) -
995 strlen(tmp) - p->precision -
996 ((p->precision != 0 || (p->flags & PF_ALTFORM)) ? 1 : 0); /* radix char */
997 PAD_RIGHT(p);
998 PUT_PLUS(d, p, 0.);
999 PUT_SPACE(d, p, 0.);
1000
1001 while (*tmp)
1002 {
1003 PUT_CHAR(*tmp, p); /* the integral */
1004 tmp++;
1005 }
1006 FREE (t);
1007
1008 if (p->precision != 0 || (p->flags & PF_ALTFORM))
1009 PUT_CHAR(decpoint, p); /* put the '.' */
1010
1011 for (; *tmp2; tmp2++)
1012 PUT_CHAR(*tmp2, p); /* the fraction */
1013
1014 PAD_LEFT(p);
1015 }
1016
1017 /* %e %E %g %G exponent representation */
1018 static void
1019 exponent(p, d)
1020 struct DATA *p;
1021 double d;
1022 {
1023 char *tmp, *tmp2;
1024 int j, i;
1025
1026 if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)))
1027 return; /* already printed nan or inf */
1028
1029 GETLOCALEDATA(decpoint, thoussep, grouping);
1030 DEF_PREC(p);
1031 if (d == 0.)
1032 j = 0;
1033 else
1034 {
1035 j = log_10(d);
1036 d = d / pow_10(j); /* get the Mantissa */
1037 d = ROUND(d, p);
1038 }
1039 tmp = dtoa(d, p->precision, &tmp2);
1040
1041 /* 1 for unit, 1 for the '.', 1 for 'e|E',
1042 * 1 for '+|-', 2 for 'exp' */
1043 /* calculate how much padding need */
1044 p->width = p->width -
1045 ((d > 0. && p->justify == RIGHT) ? 1:0) -
1046 ((p->flags & PF_SPACE) ? 1:0) - p->precision - 6;
1047
1048 PAD_RIGHT(p);
1049 PUT_PLUS(d, p, 0.);
1050 PUT_SPACE(d, p, 0.);
1051
1052 while (*tmp)
1053 {
1054 PUT_CHAR(*tmp, p);
1055 tmp++;
1056 }
1057
1058 if (p->precision != 0 || (p->flags & PF_ALTFORM))
1059 PUT_CHAR(decpoint, p); /* the '.' */
1060
1061 if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
1062 /* smash the trailing zeros unless altform */
1063 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
1064 tmp2[i] = '\0';
1065
1066 for (; *tmp2; tmp2++)
1067 PUT_CHAR(*tmp2, p); /* the fraction */
1068
1069 /* the exponent put the 'e|E' */
1070 if (*p->pf == 'g' || *p->pf == 'e')
1071 PUT_CHAR('e', p);
1072 else
1073 PUT_CHAR('E', p);
1074
1075 /* the sign of the exp */
1076 if (j >= 0)
1077 PUT_CHAR('+', p);
1078 else
1079 {
1080 PUT_CHAR('-', p);
1081 j = -j;
1082 }
1083
1084 tmp = itoa(j);
1085 /* pad out to at least two spaces. pad with `0' if the exponent is a
1086 single digit. */
1087 if (j <= 9)
1088 PUT_CHAR('0', p);
1089
1090 /* the exponent */
1091 while (*tmp)
1092 {
1093 PUT_CHAR(*tmp, p);
1094 tmp++;
1095 }
1096
1097 PAD_LEFT(p);
1098 }
1099 #endif
1100
1101 /* Return a new string with the digits in S grouped according to the locale's
1102 grouping info and thousands separator. If no grouping should be performed,
1103 this returns NULL; the caller needs to check for it. */
1104 static char *
1105 groupnum (s)
1106 char *s;
1107 {
1108 char *se, *ret, *re, *g;
1109 int len, slen;
1110
1111 if (grouping == 0 || *grouping <= 0 || *grouping == CHAR_MAX)
1112 return ((char *)NULL);
1113
1114 /* find min grouping to size returned string */
1115 for (len = *grouping, g = grouping; *g; g++)
1116 if (*g > 0 && *g < len)
1117 len = *g;
1118
1119 slen = strlen (s);
1120 len = slen / len + 1;
1121 ret = (char *)xmalloc (slen + len + 1);
1122 re = ret + slen + len;
1123 *re = '\0';
1124
1125 g = grouping;
1126 se = s + slen;
1127 len = *g;
1128
1129 while (se > s)
1130 {
1131 *--re = *--se;
1132
1133 /* handle `-' inserted by numtoa() and the fmtu* family here. */
1134 if (se > s && se[-1] == '-')
1135 continue;
1136
1137 /* begin new group. */
1138 if (--len == 0 && se > s)
1139 {
1140 *--re = thoussep;
1141 len = *++g; /* was g++, but that uses first char twice (glibc bug, too) */
1142 if (*g == '\0')
1143 len = *--g; /* use previous grouping */
1144 else if (*g == CHAR_MAX)
1145 {
1146 do
1147 *--re = *--se;
1148 while (se > s);
1149 break;
1150 }
1151 }
1152 }
1153
1154 if (re > ret)
1155 #ifdef HAVE_MEMMOVE
1156 memmove (ret, re, strlen (re) + 1);
1157 #else
1158 strcpy (ret, re);
1159 #endif
1160
1161 return ret;
1162 }
1163
1164 /* initialize the conversion specifiers */
1165 static void
1166 init_conv_flag (p)
1167 struct DATA *p;
1168 {
1169 p->flags &= PF_ALLOCBUF; /* preserve PF_ALLOCBUF flag */
1170 p->precision = p->width = NOT_FOUND;
1171 p->justify = NOT_FOUND;
1172 p->pad = ' ';
1173 }
1174
1175 static void
1176 init_data (p, string, length, format, mode)
1177 struct DATA *p;
1178 char *string;
1179 size_t length;
1180 const char *format;
1181 int mode;
1182 {
1183 p->length = length - 1; /* leave room for '\0' */
1184 p->holder = p->base = string;
1185 p->pf = format;
1186 p->counter = 0;
1187 p->flags = (mode == PFM_AS) ? PF_ALLOCBUF : 0;
1188 }
1189
1190 static int
1191 #if defined (__STDC__)
1192 vsnprintf_internal(struct DATA *data, char *string, size_t length, const char *format, va_list args)
1193 #else
1194 vsnprintf_internal(data, string, length, format, args)
1195 struct DATA *data;
1196 char *string;
1197 size_t length;
1198 const char *format;
1199 va_list args;
1200 #endif
1201 {
1202 double d; /* temporary holder */
1203 #ifdef HAVE_LONG_DOUBLE
1204 long double ld; /* for later */
1205 #endif
1206 unsigned long ul;
1207 #ifdef HAVE_LONG_LONG
1208 unsigned long long ull;
1209 #endif
1210 int state, i, c, n;
1211 char *s;
1212 #if HANDLE_MULTIBYTE
1213 wchar_t *ws;
1214 wint_t wc;
1215 #endif
1216 const char *convstart;
1217 int negprec;
1218
1219 /* Sanity check, the string length must be >= 0. C99 actually says that
1220 LENGTH can be zero here, in the case of snprintf/vsnprintf (it's never
1221 0 in the case of asprintf/vasprintf), and the return value is the number
1222 of characters that would have been written. */
1223 if (length < 0)
1224 return -1;
1225
1226 if (format == 0)
1227 return 0;
1228
1229 /* Reset these for each call because the locale might have changed. */
1230 decpoint = thoussep = 0;
1231 grouping = 0;
1232
1233 negprec = 0;
1234 for (; c = *(data->pf); data->pf++)
1235 {
1236 if (c != '%')
1237 {
1238 PUT_CHAR (c, data);
1239 continue;
1240 }
1241
1242 convstart = data->pf;
1243 init_conv_flag (data); /* initialise format flags */
1244
1245 state = 1;
1246 for (state = 1; state && *data->pf; )
1247 {
1248 c = *(++data->pf);
1249 /* fmtend = data->pf */
1250 #if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE)
1251 if (data->flags & PF_LONGDBL)
1252 {
1253 switch (c)
1254 {
1255 case 'f': case 'F':
1256 case 'e': case 'E':
1257 case 'g': case 'G':
1258 # ifdef HAVE_PRINTF_A_FORMAT
1259 case 'a': case 'A':
1260 # endif
1261 STAR_ARGS (data);
1262 ld = GETLDOUBLE (data);
1263 ldfallback (data, convstart, data->pf, ld);
1264 goto conv_break;
1265 }
1266 }
1267 #endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */
1268
1269 switch (c)
1270 {
1271 /* Parse format flags */
1272 case '\0': /* a NULL here ? ? bail out */
1273 *data->holder = '\0';
1274 return data->counter;
1275 break;
1276 case '#':
1277 data->flags |= PF_ALTFORM;
1278 continue;
1279 case '0':
1280 data->flags |= PF_ZEROPAD;
1281 data->pad = '0';
1282 continue;
1283 case '*':
1284 if (data->flags & PF_DOT)
1285 data->flags |= PF_STAR_P;
1286 else
1287 data->flags |= PF_STAR_W;
1288 continue;
1289 case '-':
1290 if ((data->flags & PF_DOT) == 0)
1291 {
1292 data->flags |= PF_LADJUST;
1293 data->justify = LEFT;
1294 }
1295 else
1296 negprec = 1;
1297 continue;
1298 case ' ':
1299 if ((data->flags & PF_PLUS) == 0)
1300 data->flags |= PF_SPACE;
1301 continue;
1302 case '+':
1303 if ((data->flags & PF_DOT) == 0)
1304 {
1305 data->flags |= PF_PLUS;
1306 data->justify = RIGHT;
1307 }
1308 continue;
1309 case '\'':
1310 data->flags |= PF_THOUSANDS;
1311 continue;
1312
1313 case '1': case '2': case '3':
1314 case '4': case '5': case '6':
1315 case '7': case '8': case '9':
1316 n = 0;
1317 do
1318 {
1319 n = n * 10 + TODIGIT(c);
1320 c = *(++data->pf);
1321 }
1322 while (DIGIT(c));
1323 data->pf--; /* went too far */
1324 if (n < 0)
1325 n = 0;
1326 if (data->flags & PF_DOT)
1327 data->precision = negprec ? NOT_FOUND : n;
1328 else
1329 data->width = n;
1330 continue;
1331
1332 /* optional precision */
1333 case '.':
1334 data->flags |= PF_DOT;
1335 data->precision = 0;
1336 continue;
1337
1338 /* length modifiers */
1339 case 'h':
1340 data->flags |= (data->flags & PF_SHORTINT) ? PF_SIGNEDCHAR : PF_SHORTINT;
1341 continue;
1342 case 'l':
1343 data->flags |= (data->flags & PF_LONGINT) ? PF_LONGLONG : PF_LONGINT;
1344 continue;
1345 case 'L':
1346 data->flags |= PF_LONGDBL;
1347 continue;
1348 case 'q':
1349 data->flags |= PF_LONGLONG;
1350 continue;
1351 case 'j':
1352 data->flags |= PF_INTMAX_T;
1353 SET_SIZE_FLAGS(data, intmax_t);
1354 continue;
1355 case 'z':
1356 data->flags |= PF_SIZE_T;
1357 SET_SIZE_FLAGS(data, size_t);
1358 continue;
1359 case 't':
1360 data->flags |= PF_PTRDIFF_T;
1361 SET_SIZE_FLAGS(data, ptrdiff_t);
1362 continue;
1363
1364 /* Conversion specifiers */
1365 #ifdef FLOATING_POINT
1366 case 'f': /* float, double */
1367 case 'F':
1368 STAR_ARGS(data);
1369 d = GETDOUBLE(data);
1370 floating(data, d);
1371 conv_break:
1372 state = 0;
1373 break;
1374 case 'g':
1375 case 'G':
1376 STAR_ARGS(data);
1377 DEF_PREC(data);
1378 d = GETDOUBLE(data);
1379 i = (d != 0.) ? log_10(d) : -1;
1380 /*
1381 * for '%g|%G' ANSI: use f if exponent
1382 * is in the range or [-4,p] exclusively
1383 * else use %e|%E
1384 */
1385 if (-4 < i && i < data->precision)
1386 {
1387 /* reset precision */
1388 data->precision -= i + 1;
1389 floating(data, d);
1390 }
1391 else
1392 {
1393 /* reduce precision by 1 because of leading digit before
1394 decimal point in e format. */
1395 data->precision--;
1396 exponent(data, d);
1397 }
1398 state = 0;
1399 break;
1400 case 'e':
1401 case 'E': /* Exponent double */
1402 STAR_ARGS(data);
1403 d = GETDOUBLE(data);
1404 exponent(data, d);
1405 state = 0;
1406 break;
1407 # ifdef HAVE_PRINTF_A_FORMAT
1408 case 'a':
1409 case 'A':
1410 STAR_ARGS(data);
1411 d = GETDOUBLE(data);
1412 dfallback(data, convstart, data->pf, d);
1413 state = 0;
1414 break;
1415 # endif /* HAVE_PRINTF_A_FORMAT */
1416 #endif /* FLOATING_POINT */
1417 case 'U':
1418 data->flags |= PF_LONGINT;
1419 /* FALLTHROUGH */
1420 case 'u':
1421 STAR_ARGS(data);
1422 #ifdef HAVE_LONG_LONG
1423 if (data->flags & PF_LONGLONG)
1424 {
1425 ull = GETARG (unsigned long long);
1426 lnumber(data, ull, 10);
1427 }
1428 else
1429 #endif
1430 {
1431 ul = GETUNSIGNED(data);
1432 number(data, ul, 10);
1433 }
1434 state = 0;
1435 break;
1436 case 'D':
1437 data->flags |= PF_LONGINT;
1438 /* FALLTHROUGH */
1439 case 'd': /* decimal */
1440 case 'i':
1441 STAR_ARGS(data);
1442 #ifdef HAVE_LONG_LONG
1443 if (data->flags & PF_LONGLONG)
1444 {
1445 ull = GETARG (long long);
1446 lnumber(data, ull, 10);
1447 }
1448 else
1449 #endif
1450 {
1451 ul = GETSIGNED(data);
1452 number(data, ul, 10);
1453 }
1454 state = 0;
1455 break;
1456 case 'o': /* octal */
1457 STAR_ARGS(data);
1458 #ifdef HAVE_LONG_LONG
1459 if (data->flags & PF_LONGLONG)
1460 {
1461 ull = GETARG (unsigned long long);
1462 lnumber(data, ull, 8);
1463 }
1464 else
1465 #endif
1466 {
1467 ul = GETUNSIGNED(data);
1468 number(data, ul, 8);
1469 }
1470 state = 0;
1471 break;
1472 case 'x':
1473 case 'X': /* hexadecimal */
1474 STAR_ARGS(data);
1475 #ifdef HAVE_LONG_LONG
1476 if (data->flags & PF_LONGLONG)
1477 {
1478 ull = GETARG (unsigned long long);
1479 lnumber(data, ull, 16);
1480 }
1481 else
1482 #endif
1483 {
1484 ul = GETUNSIGNED(data);
1485 number(data, ul, 16);
1486 }
1487 state = 0;
1488 break;
1489 case 'p':
1490 STAR_ARGS(data);
1491 ul = (unsigned long)GETARG (void *);
1492 pointer(data, ul);
1493 state = 0;
1494 break;
1495 #if HANDLE_MULTIBYTE
1496 case 'C':
1497 data->flags |= PF_LONGINT;
1498 /* FALLTHROUGH */
1499 #endif
1500 case 'c': /* character */
1501 STAR_ARGS(data);
1502 #if HANDLE_MULTIBYTE
1503 if (data->flags & PF_LONGINT)
1504 {
1505 wc = GETARG (wint_t);
1506 wchars (data, wc);
1507 }
1508 else
1509 #endif
1510 {
1511 ul = GETARG (int);
1512 PUT_CHAR(ul, data);
1513 }
1514 state = 0;
1515 break;
1516 #if HANDLE_MULTIBYTE
1517 case 'S':
1518 data->flags |= PF_LONGINT;
1519 /* FALLTHROUGH */
1520 #endif
1521 case 's': /* string */
1522 STAR_ARGS(data);
1523 #if HANDLE_MULTIBYTE
1524 if (data->flags & PF_LONGINT)
1525 {
1526 ws = GETARG (wchar_t *);
1527 wstrings (data, ws);
1528 }
1529 else
1530 #endif
1531 {
1532 s = GETARG (char *);
1533 strings(data, s);
1534 }
1535 state = 0;
1536 break;
1537 case 'n':
1538 #ifdef HAVE_LONG_LONG
1539 if (data->flags & PF_LONGLONG)
1540 *(GETARG (long long *)) = data->counter;
1541 else
1542 #endif
1543 if (data->flags & PF_LONGINT)
1544 *(GETARG (long *)) = data->counter;
1545 else if (data->flags & PF_SHORTINT)
1546 *(GETARG (short *)) = data->counter;
1547 else
1548 *(GETARG (int *)) = data->counter;
1549 state = 0;
1550 break;
1551 case '%': /* nothing just % */
1552 PUT_CHAR('%', data);
1553 state = 0;
1554 break;
1555 default:
1556 /* is this an error ? maybe bail out */
1557 state = 0;
1558 break;
1559 } /* end switch */
1560 } /* end of `%' for loop */
1561 } /* end of format string for loop */
1562
1563 if (data->length >= 0)
1564 *data->holder = '\0'; /* the end ye ! */
1565
1566 return data->counter;
1567 }
1568
1569 #if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE)
1570 /*
1571 * Printing floating point numbers accurately is an art. I'm not good
1572 * at it. Fall back to sprintf for long double formats.
1573 */
1574 static void
1575 ldfallback (data, fs, fe, ld)
1576 struct DATA *data;
1577 const char *fs, *fe;
1578 long double ld;
1579 {
1580 register char *x;
1581 char fmtbuf[FALLBACK_FMTSIZE], *obuf;
1582 int fl;
1583
1584 fl = LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2;
1585 obuf = (char *)xmalloc (fl);
1586 fl = fe - fs + 1;
1587 strncpy (fmtbuf, fs, fl);
1588 fmtbuf[fl] = '\0';
1589
1590 if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P))
1591 sprintf (obuf, fmtbuf, data->width, data->precision, ld);
1592 else if (data->flags & PF_STAR_W)
1593 sprintf (obuf, fmtbuf, data->width, ld);
1594 else if (data->flags & PF_STAR_P)
1595 sprintf (obuf, fmtbuf, data->precision, ld);
1596 else
1597 sprintf (obuf, fmtbuf, ld);
1598
1599 for (x = obuf; *x; x++)
1600 PUT_CHAR (*x, data);
1601 xfree (obuf);
1602 }
1603 #endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */
1604
1605 #ifdef FLOATING_POINT
1606 /* Used for %a, %A if the libc printf supports them. */
1607 static void
1608 dfallback (data, fs, fe, d)
1609 struct DATA *data;
1610 const char *fs, *fe;
1611 double d;
1612 {
1613 register char *x;
1614 char fmtbuf[FALLBACK_FMTSIZE], obuf[FALLBACK_BASE];
1615 int fl;
1616
1617 fl = fe - fs + 1;
1618 strncpy (fmtbuf, fs, fl);
1619 fmtbuf[fl] = '\0';
1620
1621 if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P))
1622 sprintf (obuf, fmtbuf, data->width, data->precision, d);
1623 else if (data->flags & PF_STAR_W)
1624 sprintf (obuf, fmtbuf, data->width, d);
1625 else if (data->flags & PF_STAR_P)
1626 sprintf (obuf, fmtbuf, data->precision, d);
1627 else
1628 sprintf (obuf, fmtbuf, d);
1629
1630 for (x = obuf; *x; x++)
1631 PUT_CHAR (*x, data);
1632 }
1633 #endif /* FLOATING_POINT */
1634
1635 #ifndef HAVE_SNPRINTF
1636
1637 int
1638 #if defined (__STDC__)
1639 vsnprintf(char *string, size_t length, const char *format, va_list args)
1640 #else
1641 vsnprintf(string, length, format, args)
1642 char *string;
1643 size_t length;
1644 const char *format;
1645 va_list args;
1646 #endif
1647 {
1648 struct DATA data;
1649
1650 if (string == 0 && length != 0)
1651 return 0;
1652 init_data (&data, string, length, format, PFM_SN);
1653 return (vsnprintf_internal(&data, string, length, format, args));
1654 }
1655
1656 int
1657 #if defined(PREFER_STDARG)
1658 snprintf(char *string, size_t length, const char * format, ...)
1659 #else
1660 snprintf(string, length, format, va_alist)
1661 char *string;
1662 size_t length;
1663 const char *format;
1664 va_dcl
1665 #endif
1666 {
1667 struct DATA data;
1668 int rval;
1669 va_list args;
1670
1671 SH_VA_START(args, format);
1672
1673 if (string == 0 && length != 0)
1674 return 0;
1675 init_data (&data, string, length, format, PFM_SN);
1676 rval = vsnprintf_internal (&data, string, length, format, args);
1677
1678 va_end(args);
1679
1680 return rval;
1681 }
1682
1683 #endif /* HAVE_SNPRINTF */
1684
1685 #ifndef HAVE_ASPRINTF
1686
1687 int
1688 #if defined (__STDC__)
1689 vasprintf(char **stringp, const char *format, va_list args)
1690 #else
1691 vasprintf(stringp, format, args)
1692 char **stringp;
1693 const char *format;
1694 va_list args;
1695 #endif
1696 {
1697 struct DATA data;
1698 char *string;
1699 int r;
1700
1701 string = (char *)xmalloc(ASBUFSIZE);
1702 init_data (&data, string, ASBUFSIZE, format, PFM_AS);
1703 r = vsnprintf_internal(&data, string, ASBUFSIZE, format, args);
1704 *stringp = data.base; /* not string in case reallocated */
1705 return r;
1706 }
1707
1708 int
1709 #if defined(PREFER_STDARG)
1710 asprintf(char **stringp, const char * format, ...)
1711 #else
1712 asprintf(stringp, format, va_alist)
1713 char **stringp;
1714 const char *format;
1715 va_dcl
1716 #endif
1717 {
1718 int rval;
1719 va_list args;
1720
1721 SH_VA_START(args, format);
1722
1723 rval = vasprintf (stringp, format, args);
1724
1725 va_end(args);
1726
1727 return rval;
1728 }
1729
1730 #endif
1731
1732 #endif
1733
1734 #ifdef DRIVER
1735
1736 static void
1737 memory_error_and_abort ()
1738 {
1739 write (2, "out of virtual memory\n", 22);
1740 abort ();
1741 }
1742
1743 static void *
1744 xmalloc(bytes)
1745 size_t bytes;
1746 {
1747 void *ret;
1748
1749 ret = malloc(bytes);
1750 if (ret == 0)
1751 memory_error_and_abort ();
1752 return ret;
1753 }
1754
1755 static void *
1756 xrealloc (pointer, bytes)
1757 void *pointer;
1758 size_t bytes;
1759 {
1760 void *ret;
1761
1762 ret = pointer ? realloc(pointer, bytes) : malloc(bytes);
1763 if (ret == 0)
1764 memory_error_and_abort ();
1765 return ret;
1766 }
1767
1768 static void
1769 xfree(x)
1770 void *x;
1771 {
1772 if (x)
1773 free (x);
1774 }
1775
1776 /* set of small tests for snprintf() */
1777 main()
1778 {
1779 char holder[100];
1780 char *h;
1781 int i, si, ai;
1782
1783 #ifdef HAVE_LOCALE_H
1784 setlocale(LC_ALL, "");
1785 #endif
1786
1787 #if 1
1788 si = snprintf((char *)NULL, 0, "abcde\n");
1789 printf("snprintf returns %d with NULL first argument and size of 0\n", si);
1790 si = snprintf(holder, 0, "abcde\n");
1791 printf("snprintf returns %d with non-NULL first argument and size of 0\n", si);
1792 si = snprintf((char *)NULL, 16, "abcde\n");
1793 printf("snprintf returns %d with NULL first argument and non-zero size\n", si);
1794
1795 /*
1796 printf("Suite of test for snprintf:\n");
1797 printf("a_format\n");
1798 printf("printf() format\n");
1799 printf("snprintf() format\n\n");
1800 */
1801 /* Checking the field widths */
1802
1803 printf("/%%ld %%ld/, 336, 336\n");
1804 snprintf(holder, sizeof holder, "/%ld %ld/\n", 336, 336);
1805 asprintf(&h, "/%ld %ld/\n", 336, 336);
1806 printf("/%ld %ld/\n", 336, 336);
1807 printf("%s", holder);
1808 printf("%s\n", h);
1809
1810 printf("/%%d/, 336\n");
1811 snprintf(holder, sizeof holder, "/%d/\n", 336);
1812 asprintf(&h, "/%d/\n", 336);
1813 printf("/%d/\n", 336);
1814 printf("%s", holder);
1815 printf("%s\n", h);
1816
1817 printf("/%%2d/, 336\n");
1818 snprintf(holder, sizeof holder, "/%2d/\n", 336);
1819 asprintf(&h, "/%2d/\n", 336);
1820 printf("/%2d/\n", 336);
1821 printf("%s", holder);
1822 printf("%s\n", h);
1823
1824 printf("/%%10d/, 336\n");
1825 snprintf(holder, sizeof holder, "/%10d/\n", 336);
1826 asprintf(&h, "/%10d/\n", 336);
1827 printf("/%10d/\n", 336);
1828 printf("%s", holder);
1829 printf("%s\n", h);
1830
1831 printf("/%%-10d/, 336\n");
1832 snprintf(holder, sizeof holder, "/%-10d/\n", 336);
1833 asprintf(&h, "/%-10d/\n", 336);
1834 printf("/%-10d/\n", 336);
1835 printf("%s", holder);
1836 printf("%s\n", h);
1837
1838
1839 /* floating points */
1840
1841 printf("/%%f/, 1234.56\n");
1842 snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
1843 asprintf(&h, "/%f/\n", 1234.56);
1844 printf("/%f/\n", 1234.56);
1845 printf("%s", holder);
1846 printf("%s\n", h);
1847
1848 printf("/%%e/, 1234.56\n");
1849 snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
1850 asprintf(&h, "/%e/\n", 1234.56);
1851 printf("/%e/\n", 1234.56);
1852 printf("%s", holder);
1853 printf("%s\n", h);
1854
1855 printf("/%%4.2f/, 1234.56\n");
1856 snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
1857 asprintf(&h, "/%4.2f/\n", 1234.56);
1858 printf("/%4.2f/\n", 1234.56);
1859 printf("%s", holder);
1860 printf("%s\n", h);
1861
1862 printf("/%%3.1f/, 1234.56\n");
1863 snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
1864 asprintf(&h, "/%3.1f/\n", 1234.56);
1865 printf("/%3.1f/\n", 1234.56);
1866 printf("%s", holder);
1867 printf("%s\n", h);
1868
1869 printf("/%%10.3f/, 1234.56\n");
1870 snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
1871 asprintf(&h, "/%10.3f/\n", 1234.56);
1872 printf("/%10.3f/\n", 1234.56);
1873 printf("%s", holder);
1874 printf("%s\n", h);
1875
1876 printf("/%%10.3e/, 1234.56\n");
1877 snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
1878 asprintf(&h, "/%10.3e/\n", 1234.56);
1879 printf("/%10.3e/\n", 1234.56);
1880 printf("%s", holder);
1881 printf("%s\n", h);
1882
1883 printf("/%%+4.2f/, 1234.56\n");
1884 snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
1885 asprintf(&h, "/%+4.2f/\n", 1234.56);
1886 printf("/%+4.2f/\n", 1234.56);
1887 printf("%s", holder);
1888 printf("%s\n", h);
1889
1890 printf("/%%010.2f/, 1234.56\n");
1891 snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
1892 asprintf(&h, "/%010.2f/\n", 1234.56);
1893 printf("/%010.2f/\n", 1234.56);
1894 printf("%s", holder);
1895 printf("%s\n", h);
1896
1897 #define BLURB "Outstanding acting !"
1898 /* strings precisions */
1899
1900 printf("/%%2s/, \"%s\"\n", BLURB);
1901 snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
1902 asprintf(&h, "/%2s/\n", BLURB);
1903 printf("/%2s/\n", BLURB);
1904 printf("%s", holder);
1905 printf("%s\n", h);
1906
1907 printf("/%%22s/ %s\n", BLURB);
1908 snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
1909 asprintf(&h, "/%22s/\n", BLURB);
1910 printf("/%22s/\n", BLURB);
1911 printf("%s", holder);
1912 printf("%s\n", h);
1913
1914 printf("/%%22.5s/ %s\n", BLURB);
1915 snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
1916 asprintf(&h, "/%22.5s/\n", BLURB);
1917 printf("/%22.5s/\n", BLURB);
1918 printf("%s", holder);
1919 printf("%s\n", h);
1920
1921 printf("/%%-22.5s/ %s\n", BLURB);
1922 snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
1923 asprintf(&h, "/%-22.5s/\n", BLURB);
1924 printf("/%-22.5s/\n", BLURB);
1925 printf("%s", holder);
1926 printf("%s\n", h);
1927
1928 /* see some flags */
1929
1930 printf("%%x %%X %%#x, 31, 31, 31\n");
1931 snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
1932 asprintf(&h, "%x %X %#x\n", 31, 31, 31);
1933 printf("%x %X %#x\n", 31, 31, 31);
1934 printf("%s", holder);
1935 printf("%s\n", h);
1936
1937 printf("**%%d**%% d**%% d**, 42, 42, -42\n");
1938 snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
1939 asprintf(&h, "**%d**% d**% d**\n", 42, 42, -42);
1940 printf("**%d**% d**% d**\n", 42, 42, -42);
1941 printf("%s", holder);
1942 printf("%s\n", h);
1943
1944 /* other flags */
1945
1946 printf("/%%g/, 31.4\n");
1947 snprintf(holder, sizeof holder, "/%g/\n", 31.4);
1948 asprintf(&h, "/%g/\n", 31.4);
1949 printf("/%g/\n", 31.4);
1950 printf("%s", holder);
1951 printf("%s\n", h);
1952
1953 printf("/%%.6g/, 31.4\n");
1954 snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
1955 asprintf(&h, "/%.6g/\n", 31.4);
1956 printf("/%.6g/\n", 31.4);
1957 printf("%s", holder);
1958 printf("%s\n", h);
1959
1960 printf("/%%.1G/, 31.4\n");
1961 snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
1962 asprintf(&h, "/%.1G/\n", 31.4);
1963 printf("/%.1G/\n", 31.4);
1964 printf("%s", holder);
1965 printf("%s\n", h);
1966
1967 printf("/%%.1G/, 3100000000.4\n");
1968 snprintf(holder, sizeof holder, "/%.1G/\n", 3100000000.4);
1969 asprintf(&h, "/%.1G/\n", 3100000000.4);
1970 printf("/%.1G/\n", 3100000000.4);
1971 printf("%s", holder);
1972 printf("%s\n", h);
1973
1974 printf("abc%%n\n");
1975 printf("abc%n", &i); printf("%d\n", i);
1976 snprintf(holder, sizeof holder, "abc%n", &i);
1977 printf("%s", holder); printf("%d\n\n", i);
1978 asprintf(&h, "abc%n", &i);
1979 printf("%s", h); printf("%d\n\n", i);
1980
1981 printf("%%*.*s --> 10.10\n");
1982 snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
1983 asprintf(&h, "%*.*s\n", 10, 10, BLURB);
1984 printf("%*.*s\n", 10, 10, BLURB);
1985 printf("%s", holder);
1986 printf("%s\n", h);
1987
1988 printf("%%%%%%%%\n");
1989 snprintf(holder, sizeof holder, "%%%%\n");
1990 asprintf(&h, "%%%%\n");
1991 printf("%%%%\n");
1992 printf("%s", holder);
1993 printf("%s\n", h);
1994
1995 #define BIG "Hello this is a too big string for the buffer"
1996 /* printf("A buffer to small of 10, trying to put this:\n");*/
1997 printf("<%%>, %s\n", BIG);
1998 i = snprintf(holder, 10, "%s\n", BIG);
1999 i = asprintf(&h, "%s", BIG);
2000 printf("<%s>\n", BIG);
2001 printf("<%s>\n", holder);
2002 printf("<%s>\n\n", h);
2003
2004 printf ("<%%p> vsnprintf\n");
2005 i = snprintf(holder, 100, "%p", vsnprintf);
2006 i = asprintf(&h, "%p", vsnprintf);
2007 printf("<%p>\n", vsnprintf);
2008 printf("<%s>\n", holder);
2009 printf("<%s>\n\n", h);
2010
2011 printf ("<%%lu> LONG_MAX+1\n");
2012 i = snprintf(holder, 100, "%lu", (unsigned long)(LONG_MAX)+1);
2013 i = asprintf(&h, "%lu", (unsigned long)(LONG_MAX)+1);
2014 printf("<%lu>\n", (unsigned long)(LONG_MAX)+1);
2015 printf("<%s>\n", holder);
2016 printf("<%s>\n\n", h);
2017
2018 #ifdef HAVE_LONG_LONG
2019 printf ("<%%llu> LLONG_MAX+1\n");
2020 i = snprintf(holder, 100, "%llu", (unsigned long long)(LLONG_MAX)+1);
2021 i = asprintf(&h, "%llu", (unsigned long long)(LLONG_MAX)+1);
2022 printf("<%llu>\n", (unsigned long long)(LLONG_MAX)+1);
2023 printf("<%s>\n", holder);
2024 printf("<%s>\n\n", h);
2025 #endif
2026
2027 #ifdef HAVE_LONG_DOUBLE
2028 printf ("<%%6.2LE> 42.42\n");
2029 i = snprintf(holder, 100, "%6.2LE", (long double)42.42);
2030 i = asprintf(&h, "%6.2LE", (long double)42.42);
2031 printf ("<%6.2LE>\n", (long double)42.42);
2032 printf ("<%s>\n", holder);
2033 printf ("<%s>\n\n", h);
2034 #endif
2035
2036 #ifdef HAVE_PRINTF_A_FORMAT
2037 printf ("<%%6.2A> 42.42\n");
2038 i = snprintf(holder, 100, "%6.2A", 42.42);
2039 i = asprintf(&h, "%6.2A", 42.42);
2040 printf ("<%6.2A>\n", 42.42);
2041 printf ("<%s>\n", holder);
2042 printf ("<%s>\n\n", h);
2043
2044 printf ("<%%6.2LA> 42.42\n");
2045 i = snprintf(holder, 100, "%6.2LA", (long double)42.42);
2046 i = asprintf(&h, "%6.2LA", (long double)42.42);
2047 printf ("<%6.2LA>\n", (long double)42.42);
2048 printf ("<%s>\n", holder);
2049 printf ("<%s>\n\n", h);
2050 #endif
2051
2052 printf ("<%%.10240f> DBL_MAX\n");
2053 si = snprintf(holder, 100, "%.10240f", DBL_MAX);
2054 ai = asprintf(&h, "%.10240f", DBL_MAX);
2055 printf ("<%.10240f>\n", DBL_MAX);
2056 printf ("<%d> <%s>\n", si, holder);
2057 printf ("<%d> <%s>\n\n", ai, h);
2058
2059 printf ("<%%.10240Lf> LDBL_MAX\n");
2060 si = snprintf(holder, 100, "%.10240Lf", (long double)LDBL_MAX);
2061 ai = asprintf(&h, "%.10240Lf", (long double)LDBL_MAX);
2062 printf ("<%.10240Lf>\n", (long double)LDBL_MAX);
2063 printf ("<%d> <%s>\n", si, holder);
2064 printf ("<%d> <%s>\n\n", ai, h);
2065
2066 /* huh? */
2067 printf("/%%g/, 421.2345\n");
2068 snprintf(holder, sizeof holder, "/%g/\n", 421.2345);
2069 asprintf(&h, "/%g/\n", 421.2345);
2070 printf("/%g/\n", 421.2345);
2071 printf("%s", holder);
2072 printf("%s\n", h);
2073
2074 printf("/%%g/, 4214.2345\n");
2075 snprintf(holder, sizeof holder, "/%g/\n", 4214.2345);
2076 asprintf(&h, "/%g/\n", 4214.2345);
2077 printf("/%g/\n", 4214.2345);
2078 printf("%s", holder);
2079 printf("%s\n", h);
2080
2081 printf("/%%.5g/, 4214.2345\n");
2082 snprintf(holder, sizeof holder, "/%.5g/\n", 4214.2345);
2083 asprintf(&h, "/%.5g/\n", 4214.2345);
2084 printf("/%.5g/\n", 4214.2345);
2085 printf("%s", holder);
2086 printf("%s\n", h);
2087
2088 printf("/%%.4g/, 4214.2345\n");
2089 snprintf(holder, sizeof holder, "/%.4g/\n", 4214.2345);
2090 asprintf(&h, "/%.4g/\n", 4214.2345);
2091 printf("/%.4g/\n", 4214.2345);
2092 printf("%s", holder);
2093 printf("%s\n", h);
2094
2095 printf("/%%'ld %%'ld/, 12345, 1234567\n");
2096 snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 12345, 1234567);
2097 asprintf(&h, "/%'ld %'ld/\n", 12345, 1234567);
2098 printf("/%'ld %'ld/\n", 12345, 1234567);
2099 printf("%s", holder);
2100 printf("%s\n", h);
2101
2102 printf("/%%'ld %%'ld/, 336, 3336\n");
2103 snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 336, 3336);
2104 asprintf(&h, "/%'ld %'ld/\n", 336, 3336);
2105 printf("/%'ld %'ld/\n", 336, 3336);
2106 printf("%s", holder);
2107 printf("%s\n", h);
2108
2109 printf("/%%'ld %%'ld/, -42786, -142786\n");
2110 snprintf(holder, sizeof holder, "/%'ld %'ld/\n", -42786, -142786);
2111 asprintf(&h, "/%'ld %'ld/\n", -42786, -142786);
2112 printf("/%'ld %'ld/\n", -42786, -142786);
2113 printf("%s", holder);
2114 printf("%s\n", h);
2115
2116 printf("/%%'f %%'f/, 421.2345, 421234.56789\n");
2117 snprintf(holder, sizeof holder, "/%'f %'f/\n", 421.2345, 421234.56789);
2118 asprintf(&h, "/%'f %'f/\n", 421.2345, 421234.56789);
2119 printf("/%'f %'f/\n", 421.2345, 421234.56789);
2120 printf("%s", holder);
2121 printf("%s\n", h);
2122
2123 printf("/%%'f %%'f/, -421.2345, -421234.56789\n");
2124 snprintf(holder, sizeof holder, "/%'f %'f/\n", -421.2345, -421234.56789);
2125 asprintf(&h, "/%'f %'f/\n", -421.2345, -421234.56789);
2126 printf("/%'f %'f/\n", -421.2345, -421234.56789);
2127 printf("%s", holder);
2128 printf("%s\n", h);
2129
2130 printf("/%%'g %%'g/, 421.2345, 421234.56789\n");
2131 snprintf(holder, sizeof holder, "/%'g %'g/\n", 421.2345, 421234.56789);
2132 asprintf(&h, "/%'g %'g/\n", 421.2345, 421234.56789);
2133 printf("/%'g %'g/\n", 421.2345, 421234.56789);
2134 printf("%s", holder);
2135 printf("%s\n", h);
2136
2137 printf("/%%'g %%'g/, -421.2345, -421234.56789\n");
2138 snprintf(holder, sizeof holder, "/%'g %'g/\n", -421.2345, -421234.56789);
2139 asprintf(&h, "/%'g %'g/\n", -421.2345, -421234.56789);
2140 printf("/%'g %'g/\n", -421.2345, -421234.56789);
2141 printf("%s", holder);
2142 printf("%s\n", h);
2143 #endif
2144
2145 printf("/%%'g/, 4213455.8392\n");
2146 snprintf(holder, sizeof holder, "/%'g/\n", 4213455.8392);
2147 asprintf(&h, "/%'g/\n", 4213455.8392);
2148 printf("/%'g/\n", 4213455.8392);
2149 printf("%s", holder);
2150 printf("%s\n", h);
2151
2152 exit (0);
2153 }
2154 #endif