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