xref: /freebsd/lib/libc/stdio/printfcommon.h (revision 0a4926406ae19c8057ef86b40704b8e5e9b28137)
1814d1bc9SDavid Schultz /*-
2814d1bc9SDavid Schultz  * Copyright (c) 1990, 1993
3814d1bc9SDavid Schultz  *	The Regents of the University of California.  All rights reserved.
4814d1bc9SDavid Schultz  *
5814d1bc9SDavid Schultz  * This code is derived from software contributed to Berkeley by
6814d1bc9SDavid Schultz  * Chris Torek.
7814d1bc9SDavid Schultz  *
8814d1bc9SDavid Schultz  * Redistribution and use in source and binary forms, with or without
9814d1bc9SDavid Schultz  * modification, are permitted provided that the following conditions
10814d1bc9SDavid Schultz  * are met:
11814d1bc9SDavid Schultz  * 1. Redistributions of source code must retain the above copyright
12814d1bc9SDavid Schultz  *    notice, this list of conditions and the following disclaimer.
13814d1bc9SDavid Schultz  * 2. Redistributions in binary form must reproduce the above copyright
14814d1bc9SDavid Schultz  *    notice, this list of conditions and the following disclaimer in the
15814d1bc9SDavid Schultz  *    documentation and/or other materials provided with the distribution.
16814d1bc9SDavid Schultz  * 4. Neither the name of the University nor the names of its contributors
17814d1bc9SDavid Schultz  *    may be used to endorse or promote products derived from this software
18814d1bc9SDavid Schultz  *    without specific prior written permission.
19814d1bc9SDavid Schultz  *
20814d1bc9SDavid Schultz  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21814d1bc9SDavid Schultz  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22814d1bc9SDavid Schultz  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23814d1bc9SDavid Schultz  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24814d1bc9SDavid Schultz  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25814d1bc9SDavid Schultz  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26814d1bc9SDavid Schultz  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27814d1bc9SDavid Schultz  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28814d1bc9SDavid Schultz  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29814d1bc9SDavid Schultz  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30814d1bc9SDavid Schultz  * SUCH DAMAGE.
31814d1bc9SDavid Schultz  *
32814d1bc9SDavid Schultz  * $FreeBSD$
33814d1bc9SDavid Schultz  */
34814d1bc9SDavid Schultz 
35814d1bc9SDavid Schultz /*
36814d1bc9SDavid Schultz  * This file defines common routines used by both printf and wprintf.
37814d1bc9SDavid Schultz  * You must define CHAR to either char or wchar_t prior to including this.
38814d1bc9SDavid Schultz  */
39814d1bc9SDavid Schultz 
400a492640SDavid Schultz 
410a492640SDavid Schultz #ifndef NO_FLOATING_POINT
420a492640SDavid Schultz 
430a492640SDavid Schultz #define	dtoa		__dtoa
440a492640SDavid Schultz #define	freedtoa	__freedtoa
450a492640SDavid Schultz 
460a492640SDavid Schultz #include <float.h>
470a492640SDavid Schultz #include <math.h>
480a492640SDavid Schultz #include "floatio.h"
490a492640SDavid Schultz #include "gdtoa.h"
500a492640SDavid Schultz 
510a492640SDavid Schultz #define	DEFPREC		6
520a492640SDavid Schultz 
530a492640SDavid Schultz static int exponent(CHAR *, int, CHAR);
540a492640SDavid Schultz 
550a492640SDavid Schultz #endif /* !NO_FLOATING_POINT */
560a492640SDavid Schultz 
570a492640SDavid Schultz static CHAR	*__ujtoa(uintmax_t, CHAR *, int, int, const char *, int, char,
580a492640SDavid Schultz 		    const char *);
590a492640SDavid Schultz static CHAR	*__ultoa(u_long, CHAR *, int, int, const char *, int, char,
600a492640SDavid Schultz 		    const char *);
610a492640SDavid Schultz 
62814d1bc9SDavid Schultz #define NIOV 8
63814d1bc9SDavid Schultz struct io_state {
64814d1bc9SDavid Schultz 	FILE *fp;
65814d1bc9SDavid Schultz 	struct __suio uio;	/* output information: summary */
66814d1bc9SDavid Schultz 	struct __siov iov[NIOV];/* ... and individual io vectors */
67814d1bc9SDavid Schultz 	struct __siov *iovp;	/* pointer to next free slot in iov */
68814d1bc9SDavid Schultz };
69814d1bc9SDavid Schultz 
70814d1bc9SDavid Schultz static inline void
71814d1bc9SDavid Schultz io_init(struct io_state *iop, FILE *fp)
72814d1bc9SDavid Schultz {
73814d1bc9SDavid Schultz 
74814d1bc9SDavid Schultz 	iop->uio.uio_iov = iop->iovp = iop->iov;
75814d1bc9SDavid Schultz 	iop->uio.uio_resid = 0;
76814d1bc9SDavid Schultz 	iop->uio.uio_iovcnt = 0;
77814d1bc9SDavid Schultz 	iop->fp = fp;
78814d1bc9SDavid Schultz }
79814d1bc9SDavid Schultz 
80814d1bc9SDavid Schultz /*
81814d1bc9SDavid Schultz  * WARNING: The buffer passed to io_print() is not copied immediately; it must
82814d1bc9SDavid Schultz  * remain valid until io_flush() is called.
83814d1bc9SDavid Schultz  */
84814d1bc9SDavid Schultz static inline int
85814d1bc9SDavid Schultz io_print(struct io_state *iop, const CHAR * __restrict ptr, int len)
86814d1bc9SDavid Schultz {
87814d1bc9SDavid Schultz 
88814d1bc9SDavid Schultz 	iop->iovp->iov_base = (char *)ptr;
89814d1bc9SDavid Schultz 	iop->iovp->iov_len = len;
90814d1bc9SDavid Schultz 	iop->uio.uio_resid += len;
91814d1bc9SDavid Schultz 	iop->iovp++;
92814d1bc9SDavid Schultz 	if (++iop->uio.uio_iovcnt >= NIOV) {
93814d1bc9SDavid Schultz 		iop->iovp = iop->iov;
94814d1bc9SDavid Schultz 		return (__sprint(iop->fp, &iop->uio));
95814d1bc9SDavid Schultz 	}
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
115814d1bc9SDavid Schultz io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with)
116814d1bc9SDavid Schultz {
117814d1bc9SDavid Schultz 
118814d1bc9SDavid Schultz 	while (howmany > PADSIZE) {
119814d1bc9SDavid Schultz 		if (io_print(iop, with, PADSIZE))
120814d1bc9SDavid Schultz 			return (-1);
121814d1bc9SDavid Schultz 		howmany -= PADSIZE;
122814d1bc9SDavid Schultz 	}
123814d1bc9SDavid Schultz 	if (howmany > 0 && io_print(iop, with, howmany))
124814d1bc9SDavid Schultz 		return (-1);
125814d1bc9SDavid Schultz 	return (0);
126814d1bc9SDavid Schultz }
127814d1bc9SDavid Schultz 
128814d1bc9SDavid Schultz /*
129814d1bc9SDavid Schultz  * Print exactly len characters of the string spanning p to ep, truncating
130814d1bc9SDavid Schultz  * or padding with 'with' as necessary.
131814d1bc9SDavid Schultz  */
132814d1bc9SDavid Schultz static inline int
133814d1bc9SDavid Schultz io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
134814d1bc9SDavid Schultz 	       int len, const CHAR * __restrict with)
135814d1bc9SDavid Schultz {
136814d1bc9SDavid Schultz 	int p_len;
137814d1bc9SDavid Schultz 
138814d1bc9SDavid Schultz 	p_len = ep - p;
139814d1bc9SDavid Schultz 	if (p_len > len)
140814d1bc9SDavid Schultz 		p_len = len;
141814d1bc9SDavid Schultz 	if (p_len > 0 && io_print(iop, p, p_len))
142814d1bc9SDavid Schultz 		return (-1);
143814d1bc9SDavid Schultz 	return (io_pad(iop, len - (p_len > 0 ? p_len : 0), with));
144814d1bc9SDavid Schultz }
145814d1bc9SDavid Schultz 
146814d1bc9SDavid Schultz static inline int
147814d1bc9SDavid Schultz io_flush(struct io_state *iop)
148814d1bc9SDavid Schultz {
149814d1bc9SDavid Schultz 
150814d1bc9SDavid Schultz 	iop->iovp = iop->iov;
151814d1bc9SDavid Schultz 	return (__sprint(iop->fp, &iop->uio));
152814d1bc9SDavid Schultz }
1530a492640SDavid Schultz 
1540a492640SDavid Schultz /*
1550a492640SDavid Schultz  * Convert an unsigned long to ASCII for printf purposes, returning
1560a492640SDavid Schultz  * a pointer to the first character of the string representation.
1570a492640SDavid Schultz  * Octal numbers can be forced to have a leading zero; hex numbers
1580a492640SDavid Schultz  * use the given digits.
1590a492640SDavid Schultz  */
1600a492640SDavid Schultz static CHAR *
1610a492640SDavid Schultz __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs,
1620a492640SDavid Schultz 	int needgrp, char thousep, const char *grp)
1630a492640SDavid Schultz {
1640a492640SDavid Schultz 	CHAR *cp = endp;
1650a492640SDavid Schultz 	long sval;
1660a492640SDavid Schultz 	int ndig;
1670a492640SDavid Schultz 
1680a492640SDavid Schultz 	/*
1690a492640SDavid Schultz 	 * Handle the three cases separately, in the hope of getting
1700a492640SDavid Schultz 	 * better/faster code.
1710a492640SDavid Schultz 	 */
1720a492640SDavid Schultz 	switch (base) {
1730a492640SDavid Schultz 	case 10:
1740a492640SDavid Schultz 		if (val < 10) {	/* many numbers are 1 digit */
1750a492640SDavid Schultz 			*--cp = to_char(val);
1760a492640SDavid Schultz 			return (cp);
1770a492640SDavid Schultz 		}
1780a492640SDavid Schultz 		ndig = 0;
1790a492640SDavid Schultz 		/*
1800a492640SDavid Schultz 		 * On many machines, unsigned arithmetic is harder than
1810a492640SDavid Schultz 		 * signed arithmetic, so we do at most one unsigned mod and
1820a492640SDavid Schultz 		 * divide; this is sufficient to reduce the range of
1830a492640SDavid Schultz 		 * the incoming value to where signed arithmetic works.
1840a492640SDavid Schultz 		 */
1850a492640SDavid Schultz 		if (val > LONG_MAX) {
1860a492640SDavid Schultz 			*--cp = to_char(val % 10);
1870a492640SDavid Schultz 			ndig++;
1880a492640SDavid Schultz 			sval = val / 10;
1890a492640SDavid Schultz 		} else
1900a492640SDavid Schultz 			sval = val;
1910a492640SDavid Schultz 		do {
1920a492640SDavid Schultz 			*--cp = to_char(sval % 10);
1930a492640SDavid Schultz 			ndig++;
1940a492640SDavid Schultz 			/*
1950a492640SDavid Schultz 			 * If (*grp == CHAR_MAX) then no more grouping
1960a492640SDavid Schultz 			 * should be performed.
1970a492640SDavid Schultz 			 */
1980a492640SDavid Schultz 			if (needgrp && ndig == *grp && *grp != CHAR_MAX
1990a492640SDavid Schultz 					&& sval > 9) {
2000a492640SDavid Schultz 				*--cp = thousep;
2010a492640SDavid Schultz 				ndig = 0;
2020a492640SDavid Schultz 				/*
2030a492640SDavid Schultz 				 * If (*(grp+1) == '\0') then we have to
2040a492640SDavid Schultz 				 * use *grp character (last grouping rule)
2050a492640SDavid Schultz 				 * for all next cases
2060a492640SDavid Schultz 				 */
2070a492640SDavid Schultz 				if (*(grp+1) != '\0')
2080a492640SDavid Schultz 					grp++;
2090a492640SDavid Schultz 			}
2100a492640SDavid Schultz 			sval /= 10;
2110a492640SDavid Schultz 		} while (sval != 0);
2120a492640SDavid Schultz 		break;
2130a492640SDavid Schultz 
2140a492640SDavid Schultz 	case 8:
2150a492640SDavid Schultz 		do {
2160a492640SDavid Schultz 			*--cp = to_char(val & 7);
2170a492640SDavid Schultz 			val >>= 3;
2180a492640SDavid Schultz 		} while (val);
2190a492640SDavid Schultz 		if (octzero && *cp != '0')
2200a492640SDavid Schultz 			*--cp = '0';
2210a492640SDavid Schultz 		break;
2220a492640SDavid Schultz 
2230a492640SDavid Schultz 	case 16:
2240a492640SDavid Schultz 		do {
2250a492640SDavid Schultz 			*--cp = xdigs[val & 15];
2260a492640SDavid Schultz 			val >>= 4;
2270a492640SDavid Schultz 		} while (val);
2280a492640SDavid Schultz 		break;
2290a492640SDavid Schultz 
2300a492640SDavid Schultz 	default:			/* oops */
2310a492640SDavid Schultz 		abort();
2320a492640SDavid Schultz 	}
2330a492640SDavid Schultz 	return (cp);
2340a492640SDavid Schultz }
2350a492640SDavid Schultz 
2360a492640SDavid Schultz /* Identical to __ultoa, but for intmax_t. */
2370a492640SDavid Schultz static CHAR *
2380a492640SDavid Schultz __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs,
2390a492640SDavid Schultz 	int needgrp, char thousep, const char *grp)
2400a492640SDavid Schultz {
2410a492640SDavid Schultz 	CHAR *cp = endp;
2420a492640SDavid Schultz 	intmax_t sval;
2430a492640SDavid Schultz 	int ndig;
2440a492640SDavid Schultz 
2450a492640SDavid Schultz 	/* quick test for small values; __ultoa is typically much faster */
2460a492640SDavid Schultz 	/* (perhaps instead we should run until small, then call __ultoa?) */
2470a492640SDavid Schultz 	if (val <= ULONG_MAX)
2480a492640SDavid Schultz 		return (__ultoa((u_long)val, endp, base, octzero, xdigs,
2490a492640SDavid Schultz 		    needgrp, thousep, grp));
2500a492640SDavid Schultz 	switch (base) {
2510a492640SDavid Schultz 	case 10:
2520a492640SDavid Schultz 		if (val < 10) {
2530a492640SDavid Schultz 			*--cp = to_char(val % 10);
2540a492640SDavid Schultz 			return (cp);
2550a492640SDavid Schultz 		}
2560a492640SDavid Schultz 		ndig = 0;
2570a492640SDavid Schultz 		if (val > INTMAX_MAX) {
2580a492640SDavid Schultz 			*--cp = to_char(val % 10);
2590a492640SDavid Schultz 			ndig++;
2600a492640SDavid Schultz 			sval = val / 10;
2610a492640SDavid Schultz 		} else
2620a492640SDavid Schultz 			sval = val;
2630a492640SDavid Schultz 		do {
2640a492640SDavid Schultz 			*--cp = to_char(sval % 10);
2650a492640SDavid Schultz 			ndig++;
2660a492640SDavid Schultz 			/*
2670a492640SDavid Schultz 			 * If (*grp == CHAR_MAX) then no more grouping
2680a492640SDavid Schultz 			 * should be performed.
2690a492640SDavid Schultz 			 */
2700a492640SDavid Schultz 			if (needgrp && *grp != CHAR_MAX && ndig == *grp
2710a492640SDavid Schultz 					&& sval > 9) {
2720a492640SDavid Schultz 				*--cp = thousep;
2730a492640SDavid Schultz 				ndig = 0;
2740a492640SDavid Schultz 				/*
2750a492640SDavid Schultz 				 * If (*(grp+1) == '\0') then we have to
2760a492640SDavid Schultz 				 * use *grp character (last grouping rule)
2770a492640SDavid Schultz 				 * for all next cases
2780a492640SDavid Schultz 				 */
2790a492640SDavid Schultz 				if (*(grp+1) != '\0')
2800a492640SDavid Schultz 					grp++;
2810a492640SDavid Schultz 			}
2820a492640SDavid Schultz 			sval /= 10;
2830a492640SDavid Schultz 		} while (sval != 0);
2840a492640SDavid Schultz 		break;
2850a492640SDavid Schultz 
2860a492640SDavid Schultz 	case 8:
2870a492640SDavid Schultz 		do {
2880a492640SDavid Schultz 			*--cp = to_char(val & 7);
2890a492640SDavid Schultz 			val >>= 3;
2900a492640SDavid Schultz 		} while (val);
2910a492640SDavid Schultz 		if (octzero && *cp != '0')
2920a492640SDavid Schultz 			*--cp = '0';
2930a492640SDavid Schultz 		break;
2940a492640SDavid Schultz 
2950a492640SDavid Schultz 	case 16:
2960a492640SDavid Schultz 		do {
2970a492640SDavid Schultz 			*--cp = xdigs[val & 15];
2980a492640SDavid Schultz 			val >>= 4;
2990a492640SDavid Schultz 		} while (val);
3000a492640SDavid Schultz 		break;
3010a492640SDavid Schultz 
3020a492640SDavid Schultz 	default:
3030a492640SDavid Schultz 		abort();
3040a492640SDavid Schultz 	}
3050a492640SDavid Schultz 	return (cp);
3060a492640SDavid Schultz }
3070a492640SDavid Schultz 
3080a492640SDavid Schultz #ifndef NO_FLOATING_POINT
3090a492640SDavid Schultz 
3100a492640SDavid Schultz static int
3110a492640SDavid Schultz exponent(CHAR *p0, int exp, CHAR fmtch)
3120a492640SDavid Schultz {
3130a492640SDavid Schultz 	CHAR *p, *t;
3140a492640SDavid Schultz 	CHAR expbuf[MAXEXPDIG];
3150a492640SDavid Schultz 
3160a492640SDavid Schultz 	p = p0;
3170a492640SDavid Schultz 	*p++ = fmtch;
3180a492640SDavid Schultz 	if (exp < 0) {
3190a492640SDavid Schultz 		exp = -exp;
3200a492640SDavid Schultz 		*p++ = '-';
3210a492640SDavid Schultz 	}
3220a492640SDavid Schultz 	else
3230a492640SDavid Schultz 		*p++ = '+';
3240a492640SDavid Schultz 	t = expbuf + MAXEXPDIG;
3250a492640SDavid Schultz 	if (exp > 9) {
3260a492640SDavid Schultz 		do {
3270a492640SDavid Schultz 			*--t = to_char(exp % 10);
3280a492640SDavid Schultz 		} while ((exp /= 10) > 9);
3290a492640SDavid Schultz 		*--t = to_char(exp);
3300a492640SDavid Schultz 		for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
3310a492640SDavid Schultz 	}
3320a492640SDavid Schultz 	else {
3330a492640SDavid Schultz 		/*
3340a492640SDavid Schultz 		 * Exponents for decimal floating point conversions
3350a492640SDavid Schultz 		 * (%[eEgG]) must be at least two characters long,
3360a492640SDavid Schultz 		 * whereas exponents for hexadecimal conversions can
3370a492640SDavid Schultz 		 * be only one character long.
3380a492640SDavid Schultz 		 */
3390a492640SDavid Schultz 		if (fmtch == 'e' || fmtch == 'E')
3400a492640SDavid Schultz 			*p++ = '0';
3410a492640SDavid Schultz 		*p++ = to_char(exp);
3420a492640SDavid Schultz 	}
3430a492640SDavid Schultz 	return (p - p0);
3440a492640SDavid Schultz }
3450a492640SDavid Schultz 
3460a492640SDavid Schultz #endif /* !NO_FLOATING_POINT */
347