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