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