xprintf.c revision 1.8.2.1 1 /* $NetBSD: xprintf.c,v 1.8.2.1 2004/05/28 08:31:22 tron Exp $ */
2
3 /*
4 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <stdarg.h>
36
37 #include "rtldenv.h"
38
39 #ifdef RTLD_LOADER
40 #define SZ_LONG 0x01
41 #define SZ_UNSIGNED 0x02
42
43 /*
44 * Non-mallocing printf, for use by malloc and rtld itself.
45 * This avoids putting in most of stdio.
46 *
47 * deals withs formats %x, %p, %s, and %d.
48 */
49 size_t
50 xvsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap)
51 {
52 char *bp = buf;
53 char *const ep = buf + buflen - 4;
54 int size, prec;
55
56 while (*fmt != '\0' && bp < ep) {
57 switch (*fmt) {
58 case '\\':{
59 if (fmt[1] != '\0')
60 *bp++ = *++fmt;
61 continue;
62 }
63 case '%':{
64 size = 0;
65 prec = -1;
66 rflag: switch (fmt[1]) {
67 case '*':
68 prec = va_arg(ap, int);
69 /* FALLTHROUGH */
70 case '.':
71 fmt++;
72 goto rflag;
73 case 'l':
74 size |= SZ_LONG;
75 fmt++;
76 goto rflag;
77 case 'u':
78 size |= SZ_UNSIGNED;
79 /* FALLTHROUGH */
80 case 'd':{
81 long sval;
82 unsigned long uval;
83 char digits[sizeof(int) * 3], *dp = digits;
84 #define SARG() \
85 (size & SZ_LONG ? va_arg(ap, long) : \
86 va_arg(ap, int))
87 #define UARG() \
88 (size & SZ_LONG ? va_arg(ap, unsigned long) : \
89 va_arg(ap, unsigned int))
90 #define ARG() (size & SZ_UNSIGNED ? UARG() : SARG())
91
92 if (fmt[1] == 'd') {
93 sval = ARG();
94 if (sval < 0) {
95 if ((sval << 1) == 0) {
96 /*
97 * We can't flip the
98 * sign of this since
99 * it can't be
100 * represented as a
101 * positive number in
102 * two complement,
103 * handle the first
104 * digit. After that,
105 * it can be flipped
106 * since it is now not
107 * 2^(n-1).
108 */
109 *dp++ = '0'-(sval % 10);
110 sval /= 10;
111 }
112 *bp++ = '-';
113 uval = -sval;
114 } else {
115 uval = sval;
116 }
117 } else {
118 uval = ARG();
119 }
120 do {
121 *dp++ = '0' + (uval % 10);
122 uval /= 10;
123 } while (uval != 0);
124 do {
125 *bp++ = *--dp;
126 } while (dp != digits && bp < ep);
127 fmt += 2;
128 break;
129 }
130 case 'x':
131 case 'p':{
132 unsigned long val = va_arg(ap, unsigned long);
133 unsigned long mask = ~(~0UL >> 4);
134 int bits = sizeof(val) * 8 - 4;
135 const char hexdigits[] = "0123456789abcdef";
136 if (fmt[1] == 'p') {
137 *bp++ = '0';
138 *bp++ = 'x';
139 }
140 /* handle the border case */
141 if (val == 0) {
142 *bp++ = '0';
143 fmt += 2;
144 break;
145 }
146 /* suppress 0s */
147 while ((val & mask) == 0)
148 bits -= 4, mask >>= 4;
149
150 /* emit the hex digits */
151 while (bits >= 0 && bp < ep) {
152 *bp++ = hexdigits[(val & mask) >> bits];
153 bits -= 4, mask >>= 4;
154 }
155 fmt += 2;
156 break;
157 }
158 case 's':{
159 const char *str = va_arg(ap, const char *);
160 int len;
161
162 if (str == NULL)
163 str = "(null)";
164
165 if (prec < 0)
166 len = strlen(str);
167 else
168 len = prec;
169 if (ep - bp < len)
170 len = ep - bp;
171 memcpy(bp, str, len);
172 bp += len;
173 fmt += 2;
174 break;
175 }
176 default:
177 *bp++ = *fmt;
178 break;
179 }
180 break;
181 }
182 default:
183 *bp++ = *fmt++;
184 break;
185 }
186 }
187
188 *bp = '\0';
189 return bp - buf;
190 }
191
192 void
193 xvprintf(const char *fmt, va_list ap)
194 {
195 char buf[256];
196
197 (void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap));
198 }
199
200 void
201 xprintf(const char *fmt, ...)
202 {
203 va_list ap;
204
205 va_start(ap, fmt);
206
207 xvprintf(fmt, ap);
208
209 va_end(ap);
210 }
211
212 void
213 xsnprintf(char *buf, size_t buflen, const char *fmt, ...)
214 {
215 va_list ap;
216
217 va_start(ap, fmt);
218
219 xvsnprintf(buf, buflen, fmt, ap);
220
221 va_end(ap);
222 }
223
224 const char *
225 xstrerror(int error)
226 {
227
228 if (error >= sys_nerr || error < 0) {
229 static char buf[128];
230 xsnprintf(buf, sizeof(buf), "Unknown error: %d", error);
231 return buf;
232 }
233 return sys_errlist[error];
234 }
235
236 void
237 xerrx(int eval, const char *fmt, ...)
238 {
239 va_list ap;
240
241 va_start(ap, fmt);
242 xvprintf(fmt, ap);
243 va_end(ap);
244 (void) write(2, "\n", 1);
245
246 exit(eval);
247 }
248
249 void
250 xerr(int eval, const char *fmt, ...)
251 {
252 int saved_errno = errno;
253 va_list ap;
254
255 va_start(ap, fmt);
256 xvprintf(fmt, ap);
257 va_end(ap);
258
259 xprintf(": %s\n", xstrerror(saved_errno));
260 exit(eval);
261 }
262
263 void
264 xwarn(const char *fmt, ...)
265 {
266 int saved_errno = errno;
267 va_list ap;
268
269 va_start(ap, fmt);
270 xvprintf(fmt, ap);
271 va_end(ap);
272
273 xprintf(": %s\n", xstrerror(saved_errno));
274 errno = saved_errno;
275 }
276
277 void
278 xwarnx(const char *fmt, ...)
279 {
280 va_list ap;
281
282 va_start(ap, fmt);
283 xvprintf(fmt, ap);
284 va_end(ap);
285 (void) write(2, "\n", 1);
286 }
287
288 #ifdef DEBUG
289 void
290 xassert(const char *file, int line, const char *failedexpr)
291 {
292
293 xprintf("assertion \"%s\" failed: file \"%s\", line %d\n",
294 failedexpr, file, line);
295 abort();
296 /* NOTREACHED */
297 }
298 #endif
299 #endif
300