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