1814d1bc9SDavid Schultz /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
4814d1bc9SDavid Schultz * Copyright (c) 1990, 1993
5814d1bc9SDavid Schultz * The Regents of the University of California. All rights reserved.
6814d1bc9SDavid Schultz *
7814d1bc9SDavid Schultz * This code is derived from software contributed to Berkeley by
8814d1bc9SDavid Schultz * Chris Torek.
9814d1bc9SDavid Schultz *
103c87aa1dSDavid Chisnall * Copyright (c) 2011 The FreeBSD Foundation
115b5fa75aSEd Maste *
123c87aa1dSDavid Chisnall * Portions of this software were developed by David Chisnall
133c87aa1dSDavid Chisnall * under sponsorship from the FreeBSD Foundation.
143c87aa1dSDavid Chisnall *
15814d1bc9SDavid Schultz * Redistribution and use in source and binary forms, with or without
16814d1bc9SDavid Schultz * modification, are permitted provided that the following conditions
17814d1bc9SDavid Schultz * are met:
18814d1bc9SDavid Schultz * 1. Redistributions of source code must retain the above copyright
19814d1bc9SDavid Schultz * notice, this list of conditions and the following disclaimer.
20814d1bc9SDavid Schultz * 2. Redistributions in binary form must reproduce the above copyright
21814d1bc9SDavid Schultz * notice, this list of conditions and the following disclaimer in the
22814d1bc9SDavid Schultz * documentation and/or other materials provided with the distribution.
23fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
24814d1bc9SDavid Schultz * may be used to endorse or promote products derived from this software
25814d1bc9SDavid Schultz * without specific prior written permission.
26814d1bc9SDavid Schultz *
27814d1bc9SDavid Schultz * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28814d1bc9SDavid Schultz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29814d1bc9SDavid Schultz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30814d1bc9SDavid Schultz * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31814d1bc9SDavid Schultz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32814d1bc9SDavid Schultz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33814d1bc9SDavid Schultz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34814d1bc9SDavid Schultz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35814d1bc9SDavid Schultz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36814d1bc9SDavid Schultz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37814d1bc9SDavid Schultz * SUCH DAMAGE.
38814d1bc9SDavid Schultz */
39814d1bc9SDavid Schultz
40814d1bc9SDavid Schultz /*
41814d1bc9SDavid Schultz * This file defines common routines used by both printf and wprintf.
42814d1bc9SDavid Schultz * You must define CHAR to either char or wchar_t prior to including this.
43814d1bc9SDavid Schultz */
44814d1bc9SDavid Schultz
450a492640SDavid Schultz
460a492640SDavid Schultz #ifndef NO_FLOATING_POINT
470a492640SDavid Schultz
480a492640SDavid Schultz #define dtoa __dtoa
490a492640SDavid Schultz #define freedtoa __freedtoa
500a492640SDavid Schultz
510a492640SDavid Schultz #include <float.h>
520a492640SDavid Schultz #include <math.h>
530a492640SDavid Schultz #include "floatio.h"
540a492640SDavid Schultz #include "gdtoa.h"
550a492640SDavid Schultz
560a492640SDavid Schultz #define DEFPREC 6
570a492640SDavid Schultz
580a492640SDavid Schultz static int exponent(CHAR *, int, CHAR);
590a492640SDavid Schultz
600a492640SDavid Schultz #endif /* !NO_FLOATING_POINT */
610a492640SDavid Schultz
6221ca178eSDavid Schultz static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *);
6321ca178eSDavid Schultz static CHAR *__ultoa(u_long, CHAR *, int, int, const char *);
640a492640SDavid Schultz
65814d1bc9SDavid Schultz #define NIOV 8
66814d1bc9SDavid Schultz struct io_state {
67814d1bc9SDavid Schultz FILE *fp;
68814d1bc9SDavid Schultz struct __suio uio; /* output information: summary */
69814d1bc9SDavid Schultz struct __siov iov[NIOV];/* ... and individual io vectors */
70814d1bc9SDavid Schultz };
71814d1bc9SDavid Schultz
72814d1bc9SDavid Schultz static inline void
io_init(struct io_state * iop,FILE * fp)73814d1bc9SDavid Schultz io_init(struct io_state *iop, FILE *fp)
74814d1bc9SDavid Schultz {
75814d1bc9SDavid Schultz
766ec35123SDavid Schultz iop->uio.uio_iov = iop->iov;
77814d1bc9SDavid Schultz iop->uio.uio_resid = 0;
78814d1bc9SDavid Schultz iop->uio.uio_iovcnt = 0;
79814d1bc9SDavid Schultz iop->fp = fp;
80814d1bc9SDavid Schultz }
81814d1bc9SDavid Schultz
82814d1bc9SDavid Schultz /*
83814d1bc9SDavid Schultz * WARNING: The buffer passed to io_print() is not copied immediately; it must
84814d1bc9SDavid Schultz * remain valid until io_flush() is called.
85814d1bc9SDavid Schultz */
86814d1bc9SDavid Schultz static inline int
io_print(struct io_state * iop,const CHAR * __restrict ptr,int len,locale_t locale)873c87aa1dSDavid Chisnall io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale)
88814d1bc9SDavid Schultz {
89814d1bc9SDavid Schultz
906ec35123SDavid Schultz iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr;
916ec35123SDavid Schultz iop->iov[iop->uio.uio_iovcnt].iov_len = len;
92814d1bc9SDavid Schultz iop->uio.uio_resid += len;
936ec35123SDavid Schultz if (++iop->uio.uio_iovcnt >= NIOV)
943c87aa1dSDavid Chisnall return (__sprint(iop->fp, &iop->uio, locale));
956ec35123SDavid Schultz else
96814d1bc9SDavid Schultz return (0);
97814d1bc9SDavid Schultz }
98814d1bc9SDavid Schultz
99814d1bc9SDavid Schultz /*
100814d1bc9SDavid Schultz * Choose PADSIZE to trade efficiency vs. size. If larger printf
101814d1bc9SDavid Schultz * fields occur frequently, increase PADSIZE and make the initialisers
102814d1bc9SDavid Schultz * below longer.
103814d1bc9SDavid Schultz */
104814d1bc9SDavid Schultz #define PADSIZE 16 /* pad chunk size */
105814d1bc9SDavid Schultz static const CHAR blanks[PADSIZE] =
106814d1bc9SDavid Schultz {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
107814d1bc9SDavid Schultz static const CHAR zeroes[PADSIZE] =
108814d1bc9SDavid Schultz {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
109814d1bc9SDavid Schultz
110814d1bc9SDavid Schultz /*
111814d1bc9SDavid Schultz * Pad with blanks or zeroes. 'with' should point to either the blanks array
112814d1bc9SDavid Schultz * or the zeroes array.
113814d1bc9SDavid Schultz */
114814d1bc9SDavid Schultz static inline int
io_pad(struct io_state * iop,int howmany,const CHAR * __restrict with,locale_t locale)1153c87aa1dSDavid Chisnall io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with,
1163c87aa1dSDavid Chisnall locale_t locale)
117814d1bc9SDavid Schultz {
1186ec35123SDavid Schultz int n;
119814d1bc9SDavid Schultz
1206ec35123SDavid Schultz while (howmany > 0) {
1216ec35123SDavid Schultz n = (howmany >= PADSIZE) ? PADSIZE : howmany;
1223c87aa1dSDavid Chisnall if (io_print(iop, with, n, locale))
123814d1bc9SDavid Schultz return (-1);
1246ec35123SDavid Schultz howmany -= n;
125814d1bc9SDavid Schultz }
126814d1bc9SDavid Schultz return (0);
127814d1bc9SDavid Schultz }
128814d1bc9SDavid Schultz
129814d1bc9SDavid Schultz /*
130814d1bc9SDavid Schultz * Print exactly len characters of the string spanning p to ep, truncating
131814d1bc9SDavid Schultz * or padding with 'with' as necessary.
132814d1bc9SDavid Schultz */
133814d1bc9SDavid Schultz static inline int
io_printandpad(struct io_state * iop,const CHAR * p,const CHAR * ep,int len,const CHAR * __restrict with,locale_t locale)134814d1bc9SDavid Schultz io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
1353c87aa1dSDavid Chisnall int len, const CHAR * __restrict with, locale_t locale)
136814d1bc9SDavid Schultz {
137814d1bc9SDavid Schultz int p_len;
138814d1bc9SDavid Schultz
139814d1bc9SDavid Schultz p_len = ep - p;
140814d1bc9SDavid Schultz if (p_len > len)
141814d1bc9SDavid Schultz p_len = len;
1426ec35123SDavid Schultz if (p_len > 0) {
1433c87aa1dSDavid Chisnall if (io_print(iop, p, p_len, locale))
144814d1bc9SDavid Schultz return (-1);
1456ec35123SDavid Schultz } else {
1466ec35123SDavid Schultz p_len = 0;
1476ec35123SDavid Schultz }
1483c87aa1dSDavid Chisnall return (io_pad(iop, len - p_len, with, locale));
149814d1bc9SDavid Schultz }
150814d1bc9SDavid Schultz
151814d1bc9SDavid Schultz static inline int
io_flush(struct io_state * iop,locale_t locale)1523c87aa1dSDavid Chisnall io_flush(struct io_state *iop, locale_t locale)
153814d1bc9SDavid Schultz {
154814d1bc9SDavid Schultz
1553c87aa1dSDavid Chisnall return (__sprint(iop->fp, &iop->uio, locale));
156814d1bc9SDavid Schultz }
1570a492640SDavid Schultz
1580a492640SDavid Schultz /*
1590a492640SDavid Schultz * Convert an unsigned long to ASCII for printf purposes, returning
1600a492640SDavid Schultz * a pointer to the first character of the string representation.
1610a492640SDavid Schultz * Octal numbers can be forced to have a leading zero; hex numbers
1620a492640SDavid Schultz * use the given digits.
1630a492640SDavid Schultz */
1640a492640SDavid Schultz static CHAR *
__ultoa(u_long val,CHAR * endp,int base,int octzero,const char * xdigs)16521ca178eSDavid Schultz __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs)
1660a492640SDavid Schultz {
1670a492640SDavid Schultz CHAR *cp = endp;
1680a492640SDavid Schultz long sval;
1690a492640SDavid Schultz
1700a492640SDavid Schultz /*
1710a492640SDavid Schultz * Handle the three cases separately, in the hope of getting
1720a492640SDavid Schultz * better/faster code.
1730a492640SDavid Schultz */
1740a492640SDavid Schultz switch (base) {
1750a492640SDavid Schultz case 10:
1760a492640SDavid Schultz if (val < 10) { /* many numbers are 1 digit */
1770a492640SDavid Schultz *--cp = to_char(val);
1780a492640SDavid Schultz return (cp);
1790a492640SDavid Schultz }
1800a492640SDavid Schultz /*
1810a492640SDavid Schultz * On many machines, unsigned arithmetic is harder than
1820a492640SDavid Schultz * signed arithmetic, so we do at most one unsigned mod and
1830a492640SDavid Schultz * divide; this is sufficient to reduce the range of
1840a492640SDavid Schultz * the incoming value to where signed arithmetic works.
1850a492640SDavid Schultz */
1860a492640SDavid Schultz if (val > LONG_MAX) {
1870a492640SDavid Schultz *--cp = to_char(val % 10);
1880a492640SDavid Schultz sval = val / 10;
1890a492640SDavid Schultz } else
1900a492640SDavid Schultz sval = val;
1910a492640SDavid Schultz do {
1920a492640SDavid Schultz *--cp = to_char(sval % 10);
1930a492640SDavid Schultz sval /= 10;
1940a492640SDavid Schultz } while (sval != 0);
1950a492640SDavid Schultz break;
1960a492640SDavid Schultz
197*d9dc1603SDag-Erling Smørgrav case 2:
198*d9dc1603SDag-Erling Smørgrav do {
199*d9dc1603SDag-Erling Smørgrav *--cp = to_char(val & 1);
200*d9dc1603SDag-Erling Smørgrav val >>= 1;
201*d9dc1603SDag-Erling Smørgrav } while (val);
202*d9dc1603SDag-Erling Smørgrav break;
203*d9dc1603SDag-Erling Smørgrav
2040a492640SDavid Schultz case 8:
2050a492640SDavid Schultz do {
2060a492640SDavid Schultz *--cp = to_char(val & 7);
2070a492640SDavid Schultz val >>= 3;
2080a492640SDavid Schultz } while (val);
2090a492640SDavid Schultz if (octzero && *cp != '0')
2100a492640SDavid Schultz *--cp = '0';
2110a492640SDavid Schultz break;
2120a492640SDavid Schultz
2130a492640SDavid Schultz case 16:
2140a492640SDavid Schultz do {
2150a492640SDavid Schultz *--cp = xdigs[val & 15];
2160a492640SDavid Schultz val >>= 4;
2170a492640SDavid Schultz } while (val);
2180a492640SDavid Schultz break;
2190a492640SDavid Schultz
2200a492640SDavid Schultz default: /* oops */
2210a492640SDavid Schultz abort();
2220a492640SDavid Schultz }
2230a492640SDavid Schultz return (cp);
2240a492640SDavid Schultz }
2250a492640SDavid Schultz
2260a492640SDavid Schultz /* Identical to __ultoa, but for intmax_t. */
2270a492640SDavid Schultz static CHAR *
__ujtoa(uintmax_t val,CHAR * endp,int base,int octzero,const char * xdigs)22821ca178eSDavid Schultz __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs)
2290a492640SDavid Schultz {
2300a492640SDavid Schultz CHAR *cp = endp;
2310a492640SDavid Schultz intmax_t sval;
2320a492640SDavid Schultz
2330a492640SDavid Schultz /* quick test for small values; __ultoa is typically much faster */
2340a492640SDavid Schultz /* (perhaps instead we should run until small, then call __ultoa?) */
2350a492640SDavid Schultz if (val <= ULONG_MAX)
23621ca178eSDavid Schultz return (__ultoa((u_long)val, endp, base, octzero, xdigs));
2370a492640SDavid Schultz switch (base) {
2380a492640SDavid Schultz case 10:
2390a492640SDavid Schultz if (val < 10) {
2400a492640SDavid Schultz *--cp = to_char(val % 10);
2410a492640SDavid Schultz return (cp);
2420a492640SDavid Schultz }
2430a492640SDavid Schultz if (val > INTMAX_MAX) {
2440a492640SDavid Schultz *--cp = to_char(val % 10);
2450a492640SDavid Schultz sval = val / 10;
2460a492640SDavid Schultz } else
2470a492640SDavid Schultz sval = val;
2480a492640SDavid Schultz do {
2490a492640SDavid Schultz *--cp = to_char(sval % 10);
2500a492640SDavid Schultz sval /= 10;
2510a492640SDavid Schultz } while (sval != 0);
2520a492640SDavid Schultz break;
2530a492640SDavid Schultz
254*d9dc1603SDag-Erling Smørgrav case 2:
255*d9dc1603SDag-Erling Smørgrav do {
256*d9dc1603SDag-Erling Smørgrav *--cp = to_char(val & 1);
257*d9dc1603SDag-Erling Smørgrav val >>= 1;
258*d9dc1603SDag-Erling Smørgrav } while (val);
259*d9dc1603SDag-Erling Smørgrav break;
260*d9dc1603SDag-Erling Smørgrav
2610a492640SDavid Schultz case 8:
2620a492640SDavid Schultz do {
2630a492640SDavid Schultz *--cp = to_char(val & 7);
2640a492640SDavid Schultz val >>= 3;
2650a492640SDavid Schultz } while (val);
2660a492640SDavid Schultz if (octzero && *cp != '0')
2670a492640SDavid Schultz *--cp = '0';
2680a492640SDavid Schultz break;
2690a492640SDavid Schultz
2700a492640SDavid Schultz case 16:
2710a492640SDavid Schultz do {
2720a492640SDavid Schultz *--cp = xdigs[val & 15];
2730a492640SDavid Schultz val >>= 4;
2740a492640SDavid Schultz } while (val);
2750a492640SDavid Schultz break;
2760a492640SDavid Schultz
2770a492640SDavid Schultz default:
2780a492640SDavid Schultz abort();
2790a492640SDavid Schultz }
2800a492640SDavid Schultz return (cp);
2810a492640SDavid Schultz }
2820a492640SDavid Schultz
2830a492640SDavid Schultz #ifndef NO_FLOATING_POINT
2840a492640SDavid Schultz
2850a492640SDavid Schultz static int
exponent(CHAR * p0,int exp,CHAR fmtch)2860a492640SDavid Schultz exponent(CHAR *p0, int exp, CHAR fmtch)
2870a492640SDavid Schultz {
2880a492640SDavid Schultz CHAR *p, *t;
2890a492640SDavid Schultz CHAR expbuf[MAXEXPDIG];
2900a492640SDavid Schultz
2910a492640SDavid Schultz p = p0;
2920a492640SDavid Schultz *p++ = fmtch;
2930a492640SDavid Schultz if (exp < 0) {
2940a492640SDavid Schultz exp = -exp;
2950a492640SDavid Schultz *p++ = '-';
2960a492640SDavid Schultz }
2970a492640SDavid Schultz else
2980a492640SDavid Schultz *p++ = '+';
2990a492640SDavid Schultz t = expbuf + MAXEXPDIG;
3000a492640SDavid Schultz if (exp > 9) {
3010a492640SDavid Schultz do {
3020a492640SDavid Schultz *--t = to_char(exp % 10);
3030a492640SDavid Schultz } while ((exp /= 10) > 9);
3040a492640SDavid Schultz *--t = to_char(exp);
3050a492640SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
3060a492640SDavid Schultz }
3070a492640SDavid Schultz else {
3080a492640SDavid Schultz /*
3090a492640SDavid Schultz * Exponents for decimal floating point conversions
3100a492640SDavid Schultz * (%[eEgG]) must be at least two characters long,
3110a492640SDavid Schultz * whereas exponents for hexadecimal conversions can
3120a492640SDavid Schultz * be only one character long.
3130a492640SDavid Schultz */
3140a492640SDavid Schultz if (fmtch == 'e' || fmtch == 'E')
3150a492640SDavid Schultz *p++ = '0';
3160a492640SDavid Schultz *p++ = to_char(exp);
3170a492640SDavid Schultz }
3180a492640SDavid Schultz return (p - p0);
3190a492640SDavid Schultz }
3200a492640SDavid Schultz
3210a492640SDavid Schultz #endif /* !NO_FLOATING_POINT */
322