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