xref: /dragonfly/lib/libc/stdio/printfcommon.h (revision 6e278935)
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 
53 static int exponent(CHAR *, int, CHAR);
54 
55 #endif /* !NO_FLOATING_POINT */
56 
57 static CHAR	*__ujtoa(uintmax_t, CHAR *, int, int, const char *);
58 static CHAR	*__ultoa(u_long, CHAR *, int, int, const char *);
59 
60 #define NIOV 8
61 struct io_state {
62 	FILE *fp;
63 	struct __suio uio;	/* output information: summary */
64 	struct __siov iov[NIOV];/* ... and individual io vectors */
65 };
66 
67 static inline void
68 io_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  */
81 static inline int
82 io_print(struct io_state *iop, const CHAR * __restrict ptr, int len)
83 {
84 
85 	iop->iov[iop->uio.uio_iovcnt].iov_base = __DECONST(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, &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 */
100 static const CHAR blanks[PADSIZE] =
101 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
102 static 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  */
109 static inline int
110 io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with)
111 {
112 	int n;
113 
114 	while (howmany > 0) {
115 		n = (howmany >= PADSIZE) ? PADSIZE : howmany;
116 		if (io_print(iop, with, n))
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  */
127 static inline int
128 io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
129 	       int len, const CHAR * __restrict with)
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))
138 			return (-1);
139 	} else {
140 		p_len = 0;
141 	}
142 	return (io_pad(iop, len - p_len, with));
143 }
144 
145 static inline int
146 io_flush(struct io_state *iop)
147 {
148 
149 	return (__sprint(iop->fp, &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  */
158 static 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 		abort();
209 	}
210 	return (cp);
211 }
212 
213 /* Identical to __ultoa, but for intmax_t. */
214 static 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 > INTMAX_MAX) {
227 			*--cp = to_char(val % 10);
228 			sval = val / 10;
229 		} else
230 			sval = val;
231 		do {
232 			*--cp = to_char(sval % 10);
233 			sval /= 10;
234 		} while (sval != 0);
235 		break;
236 
237 	case 8:
238 		do {
239 			*--cp = to_char(val & 7);
240 			val >>= 3;
241 		} while (val);
242 		if (octzero && *cp != '0')
243 			*--cp = '0';
244 		break;
245 
246 	case 16:
247 		do {
248 			*--cp = xdigs[val & 15];
249 			val >>= 4;
250 		} while (val);
251 		break;
252 
253 	default:
254 		abort();
255 	}
256 	return (cp);
257 }
258 
259 #ifndef NO_FLOATING_POINT
260 
261 static int
262 exponent(CHAR *p0, int exp, CHAR fmtch)
263 {
264 	CHAR *p, *t;
265 	CHAR expbuf[MAXEXPDIG];
266 
267 	p = p0;
268 	*p++ = fmtch;
269 	if (exp < 0) {
270 		exp = -exp;
271 		*p++ = '-';
272 	}
273 	else
274 		*p++ = '+';
275 	t = expbuf + MAXEXPDIG;
276 	if (exp > 9) {
277 		do {
278 			*--t = to_char(exp % 10);
279 		} while ((exp /= 10) > 9);
280 		*--t = to_char(exp);
281 		for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
282 	}
283 	else {
284 		/*
285 		 * Exponents for decimal floating point conversions
286 		 * (%[eEgG]) must be at least two characters long,
287 		 * whereas exponents for hexadecimal conversions can
288 		 * be only one character long.
289 		 */
290 		if (fmtch == 'e' || fmtch == 'E')
291 			*p++ = '0';
292 		*p++ = to_char(exp);
293 	}
294 	return (p - p0);
295 }
296 
297 #endif /* !NO_FLOATING_POINT */
298