1d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	assert(e) do {							\
2d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (config_debug && !(e)) {					\
3d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		malloc_write("<jemalloc>: Failed assertion\n");		\
4d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		abort();						\
5d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}								\
6d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans} while (0)
7d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
8d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	not_reached() do {						\
9d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (config_debug) {						\
10d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		malloc_write("<jemalloc>: Unreachable code reached\n");	\
11d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		abort();						\
12d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}								\
13d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans} while (0)
14d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
15d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	not_implemented() do {						\
16d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (config_debug) {						\
17d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		malloc_write("<jemalloc>: Not implemented\n");		\
18d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		abort();						\
19d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}								\
20d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans} while (0)
21d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
22d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	JEMALLOC_UTIL_C_
23d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#include "jemalloc/internal/jemalloc_internal.h"
24d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
25d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans/******************************************************************************/
26d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans/* Function prototypes for non-inline static functions. */
27d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
28d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansstatic void	wrtmessage(void *cbopaque, const char *s);
29d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	U2S_BUFSIZE	((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1)
30d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansstatic char	*u2s(uintmax_t x, unsigned base, bool uppercase, char *s,
31d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans    size_t *slen_p);
32d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	D2S_BUFSIZE	(1 + U2S_BUFSIZE)
33d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansstatic char	*d2s(intmax_t x, char sign, char *s, size_t *slen_p);
34d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	O2S_BUFSIZE	(1 + U2S_BUFSIZE)
35d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansstatic char	*o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p);
36d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	X2S_BUFSIZE	(2 + U2S_BUFSIZE)
37d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansstatic char	*x2s(uintmax_t x, bool alt_form, bool uppercase, char *s,
38d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans    size_t *slen_p);
39d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
40d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans/******************************************************************************/
41d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
42d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans/* malloc_message() setup. */
43da99e31105eb709ef4ec8a120b115c32a6b9723aMike Hommeystatic void
44d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evanswrtmessage(void *cbopaque, const char *s)
45d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
461a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey
471a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey#ifdef SYS_write
481a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey	/*
491a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey	 * Use syscall(2) rather than write(2) when possible in order to avoid
501a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey	 * the possibility of memory allocation within libc.  This is necessary
511a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey	 * on FreeBSD; most operating systems do not have this problem though.
521a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey	 */
5341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	UNUSED int result = syscall(SYS_write, STDERR_FILENO, s, strlen(s));
541a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey#else
551a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey	UNUSED int result = write(STDERR_FILENO, s, strlen(s));
561a0e7770243e0539fa8fef7bb1512f784f93389fMike Hommey#endif
57d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
58d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
593597e91482c804592105ea078a0825fdb7c68dffMike HommeyJEMALLOC_EXPORT void	(*je_malloc_message)(void *, const char *s);
60d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
61d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans/*
62889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evans * Wrapper around malloc_message() that avoids the need for
63889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evans * je_malloc_message(...) throughout the code.
64889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evans */
65889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evansvoid
66889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evansmalloc_write(const char *s)
67889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evans{
68889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evans
693597e91482c804592105ea078a0825fdb7c68dffMike Hommey	if (je_malloc_message != NULL)
703597e91482c804592105ea078a0825fdb7c68dffMike Hommey		je_malloc_message(NULL, s);
713597e91482c804592105ea078a0825fdb7c68dffMike Hommey	else
723597e91482c804592105ea078a0825fdb7c68dffMike Hommey		wrtmessage(NULL, s);
73889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evans}
74889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evans
75889ec59bd3ae3190fb715e64d8d15b6a1b47314aJason Evans/*
76d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so
77d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans * provide a wrapper.
78d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans */
79d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansint
802a83ed0284e92c7ba4bd4efe9df149ac724b2f26Jason Evansbuferror(int err, char *buf, size_t buflen)
81d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
82a19e87fbad020e8dd3d26682032929e8e5ae71c1Mike Hommey
83a19e87fbad020e8dd3d26682032929e8e5ae71c1Mike Hommey#ifdef _WIN32
84a19e87fbad020e8dd3d26682032929e8e5ae71c1Mike Hommey	FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
85a19e87fbad020e8dd3d26682032929e8e5ae71c1Mike Hommey	    (LPSTR)buf, buflen, NULL);
86a19e87fbad020e8dd3d26682032929e8e5ae71c1Mike Hommey	return (0);
87a19e87fbad020e8dd3d26682032929e8e5ae71c1Mike Hommey#elif defined(_GNU_SOURCE)
882a83ed0284e92c7ba4bd4efe9df149ac724b2f26Jason Evans	char *b = strerror_r(err, buf, buflen);
89d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (b != buf) {
90d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		strncpy(buf, b, buflen);
91d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		buf[buflen-1] = '\0';
92d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}
93d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	return (0);
94d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#else
952a83ed0284e92c7ba4bd4efe9df149ac724b2f26Jason Evans	return (strerror_r(err, buf, buflen));
96d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#endif
97d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
98d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
9941b6afb834b1f5250223678c52bd4f013d4234f6Jason Evansuintmax_t
100e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evansmalloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base)
10141b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans{
10241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	uintmax_t ret, digit;
103932d77dc8089af14d4d334188aa800d405fc51f6Chris Peterson	unsigned b;
10441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	bool neg;
10541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	const char *p, *ns;
10641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans
107e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans	p = nptr;
10841b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	if (base < 0 || base == 1 || base > 36) {
109e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		ns = p;
110a14bce85e885f83c96116cc5438ae52d740f3727Mike Hommey		set_errno(EINVAL);
111e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		ret = UINTMAX_MAX;
112e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		goto label_return;
11341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	}
11441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	b = base;
11541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans
11641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	/* Swallow leading whitespace and get sign, if any. */
11741b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	neg = false;
11841b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	while (true) {
11941b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		switch (*p) {
12041b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
12141b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			p++;
12241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			break;
12341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		case '-':
12441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			neg = true;
12541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			/* Fall through. */
12641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		case '+':
12741b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			p++;
12841b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			/* Fall through. */
12941b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		default:
130a1ee7838e14b321a97bfacb1f1cf5004198f2203Jason Evans			goto label_prefix;
13141b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		}
13241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	}
13341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans
13441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	/* Get prefix, if any. */
135a1ee7838e14b321a97bfacb1f1cf5004198f2203Jason Evans	label_prefix:
13641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	/*
13741b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	 * Note where the first non-whitespace/sign character is so that it is
13841b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	 * possible to tell whether any digits are consumed (e.g., "  0" vs.
13941b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	 * "  -x").
14041b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	 */
14141b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	ns = p;
14241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	if (*p == '0') {
14341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		switch (p[1]) {
14441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		case '0': case '1': case '2': case '3': case '4': case '5':
14541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		case '6': case '7':
14641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			if (b == 0)
14741b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				b = 8;
14841b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			if (b == 8)
14941b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				p++;
15041b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			break;
151e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		case 'X': case 'x':
15241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			switch (p[2]) {
15341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			case '0': case '1': case '2': case '3': case '4':
15441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			case '5': case '6': case '7': case '8': case '9':
15541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			case 'A': case 'B': case 'C': case 'D': case 'E':
15641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			case 'F':
15741b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			case 'a': case 'b': case 'c': case 'd': case 'e':
15841b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			case 'f':
15941b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				if (b == 0)
16041b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans					b = 16;
16141b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				if (b == 16)
16241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans					p += 2;
16341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				break;
16441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			default:
16541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				break;
16641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			}
16741b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			break;
16841b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		default:
169e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			p++;
170e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			ret = 0;
171e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			goto label_return;
17241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		}
17341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	}
17441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	if (b == 0)
17541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		b = 10;
17641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans
17741b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	/* Convert. */
17841b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	ret = 0;
17941b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b)
18041b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	    || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b)
18141b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	    || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) {
18241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		uintmax_t pret = ret;
18341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		ret *= b;
18441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		ret += digit;
18541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		if (ret < pret) {
18641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			/* Overflow. */
187a14bce85e885f83c96116cc5438ae52d740f3727Mike Hommey			set_errno(ERANGE);
188e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			ret = UINTMAX_MAX;
189e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			goto label_return;
19041b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		}
19141b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		p++;
19241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	}
19341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	if (neg)
19441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		ret = -ret;
19541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans
196e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans	if (p == ns) {
197e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		/* No conversion performed. */
198e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		set_errno(EINVAL);
199e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		ret = UINTMAX_MAX;
200e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		goto label_return;
201e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans	}
202e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans
203e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evanslabel_return:
20441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	if (endptr != NULL) {
20541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		if (p == ns) {
20641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			/* No characters were converted. */
20741b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			*endptr = (char *)nptr;
20841b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		} else
20941b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans			*endptr = (char *)p;
21041b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	}
21141b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans	return (ret);
21241b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans}
21341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans
214d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansstatic char *
215d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansu2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p)
216d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
217d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	unsigned i;
218d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
219d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	i = U2S_BUFSIZE - 1;
220d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	s[i] = '\0';
221d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	switch (base) {
222d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case 10:
223d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		do {
224d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			i--;
225d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			s[i] = "0123456789"[x % (uint64_t)10];
226d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			x /= (uint64_t)10;
227d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		} while (x > 0);
228d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		break;
229d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case 16: {
230d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		const char *digits = (uppercase)
231d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		    ? "0123456789ABCDEF"
232d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		    : "0123456789abcdef";
233d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
234d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		do {
235d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			i--;
236d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			s[i] = digits[x & 0xf];
237d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			x >>= 4;
238d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		} while (x > 0);
239d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		break;
240d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	} default: {
241d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		const char *digits = (uppercase)
242d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		    ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
243d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		    : "0123456789abcdefghijklmnopqrstuvwxyz";
244d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
245d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		assert(base >= 2 && base <= 36);
246d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		do {
247d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			i--;
248d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			s[i] = digits[x % (uint64_t)base];
249d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			x /= (uint64_t)base;
250d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		} while (x > 0);
251d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}}
252d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
253d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	*slen_p = U2S_BUFSIZE - 1 - i;
254d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	return (&s[i]);
255d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
256d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
257d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansstatic char *
258d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansd2s(intmax_t x, char sign, char *s, size_t *slen_p)
259d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
260d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	bool neg;
261d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
262d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if ((neg = (x < 0)))
263d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		x = -x;
264d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	s = u2s(x, 10, false, s, slen_p);
265d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (neg)
266d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		sign = '-';
267d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	switch (sign) {
268d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case '-':
269d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		if (neg == false)
270d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			break;
271d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		/* Fall through. */
272d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case ' ':
273d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case '+':
274d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		s--;
275d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		(*slen_p)++;
276d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		*s = sign;
277d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		break;
278d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	default: not_reached();
279d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}
280d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	return (s);
281d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
282d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
283d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansstatic char *
284d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evanso2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p)
285d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
286d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
287d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	s = u2s(x, 8, false, s, slen_p);
288d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (alt_form && *s != '0') {
289d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		s--;
290d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		(*slen_p)++;
291d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		*s = '0';
292d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}
293d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	return (s);
294d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
295d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
296d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansstatic char *
297d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansx2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p)
298d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
299d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
300d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	s = u2s(x, 16, uppercase, s, slen_p);
301d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (alt_form) {
302d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		s -= 2;
303d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		(*slen_p) += 2;
304d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		memcpy(s, uppercase ? "0X" : "0x", 2);
305d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}
306d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	return (s);
307d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
308d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
309d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansint
310d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansmalloc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
311d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
312d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	int ret;
313d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	size_t i;
314d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	const char *f;
315d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
316d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	APPEND_C(c) do {						\
317d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (i < size)							\
318d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		str[i] = (c);						\
319d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	i++;								\
320d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans} while (0)
321d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	APPEND_S(s, slen) do {						\
322d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (i < size) {							\
323d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		size_t cpylen = (slen <= size - i) ? slen : size - i;	\
324d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		memcpy(&str[i], s, cpylen);				\
325d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}								\
326d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	i += slen;							\
327d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans} while (0)
328d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#define	APPEND_PADDED_S(s, slen, width, left_justify) do {		\
329d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	/* Left padding. */						\
330d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ?	\
331d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	    (size_t)width - slen : 0);					\
332d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (left_justify == false && pad_len != 0) {			\
333d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		size_t j;						\
334d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		for (j = 0; j < pad_len; j++)				\
335d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			APPEND_C(' ');					\
336d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}								\
337d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	/* Value. */							\
338d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	APPEND_S(s, slen);						\
339d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	/* Right padding. */						\
340d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (left_justify && pad_len != 0) {				\
341d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		size_t j;						\
342d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		for (j = 0; j < pad_len; j++)				\
343d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			APPEND_C(' ');					\
344d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}								\
345d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans} while (0)
346a4f124f59fa5f702231432a7e5fa45140ba81e2aJason Evans#define	GET_ARG_NUMERIC(val, len) do {					\
347d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	switch (len) {							\
348d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case '?':							\
349d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		val = va_arg(ap, int);					\
350d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		break;							\
3511ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey	case '?' | 0x80:						\
3521ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey		val = va_arg(ap, unsigned int);				\
3531ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey		break;							\
354d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case 'l':							\
355d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		val = va_arg(ap, long);					\
356d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		break;							\
3571ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey	case 'l' | 0x80:						\
3581ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey		val = va_arg(ap, unsigned long);			\
3591ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey		break;							\
360d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case 'q':							\
361d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		val = va_arg(ap, long long);				\
362d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		break;							\
3631ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey	case 'q' | 0x80:						\
3641ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey		val = va_arg(ap, unsigned long long);			\
3651ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey		break;							\
366d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case 'j':							\
367d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		val = va_arg(ap, intmax_t);				\
368d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		break;							\
369e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans	case 'j' | 0x80:						\
370e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		val = va_arg(ap, uintmax_t);				\
371e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans		break;							\
372d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case 't':							\
373d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		val = va_arg(ap, ptrdiff_t);				\
374d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		break;							\
375d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	case 'z':							\
37641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans		val = va_arg(ap, ssize_t);				\
377d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		break;							\
3781ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey	case 'z' | 0x80:						\
3791ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey		val = va_arg(ap, size_t);				\
3801ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey		break;							\
381cd9a1346e96f71bdecdc654ea50fc62d76371e74Jason Evans	case 'p': /* Synthetic; used for %p. */				\
382cd9a1346e96f71bdecdc654ea50fc62d76371e74Jason Evans		val = va_arg(ap, uintptr_t);				\
383cd9a1346e96f71bdecdc654ea50fc62d76371e74Jason Evans		break;							\
384338c9bf92ebf4e196bc9bbaf845b85b66ee2c77bChris Peterson	default:							\
385338c9bf92ebf4e196bc9bbaf845b85b66ee2c77bChris Peterson		not_reached();						\
386338c9bf92ebf4e196bc9bbaf845b85b66ee2c77bChris Peterson		val = 0;						\
387d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}								\
388d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans} while (0)
389d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
390d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	i = 0;
391d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	f = format;
392d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	while (true) {
393d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		switch (*f) {
394a1ee7838e14b321a97bfacb1f1cf5004198f2203Jason Evans		case '\0': goto label_out;
395d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		case '%': {
396d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			bool alt_form = false;
397d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			bool left_justify = false;
398d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			bool plus_space = false;
399d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			bool plus_plus = false;
400d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			int prec = -1;
401d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			int width = -1;
4021ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey			unsigned char len = '?';
403d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
404d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			f++;
405d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			/* Flags. */
406d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			while (true) {
407d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				switch (*f) {
408d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				case '#':
409d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					assert(alt_form == false);
410d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					alt_form = true;
411d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					break;
412d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				case '-':
413d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					assert(left_justify == false);
414d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					left_justify = true;
415d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					break;
416d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				case ' ':
417d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					assert(plus_space == false);
418d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					plus_space = true;
419d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					break;
420d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				case '+':
421d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					assert(plus_plus == false);
422d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					plus_plus = true;
423d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					break;
424a1ee7838e14b321a97bfacb1f1cf5004198f2203Jason Evans				default: goto label_width;
425d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				}
426d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
427d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			}
428d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			/* Width. */
429a1ee7838e14b321a97bfacb1f1cf5004198f2203Jason Evans			label_width:
430d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			switch (*f) {
431d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			case '*':
432d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				width = va_arg(ap, int);
433d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
434e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans				if (width < 0) {
435e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans					left_justify = true;
436e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans					width = -width;
437e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans				}
438d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
439d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			case '0': case '1': case '2': case '3': case '4':
440d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			case '5': case '6': case '7': case '8': case '9': {
44141b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				uintmax_t uwidth;
442a14bce85e885f83c96116cc5438ae52d740f3727Mike Hommey				set_errno(0);
44341b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				uwidth = malloc_strtoumax(f, (char **)&f, 10);
444a14bce85e885f83c96116cc5438ae52d740f3727Mike Hommey				assert(uwidth != UINTMAX_MAX || get_errno() !=
44541b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				    ERANGE);
446d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				width = (int)uwidth;
447d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
448e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			} default:
449e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans				break;
450d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			}
451e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			/* Width/precision separator. */
452e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			if (*f == '.')
453e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans				f++;
454e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			else
455e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans				goto label_length;
456d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			/* Precision. */
457d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			switch (*f) {
458d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			case '*':
459d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				prec = va_arg(ap, int);
460d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
461d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
462d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			case '0': case '1': case '2': case '3': case '4':
463d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			case '5': case '6': case '7': case '8': case '9': {
46441b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				uintmax_t uprec;
465a14bce85e885f83c96116cc5438ae52d740f3727Mike Hommey				set_errno(0);
46641b6afb834b1f5250223678c52bd4f013d4234f6Jason Evans				uprec = malloc_strtoumax(f, (char **)&f, 10);
467a14bce85e885f83c96116cc5438ae52d740f3727Mike Hommey				assert(uprec != UINTMAX_MAX || get_errno() !=
468a14bce85e885f83c96116cc5438ae52d740f3727Mike Hommey				    ERANGE);
469d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				prec = (int)uprec;
470d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
471d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			}
472d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			default: break;
473d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			}
474d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			/* Length. */
475a1ee7838e14b321a97bfacb1f1cf5004198f2203Jason Evans			label_length:
476d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			switch (*f) {
477d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			case 'l':
478d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
479d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				if (*f == 'l') {
480d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					len = 'q';
481d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					f++;
482d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				} else
483d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans					len = 'l';
484d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
485e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans			case 'q': case 'j': case 't': case 'z':
486e18c25d23de0e845f0ee7e11d02c1be044738a3cJason Evans				len = *f;
487d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
488d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
489d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			default: break;
490d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			}
491d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			/* Conversion specifier. */
492d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			switch (*f) {
493d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				char *s;
494d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				size_t slen;
4950c4e743eaf2ab6bcfd56e002fb82f95801b9292eJason Evans			case '%':
4960c4e743eaf2ab6bcfd56e002fb82f95801b9292eJason Evans				/* %% */
4970c4e743eaf2ab6bcfd56e002fb82f95801b9292eJason Evans				APPEND_C(*f);
4980c4e743eaf2ab6bcfd56e002fb82f95801b9292eJason Evans				f++;
4990c4e743eaf2ab6bcfd56e002fb82f95801b9292eJason Evans				break;
500d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			case 'd': case 'i': {
5019225a1991a58190207cca2ff3cdba966bb322dd5Jason Evans				intmax_t val JEMALLOC_CC_SILENCE_INIT(0);
502d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				char buf[D2S_BUFSIZE];
503d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
504d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				GET_ARG_NUMERIC(val, len);
505d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				s = d2s(val, (plus_plus ? '+' : (plus_space ?
506d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				    ' ' : '-')), buf, &slen);
507d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				APPEND_PADDED_S(s, slen, width, left_justify);
508d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
509d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
510d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			} case 'o': {
5119225a1991a58190207cca2ff3cdba966bb322dd5Jason Evans				uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
512d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				char buf[O2S_BUFSIZE];
513d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
5141ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey				GET_ARG_NUMERIC(val, len | 0x80);
515d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				s = o2s(val, alt_form, buf, &slen);
516d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				APPEND_PADDED_S(s, slen, width, left_justify);
517d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
518d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
519d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			} case 'u': {
5209225a1991a58190207cca2ff3cdba966bb322dd5Jason Evans				uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
521d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				char buf[U2S_BUFSIZE];
522d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
5231ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey				GET_ARG_NUMERIC(val, len | 0x80);
524d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				s = u2s(val, 10, false, buf, &slen);
525d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				APPEND_PADDED_S(s, slen, width, left_justify);
526d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
527d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
528d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			} case 'x': case 'X': {
5299225a1991a58190207cca2ff3cdba966bb322dd5Jason Evans				uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
530d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				char buf[X2S_BUFSIZE];
531d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
5321ad56385adc40cfbca1b14c240a9c647135ac641Mike Hommey				GET_ARG_NUMERIC(val, len | 0x80);
533d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				s = x2s(val, alt_form, *f == 'X', buf, &slen);
534d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				APPEND_PADDED_S(s, slen, width, left_justify);
535d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
536d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
537d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			} case 'c': {
538d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				unsigned char val;
539d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				char buf[2];
540d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
541d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				assert(len == '?' || len == 'l');
542d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				assert_not_implemented(len != 'l');
543d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				val = va_arg(ap, int);
544d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				buf[0] = val;
545d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				buf[1] = '\0';
546d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				APPEND_PADDED_S(buf, 1, width, left_justify);
547d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
548d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
549d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			} case 's':
550d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				assert(len == '?' || len == 'l');
551d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				assert_not_implemented(len != 'l');
552d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				s = va_arg(ap, char *);
553932d77dc8089af14d4d334188aa800d405fc51f6Chris Peterson				slen = (prec < 0) ? strlen(s) : (size_t)prec;
554d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				APPEND_PADDED_S(s, slen, width, left_justify);
555d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
556d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
557d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			case 'p': {
558d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				uintmax_t val;
559d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				char buf[X2S_BUFSIZE];
560d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
561cd9a1346e96f71bdecdc654ea50fc62d76371e74Jason Evans				GET_ARG_NUMERIC(val, 'p');
562d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				s = x2s(val, true, false, buf, &slen);
563d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				APPEND_PADDED_S(s, slen, width, left_justify);
564d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				f++;
565d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans				break;
5660c4e743eaf2ab6bcfd56e002fb82f95801b9292eJason Evans			} default: not_reached();
567d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			}
568d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			break;
569d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		} default: {
570d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			APPEND_C(*f);
571d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			f++;
572d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans			break;
573d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		}}
574d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}
575a1ee7838e14b321a97bfacb1f1cf5004198f2203Jason Evans	label_out:
576d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (i < size)
577d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		str[i] = '\0';
578d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	else
579d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		str[size - 1] = '\0';
580d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	ret = i;
581d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
582d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#undef APPEND_C
583d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#undef APPEND_S
584d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#undef APPEND_PADDED_S
585d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans#undef GET_ARG_NUMERIC
586d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	return (ret);
587d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
588d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
589d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason EvansJEMALLOC_ATTR(format(printf, 3, 4))
590d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansint
591d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansmalloc_snprintf(char *str, size_t size, const char *format, ...)
592d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
593d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	int ret;
594d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	va_list ap;
595d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
596d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	va_start(ap, format);
597d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	ret = malloc_vsnprintf(str, size, format, ap);
598d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	va_end(ap);
599d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
600d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	return (ret);
601d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
602d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
603d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansvoid
604d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansmalloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
605d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans    const char *format, va_list ap)
606d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
607cd9a1346e96f71bdecdc654ea50fc62d76371e74Jason Evans	char buf[MALLOC_PRINTF_BUFSIZE];
608d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
609d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	if (write_cb == NULL) {
610d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		/*
611d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		 * The caller did not provide an alternate write_cb callback
612d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		 * function, so use the default one.  malloc_write() is an
613d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		 * inline function, so use malloc_message() directly here.
614d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		 */
6153597e91482c804592105ea078a0825fdb7c68dffMike Hommey		write_cb = (je_malloc_message != NULL) ? je_malloc_message :
6163597e91482c804592105ea078a0825fdb7c68dffMike Hommey		    wrtmessage;
617d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans		cbopaque = NULL;
618d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	}
619d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
620cd9a1346e96f71bdecdc654ea50fc62d76371e74Jason Evans	malloc_vsnprintf(buf, sizeof(buf), format, ap);
621cd9a1346e96f71bdecdc654ea50fc62d76371e74Jason Evans	write_cb(cbopaque, buf);
622d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
623d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
624d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans/*
625d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans * Print to a callback function in such a way as to (hopefully) avoid memory
626d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans * allocation.
627d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans */
628d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason EvansJEMALLOC_ATTR(format(printf, 3, 4))
629d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansvoid
630d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansmalloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque,
631d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans    const char *format, ...)
632d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
633d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	va_list ap;
634d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
635d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	va_start(ap, format);
636d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	malloc_vcprintf(write_cb, cbopaque, format, ap);
637d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	va_end(ap);
638d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
639d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
640d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans/* Print to stderr in such a way as to avoid memory allocation. */
641d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason EvansJEMALLOC_ATTR(format(printf, 1, 2))
642d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansvoid
643d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evansmalloc_printf(const char *format, ...)
644d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans{
645d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	va_list ap;
646d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans
647d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	va_start(ap, format);
648d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	malloc_vcprintf(NULL, NULL, format, ap);
649d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans	va_end(ap);
650d81e4bdd5c991bd5642c8b859ef1f752b51cd9beJason Evans}
651