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