summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/stdio/printfcommon.h130
-rw-r--r--lib/libc/stdio/vfprintf.c64
-rw-r--r--lib/libc/stdio/vfwprintf.c96
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)
OpenPOWER on IntegriCloud