xref: /optee_os/lib/libutils/ext/snprintk.c (revision fe3ccf2450fb11c10c334a0c22de79fe8d2591a5)
1*fe3ccf24SJerome Forissier /*
2*fe3ccf24SJerome Forissier  * Imported from NetBSD 5.1 with modifications to make it a vsnprintf(3)
3*fe3ccf24SJerome Forissier  * function
4*fe3ccf24SJerome Forissier  */
5*fe3ccf24SJerome Forissier 
6*fe3ccf24SJerome Forissier /*	$NetBSD: subr_prf.c,v 1.156 2014/08/15 11:05:35 apb Exp $	*/
7*fe3ccf24SJerome Forissier 
8*fe3ccf24SJerome Forissier /*-
9*fe3ccf24SJerome Forissier  * Copyright (c) 1986, 1988, 1991, 1993
10*fe3ccf24SJerome Forissier  *	The Regents of the University of California.  All rights reserved.
11*fe3ccf24SJerome Forissier  * (c) UNIX System Laboratories, Inc.
12*fe3ccf24SJerome Forissier  * All or some portions of this file are derived from material licensed
13*fe3ccf24SJerome Forissier  * to the University of California by American Telephone and Telegraph
14*fe3ccf24SJerome Forissier  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
15*fe3ccf24SJerome Forissier  * the permission of UNIX System Laboratories, Inc.
16*fe3ccf24SJerome Forissier  *
17*fe3ccf24SJerome Forissier  * Redistribution and use in source and binary forms, with or without
18*fe3ccf24SJerome Forissier  * modification, are permitted provided that the following conditions
19*fe3ccf24SJerome Forissier  * are met:
20*fe3ccf24SJerome Forissier  * 1. Redistributions of source code must retain the above copyright
21*fe3ccf24SJerome Forissier  *    notice, this list of conditions and the following disclaimer.
22*fe3ccf24SJerome Forissier  * 2. Redistributions in binary form must reproduce the above copyright
23*fe3ccf24SJerome Forissier  *    notice, this list of conditions and the following disclaimer in the
24*fe3ccf24SJerome Forissier  *    documentation and/or other materials provided with the distribution.
25*fe3ccf24SJerome Forissier  * 3. Neither the name of the University nor the names of its contributors
26*fe3ccf24SJerome Forissier  *    may be used to endorse or promote products derived from this software
27*fe3ccf24SJerome Forissier  *    without specific prior written permission.
28*fe3ccf24SJerome Forissier  *
29*fe3ccf24SJerome Forissier  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30*fe3ccf24SJerome Forissier  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31*fe3ccf24SJerome Forissier  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32*fe3ccf24SJerome Forissier  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33*fe3ccf24SJerome Forissier  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34*fe3ccf24SJerome Forissier  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35*fe3ccf24SJerome Forissier  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36*fe3ccf24SJerome Forissier  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37*fe3ccf24SJerome Forissier  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38*fe3ccf24SJerome Forissier  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39*fe3ccf24SJerome Forissier  * SUCH DAMAGE.
40*fe3ccf24SJerome Forissier  *
41*fe3ccf24SJerome Forissier  *	@(#)subr_prf.c	8.4 (Berkeley) 5/4/95
42*fe3ccf24SJerome Forissier  *
43*fe3ccf24SJerome Forissier  * Copyright (c) 2015 Linaro Limited
44*fe3ccf24SJerome Forissier  * All rights reserved.
45*fe3ccf24SJerome Forissier  *
46*fe3ccf24SJerome Forissier  * Redistribution and use in source and binary forms, with or without
47*fe3ccf24SJerome Forissier  * modification, are permitted provided that the following conditions are met:
48*fe3ccf24SJerome Forissier  *
49*fe3ccf24SJerome Forissier  * 1. Redistributions of source code must retain the above copyright notice,
50*fe3ccf24SJerome Forissier  * this list of conditions and the following disclaimer.
51*fe3ccf24SJerome Forissier  *
52*fe3ccf24SJerome Forissier  * 2. Redistributions in binary form must reproduce the above copyright notice,
53*fe3ccf24SJerome Forissier  * this list of conditions and the following disclaimer in the documentation
54*fe3ccf24SJerome Forissier  * and/or other materials provided with the distribution.
55*fe3ccf24SJerome Forissier  *
56*fe3ccf24SJerome Forissier  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
57*fe3ccf24SJerome Forissier  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58*fe3ccf24SJerome Forissier  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59*fe3ccf24SJerome Forissier  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
60*fe3ccf24SJerome Forissier  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
61*fe3ccf24SJerome Forissier  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
62*fe3ccf24SJerome Forissier  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
63*fe3ccf24SJerome Forissier  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
64*fe3ccf24SJerome Forissier  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
65*fe3ccf24SJerome Forissier  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66*fe3ccf24SJerome Forissier  * POSSIBILITY OF SUCH DAMAGE.
67*fe3ccf24SJerome Forissier  */
68*fe3ccf24SJerome Forissier #include <unistd.h>
69*fe3ccf24SJerome Forissier #include <stdint.h>
70*fe3ccf24SJerome Forissier #include <string.h>
71*fe3ccf24SJerome Forissier #include <stdarg.h>
72*fe3ccf24SJerome Forissier #include <printk.h>
73*fe3ccf24SJerome Forissier 
74*fe3ccf24SJerome Forissier /* flags for kprintf */
75*fe3ccf24SJerome Forissier #define TOCONS        0x0001	/* to the console */
76*fe3ccf24SJerome Forissier #define TOTTY        0x0002	/* to the process' tty */
77*fe3ccf24SJerome Forissier #define TOLOG        0x0004	/* to the kernel message buffer */
78*fe3ccf24SJerome Forissier #define TOBUFONLY    0x0008	/* to the buffer (only) [for snprintk] */
79*fe3ccf24SJerome Forissier #define TODDB        0x0010	/* to ddb console */
80*fe3ccf24SJerome Forissier #define NOLOCK        0x1000	/* don't acquire a tty lock */
81*fe3ccf24SJerome Forissier 
82*fe3ccf24SJerome Forissier /* max size buffer kprintf needs to print a UUID */
83*fe3ccf24SJerome Forissier #define KPRINTF_BUFSIZE        36
84*fe3ccf24SJerome Forissier 
85*fe3ccf24SJerome Forissier /*
86*fe3ccf24SJerome Forissier  * The following macro is used to remove const cast-away warnings
87*fe3ccf24SJerome Forissier  * from gcc -Wcast-qual; it should be used with caution because it
88*fe3ccf24SJerome Forissier  * can hide valid errors; in particular most valid uses are in
89*fe3ccf24SJerome Forissier  * situations where the API requires it, not to cast away string
90*fe3ccf24SJerome Forissier  * constants. We don't use *intptr_t on purpose here and we are
91*fe3ccf24SJerome Forissier  * explicit about unsigned long so that we don't have additional
92*fe3ccf24SJerome Forissier  * dependencies.
93*fe3ccf24SJerome Forissier  */
94*fe3ccf24SJerome Forissier #define __UNCONST(a)    ((void *)(unsigned long)(const void *)(a))
95*fe3ccf24SJerome Forissier 
96*fe3ccf24SJerome Forissier #define putchar(c, flags, tty) \
97*fe3ccf24SJerome Forissier 	do { (void)(c); (void)(flags); (void)(tty); } while(0)
98*fe3ccf24SJerome Forissier 
99*fe3ccf24SJerome Forissier static int kprintf(const char *fmt0, int oflags, void *vp, char *sbuf,
100*fe3ccf24SJerome Forissier 		   va_list ap, bool ext);
101*fe3ccf24SJerome Forissier 
102*fe3ccf24SJerome Forissier static const char hexdigits[] = "0123456789abcdef";
103*fe3ccf24SJerome Forissier static const char HEXDIGITS[] = "0123456789ABCDEF";
104*fe3ccf24SJerome Forissier 
105*fe3ccf24SJerome Forissier /*
106*fe3ccf24SJerome Forissier  * snprintk: print a message to a buffer. Same as snprintf but supports
107*fe3ccf24SJerome Forissier  * format extensions.
108*fe3ccf24SJerome Forissier  */
109*fe3ccf24SJerome Forissier int
110*fe3ccf24SJerome Forissier snprintk(char *bf, size_t size, const char *fmt, ...)
111*fe3ccf24SJerome Forissier {
112*fe3ccf24SJerome Forissier 	int retval;
113*fe3ccf24SJerome Forissier 	va_list ap;
114*fe3ccf24SJerome Forissier 
115*fe3ccf24SJerome Forissier 	va_start(ap, fmt);
116*fe3ccf24SJerome Forissier 	retval = vsnprintk(bf, size, fmt, ap);
117*fe3ccf24SJerome Forissier 	va_end(ap);
118*fe3ccf24SJerome Forissier 
119*fe3ccf24SJerome Forissier 	return retval;
120*fe3ccf24SJerome Forissier }
121*fe3ccf24SJerome Forissier 
122*fe3ccf24SJerome Forissier /*
123*fe3ccf24SJerome Forissier  * vsnprintk: print a message to a buffer [already have va_list]
124*fe3ccf24SJerome Forissier  * Same as vsnprintf but supports format extensions.
125*fe3ccf24SJerome Forissier  */
126*fe3ccf24SJerome Forissier int
127*fe3ccf24SJerome Forissier vsnprintk(char *bf, size_t size, const char *fmt, va_list ap)
128*fe3ccf24SJerome Forissier {
129*fe3ccf24SJerome Forissier 	return __vsnprintf(bf, size, fmt, ap, true);
130*fe3ccf24SJerome Forissier }
131*fe3ccf24SJerome Forissier 
132*fe3ccf24SJerome Forissier int
133*fe3ccf24SJerome Forissier __vsnprintf(char *bf, size_t size, const char *fmt, va_list ap,
134*fe3ccf24SJerome Forissier 	    bool ext)
135*fe3ccf24SJerome Forissier 
136*fe3ccf24SJerome Forissier {
137*fe3ccf24SJerome Forissier 	int retval;
138*fe3ccf24SJerome Forissier 	char *p;
139*fe3ccf24SJerome Forissier 
140*fe3ccf24SJerome Forissier 	p = bf + size;
141*fe3ccf24SJerome Forissier 	retval = kprintf(fmt, TOBUFONLY, &p, bf, ap, ext);
142*fe3ccf24SJerome Forissier 	if (bf && size > 0) {
143*fe3ccf24SJerome Forissier 		/* nul terminate */
144*fe3ccf24SJerome Forissier 		if (size <= (size_t)retval)
145*fe3ccf24SJerome Forissier 			bf[size - 1] = '\0';
146*fe3ccf24SJerome Forissier 		else
147*fe3ccf24SJerome Forissier 			bf[retval] = '\0';
148*fe3ccf24SJerome Forissier 	}
149*fe3ccf24SJerome Forissier 	return retval;
150*fe3ccf24SJerome Forissier }
151*fe3ccf24SJerome Forissier 
152*fe3ccf24SJerome Forissier /*
153*fe3ccf24SJerome Forissier  * kprintf: scaled down version of printf(3).
154*fe3ccf24SJerome Forissier  *
155*fe3ccf24SJerome Forissier  * this version based on vfprintf() from libc which was derived from
156*fe3ccf24SJerome Forissier  * software contributed to Berkeley by Chris Torek.
157*fe3ccf24SJerome Forissier  *
158*fe3ccf24SJerome Forissier  */
159*fe3ccf24SJerome Forissier 
160*fe3ccf24SJerome Forissier /*
161*fe3ccf24SJerome Forissier  * macros for converting digits to letters and vice versa
162*fe3ccf24SJerome Forissier  */
163*fe3ccf24SJerome Forissier #define	to_digit(c)	((c) - '0')
164*fe3ccf24SJerome Forissier #define is_digit(c)	((unsigned)to_digit(c) <= 9)
165*fe3ccf24SJerome Forissier #define	to_char(n)	((n) + '0')
166*fe3ccf24SJerome Forissier 
167*fe3ccf24SJerome Forissier /*
168*fe3ccf24SJerome Forissier  * flags used during conversion.
169*fe3ccf24SJerome Forissier  */
170*fe3ccf24SJerome Forissier #define	ALT		0x001		/* alternate form */
171*fe3ccf24SJerome Forissier #define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
172*fe3ccf24SJerome Forissier #define	LADJUST		0x004		/* left adjustment */
173*fe3ccf24SJerome Forissier #define	LONGDBL		0x008		/* long double; unimplemented */
174*fe3ccf24SJerome Forissier #define	LONGINT		0x010		/* long integer */
175*fe3ccf24SJerome Forissier #define	QUADINT		0x020		/* quad integer */
176*fe3ccf24SJerome Forissier #define	SHORTINT	0x040		/* short integer */
177*fe3ccf24SJerome Forissier #define	MAXINT		0x080		/* intmax_t */
178*fe3ccf24SJerome Forissier #define	PTRINT		0x100		/* intptr_t */
179*fe3ccf24SJerome Forissier #define	SIZEINT		0x200		/* size_t */
180*fe3ccf24SJerome Forissier #define	ZEROPAD		0x400		/* zero (as opposed to blank) pad */
181*fe3ccf24SJerome Forissier #define FPT		0x800		/* Floating point number */
182*fe3ccf24SJerome Forissier 
183*fe3ccf24SJerome Forissier 	/*
184*fe3ccf24SJerome Forissier 	 * To extend shorts properly, we need both signed and unsigned
185*fe3ccf24SJerome Forissier 	 * argument extraction methods.
186*fe3ccf24SJerome Forissier 	 */
187*fe3ccf24SJerome Forissier #define	SARG() \
188*fe3ccf24SJerome Forissier 	(flags&MAXINT ? va_arg(ap, intmax_t) : \
189*fe3ccf24SJerome Forissier 	    flags&PTRINT ? va_arg(ap, intptr_t) : \
190*fe3ccf24SJerome Forissier 	    flags&SIZEINT ? va_arg(ap, ssize_t) : /* XXX */ \
191*fe3ccf24SJerome Forissier 	    flags&QUADINT ? va_arg(ap, int64_t) : \
192*fe3ccf24SJerome Forissier 	    flags&LONGINT ? va_arg(ap, long) : \
193*fe3ccf24SJerome Forissier 	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
194*fe3ccf24SJerome Forissier 	    (long)va_arg(ap, int))
195*fe3ccf24SJerome Forissier #define	UARG() \
196*fe3ccf24SJerome Forissier 	(flags&MAXINT ? va_arg(ap, uintmax_t) : \
197*fe3ccf24SJerome Forissier 	    flags&PTRINT ? va_arg(ap, uintptr_t) : \
198*fe3ccf24SJerome Forissier 	    flags&SIZEINT ? va_arg(ap, size_t) : \
199*fe3ccf24SJerome Forissier 	    flags&QUADINT ? va_arg(ap, uint64_t) : \
200*fe3ccf24SJerome Forissier 	    flags&LONGINT ? va_arg(ap, unsigned long) : \
201*fe3ccf24SJerome Forissier 	    flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
202*fe3ccf24SJerome Forissier 	    (unsigned long)va_arg(ap, unsigned int))
203*fe3ccf24SJerome Forissier 
204*fe3ccf24SJerome Forissier #define KPRINTF_PUTCHAR(C) {						\
205*fe3ccf24SJerome Forissier 	if (oflags == TOBUFONLY) {					\
206*fe3ccf24SJerome Forissier 		if (sbuf && ((vp == NULL) || (sbuf < tailp))) 		\
207*fe3ccf24SJerome Forissier 			*sbuf++ = (C);					\
208*fe3ccf24SJerome Forissier 	} else {							\
209*fe3ccf24SJerome Forissier 		putchar((C), oflags, vp);				\
210*fe3ccf24SJerome Forissier 	}								\
211*fe3ccf24SJerome Forissier }
212*fe3ccf24SJerome Forissier 
213*fe3ccf24SJerome Forissier static int uuid2str(char *dst, size_t size, void *ptr)
214*fe3ccf24SJerome Forissier {
215*fe3ccf24SJerome Forissier 	struct {
216*fe3ccf24SJerome Forissier 		uint32_t lo;
217*fe3ccf24SJerome Forissier 		uint16_t mid;
218*fe3ccf24SJerome Forissier 		uint16_t hi_ver;
219*fe3ccf24SJerome Forissier 		uint8_t seq_n[8];
220*fe3ccf24SJerome Forissier 	} *uuid = ptr;
221*fe3ccf24SJerome Forissier 
222*fe3ccf24SJerome Forissier 	return snprintk(dst, size,
223*fe3ccf24SJerome Forissier 			"%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
224*fe3ccf24SJerome Forissier 			uuid->lo, uuid->mid, uuid->hi_ver,
225*fe3ccf24SJerome Forissier 			uuid->seq_n[0], uuid->seq_n[1],
226*fe3ccf24SJerome Forissier 			uuid->seq_n[2],	uuid->seq_n[3],
227*fe3ccf24SJerome Forissier 			uuid->seq_n[4],	uuid->seq_n[5],
228*fe3ccf24SJerome Forissier 			uuid->seq_n[6],	uuid->seq_n[7]);
229*fe3ccf24SJerome Forissier }
230*fe3ccf24SJerome Forissier 
231*fe3ccf24SJerome Forissier /*
232*fe3ccf24SJerome Forissier  * Guts of kernel printf.  Note, we already expect to be in a mutex!
233*fe3ccf24SJerome Forissier  */
234*fe3ccf24SJerome Forissier static int
235*fe3ccf24SJerome Forissier kprintf(const char *fmt0, int oflags, void *vp, char *sbuf, va_list ap,
236*fe3ccf24SJerome Forissier 	bool ext)
237*fe3ccf24SJerome Forissier {
238*fe3ccf24SJerome Forissier 	const char *fmt;	/* format string */
239*fe3ccf24SJerome Forissier 	int ch;			/* character from fmt */
240*fe3ccf24SJerome Forissier 	int n;			/* handy integer (short term usage) */
241*fe3ccf24SJerome Forissier 	char *cp;		/* handy char pointer (short term usage) */
242*fe3ccf24SJerome Forissier 	int flags;		/* flags as above */
243*fe3ccf24SJerome Forissier 	int ret;		/* return value accumulator */
244*fe3ccf24SJerome Forissier 	int width;		/* width from format (%8d), or 0 */
245*fe3ccf24SJerome Forissier 	int prec;		/* precision from format (%.3d), or -1 */
246*fe3ccf24SJerome Forissier 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
247*fe3ccf24SJerome Forissier 
248*fe3ccf24SJerome Forissier 	uint64_t _uquad;	/* integer arguments %[diouxX] */
249*fe3ccf24SJerome Forissier 	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
250*fe3ccf24SJerome Forissier 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
251*fe3ccf24SJerome Forissier 	int realsz;		/* field size expanded by dprec */
252*fe3ccf24SJerome Forissier 	int size;		/* size of converted field or string */
253*fe3ccf24SJerome Forissier 	const char *xdigs;	/* digits for [xX] conversion */
254*fe3ccf24SJerome Forissier 	char bf[KPRINTF_BUFSIZE]; /* space for %c, %[diouxX], possibly %pUl */
255*fe3ccf24SJerome Forissier 	char *tailp;		/* tail pointer for snprintk */
256*fe3ccf24SJerome Forissier 
257*fe3ccf24SJerome Forissier 	if (oflags == TOBUFONLY && (vp != NULL))
258*fe3ccf24SJerome Forissier 		tailp = *(char **)vp;
259*fe3ccf24SJerome Forissier 	else
260*fe3ccf24SJerome Forissier 		tailp = NULL;
261*fe3ccf24SJerome Forissier 
262*fe3ccf24SJerome Forissier 	cp = NULL;	/* XXX: shutup gcc */
263*fe3ccf24SJerome Forissier 	size = 0;	/* XXX: shutup gcc */
264*fe3ccf24SJerome Forissier 
265*fe3ccf24SJerome Forissier 	fmt = fmt0;
266*fe3ccf24SJerome Forissier 	ret = 0;
267*fe3ccf24SJerome Forissier 
268*fe3ccf24SJerome Forissier 	xdigs = NULL;		/* XXX: shut up gcc warning */
269*fe3ccf24SJerome Forissier 
270*fe3ccf24SJerome Forissier 	/*
271*fe3ccf24SJerome Forissier 	 * Scan the format for conversions (`%' character).
272*fe3ccf24SJerome Forissier 	 */
273*fe3ccf24SJerome Forissier 	for (;;) {
274*fe3ccf24SJerome Forissier 		for (; *fmt != '%' && *fmt; fmt++) {
275*fe3ccf24SJerome Forissier 			ret++;
276*fe3ccf24SJerome Forissier 			KPRINTF_PUTCHAR(*fmt);
277*fe3ccf24SJerome Forissier 		}
278*fe3ccf24SJerome Forissier 		if (*fmt == 0)
279*fe3ccf24SJerome Forissier 			goto done;
280*fe3ccf24SJerome Forissier 
281*fe3ccf24SJerome Forissier 		fmt++;		/* skip over '%' */
282*fe3ccf24SJerome Forissier 
283*fe3ccf24SJerome Forissier 		flags = 0;
284*fe3ccf24SJerome Forissier 		dprec = 0;
285*fe3ccf24SJerome Forissier 		width = 0;
286*fe3ccf24SJerome Forissier 		prec = -1;
287*fe3ccf24SJerome Forissier 		sign = '\0';
288*fe3ccf24SJerome Forissier 
289*fe3ccf24SJerome Forissier rflag:		ch = *fmt++;
290*fe3ccf24SJerome Forissier reswitch:	switch (ch) {
291*fe3ccf24SJerome Forissier 		case ' ':
292*fe3ccf24SJerome Forissier 			/*
293*fe3ccf24SJerome Forissier 			 * ``If the space and + flags both appear, the space
294*fe3ccf24SJerome Forissier 			 * flag will be ignored.''
295*fe3ccf24SJerome Forissier 			 *	-- ANSI X3J11
296*fe3ccf24SJerome Forissier 			 */
297*fe3ccf24SJerome Forissier 			if (!sign)
298*fe3ccf24SJerome Forissier 				sign = ' ';
299*fe3ccf24SJerome Forissier 			goto rflag;
300*fe3ccf24SJerome Forissier 		case '#':
301*fe3ccf24SJerome Forissier 			flags |= ALT;
302*fe3ccf24SJerome Forissier 			goto rflag;
303*fe3ccf24SJerome Forissier 		case '*':
304*fe3ccf24SJerome Forissier 			/*
305*fe3ccf24SJerome Forissier 			 * ``A negative field width argument is taken as a
306*fe3ccf24SJerome Forissier 			 * - flag followed by a positive field width.''
307*fe3ccf24SJerome Forissier 			 *	-- ANSI X3J11
308*fe3ccf24SJerome Forissier 			 * They don't exclude field widths read from args.
309*fe3ccf24SJerome Forissier 			 */
310*fe3ccf24SJerome Forissier 			if ((width = va_arg(ap, int)) >= 0)
311*fe3ccf24SJerome Forissier 				goto rflag;
312*fe3ccf24SJerome Forissier 			width = -width;
313*fe3ccf24SJerome Forissier 			/* FALLTHROUGH */
314*fe3ccf24SJerome Forissier 		case '-':
315*fe3ccf24SJerome Forissier 			flags |= LADJUST;
316*fe3ccf24SJerome Forissier 			goto rflag;
317*fe3ccf24SJerome Forissier 		case '+':
318*fe3ccf24SJerome Forissier 			sign = '+';
319*fe3ccf24SJerome Forissier 			goto rflag;
320*fe3ccf24SJerome Forissier 		case '.':
321*fe3ccf24SJerome Forissier 			if ((ch = *fmt++) == '*') {
322*fe3ccf24SJerome Forissier 				n = va_arg(ap, int);
323*fe3ccf24SJerome Forissier 				prec = n < 0 ? -1 : n;
324*fe3ccf24SJerome Forissier 				goto rflag;
325*fe3ccf24SJerome Forissier 			}
326*fe3ccf24SJerome Forissier 			n = 0;
327*fe3ccf24SJerome Forissier 			while (is_digit(ch)) {
328*fe3ccf24SJerome Forissier 				n = 10 * n + to_digit(ch);
329*fe3ccf24SJerome Forissier 				ch = *fmt++;
330*fe3ccf24SJerome Forissier 			}
331*fe3ccf24SJerome Forissier 			prec = n < 0 ? -1 : n;
332*fe3ccf24SJerome Forissier 			goto reswitch;
333*fe3ccf24SJerome Forissier 		case '0':
334*fe3ccf24SJerome Forissier 			/*
335*fe3ccf24SJerome Forissier 			 * ``Note that 0 is taken as a flag, not as the
336*fe3ccf24SJerome Forissier 			 * beginning of a field width.''
337*fe3ccf24SJerome Forissier 			 *	-- ANSI X3J11
338*fe3ccf24SJerome Forissier 			 */
339*fe3ccf24SJerome Forissier 			flags |= ZEROPAD;
340*fe3ccf24SJerome Forissier 			goto rflag;
341*fe3ccf24SJerome Forissier 		case '1': case '2': case '3': case '4':
342*fe3ccf24SJerome Forissier 		case '5': case '6': case '7': case '8': case '9':
343*fe3ccf24SJerome Forissier 			n = 0;
344*fe3ccf24SJerome Forissier 			do {
345*fe3ccf24SJerome Forissier 				n = 10 * n + to_digit(ch);
346*fe3ccf24SJerome Forissier 				ch = *fmt++;
347*fe3ccf24SJerome Forissier 			} while (is_digit(ch));
348*fe3ccf24SJerome Forissier 			width = n;
349*fe3ccf24SJerome Forissier 			goto reswitch;
350*fe3ccf24SJerome Forissier 		case 'h':
351*fe3ccf24SJerome Forissier 			flags |= SHORTINT;
352*fe3ccf24SJerome Forissier 			goto rflag;
353*fe3ccf24SJerome Forissier 		case 'j':
354*fe3ccf24SJerome Forissier 			flags |= MAXINT;
355*fe3ccf24SJerome Forissier 			goto rflag;
356*fe3ccf24SJerome Forissier 		case 'l':
357*fe3ccf24SJerome Forissier 			if (*fmt == 'l') {
358*fe3ccf24SJerome Forissier 				fmt++;
359*fe3ccf24SJerome Forissier 				flags |= QUADINT;
360*fe3ccf24SJerome Forissier 			} else {
361*fe3ccf24SJerome Forissier 				flags |= LONGINT;
362*fe3ccf24SJerome Forissier 			}
363*fe3ccf24SJerome Forissier 			goto rflag;
364*fe3ccf24SJerome Forissier 		case 'q':
365*fe3ccf24SJerome Forissier 			flags |= QUADINT;
366*fe3ccf24SJerome Forissier 			goto rflag;
367*fe3ccf24SJerome Forissier 		case 't':
368*fe3ccf24SJerome Forissier 			flags |= PTRINT;
369*fe3ccf24SJerome Forissier 			goto rflag;
370*fe3ccf24SJerome Forissier 		case 'z':
371*fe3ccf24SJerome Forissier 			flags |= SIZEINT;
372*fe3ccf24SJerome Forissier 			goto rflag;
373*fe3ccf24SJerome Forissier 		case 'c':
374*fe3ccf24SJerome Forissier 			*(cp = bf) = va_arg(ap, int);
375*fe3ccf24SJerome Forissier 			size = 1;
376*fe3ccf24SJerome Forissier 			sign = '\0';
377*fe3ccf24SJerome Forissier 			break;
378*fe3ccf24SJerome Forissier 		case 'D':
379*fe3ccf24SJerome Forissier 			flags |= LONGINT;
380*fe3ccf24SJerome Forissier 			/*FALLTHROUGH*/
381*fe3ccf24SJerome Forissier 		case 'd':
382*fe3ccf24SJerome Forissier 		case 'i':
383*fe3ccf24SJerome Forissier 			_uquad = SARG();
384*fe3ccf24SJerome Forissier 			if ((int64_t)_uquad < 0) {
385*fe3ccf24SJerome Forissier 				_uquad = -_uquad;
386*fe3ccf24SJerome Forissier 				sign = '-';
387*fe3ccf24SJerome Forissier 			}
388*fe3ccf24SJerome Forissier 			base = DEC;
389*fe3ccf24SJerome Forissier 			goto number;
390*fe3ccf24SJerome Forissier 		case 'n':
391*fe3ccf24SJerome Forissier 			if (flags & MAXINT)
392*fe3ccf24SJerome Forissier 				*va_arg(ap, intmax_t *) = ret;
393*fe3ccf24SJerome Forissier 			else if (flags & PTRINT)
394*fe3ccf24SJerome Forissier 				*va_arg(ap, intptr_t *) = ret;
395*fe3ccf24SJerome Forissier 			else if (flags & SIZEINT)
396*fe3ccf24SJerome Forissier 				*va_arg(ap, ssize_t *) = ret;
397*fe3ccf24SJerome Forissier 			else if (flags & QUADINT)
398*fe3ccf24SJerome Forissier 				*va_arg(ap, int64_t *) = ret;
399*fe3ccf24SJerome Forissier 			else if (flags & LONGINT)
400*fe3ccf24SJerome Forissier 				*va_arg(ap, long *) = ret;
401*fe3ccf24SJerome Forissier 			else if (flags & SHORTINT)
402*fe3ccf24SJerome Forissier 				*va_arg(ap, short *) = ret;
403*fe3ccf24SJerome Forissier 			else
404*fe3ccf24SJerome Forissier 				*va_arg(ap, int *) = ret;
405*fe3ccf24SJerome Forissier 			continue;	/* no output */
406*fe3ccf24SJerome Forissier 		case 'O':
407*fe3ccf24SJerome Forissier 			flags |= LONGINT;
408*fe3ccf24SJerome Forissier 			/*FALLTHROUGH*/
409*fe3ccf24SJerome Forissier 		case 'o':
410*fe3ccf24SJerome Forissier 			_uquad = UARG();
411*fe3ccf24SJerome Forissier 			base = OCT;
412*fe3ccf24SJerome Forissier 			goto nosign;
413*fe3ccf24SJerome Forissier 		case 'p':
414*fe3ccf24SJerome Forissier 			if (ext && *fmt == 'U' && *(fmt+1) == 'l') {
415*fe3ccf24SJerome Forissier 				/*
416*fe3ccf24SJerome Forissier 				 * Non-standard format available in [v]snprintk
417*fe3ccf24SJerome Forissier 				 * only
418*fe3ccf24SJerome Forissier 				 */
419*fe3ccf24SJerome Forissier 				fmt += 2;
420*fe3ccf24SJerome Forissier 				size = uuid2str(bf, sizeof(bf),
421*fe3ccf24SJerome Forissier 						va_arg(ap, void *));
422*fe3ccf24SJerome Forissier 				cp = bf;
423*fe3ccf24SJerome Forissier 				sign = '\0';
424*fe3ccf24SJerome Forissier 				break;
425*fe3ccf24SJerome Forissier 			}
426*fe3ccf24SJerome Forissier 			/*
427*fe3ccf24SJerome Forissier 			 * ``The argument shall be a pointer to void.  The
428*fe3ccf24SJerome Forissier 			 * value of the pointer is converted to a sequence
429*fe3ccf24SJerome Forissier 			 * of printable characters, in an implementation-
430*fe3ccf24SJerome Forissier 			 * defined manner.''
431*fe3ccf24SJerome Forissier 			 *	-- ANSI X3J11
432*fe3ccf24SJerome Forissier 			 */
433*fe3ccf24SJerome Forissier 			/* NOSTRICT */
434*fe3ccf24SJerome Forissier 			_uquad = (unsigned long)va_arg(ap, void *);
435*fe3ccf24SJerome Forissier 			base = HEX;
436*fe3ccf24SJerome Forissier 			xdigs = hexdigits;
437*fe3ccf24SJerome Forissier 			flags |= HEXPREFIX;
438*fe3ccf24SJerome Forissier 			ch = 'x';
439*fe3ccf24SJerome Forissier 			goto nosign;
440*fe3ccf24SJerome Forissier 		case 's':
441*fe3ccf24SJerome Forissier 			if ((cp = va_arg(ap, char *)) == NULL)
442*fe3ccf24SJerome Forissier 				/*XXXUNCONST*/
443*fe3ccf24SJerome Forissier 				cp = __UNCONST("(null)");
444*fe3ccf24SJerome Forissier 			if (prec >= 0) {
445*fe3ccf24SJerome Forissier 				/*
446*fe3ccf24SJerome Forissier 				 * can't use strlen; can only look for the
447*fe3ccf24SJerome Forissier 				 * NUL in the first `prec' characters, and
448*fe3ccf24SJerome Forissier 				 * strlen() will go further.
449*fe3ccf24SJerome Forissier 				 */
450*fe3ccf24SJerome Forissier 				char *p = memchr(cp, 0, prec);
451*fe3ccf24SJerome Forissier 
452*fe3ccf24SJerome Forissier 				if (p != NULL) {
453*fe3ccf24SJerome Forissier 					size = p - cp;
454*fe3ccf24SJerome Forissier 					if (size > prec)
455*fe3ccf24SJerome Forissier 						size = prec;
456*fe3ccf24SJerome Forissier 				} else
457*fe3ccf24SJerome Forissier 					size = prec;
458*fe3ccf24SJerome Forissier 			} else
459*fe3ccf24SJerome Forissier 				size = strlen(cp);
460*fe3ccf24SJerome Forissier 			sign = '\0';
461*fe3ccf24SJerome Forissier 			break;
462*fe3ccf24SJerome Forissier 		case 'U':
463*fe3ccf24SJerome Forissier 			flags |= LONGINT;
464*fe3ccf24SJerome Forissier 			/*FALLTHROUGH*/
465*fe3ccf24SJerome Forissier 		case 'u':
466*fe3ccf24SJerome Forissier 			_uquad = UARG();
467*fe3ccf24SJerome Forissier 			base = DEC;
468*fe3ccf24SJerome Forissier 			goto nosign;
469*fe3ccf24SJerome Forissier 		case 'X':
470*fe3ccf24SJerome Forissier 			xdigs = HEXDIGITS;
471*fe3ccf24SJerome Forissier 			goto hex;
472*fe3ccf24SJerome Forissier 		case 'x':
473*fe3ccf24SJerome Forissier 			xdigs = hexdigits;
474*fe3ccf24SJerome Forissier hex:			_uquad = UARG();
475*fe3ccf24SJerome Forissier 			base = HEX;
476*fe3ccf24SJerome Forissier 			/* leading 0x/X only if non-zero */
477*fe3ccf24SJerome Forissier 			if (flags & ALT && _uquad != 0)
478*fe3ccf24SJerome Forissier 				flags |= HEXPREFIX;
479*fe3ccf24SJerome Forissier 
480*fe3ccf24SJerome Forissier 			/* unsigned conversions */
481*fe3ccf24SJerome Forissier nosign:			sign = '\0';
482*fe3ccf24SJerome Forissier 			/*
483*fe3ccf24SJerome Forissier 			 * ``... diouXx conversions ... if a precision is
484*fe3ccf24SJerome Forissier 			 * specified, the 0 flag will be ignored.''
485*fe3ccf24SJerome Forissier 			 *	-- ANSI X3J11
486*fe3ccf24SJerome Forissier 			 */
487*fe3ccf24SJerome Forissier number:			if ((dprec = prec) >= 0)
488*fe3ccf24SJerome Forissier 				flags &= ~ZEROPAD;
489*fe3ccf24SJerome Forissier 
490*fe3ccf24SJerome Forissier 			/*
491*fe3ccf24SJerome Forissier 			 * ``The result of converting a zero value with an
492*fe3ccf24SJerome Forissier 			 * explicit precision of zero is no characters.''
493*fe3ccf24SJerome Forissier 			 *	-- ANSI X3J11
494*fe3ccf24SJerome Forissier 			 */
495*fe3ccf24SJerome Forissier 			cp = bf + KPRINTF_BUFSIZE;
496*fe3ccf24SJerome Forissier 			if (_uquad != 0 || prec != 0) {
497*fe3ccf24SJerome Forissier 				/*
498*fe3ccf24SJerome Forissier 				 * Unsigned mod is hard, and unsigned mod
499*fe3ccf24SJerome Forissier 				 * by a constant is easier than that by
500*fe3ccf24SJerome Forissier 				 * a variable; hence this switch.
501*fe3ccf24SJerome Forissier 				 */
502*fe3ccf24SJerome Forissier 				switch (base) {
503*fe3ccf24SJerome Forissier 				case OCT:
504*fe3ccf24SJerome Forissier 					do {
505*fe3ccf24SJerome Forissier 						*--cp = to_char(_uquad & 7);
506*fe3ccf24SJerome Forissier 						_uquad >>= 3;
507*fe3ccf24SJerome Forissier 					} while (_uquad);
508*fe3ccf24SJerome Forissier 					/* handle octal leading 0 */
509*fe3ccf24SJerome Forissier 					if (flags & ALT && *cp != '0')
510*fe3ccf24SJerome Forissier 						*--cp = '0';
511*fe3ccf24SJerome Forissier 					break;
512*fe3ccf24SJerome Forissier 
513*fe3ccf24SJerome Forissier 				case DEC:
514*fe3ccf24SJerome Forissier 					/* many numbers are 1 digit */
515*fe3ccf24SJerome Forissier 					while (_uquad >= 10) {
516*fe3ccf24SJerome Forissier 						*--cp = to_char(_uquad % 10);
517*fe3ccf24SJerome Forissier 						_uquad /= 10;
518*fe3ccf24SJerome Forissier 					}
519*fe3ccf24SJerome Forissier 					*--cp = to_char(_uquad);
520*fe3ccf24SJerome Forissier 					break;
521*fe3ccf24SJerome Forissier 
522*fe3ccf24SJerome Forissier 				case HEX:
523*fe3ccf24SJerome Forissier 					do {
524*fe3ccf24SJerome Forissier 						*--cp = xdigs[_uquad & 15];
525*fe3ccf24SJerome Forissier 						_uquad >>= 4;
526*fe3ccf24SJerome Forissier 					} while (_uquad);
527*fe3ccf24SJerome Forissier 					break;
528*fe3ccf24SJerome Forissier 
529*fe3ccf24SJerome Forissier 				default:
530*fe3ccf24SJerome Forissier 					/*XXXUNCONST*/
531*fe3ccf24SJerome Forissier 					cp = __UNCONST("bug in kprintf: bad base");
532*fe3ccf24SJerome Forissier 					size = strlen(cp);
533*fe3ccf24SJerome Forissier 					goto skipsize;
534*fe3ccf24SJerome Forissier 				}
535*fe3ccf24SJerome Forissier 			}
536*fe3ccf24SJerome Forissier 			size = bf + KPRINTF_BUFSIZE - cp;
537*fe3ccf24SJerome Forissier 		skipsize:
538*fe3ccf24SJerome Forissier 			break;
539*fe3ccf24SJerome Forissier 		default:	/* "%?" prints ?, unless ? is NUL */
540*fe3ccf24SJerome Forissier 			if (ch == '\0')
541*fe3ccf24SJerome Forissier 				goto done;
542*fe3ccf24SJerome Forissier 			/* pretend it was %c with argument ch */
543*fe3ccf24SJerome Forissier 			cp = bf;
544*fe3ccf24SJerome Forissier 			*cp = ch;
545*fe3ccf24SJerome Forissier 			size = 1;
546*fe3ccf24SJerome Forissier 			sign = '\0';
547*fe3ccf24SJerome Forissier 			break;
548*fe3ccf24SJerome Forissier 		}
549*fe3ccf24SJerome Forissier 
550*fe3ccf24SJerome Forissier 		/*
551*fe3ccf24SJerome Forissier 		 * All reasonable formats wind up here.  At this point, `cp'
552*fe3ccf24SJerome Forissier 		 * points to a string which (if not flags&LADJUST) should be
553*fe3ccf24SJerome Forissier 		 * padded out to `width' places.  If flags&ZEROPAD, it should
554*fe3ccf24SJerome Forissier 		 * first be prefixed by any sign or other prefix; otherwise,
555*fe3ccf24SJerome Forissier 		 * it should be blank padded before the prefix is emitted.
556*fe3ccf24SJerome Forissier 		 * After any left-hand padding and prefixing, emit zeroes
557*fe3ccf24SJerome Forissier 		 * required by a decimal [diouxX] precision, then print the
558*fe3ccf24SJerome Forissier 		 * string proper, then emit zeroes required by any leftover
559*fe3ccf24SJerome Forissier 		 * floating precision; finally, if LADJUST, pad with blanks.
560*fe3ccf24SJerome Forissier 		 *
561*fe3ccf24SJerome Forissier 		 * Compute actual size, so we know how much to pad.
562*fe3ccf24SJerome Forissier 		 * size excludes decimal prec; realsz includes it.
563*fe3ccf24SJerome Forissier 		 */
564*fe3ccf24SJerome Forissier 		realsz = dprec > size ? dprec : size;
565*fe3ccf24SJerome Forissier 		if (sign)
566*fe3ccf24SJerome Forissier 			realsz++;
567*fe3ccf24SJerome Forissier 		else if (flags & HEXPREFIX)
568*fe3ccf24SJerome Forissier 			realsz+= 2;
569*fe3ccf24SJerome Forissier 
570*fe3ccf24SJerome Forissier 		/* adjust ret */
571*fe3ccf24SJerome Forissier 		ret += width > realsz ? width : realsz;
572*fe3ccf24SJerome Forissier 
573*fe3ccf24SJerome Forissier 		/* right-adjusting blank padding */
574*fe3ccf24SJerome Forissier 		if ((flags & (LADJUST|ZEROPAD)) == 0) {
575*fe3ccf24SJerome Forissier 			n = width - realsz;
576*fe3ccf24SJerome Forissier 			while (n-- > 0)
577*fe3ccf24SJerome Forissier 				KPRINTF_PUTCHAR(' ');
578*fe3ccf24SJerome Forissier 		}
579*fe3ccf24SJerome Forissier 
580*fe3ccf24SJerome Forissier 		/* prefix */
581*fe3ccf24SJerome Forissier 		if (sign) {
582*fe3ccf24SJerome Forissier 			KPRINTF_PUTCHAR(sign);
583*fe3ccf24SJerome Forissier 		} else if (flags & HEXPREFIX) {
584*fe3ccf24SJerome Forissier 			KPRINTF_PUTCHAR('0');
585*fe3ccf24SJerome Forissier 			KPRINTF_PUTCHAR(ch);
586*fe3ccf24SJerome Forissier 		}
587*fe3ccf24SJerome Forissier 
588*fe3ccf24SJerome Forissier 		/* right-adjusting zero padding */
589*fe3ccf24SJerome Forissier 		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) {
590*fe3ccf24SJerome Forissier 			n = width - realsz;
591*fe3ccf24SJerome Forissier 			while (n-- > 0)
592*fe3ccf24SJerome Forissier 				KPRINTF_PUTCHAR('0');
593*fe3ccf24SJerome Forissier 		}
594*fe3ccf24SJerome Forissier 
595*fe3ccf24SJerome Forissier 		/* leading zeroes from decimal precision */
596*fe3ccf24SJerome Forissier 		n = dprec - size;
597*fe3ccf24SJerome Forissier 		while (n-- > 0)
598*fe3ccf24SJerome Forissier 			KPRINTF_PUTCHAR('0');
599*fe3ccf24SJerome Forissier 
600*fe3ccf24SJerome Forissier 		/* the string or number proper */
601*fe3ccf24SJerome Forissier 		for (; size--; cp++)
602*fe3ccf24SJerome Forissier 			KPRINTF_PUTCHAR(*cp);
603*fe3ccf24SJerome Forissier 		/* left-adjusting padding (always blank) */
604*fe3ccf24SJerome Forissier 		if (flags & LADJUST) {
605*fe3ccf24SJerome Forissier 			n = width - realsz;
606*fe3ccf24SJerome Forissier 			while (n-- > 0)
607*fe3ccf24SJerome Forissier 				KPRINTF_PUTCHAR(' ');
608*fe3ccf24SJerome Forissier 		}
609*fe3ccf24SJerome Forissier 	}
610*fe3ccf24SJerome Forissier 
611*fe3ccf24SJerome Forissier done:
612*fe3ccf24SJerome Forissier 	if ((oflags == TOBUFONLY) && (vp != NULL))
613*fe3ccf24SJerome Forissier 		*(char **)vp = sbuf;
614*fe3ccf24SJerome Forissier 	return ret;
615*fe3ccf24SJerome Forissier }
616