diff options
-rw-r--r-- | lib/libc/stdio/printfcommon.h | 130 | ||||
-rw-r--r-- | lib/libc/stdio/vfprintf.c | 64 | ||||
-rw-r--r-- | lib/libc/stdio/vfwprintf.c | 96 |
3 files changed, 204 insertions, 86 deletions
diff --git a/lib/libc/stdio/printfcommon.h b/lib/libc/stdio/printfcommon.h new file mode 100644 index 0000000..7bc357a --- /dev/null +++ b/lib/libc/stdio/printfcommon.h @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * This file defines common routines used by both printf and wprintf. + * You must define CHAR to either char or wchar_t prior to including this. + */ + +#define NIOV 8 +struct io_state { + FILE *fp; + struct __suio uio; /* output information: summary */ + struct __siov iov[NIOV];/* ... and individual io vectors */ + struct __siov *iovp; /* pointer to next free slot in iov */ +}; + +static inline void +io_init(struct io_state *iop, FILE *fp) +{ + + iop->uio.uio_iov = iop->iovp = iop->iov; + iop->uio.uio_resid = 0; + iop->uio.uio_iovcnt = 0; + iop->fp = fp; +} + +/* + * WARNING: The buffer passed to io_print() is not copied immediately; it must + * remain valid until io_flush() is called. + */ +static inline int +io_print(struct io_state *iop, const CHAR * __restrict ptr, int len) +{ + + iop->iovp->iov_base = (char *)ptr; + iop->iovp->iov_len = len; + iop->uio.uio_resid += len; + iop->iovp++; + if (++iop->uio.uio_iovcnt >= NIOV) { + iop->iovp = iop->iov; + return (__sprint(iop->fp, &iop->uio)); + } + return (0); +} + +/* + * Choose PADSIZE to trade efficiency vs. size. If larger printf + * fields occur frequently, increase PADSIZE and make the initialisers + * below longer. + */ +#define PADSIZE 16 /* pad chunk size */ +static const CHAR blanks[PADSIZE] = +{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; +static const CHAR zeroes[PADSIZE] = +{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; + +/* + * Pad with blanks or zeroes. 'with' should point to either the blanks array + * or the zeroes array. + */ +static inline int +io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with) +{ + + while (howmany > PADSIZE) { + if (io_print(iop, with, PADSIZE)) + return (-1); + howmany -= PADSIZE; + } + if (howmany > 0 && io_print(iop, with, howmany)) + return (-1); + return (0); +} + +/* + * Print exactly len characters of the string spanning p to ep, truncating + * or padding with 'with' as necessary. + */ +static inline int +io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, + int len, const CHAR * __restrict with) +{ + int p_len; + + p_len = ep - p; + if (p_len > len) + p_len = len; + if (p_len > 0 && io_print(iop, p, p_len)) + return (-1); + return (io_pad(iop, len - (p_len > 0 ? p_len : 0), with)); +} + +static inline int +io_flush(struct io_state *iop) +{ + + iop->iovp = iop->iov; + return (__sprint(iop->fp, &iop->uio)); +} diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index dab331d..69235da 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -72,6 +72,9 @@ static char *__ultoa(u_long, char *, int, int, const char *, int, char, const char *); static char *__wcsconv(wchar_t *, int); +#define CHAR char +#include "printfcommon.h" + /* * Flush out all the vectors defined by the given uio, * then reset it so that it can be reused. @@ -388,7 +391,6 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) int ch; /* character from fmt */ int n, n2; /* handy integer (short term usage) */ char *cp; /* handy char pointer (short term usage) */ - struct __siov *iovp; /* for PRINT macro */ int flags; /* flags as above */ int ret; /* return value accumulator */ int width; /* width from format (%8d), or 0 */ @@ -396,6 +398,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) char sign; /* sign prefix (' ', '+', '-', or \0) */ char thousands_sep; /* locale specific thousands separator */ const char *grouping; /* locale specific numeric grouping rules */ + #ifndef NO_FLOATING_POINT /* * We can decompose the printed representation of floating @@ -436,9 +439,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) int size; /* size of converted field or string */ int prsize; /* max size of printed field */ const char *xdigs; /* digits for %[xX] conversion */ -#define NIOV 8 - struct __suio uio; /* output information: summary */ - struct __siov iov[NIOV];/* ... and individual io vectors */ + struct io_state io; /* I/O buffering state */ char buf[BUF]; /* buffer with space for digits of uintmax_t */ char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ union arg *argtable; /* args, built due to positional arg */ @@ -447,56 +448,25 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) va_list orgap; /* original argument pointer */ char *convbuf; /* wide to multibyte conversion result */ - /* - * Choose PADSIZE to trade efficiency vs. size. If larger printf - * fields occur frequently, increase PADSIZE and make the initialisers - * below longer. - */ -#define PADSIZE 16 /* pad chunk size */ - static char blanks[PADSIZE] = - {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; - static char zeroes[PADSIZE] = - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; - static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; - /* - * BEWARE, these `goto error' on error, and PAD uses `n'. - */ + /* BEWARE, these `goto error' on error. */ #define PRINT(ptr, len) { \ - iovp->iov_base = (ptr); \ - iovp->iov_len = (len); \ - uio.uio_resid += (len); \ - iovp++; \ - if (++uio.uio_iovcnt >= NIOV) { \ - if (__sprint(fp, &uio)) \ - goto error; \ - iovp = iov; \ - } \ + if (io_print(&io, (ptr), (len))) \ + goto error; \ } #define PAD(howmany, with) { \ - if ((n = (howmany)) > 0) { \ - while (n > PADSIZE) { \ - PRINT(with, PADSIZE); \ - n -= PADSIZE; \ - } \ - PRINT(with, n); \ - } \ + if (io_pad(&io, (howmany), (with))) \ + goto error; \ +} +#define PRINTANDPAD(p, ep, len, with) { \ + if (io_printandpad(&io, (p), (ep), (len), (with))) \ + goto error; \ } -#define PRINTANDPAD(p, ep, len, with) do { \ - n2 = (ep) - (p); \ - if (n2 > (len)) \ - n2 = (len); \ - if (n2 > 0) \ - PRINT((p), n2); \ - PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ -} while(0) #define FLUSH() { \ - if (uio.uio_resid && __sprint(fp, &uio)) \ + if (io_flush(&io)) \ goto error; \ - uio.uio_iovcnt = 0; \ - iovp = iov; \ } /* @@ -583,9 +553,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) argtable = NULL; nextarg = 1; va_copy(orgap, ap); - uio.uio_iov = iovp = iov; - uio.uio_resid = 0; - uio.uio_iovcnt = 0; + io_init(&io, fp); ret = 0; #ifndef NO_FLOATING_POINT dtoaresult = NULL; diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c index 9f06f1b..aa2fdc8 100644 --- a/lib/libc/stdio/vfwprintf.c +++ b/lib/libc/stdio/vfwprintf.c @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include "fvwrite.h" #include "printflocal.h" +static int __sprint(FILE *, struct __suio *); static int __sbprintf(FILE *, const wchar_t *, va_list); static wint_t __xfputwc(wchar_t, FILE *); static wchar_t *__ujtoa(uintmax_t, wchar_t *, int, int, const char *, int, @@ -74,6 +75,37 @@ static wchar_t *__ultoa(u_long, wchar_t *, int, int, const char *, int, char, const char *); static wchar_t *__mbsconv(char *, int); +#define CHAR wchar_t +#include "printfcommon.h" + +/* + * Flush out all the vectors defined by the given uio, + * then reset it so that it can be reused. + * + * XXX The fact that we do this a character at a time and convert to a + * multibyte character sequence even if the destination is a wide + * string eclipses the benefits of buffering. + */ +static int +__sprint(FILE *fp, struct __suio *uio) +{ + struct __siov *iov; + wchar_t *p; + int i, len; + + iov = uio->uio_iov; + for (; uio->uio_resid != 0; uio->uio_resid -= len, iov++) { + p = (wchar_t *)iov->iov_base; + len = iov->iov_len; + for (i = 0; i < len; i++) { + if (__xfputwc(p[i], fp) == WEOF) + return (-1); + } + } + uio->uio_iovcnt = 0; + return (0); +} + /* * Helper function for `fprintf to unbuffered unix file': creates a * temporary buffer. We only work on write-only files; this avoids @@ -414,14 +446,14 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) { wchar_t *fmt; /* format string */ wchar_t ch; /* character from fmt */ - int n, n2, n3; /* handy integer (short term usage) */ + int n, n2; /* handy integer (short term usage) */ wchar_t *cp; /* handy char pointer (short term usage) */ int flags; /* flags as above */ int ret; /* return value accumulator */ int width; /* width from format (%8d), or 0 */ int prec; /* precision from format; <0 for N/A */ wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */ - char thousands_sep; /* locale specific thousands separator */ + wchar_t thousands_sep; /* locale specific thousands separator */ const char *grouping; /* locale specific numeric grouping rules */ #ifndef NO_FLOATING_POINT /* @@ -463,6 +495,7 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) int size; /* size of converted field or string */ int prsize; /* max size of printed field */ const char *xdigs; /* digits for [xX] conversion */ + struct io_state io; /* I/O buffering state */ wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */ wchar_t ox[2]; /* space for 0x hex-prefix */ union arg *argtable; /* args, built due to positional arg */ @@ -471,45 +504,26 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) va_list orgap; /* original argument pointer */ wchar_t *convbuf; /* multibyte to wide conversion result */ - /* - * Choose PADSIZE to trade efficiency vs. size. If larger printf - * fields occur frequently, increase PADSIZE and make the initialisers - * below longer. - */ -#define PADSIZE 16 /* pad chunk size */ - static wchar_t blanks[PADSIZE] = - {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; - static wchar_t zeroes[PADSIZE] = - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; - static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; - /* - * BEWARE, these `goto error' on error, PRINT uses `n2' and - * PAD uses `n'. - */ + /* BEWARE, these `goto error' on error. */ #define PRINT(ptr, len) do { \ - for (n3 = 0; n3 < (len); n3++) \ - __xfputwc((ptr)[n3], fp); \ + if (io_print(&io, (ptr), (len))) \ + goto error; \ } while (0) -#define PAD(howmany, with) do { \ - if ((n = (howmany)) > 0) { \ - while (n > PADSIZE) { \ - PRINT(with, PADSIZE); \ - n -= PADSIZE; \ - } \ - PRINT(with, n); \ - } \ -} while (0) -#define PRINTANDPAD(p, ep, len, with) do { \ - n2 = (ep) - (p); \ - if (n2 > (len)) \ - n2 = (len); \ - if (n2 > 0) \ - PRINT((p), n2); \ - PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ -} while(0) +#define PAD(howmany, with) { \ + if (io_pad(&io, (howmany), (with))) \ + goto error; \ +} +#define PRINTANDPAD(p, ep, len, with) { \ + if (io_printandpad(&io, (p), (ep), (len), (with))) \ + goto error; \ +} +#define FLUSH() { \ + if (io_flush(&io)) \ + goto error; \ +} /* * Get the argument indexed by nextarg. If the argument table is @@ -591,6 +605,7 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) argtable = NULL; nextarg = 1; va_copy(orgap, ap); + io_init(&io, fp); ret = 0; #ifndef NO_FLOATING_POINT decimal_point = localeconv()->decimal_point; @@ -1120,8 +1135,10 @@ number: if ((dprec = prec) >= 0) if (!expchar) { /* %[fF] or sufficiently short %[gG] */ if (expt <= 0) { PRINT(zeroes, 1); - if (prec || flags & ALT) - PRINT(decimal_point, 1); + if (prec || flags & ALT) { + buf[0] = *decimal_point; + PRINT(buf, 1); + } PAD(-expt, zeroes); /* already handled initial 0's */ prec += expt; @@ -1173,8 +1190,11 @@ number: if ((dprec = prec) >= 0) /* finally, adjust ret */ ret += prsize; + + FLUSH(); /* copy out the I/O vectors */ } done: + FLUSH(); error: va_end(orgap); if (convbuf != NULL) |