xref: /openbsd/sys/lib/libsa/printf.c (revision 264ca280)
1 /*	$OpenBSD: printf.c,v 1.27 2015/06/14 10:55:50 miod 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/types.h>
59 #include <sys/stdarg.h>
60 
61 #include "stand.h"
62 
63 void kprintn(void (*)(int), u_long, int);
64 #ifdef LIBSA_LONGLONG_PRINTF
65 void kprintn64(void (*)(int), u_int64_t, int);
66 #endif
67 void kdoprnt(void (*)(int), const char *, va_list);
68 
69 const char hexdig[] = "0123456789abcdef";
70 
71 void
72 printf(const char *fmt, ...)
73 {
74 	va_list ap;
75 
76 	va_start(ap, fmt);
77 	kdoprnt(putchar, fmt, ap);
78 	va_end(ap);
79 }
80 
81 void
82 vprintf(const char *fmt, va_list ap)
83 {
84 	kdoprnt(putchar, fmt, ap);
85 }
86 
87 void
88 kdoprnt(void (*put)(int), const char *fmt, va_list ap)
89 {
90 #ifdef LIBSA_LONGLONG_PRINTF
91 	u_int64_t ull;
92 #endif
93 	unsigned long ul;
94 	int ch, lflag;
95 	char *p;
96 
97 	for (;;) {
98 		while ((ch = *fmt++) != '%') {
99 			if (ch == '\0')
100 				return;
101 			put(ch);
102 		}
103 		lflag = 0;
104 reswitch:	switch (ch = *fmt++) {
105 		case 'l':
106 			lflag++;
107 			goto reswitch;
108 #ifndef	STRIPPED
109 		case 'b':
110 		{
111 			int set, n;
112 
113 			ul = va_arg(ap, int);
114 			p = va_arg(ap, char *);
115 			kprintn(put, ul, *p++);
116 
117 			if (!ul)
118 				break;
119 
120 			for (set = 0; (n = *p++);) {
121 				if (ul & (1 << (n - 1))) {
122 					put(set ? ',' : '<');
123 					for (; (n = *p) > ' '; ++p)
124 						put(n);
125 					set = 1;
126 				} else
127 					for (; *p > ' '; ++p)
128 						;
129 			}
130 			if (set)
131 				put('>');
132 		}
133 			break;
134 #endif
135 		case 'c':
136 			ch = va_arg(ap, int);
137 			put(ch & 0x7f);
138 			break;
139 		case 's':
140 			p = va_arg(ap, char *);
141 			while ((ch = *p++))
142 				put(ch);
143 			break;
144 		case 'd':
145 #ifdef LIBSA_LONGLONG_PRINTF
146 			if (lflag > 1) {
147 				ull = va_arg(ap, int64_t);
148 				if ((int64_t)ull < 0) {
149 					put('-');
150 					ull = -(int64_t)ull;
151 				}
152 				kprintn64(put, ull, 10);
153 				break;
154 			}
155 #endif
156 			ul = lflag ?
157 			    va_arg(ap, long) : va_arg(ap, int);
158 			if ((long)ul < 0) {
159 				put('-');
160 				ul = -(long)ul;
161 			}
162 			kprintn(put, ul, 10);
163 			break;
164 		case 'o':
165 #ifdef LIBSA_LONGLONG_PRINTF
166 			if (lflag > 1) {
167 				ull = va_arg(ap, u_int64_t);
168 				kprintn64(put, ull, 8);
169 				break;
170 			}
171 #endif
172 			ul = lflag ?
173 			    va_arg(ap, u_long) : va_arg(ap, u_int);
174 			kprintn(put, ul, 8);
175 			break;
176 		case 'u':
177 #ifdef LIBSA_LONGLONG_PRINTF
178 			if (lflag > 1) {
179 				ull = va_arg(ap, u_int64_t);
180 				kprintn64(put, ull, 10);
181 				break;
182 			}
183 #endif
184 			ul = lflag ?
185 			    va_arg(ap, u_long) : va_arg(ap, u_int);
186 			kprintn(put, ul, 10);
187 			break;
188 		case 'p':
189 			put('0');
190 			put('x');
191 			lflag += sizeof(void *)==sizeof(u_long)? 1 : 0;
192 		case 'x':
193 #ifdef LIBSA_LONGLONG_PRINTF
194 			if (lflag > 1) {
195 				ull = va_arg(ap, u_int64_t);
196 				kprintn64(put, ull, 16);
197 				break;
198 			}
199 #else
200  			if (lflag > 1) {
201 				/* hold an int64_t in base 16 */
202 				char *p, buf[(sizeof(u_int64_t) * NBBY / 4) + 1];
203 				u_int64_t ull;
204 
205  				ull = va_arg(ap, u_int64_t);
206 				p = buf;
207 				do {
208 					*p++ = hexdig[ull & 15];
209 				} while (ull >>= 4);
210 				do {
211 					put(*--p);
212 				} while (p > buf);
213  				break;
214  			}
215 #endif
216 			ul = lflag ?
217 			    va_arg(ap, u_long) : va_arg(ap, u_int);
218 			kprintn(put, ul, 16);
219 			break;
220 		default:
221 			put('%');
222 #ifdef LIBSA_LONGLONG_PRINTF
223 			while (--lflag)
224 #else
225 			if (lflag)
226 #endif
227 				put('l');
228 			put(ch);
229 		}
230 	}
231 }
232 
233 void
234 kprintn(void (*put)(int), unsigned long ul, int base)
235 {
236 	/* hold a long in base 8 */
237 	char *p, buf[(sizeof(long) * NBBY / 3) + 1];
238 
239 	p = buf;
240 	do {
241 		*p++ = hexdig[ul % base];
242 	} while (ul /= base);
243 	do {
244 		put(*--p);
245 	} while (p > buf);
246 }
247 
248 #ifdef LIBSA_LONGLONG_PRINTF
249 void
250 kprintn64(void (*put)(int), u_int64_t ull, int base)
251 {
252 	/* hold an int64_t in base 8 */
253 	char *p, buf[(sizeof(u_int64_t) * NBBY / 3) + 1];
254 
255 	p = buf;
256 	do {
257 		*p++ = hexdig[ull % base];
258 	} while (ull /= base);
259 	do {
260 		put(*--p);
261 	} while (p > buf);
262 }
263 #endif
264 
265 int donottwiddle = 0;
266 
267 void
268 twiddle(void)
269 {
270 	static int pos;
271 
272 	if (!donottwiddle) {
273 		putchar("|/-\\"[pos++ & 3]);
274 		putchar('\b');
275 	}
276 }
277