1e0f95098SPeter Avalos /*-
2e0f95098SPeter Avalos * Copyright (c) 2005 Poul-Henning Kamp
3e0f95098SPeter Avalos * Copyright (c) 1990, 1993
4e0f95098SPeter Avalos * The Regents of the University of California. All rights reserved.
5e0f95098SPeter Avalos *
6e0f95098SPeter Avalos * This code is derived from software contributed to Berkeley by
7e0f95098SPeter Avalos * Chris Torek.
8e0f95098SPeter Avalos *
9e0f95098SPeter Avalos * Redistribution and use in source and binary forms, with or without
10e0f95098SPeter Avalos * modification, are permitted provided that the following conditions
11e0f95098SPeter Avalos * are met:
12e0f95098SPeter Avalos * 1. Redistributions of source code must retain the above copyright
13e0f95098SPeter Avalos * notice, this list of conditions and the following disclaimer.
14e0f95098SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
15e0f95098SPeter Avalos * notice, this list of conditions and the following disclaimer in the
16e0f95098SPeter Avalos * documentation and/or other materials provided with the distribution.
17e0f95098SPeter Avalos * 3. Neither the name of the University nor the names of its contributors
18e0f95098SPeter Avalos * may be used to endorse or promote products derived from this software
19e0f95098SPeter Avalos * without specific prior written permission.
20e0f95098SPeter Avalos *
21e0f95098SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22e0f95098SPeter Avalos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23e0f95098SPeter Avalos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24e0f95098SPeter Avalos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25e0f95098SPeter Avalos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26e0f95098SPeter Avalos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27e0f95098SPeter Avalos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28e0f95098SPeter Avalos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29e0f95098SPeter Avalos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30e0f95098SPeter Avalos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31e0f95098SPeter Avalos * SUCH DAMAGE.
32e0f95098SPeter Avalos *
33e0f95098SPeter Avalos * $FreeBSD: src/lib/libc/stdio/xprintf.c,v 1.8 2008/05/05 16:03:52 jhb Exp $
34e0f95098SPeter Avalos */
35e0f95098SPeter Avalos
36e0f95098SPeter Avalos #include "namespace.h"
37e0f95098SPeter Avalos #include <err.h>
38e0f95098SPeter Avalos #include <sys/types.h>
39e0f95098SPeter Avalos #include <stdio.h>
40e0f95098SPeter Avalos #include <stddef.h>
41e0f95098SPeter Avalos #include <stdlib.h>
42e0f95098SPeter Avalos #include <locale.h>
43e0f95098SPeter Avalos #include <stdint.h>
44e0f95098SPeter Avalos #include <assert.h>
45e0f95098SPeter Avalos #include <stdarg.h>
46e0f95098SPeter Avalos #include <string.h>
47e0f95098SPeter Avalos #include <wchar.h>
48e0f95098SPeter Avalos #include "un-namespace.h"
49e0f95098SPeter Avalos
50e0f95098SPeter Avalos #include "printf.h"
51e0f95098SPeter Avalos #include "priv_stdio.h"
52e0f95098SPeter Avalos
53e0f95098SPeter Avalos int __use_xprintf = -1;
54e0f95098SPeter Avalos
55e0f95098SPeter Avalos /* private stuff -----------------------------------------------------*/
56e0f95098SPeter Avalos
57e0f95098SPeter Avalos union arg {
58e0f95098SPeter Avalos int intarg;
59e0f95098SPeter Avalos long longarg;
60e0f95098SPeter Avalos intmax_t intmaxarg;
61e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
62e0f95098SPeter Avalos double doublearg;
63e0f95098SPeter Avalos long double longdoublearg;
64e0f95098SPeter Avalos #endif
65e0f95098SPeter Avalos wint_t wintarg;
66e0f95098SPeter Avalos char *pchararg;
67e0f95098SPeter Avalos wchar_t *pwchararg;
68e0f95098SPeter Avalos void *pvoidarg;
69e0f95098SPeter Avalos };
70e0f95098SPeter Avalos
71e0f95098SPeter Avalos /*
72e0f95098SPeter Avalos * Macros for converting digits to letters and vice versa
73e0f95098SPeter Avalos */
74e0f95098SPeter Avalos #define to_digit(c) ((c) - '0')
75e0f95098SPeter Avalos #define is_digit(c) (((unsigned)to_digit(c)) <= 9)
76e0f95098SPeter Avalos
77e0f95098SPeter Avalos /* various globals ---------------------------------------------------*/
78e0f95098SPeter Avalos
79e0f95098SPeter Avalos const char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */
80e0f95098SPeter Avalos const char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */
81e0f95098SPeter Avalos
82e0f95098SPeter Avalos #define PADSIZE 16
83e0f95098SPeter Avalos static char blanks[PADSIZE] =
84e0f95098SPeter Avalos {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
85e0f95098SPeter Avalos static char zeroes[PADSIZE] =
86e0f95098SPeter Avalos {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
87e0f95098SPeter Avalos
88e0f95098SPeter Avalos /* printing and padding functions ------------------------------------*/
89e0f95098SPeter Avalos
90e0f95098SPeter Avalos #define NIOV 8
91e0f95098SPeter Avalos
92e0f95098SPeter Avalos struct __printf_io {
93e0f95098SPeter Avalos FILE *fp;
94e0f95098SPeter Avalos struct __suio uio;
95e0f95098SPeter Avalos struct __siov iov[NIOV];
96e0f95098SPeter Avalos struct __siov *iovp;
97e0f95098SPeter Avalos };
98e0f95098SPeter Avalos
99e0f95098SPeter Avalos static void
__printf_init(struct __printf_io * io)100e0f95098SPeter Avalos __printf_init(struct __printf_io *io)
101e0f95098SPeter Avalos {
102e0f95098SPeter Avalos
103e0f95098SPeter Avalos io->uio.uio_iov = io->iovp = &io->iov[0];
104e0f95098SPeter Avalos io->uio.uio_resid = 0;
105e0f95098SPeter Avalos io->uio.uio_iovcnt = 0;
106e0f95098SPeter Avalos }
107e0f95098SPeter Avalos
108e0f95098SPeter Avalos void
__printf_flush(struct __printf_io * io)109e0f95098SPeter Avalos __printf_flush(struct __printf_io *io)
110e0f95098SPeter Avalos {
111e0f95098SPeter Avalos
112e0f95098SPeter Avalos __sfvwrite(io->fp, &io->uio);
113e0f95098SPeter Avalos __printf_init(io);
114e0f95098SPeter Avalos }
115e0f95098SPeter Avalos
116e0f95098SPeter Avalos int
__printf_puts(struct __printf_io * io,const void * ptr,int len)117e0f95098SPeter Avalos __printf_puts(struct __printf_io *io, const void *ptr, int len)
118e0f95098SPeter Avalos {
119e0f95098SPeter Avalos
120e0f95098SPeter Avalos if (io->fp->pub._flags & __SERR)
121e0f95098SPeter Avalos return (0);
122e0f95098SPeter Avalos if (len == 0)
123e0f95098SPeter Avalos return (0);
124e0f95098SPeter Avalos io->iovp->iov_base = __DECONST(void *, ptr);
125e0f95098SPeter Avalos io->iovp->iov_len = len;
126e0f95098SPeter Avalos io->uio.uio_resid += len;
127e0f95098SPeter Avalos io->iovp++;
128e0f95098SPeter Avalos io->uio.uio_iovcnt++;
129e0f95098SPeter Avalos if (io->uio.uio_iovcnt >= NIOV)
130e0f95098SPeter Avalos __printf_flush(io);
131e0f95098SPeter Avalos return (len);
132e0f95098SPeter Avalos }
133e0f95098SPeter Avalos
134e0f95098SPeter Avalos int
__printf_pad(struct __printf_io * io,int howmany,int zero)135e0f95098SPeter Avalos __printf_pad(struct __printf_io *io, int howmany, int zero)
136e0f95098SPeter Avalos {
137e0f95098SPeter Avalos int n;
138e0f95098SPeter Avalos const char *with;
139e0f95098SPeter Avalos int ret = 0;
140e0f95098SPeter Avalos
141e0f95098SPeter Avalos if (zero)
142e0f95098SPeter Avalos with = zeroes;
143e0f95098SPeter Avalos else
144e0f95098SPeter Avalos with = blanks;
145e0f95098SPeter Avalos
146e0f95098SPeter Avalos if ((n = (howmany)) > 0) {
147e0f95098SPeter Avalos while (n > PADSIZE) {
148e0f95098SPeter Avalos ret += __printf_puts(io, with, PADSIZE);
149e0f95098SPeter Avalos n -= PADSIZE;
150e0f95098SPeter Avalos }
151e0f95098SPeter Avalos ret += __printf_puts(io, with, n);
152e0f95098SPeter Avalos }
153e0f95098SPeter Avalos return (ret);
154e0f95098SPeter Avalos }
155e0f95098SPeter Avalos
156e0f95098SPeter Avalos int
__printf_out(struct __printf_io * io,const struct printf_info * pi,const void * ptr,int len)157e0f95098SPeter Avalos __printf_out(struct __printf_io *io, const struct printf_info *pi,
158e0f95098SPeter Avalos const void *ptr, int len)
159e0f95098SPeter Avalos {
160e0f95098SPeter Avalos int ret = 0;
161e0f95098SPeter Avalos
162e0f95098SPeter Avalos if ((!pi->left) && pi->width > len)
163e0f95098SPeter Avalos ret += __printf_pad(io, pi->width - len, pi->pad == '0');
164e0f95098SPeter Avalos ret += __printf_puts(io, ptr, len);
165e0f95098SPeter Avalos if (pi->left && pi->width > len)
166e0f95098SPeter Avalos ret += __printf_pad(io, pi->width - len, pi->pad == '0');
167e0f95098SPeter Avalos return (ret);
168e0f95098SPeter Avalos }
169e0f95098SPeter Avalos
170e0f95098SPeter Avalos
171e0f95098SPeter Avalos /* percent handling -------------------------------------------------*/
172e0f95098SPeter Avalos
173e0f95098SPeter Avalos static int
__printf_arginfo_pct(const struct printf_info * pi __unused,size_t n __unused,int * argt __unused)174e0f95098SPeter Avalos __printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused,
175e0f95098SPeter Avalos int *argt __unused)
176e0f95098SPeter Avalos {
177e0f95098SPeter Avalos
178e0f95098SPeter Avalos return (0);
179e0f95098SPeter Avalos }
180e0f95098SPeter Avalos
181e0f95098SPeter Avalos static int
__printf_render_pct(struct __printf_io * io,const struct printf_info * pi __unused,const void * const * arg __unused)182e0f95098SPeter Avalos __printf_render_pct(struct __printf_io *io,
183e0f95098SPeter Avalos const struct printf_info *pi __unused,
184e0f95098SPeter Avalos const void *const *arg __unused)
185e0f95098SPeter Avalos {
186e0f95098SPeter Avalos
187e0f95098SPeter Avalos return (__printf_puts(io, "%", 1));
188e0f95098SPeter Avalos }
189e0f95098SPeter Avalos
190e0f95098SPeter Avalos /* 'n' ---------------------------------------------------------------*/
191e0f95098SPeter Avalos
192e0f95098SPeter Avalos static int
__printf_arginfo_n(const struct printf_info * pi __unused,size_t n,int * argt)193*6d7019e6SSascha Wildner __printf_arginfo_n(const struct printf_info *pi __unused, size_t n, int *argt)
194e0f95098SPeter Avalos {
195e0f95098SPeter Avalos
196e0f95098SPeter Avalos assert(n >= 1);
197e0f95098SPeter Avalos argt[0] = PA_POINTER;
198e0f95098SPeter Avalos return (1);
199e0f95098SPeter Avalos }
200e0f95098SPeter Avalos
201e0f95098SPeter Avalos /*
202e0f95098SPeter Avalos * This is a printf_render so that all output has been flushed before it
203e0f95098SPeter Avalos * gets called.
204e0f95098SPeter Avalos */
205e0f95098SPeter Avalos
206e0f95098SPeter Avalos static int
__printf_render_n(FILE * io __unused,const struct printf_info * pi,const void * const * arg)207e0f95098SPeter Avalos __printf_render_n(FILE *io __unused, const struct printf_info *pi,
208e0f95098SPeter Avalos const void *const *arg)
209e0f95098SPeter Avalos {
210e0f95098SPeter Avalos
211e0f95098SPeter Avalos if (pi->is_char)
212e0f95098SPeter Avalos **((signed char **)arg[0]) = (signed char)pi->sofar;
213e0f95098SPeter Avalos else if (pi->is_short)
214e0f95098SPeter Avalos **((short **)arg[0]) = (short)pi->sofar;
215e0f95098SPeter Avalos else if (pi->is_long)
216e0f95098SPeter Avalos **((long **)arg[0]) = pi->sofar;
217e0f95098SPeter Avalos else if (pi->is_long_double)
218e0f95098SPeter Avalos **((long long **)arg[0]) = pi->sofar;
219e0f95098SPeter Avalos else if (pi->is_intmax)
220e0f95098SPeter Avalos **((intmax_t **)arg[0]) = pi->sofar;
221e0f95098SPeter Avalos else if (pi->is_ptrdiff)
222e0f95098SPeter Avalos **((ptrdiff_t **)arg[0]) = pi->sofar;
223e0f95098SPeter Avalos else if (pi->is_quad)
224e0f95098SPeter Avalos **((quad_t **)arg[0]) = pi->sofar;
225e0f95098SPeter Avalos else if (pi->is_size)
226e0f95098SPeter Avalos **((size_t **)arg[0]) = pi->sofar;
227e0f95098SPeter Avalos else
228e0f95098SPeter Avalos **((int **)arg[0]) = pi->sofar;
229e0f95098SPeter Avalos
230e0f95098SPeter Avalos return (0);
231e0f95098SPeter Avalos }
232e0f95098SPeter Avalos
233e0f95098SPeter Avalos /* table -------------------------------------------------------------*/
234e0f95098SPeter Avalos
235e0f95098SPeter Avalos /*lint -esym(785, printf_tbl) */
236e0f95098SPeter Avalos static struct {
237e0f95098SPeter Avalos printf_arginfo_function *arginfo;
238e0f95098SPeter Avalos printf_function *gnurender;
239e0f95098SPeter Avalos printf_render *render;
240e0f95098SPeter Avalos } printf_tbl[256] = {
241e0f95098SPeter Avalos ['%'] = { __printf_arginfo_pct, NULL, __printf_render_pct },
242e0f95098SPeter Avalos ['A'] = { __printf_arginfo_float, NULL, __printf_render_float },
243e0f95098SPeter Avalos ['C'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
244e0f95098SPeter Avalos ['E'] = { __printf_arginfo_float, NULL, __printf_render_float },
245e0f95098SPeter Avalos ['F'] = { __printf_arginfo_float, NULL, __printf_render_float },
246e0f95098SPeter Avalos ['G'] = { __printf_arginfo_float, NULL, __printf_render_float },
247e0f95098SPeter Avalos ['S'] = { __printf_arginfo_str, NULL, __printf_render_str },
248e0f95098SPeter Avalos ['X'] = { __printf_arginfo_int, NULL, __printf_render_int },
249e0f95098SPeter Avalos ['a'] = { __printf_arginfo_float, NULL, __printf_render_float },
250e0f95098SPeter Avalos ['c'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
251e0f95098SPeter Avalos ['d'] = { __printf_arginfo_int, NULL, __printf_render_int },
252e0f95098SPeter Avalos ['e'] = { __printf_arginfo_float, NULL, __printf_render_float },
253e0f95098SPeter Avalos ['f'] = { __printf_arginfo_float, NULL, __printf_render_float },
254e0f95098SPeter Avalos ['g'] = { __printf_arginfo_float, NULL, __printf_render_float },
255e0f95098SPeter Avalos ['i'] = { __printf_arginfo_int, NULL, __printf_render_int },
256e0f95098SPeter Avalos ['n'] = { __printf_arginfo_n, __printf_render_n, NULL },
257e0f95098SPeter Avalos ['o'] = { __printf_arginfo_int, NULL, __printf_render_int },
258e0f95098SPeter Avalos ['p'] = { __printf_arginfo_ptr, NULL, __printf_render_ptr },
259e0f95098SPeter Avalos ['q'] = { __printf_arginfo_int, NULL, __printf_render_int },
260e0f95098SPeter Avalos ['s'] = { __printf_arginfo_str, NULL, __printf_render_str },
261e0f95098SPeter Avalos ['u'] = { __printf_arginfo_int, NULL, __printf_render_int },
262e0f95098SPeter Avalos ['x'] = { __printf_arginfo_int, NULL, __printf_render_int },
263e0f95098SPeter Avalos };
264e0f95098SPeter Avalos
265e0f95098SPeter Avalos
266e0f95098SPeter Avalos static int
__v2printf(FILE * fp,const char * fmt0,unsigned pct,va_list ap)267e0f95098SPeter Avalos __v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap)
268e0f95098SPeter Avalos {
269e0f95098SPeter Avalos struct printf_info *pi, *pil;
270e0f95098SPeter Avalos const char *fmt;
271e0f95098SPeter Avalos int ch;
272e0f95098SPeter Avalos struct printf_info pia[pct + 10];
273e0f95098SPeter Avalos int argt[pct + 10];
274e0f95098SPeter Avalos union arg args[pct + 10];
275e0f95098SPeter Avalos int nextarg;
276e0f95098SPeter Avalos int maxarg;
277e0f95098SPeter Avalos int ret = 0;
278e0f95098SPeter Avalos int n;
279e0f95098SPeter Avalos struct __printf_io io;
280e0f95098SPeter Avalos
281e0f95098SPeter Avalos __printf_init(&io);
282e0f95098SPeter Avalos io.fp = fp;
283e0f95098SPeter Avalos
284e0f95098SPeter Avalos fmt = fmt0;
285e0f95098SPeter Avalos maxarg = 0;
286e0f95098SPeter Avalos nextarg = 1;
287e0f95098SPeter Avalos memset(argt, 0, sizeof argt);
288e0f95098SPeter Avalos for (pi = pia; ; pi++) {
289e0f95098SPeter Avalos memset(pi, 0, sizeof *pi);
290e0f95098SPeter Avalos pil = pi;
291e0f95098SPeter Avalos if (*fmt == '\0')
292e0f95098SPeter Avalos break;
293e0f95098SPeter Avalos pil = pi + 1;
294e0f95098SPeter Avalos pi->prec = -1;
295e0f95098SPeter Avalos pi->pad = ' ';
296e0f95098SPeter Avalos pi->begin = pi->end = fmt;
297e0f95098SPeter Avalos while (*fmt != '\0' && *fmt != '%')
298e0f95098SPeter Avalos pi->end = ++fmt;
299e0f95098SPeter Avalos if (*fmt == '\0')
300e0f95098SPeter Avalos break;
301e0f95098SPeter Avalos fmt++;
302e0f95098SPeter Avalos for (;;) {
303e0f95098SPeter Avalos pi->spec = *fmt;
304e0f95098SPeter Avalos switch (pi->spec) {
305e0f95098SPeter Avalos case ' ':
306e0f95098SPeter Avalos /*-
307e0f95098SPeter Avalos * ``If the space and + flags both appear, the space
308e0f95098SPeter Avalos * flag will be ignored.''
309e0f95098SPeter Avalos * -- ANSI X3J11
310e0f95098SPeter Avalos */
311e0f95098SPeter Avalos if (pi->showsign == 0)
312e0f95098SPeter Avalos pi->showsign = ' ';
313e0f95098SPeter Avalos fmt++;
314e0f95098SPeter Avalos continue;
315e0f95098SPeter Avalos case '#':
316e0f95098SPeter Avalos pi->alt = 1;
317e0f95098SPeter Avalos fmt++;
318e0f95098SPeter Avalos continue;
319e0f95098SPeter Avalos case '.':
320e0f95098SPeter Avalos pi->prec = 0;
321e0f95098SPeter Avalos fmt++;
322e0f95098SPeter Avalos if (*fmt == '*') {
323e0f95098SPeter Avalos fmt++;
324e0f95098SPeter Avalos pi->get_prec = nextarg;
325e0f95098SPeter Avalos argt[nextarg++] = PA_INT;
326e0f95098SPeter Avalos continue;
327e0f95098SPeter Avalos }
328e0f95098SPeter Avalos while (*fmt != '\0' && is_digit(*fmt)) {
329e0f95098SPeter Avalos pi->prec *= 10;
330e0f95098SPeter Avalos pi->prec += to_digit(*fmt);
331e0f95098SPeter Avalos fmt++;
332e0f95098SPeter Avalos }
333e0f95098SPeter Avalos continue;
334e0f95098SPeter Avalos case '-':
335e0f95098SPeter Avalos pi->left = 1;
336e0f95098SPeter Avalos fmt++;
337e0f95098SPeter Avalos continue;
338e0f95098SPeter Avalos case '+':
339e0f95098SPeter Avalos pi->showsign = '+';
340e0f95098SPeter Avalos fmt++;
341e0f95098SPeter Avalos continue;
342e0f95098SPeter Avalos case '*':
343e0f95098SPeter Avalos fmt++;
344e0f95098SPeter Avalos pi->get_width = nextarg;
345e0f95098SPeter Avalos argt[nextarg++] = PA_INT;
346e0f95098SPeter Avalos continue;
347e0f95098SPeter Avalos case '%':
348e0f95098SPeter Avalos fmt++;
349e0f95098SPeter Avalos break;
350e0f95098SPeter Avalos case '\'':
351e0f95098SPeter Avalos pi->group = 1;
352e0f95098SPeter Avalos fmt++;
353e0f95098SPeter Avalos continue;
354e0f95098SPeter Avalos case '0':
355e0f95098SPeter Avalos /*-
356e0f95098SPeter Avalos * ``Note that 0 is taken as a flag, not as the
357e0f95098SPeter Avalos * beginning of a field width.''
358e0f95098SPeter Avalos * -- ANSI X3J11
359e0f95098SPeter Avalos */
360e0f95098SPeter Avalos pi->pad = '0';
361e0f95098SPeter Avalos fmt++;
362e0f95098SPeter Avalos continue;
363e0f95098SPeter Avalos case '1': case '2': case '3':
364e0f95098SPeter Avalos case '4': case '5': case '6':
365e0f95098SPeter Avalos case '7': case '8': case '9':
366e0f95098SPeter Avalos n = 0;
367e0f95098SPeter Avalos while (*fmt != '\0' && is_digit(*fmt)) {
368e0f95098SPeter Avalos n *= 10;
369e0f95098SPeter Avalos n += to_digit(*fmt);
370e0f95098SPeter Avalos fmt++;
371e0f95098SPeter Avalos }
372e0f95098SPeter Avalos if (*fmt == '$') {
373e0f95098SPeter Avalos if (nextarg > maxarg)
374e0f95098SPeter Avalos maxarg = nextarg;
375e0f95098SPeter Avalos nextarg = n;
376e0f95098SPeter Avalos fmt++;
377e0f95098SPeter Avalos } else {
378e0f95098SPeter Avalos pi->width = n;
379e0f95098SPeter Avalos }
380e0f95098SPeter Avalos continue;
381e0f95098SPeter Avalos case 'D':
382e0f95098SPeter Avalos case 'O':
383e0f95098SPeter Avalos case 'U':
384e0f95098SPeter Avalos pi->spec += ('a' - 'A');
385e0f95098SPeter Avalos pi->is_intmax = 0;
386e0f95098SPeter Avalos if (pi->is_long_double || pi->is_quad) {
387e0f95098SPeter Avalos pi->is_long = 0;
388e0f95098SPeter Avalos pi->is_long_double = 1;
389e0f95098SPeter Avalos } else {
390e0f95098SPeter Avalos pi->is_long = 1;
391e0f95098SPeter Avalos pi->is_long_double = 0;
392e0f95098SPeter Avalos }
393e0f95098SPeter Avalos fmt++;
394e0f95098SPeter Avalos break;
395e0f95098SPeter Avalos case 'j':
396e0f95098SPeter Avalos pi->is_intmax = 1;
397e0f95098SPeter Avalos fmt++;
398e0f95098SPeter Avalos continue;
399e0f95098SPeter Avalos case 'q':
400e0f95098SPeter Avalos pi->is_long = 0;
401e0f95098SPeter Avalos pi->is_quad = 1;
402e0f95098SPeter Avalos fmt++;
403e0f95098SPeter Avalos continue;
404e0f95098SPeter Avalos case 'L':
405e0f95098SPeter Avalos pi->is_long_double = 1;
406e0f95098SPeter Avalos fmt++;
407e0f95098SPeter Avalos continue;
408e0f95098SPeter Avalos case 'h':
409e0f95098SPeter Avalos fmt++;
410e0f95098SPeter Avalos if (*fmt == 'h') {
411e0f95098SPeter Avalos fmt++;
412e0f95098SPeter Avalos pi->is_char = 1;
413e0f95098SPeter Avalos } else {
414e0f95098SPeter Avalos pi->is_short = 1;
415e0f95098SPeter Avalos }
416e0f95098SPeter Avalos continue;
417e0f95098SPeter Avalos case 'l':
418e0f95098SPeter Avalos fmt++;
419e0f95098SPeter Avalos if (*fmt == 'l') {
420e0f95098SPeter Avalos fmt++;
421e0f95098SPeter Avalos pi->is_long_double = 1;
422e0f95098SPeter Avalos pi->is_quad = 0;
423e0f95098SPeter Avalos } else {
424e0f95098SPeter Avalos pi->is_quad = 0;
425e0f95098SPeter Avalos pi->is_long = 1;
426e0f95098SPeter Avalos }
427e0f95098SPeter Avalos continue;
428e0f95098SPeter Avalos case 't':
429e0f95098SPeter Avalos pi->is_ptrdiff = 1;
430e0f95098SPeter Avalos fmt++;
431e0f95098SPeter Avalos continue;
432e0f95098SPeter Avalos case 'z':
433e0f95098SPeter Avalos pi->is_size = 1;
434e0f95098SPeter Avalos fmt++;
435e0f95098SPeter Avalos continue;
436e0f95098SPeter Avalos default:
437e0f95098SPeter Avalos fmt++;
438e0f95098SPeter Avalos break;
439e0f95098SPeter Avalos }
440e0f95098SPeter Avalos if (printf_tbl[pi->spec].arginfo == NULL)
441e0f95098SPeter Avalos errx(1, "arginfo[%c] = NULL", pi->spec);
442e0f95098SPeter Avalos ch = printf_tbl[pi->spec].arginfo(
443e0f95098SPeter Avalos pi, __PRINTFMAXARG, &argt[nextarg]);
444e0f95098SPeter Avalos if (ch > 0)
445e0f95098SPeter Avalos pi->arg[0] = &args[nextarg];
446e0f95098SPeter Avalos if (ch > 1)
447e0f95098SPeter Avalos pi->arg[1] = &args[nextarg + 1];
448e0f95098SPeter Avalos nextarg += ch;
449e0f95098SPeter Avalos break;
450e0f95098SPeter Avalos }
451e0f95098SPeter Avalos }
452e0f95098SPeter Avalos if (nextarg > maxarg)
453e0f95098SPeter Avalos maxarg = nextarg;
454e0f95098SPeter Avalos #if 0
455e0f95098SPeter Avalos fprintf(stderr, "fmt0 <%s>\n", fmt0);
456e0f95098SPeter Avalos fprintf(stderr, "pil %p\n", pil);
457e0f95098SPeter Avalos #endif
458e0f95098SPeter Avalos for (ch = 1; ch < maxarg; ch++) {
459e0f95098SPeter Avalos #if 0
460e0f95098SPeter Avalos fprintf(stderr, "arg %d %x\n", ch, argt[ch]);
461e0f95098SPeter Avalos #endif
462e0f95098SPeter Avalos switch(argt[ch]) {
463e0f95098SPeter Avalos case PA_CHAR:
464e0f95098SPeter Avalos args[ch].intarg = (char)va_arg(ap, int);
465e0f95098SPeter Avalos break;
466e0f95098SPeter Avalos case PA_INT:
467e0f95098SPeter Avalos args[ch].intarg = va_arg(ap, int);
468e0f95098SPeter Avalos break;
469e0f95098SPeter Avalos case PA_INT | PA_FLAG_SHORT:
470e0f95098SPeter Avalos args[ch].intarg = (short)va_arg(ap, int);
471e0f95098SPeter Avalos break;
472e0f95098SPeter Avalos case PA_INT | PA_FLAG_LONG:
473e0f95098SPeter Avalos args[ch].longarg = va_arg(ap, long);
474e0f95098SPeter Avalos break;
475e0f95098SPeter Avalos case PA_INT | PA_FLAG_INTMAX:
476e0f95098SPeter Avalos args[ch].intmaxarg = va_arg(ap, intmax_t);
477e0f95098SPeter Avalos break;
478e0f95098SPeter Avalos case PA_INT | PA_FLAG_QUAD:
479e0f95098SPeter Avalos args[ch].intmaxarg = va_arg(ap, quad_t);
480e0f95098SPeter Avalos break;
481e0f95098SPeter Avalos case PA_INT | PA_FLAG_LONG_LONG:
482e0f95098SPeter Avalos args[ch].intmaxarg = va_arg(ap, long long);
483e0f95098SPeter Avalos break;
484e0f95098SPeter Avalos case PA_INT | PA_FLAG_SIZE:
485e0f95098SPeter Avalos args[ch].intmaxarg = va_arg(ap, size_t);
486e0f95098SPeter Avalos break;
487e0f95098SPeter Avalos case PA_INT | PA_FLAG_PTRDIFF:
488e0f95098SPeter Avalos args[ch].intmaxarg = va_arg(ap, ptrdiff_t);
489e0f95098SPeter Avalos break;
490e0f95098SPeter Avalos case PA_WCHAR:
491e0f95098SPeter Avalos args[ch].wintarg = va_arg(ap, wint_t);
492e0f95098SPeter Avalos break;
493e0f95098SPeter Avalos case PA_POINTER:
494e0f95098SPeter Avalos args[ch].pvoidarg = va_arg(ap, void *);
495e0f95098SPeter Avalos break;
496e0f95098SPeter Avalos case PA_STRING:
497e0f95098SPeter Avalos args[ch].pchararg = va_arg(ap, char *);
498e0f95098SPeter Avalos break;
499e0f95098SPeter Avalos case PA_WSTRING:
500e0f95098SPeter Avalos args[ch].pwchararg = va_arg(ap, wchar_t *);
501e0f95098SPeter Avalos break;
502e0f95098SPeter Avalos case PA_DOUBLE:
503e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
504e0f95098SPeter Avalos args[ch].doublearg = va_arg(ap, double);
505e0f95098SPeter Avalos #endif
506e0f95098SPeter Avalos break;
507e0f95098SPeter Avalos case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
508e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
509e0f95098SPeter Avalos args[ch].longdoublearg = va_arg(ap, long double);
510e0f95098SPeter Avalos #endif
511e0f95098SPeter Avalos break;
512e0f95098SPeter Avalos default:
513e0f95098SPeter Avalos errx(1, "argtype = %x (fmt = \"%s\")\n",
514e0f95098SPeter Avalos argt[ch], fmt0);
515e0f95098SPeter Avalos }
516e0f95098SPeter Avalos }
517e0f95098SPeter Avalos for (pi = pia; pi < pil; pi++) {
518e0f95098SPeter Avalos #if 0
519e0f95098SPeter Avalos fprintf(stderr, "pi %p", pi);
520e0f95098SPeter Avalos fprintf(stderr, " spec '%c'", pi->spec);
521e0f95098SPeter Avalos fprintf(stderr, " args %d",
522e0f95098SPeter Avalos ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]);
523e0f95098SPeter Avalos if (pi->width) fprintf(stderr, " width %d", pi->width);
524e0f95098SPeter Avalos if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
525e0f95098SPeter Avalos if (pi->left) fprintf(stderr, " left");
526e0f95098SPeter Avalos if (pi->showsign) fprintf(stderr, " showsign");
527e0f95098SPeter Avalos if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
528e0f95098SPeter Avalos if (pi->is_char) fprintf(stderr, " char");
529e0f95098SPeter Avalos if (pi->is_short) fprintf(stderr, " short");
530e0f95098SPeter Avalos if (pi->is_long) fprintf(stderr, " long");
531e0f95098SPeter Avalos if (pi->is_long_double) fprintf(stderr, " long_double");
532e0f95098SPeter Avalos fprintf(stderr, "\n");
533e0f95098SPeter Avalos fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
534e0f95098SPeter Avalos #endif
535e0f95098SPeter Avalos if (pi->get_width) {
536e0f95098SPeter Avalos pi->width = args[pi->get_width].intarg;
537e0f95098SPeter Avalos /*-
538e0f95098SPeter Avalos * ``A negative field width argument is taken as a
539e0f95098SPeter Avalos * - flag followed by a positive field width.''
540e0f95098SPeter Avalos * -- ANSI X3J11
541e0f95098SPeter Avalos * They don't exclude field widths read from args.
542e0f95098SPeter Avalos */
543e0f95098SPeter Avalos if (pi->width < 0) {
544e0f95098SPeter Avalos pi->left = 1;
545e0f95098SPeter Avalos pi->width = -pi->width;
546e0f95098SPeter Avalos }
547e0f95098SPeter Avalos }
548e0f95098SPeter Avalos if (pi->get_prec)
549e0f95098SPeter Avalos pi->prec = args[pi->get_prec].intarg;
550e0f95098SPeter Avalos ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
551e0f95098SPeter Avalos if (printf_tbl[pi->spec].gnurender != NULL) {
552e0f95098SPeter Avalos __printf_flush(&io);
553e0f95098SPeter Avalos pi->sofar = ret;
554e0f95098SPeter Avalos ret += printf_tbl[pi->spec].gnurender(
555e0f95098SPeter Avalos fp, pi, (const void *)pi->arg);
556e0f95098SPeter Avalos } else if (printf_tbl[pi->spec].render != NULL) {
557e0f95098SPeter Avalos pi->sofar = ret;
558e0f95098SPeter Avalos n = printf_tbl[pi->spec].render(
559e0f95098SPeter Avalos &io, pi, (const void *)pi->arg);
560e0f95098SPeter Avalos if (n < 0)
561e0f95098SPeter Avalos io.fp->pub._flags |= __SERR;
562e0f95098SPeter Avalos else
563e0f95098SPeter Avalos ret += n;
564e0f95098SPeter Avalos } else if (pi->begin == pi->end)
565e0f95098SPeter Avalos errx(1, "render[%c] = NULL", *fmt);
566e0f95098SPeter Avalos }
567e0f95098SPeter Avalos __printf_flush(&io);
568e0f95098SPeter Avalos return (ret);
569e0f95098SPeter Avalos }
570e0f95098SPeter Avalos
571e0f95098SPeter Avalos extern int __fflush(FILE *fp);
572e0f95098SPeter Avalos
573e0f95098SPeter Avalos /*
574e0f95098SPeter Avalos * Helper function for `fprintf to unbuffered unix file': creates a
575e0f95098SPeter Avalos * temporary buffer. We only work on write-only files; this avoids
576e0f95098SPeter Avalos * worries about ungetc buffers and so forth.
577e0f95098SPeter Avalos */
578e0f95098SPeter Avalos static int
__v3printf(FILE * fp,const char * fmt,int pct,va_list ap)579e0f95098SPeter Avalos __v3printf(FILE *fp, const char *fmt, int pct, va_list ap)
580e0f95098SPeter Avalos {
581e0f95098SPeter Avalos int ret;
582e0f95098SPeter Avalos FILE fake;
583e0f95098SPeter Avalos unsigned char buf[BUFSIZ];
584e0f95098SPeter Avalos
585e0f95098SPeter Avalos /* copy the important variables */
586e0f95098SPeter Avalos fake.pub._flags = fp->pub._flags & ~__SNBF;
587e0f95098SPeter Avalos fake.pub._fileno = fp->pub._fileno;
588e0f95098SPeter Avalos fake._cookie = fp->_cookie;
589e0f95098SPeter Avalos fake._write = fp->_write;
590e0f95098SPeter Avalos memcpy(WCIO_GET(&fake), WCIO_GET(fp), sizeof(struct wchar_io_data));
591e0f95098SPeter Avalos
592e0f95098SPeter Avalos /* set up the buffer */
593e0f95098SPeter Avalos fake._bf._base = fake.pub._p = buf;
594e0f95098SPeter Avalos fake._bf._size = fake.pub._w = sizeof(buf);
595e0f95098SPeter Avalos fake.pub._lbfsize = 0; /* not actually used, but Just In Case */
596e0f95098SPeter Avalos
597e0f95098SPeter Avalos /* do the work, then copy any error status */
598e0f95098SPeter Avalos ret = __v2printf(&fake, fmt, pct, ap);
599e0f95098SPeter Avalos if (ret >= 0 && __fflush(&fake))
600e0f95098SPeter Avalos ret = EOF;
601e0f95098SPeter Avalos if (fake.pub._flags & __SERR)
602e0f95098SPeter Avalos fp->pub._flags |= __SERR;
603e0f95098SPeter Avalos return (ret);
604e0f95098SPeter Avalos }
605e0f95098SPeter Avalos
606e0f95098SPeter Avalos int
__xvprintf(FILE * fp,const char * fmt0,va_list ap)607e0f95098SPeter Avalos __xvprintf(FILE *fp, const char *fmt0, va_list ap)
608e0f95098SPeter Avalos {
609e0f95098SPeter Avalos unsigned u;
610e0f95098SPeter Avalos const char *p;
611e0f95098SPeter Avalos
612e0f95098SPeter Avalos /* Count number of '%' signs handling double '%' signs */
613e0f95098SPeter Avalos for (p = fmt0, u = 0; *p; p++) {
614e0f95098SPeter Avalos if (*p != '%')
615e0f95098SPeter Avalos continue;
616e0f95098SPeter Avalos u++;
617e0f95098SPeter Avalos if (p[1] == '%')
618e0f95098SPeter Avalos p++;
619e0f95098SPeter Avalos }
620e0f95098SPeter Avalos
621e0f95098SPeter Avalos /* optimise fprintf(stderr) (and other unbuffered Unix files) */
622e0f95098SPeter Avalos if ((fp->pub._flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
623e0f95098SPeter Avalos fp->pub._fileno >= 0)
624e0f95098SPeter Avalos return (__v3printf(fp, fmt0, u, ap));
625e0f95098SPeter Avalos else
626e0f95098SPeter Avalos return (__v2printf(fp, fmt0, u, ap));
627e0f95098SPeter Avalos }
628e0f95098SPeter Avalos
629e0f95098SPeter Avalos /* extending ---------------------------------------------------------*/
630e0f95098SPeter Avalos
631e0f95098SPeter Avalos int
register_printf_function(int spec,printf_function * render,printf_arginfo_function * arginfo)632e0f95098SPeter Avalos register_printf_function(int spec, printf_function *render,
633e0f95098SPeter Avalos printf_arginfo_function *arginfo)
634e0f95098SPeter Avalos {
635e0f95098SPeter Avalos
636e0f95098SPeter Avalos if (spec > 255 || spec < 0)
637e0f95098SPeter Avalos return (-1);
638e0f95098SPeter Avalos printf_tbl[spec].gnurender = render;
639e0f95098SPeter Avalos printf_tbl[spec].arginfo = arginfo;
640e0f95098SPeter Avalos __use_xprintf = 1;
641e0f95098SPeter Avalos return (0);
642e0f95098SPeter Avalos }
643e0f95098SPeter Avalos
644e0f95098SPeter Avalos int
register_printf_render(int spec,printf_render * render,printf_arginfo_function * arginfo)645e0f95098SPeter Avalos register_printf_render(int spec, printf_render *render,
646e0f95098SPeter Avalos printf_arginfo_function *arginfo)
647e0f95098SPeter Avalos {
648e0f95098SPeter Avalos
649e0f95098SPeter Avalos if (spec > 255 || spec < 0)
650e0f95098SPeter Avalos return (-1);
651e0f95098SPeter Avalos printf_tbl[spec].render = render;
652e0f95098SPeter Avalos printf_tbl[spec].arginfo = arginfo;
653e0f95098SPeter Avalos __use_xprintf = 1;
654e0f95098SPeter Avalos return (0);
655e0f95098SPeter Avalos }
656e0f95098SPeter Avalos
657e0f95098SPeter Avalos int
register_printf_render_std(const unsigned char * specs)658e0f95098SPeter Avalos register_printf_render_std(const unsigned char *specs)
659e0f95098SPeter Avalos {
660e0f95098SPeter Avalos
661e0f95098SPeter Avalos for (; *specs != '\0'; specs++) {
662e0f95098SPeter Avalos switch (*specs) {
663e0f95098SPeter Avalos case 'H':
664e0f95098SPeter Avalos register_printf_render(*specs,
665e0f95098SPeter Avalos __printf_render_hexdump,
666e0f95098SPeter Avalos __printf_arginfo_hexdump);
667e0f95098SPeter Avalos break;
668e0f95098SPeter Avalos case 'M':
669e0f95098SPeter Avalos register_printf_render(*specs,
670e0f95098SPeter Avalos __printf_render_errno,
671e0f95098SPeter Avalos __printf_arginfo_errno);
672e0f95098SPeter Avalos break;
673e0f95098SPeter Avalos case 'Q':
674e0f95098SPeter Avalos register_printf_render(*specs,
675e0f95098SPeter Avalos __printf_render_quote,
676e0f95098SPeter Avalos __printf_arginfo_quote);
677e0f95098SPeter Avalos break;
678e0f95098SPeter Avalos case 'T':
679e0f95098SPeter Avalos register_printf_render(*specs,
680e0f95098SPeter Avalos __printf_render_time,
681e0f95098SPeter Avalos __printf_arginfo_time);
682e0f95098SPeter Avalos break;
683e0f95098SPeter Avalos case 'V':
684e0f95098SPeter Avalos register_printf_render(*specs,
685e0f95098SPeter Avalos __printf_render_vis,
686e0f95098SPeter Avalos __printf_arginfo_vis);
687e0f95098SPeter Avalos break;
688e0f95098SPeter Avalos default:
689e0f95098SPeter Avalos return (-1);
690e0f95098SPeter Avalos }
691e0f95098SPeter Avalos }
692e0f95098SPeter Avalos return (0);
693e0f95098SPeter Avalos }
694