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_SNPRINTF and HAVE_VSNPRINTF
29 * add #include <config.h> ifdef HAVE_CONFIG_H
30 * cosmetic change, when exponent is 0 print xxxE+00
33 * put the program under LGPL.
35 * added changes from Miles Bader
36 * corrected a bug with %f
37 * added support for %#g
38 * added more comments :-)
40 * supporting must ANSI syntaxic_sugars
44 THANKS(for the patches and ideas):
52 #include <freeradius-devel/ident.h>
55 #include <freeradius-devel/autoconf.h>
58 #ifndef HAVE_VSNPRINTF
61 * Find the nth power of 10
75 for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;}
77 for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;}
82 * Find the integral part of the log in base 10
83 * Note: this not a real log10()
84 I just need and approximation(integerpart) of x in:
104 while (result >= r) {result *= .1; i++;}
107 while (result <= r) {result *= 10.; i++;}
113 * This function return the fraction part of a double
114 * and set in ip the integral part.
115 * In many ways it resemble the modf() found on most Un*x
119 integral(double real, double * ip)
128 double real_integral = 0.;
130 /* take care of the obvious */
131 /* equal to zero ? */
137 /* negative number ? */
146 /* the real work :-) */
147 for (j = log_10(real); j >= 0; j--) {
149 s = (real - real_integral)/p;
151 while (i + 1. <= s) {i++;}
152 real_integral += i*p;
155 return (real - real_integral);
158 #define PRECISION 1.e-6
160 * return an ascii representation of the integral part of the number
161 * and set fract to be an ascii representation of the fraction part
162 * the container for the fraction and the integral part or staticly
163 * declare with fix size
167 numtoa(double number, int base, int precision, char ** fract)
169 numtoa(number, base, precision, fract)
177 double ip, fp; /* integer and fraction part */
179 int digits = MAX_INT - 1;
180 static char integral_part[MAX_INT];
181 static char fraction_part[MAX_FRACT];
185 /* taking care of the obvious case: 0.0 */
187 integral_part[0] = '0';
188 integral_part[1] = '\0';
189 fraction_part[0] = '0';
190 fraction_part[1] = '\0';
191 return integral_part;
194 /* for negative numbers */
195 if ((sign = number) < 0.) {
197 digits--; /* sign consume one digit */
200 fraction = integral(number, &ip);
202 /* do the integral part */
204 integral_part[0] = '0';
207 for ( i = 0; i < digits && number != 0.; ++i) {
209 fp = integral(number, &ip);
210 ch = (int)((fp + PRECISION)*base); /* force to round */
211 integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
212 if (! isxdigit(integral_part[i])) /* bail out overflow !! */
218 /* Oh No !! out of bound, ho well fill it up ! */
220 for (i = 0; i < digits; ++i)
221 integral_part[i] = '9';
225 integral_part[i++] = '-';
227 integral_part[i] = '\0';
229 /* reverse every thing */
230 for ( i--, j = 0; j < i; j++, i--)
231 SWAP_INT(integral_part[i], integral_part[j]);
233 /* the fractionnal part */
234 for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision-- ) {
235 fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
236 if (! isdigit(fraction_part[i])) /* underflow ? */
238 fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
240 fraction_part[i] = '\0';
242 if (fract != (char **)0)
243 *fract = fraction_part;
245 return integral_part;
249 /* for %d and friends, it puts in holder
250 * the representation with the right padding
254 decimal(struct DATA *p, double d)
264 p->width -= strlen(tmp);
268 while (*tmp) { /* the integral */
275 /* for %o octal representation */
278 octal(struct DATA *p, double d)
288 p->width -= strlen(tmp);
290 if (p->square == FOUND) /* had prefix '0' for octal */
292 while (*tmp) { /* octal */
299 /* for %x %X hexadecimal representation */
302 hexa(struct DATA *p, double d)
312 p->width -= strlen(tmp);
314 if (p->square == FOUND) { /* prefix '0x' for hexa */
315 PUT_CHAR('0', p); PUT_CHAR(*p->pf, p);
317 while (*tmp) { /* hexa */
318 PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p);
327 strings(struct DATA *p, char *tmp)
337 if (p->precision != NOT_FOUND) /* the smallest number */
338 i = (i < p->precision ? i : p->precision);
341 while (i-- > 0) { /* put the sting */
348 /* %f or %g floating point representation */
351 floating(struct DATA *p, double d)
363 tmp = dtoa(d, p->precision, &tmp2);
364 /* calculate the padding. 1 for the dot */
365 p->width = p->width -
366 ((d > 0. && p->justify == RIGHT) ? 1:0) -
367 ((p->space == FOUND) ? 1:0) -
368 strlen(tmp) - p->precision - 1;
372 while (*tmp) { /* the integral */
376 if (p->precision != 0 || p->square == FOUND)
377 PUT_CHAR('.', p); /* put the '.' */
378 if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
379 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
381 for (; *tmp2; tmp2++)
382 PUT_CHAR(*tmp2, p); /* the fraction */
387 /* %e %E %g exponent representation */
390 exponent(struct DATA *p, double d)
402 d = d / pow_10(j); /* get the Mantissa */
404 tmp = dtoa(d, p->precision, &tmp2);
405 /* 1 for unit, 1 for the '.', 1 for 'e|E',
406 * 1 for '+|-', 3 for 'exp' */
407 /* calculate how much padding need */
408 p->width = p->width -
409 ((d > 0. && p->justify == RIGHT) ? 1:0) -
410 ((p->space == FOUND) ? 1:0) - p->precision - 7;
414 while (*tmp) {/* the integral */
418 if (p->precision != 0 || p->square == FOUND)
419 PUT_CHAR('.', p); /* the '.' */
420 if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
421 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
423 for (; *tmp2; tmp2++)
424 PUT_CHAR(*tmp2, p); /* the fraction */
426 if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
430 if (j >= 0) { /* the sign of the exp */
436 tmp = itoa((double)j);
437 if (j < 9) { /* need to pad the exponent with 0 '000' */
438 PUT_CHAR('0', p); PUT_CHAR('0', p);
441 while (*tmp) { /* the exponent */
448 /* initialize the conversion specifiers */
451 conv_flag(char * s, struct DATA * p)
458 char number[MAX_FIELD/2];
461 /* reset the flags. */
462 p->precision = p->width = NOT_FOUND;
463 p->star_w = p->star_p = NOT_FOUND;
464 p->square = p->space = NOT_FOUND;
465 p->a_long = p->justify = NOT_FOUND;
466 p->a_longlong = NOT_FOUND;
471 case ' ': p->space = FOUND; break;
472 case '#': p->square = FOUND; break;
473 case '*': if (p->width == NOT_FOUND)
474 p->width = p->star_w = FOUND;
476 p->precision = p->star_p = FOUND;
478 case '+': p->justify = RIGHT; break;
479 case '-': p->justify = LEFT; break;
480 case '.': if (p->width == NOT_FOUND)
483 case '0': p->pad = '0'; break;
484 case '1': case '2': case '3':
485 case '4': case '5': case '6':
486 case '7': case '8': case '9': /* gob all the digits */
487 for (i = 0; isdigit(*s); i++, s++)
488 if (i < MAX_FIELD/2 - 1)
491 if (p->width == NOT_FOUND)
492 p->width = atoi(number);
494 p->precision = atoi(number);
495 s--; /* went to far go back */
503 vsnprintf(char *string, size_t length, const char * format, va_list args)
505 vsnprintf(string, length, format, args)
513 char conv_field[MAX_FIELD];
514 double d; /* temporary holder */
518 data.length = length - 1; /* leave room for '\0' */
519 data.holder = string;
524 /* sanity check, the string must be > 1 */
529 for (; *data.pf && (data.counter < data.length); data.pf++) {
530 if ( *data.pf == '%' ) { /* we got a magic % cookie */
531 conv_flag((char *)0, &data); /* initialise format flags */
532 for (state = 1; *data.pf && state;) {
533 switch (*(++data.pf)) {
534 case '\0': /* a NULL here ? ? bail out */
538 case 'f': /* float, double */
540 if (data.a_long == FOUND)
541 d = va_arg(args, LONG_DOUBLE);
543 d = va_arg(args, double);
551 if (data.a_long == FOUND)
552 d = va_arg(args, LONG_DOUBLE);
554 d = va_arg(args, double);
557 * for '%g|%G' ANSI: use f if exponent
558 * is in the range or [-4,p] exclusively
561 if (-4 < i && i < data.precision)
568 case 'E': /* Exponent double */
570 if (data.a_long == FOUND)
571 d = va_arg(args, LONG_DOUBLE);
573 d = va_arg(args, double);
577 case 'u': /* unsigned decimal */
579 if (data.a_longlong == FOUND)
580 d = va_arg(args, unsigned LONG_LONG);
581 else if (data.a_long == FOUND)
582 d = va_arg(args, unsigned long);
584 d = va_arg(args, unsigned int);
588 case 'd': /* decimal */
590 if (data.a_longlong == FOUND)
591 d = va_arg(args, LONG_LONG);
592 else if (data.a_long == FOUND)
593 d = va_arg(args, long);
595 d = va_arg(args, int);
599 case 'o': /* octal */
601 if (data.a_longlong == FOUND)
602 d = va_arg(args, LONG_LONG);
603 else if (data.a_long == FOUND)
604 d = va_arg(args, long);
606 d = va_arg(args, int);
611 case 'X': /* hexadecimal */
613 if (data.a_longlong == FOUND)
614 d = va_arg(args, LONG_LONG);
615 else if (data.a_long == FOUND)
616 d = va_arg(args, long);
618 d = va_arg(args, int);
622 case 'c': /* character */
623 d = va_arg(args, int);
627 case 's': /* string */
629 strings(&data, va_arg(args, char *));
633 *(va_arg(args, int *)) = data.counter; /* what's the count ? */
637 data.a_longlong = FOUND;
641 if (data.a_long == FOUND)
642 data.a_longlong = FOUND;
648 case '%': /* nothing just % */
649 PUT_CHAR('%', &data);
652 case '#': case ' ': case '+': case '*':
653 case '-': case '.': case '0': case '1':
654 case '2': case '3': case '4': case '5':
655 case '6': case '7': case '8': case '9':
656 /* initialize width and precision */
657 for (i = 0; isflag(*data.pf); i++, data.pf++)
658 if (i < MAX_FIELD - 1)
659 conv_field[i] = *data.pf;
660 conv_field[i] = '\0';
661 conv_flag(conv_field, &data);
662 data.pf--; /* went to far go back */
665 /* is this an error ? maybe bail out */
669 } /* end of for state */
671 PUT_CHAR(*data.pf, &data); /* add the char the string */
675 *data.holder = '\0'; /* the end ye ! */
680 #endif /* HAVE_VSNPRINTF */
682 #ifndef HAVE_SNPRINTF
686 snprintf(char *string, size_t length, const char * format, ...)
688 snprintf(string, length, format, va_alist)
699 va_start(args, format);
704 rval = vsnprintf (string, length, format, args);
711 #endif /* HAVE_SNPRINTF */
718 /* set of small tests for snprintf() */
725 printf("Suite of test for snprintf:\n");
726 printf("a_format\n");
727 printf("printf() format\n");
728 printf("snprintf() format\n\n");
730 /* Checking the field widths */
732 printf("/%%d/, 336\n");
733 snprintf(holder, sizeof holder, "/%d/\n", 336);
734 printf("/%d/\n", 336);
735 printf("%s\n", holder);
737 printf("/%%2d/, 336\n");
738 snprintf(holder, sizeof holder, "/%2d/\n", 336);
739 printf("/%2d/\n", 336);
740 printf("%s\n", holder);
742 printf("/%%10d/, 336\n");
743 snprintf(holder, sizeof holder, "/%10d/\n", 336);
744 printf("/%10d/\n", 336);
745 printf("%s\n", holder);
747 printf("/%%-10d/, 336\n");
748 snprintf(holder, sizeof holder, "/%-10d/\n", 336);
749 printf("/%-10d/\n", 336);
750 printf("%s\n", holder);
754 printf("/%%lld/, 336\n");
755 snprintf(holder, sizeof holder, "/%lld/\n", (LONG_LONG)336);
756 printf("/%lld/\n", (LONG_LONG)336);
757 printf("%s\n", holder);
759 printf("/%%2qd/, 336\n");
760 snprintf(holder, sizeof holder, "/%2qd/\n", (LONG_LONG)336);
761 printf("/%2qd/\n", (LONG_LONG)336);
762 printf("%s\n", holder);
764 /* floating points */
766 printf("/%%f/, 1234.56\n");
767 snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
768 printf("/%f/\n", 1234.56);
769 printf("%s\n", holder);
771 printf("/%%e/, 1234.56\n");
772 snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
773 printf("/%e/\n", 1234.56);
774 printf("%s\n", holder);
776 printf("/%%4.2f/, 1234.56\n");
777 snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
778 printf("/%4.2f/\n", 1234.56);
779 printf("%s\n", holder);
781 printf("/%%3.1f/, 1234.56\n");
782 snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
783 printf("/%3.1f/\n", 1234.56);
784 printf("%s\n", holder);
786 printf("/%%10.3f/, 1234.56\n");
787 snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
788 printf("/%10.3f/\n", 1234.56);
789 printf("%s\n", holder);
791 printf("/%%10.3e/, 1234.56\n");
792 snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
793 printf("/%10.3e/\n", 1234.56);
794 printf("%s\n", holder);
796 printf("/%%+4.2f/, 1234.56\n");
797 snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
798 printf("/%+4.2f/\n", 1234.56);
799 printf("%s\n", holder);
801 printf("/%%010.2f/, 1234.56\n");
802 snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
803 printf("/%010.2f/\n", 1234.56);
804 printf("%s\n", holder);
806 #define BLURB "Outstanding acting !"
807 /* strings precisions */
809 printf("/%%2s/, \"%s\"\n", BLURB);
810 snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
811 printf("/%2s/\n", BLURB);
812 printf("%s\n", holder);
814 printf("/%%22s/ %s\n", BLURB);
815 snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
816 printf("/%22s/\n", BLURB);
817 printf("%s\n", holder);
819 printf("/%%22.5s/ %s\n", BLURB);
820 snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
821 printf("/%22.5s/\n", BLURB);
822 printf("%s\n", holder);
824 printf("/%%-22.5s/ %s\n", BLURB);
825 snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
826 printf("/%-22.5s/\n", BLURB);
827 printf("%s\n", holder);
831 printf("%%x %%X %%#x, 31, 31, 31\n");
832 snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
833 printf("%x %X %#x\n", 31, 31, 31);
834 printf("%s\n", holder);
836 printf("**%%d**%% d**%% d**, 42, 42, -42\n");
837 snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
838 printf("**%d**% d**% d**\n", 42, 42, -42);
839 printf("%s\n", holder);
843 printf("/%%g/, 31.4\n");
844 snprintf(holder, sizeof holder, "/%g/\n", 31.4);
845 printf("/%g/\n", 31.4);
846 printf("%s\n", holder);
848 printf("/%%.6g/, 31.4\n");
849 snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
850 printf("/%.6g/\n", 31.4);
851 printf("%s\n", holder);
853 printf("/%%.1G/, 31.4\n");
854 snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
855 printf("/%.1G/\n", 31.4);
856 printf("%s\n", holder);
859 printf("abc%n", &i); printf("%d\n", i);
860 snprintf(holder, sizeof holder, "abc%n", &i);
861 printf("%s", holder); printf("%d\n\n", i);
863 printf("%%*.*s --> 10.10\n");
864 snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
865 printf("%*.*s\n", 10, 10, BLURB);
866 printf("%s\n", holder);
868 printf("%%%%%%%%\n");
869 snprintf(holder, sizeof holder, "%%%%\n");
871 printf("%s\n", holder);
873 #define BIG "Hello this is a too big string for the buffer"
874 /* printf("A buffer to small of 10, trying to put this:\n");*/
875 printf("<%%>, %s\n", BIG);
876 i = snprintf(holder, 10, "%s\n", BIG);
877 printf("<%s>\n", BIG);
878 printf("<%s>\n", holder);