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