xprintf.c revision 178287
1153486Sphk/*-
2153486Sphk * Copyright (c) 2005 Poul-Henning Kamp
3153486Sphk * Copyright (c) 1990, 1993
4153486Sphk *	The Regents of the University of California.  All rights reserved.
5153486Sphk *
6153486Sphk * This code is derived from software contributed to Berkeley by
7153486Sphk * Chris Torek.
8153486Sphk *
9153486Sphk * Redistribution and use in source and binary forms, with or without
10153486Sphk * modification, are permitted provided that the following conditions
11153486Sphk * are met:
12153486Sphk * 1. Redistributions of source code must retain the above copyright
13153486Sphk *    notice, this list of conditions and the following disclaimer.
14153486Sphk * 2. Redistributions in binary form must reproduce the above copyright
15153486Sphk *    notice, this list of conditions and the following disclaimer in the
16153486Sphk *    documentation and/or other materials provided with the distribution.
17153486Sphk * 3. Neither the name of the University nor the names of its contributors
18153486Sphk *    may be used to endorse or promote products derived from this software
19153486Sphk *    without specific prior written permission.
20153486Sphk *
21153486Sphk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22153486Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23153486Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24153486Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25153486Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26153486Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27153486Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28153486Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29153486Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30153486Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31153486Sphk * SUCH DAMAGE.
32153486Sphk *
33153486Sphk * $FreeBSD: head/lib/libc/stdio/xprintf.c 178287 2008-04-17 22:17:54Z jhb $
34153486Sphk */
35153486Sphk
36153486Sphk#include <namespace.h>
37153486Sphk#include <err.h>
38153486Sphk#include <sys/types.h>
39153486Sphk#include <stdio.h>
40153486Sphk#include <stddef.h>
41153486Sphk#include <stdlib.h>
42153486Sphk#include <locale.h>
43153486Sphk#include <stdint.h>
44153486Sphk#include <assert.h>
45153486Sphk#include <stdarg.h>
46153486Sphk#include <namespace.h>
47153486Sphk#include <string.h>
48153486Sphk#include <wchar.h>
49153486Sphk#include <un-namespace.h>
50153486Sphk
51153486Sphk#include "printf.h"
52153486Sphk#include "fvwrite.h"
53153486Sphk
54153486Sphkint __use_xprintf = -1;
55153486Sphk
56153486Sphk/* private stuff -----------------------------------------------------*/
57153486Sphk
58153486Sphkunion arg {
59153486Sphk	int			intarg;
60153486Sphk	long			longarg;
61153486Sphk	intmax_t 		intmaxarg;
62153486Sphk#ifndef NO_FLOATING_POINT
63153486Sphk	double			doublearg;
64153486Sphk	long double 		longdoublearg;
65153486Sphk#endif
66153486Sphk	wint_t			wintarg;
67153486Sphk	char			*pchararg;
68153486Sphk	wchar_t			*pwchararg;
69153486Sphk	void			*pvoidarg;
70153486Sphk};
71153486Sphk
72153486Sphk/*
73153486Sphk * Macros for converting digits to letters and vice versa
74153486Sphk */
75153486Sphk#define	to_digit(c)	((c) - '0')
76153486Sphk#define is_digit(c)	(((unsigned)to_digit(c)) <= 9)
77153486Sphk
78153486Sphk/* various globals ---------------------------------------------------*/
79153486Sphk
80153486Sphkconst char __lowercase_hex[17] = "0123456789abcdef?";	/*lint !e784 */
81153486Sphkconst char __uppercase_hex[17] = "0123456789ABCDEF?";	/*lint !e784 */
82153486Sphk
83153486Sphk#define PADSIZE 16
84153486Sphkstatic char blanks[PADSIZE] =
85153486Sphk	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
86153486Sphkstatic char zeroes[PADSIZE] =
87153486Sphk	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
88153486Sphk
89153486Sphk/* printing and padding functions ------------------------------------*/
90153486Sphk
91153486Sphk#define NIOV 8
92153486Sphk
93153486Sphkstruct __printf_io {
94153486Sphk	FILE		*fp;
95153486Sphk	struct __suio	uio;
96153486Sphk	struct __siov	iov[NIOV];
97153486Sphk	struct __siov	*iovp;
98153486Sphk};
99153486Sphk
100153486Sphkstatic void
101153486Sphk__printf_init(struct __printf_io *io)
102153486Sphk{
103153486Sphk
104153486Sphk	io->uio.uio_iov = io->iovp = &io->iov[0];
105153486Sphk	io->uio.uio_resid = 0;
106153486Sphk	io->uio.uio_iovcnt = 0;
107153486Sphk}
108153486Sphk
109153486Sphkvoid
110153486Sphk__printf_flush(struct __printf_io *io)
111153486Sphk{
112153486Sphk
113153486Sphk	__sfvwrite(io->fp, &io->uio);
114153486Sphk	__printf_init(io);
115153486Sphk}
116153486Sphk
117153486Sphkint
118153486Sphk__printf_puts(struct __printf_io *io, const void *ptr, int len)
119153486Sphk{
120153486Sphk
121153486Sphk
122153486Sphk	if (io->fp->_flags & __SERR)
123153486Sphk		return (0);
124153486Sphk	if (len == 0)
125153486Sphk		return (0);
126153486Sphk	io->iovp->iov_base = __DECONST(void *, ptr);
127153486Sphk	io->iovp->iov_len = len;
128153486Sphk	io->uio.uio_resid += len;
129153486Sphk	io->iovp++;
130153486Sphk	io->uio.uio_iovcnt++;
131153486Sphk	if (io->uio.uio_iovcnt >= NIOV)
132153486Sphk		__printf_flush(io);
133153486Sphk	return (len);
134153486Sphk}
135153486Sphk
136153486Sphkint
137153486Sphk__printf_pad(struct __printf_io *io, int howmany, int zero)
138153486Sphk{
139153486Sphk	int n;
140153486Sphk	const char *with;
141153486Sphk	int ret = 0;
142153486Sphk
143153486Sphk	if (zero)
144153486Sphk		with = zeroes;
145153486Sphk	else
146153486Sphk		with = blanks;
147153486Sphk
148153486Sphk	if ((n = (howmany)) > 0) {
149153486Sphk		while (n > PADSIZE) {
150153486Sphk			ret += __printf_puts(io, with, PADSIZE);
151153486Sphk			n -= PADSIZE;
152153486Sphk		}
153153486Sphk		ret += __printf_puts(io, with, n);
154153486Sphk	}
155153486Sphk	return (ret);
156153486Sphk}
157153486Sphk
158153486Sphkint
159153486Sphk__printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len)
160153486Sphk{
161153486Sphk	int ret = 0;
162153486Sphk
163153486Sphk	if ((!pi->left) && pi->width > len)
164153486Sphk		ret += __printf_pad(io, pi->width - len, pi->pad == '0');
165153486Sphk	ret += __printf_puts(io, ptr, len);
166153486Sphk	if (pi->left && pi->width > len)
167153486Sphk		ret += __printf_pad(io, pi->width - len, pi->pad == '0');
168153486Sphk	return (ret);
169153486Sphk}
170153486Sphk
171153486Sphk
172153486Sphk/* percent handling  -------------------------------------------------*/
173153486Sphk
174153486Sphkstatic int
175153486Sphk__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused)
176153486Sphk{
177153486Sphk
178153486Sphk	return (0);
179153486Sphk}
180153486Sphk
181153486Sphkstatic int
182153486Sphk__printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused)
183153486Sphk{
184153486Sphk
185153486Sphk	return (__printf_puts(io, "%", 1));
186153486Sphk}
187153486Sphk
188153486Sphk/* 'n' ---------------------------------------------------------------*/
189153486Sphk
190153486Sphkstatic int
191153486Sphk__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt)
192153486Sphk{
193153486Sphk
194153486Sphk	assert(n >= 1);
195153486Sphk	argt[0] = PA_POINTER;
196153486Sphk	return (1);
197153486Sphk}
198153486Sphk
199153486Sphk/*
200153486Sphk * This is a printf_render so that all output has been flushed before it
201153486Sphk * gets called.
202153486Sphk */
203153486Sphk
204153486Sphkstatic int
205153486Sphk__printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg)
206153486Sphk{
207153486Sphk
208153486Sphk	if (pi->is_char)
209153486Sphk		**((signed char **)arg[0]) = (signed char)pi->sofar;
210153486Sphk	else if (pi->is_short)
211153486Sphk		**((short **)arg[0]) = (short)pi->sofar;
212153486Sphk	else if (pi->is_long)
213153486Sphk		**((long **)arg[0]) = pi->sofar;
214153486Sphk	else if (pi->is_long_double)
215153486Sphk		**((long long **)arg[0]) = pi->sofar;
216153486Sphk	else if (pi->is_intmax)
217153486Sphk		**((intmax_t **)arg[0]) = pi->sofar;
218153486Sphk	else if (pi->is_ptrdiff)
219153486Sphk		**((ptrdiff_t **)arg[0]) = pi->sofar;
220153486Sphk	else if (pi->is_quad)
221153486Sphk		**((quad_t **)arg[0]) = pi->sofar;
222153486Sphk	else if (pi->is_size)
223153486Sphk		**((size_t **)arg[0]) = pi->sofar;
224153486Sphk	else
225153486Sphk		**((int **)arg[0]) = pi->sofar;
226153486Sphk
227153486Sphk	return (0);
228153486Sphk}
229153486Sphk
230153486Sphk/* table -------------------------------------------------------------*/
231153486Sphk
232153486Sphk/*lint -esym(785, printf_tbl) */
233153486Sphkstatic struct {
234153486Sphk	printf_arginfo_function	*arginfo;
235153486Sphk	printf_function		*gnurender;
236153486Sphk	printf_render		*render;
237153486Sphk} printf_tbl[256] = {
238153486Sphk	['%'] = { __printf_arginfo_pct,		NULL,	__printf_render_pct },
239153486Sphk	['A'] = { __printf_arginfo_float,	NULL,	__printf_render_float },
240153486Sphk	['C'] = { __printf_arginfo_chr,		NULL,	__printf_render_chr },
241153486Sphk	['E'] = { __printf_arginfo_float,	NULL,	__printf_render_float },
242153486Sphk	['F'] = { __printf_arginfo_float,	NULL,	__printf_render_float },
243153486Sphk	['G'] = { __printf_arginfo_float,	NULL,	__printf_render_float },
244153486Sphk	['S'] = { __printf_arginfo_str,		NULL,	__printf_render_str },
245153486Sphk	['X'] = { __printf_arginfo_int,		NULL,	__printf_render_int },
246153486Sphk	['a'] = { __printf_arginfo_float,	NULL,	__printf_render_float },
247153486Sphk	['c'] = { __printf_arginfo_chr,		NULL,	__printf_render_chr },
248153486Sphk	['d'] = { __printf_arginfo_int,		NULL,	__printf_render_int },
249153486Sphk	['e'] = { __printf_arginfo_float,	NULL,	__printf_render_float },
250153486Sphk	['f'] = { __printf_arginfo_float,	NULL,	__printf_render_float },
251153486Sphk	['g'] = { __printf_arginfo_float,	NULL,	__printf_render_float },
252153486Sphk	['i'] = { __printf_arginfo_int,		NULL,	__printf_render_int },
253153486Sphk	['n'] = { __printf_arginfo_n,		__printf_render_n, NULL },
254153486Sphk	['o'] = { __printf_arginfo_int,		NULL,	__printf_render_int },
255153486Sphk	['p'] = { __printf_arginfo_ptr,		NULL,	__printf_render_ptr },
256153486Sphk	['q'] = { __printf_arginfo_int,		NULL,	__printf_render_int },
257153486Sphk	['s'] = { __printf_arginfo_str,		NULL,	__printf_render_str },
258153486Sphk	['u'] = { __printf_arginfo_int,		NULL,	__printf_render_int },
259153486Sphk	['x'] = { __printf_arginfo_int,		NULL,	__printf_render_int },
260153486Sphk};
261153486Sphk
262153486Sphk
263153486Sphkstatic int
264163624Skib__v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap)
265153486Sphk{
266153486Sphk	struct printf_info	*pi, *pil;
267153486Sphk	const char		*fmt;
268153486Sphk	int			ch;
269153486Sphk	struct printf_info	pia[pct + 10];
270153486Sphk	int			argt[pct + 10];
271153486Sphk	union arg		args[pct + 10];
272153486Sphk	int			nextarg;
273153486Sphk	int			maxarg;
274153486Sphk	int			ret = 0;
275153486Sphk	int			n;
276153486Sphk	struct __printf_io	io;
277153486Sphk
278153486Sphk	__printf_init(&io);
279153486Sphk	io.fp = fp;
280153486Sphk
281153486Sphk	fmt = fmt0;
282153486Sphk	maxarg = 0;
283153486Sphk	nextarg = 1;
284153486Sphk	memset(argt, 0, sizeof argt);
285153486Sphk	for (pi = pia; ; pi++) {
286153486Sphk		memset(pi, 0, sizeof *pi);
287153486Sphk		pil = pi;
288153486Sphk		if (*fmt == '\0')
289153486Sphk			break;
290153486Sphk		pil = pi + 1;
291153486Sphk		pi->prec = -1;
292153486Sphk		pi->pad = ' ';
293153486Sphk		pi->begin = pi->end = fmt;
294153486Sphk		while (*fmt != '\0' && *fmt != '%')
295153486Sphk			pi->end = ++fmt;
296153486Sphk		if (*fmt == '\0')
297153486Sphk			break;
298153486Sphk		fmt++;
299153486Sphk		for (;;) {
300153486Sphk			pi->spec = *fmt;
301153486Sphk			switch (pi->spec) {
302153486Sphk			case ' ':
303153486Sphk				/*-
304153486Sphk				 * ``If the space and + flags both appear, the space
305153486Sphk				 * flag will be ignored.''
306153486Sphk				 *      -- ANSI X3J11
307153486Sphk				 */
308153486Sphk				if (pi->showsign == 0)
309153486Sphk					pi->showsign = ' ';
310153486Sphk				fmt++;
311153486Sphk				continue;
312153486Sphk			case '#':
313153486Sphk				pi->alt = 1;
314153486Sphk				fmt++;
315153486Sphk				continue;
316153486Sphk			case '.':
317153486Sphk				pi->prec = 0;
318153486Sphk				fmt++;
319153486Sphk				if (*fmt == '*') {
320153486Sphk					fmt++;
321153486Sphk					pi->get_prec = nextarg;
322153486Sphk					argt[nextarg++] = PA_INT;
323153486Sphk					continue;
324153486Sphk				}
325153486Sphk				while (*fmt != '\0' && is_digit(*fmt)) {
326153486Sphk					pi->prec *= 10;
327153486Sphk					pi->prec += to_digit(*fmt);
328153486Sphk					fmt++;
329153486Sphk				}
330153486Sphk				continue;
331153486Sphk			case '-':
332153486Sphk				pi->left = 1;
333153486Sphk				fmt++;
334153486Sphk				continue;
335153486Sphk			case '+':
336153486Sphk				pi->showsign = '+';
337153486Sphk				fmt++;
338153486Sphk				continue;
339153486Sphk			case '*':
340153486Sphk				fmt++;
341153486Sphk				pi->get_width = nextarg;
342153486Sphk				argt[nextarg++] = PA_INT;
343153486Sphk				continue;
344153486Sphk			case '%':
345153486Sphk				fmt++;
346153486Sphk				break;
347153486Sphk			case '\'':
348153486Sphk				pi->group = 1;
349153486Sphk				fmt++;
350153486Sphk				continue;
351153486Sphk			case '0':
352153486Sphk				/*-
353153486Sphk				 * ``Note that 0 is taken as a flag, not as the
354153486Sphk				 * beginning of a field width.''
355153486Sphk				 *      -- ANSI X3J11
356153486Sphk				 */
357153486Sphk				pi->pad = '0';
358153486Sphk				fmt++;
359153486Sphk				continue;
360153486Sphk			case '1': case '2': case '3':
361153486Sphk			case '4': case '5': case '6':
362153486Sphk			case '7': case '8': case '9':
363153486Sphk				n = 0;
364153486Sphk				while (*fmt != '\0' && is_digit(*fmt)) {
365153486Sphk					n *= 10;
366153486Sphk					n += to_digit(*fmt);
367153486Sphk					fmt++;
368153486Sphk				}
369153486Sphk				if (*fmt == '$') {
370153486Sphk					if (nextarg > maxarg)
371153486Sphk						maxarg = nextarg;
372153486Sphk					nextarg = n;
373153486Sphk					fmt++;
374153486Sphk				} else
375153486Sphk					pi->width = n;
376153486Sphk				continue;
377153486Sphk			case 'D':
378153486Sphk			case 'O':
379153486Sphk			case 'U':
380153486Sphk				pi->spec += ('a' - 'A');
381153486Sphk				pi->is_intmax = 0;
382153486Sphk				if (pi->is_long_double || pi->is_quad) {
383153486Sphk					pi->is_long = 0;
384153486Sphk					pi->is_long_double = 1;
385153486Sphk				} else {
386153486Sphk					pi->is_long = 1;
387153486Sphk					pi->is_long_double = 0;
388153486Sphk				}
389153486Sphk				fmt++;
390153486Sphk				break;
391153486Sphk			case 'j':
392153486Sphk				pi->is_intmax = 1;
393153486Sphk				fmt++;
394153486Sphk				continue;
395153486Sphk			case 'q':
396153486Sphk				pi->is_long = 0;
397153486Sphk				pi->is_quad = 1;
398153486Sphk				fmt++;
399153486Sphk				continue;
400153486Sphk			case 'L':
401153486Sphk				pi->is_long_double = 1;
402153486Sphk				fmt++;
403153486Sphk				continue;
404153486Sphk			case 'h':
405153486Sphk				fmt++;
406153486Sphk				if (*fmt == 'h') {
407153486Sphk					fmt++;
408153486Sphk					pi->is_char = 1;
409153486Sphk				} else {
410153486Sphk					pi->is_short = 1;
411153486Sphk				}
412153486Sphk				continue;
413153486Sphk			case 'l':
414153486Sphk				fmt++;
415153486Sphk				if (*fmt == 'l') {
416153486Sphk					fmt++;
417153486Sphk					pi->is_long_double = 1;
418153486Sphk					pi->is_quad = 0;
419153486Sphk				} else {
420153486Sphk					pi->is_quad = 0;
421153486Sphk					pi->is_long = 1;
422153486Sphk				}
423153486Sphk				continue;
424153486Sphk			case 't':
425153486Sphk				pi->is_ptrdiff = 1;
426153486Sphk				fmt++;
427153486Sphk				continue;
428153486Sphk			case 'z':
429153486Sphk				pi->is_size = 1;
430153486Sphk				fmt++;
431153486Sphk				continue;
432153486Sphk			default:
433153486Sphk				fmt++;
434153486Sphk				break;
435153486Sphk			}
436153486Sphk			if (printf_tbl[pi->spec].arginfo == NULL)
437153486Sphk				errx(1, "arginfo[%c] = NULL", pi->spec);
438153486Sphk			ch = printf_tbl[pi->spec].arginfo(
439153486Sphk			    pi, __PRINTFMAXARG, &argt[nextarg]);
440153486Sphk			if (ch > 0)
441153486Sphk				pi->arg[0] = &args[nextarg];
442153486Sphk			if (ch > 1)
443153486Sphk				pi->arg[1] = &args[nextarg + 1];
444153486Sphk			nextarg += ch;
445153486Sphk			break;
446153486Sphk		}
447153486Sphk	}
448153486Sphk	if (nextarg > maxarg)
449153486Sphk		maxarg = nextarg;
450153486Sphk#if 0
451153486Sphk	fprintf(stderr, "fmt0 <%s>\n", fmt0);
452153486Sphk	fprintf(stderr, "pil %p\n", pil);
453153486Sphk#endif
454153486Sphk	for (ch = 1; ch < maxarg; ch++) {
455153486Sphk#if 0
456153486Sphk		fprintf(stderr, "arg %d %x\n", ch, argt[ch]);
457153486Sphk#endif
458153486Sphk		switch(argt[ch]) {
459153486Sphk		case PA_CHAR:
460153486Sphk			args[ch].intarg = (char)va_arg (ap, int);
461153486Sphk			break;
462153486Sphk		case PA_INT:
463153486Sphk			args[ch].intarg = va_arg (ap, int);
464153486Sphk			break;
465153486Sphk		case PA_INT | PA_FLAG_SHORT:
466153486Sphk			args[ch].intarg = (short)va_arg (ap, int);
467153486Sphk			break;
468153486Sphk		case PA_INT | PA_FLAG_LONG:
469153486Sphk			args[ch].longarg = va_arg (ap, long);
470153486Sphk			break;
471153486Sphk		case PA_INT | PA_FLAG_INTMAX:
472153486Sphk			args[ch].intmaxarg = va_arg (ap, intmax_t);
473153486Sphk			break;
474153486Sphk		case PA_INT | PA_FLAG_QUAD:
475153486Sphk			args[ch].intmaxarg = va_arg (ap, quad_t);
476153486Sphk			break;
477153486Sphk		case PA_INT | PA_FLAG_LONG_LONG:
478153486Sphk			args[ch].intmaxarg = va_arg (ap, long long);
479153486Sphk			break;
480153486Sphk		case PA_INT | PA_FLAG_SIZE:
481153486Sphk			args[ch].intmaxarg = va_arg (ap, size_t);
482153486Sphk			break;
483153486Sphk		case PA_INT | PA_FLAG_PTRDIFF:
484153486Sphk			args[ch].intmaxarg = va_arg (ap, ptrdiff_t);
485153486Sphk			break;
486153486Sphk		case PA_WCHAR:
487153486Sphk			args[ch].wintarg = va_arg (ap, wint_t);
488153486Sphk			break;
489153486Sphk		case PA_POINTER:
490153486Sphk			args[ch].pvoidarg = va_arg (ap, void *);
491153486Sphk			break;
492153486Sphk		case PA_STRING:
493153486Sphk			args[ch].pchararg = va_arg (ap, char *);
494153486Sphk			break;
495153486Sphk		case PA_WSTRING:
496153486Sphk			args[ch].pwchararg = va_arg (ap, wchar_t *);
497153486Sphk			break;
498153486Sphk		case PA_DOUBLE:
499157381Sphk#ifndef NO_FLOATING_POINT
500153486Sphk			args[ch].doublearg = va_arg (ap, double);
501157381Sphk#endif
502153486Sphk			break;
503153486Sphk		case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
504157381Sphk#ifndef NO_FLOATING_POINT
505153486Sphk			args[ch].longdoublearg = va_arg (ap, long double);
506157381Sphk#endif
507153486Sphk			break;
508153486Sphk		default:
509153486Sphk			errx(1, "argtype = %x (fmt = \"%s\")\n",
510153486Sphk			    argt[ch], fmt0);
511153486Sphk		}
512153486Sphk	}
513153486Sphk	for (pi = pia; pi < pil; pi++) {
514153486Sphk#if 0
515153486Sphk		fprintf(stderr, "pi %p", pi);
516153486Sphk		fprintf(stderr, " spec '%c'", pi->spec);
517153486Sphk		fprintf(stderr, " args %d",
518153486Sphk		    ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]);
519153486Sphk		if (pi->width) fprintf(stderr, " width %d", pi->width);
520153486Sphk		if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
521153486Sphk		if (pi->left) fprintf(stderr, " left");
522153486Sphk		if (pi->showsign) fprintf(stderr, " showsign");
523153486Sphk		if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
524153486Sphk		if (pi->is_char) fprintf(stderr, " char");
525153486Sphk		if (pi->is_short) fprintf(stderr, " short");
526153486Sphk		if (pi->is_long) fprintf(stderr, " long");
527153486Sphk		if (pi->is_long_double) fprintf(stderr, " long_double");
528153486Sphk		fprintf(stderr, "\n");
529153486Sphk		fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
530153486Sphk#endif
531153486Sphk		if (pi->get_width) {
532153486Sphk			pi->width = args[pi->get_width].intarg;
533153486Sphk			/*-
534153486Sphk			 * ``A negative field width argument is taken as a
535153486Sphk			 * - flag followed by a positive field width.''
536153486Sphk			 *      -- ANSI X3J11
537153486Sphk			 * They don't exclude field widths read from args.
538153486Sphk			 */
539153486Sphk			if (pi->width < 0) {
540153486Sphk				pi->left = 1;
541153486Sphk				pi->width = -pi->width;
542153486Sphk			}
543153486Sphk		}
544153486Sphk		if (pi->get_prec)
545153486Sphk			pi->prec = args[pi->get_prec].intarg;
546153486Sphk		ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
547153486Sphk		if (printf_tbl[pi->spec].gnurender != NULL) {
548153486Sphk			__printf_flush(&io);
549153486Sphk			pi->sofar = ret;
550153486Sphk			ret += printf_tbl[pi->spec].gnurender(
551153486Sphk			    fp, pi, (const void *)pi->arg);
552153486Sphk		} else if (printf_tbl[pi->spec].render != NULL) {
553153486Sphk			pi->sofar = ret;
554153486Sphk			n = printf_tbl[pi->spec].render(
555153486Sphk			    &io, pi, (const void *)pi->arg);
556153486Sphk			if (n < 0)
557153486Sphk				io.fp->_flags |= __SERR;
558153486Sphk			else
559153486Sphk				ret += n;
560153486Sphk		} else if (pi->begin == pi->end)
561153486Sphk			errx(1, "render[%c] = NULL", *fmt);
562153486Sphk	}
563153486Sphk	__printf_flush(&io);
564153486Sphk	return (ret);
565153486Sphk}
566153486Sphk
567153486Sphkextern int      __fflush(FILE *fp);
568153486Sphk
569153486Sphk/*
570153486Sphk * Helper function for `fprintf to unbuffered unix file': creates a
571153486Sphk * temporary buffer.  We only work on write-only files; this avoids
572153486Sphk * worries about ungetc buffers and so forth.
573153486Sphk */
574153486Sphkstatic int
575153486Sphk__v3printf(FILE *fp, const char *fmt, int pct, va_list ap)
576153486Sphk{
577153486Sphk	int ret;
578153486Sphk	FILE fake;
579153486Sphk	unsigned char buf[BUFSIZ];
580153486Sphk
581153486Sphk	/* copy the important variables */
582153486Sphk	fake._flags = fp->_flags & ~__SNBF;
583153486Sphk	fake._file = fp->_file;
584153486Sphk	fake._cookie = fp->_cookie;
585153486Sphk	fake._write = fp->_write;
586178287Sjhb	fake._orientation = fp->_orientation;
587178287Sjhb	fake._mbstate = fp->_mbstate;
588153486Sphk
589153486Sphk	/* set up the buffer */
590153486Sphk	fake._bf._base = fake._p = buf;
591153486Sphk	fake._bf._size = fake._w = sizeof(buf);
592153486Sphk	fake._lbfsize = 0;	/* not actually used, but Just In Case */
593153486Sphk
594153486Sphk	/* do the work, then copy any error status */
595153486Sphk	ret = __v2printf(&fake, fmt, pct, ap);
596153486Sphk	if (ret >= 0 && __fflush(&fake))
597153486Sphk		ret = EOF;
598153486Sphk	if (fake._flags & __SERR)
599153486Sphk		fp->_flags |= __SERR;
600153486Sphk	return (ret);
601153486Sphk}
602153486Sphk
603153486Sphkint
604153486Sphk__xvprintf(FILE *fp, const char *fmt0, va_list ap)
605153486Sphk{
606153486Sphk	unsigned u;
607153486Sphk	const char *p;
608153486Sphk
609153486Sphk	/* Count number of '%' signs handling double '%' signs */
610153486Sphk	for (p = fmt0, u = 0; *p; p++) {
611153486Sphk		if (*p != '%')
612153486Sphk			continue;
613153486Sphk		u++;
614153486Sphk		if (p[1] == '%')
615153486Sphk			p++;
616153486Sphk	}
617153486Sphk
618153486Sphk	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
619153486Sphk	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
620153486Sphk	    fp->_file >= 0)
621153486Sphk		return (__v3printf(fp, fmt0, u, ap));
622153486Sphk	else
623153486Sphk		return (__v2printf(fp, fmt0, u, ap));
624153486Sphk}
625153486Sphk
626153486Sphk/* extending ---------------------------------------------------------*/
627153486Sphk
628153486Sphkint
629153486Sphkregister_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo)
630153486Sphk{
631153486Sphk
632153486Sphk	if (spec > 255 || spec < 0)
633153486Sphk		return (-1);
634153486Sphk	printf_tbl[spec].gnurender = render;
635153486Sphk	printf_tbl[spec].arginfo = arginfo;
636153486Sphk	__use_xprintf = 1;
637153486Sphk	return (0);
638153486Sphk}
639153486Sphk
640153486Sphkint
641153486Sphkregister_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo)
642153486Sphk{
643153486Sphk
644153486Sphk	if (spec > 255 || spec < 0)
645153486Sphk		return (-1);
646153486Sphk	printf_tbl[spec].render = render;
647153486Sphk	printf_tbl[spec].arginfo = arginfo;
648153486Sphk	__use_xprintf = 1;
649153486Sphk	return (0);
650153486Sphk}
651153486Sphk
652153486Sphkint
653153486Sphkregister_printf_render_std(const unsigned char *specs)
654153486Sphk{
655153486Sphk
656153486Sphk	for (; *specs != '\0'; specs++) {
657153486Sphk		switch (*specs) {
658153486Sphk		case 'H':
659153486Sphk			register_printf_render(*specs,
660153486Sphk			    __printf_render_hexdump,
661153486Sphk			    __printf_arginfo_hexdump);
662153486Sphk			break;
663154815Sphk		case 'M':
664154815Sphk			register_printf_render(*specs,
665154815Sphk			    __printf_render_errno,
666154815Sphk			    __printf_arginfo_errno);
667154815Sphk			break;
668154815Sphk		case 'Q':
669154815Sphk			register_printf_render(*specs,
670154815Sphk			    __printf_render_quote,
671154815Sphk			    __printf_arginfo_quote);
672154815Sphk			break;
673153486Sphk		case 'T':
674153486Sphk			register_printf_render(*specs,
675153486Sphk			    __printf_render_time,
676153486Sphk			    __printf_arginfo_time);
677153486Sphk			break;
678153486Sphk		case 'V':
679153486Sphk			register_printf_render(*specs,
680153486Sphk			    __printf_render_vis,
681153486Sphk			    __printf_arginfo_vis);
682153486Sphk			break;
683153486Sphk		default:
684153486Sphk			return (-1);
685153486Sphk		}
686153486Sphk	}
687153486Sphk	return (0);
688153486Sphk}
689153486Sphk
690