xref: /openbsd-src/sys/lib/libsa/printf.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: printf.c,v 1.20 2003/06/02 23:28:09 millert 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 <machine/stdarg.h>
61 
62 #include "stand.h"
63 
64 void kprintn(void (*)(int), u_long, int);
65 void kdoprnt(void (*)(int), const char *, va_list);
66 
67 void
68 printf(const char *fmt, ...)
69 {
70 	va_list ap;
71 
72 	va_start(ap, fmt);
73 	kdoprnt(putchar, fmt, ap);
74 	va_end(ap);
75 }
76 
77 void
78 vprintf(const char *fmt, va_list ap)
79 {
80 	kdoprnt(putchar, fmt, ap);
81 }
82 
83 void
84 kdoprnt(put, fmt, ap)
85 	void (*put)(int);
86 	const char *fmt;
87 	va_list ap;
88 {
89 	char *p;
90 	unsigned long ul;
91 	int ch, lflag;
92 
93 	for (;;) {
94 		while ((ch = *fmt++) != '%') {
95 			if (ch == '\0')
96 				return;
97 			put(ch);
98 		}
99 		lflag = 0;
100 reswitch:	switch (ch = *fmt++) {
101 		case 'l':
102 			lflag = 1;
103 			goto reswitch;
104 #ifndef	STRIPPED
105 		case 'b':
106 		{
107 			int set, n;
108 			ul = va_arg(ap, int);
109 			p = va_arg(ap, char *);
110 			kprintn(put, ul, *p++);
111 
112 			if (!ul)
113 				break;
114 
115 			for (set = 0; (n = *p++);) {
116 				if (ul & (1 << (n - 1))) {
117 					put(set ? ',' : '<');
118 					for (; (n = *p) > ' '; ++p)
119 						put(n);
120 					set = 1;
121 				} else
122 					for (; *p > ' '; ++p);
123 			}
124 			if (set)
125 				put('>');
126 		}
127 			break;
128 #endif
129 		case 'c':
130 			ch = va_arg(ap, int);
131 				put(ch & 0x7f);
132 			break;
133 		case 's':
134 			p = va_arg(ap, char *);
135 			while ((ch = *p++))
136 				put(ch);
137 			break;
138 		case 'd':
139 			ul = lflag ?
140 			    va_arg(ap, long) : va_arg(ap, int);
141 			if ((long)ul < 0) {
142 				put('-');
143 				ul = -(long)ul;
144 			}
145 			kprintn(put, ul, 10);
146 			break;
147 		case 'o':
148 			ul = lflag ?
149 			    va_arg(ap, u_long) : va_arg(ap, u_int);
150 			kprintn(put, ul, 8);
151 			break;
152 		case 'u':
153 			ul = lflag ?
154 			    va_arg(ap, u_long) : va_arg(ap, u_int);
155 			kprintn(put, ul, 10);
156 			break;
157 		case 'p':
158 			put('0');
159 			put('x');
160 			lflag += sizeof(void *)==sizeof(u_long)? 1 : 0;
161 		case 'x':
162 			ul = lflag ?
163 			    va_arg(ap, u_long) : va_arg(ap, u_int);
164 			kprintn(put, ul, 16);
165 			break;
166 		default:
167 			put('%');
168 			if (lflag)
169 				put('l');
170 			put(ch);
171 		}
172 	}
173 	va_end(ap);
174 }
175 
176 void
177 kprintn(put, ul, base)
178 	void (*put)(int);
179 	unsigned long ul;
180 	int base;
181 {
182 					/* hold a long in base 8 */
183 	char *p, buf[(sizeof(long) * NBBY / 3) + 1];
184 
185 	p = buf;
186 	do {
187 		*p++ = "0123456789abcdef"[ul % base];
188 	} while (ul /= base);
189 	do {
190 		put(*--p);
191 	} while (p > buf);
192 }
193 
194 int donottwiddle = 0;
195 
196 void
197 twiddle()
198 {
199 	static int pos;
200 
201 	if (!donottwiddle) {
202 		putchar("|/-\\"[pos++ & 3]);
203 		putchar('\b');
204 	}
205 }
206