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