printf.c revision 1.14 1 /* $NetBSD: printf.c,v 1.14 1999/02/11 14:32:00 pk Exp $ */
2
3 /*-
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)printf.c 8.1 (Berkeley) 6/11/93
36 */
37
38 /*
39 * Scaled down version of printf(3).
40 *
41 * One additional format:
42 *
43 * The format %b is supported to decode error registers.
44 * Its usage is:
45 *
46 * printf("reg=%b\n", regval, "<base><arg>*");
47 *
48 * where <base> is the output base expressed as a control character, e.g.
49 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
50 * the first of which gives the bit number to be inspected (origin 1), and
51 * the next characters (up to a control character, i.e. a character <= 32),
52 * give the name of the register. Thus:
53 *
54 * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
55 *
56 * would produce output:
57 *
58 * reg=3<BITTWO,BITONE>
59 */
60
61 #include <sys/cdefs.h>
62 #include <sys/types.h>
63 #ifdef __STDC__
64 #include <machine/stdarg.h>
65 #else
66 #include <machine/varargs.h>
67 #endif
68
69 #include "stand.h"
70
71 static void kprintn __P((void (*)(int), u_long, int));
72 static void sputchar __P((int));
73 static void kdoprnt __P((void (*)(int), const char *, va_list));
74
75 static char *sbuf, *ebuf;
76
77 static void
78 sputchar(c)
79 int c;
80 {
81 if (sbuf < ebuf)
82 *sbuf++ = c;
83 }
84
85 int
86 #ifdef __STDC__
87 sprintf(char *buf, const char *fmt, ...)
88 #else
89 sprintf(buf, fmt, va_alist)
90 char *buf, *fmt;
91 #endif
92 {
93 va_list ap;
94 int len;
95
96 #ifdef __STDC__
97 va_start(ap, fmt);
98 #else
99 va_start(ap);
100 #endif
101 len = vsnprintf(buf, -(size_t)buf, fmt, ap);
102 va_end(ap);
103 return (len);
104 }
105
106 int
107 #ifdef __STDC__
108 snprintf(char *buf, size_t size, const char *fmt, ...)
109 #else
110 snprintf(buf, size, fmt, va_alist)
111 char *buf, *fmt;
112 size_t size;
113 #endif
114 {
115 va_list ap;
116 int len;
117
118 #ifdef __STDC__
119 va_start(ap, fmt);
120 #else
121 va_start(ap);
122 #endif
123 len = vsnprintf(buf, size, fmt, ap);
124 va_end(ap);
125 return (len);
126 }
127
128 void
129 #ifdef __STDC__
130 printf(const char *fmt, ...)
131 #else
132 printf(fmt, va_alist)
133 char *fmt;
134 #endif
135 {
136 va_list ap;
137
138 #ifdef __STDC__
139 va_start(ap, fmt);
140 #else
141 va_start(ap);
142 #endif
143 kdoprnt(putchar, fmt, ap);
144 va_end(ap);
145 }
146
147 void
148 vprintf(const char *fmt, va_list ap)
149 {
150
151 kdoprnt(putchar, fmt, ap);
152 }
153
154 int
155 vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
156 {
157
158 sbuf = buf;
159 ebuf = buf + size - 1;
160 kdoprnt(sputchar, fmt, ap);
161 *sbuf = '\0';
162 return (sbuf - buf);
163 }
164
165 int
166 vsprintf(char *buf, const char *fmt, va_list ap)
167 {
168
169 return (vsnprintf(buf, -(size_t)buf, fmt, ap));
170 }
171
172 void
173 kdoprnt(put, fmt, ap)
174 void (*put)__P((int));
175 const char *fmt;
176 va_list ap;
177 {
178 register char *p;
179 register int ch, n;
180 unsigned long ul;
181 int lflag, set;
182
183 for (;;) {
184 while ((ch = *fmt++) != '%') {
185 if (ch == '\0')
186 return;
187 put(ch);
188 }
189 lflag = 0;
190 reswitch: switch (ch = *fmt++) {
191 case '\0':
192 /* XXX print the last format character? */
193 return;
194 case 'l':
195 lflag = 1;
196 goto reswitch;
197 case 'b':
198 ul = va_arg(ap, int);
199 p = va_arg(ap, char *);
200 kprintn(put, ul, *p++);
201
202 if (!ul)
203 break;
204
205 for (set = 0; (n = *p++);) {
206 if (ul & (1 << (n - 1))) {
207 put(set ? ',' : '<');
208 for (; (n = *p) > ' '; ++p)
209 put(n);
210 set = 1;
211 } else
212 for (; *p > ' '; ++p);
213 }
214 if (set)
215 put('>');
216 break;
217 case 'c':
218 ch = va_arg(ap, int);
219 put(ch & 0x7f);
220 break;
221 case 's':
222 p = va_arg(ap, char *);
223 while ((ch = *p++))
224 put(ch);
225 break;
226 case 'd':
227 ul = lflag ?
228 va_arg(ap, long) : va_arg(ap, int);
229 if ((long)ul < 0) {
230 put('-');
231 ul = -(long)ul;
232 }
233 kprintn(put, ul, 10);
234 break;
235 case 'o':
236 ul = lflag ?
237 va_arg(ap, u_long) : va_arg(ap, u_int);
238 kprintn(put, ul, 8);
239 break;
240 case 'u':
241 ul = lflag ?
242 va_arg(ap, u_long) : va_arg(ap, u_int);
243 kprintn(put, ul, 10);
244 break;
245 case 'p':
246 put('0');
247 put('x');
248 /* fall through */
249 case 'x':
250 ul = lflag ?
251 va_arg(ap, u_long) : va_arg(ap, u_int);
252 kprintn(put, ul, 16);
253 break;
254 default:
255 put('%');
256 if (lflag)
257 put('l');
258 put(ch);
259 }
260 }
261 va_end(ap);
262 }
263
264 static void
265 kprintn(put, ul, base)
266 void (*put)__P((int));
267 unsigned long ul;
268 int base;
269 {
270 /* hold a long in base 8 */
271 char *p, buf[(sizeof(long) * NBBY / 3) + 1];
272
273 p = buf;
274 do {
275 *p++ = "0123456789abcdef"[ul % base];
276 } while (ul /= base);
277 do {
278 put(*--p);
279 } while (p > buf);
280 }
281
282 void
283 twiddle()
284 {
285 static int pos;
286
287 putchar("|/-\\"[pos++ & 3]);
288 putchar('\b');
289 }
290