--- vfprintf.c 2010-09-17 10:38:26.434032245 -0700 +++ vcb_printf.c 2010-09-17 14:21:24.533422834 -0700 @@ -62,18 +62,15 @@ #include "libc_private.h" #include "local.h" #include "fvwrite.h" #include "printflocal.h" -static int __sprint(FILE *, struct __suio *); -static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0) - __noinline; static char *__wcsconv(wchar_t *, int); #define CHAR char + #include "printfcommon.h" -#include "printfcommon_io.h" struct grouping_state { char *thousands_sep; /* locale-specific thousands separator */ int thousep_len; /* length of thousands_sep */ const char *grouping; /* locale-specific numeric grouping rules */ @@ -81,10 +78,63 @@ int nseps; /* number of group separators with ' */ int nrepeats; /* number of repeats of the last group */ }; /* + * XXX no errno in kernel... make func() set it? + */ + +static inline int +io_print(cb_printf_f *func, void *arg, const CHAR *__restrict ptr, int len) +{ + return (func(ptr, len, arg)); +} + +/* + * Pad with blanks or zeroes. 'with' should point to either the blanks + * array or the zeroes array. + */ +static inline int +io_pad(cb_printf_f *func, void *arg, int howmany, const CHAR * __restrict with) +{ + int n; + + while (howmany > 0) { + n = (howmany >= PADSIZE) ? PADSIZE : howmany; + if (io_print(func, arg, with, n)) + return (-1); + howmany -= n; + } + 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(cb_printf_f func, void *arg, 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) { + if (io_print(func, arg, p, p_len)) + return (-1); + } else { + p_len = 0; + } + return (io_pad(func, arg, len - p_len, with)); +} + + + + +/* * Initialize the thousands' grouping state in preparation to print a * number with ndigits digits. This routine returns the total number * of bytes that will be needed. */ static int @@ -114,94 +164,37 @@ /* * Print a number with thousands' separators. */ static int -grouping_print(struct grouping_state *gs, struct io_state *iop, +grouping_print(struct grouping_state *gs, cb_printf_f *func, void *arg, const CHAR *cp, const CHAR *ep) { const CHAR *cp0 = cp; - if (io_printandpad(iop, cp, ep, gs->lead, zeroes)) + if (io_printandpad(func, arg, cp, ep, gs->lead, zeroes)) return (-1); cp += gs->lead; while (gs->nseps > 0 || gs->nrepeats > 0) { if (gs->nrepeats > 0) gs->nrepeats--; else { gs->grouping--; gs->nseps--; } - if (io_print(iop, gs->thousands_sep, gs->thousep_len)) + if (io_print(func, arg, gs->thousands_sep, gs->thousep_len)) return (-1); - if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes)) + if (io_printandpad(func, arg, cp, ep, *gs->grouping, zeroes)) return (-1); cp += *gs->grouping; } if (cp > ep) cp = ep; return (cp - cp0); } /* - * Flush out all the vectors defined by the given uio, - * then reset it so that it can be reused. - */ -static int -__sprint(FILE *fp, struct __suio *uio) -{ - int err; - - if (uio->uio_resid == 0) { - uio->uio_iovcnt = 0; - return (0); - } - err = __sfvwrite(fp, uio); - uio->uio_resid = 0; - uio->uio_iovcnt = 0; - return (err); -} - -/* - * Helper function for `fprintf to unbuffered unix file': creates a - * temporary buffer. We only work on write-only files; this avoids - * worries about ungetc buffers and so forth. - */ -static int -__sbprintf(FILE *fp, const char *fmt, va_list ap) -{ - int ret; - FILE fake = FAKE_FILE; - unsigned char buf[BUFSIZ]; - - /* XXX This is probably not needed. */ - if (prepwrite(fp) != 0) - return (EOF); - - /* copy the important variables */ - fake._flags = fp->_flags & ~__SNBF; - fake._file = fp->_file; - fake._cookie = fp->_cookie; - fake._write = fp->_write; - fake._orientation = fp->_orientation; - fake._mbstate = fp->_mbstate; - - /* set up the buffer */ - fake._bf._base = fake._p = buf; - fake._bf._size = fake._w = sizeof(buf); - fake._lbfsize = 0; /* not actually used, but Just In Case */ - - /* do the work, then copy any error status */ - ret = __vfprintf(&fake, fmt, ap); - if (ret >= 0 && __fflush(&fake)) - ret = EOF; - if (fake._flags & __SERR) - fp->_flags |= __SERR; - return (ret); -} - -/* * Convert a wide character string argument for the %ls format to a multibyte * string representation. If not -1, prec specifies the maximum number of * bytes to output, and also means that we can't assume that the wide char. * string ends is null-terminated. */ @@ -256,30 +249,24 @@ } convbuf[nbytes] = '\0'; return (convbuf); } -/* - * MT-safe version - */ +/*XXX diff files... */ int -vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) - +cb_printf(cb_printf_f *cb_func, void *cb_arg, const char * __restrict fmt0, ...) { - int ret; + va_list ap; + int rc; - FLOCKFILE(fp); - /* optimise fprintf(stderr) (and other unbuffered Unix files) */ - if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && - fp->_file >= 0) - ret = __sbprintf(fp, fmt0, ap); - else - ret = __vfprintf(fp, fmt0, ap); - FUNLOCKFILE(fp); - return (ret); + va_start(ap, fmt0); + rc = vcb_printf(cb_func, cb_arg, fmt0, ap); + va_end(ap); + return (rc); } + /* * The size of the buffer we use as scratch space for integer * conversions, among other things. We need enough space to * write a uintmax_t in octal (plus one byte). */ @@ -287,15 +274,13 @@ #define BUF 32 #else #error "BUF must be large enough to format a uintmax_t" #endif -/* - * Non-MT-safe version - */ int -__vfprintf(FILE *fp, const char *fmt0, va_list ap) +vcb_printf(cb_printf_f *cb_func, void *cb_arg, + const char * __restrict fmt0, va_list ap) { char *fmt; /* format string */ int ch; /* character from fmt */ int n, n2; /* handy integer (short term usage) */ char *cp; /* handy char pointer (short term usage) */ @@ -342,39 +327,39 @@ int dprec; /* a copy of prec if [diouxX], 0 otherwise */ int realsz; /* field size expanded by dprec, sign, etc */ 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 */ 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 */ union arg statargtable [STATIC_ARG_TBL_SIZE]; int nextarg; /* 1-based argument index */ va_list orgap; /* original argument pointer */ char *convbuf; /* wide to multibyte conversion result */ + int fp_flags = 0; /* record flags that would be set on the FILE */ static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; /* BEWARE, these `goto error' on error. */ -#define PRINT(ptr, len) { \ - if (io_print(&io, (ptr), (len))) \ - goto error; \ -} -#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; \ -} +#define PRINT(ptr, len) do { \ + if (io_print(cb_func, cb_arg, (ptr), (len))) \ + goto error; \ +} while (0) +#define PAD(howmany, with) do { \ + if (io_pad(cb_func, cb_arg, (howmany), (with))) \ + goto error; \ +} while (0) +#define PRINTANDPAD(p, ep, len, with) do { \ + if (io_printandpad(cb_func, cb_arg, (p), (ep), (len), (with))) \ + goto error; \ +} while (0) +#define FLUSH() do { \ + if (io_print(cb_func, cb_arg, NULL, 0)) \ + goto error; \ + } while (0) /* * Get the argument indexed by nextarg. If the argument table is * built, use it to get the argument. If its not, get the next * argument (and arguments must be gotten sequentially). @@ -435,25 +420,35 @@ fmt = ++cp; \ } else { \ val = GETARG (int); \ } +#if 0 /* XXX */ if (__use_xprintf == 0 && getenv("USE_XPRINTF")) __use_xprintf = 1; if (__use_xprintf > 0) return (__xvprintf(fp, fmt0, ap)); +#endif +#if 0 + /* + * XXX cb_func is responsible for this on first write, or call + * before calling cb_printf(). + */ /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ if (prepwrite(fp) != 0) return (EOF); +#endif convbuf = NULL; fmt = (char *)fmt0; argtable = NULL; nextarg = 1; va_copy(orgap, ap); +#if 0 io_init(&io, fp); +#endif /* XXX */ ret = 0; #ifndef NO_FLOATING_POINT dtoaresult = NULL; decimal_point = localeconv()->decimal_point; /* The overwhelmingly common case is decpt_len == 1. */ @@ -603,11 +598,11 @@ mbs = initial; mbseqlen = wcrtomb(cp = buf, (wchar_t)GETARG(wint_t), &mbs); if (mbseqlen == (size_t)-1) { - fp->_flags |= __SERR; + fp_flags |= __SERR; goto error; } size = (int)mbseqlen; } else { *(cp = buf) = GETARG(int); @@ -814,11 +809,11 @@ if ((wcp = GETARG(wchar_t *)) == NULL) cp = "(null)"; else { convbuf = __wcsconv(wcp, prec); if (convbuf == NULL) { - fp->_flags |= __SERR; + fp_flags |= __SERR; goto error; } cp = convbuf; } } else if ((cp = GETARG(char *)) == NULL) @@ -949,11 +944,13 @@ if ((flags & FPT) == 0) { #endif /* leading zeroes from decimal precision */ PAD(dprec - size, zeroes); if (gs.grouping) { - if (grouping_print(&gs, &io, cp, buf+BUF) < 0) + n = grouping_print(&gs, cb_func, cb_arg, + cp, buf+BUF); + if (n < 0) goto error; } else { PRINT(cp, size); } #ifndef NO_FLOATING_POINT @@ -966,11 +963,12 @@ PAD(-expt, zeroes); /* already handled initial 0's */ prec += expt; } else { if (gs.grouping) { - n = grouping_print(&gs, &io, + n = grouping_print(&gs, + cb_func, cb_arg, cp, dtoaend); if (n < 0) goto error; cp += n; } else { @@ -1011,11 +1009,11 @@ if (dtoaresult != NULL) freedtoa(dtoaresult); #endif if (convbuf != NULL) free(convbuf); - if (__sferror(fp)) + if ((fp_flags & __SERR) != 0) ret = EOF; if ((argtable != NULL) && (argtable != statargtable)) free (argtable); return (ret); /* NOTREACHED */