printf.c revision 185037
138451Smsmith/*-
238451Smsmith * Copyright (c) 1986, 1988, 1991, 1993
338451Smsmith *	The Regents of the University of California.  All rights reserved.
438451Smsmith * (c) UNIX System Laboratories, Inc.
538451Smsmith * All or some portions of this file are derived from material licensed
638451Smsmith * to the University of California by American Telephone and Telegraph
738451Smsmith * Co. or Unix System Laboratories, Inc. and are reproduced herein with
838451Smsmith * the permission of UNIX System Laboratories, Inc.
938451Smsmith *
1038451Smsmith * Redistribution and use in source and binary forms, with or without
1138451Smsmith * modification, are permitted provided that the following conditions
1238451Smsmith * are met:
1338451Smsmith * 1. Redistributions of source code must retain the above copyright
1438451Smsmith *    notice, this list of conditions and the following disclaimer.
1538451Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1638451Smsmith *    notice, this list of conditions and the following disclaimer in the
1738451Smsmith *    documentation and/or other materials provided with the distribution.
1838451Smsmith * 4. Neither the name of the University nor the names of its contributors
1938451Smsmith *    may be used to endorse or promote products derived from this software
2038451Smsmith *    without specific prior written permission.
2138451Smsmith *
2238451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2338451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2438451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2538451Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2638451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2738451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2838451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2938451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3038451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3138451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3238451Smsmith * SUCH DAMAGE.
3338451Smsmith *
3438451Smsmith *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
3538451Smsmith */
3638451Smsmith
3784221Sdillon#include <sys/cdefs.h>
3884221Sdillon__FBSDID("$FreeBSD: head/lib/libstand/printf.c 185037 2008-11-18 00:01:16Z delphij $");
3984221Sdillon
4038451Smsmith/*
4138451Smsmith * Standaloneified version of the FreeBSD kernel printf family.
4238451Smsmith */
4338451Smsmith
4438451Smsmith#include <sys/types.h>
45113159Speter#include <sys/stddef.h>
46113159Speter#include <sys/stdint.h>
47103949Smike#include <limits.h>
4855137Speter#include <string.h>
4938451Smsmith#include "stand.h"
5038451Smsmith
5138451Smsmith/*
5238451Smsmith * Note that stdarg.h and the ANSI style va_start macro is used for both
5338451Smsmith * ANSI and traditional C compilers.
5438451Smsmith */
5538451Smsmith#include <machine/stdarg.h>
5638451Smsmith
57113159Speter#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
58113159Speter
59156518Sjkimstatic char	*ksprintn (char *buf, uintmax_t num, int base, int *len, int upper);
6038451Smsmithstatic int	kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
6138451Smsmith
6238451Smsmithint
6338451Smsmithprintf(const char *fmt, ...)
6438451Smsmith{
6538451Smsmith	va_list ap;
6638451Smsmith	int retval;
6738451Smsmith
6838451Smsmith	va_start(ap, fmt);
6938451Smsmith	retval = kvprintf(fmt, putchar, NULL, 10, ap);
7038451Smsmith	va_end(ap);
7138451Smsmith	return retval;
7238451Smsmith}
7338451Smsmith
7438451Smsmithvoid
7538451Smsmithvprintf(const char *fmt, va_list ap)
7638451Smsmith{
7738451Smsmith
7838451Smsmith	kvprintf(fmt, putchar, NULL, 10, ap);
7938451Smsmith}
8038451Smsmith
8138451Smsmithint
8238451Smsmithsprintf(char *buf, const char *cfmt, ...)
8338451Smsmith{
8438451Smsmith	int retval;
8538451Smsmith	va_list ap;
8638451Smsmith
8738451Smsmith	va_start(ap, cfmt);
8838451Smsmith	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
8938451Smsmith	buf[retval] = '\0';
9038451Smsmith	va_end(ap);
9138451Smsmith	return retval;
9238451Smsmith}
9338451Smsmith
9440805Smsmithvoid
9540805Smsmithvsprintf(char *buf, const char *cfmt, va_list ap)
9640805Smsmith{
9740805Smsmith	int	retval;
9840805Smsmith
9940805Smsmith	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
10040805Smsmith	buf[retval] = '\0';
10140805Smsmith}
10240805Smsmith
10338451Smsmith/*
104113159Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
105113159Speter * order; return an optional length and a pointer to the last character
106113159Speter * written in the buffer (i.e., the first character of the string).
107113159Speter * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
10838451Smsmith */
10938451Smsmithstatic char *
110156518Sjkimksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
111113159Speter{
112156518Sjkim	char *p, c;
11338451Smsmith
114113159Speter	p = nbuf;
115113159Speter	*p = '\0';
11638451Smsmith	do {
117156518Sjkim		c = hex2ascii(num % base);
118156518Sjkim		*++p = upper ? toupper(c) : c;
119113159Speter	} while (num /= base);
12038451Smsmith	if (lenp)
121113159Speter		*lenp = p - nbuf;
12238451Smsmith	return (p);
12338451Smsmith}
12438451Smsmith
12538451Smsmith/*
12638451Smsmith * Scaled down version of printf(3).
12738451Smsmith *
12838451Smsmith * Two additional formats:
12938451Smsmith *
13038451Smsmith * The format %b is supported to decode error registers.
13138451Smsmith * Its usage is:
13238451Smsmith *
13338451Smsmith *	printf("reg=%b\n", regval, "<base><arg>*");
13438451Smsmith *
13538451Smsmith * where <base> is the output base expressed as a control character, e.g.
13638451Smsmith * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
13738451Smsmith * the first of which gives the bit number to be inspected (origin 1), and
13838451Smsmith * the next characters (up to a control character, i.e. a character <= 32),
13938451Smsmith * give the name of the register.  Thus:
14038451Smsmith *
14138451Smsmith *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
14238451Smsmith *
14338451Smsmith * would produce output:
14438451Smsmith *
14538451Smsmith *	reg=3<BITTWO,BITONE>
14638451Smsmith *
14738451Smsmith * XXX:  %D  -- Hexdump, takes pointer and separator string:
14838451Smsmith *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
14938451Smsmith *		("%*D", len, ptr, " " -> XX XX XX XX ...
15038451Smsmith */
15138451Smsmithstatic int
15238451Smsmithkvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
15338451Smsmith{
15438451Smsmith#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
155113159Speter	char nbuf[MAXNBUF];
156113159Speter	char *d;
157113159Speter	const char *p, *percent, *q;
15838451Smsmith	u_char *up;
15938451Smsmith	int ch, n;
160113159Speter	uintmax_t num;
161113159Speter	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
162113159Speter	int jflag, tflag, zflag;
163156518Sjkim	int dwidth, upper;
16438451Smsmith	char padc;
16538451Smsmith	int retval = 0;
16638451Smsmith
167113159Speter	num = 0;
16838451Smsmith	if (!func)
16938451Smsmith		d = (char *) arg;
17038451Smsmith	else
17138451Smsmith		d = NULL;
17238451Smsmith
17338451Smsmith	if (fmt == NULL)
17438451Smsmith		fmt = "(fmt null)\n";
17538451Smsmith
17638451Smsmith	if (radix < 2 || radix > 36)
17738451Smsmith		radix = 10;
17838451Smsmith
17938451Smsmith	for (;;) {
18038451Smsmith		padc = ' ';
18138451Smsmith		width = 0;
18238451Smsmith		while ((ch = (u_char)*fmt++) != '%') {
183113159Speter			if (ch == '\0')
184113159Speter				return (retval);
18538451Smsmith			PCHAR(ch);
18638451Smsmith		}
187113159Speter		percent = fmt - 1;
188113159Speter		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
189156518Sjkim		sign = 0; dot = 0; dwidth = 0; upper = 0;
190113159Speter		jflag = 0; tflag = 0; zflag = 0;
19138451Smsmithreswitch:	switch (ch = (u_char)*fmt++) {
19238451Smsmith		case '.':
19338451Smsmith			dot = 1;
19438451Smsmith			goto reswitch;
19538451Smsmith		case '#':
19638451Smsmith			sharpflag = 1;
19738451Smsmith			goto reswitch;
19838451Smsmith		case '+':
19938451Smsmith			sign = 1;
20038451Smsmith			goto reswitch;
20138451Smsmith		case '-':
20238451Smsmith			ladjust = 1;
20338451Smsmith			goto reswitch;
20438451Smsmith		case '%':
20538451Smsmith			PCHAR(ch);
20638451Smsmith			break;
20738451Smsmith		case '*':
20838451Smsmith			if (!dot) {
20938451Smsmith				width = va_arg(ap, int);
21038451Smsmith				if (width < 0) {
21138451Smsmith					ladjust = !ladjust;
21238451Smsmith					width = -width;
21338451Smsmith				}
21438451Smsmith			} else {
21538451Smsmith				dwidth = va_arg(ap, int);
21638451Smsmith			}
21738451Smsmith			goto reswitch;
21838451Smsmith		case '0':
21938451Smsmith			if (!dot) {
22038451Smsmith				padc = '0';
22138451Smsmith				goto reswitch;
22238451Smsmith			}
22338451Smsmith		case '1': case '2': case '3': case '4':
22438451Smsmith		case '5': case '6': case '7': case '8': case '9':
22538451Smsmith				for (n = 0;; ++fmt) {
22638451Smsmith					n = n * 10 + ch - '0';
22738451Smsmith					ch = *fmt;
22838451Smsmith					if (ch < '0' || ch > '9')
22938451Smsmith						break;
23038451Smsmith				}
23138451Smsmith			if (dot)
23238451Smsmith				dwidth = n;
23338451Smsmith			else
23438451Smsmith				width = n;
23538451Smsmith			goto reswitch;
23638451Smsmith		case 'b':
237113159Speter			num = va_arg(ap, int);
23838451Smsmith			p = va_arg(ap, char *);
239156518Sjkim			for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
24038451Smsmith				PCHAR(*q--);
24138451Smsmith
242113159Speter			if (num == 0)
24338451Smsmith				break;
24438451Smsmith
24538451Smsmith			for (tmp = 0; *p;) {
24638451Smsmith				n = *p++;
247113159Speter				if (num & (1 << (n - 1))) {
24838451Smsmith					PCHAR(tmp ? ',' : '<');
24938451Smsmith					for (; (n = *p) > ' '; ++p)
25038451Smsmith						PCHAR(n);
25138451Smsmith					tmp = 1;
25238451Smsmith				} else
25338451Smsmith					for (; *p > ' '; ++p)
25438451Smsmith						continue;
25538451Smsmith			}
25638451Smsmith			if (tmp)
25738451Smsmith				PCHAR('>');
25838451Smsmith			break;
25938451Smsmith		case 'c':
26038451Smsmith			PCHAR(va_arg(ap, int));
26138451Smsmith			break;
26238451Smsmith		case 'D':
26338451Smsmith			up = va_arg(ap, u_char *);
26438451Smsmith			p = va_arg(ap, char *);
26538451Smsmith			if (!width)
26638451Smsmith				width = 16;
26738451Smsmith			while(width--) {
26838451Smsmith				PCHAR(hex2ascii(*up >> 4));
26938451Smsmith				PCHAR(hex2ascii(*up & 0x0f));
27038451Smsmith				up++;
27138451Smsmith				if (width)
27238451Smsmith					for (q=p;*q;q++)
27338451Smsmith						PCHAR(*q);
27438451Smsmith			}
27538451Smsmith			break;
27638451Smsmith		case 'd':
277113159Speter		case 'i':
278113159Speter			base = 10;
27938451Smsmith			sign = 1;
280113159Speter			goto handle_sign;
281113159Speter		case 'j':
282113159Speter			jflag = 1;
283113159Speter			goto reswitch;
28438451Smsmith		case 'l':
285113159Speter			if (lflag) {
286113159Speter				lflag = 0;
287113159Speter				qflag = 1;
288113159Speter			} else
289113159Speter				lflag = 1;
29038451Smsmith			goto reswitch;
29138451Smsmith		case 'n':
292113159Speter			if (jflag)
293113159Speter				*(va_arg(ap, intmax_t *)) = retval;
294113159Speter			else if (qflag)
295113159Speter				*(va_arg(ap, quad_t *)) = retval;
296113159Speter			else if (lflag)
297113159Speter				*(va_arg(ap, long *)) = retval;
298113159Speter			else if (zflag)
299113159Speter				*(va_arg(ap, size_t *)) = retval;
300113159Speter			else
301113159Speter				*(va_arg(ap, int *)) = retval;
302113159Speter			break;
30338451Smsmith		case 'o':
30438451Smsmith			base = 8;
305113159Speter			goto handle_nosign;
30638451Smsmith		case 'p':
30738451Smsmith			base = 16;
308113159Speter			sharpflag = (width == 0);
309113159Speter			sign = 0;
310113159Speter			num = (uintptr_t)va_arg(ap, void *);
31138451Smsmith			goto number;
312113159Speter		case 'q':
313113159Speter			qflag = 1;
314113159Speter			goto reswitch;
315113159Speter		case 'r':
316113159Speter			base = radix;
317113159Speter			if (sign)
318113159Speter				goto handle_sign;
319113159Speter			goto handle_nosign;
32038451Smsmith		case 's':
32138451Smsmith			p = va_arg(ap, char *);
32238451Smsmith			if (p == NULL)
32338451Smsmith				p = "(null)";
32438451Smsmith			if (!dot)
32538451Smsmith				n = strlen (p);
32638451Smsmith			else
32738451Smsmith				for (n = 0; n < dwidth && p[n]; n++)
32838451Smsmith					continue;
32938451Smsmith
33038451Smsmith			width -= n;
33138451Smsmith
33238451Smsmith			if (!ladjust && width > 0)
33338451Smsmith				while (width--)
33438451Smsmith					PCHAR(padc);
33538451Smsmith			while (n--)
33638451Smsmith				PCHAR(*p++);
33738451Smsmith			if (ladjust && width > 0)
33838451Smsmith				while (width--)
33938451Smsmith					PCHAR(padc);
34038451Smsmith			break;
341113159Speter		case 't':
342113159Speter			tflag = 1;
343113159Speter			goto reswitch;
34438451Smsmith		case 'u':
34538451Smsmith			base = 10;
346113159Speter			goto handle_nosign;
347156518Sjkim		case 'X':
348156518Sjkim			upper = 1;
34938451Smsmith		case 'x':
35038451Smsmith			base = 16;
351113159Speter			goto handle_nosign;
352113159Speter		case 'y':
353113159Speter			base = 16;
354113159Speter			sign = 1;
355113159Speter			goto handle_sign;
356113159Speter		case 'z':
357113159Speter			zflag = 1;
358113159Speter			goto reswitch;
359113159Speterhandle_nosign:
360113159Speter			sign = 0;
361113159Speter			if (jflag)
362113159Speter				num = va_arg(ap, uintmax_t);
363113159Speter			else if (qflag)
364113159Speter				num = va_arg(ap, u_quad_t);
365113159Speter			else if (tflag)
366113159Speter				num = va_arg(ap, ptrdiff_t);
367113159Speter			else if (lflag)
368113159Speter				num = va_arg(ap, u_long);
369113159Speter			else if (zflag)
370113159Speter				num = va_arg(ap, size_t);
371113159Speter			else
372113159Speter				num = va_arg(ap, u_int);
373113159Speter			goto number;
374113159Speterhandle_sign:
375113159Speter			if (jflag)
376113159Speter				num = va_arg(ap, intmax_t);
377113159Speter			else if (qflag)
378113159Speter				num = va_arg(ap, quad_t);
379113159Speter			else if (tflag)
380113159Speter				num = va_arg(ap, ptrdiff_t);
381113159Speter			else if (lflag)
382113159Speter				num = va_arg(ap, long);
383113159Speter			else if (zflag)
384185037Sdelphij				num = va_arg(ap, ssize_t);
385113159Speter			else
386113159Speter				num = va_arg(ap, int);
387113159Speternumber:
388113159Speter			if (sign && (intmax_t)num < 0) {
38938451Smsmith				neg = 1;
390113159Speter				num = -(intmax_t)num;
39138451Smsmith			}
392156518Sjkim			p = ksprintn(nbuf, num, base, &tmp, upper);
393113159Speter			if (sharpflag && num != 0) {
39438451Smsmith				if (base == 8)
39538451Smsmith					tmp++;
39638451Smsmith				else if (base == 16)
39738451Smsmith					tmp += 2;
39838451Smsmith			}
39938451Smsmith			if (neg)
40038451Smsmith				tmp++;
40138451Smsmith
40238451Smsmith			if (!ladjust && width && (width -= tmp) > 0)
40338451Smsmith				while (width--)
40438451Smsmith					PCHAR(padc);
40538451Smsmith			if (neg)
40638451Smsmith				PCHAR('-');
407113159Speter			if (sharpflag && num != 0) {
40838451Smsmith				if (base == 8) {
40938451Smsmith					PCHAR('0');
41038451Smsmith				} else if (base == 16) {
41138451Smsmith					PCHAR('0');
41238451Smsmith					PCHAR('x');
41338451Smsmith				}
41438451Smsmith			}
41538451Smsmith
41638451Smsmith			while (*p)
41738451Smsmith				PCHAR(*p--);
41838451Smsmith
41938451Smsmith			if (ladjust && width && (width -= tmp) > 0)
42038451Smsmith				while (width--)
42138451Smsmith					PCHAR(padc);
42238451Smsmith
42338451Smsmith			break;
42438451Smsmith		default:
425113159Speter			while (percent < fmt)
426113159Speter				PCHAR(*percent++);
42738451Smsmith			break;
42838451Smsmith		}
42938451Smsmith	}
43038451Smsmith#undef PCHAR
43138451Smsmith}
432