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