xref: /openbsd-src/sys/lib/libsa/printf.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: printf.c,v 1.21 2003/08/11 06:23:09 deraadt Exp $	*/
2 /*	$NetBSD: printf.c,v 1.10 1996/11/30 04:19:21 gwr Exp $	*/
3 
4 /*-
5  * Copyright (c) 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)printf.c	8.1 (Berkeley) 6/11/93
33  */
34 
35 /*
36  * Scaled down version of printf(3).
37  *
38  * One additional format:
39  *
40  * The format %b is supported to decode error registers.
41  * Its usage is:
42  *
43  *	printf("reg=%b\n", regval, "<base><arg>*");
44  *
45  * where <base> is the output base expressed as a control character, e.g.
46  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
47  * the first of which gives the bit number to be inspected (origin 1), and
48  * the next characters (up to a control character, i.e. a character <= 32),
49  * give the name of the register.  Thus:
50  *
51  *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
52  *
53  * would produce output:
54  *
55  *	reg=3<BITTWO,BITONE>
56  */
57 
58 #include <sys/cdefs.h>
59 #include <sys/types.h>
60 #include <machine/stdarg.h>
61 
62 #include "stand.h"
63 
64 void kprintn(void (*)(int), u_long, int);
65 void kdoprnt(void (*)(int), const char *, va_list);
66 
67 void
68 printf(const char *fmt, ...)
69 {
70 	va_list ap;
71 
72 	va_start(ap, fmt);
73 	kdoprnt(putchar, fmt, ap);
74 	va_end(ap);
75 }
76 
77 void
78 vprintf(const char *fmt, va_list ap)
79 {
80 	kdoprnt(putchar, fmt, ap);
81 }
82 
83 void
84 kdoprnt(void (*put)(int), const char *fmt, va_list ap)
85 {
86 	unsigned long ul;
87 	int ch, lflag;
88 	char *p;
89 
90 	for (;;) {
91 		while ((ch = *fmt++) != '%') {
92 			if (ch == '\0')
93 				return;
94 			put(ch);
95 		}
96 		lflag = 0;
97 reswitch:	switch (ch = *fmt++) {
98 		case 'l':
99 			lflag = 1;
100 			goto reswitch;
101 #ifndef	STRIPPED
102 		case 'b':
103 		{
104 			int set, n;
105 
106 			ul = va_arg(ap, int);
107 			p = va_arg(ap, char *);
108 			kprintn(put, ul, *p++);
109 
110 			if (!ul)
111 				break;
112 
113 			for (set = 0; (n = *p++);) {
114 				if (ul & (1 << (n - 1))) {
115 					put(set ? ',' : '<');
116 					for (; (n = *p) > ' '; ++p)
117 						put(n);
118 					set = 1;
119 				} else
120 					for (; *p > ' '; ++p)
121 						;
122 			}
123 			if (set)
124 				put('>');
125 		}
126 			break;
127 #endif
128 		case 'c':
129 			ch = va_arg(ap, int);
130 			put(ch & 0x7f);
131 			break;
132 		case 's':
133 			p = va_arg(ap, char *);
134 			while ((ch = *p++))
135 				put(ch);
136 			break;
137 		case 'd':
138 			ul = lflag ?
139 			    va_arg(ap, long) : va_arg(ap, int);
140 			if ((long)ul < 0) {
141 				put('-');
142 				ul = -(long)ul;
143 			}
144 			kprintn(put, ul, 10);
145 			break;
146 		case 'o':
147 			ul = lflag ?
148 			    va_arg(ap, u_long) : va_arg(ap, u_int);
149 			kprintn(put, ul, 8);
150 			break;
151 		case 'u':
152 			ul = lflag ?
153 			    va_arg(ap, u_long) : va_arg(ap, u_int);
154 			kprintn(put, ul, 10);
155 			break;
156 		case 'p':
157 			put('0');
158 			put('x');
159 			lflag += sizeof(void *)==sizeof(u_long)? 1 : 0;
160 		case 'x':
161 			ul = lflag ?
162 			    va_arg(ap, u_long) : va_arg(ap, u_int);
163 			kprintn(put, ul, 16);
164 			break;
165 		default:
166 			put('%');
167 			if (lflag)
168 				put('l');
169 			put(ch);
170 		}
171 	}
172 	va_end(ap);
173 }
174 
175 void
176 kprintn(void (*put)(int), unsigned long ul, int base)
177 {
178 	/* hold a long in base 8 */
179 	char *p, buf[(sizeof(long) * NBBY / 3) + 1];
180 
181 	p = buf;
182 	do {
183 		*p++ = "0123456789abcdef"[ul % base];
184 	} while (ul /= base);
185 	do {
186 		put(*--p);
187 	} while (p > buf);
188 }
189 
190 int donottwiddle = 0;
191 
192 void
193 twiddle(void)
194 {
195 	static int pos;
196 
197 	if (!donottwiddle) {
198 		putchar("|/-\\"[pos++ & 3]);
199 		putchar('\b');
200 	}
201 }
202