source: trunk/essentials/app-shells/bash/lib/sh/snprintf.c

Last change on this file was 3231, checked in by bird, 18 years ago

eol style.

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