1 /* $OpenBSD: printf.c,v 1.29 2019/05/11 16:56:47 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/types.h>
59 #include <sys/stdarg.h>
60
61 #include "stand.h"
62
63 /*
64 * macros for converting digits to letters and vice versa
65 */
66 #define to_digit(c) ((c) - '0')
67 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
68 #define to_char(n) ((n) + '0')
69
70 void kprintn(void (*)(int), u_long, int, int, char);
71 #ifdef LIBSA_LONGLONG_PRINTF
72 void kprintn64(void (*)(int), u_int64_t, int, int, char);
73 #endif
74 void kdoprnt(void (*)(int), const char *, va_list);
75
76 const char hexdig[] = "0123456789abcdef";
77
78 void
printf(const char * fmt,...)79 printf(const char *fmt, ...)
80 {
81 va_list ap;
82
83 va_start(ap, fmt);
84 kdoprnt(putchar, fmt, ap);
85 va_end(ap);
86 }
87
88 void
vprintf(const char * fmt,va_list ap)89 vprintf(const char *fmt, va_list ap)
90 {
91 kdoprnt(putchar, fmt, ap);
92 }
93
94 void
kdoprnt(void (* put)(int),const char * fmt,va_list ap)95 kdoprnt(void (*put)(int), const char *fmt, va_list ap)
96 {
97 #ifdef LIBSA_LONGLONG_PRINTF
98 u_int64_t ull;
99 #endif
100 unsigned long ul;
101 int ch, lflag, width, n;
102 char *p, padchar;
103
104 for (;;) {
105 while ((ch = *fmt++) != '%') {
106 if (ch == '\0')
107 return;
108 put(ch);
109 }
110 lflag = 0;
111 padchar = ' ';
112 width = 0;
113 rflag: ch = *fmt++;
114 reswitch: switch (ch) {
115 case '0':
116 /*
117 * ``Note that 0 is taken as a flag, not as the
118 * beginning of a field width.''
119 * -- ANSI X3J11
120 */
121 padchar = '0';
122 goto rflag;
123 case '1': case '2': case '3': case '4':
124 case '5': case '6': case '7': case '8': case '9':
125 n = 0;
126 do {
127 n = 10 * n + to_digit(ch);
128 ch = *fmt++;
129 } while (is_digit(ch));
130 width = n;
131 goto reswitch;
132 case 'l':
133 lflag++;
134 goto rflag;
135 case 'b':
136 {
137 int set, n;
138
139 ul = va_arg(ap, int);
140 p = va_arg(ap, char *);
141 kprintn(put, ul, *p++, width, padchar);
142
143 if (!ul)
144 break;
145
146 for (set = 0; (n = *p++);) {
147 if (ul & (1 << (n - 1))) {
148 put(set ? ',' : '<');
149 for (; (n = *p) > ' '; ++p)
150 put(n);
151 set = 1;
152 } else
153 for (; *p > ' '; ++p)
154 ;
155 }
156 if (set)
157 put('>');
158 }
159 break;
160 case 'c':
161 ch = va_arg(ap, int);
162 put(ch & 0x7f);
163 break;
164 case 's':
165 p = va_arg(ap, char *);
166 while ((ch = *p++))
167 put(ch);
168 break;
169 case 'd':
170 #ifdef LIBSA_LONGLONG_PRINTF
171 if (lflag > 1) {
172 ull = va_arg(ap, int64_t);
173 if ((int64_t)ull < 0) {
174 put('-');
175 ull = -(int64_t)ull;
176 }
177 kprintn64(put, ull, 10, width, padchar);
178 break;
179 }
180 #endif
181 ul = lflag ?
182 va_arg(ap, long) : va_arg(ap, int);
183 if ((long)ul < 0) {
184 put('-');
185 ul = -(long)ul;
186 }
187 kprintn(put, ul, 10, width, padchar);
188 break;
189 case 'o':
190 #ifdef LIBSA_LONGLONG_PRINTF
191 if (lflag > 1) {
192 ull = va_arg(ap, u_int64_t);
193 kprintn64(put, ull, 8, width, padchar);
194 break;
195 }
196 #endif
197 ul = lflag ?
198 va_arg(ap, u_long) : va_arg(ap, u_int);
199 kprintn(put, ul, 8, width, padchar);
200 break;
201 case 'u':
202 #ifdef LIBSA_LONGLONG_PRINTF
203 if (lflag > 1) {
204 ull = va_arg(ap, u_int64_t);
205 kprintn64(put, ull, 10, width, padchar);
206 break;
207 }
208 #endif
209 ul = lflag ?
210 va_arg(ap, u_long) : va_arg(ap, u_int);
211 kprintn(put, ul, 10, width, padchar);
212 break;
213 case 'p':
214 put('0');
215 put('x');
216 lflag += sizeof(void *)==sizeof(u_long)? 1 : 0;
217 case 'x':
218 #ifdef LIBSA_LONGLONG_PRINTF
219 if (lflag > 1) {
220 ull = va_arg(ap, u_int64_t);
221 kprintn64(put, ull, 16, width, padchar);
222 break;
223 }
224 #else
225 if (lflag > 1) {
226 /* hold an int64_t in base 16 */
227 char *p, buf[(sizeof(u_int64_t) * NBBY / 4) + 1];
228 u_int64_t ull;
229
230 ull = va_arg(ap, u_int64_t);
231 p = buf;
232 do {
233 *p++ = hexdig[ull & 15];
234 } while (ull >>= 4);
235 while ((p - buf) < width &&
236 (p - buf) < sizeof(buf)) {
237 *p++ = padchar;
238 }
239 do {
240 put(*--p);
241 } while (p > buf);
242 break;
243 }
244 #endif
245 ul = lflag ?
246 va_arg(ap, u_long) : va_arg(ap, u_int);
247 kprintn(put, ul, 16, width, padchar);
248 break;
249 default:
250 put('%');
251 #ifdef LIBSA_LONGLONG_PRINTF
252 while (--lflag)
253 #else
254 if (lflag)
255 #endif
256 put('l');
257 put(ch);
258 }
259 }
260 }
261
262 void
kprintn(void (* put)(int),unsigned long ul,int base,int width,char padchar)263 kprintn(void (*put)(int), unsigned long ul, int base, int width, char padchar)
264 {
265 /* hold a long in base 8 */
266 char *p, buf[(sizeof(long) * NBBY / 3) + 1];
267
268 p = buf;
269 do {
270 *p++ = hexdig[ul % base];
271 } while (ul /= base);
272 while ((p - buf) < width && (p - buf) < sizeof(buf)) {
273 *p++ = padchar;
274 }
275 do {
276 put(*--p);
277 } while (p > buf);
278 }
279
280 #ifdef LIBSA_LONGLONG_PRINTF
281 void
kprintn64(void (* put)(int),u_int64_t ull,int base,int width,char padchar)282 kprintn64(void (*put)(int), u_int64_t ull, int base, int width, char padchar)
283 {
284 /* hold an int64_t in base 8 */
285 char *p, buf[(sizeof(u_int64_t) * NBBY / 3) + 1];
286
287 p = buf;
288 do {
289 *p++ = hexdig[ull % base];
290 } while (ull /= base);
291 while ((p - buf) < width && (p - buf) < sizeof(buf)) {
292 *p++ = padchar;
293 }
294 do {
295 put(*--p);
296 } while (p > buf);
297 }
298 #endif
299
300 int donottwiddle = 0;
301
302 void
twiddle(void)303 twiddle(void)
304 {
305 static int pos;
306
307 if (!donottwiddle) {
308 putchar("|/-\\"[pos++ & 3]);
309 putchar('\b');
310 }
311 }
312