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