xprintf.c revision 1.5 1 1.5 christos /* $NetBSD: xprintf.c,v 1.5 1999/03/03 21:18:01 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.5 christos #ifdef RTLD_LOADER
42 1.2 christos #define SZ_SHORT 0x01
43 1.2 christos #define SZ_INT 0x02
44 1.2 christos #define SZ_LONG 0x04
45 1.2 christos #define SZ_QUAD 0x08
46 1.2 christos #define SZ_UNSIGNED 0x10
47 1.2 christos #define SZ_MASK 0x0f
48 1.2 christos
49 1.1 cgd /*
50 1.1 cgd * Non-mallocing printf, for use by malloc and rtld itself.
51 1.1 cgd * This avoids putting in most of stdio.
52 1.1 cgd *
53 1.1 cgd * deals withs formats %x, %p, %s, and %d.
54 1.1 cgd */
55 1.1 cgd size_t
56 1.4 christos xvsnprintf(buf, buflen, fmt, ap)
57 1.4 christos char *buf;
58 1.4 christos size_t buflen;
59 1.4 christos const char *fmt;
60 1.4 christos va_list ap;
61 1.1 cgd {
62 1.4 christos char *bp = buf;
63 1.4 christos char *const ep = buf + buflen - 4;
64 1.4 christos int size;
65 1.4 christos
66 1.4 christos while (*fmt != NULL && bp < ep) {
67 1.4 christos switch (*fmt) {
68 1.4 christos case '\\':{
69 1.4 christos if (fmt[1] != '\0')
70 1.4 christos *bp++ = *++fmt;
71 1.4 christos continue;
72 1.2 christos }
73 1.4 christos case '%':{
74 1.4 christos size = SZ_INT;
75 1.4 christos rflag: switch (fmt[1]) {
76 1.4 christos case 'h':
77 1.4 christos size = (size&SZ_MASK)|SZ_SHORT;
78 1.4 christos fmt++;
79 1.4 christos goto rflag;
80 1.4 christos case 'l':
81 1.4 christos size = (size&SZ_MASK)|SZ_LONG;
82 1.4 christos fmt++;
83 1.4 christos if (fmt[1] == 'l') {
84 1.4 christos case 'q':
85 1.4 christos size = (size&SZ_MASK)|SZ_QUAD;
86 1.4 christos fmt++;
87 1.4 christos }
88 1.4 christos goto rflag;
89 1.4 christos case 'u':
90 1.4 christos size |= SZ_UNSIGNED;
91 1.4 christos /* FALLTHROUGH */
92 1.4 christos case 'd':{
93 1.4 christos long long sval;
94 1.4 christos unsigned long long uval;
95 1.4 christos char digits[sizeof(int) * 3], *dp = digits;
96 1.3 scottr #define SARG() \
97 1.4 christos (size & SZ_SHORT ? va_arg(ap, short) : \
98 1.4 christos size & SZ_LONG ? va_arg(ap, long) : \
99 1.4 christos size & SZ_QUAD ? va_arg(ap, long long) : \
100 1.4 christos va_arg(ap, int))
101 1.3 scottr #define UARG() \
102 1.4 christos (size & SZ_SHORT ? va_arg(ap, unsigned short) : \
103 1.4 christos size & SZ_LONG ? va_arg(ap, unsigned long) : \
104 1.4 christos size & SZ_QUAD ? va_arg(ap, unsigned long long) : \
105 1.4 christos va_arg(ap, unsigned int))
106 1.3 scottr #define ARG() (size & SZ_UNSIGNED ? UARG() : SARG())
107 1.1 cgd
108 1.4 christos if (fmt[1] == 'd') {
109 1.4 christos sval = ARG();
110 1.4 christos if (sval < 0) {
111 1.4 christos if ((sval << 1) == 0) {
112 1.4 christos /*
113 1.4 christos * We can't flip the
114 1.4 christos * sign of this since
115 1.4 christos * it can't be
116 1.4 christos * represented as a
117 1.4 christos * positive number in
118 1.4 christos * two complement,
119 1.4 christos * handle the first
120 1.4 christos * digit. After that,
121 1.4 christos * it can be flipped
122 1.4 christos * since it is now not
123 1.4 christos * 2^(n-1).
124 1.4 christos */
125 1.4 christos *dp++ = '0'-(sval % 10);
126 1.4 christos sval /= 10;
127 1.4 christos }
128 1.4 christos *bp++ = '-';
129 1.4 christos uval = -sval;
130 1.4 christos } else {
131 1.4 christos uval = sval;
132 1.4 christos }
133 1.4 christos } else {
134 1.4 christos uval = ARG();
135 1.4 christos }
136 1.4 christos do {
137 1.4 christos *dp++ = '0' + (uval % 10);
138 1.4 christos uval /= 10;
139 1.4 christos } while (uval != 0);
140 1.4 christos do {
141 1.4 christos *bp++ = *--dp;
142 1.4 christos } while (dp != digits && bp < ep);
143 1.4 christos fmt += 2;
144 1.4 christos break;
145 1.4 christos }
146 1.4 christos case 'x':
147 1.4 christos case 'p':{
148 1.4 christos unsigned long val = va_arg(ap, unsigned long);
149 1.4 christos unsigned long mask = ~(~0UL >> 4);
150 1.4 christos int bits = sizeof(val) * 8 - 4;
151 1.4 christos const char hexdigits[] = "0123456789abcdef";
152 1.4 christos if (fmt[1] == 'p') {
153 1.4 christos *bp++ = '0';
154 1.4 christos *bp++ = 'x';
155 1.4 christos }
156 1.4 christos /* handle the border case */
157 1.4 christos if (val == 0) {
158 1.4 christos *bp++ = '0';
159 1.4 christos fmt += 2;
160 1.4 christos break;
161 1.4 christos }
162 1.4 christos /* suppress 0s */
163 1.4 christos while ((val & mask) == 0)
164 1.4 christos bits -= 4, mask >>= 4;
165 1.4 christos
166 1.4 christos /* emit the hex digits */
167 1.4 christos while (bits >= 0 && bp < ep) {
168 1.4 christos *bp++ = hexdigits[(val & mask) >> bits];
169 1.4 christos bits -= 4, mask >>= 4;
170 1.4 christos }
171 1.4 christos fmt += 2;
172 1.4 christos break;
173 1.4 christos }
174 1.4 christos case 's':{
175 1.4 christos const char *str = va_arg(ap, const char *);
176 1.4 christos int len;
177 1.4 christos
178 1.4 christos if (str == NULL)
179 1.4 christos str = "(null)";
180 1.4 christos
181 1.4 christos len = strlen(str);
182 1.4 christos if (ep - bp < len)
183 1.4 christos len = ep - bp;
184 1.4 christos memcpy(bp, str, len);
185 1.4 christos bp += len;
186 1.4 christos fmt += 2;
187 1.4 christos break;
188 1.4 christos }
189 1.4 christos default:
190 1.4 christos *bp++ = *fmt;
191 1.4 christos break;
192 1.1 cgd }
193 1.4 christos break;
194 1.1 cgd }
195 1.4 christos default:
196 1.4 christos *bp++ = *fmt++;
197 1.4 christos break;
198 1.1 cgd }
199 1.1 cgd }
200 1.1 cgd
201 1.4 christos *bp = '\0';
202 1.4 christos return bp - buf;
203 1.1 cgd }
204 1.1 cgd
205 1.1 cgd void
206 1.4 christos xvprintf(fmt, ap)
207 1.4 christos const char *fmt;
208 1.4 christos va_list ap;
209 1.1 cgd {
210 1.4 christos char buf[256];
211 1.4 christos (void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap));
212 1.1 cgd }
213 1.1 cgd
214 1.1 cgd void
215 1.4 christos #ifdef __STDC__
216 1.4 christos xprintf(const char *fmt, ...)
217 1.4 christos #else
218 1.4 christos xprintf(va_alist)
219 1.4 christos va_dcl
220 1.4 christos #endif
221 1.1 cgd {
222 1.4 christos va_list ap;
223 1.1 cgd
224 1.4 christos #ifdef __STDC__
225 1.4 christos va_start(ap, fmt);
226 1.4 christos #else
227 1.4 christos const char *fmt;
228 1.1 cgd
229 1.4 christos va_start(ap);
230 1.4 christos fmt = va_arg(ap, const char *);
231 1.4 christos #endif
232 1.4 christos
233 1.4 christos xvprintf(fmt, ap);
234 1.4 christos
235 1.4 christos va_end(ap);
236 1.1 cgd }
237 1.1 cgd
238 1.1 cgd void
239 1.4 christos #ifdef __STDC__
240 1.4 christos xsnprintf(char *buf, size_t buflen, const char *fmt, ...)
241 1.4 christos #else
242 1.4 christos xsnprintf(va_alist)
243 1.4 christos va_dcl
244 1.4 christos #endif
245 1.1 cgd {
246 1.4 christos va_list ap;
247 1.4 christos #ifdef __STDC__
248 1.4 christos va_start(ap, fmt);
249 1.4 christos #else
250 1.4 christos char *buf;
251 1.4 christos size_t buflen;
252 1.4 christos const char *fmt;
253 1.4 christos
254 1.4 christos va_start(ap);
255 1.4 christos buf = va_arg(ap, char *);
256 1.4 christos buflen = va_arg(ap, size_t);
257 1.4 christos fmt = va_arg(ap, const char *);
258 1.4 christos #endif
259 1.4 christos xvsnprintf(buf, buflen, fmt, ap);
260 1.1 cgd
261 1.4 christos va_end(ap);
262 1.1 cgd }
263 1.1 cgd
264 1.1 cgd const char *
265 1.4 christos xstrerror(error)
266 1.4 christos int error;
267 1.1 cgd {
268 1.4 christos if (error >= sys_nerr || error < 0) {
269 1.4 christos static char buf[128];
270 1.4 christos xsnprintf(buf, sizeof(buf), "Unknown error: %d", error);
271 1.4 christos return buf;
272 1.4 christos }
273 1.4 christos return sys_errlist[error];
274 1.1 cgd }
275 1.1 cgd
276 1.1 cgd void
277 1.4 christos #ifdef __STDC__
278 1.4 christos xerrx(int eval, const char *fmt, ...)
279 1.4 christos #else
280 1.4 christos xerrx(va_alist)
281 1.4 christos va_dcl
282 1.4 christos #endif
283 1.1 cgd {
284 1.4 christos va_list ap;
285 1.4 christos #ifdef __STDC__
286 1.4 christos va_start(ap, fmt);
287 1.4 christos #else
288 1.4 christos int eval;
289 1.4 christos const char *fmt;
290 1.4 christos
291 1.4 christos va_start(ap);
292 1.4 christos eval = va_arg(ap, int);
293 1.4 christos fmt = va_arg(ap, const char *);
294 1.4 christos #endif
295 1.1 cgd
296 1.4 christos xvprintf(fmt, ap);
297 1.4 christos va_end(ap);
298 1.4 christos
299 1.4 christos exit(eval);
300 1.1 cgd }
301 1.1 cgd
302 1.1 cgd void
303 1.4 christos #ifdef __STDC__
304 1.4 christos xerr(int eval, const char *fmt, ...)
305 1.4 christos #else
306 1.4 christos xerr(va_alist)
307 1.4 christos va_dcl
308 1.4 christos #endif
309 1.1 cgd {
310 1.4 christos int saved_errno = errno;
311 1.4 christos va_list ap;
312 1.4 christos #ifdef __STDC__
313 1.4 christos va_start(ap, fmt);
314 1.4 christos #else
315 1.4 christos int eval;
316 1.4 christos const char *fmt;
317 1.4 christos
318 1.4 christos va_start(ap);
319 1.4 christos eval = va_arg(ap, int);
320 1.4 christos fmt = va_arg(ap, const char *);
321 1.4 christos #endif
322 1.4 christos xvprintf(fmt, ap);
323 1.4 christos va_end(ap);
324 1.1 cgd
325 1.4 christos xprintf(": %s\n", xstrerror(saved_errno));
326 1.4 christos exit(eval);
327 1.1 cgd }
328 1.1 cgd
329 1.1 cgd void
330 1.4 christos #ifdef __STDC__
331 1.4 christos xwarn(const char *fmt, ...)
332 1.4 christos #else
333 1.4 christos xwarn(va_alist)
334 1.4 christos va_dcl
335 1.4 christos #endif
336 1.1 cgd {
337 1.4 christos int saved_errno = errno;
338 1.4 christos va_list ap;
339 1.4 christos #ifdef __STDC__
340 1.4 christos va_start(ap, fmt);
341 1.4 christos #else
342 1.4 christos const char *fmt;
343 1.4 christos
344 1.4 christos va_start(ap);
345 1.4 christos fmt = va_arg(ap, const char *);
346 1.4 christos #endif
347 1.4 christos xvprintf(fmt, ap);
348 1.4 christos va_end(ap);
349 1.1 cgd
350 1.4 christos xprintf(": %s\n", xstrerror(saved_errno));
351 1.4 christos errno = saved_errno;
352 1.1 cgd }
353 1.1 cgd
354 1.1 cgd void
355 1.4 christos #ifdef __STDC__
356 1.4 christos xwarnx(const char *fmt, ...)
357 1.4 christos #else
358 1.4 christos xwarnx(va_alist)
359 1.4 christos va_dcl
360 1.4 christos #endif
361 1.1 cgd {
362 1.4 christos va_list ap;
363 1.4 christos #ifdef __STDC__
364 1.4 christos va_start(ap, fmt);
365 1.4 christos #else
366 1.4 christos const char *fmt;
367 1.4 christos
368 1.4 christos va_start(ap);
369 1.4 christos fmt = va_arg(ap, const char *);
370 1.4 christos #endif
371 1.4 christos xvprintf(fmt, ap);
372 1.4 christos va_end(ap);
373 1.1 cgd }
374 1.1 cgd
375 1.1 cgd void
376 1.4 christos xassert(file, line, failedexpr)
377 1.4 christos const char *file;
378 1.4 christos int line;
379 1.4 christos const char *failedexpr;
380 1.1 cgd {
381 1.4 christos xprintf("assertion \"%s\" failed: file \"%s\", line %d\n",
382 1.4 christos failedexpr, file, line);
383 1.4 christos abort();
384 1.4 christos /* NOTREACHED */
385 1.1 cgd }
386 1.5 christos #endif
387