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