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