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