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