summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/Makefile2
-rw-r--r--include/printf.h155
-rw-r--r--lib/libc/stdio/Makefile.inc3
-rw-r--r--lib/libc/stdio/vfprintf.c7
-rw-r--r--lib/libc/stdio/xprintf.c674
-rw-r--r--lib/libc/stdio/xprintf_float.c425
-rw-r--r--lib/libc/stdio/xprintf_hexdump.c97
-rw-r--r--lib/libc/stdio/xprintf_int.c471
-rw-r--r--lib/libc/stdio/xprintf_str.c187
-rw-r--r--lib/libc/stdio/xprintf_time.c114
-rw-r--r--lib/libc/stdio/xprintf_vis.c76
11 files changed, 2210 insertions, 1 deletions
diff --git a/include/Makefile b/include/Makefile
index 89554f0..e488788 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -14,7 +14,7 @@ INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h _ctype.h ctype.h \
locale.h malloc.h memory.h monetary.h mpool.h mqueue.h \
ndbm.h netconfig.h \
netdb.h nl_types.h nlist.h nss.h nsswitch.h objformat.h paths.h \
- proc_service.h pthread.h \
+ printf.h proc_service.h pthread.h \
pthread_np.h pwd.h ranlib.h readpassphrase.h regex.h regexp.h \
resolv.h runetype.h search.h setjmp.h sgtty.h \
signal.h stab.h \
diff --git a/include/printf.h b/include/printf.h
new file mode 100644
index 0000000..d16ad6e
--- /dev/null
+++ b/include/printf.h
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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$
+ */
+
+#ifndef _PRINTF_H_
+#define _PRINTF_H_
+
+union arg;
+
+/*
+ * The API defined by glibc allows a renderer to take multiple arguments
+ * This is obviously usable for things like (ptr+len) pairs etc.
+ * But the do not actually provide support for it at the end of the day,
+ * they offer only one argument to the arginfo function, but do accept
+ * >1 returns, although the do not check the types of those arguments
+ * argument
+ * Be compatible for now.
+ */
+#define __PRINTFMAXARG 2
+
+struct printf_info {
+ /* GLIBC compatible */
+ int prec;
+ int width;
+ wchar_t spec;
+ unsigned is_long_double;
+ unsigned is_char;
+ unsigned is_short;
+ unsigned is_long;
+ unsigned alt;
+ unsigned space;
+ unsigned left;
+ unsigned showsign;
+ unsigned group;
+ unsigned extra;
+ unsigned wide;
+ wchar_t pad;
+
+ /* FreeBSD extensions */
+
+ unsigned is_quad;
+ unsigned is_intmax;
+ unsigned is_ptrdiff;
+ unsigned is_size;
+
+ /* private */
+ int sofar;
+ unsigned get_width;
+ unsigned get_prec;
+ const char *begin;
+ const char *end;
+ void *arg[__PRINTFMAXARG];
+};
+
+enum {
+ PA_INT = (1 << 0), /* int */
+ PA_CHAR = (1 << 1), /* int, cast to char */
+ PA_WCHAR = (1 << 2), /* wide char */
+ PA_STRING = (1 << 3), /* const char * (with '\0') */
+ PA_WSTRING = (1 << 4), /* const wchar_t * */
+ PA_POINTER = (1 << 5), /* void * */
+ PA_FLOAT = (1 << 6), /* float */
+ PA_DOUBLE = (1 << 7) /* double */
+};
+
+#define PA_FLAG_MASK 0xff0000
+#define PA_FLAG_LONG_LONG (1 << 16)
+#define PA_FLAG_LONG (1 << 17)
+#define PA_FLAG_SHORT (1 << 18)
+#define PA_FLAG_PTR (1 << 19)
+#define PA_FLAG_QUAD (1 << 20)
+#define PA_FLAG_INTMAX (1 << 21)
+#define PA_FLAG_SIZE (1 << 22)
+#define PA_FLAG_PTRDIFF (1 << 23)
+#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG
+
+typedef int printf_arginfo_function(const struct printf_info *, size_t, int *);
+typedef int printf_function(FILE *, const struct printf_info *, const void *const *);
+
+/* FreeBSD extension */
+struct __printf_io;
+typedef int printf_render(struct __printf_io *, const struct printf_info *, const void *const *);
+
+/* vprintf.c */
+extern const char __lowercase_hex[17];
+extern const char __uppercase_hex[17];
+
+void __printf_flush(struct __printf_io *io);
+int __printf_puts(struct __printf_io *io, const void *ptr, int len);
+int __printf_pad(struct __printf_io *io, int n, int zero);
+int __printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len);
+
+int __xvprintf(FILE *fp, const char *fmt0, va_list ap);
+extern int __use_xprintf;
+
+/* GLIBC compat */
+int register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo);
+
+/* FreeBSD */
+int register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo);
+int register_printf_render_std(const unsigned char *specs);
+
+/* vprintf_float.c */
+printf_arginfo_function __printf_arginfo_float;
+printf_render __printf_render_float;
+
+/* vprintf_int.c */
+printf_arginfo_function __printf_arginfo_ptr;
+printf_arginfo_function __printf_arginfo_int;
+printf_render __printf_render_ptr;
+printf_render __printf_render_int;
+
+/* vprintf_str.c */
+printf_arginfo_function __printf_arginfo_chr;
+printf_render __printf_render_chr;
+printf_arginfo_function __printf_arginfo_str;
+printf_render __printf_render_str;
+
+/* vprintf_time.c */
+printf_arginfo_function __printf_arginfo_time;
+printf_render __printf_render_time;
+
+/* vprintf_hexdump.c */
+printf_arginfo_function __printf_arginfo_hexdump;
+printf_render __printf_render_hexdump;
+
+/* vprintf_vis.c */
+printf_arginfo_function __printf_arginfo_vis;
+printf_render __printf_render_vis;
+
+#endif /* !_PRINTF_H */
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc
index f8a90f8..495c85f 100644
--- a/lib/libc/stdio/Makefile.inc
+++ b/lib/libc/stdio/Makefile.inc
@@ -23,6 +23,9 @@ SRCS+= _flock_stub.c asprintf.c clrerr.c fclose.c fdopen.c feof.c ferror.c \
vswprintf.c vswscanf.c vwprintf.c vwscanf.c wbuf.c wprintf.c wscanf.c \
wsetup.c
+SRCS+= xprintf.c xprintf_float.c xprintf_int.c xprintf_str.c
+SRCS+= xprintf_hexdump.c xprintf_time.c xprintf_vis.c
+
MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fgetwln.3 fgetws.3 \
flockfile.3 \
fopen.3 fputs.3 \
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index 25ac2d7..34e6bf0 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
+#include <printf.h>
#include <stdarg.h>
#include "un-namespace.h"
@@ -466,6 +467,12 @@ __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 */
+
+ if (__use_xprintf == 0 && getenv("USE_XPRINTF"))
+ __use_xprintf = 1;
+ if (__use_xprintf > 0)
+ return (__xvprintf(fp, fmt0, ap));
+
#ifndef NO_FLOATING_POINT
/*
* We can decompose the printed representation of floating
diff --git a/lib/libc/stdio/xprintf.c b/lib/libc/stdio/xprintf.c
new file mode 100644
index 0000000..3b27782
--- /dev/null
+++ b/lib/libc/stdio/xprintf.c
@@ -0,0 +1,674 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * 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.
+ * 3. 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$
+ */
+
+#include <namespace.h>
+#include <err.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <stdint.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <namespace.h>
+#include <string.h>
+#include <wchar.h>
+#include <un-namespace.h>
+
+#include "printf.h"
+#include "fvwrite.h"
+
+int __use_xprintf = -1;
+
+/* private stuff -----------------------------------------------------*/
+
+union arg {
+ int intarg;
+ long longarg;
+ intmax_t intmaxarg;
+#ifndef NO_FLOATING_POINT
+ double doublearg;
+ long double longdoublearg;
+#endif
+ wint_t wintarg;
+ char *pchararg;
+ wchar_t *pwchararg;
+ void *pvoidarg;
+};
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define to_digit(c) ((c) - '0')
+#define is_digit(c) (((unsigned)to_digit(c)) <= 9)
+
+/* various globals ---------------------------------------------------*/
+
+const char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */
+const char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */
+
+#define PADSIZE 16
+static char blanks[PADSIZE] =
+ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+static char zeroes[PADSIZE] =
+ {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+/* printing and padding functions ------------------------------------*/
+
+#define NIOV 8
+
+struct __printf_io {
+ FILE *fp;
+ struct __suio uio;
+ struct __siov iov[NIOV];
+ struct __siov *iovp;
+};
+
+static void
+__printf_init(struct __printf_io *io)
+{
+
+ io->uio.uio_iov = io->iovp = &io->iov[0];
+ io->uio.uio_resid = 0;
+ io->uio.uio_iovcnt = 0;
+}
+
+void
+__printf_flush(struct __printf_io *io)
+{
+
+ __sfvwrite(io->fp, &io->uio);
+ __printf_init(io);
+}
+
+int
+__printf_puts(struct __printf_io *io, const void *ptr, int len)
+{
+
+
+ if (io->fp->_flags & __SERR)
+ return (0);
+ if (len == 0)
+ return (0);
+ io->iovp->iov_base = __DECONST(void *, ptr);
+ io->iovp->iov_len = len;
+ io->uio.uio_resid += len;
+ io->iovp++;
+ io->uio.uio_iovcnt++;
+ if (io->uio.uio_iovcnt >= NIOV)
+ __printf_flush(io);
+ return (len);
+}
+
+int
+__printf_pad(struct __printf_io *io, int howmany, int zero)
+{
+ int n;
+ const char *with;
+ int ret = 0;
+
+ if (zero)
+ with = zeroes;
+ else
+ with = blanks;
+
+ if ((n = (howmany)) > 0) {
+ while (n > PADSIZE) {
+ ret += __printf_puts(io, with, PADSIZE);
+ n -= PADSIZE;
+ }
+ ret += __printf_puts(io, with, n);
+ }
+ return (ret);
+}
+
+int
+__printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len)
+{
+ int ret = 0;
+
+ if ((!pi->left) && pi->width > len)
+ ret += __printf_pad(io, pi->width - len, pi->pad == '0');
+ ret += __printf_puts(io, ptr, len);
+ if (pi->left && pi->width > len)
+ ret += __printf_pad(io, pi->width - len, pi->pad == '0');
+ return (ret);
+}
+
+
+/* percent handling -------------------------------------------------*/
+
+static int
+__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused)
+{
+
+ return (0);
+}
+
+static int
+__printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused)
+{
+
+ return (__printf_puts(io, "%", 1));
+}
+
+/* 'n' ---------------------------------------------------------------*/
+
+static int
+__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+
+/*
+ * This is a printf_render so that all output has been flushed before it
+ * gets called.
+ */
+
+static int
+__printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg)
+{
+
+ if (pi->is_char)
+ **((signed char **)arg[0]) = (signed char)pi->sofar;
+ else if (pi->is_short)
+ **((short **)arg[0]) = (short)pi->sofar;
+ else if (pi->is_long)
+ **((long **)arg[0]) = pi->sofar;
+ else if (pi->is_long_double)
+ **((long long **)arg[0]) = pi->sofar;
+ else if (pi->is_intmax)
+ **((intmax_t **)arg[0]) = pi->sofar;
+ else if (pi->is_ptrdiff)
+ **((ptrdiff_t **)arg[0]) = pi->sofar;
+ else if (pi->is_quad)
+ **((quad_t **)arg[0]) = pi->sofar;
+ else if (pi->is_size)
+ **((size_t **)arg[0]) = pi->sofar;
+ else
+ **((int **)arg[0]) = pi->sofar;
+
+ return (0);
+}
+
+/* table -------------------------------------------------------------*/
+
+/*lint -esym(785, printf_tbl) */
+static struct {
+ printf_arginfo_function *arginfo;
+ printf_function *gnurender;
+ printf_render *render;
+} printf_tbl[256] = {
+ ['%'] = { __printf_arginfo_pct, NULL, __printf_render_pct },
+ ['A'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['C'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
+ ['E'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['F'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['G'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['S'] = { __printf_arginfo_str, NULL, __printf_render_str },
+ ['X'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['a'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['c'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
+ ['d'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['e'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['f'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['g'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['i'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['n'] = { __printf_arginfo_n, __printf_render_n, NULL },
+ ['o'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['p'] = { __printf_arginfo_ptr, NULL, __printf_render_ptr },
+ ['q'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['s'] = { __printf_arginfo_str, NULL, __printf_render_str },
+ ['u'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['x'] = { __printf_arginfo_int, NULL, __printf_render_int },
+};
+
+
+static int
+__v2printf(FILE *fp, const char *fmt0, unsigned pct, const va_list ap)
+{
+ struct printf_info *pi, *pil;
+ const char *fmt;
+ int ch;
+ struct printf_info pia[pct + 10];
+ int argt[pct + 10];
+ union arg args[pct + 10];
+ int nextarg;
+ int maxarg;
+ int ret = 0;
+ int n;
+ struct __printf_io io;
+
+ __printf_init(&io);
+ io.fp = fp;
+
+ fmt = fmt0;
+ maxarg = 0;
+ nextarg = 1;
+ memset(argt, 0, sizeof argt);
+ for (pi = pia; ; pi++) {
+ memset(pi, 0, sizeof *pi);
+ pil = pi;
+ if (*fmt == '\0')
+ break;
+ pil = pi + 1;
+ pi->prec = -1;
+ pi->pad = ' ';
+ pi->begin = pi->end = fmt;
+ while (*fmt != '\0' && *fmt != '%')
+ pi->end = ++fmt;
+ if (*fmt == '\0')
+ break;
+ fmt++;
+ for (;;) {
+ pi->spec = *fmt;
+ switch (pi->spec) {
+ case ' ':
+ /*-
+ * ``If the space and + flags both appear, the space
+ * flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (pi->showsign == 0)
+ pi->showsign = ' ';
+ fmt++;
+ continue;
+ case '#':
+ pi->alt = 1;
+ fmt++;
+ continue;
+ case '.':
+ pi->prec = 0;
+ fmt++;
+ if (*fmt == '*') {
+ fmt++;
+ pi->get_prec = nextarg;
+ argt[nextarg++] = PA_INT;
+ continue;
+ }
+ while (*fmt != '\0' && is_digit(*fmt)) {
+ pi->prec *= 10;
+ pi->prec += to_digit(*fmt);
+ fmt++;
+ }
+ continue;
+ case '-':
+ pi->left = 1;
+ fmt++;
+ continue;
+ case '+':
+ pi->showsign = '+';
+ fmt++;
+ continue;
+ case '*':
+ fmt++;
+ pi->get_width = nextarg;
+ argt[nextarg++] = PA_INT;
+ continue;
+ case '%':
+ fmt++;
+ break;
+ case '\'':
+ pi->group = 1;
+ fmt++;
+ continue;
+ case '0':
+ /*-
+ * ``Note that 0 is taken as a flag, not as the
+ * beginning of a field width.''
+ * -- ANSI X3J11
+ */
+ pi->pad = '0';
+ fmt++;
+ continue;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ n = 0;
+ while (*fmt != '\0' && is_digit(*fmt)) {
+ n *= 10;
+ n += to_digit(*fmt);
+ fmt++;
+ }
+ if (*fmt == '$') {
+ if (nextarg > maxarg)
+ maxarg = nextarg;
+ nextarg = n;
+ fmt++;
+ } else
+ pi->width = n;
+ continue;
+ case 'D':
+ case 'O':
+ case 'U':
+ pi->spec += ('a' - 'A');
+ pi->is_intmax = 0;
+ if (pi->is_long_double || pi->is_quad) {
+ pi->is_long = 0;
+ pi->is_long_double = 1;
+ } else {
+ pi->is_long = 1;
+ pi->is_long_double = 0;
+ }
+ fmt++;
+ break;
+ case 'j':
+ pi->is_intmax = 1;
+ fmt++;
+ continue;
+ case 'q':
+ pi->is_long = 0;
+ pi->is_quad = 1;
+ fmt++;
+ continue;
+ case 'L':
+ pi->is_long_double = 1;
+ fmt++;
+ continue;
+ case 'h':
+ fmt++;
+ if (*fmt == 'h') {
+ fmt++;
+ pi->is_char = 1;
+ } else {
+ pi->is_short = 1;
+ }
+ continue;
+ case 'l':
+ fmt++;
+ if (*fmt == 'l') {
+ fmt++;
+ pi->is_long_double = 1;
+ pi->is_quad = 0;
+ } else {
+ pi->is_quad = 0;
+ pi->is_long = 1;
+ }
+ continue;
+ case 't':
+ pi->is_ptrdiff = 1;
+ fmt++;
+ continue;
+ case 'z':
+ pi->is_size = 1;
+ fmt++;
+ continue;
+ default:
+ fmt++;
+ break;
+ }
+ if (printf_tbl[pi->spec].arginfo == NULL)
+ errx(1, "arginfo[%c] = NULL", pi->spec);
+ ch = printf_tbl[pi->spec].arginfo(
+ pi, __PRINTFMAXARG, &argt[nextarg]);
+ if (ch > 0)
+ pi->arg[0] = &args[nextarg];
+ if (ch > 1)
+ pi->arg[1] = &args[nextarg + 1];
+ nextarg += ch;
+ break;
+ }
+ }
+ if (nextarg > maxarg)
+ maxarg = nextarg;
+#if 0
+ fprintf(stderr, "fmt0 <%s>\n", fmt0);
+ fprintf(stderr, "pil %p\n", pil);
+#endif
+ for (ch = 1; ch < maxarg; ch++) {
+#if 0
+ fprintf(stderr, "arg %d %x\n", ch, argt[ch]);
+#endif
+ switch(argt[ch]) {
+ case PA_CHAR:
+ args[ch].intarg = (char)va_arg (ap, int);
+ break;
+ case PA_INT:
+ args[ch].intarg = va_arg (ap, int);
+ break;
+ case PA_INT | PA_FLAG_SHORT:
+ args[ch].intarg = (short)va_arg (ap, int);
+ break;
+ case PA_INT | PA_FLAG_LONG:
+ args[ch].longarg = va_arg (ap, long);
+ break;
+ case PA_INT | PA_FLAG_INTMAX:
+ args[ch].intmaxarg = va_arg (ap, intmax_t);
+ break;
+ case PA_INT | PA_FLAG_QUAD:
+ args[ch].intmaxarg = va_arg (ap, quad_t);
+ break;
+ case PA_INT | PA_FLAG_LONG_LONG:
+ args[ch].intmaxarg = va_arg (ap, long long);
+ break;
+ case PA_INT | PA_FLAG_SIZE:
+ args[ch].intmaxarg = va_arg (ap, size_t);
+ break;
+ case PA_INT | PA_FLAG_PTRDIFF:
+ args[ch].intmaxarg = va_arg (ap, ptrdiff_t);
+ break;
+ case PA_WCHAR:
+ args[ch].wintarg = va_arg (ap, wint_t);
+ break;
+ case PA_POINTER:
+ args[ch].pvoidarg = va_arg (ap, void *);
+ break;
+ case PA_STRING:
+ args[ch].pchararg = va_arg (ap, char *);
+ break;
+ case PA_WSTRING:
+ args[ch].pwchararg = va_arg (ap, wchar_t *);
+ break;
+ case PA_DOUBLE:
+ args[ch].doublearg = va_arg (ap, double);
+ break;
+ case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
+ args[ch].longdoublearg = va_arg (ap, long double);
+ break;
+ default:
+ errx(1, "argtype = %x (fmt = \"%s\")\n",
+ argt[ch], fmt0);
+ }
+ }
+ for (pi = pia; pi < pil; pi++) {
+#if 0
+ fprintf(stderr, "pi %p", pi);
+ fprintf(stderr, " spec '%c'", pi->spec);
+ fprintf(stderr, " args %d",
+ ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]);
+ if (pi->width) fprintf(stderr, " width %d", pi->width);
+ if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
+ if (pi->left) fprintf(stderr, " left");
+ if (pi->showsign) fprintf(stderr, " showsign");
+ if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
+ if (pi->is_char) fprintf(stderr, " char");
+ if (pi->is_short) fprintf(stderr, " short");
+ if (pi->is_long) fprintf(stderr, " long");
+ if (pi->is_long_double) fprintf(stderr, " long_double");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
+#endif
+ if (pi->get_width) {
+ pi->width = args[pi->get_width].intarg;
+ /*-
+ * ``A negative field width argument is taken as a
+ * - flag followed by a positive field width.''
+ * -- ANSI X3J11
+ * They don't exclude field widths read from args.
+ */
+ if (pi->width < 0) {
+ pi->left = 1;
+ pi->width = -pi->width;
+ }
+ }
+ if (pi->get_prec)
+ pi->prec = args[pi->get_prec].intarg;
+ ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
+ if (printf_tbl[pi->spec].gnurender != NULL) {
+ __printf_flush(&io);
+ pi->sofar = ret;
+ ret += printf_tbl[pi->spec].gnurender(
+ fp, pi, (const void *)pi->arg);
+ } else if (printf_tbl[pi->spec].render != NULL) {
+ pi->sofar = ret;
+ n = printf_tbl[pi->spec].render(
+ &io, pi, (const void *)pi->arg);
+ if (n < 0)
+ io.fp->_flags |= __SERR;
+ else
+ ret += n;
+ } else if (pi->begin == pi->end)
+ errx(1, "render[%c] = NULL", *fmt);
+ }
+ __printf_flush(&io);
+ return (ret);
+}
+
+extern int __fflush(FILE *fp);
+
+/*
+ * 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
+__v3printf(FILE *fp, const char *fmt, int pct, va_list ap)
+{
+ int ret;
+ FILE fake;
+ unsigned char buf[BUFSIZ];
+
+ /* copy the important variables */
+ fake._flags = fp->_flags & ~__SNBF;
+ fake._file = fp->_file;
+ fake._cookie = fp->_cookie;
+ fake._write = fp->_write;
+ fake._extra = fp->_extra;
+
+ /* 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 = __v2printf(&fake, fmt, pct, ap);
+ if (ret >= 0 && __fflush(&fake))
+ ret = EOF;
+ if (fake._flags & __SERR)
+ fp->_flags |= __SERR;
+ return (ret);
+}
+
+int
+__xvprintf(FILE *fp, const char *fmt0, va_list ap)
+{
+ unsigned u;
+ const char *p;
+
+ /* Count number of '%' signs handling double '%' signs */
+ for (p = fmt0, u = 0; *p; p++) {
+ if (*p != '%')
+ continue;
+ u++;
+ if (p[1] == '%')
+ p++;
+ }
+
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+ fp->_file >= 0)
+ return (__v3printf(fp, fmt0, u, ap));
+ else
+ return (__v2printf(fp, fmt0, u, ap));
+}
+
+/* extending ---------------------------------------------------------*/
+
+int
+register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo)
+{
+
+ if (spec > 255 || spec < 0)
+ return (-1);
+ printf_tbl[spec].gnurender = render;
+ printf_tbl[spec].arginfo = arginfo;
+ __use_xprintf = 1;
+ return (0);
+}
+
+int
+register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo)
+{
+
+ if (spec > 255 || spec < 0)
+ return (-1);
+ printf_tbl[spec].render = render;
+ printf_tbl[spec].arginfo = arginfo;
+ __use_xprintf = 1;
+ return (0);
+}
+
+int
+register_printf_render_std(const unsigned char *specs)
+{
+
+ for (; *specs != '\0'; specs++) {
+ switch (*specs) {
+ case 'H':
+ register_printf_render(*specs,
+ __printf_render_hexdump,
+ __printf_arginfo_hexdump);
+ break;
+ case 'T':
+ register_printf_render(*specs,
+ __printf_render_time,
+ __printf_arginfo_time);
+ break;
+ case 'V':
+ register_printf_render(*specs,
+ __printf_render_vis,
+ __printf_arginfo_vis);
+ break;
+ default:
+ return (-1);
+ }
+ }
+ return (0);
+}
+
diff --git a/lib/libc/stdio/xprintf_float.c b/lib/libc/stdio/xprintf_float.c
new file mode 100644
index 0000000..b719aac
--- /dev/null
+++ b/lib/libc/stdio/xprintf_float.c
@@ -0,0 +1,425 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * 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.
+ * 3. 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$
+ */
+
+#include <namespace.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <assert.h>
+#include <locale.h>
+#include <limits.h>
+
+#define dtoa __dtoa
+#define freedtoa __freedtoa
+
+#include <float.h>
+#include <math.h>
+#include "gdtoa.h"
+#include "floatio.h"
+#include "printf.h"
+#include <un-namespace.h>
+
+/*
+ * The size of the buffer we use as scratch space for integer
+ * conversions, among other things. Technically, we would need the
+ * most space for base 10 conversions with thousands' grouping
+ * characters between each pair of digits. 100 bytes is a
+ * conservative overestimate even for a 128-bit uintmax_t.
+ */
+#define BUF 100
+
+#define DEFPREC 6 /* Default FP precision */
+
+
+/* various globals ---------------------------------------------------*/
+
+
+/* padding function---------------------------------------------------*/
+
+#define PRINTANDPAD(p, ep, len, with) do { \
+ n2 = (ep) - (p); \
+ if (n2 > (len)) \
+ n2 = (len); \
+ if (n2 > 0) \
+ ret += __printf_puts(io, (p), n2); \
+ ret += __printf_pad(io, (len) - (n2 > 0 ? n2 : 0), (with)); \
+} while(0)
+
+/* misc --------------------------------------------------------------*/
+
+#define to_char(n) ((n) + '0')
+
+static int
+exponent(char *p0, int expo, int fmtch)
+{
+ char *p, *t;
+ char expbuf[MAXEXPDIG];
+
+ p = p0;
+ *p++ = fmtch;
+ if (expo < 0) {
+ expo = -expo;
+ *p++ = '-';
+ }
+ else
+ *p++ = '+';
+ t = expbuf + MAXEXPDIG;
+ if (expo > 9) {
+ do {
+ *--t = to_char(expo % 10);
+ } while ((expo /= 10) > 9);
+ *--t = to_char(expo);
+ 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(expo);
+ }
+ return (p - p0);
+}
+
+/* 'f' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt)
+{
+ assert (n > 0);
+ argt[0] = PA_DOUBLE;
+ if (pi->is_long_double)
+ argt[0] |= PA_FLAG_LONG_DOUBLE;
+ return (1);
+}
+
+/*
+ * We can decompose the printed representation of floating
+ * point numbers into several parts, some of which may be empty:
+ *
+ * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
+ * A B ---C--- D E F
+ *
+ * A: 'sign' holds this value if present; '\0' otherwise
+ * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
+ * C: cp points to the string MMMNNN. Leading and trailing
+ * zeros are not in the string and must be added.
+ * D: expchar holds this character; '\0' if no exponent, e.g. %f
+ * F: at least two digits for decimal, at least one digit for hex
+ */
+
+int
+__printf_render_float(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ int prec; /* precision from format; <0 for N/A */
+ char *dtoaresult; /* buffer allocated by dtoa */
+ char expchar; /* exponent character: [eEpP\0] */
+ char *cp;
+ int expt; /* integer value of exponent */
+ int signflag; /* true if float is negative */
+ char *dtoaend; /* pointer to end of converted digits */
+ char sign; /* sign prefix (' ', '+', '-', or \0) */
+ int size; /* size of converted field or string */
+ int ndig; /* actual number of digits returned by dtoa */
+ int expsize; /* character count for expstr */
+ char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
+ int nseps; /* number of group separators with ' */
+ int nrepeats; /* number of repeats of the last group */
+ const char *grouping; /* locale specific numeric grouping rules */
+ int lead; /* sig figs before decimal or group sep */
+ long double ld;
+ double d;
+ int realsz; /* field size expanded by dprec, sign, etc */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
+ int prsize; /* max size of printed field */
+ int ret; /* return value accumulator */
+ char *decimal_point; /* locale specific decimal point */
+ int n2; /* XXX: for PRINTANDPAD */
+ char thousands_sep; /* locale specific thousands separator */
+ char buf[BUF]; /* buffer with space for digits of uintmax_t */
+ const char *xdigs;
+ int flag;
+
+ prec = pi->prec;
+ ox[1] = '\0';
+ sign = pi->showsign;
+ flag = 0;
+ ret = 0;
+
+ thousands_sep = *(localeconv()->thousands_sep);
+ grouping = NULL;
+ if (pi->alt)
+ grouping = localeconv()->grouping;
+ decimal_point = localeconv()->decimal_point;
+ dprec = -1;
+
+ switch(pi->spec) {
+ case 'a':
+ case 'A':
+ if (pi->spec == 'a') {
+ ox[1] = 'x';
+ xdigs = __lowercase_hex;
+ expchar = 'p';
+ } else {
+ ox[1] = 'X';
+ xdigs = __uppercase_hex;
+ expchar = 'P';
+ }
+ if (prec >= 0)
+ prec++;
+ if (pi->is_long_double) {
+ ld = *((long double *)arg[0]);
+ dtoaresult = cp =
+ __hldtoa(ld, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+ } else {
+ d = *((double *)arg[0]);
+ dtoaresult = cp =
+ __hdtoa(d, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+ }
+ if (prec < 0)
+ prec = dtoaend - cp;
+ if (expt == INT_MAX)
+ ox[1] = '\0';
+ goto fp_common;
+ case 'e':
+ case 'E':
+ expchar = pi->spec;
+ if (prec < 0) /* account for digit before decpt */
+ prec = DEFPREC + 1;
+ else
+ prec++;
+ break;
+ case 'f':
+ case 'F':
+ expchar = '\0';
+ break;
+ case 'g':
+ case 'G':
+ expchar = pi->spec - ('g' - 'e');
+ if (prec == 0)
+ prec = 1;
+ break;
+ default:
+ assert(pi->spec == 'f');
+ }
+
+ if (prec < 0)
+ prec = DEFPREC;
+ if (pi->is_long_double) {
+ ld = *((long double *)arg[0]);
+ dtoaresult = cp =
+ __ldtoa(&ld, expchar ? 2 : 3, prec,
+ &expt, &signflag, &dtoaend);
+ } else {
+ d = *((double *)arg[0]);
+ dtoaresult = cp =
+ dtoa(d, expchar ? 2 : 3, prec,
+ &expt, &signflag, &dtoaend);
+ if (expt == 9999)
+ expt = INT_MAX;
+ }
+fp_common:
+ if (signflag)
+ sign = '-';
+ if (expt == INT_MAX) { /* inf or nan */
+ if (*cp == 'N') {
+ cp = (pi->spec >= 'a') ? "nan" : "NAN";
+ sign = '\0';
+ } else
+ cp = (pi->spec >= 'a') ? "inf" : "INF";
+ size = 3;
+ flag = 1;
+ goto here;
+ }
+ ndig = dtoaend - cp;
+ if (pi->spec == 'g' || pi->spec == 'G') {
+ if (expt > -4 && expt <= prec) {
+ /* Make %[gG] smell like %[fF] */
+ expchar = '\0';
+ if (pi->alt)
+ prec -= expt;
+ else
+ prec = ndig - expt;
+ if (prec < 0)
+ prec = 0;
+ } else {
+ /*
+ * Make %[gG] smell like %[eE], but
+ * trim trailing zeroes if no # flag.
+ */
+ if (!pi->alt)
+ prec = ndig;
+ }
+ }
+ if (expchar) {
+ expsize = exponent(expstr, expt - 1, expchar);
+ size = expsize + prec;
+ if (prec > 1 || pi->alt)
+ ++size;
+ } else {
+ /* space for digits before decimal point */
+ if (expt > 0)
+ size = expt;
+ else /* "0" */
+ size = 1;
+ /* space for decimal pt and following digits */
+ if (prec || pi->alt)
+ size += prec + 1;
+ if (grouping && expt > 0) {
+ /* space for thousands' grouping */
+ nseps = nrepeats = 0;
+ lead = expt;
+ while (*grouping != CHAR_MAX) {
+ if (lead <= *grouping)
+ break;
+ lead -= *grouping;
+ if (*(grouping+1)) {
+ nseps++;
+ grouping++;
+ } else
+ nrepeats++;
+ }
+ size += nseps + nrepeats;
+ } else
+ lead = expt;
+ }
+
+here:
+ /*
+ * All reasonable formats wind up here. At this point, `cp'
+ * points to a string which (if not flags&LADJUST) should be
+ * padded out to `width' places. If flags&ZEROPAD, it should
+ * first be prefixed by any sign or other prefix; otherwise,
+ * it should be blank padded before the prefix is emitted.
+ * After any left-hand padding and prefixing, emit zeroes
+ * required by a decimal [diouxX] precision, then print the
+ * string proper, then emit zeroes required by any leftover
+ * floating precision; finally, if LADJUST, pad with blanks.
+ *
+ * Compute actual size, so we know how much to pad.
+ * size excludes decimal prec; realsz includes it.
+ */
+ realsz = dprec > size ? dprec : size;
+ if (sign)
+ realsz++;
+ if (ox[1])
+ realsz += 2;
+
+ prsize = pi->width > realsz ? pi->width : realsz;
+
+ /* right-adjusting blank padding */
+ if (pi->pad != '0' && pi->left == 0)
+ ret += __printf_pad(io, pi->width - realsz, 0);
+
+ /* prefix */
+ if (sign)
+ ret += __printf_puts(io, &sign, 1);
+
+ if (ox[1]) { /* ox[1] is either x, X, or \0 */
+ ox[0] = '0';
+ ret += __printf_puts(io, ox, 2);
+ }
+
+ /* right-adjusting zero padding */
+ if (pi->pad == '0' && pi->left == 0)
+ ret += __printf_pad(io, pi->width - realsz, 1);
+
+ /* leading zeroes from decimal precision */
+ ret += __printf_pad(io, dprec - size, 1);
+
+ if (flag)
+ ret += __printf_puts(io, cp, size);
+ else {
+ /* glue together f_p fragments */
+ if (!expchar) { /* %[fF] or sufficiently short %[gG] */
+ if (expt <= 0) {
+ ret += __printf_puts(io, "0", 1);
+ if (prec || pi->alt)
+ ret += __printf_puts(io, decimal_point, 1);
+ ret += __printf_pad(io, -expt, 1);
+ /* already handled initial 0's */
+ prec += expt;
+ } else {
+ PRINTANDPAD(cp, dtoaend, lead, 1);
+ cp += lead;
+ if (grouping) {
+ while (nseps>0 || nrepeats>0) {
+ if (nrepeats > 0)
+ nrepeats--;
+ else {
+ grouping--;
+ nseps--;
+ }
+ ret += __printf_puts(io, &thousands_sep, 1);
+ PRINTANDPAD(cp,dtoaend,
+ *grouping, 1);
+ cp += *grouping;
+ }
+ if (cp > dtoaend)
+ cp = dtoaend;
+ }
+ if (prec || pi->alt)
+ ret += __printf_puts(io, decimal_point,1);
+ }
+ PRINTANDPAD(cp, dtoaend, prec, 1);
+ } else { /* %[eE] or sufficiently long %[gG] */
+ if (prec > 1 || pi->alt) {
+ buf[0] = *cp++;
+ buf[1] = *decimal_point;
+ ret += __printf_puts(io, buf, 2);
+ ret += __printf_puts(io, cp, ndig-1);
+ ret += __printf_pad(io, prec - ndig, 1);
+ } else /* XeYYY */
+ ret += __printf_puts(io, cp, 1);
+ ret += __printf_puts(io, expstr, expsize);
+ }
+ }
+ /* left-adjusting padding (always blank) */
+ if (pi->left)
+ ret += __printf_pad(io, pi->width - realsz, 0);
+
+ __printf_flush(io);
+ if (dtoaresult != NULL)
+ freedtoa(dtoaresult);
+
+ return (ret);
+}
diff --git a/lib/libc/stdio/xprintf_hexdump.c b/lib/libc/stdio/xprintf_hexdump.c
new file mode 100644
index 0000000..a2956ba
--- /dev/null
+++ b/lib/libc/stdio/xprintf_hexdump.c
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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$
+ */
+
+#include <namespace.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdint.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "printf.h"
+
+int
+__printf_arginfo_hexdump(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert(n >= 2);
+ argt[0] = PA_POINTER;
+ argt[1] = PA_INT;
+ return (2);
+}
+
+int
+__printf_render_hexdump(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ unsigned char *p;
+ unsigned u, l, j, a;
+ char buf[100], *q;
+ int ret;
+
+ if (pi->width > 0 && pi->width < 16)
+ l = pi->width;
+ else
+ l = 16;
+ p = *((unsigned char **)arg[0]);
+ u = *((unsigned *)arg[1]);
+
+ ret = 0;
+ a = 0;
+ while (u > 0) {
+ q = buf;
+ if (pi->showsign)
+ q += sprintf(q, " %04x", a);
+ for (j = 0; j < l && j < u; j++)
+ q += sprintf(q, " %02x", p[j]);
+ if (pi->alt) {
+ for (; j < l; j++)
+ q += sprintf(q, " ");
+ q += sprintf(q, " |");
+ for (j = 0; j < l && j < u; j++) {
+ if (p[j] < ' ' || p[j] > '~')
+ *q++ = '.';
+ else
+ *q++ = p[j];
+ }
+ for (; j < l; j++)
+ *q++ = ' ';
+ *q++ = '|';
+ }
+ if (l < u)
+ j = l;
+ else
+ j = u;
+ p += j;
+ u -= j;
+ a += j;
+ if (u > 0)
+ *q++ = '\n';
+ ret += __printf_puts(io, buf + 1, q - (buf + 1));
+ __printf_flush(io);
+ }
+ return (ret);
+}
diff --git a/lib/libc/stdio/xprintf_int.c b/lib/libc/stdio/xprintf_int.c
new file mode 100644
index 0000000..641690c
--- /dev/null
+++ b/lib/libc/stdio/xprintf_int.c
@@ -0,0 +1,471 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * 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.
+ * 3. 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$
+ */
+
+#include <namespace.h>
+#include <err.h>
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdint.h>
+#include <assert.h>
+#include <namespace.h>
+#include <string.h>
+#include <wchar.h>
+#include <un-namespace.h>
+
+#include "printf.h"
+
+/* private stuff -----------------------------------------------------*/
+
+union arg {
+ int intarg;
+ u_int uintarg;
+ long longarg;
+ u_long ulongarg;
+ intmax_t intmaxarg;
+ uintmax_t uintmaxarg;
+};
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define to_char(n) ((n) + '0')
+
+/* various globals ---------------------------------------------------*/
+
+/*
+ * The size of the buffer we use for integer conversions.
+ * Technically, we would need the most space for base 10
+ * conversions with thousands' grouping characters between
+ * each pair of digits: 60 digits for 128 bit intmax_t.
+ * Use a bit more for better alignment of stuff.
+ */
+#define BUF 64
+
+/* misc --------------------------------------------------------------*/
+
+/*
+ * 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, 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);
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default: /* oops */
+ assert(base == 16);
+ }
+ return (cp);
+}
+
+
+/* Identical to __ultoa, but for intmax_t. */
+static char *
+__ujtoa(uintmax_t val, char *endp, int base, const char *xdigs,
+ int needgrp, char thousep, const char *grp)
+{
+ char *cp = endp;
+ intmax_t sval;
+ int ndig;
+
+ 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);
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default:
+ abort();
+ }
+ return (cp);
+}
+
+
+/* 'd' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_int(const struct printf_info *pi, size_t n, int *argt)
+{
+ assert (n > 0);
+ argt[0] = PA_INT;
+ if (pi->is_ptrdiff)
+ argt[0] |= PA_FLAG_PTRDIFF;
+ else if (pi->is_size)
+ argt[0] |= PA_FLAG_SIZE;
+ else if (pi->is_long)
+ argt[0] |= PA_FLAG_LONG;
+ else if (pi->is_intmax)
+ argt[0] |= PA_FLAG_INTMAX;
+ else if (pi->is_quad)
+ argt[0] |= PA_FLAG_QUAD;
+ else if (pi->is_long_double)
+ argt[0] |= PA_FLAG_LONG_LONG;
+ else if (pi->is_short)
+ argt[0] |= PA_FLAG_SHORT;
+ else if (pi->is_char)
+ argt[0] = PA_CHAR;
+ return (1);
+}
+
+int
+__printf_render_int(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ const union arg *argp;
+ char buf[BUF];
+ char *p, *pe;
+ char ns, l;
+ int rdx, sign, zext, ngrp;
+ const char *nalt, *digit;
+ char thousands_sep; /* locale specific thousands separator */
+ const char *grouping; /* locale specific numeric grouping rules */
+ uintmax_t uu;
+ int ret;
+
+ ret = 0;
+ nalt = NULL;
+ digit = __lowercase_hex;
+ ns = '\0';
+ pe = buf + sizeof buf - 1;
+
+ if (pi->group) {
+ thousands_sep = *(localeconv()->thousands_sep);
+ grouping = localeconv()->grouping;
+ ngrp = 1;
+ } else {
+ thousands_sep = 0;
+ grouping = NULL;
+ ngrp = 0;
+ }
+
+ switch(pi->spec) {
+ case 'd':
+ case 'i':
+ rdx = 10;
+ sign = 1;
+ break;
+ case 'X':
+ digit = __uppercase_hex;
+ /*FALLTHOUGH*/
+ case 'x':
+ rdx = 16;
+ sign = 0;
+ break;
+ case 'u':
+ case 'U':
+ rdx = 10;
+ sign = 0;
+ break;
+ case 'o':
+ case 'O':
+ rdx = 8;
+ sign = 0;
+ break;
+ default:
+ fprintf(stderr, "pi->spec = '%c'\n", pi->spec);
+ assert(1 == 0);
+ }
+ argp = arg[0];
+
+ if (sign)
+ ns = pi->showsign;
+
+ if (pi->is_long_double || pi->is_quad || pi->is_intmax ||
+ pi->is_size || pi->is_ptrdiff) {
+ if (sign && argp->intmaxarg < 0) {
+ uu = -argp->intmaxarg;
+ ns = '-';
+ } else
+ uu = argp->uintmaxarg;
+ } else if (pi->is_long) {
+ if (sign && argp->longarg < 0) {
+ uu = (u_long)-argp->longarg;
+ ns = '-';
+ } else
+ uu = argp->ulongarg;
+ } else if (pi->is_short) {
+ if (sign && (short)argp->intarg < 0) {
+ uu = -(short)argp->intarg;
+ ns = '-';
+ } else
+ uu = (unsigned short)argp->uintarg;
+ } else if (pi->is_char) {
+ if (sign && (char)argp->intarg < 0) {
+ uu = -(char)argp->intarg;
+ ns = '-';
+ } else
+ uu = (unsigned char)argp->uintarg;
+ } else {
+ if (sign && argp->intarg < 0) {
+ uu = (unsigned)-argp->intarg;
+ ns = '-';
+ } else
+ uu = argp->uintarg;
+ }
+ if (uu <= ULONG_MAX)
+ p = __ultoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
+ else
+ p = __ujtoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
+
+ l = 0;
+ if (uu == 0) {
+ /*-
+ * ``The result of converting a zero value with an
+ * explicit precision of zero is no characters.''
+ * -- ANSI X3J11
+ *
+ * ``The C Standard is clear enough as is. The call
+ * printf("%#.0o", 0) should print 0.''
+ * -- Defect Report #151
+ */
+ ;
+ if (pi->prec == 0 && !(pi->alt && rdx == 8))
+ p = pe;
+ } else if (pi->alt) {
+ if (rdx == 8)
+ *--p = '0';
+ if (rdx == 16) {
+ if (pi->spec == 'x')
+ nalt = "0x";
+ else
+ nalt = "0X";
+ l += 2;
+ }
+ }
+ l += pe - p;
+ if (ns)
+ l++;
+
+ /*-
+ * ``... diouXx conversions ... if a precision is
+ * specified, the 0 flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (pi->prec > (pe - p))
+ zext = pi->prec - (pe - p);
+ else if (pi->prec != -1)
+ zext = 0;
+ else if (pi->pad == '0' && pi->width > l && !pi->left)
+ zext = pi->width - l;
+ else
+ zext = 0;
+
+ l += zext;
+
+ while (zext > 0 && p > buf) {
+ *--p = '0';
+ zext--;
+ }
+
+ if (l < BUF) {
+ if (ns) {
+ *--p = ns;
+ } else if (nalt != NULL) {
+ *--p = nalt[1];
+ *--p = nalt[0];
+ }
+ if (pi->width > (pe - p) && !pi->left) {
+ l = pi->width - (pe - p);
+ while (l > 0 && p > buf) {
+ *--p = ' ';
+ l--;
+ }
+ if (l)
+ ret += __printf_pad(io, l, 0);
+ }
+ } else {
+ if (!pi->left && pi->width > l)
+ ret += __printf_pad(io, pi->width - l, 0);
+ if (ns != '\0')
+ ret += __printf_puts(io, &ns, 1);
+ else if (nalt != NULL)
+ ret += __printf_puts(io, nalt, 2);
+ if (zext > 0)
+ ret += __printf_pad(io, zext, 1);
+ }
+
+ ret += __printf_puts(io, p, pe - p);
+ if (pi->width > ret && pi->left)
+ ret += __printf_pad(io, pi->width - ret, 0);
+ __printf_flush(io);
+ return (ret);
+}
+
+/* 'p' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_ptr(const struct printf_info *pi __unused, size_t n, int *argt)
+{
+
+ assert (n > 0);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+
+int
+__printf_render_ptr(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ struct printf_info p2;
+ uintmax_t u;
+ const void *p;
+
+ /*-
+ * ``The argument shall be a pointer to void. The
+ * value of the pointer is converted to a sequence
+ * of printable characters, in an implementation-
+ * defined manner.''
+ * -- ANSI X3J11
+ */
+ u = (uintmax_t)(uintptr_t) *((void **)arg[0]);
+ p2 = *pi;
+
+ p2.spec = 'x';
+ p2.alt = 1;
+ p2.is_long_double = 1;
+ p = &u;
+ return (__printf_render_int(io, &p2, &p));
+}
diff --git a/lib/libc/stdio/xprintf_str.c b/lib/libc/stdio/xprintf_str.c
new file mode 100644
index 0000000..d46fa85
--- /dev/null
+++ b/lib/libc/stdio/xprintf_str.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * 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.
+ * 3. 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$
+ */
+
+#include <namespace.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+#include <assert.h>
+#include <wchar.h>
+#include "printf.h"
+
+/*
+ * 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.
+ */
+static char *
+__wcsconv(wchar_t *wcsarg, int prec)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ char buf[MB_LEN_MAX];
+ wchar_t *p;
+ char *convbuf;
+ size_t clen, nbytes;
+
+ /* Allocate space for the maximum number of bytes we could output. */
+ if (prec < 0) {
+ p = wcsarg;
+ mbs = initial;
+ nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
+ if (nbytes == (size_t)-1)
+ return (NULL);
+ } else {
+ /*
+ * Optimisation: if the output precision is small enough,
+ * just allocate enough memory for the maximum instead of
+ * scanning the string.
+ */
+ if (prec < 128)
+ nbytes = prec;
+ else {
+ nbytes = 0;
+ p = wcsarg;
+ mbs = initial;
+ for (;;) {
+ clen = wcrtomb(buf, *p++, &mbs);
+ if (clen == 0 || clen == (size_t)-1 ||
+ (int)(nbytes + clen) > prec)
+ break;
+ nbytes += clen;
+ }
+ }
+ }
+ if ((convbuf = malloc(nbytes + 1)) == NULL)
+ return (NULL);
+
+ /* Fill the output buffer. */
+ p = wcsarg;
+ mbs = initial;
+ if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
+ nbytes, &mbs)) == (size_t)-1) {
+ free(convbuf);
+ return (NULL);
+ }
+ convbuf[nbytes] = '\0';
+ return (convbuf);
+}
+
+
+/* 's' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_str(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert (n > 0);
+ if (pi->is_long || pi->spec == 'C')
+ argt[0] = PA_WSTRING;
+ else
+ argt[0] = PA_STRING;
+ return (1);
+}
+
+int
+__printf_render_str(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ const char *p;
+ wchar_t *wcp;
+ char *convbuf;
+ int l;
+
+ if (pi->is_long || pi->spec == 'S') {
+ wcp = *((wint_t **)arg[0]);
+ if (wcp == NULL)
+ return (__printf_out(io, pi, "(null)", 6));
+ convbuf = __wcsconv(wcp, pi->prec);
+ if (convbuf == NULL)
+ return (-1);
+ l = __printf_out(io, pi, convbuf, strlen(convbuf));
+ free(convbuf);
+ return (l);
+ }
+ p = *((char **)arg[0]);
+ if (p == NULL)
+ return (__printf_out(io, pi, "(null)", 6));
+ l = strlen(p);
+ if (pi->prec >= 0 && pi->prec < l)
+ l = pi->prec;
+ return (__printf_out(io, pi, p, l));
+}
+
+/* 'c' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_chr(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert (n > 0);
+ if (pi->is_long || pi->spec == 'C')
+ argt[0] = PA_WCHAR;
+ else
+ argt[0] = PA_INT;
+ return (1);
+}
+
+int
+__printf_render_chr(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ int i;
+ wint_t ii;
+ unsigned char c;
+ static const mbstate_t initial; /* XXX: this is bogus! */
+ mbstate_t mbs;
+ size_t mbseqlen;
+ char buf[MB_CUR_MAX];
+
+ if (pi->is_long || pi->spec == 'C') {
+ ii = *((wint_t *)arg[0]);
+
+ mbs = initial;
+ mbseqlen = wcrtomb(buf, (wchar_t)ii, &mbs);
+ if (mbseqlen == (size_t) -1)
+ return (-1);
+ return (__printf_out(io, pi, buf, mbseqlen));
+ }
+ i = *((int *)arg[0]);
+ c = i;
+ i = __printf_out(io, pi, &c, 1);
+ __printf_flush(io);
+ return (i);
+}
diff --git a/lib/libc/stdio/xprintf_time.c b/lib/libc/stdio/xprintf_time.c
new file mode 100644
index 0000000..b566aa0
--- /dev/null
+++ b/lib/libc/stdio/xprintf_time.c
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * 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.
+ * 3. 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$
+ */
+#include <namespace.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdint.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "printf.h"
+
+int
+__printf_arginfo_time(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+#define MINUTE 60
+#define HOUR (60 * MINUTE)
+#define DAY (24 * HOUR)
+#define YEAR (365 * DAY)
+
+int
+__printf_render_time(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ char buf[100];
+ char *p;
+ struct timeval *tv;
+ struct timespec *ts;
+ time_t *tp;
+ intmax_t t;
+ int i, prec, nsec;
+
+ prec = 0;
+ if (pi->is_long) {
+ tv = *((struct timeval **)arg[0]);
+ t = tv->tv_sec;
+ nsec = tv->tv_usec * 1000;
+ prec = 6;
+ } else if (pi->is_long_double) {
+ ts = *((struct timespec **)arg[0]);
+ t = ts->tv_sec;
+ nsec = ts->tv_nsec;
+ prec = 9;
+ } else {
+ tp = *((time_t **)arg[0]);
+ t = *tp;
+ }
+
+ p = buf;
+ if (pi->alt) {
+ if (t >= YEAR) {
+ p += sprintf(p, "%jdy", t / YEAR);
+ t %= YEAR;
+ }
+ if (t >= DAY && t != 0) {
+ p += sprintf(p, "%jdd", t / DAY);
+ t %= DAY;
+ }
+ if (t >= HOUR && t != 0) {
+ p += sprintf(p, "%jdh", t / HOUR);
+ t %= HOUR;
+ }
+ if (t >= MINUTE && t != 0) {
+ p += sprintf(p, "%jdm", t / MINUTE);
+ t %= MINUTE;
+ }
+ if (t != 0)
+ p += sprintf(p, "%jd", t);
+ } else {
+ p += sprintf(p, "%jd", (intmax_t)t);
+ }
+ if (pi->is_long || pi->is_long_double) {
+ if (pi->prec >= 0)
+ prec = pi->prec;
+ for (i = prec; i < 9; i++)
+ nsec /= 10;
+ p += sprintf(p, ".%.*d", prec, nsec);
+ }
+ return(__printf_out(io, pi, buf, p - buf));
+}
diff --git a/lib/libc/stdio/xprintf_vis.c b/lib/libc/stdio/xprintf_vis.c
new file mode 100644
index 0000000..2f8d63e
--- /dev/null
+++ b/lib/libc/stdio/xprintf_vis.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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$
+ */
+
+#include <namespace.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <vis.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "printf.h"
+
+int
+__printf_arginfo_vis(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+
+int
+__printf_render_vis(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ char *p, *buf;
+ unsigned l;
+ int ret;
+
+ ret = 0;
+ p = *((char **)arg[0]);
+ if (pi->prec >= 0)
+ l = pi->prec;
+ else
+ l = strlen(p);
+ buf = malloc(l * 4 + 1);
+ if (buf == NULL)
+ return (-1);
+ if (pi->showsign)
+ ret = strvisx(buf, p, l, VIS_WHITE | VIS_HTTPSTYLE);
+ else if (pi->pad == '0')
+ ret = strvisx(buf, p, l, VIS_WHITE | VIS_OCTAL);
+ else if (pi->alt)
+ ret = strvisx(buf, p, l, VIS_WHITE);
+ else
+ ret = strvisx(buf, p, l, VIS_WHITE | VIS_CSTYLE | VIS_OCTAL);
+ ret += __printf_out(io, pi, buf, ret);
+ __printf_flush(io);
+ free(buf);
+ return(ret);
+}
OpenPOWER on IntegriCloud