diff options
author | das <das@FreeBSD.org> | 2009-01-15 04:49:43 +0000 |
---|---|---|
committer | das <das@FreeBSD.org> | 2009-01-15 04:49:43 +0000 |
commit | 8e6c149fe3004d4eb2e0a18b523e6a135b498b5f (patch) | |
tree | 6d08eff0b17d9591026e379a9b3a9763c3be0993 /lib/libc/stdio/printfcommon.h | |
parent | 692fda68c21b7c0ddecfef66518b491ce012b953 (diff) | |
download | FreeBSD-src-8e6c149fe3004d4eb2e0a18b523e6a135b498b5f.zip FreeBSD-src-8e6c149fe3004d4eb2e0a18b523e6a135b498b5f.tar.gz |
Reduce code duplication by moving functions that are identical in both
vfprintf.c and vfwprintf.c (except for char/wchar_t differences) to a
common header file.
Diffstat (limited to 'lib/libc/stdio/printfcommon.h')
-rw-r--r-- | lib/libc/stdio/printfcommon.h | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/lib/libc/stdio/printfcommon.h b/lib/libc/stdio/printfcommon.h index 7bc357a..a3a32f6 100644 --- a/lib/libc/stdio/printfcommon.h +++ b/lib/libc/stdio/printfcommon.h @@ -37,6 +37,28 @@ * You must define CHAR to either char or wchar_t prior to including this. */ + +#ifndef NO_FLOATING_POINT + +#define dtoa __dtoa +#define freedtoa __freedtoa + +#include <float.h> +#include <math.h> +#include "floatio.h" +#include "gdtoa.h" + +#define DEFPREC 6 + +static int exponent(CHAR *, int, CHAR); + +#endif /* !NO_FLOATING_POINT */ + +static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *, int, char, + const char *); +static CHAR *__ultoa(u_long, CHAR *, int, int, const char *, int, char, + const char *); + #define NIOV 8 struct io_state { FILE *fp; @@ -128,3 +150,197 @@ io_flush(struct io_state *iop) iop->iovp = iop->iov; return (__sprint(iop->fp, &iop->uio)); } + +/* + * Convert an unsigned long to ASCII for printf purposes, returning + * a pointer to the first character of the string representation. + * Octal numbers can be forced to have a leading zero; hex numbers + * use the given digits. + */ +static CHAR * +__ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs, + int needgrp, char thousep, const char *grp) +{ + CHAR *cp = endp; + long sval; + int ndig; + + /* + * Handle the three cases separately, in the hope of getting + * better/faster code. + */ + switch (base) { + case 10: + if (val < 10) { /* many numbers are 1 digit */ + *--cp = to_char(val); + return (cp); + } + ndig = 0; + /* + * On many machines, unsigned arithmetic is harder than + * signed arithmetic, so we do at most one unsigned mod and + * divide; this is sufficient to reduce the range of + * the incoming value to where signed arithmetic works. + */ + if (val > LONG_MAX) { + *--cp = to_char(val % 10); + ndig++; + sval = val / 10; + } else + sval = val; + do { + *--cp = to_char(sval % 10); + ndig++; + /* + * If (*grp == CHAR_MAX) then no more grouping + * should be performed. + */ + if (needgrp && ndig == *grp && *grp != CHAR_MAX + && sval > 9) { + *--cp = thousep; + ndig = 0; + /* + * If (*(grp+1) == '\0') then we have to + * use *grp character (last grouping rule) + * for all next cases + */ + if (*(grp+1) != '\0') + grp++; + } + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + if (octzero && *cp != '0') + *--cp = '0'; + break; + + case 16: + do { + *--cp = xdigs[val & 15]; + val >>= 4; + } while (val); + break; + + default: /* oops */ + abort(); + } + return (cp); +} + +/* Identical to __ultoa, but for intmax_t. */ +static CHAR * +__ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs, + int needgrp, char thousep, const char *grp) +{ + CHAR *cp = endp; + intmax_t sval; + int ndig; + + /* quick test for small values; __ultoa is typically much faster */ + /* (perhaps instead we should run until small, then call __ultoa?) */ + if (val <= ULONG_MAX) + return (__ultoa((u_long)val, endp, base, octzero, xdigs, + needgrp, thousep, grp)); + switch (base) { + case 10: + if (val < 10) { + *--cp = to_char(val % 10); + return (cp); + } + ndig = 0; + if (val > INTMAX_MAX) { + *--cp = to_char(val % 10); + ndig++; + sval = val / 10; + } else + sval = val; + do { + *--cp = to_char(sval % 10); + ndig++; + /* + * If (*grp == CHAR_MAX) then no more grouping + * should be performed. + */ + if (needgrp && *grp != CHAR_MAX && ndig == *grp + && sval > 9) { + *--cp = thousep; + ndig = 0; + /* + * If (*(grp+1) == '\0') then we have to + * use *grp character (last grouping rule) + * for all next cases + */ + if (*(grp+1) != '\0') + grp++; + } + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + if (octzero && *cp != '0') + *--cp = '0'; + break; + + case 16: + do { + *--cp = xdigs[val & 15]; + val >>= 4; + } while (val); + break; + + default: + abort(); + } + return (cp); +} + +#ifndef NO_FLOATING_POINT + +static int +exponent(CHAR *p0, int exp, CHAR fmtch) +{ + CHAR *p, *t; + CHAR expbuf[MAXEXPDIG]; + + p = p0; + *p++ = fmtch; + if (exp < 0) { + exp = -exp; + *p++ = '-'; + } + else + *p++ = '+'; + t = expbuf + MAXEXPDIG; + if (exp > 9) { + do { + *--t = to_char(exp % 10); + } while ((exp /= 10) > 9); + *--t = to_char(exp); + for (; t < expbuf + MAXEXPDIG; *p++ = *t++); + } + else { + /* + * Exponents for decimal floating point conversions + * (%[eEgG]) must be at least two characters long, + * whereas exponents for hexadecimal conversions can + * be only one character long. + */ + if (fmtch == 'e' || fmtch == 'E') + *p++ = '0'; + *p++ = to_char(exp); + } + return (p - p0); +} + +#endif /* !NO_FLOATING_POINT */ |