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