xref: /freebsd/libexec/rtld-elf/rtld_printf.c (revision b236731716168a130e176bbd18d4790a6d3940d6)
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.
190e9a2605SKonstantin Belousov  * 4. 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 <ctype.h>
400e9a2605SKonstantin Belousov #include <inttypes.h>
410e9a2605SKonstantin Belousov #include <stdarg.h>
420e9a2605SKonstantin Belousov #include <stddef.h>
430e9a2605SKonstantin Belousov #include <string.h>
440e9a2605SKonstantin Belousov #include <unistd.h>
450e9a2605SKonstantin Belousov #include "rtld_printf.h"
460e9a2605SKonstantin Belousov 
470e9a2605SKonstantin Belousov #define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
480e9a2605SKonstantin Belousov 
49*b2367317SKonstantin Belousov #define	PRINT_METHOD_SNPRINTF	1
50*b2367317SKonstantin Belousov #define	PRINT_METHOD_WRITE	2
51*b2367317SKonstantin Belousov 
520e9a2605SKonstantin Belousov struct snprintf_arg {
53*b2367317SKonstantin 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
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
73*b2367317SKonstantin Belousov snprintf_func(int ch, struct snprintf_arg *const info)
740e9a2605SKonstantin Belousov {
750e9a2605SKonstantin Belousov 
76*b2367317SKonstantin Belousov 	switch (info->method) {
77*b2367317SKonstantin Belousov 	case PRINT_METHOD_SNPRINTF:
78*b2367317SKonstantin Belousov 		if (info->remain >= 2) {
79*b2367317SKonstantin Belousov 			*info->str++ = ch;
80*b2367317SKonstantin Belousov 			info->remain--;
81*b2367317SKonstantin Belousov 		}
82*b2367317SKonstantin Belousov 		break;
83*b2367317SKonstantin Belousov 	case PRINT_METHOD_WRITE:
840e9a2605SKonstantin Belousov 		if (info->remain > 0) {
850e9a2605SKonstantin Belousov 			*info->str++ = ch;
860e9a2605SKonstantin Belousov 			info->remain--;
870e9a2605SKonstantin Belousov 		} else
880e9a2605SKonstantin Belousov 			printf_out(info);
89*b2367317SKonstantin Belousov 		break;
90*b2367317SKonstantin Belousov 	}
910e9a2605SKonstantin Belousov }
920e9a2605SKonstantin Belousov 
930e9a2605SKonstantin Belousov static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
940e9a2605SKonstantin Belousov #define	hex2ascii(hex)	(hex2ascii_data[hex])
950e9a2605SKonstantin Belousov 
960e9a2605SKonstantin Belousov static __inline int
970e9a2605SKonstantin Belousov imax(int a, int b)
980e9a2605SKonstantin Belousov {
990e9a2605SKonstantin Belousov 
1000e9a2605SKonstantin Belousov 	return (a > b ? a : b);
1010e9a2605SKonstantin Belousov }
1020e9a2605SKonstantin Belousov 
1030e9a2605SKonstantin Belousov static char *
1040e9a2605SKonstantin Belousov ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
1050e9a2605SKonstantin Belousov {
1060e9a2605SKonstantin Belousov 	char *p, c;
1070e9a2605SKonstantin Belousov 
1080e9a2605SKonstantin Belousov 	p = nbuf;
1090e9a2605SKonstantin Belousov 	*p = '\0';
1100e9a2605SKonstantin Belousov 	do {
1110e9a2605SKonstantin Belousov 		c = hex2ascii(num % base);
1120e9a2605SKonstantin Belousov 		*++p = upper ? toupper(c) : c;
1130e9a2605SKonstantin Belousov 	} while (num /= base);
1140e9a2605SKonstantin Belousov 	if (lenp)
1150e9a2605SKonstantin Belousov 		*lenp = p - nbuf;
1160e9a2605SKonstantin Belousov 	return (p);
1170e9a2605SKonstantin Belousov }
1180e9a2605SKonstantin Belousov 
1190e9a2605SKonstantin Belousov static int
120*b2367317SKonstantin Belousov kvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap)
1210e9a2605SKonstantin Belousov {
122*b2367317SKonstantin Belousov #define PCHAR(c) snprintf_func((c), arg)
1230e9a2605SKonstantin Belousov 	char nbuf[MAXNBUF];
1240e9a2605SKonstantin Belousov 	const char *p, *percent, *q;
1250e9a2605SKonstantin Belousov 	u_char *up;
1260e9a2605SKonstantin Belousov 	int ch, n;
1270e9a2605SKonstantin Belousov 	uintmax_t num;
1280e9a2605SKonstantin Belousov 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
1290e9a2605SKonstantin Belousov 	int cflag, hflag, jflag, tflag, zflag;
1300e9a2605SKonstantin Belousov 	int dwidth, upper;
1310e9a2605SKonstantin Belousov 	char padc;
1320e9a2605SKonstantin Belousov 	int stop = 0, retval = 0;
1330e9a2605SKonstantin Belousov 
1340e9a2605SKonstantin Belousov 	num = 0;
1350e9a2605SKonstantin Belousov 
1360e9a2605SKonstantin Belousov 	if (fmt == NULL)
1370e9a2605SKonstantin Belousov 		fmt = "(fmt null)\n";
1380e9a2605SKonstantin Belousov 
1390e9a2605SKonstantin Belousov 	if (radix < 2 || radix > 36)
1400e9a2605SKonstantin Belousov 		radix = 10;
1410e9a2605SKonstantin Belousov 
1420e9a2605SKonstantin Belousov 	for (;;) {
1430e9a2605SKonstantin Belousov 		padc = ' ';
1440e9a2605SKonstantin Belousov 		width = 0;
1450e9a2605SKonstantin Belousov 		while ((ch = (u_char)*fmt++) != '%' || stop) {
1460e9a2605SKonstantin Belousov 			if (ch == '\0')
1470e9a2605SKonstantin Belousov 				return (retval);
1480e9a2605SKonstantin Belousov 			PCHAR(ch);
1490e9a2605SKonstantin Belousov 		}
1500e9a2605SKonstantin Belousov 		percent = fmt - 1;
1510e9a2605SKonstantin Belousov 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
1520e9a2605SKonstantin Belousov 		sign = 0; dot = 0; dwidth = 0; upper = 0;
1530e9a2605SKonstantin Belousov 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
1540e9a2605SKonstantin Belousov reswitch:	switch (ch = (u_char)*fmt++) {
1550e9a2605SKonstantin Belousov 		case '.':
1560e9a2605SKonstantin Belousov 			dot = 1;
1570e9a2605SKonstantin Belousov 			goto reswitch;
1580e9a2605SKonstantin Belousov 		case '#':
1590e9a2605SKonstantin Belousov 			sharpflag = 1;
1600e9a2605SKonstantin Belousov 			goto reswitch;
1610e9a2605SKonstantin Belousov 		case '+':
1620e9a2605SKonstantin Belousov 			sign = 1;
1630e9a2605SKonstantin Belousov 			goto reswitch;
1640e9a2605SKonstantin Belousov 		case '-':
1650e9a2605SKonstantin Belousov 			ladjust = 1;
1660e9a2605SKonstantin Belousov 			goto reswitch;
1670e9a2605SKonstantin Belousov 		case '%':
1680e9a2605SKonstantin Belousov 			PCHAR(ch);
1690e9a2605SKonstantin Belousov 			break;
1700e9a2605SKonstantin Belousov 		case '*':
1710e9a2605SKonstantin Belousov 			if (!dot) {
1720e9a2605SKonstantin Belousov 				width = va_arg(ap, int);
1730e9a2605SKonstantin Belousov 				if (width < 0) {
1740e9a2605SKonstantin Belousov 					ladjust = !ladjust;
1750e9a2605SKonstantin Belousov 					width = -width;
1760e9a2605SKonstantin Belousov 				}
1770e9a2605SKonstantin Belousov 			} else {
1780e9a2605SKonstantin Belousov 				dwidth = va_arg(ap, int);
1790e9a2605SKonstantin Belousov 			}
1800e9a2605SKonstantin Belousov 			goto reswitch;
1810e9a2605SKonstantin Belousov 		case '0':
1820e9a2605SKonstantin Belousov 			if (!dot) {
1830e9a2605SKonstantin Belousov 				padc = '0';
1840e9a2605SKonstantin Belousov 				goto reswitch;
1850e9a2605SKonstantin Belousov 			}
1860e9a2605SKonstantin Belousov 		case '1': case '2': case '3': case '4':
1870e9a2605SKonstantin Belousov 		case '5': case '6': case '7': case '8': case '9':
1880e9a2605SKonstantin Belousov 				for (n = 0;; ++fmt) {
1890e9a2605SKonstantin Belousov 					n = n * 10 + ch - '0';
1900e9a2605SKonstantin Belousov 					ch = *fmt;
1910e9a2605SKonstantin Belousov 					if (ch < '0' || ch > '9')
1920e9a2605SKonstantin Belousov 						break;
1930e9a2605SKonstantin Belousov 				}
1940e9a2605SKonstantin Belousov 			if (dot)
1950e9a2605SKonstantin Belousov 				dwidth = n;
1960e9a2605SKonstantin Belousov 			else
1970e9a2605SKonstantin Belousov 				width = n;
1980e9a2605SKonstantin Belousov 			goto reswitch;
1990e9a2605SKonstantin Belousov 		case 'b':
2000e9a2605SKonstantin Belousov 			num = (u_int)va_arg(ap, int);
2010e9a2605SKonstantin Belousov 			p = va_arg(ap, char *);
2020e9a2605SKonstantin Belousov 			for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
2030e9a2605SKonstantin Belousov 				PCHAR(*q--);
2040e9a2605SKonstantin Belousov 
2050e9a2605SKonstantin Belousov 			if (num == 0)
2060e9a2605SKonstantin Belousov 				break;
2070e9a2605SKonstantin Belousov 
2080e9a2605SKonstantin Belousov 			for (tmp = 0; *p;) {
2090e9a2605SKonstantin Belousov 				n = *p++;
2100e9a2605SKonstantin Belousov 				if (num & (1 << (n - 1))) {
2110e9a2605SKonstantin Belousov 					PCHAR(tmp ? ',' : '<');
2120e9a2605SKonstantin Belousov 					for (; (n = *p) > ' '; ++p)
2130e9a2605SKonstantin Belousov 						PCHAR(n);
2140e9a2605SKonstantin Belousov 					tmp = 1;
2150e9a2605SKonstantin Belousov 				} else
2160e9a2605SKonstantin Belousov 					for (; *p > ' '; ++p)
2170e9a2605SKonstantin Belousov 						continue;
2180e9a2605SKonstantin Belousov 			}
2190e9a2605SKonstantin Belousov 			if (tmp)
2200e9a2605SKonstantin Belousov 				PCHAR('>');
2210e9a2605SKonstantin Belousov 			break;
2220e9a2605SKonstantin Belousov 		case 'c':
2230e9a2605SKonstantin Belousov 			PCHAR(va_arg(ap, int));
2240e9a2605SKonstantin Belousov 			break;
2250e9a2605SKonstantin Belousov 		case 'D':
2260e9a2605SKonstantin Belousov 			up = va_arg(ap, u_char *);
2270e9a2605SKonstantin Belousov 			p = va_arg(ap, char *);
2280e9a2605SKonstantin Belousov 			if (!width)
2290e9a2605SKonstantin Belousov 				width = 16;
2300e9a2605SKonstantin Belousov 			while(width--) {
2310e9a2605SKonstantin Belousov 				PCHAR(hex2ascii(*up >> 4));
2320e9a2605SKonstantin Belousov 				PCHAR(hex2ascii(*up & 0x0f));
2330e9a2605SKonstantin Belousov 				up++;
2340e9a2605SKonstantin Belousov 				if (width)
2350e9a2605SKonstantin Belousov 					for (q=p;*q;q++)
2360e9a2605SKonstantin Belousov 						PCHAR(*q);
2370e9a2605SKonstantin Belousov 			}
2380e9a2605SKonstantin Belousov 			break;
2390e9a2605SKonstantin Belousov 		case 'd':
2400e9a2605SKonstantin Belousov 		case 'i':
2410e9a2605SKonstantin Belousov 			base = 10;
2420e9a2605SKonstantin Belousov 			sign = 1;
2430e9a2605SKonstantin Belousov 			goto handle_sign;
2440e9a2605SKonstantin Belousov 		case 'h':
2450e9a2605SKonstantin Belousov 			if (hflag) {
2460e9a2605SKonstantin Belousov 				hflag = 0;
2470e9a2605SKonstantin Belousov 				cflag = 1;
2480e9a2605SKonstantin Belousov 			} else
2490e9a2605SKonstantin Belousov 				hflag = 1;
2500e9a2605SKonstantin Belousov 			goto reswitch;
2510e9a2605SKonstantin Belousov 		case 'j':
2520e9a2605SKonstantin Belousov 			jflag = 1;
2530e9a2605SKonstantin Belousov 			goto reswitch;
2540e9a2605SKonstantin Belousov 		case 'l':
2550e9a2605SKonstantin Belousov 			if (lflag) {
2560e9a2605SKonstantin Belousov 				lflag = 0;
2570e9a2605SKonstantin Belousov 				qflag = 1;
2580e9a2605SKonstantin Belousov 			} else
2590e9a2605SKonstantin Belousov 				lflag = 1;
2600e9a2605SKonstantin Belousov 			goto reswitch;
2610e9a2605SKonstantin Belousov 		case 'n':
2620e9a2605SKonstantin Belousov 			if (jflag)
2630e9a2605SKonstantin Belousov 				*(va_arg(ap, intmax_t *)) = retval;
2640e9a2605SKonstantin Belousov 			else if (qflag)
2650e9a2605SKonstantin Belousov 				*(va_arg(ap, quad_t *)) = retval;
2660e9a2605SKonstantin Belousov 			else if (lflag)
2670e9a2605SKonstantin Belousov 				*(va_arg(ap, long *)) = retval;
2680e9a2605SKonstantin Belousov 			else if (zflag)
2690e9a2605SKonstantin Belousov 				*(va_arg(ap, size_t *)) = retval;
2700e9a2605SKonstantin Belousov 			else if (hflag)
2710e9a2605SKonstantin Belousov 				*(va_arg(ap, short *)) = retval;
2720e9a2605SKonstantin Belousov 			else if (cflag)
2730e9a2605SKonstantin Belousov 				*(va_arg(ap, char *)) = retval;
2740e9a2605SKonstantin Belousov 			else
2750e9a2605SKonstantin Belousov 				*(va_arg(ap, int *)) = retval;
2760e9a2605SKonstantin Belousov 			break;
2770e9a2605SKonstantin Belousov 		case 'o':
2780e9a2605SKonstantin Belousov 			base = 8;
2790e9a2605SKonstantin Belousov 			goto handle_nosign;
2800e9a2605SKonstantin Belousov 		case 'p':
2810e9a2605SKonstantin Belousov 			base = 16;
2820e9a2605SKonstantin Belousov 			sharpflag = (width == 0);
2830e9a2605SKonstantin Belousov 			sign = 0;
2840e9a2605SKonstantin Belousov 			num = (uintptr_t)va_arg(ap, void *);
2850e9a2605SKonstantin Belousov 			goto number;
2860e9a2605SKonstantin Belousov 		case 'q':
2870e9a2605SKonstantin Belousov 			qflag = 1;
2880e9a2605SKonstantin Belousov 			goto reswitch;
2890e9a2605SKonstantin Belousov 		case 'r':
2900e9a2605SKonstantin Belousov 			base = radix;
2910e9a2605SKonstantin Belousov 			if (sign)
2920e9a2605SKonstantin Belousov 				goto handle_sign;
2930e9a2605SKonstantin Belousov 			goto handle_nosign;
2940e9a2605SKonstantin Belousov 		case 's':
2950e9a2605SKonstantin Belousov 			p = va_arg(ap, char *);
2960e9a2605SKonstantin Belousov 			if (p == NULL)
2970e9a2605SKonstantin Belousov 				p = "(null)";
2980e9a2605SKonstantin Belousov 			if (!dot)
2990e9a2605SKonstantin Belousov 				n = strlen (p);
3000e9a2605SKonstantin Belousov 			else
3010e9a2605SKonstantin Belousov 				for (n = 0; n < dwidth && p[n]; n++)
3020e9a2605SKonstantin Belousov 					continue;
3030e9a2605SKonstantin Belousov 
3040e9a2605SKonstantin Belousov 			width -= n;
3050e9a2605SKonstantin Belousov 
3060e9a2605SKonstantin Belousov 			if (!ladjust && width > 0)
3070e9a2605SKonstantin Belousov 				while (width--)
3080e9a2605SKonstantin Belousov 					PCHAR(padc);
3090e9a2605SKonstantin Belousov 			while (n--)
3100e9a2605SKonstantin Belousov 				PCHAR(*p++);
3110e9a2605SKonstantin Belousov 			if (ladjust && width > 0)
3120e9a2605SKonstantin Belousov 				while (width--)
3130e9a2605SKonstantin Belousov 					PCHAR(padc);
3140e9a2605SKonstantin Belousov 			break;
3150e9a2605SKonstantin Belousov 		case 't':
3160e9a2605SKonstantin Belousov 			tflag = 1;
3170e9a2605SKonstantin Belousov 			goto reswitch;
3180e9a2605SKonstantin Belousov 		case 'u':
3190e9a2605SKonstantin Belousov 			base = 10;
3200e9a2605SKonstantin Belousov 			goto handle_nosign;
3210e9a2605SKonstantin Belousov 		case 'X':
3220e9a2605SKonstantin Belousov 			upper = 1;
3230e9a2605SKonstantin Belousov 		case 'x':
3240e9a2605SKonstantin Belousov 			base = 16;
3250e9a2605SKonstantin Belousov 			goto handle_nosign;
3260e9a2605SKonstantin Belousov 		case 'y':
3270e9a2605SKonstantin Belousov 			base = 16;
3280e9a2605SKonstantin Belousov 			sign = 1;
3290e9a2605SKonstantin Belousov 			goto handle_sign;
3300e9a2605SKonstantin Belousov 		case 'z':
3310e9a2605SKonstantin Belousov 			zflag = 1;
3320e9a2605SKonstantin Belousov 			goto reswitch;
3330e9a2605SKonstantin Belousov handle_nosign:
3340e9a2605SKonstantin Belousov 			sign = 0;
3350e9a2605SKonstantin Belousov 			if (jflag)
3360e9a2605SKonstantin Belousov 				num = va_arg(ap, uintmax_t);
3370e9a2605SKonstantin Belousov 			else if (qflag)
3380e9a2605SKonstantin Belousov 				num = va_arg(ap, u_quad_t);
3390e9a2605SKonstantin Belousov 			else if (tflag)
3400e9a2605SKonstantin Belousov 				num = va_arg(ap, ptrdiff_t);
3410e9a2605SKonstantin Belousov 			else if (lflag)
3420e9a2605SKonstantin Belousov 				num = va_arg(ap, u_long);
3430e9a2605SKonstantin Belousov 			else if (zflag)
3440e9a2605SKonstantin Belousov 				num = va_arg(ap, size_t);
3450e9a2605SKonstantin Belousov 			else if (hflag)
3460e9a2605SKonstantin Belousov 				num = (u_short)va_arg(ap, int);
3470e9a2605SKonstantin Belousov 			else if (cflag)
3480e9a2605SKonstantin Belousov 				num = (u_char)va_arg(ap, int);
3490e9a2605SKonstantin Belousov 			else
3500e9a2605SKonstantin Belousov 				num = va_arg(ap, u_int);
3510e9a2605SKonstantin Belousov 			goto number;
3520e9a2605SKonstantin Belousov handle_sign:
3530e9a2605SKonstantin Belousov 			if (jflag)
3540e9a2605SKonstantin Belousov 				num = va_arg(ap, intmax_t);
3550e9a2605SKonstantin Belousov 			else if (qflag)
3560e9a2605SKonstantin Belousov 				num = va_arg(ap, quad_t);
3570e9a2605SKonstantin Belousov 			else if (tflag)
3580e9a2605SKonstantin Belousov 				num = va_arg(ap, ptrdiff_t);
3590e9a2605SKonstantin Belousov 			else if (lflag)
3600e9a2605SKonstantin Belousov 				num = va_arg(ap, long);
3610e9a2605SKonstantin Belousov 			else if (zflag)
3620e9a2605SKonstantin Belousov 				num = va_arg(ap, ssize_t);
3630e9a2605SKonstantin Belousov 			else if (hflag)
3640e9a2605SKonstantin Belousov 				num = (short)va_arg(ap, int);
3650e9a2605SKonstantin Belousov 			else if (cflag)
3660e9a2605SKonstantin Belousov 				num = (char)va_arg(ap, int);
3670e9a2605SKonstantin Belousov 			else
3680e9a2605SKonstantin Belousov 				num = va_arg(ap, int);
3690e9a2605SKonstantin Belousov number:
3700e9a2605SKonstantin Belousov 			if (sign && (intmax_t)num < 0) {
3710e9a2605SKonstantin Belousov 				neg = 1;
3720e9a2605SKonstantin Belousov 				num = -(intmax_t)num;
3730e9a2605SKonstantin Belousov 			}
3740e9a2605SKonstantin Belousov 			p = ksprintn(nbuf, num, base, &n, upper);
3750e9a2605SKonstantin Belousov 			tmp = 0;
3760e9a2605SKonstantin Belousov 			if (sharpflag && num != 0) {
3770e9a2605SKonstantin Belousov 				if (base == 8)
3780e9a2605SKonstantin Belousov 					tmp++;
3790e9a2605SKonstantin Belousov 				else if (base == 16)
3800e9a2605SKonstantin Belousov 					tmp += 2;
3810e9a2605SKonstantin Belousov 			}
3820e9a2605SKonstantin Belousov 			if (neg)
3830e9a2605SKonstantin Belousov 				tmp++;
3840e9a2605SKonstantin Belousov 
3850e9a2605SKonstantin Belousov 			if (!ladjust && padc == '0')
3860e9a2605SKonstantin Belousov 				dwidth = width - tmp;
3870e9a2605SKonstantin Belousov 			width -= tmp + imax(dwidth, n);
3880e9a2605SKonstantin Belousov 			dwidth -= n;
3890e9a2605SKonstantin Belousov 			if (!ladjust)
3900e9a2605SKonstantin Belousov 				while (width-- > 0)
3910e9a2605SKonstantin Belousov 					PCHAR(' ');
3920e9a2605SKonstantin Belousov 			if (neg)
3930e9a2605SKonstantin Belousov 				PCHAR('-');
3940e9a2605SKonstantin Belousov 			if (sharpflag && num != 0) {
3950e9a2605SKonstantin Belousov 				if (base == 8) {
3960e9a2605SKonstantin Belousov 					PCHAR('0');
3970e9a2605SKonstantin Belousov 				} else if (base == 16) {
3980e9a2605SKonstantin Belousov 					PCHAR('0');
3990e9a2605SKonstantin Belousov 					PCHAR('x');
4000e9a2605SKonstantin Belousov 				}
4010e9a2605SKonstantin Belousov 			}
4020e9a2605SKonstantin Belousov 			while (dwidth-- > 0)
4030e9a2605SKonstantin Belousov 				PCHAR('0');
4040e9a2605SKonstantin Belousov 
4050e9a2605SKonstantin Belousov 			while (*p)
4060e9a2605SKonstantin Belousov 				PCHAR(*p--);
4070e9a2605SKonstantin Belousov 
4080e9a2605SKonstantin Belousov 			if (ladjust)
4090e9a2605SKonstantin Belousov 				while (width-- > 0)
4100e9a2605SKonstantin Belousov 					PCHAR(' ');
4110e9a2605SKonstantin Belousov 
4120e9a2605SKonstantin Belousov 			break;
4130e9a2605SKonstantin Belousov 		default:
4140e9a2605SKonstantin Belousov 			while (percent < fmt)
4150e9a2605SKonstantin Belousov 				PCHAR(*percent++);
4160e9a2605SKonstantin Belousov 			/*
4170e9a2605SKonstantin Belousov 			 * Since we ignore an formatting argument it is no
4180e9a2605SKonstantin Belousov 			 * longer safe to obey the remaining formatting
4190e9a2605SKonstantin Belousov 			 * arguments as the arguments will no longer match
4200e9a2605SKonstantin Belousov 			 * the format specs.
4210e9a2605SKonstantin Belousov 			 */
4220e9a2605SKonstantin Belousov 			stop = 1;
4230e9a2605SKonstantin Belousov 			break;
4240e9a2605SKonstantin Belousov 		}
4250e9a2605SKonstantin Belousov 	}
4260e9a2605SKonstantin Belousov #undef PCHAR
4270e9a2605SKonstantin Belousov }
4280e9a2605SKonstantin Belousov 
4290e9a2605SKonstantin Belousov int
4300e9a2605SKonstantin Belousov rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap)
4310e9a2605SKonstantin Belousov {
4320e9a2605SKonstantin Belousov 	struct snprintf_arg info;
4330e9a2605SKonstantin Belousov 	int retval;
4340e9a2605SKonstantin Belousov 
435*b2367317SKonstantin Belousov 	info.method = PRINT_METHOD_SNPRINTF;
4360e9a2605SKonstantin Belousov 	info.buf = info.str = buf;
4370e9a2605SKonstantin Belousov 	info.buf_total = info.remain = bufsize;
4380e9a2605SKonstantin Belousov 	info.fd = -1;
439*b2367317SKonstantin Belousov 	retval = kvprintf(fmt, &info, 10, ap);
4400e9a2605SKonstantin Belousov 	if (info.remain >= 1)
4410e9a2605SKonstantin Belousov 		*info.str++ = '\0';
4420e9a2605SKonstantin Belousov 	return (retval);
4430e9a2605SKonstantin Belousov }
4440e9a2605SKonstantin Belousov 
4450e9a2605SKonstantin Belousov int
4460e9a2605SKonstantin Belousov rtld_vfdprintf(int fd, const char *fmt, va_list ap)
4470e9a2605SKonstantin Belousov {
4480e9a2605SKonstantin Belousov 	char buf[512];
4490e9a2605SKonstantin Belousov 	struct snprintf_arg info;
4500e9a2605SKonstantin Belousov 	int retval;
4510e9a2605SKonstantin Belousov 
452*b2367317SKonstantin Belousov 	info.method = PRINT_METHOD_WRITE;
4530e9a2605SKonstantin Belousov 	info.buf = info.str = buf;
4540e9a2605SKonstantin Belousov 	info.buf_total = info.remain = sizeof(buf);
4550e9a2605SKonstantin Belousov 	info.fd = fd;
456*b2367317SKonstantin Belousov 	retval = kvprintf(fmt, &info, 10, ap);
4570e9a2605SKonstantin Belousov 	printf_out(&info);
4580e9a2605SKonstantin Belousov 	return (retval);
4590e9a2605SKonstantin Belousov }
4600e9a2605SKonstantin Belousov 
4610e9a2605SKonstantin Belousov int
4620e9a2605SKonstantin Belousov rtld_fdprintf(int fd, const char *fmt, ...)
4630e9a2605SKonstantin Belousov {
4640e9a2605SKonstantin Belousov 	va_list ap;
4650e9a2605SKonstantin Belousov 	int retval;
4660e9a2605SKonstantin Belousov 
4670e9a2605SKonstantin Belousov 	va_start(ap, fmt);
4680e9a2605SKonstantin Belousov 	retval = rtld_vfdprintf(fd, fmt, ap);
4690e9a2605SKonstantin Belousov 	va_end(ap);
4700e9a2605SKonstantin Belousov 	return (retval);
4710e9a2605SKonstantin Belousov }
4720e9a2605SKonstantin Belousov 
4730e9a2605SKonstantin Belousov void
4740e9a2605SKonstantin Belousov rtld_fdputstr(int fd, const char *str)
4750e9a2605SKonstantin Belousov {
4760e9a2605SKonstantin Belousov 
4770e9a2605SKonstantin Belousov 	write(fd, str, strlen(str));
4780e9a2605SKonstantin Belousov }
4790e9a2605SKonstantin Belousov 
4800e9a2605SKonstantin Belousov void
4810e9a2605SKonstantin Belousov rtld_fdputchar(int fd, int c)
4820e9a2605SKonstantin Belousov {
4830e9a2605SKonstantin Belousov 	char c1;
4840e9a2605SKonstantin Belousov 
4850e9a2605SKonstantin Belousov 	c1 = c;
4860e9a2605SKonstantin Belousov 	write(fd, &c1, 1);
4870e9a2605SKonstantin Belousov }
488