xref: /freebsd/stand/libsa/printf.c (revision 3e15b01d)
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 
35ca987d46SWarner Losh /*
36ca987d46SWarner Losh  * Standaloneified version of the FreeBSD kernel printf family.
37ca987d46SWarner Losh  */
38ca987d46SWarner Losh 
39ca987d46SWarner Losh #include <sys/types.h>
40ca987d46SWarner Losh #include <sys/stddef.h>
41ca987d46SWarner Losh #include <sys/stdint.h>
42ca987d46SWarner Losh #include <limits.h>
43ca987d46SWarner Losh #include <string.h>
44ca987d46SWarner Losh #include "stand.h"
45ca987d46SWarner Losh 
46ca987d46SWarner Losh /*
47ca987d46SWarner Losh  * Note that stdarg.h and the ANSI style va_start macro is used for both
48ca987d46SWarner Losh  * ANSI and traditional C compilers.
49ca987d46SWarner Losh  */
50ca987d46SWarner Losh #include <machine/stdarg.h>
51ca987d46SWarner Losh 
52ca987d46SWarner Losh #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
53ca987d46SWarner Losh 
54ca987d46SWarner Losh typedef void (kvprintf_fn_t)(int, void *);
55ca987d46SWarner Losh 
56ca987d46SWarner Losh static char	*ksprintn (char *buf, uintmax_t num, int base, int *len, int upper);
57ca987d46SWarner Losh static int	kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap);
58ca987d46SWarner Losh 
59ca987d46SWarner Losh static void
putchar_wrapper(int cc,void * arg)60ca987d46SWarner Losh putchar_wrapper(int cc, void *arg)
61ca987d46SWarner Losh {
62ca987d46SWarner Losh 
63ca987d46SWarner Losh 	putchar(cc);
64ca987d46SWarner Losh }
65ca987d46SWarner Losh 
66ca987d46SWarner Losh int
printf(const char * fmt,...)67ca987d46SWarner Losh printf(const char *fmt, ...)
68ca987d46SWarner Losh {
69ca987d46SWarner Losh 	va_list ap;
70ca987d46SWarner Losh 	int retval;
71ca987d46SWarner Losh 
72ca987d46SWarner Losh 	va_start(ap, fmt);
73ca987d46SWarner Losh 	retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap);
74ca987d46SWarner Losh 	va_end(ap);
75ca987d46SWarner Losh 	return retval;
76ca987d46SWarner Losh }
77ca987d46SWarner Losh 
783e9c7874SIan Lepore int
vprintf(const char * fmt,va_list ap)79ca987d46SWarner Losh vprintf(const char *fmt, va_list ap)
80ca987d46SWarner Losh {
81ca987d46SWarner Losh 
823e9c7874SIan Lepore 	return (kvprintf(fmt, putchar_wrapper, NULL, 10, ap));
83ca987d46SWarner Losh }
84ca987d46SWarner Losh 
85ca987d46SWarner Losh int
sprintf(char * buf,const char * cfmt,...)86ca987d46SWarner Losh sprintf(char *buf, const char *cfmt, ...)
87ca987d46SWarner Losh {
88ca987d46SWarner Losh 	int retval;
89ca987d46SWarner Losh 	va_list ap;
90ca987d46SWarner Losh 
91ca987d46SWarner Losh 	va_start(ap, cfmt);
92ca987d46SWarner Losh 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
93ca987d46SWarner Losh 	buf[retval] = '\0';
94ca987d46SWarner Losh 	va_end(ap);
95ca987d46SWarner Losh 	return retval;
96ca987d46SWarner Losh }
97ca987d46SWarner Losh 
98ca987d46SWarner Losh struct print_buf {
99ca987d46SWarner Losh 	char *buf;
100ca987d46SWarner Losh 	size_t size;
101ca987d46SWarner Losh };
102ca987d46SWarner Losh 
103ca987d46SWarner Losh static void
snprint_func(int ch,void * arg)104ca987d46SWarner Losh snprint_func(int ch, void *arg)
105ca987d46SWarner Losh {
106ca987d46SWarner Losh 	struct print_buf *pbuf = arg;
107ca987d46SWarner Losh 
108ca987d46SWarner Losh 	if (pbuf->size < 2) {
109ca987d46SWarner Losh 		/*
110ca987d46SWarner Losh 		 * Reserve last buffer position for the terminating
111ca987d46SWarner Losh 		 * character:
112ca987d46SWarner Losh 		 */
113ca987d46SWarner Losh 		return;
114ca987d46SWarner Losh 	}
115ca987d46SWarner Losh 	*(pbuf->buf)++ = ch;
116ca987d46SWarner Losh 	pbuf->size--;
117ca987d46SWarner Losh }
118ca987d46SWarner Losh 
119ca987d46SWarner Losh int
asprintf(char ** buf,const char * cfmt,...)1205e84b578SToomas Soome asprintf(char **buf, const char *cfmt, ...)
1215e84b578SToomas Soome {
1225e84b578SToomas Soome 	int retval;
1235e84b578SToomas Soome 	struct print_buf arg;
1245e84b578SToomas Soome 	va_list ap;
1255e84b578SToomas Soome 
1265e84b578SToomas Soome 	*buf = NULL;
1275e84b578SToomas Soome 	va_start(ap, cfmt);
1285e84b578SToomas Soome 	retval = kvprintf(cfmt, NULL, NULL, 10, ap);
1295e84b578SToomas Soome 	va_end(ap);
1305e84b578SToomas Soome 	if (retval <= 0)
1315e84b578SToomas Soome 		return (-1);
1325e84b578SToomas Soome 
1335e84b578SToomas Soome 	arg.size = retval + 1;
1345e84b578SToomas Soome 	arg.buf = *buf = malloc(arg.size);
1355e84b578SToomas Soome 	if (*buf == NULL)
1365e84b578SToomas Soome 		return (-1);
1375e84b578SToomas Soome 
1385e84b578SToomas Soome 	va_start(ap, cfmt);
1395e84b578SToomas Soome 	retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap);
1405e84b578SToomas Soome 	va_end(ap);
1415e84b578SToomas Soome 
1425e84b578SToomas Soome 	if (arg.size >= 1)
1435e84b578SToomas Soome 		*(arg.buf)++ = 0;
1445e84b578SToomas Soome 	return (retval);
1455e84b578SToomas Soome }
1465e84b578SToomas Soome 
1475e84b578SToomas Soome int
snprintf(char * buf,size_t size,const char * cfmt,...)148ca987d46SWarner Losh snprintf(char *buf, size_t size, const char *cfmt, ...)
149ca987d46SWarner Losh {
150ca987d46SWarner Losh 	int retval;
151ca987d46SWarner Losh 	va_list ap;
152ca987d46SWarner Losh 	struct print_buf arg;
153ca987d46SWarner Losh 
154ca987d46SWarner Losh 	arg.buf = buf;
155ca987d46SWarner Losh 	arg.size = size;
156ca987d46SWarner Losh 
157ca987d46SWarner Losh 	va_start(ap, cfmt);
158ca987d46SWarner Losh 	retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap);
159ca987d46SWarner Losh 	va_end(ap);
160ca987d46SWarner Losh 
161ca987d46SWarner Losh 	if (arg.size >= 1)
162ca987d46SWarner Losh 		*(arg.buf)++ = 0;
163ca987d46SWarner Losh 	return retval;
164ca987d46SWarner Losh }
165ca987d46SWarner Losh 
1663e9c7874SIan Lepore int
vsnprintf(char * buf,size_t size,const char * cfmt,va_list ap)1671851d70dSIan Lepore vsnprintf(char *buf, size_t size, const char *cfmt, va_list ap)
1681851d70dSIan Lepore {
1691851d70dSIan Lepore 	struct print_buf arg;
1703e9c7874SIan Lepore 	int retval;
1711851d70dSIan Lepore 
1721851d70dSIan Lepore 	arg.buf = buf;
1731851d70dSIan Lepore 	arg.size = size;
1741851d70dSIan Lepore 
1753e9c7874SIan Lepore 	retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap);
1761851d70dSIan Lepore 
1771851d70dSIan Lepore 	if (arg.size >= 1)
1781851d70dSIan Lepore 		*(arg.buf)++ = 0;
1793e9c7874SIan Lepore 
1803e9c7874SIan Lepore 	return (retval);
1811851d70dSIan Lepore }
1821851d70dSIan Lepore 
1833e9c7874SIan Lepore int
vsprintf(char * buf,const char * cfmt,va_list ap)184ca987d46SWarner Losh vsprintf(char *buf, const char *cfmt, va_list ap)
185ca987d46SWarner Losh {
186ca987d46SWarner Losh 	int	retval;
187ca987d46SWarner Losh 
188ca987d46SWarner Losh 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
189ca987d46SWarner Losh 	buf[retval] = '\0';
1903e9c7874SIan Lepore 
1913e9c7874SIan Lepore 	return (retval);
192ca987d46SWarner Losh }
193ca987d46SWarner Losh 
194ca987d46SWarner Losh /*
195ca987d46SWarner Losh  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
196ca987d46SWarner Losh  * order; return an optional length and a pointer to the last character
197ca987d46SWarner Losh  * written in the buffer (i.e., the first character of the string).
198ca987d46SWarner Losh  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
199ca987d46SWarner Losh  */
200ca987d46SWarner Losh static char *
ksprintn(char * nbuf,uintmax_t num,int base,int * lenp,int upper)201ca987d46SWarner Losh ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
202ca987d46SWarner Losh {
203ca987d46SWarner Losh 	char *p, c;
204ca987d46SWarner Losh 
205ca987d46SWarner Losh 	p = nbuf;
206ca987d46SWarner Losh 	*p = '\0';
207ca987d46SWarner Losh 	do {
208ca987d46SWarner Losh 		c = hex2ascii(num % base);
209ca987d46SWarner Losh 		*++p = upper ? toupper(c) : c;
210ca987d46SWarner Losh 	} while (num /= base);
211ca987d46SWarner Losh 	if (lenp)
212ca987d46SWarner Losh 		*lenp = p - nbuf;
213ca987d46SWarner Losh 	return (p);
214ca987d46SWarner Losh }
215ca987d46SWarner Losh 
216ca987d46SWarner Losh /*
217ca987d46SWarner Losh  * Scaled down version of printf(3).
218ca987d46SWarner Losh  *
219ca987d46SWarner Losh  * Two additional formats:
220ca987d46SWarner Losh  *
221ca987d46SWarner Losh  * The format %b is supported to decode error registers.
222ca987d46SWarner Losh  * Its usage is:
223ca987d46SWarner Losh  *
224ca987d46SWarner Losh  *	printf("reg=%b\n", regval, "<base><arg>*");
225ca987d46SWarner Losh  *
226ca987d46SWarner Losh  * where <base> is the output base expressed as a control character, e.g.
227ca987d46SWarner Losh  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
228ca987d46SWarner Losh  * the first of which gives the bit number to be inspected (origin 1), and
229ca987d46SWarner Losh  * the next characters (up to a control character, i.e. a character <= 32),
230ca987d46SWarner Losh  * give the name of the register.  Thus:
231ca987d46SWarner Losh  *
232ca987d46SWarner Losh  *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
233ca987d46SWarner Losh  *
234ca987d46SWarner Losh  * would produce output:
235ca987d46SWarner Losh  *
236ca987d46SWarner Losh  *	reg=3<BITTWO,BITONE>
237ca987d46SWarner Losh  *
238ca987d46SWarner Losh  * XXX:  %D  -- Hexdump, takes pointer and separator string:
239ca987d46SWarner Losh  *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
240ca987d46SWarner Losh  *		("%*D", len, ptr, " " -> XX XX XX XX ...
241ca987d46SWarner Losh  */
242ca987d46SWarner Losh static int
kvprintf(char const * fmt,kvprintf_fn_t * func,void * arg,int radix,va_list ap)243ca987d46SWarner Losh kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap)
244ca987d46SWarner Losh {
24598e28b71SToomas Soome #define PCHAR(c) { \
24698e28b71SToomas Soome 	int cc = (c);				\
24798e28b71SToomas Soome 						\
24898e28b71SToomas Soome 	if (func) {				\
24998e28b71SToomas Soome 		(*func)(cc, arg);		\
25098e28b71SToomas Soome 	} else if (d != NULL) {			\
25198e28b71SToomas Soome 		*d++ = cc;			\
25298e28b71SToomas Soome 	}					\
25398e28b71SToomas Soome 	retval++;				\
25498e28b71SToomas Soome 	}
25598e28b71SToomas Soome 
256ca987d46SWarner Losh 	char nbuf[MAXNBUF];
257ca987d46SWarner Losh 	char *d;
258ca987d46SWarner Losh 	const char *p, *percent, *q;
259ca987d46SWarner Losh 	uint16_t *S;
260ca987d46SWarner Losh 	u_char *up;
261ca987d46SWarner Losh 	int ch, n;
262ca987d46SWarner Losh 	uintmax_t num;
263ca987d46SWarner Losh 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
264ca987d46SWarner Losh 	int cflag, hflag, jflag, tflag, zflag;
265ca987d46SWarner Losh 	int dwidth, upper;
266ca987d46SWarner Losh 	char padc;
267ca987d46SWarner Losh 	int stop = 0, retval = 0;
268ca987d46SWarner Losh 
2690a35c4b3SColin Percival 	TSENTER();
270ca987d46SWarner Losh 	num = 0;
271ca987d46SWarner Losh 	if (!func)
272ca987d46SWarner Losh 		d = (char *) arg;
273ca987d46SWarner Losh 	else
274ca987d46SWarner Losh 		d = NULL;
275ca987d46SWarner Losh 
276ca987d46SWarner Losh 	if (fmt == NULL)
277ca987d46SWarner Losh 		fmt = "(fmt null)\n";
278ca987d46SWarner Losh 
279ca987d46SWarner Losh 	if (radix < 2 || radix > 36)
280ca987d46SWarner Losh 		radix = 10;
281ca987d46SWarner Losh 
282ca987d46SWarner Losh 	for (;;) {
283ca987d46SWarner Losh 		padc = ' ';
284ca987d46SWarner Losh 		width = 0;
285ca987d46SWarner Losh 		while ((ch = (u_char)*fmt++) != '%' || stop) {
2860a35c4b3SColin Percival 			if (ch == '\0') {
2870a35c4b3SColin Percival 				TSEXIT();
288ca987d46SWarner Losh 				return (retval);
2890a35c4b3SColin Percival 			}
290ca987d46SWarner Losh 			PCHAR(ch);
291ca987d46SWarner Losh 		}
292ca987d46SWarner Losh 		percent = fmt - 1;
293ca987d46SWarner Losh 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
294ca987d46SWarner Losh 		sign = 0; dot = 0; dwidth = 0; upper = 0;
295ca987d46SWarner Losh 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
296ca987d46SWarner Losh reswitch:	switch (ch = (u_char)*fmt++) {
297ca987d46SWarner Losh 		case '.':
298ca987d46SWarner Losh 			dot = 1;
299ca987d46SWarner Losh 			goto reswitch;
300ca987d46SWarner Losh 		case '#':
301ca987d46SWarner Losh 			sharpflag = 1;
302ca987d46SWarner Losh 			goto reswitch;
303ca987d46SWarner Losh 		case '+':
304ca987d46SWarner Losh 			sign = 1;
305ca987d46SWarner Losh 			goto reswitch;
306ca987d46SWarner Losh 		case '-':
307ca987d46SWarner Losh 			ladjust = 1;
308ca987d46SWarner Losh 			goto reswitch;
309ca987d46SWarner Losh 		case '%':
310ca987d46SWarner Losh 			PCHAR(ch);
311ca987d46SWarner Losh 			break;
312ca987d46SWarner Losh 		case '*':
313ca987d46SWarner Losh 			if (!dot) {
314ca987d46SWarner Losh 				width = va_arg(ap, int);
315ca987d46SWarner Losh 				if (width < 0) {
316ca987d46SWarner Losh 					ladjust = !ladjust;
317ca987d46SWarner Losh 					width = -width;
318ca987d46SWarner Losh 				}
319ca987d46SWarner Losh 			} else {
320ca987d46SWarner Losh 				dwidth = va_arg(ap, int);
321ca987d46SWarner Losh 			}
322ca987d46SWarner Losh 			goto reswitch;
323ca987d46SWarner Losh 		case '0':
324ca987d46SWarner Losh 			if (!dot) {
325ca987d46SWarner Losh 				padc = '0';
326ca987d46SWarner Losh 				goto reswitch;
327ca987d46SWarner Losh 			}
328ca987d46SWarner Losh 		case '1': case '2': case '3': case '4':
329ca987d46SWarner Losh 		case '5': case '6': case '7': case '8': case '9':
330ca987d46SWarner Losh 				for (n = 0;; ++fmt) {
331ca987d46SWarner Losh 					n = n * 10 + ch - '0';
332ca987d46SWarner Losh 					ch = *fmt;
333ca987d46SWarner Losh 					if (ch < '0' || ch > '9')
334ca987d46SWarner Losh 						break;
335ca987d46SWarner Losh 				}
336ca987d46SWarner Losh 			if (dot)
337ca987d46SWarner Losh 				dwidth = n;
338ca987d46SWarner Losh 			else
339ca987d46SWarner Losh 				width = n;
340ca987d46SWarner Losh 			goto reswitch;
341ca987d46SWarner Losh 		case 'b':
342ca987d46SWarner Losh 			num = (u_int)va_arg(ap, int);
343ca987d46SWarner Losh 			p = va_arg(ap, char *);
344ca987d46SWarner Losh 			for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
345ca987d46SWarner Losh 				PCHAR(*q--);
346ca987d46SWarner Losh 
347ca987d46SWarner Losh 			if (num == 0)
348ca987d46SWarner Losh 				break;
349ca987d46SWarner Losh 
350ca987d46SWarner Losh 			for (tmp = 0; *p;) {
351ca987d46SWarner Losh 				n = *p++;
352ca987d46SWarner Losh 				if (num & (1 << (n - 1))) {
353ca987d46SWarner Losh 					PCHAR(tmp ? ',' : '<');
354ca987d46SWarner Losh 					for (; (n = *p) > ' '; ++p)
355ca987d46SWarner Losh 						PCHAR(n);
356ca987d46SWarner Losh 					tmp = 1;
357ca987d46SWarner Losh 				} else
358ca987d46SWarner Losh 					for (; *p > ' '; ++p)
359ca987d46SWarner Losh 						continue;
360ca987d46SWarner Losh 			}
361ca987d46SWarner Losh 			if (tmp)
362ca987d46SWarner Losh 				PCHAR('>');
363ca987d46SWarner Losh 			break;
364ca987d46SWarner Losh 		case 'c':
365ca987d46SWarner Losh 			PCHAR(va_arg(ap, int));
366ca987d46SWarner Losh 			break;
367ca987d46SWarner Losh 		case 'D':
368ca987d46SWarner Losh 			up = va_arg(ap, u_char *);
369ca987d46SWarner Losh 			p = va_arg(ap, char *);
370ca987d46SWarner Losh 			if (!width)
371ca987d46SWarner Losh 				width = 16;
372ca987d46SWarner Losh 			while(width--) {
373ca987d46SWarner Losh 				PCHAR(hex2ascii(*up >> 4));
374ca987d46SWarner Losh 				PCHAR(hex2ascii(*up & 0x0f));
375ca987d46SWarner Losh 				up++;
376ca987d46SWarner Losh 				if (width)
377ca987d46SWarner Losh 					for (q=p;*q;q++)
378ca987d46SWarner Losh 						PCHAR(*q);
379ca987d46SWarner Losh 			}
380ca987d46SWarner Losh 			break;
381ca987d46SWarner Losh 		case 'd':
382ca987d46SWarner Losh 		case 'i':
383ca987d46SWarner Losh 			base = 10;
384ca987d46SWarner Losh 			sign = 1;
385ca987d46SWarner Losh 			goto handle_sign;
386ca987d46SWarner Losh 		case 'h':
387ca987d46SWarner Losh 			if (hflag) {
388ca987d46SWarner Losh 				hflag = 0;
389ca987d46SWarner Losh 				cflag = 1;
390ca987d46SWarner Losh 			} else
391ca987d46SWarner Losh 				hflag = 1;
392ca987d46SWarner Losh 			goto reswitch;
393ca987d46SWarner Losh 		case 'j':
394ca987d46SWarner Losh 			jflag = 1;
395ca987d46SWarner Losh 			goto reswitch;
396ca987d46SWarner Losh 		case 'l':
397ca987d46SWarner Losh 			if (lflag) {
398ca987d46SWarner Losh 				lflag = 0;
399ca987d46SWarner Losh 				qflag = 1;
400ca987d46SWarner Losh 			} else
401ca987d46SWarner Losh 				lflag = 1;
402ca987d46SWarner Losh 			goto reswitch;
403ca987d46SWarner Losh 		case 'n':
404ca987d46SWarner Losh 			if (jflag)
405ca987d46SWarner Losh 				*(va_arg(ap, intmax_t *)) = retval;
406ca987d46SWarner Losh 			else if (qflag)
407ca987d46SWarner Losh 				*(va_arg(ap, quad_t *)) = retval;
408ca987d46SWarner Losh 			else if (lflag)
409ca987d46SWarner Losh 				*(va_arg(ap, long *)) = retval;
410ca987d46SWarner Losh 			else if (zflag)
411ca987d46SWarner Losh 				*(va_arg(ap, size_t *)) = retval;
412ca987d46SWarner Losh 			else if (hflag)
413ca987d46SWarner Losh 				*(va_arg(ap, short *)) = retval;
414ca987d46SWarner Losh 			else if (cflag)
415ca987d46SWarner Losh 				*(va_arg(ap, char *)) = retval;
416ca987d46SWarner Losh 			else
417ca987d46SWarner Losh 				*(va_arg(ap, int *)) = retval;
418ca987d46SWarner Losh 			break;
419ca987d46SWarner Losh 		case 'o':
420ca987d46SWarner Losh 			base = 8;
421ca987d46SWarner Losh 			goto handle_nosign;
422ca987d46SWarner Losh 		case 'p':
423ca987d46SWarner Losh 			base = 16;
424ca987d46SWarner Losh 			sharpflag = (width == 0);
425ca987d46SWarner Losh 			sign = 0;
426ca987d46SWarner Losh 			num = (uintptr_t)va_arg(ap, void *);
427ca987d46SWarner Losh 			goto number;
428ca987d46SWarner Losh 		case 'q':
429ca987d46SWarner Losh 			qflag = 1;
430ca987d46SWarner Losh 			goto reswitch;
431ca987d46SWarner Losh 		case 'r':
432ca987d46SWarner Losh 			base = radix;
433ca987d46SWarner Losh 			if (sign)
434ca987d46SWarner Losh 				goto handle_sign;
435ca987d46SWarner Losh 			goto handle_nosign;
436ca987d46SWarner Losh 		case 's':
437ca987d46SWarner Losh 			p = va_arg(ap, char *);
438ca987d46SWarner Losh 			if (p == NULL)
439ca987d46SWarner Losh 				p = "(null)";
440ca987d46SWarner Losh 			if (!dot)
441ca987d46SWarner Losh 				n = strlen (p);
442ca987d46SWarner Losh 			else
443ca987d46SWarner Losh 				for (n = 0; n < dwidth && p[n]; n++)
444ca987d46SWarner Losh 					continue;
445ca987d46SWarner Losh 
446ca987d46SWarner Losh 			width -= n;
447ca987d46SWarner Losh 
448ca987d46SWarner Losh 			if (!ladjust && width > 0)
449ca987d46SWarner Losh 				while (width--)
450ca987d46SWarner Losh 					PCHAR(padc);
451ca987d46SWarner Losh 			while (n--)
452ca987d46SWarner Losh 				PCHAR(*p++);
453ca987d46SWarner Losh 			if (ladjust && width > 0)
454ca987d46SWarner Losh 				while (width--)
455ca987d46SWarner Losh 					PCHAR(padc);
456ca987d46SWarner Losh 			break;
457ca987d46SWarner Losh 		case 'S':	/* Assume console can cope with wide chars */
458ca987d46SWarner Losh 			for (S = va_arg(ap, uint16_t *); *S != 0; S++)
459ca987d46SWarner Losh 				PCHAR(*S);
460ca987d46SWarner Losh  			break;
461ca987d46SWarner Losh 		case 't':
462ca987d46SWarner Losh 			tflag = 1;
463ca987d46SWarner Losh 			goto reswitch;
464ca987d46SWarner Losh 		case 'u':
465ca987d46SWarner Losh 			base = 10;
466ca987d46SWarner Losh 			goto handle_nosign;
467ca987d46SWarner Losh 		case 'X':
468ca987d46SWarner Losh 			upper = 1;
469ca987d46SWarner Losh 		case 'x':
470ca987d46SWarner Losh 			base = 16;
471ca987d46SWarner Losh 			goto handle_nosign;
472ca987d46SWarner Losh 		case 'y':
473ca987d46SWarner Losh 			base = 16;
474ca987d46SWarner Losh 			sign = 1;
475ca987d46SWarner Losh 			goto handle_sign;
476ca987d46SWarner Losh 		case 'z':
477ca987d46SWarner Losh 			zflag = 1;
478ca987d46SWarner Losh 			goto reswitch;
479ca987d46SWarner Losh handle_nosign:
480ca987d46SWarner Losh 			sign = 0;
481ca987d46SWarner Losh 			if (jflag)
482ca987d46SWarner Losh 				num = va_arg(ap, uintmax_t);
483ca987d46SWarner Losh 			else if (qflag)
484ca987d46SWarner Losh 				num = va_arg(ap, u_quad_t);
485ca987d46SWarner Losh 			else if (tflag)
486ca987d46SWarner Losh 				num = va_arg(ap, ptrdiff_t);
487ca987d46SWarner Losh 			else if (lflag)
488ca987d46SWarner Losh 				num = va_arg(ap, u_long);
489ca987d46SWarner Losh 			else if (zflag)
490ca987d46SWarner Losh 				num = va_arg(ap, size_t);
491ca987d46SWarner Losh 			else if (hflag)
492ca987d46SWarner Losh 				num = (u_short)va_arg(ap, int);
493ca987d46SWarner Losh 			else if (cflag)
494ca987d46SWarner Losh 				num = (u_char)va_arg(ap, int);
495ca987d46SWarner Losh 			else
496ca987d46SWarner Losh 				num = va_arg(ap, u_int);
497ca987d46SWarner Losh 			goto number;
498ca987d46SWarner Losh handle_sign:
499ca987d46SWarner Losh 			if (jflag)
500ca987d46SWarner Losh 				num = va_arg(ap, intmax_t);
501ca987d46SWarner Losh 			else if (qflag)
502ca987d46SWarner Losh 				num = va_arg(ap, quad_t);
503ca987d46SWarner Losh 			else if (tflag)
504ca987d46SWarner Losh 				num = va_arg(ap, ptrdiff_t);
505ca987d46SWarner Losh 			else if (lflag)
506ca987d46SWarner Losh 				num = va_arg(ap, long);
507ca987d46SWarner Losh 			else if (zflag)
508ca987d46SWarner Losh 				num = va_arg(ap, ssize_t);
509ca987d46SWarner Losh 			else if (hflag)
510ca987d46SWarner Losh 				num = (short)va_arg(ap, int);
511ca987d46SWarner Losh 			else if (cflag)
512ca987d46SWarner Losh 				num = (char)va_arg(ap, int);
513ca987d46SWarner Losh 			else
514ca987d46SWarner Losh 				num = va_arg(ap, int);
515ca987d46SWarner Losh number:
516ca987d46SWarner Losh 			if (sign && (intmax_t)num < 0) {
517ca987d46SWarner Losh 				neg = 1;
518ca987d46SWarner Losh 				num = -(intmax_t)num;
519ca987d46SWarner Losh 			}
520ca987d46SWarner Losh 			p = ksprintn(nbuf, num, base, &n, upper);
521ca987d46SWarner Losh 			tmp = 0;
522ca987d46SWarner Losh 			if (sharpflag && num != 0) {
523ca987d46SWarner Losh 				if (base == 8)
524ca987d46SWarner Losh 					tmp++;
525ca987d46SWarner Losh 				else if (base == 16)
526ca987d46SWarner Losh 					tmp += 2;
527ca987d46SWarner Losh 			}
528ca987d46SWarner Losh 			if (neg)
529ca987d46SWarner Losh 				tmp++;
530ca987d46SWarner Losh 
531ca987d46SWarner Losh 			if (!ladjust && padc == '0')
532ca987d46SWarner Losh 				dwidth = width - tmp;
533ca987d46SWarner Losh 			width -= tmp + imax(dwidth, n);
534ca987d46SWarner Losh 			dwidth -= n;
535ca987d46SWarner Losh 			if (!ladjust)
536ca987d46SWarner Losh 				while (width-- > 0)
537ca987d46SWarner Losh 					PCHAR(' ');
538ca987d46SWarner Losh 			if (neg)
539ca987d46SWarner Losh 				PCHAR('-');
540ca987d46SWarner Losh 			if (sharpflag && num != 0) {
541ca987d46SWarner Losh 				if (base == 8) {
542ca987d46SWarner Losh 					PCHAR('0');
543ca987d46SWarner Losh 				} else if (base == 16) {
544ca987d46SWarner Losh 					PCHAR('0');
545ca987d46SWarner Losh 					PCHAR('x');
546ca987d46SWarner Losh 				}
547ca987d46SWarner Losh 			}
548ca987d46SWarner Losh 			while (dwidth-- > 0)
549ca987d46SWarner Losh 				PCHAR('0');
550ca987d46SWarner Losh 
551ca987d46SWarner Losh 			while (*p)
552ca987d46SWarner Losh 				PCHAR(*p--);
553ca987d46SWarner Losh 
554ca987d46SWarner Losh 			if (ladjust)
555ca987d46SWarner Losh 				while (width-- > 0)
556ca987d46SWarner Losh 					PCHAR(' ');
557ca987d46SWarner Losh 
558ca987d46SWarner Losh 			break;
559ca987d46SWarner Losh 		default:
560ca987d46SWarner Losh 			while (percent < fmt)
561ca987d46SWarner Losh 				PCHAR(*percent++);
562ca987d46SWarner Losh 			/*
563ca987d46SWarner Losh 			 * Since we ignore a formatting argument it is no
564ca987d46SWarner Losh 			 * longer safe to obey the remaining formatting
565ca987d46SWarner Losh 			 * arguments as the arguments will no longer match
566ca987d46SWarner Losh 			 * the format specs.
567ca987d46SWarner Losh 			 */
568ca987d46SWarner Losh 			stop = 1;
569ca987d46SWarner Losh 			break;
570ca987d46SWarner Losh 		}
571ca987d46SWarner Losh 	}
572ca987d46SWarner Losh #undef PCHAR
573ca987d46SWarner Losh }
574