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/autoconf.h>
55 #ifndef HAVE_VSNPRINTF
58 * Find the nth power of 10
72 for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;}
74 for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;}
79 * Find the integral part of the log in base 10
80 * Note: this not a real log10()
81 I just need and approximation(integerpart) of x in:
101 while (result >= r) {result *= .1; i++;}
104 while (result <= r) {result *= 10.; i++;}
110 * This function return the fraction part of a double
111 * and set in ip the integral part.
112 * In many ways it resemble the modf() found on most Un*x
116 integral(double real, double * ip)
125 double real_integral = 0.;
127 /* take care of the obvious */
128 /* equal to zero ? */
134 /* negative number ? */
143 /* the real work :-) */
144 for (j = log_10(real); j >= 0; j--) {
146 s = (real - real_integral)/p;
148 while (i + 1. <= s) {i++;}
149 real_integral += i*p;
152 return (real - real_integral);
155 #define PRECISION 1.e-6
157 * return an ascii representation of the integral part of the number
158 * and set fract to be an ascii representation of the fraction part
159 * the container for the fraction and the integral part or staticly
160 * declare with fix size
164 numtoa(double number, int base, int precision, char ** fract)
166 numtoa(number, base, precision, fract)
174 double ip, fp; /* integer and fraction part */
176 int digits = MAX_INT - 1;
177 static char integral_part[MAX_INT];
178 static char fraction_part[MAX_FRACT];
182 /* taking care of the obvious case: 0.0 */
184 integral_part[0] = '0';
185 integral_part[1] = '\0';
186 fraction_part[0] = '0';
187 fraction_part[1] = '\0';
188 return integral_part;
191 /* for negative numbers */
192 if ((sign = number) < 0.) {
194 digits--; /* sign consume one digit */
197 fraction = integral(number, &ip);
199 /* do the integral part */
201 integral_part[0] = '0';
204 for ( i = 0; i < digits && number != 0.; ++i) {
206 fp = integral(number, &ip);
207 ch = (int)((fp + PRECISION)*base); /* force to round */
208 integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
209 if (! isxdigit(integral_part[i])) /* bail out overflow !! */
215 /* Oh No !! out of bound, ho well fill it up ! */
217 for (i = 0; i < digits; ++i)
218 integral_part[i] = '9';
222 integral_part[i++] = '-';
224 integral_part[i] = '\0';
226 /* reverse every thing */
227 for ( i--, j = 0; j < i; j++, i--)
228 SWAP_INT(integral_part[i], integral_part[j]);
230 /* the fractionnal part */
231 for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision-- ) {
232 fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
233 if (! isdigit(fraction_part[i])) /* underflow ? */
235 fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
237 fraction_part[i] = '\0';
239 if (fract != (char **)0)
240 *fract = fraction_part;
242 return integral_part;
246 /* for %d and friends, it puts in holder
247 * the representation with the right padding
251 decimal(struct DATA *p, double d)
261 p->width -= strlen(tmp);
265 while (*tmp) { /* the integral */
272 /* for %o octal representation */
275 octal(struct DATA *p, double d)
285 p->width -= strlen(tmp);
287 if (p->square == FOUND) /* had prefix '0' for octal */
289 while (*tmp) { /* octal */
296 /* for %x %X hexadecimal representation */
299 hexa(struct DATA *p, double d)
309 p->width -= strlen(tmp);
311 if (p->square == FOUND) { /* prefix '0x' for hexa */
312 PUT_CHAR('0', p); PUT_CHAR(*p->pf, p);
314 while (*tmp) { /* hexa */
315 PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p);
324 strings(struct DATA *p, char *tmp)
334 if (p->precision != NOT_FOUND) /* the smallest number */
335 i = (i < p->precision ? i : p->precision);
338 while (i-- > 0) { /* put the sting */
345 /* %f or %g floating point representation */
348 floating(struct DATA *p, double d)
360 tmp = dtoa(d, p->precision, &tmp2);
361 /* calculate the padding. 1 for the dot */
362 p->width = p->width -
363 ((d > 0. && p->justify == RIGHT) ? 1:0) -
364 ((p->space == FOUND) ? 1:0) -
365 strlen(tmp) - p->precision - 1;
369 while (*tmp) { /* the integral */
373 if (p->precision != 0 || p->square == FOUND)
374 PUT_CHAR('.', p); /* put the '.' */
375 if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
376 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
378 for (; *tmp2; tmp2++)
379 PUT_CHAR(*tmp2, p); /* the fraction */
384 /* %e %E %g exponent representation */
387 exponent(struct DATA *p, double d)
399 d = d / pow_10(j); /* get the Mantissa */
401 tmp = dtoa(d, p->precision, &tmp2);
402 /* 1 for unit, 1 for the '.', 1 for 'e|E',
403 * 1 for '+|-', 3 for 'exp' */
404 /* calculate how much padding need */
405 p->width = p->width -
406 ((d > 0. && p->justify == RIGHT) ? 1:0) -
407 ((p->space == FOUND) ? 1:0) - p->precision - 7;
411 while (*tmp) {/* the integral */
415 if (p->precision != 0 || p->square == FOUND)
416 PUT_CHAR('.', p); /* the '.' */
417 if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
418 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
420 for (; *tmp2; tmp2++)
421 PUT_CHAR(*tmp2, p); /* the fraction */
423 if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
427 if (j >= 0) { /* the sign of the exp */
433 tmp = itoa((double)j);
434 if (j < 9) { /* need to pad the exponent with 0 '000' */
435 PUT_CHAR('0', p); PUT_CHAR('0', p);
438 while (*tmp) { /* the exponent */
445 /* initialize the conversion specifiers */
448 conv_flag(char * s, struct DATA * p)
455 char number[MAX_FIELD/2];
458 /* reset the flags. */
459 p->precision = p->width = NOT_FOUND;
460 p->star_w = p->star_p = NOT_FOUND;
461 p->square = p->space = NOT_FOUND;
462 p->a_long = p->justify = NOT_FOUND;
463 p->a_longlong = NOT_FOUND;
468 case ' ': p->space = FOUND; break;
469 case '#': p->square = FOUND; break;
470 case '*': if (p->width == NOT_FOUND)
471 p->width = p->star_w = FOUND;
473 p->precision = p->star_p = FOUND;
475 case '+': p->justify = RIGHT; break;
476 case '-': p->justify = LEFT; break;
477 case '.': if (p->width == NOT_FOUND)
480 case '0': p->pad = '0'; break;
481 case '1': case '2': case '3':
482 case '4': case '5': case '6':
483 case '7': case '8': case '9': /* gob all the digits */
484 for (i = 0; isdigit(*s); i++, s++)
485 if (i < MAX_FIELD/2 - 1)
488 if (p->width == NOT_FOUND)
489 p->width = atoi(number);
491 p->precision = atoi(number);
492 s--; /* went to far go back */
500 vsnprintf(char *string, size_t length, const char * format, va_list args)
502 vsnprintf(string, length, format, args)
510 char conv_field[MAX_FIELD];
511 double d; /* temporary holder */
515 data.length = length - 1; /* leave room for '\0' */
516 data.holder = string;
521 /* sanity check, the string must be > 1 */
526 for (; *data.pf && (data.counter < data.length); data.pf++) {
527 if ( *data.pf == '%' ) { /* we got a magic % cookie */
528 conv_flag((char *)0, &data); /* initialise format flags */
529 for (state = 1; *data.pf && state;) {
530 switch (*(++data.pf)) {
531 case '\0': /* a NULL here ? ? bail out */
535 case 'f': /* float, double */
537 if (data.a_long == FOUND)
538 d = va_arg(args, LONG_DOUBLE);
540 d = va_arg(args, double);
548 if (data.a_long == FOUND)
549 d = va_arg(args, LONG_DOUBLE);
551 d = va_arg(args, double);
554 * for '%g|%G' ANSI: use f if exponent
555 * is in the range or [-4,p] exclusively
558 if (-4 < i && i < data.precision)
565 case 'E': /* Exponent double */
567 if (data.a_long == FOUND)
568 d = va_arg(args, LONG_DOUBLE);
570 d = va_arg(args, double);
574 case 'u': /* unsigned decimal */
576 if (data.a_longlong == FOUND)
577 d = va_arg(args, unsigned LONG_LONG);
578 else if (data.a_long == FOUND)
579 d = va_arg(args, unsigned long);
581 d = va_arg(args, unsigned int);
585 case 'd': /* decimal */
587 if (data.a_longlong == FOUND)
588 d = va_arg(args, LONG_LONG);
589 else if (data.a_long == FOUND)
590 d = va_arg(args, long);
592 d = va_arg(args, int);
596 case 'o': /* octal */
598 if (data.a_longlong == FOUND)
599 d = va_arg(args, LONG_LONG);
600 else if (data.a_long == FOUND)
601 d = va_arg(args, long);
603 d = va_arg(args, int);
608 case 'X': /* hexadecimal */
610 if (data.a_longlong == FOUND)
611 d = va_arg(args, LONG_LONG);
612 else if (data.a_long == FOUND)
613 d = va_arg(args, long);
615 d = va_arg(args, int);
619 case 'c': /* character */
620 d = va_arg(args, int);
624 case 's': /* string */
626 strings(&data, va_arg(args, char *));
630 *(va_arg(args, int *)) = data.counter; /* what's the count ? */
634 data.a_longlong = FOUND;
638 if (data.a_long == FOUND)
639 data.a_longlong = FOUND;
645 case '%': /* nothing just % */
646 PUT_CHAR('%', &data);
649 case '#': case ' ': case '+': case '*':
650 case '-': case '.': case '0': case '1':
651 case '2': case '3': case '4': case '5':
652 case '6': case '7': case '8': case '9':
653 /* initialize width and precision */
654 for (i = 0; isflag(*data.pf); i++, data.pf++)
655 if (i < MAX_FIELD - 1)
656 conv_field[i] = *data.pf;
657 conv_field[i] = '\0';
658 conv_flag(conv_field, &data);
659 data.pf--; /* went to far go back */
662 /* is this an error ? maybe bail out */
666 } /* end of for state */
668 PUT_CHAR(*data.pf, &data); /* add the char the string */
672 *data.holder = '\0'; /* the end ye ! */
677 #endif /* HAVE_VSNPRINTF */
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);