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