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