1*c2c66affSColin Finck /* @(#)format.c	1.62 17/08/03 Copyright 1985-2017 J. Schilling */
2*c2c66affSColin Finck /*
3*c2c66affSColin Finck  *	format
4*c2c66affSColin Finck  *	common code for printf fprintf & sprintf
5*c2c66affSColin Finck  *
6*c2c66affSColin Finck  *	allows recursive printf with "%r", used in:
7*c2c66affSColin Finck  *	error, comerr, comerrno, errmsg, errmsgno and the like
8*c2c66affSColin Finck  *
9*c2c66affSColin Finck  *	Copyright (c) 1985-2017 J. Schilling
10*c2c66affSColin Finck  */
11*c2c66affSColin Finck /*
12*c2c66affSColin Finck  * The contents of this file are subject to the terms of the
13*c2c66affSColin Finck  * Common Development and Distribution License, Version 1.0 only
14*c2c66affSColin Finck  * (the "License").  You may not use this file except in compliance
15*c2c66affSColin Finck  * with the License.
16*c2c66affSColin Finck  *
17*c2c66affSColin Finck  * See the file CDDL.Schily.txt in this distribution for details.
18*c2c66affSColin Finck  * A copy of the CDDL is also available via the Internet at
19*c2c66affSColin Finck  * http://www.opensource.org/licenses/cddl1.txt
20*c2c66affSColin Finck  *
21*c2c66affSColin Finck  * When distributing Covered Code, include this CDDL HEADER in each
22*c2c66affSColin Finck  * file and include the License file CDDL.Schily.txt from this distribution.
23*c2c66affSColin Finck  */
24*c2c66affSColin Finck 
25*c2c66affSColin Finck #include <schily/mconfig.h>
26*c2c66affSColin Finck #include <schily/varargs.h>
27*c2c66affSColin Finck #include <schily/string.h>
28*c2c66affSColin Finck #include <schily/stdlib.h>
29*c2c66affSColin Finck #ifdef	DEBUG
30*c2c66affSColin Finck #include <schily/unistd.h>
31*c2c66affSColin Finck #endif
32*c2c66affSColin Finck #if	!defined(HAVE_STDLIB_H) || !defined(HAVE_GCVT)
33*c2c66affSColin Finck extern	char	*gcvt __PR((double, int, char *));
34*c2c66affSColin Finck #endif
35*c2c66affSColin Finck #include <schily/standard.h>
36*c2c66affSColin Finck #include <schily/utypes.h>
37*c2c66affSColin Finck #include <schily/schily.h>
38*c2c66affSColin Finck 
39*c2c66affSColin Finck /*
40*c2c66affSColin Finck  * As Llong is currently a 'best effort' long long, we usually need to
41*c2c66affSColin Finck  * include long long print formats.
42*c2c66affSColin Finck  * This may go away, if we implement maxint_t formats.
43*c2c66affSColin Finck  */
44*c2c66affSColin Finck #ifndef	USE_LONGLONG
45*c2c66affSColin Finck #define	USE_LONGLONG
46*c2c66affSColin Finck #endif
47*c2c66affSColin Finck 
48*c2c66affSColin Finck #ifdef	NO_LONGLONG
49*c2c66affSColin Finck #undef	USE_LONGLONG
50*c2c66affSColin Finck #endif
51*c2c66affSColin Finck 
52*c2c66affSColin Finck #ifndef	USE_NL_ARGS
53*c2c66affSColin Finck #define	USE_NL_ARGS
54*c2c66affSColin Finck #endif
55*c2c66affSColin Finck 
56*c2c66affSColin Finck #ifdef	NO_NL_ARGS
57*c2c66affSColin Finck #undef	USE_NL_ARGS
58*c2c66affSColin Finck #endif
59*c2c66affSColin Finck 
60*c2c66affSColin Finck /*
61*c2c66affSColin Finck  * Avoid to keep copies of the variable arg list in case that
62*c2c66affSColin Finck  * format() was compiled without including NL support for
63*c2c66affSColin Finck  * argument reordering.
64*c2c66affSColin Finck  */
65*c2c66affSColin Finck #ifdef	USE_NL_ARGS
66*c2c66affSColin Finck #define	args		fargs.ap	/* Use working copy */
67*c2c66affSColin Finck #else
68*c2c66affSColin Finck #define	args		oargs		/* Directly use format() arg */
69*c2c66affSColin Finck #endif
70*c2c66affSColin Finck 
71*c2c66affSColin Finck /*
72*c2c66affSColin Finck  * We may need to decide whether we should check whether all
73*c2c66affSColin Finck  * flags occur according to the standard which is either directly past:
74*c2c66affSColin Finck  * "%" or directly past "%n$".
75*c2c66affSColin Finck  *
76*c2c66affSColin Finck  * This however may make printf() slower in some cases.
77*c2c66affSColin Finck  */
78*c2c66affSColin Finck #ifdef	USE_CHECKFLAG
79*c2c66affSColin Finck #define	CHECKFLAG()	if (fa.flags & GOTSTAR) goto flagerror
80*c2c66affSColin Finck #else
81*c2c66affSColin Finck #define	CHECKFLAG()
82*c2c66affSColin Finck #endif
83*c2c66affSColin Finck 
84*c2c66affSColin Finck #ifdef	NO_USER_XCVT
85*c2c66affSColin Finck 	/*
86*c2c66affSColin Finck 	 * We cannot define our own gcvt() so we need to use a
87*c2c66affSColin Finck 	 * local name instead.
88*c2c66affSColin Finck 	 */
89*c2c66affSColin Finck #ifndef	HAVE_GCVT
90*c2c66affSColin Finck #	define	gcvt	js_gcvt
91*c2c66affSColin Finck EXPORT	char *gcvt	__PR((double value, int ndigit, char *buf));
92*c2c66affSColin Finck #endif
93*c2c66affSColin Finck #endif
94*c2c66affSColin Finck 
95*c2c66affSColin Finck /*
96*c2c66affSColin Finck  * Some CPU's (e.g. PDP-11) cannot do logical shifts.
97*c2c66affSColin Finck  * They use rotate instead. Masking the low bits before,
98*c2c66affSColin Finck  * makes rotate work too.
99*c2c66affSColin Finck  */
100*c2c66affSColin Finck #define	allmask(t)	((unsigned t)~((unsigned t)0))
101*c2c66affSColin Finck #define	lowmask(t, x)	((unsigned t)~((unsigned t)((1 << (x))-1)))
102*c2c66affSColin Finck #define	rshiftmask(t, s)((allmask(t) & lowmask(t, s)) >> (s))
103*c2c66affSColin Finck 
104*c2c66affSColin Finck #define	CHARMASK	makemask(char)
105*c2c66affSColin Finck #define	SHORTMASK	makemask(short)
106*c2c66affSColin Finck #define	INTMASK		makemask(int)
107*c2c66affSColin Finck #define	LONGMASK	makemask(long)
108*c2c66affSColin Finck 
109*c2c66affSColin Finck #ifdef	DIVLBYS
110*c2c66affSColin Finck extern	long	divlbys();
111*c2c66affSColin Finck extern	long	modlbys();
112*c2c66affSColin Finck #else
113*c2c66affSColin Finck #define	divlbys(val, base)	((val)/(base))
114*c2c66affSColin Finck #define	modlbys(val, base)	((val)%(base))
115*c2c66affSColin Finck #endif
116*c2c66affSColin Finck 
117*c2c66affSColin Finck /*
118*c2c66affSColin Finck  *	We use macros here to avoid the need to link to the international
119*c2c66affSColin Finck  *	character routines.
120*c2c66affSColin Finck  *	We don't need internationalization for our purpose.
121*c2c66affSColin Finck  */
122*c2c66affSColin Finck #define	is_dig(c)	(((c) >= '0') && ((c) <= '9'))
123*c2c66affSColin Finck #define	is_cap(c)	((c) >= 'A' && (c) <= 'Z')
124*c2c66affSColin Finck #define	to_cap(c)	(is_cap(c) ? c : c - 'a' + 'A')
125*c2c66affSColin Finck #define	cap_ty(c)	(is_cap(c) ? 'L' : 'I')
126*c2c66affSColin Finck 
127*c2c66affSColin Finck #ifdef	HAVE_LONGLONG
128*c2c66affSColin Finck typedef union {
129*c2c66affSColin Finck 	Ullong	ll;
130*c2c66affSColin Finck 	Ulong	l[2];
131*c2c66affSColin Finck 	char	c[8];
132*c2c66affSColin Finck } quad_u;
133*c2c66affSColin Finck #endif
134*c2c66affSColin Finck 
135*c2c66affSColin Finck typedef struct f_args {
136*c2c66affSColin Finck #ifdef	FORMAT_BUFFER
137*c2c66affSColin Finck #define	BFSIZ	256
138*c2c66affSColin Finck 	char	*ptr;			/* Current ptr in buf		*/
139*c2c66affSColin Finck 	int	cnt;			/* Free char count in buf	*/
140*c2c66affSColin Finck #else
141*c2c66affSColin Finck 	void  (*outf)__PR((char, void *)); /* Func from format(fun, arg)	*/
142*c2c66affSColin Finck #endif
143*c2c66affSColin Finck 	void	*farg;			/* Arg from format (fun, arg)	*/
144*c2c66affSColin Finck 	int	minusflag;		/* Fieldwidth is negative	*/
145*c2c66affSColin Finck 	int	flags;			/* General flags (+-#)		*/
146*c2c66affSColin Finck 	int	fldwidth;		/* Field width as in %3d	*/
147*c2c66affSColin Finck 	int	signific;		/* Significant chars as in %.4d	*/
148*c2c66affSColin Finck 	int	lzero;			/* Left '0' pad flag		*/
149*c2c66affSColin Finck 	char	*buf;			/* Out print buffer		*/
150*c2c66affSColin Finck 	char	*bufp;			/* Write ptr into buffer	*/
151*c2c66affSColin Finck 	char	fillc;			/* Left fill char (' ' or '0')	*/
152*c2c66affSColin Finck 	char	*prefix;		/* Prefix to print before buf	*/
153*c2c66affSColin Finck 	int	prefixlen;		/* Len of prefix ('+','-','0x')	*/
154*c2c66affSColin Finck #ifdef	FORMAT_BUFFER
155*c2c66affSColin Finck 					/* rarely used members last:	*/
156*c2c66affSColin Finck 	char	iobuf[BFSIZ];		/* buffer for stdio		*/
157*c2c66affSColin Finck 	FILE	*fp;			/* FILE * for fprformat()	*/
158*c2c66affSColin Finck 	int	err;			/* FILE * I/O error		*/
159*c2c66affSColin Finck #endif
160*c2c66affSColin Finck } f_args;
161*c2c66affSColin Finck 
162*c2c66affSColin Finck #define	MINUSFLG	1	/* '-' flag */
163*c2c66affSColin Finck #define	PLUSFLG		2	/* '+' flag */
164*c2c66affSColin Finck #define	SPACEFLG	4	/* ' ' flag */
165*c2c66affSColin Finck #define	HASHFLG		8	/* '#' flag */
166*c2c66affSColin Finck #define	APOFLG		16	/* '\'' flag */
167*c2c66affSColin Finck #define	GOTDOT		32	/* '.' found */
168*c2c66affSColin Finck #define	GOTSTAR		64	/* '*' found */
169*c2c66affSColin Finck 
170*c2c66affSColin Finck #define	FMT_ARGMAX	30	/* Number of fast args */
171*c2c66affSColin Finck 
172*c2c66affSColin Finck LOCAL	void	prnum  __PR((Ulong, unsigned, f_args *));
173*c2c66affSColin Finck LOCAL	void	prdnum __PR((Ulong, f_args *));
174*c2c66affSColin Finck LOCAL	void	pronum __PR((Ulong, f_args *));
175*c2c66affSColin Finck LOCAL	void	prxnum __PR((Ulong, f_args *));
176*c2c66affSColin Finck LOCAL	void	prXnum __PR((Ulong, f_args *));
177*c2c66affSColin Finck #ifdef	USE_LONGLONG
178*c2c66affSColin Finck LOCAL	void	prlnum  __PR((Ullong, unsigned, f_args *));
179*c2c66affSColin Finck LOCAL	void	prldnum __PR((Ullong, f_args *));
180*c2c66affSColin Finck LOCAL	void	prlonum __PR((Ullong, f_args *));
181*c2c66affSColin Finck LOCAL	void	prlxnum __PR((Ullong, f_args *));
182*c2c66affSColin Finck LOCAL	void	prlXnum __PR((Ullong, f_args *));
183*c2c66affSColin Finck #endif
184*c2c66affSColin Finck LOCAL	int	prbuf  __PR((const char *, f_args *));
185*c2c66affSColin Finck LOCAL	int	prc    __PR((char, f_args *));
186*c2c66affSColin Finck LOCAL	int	prstring __PR((const char *, f_args *));
187*c2c66affSColin Finck #ifdef	DEBUG
188*c2c66affSColin Finck LOCAL	void	dbg_print __PR((char *fmt, int a, int b, int c, int d, int e, int f, int g, int h, int i));
189*c2c66affSColin Finck #endif
190*c2c66affSColin Finck 
191*c2c66affSColin Finck #ifdef	USE_NL_ARGS
192*c2c66affSColin Finck #ifndef	FORMAT_FUNC_NAME
193*c2c66affSColin Finck #define	FORMAT_IMPL
194*c2c66affSColin Finck EXPORT	void	_fmtarglist __PR((const char *fmt, va_lists_t, va_lists_t arglist[]));
195*c2c66affSColin Finck EXPORT	void	_fmtgetarg  __PR((const char *fmt, int num, va_lists_t *));
196*c2c66affSColin Finck #else
197*c2c66affSColin Finck extern	void	_fmtarglist __PR((const char *fmt, va_lists_t, va_lists_t arglist[]));
198*c2c66affSColin Finck extern	void	_fmtgetarg  __PR((const char *fmt, int num, va_lists_t *));
199*c2c66affSColin Finck #endif
200*c2c66affSColin Finck #endif
201*c2c66affSColin Finck 
202*c2c66affSColin Finck #ifdef	FORMAT_BUFFER
203*c2c66affSColin Finck LOCAL char	xflsbuf	__PR((int c, f_args *ap));
204*c2c66affSColin Finck 
205*c2c66affSColin Finck LOCAL char
xflsbuf(c,ap)206*c2c66affSColin Finck xflsbuf(c, ap)
207*c2c66affSColin Finck 	int	c;
208*c2c66affSColin Finck 	f_args	*ap;
209*c2c66affSColin Finck {
210*c2c66affSColin Finck 	*ap->ptr++ = c;
211*c2c66affSColin Finck 	if (filewrite((FILE *)ap->fp, ap->iobuf, ap->ptr - ap->iobuf) < 0)
212*c2c66affSColin Finck 		ap->err = 1;
213*c2c66affSColin Finck 
214*c2c66affSColin Finck 	ap->cnt = BFSIZ;
215*c2c66affSColin Finck 	ap->ptr = ap->iobuf;
216*c2c66affSColin Finck 	return (c);
217*c2c66affSColin Finck }
218*c2c66affSColin Finck 
219*c2c66affSColin Finck #undef	ofun
220*c2c66affSColin Finck #define	ofun(c, xp)		(--((f_args *)xp)->cnt <= 0 ? \
221*c2c66affSColin Finck 					xflsbuf(c, (f_args *)xp) : \
222*c2c66affSColin Finck 					(*(((f_args *)xp)->ptr)++ = (c)))
223*c2c66affSColin Finck 
224*c2c66affSColin Finck #endif
225*c2c66affSColin Finck 
226*c2c66affSColin Finck #ifndef	FORMAT_FUNC_NAME
227*c2c66affSColin Finck #define	FORMAT_FUNC_NAME	format
228*c2c66affSColin Finck #define	FORMAT_FUNC_PARM
229*c2c66affSColin Finck 
230*c2c66affSColin Finck #define	FORMAT_FUNC_PROTO_DECL	void (*fun)(char, void *),
231*c2c66affSColin Finck #define	FORMAT_FUNC_KR_DECL	register void (*fun)();
232*c2c66affSColin Finck #define	FORMAT_FUNC_KR_ARGS	fun,
233*c2c66affSColin Finck 
234*c2c66affSColin Finck #define	ofun(c, fp)		(*fun)(c, fp)
235*c2c66affSColin Finck #endif
236*c2c66affSColin Finck 
237*c2c66affSColin Finck #ifdef	FORMAT_BUFFER
238*c2c66affSColin Finck #define	FARG		((void *)((UIntptr_t)farg|1))
239*c2c66affSColin Finck #else
240*c2c66affSColin Finck #define	FARG		farg
241*c2c66affSColin Finck #endif
242*c2c66affSColin Finck 
243*c2c66affSColin Finck #ifdef	PROTOTYPES
244*c2c66affSColin Finck EXPORT int
FORMAT_FUNC_NAME(FORMAT_FUNC_PROTO_DECL void * farg,const char * fmt,va_list oargs)245*c2c66affSColin Finck FORMAT_FUNC_NAME(FORMAT_FUNC_PROTO_DECL
246*c2c66affSColin Finck 			void *farg,
247*c2c66affSColin Finck 			const char *fmt,
248*c2c66affSColin Finck 			va_list oargs)
249*c2c66affSColin Finck #else
250*c2c66affSColin Finck EXPORT int
251*c2c66affSColin Finck FORMAT_FUNC_NAME(FORMAT_FUNC_KR_ARGS farg, fmt, oargs)
252*c2c66affSColin Finck 	FORMAT_FUNC_KR_DECL
253*c2c66affSColin Finck 	register void	*farg;
254*c2c66affSColin Finck 	register char	*fmt;
255*c2c66affSColin Finck 	va_list		oargs;
256*c2c66affSColin Finck #endif
257*c2c66affSColin Finck {
258*c2c66affSColin Finck #ifdef	FORMAT_LOW_MEM
259*c2c66affSColin Finck 	char buf[512];
260*c2c66affSColin Finck #else
261*c2c66affSColin Finck 	char buf[8192];
262*c2c66affSColin Finck #endif
263*c2c66affSColin Finck 	const char *sfmt;
264*c2c66affSColin Finck 	register int unsflag;
265*c2c66affSColin Finck 	register long val;
266*c2c66affSColin Finck 	register char type;
267*c2c66affSColin Finck 	register char mode;
268*c2c66affSColin Finck 	register char c;
269*c2c66affSColin Finck 	int count;
270*c2c66affSColin Finck 	int num;
271*c2c66affSColin Finck 	int i;
272*c2c66affSColin Finck 	short sh;
273*c2c66affSColin Finck 	const char *str;
274*c2c66affSColin Finck 	double dval;
275*c2c66affSColin Finck #ifdef	USE_LONGLONG
276*c2c66affSColin Finck 	Llong llval = 0;
277*c2c66affSColin Finck #endif
278*c2c66affSColin Finck 	Ulong res;
279*c2c66affSColin Finck 	char *rfmt;
280*c2c66affSColin Finck 	f_args	fa;
281*c2c66affSColin Finck #ifdef	USE_NL_ARGS
282*c2c66affSColin Finck 	va_lists_t	fargs;		/* Used to get arguments */
283*c2c66affSColin Finck 	va_lists_t	sargs;		/* Saved argument state */
284*c2c66affSColin Finck 	va_lists_t	arglist[FMT_ARGMAX+1]; /* List of fast args */
285*c2c66affSColin Finck 	const char 	*ofmt = fmt;	/* Saved original format */
286*c2c66affSColin Finck 	BOOL		didlist = FALSE; /* Need to scan arguments */
287*c2c66affSColin Finck #endif
288*c2c66affSColin Finck 
289*c2c66affSColin Finck #ifdef	FORMAT_BUFFER
290*c2c66affSColin Finck 	if (((UIntptr_t)farg & 1) == 0) { /* Called externally	*/
291*c2c66affSColin Finck 		fa.cnt	= BFSIZ;
292*c2c66affSColin Finck 		fa.ptr	= fa.iobuf;
293*c2c66affSColin Finck 		fa.fp	= (FILE *)farg;
294*c2c66affSColin Finck 		fa.err	= 0;
295*c2c66affSColin Finck 		farg	= fa.farg = &fa;
296*c2c66affSColin Finck 	} else {			/* recursion		*/
297*c2c66affSColin Finck 		farg = (void *)((UIntptr_t)farg & ~1);
298*c2c66affSColin Finck 	}
299*c2c66affSColin Finck #endif
300*c2c66affSColin Finck #ifdef	FORMAT_FUNC_PARM
301*c2c66affSColin Finck 	fa.outf = fun;
302*c2c66affSColin Finck #endif
303*c2c66affSColin Finck 	fa.farg = farg;
304*c2c66affSColin Finck 	count = 0;
305*c2c66affSColin Finck 
306*c2c66affSColin Finck #ifdef	USE_NL_ARGS
307*c2c66affSColin Finck 	va_copy(sargs.ap, oargs);	/* Keep a copy in sargs */
308*c2c66affSColin Finck 	fargs = sargs;			/* Make a working copy  */
309*c2c66affSColin Finck #endif
310*c2c66affSColin Finck 
311*c2c66affSColin Finck 	/*
312*c2c66affSColin Finck 	 * Main loop over the format string.
313*c2c66affSColin Finck 	 * Increment and check for end of string is made here.
314*c2c66affSColin Finck 	 */
315*c2c66affSColin Finck 	for (; *fmt != '\0'; fmt++) {
316*c2c66affSColin Finck 		c = *fmt;
317*c2c66affSColin Finck 		while (c != '%') {
318*c2c66affSColin Finck 			if (c == '\0')
319*c2c66affSColin Finck 				goto out;
320*c2c66affSColin Finck 			ofun(c, farg);
321*c2c66affSColin Finck 			c = *(++fmt);
322*c2c66affSColin Finck 			count++;
323*c2c66affSColin Finck 		}
324*c2c66affSColin Finck 
325*c2c66affSColin Finck 		/*
326*c2c66affSColin Finck 		 * We reached a '%' sign.
327*c2c66affSColin Finck 		 */
328*c2c66affSColin Finck 		buf[0] = '\0';
329*c2c66affSColin Finck 		fa.buf = fa.bufp = buf;
330*c2c66affSColin Finck 		fa.minusflag = 0;
331*c2c66affSColin Finck 		fa.flags = 0;
332*c2c66affSColin Finck 		fa.fldwidth = 0;
333*c2c66affSColin Finck 		fa.signific = -1;
334*c2c66affSColin Finck 		fa.lzero = 0;
335*c2c66affSColin Finck 		fa.fillc = ' ';
336*c2c66affSColin Finck 		fa.prefixlen = 0;
337*c2c66affSColin Finck 		sfmt = fmt;
338*c2c66affSColin Finck 		unsflag = FALSE;
339*c2c66affSColin Finck 		type = '\0';
340*c2c66affSColin Finck 		mode = '\0';
341*c2c66affSColin Finck 		/*
342*c2c66affSColin Finck 		 * %<flags>f.s<length-mod><conversion-spec>
343*c2c66affSColin Finck 		 * %<flags>*.*<length-mod><conversion-spec>
344*c2c66affSColin Finck 		 * %n$<flags>f.s<length-mod><conversion-spec>
345*c2c66affSColin Finck 		 * %n$<flags>*n$.*n$<length-mod><conversion-spec>
346*c2c66affSColin Finck 		 */
347*c2c66affSColin Finck 	newflag:
348*c2c66affSColin Finck 		switch (*(++fmt)) {
349*c2c66affSColin Finck 
350*c2c66affSColin Finck 		case '+':
351*c2c66affSColin Finck 			CHECKFLAG();
352*c2c66affSColin Finck 			fa.flags |= PLUSFLG;
353*c2c66affSColin Finck 			goto newflag;
354*c2c66affSColin Finck 
355*c2c66affSColin Finck 		case '-':
356*c2c66affSColin Finck 			CHECKFLAG();
357*c2c66affSColin Finck 			fa.minusflag++;
358*c2c66affSColin Finck 			fa.flags |= MINUSFLG;
359*c2c66affSColin Finck 			goto newflag;
360*c2c66affSColin Finck 
361*c2c66affSColin Finck 		case ' ':
362*c2c66affSColin Finck 			CHECKFLAG();
363*c2c66affSColin Finck 			/*
364*c2c66affSColin Finck 			 * If the space and the + flag are present,
365*c2c66affSColin Finck 			 * the space flag will be ignored.
366*c2c66affSColin Finck 			 */
367*c2c66affSColin Finck 			fa.flags |= SPACEFLG;
368*c2c66affSColin Finck 			goto newflag;
369*c2c66affSColin Finck 
370*c2c66affSColin Finck 		case '#':
371*c2c66affSColin Finck 			CHECKFLAG();
372*c2c66affSColin Finck 			fa.flags |= HASHFLG;
373*c2c66affSColin Finck 			goto newflag;
374*c2c66affSColin Finck 
375*c2c66affSColin Finck 		case '\'':
376*c2c66affSColin Finck 			CHECKFLAG();
377*c2c66affSColin Finck 			fa.flags |= APOFLG;
378*c2c66affSColin Finck 			goto newflag;
379*c2c66affSColin Finck 
380*c2c66affSColin Finck 		case '.':
381*c2c66affSColin Finck 			fa.flags |= GOTDOT;
382*c2c66affSColin Finck 			fa.signific = 0;
383*c2c66affSColin Finck 			goto newflag;
384*c2c66affSColin Finck 
385*c2c66affSColin Finck 		case '*':
386*c2c66affSColin Finck 			fa.flags |= GOTSTAR;
387*c2c66affSColin Finck #ifdef	USE_NL_ARGS
388*c2c66affSColin Finck 			if (is_dig(fmt[1])) {	/* *n$ */
389*c2c66affSColin Finck 				fmt++;		/* Eat up '*' */
390*c2c66affSColin Finck 				goto dodig;
391*c2c66affSColin Finck 			}
392*c2c66affSColin Finck #endif
393*c2c66affSColin Finck 			if (!(fa.flags & GOTDOT)) {
394*c2c66affSColin Finck 				fa.fldwidth = va_arg(args, int);
395*c2c66affSColin Finck 				/*
396*c2c66affSColin Finck 				 * A negative fieldwith is a minus flag with a
397*c2c66affSColin Finck 				 * positive fieldwidth.
398*c2c66affSColin Finck 				 */
399*c2c66affSColin Finck 				if (fa.fldwidth < 0) {
400*c2c66affSColin Finck 					fa.fldwidth = -fa.fldwidth;
401*c2c66affSColin Finck 					fa.minusflag = 1;
402*c2c66affSColin Finck 				}
403*c2c66affSColin Finck 			} else {
404*c2c66affSColin Finck 				/*
405*c2c66affSColin Finck 				 * A negative significance (precision) is taken
406*c2c66affSColin Finck 				 * as if the precision and '.' were omitted.
407*c2c66affSColin Finck 				 */
408*c2c66affSColin Finck 				fa.signific = va_arg(args, int);
409*c2c66affSColin Finck 				if (fa.signific < 0)
410*c2c66affSColin Finck 					fa.signific = -1;
411*c2c66affSColin Finck 			}
412*c2c66affSColin Finck 			goto newflag;
413*c2c66affSColin Finck 
414*c2c66affSColin Finck 		case '0':
415*c2c66affSColin Finck 			/*
416*c2c66affSColin Finck 			 * '0' may be a flag.
417*c2c66affSColin Finck 			 */
418*c2c66affSColin Finck 			if (!(fa.flags & (GOTDOT | GOTSTAR | MINUSFLG)))
419*c2c66affSColin Finck 				fa.fillc = '0';
420*c2c66affSColin Finck 			/* FALLTHRU */
421*c2c66affSColin Finck 		case '1': case '2': case '3': case '4':
422*c2c66affSColin Finck 		case '5': case '6': case '7': case '8': case '9':
423*c2c66affSColin Finck #ifdef	USE_NL_ARGS
424*c2c66affSColin Finck 		dodig:
425*c2c66affSColin Finck #endif
426*c2c66affSColin Finck 			num = *fmt++ - '0';
427*c2c66affSColin Finck 			while (c = *fmt, is_dig(c)) {
428*c2c66affSColin Finck 				num *= 10;
429*c2c66affSColin Finck 				num += c - '0';
430*c2c66affSColin Finck 				fmt++;
431*c2c66affSColin Finck 			}
432*c2c66affSColin Finck #ifdef	USE_NL_ARGS
433*c2c66affSColin Finck 			if (c == '$')
434*c2c66affSColin Finck 				goto doarglist;
435*c2c66affSColin Finck #endif
436*c2c66affSColin Finck 			fmt--;			/* backup to last digit */
437*c2c66affSColin Finck 			if (!(fa.flags & GOTDOT))
438*c2c66affSColin Finck 				fa.fldwidth = num;
439*c2c66affSColin Finck 			else
440*c2c66affSColin Finck 				fa.signific = num;
441*c2c66affSColin Finck 			goto newflag;
442*c2c66affSColin Finck 
443*c2c66affSColin Finck #ifdef	USE_NL_ARGS
444*c2c66affSColin Finck 		doarglist:
445*c2c66affSColin Finck 			{
446*c2c66affSColin Finck 			va_lists_t	tmp;	/* Temporary arg state */
447*c2c66affSColin Finck 			if (num <= 0)		/* Illegal arg offset */
448*c2c66affSColin Finck 				goto newflag;	/* Continue after '$' */
449*c2c66affSColin Finck 			if (!didlist) {		/* Need to init arglist */
450*c2c66affSColin Finck 				_fmtarglist(ofmt, sargs, arglist);
451*c2c66affSColin Finck 				didlist = TRUE;
452*c2c66affSColin Finck 			}
453*c2c66affSColin Finck 			if (num <= FMT_ARGMAX) {
454*c2c66affSColin Finck 				tmp = arglist[num-1];
455*c2c66affSColin Finck 			} else {
456*c2c66affSColin Finck 				tmp = arglist[FMT_ARGMAX-1];
457*c2c66affSColin Finck 				_fmtgetarg(ofmt, num, &tmp);
458*c2c66affSColin Finck 			}
459*c2c66affSColin Finck 			if (!(fa.flags & GOTSTAR)) {
460*c2c66affSColin Finck 				fargs = tmp;
461*c2c66affSColin Finck 			} else {
462*c2c66affSColin Finck 				if (!(fa.flags & GOTDOT)) {
463*c2c66affSColin Finck 					fa.fldwidth = va_arg(tmp.ap, int);
464*c2c66affSColin Finck 					/*
465*c2c66affSColin Finck 					 * A negative fieldwith is a minus flag
466*c2c66affSColin Finck 					 * with a positive fieldwidth.
467*c2c66affSColin Finck 					 */
468*c2c66affSColin Finck 					if (fa.fldwidth < 0) {
469*c2c66affSColin Finck 						fa.fldwidth = -fa.fldwidth;
470*c2c66affSColin Finck 						fa.minusflag = 1;
471*c2c66affSColin Finck 					}
472*c2c66affSColin Finck 				} else {
473*c2c66affSColin Finck 					/*
474*c2c66affSColin Finck 					 * A negative significance (precision)
475*c2c66affSColin Finck 					 * is taken as if the precision and '.'
476*c2c66affSColin Finck 					 * were omitted.
477*c2c66affSColin Finck 					 */
478*c2c66affSColin Finck 					fa.signific = va_arg(tmp.ap, int);
479*c2c66affSColin Finck 					if (fa.signific < 0)
480*c2c66affSColin Finck 						fa.signific = -1;
481*c2c66affSColin Finck 				}
482*c2c66affSColin Finck 			}
483*c2c66affSColin Finck 			goto newflag;
484*c2c66affSColin Finck 			}
485*c2c66affSColin Finck #endif
486*c2c66affSColin Finck 
487*c2c66affSColin Finck #ifdef	USE_CHECKFLAG
488*c2c66affSColin Finck 		flagerror:
489*c2c66affSColin Finck 			fmt = ++sfmt;		/* Don't print '%'   */
490*c2c66affSColin Finck 			continue;
491*c2c66affSColin Finck #endif
492*c2c66affSColin Finck 		}
493*c2c66affSColin Finck 
494*c2c66affSColin Finck 		if (strchr("UCSIL", *fmt)) {
495*c2c66affSColin Finck 			/*
496*c2c66affSColin Finck 			 * Enhancements to K&R and ANSI:
497*c2c66affSColin Finck 			 *
498*c2c66affSColin Finck 			 * got a type specifyer
499*c2c66affSColin Finck 			 *
500*c2c66affSColin Finck 			 * XXX 'S' in C99 is %ls, 'S' should become 'H'
501*c2c66affSColin Finck 			 */
502*c2c66affSColin Finck 			if (*fmt == 'U') {
503*c2c66affSColin Finck 				fmt++;
504*c2c66affSColin Finck 				unsflag = TRUE;
505*c2c66affSColin Finck 			}
506*c2c66affSColin Finck 			if (!strchr("CSILZODX", *fmt)) {
507*c2c66affSColin Finck 				/*
508*c2c66affSColin Finck 				 * Got only 'U'nsigned specifyer,
509*c2c66affSColin Finck 				 * use default type and mode.
510*c2c66affSColin Finck 				 */
511*c2c66affSColin Finck 				type = 'I';
512*c2c66affSColin Finck 				mode = 'D';
513*c2c66affSColin Finck 				fmt--;
514*c2c66affSColin Finck 			} else if (!strchr("CSIL", *fmt)) {
515*c2c66affSColin Finck 				/*
516*c2c66affSColin Finck 				 * no type, use default
517*c2c66affSColin Finck 				 */
518*c2c66affSColin Finck 				type = 'I';
519*c2c66affSColin Finck 				mode = *fmt;
520*c2c66affSColin Finck 			} else {
521*c2c66affSColin Finck 				/*
522*c2c66affSColin Finck 				 * got CSIL type
523*c2c66affSColin Finck 				 */
524*c2c66affSColin Finck 				type = *fmt++;
525*c2c66affSColin Finck 				if (!strchr("ZODX", mode = *fmt)) {
526*c2c66affSColin Finck 					/*
527*c2c66affSColin Finck 					 * Check long double "Le", "Lf" or "Lg"
528*c2c66affSColin Finck 					 */
529*c2c66affSColin Finck 					if (type == 'L' &&
530*c2c66affSColin Finck 					    (mode == 'e' ||
531*c2c66affSColin Finck 					    mode == 'f' ||
532*c2c66affSColin Finck 					    mode == 'g'))
533*c2c66affSColin Finck 						goto checkfmt;
534*c2c66affSColin Finck 					fmt--;
535*c2c66affSColin Finck 					mode = 'D'; /* default mode */
536*c2c66affSColin Finck 				}
537*c2c66affSColin Finck 			}
538*c2c66affSColin Finck 		} else {
539*c2c66affSColin Finck 	checkfmt:
540*c2c66affSColin Finck 		switch (*fmt) {
541*c2c66affSColin Finck 
542*c2c66affSColin Finck 		case 'h':
543*c2c66affSColin Finck 			if (!type)
544*c2c66affSColin Finck 				type = 'H';	/* convert to short type */
545*c2c66affSColin Finck 			goto getmode;
546*c2c66affSColin Finck 
547*c2c66affSColin Finck 		case 'l':
548*c2c66affSColin Finck 			if (!type)
549*c2c66affSColin Finck 				type = 'L';	/* convert to long type */
550*c2c66affSColin Finck 			goto getmode;
551*c2c66affSColin Finck 
552*c2c66affSColin Finck 		case 'j':
553*c2c66affSColin Finck 			if (!type)
554*c2c66affSColin Finck 				type = 'J';	/* convert to intmax_t type */
555*c2c66affSColin Finck 			goto getmode;
556*c2c66affSColin Finck 
557*c2c66affSColin Finck 		case 'z':			/* size_t */
558*c2c66affSColin Finck #if	SIZEOF_SIZE_T == SIZEOF_INT
559*c2c66affSColin Finck 			if (!type)
560*c2c66affSColin Finck 				type = 'I';	/* convert to int type */
561*c2c66affSColin Finck #else
562*c2c66affSColin Finck #if	SIZEOF_SIZE_T == SIZEOF_LONG_INT
563*c2c66affSColin Finck 			if (!type)
564*c2c66affSColin Finck 				type = 'L';	/* convert to long type */
565*c2c66affSColin Finck #else
566*c2c66affSColin Finck #if	SIZEOF_SIZE_T == SIZEOF_LLONG
567*c2c66affSColin Finck 			if (!type)
568*c2c66affSColin Finck 				type = 'Q';	/* convert to long long type */
569*c2c66affSColin Finck #else
570*c2c66affSColin Finck error sizeof (size_t) is unknown
571*c2c66affSColin Finck #endif
572*c2c66affSColin Finck #endif
573*c2c66affSColin Finck #endif
574*c2c66affSColin Finck 			goto getmode;
575*c2c66affSColin Finck 
576*c2c66affSColin Finck 		case 't':			/* ptrdiff_t */
577*c2c66affSColin Finck #if	SIZEOF_PTRDIFF_T == SIZEOF_INT
578*c2c66affSColin Finck 			if (!type)
579*c2c66affSColin Finck 				type = 'I';	/* convert to int type */
580*c2c66affSColin Finck #else
581*c2c66affSColin Finck #if	SIZEOF_PTRDIFF_T == SIZEOF_LONG_INT
582*c2c66affSColin Finck 			if (!type)
583*c2c66affSColin Finck 				type = 'L';	/* convert to long type */
584*c2c66affSColin Finck #else
585*c2c66affSColin Finck #if	SIZEOF_PTRDIFF_T == SIZEOF_LLONG
586*c2c66affSColin Finck 			if (!type)
587*c2c66affSColin Finck 				type = 'Q';	/* convert to long long type */
588*c2c66affSColin Finck #else
589*c2c66affSColin Finck error sizeof (ptrdiff_t) is unknown
590*c2c66affSColin Finck #endif
591*c2c66affSColin Finck #endif
592*c2c66affSColin Finck #endif
593*c2c66affSColin Finck 		/*
594*c2c66affSColin Finck 		 * XXX Future length modifiers:
595*c2c66affSColin Finck 		 * XXX	'L' with double: long double
596*c2c66affSColin Finck 		 */
597*c2c66affSColin Finck 
598*c2c66affSColin Finck 		getmode:
599*c2c66affSColin Finck 			if (!strchr("udioxXn", *(++fmt))) {
600*c2c66affSColin Finck 				/*
601*c2c66affSColin Finck 				 * %hhd -> char in decimal
602*c2c66affSColin Finck 				 */
603*c2c66affSColin Finck 				if (type == 'H' && *fmt == 'h') {
604*c2c66affSColin Finck 					type = 'C';
605*c2c66affSColin Finck 					goto getmode;
606*c2c66affSColin Finck 				}
607*c2c66affSColin Finck #ifdef	USE_LONGLONG
608*c2c66affSColin Finck 				if (type == 'L' && *fmt == 'l') {
609*c2c66affSColin Finck 					type = 'Q';
610*c2c66affSColin Finck 					goto getmode;
611*c2c66affSColin Finck 				}
612*c2c66affSColin Finck #endif
613*c2c66affSColin Finck 				fmt--;
614*c2c66affSColin Finck 				mode = 'D';
615*c2c66affSColin Finck 			} else {		/* One of "udioxXn": */
616*c2c66affSColin Finck 				mode = *fmt;
617*c2c66affSColin Finck 				if (mode == 'n')
618*c2c66affSColin Finck 					goto gotn;
619*c2c66affSColin Finck 				if (mode != 'x')
620*c2c66affSColin Finck 					mode = to_cap(mode);
621*c2c66affSColin Finck 				if (mode == 'U')
622*c2c66affSColin Finck 					unsflag = TRUE;
623*c2c66affSColin Finck 				else if (mode == 'I')	/* XXX */
624*c2c66affSColin Finck 					mode = 'D';
625*c2c66affSColin Finck 			}
626*c2c66affSColin Finck 			break;
627*c2c66affSColin Finck 		case 'x':
628*c2c66affSColin Finck 			mode = 'x';
629*c2c66affSColin Finck 			goto havemode;
630*c2c66affSColin Finck 		case 'X':
631*c2c66affSColin Finck 			mode = 'X';
632*c2c66affSColin Finck 			type = 'I';
633*c2c66affSColin Finck 			goto havemode;
634*c2c66affSColin Finck 		case 'u':
635*c2c66affSColin Finck 			unsflag = TRUE;
636*c2c66affSColin Finck 		/*
637*c2c66affSColin Finck 		 * XXX Need to remove uppercase letters for 'long'
638*c2c66affSColin Finck 		 * XXX in future for POSIX/C99 compliance.
639*c2c66affSColin Finck 		 */
640*c2c66affSColin Finck 			/* FALLTHRU */
641*c2c66affSColin Finck 		case 'o': case 'O':
642*c2c66affSColin Finck 		case 'd': case 'D':
643*c2c66affSColin Finck 		case 'i': case 'I':
644*c2c66affSColin Finck 		case 'Z':
645*c2c66affSColin Finck 			mode = to_cap(*fmt);
646*c2c66affSColin Finck 		havemode:
647*c2c66affSColin Finck 			if (!type)
648*c2c66affSColin Finck 				type = cap_ty(*fmt);
649*c2c66affSColin Finck #ifdef	DEBUG
650*c2c66affSColin Finck 			dbg_print("*fmt: '%c' mode: '%c' type: '%c'\n",
651*c2c66affSColin Finck 							*fmt, mode, type);
652*c2c66affSColin Finck #endif
653*c2c66affSColin Finck 			if (mode == 'I')	/* XXX kann entfallen */
654*c2c66affSColin Finck 				mode = 'D';	/* wenn besseres uflg */
655*c2c66affSColin Finck 			break;
656*c2c66affSColin Finck 		case 'p':
657*c2c66affSColin Finck 			mode = 'P';
658*c2c66affSColin Finck 			type = 'L';
659*c2c66affSColin Finck 			break;
660*c2c66affSColin Finck 
661*c2c66affSColin Finck 		case '%':
662*c2c66affSColin Finck 			count += prc('%', &fa);
663*c2c66affSColin Finck 			continue;
664*c2c66affSColin Finck 		case ' ':
665*c2c66affSColin Finck 			count += prbuf("", &fa);
666*c2c66affSColin Finck 			continue;
667*c2c66affSColin Finck 		case 'c':
668*c2c66affSColin Finck 			c = va_arg(args, int);
669*c2c66affSColin Finck 			count += prc(c, &fa);
670*c2c66affSColin Finck 			continue;
671*c2c66affSColin Finck 		case 's':
672*c2c66affSColin Finck 			str = va_arg(args, char *);
673*c2c66affSColin Finck 			count += prstring(str, &fa);
674*c2c66affSColin Finck 			continue;
675*c2c66affSColin Finck 		case 'b':
676*c2c66affSColin Finck 			str = va_arg(args, char *);
677*c2c66affSColin Finck 			fa.signific = va_arg(args, int);
678*c2c66affSColin Finck 			count += prstring(str, &fa);
679*c2c66affSColin Finck 			continue;
680*c2c66affSColin Finck 
681*c2c66affSColin Finck #ifndef	NO_FLOATINGPOINT
682*c2c66affSColin Finck 		case 'e':
683*c2c66affSColin Finck 			if (fa.signific == -1)
684*c2c66affSColin Finck 				fa.signific = 6;
685*c2c66affSColin Finck 			if (type == 'L') {
686*c2c66affSColin Finck #ifdef	HAVE_LONGDOUBLE
687*c2c66affSColin Finck 				long double ldval = va_arg(args, long double);
688*c2c66affSColin Finck 
689*c2c66affSColin Finck #if	(defined(HAVE_QECVT) || defined(HAVE__LDECVT))
690*c2c66affSColin Finck 				qftoes(buf, ldval, 0, fa.signific);
691*c2c66affSColin Finck 				count += prbuf(buf, &fa);
692*c2c66affSColin Finck 				continue;
693*c2c66affSColin Finck #else
694*c2c66affSColin Finck 				dval = ldval;
695*c2c66affSColin Finck #endif
696*c2c66affSColin Finck #endif
697*c2c66affSColin Finck 			}
698*c2c66affSColin Finck 			dval = va_arg(args, double);
699*c2c66affSColin Finck 			ftoes(buf, dval, 0, fa.signific);
700*c2c66affSColin Finck 			count += prbuf(buf, &fa);
701*c2c66affSColin Finck 			continue;
702*c2c66affSColin Finck 		case 'f':
703*c2c66affSColin Finck 			if (fa.signific == -1)
704*c2c66affSColin Finck 				fa.signific = 6;
705*c2c66affSColin Finck 			if (type == 'L') {
706*c2c66affSColin Finck #ifdef	HAVE_LONGDOUBLE
707*c2c66affSColin Finck 				long double ldval = va_arg(args, long double);
708*c2c66affSColin Finck 
709*c2c66affSColin Finck #if	(defined(HAVE_QFCVT) || defined(HAVE__LDFCVT))
710*c2c66affSColin Finck 				qftofs(buf, ldval, 0, fa.signific);
711*c2c66affSColin Finck 				count += prbuf(buf, &fa);
712*c2c66affSColin Finck 				continue;
713*c2c66affSColin Finck #else
714*c2c66affSColin Finck 				dval = ldval;
715*c2c66affSColin Finck #endif
716*c2c66affSColin Finck #endif
717*c2c66affSColin Finck 			}
718*c2c66affSColin Finck 			dval = va_arg(args, double);
719*c2c66affSColin Finck 			ftofs(buf, dval, 0, fa.signific);
720*c2c66affSColin Finck 			count += prbuf(buf, &fa);
721*c2c66affSColin Finck 			continue;
722*c2c66affSColin Finck 		case 'g':
723*c2c66affSColin Finck 			if (fa.signific == -1)
724*c2c66affSColin Finck 				fa.signific = 6;
725*c2c66affSColin Finck 			if (fa.signific == 0)
726*c2c66affSColin Finck 				fa.signific = 1;
727*c2c66affSColin Finck 			if (type == 'L') {
728*c2c66affSColin Finck #ifdef	HAVE_LONGDOUBLE
729*c2c66affSColin Finck 				long double ldval = va_arg(args, long double);
730*c2c66affSColin Finck 
731*c2c66affSColin Finck #if	(defined(HAVE_QGCVT) || defined(HAVE__LDGCVT))
732*c2c66affSColin Finck 
733*c2c66affSColin Finck #ifdef	HAVE__LDGCVT
734*c2c66affSColin Finck #define	qgcvt(ld, n, b)	_ldgcvt(*(long_double *)&ld, n, b)
735*c2c66affSColin Finck #endif
736*c2c66affSColin Finck 				(void) qgcvt(ldval, fa.signific, buf);
737*c2c66affSColin Finck 				count += prbuf(buf, &fa);
738*c2c66affSColin Finck 				continue;
739*c2c66affSColin Finck #else
740*c2c66affSColin Finck 				dval = ldval;
741*c2c66affSColin Finck #endif
742*c2c66affSColin Finck #endif
743*c2c66affSColin Finck 			}
744*c2c66affSColin Finck 			dval = va_arg(args, double);
745*c2c66affSColin Finck 			(void) gcvt(dval, fa.signific, buf);
746*c2c66affSColin Finck 			count += prbuf(buf, &fa);
747*c2c66affSColin Finck 			continue;
748*c2c66affSColin Finck #else
749*c2c66affSColin Finck #	ifdef	USE_FLOATINGARGS
750*c2c66affSColin Finck 		case 'e':
751*c2c66affSColin Finck 		case 'f':
752*c2c66affSColin Finck 		case 'g':
753*c2c66affSColin Finck 			dval = va_arg(args, double);
754*c2c66affSColin Finck 			continue;
755*c2c66affSColin Finck #	endif
756*c2c66affSColin Finck #endif
757*c2c66affSColin Finck 
758*c2c66affSColin Finck 		case 'r':			/* recursive printf */
759*c2c66affSColin Finck 		case 'R':			/* recursive printf */
760*c2c66affSColin Finck 			rfmt  = va_arg(args, char *);
761*c2c66affSColin Finck 			/*
762*c2c66affSColin Finck 			 * I don't know any portable way to get an arbitrary
763*c2c66affSColin Finck 			 * C object from a var arg list so I use a
764*c2c66affSColin Finck 			 * system-specific routine __va_arg_list() that knows
765*c2c66affSColin Finck 			 * if 'va_list' is an array. You will not be able to
766*c2c66affSColin Finck 			 * assign the value of __va_arg_list() but it works
767*c2c66affSColin Finck 			 * to be used as an argument of a function.
768*c2c66affSColin Finck 			 * It is a requirement for recursive printf to be able
769*c2c66affSColin Finck 			 * to use this function argument. If your system
770*c2c66affSColin Finck 			 * defines va_list to be an array you need to know this
771*c2c66affSColin Finck 			 * via autoconf or another mechanism.
772*c2c66affSColin Finck 			 * It would be nice to have something like
773*c2c66affSColin Finck 			 * __va_arg_list() in stdarg.h
774*c2c66affSColin Finck 			 */
775*c2c66affSColin Finck 			count += FORMAT_FUNC_NAME(FORMAT_FUNC_KR_ARGS
776*c2c66affSColin Finck 					FARG, rfmt, __va_arg_list(args));
777*c2c66affSColin Finck 			continue;
778*c2c66affSColin Finck 
779*c2c66affSColin Finck 		gotn:
780*c2c66affSColin Finck 		case 'n':
781*c2c66affSColin Finck 			switch (type) {
782*c2c66affSColin Finck 
783*c2c66affSColin Finck 			case 'C': {
784*c2c66affSColin Finck 				signed char *cp = va_arg(args, signed char *);
785*c2c66affSColin Finck 
786*c2c66affSColin Finck 				*cp = count;
787*c2c66affSColin Finck 				}
788*c2c66affSColin Finck 				continue;
789*c2c66affSColin Finck 			case 'H': {
790*c2c66affSColin Finck 				short	*sp = va_arg(args, short *);
791*c2c66affSColin Finck 
792*c2c66affSColin Finck 				*sp = count;
793*c2c66affSColin Finck 				}
794*c2c66affSColin Finck 				continue;
795*c2c66affSColin Finck 			case 'L': {
796*c2c66affSColin Finck 				long	*lp = va_arg(args, long *);
797*c2c66affSColin Finck 
798*c2c66affSColin Finck 				*lp = count;
799*c2c66affSColin Finck 				}
800*c2c66affSColin Finck 				continue;
801*c2c66affSColin Finck #ifdef	USE_LONGLONG
802*c2c66affSColin Finck 			case 'J':		/* For now Intmax_t is Llong */
803*c2c66affSColin Finck 			case 'Q': {
804*c2c66affSColin Finck 				Llong *qp = va_arg(args, Llong *);
805*c2c66affSColin Finck 
806*c2c66affSColin Finck 				*qp = count;
807*c2c66affSColin Finck 				}
808*c2c66affSColin Finck 				continue;
809*c2c66affSColin Finck #endif
810*c2c66affSColin Finck 			default: {
811*c2c66affSColin Finck 				int	*ip = va_arg(args, int *);
812*c2c66affSColin Finck 
813*c2c66affSColin Finck 				*ip = count;
814*c2c66affSColin Finck 				}
815*c2c66affSColin Finck 				continue;
816*c2c66affSColin Finck 			}
817*c2c66affSColin Finck 
818*c2c66affSColin Finck 		default:			/* Unknown '%' format */
819*c2c66affSColin Finck 			sfmt++;			/* Dont't print '%'   */
820*c2c66affSColin Finck 			count += fmt - sfmt;
821*c2c66affSColin Finck 			while (sfmt < fmt)
822*c2c66affSColin Finck 				ofun(*(sfmt++), farg);
823*c2c66affSColin Finck 			if (*fmt == '\0') {
824*c2c66affSColin Finck 				fmt--;
825*c2c66affSColin Finck 				continue;
826*c2c66affSColin Finck 			} else {
827*c2c66affSColin Finck 				ofun(*fmt, farg);
828*c2c66affSColin Finck 				count++;
829*c2c66affSColin Finck 				continue;
830*c2c66affSColin Finck 			}
831*c2c66affSColin Finck 		}
832*c2c66affSColin Finck 		}
833*c2c66affSColin Finck 		/*
834*c2c66affSColin Finck 		 * print numbers:
835*c2c66affSColin Finck 		 * first prepare type 'C'har, s'H'ort, 'I'nt, or 'L'ong
836*c2c66affSColin Finck 		 * or 'Q'ad and 'J'==maxint_t
837*c2c66affSColin Finck 		 */
838*c2c66affSColin Finck 		switch (type) {
839*c2c66affSColin Finck 
840*c2c66affSColin Finck 		case 'C':
841*c2c66affSColin Finck 			c = va_arg(args, int);
842*c2c66affSColin Finck 			val = c;		/* extend sign here */
843*c2c66affSColin Finck 			if (unsflag || mode != 'D')
844*c2c66affSColin Finck #ifdef	DO_MASK
845*c2c66affSColin Finck 				val &= CHARMASK;
846*c2c66affSColin Finck #else
847*c2c66affSColin Finck 				val = (unsigned char)val;
848*c2c66affSColin Finck #endif
849*c2c66affSColin Finck 			break;
850*c2c66affSColin Finck 		case 'H':
851*c2c66affSColin Finck 		case 'S':			/* XXX remove 'S' in future */
852*c2c66affSColin Finck 			sh = va_arg(args, int);
853*c2c66affSColin Finck 			val = sh;		/* extend sign here */
854*c2c66affSColin Finck 			if (unsflag || mode != 'D')
855*c2c66affSColin Finck #ifdef	DO_MASK
856*c2c66affSColin Finck 				val &= SHORTMASK;
857*c2c66affSColin Finck #else
858*c2c66affSColin Finck 				val = (unsigned short)val;
859*c2c66affSColin Finck #endif
860*c2c66affSColin Finck 			break;
861*c2c66affSColin Finck 		case 'I':
862*c2c66affSColin Finck 		default:
863*c2c66affSColin Finck 			i = va_arg(args, int);
864*c2c66affSColin Finck 			val = i;		/* extend sign here */
865*c2c66affSColin Finck 			if (unsflag || mode != 'D')
866*c2c66affSColin Finck #ifdef	DO_MASK
867*c2c66affSColin Finck 				val &= INTMASK;
868*c2c66affSColin Finck #else
869*c2c66affSColin Finck 				val = (unsigned int)val;
870*c2c66affSColin Finck #endif
871*c2c66affSColin Finck 			break;
872*c2c66affSColin Finck 		case 'P':
873*c2c66affSColin Finck 		case 'L':
874*c2c66affSColin Finck 			val = va_arg(args, long);
875*c2c66affSColin Finck 			break;
876*c2c66affSColin Finck #ifdef	USE_LONGLONG
877*c2c66affSColin Finck 		case 'J':			/* For now Intmax_t is Llong */
878*c2c66affSColin Finck 			type = 'Q';		/* use 'Q' for processing    */
879*c2c66affSColin Finck 		case 'Q':
880*c2c66affSColin Finck 			llval = va_arg(args, Llong);
881*c2c66affSColin Finck 			val = llval != 0;
882*c2c66affSColin Finck 			break;
883*c2c66affSColin Finck #endif
884*c2c66affSColin Finck 		}
885*c2c66affSColin Finck 
886*c2c66affSColin Finck 		/*
887*c2c66affSColin Finck 		 * Final print out, take care of mode:
888*c2c66affSColin Finck 		 * mode is one of: 'O'ctal, 'D'ecimal, or he'X'
889*c2c66affSColin Finck 		 * oder 'Z'weierdarstellung.
890*c2c66affSColin Finck 		 */
891*c2c66affSColin Finck 		fa.bufp = &buf[sizeof (buf)-1];
892*c2c66affSColin Finck 		*--fa.bufp = '\0';
893*c2c66affSColin Finck 
894*c2c66affSColin Finck 		if (val == 0 && mode != 'D') {
895*c2c66affSColin Finck 		printzero:
896*c2c66affSColin Finck 			/*
897*c2c66affSColin Finck 			 * Printing '0' with fieldwidth 0 results in no chars.
898*c2c66affSColin Finck 			 */
899*c2c66affSColin Finck 			fa.lzero = -1;
900*c2c66affSColin Finck 			if (fa.signific >= 0)
901*c2c66affSColin Finck 				fa.fillc = ' ';
902*c2c66affSColin Finck 			count += prstring("0", &fa);
903*c2c66affSColin Finck 			continue;
904*c2c66affSColin Finck 		} else switch (mode) {
905*c2c66affSColin Finck 
906*c2c66affSColin Finck 		case 'D':
907*c2c66affSColin Finck #ifdef	USE_LONGLONG
908*c2c66affSColin Finck 			if (type == 'Q') {
909*c2c66affSColin Finck 				if (!unsflag && llval < 0) {
910*c2c66affSColin Finck 					fa.prefix = "-";
911*c2c66affSColin Finck 					fa.prefixlen = 1;
912*c2c66affSColin Finck 					llval = -llval;
913*c2c66affSColin Finck 				} else if (fa.flags & PLUSFLG) {
914*c2c66affSColin Finck 					fa.prefix = "+";
915*c2c66affSColin Finck 					fa.prefixlen = 1;
916*c2c66affSColin Finck 				} else if (fa.flags & SPACEFLG) {
917*c2c66affSColin Finck 					fa.prefix = " ";
918*c2c66affSColin Finck 					fa.prefixlen = 1;
919*c2c66affSColin Finck 				}
920*c2c66affSColin Finck 				if (llval == 0)
921*c2c66affSColin Finck 					goto printzero;
922*c2c66affSColin Finck 				goto prunsigned;
923*c2c66affSColin Finck 			}
924*c2c66affSColin Finck #endif
925*c2c66affSColin Finck 			if (!unsflag && val < 0) {
926*c2c66affSColin Finck 				fa.prefix = "-";
927*c2c66affSColin Finck 				fa.prefixlen = 1;
928*c2c66affSColin Finck 				val = -val;
929*c2c66affSColin Finck 			} else if (fa.flags & PLUSFLG) {
930*c2c66affSColin Finck 				fa.prefix = "+";
931*c2c66affSColin Finck 				fa.prefixlen = 1;
932*c2c66affSColin Finck 			} else if (fa.flags & SPACEFLG) {
933*c2c66affSColin Finck 				fa.prefix = " ";
934*c2c66affSColin Finck 				fa.prefixlen = 1;
935*c2c66affSColin Finck 			}
936*c2c66affSColin Finck 			if (val == 0)
937*c2c66affSColin Finck 				goto printzero;
938*c2c66affSColin Finck 			/* FALLTHRU */
939*c2c66affSColin Finck 		case 'U':
940*c2c66affSColin Finck 			/* output a long unsigned decimal number */
941*c2c66affSColin Finck #ifdef	USE_LONGLONG
942*c2c66affSColin Finck 		prunsigned:
943*c2c66affSColin Finck 			if (type == 'Q')
944*c2c66affSColin Finck 				prldnum(llval, &fa);
945*c2c66affSColin Finck 			else
946*c2c66affSColin Finck #endif
947*c2c66affSColin Finck 			prdnum(val, &fa);
948*c2c66affSColin Finck 			break;
949*c2c66affSColin Finck 		case 'O':
950*c2c66affSColin Finck 			/* output a long octal number */
951*c2c66affSColin Finck 			if (fa.flags & HASHFLG) {
952*c2c66affSColin Finck 				fa.prefix = "0";
953*c2c66affSColin Finck 				fa.prefixlen = 1;
954*c2c66affSColin Finck 			}
955*c2c66affSColin Finck #ifdef	USE_LONGLONG
956*c2c66affSColin Finck 			if (type == 'Q') {
957*c2c66affSColin Finck 				prlonum(llval, &fa);
958*c2c66affSColin Finck 			} else
959*c2c66affSColin Finck #endif
960*c2c66affSColin Finck 			{
961*c2c66affSColin Finck 				pronum(val & 07, &fa);
962*c2c66affSColin Finck 				if ((res = (val>>3) & rshiftmask(long, 3)) != 0)
963*c2c66affSColin Finck 					pronum(res, &fa);
964*c2c66affSColin Finck 			}
965*c2c66affSColin Finck 			break;
966*c2c66affSColin Finck 		case 'p':
967*c2c66affSColin Finck 		case 'x':
968*c2c66affSColin Finck 			/* output a hex long */
969*c2c66affSColin Finck 			if (fa.flags & HASHFLG) {
970*c2c66affSColin Finck 				fa.prefix = "0x";
971*c2c66affSColin Finck 				fa.prefixlen = 2;
972*c2c66affSColin Finck 			}
973*c2c66affSColin Finck #ifdef	USE_LONGLONG
974*c2c66affSColin Finck 			if (type == 'Q')
975*c2c66affSColin Finck 				prlxnum(llval, &fa);
976*c2c66affSColin Finck 			else
977*c2c66affSColin Finck #endif
978*c2c66affSColin Finck 			{
979*c2c66affSColin Finck 				prxnum(val & 0xF, &fa);
980*c2c66affSColin Finck 				if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
981*c2c66affSColin Finck 					prxnum(res, &fa);
982*c2c66affSColin Finck 			}
983*c2c66affSColin Finck 			break;
984*c2c66affSColin Finck 		case 'P':
985*c2c66affSColin Finck 		case 'X':
986*c2c66affSColin Finck 			/* output a hex long */
987*c2c66affSColin Finck 			if (fa.flags & HASHFLG) {
988*c2c66affSColin Finck 				fa.prefix = "0X";
989*c2c66affSColin Finck 				fa.prefixlen = 2;
990*c2c66affSColin Finck 			}
991*c2c66affSColin Finck #ifdef	USE_LONGLONG
992*c2c66affSColin Finck 			if (type == 'Q')
993*c2c66affSColin Finck 				prlXnum(llval, &fa);
994*c2c66affSColin Finck 			else
995*c2c66affSColin Finck #endif
996*c2c66affSColin Finck 			{
997*c2c66affSColin Finck 				prXnum(val & 0xF, &fa);
998*c2c66affSColin Finck 				if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
999*c2c66affSColin Finck 					prXnum(res, &fa);
1000*c2c66affSColin Finck 			}
1001*c2c66affSColin Finck 			break;
1002*c2c66affSColin Finck 		case 'Z':
1003*c2c66affSColin Finck 			/* output a binary long */
1004*c2c66affSColin Finck #ifdef	USE_LONGLONG
1005*c2c66affSColin Finck 			if (type == 'Q')
1006*c2c66affSColin Finck 				prlnum(llval, 2, &fa);
1007*c2c66affSColin Finck 			else
1008*c2c66affSColin Finck #endif
1009*c2c66affSColin Finck 			{
1010*c2c66affSColin Finck 				prnum(val & 0x1, 2, &fa);
1011*c2c66affSColin Finck 				if ((res = (val>>1) & rshiftmask(long, 1)) != 0)
1012*c2c66affSColin Finck 					prnum(res, 2, &fa);
1013*c2c66affSColin Finck 			}
1014*c2c66affSColin Finck 		}
1015*c2c66affSColin Finck 		fa.lzero = -1;
1016*c2c66affSColin Finck 		/*
1017*c2c66affSColin Finck 		 * If a precision (fielwidth) is specified
1018*c2c66affSColin Finck 		 * on diouXx conversions, the '0' flag is ignored.
1019*c2c66affSColin Finck 		 */
1020*c2c66affSColin Finck 		if (fa.signific >= 0)
1021*c2c66affSColin Finck 			fa.fillc = ' ';
1022*c2c66affSColin Finck 		count += prbuf(fa.bufp, &fa);
1023*c2c66affSColin Finck 	}
1024*c2c66affSColin Finck out:
1025*c2c66affSColin Finck #ifdef	FORMAT_BUFFER
1026*c2c66affSColin Finck 	if (farg == &fa) {		/* Top level call, flush buffer */
1027*c2c66affSColin Finck 		if (fa.err)
1028*c2c66affSColin Finck 			return (EOF);
1029*c2c66affSColin Finck 		if ((fa.ptr != fa.iobuf) &&
1030*c2c66affSColin Finck 		    (filewrite(fa.fp, fa.iobuf, fa.ptr - fa.iobuf) < 0))
1031*c2c66affSColin Finck 			return (EOF);
1032*c2c66affSColin Finck 	}
1033*c2c66affSColin Finck #endif
1034*c2c66affSColin Finck 	return (count);
1035*c2c66affSColin Finck }
1036*c2c66affSColin Finck 
1037*c2c66affSColin Finck /*
1038*c2c66affSColin Finck  * Routines to print (not negative) numbers in an arbitrary base
1039*c2c66affSColin Finck  */
1040*c2c66affSColin Finck LOCAL	unsigned char	dtab[]  = "0123456789abcdef";
1041*c2c66affSColin Finck LOCAL	unsigned char	udtab[] = "0123456789ABCDEF";
1042*c2c66affSColin Finck 
1043*c2c66affSColin Finck LOCAL void
prnum(val,base,fa)1044*c2c66affSColin Finck prnum(val, base, fa)
1045*c2c66affSColin Finck 	register Ulong val;
1046*c2c66affSColin Finck 	register unsigned base;
1047*c2c66affSColin Finck 	f_args *fa;
1048*c2c66affSColin Finck {
1049*c2c66affSColin Finck 	register char *p = fa->bufp;
1050*c2c66affSColin Finck 
1051*c2c66affSColin Finck 	do {
1052*c2c66affSColin Finck 		*--p = dtab[modlbys(val, base)];
1053*c2c66affSColin Finck 		val = divlbys(val, base);
1054*c2c66affSColin Finck 	} while (val > 0);
1055*c2c66affSColin Finck 
1056*c2c66affSColin Finck 	fa->bufp = p;
1057*c2c66affSColin Finck }
1058*c2c66affSColin Finck 
1059*c2c66affSColin Finck LOCAL void
prdnum(val,fa)1060*c2c66affSColin Finck prdnum(val, fa)
1061*c2c66affSColin Finck 	register Ulong val;
1062*c2c66affSColin Finck 	f_args *fa;
1063*c2c66affSColin Finck {
1064*c2c66affSColin Finck 	register char *p = fa->bufp;
1065*c2c66affSColin Finck 
1066*c2c66affSColin Finck 	do {
1067*c2c66affSColin Finck 		*--p = dtab[modlbys(val, (unsigned)10)];
1068*c2c66affSColin Finck 		val = divlbys(val, (unsigned)10);
1069*c2c66affSColin Finck 	} while (val > 0);
1070*c2c66affSColin Finck 
1071*c2c66affSColin Finck 	fa->bufp = p;
1072*c2c66affSColin Finck }
1073*c2c66affSColin Finck 
1074*c2c66affSColin Finck /*
1075*c2c66affSColin Finck  * We may need to use division here too (PDP-11, non two's complement ...)
1076*c2c66affSColin Finck  */
1077*c2c66affSColin Finck LOCAL void
pronum(val,fa)1078*c2c66affSColin Finck pronum(val, fa)
1079*c2c66affSColin Finck 	register Ulong val;
1080*c2c66affSColin Finck 	f_args *fa;
1081*c2c66affSColin Finck {
1082*c2c66affSColin Finck 	register char *p = fa->bufp;
1083*c2c66affSColin Finck 
1084*c2c66affSColin Finck 	do {
1085*c2c66affSColin Finck 		*--p = dtab[val & 7];
1086*c2c66affSColin Finck 		val >>= 3;
1087*c2c66affSColin Finck 	} while (val > 0);
1088*c2c66affSColin Finck 
1089*c2c66affSColin Finck 	fa->bufp = p;
1090*c2c66affSColin Finck }
1091*c2c66affSColin Finck 
1092*c2c66affSColin Finck LOCAL void
prxnum(val,fa)1093*c2c66affSColin Finck prxnum(val, fa)
1094*c2c66affSColin Finck 	register Ulong val;
1095*c2c66affSColin Finck 	f_args *fa;
1096*c2c66affSColin Finck {
1097*c2c66affSColin Finck 	register char *p = fa->bufp;
1098*c2c66affSColin Finck 
1099*c2c66affSColin Finck 	do {
1100*c2c66affSColin Finck 		*--p = dtab[val & 15];
1101*c2c66affSColin Finck 		val >>= 4;
1102*c2c66affSColin Finck 	} while (val > 0);
1103*c2c66affSColin Finck 
1104*c2c66affSColin Finck 	fa->bufp = p;
1105*c2c66affSColin Finck }
1106*c2c66affSColin Finck 
1107*c2c66affSColin Finck LOCAL void
prXnum(val,fa)1108*c2c66affSColin Finck prXnum(val, fa)
1109*c2c66affSColin Finck 	register Ulong val;
1110*c2c66affSColin Finck 	f_args *fa;
1111*c2c66affSColin Finck {
1112*c2c66affSColin Finck 	register char *p = fa->bufp;
1113*c2c66affSColin Finck 
1114*c2c66affSColin Finck 	do {
1115*c2c66affSColin Finck 		*--p = udtab[val & 15];
1116*c2c66affSColin Finck 		val >>= 4;
1117*c2c66affSColin Finck 	} while (val > 0);
1118*c2c66affSColin Finck 
1119*c2c66affSColin Finck 	fa->bufp = p;
1120*c2c66affSColin Finck }
1121*c2c66affSColin Finck 
1122*c2c66affSColin Finck #ifdef	USE_LONGLONG
1123*c2c66affSColin Finck LOCAL void
prlnum(val,base,fa)1124*c2c66affSColin Finck prlnum(val, base, fa)
1125*c2c66affSColin Finck 	register Ullong val;
1126*c2c66affSColin Finck 	register unsigned base;
1127*c2c66affSColin Finck 	f_args *fa;
1128*c2c66affSColin Finck {
1129*c2c66affSColin Finck 	register char *p = fa->bufp;
1130*c2c66affSColin Finck 
1131*c2c66affSColin Finck 	do {
1132*c2c66affSColin Finck 		*--p = dtab[modlbys(val, base)];
1133*c2c66affSColin Finck 		val = divlbys(val, base);
1134*c2c66affSColin Finck 	} while (val > 0);
1135*c2c66affSColin Finck 
1136*c2c66affSColin Finck 	fa->bufp = p;
1137*c2c66affSColin Finck }
1138*c2c66affSColin Finck 
1139*c2c66affSColin Finck LOCAL void
prldnum(val,fa)1140*c2c66affSColin Finck prldnum(val, fa)
1141*c2c66affSColin Finck 	register Ullong val;
1142*c2c66affSColin Finck 	f_args *fa;
1143*c2c66affSColin Finck {
1144*c2c66affSColin Finck 	register char *p = fa->bufp;
1145*c2c66affSColin Finck 
1146*c2c66affSColin Finck 	do {
1147*c2c66affSColin Finck 		*--p = dtab[val % (unsigned)10];
1148*c2c66affSColin Finck 		val = val / (unsigned)10;
1149*c2c66affSColin Finck 	} while (val > 0);
1150*c2c66affSColin Finck 
1151*c2c66affSColin Finck 	fa->bufp = p;
1152*c2c66affSColin Finck }
1153*c2c66affSColin Finck 
1154*c2c66affSColin Finck LOCAL void
prlonum(val,fa)1155*c2c66affSColin Finck prlonum(val, fa)
1156*c2c66affSColin Finck 	register Ullong val;
1157*c2c66affSColin Finck 	f_args *fa;
1158*c2c66affSColin Finck {
1159*c2c66affSColin Finck 	register char *p = fa->bufp;
1160*c2c66affSColin Finck 
1161*c2c66affSColin Finck 	do {
1162*c2c66affSColin Finck 		*--p = dtab[val & 7];
1163*c2c66affSColin Finck 		val >>= 3;
1164*c2c66affSColin Finck 	} while (val > 0);
1165*c2c66affSColin Finck 
1166*c2c66affSColin Finck 	fa->bufp = p;
1167*c2c66affSColin Finck }
1168*c2c66affSColin Finck 
1169*c2c66affSColin Finck LOCAL void
prlxnum(val,fa)1170*c2c66affSColin Finck prlxnum(val, fa)
1171*c2c66affSColin Finck 	register Ullong val;
1172*c2c66affSColin Finck 	f_args *fa;
1173*c2c66affSColin Finck {
1174*c2c66affSColin Finck 	register char *p = fa->bufp;
1175*c2c66affSColin Finck 
1176*c2c66affSColin Finck 	do {
1177*c2c66affSColin Finck 		*--p = dtab[val & 15];
1178*c2c66affSColin Finck 		val >>= 4;
1179*c2c66affSColin Finck 	} while (val > 0);
1180*c2c66affSColin Finck 
1181*c2c66affSColin Finck 	fa->bufp = p;
1182*c2c66affSColin Finck }
1183*c2c66affSColin Finck 
1184*c2c66affSColin Finck LOCAL void
prlXnum(val,fa)1185*c2c66affSColin Finck prlXnum(val, fa)
1186*c2c66affSColin Finck 	register Ullong val;
1187*c2c66affSColin Finck 	f_args *fa;
1188*c2c66affSColin Finck {
1189*c2c66affSColin Finck 	register char *p = fa->bufp;
1190*c2c66affSColin Finck 
1191*c2c66affSColin Finck 	do {
1192*c2c66affSColin Finck 		*--p = udtab[val & 15];
1193*c2c66affSColin Finck 		val >>= 4;
1194*c2c66affSColin Finck 	} while (val > 0);
1195*c2c66affSColin Finck 
1196*c2c66affSColin Finck 	fa->bufp = p;
1197*c2c66affSColin Finck }
1198*c2c66affSColin Finck 
1199*c2c66affSColin Finck #endif
1200*c2c66affSColin Finck 
1201*c2c66affSColin Finck /*
1202*c2c66affSColin Finck  * Final buffer print out routine.
1203*c2c66affSColin Finck  */
1204*c2c66affSColin Finck LOCAL int
prbuf(s,fa)1205*c2c66affSColin Finck prbuf(s, fa)
1206*c2c66affSColin Finck 	register const char *s;
1207*c2c66affSColin Finck 	f_args *fa;
1208*c2c66affSColin Finck {
1209*c2c66affSColin Finck 	register int diff;
1210*c2c66affSColin Finck 	register int rfillc;
1211*c2c66affSColin Finck 	register void *arg				= fa->farg;
1212*c2c66affSColin Finck #ifdef	FORMAT_FUNC_PARM
1213*c2c66affSColin Finck 	register void (*fun) __PR((char, void *))	= fa->outf;
1214*c2c66affSColin Finck #endif
1215*c2c66affSColin Finck 	register int count;
1216*c2c66affSColin Finck 	register int lzero = 0;
1217*c2c66affSColin Finck 
1218*c2c66affSColin Finck 	count = strlen(s);
1219*c2c66affSColin Finck 
1220*c2c66affSColin Finck 	/*
1221*c2c66affSColin Finck 	 * lzero becomes the number of left fill chars needed to reach signific
1222*c2c66affSColin Finck 	 */
1223*c2c66affSColin Finck 	if (fa->lzero < 0 && count < fa->signific)
1224*c2c66affSColin Finck 		lzero = fa->signific - count;
1225*c2c66affSColin Finck 	count += lzero + fa->prefixlen;
1226*c2c66affSColin Finck 	diff = fa->fldwidth - count;
1227*c2c66affSColin Finck 	if (diff > 0)
1228*c2c66affSColin Finck 		count += diff;
1229*c2c66affSColin Finck 
1230*c2c66affSColin Finck 	if (fa->prefixlen && fa->fillc != ' ') {
1231*c2c66affSColin Finck 		while (*fa->prefix != '\0')
1232*c2c66affSColin Finck 			ofun(*fa->prefix++, arg);
1233*c2c66affSColin Finck 	}
1234*c2c66affSColin Finck 	if (!fa->minusflag) {
1235*c2c66affSColin Finck 		rfillc = fa->fillc;
1236*c2c66affSColin Finck 		while (--diff >= 0)
1237*c2c66affSColin Finck 			ofun(rfillc, arg);
1238*c2c66affSColin Finck 	}
1239*c2c66affSColin Finck 	if (fa->prefixlen && fa->fillc == ' ') {
1240*c2c66affSColin Finck 		while (*fa->prefix != '\0')
1241*c2c66affSColin Finck 			ofun(*fa->prefix++, arg);
1242*c2c66affSColin Finck 	}
1243*c2c66affSColin Finck 	if (lzero > 0) {
1244*c2c66affSColin Finck 		rfillc = '0';
1245*c2c66affSColin Finck 		while (--lzero >= 0)
1246*c2c66affSColin Finck 			ofun(rfillc, arg);
1247*c2c66affSColin Finck 	}
1248*c2c66affSColin Finck 	while (*s != '\0')
1249*c2c66affSColin Finck 		ofun(*s++, arg);
1250*c2c66affSColin Finck 	if (fa->minusflag) {
1251*c2c66affSColin Finck 		rfillc = ' ';
1252*c2c66affSColin Finck 		while (--diff >= 0)
1253*c2c66affSColin Finck 			ofun(rfillc, arg);
1254*c2c66affSColin Finck 	}
1255*c2c66affSColin Finck 	return (count);
1256*c2c66affSColin Finck }
1257*c2c66affSColin Finck 
1258*c2c66affSColin Finck /*
1259*c2c66affSColin Finck  * Print out one char, allowing prc('\0')
1260*c2c66affSColin Finck  * Similar to prbuf()
1261*c2c66affSColin Finck  */
1262*c2c66affSColin Finck #ifdef	PROTOTYPES
1263*c2c66affSColin Finck 
1264*c2c66affSColin Finck LOCAL int
prc(char c,f_args * fa)1265*c2c66affSColin Finck prc(char c, f_args *fa)
1266*c2c66affSColin Finck 
1267*c2c66affSColin Finck #else
1268*c2c66affSColin Finck 
1269*c2c66affSColin Finck LOCAL int
1270*c2c66affSColin Finck prc(c, fa)
1271*c2c66affSColin Finck 	char	c;
1272*c2c66affSColin Finck 	f_args *fa;
1273*c2c66affSColin Finck #endif
1274*c2c66affSColin Finck {
1275*c2c66affSColin Finck 	register int diff;
1276*c2c66affSColin Finck 	register int rfillc;
1277*c2c66affSColin Finck 	register void *arg				= fa->farg;
1278*c2c66affSColin Finck #ifdef	FORMAT_FUNC_PARM
1279*c2c66affSColin Finck 	register void (*fun) __PR((char, void *))	= fa->outf;
1280*c2c66affSColin Finck #endif
1281*c2c66affSColin Finck 	register int count;
1282*c2c66affSColin Finck 
1283*c2c66affSColin Finck 	count = 1;
1284*c2c66affSColin Finck 	diff = fa->fldwidth - 1;
1285*c2c66affSColin Finck 	if (diff > 0)
1286*c2c66affSColin Finck 		count += diff;
1287*c2c66affSColin Finck 
1288*c2c66affSColin Finck 	if (!fa->minusflag) {
1289*c2c66affSColin Finck 		rfillc = fa->fillc;
1290*c2c66affSColin Finck 		while (--diff >= 0)
1291*c2c66affSColin Finck 			ofun(rfillc, arg);
1292*c2c66affSColin Finck 	}
1293*c2c66affSColin Finck 	ofun(c, arg);
1294*c2c66affSColin Finck 	if (fa->minusflag) {
1295*c2c66affSColin Finck 		rfillc = ' ';
1296*c2c66affSColin Finck 		while (--diff >= 0)
1297*c2c66affSColin Finck 			ofun(rfillc, arg);
1298*c2c66affSColin Finck 	}
1299*c2c66affSColin Finck 	return (count);
1300*c2c66affSColin Finck }
1301*c2c66affSColin Finck 
1302*c2c66affSColin Finck /*
1303*c2c66affSColin Finck  * String output routine.
1304*c2c66affSColin Finck  * If fa->signific is >= 0, it uses only fa->signific chars.
1305*c2c66affSColin Finck  * If fa->signific is 0, print no characters.
1306*c2c66affSColin Finck  */
1307*c2c66affSColin Finck LOCAL int
prstring(s,fa)1308*c2c66affSColin Finck prstring(s, fa)
1309*c2c66affSColin Finck 	register const char	*s;
1310*c2c66affSColin Finck 	f_args *fa;
1311*c2c66affSColin Finck {
1312*c2c66affSColin Finck 	register char	*bp;
1313*c2c66affSColin Finck 	register int	signific;
1314*c2c66affSColin Finck 
1315*c2c66affSColin Finck 	if (s == NULL)
1316*c2c66affSColin Finck 		return (prbuf("(NULL POINTER)", fa));
1317*c2c66affSColin Finck 
1318*c2c66affSColin Finck 	if (fa->signific < 0)
1319*c2c66affSColin Finck 		return (prbuf(s, fa));
1320*c2c66affSColin Finck 
1321*c2c66affSColin Finck 	bp = fa->buf;
1322*c2c66affSColin Finck 	signific = fa->signific;
1323*c2c66affSColin Finck 
1324*c2c66affSColin Finck 	while (--signific >= 0 && *s != '\0')
1325*c2c66affSColin Finck 		*bp++ = *s++;
1326*c2c66affSColin Finck 	*bp = '\0';
1327*c2c66affSColin Finck 
1328*c2c66affSColin Finck 	return (prbuf(fa->buf, fa));
1329*c2c66affSColin Finck }
1330*c2c66affSColin Finck 
1331*c2c66affSColin Finck #ifdef	DEBUG
1332*c2c66affSColin Finck LOCAL void
dbg_print(fmt,a,b,c,d,e,f,g,h,i)1333*c2c66affSColin Finck dbg_print(fmt, a, b, c, d, e, f, g, h, i)
1334*c2c66affSColin Finck char *fmt;
1335*c2c66affSColin Finck {
1336*c2c66affSColin Finck 	char	ff[1024];
1337*c2c66affSColin Finck 
1338*c2c66affSColin Finck 	sprintf(ff, fmt, a, b, c, d, e, f, g, h, i);
1339*c2c66affSColin Finck 	write(STDERR_FILENO, ff, strlen(ff));
1340*c2c66affSColin Finck }
1341*c2c66affSColin Finck #endif
1342*c2c66affSColin Finck 
1343*c2c66affSColin Finck #ifdef	USE_NL_ARGS
1344*c2c66affSColin Finck #ifdef	FORMAT_IMPL
1345*c2c66affSColin Finck /*
1346*c2c66affSColin Finck  * The following code is shared between format() and fprformat().
1347*c2c66affSColin Finck  */
1348*c2c66affSColin Finck 
1349*c2c66affSColin Finck /*
1350*c2c66affSColin Finck  * Format argument types.
1351*c2c66affSColin Finck  * As "char" and "short" type arguments are fetched as "int"
1352*c2c66affSColin Finck  * we start with size "int" and ignore the 'h' modifier when
1353*c2c66affSColin Finck  * parsing sizes.
1354*c2c66affSColin Finck  */
1355*c2c66affSColin Finck #define	AT_NONE			0
1356*c2c66affSColin Finck #define	AT_INT			1
1357*c2c66affSColin Finck #define	AT_LONG			2
1358*c2c66affSColin Finck #define	AT_LONG_LONG		3
1359*c2c66affSColin Finck #define	AT_DOUBLE		4
1360*c2c66affSColin Finck #define	AT_LONG_DOUBLE		5
1361*c2c66affSColin Finck #define	AT_VOID_PTR		6
1362*c2c66affSColin Finck #define	AT_CHAR_PTR		7
1363*c2c66affSColin Finck #define	AT_SHORT_PTR		8
1364*c2c66affSColin Finck #define	AT_INT_PTR		9
1365*c2c66affSColin Finck #define	AT_LONG_PTR		10
1366*c2c66affSColin Finck #define	AT_LONG_LONG_PTR	11
1367*c2c66affSColin Finck #define	AT_R_FMT		12
1368*c2c66affSColin Finck #define	AT_R_VA_LIST		13
1369*c2c66affSColin Finck #define	AT_BOUNDS		14
1370*c2c66affSColin Finck 
1371*c2c66affSColin Finck #define	AF_NONE			0
1372*c2c66affSColin Finck #define	AF_LONG			1
1373*c2c66affSColin Finck #define	AF_LONG_LONG		2
1374*c2c66affSColin Finck #define	AF_LONG_DOUBLE		4
1375*c2c66affSColin Finck #define	AF_STAR			8
1376*c2c66affSColin Finck 
1377*c2c66affSColin Finck static	const char	skips[] = "+- #'.$h1234567890";
1378*c2c66affSColin Finck static	const char	*digits = &skips[8];
1379*c2c66affSColin Finck 
1380*c2c66affSColin Finck /*
1381*c2c66affSColin Finck  * Parse the format string and store the first FMT_ARGMAX args in the arglist
1382*c2c66affSColin Finck  * parameter.
1383*c2c66affSColin Finck  *
1384*c2c66affSColin Finck  * This is done in two stages:
1385*c2c66affSColin Finck  *	1	parse the format string and store the types in argtypes[].
1386*c2c66affSColin Finck  *	2	use the type list in argtypes[], fetch the args in order and
1387*c2c66affSColin Finck  *		store the related va_list state in arglist[]
1388*c2c66affSColin Finck  */
1389*c2c66affSColin Finck EXPORT void
_fmtarglist(fmt,fargs,arglist)1390*c2c66affSColin Finck _fmtarglist(fmt, fargs, arglist)
1391*c2c66affSColin Finck 	const char	*fmt;
1392*c2c66affSColin Finck 	va_lists_t	fargs;
1393*c2c66affSColin Finck 	va_lists_t	arglist[];
1394*c2c66affSColin Finck {
1395*c2c66affSColin Finck 	int	i;
1396*c2c66affSColin Finck 	int	argindex;
1397*c2c66affSColin Finck 	int	maxindex;
1398*c2c66affSColin Finck 	int	thistype;
1399*c2c66affSColin Finck 	int	thisflag;
1400*c2c66affSColin Finck 	int	argtypes[FMT_ARGMAX+1];
1401*c2c66affSColin Finck 
1402*c2c66affSColin Finck 	for (i = 0; i < FMT_ARGMAX; i++)
1403*c2c66affSColin Finck 		argtypes[i] = AT_NONE;
1404*c2c66affSColin Finck 
1405*c2c66affSColin Finck 	maxindex = -1;
1406*c2c66affSColin Finck 	argindex = 0;
1407*c2c66affSColin Finck 	while ((fmt = strchr(fmt, '%')) != NULL) {
1408*c2c66affSColin Finck 		fmt++;
1409*c2c66affSColin Finck 		i = strspn(fmt, digits);
1410*c2c66affSColin Finck 		if (fmt[i] == '$') {
1411*c2c66affSColin Finck 			int	c;
1412*c2c66affSColin Finck 
1413*c2c66affSColin Finck 			argindex = *fmt++ - '0';
1414*c2c66affSColin Finck 			while (c = *fmt, is_dig(c)) {
1415*c2c66affSColin Finck 				argindex *= 10;
1416*c2c66affSColin Finck 				argindex += c - '0';
1417*c2c66affSColin Finck 				fmt++;
1418*c2c66affSColin Finck 			}
1419*c2c66affSColin Finck 			argindex -= 1;
1420*c2c66affSColin Finck 		}
1421*c2c66affSColin Finck 		thistype = AT_NONE;
1422*c2c66affSColin Finck 		thisflag = AF_NONE;
1423*c2c66affSColin Finck 	newarg:
1424*c2c66affSColin Finck 		fmt += strspn(fmt, skips);
1425*c2c66affSColin Finck 		switch (*fmt++) {
1426*c2c66affSColin Finck 
1427*c2c66affSColin Finck 		case '%':		/* %% format no arg */
1428*c2c66affSColin Finck 			continue;
1429*c2c66affSColin Finck 
1430*c2c66affSColin Finck 		case 'l':
1431*c2c66affSColin Finck 			if (thisflag & AF_LONG) {
1432*c2c66affSColin Finck 				thisflag |= AF_LONG_LONG;
1433*c2c66affSColin Finck 			} else {
1434*c2c66affSColin Finck 				thisflag |= AF_LONG;
1435*c2c66affSColin Finck 			}
1436*c2c66affSColin Finck 			goto newarg;
1437*c2c66affSColin Finck 		case 'j':		/* intmax_t for now is long long */
1438*c2c66affSColin Finck 			thisflag |= AF_LONG_LONG;
1439*c2c66affSColin Finck 			goto newarg;
1440*c2c66affSColin Finck 		case 'z':		/* size_t */
1441*c2c66affSColin Finck #if	SIZEOF_SIZE_T == SIZEOF_INT
1442*c2c66affSColin Finck 			if (thistype == AT_NONE)
1443*c2c66affSColin Finck 				thistype = AT_INT;
1444*c2c66affSColin Finck #else
1445*c2c66affSColin Finck #if	SIZEOF_SIZE_T == SIZEOF_LONG_INT
1446*c2c66affSColin Finck 			if (thistype == AT_NONE)
1447*c2c66affSColin Finck 				thistype = AT_LONG;
1448*c2c66affSColin Finck #else
1449*c2c66affSColin Finck #if	SIZEOF_SIZE_T == SIZEOF_LLONG
1450*c2c66affSColin Finck 			if (thistype == AT_NONE)
1451*c2c66affSColin Finck 				thistype = AT_LONG_LONG;
1452*c2c66affSColin Finck #else
1453*c2c66affSColin Finck error sizeof (size_t) is unknown
1454*c2c66affSColin Finck #endif
1455*c2c66affSColin Finck #endif
1456*c2c66affSColin Finck #endif
1457*c2c66affSColin Finck 			goto newarg;
1458*c2c66affSColin Finck 		case 't':		/* ptrdiff_t */
1459*c2c66affSColin Finck #if	SIZEOF_PTRDIFF_T == SIZEOF_INT
1460*c2c66affSColin Finck 			if (thistype == AT_NONE)
1461*c2c66affSColin Finck 				thistype = AT_INT;
1462*c2c66affSColin Finck #else
1463*c2c66affSColin Finck #if	SIZEOF_PTRDIFF_T == SIZEOF_LONG_INT
1464*c2c66affSColin Finck 			if (thistype == AT_NONE)
1465*c2c66affSColin Finck 				thistype = AT_LONG;
1466*c2c66affSColin Finck #else
1467*c2c66affSColin Finck #if	SIZEOF_PTRDIFF_T == SIZEOF_LLONG
1468*c2c66affSColin Finck 			if (thistype == AT_NONE)
1469*c2c66affSColin Finck 				thistype = AT_LONG_LONG;
1470*c2c66affSColin Finck #else
1471*c2c66affSColin Finck error sizeof (ptrdiff_t) is unknown
1472*c2c66affSColin Finck #endif
1473*c2c66affSColin Finck #endif
1474*c2c66affSColin Finck #endif
1475*c2c66affSColin Finck 			goto newarg;
1476*c2c66affSColin Finck #ifndef	NO_UCSIL
1477*c2c66affSColin Finck 			/*
1478*c2c66affSColin Finck 			 * Enhancements to K&R and ANSI:
1479*c2c66affSColin Finck 			 *
1480*c2c66affSColin Finck 			 * got a type specifyer
1481*c2c66affSColin Finck 			 *
1482*c2c66affSColin Finck 			 * XXX 'S' in C99 is %ls, 'S' should become 'H'
1483*c2c66affSColin Finck 			 */
1484*c2c66affSColin Finck 		case 'U':
1485*c2c66affSColin Finck 			if (!strchr("CSILZODX", *fmt)) {
1486*c2c66affSColin Finck 				/*
1487*c2c66affSColin Finck 				 * Got only 'U'nsigned specifyer,
1488*c2c66affSColin Finck 				 * use default type and mode.
1489*c2c66affSColin Finck 				 */
1490*c2c66affSColin Finck 				thistype = AT_INT;
1491*c2c66affSColin Finck 				break;
1492*c2c66affSColin Finck 			}
1493*c2c66affSColin Finck 			if (!strchr("CSIL", *fmt)) {
1494*c2c66affSColin Finck 				/*
1495*c2c66affSColin Finck 				 * Got 'U' and ZODX.
1496*c2c66affSColin Finck 				 * no type, use default
1497*c2c66affSColin Finck 				 */
1498*c2c66affSColin Finck 				thistype = AT_INT;
1499*c2c66affSColin Finck 				fmt++;	/* Skip ZODX */
1500*c2c66affSColin Finck 				break;
1501*c2c66affSColin Finck 			}
1502*c2c66affSColin Finck 			fmt++;		/* Unsigned, skip 'U', get CSIL */
1503*c2c66affSColin Finck 			/* FALLTHRU */
1504*c2c66affSColin Finck 		case 'C':
1505*c2c66affSColin Finck 		case 'S':
1506*c2c66affSColin Finck 		case 'I':
1507*c2c66affSColin Finck 		case 'L':
1508*c2c66affSColin Finck 			fmt--;		/* Undo fmt++ from switch() */
1509*c2c66affSColin Finck 			{
1510*c2c66affSColin Finck 				/*
1511*c2c66affSColin Finck 				 * got CSIL type
1512*c2c66affSColin Finck 				 */
1513*c2c66affSColin Finck 				int	type = *fmt++;	/* Undo above fmt-- */
1514*c2c66affSColin Finck 				int	mode = *fmt;
1515*c2c66affSColin Finck 				if (!strchr("ZODX", mode)) {
1516*c2c66affSColin Finck 					/*
1517*c2c66affSColin Finck 					 * Check long double "Le", "Lf" or "Lg"
1518*c2c66affSColin Finck 					 */
1519*c2c66affSColin Finck 					if (type == 'L' &&
1520*c2c66affSColin Finck 					    (mode == 'e' ||
1521*c2c66affSColin Finck 					    mode == 'f' ||
1522*c2c66affSColin Finck 					    mode == 'g')) {
1523*c2c66affSColin Finck 						thisflag |= AF_LONG_DOUBLE;
1524*c2c66affSColin Finck 						goto newarg;
1525*c2c66affSColin Finck 					}
1526*c2c66affSColin Finck 				} else {
1527*c2c66affSColin Finck 					fmt++;	/* Skip ZODX */
1528*c2c66affSColin Finck 				}
1529*c2c66affSColin Finck 				if (type == 'L')
1530*c2c66affSColin Finck 					thistype = AT_LONG;
1531*c2c66affSColin Finck 				else
1532*c2c66affSColin Finck 					thistype = AT_INT;
1533*c2c66affSColin Finck 			}
1534*c2c66affSColin Finck 			break;
1535*c2c66affSColin Finck #else
1536*c2c66affSColin Finck 		case 'L':
1537*c2c66affSColin Finck 			thisflag |= AF_LONG_DOUBLE;
1538*c2c66affSColin Finck 			goto newarg;
1539*c2c66affSColin Finck #endif
1540*c2c66affSColin Finck 
1541*c2c66affSColin Finck 		case 'e':
1542*c2c66affSColin Finck 		case 'E':
1543*c2c66affSColin Finck 		case 'f':
1544*c2c66affSColin Finck 		case 'F':
1545*c2c66affSColin Finck 		case 'g':
1546*c2c66affSColin Finck 		case 'G':
1547*c2c66affSColin Finck 			if (thisflag & AF_LONG_DOUBLE)
1548*c2c66affSColin Finck 				thistype = AT_LONG_DOUBLE;
1549*c2c66affSColin Finck 			else
1550*c2c66affSColin Finck 				thistype = AT_DOUBLE;
1551*c2c66affSColin Finck 			break;
1552*c2c66affSColin Finck 
1553*c2c66affSColin Finck 		case 'p':
1554*c2c66affSColin Finck 			thistype = AT_VOID_PTR;
1555*c2c66affSColin Finck 			break;
1556*c2c66affSColin Finck 		case 's':
1557*c2c66affSColin Finck 			thistype = AT_CHAR_PTR;
1558*c2c66affSColin Finck 			break;
1559*c2c66affSColin Finck 		case 'b':
1560*c2c66affSColin Finck 			thistype = AT_BOUNDS;
1561*c2c66affSColin Finck 			break;
1562*c2c66affSColin Finck 		case 'n':
1563*c2c66affSColin Finck 			if (thisflag & AF_LONG_LONG)
1564*c2c66affSColin Finck 				thistype = AT_LONG_LONG_PTR;
1565*c2c66affSColin Finck 			else if (thistype & AF_LONG)
1566*c2c66affSColin Finck 				thistype = AT_LONG_PTR;
1567*c2c66affSColin Finck 			else
1568*c2c66affSColin Finck 				thistype = AT_INT_PTR;
1569*c2c66affSColin Finck 			break;
1570*c2c66affSColin Finck 		case 'r':
1571*c2c66affSColin Finck 			thistype = AT_R_FMT;
1572*c2c66affSColin Finck 			break;
1573*c2c66affSColin Finck 		default:
1574*c2c66affSColin Finck 			if (thistype == AT_NONE) {
1575*c2c66affSColin Finck 				if (thisflag & AF_LONG_LONG)
1576*c2c66affSColin Finck 					thistype = AT_LONG_LONG;
1577*c2c66affSColin Finck 				else if (thistype & AF_LONG)
1578*c2c66affSColin Finck 					thistype = AT_LONG;
1579*c2c66affSColin Finck 				else
1580*c2c66affSColin Finck 					thistype = AT_INT;
1581*c2c66affSColin Finck 			}
1582*c2c66affSColin Finck 			break;
1583*c2c66affSColin Finck 
1584*c2c66affSColin Finck 		case '*':
1585*c2c66affSColin Finck 			if (is_dig(*fmt)) {
1586*c2c66affSColin Finck 				int	c;
1587*c2c66affSColin Finck 				int	starindex;
1588*c2c66affSColin Finck 
1589*c2c66affSColin Finck 				starindex = *fmt++ - '0';
1590*c2c66affSColin Finck 				while (c = *fmt, is_dig(c)) {
1591*c2c66affSColin Finck 					starindex *= 10;
1592*c2c66affSColin Finck 					starindex += c - '0';
1593*c2c66affSColin Finck 					fmt++;
1594*c2c66affSColin Finck 				}
1595*c2c66affSColin Finck 				starindex -= 1;
1596*c2c66affSColin Finck 				if (starindex >= 0 && starindex < FMT_ARGMAX) {
1597*c2c66affSColin Finck 					argtypes[starindex] = AT_INT;
1598*c2c66affSColin Finck 					if (starindex > maxindex)
1599*c2c66affSColin Finck 						maxindex = starindex;
1600*c2c66affSColin Finck 				}
1601*c2c66affSColin Finck 				goto newarg;
1602*c2c66affSColin Finck 			}
1603*c2c66affSColin Finck 			thistype = AT_INT;
1604*c2c66affSColin Finck 			thisflag |= AF_STAR; /* Make sure to rescan for type */
1605*c2c66affSColin Finck 			break;
1606*c2c66affSColin Finck 		}
1607*c2c66affSColin Finck 		if (argindex >= 0 && argindex < FMT_ARGMAX) {
1608*c2c66affSColin Finck 			argtypes[argindex] = thistype;
1609*c2c66affSColin Finck 			if (thistype == AT_R_FMT)
1610*c2c66affSColin Finck 				argtypes[++argindex] = AT_R_VA_LIST;
1611*c2c66affSColin Finck 			else if (thistype == AT_BOUNDS)
1612*c2c66affSColin Finck 				argtypes[++argindex] = AT_INT;
1613*c2c66affSColin Finck 
1614*c2c66affSColin Finck 			if (argindex > maxindex)
1615*c2c66affSColin Finck 				maxindex = argindex;
1616*c2c66affSColin Finck 		}
1617*c2c66affSColin Finck 		++argindex;		/* Default to next arg in list */
1618*c2c66affSColin Finck 		if (thisflag & AF_STAR) { /* Found '*', continue for type */
1619*c2c66affSColin Finck 			thisflag &= ~AF_STAR;
1620*c2c66affSColin Finck 			goto newarg;
1621*c2c66affSColin Finck 		}
1622*c2c66affSColin Finck 	}
1623*c2c66affSColin Finck 
1624*c2c66affSColin Finck 	for (i = 0; i <= maxindex; i++) { /* Do not fetch more args than known */
1625*c2c66affSColin Finck 		arglist[i] = fargs;	/* Save state before fetching this */
1626*c2c66affSColin Finck 
1627*c2c66affSColin Finck 		switch (argtypes[i]) {
1628*c2c66affSColin Finck 
1629*c2c66affSColin Finck 		default:
1630*c2c66affSColin Finck 			/* FALLTHRU */
1631*c2c66affSColin Finck 		case AT_NONE:		/* This matches '*' args */
1632*c2c66affSColin Finck 			/* FALLTHRU */
1633*c2c66affSColin Finck 		case AT_INT:
1634*c2c66affSColin Finck 			(void) va_arg(fargs.ap, int);
1635*c2c66affSColin Finck 			break;
1636*c2c66affSColin Finck 		case AT_LONG:
1637*c2c66affSColin Finck 			(void) va_arg(fargs.ap, long);
1638*c2c66affSColin Finck 			break;
1639*c2c66affSColin Finck 		case AT_LONG_LONG:
1640*c2c66affSColin Finck 			(void) va_arg(fargs.ap, Llong);
1641*c2c66affSColin Finck 			break;
1642*c2c66affSColin Finck 		case AT_DOUBLE:
1643*c2c66affSColin Finck 			(void) va_arg(fargs.ap, double);
1644*c2c66affSColin Finck 			break;
1645*c2c66affSColin Finck 		case AT_LONG_DOUBLE:
1646*c2c66affSColin Finck #ifdef	HAVE_LONGDOUBLE
1647*c2c66affSColin Finck 			(void) va_arg(fargs.ap, long double);
1648*c2c66affSColin Finck #endif
1649*c2c66affSColin Finck 			break;
1650*c2c66affSColin Finck 		case AT_VOID_PTR:
1651*c2c66affSColin Finck 			(void) va_arg(fargs.ap, void *);
1652*c2c66affSColin Finck 			break;
1653*c2c66affSColin Finck 		case AT_CHAR_PTR:
1654*c2c66affSColin Finck 			(void) va_arg(fargs.ap, char *);
1655*c2c66affSColin Finck 			break;
1656*c2c66affSColin Finck 		case AT_SHORT_PTR:
1657*c2c66affSColin Finck 			(void) va_arg(fargs.ap, short *);
1658*c2c66affSColin Finck 			break;
1659*c2c66affSColin Finck 		case AT_INT_PTR:
1660*c2c66affSColin Finck 			(void) va_arg(fargs.ap, int *);
1661*c2c66affSColin Finck 			break;
1662*c2c66affSColin Finck 		case AT_LONG_PTR:
1663*c2c66affSColin Finck 			(void) va_arg(fargs.ap, long *);
1664*c2c66affSColin Finck 			break;
1665*c2c66affSColin Finck 		case AT_LONG_LONG_PTR:
1666*c2c66affSColin Finck 			(void) va_arg(fargs.ap, Llong *);
1667*c2c66affSColin Finck 			break;
1668*c2c66affSColin Finck 		case AT_R_FMT:
1669*c2c66affSColin Finck 			(void) va_arg(fargs.ap, char *);
1670*c2c66affSColin Finck 			arglist[++i] = fargs;
1671*c2c66affSColin Finck 			(void) __va_arg_list(fargs.ap);
1672*c2c66affSColin Finck 			break;
1673*c2c66affSColin Finck 		case AT_R_VA_LIST:
1674*c2c66affSColin Finck 			break;
1675*c2c66affSColin Finck 		case AT_BOUNDS:
1676*c2c66affSColin Finck 			(void) va_arg(fargs.ap, char *);
1677*c2c66affSColin Finck 			arglist[++i] = fargs;
1678*c2c66affSColin Finck 			(void) va_arg(fargs.ap, int);
1679*c2c66affSColin Finck 			break;
1680*c2c66affSColin Finck 		}
1681*c2c66affSColin Finck 	}
1682*c2c66affSColin Finck }
1683*c2c66affSColin Finck 
1684*c2c66affSColin Finck /*
1685*c2c66affSColin Finck  * In case that the format references an argument > FMT_ARGMAX, we use this
1686*c2c66affSColin Finck  * implementation. It is slow (n*n - where n is (argno - FMT_ARGMAX)).
1687*c2c66affSColin Finck  * Fortunately, it is most unlikely that there are more positional args than
1688*c2c66affSColin Finck  * the current FMT_ARGMAX definition of 30.
1689*c2c66affSColin Finck  */
1690*c2c66affSColin Finck EXPORT void
_fmtgetarg(fmt,num,fargs)1691*c2c66affSColin Finck _fmtgetarg(fmt, num, fargs)
1692*c2c66affSColin Finck 	const char	*fmt;
1693*c2c66affSColin Finck 	int		num;
1694*c2c66affSColin Finck 	va_lists_t	*fargs;
1695*c2c66affSColin Finck {
1696*c2c66affSColin Finck 	const char	*sfmt = fmt;
1697*c2c66affSColin Finck 	int		i;
1698*c2c66affSColin Finck 
1699*c2c66affSColin Finck 	/*
1700*c2c66affSColin Finck 	 * Hacky preliminary support for all int type args bejond FMT_ARGMAX.
1701*c2c66affSColin Finck 	 */
1702*c2c66affSColin Finck 	for (i = FMT_ARGMAX; i < num; i++)
1703*c2c66affSColin Finck 		(void) va_arg((*fargs).ap, int);
1704*c2c66affSColin Finck }
1705*c2c66affSColin Finck #endif	/* FORMAT_IMPL */
1706*c2c66affSColin Finck #endif	/* USE_NL_ARGS */
1707