xprintf.c revision 1.2 1 /* $NetBSD: xprintf.c,v 1.2 1999/02/07 17:23:40 christos Exp $ */
2
3 /*
4 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
5 * 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. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "rtldenv.h"
31 #include <string.h>
32 #include <unistd.h>
33 #include <errno.h>
34
35 static __inline long long xva_arg __P((va_list *, int));
36
37 #define SZ_SHORT 0x01
38 #define SZ_INT 0x02
39 #define SZ_LONG 0x04
40 #define SZ_QUAD 0x08
41 #define SZ_UNSIGNED 0x10
42 #define SZ_MASK 0x0f
43
44 static __inline long long
45 xva_arg(ap, size)
46 va_list *ap;
47 int size;
48 {
49 switch (size) {
50 case SZ_SHORT:
51 return va_arg(*ap, short);
52 default:
53 case SZ_INT:
54 return va_arg(*ap, int);
55 case SZ_LONG:
56 return va_arg(*ap, long);
57 case SZ_QUAD:
58 return va_arg(*ap, long long);
59 case SZ_SHORT|SZ_UNSIGNED:
60 return va_arg(*ap, unsigned short);
61 case SZ_INT|SZ_UNSIGNED:
62 return va_arg(*ap, unsigned int);
63 case SZ_LONG|SZ_UNSIGNED:
64 return va_arg(*ap, unsigned long);
65 case SZ_QUAD|SZ_UNSIGNED:
66 return va_arg(*ap, unsigned long long);
67 }
68 }
69 /*
70 * Non-mallocing printf, for use by malloc and rtld itself.
71 * This avoids putting in most of stdio.
72 *
73 * deals withs formats %x, %p, %s, and %d.
74 */
75 size_t
76 xvsnprintf(
77 char *buf,
78 size_t buflen,
79 const char *fmt,
80 va_list ap)
81 {
82 char *bp = buf;
83 char * const ep = buf + buflen - 4;
84 int size;
85
86 while (*fmt != NULL && bp < ep) {
87 switch (*fmt) {
88 case '\\': {
89 if (fmt[1] != '\0')
90 *bp++ = *++fmt;
91 continue;
92 }
93 case '%': {
94 size = SZ_INT;
95 rflag: switch (fmt[1]) {
96 case 'h':
97 size = (size & SZ_MASK) | SZ_SHORT;
98 fmt++;
99 goto rflag;
100 case 'l':
101 size = (size & SZ_MASK) | SZ_LONG;
102 fmt++;
103 if (fmt[1] == 'l') {
104 case 'q':
105 size = (size & SZ_MASK) | SZ_QUAD;
106 fmt++;
107 }
108 goto rflag;
109 case 'u':
110 size |= SZ_UNSIGNED;
111 /* FALLTHROUGH*/
112 case 'd': {
113 long long sval;
114 unsigned long long uval;
115 char digits[sizeof(int) * 3], *dp = digits;
116
117 if (fmt[1] == 'd') {
118 sval = xva_arg(&ap, size);
119 if (sval < 0) {
120 if ((sval << 1) == 0) {
121 /*
122 * We can't flip the sign of this since
123 * it's can't represented as a postive
124 * number in two complement, handle the
125 * first digit. After that, it can be
126 * flipped since it is now not 2^(n-1).
127 */
128 *dp++ = '0' - (sval % 10);
129 sval /= 10;
130 }
131 *bp++ = '-';
132 uval = -sval;
133 } else {
134 uval = sval;
135 }
136 } else {
137 uval = xva_arg(&ap, size);
138 }
139 do {
140 *dp++ = '0' + (uval % 10);
141 uval /= 10;
142 } while (uval != 0);
143 do {
144 *bp++ = *--dp;
145 } while (dp != digits && bp < ep);
146 fmt += 2;
147 break;
148 }
149 case 'x': case 'p': {
150 unsigned long val = va_arg(ap, unsigned long);
151 unsigned long mask = ~(~0UL >> 4);
152 int bits = sizeof(val) * 8 - 4;
153 const char hexdigits[] = "0123456789abcdef";
154 if (fmt[1] == 'p') {
155 *bp++ = '0';
156 *bp++ = 'x';
157 }
158 /* handle the border case */
159 if (val == 0) {
160 *bp++ = '0';
161 fmt += 2;
162 break;
163 }
164 /* suppress 0s */
165 while ((val & mask) == 0)
166 bits -= 4, mask >>= 4;
167
168 /* emit the hex digits */
169 while (bits >= 0 && bp < ep) {
170 *bp++ = hexdigits[(val & mask) >> bits];
171 bits -= 4, mask >>= 4;
172 }
173 fmt += 2;
174 break;
175 }
176 case 's': {
177 const char *str = va_arg(ap, const char *);
178 int len;
179 if (str == NULL)
180 str = "(null)";
181
182 len = strlen(str);
183 if (ep - bp < len)
184 len = ep - bp;
185 memcpy(bp, str, len);
186 bp += len;
187 fmt += 2;
188 break;
189 }
190 default:
191 *bp++ = *fmt;
192 break;
193 }
194 break;
195 }
196 default:
197 *bp++ = *fmt++;
198 break;
199 }
200 }
201
202
203 *bp = '\0';
204 return bp - buf;
205 }
206
207 void
208 xvprintf(
209 const char *fmt,
210 va_list ap)
211 {
212 char buf[256];
213 (void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap));
214 }
215
216 void
217 xprintf(
218 const char *fmt,
219 ...)
220 {
221 va_list ap;
222 va_start(ap, fmt);
223
224 xvprintf(fmt, ap);
225
226 va_end(ap);
227 }
228
229 void
230 xsnprintf(
231 char *buf,
232 size_t buflen,
233 const char *fmt,
234 ...)
235 {
236 va_list ap;
237 va_start(ap, fmt);
238
239 xvprintf(fmt, ap);
240
241 va_end(ap);
242 }
243
244 const char *
245 xstrerror(
246 int error)
247 {
248 if (error >= sys_nerr) {
249 static char buf[128];
250 xsnprintf(buf, sizeof(buf), "Unknown error: %d", error);
251 return buf;
252 }
253 return sys_errlist[error];
254 }
255
256 void
257 xerrx(
258 int eval,
259 const char *fmt,
260 ...)
261 {
262 va_list ap;
263 va_start(ap, fmt);
264 xvprintf(fmt, ap);
265 va_end(ap);
266
267 exit(eval);
268 }
269
270 void
271 xerr(
272 int eval,
273 const char *fmt,
274 ...)
275 {
276 int saved_errno = errno;
277
278 va_list ap;
279 va_start(ap, fmt);
280 xvprintf(fmt, ap);
281 va_end(ap);
282
283 xprintf(": %s\n", xstrerror(saved_errno));
284 exit(eval);
285 }
286
287 void
288 xwarn(
289 const char *fmt,
290 ...)
291 {
292 int saved_errno = errno;
293
294 va_list ap;
295 va_start(ap, fmt);
296 xvprintf(fmt, ap);
297 va_end(ap);
298
299 xprintf(": %s\n", xstrerror(saved_errno));
300 errno = saved_errno;
301 }
302
303 void
304 xwarnx(
305 const char *fmt,
306 ...)
307 {
308 va_list ap;
309 va_start(ap, fmt);
310 xvprintf(fmt, ap);
311 va_end(ap);
312 }
313
314 void
315 xassert(
316 const char *file,
317 int line,
318 const char *failedexpr)
319 {
320 xprintf("assertion \"%s\" failed: file \"%s\", line %d\n",
321 failedexpr, file, line);
322 abort();
323 /* NOTREACHED */
324 }
325