]> git.saurik.com Git - apple/libc.git/blame - stdio/FreeBSD/printfcommon.h
Libc-997.90.3.tar.gz
[apple/libc.git] / stdio / FreeBSD / printfcommon.h
CommitLineData
1f2f436a
A
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
ad3c9f2a 82io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t loc)
1f2f436a
A
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)
ad3c9f2a 89 return (__sprint(iop->fp, loc, &iop->uio));
1f2f436a
A
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
ad3c9f2a 110io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with, locale_t loc)
1f2f436a
A
111{
112 int n;
113
114 while (howmany > 0) {
115 n = (howmany >= PADSIZE) ? PADSIZE : howmany;
ad3c9f2a 116 if (io_print(iop, with, n, loc))
1f2f436a
A
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,
ad3c9f2a 129 int len, const CHAR * __restrict with, locale_t loc)
1f2f436a
A
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) {
ad3c9f2a 137 if (io_print(iop, p, p_len, loc))
1f2f436a
A
138 return (-1);
139 } else {
140 p_len = 0;
141 }
ad3c9f2a 142 return (io_pad(iop, len - p_len, with, loc));
1f2f436a
A
143}
144
145static inline int
ad3c9f2a 146io_flush(struct io_state *iop, locale_t loc)
1f2f436a
A
147{
148
ad3c9f2a 149 return (__sprint(iop->fp, loc, &iop->uio));
1f2f436a
A
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 */
ad3c9f2a 208 LIBC_ABORT("__ultoa: invalid base=%d", base);
1f2f436a
A
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:
ad3c9f2a 258 LIBC_ABORT("__ujtoa: invalid base=%d", base);
1f2f436a
A
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 */