xref: /dflybsd-src/lib/libc/stdio/printfcommon.h (revision c66c7e2fb8d0d28477d550f1d2a50c4677d547ff)
1e0f95098SPeter Avalos /*-
2e0f95098SPeter Avalos  * Copyright (c) 1990, 1993
3e0f95098SPeter Avalos  *	The Regents of the University of California.  All rights reserved.
4e0f95098SPeter Avalos  *
5e0f95098SPeter Avalos  * This code is derived from software contributed to Berkeley by
6e0f95098SPeter Avalos  * Chris Torek.
7e0f95098SPeter Avalos  *
80d5acd74SJohn Marino  * Copyright (c) 2011 The FreeBSD Foundation
90d5acd74SJohn Marino  * All rights reserved.
100d5acd74SJohn Marino  * Portions of this software were developed by David Chisnall
110d5acd74SJohn Marino  * under sponsorship from the FreeBSD Foundation.
120d5acd74SJohn Marino  *
13e0f95098SPeter Avalos  * Redistribution and use in source and binary forms, with or without
14e0f95098SPeter Avalos  * modification, are permitted provided that the following conditions
15e0f95098SPeter Avalos  * are met:
16e0f95098SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
17e0f95098SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
18e0f95098SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
19e0f95098SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
20e0f95098SPeter Avalos  *    documentation and/or other materials provided with the distribution.
21*c66c7e2fSzrj  * 3. Neither the name of the University nor the names of its contributors
22e0f95098SPeter Avalos  *    may be used to endorse or promote products derived from this software
23e0f95098SPeter Avalos  *    without specific prior written permission.
24e0f95098SPeter Avalos  *
25e0f95098SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26e0f95098SPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27e0f95098SPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28e0f95098SPeter Avalos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29e0f95098SPeter Avalos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30e0f95098SPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31e0f95098SPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32e0f95098SPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33e0f95098SPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34e0f95098SPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35e0f95098SPeter Avalos  * SUCH DAMAGE.
36e0f95098SPeter Avalos  *
370d5acd74SJohn Marino  * $FreeBSD: head/lib/libc/stdio/printfcommon.h 227753 2011-11-20 14:45:42Z theraven $
38e0f95098SPeter Avalos  */
39e0f95098SPeter Avalos 
40e0f95098SPeter Avalos /*
41e0f95098SPeter Avalos  * This file defines common routines used by both printf and wprintf.
42e0f95098SPeter Avalos  * You must define CHAR to either char or wchar_t prior to including this.
43e0f95098SPeter Avalos  */
44e0f95098SPeter Avalos 
45e0f95098SPeter Avalos 
46e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
47e0f95098SPeter Avalos 
48e0f95098SPeter Avalos #define	dtoa		__dtoa
49e0f95098SPeter Avalos #define	freedtoa	__freedtoa
50e0f95098SPeter Avalos 
51e0f95098SPeter Avalos #include <float.h>
52e0f95098SPeter Avalos #include <math.h>
53e0f95098SPeter Avalos #include "floatio.h"
54e0f95098SPeter Avalos #include "gdtoa.h"
55e0f95098SPeter Avalos 
56e0f95098SPeter Avalos #define	DEFPREC		6
57e0f95098SPeter Avalos 
58e0f95098SPeter Avalos static int exponent(CHAR *, int, CHAR);
59e0f95098SPeter Avalos 
60e0f95098SPeter Avalos #endif /* !NO_FLOATING_POINT */
61e0f95098SPeter Avalos 
62e0f95098SPeter Avalos static CHAR	*__ujtoa(uintmax_t, CHAR *, int, int, const char *);
63e0f95098SPeter Avalos static CHAR	*__ultoa(u_long, CHAR *, int, int, const char *);
64e0f95098SPeter Avalos 
65e0f95098SPeter Avalos #define NIOV 8
66e0f95098SPeter Avalos struct io_state {
67e0f95098SPeter Avalos 	FILE *fp;
68e0f95098SPeter Avalos 	struct __suio uio;	/* output information: summary */
69e0f95098SPeter Avalos 	struct __siov iov[NIOV];/* ... and individual io vectors */
70e0f95098SPeter Avalos };
71e0f95098SPeter Avalos 
72e0f95098SPeter Avalos static inline void
io_init(struct io_state * iop,FILE * fp)73e0f95098SPeter Avalos io_init(struct io_state *iop, FILE *fp)
74e0f95098SPeter Avalos {
75e0f95098SPeter Avalos 
76e0f95098SPeter Avalos 	iop->uio.uio_iov = iop->iov;
77e0f95098SPeter Avalos 	iop->uio.uio_resid = 0;
78e0f95098SPeter Avalos 	iop->uio.uio_iovcnt = 0;
79e0f95098SPeter Avalos 	iop->fp = fp;
80e0f95098SPeter Avalos }
81e0f95098SPeter Avalos 
82e0f95098SPeter Avalos /*
83e0f95098SPeter Avalos  * WARNING: The buffer passed to io_print() is not copied immediately; it must
84e0f95098SPeter Avalos  * remain valid until io_flush() is called.
85e0f95098SPeter Avalos  */
86e0f95098SPeter Avalos static inline int
io_print(struct io_state * iop,const CHAR * __restrict ptr,int len,locale_t locale)870d5acd74SJohn Marino io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale)
88e0f95098SPeter Avalos {
89e0f95098SPeter Avalos 
900d5acd74SJohn Marino 	iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr;
91e0f95098SPeter Avalos 	iop->iov[iop->uio.uio_iovcnt].iov_len = len;
92e0f95098SPeter Avalos 	iop->uio.uio_resid += len;
93e0f95098SPeter Avalos 	if (++iop->uio.uio_iovcnt >= NIOV)
940d5acd74SJohn Marino 		return (__sprint(iop->fp, &iop->uio, locale));
95e0f95098SPeter Avalos 	else
96e0f95098SPeter Avalos 		return (0);
97e0f95098SPeter Avalos }
98e0f95098SPeter Avalos 
99e0f95098SPeter Avalos /*
100e0f95098SPeter Avalos  * Choose PADSIZE to trade efficiency vs. size.  If larger printf
101e0f95098SPeter Avalos  * fields occur frequently, increase PADSIZE and make the initialisers
102e0f95098SPeter Avalos  * below longer.
103e0f95098SPeter Avalos  */
104e0f95098SPeter Avalos #define	PADSIZE	16		/* pad chunk size */
105e0f95098SPeter Avalos static const CHAR blanks[PADSIZE] =
106e0f95098SPeter Avalos {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
107e0f95098SPeter Avalos static const CHAR zeroes[PADSIZE] =
108e0f95098SPeter Avalos {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
109e0f95098SPeter Avalos 
110e0f95098SPeter Avalos /*
111e0f95098SPeter Avalos  * Pad with blanks or zeroes. 'with' should point to either the blanks array
112e0f95098SPeter Avalos  * or the zeroes array.
113e0f95098SPeter Avalos  */
114e0f95098SPeter Avalos static inline int
io_pad(struct io_state * iop,int howmany,const CHAR * __restrict with,locale_t locale)1150d5acd74SJohn Marino io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with,
1160d5acd74SJohn Marino 		locale_t locale)
117e0f95098SPeter Avalos {
118e0f95098SPeter Avalos 	int n;
119e0f95098SPeter Avalos 
120e0f95098SPeter Avalos 	while (howmany > 0) {
121e0f95098SPeter Avalos 		n = (howmany >= PADSIZE) ? PADSIZE : howmany;
1220d5acd74SJohn Marino 		if (io_print(iop, with, n, locale))
123e0f95098SPeter Avalos 			return (-1);
124e0f95098SPeter Avalos 		howmany -= n;
125e0f95098SPeter Avalos 	}
126e0f95098SPeter Avalos 	return (0);
127e0f95098SPeter Avalos }
128e0f95098SPeter Avalos 
129e0f95098SPeter Avalos /*
130e0f95098SPeter Avalos  * Print exactly len characters of the string spanning p to ep, truncating
131e0f95098SPeter Avalos  * or padding with 'with' as necessary.
132e0f95098SPeter Avalos  */
133e0f95098SPeter Avalos static inline int
io_printandpad(struct io_state * iop,const CHAR * p,const CHAR * ep,int len,const CHAR * __restrict with,locale_t locale)134e0f95098SPeter Avalos io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
1350d5acd74SJohn Marino 	       int len, const CHAR * __restrict with, locale_t locale)
136e0f95098SPeter Avalos {
137e0f95098SPeter Avalos 	int p_len;
138e0f95098SPeter Avalos 
139e0f95098SPeter Avalos 	p_len = ep - p;
140e0f95098SPeter Avalos 	if (p_len > len)
141e0f95098SPeter Avalos 		p_len = len;
142e0f95098SPeter Avalos 	if (p_len > 0) {
1430d5acd74SJohn Marino 		if (io_print(iop, p, p_len, locale))
144e0f95098SPeter Avalos 			return (-1);
145e0f95098SPeter Avalos 	} else {
146e0f95098SPeter Avalos 		p_len = 0;
147e0f95098SPeter Avalos 	}
1480d5acd74SJohn Marino 	return (io_pad(iop, len - p_len, with, locale));
149e0f95098SPeter Avalos }
150e0f95098SPeter Avalos 
151e0f95098SPeter Avalos static inline int
io_flush(struct io_state * iop,locale_t locale)1520d5acd74SJohn Marino io_flush(struct io_state *iop, locale_t locale)
153e0f95098SPeter Avalos {
154e0f95098SPeter Avalos 
1550d5acd74SJohn Marino 	return (__sprint(iop->fp, &iop->uio, locale));
156e0f95098SPeter Avalos }
157e0f95098SPeter Avalos 
158e0f95098SPeter Avalos /*
159e0f95098SPeter Avalos  * Convert an unsigned long to ASCII for printf purposes, returning
160e0f95098SPeter Avalos  * a pointer to the first character of the string representation.
161e0f95098SPeter Avalos  * Octal numbers can be forced to have a leading zero; hex numbers
162e0f95098SPeter Avalos  * use the given digits.
163e0f95098SPeter Avalos  */
164e0f95098SPeter Avalos static CHAR *
__ultoa(u_long val,CHAR * endp,int base,int octzero,const char * xdigs)165e0f95098SPeter Avalos __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs)
166e0f95098SPeter Avalos {
167e0f95098SPeter Avalos 	CHAR *cp = endp;
168e0f95098SPeter Avalos 	long sval;
169e0f95098SPeter Avalos 
170e0f95098SPeter Avalos 	/*
171e0f95098SPeter Avalos 	 * Handle the three cases separately, in the hope of getting
172e0f95098SPeter Avalos 	 * better/faster code.
173e0f95098SPeter Avalos 	 */
174e0f95098SPeter Avalos 	switch (base) {
175e0f95098SPeter Avalos 	case 10:
176e0f95098SPeter Avalos 		if (val < 10) {	/* many numbers are 1 digit */
177e0f95098SPeter Avalos 			*--cp = to_char(val);
178e0f95098SPeter Avalos 			return (cp);
179e0f95098SPeter Avalos 		}
180e0f95098SPeter Avalos 		/*
181e0f95098SPeter Avalos 		 * On many machines, unsigned arithmetic is harder than
182e0f95098SPeter Avalos 		 * signed arithmetic, so we do at most one unsigned mod and
183e0f95098SPeter Avalos 		 * divide; this is sufficient to reduce the range of
184e0f95098SPeter Avalos 		 * the incoming value to where signed arithmetic works.
185e0f95098SPeter Avalos 		 */
186e0f95098SPeter Avalos 		if (val > LONG_MAX) {
187e0f95098SPeter Avalos 			*--cp = to_char(val % 10);
188e0f95098SPeter Avalos 			sval = val / 10;
189e0f95098SPeter Avalos 		} else
190e0f95098SPeter Avalos 			sval = val;
191e0f95098SPeter Avalos 		do {
192e0f95098SPeter Avalos 			*--cp = to_char(sval % 10);
193e0f95098SPeter Avalos 			sval /= 10;
194e0f95098SPeter Avalos 		} while (sval != 0);
195e0f95098SPeter Avalos 		break;
196e0f95098SPeter Avalos 
197e0f95098SPeter Avalos 	case 8:
198e0f95098SPeter Avalos 		do {
199e0f95098SPeter Avalos 			*--cp = to_char(val & 7);
200e0f95098SPeter Avalos 			val >>= 3;
201e0f95098SPeter Avalos 		} while (val);
202e0f95098SPeter Avalos 		if (octzero && *cp != '0')
203e0f95098SPeter Avalos 			*--cp = '0';
204e0f95098SPeter Avalos 		break;
205e0f95098SPeter Avalos 
206e0f95098SPeter Avalos 	case 16:
207e0f95098SPeter Avalos 		do {
208e0f95098SPeter Avalos 			*--cp = xdigs[val & 15];
209e0f95098SPeter Avalos 			val >>= 4;
210e0f95098SPeter Avalos 		} while (val);
211e0f95098SPeter Avalos 		break;
212e0f95098SPeter Avalos 
213e0f95098SPeter Avalos 	default:			/* oops */
214e0f95098SPeter Avalos 		abort();
215e0f95098SPeter Avalos 	}
216e0f95098SPeter Avalos 	return (cp);
217e0f95098SPeter Avalos }
218e0f95098SPeter Avalos 
219e0f95098SPeter Avalos /* Identical to __ultoa, but for intmax_t. */
220e0f95098SPeter Avalos static CHAR *
__ujtoa(uintmax_t val,CHAR * endp,int base,int octzero,const char * xdigs)221e0f95098SPeter Avalos __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs)
222e0f95098SPeter Avalos {
223e0f95098SPeter Avalos 	CHAR *cp = endp;
224e0f95098SPeter Avalos 	intmax_t sval;
225e0f95098SPeter Avalos 
226e0f95098SPeter Avalos 	/* quick test for small values; __ultoa is typically much faster */
227e0f95098SPeter Avalos 	/* (perhaps instead we should run until small, then call __ultoa?) */
228e0f95098SPeter Avalos 	if (val <= ULONG_MAX)
229e0f95098SPeter Avalos 		return (__ultoa((u_long)val, endp, base, octzero, xdigs));
230e0f95098SPeter Avalos 	switch (base) {
231e0f95098SPeter Avalos 	case 10:
232e0f95098SPeter Avalos 		if (val > INTMAX_MAX) {
233e0f95098SPeter Avalos 			*--cp = to_char(val % 10);
234e0f95098SPeter Avalos 			sval = val / 10;
235e0f95098SPeter Avalos 		} else
236e0f95098SPeter Avalos 			sval = val;
237e0f95098SPeter Avalos 		do {
238e0f95098SPeter Avalos 			*--cp = to_char(sval % 10);
239e0f95098SPeter Avalos 			sval /= 10;
240e0f95098SPeter Avalos 		} while (sval != 0);
241e0f95098SPeter Avalos 		break;
242e0f95098SPeter Avalos 
243e0f95098SPeter Avalos 	case 8:
244e0f95098SPeter Avalos 		do {
245e0f95098SPeter Avalos 			*--cp = to_char(val & 7);
246e0f95098SPeter Avalos 			val >>= 3;
247e0f95098SPeter Avalos 		} while (val);
248e0f95098SPeter Avalos 		if (octzero && *cp != '0')
249e0f95098SPeter Avalos 			*--cp = '0';
250e0f95098SPeter Avalos 		break;
251e0f95098SPeter Avalos 
252e0f95098SPeter Avalos 	case 16:
253e0f95098SPeter Avalos 		do {
254e0f95098SPeter Avalos 			*--cp = xdigs[val & 15];
255e0f95098SPeter Avalos 			val >>= 4;
256e0f95098SPeter Avalos 		} while (val);
257e0f95098SPeter Avalos 		break;
258e0f95098SPeter Avalos 
259e0f95098SPeter Avalos 	default:
260e0f95098SPeter Avalos 		abort();
261e0f95098SPeter Avalos 	}
262e0f95098SPeter Avalos 	return (cp);
263e0f95098SPeter Avalos }
264e0f95098SPeter Avalos 
265e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
266e0f95098SPeter Avalos 
267e0f95098SPeter Avalos static int
exponent(CHAR * p0,int exp,CHAR fmtch)268e0f95098SPeter Avalos exponent(CHAR *p0, int exp, CHAR fmtch)
269e0f95098SPeter Avalos {
270e0f95098SPeter Avalos 	CHAR *p, *t;
271e0f95098SPeter Avalos 	CHAR expbuf[MAXEXPDIG];
272e0f95098SPeter Avalos 
273e0f95098SPeter Avalos 	p = p0;
274e0f95098SPeter Avalos 	*p++ = fmtch;
275e0f95098SPeter Avalos 	if (exp < 0) {
276e0f95098SPeter Avalos 		exp = -exp;
277e0f95098SPeter Avalos 		*p++ = '-';
278e0f95098SPeter Avalos 	}
279e0f95098SPeter Avalos 	else
280e0f95098SPeter Avalos 		*p++ = '+';
281e0f95098SPeter Avalos 	t = expbuf + MAXEXPDIG;
282e0f95098SPeter Avalos 	if (exp > 9) {
283e0f95098SPeter Avalos 		do {
284e0f95098SPeter Avalos 			*--t = to_char(exp % 10);
285e0f95098SPeter Avalos 		} while ((exp /= 10) > 9);
286e0f95098SPeter Avalos 		*--t = to_char(exp);
287e0f95098SPeter Avalos 		for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
288e0f95098SPeter Avalos 	}
289e0f95098SPeter Avalos 	else {
290e0f95098SPeter Avalos 		/*
291e0f95098SPeter Avalos 		 * Exponents for decimal floating point conversions
292e0f95098SPeter Avalos 		 * (%[eEgG]) must be at least two characters long,
293e0f95098SPeter Avalos 		 * whereas exponents for hexadecimal conversions can
294e0f95098SPeter Avalos 		 * be only one character long.
295e0f95098SPeter Avalos 		 */
296e0f95098SPeter Avalos 		if (fmtch == 'e' || fmtch == 'E')
297e0f95098SPeter Avalos 			*p++ = '0';
298e0f95098SPeter Avalos 		*p++ = to_char(exp);
299e0f95098SPeter Avalos 	}
300e0f95098SPeter Avalos 	return (p - p0);
301e0f95098SPeter Avalos }
302e0f95098SPeter Avalos 
303e0f95098SPeter Avalos #endif /* !NO_FLOATING_POINT */
304