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