3 Unix snprintf implementation.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Library General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * integrate in FreeRADIUS's libradius:
24 * Fetched from: http://savannah.gnu.org/cgi-bin/viewcvs/mailutils/mailutils/lib/snprintf.c?rev=1.4
25 * Fetched from: http://savannah.gnu.org/cgi-bin/viewcvs/mailutils/mailutils/lib/snprintf.h?rev=1.4
26 * Replace config.h with autoconf.h
27 * Protect with HAVE_LOCAL_SNPRINTF
30 * add #include <config.h> ifdef HAVE_CONFIG_H
31 * cosmetic change, when exponent is 0 print xxxE+00
34 * put the program under LGPL.
36 * added changes from Miles Bader
37 * corrected a bug with %f
38 * added support for %#g
39 * added more comments :-)
41 * supporting must ANSI syntaxic_sugars
45 THANKS(for the patches and ideas):
55 #ifdef HAVE_LOCAL_SNPRINTF
60 * Find the nth power of 10
74 for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;}
76 for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;}
81 * Find the integral part of the log in base 10
82 * Note: this not a real log10()
83 I just need and approximation(integerpart) of x in:
103 while (result >= r) {result *= .1; i++;}
106 while (result <= r) {result *= 10.; i++;}
112 * This function return the fraction part of a double
113 * and set in ip the integral part.
114 * In many ways it resemble the modf() found on most Un*x
118 integral(double real, double * ip)
127 double real_integral = 0.;
129 /* take care of the obvious */
130 /* equal to zero ? */
136 /* negative number ? */
145 /* the real work :-) */
146 for (j = log_10(real); j >= 0; j--) {
148 s = (real - real_integral)/p;
150 while (i + 1. <= s) {i++;}
151 real_integral += i*p;
154 return (real - real_integral);
157 #define PRECISION 1.e-6
159 * return an ascii representation of the integral part of the number
160 * and set fract to be an ascii representation of the fraction part
161 * the container for the fraction and the integral part or staticly
162 * declare with fix size
166 numtoa(double number, int base, int precision, char ** fract)
168 numtoa(number, base, precision, fract)
176 double ip, fp; /* integer and fraction part */
178 int digits = MAX_INT - 1;
179 static char integral_part[MAX_INT];
180 static char fraction_part[MAX_FRACT];
184 /* taking care of the obvious case: 0.0 */
186 integral_part[0] = '0';
187 integral_part[1] = '\0';
188 fraction_part[0] = '0';
189 fraction_part[1] = '\0';
190 return integral_part;
193 /* for negative numbers */
194 if ((sign = number) < 0.) {
196 digits--; /* sign consume one digit */
199 fraction = integral(number, &ip);
201 /* do the integral part */
203 integral_part[0] = '0';
206 for ( i = 0; i < digits && number != 0.; ++i) {
208 fp = integral(number, &ip);
209 ch = (int)((fp + PRECISION)*base); /* force to round */
210 integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
211 if (! isxdigit(integral_part[i])) /* bail out overflow !! */
217 /* Oh No !! out of bound, ho well fill it up ! */
219 for (i = 0; i < digits; ++i)
220 integral_part[i] = '9';
224 integral_part[i++] = '-';
226 integral_part[i] = '\0';
228 /* reverse every thing */
229 for ( i--, j = 0; j < i; j++, i--)
230 SWAP_INT(integral_part[i], integral_part[j]);
232 /* the fractionnal part */
233 for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision-- ) {
234 fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
235 if (! isdigit(fraction_part[i])) /* underflow ? */
237 fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
239 fraction_part[i] = '\0';
241 if (fract != (char **)0)
242 *fract = fraction_part;
244 return integral_part;
248 /* for %d and friends, it puts in holder
249 * the representation with the right padding
253 decimal(struct DATA *p, double d)
263 p->width -= strlen(tmp);
267 while (*tmp) { /* the integral */
274 /* for %o octal representation */
277 octal(struct DATA *p, double d)
287 p->width -= strlen(tmp);
289 if (p->square == FOUND) /* had prefix '0' for octal */
291 while (*tmp) { /* octal */
298 /* for %x %X hexadecimal representation */
301 hexa(struct DATA *p, double d)
311 p->width -= strlen(tmp);
313 if (p->square == FOUND) { /* prefix '0x' for hexa */
314 PUT_CHAR('0', p); PUT_CHAR(*p->pf, p);
316 while (*tmp) { /* hexa */
317 PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p);
326 strings(struct DATA *p, char *tmp)
336 if (p->precision != NOT_FOUND) /* the smallest number */
337 i = (i < p->precision ? i : p->precision);
340 while (i-- > 0) { /* put the sting */
347 /* %f or %g floating point representation */
350 floating(struct DATA *p, double d)
362 tmp = dtoa(d, p->precision, &tmp2);
363 /* calculate the padding. 1 for the dot */
364 p->width = p->width -
365 ((d > 0. && p->justify == RIGHT) ? 1:0) -
366 ((p->space == FOUND) ? 1:0) -
367 strlen(tmp) - p->precision - 1;
371 while (*tmp) { /* the integral */
375 if (p->precision != 0 || p->square == FOUND)
376 PUT_CHAR('.', p); /* put the '.' */
377 if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
378 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
380 for (; *tmp2; tmp2++)
381 PUT_CHAR(*tmp2, p); /* the fraction */
386 /* %e %E %g exponent representation */
389 exponent(struct DATA *p, double d)
401 d = d / pow_10(j); /* get the Mantissa */
403 tmp = dtoa(d, p->precision, &tmp2);
404 /* 1 for unit, 1 for the '.', 1 for 'e|E',
405 * 1 for '+|-', 3 for 'exp' */
406 /* calculate how much padding need */
407 p->width = p->width -
408 ((d > 0. && p->justify == RIGHT) ? 1:0) -
409 ((p->space == FOUND) ? 1:0) - p->precision - 7;
413 while (*tmp) {/* the integral */
417 if (p->precision != 0 || p->square == FOUND)
418 PUT_CHAR('.', p); /* the '.' */
419 if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
420 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
422 for (; *tmp2; tmp2++)
423 PUT_CHAR(*tmp2, p); /* the fraction */
425 if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
429 if (j >= 0) { /* the sign of the exp */
435 tmp = itoa((double)j);
436 if (j < 9) { /* need to pad the exponent with 0 '000' */
437 PUT_CHAR('0', p); PUT_CHAR('0', p);
440 while (*tmp) { /* the exponent */
447 /* initialize the conversion specifiers */
450 conv_flag(char * s, struct DATA * p)
457 char number[MAX_FIELD/2];
460 /* reset the flags. */
461 p->precision = p->width = NOT_FOUND;
462 p->star_w = p->star_p = NOT_FOUND;
463 p->square = p->space = NOT_FOUND;
464 p->a_long = p->justify = NOT_FOUND;
465 p->a_longlong = NOT_FOUND;
470 case ' ': p->space = FOUND; break;
471 case '#': p->square = FOUND; break;
472 case '*': if (p->width == NOT_FOUND)
473 p->width = p->star_w = FOUND;
475 p->precision = p->star_p = FOUND;
477 case '+': p->justify = RIGHT; break;
478 case '-': p->justify = LEFT; break;
479 case '.': if (p->width == NOT_FOUND)
482 case '0': p->pad = '0'; break;
483 case '1': case '2': case '3':
484 case '4': case '5': case '6':
485 case '7': case '8': case '9': /* gob all the digits */
486 for (i = 0; isdigit(*s); i++, s++)
487 if (i < MAX_FIELD/2 - 1)
490 if (p->width == NOT_FOUND)
491 p->width = atoi(number);
493 p->precision = atoi(number);
494 s--; /* went to far go back */
502 vsnprintf(char *string, size_t length, const char * format, va_list args)
504 vsnprintf(string, length, format, args)
512 char conv_field[MAX_FIELD];
513 double d; /* temporary holder */
517 data.length = length - 1; /* leave room for '\0' */
518 data.holder = string;
523 /* sanity check, the string must be > 1 */
528 for (; *data.pf && (data.counter < data.length); data.pf++) {
529 if ( *data.pf == '%' ) { /* we got a magic % cookie */
530 conv_flag((char *)0, &data); /* initialise format flags */
531 for (state = 1; *data.pf && state;) {
532 switch (*(++data.pf)) {
533 case '\0': /* a NULL here ? ? bail out */
537 case 'f': /* float, double */
539 if (data.a_long == FOUND)
540 d = va_arg(args, LONG_DOUBLE);
542 d = va_arg(args, double);
550 if (data.a_long == FOUND)
551 d = va_arg(args, LONG_DOUBLE);
553 d = va_arg(args, double);
556 * for '%g|%G' ANSI: use f if exponent
557 * is in the range or [-4,p] exclusively
560 if (-4 < i && i < data.precision)
567 case 'E': /* Exponent double */
569 if (data.a_long == FOUND)
570 d = va_arg(args, LONG_DOUBLE);
572 d = va_arg(args, double);
576 case 'u': /* unsigned decimal */
578 if (data.a_longlong == FOUND)
579 d = va_arg(args, unsigned LONG_LONG);
580 else if (data.a_long == FOUND)
581 d = va_arg(args, unsigned long);
583 d = va_arg(args, unsigned int);
587 case 'd': /* decimal */
589 if (data.a_longlong == FOUND)
590 d = va_arg(args, LONG_LONG);
591 else if (data.a_long == FOUND)
592 d = va_arg(args, long);
594 d = va_arg(args, int);
598 case 'o': /* octal */
600 if (data.a_longlong == FOUND)
601 d = va_arg(args, LONG_LONG);
602 else if (data.a_long == FOUND)
603 d = va_arg(args, long);
605 d = va_arg(args, int);
610 case 'X': /* hexadecimal */
612 if (data.a_longlong == FOUND)
613 d = va_arg(args, LONG_LONG);
614 else if (data.a_long == FOUND)
615 d = va_arg(args, long);
617 d = va_arg(args, int);
621 case 'c': /* character */
622 d = va_arg(args, int);
626 case 's': /* string */
628 strings(&data, va_arg(args, char *));
632 *(va_arg(args, int *)) = data.counter; /* what's the count ? */
636 data.a_longlong = FOUND;
640 if (data.a_long == FOUND)
641 data.a_longlong = FOUND;
647 case '%': /* nothing just % */
648 PUT_CHAR('%', &data);
651 case '#': case ' ': case '+': case '*':
652 case '-': case '.': case '0': case '1':
653 case '2': case '3': case '4': case '5':
654 case '6': case '7': case '8': case '9':
655 /* initialize width and precision */
656 for (i = 0; isflag(*data.pf); i++, data.pf++)
657 if (i < MAX_FIELD - 1)
658 conv_field[i] = *data.pf;
659 conv_field[i] = '\0';
660 conv_flag(conv_field, &data);
661 data.pf--; /* went to far go back */
664 /* is this an error ? maybe bail out */
668 } /* end of for state */
670 PUT_CHAR(*data.pf, &data); /* add the char the string */
674 *data.holder = '\0'; /* the end ye ! */
679 #ifndef HAVE_SNPRINTF
683 snprintf(char *string, size_t length, const char * format, ...)
685 snprintf(string, length, format, va_alist)
696 va_start(args, format);
701 rval = vsnprintf (string, length, format, args);
708 #endif /* HAVE_SNPRINTF */
715 /* set of small tests for snprintf() */
722 printf("Suite of test for snprintf:\n");
723 printf("a_format\n");
724 printf("printf() format\n");
725 printf("snprintf() format\n\n");
727 /* Checking the field widths */
729 printf("/%%d/, 336\n");
730 snprintf(holder, sizeof holder, "/%d/\n", 336);
731 printf("/%d/\n", 336);
732 printf("%s\n", holder);
734 printf("/%%2d/, 336\n");
735 snprintf(holder, sizeof holder, "/%2d/\n", 336);
736 printf("/%2d/\n", 336);
737 printf("%s\n", holder);
739 printf("/%%10d/, 336\n");
740 snprintf(holder, sizeof holder, "/%10d/\n", 336);
741 printf("/%10d/\n", 336);
742 printf("%s\n", holder);
744 printf("/%%-10d/, 336\n");
745 snprintf(holder, sizeof holder, "/%-10d/\n", 336);
746 printf("/%-10d/\n", 336);
747 printf("%s\n", holder);
751 printf("/%%lld/, 336\n");
752 snprintf(holder, sizeof holder, "/%lld/\n", (LONG_LONG)336);
753 printf("/%lld/\n", (LONG_LONG)336);
754 printf("%s\n", holder);
756 printf("/%%2qd/, 336\n");
757 snprintf(holder, sizeof holder, "/%2qd/\n", (LONG_LONG)336);
758 printf("/%2qd/\n", (LONG_LONG)336);
759 printf("%s\n", holder);
761 /* floating points */
763 printf("/%%f/, 1234.56\n");
764 snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
765 printf("/%f/\n", 1234.56);
766 printf("%s\n", holder);
768 printf("/%%e/, 1234.56\n");
769 snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
770 printf("/%e/\n", 1234.56);
771 printf("%s\n", holder);
773 printf("/%%4.2f/, 1234.56\n");
774 snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
775 printf("/%4.2f/\n", 1234.56);
776 printf("%s\n", holder);
778 printf("/%%3.1f/, 1234.56\n");
779 snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
780 printf("/%3.1f/\n", 1234.56);
781 printf("%s\n", holder);
783 printf("/%%10.3f/, 1234.56\n");
784 snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
785 printf("/%10.3f/\n", 1234.56);
786 printf("%s\n", holder);
788 printf("/%%10.3e/, 1234.56\n");
789 snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
790 printf("/%10.3e/\n", 1234.56);
791 printf("%s\n", holder);
793 printf("/%%+4.2f/, 1234.56\n");
794 snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
795 printf("/%+4.2f/\n", 1234.56);
796 printf("%s\n", holder);
798 printf("/%%010.2f/, 1234.56\n");
799 snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
800 printf("/%010.2f/\n", 1234.56);
801 printf("%s\n", holder);
803 #define BLURB "Outstanding acting !"
804 /* strings precisions */
806 printf("/%%2s/, \"%s\"\n", BLURB);
807 snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
808 printf("/%2s/\n", BLURB);
809 printf("%s\n", holder);
811 printf("/%%22s/ %s\n", BLURB);
812 snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
813 printf("/%22s/\n", BLURB);
814 printf("%s\n", holder);
816 printf("/%%22.5s/ %s\n", BLURB);
817 snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
818 printf("/%22.5s/\n", BLURB);
819 printf("%s\n", holder);
821 printf("/%%-22.5s/ %s\n", BLURB);
822 snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
823 printf("/%-22.5s/\n", BLURB);
824 printf("%s\n", holder);
828 printf("%%x %%X %%#x, 31, 31, 31\n");
829 snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
830 printf("%x %X %#x\n", 31, 31, 31);
831 printf("%s\n", holder);
833 printf("**%%d**%% d**%% d**, 42, 42, -42\n");
834 snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
835 printf("**%d**% d**% d**\n", 42, 42, -42);
836 printf("%s\n", holder);
840 printf("/%%g/, 31.4\n");
841 snprintf(holder, sizeof holder, "/%g/\n", 31.4);
842 printf("/%g/\n", 31.4);
843 printf("%s\n", holder);
845 printf("/%%.6g/, 31.4\n");
846 snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
847 printf("/%.6g/\n", 31.4);
848 printf("%s\n", holder);
850 printf("/%%.1G/, 31.4\n");
851 snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
852 printf("/%.1G/\n", 31.4);
853 printf("%s\n", holder);
856 printf("abc%n", &i); printf("%d\n", i);
857 snprintf(holder, sizeof holder, "abc%n", &i);
858 printf("%s", holder); printf("%d\n\n", i);
860 printf("%%*.*s --> 10.10\n");
861 snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
862 printf("%*.*s\n", 10, 10, BLURB);
863 printf("%s\n", holder);
865 printf("%%%%%%%%\n");
866 snprintf(holder, sizeof holder, "%%%%\n");
868 printf("%s\n", holder);
870 #define BIG "Hello this is a too big string for the buffer"
871 /* printf("A buffer to small of 10, trying to put this:\n");*/
872 printf("<%%>, %s\n", BIG);
873 i = snprintf(holder, 10, "%s\n", BIG);
874 printf("<%s>\n", BIG);
875 printf("<%s>\n", holder);
881 #endif /* !HAVE_LOCAL_SNPRINTF */