xref: /freebsd/stand/libsa/printf.c (revision 98e28b71b2a7053365d713ddfecabedb65f5fc75)
1ca987d46SWarner Losh /*-
2ca987d46SWarner Losh  * Copyright (c) 1986, 1988, 1991, 1993
3ca987d46SWarner Losh  *	The Regents of the University of California.  All rights reserved.
4ca987d46SWarner Losh  * (c) UNIX System Laboratories, Inc.
5ca987d46SWarner Losh  * All or some portions of this file are derived from material licensed
6ca987d46SWarner Losh  * to the University of California by American Telephone and Telegraph
7ca987d46SWarner Losh  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8ca987d46SWarner Losh  * the permission of UNIX System Laboratories, Inc.
9ca987d46SWarner Losh  *
10ca987d46SWarner Losh  * Redistribution and use in source and binary forms, with or without
11ca987d46SWarner Losh  * modification, are permitted provided that the following conditions
12ca987d46SWarner Losh  * are met:
13ca987d46SWarner Losh  * 1. Redistributions of source code must retain the above copyright
14ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer.
15ca987d46SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
16ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
17ca987d46SWarner Losh  *    documentation and/or other materials provided with the distribution.
18ca987d46SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
19ca987d46SWarner Losh  *    may be used to endorse or promote products derived from this software
20ca987d46SWarner Losh  *    without specific prior written permission.
21ca987d46SWarner Losh  *
22ca987d46SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23ca987d46SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24ca987d46SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25ca987d46SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26ca987d46SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27ca987d46SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28ca987d46SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29ca987d46SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30ca987d46SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31ca987d46SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32ca987d46SWarner Losh  * SUCH DAMAGE.
33ca987d46SWarner Losh  *
34ca987d46SWarner Losh  *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
35ca987d46SWarner Losh  */
36ca987d46SWarner Losh 
37ca987d46SWarner Losh #include <sys/cdefs.h>
38ca987d46SWarner Losh __FBSDID("$FreeBSD$");
39ca987d46SWarner Losh 
40ca987d46SWarner Losh /*
41ca987d46SWarner Losh  * Standaloneified version of the FreeBSD kernel printf family.
42ca987d46SWarner Losh  */
43ca987d46SWarner Losh 
44ca987d46SWarner Losh #include <sys/types.h>
45ca987d46SWarner Losh #include <sys/stddef.h>
46ca987d46SWarner Losh #include <sys/stdint.h>
47ca987d46SWarner Losh #include <limits.h>
48ca987d46SWarner Losh #include <string.h>
49ca987d46SWarner Losh #include "stand.h"
50ca987d46SWarner Losh 
51ca987d46SWarner Losh /*
52ca987d46SWarner Losh  * Note that stdarg.h and the ANSI style va_start macro is used for both
53ca987d46SWarner Losh  * ANSI and traditional C compilers.
54ca987d46SWarner Losh  */
55ca987d46SWarner Losh #include <machine/stdarg.h>
56ca987d46SWarner Losh 
57ca987d46SWarner Losh #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
58ca987d46SWarner Losh 
59ca987d46SWarner Losh typedef void (kvprintf_fn_t)(int, void *);
60ca987d46SWarner Losh 
61ca987d46SWarner Losh static char	*ksprintn (char *buf, uintmax_t num, int base, int *len, int upper);
62ca987d46SWarner Losh static int	kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap);
63ca987d46SWarner Losh 
64ca987d46SWarner Losh static void
65ca987d46SWarner Losh putchar_wrapper(int cc, void *arg)
66ca987d46SWarner Losh {
67ca987d46SWarner Losh 
68ca987d46SWarner Losh 	putchar(cc);
69ca987d46SWarner Losh }
70ca987d46SWarner Losh 
71ca987d46SWarner Losh int
72ca987d46SWarner Losh printf(const char *fmt, ...)
73ca987d46SWarner Losh {
74ca987d46SWarner Losh 	va_list ap;
75ca987d46SWarner Losh 	int retval;
76ca987d46SWarner Losh 
77ca987d46SWarner Losh 	va_start(ap, fmt);
78ca987d46SWarner Losh 	retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap);
79ca987d46SWarner Losh 	va_end(ap);
80ca987d46SWarner Losh 	return retval;
81ca987d46SWarner Losh }
82ca987d46SWarner Losh 
833e9c7874SIan Lepore int
84ca987d46SWarner Losh vprintf(const char *fmt, va_list ap)
85ca987d46SWarner Losh {
86ca987d46SWarner Losh 
873e9c7874SIan Lepore 	return (kvprintf(fmt, putchar_wrapper, NULL, 10, ap));
88ca987d46SWarner Losh }
89ca987d46SWarner Losh 
90ca987d46SWarner Losh int
91ca987d46SWarner Losh sprintf(char *buf, const char *cfmt, ...)
92ca987d46SWarner Losh {
93ca987d46SWarner Losh 	int retval;
94ca987d46SWarner Losh 	va_list ap;
95ca987d46SWarner Losh 
96ca987d46SWarner Losh 	va_start(ap, cfmt);
97ca987d46SWarner Losh 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
98ca987d46SWarner Losh 	buf[retval] = '\0';
99ca987d46SWarner Losh 	va_end(ap);
100ca987d46SWarner Losh 	return retval;
101ca987d46SWarner Losh }
102ca987d46SWarner Losh 
103ca987d46SWarner Losh struct print_buf {
104ca987d46SWarner Losh 	char *buf;
105ca987d46SWarner Losh 	size_t size;
106ca987d46SWarner Losh };
107ca987d46SWarner Losh 
108ca987d46SWarner Losh static void
109ca987d46SWarner Losh snprint_func(int ch, void *arg)
110ca987d46SWarner Losh {
111ca987d46SWarner Losh 	struct print_buf *pbuf = arg;
112ca987d46SWarner Losh 
113ca987d46SWarner Losh 	if (pbuf->size < 2) {
114ca987d46SWarner Losh 		/*
115ca987d46SWarner Losh 		 * Reserve last buffer position for the terminating
116ca987d46SWarner Losh 		 * character:
117ca987d46SWarner Losh 		 */
118ca987d46SWarner Losh 		return;
119ca987d46SWarner Losh 	}
120ca987d46SWarner Losh 	*(pbuf->buf)++ = ch;
121ca987d46SWarner Losh 	pbuf->size--;
122ca987d46SWarner Losh }
123ca987d46SWarner Losh 
124ca987d46SWarner Losh int
1255e84b578SToomas Soome asprintf(char **buf, const char *cfmt, ...)
1265e84b578SToomas Soome {
1275e84b578SToomas Soome 	int retval;
1285e84b578SToomas Soome 	struct print_buf arg;
1295e84b578SToomas Soome 	va_list ap;
1305e84b578SToomas Soome 
1315e84b578SToomas Soome 	*buf = NULL;
1325e84b578SToomas Soome 	va_start(ap, cfmt);
1335e84b578SToomas Soome 	retval = kvprintf(cfmt, NULL, NULL, 10, ap);
1345e84b578SToomas Soome 	va_end(ap);
1355e84b578SToomas Soome 	if (retval <= 0)
1365e84b578SToomas Soome 		return (-1);
1375e84b578SToomas Soome 
1385e84b578SToomas Soome 	arg.size = retval + 1;
1395e84b578SToomas Soome 	arg.buf = *buf = malloc(arg.size);
1405e84b578SToomas Soome 	if (*buf == NULL)
1415e84b578SToomas Soome 		return (-1);
1425e84b578SToomas Soome 
1435e84b578SToomas Soome 	va_start(ap, cfmt);
1445e84b578SToomas Soome 	retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap);
1455e84b578SToomas Soome 	va_end(ap);
1465e84b578SToomas Soome 
1475e84b578SToomas Soome 	if (arg.size >= 1)
1485e84b578SToomas Soome 		*(arg.buf)++ = 0;
1495e84b578SToomas Soome 	return (retval);
1505e84b578SToomas Soome }
1515e84b578SToomas Soome 
1525e84b578SToomas Soome int
153ca987d46SWarner Losh snprintf(char *buf, size_t size, const char *cfmt, ...)
154ca987d46SWarner Losh {
155ca987d46SWarner Losh 	int retval;
156ca987d46SWarner Losh 	va_list ap;
157ca987d46SWarner Losh 	struct print_buf arg;
158ca987d46SWarner Losh 
159ca987d46SWarner Losh 	arg.buf = buf;
160ca987d46SWarner Losh 	arg.size = size;
161ca987d46SWarner Losh 
162ca987d46SWarner Losh 	va_start(ap, cfmt);
163ca987d46SWarner Losh 	retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap);
164ca987d46SWarner Losh 	va_end(ap);
165ca987d46SWarner Losh 
166ca987d46SWarner Losh 	if (arg.size >= 1)
167ca987d46SWarner Losh 		*(arg.buf)++ = 0;
168ca987d46SWarner Losh 	return retval;
169ca987d46SWarner Losh }
170ca987d46SWarner Losh 
1713e9c7874SIan Lepore int
1721851d70dSIan Lepore vsnprintf(char *buf, size_t size, const char *cfmt, va_list ap)
1731851d70dSIan Lepore {
1741851d70dSIan Lepore 	struct print_buf arg;
1753e9c7874SIan Lepore 	int retval;
1761851d70dSIan Lepore 
1771851d70dSIan Lepore 	arg.buf = buf;
1781851d70dSIan Lepore 	arg.size = size;
1791851d70dSIan Lepore 
1803e9c7874SIan Lepore 	retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap);
1811851d70dSIan Lepore 
1821851d70dSIan Lepore 	if (arg.size >= 1)
1831851d70dSIan Lepore 		*(arg.buf)++ = 0;
1843e9c7874SIan Lepore 
1853e9c7874SIan Lepore 	return (retval);
1861851d70dSIan Lepore }
1871851d70dSIan Lepore 
1883e9c7874SIan Lepore int
189ca987d46SWarner Losh vsprintf(char *buf, const char *cfmt, va_list ap)
190ca987d46SWarner Losh {
191ca987d46SWarner Losh 	int	retval;
192ca987d46SWarner Losh 
193ca987d46SWarner Losh 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
194ca987d46SWarner Losh 	buf[retval] = '\0';
1953e9c7874SIan Lepore 
1963e9c7874SIan Lepore 	return (retval);
197ca987d46SWarner Losh }
198ca987d46SWarner Losh 
199ca987d46SWarner Losh /*
200ca987d46SWarner Losh  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
201ca987d46SWarner Losh  * order; return an optional length and a pointer to the last character
202ca987d46SWarner Losh  * written in the buffer (i.e., the first character of the string).
203ca987d46SWarner Losh  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
204ca987d46SWarner Losh  */
205ca987d46SWarner Losh static char *
206ca987d46SWarner Losh ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
207ca987d46SWarner Losh {
208ca987d46SWarner Losh 	char *p, c;
209ca987d46SWarner Losh 
210ca987d46SWarner Losh 	p = nbuf;
211ca987d46SWarner Losh 	*p = '\0';
212ca987d46SWarner Losh 	do {
213ca987d46SWarner Losh 		c = hex2ascii(num % base);
214ca987d46SWarner Losh 		*++p = upper ? toupper(c) : c;
215ca987d46SWarner Losh 	} while (num /= base);
216ca987d46SWarner Losh 	if (lenp)
217ca987d46SWarner Losh 		*lenp = p - nbuf;
218ca987d46SWarner Losh 	return (p);
219ca987d46SWarner Losh }
220ca987d46SWarner Losh 
221ca987d46SWarner Losh /*
222ca987d46SWarner Losh  * Scaled down version of printf(3).
223ca987d46SWarner Losh  *
224ca987d46SWarner Losh  * Two additional formats:
225ca987d46SWarner Losh  *
226ca987d46SWarner Losh  * The format %b is supported to decode error registers.
227ca987d46SWarner Losh  * Its usage is:
228ca987d46SWarner Losh  *
229ca987d46SWarner Losh  *	printf("reg=%b\n", regval, "<base><arg>*");
230ca987d46SWarner Losh  *
231ca987d46SWarner Losh  * where <base> is the output base expressed as a control character, e.g.
232ca987d46SWarner Losh  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
233ca987d46SWarner Losh  * the first of which gives the bit number to be inspected (origin 1), and
234ca987d46SWarner Losh  * the next characters (up to a control character, i.e. a character <= 32),
235ca987d46SWarner Losh  * give the name of the register.  Thus:
236ca987d46SWarner Losh  *
237ca987d46SWarner Losh  *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
238ca987d46SWarner Losh  *
239ca987d46SWarner Losh  * would produce output:
240ca987d46SWarner Losh  *
241ca987d46SWarner Losh  *	reg=3<BITTWO,BITONE>
242ca987d46SWarner Losh  *
243ca987d46SWarner Losh  * XXX:  %D  -- Hexdump, takes pointer and separator string:
244ca987d46SWarner Losh  *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
245ca987d46SWarner Losh  *		("%*D", len, ptr, " " -> XX XX XX XX ...
246ca987d46SWarner Losh  */
247ca987d46SWarner Losh static int
248ca987d46SWarner Losh kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap)
249ca987d46SWarner Losh {
250*98e28b71SToomas Soome #define PCHAR(c) { \
251*98e28b71SToomas Soome 	int cc = (c);				\
252*98e28b71SToomas Soome 						\
253*98e28b71SToomas Soome 	if (func) {				\
254*98e28b71SToomas Soome 		(*func)(cc, arg);		\
255*98e28b71SToomas Soome 	} else if (d != NULL) {			\
256*98e28b71SToomas Soome 		*d++ = cc;			\
257*98e28b71SToomas Soome 	}					\
258*98e28b71SToomas Soome 	retval++;				\
259*98e28b71SToomas Soome 	}
260*98e28b71SToomas Soome 
261ca987d46SWarner Losh 	char nbuf[MAXNBUF];
262ca987d46SWarner Losh 	char *d;
263ca987d46SWarner Losh 	const char *p, *percent, *q;
264ca987d46SWarner Losh 	uint16_t *S;
265ca987d46SWarner Losh 	u_char *up;
266ca987d46SWarner Losh 	int ch, n;
267ca987d46SWarner Losh 	uintmax_t num;
268ca987d46SWarner Losh 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
269ca987d46SWarner Losh 	int cflag, hflag, jflag, tflag, zflag;
270ca987d46SWarner Losh 	int dwidth, upper;
271ca987d46SWarner Losh 	char padc;
272ca987d46SWarner Losh 	int stop = 0, retval = 0;
273ca987d46SWarner Losh 
274ca987d46SWarner Losh 	num = 0;
275ca987d46SWarner Losh 	if (!func)
276ca987d46SWarner Losh 		d = (char *) arg;
277ca987d46SWarner Losh 	else
278ca987d46SWarner Losh 		d = NULL;
279ca987d46SWarner Losh 
280ca987d46SWarner Losh 	if (fmt == NULL)
281ca987d46SWarner Losh 		fmt = "(fmt null)\n";
282ca987d46SWarner Losh 
283ca987d46SWarner Losh 	if (radix < 2 || radix > 36)
284ca987d46SWarner Losh 		radix = 10;
285ca987d46SWarner Losh 
286ca987d46SWarner Losh 	for (;;) {
287ca987d46SWarner Losh 		padc = ' ';
288ca987d46SWarner Losh 		width = 0;
289ca987d46SWarner Losh 		while ((ch = (u_char)*fmt++) != '%' || stop) {
290ca987d46SWarner Losh 			if (ch == '\0')
291ca987d46SWarner Losh 				return (retval);
292ca987d46SWarner Losh 			PCHAR(ch);
293ca987d46SWarner Losh 		}
294ca987d46SWarner Losh 		percent = fmt - 1;
295ca987d46SWarner Losh 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
296ca987d46SWarner Losh 		sign = 0; dot = 0; dwidth = 0; upper = 0;
297ca987d46SWarner Losh 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
298ca987d46SWarner Losh reswitch:	switch (ch = (u_char)*fmt++) {
299ca987d46SWarner Losh 		case '.':
300ca987d46SWarner Losh 			dot = 1;
301ca987d46SWarner Losh 			goto reswitch;
302ca987d46SWarner Losh 		case '#':
303ca987d46SWarner Losh 			sharpflag = 1;
304ca987d46SWarner Losh 			goto reswitch;
305ca987d46SWarner Losh 		case '+':
306ca987d46SWarner Losh 			sign = 1;
307ca987d46SWarner Losh 			goto reswitch;
308ca987d46SWarner Losh 		case '-':
309ca987d46SWarner Losh 			ladjust = 1;
310ca987d46SWarner Losh 			goto reswitch;
311ca987d46SWarner Losh 		case '%':
312ca987d46SWarner Losh 			PCHAR(ch);
313ca987d46SWarner Losh 			break;
314ca987d46SWarner Losh 		case '*':
315ca987d46SWarner Losh 			if (!dot) {
316ca987d46SWarner Losh 				width = va_arg(ap, int);
317ca987d46SWarner Losh 				if (width < 0) {
318ca987d46SWarner Losh 					ladjust = !ladjust;
319ca987d46SWarner Losh 					width = -width;
320ca987d46SWarner Losh 				}
321ca987d46SWarner Losh 			} else {
322ca987d46SWarner Losh 				dwidth = va_arg(ap, int);
323ca987d46SWarner Losh 			}
324ca987d46SWarner Losh 			goto reswitch;
325ca987d46SWarner Losh 		case '0':
326ca987d46SWarner Losh 			if (!dot) {
327ca987d46SWarner Losh 				padc = '0';
328ca987d46SWarner Losh 				goto reswitch;
329ca987d46SWarner Losh 			}
330ca987d46SWarner Losh 		case '1': case '2': case '3': case '4':
331ca987d46SWarner Losh 		case '5': case '6': case '7': case '8': case '9':
332ca987d46SWarner Losh 				for (n = 0;; ++fmt) {
333ca987d46SWarner Losh 					n = n * 10 + ch - '0';
334ca987d46SWarner Losh 					ch = *fmt;
335ca987d46SWarner Losh 					if (ch < '0' || ch > '9')
336ca987d46SWarner Losh 						break;
337ca987d46SWarner Losh 				}
338ca987d46SWarner Losh 			if (dot)
339ca987d46SWarner Losh 				dwidth = n;
340ca987d46SWarner Losh 			else
341ca987d46SWarner Losh 				width = n;
342ca987d46SWarner Losh 			goto reswitch;
343ca987d46SWarner Losh 		case 'b':
344ca987d46SWarner Losh 			num = (u_int)va_arg(ap, int);
345ca987d46SWarner Losh 			p = va_arg(ap, char *);
346ca987d46SWarner Losh 			for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
347ca987d46SWarner Losh 				PCHAR(*q--);
348ca987d46SWarner Losh 
349ca987d46SWarner Losh 			if (num == 0)
350ca987d46SWarner Losh 				break;
351ca987d46SWarner Losh 
352ca987d46SWarner Losh 			for (tmp = 0; *p;) {
353ca987d46SWarner Losh 				n = *p++;
354ca987d46SWarner Losh 				if (num & (1 << (n - 1))) {
355ca987d46SWarner Losh 					PCHAR(tmp ? ',' : '<');
356ca987d46SWarner Losh 					for (; (n = *p) > ' '; ++p)
357ca987d46SWarner Losh 						PCHAR(n);
358ca987d46SWarner Losh 					tmp = 1;
359ca987d46SWarner Losh 				} else
360ca987d46SWarner Losh 					for (; *p > ' '; ++p)
361ca987d46SWarner Losh 						continue;
362ca987d46SWarner Losh 			}
363ca987d46SWarner Losh 			if (tmp)
364ca987d46SWarner Losh 				PCHAR('>');
365ca987d46SWarner Losh 			break;
366ca987d46SWarner Losh 		case 'c':
367ca987d46SWarner Losh 			PCHAR(va_arg(ap, int));
368ca987d46SWarner Losh 			break;
369ca987d46SWarner Losh 		case 'D':
370ca987d46SWarner Losh 			up = va_arg(ap, u_char *);
371ca987d46SWarner Losh 			p = va_arg(ap, char *);
372ca987d46SWarner Losh 			if (!width)
373ca987d46SWarner Losh 				width = 16;
374ca987d46SWarner Losh 			while(width--) {
375ca987d46SWarner Losh 				PCHAR(hex2ascii(*up >> 4));
376ca987d46SWarner Losh 				PCHAR(hex2ascii(*up & 0x0f));
377ca987d46SWarner Losh 				up++;
378ca987d46SWarner Losh 				if (width)
379ca987d46SWarner Losh 					for (q=p;*q;q++)
380ca987d46SWarner Losh 						PCHAR(*q);
381ca987d46SWarner Losh 			}
382ca987d46SWarner Losh 			break;
383ca987d46SWarner Losh 		case 'd':
384ca987d46SWarner Losh 		case 'i':
385ca987d46SWarner Losh 			base = 10;
386ca987d46SWarner Losh 			sign = 1;
387ca987d46SWarner Losh 			goto handle_sign;
388ca987d46SWarner Losh 		case 'h':
389ca987d46SWarner Losh 			if (hflag) {
390ca987d46SWarner Losh 				hflag = 0;
391ca987d46SWarner Losh 				cflag = 1;
392ca987d46SWarner Losh 			} else
393ca987d46SWarner Losh 				hflag = 1;
394ca987d46SWarner Losh 			goto reswitch;
395ca987d46SWarner Losh 		case 'j':
396ca987d46SWarner Losh 			jflag = 1;
397ca987d46SWarner Losh 			goto reswitch;
398ca987d46SWarner Losh 		case 'l':
399ca987d46SWarner Losh 			if (lflag) {
400ca987d46SWarner Losh 				lflag = 0;
401ca987d46SWarner Losh 				qflag = 1;
402ca987d46SWarner Losh 			} else
403ca987d46SWarner Losh 				lflag = 1;
404ca987d46SWarner Losh 			goto reswitch;
405ca987d46SWarner Losh 		case 'n':
406ca987d46SWarner Losh 			if (jflag)
407ca987d46SWarner Losh 				*(va_arg(ap, intmax_t *)) = retval;
408ca987d46SWarner Losh 			else if (qflag)
409ca987d46SWarner Losh 				*(va_arg(ap, quad_t *)) = retval;
410ca987d46SWarner Losh 			else if (lflag)
411ca987d46SWarner Losh 				*(va_arg(ap, long *)) = retval;
412ca987d46SWarner Losh 			else if (zflag)
413ca987d46SWarner Losh 				*(va_arg(ap, size_t *)) = retval;
414ca987d46SWarner Losh 			else if (hflag)
415ca987d46SWarner Losh 				*(va_arg(ap, short *)) = retval;
416ca987d46SWarner Losh 			else if (cflag)
417ca987d46SWarner Losh 				*(va_arg(ap, char *)) = retval;
418ca987d46SWarner Losh 			else
419ca987d46SWarner Losh 				*(va_arg(ap, int *)) = retval;
420ca987d46SWarner Losh 			break;
421ca987d46SWarner Losh 		case 'o':
422ca987d46SWarner Losh 			base = 8;
423ca987d46SWarner Losh 			goto handle_nosign;
424ca987d46SWarner Losh 		case 'p':
425ca987d46SWarner Losh 			base = 16;
426ca987d46SWarner Losh 			sharpflag = (width == 0);
427ca987d46SWarner Losh 			sign = 0;
428ca987d46SWarner Losh 			num = (uintptr_t)va_arg(ap, void *);
429ca987d46SWarner Losh 			goto number;
430ca987d46SWarner Losh 		case 'q':
431ca987d46SWarner Losh 			qflag = 1;
432ca987d46SWarner Losh 			goto reswitch;
433ca987d46SWarner Losh 		case 'r':
434ca987d46SWarner Losh 			base = radix;
435ca987d46SWarner Losh 			if (sign)
436ca987d46SWarner Losh 				goto handle_sign;
437ca987d46SWarner Losh 			goto handle_nosign;
438ca987d46SWarner Losh 		case 's':
439ca987d46SWarner Losh 			p = va_arg(ap, char *);
440ca987d46SWarner Losh 			if (p == NULL)
441ca987d46SWarner Losh 				p = "(null)";
442ca987d46SWarner Losh 			if (!dot)
443ca987d46SWarner Losh 				n = strlen (p);
444ca987d46SWarner Losh 			else
445ca987d46SWarner Losh 				for (n = 0; n < dwidth && p[n]; n++)
446ca987d46SWarner Losh 					continue;
447ca987d46SWarner Losh 
448ca987d46SWarner Losh 			width -= n;
449ca987d46SWarner Losh 
450ca987d46SWarner Losh 			if (!ladjust && width > 0)
451ca987d46SWarner Losh 				while (width--)
452ca987d46SWarner Losh 					PCHAR(padc);
453ca987d46SWarner Losh 			while (n--)
454ca987d46SWarner Losh 				PCHAR(*p++);
455ca987d46SWarner Losh 			if (ladjust && width > 0)
456ca987d46SWarner Losh 				while (width--)
457ca987d46SWarner Losh 					PCHAR(padc);
458ca987d46SWarner Losh 			break;
459ca987d46SWarner Losh 		case 'S':	/* Assume console can cope with wide chars */
460ca987d46SWarner Losh 			for (S = va_arg(ap, uint16_t *); *S != 0; S++)
461ca987d46SWarner Losh 				PCHAR(*S);
462ca987d46SWarner Losh  			break;
463ca987d46SWarner Losh 		case 't':
464ca987d46SWarner Losh 			tflag = 1;
465ca987d46SWarner Losh 			goto reswitch;
466ca987d46SWarner Losh 		case 'u':
467ca987d46SWarner Losh 			base = 10;
468ca987d46SWarner Losh 			goto handle_nosign;
469ca987d46SWarner Losh 		case 'X':
470ca987d46SWarner Losh 			upper = 1;
471ca987d46SWarner Losh 		case 'x':
472ca987d46SWarner Losh 			base = 16;
473ca987d46SWarner Losh 			goto handle_nosign;
474ca987d46SWarner Losh 		case 'y':
475ca987d46SWarner Losh 			base = 16;
476ca987d46SWarner Losh 			sign = 1;
477ca987d46SWarner Losh 			goto handle_sign;
478ca987d46SWarner Losh 		case 'z':
479ca987d46SWarner Losh 			zflag = 1;
480ca987d46SWarner Losh 			goto reswitch;
481ca987d46SWarner Losh handle_nosign:
482ca987d46SWarner Losh 			sign = 0;
483ca987d46SWarner Losh 			if (jflag)
484ca987d46SWarner Losh 				num = va_arg(ap, uintmax_t);
485ca987d46SWarner Losh 			else if (qflag)
486ca987d46SWarner Losh 				num = va_arg(ap, u_quad_t);
487ca987d46SWarner Losh 			else if (tflag)
488ca987d46SWarner Losh 				num = va_arg(ap, ptrdiff_t);
489ca987d46SWarner Losh 			else if (lflag)
490ca987d46SWarner Losh 				num = va_arg(ap, u_long);
491ca987d46SWarner Losh 			else if (zflag)
492ca987d46SWarner Losh 				num = va_arg(ap, size_t);
493ca987d46SWarner Losh 			else if (hflag)
494ca987d46SWarner Losh 				num = (u_short)va_arg(ap, int);
495ca987d46SWarner Losh 			else if (cflag)
496ca987d46SWarner Losh 				num = (u_char)va_arg(ap, int);
497ca987d46SWarner Losh 			else
498ca987d46SWarner Losh 				num = va_arg(ap, u_int);
499ca987d46SWarner Losh 			goto number;
500ca987d46SWarner Losh handle_sign:
501ca987d46SWarner Losh 			if (jflag)
502ca987d46SWarner Losh 				num = va_arg(ap, intmax_t);
503ca987d46SWarner Losh 			else if (qflag)
504ca987d46SWarner Losh 				num = va_arg(ap, quad_t);
505ca987d46SWarner Losh 			else if (tflag)
506ca987d46SWarner Losh 				num = va_arg(ap, ptrdiff_t);
507ca987d46SWarner Losh 			else if (lflag)
508ca987d46SWarner Losh 				num = va_arg(ap, long);
509ca987d46SWarner Losh 			else if (zflag)
510ca987d46SWarner Losh 				num = va_arg(ap, ssize_t);
511ca987d46SWarner Losh 			else if (hflag)
512ca987d46SWarner Losh 				num = (short)va_arg(ap, int);
513ca987d46SWarner Losh 			else if (cflag)
514ca987d46SWarner Losh 				num = (char)va_arg(ap, int);
515ca987d46SWarner Losh 			else
516ca987d46SWarner Losh 				num = va_arg(ap, int);
517ca987d46SWarner Losh number:
518ca987d46SWarner Losh 			if (sign && (intmax_t)num < 0) {
519ca987d46SWarner Losh 				neg = 1;
520ca987d46SWarner Losh 				num = -(intmax_t)num;
521ca987d46SWarner Losh 			}
522ca987d46SWarner Losh 			p = ksprintn(nbuf, num, base, &n, upper);
523ca987d46SWarner Losh 			tmp = 0;
524ca987d46SWarner Losh 			if (sharpflag && num != 0) {
525ca987d46SWarner Losh 				if (base == 8)
526ca987d46SWarner Losh 					tmp++;
527ca987d46SWarner Losh 				else if (base == 16)
528ca987d46SWarner Losh 					tmp += 2;
529ca987d46SWarner Losh 			}
530ca987d46SWarner Losh 			if (neg)
531ca987d46SWarner Losh 				tmp++;
532ca987d46SWarner Losh 
533ca987d46SWarner Losh 			if (!ladjust && padc == '0')
534ca987d46SWarner Losh 				dwidth = width - tmp;
535ca987d46SWarner Losh 			width -= tmp + imax(dwidth, n);
536ca987d46SWarner Losh 			dwidth -= n;
537ca987d46SWarner Losh 			if (!ladjust)
538ca987d46SWarner Losh 				while (width-- > 0)
539ca987d46SWarner Losh 					PCHAR(' ');
540ca987d46SWarner Losh 			if (neg)
541ca987d46SWarner Losh 				PCHAR('-');
542ca987d46SWarner Losh 			if (sharpflag && num != 0) {
543ca987d46SWarner Losh 				if (base == 8) {
544ca987d46SWarner Losh 					PCHAR('0');
545ca987d46SWarner Losh 				} else if (base == 16) {
546ca987d46SWarner Losh 					PCHAR('0');
547ca987d46SWarner Losh 					PCHAR('x');
548ca987d46SWarner Losh 				}
549ca987d46SWarner Losh 			}
550ca987d46SWarner Losh 			while (dwidth-- > 0)
551ca987d46SWarner Losh 				PCHAR('0');
552ca987d46SWarner Losh 
553ca987d46SWarner Losh 			while (*p)
554ca987d46SWarner Losh 				PCHAR(*p--);
555ca987d46SWarner Losh 
556ca987d46SWarner Losh 			if (ladjust)
557ca987d46SWarner Losh 				while (width-- > 0)
558ca987d46SWarner Losh 					PCHAR(' ');
559ca987d46SWarner Losh 
560ca987d46SWarner Losh 			break;
561ca987d46SWarner Losh 		default:
562ca987d46SWarner Losh 			while (percent < fmt)
563ca987d46SWarner Losh 				PCHAR(*percent++);
564ca987d46SWarner Losh 			/*
565ca987d46SWarner Losh 			 * Since we ignore a formatting argument it is no
566ca987d46SWarner Losh 			 * longer safe to obey the remaining formatting
567ca987d46SWarner Losh 			 * arguments as the arguments will no longer match
568ca987d46SWarner Losh 			 * the format specs.
569ca987d46SWarner Losh 			 */
570ca987d46SWarner Losh 			stop = 1;
571ca987d46SWarner Losh 			break;
572ca987d46SWarner Losh 		}
573ca987d46SWarner Losh 	}
574ca987d46SWarner Losh #undef PCHAR
575ca987d46SWarner Losh }
576