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