xref: /freebsd/libexec/rtld-elf/rtld_printf.c (revision 56ee5fc4)
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 
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"
45b54a59f3SAlex Richardson #include "rtld_libc.h"
460e9a2605SKonstantin Belousov 
470e9a2605SKonstantin Belousov #define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
480e9a2605SKonstantin Belousov 
49b2367317SKonstantin Belousov #define	PRINT_METHOD_SNPRINTF	1
50b2367317SKonstantin Belousov #define	PRINT_METHOD_WRITE	2
51b2367317SKonstantin Belousov 
520e9a2605SKonstantin Belousov struct snprintf_arg {
53b2367317SKonstantin Belousov 	int	method;
540e9a2605SKonstantin Belousov 	char	*str;
550e9a2605SKonstantin Belousov 	char	*buf;
560e9a2605SKonstantin Belousov 	size_t	remain;
570e9a2605SKonstantin Belousov 	size_t	buf_total;
580e9a2605SKonstantin Belousov 	int	fd;
590e9a2605SKonstantin Belousov };
600e9a2605SKonstantin Belousov 
610e9a2605SKonstantin Belousov static void
printf_out(struct snprintf_arg * info)620e9a2605SKonstantin Belousov printf_out(struct snprintf_arg *info)
630e9a2605SKonstantin Belousov {
640e9a2605SKonstantin Belousov 
650e9a2605SKonstantin Belousov 	if (info->remain == info->buf_total)
660e9a2605SKonstantin Belousov 		return;
670e9a2605SKonstantin Belousov 	write(info->fd, info->buf, info->buf_total - info->remain);
680e9a2605SKonstantin Belousov 	info->str = info->buf;
690e9a2605SKonstantin Belousov 	info->remain = info->buf_total;
700e9a2605SKonstantin Belousov }
710e9a2605SKonstantin Belousov 
720e9a2605SKonstantin Belousov static void
snprintf_func(int ch,struct snprintf_arg * const info)73b2367317SKonstantin Belousov snprintf_func(int ch, struct snprintf_arg *const info)
740e9a2605SKonstantin Belousov {
750e9a2605SKonstantin Belousov 
76b2367317SKonstantin Belousov 	switch (info->method) {
77b2367317SKonstantin Belousov 	case PRINT_METHOD_SNPRINTF:
78b2367317SKonstantin Belousov 		if (info->remain >= 2) {
79b2367317SKonstantin Belousov 			*info->str++ = ch;
80b2367317SKonstantin Belousov 			info->remain--;
81b2367317SKonstantin Belousov 		}
82b2367317SKonstantin Belousov 		break;
83b2367317SKonstantin Belousov 	case PRINT_METHOD_WRITE:
8456ee5fc4SKonstantin Belousov 		if (info->remain == 0)
8556ee5fc4SKonstantin Belousov 			printf_out(info);
860e9a2605SKonstantin Belousov 		*info->str++ = ch;
870e9a2605SKonstantin Belousov 		info->remain--;
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
imax(int a,int b)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 *
ksprintn(char * nbuf,uintmax_t num,int base,int * lenp,int upper)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
kvprintf(char const * fmt,struct snprintf_arg * arg,int radix,va_list ap)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 			}
1883ab5b6bdSAlex Richardson 			/* FALLTHROUGH */
1890e9a2605SKonstantin Belousov 		case '1': case '2': case '3': case '4':
1900e9a2605SKonstantin Belousov 		case '5': case '6': case '7': case '8': case '9':
1910e9a2605SKonstantin Belousov 				for (n = 0;; ++fmt) {
1920e9a2605SKonstantin Belousov 					n = n * 10 + ch - '0';
1930e9a2605SKonstantin Belousov 					ch = *fmt;
1940e9a2605SKonstantin Belousov 					if (ch < '0' || ch > '9')
1950e9a2605SKonstantin Belousov 						break;
1960e9a2605SKonstantin Belousov 				}
1970e9a2605SKonstantin Belousov 			if (dot)
1980e9a2605SKonstantin Belousov 				dwidth = n;
1990e9a2605SKonstantin Belousov 			else
2000e9a2605SKonstantin Belousov 				width = n;
2010e9a2605SKonstantin Belousov 			goto reswitch;
2020e9a2605SKonstantin Belousov 		case 'b':
2030e9a2605SKonstantin Belousov 			num = (u_int)va_arg(ap, int);
2040e9a2605SKonstantin Belousov 			p = va_arg(ap, char *);
2050e9a2605SKonstantin Belousov 			for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
2060e9a2605SKonstantin Belousov 				PCHAR(*q--);
2070e9a2605SKonstantin Belousov 
2080e9a2605SKonstantin Belousov 			if (num == 0)
2090e9a2605SKonstantin Belousov 				break;
2100e9a2605SKonstantin Belousov 
2110e9a2605SKonstantin Belousov 			for (tmp = 0; *p;) {
2120e9a2605SKonstantin Belousov 				n = *p++;
2130e9a2605SKonstantin Belousov 				if (num & (1 << (n - 1))) {
2140e9a2605SKonstantin Belousov 					PCHAR(tmp ? ',' : '<');
2150e9a2605SKonstantin Belousov 					for (; (n = *p) > ' '; ++p)
2160e9a2605SKonstantin Belousov 						PCHAR(n);
2170e9a2605SKonstantin Belousov 					tmp = 1;
2180e9a2605SKonstantin Belousov 				} else
2190e9a2605SKonstantin Belousov 					for (; *p > ' '; ++p)
2200e9a2605SKonstantin Belousov 						continue;
2210e9a2605SKonstantin Belousov 			}
2220e9a2605SKonstantin Belousov 			if (tmp)
2230e9a2605SKonstantin Belousov 				PCHAR('>');
2240e9a2605SKonstantin Belousov 			break;
2250e9a2605SKonstantin Belousov 		case 'c':
2260e9a2605SKonstantin Belousov 			PCHAR(va_arg(ap, int));
2270e9a2605SKonstantin Belousov 			break;
2280e9a2605SKonstantin Belousov 		case 'D':
2290e9a2605SKonstantin Belousov 			up = va_arg(ap, u_char *);
2300e9a2605SKonstantin Belousov 			p = va_arg(ap, char *);
2310e9a2605SKonstantin Belousov 			if (!width)
2320e9a2605SKonstantin Belousov 				width = 16;
2330e9a2605SKonstantin Belousov 			while(width--) {
2340e9a2605SKonstantin Belousov 				PCHAR(hex2ascii(*up >> 4));
2350e9a2605SKonstantin Belousov 				PCHAR(hex2ascii(*up & 0x0f));
2360e9a2605SKonstantin Belousov 				up++;
2370e9a2605SKonstantin Belousov 				if (width)
2380e9a2605SKonstantin Belousov 					for (q=p;*q;q++)
2390e9a2605SKonstantin Belousov 						PCHAR(*q);
2400e9a2605SKonstantin Belousov 			}
2410e9a2605SKonstantin Belousov 			break;
2420e9a2605SKonstantin Belousov 		case 'd':
2430e9a2605SKonstantin Belousov 		case 'i':
2440e9a2605SKonstantin Belousov 			base = 10;
2450e9a2605SKonstantin Belousov 			sign = 1;
2460e9a2605SKonstantin Belousov 			goto handle_sign;
2470e9a2605SKonstantin Belousov 		case 'h':
2480e9a2605SKonstantin Belousov 			if (hflag) {
2490e9a2605SKonstantin Belousov 				hflag = 0;
2500e9a2605SKonstantin Belousov 				cflag = 1;
2510e9a2605SKonstantin Belousov 			} else
2520e9a2605SKonstantin Belousov 				hflag = 1;
2530e9a2605SKonstantin Belousov 			goto reswitch;
2540e9a2605SKonstantin Belousov 		case 'j':
2550e9a2605SKonstantin Belousov 			jflag = 1;
2560e9a2605SKonstantin Belousov 			goto reswitch;
2570e9a2605SKonstantin Belousov 		case 'l':
2580e9a2605SKonstantin Belousov 			if (lflag) {
2590e9a2605SKonstantin Belousov 				lflag = 0;
2600e9a2605SKonstantin Belousov 				qflag = 1;
2610e9a2605SKonstantin Belousov 			} else
2620e9a2605SKonstantin Belousov 				lflag = 1;
2630e9a2605SKonstantin Belousov 			goto reswitch;
2640e9a2605SKonstantin Belousov 		case 'n':
2650e9a2605SKonstantin Belousov 			if (jflag)
2660e9a2605SKonstantin Belousov 				*(va_arg(ap, intmax_t *)) = retval;
2670e9a2605SKonstantin Belousov 			else if (qflag)
2680e9a2605SKonstantin Belousov 				*(va_arg(ap, quad_t *)) = retval;
2690e9a2605SKonstantin Belousov 			else if (lflag)
2700e9a2605SKonstantin Belousov 				*(va_arg(ap, long *)) = retval;
2710e9a2605SKonstantin Belousov 			else if (zflag)
2720e9a2605SKonstantin Belousov 				*(va_arg(ap, size_t *)) = retval;
2730e9a2605SKonstantin Belousov 			else if (hflag)
2740e9a2605SKonstantin Belousov 				*(va_arg(ap, short *)) = retval;
2750e9a2605SKonstantin Belousov 			else if (cflag)
2760e9a2605SKonstantin Belousov 				*(va_arg(ap, char *)) = retval;
2770e9a2605SKonstantin Belousov 			else
2780e9a2605SKonstantin Belousov 				*(va_arg(ap, int *)) = retval;
2790e9a2605SKonstantin Belousov 			break;
2800e9a2605SKonstantin Belousov 		case 'o':
2810e9a2605SKonstantin Belousov 			base = 8;
2820e9a2605SKonstantin Belousov 			goto handle_nosign;
2830e9a2605SKonstantin Belousov 		case 'p':
2840e9a2605SKonstantin Belousov 			base = 16;
2850e9a2605SKonstantin Belousov 			sharpflag = (width == 0);
2860e9a2605SKonstantin Belousov 			sign = 0;
2870e9a2605SKonstantin Belousov 			num = (uintptr_t)va_arg(ap, void *);
2880e9a2605SKonstantin Belousov 			goto number;
2890e9a2605SKonstantin Belousov 		case 'q':
2900e9a2605SKonstantin Belousov 			qflag = 1;
2910e9a2605SKonstantin Belousov 			goto reswitch;
2920e9a2605SKonstantin Belousov 		case 'r':
2930e9a2605SKonstantin Belousov 			base = radix;
2940e9a2605SKonstantin Belousov 			if (sign)
2950e9a2605SKonstantin Belousov 				goto handle_sign;
2960e9a2605SKonstantin Belousov 			goto handle_nosign;
2970e9a2605SKonstantin Belousov 		case 's':
2980e9a2605SKonstantin Belousov 			p = va_arg(ap, char *);
2990e9a2605SKonstantin Belousov 			if (p == NULL)
3000e9a2605SKonstantin Belousov 				p = "(null)";
3010e9a2605SKonstantin Belousov 			if (!dot)
3020e9a2605SKonstantin Belousov 				n = strlen (p);
3030e9a2605SKonstantin Belousov 			else
3040e9a2605SKonstantin Belousov 				for (n = 0; n < dwidth && p[n]; n++)
3050e9a2605SKonstantin Belousov 					continue;
3060e9a2605SKonstantin Belousov 
3070e9a2605SKonstantin Belousov 			width -= n;
3080e9a2605SKonstantin Belousov 
3090e9a2605SKonstantin Belousov 			if (!ladjust && width > 0)
3100e9a2605SKonstantin Belousov 				while (width--)
3110e9a2605SKonstantin Belousov 					PCHAR(padc);
3120e9a2605SKonstantin Belousov 			while (n--)
3130e9a2605SKonstantin Belousov 				PCHAR(*p++);
3140e9a2605SKonstantin Belousov 			if (ladjust && width > 0)
3150e9a2605SKonstantin Belousov 				while (width--)
3160e9a2605SKonstantin Belousov 					PCHAR(padc);
3170e9a2605SKonstantin Belousov 			break;
3180e9a2605SKonstantin Belousov 		case 't':
3190e9a2605SKonstantin Belousov 			tflag = 1;
3200e9a2605SKonstantin Belousov 			goto reswitch;
3210e9a2605SKonstantin Belousov 		case 'u':
3220e9a2605SKonstantin Belousov 			base = 10;
3230e9a2605SKonstantin Belousov 			goto handle_nosign;
3240e9a2605SKonstantin Belousov 		case 'X':
3250e9a2605SKonstantin Belousov 			upper = 1;
3263ab5b6bdSAlex Richardson 			/* FALLTHROUGH */
3270e9a2605SKonstantin Belousov 		case 'x':
3280e9a2605SKonstantin Belousov 			base = 16;
3290e9a2605SKonstantin Belousov 			goto handle_nosign;
3300e9a2605SKonstantin Belousov 		case 'y':
3310e9a2605SKonstantin Belousov 			base = 16;
3320e9a2605SKonstantin Belousov 			sign = 1;
3330e9a2605SKonstantin Belousov 			goto handle_sign;
3340e9a2605SKonstantin Belousov 		case 'z':
3350e9a2605SKonstantin Belousov 			zflag = 1;
3360e9a2605SKonstantin Belousov 			goto reswitch;
3370e9a2605SKonstantin Belousov handle_nosign:
3380e9a2605SKonstantin Belousov 			sign = 0;
3390e9a2605SKonstantin Belousov 			if (jflag)
3400e9a2605SKonstantin Belousov 				num = va_arg(ap, uintmax_t);
3410e9a2605SKonstantin Belousov 			else if (qflag)
3420e9a2605SKonstantin Belousov 				num = va_arg(ap, u_quad_t);
3430e9a2605SKonstantin Belousov 			else if (tflag)
3440e9a2605SKonstantin Belousov 				num = va_arg(ap, ptrdiff_t);
3450e9a2605SKonstantin Belousov 			else if (lflag)
3460e9a2605SKonstantin Belousov 				num = va_arg(ap, u_long);
3470e9a2605SKonstantin Belousov 			else if (zflag)
3480e9a2605SKonstantin Belousov 				num = va_arg(ap, size_t);
3490e9a2605SKonstantin Belousov 			else if (hflag)
3500e9a2605SKonstantin Belousov 				num = (u_short)va_arg(ap, int);
3510e9a2605SKonstantin Belousov 			else if (cflag)
3520e9a2605SKonstantin Belousov 				num = (u_char)va_arg(ap, int);
3530e9a2605SKonstantin Belousov 			else
3540e9a2605SKonstantin Belousov 				num = va_arg(ap, u_int);
3550e9a2605SKonstantin Belousov 			goto number;
3560e9a2605SKonstantin Belousov handle_sign:
3570e9a2605SKonstantin Belousov 			if (jflag)
3580e9a2605SKonstantin Belousov 				num = va_arg(ap, intmax_t);
3590e9a2605SKonstantin Belousov 			else if (qflag)
3600e9a2605SKonstantin Belousov 				num = va_arg(ap, quad_t);
3610e9a2605SKonstantin Belousov 			else if (tflag)
3620e9a2605SKonstantin Belousov 				num = va_arg(ap, ptrdiff_t);
3630e9a2605SKonstantin Belousov 			else if (lflag)
3640e9a2605SKonstantin Belousov 				num = va_arg(ap, long);
3650e9a2605SKonstantin Belousov 			else if (zflag)
3660e9a2605SKonstantin Belousov 				num = va_arg(ap, ssize_t);
3670e9a2605SKonstantin Belousov 			else if (hflag)
3680e9a2605SKonstantin Belousov 				num = (short)va_arg(ap, int);
3690e9a2605SKonstantin Belousov 			else if (cflag)
3700e9a2605SKonstantin Belousov 				num = (char)va_arg(ap, int);
3710e9a2605SKonstantin Belousov 			else
3720e9a2605SKonstantin Belousov 				num = va_arg(ap, int);
3730e9a2605SKonstantin Belousov number:
3740e9a2605SKonstantin Belousov 			if (sign && (intmax_t)num < 0) {
3750e9a2605SKonstantin Belousov 				neg = 1;
3760e9a2605SKonstantin Belousov 				num = -(intmax_t)num;
3770e9a2605SKonstantin Belousov 			}
3780e9a2605SKonstantin Belousov 			p = ksprintn(nbuf, num, base, &n, upper);
3790e9a2605SKonstantin Belousov 			tmp = 0;
3800e9a2605SKonstantin Belousov 			if (sharpflag && num != 0) {
3810e9a2605SKonstantin Belousov 				if (base == 8)
3820e9a2605SKonstantin Belousov 					tmp++;
3830e9a2605SKonstantin Belousov 				else if (base == 16)
3840e9a2605SKonstantin Belousov 					tmp += 2;
3850e9a2605SKonstantin Belousov 			}
3860e9a2605SKonstantin Belousov 			if (neg)
3870e9a2605SKonstantin Belousov 				tmp++;
3880e9a2605SKonstantin Belousov 
3890e9a2605SKonstantin Belousov 			if (!ladjust && padc == '0')
3900e9a2605SKonstantin Belousov 				dwidth = width - tmp;
3910e9a2605SKonstantin Belousov 			width -= tmp + imax(dwidth, n);
3920e9a2605SKonstantin Belousov 			dwidth -= n;
3930e9a2605SKonstantin Belousov 			if (!ladjust)
3940e9a2605SKonstantin Belousov 				while (width-- > 0)
3950e9a2605SKonstantin Belousov 					PCHAR(' ');
3960e9a2605SKonstantin Belousov 			if (neg)
3970e9a2605SKonstantin Belousov 				PCHAR('-');
3980e9a2605SKonstantin Belousov 			if (sharpflag && num != 0) {
3990e9a2605SKonstantin Belousov 				if (base == 8) {
4000e9a2605SKonstantin Belousov 					PCHAR('0');
4010e9a2605SKonstantin Belousov 				} else if (base == 16) {
4020e9a2605SKonstantin Belousov 					PCHAR('0');
4030e9a2605SKonstantin Belousov 					PCHAR('x');
4040e9a2605SKonstantin Belousov 				}
4050e9a2605SKonstantin Belousov 			}
4060e9a2605SKonstantin Belousov 			while (dwidth-- > 0)
4070e9a2605SKonstantin Belousov 				PCHAR('0');
4080e9a2605SKonstantin Belousov 
4090e9a2605SKonstantin Belousov 			while (*p)
4100e9a2605SKonstantin Belousov 				PCHAR(*p--);
4110e9a2605SKonstantin Belousov 
4120e9a2605SKonstantin Belousov 			if (ladjust)
4130e9a2605SKonstantin Belousov 				while (width-- > 0)
4140e9a2605SKonstantin Belousov 					PCHAR(' ');
4150e9a2605SKonstantin Belousov 
4160e9a2605SKonstantin Belousov 			break;
4170e9a2605SKonstantin Belousov 		default:
4180e9a2605SKonstantin Belousov 			while (percent < fmt)
4190e9a2605SKonstantin Belousov 				PCHAR(*percent++);
4200e9a2605SKonstantin Belousov 			/*
4210e9a2605SKonstantin Belousov 			 * Since we ignore an formatting argument it is no
4220e9a2605SKonstantin Belousov 			 * longer safe to obey the remaining formatting
4230e9a2605SKonstantin Belousov 			 * arguments as the arguments will no longer match
4240e9a2605SKonstantin Belousov 			 * the format specs.
4250e9a2605SKonstantin Belousov 			 */
4260e9a2605SKonstantin Belousov 			stop = 1;
4270e9a2605SKonstantin Belousov 			break;
4280e9a2605SKonstantin Belousov 		}
4290e9a2605SKonstantin Belousov 	}
4300e9a2605SKonstantin Belousov #undef PCHAR
4310e9a2605SKonstantin Belousov }
4320e9a2605SKonstantin Belousov 
4330e9a2605SKonstantin Belousov int
rtld_snprintf(char * buf,size_t bufsize,const char * fmt,...)43402d3b38eSJonathan Anderson rtld_snprintf(char *buf, size_t bufsize, const char *fmt, ...)
43502d3b38eSJonathan Anderson {
43602d3b38eSJonathan Anderson 	va_list ap;
43702d3b38eSJonathan Anderson 	int retval;
43802d3b38eSJonathan Anderson 
43902d3b38eSJonathan Anderson 	va_start(ap, fmt);
44002d3b38eSJonathan Anderson 	retval = rtld_vsnprintf(buf, bufsize, fmt, ap);
44102d3b38eSJonathan Anderson 	va_end(ap);
44202d3b38eSJonathan Anderson 	return (retval);
44302d3b38eSJonathan Anderson }
44402d3b38eSJonathan Anderson 
44502d3b38eSJonathan Anderson int
rtld_vsnprintf(char * buf,size_t bufsize,const char * fmt,va_list ap)4460e9a2605SKonstantin Belousov rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap)
4470e9a2605SKonstantin Belousov {
4480e9a2605SKonstantin Belousov 	struct snprintf_arg info;
4490e9a2605SKonstantin Belousov 	int retval;
4500e9a2605SKonstantin Belousov 
451b2367317SKonstantin Belousov 	info.method = PRINT_METHOD_SNPRINTF;
4520e9a2605SKonstantin Belousov 	info.buf = info.str = buf;
4530e9a2605SKonstantin Belousov 	info.buf_total = info.remain = bufsize;
4540e9a2605SKonstantin Belousov 	info.fd = -1;
455b2367317SKonstantin Belousov 	retval = kvprintf(fmt, &info, 10, ap);
4560e9a2605SKonstantin Belousov 	if (info.remain >= 1)
4570e9a2605SKonstantin Belousov 		*info.str++ = '\0';
4580e9a2605SKonstantin Belousov 	return (retval);
4590e9a2605SKonstantin Belousov }
4600e9a2605SKonstantin Belousov 
4610e9a2605SKonstantin Belousov int
rtld_vfdprintf(int fd,const char * fmt,va_list ap)4620e9a2605SKonstantin Belousov rtld_vfdprintf(int fd, const char *fmt, va_list ap)
4630e9a2605SKonstantin Belousov {
4640e9a2605SKonstantin Belousov 	char buf[512];
4650e9a2605SKonstantin Belousov 	struct snprintf_arg info;
4660e9a2605SKonstantin Belousov 	int retval;
4670e9a2605SKonstantin Belousov 
468b2367317SKonstantin Belousov 	info.method = PRINT_METHOD_WRITE;
4690e9a2605SKonstantin Belousov 	info.buf = info.str = buf;
4700e9a2605SKonstantin Belousov 	info.buf_total = info.remain = sizeof(buf);
4710e9a2605SKonstantin Belousov 	info.fd = fd;
472b2367317SKonstantin Belousov 	retval = kvprintf(fmt, &info, 10, ap);
4730e9a2605SKonstantin Belousov 	printf_out(&info);
4740e9a2605SKonstantin Belousov 	return (retval);
4750e9a2605SKonstantin Belousov }
4760e9a2605SKonstantin Belousov 
4770e9a2605SKonstantin Belousov int
rtld_fdprintf(int fd,const char * fmt,...)4780e9a2605SKonstantin Belousov rtld_fdprintf(int fd, const char *fmt, ...)
4790e9a2605SKonstantin Belousov {
4800e9a2605SKonstantin Belousov 	va_list ap;
4810e9a2605SKonstantin Belousov 	int retval;
4820e9a2605SKonstantin Belousov 
4830e9a2605SKonstantin Belousov 	va_start(ap, fmt);
4840e9a2605SKonstantin Belousov 	retval = rtld_vfdprintf(fd, fmt, ap);
4850e9a2605SKonstantin Belousov 	va_end(ap);
4860e9a2605SKonstantin Belousov 	return (retval);
4870e9a2605SKonstantin Belousov }
4880e9a2605SKonstantin Belousov 
48977c088abSKonstantin Belousov int
rtld_fdprintfx(int fd,const char * fmt,...)49077c088abSKonstantin Belousov rtld_fdprintfx(int fd, const char *fmt, ...)
49177c088abSKonstantin Belousov {
49277c088abSKonstantin Belousov 	va_list ap;
49377c088abSKonstantin Belousov 	int retval;
49477c088abSKonstantin Belousov 
49577c088abSKonstantin Belousov 	va_start(ap, fmt);
49677c088abSKonstantin Belousov 	retval = rtld_vfdprintf(fd, fmt, ap);
49777c088abSKonstantin Belousov 	va_end(ap);
49877c088abSKonstantin Belousov 	return (retval);
49977c088abSKonstantin Belousov }
50077c088abSKonstantin Belousov 
5010e9a2605SKonstantin Belousov void
rtld_fdputstr(int fd,const char * str)5020e9a2605SKonstantin Belousov rtld_fdputstr(int fd, const char *str)
5030e9a2605SKonstantin Belousov {
5040e9a2605SKonstantin Belousov 
5050e9a2605SKonstantin Belousov 	write(fd, str, strlen(str));
5060e9a2605SKonstantin Belousov }
5070e9a2605SKonstantin Belousov 
5080e9a2605SKonstantin Belousov void
rtld_fdputchar(int fd,int c)5090e9a2605SKonstantin Belousov rtld_fdputchar(int fd, int c)
5100e9a2605SKonstantin Belousov {
5110e9a2605SKonstantin Belousov 	char c1;
5120e9a2605SKonstantin Belousov 
5130e9a2605SKonstantin Belousov 	c1 = c;
5140e9a2605SKonstantin Belousov 	write(fd, &c1, 1);
5150e9a2605SKonstantin Belousov }
516