Update fmemopen from NetBSD.
[dragonfly.git] / lib / libc / stdio / printfcommon.h
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 */