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