xref: /freebsd/libexec/rtld-elf/rtld_printf.c (revision fbbd9655e5107c68e4e0146ff22b73d7350475bc)
10e9a2605SKonstantin Belousov /*-
20e9a2605SKonstantin Belousov  * Copyright (c) 1986, 1988, 1991, 1993
30e9a2605SKonstantin Belousov  *	The Regents of the University of California.  All rights reserved.
40e9a2605SKonstantin Belousov  * (c) UNIX System Laboratories, Inc.
50e9a2605SKonstantin Belousov  * All or some portions of this file are derived from material licensed
60e9a2605SKonstantin Belousov  * to the University of California by American Telephone and Telegraph
70e9a2605SKonstantin Belousov  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
80e9a2605SKonstantin Belousov  * the permission of UNIX System Laboratories, Inc.
90e9a2605SKonstantin Belousov  * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org>
100e9a2605SKonstantin Belousov  *
110e9a2605SKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
120e9a2605SKonstantin Belousov  * modification, are permitted provided that the following conditions
130e9a2605SKonstantin Belousov  * are met:
140e9a2605SKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
150e9a2605SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer.
160e9a2605SKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
170e9a2605SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
180e9a2605SKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
19*fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
200e9a2605SKonstantin Belousov  *    may be used to endorse or promote products derived from this software
210e9a2605SKonstantin Belousov  *    without specific prior written permission.
220e9a2605SKonstantin Belousov  *
230e9a2605SKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
240e9a2605SKonstantin Belousov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
250e9a2605SKonstantin Belousov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
260e9a2605SKonstantin Belousov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
270e9a2605SKonstantin Belousov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
280e9a2605SKonstantin Belousov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
290e9a2605SKonstantin Belousov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
300e9a2605SKonstantin Belousov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
310e9a2605SKonstantin Belousov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
320e9a2605SKonstantin Belousov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
330e9a2605SKonstantin Belousov  * SUCH DAMAGE.
340e9a2605SKonstantin Belousov  *
350e9a2605SKonstantin Belousov  * $FreeBSD$
360e9a2605SKonstantin Belousov  */
370e9a2605SKonstantin Belousov 
380e9a2605SKonstantin Belousov #include <sys/param.h>
390e9a2605SKonstantin Belousov #include <inttypes.h>
400e9a2605SKonstantin Belousov #include <stdarg.h>
410e9a2605SKonstantin Belousov #include <stddef.h>
420e9a2605SKonstantin Belousov #include <string.h>
430e9a2605SKonstantin Belousov #include <unistd.h>
440e9a2605SKonstantin Belousov #include "rtld_printf.h"
450e9a2605SKonstantin Belousov 
460e9a2605SKonstantin Belousov #define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
470e9a2605SKonstantin Belousov 
48b2367317SKonstantin Belousov #define	PRINT_METHOD_SNPRINTF	1
49b2367317SKonstantin Belousov #define	PRINT_METHOD_WRITE	2
50b2367317SKonstantin Belousov 
510e9a2605SKonstantin Belousov struct snprintf_arg {
52b2367317SKonstantin Belousov 	int	method;
530e9a2605SKonstantin Belousov 	char	*str;
540e9a2605SKonstantin Belousov 	char	*buf;
550e9a2605SKonstantin Belousov 	size_t	remain;
560e9a2605SKonstantin Belousov 	size_t	buf_total;
570e9a2605SKonstantin Belousov 	int	fd;
580e9a2605SKonstantin Belousov };
590e9a2605SKonstantin Belousov 
600e9a2605SKonstantin Belousov static void
610e9a2605SKonstantin Belousov printf_out(struct snprintf_arg *info)
620e9a2605SKonstantin Belousov {
630e9a2605SKonstantin Belousov 
640e9a2605SKonstantin Belousov 	if (info->remain == info->buf_total)
650e9a2605SKonstantin Belousov 		return;
660e9a2605SKonstantin Belousov 	write(info->fd, info->buf, info->buf_total - info->remain);
670e9a2605SKonstantin Belousov 	info->str = info->buf;
680e9a2605SKonstantin Belousov 	info->remain = info->buf_total;
690e9a2605SKonstantin Belousov }
700e9a2605SKonstantin Belousov 
710e9a2605SKonstantin Belousov static void
72b2367317SKonstantin Belousov snprintf_func(int ch, struct snprintf_arg *const info)
730e9a2605SKonstantin Belousov {
740e9a2605SKonstantin Belousov 
75b2367317SKonstantin Belousov 	switch (info->method) {
76b2367317SKonstantin Belousov 	case PRINT_METHOD_SNPRINTF:
77b2367317SKonstantin Belousov 		if (info->remain >= 2) {
78b2367317SKonstantin Belousov 			*info->str++ = ch;
79b2367317SKonstantin Belousov 			info->remain--;
80b2367317SKonstantin Belousov 		}
81b2367317SKonstantin Belousov 		break;
82b2367317SKonstantin Belousov 	case PRINT_METHOD_WRITE:
830e9a2605SKonstantin Belousov 		if (info->remain > 0) {
840e9a2605SKonstantin Belousov 			*info->str++ = ch;
850e9a2605SKonstantin Belousov 			info->remain--;
860e9a2605SKonstantin Belousov 		} else
870e9a2605SKonstantin Belousov 			printf_out(info);
88b2367317SKonstantin Belousov 		break;
89b2367317SKonstantin Belousov 	}
900e9a2605SKonstantin Belousov }
910e9a2605SKonstantin Belousov 
925983b871SKonstantin Belousov static char const hex2ascii_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
935983b871SKonstantin Belousov static char const hex2ascii_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
945983b871SKonstantin Belousov #define	hex2ascii(hex)	(hex2ascii_lower[hex])
955983b871SKonstantin Belousov #define	hex2ascii_upper(hex)	(hex2ascii_upper[hex])
960e9a2605SKonstantin Belousov 
970e9a2605SKonstantin Belousov static __inline int
980e9a2605SKonstantin Belousov imax(int a, int b)
990e9a2605SKonstantin Belousov {
1000e9a2605SKonstantin Belousov 
1010e9a2605SKonstantin Belousov 	return (a > b ? a : b);
1020e9a2605SKonstantin Belousov }
1030e9a2605SKonstantin Belousov 
1040e9a2605SKonstantin Belousov static char *
1050e9a2605SKonstantin Belousov ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
1060e9a2605SKonstantin Belousov {
1070e9a2605SKonstantin Belousov 	char *p, c;
1080e9a2605SKonstantin Belousov 
1090e9a2605SKonstantin Belousov 	p = nbuf;
1100e9a2605SKonstantin Belousov 	*p = '\0';
1110e9a2605SKonstantin Belousov 	do {
1125983b871SKonstantin Belousov 		c = upper ? hex2ascii_upper(num % base) :
1135983b871SKonstantin Belousov 		    hex2ascii(num % base);
1145983b871SKonstantin Belousov 		*++p = c;
1150e9a2605SKonstantin Belousov 	} while (num /= base);
1160e9a2605SKonstantin Belousov 	if (lenp)
1170e9a2605SKonstantin Belousov 		*lenp = p - nbuf;
1180e9a2605SKonstantin Belousov 	return (p);
1190e9a2605SKonstantin Belousov }
1200e9a2605SKonstantin Belousov 
1210e9a2605SKonstantin Belousov static int
122b2367317SKonstantin Belousov kvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap)
1230e9a2605SKonstantin Belousov {
124b2367317SKonstantin Belousov #define PCHAR(c) snprintf_func((c), arg)
1250e9a2605SKonstantin Belousov 	char nbuf[MAXNBUF];
1260e9a2605SKonstantin Belousov 	const char *p, *percent, *q;
1270e9a2605SKonstantin Belousov 	u_char *up;
1280e9a2605SKonstantin Belousov 	int ch, n;
1290e9a2605SKonstantin Belousov 	uintmax_t num;
1300e9a2605SKonstantin Belousov 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
1310e9a2605SKonstantin Belousov 	int cflag, hflag, jflag, tflag, zflag;
1320e9a2605SKonstantin Belousov 	int dwidth, upper;
1330e9a2605SKonstantin Belousov 	char padc;
1340e9a2605SKonstantin Belousov 	int stop = 0, retval = 0;
1350e9a2605SKonstantin Belousov 
1360e9a2605SKonstantin Belousov 	num = 0;
1370e9a2605SKonstantin Belousov 
1380e9a2605SKonstantin Belousov 	if (fmt == NULL)
1390e9a2605SKonstantin Belousov 		fmt = "(fmt null)\n";
1400e9a2605SKonstantin Belousov 
1410e9a2605SKonstantin Belousov 	if (radix < 2 || radix > 36)
1420e9a2605SKonstantin Belousov 		radix = 10;
1430e9a2605SKonstantin Belousov 
1440e9a2605SKonstantin Belousov 	for (;;) {
1450e9a2605SKonstantin Belousov 		padc = ' ';
1460e9a2605SKonstantin Belousov 		width = 0;
1470e9a2605SKonstantin Belousov 		while ((ch = (u_char)*fmt++) != '%' || stop) {
1480e9a2605SKonstantin Belousov 			if (ch == '\0')
1490e9a2605SKonstantin Belousov 				return (retval);
1500e9a2605SKonstantin Belousov 			PCHAR(ch);
1510e9a2605SKonstantin Belousov 		}
1520e9a2605SKonstantin Belousov 		percent = fmt - 1;
1530e9a2605SKonstantin Belousov 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
1540e9a2605SKonstantin Belousov 		sign = 0; dot = 0; dwidth = 0; upper = 0;
1550e9a2605SKonstantin Belousov 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
1560e9a2605SKonstantin Belousov reswitch:	switch (ch = (u_char)*fmt++) {
1570e9a2605SKonstantin Belousov 		case '.':
1580e9a2605SKonstantin Belousov 			dot = 1;
1590e9a2605SKonstantin Belousov 			goto reswitch;
1600e9a2605SKonstantin Belousov 		case '#':
1610e9a2605SKonstantin Belousov 			sharpflag = 1;
1620e9a2605SKonstantin Belousov 			goto reswitch;
1630e9a2605SKonstantin Belousov 		case '+':
1640e9a2605SKonstantin Belousov 			sign = 1;
1650e9a2605SKonstantin Belousov 			goto reswitch;
1660e9a2605SKonstantin Belousov 		case '-':
1670e9a2605SKonstantin Belousov 			ladjust = 1;
1680e9a2605SKonstantin Belousov 			goto reswitch;
1690e9a2605SKonstantin Belousov 		case '%':
1700e9a2605SKonstantin Belousov 			PCHAR(ch);
1710e9a2605SKonstantin Belousov 			break;
1720e9a2605SKonstantin Belousov 		case '*':
1730e9a2605SKonstantin Belousov 			if (!dot) {
1740e9a2605SKonstantin Belousov 				width = va_arg(ap, int);
1750e9a2605SKonstantin Belousov 				if (width < 0) {
1760e9a2605SKonstantin Belousov 					ladjust = !ladjust;
1770e9a2605SKonstantin Belousov 					width = -width;
1780e9a2605SKonstantin Belousov 				}
1790e9a2605SKonstantin Belousov 			} else {
1800e9a2605SKonstantin Belousov 				dwidth = va_arg(ap, int);
1810e9a2605SKonstantin Belousov 			}
1820e9a2605SKonstantin Belousov 			goto reswitch;
1830e9a2605SKonstantin Belousov 		case '0':
1840e9a2605SKonstantin Belousov 			if (!dot) {
1850e9a2605SKonstantin Belousov 				padc = '0';
1860e9a2605SKonstantin Belousov 				goto reswitch;
1870e9a2605SKonstantin Belousov 			}
1880e9a2605SKonstantin Belousov 		case '1': case '2': case '3': case '4':
1890e9a2605SKonstantin Belousov 		case '5': case '6': case '7': case '8': case '9':
1900e9a2605SKonstantin Belousov 				for (n = 0;; ++fmt) {
1910e9a2605SKonstantin Belousov 					n = n * 10 + ch - '0';
1920e9a2605SKonstantin Belousov 					ch = *fmt;
1930e9a2605SKonstantin Belousov 					if (ch < '0' || ch > '9')
1940e9a2605SKonstantin Belousov 						break;
1950e9a2605SKonstantin Belousov 				}
1960e9a2605SKonstantin Belousov 			if (dot)
1970e9a2605SKonstantin Belousov 				dwidth = n;
1980e9a2605SKonstantin Belousov 			else
1990e9a2605SKonstantin Belousov 				width = n;
2000e9a2605SKonstantin Belousov 			goto reswitch;
2010e9a2605SKonstantin Belousov 		case 'b':
2020e9a2605SKonstantin Belousov 			num = (u_int)va_arg(ap, int);
2030e9a2605SKonstantin Belousov 			p = va_arg(ap, char *);
2040e9a2605SKonstantin Belousov 			for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
2050e9a2605SKonstantin Belousov 				PCHAR(*q--);
2060e9a2605SKonstantin Belousov 
2070e9a2605SKonstantin Belousov 			if (num == 0)
2080e9a2605SKonstantin Belousov 				break;
2090e9a2605SKonstantin Belousov 
2100e9a2605SKonstantin Belousov 			for (tmp = 0; *p;) {
2110e9a2605SKonstantin Belousov 				n = *p++;
2120e9a2605SKonstantin Belousov 				if (num & (1 << (n - 1))) {
2130e9a2605SKonstantin Belousov 					PCHAR(tmp ? ',' : '<');
2140e9a2605SKonstantin Belousov 					for (; (n = *p) > ' '; ++p)
2150e9a2605SKonstantin Belousov 						PCHAR(n);
2160e9a2605SKonstantin Belousov 					tmp = 1;
2170e9a2605SKonstantin Belousov 				} else
2180e9a2605SKonstantin Belousov 					for (; *p > ' '; ++p)
2190e9a2605SKonstantin Belousov 						continue;
2200e9a2605SKonstantin Belousov 			}
2210e9a2605SKonstantin Belousov 			if (tmp)
2220e9a2605SKonstantin Belousov 				PCHAR('>');
2230e9a2605SKonstantin Belousov 			break;
2240e9a2605SKonstantin Belousov 		case 'c':
2250e9a2605SKonstantin Belousov 			PCHAR(va_arg(ap, int));
2260e9a2605SKonstantin Belousov 			break;
2270e9a2605SKonstantin Belousov 		case 'D':
2280e9a2605SKonstantin Belousov 			up = va_arg(ap, u_char *);
2290e9a2605SKonstantin Belousov 			p = va_arg(ap, char *);
2300e9a2605SKonstantin Belousov 			if (!width)
2310e9a2605SKonstantin Belousov 				width = 16;
2320e9a2605SKonstantin Belousov 			while(width--) {
2330e9a2605SKonstantin Belousov 				PCHAR(hex2ascii(*up >> 4));
2340e9a2605SKonstantin Belousov 				PCHAR(hex2ascii(*up & 0x0f));
2350e9a2605SKonstantin Belousov 				up++;
2360e9a2605SKonstantin Belousov 				if (width)
2370e9a2605SKonstantin Belousov 					for (q=p;*q;q++)
2380e9a2605SKonstantin Belousov 						PCHAR(*q);
2390e9a2605SKonstantin Belousov 			}
2400e9a2605SKonstantin Belousov 			break;
2410e9a2605SKonstantin Belousov 		case 'd':
2420e9a2605SKonstantin Belousov 		case 'i':
2430e9a2605SKonstantin Belousov 			base = 10;
2440e9a2605SKonstantin Belousov 			sign = 1;
2450e9a2605SKonstantin Belousov 			goto handle_sign;
2460e9a2605SKonstantin Belousov 		case 'h':
2470e9a2605SKonstantin Belousov 			if (hflag) {
2480e9a2605SKonstantin Belousov 				hflag = 0;
2490e9a2605SKonstantin Belousov 				cflag = 1;
2500e9a2605SKonstantin Belousov 			} else
2510e9a2605SKonstantin Belousov 				hflag = 1;
2520e9a2605SKonstantin Belousov 			goto reswitch;
2530e9a2605SKonstantin Belousov 		case 'j':
2540e9a2605SKonstantin Belousov 			jflag = 1;
2550e9a2605SKonstantin Belousov 			goto reswitch;
2560e9a2605SKonstantin Belousov 		case 'l':
2570e9a2605SKonstantin Belousov 			if (lflag) {
2580e9a2605SKonstantin Belousov 				lflag = 0;
2590e9a2605SKonstantin Belousov 				qflag = 1;
2600e9a2605SKonstantin Belousov 			} else
2610e9a2605SKonstantin Belousov 				lflag = 1;
2620e9a2605SKonstantin Belousov 			goto reswitch;
2630e9a2605SKonstantin Belousov 		case 'n':
2640e9a2605SKonstantin Belousov 			if (jflag)
2650e9a2605SKonstantin Belousov 				*(va_arg(ap, intmax_t *)) = retval;
2660e9a2605SKonstantin Belousov 			else if (qflag)
2670e9a2605SKonstantin Belousov 				*(va_arg(ap, quad_t *)) = retval;
2680e9a2605SKonstantin Belousov 			else if (lflag)
2690e9a2605SKonstantin Belousov 				*(va_arg(ap, long *)) = retval;
2700e9a2605SKonstantin Belousov 			else if (zflag)
2710e9a2605SKonstantin Belousov 				*(va_arg(ap, size_t *)) = retval;
2720e9a2605SKonstantin Belousov 			else if (hflag)
2730e9a2605SKonstantin Belousov 				*(va_arg(ap, short *)) = retval;
2740e9a2605SKonstantin Belousov 			else if (cflag)
2750e9a2605SKonstantin Belousov 				*(va_arg(ap, char *)) = retval;
2760e9a2605SKonstantin Belousov 			else
2770e9a2605SKonstantin Belousov 				*(va_arg(ap, int *)) = retval;
2780e9a2605SKonstantin Belousov 			break;
2790e9a2605SKonstantin Belousov 		case 'o':
2800e9a2605SKonstantin Belousov 			base = 8;
2810e9a2605SKonstantin Belousov 			goto handle_nosign;
2820e9a2605SKonstantin Belousov 		case 'p':
2830e9a2605SKonstantin Belousov 			base = 16;
2840e9a2605SKonstantin Belousov 			sharpflag = (width == 0);
2850e9a2605SKonstantin Belousov 			sign = 0;
2860e9a2605SKonstantin Belousov 			num = (uintptr_t)va_arg(ap, void *);
2870e9a2605SKonstantin Belousov 			goto number;
2880e9a2605SKonstantin Belousov 		case 'q':
2890e9a2605SKonstantin Belousov 			qflag = 1;
2900e9a2605SKonstantin Belousov 			goto reswitch;
2910e9a2605SKonstantin Belousov 		case 'r':
2920e9a2605SKonstantin Belousov 			base = radix;
2930e9a2605SKonstantin Belousov 			if (sign)
2940e9a2605SKonstantin Belousov 				goto handle_sign;
2950e9a2605SKonstantin Belousov 			goto handle_nosign;
2960e9a2605SKonstantin Belousov 		case 's':
2970e9a2605SKonstantin Belousov 			p = va_arg(ap, char *);
2980e9a2605SKonstantin Belousov 			if (p == NULL)
2990e9a2605SKonstantin Belousov 				p = "(null)";
3000e9a2605SKonstantin Belousov 			if (!dot)
3010e9a2605SKonstantin Belousov 				n = strlen (p);
3020e9a2605SKonstantin Belousov 			else
3030e9a2605SKonstantin Belousov 				for (n = 0; n < dwidth && p[n]; n++)
3040e9a2605SKonstantin Belousov 					continue;
3050e9a2605SKonstantin Belousov 
3060e9a2605SKonstantin Belousov 			width -= n;
3070e9a2605SKonstantin Belousov 
3080e9a2605SKonstantin Belousov 			if (!ladjust && width > 0)
3090e9a2605SKonstantin Belousov 				while (width--)
3100e9a2605SKonstantin Belousov 					PCHAR(padc);
3110e9a2605SKonstantin Belousov 			while (n--)
3120e9a2605SKonstantin Belousov 				PCHAR(*p++);
3130e9a2605SKonstantin Belousov 			if (ladjust && width > 0)
3140e9a2605SKonstantin Belousov 				while (width--)
3150e9a2605SKonstantin Belousov 					PCHAR(padc);
3160e9a2605SKonstantin Belousov 			break;
3170e9a2605SKonstantin Belousov 		case 't':
3180e9a2605SKonstantin Belousov 			tflag = 1;
3190e9a2605SKonstantin Belousov 			goto reswitch;
3200e9a2605SKonstantin Belousov 		case 'u':
3210e9a2605SKonstantin Belousov 			base = 10;
3220e9a2605SKonstantin Belousov 			goto handle_nosign;
3230e9a2605SKonstantin Belousov 		case 'X':
3240e9a2605SKonstantin Belousov 			upper = 1;
3250e9a2605SKonstantin Belousov 		case 'x':
3260e9a2605SKonstantin Belousov 			base = 16;
3270e9a2605SKonstantin Belousov 			goto handle_nosign;
3280e9a2605SKonstantin Belousov 		case 'y':
3290e9a2605SKonstantin Belousov 			base = 16;
3300e9a2605SKonstantin Belousov 			sign = 1;
3310e9a2605SKonstantin Belousov 			goto handle_sign;
3320e9a2605SKonstantin Belousov 		case 'z':
3330e9a2605SKonstantin Belousov 			zflag = 1;
3340e9a2605SKonstantin Belousov 			goto reswitch;
3350e9a2605SKonstantin Belousov handle_nosign:
3360e9a2605SKonstantin Belousov 			sign = 0;
3370e9a2605SKonstantin Belousov 			if (jflag)
3380e9a2605SKonstantin Belousov 				num = va_arg(ap, uintmax_t);
3390e9a2605SKonstantin Belousov 			else if (qflag)
3400e9a2605SKonstantin Belousov 				num = va_arg(ap, u_quad_t);
3410e9a2605SKonstantin Belousov 			else if (tflag)
3420e9a2605SKonstantin Belousov 				num = va_arg(ap, ptrdiff_t);
3430e9a2605SKonstantin Belousov 			else if (lflag)
3440e9a2605SKonstantin Belousov 				num = va_arg(ap, u_long);
3450e9a2605SKonstantin Belousov 			else if (zflag)
3460e9a2605SKonstantin Belousov 				num = va_arg(ap, size_t);
3470e9a2605SKonstantin Belousov 			else if (hflag)
3480e9a2605SKonstantin Belousov 				num = (u_short)va_arg(ap, int);
3490e9a2605SKonstantin Belousov 			else if (cflag)
3500e9a2605SKonstantin Belousov 				num = (u_char)va_arg(ap, int);
3510e9a2605SKonstantin Belousov 			else
3520e9a2605SKonstantin Belousov 				num = va_arg(ap, u_int);
3530e9a2605SKonstantin Belousov 			goto number;
3540e9a2605SKonstantin Belousov handle_sign:
3550e9a2605SKonstantin Belousov 			if (jflag)
3560e9a2605SKonstantin Belousov 				num = va_arg(ap, intmax_t);
3570e9a2605SKonstantin Belousov 			else if (qflag)
3580e9a2605SKonstantin Belousov 				num = va_arg(ap, quad_t);
3590e9a2605SKonstantin Belousov 			else if (tflag)
3600e9a2605SKonstantin Belousov 				num = va_arg(ap, ptrdiff_t);
3610e9a2605SKonstantin Belousov 			else if (lflag)
3620e9a2605SKonstantin Belousov 				num = va_arg(ap, long);
3630e9a2605SKonstantin Belousov 			else if (zflag)
3640e9a2605SKonstantin Belousov 				num = va_arg(ap, ssize_t);
3650e9a2605SKonstantin Belousov 			else if (hflag)
3660e9a2605SKonstantin Belousov 				num = (short)va_arg(ap, int);
3670e9a2605SKonstantin Belousov 			else if (cflag)
3680e9a2605SKonstantin Belousov 				num = (char)va_arg(ap, int);
3690e9a2605SKonstantin Belousov 			else
3700e9a2605SKonstantin Belousov 				num = va_arg(ap, int);
3710e9a2605SKonstantin Belousov number:
3720e9a2605SKonstantin Belousov 			if (sign && (intmax_t)num < 0) {
3730e9a2605SKonstantin Belousov 				neg = 1;
3740e9a2605SKonstantin Belousov 				num = -(intmax_t)num;
3750e9a2605SKonstantin Belousov 			}
3760e9a2605SKonstantin Belousov 			p = ksprintn(nbuf, num, base, &n, upper);
3770e9a2605SKonstantin Belousov 			tmp = 0;
3780e9a2605SKonstantin Belousov 			if (sharpflag && num != 0) {
3790e9a2605SKonstantin Belousov 				if (base == 8)
3800e9a2605SKonstantin Belousov 					tmp++;
3810e9a2605SKonstantin Belousov 				else if (base == 16)
3820e9a2605SKonstantin Belousov 					tmp += 2;
3830e9a2605SKonstantin Belousov 			}
3840e9a2605SKonstantin Belousov 			if (neg)
3850e9a2605SKonstantin Belousov 				tmp++;
3860e9a2605SKonstantin Belousov 
3870e9a2605SKonstantin Belousov 			if (!ladjust && padc == '0')
3880e9a2605SKonstantin Belousov 				dwidth = width - tmp;
3890e9a2605SKonstantin Belousov 			width -= tmp + imax(dwidth, n);
3900e9a2605SKonstantin Belousov 			dwidth -= n;
3910e9a2605SKonstantin Belousov 			if (!ladjust)
3920e9a2605SKonstantin Belousov 				while (width-- > 0)
3930e9a2605SKonstantin Belousov 					PCHAR(' ');
3940e9a2605SKonstantin Belousov 			if (neg)
3950e9a2605SKonstantin Belousov 				PCHAR('-');
3960e9a2605SKonstantin Belousov 			if (sharpflag && num != 0) {
3970e9a2605SKonstantin Belousov 				if (base == 8) {
3980e9a2605SKonstantin Belousov 					PCHAR('0');
3990e9a2605SKonstantin Belousov 				} else if (base == 16) {
4000e9a2605SKonstantin Belousov 					PCHAR('0');
4010e9a2605SKonstantin Belousov 					PCHAR('x');
4020e9a2605SKonstantin Belousov 				}
4030e9a2605SKonstantin Belousov 			}
4040e9a2605SKonstantin Belousov 			while (dwidth-- > 0)
4050e9a2605SKonstantin Belousov 				PCHAR('0');
4060e9a2605SKonstantin Belousov 
4070e9a2605SKonstantin Belousov 			while (*p)
4080e9a2605SKonstantin Belousov 				PCHAR(*p--);
4090e9a2605SKonstantin Belousov 
4100e9a2605SKonstantin Belousov 			if (ladjust)
4110e9a2605SKonstantin Belousov 				while (width-- > 0)
4120e9a2605SKonstantin Belousov 					PCHAR(' ');
4130e9a2605SKonstantin Belousov 
4140e9a2605SKonstantin Belousov 			break;
4150e9a2605SKonstantin Belousov 		default:
4160e9a2605SKonstantin Belousov 			while (percent < fmt)
4170e9a2605SKonstantin Belousov 				PCHAR(*percent++);
4180e9a2605SKonstantin Belousov 			/*
4190e9a2605SKonstantin Belousov 			 * Since we ignore an formatting argument it is no
4200e9a2605SKonstantin Belousov 			 * longer safe to obey the remaining formatting
4210e9a2605SKonstantin Belousov 			 * arguments as the arguments will no longer match
4220e9a2605SKonstantin Belousov 			 * the format specs.
4230e9a2605SKonstantin Belousov 			 */
4240e9a2605SKonstantin Belousov 			stop = 1;
4250e9a2605SKonstantin Belousov 			break;
4260e9a2605SKonstantin Belousov 		}
4270e9a2605SKonstantin Belousov 	}
4280e9a2605SKonstantin Belousov #undef PCHAR
4290e9a2605SKonstantin Belousov }
4300e9a2605SKonstantin Belousov 
4310e9a2605SKonstantin Belousov int
43202d3b38eSJonathan Anderson rtld_snprintf(char *buf, size_t bufsize, const char *fmt, ...)
43302d3b38eSJonathan Anderson {
43402d3b38eSJonathan Anderson 	va_list ap;
43502d3b38eSJonathan Anderson 	int retval;
43602d3b38eSJonathan Anderson 
43702d3b38eSJonathan Anderson 	va_start(ap, fmt);
43802d3b38eSJonathan Anderson 	retval = rtld_vsnprintf(buf, bufsize, fmt, ap);
43902d3b38eSJonathan Anderson 	va_end(ap);
44002d3b38eSJonathan Anderson 	return (retval);
44102d3b38eSJonathan Anderson }
44202d3b38eSJonathan Anderson 
44302d3b38eSJonathan Anderson int
4440e9a2605SKonstantin Belousov rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap)
4450e9a2605SKonstantin Belousov {
4460e9a2605SKonstantin Belousov 	struct snprintf_arg info;
4470e9a2605SKonstantin Belousov 	int retval;
4480e9a2605SKonstantin Belousov 
449b2367317SKonstantin Belousov 	info.method = PRINT_METHOD_SNPRINTF;
4500e9a2605SKonstantin Belousov 	info.buf = info.str = buf;
4510e9a2605SKonstantin Belousov 	info.buf_total = info.remain = bufsize;
4520e9a2605SKonstantin Belousov 	info.fd = -1;
453b2367317SKonstantin Belousov 	retval = kvprintf(fmt, &info, 10, ap);
4540e9a2605SKonstantin Belousov 	if (info.remain >= 1)
4550e9a2605SKonstantin Belousov 		*info.str++ = '\0';
4560e9a2605SKonstantin Belousov 	return (retval);
4570e9a2605SKonstantin Belousov }
4580e9a2605SKonstantin Belousov 
4590e9a2605SKonstantin Belousov int
4600e9a2605SKonstantin Belousov rtld_vfdprintf(int fd, const char *fmt, va_list ap)
4610e9a2605SKonstantin Belousov {
4620e9a2605SKonstantin Belousov 	char buf[512];
4630e9a2605SKonstantin Belousov 	struct snprintf_arg info;
4640e9a2605SKonstantin Belousov 	int retval;
4650e9a2605SKonstantin Belousov 
466b2367317SKonstantin Belousov 	info.method = PRINT_METHOD_WRITE;
4670e9a2605SKonstantin Belousov 	info.buf = info.str = buf;
4680e9a2605SKonstantin Belousov 	info.buf_total = info.remain = sizeof(buf);
4690e9a2605SKonstantin Belousov 	info.fd = fd;
470b2367317SKonstantin Belousov 	retval = kvprintf(fmt, &info, 10, ap);
4710e9a2605SKonstantin Belousov 	printf_out(&info);
4720e9a2605SKonstantin Belousov 	return (retval);
4730e9a2605SKonstantin Belousov }
4740e9a2605SKonstantin Belousov 
4750e9a2605SKonstantin Belousov int
4760e9a2605SKonstantin Belousov rtld_fdprintf(int fd, const char *fmt, ...)
4770e9a2605SKonstantin Belousov {
4780e9a2605SKonstantin Belousov 	va_list ap;
4790e9a2605SKonstantin Belousov 	int retval;
4800e9a2605SKonstantin Belousov 
4810e9a2605SKonstantin Belousov 	va_start(ap, fmt);
4820e9a2605SKonstantin Belousov 	retval = rtld_vfdprintf(fd, fmt, ap);
4830e9a2605SKonstantin Belousov 	va_end(ap);
4840e9a2605SKonstantin Belousov 	return (retval);
4850e9a2605SKonstantin Belousov }
4860e9a2605SKonstantin Belousov 
4870e9a2605SKonstantin Belousov void
4880e9a2605SKonstantin Belousov rtld_fdputstr(int fd, const char *str)
4890e9a2605SKonstantin Belousov {
4900e9a2605SKonstantin Belousov 
4910e9a2605SKonstantin Belousov 	write(fd, str, strlen(str));
4920e9a2605SKonstantin Belousov }
4930e9a2605SKonstantin Belousov 
4940e9a2605SKonstantin Belousov void
4950e9a2605SKonstantin Belousov rtld_fdputchar(int fd, int c)
4960e9a2605SKonstantin Belousov {
4970e9a2605SKonstantin Belousov 	char c1;
4980e9a2605SKonstantin Belousov 
4990e9a2605SKonstantin Belousov 	c1 = c;
5000e9a2605SKonstantin Belousov 	write(fd, &c1, 1);
5010e9a2605SKonstantin Belousov }
502