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