158f0484fSRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
458f0484fSRodney W. Grimes * Copyright (c) 1990, 1993
558f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved.
658f0484fSRodney W. Grimes *
758f0484fSRodney W. Grimes * This code is derived from software contributed to Berkeley by
858f0484fSRodney W. Grimes * Chris Torek.
958f0484fSRodney W. Grimes *
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 *
1558f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without
1658f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions
1758f0484fSRodney W. Grimes * are met:
1858f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
1958f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer.
2058f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
2158f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
2258f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution.
231d8053c5SEd Maste * 3. Neither the name of the University nor the names of its contributors
2458f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software
2558f0484fSRodney W. Grimes * without specific prior written permission.
2658f0484fSRodney W. Grimes *
2758f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2858f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2958f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3058f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3158f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3258f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3358f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3458f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3558f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3658f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3758f0484fSRodney W. Grimes * SUCH DAMAGE.
3858f0484fSRodney W. Grimes */
3958f0484fSRodney W. Grimes
4058f0484fSRodney W. Grimes /*
4158f0484fSRodney W. Grimes * Actual printf innards.
4258f0484fSRodney W. Grimes *
4358f0484fSRodney W. Grimes * This code is large and complicated...
4458f0484fSRodney W. Grimes */
4558f0484fSRodney W. Grimes
46d201fe46SDaniel Eischen #include "namespace.h"
4758f0484fSRodney W. Grimes #include <sys/types.h>
4858f0484fSRodney W. Grimes
497735bb0fSBill Fenner #include <ctype.h>
50666d00d3SDavid Schultz #include <errno.h>
5158f0484fSRodney W. Grimes #include <limits.h>
527ae5c679SAlexey Zelkin #include <locale.h>
537735bb0fSBill Fenner #include <stddef.h>
547735bb0fSBill Fenner #include <stdint.h>
5558f0484fSRodney W. Grimes #include <stdio.h>
5658f0484fSRodney W. Grimes #include <stdlib.h>
5758f0484fSRodney W. Grimes #include <string.h>
58b9aac308STim J. Robbins #include <wchar.h>
5975067f4fSPoul-Henning Kamp #include <printf.h>
6058f0484fSRodney W. Grimes
6158f0484fSRodney W. Grimes #include <stdarg.h>
623c87aa1dSDavid Chisnall #include "xlocale_private.h"
63d201fe46SDaniel Eischen #include "un-namespace.h"
6458f0484fSRodney W. Grimes
65d201fe46SDaniel Eischen #include "libc_private.h"
6658f0484fSRodney W. Grimes #include "local.h"
6758f0484fSRodney W. Grimes #include "fvwrite.h"
682591efccSDavid Schultz #include "printflocal.h"
69e5abb5e6SDavid Schultz
703c87aa1dSDavid Chisnall static int __sprint(FILE *, struct __suio *, locale_t);
7174f1007fSDag-Erling Smørgrav static int __sbprintf(FILE *, locale_t, int, const char *, va_list)
7274f1007fSDag-Erling Smørgrav __printflike(4, 0)
73a1805f7bSDavid Schultz __noinline;
74b9aac308STim J. Robbins static char *__wcsconv(wchar_t *, int);
75ce51cf03SJames Raynard
76814d1bc9SDavid Schultz #define CHAR char
77814d1bc9SDavid Schultz #include "printfcommon.h"
78814d1bc9SDavid Schultz
7921ca178eSDavid Schultz struct grouping_state {
8021ca178eSDavid Schultz char *thousands_sep; /* locale-specific thousands separator */
8121ca178eSDavid Schultz int thousep_len; /* length of thousands_sep */
8221ca178eSDavid Schultz const char *grouping; /* locale-specific numeric grouping rules */
8321ca178eSDavid Schultz int lead; /* sig figs before decimal or group sep */
8421ca178eSDavid Schultz int nseps; /* number of group separators with ' */
8521ca178eSDavid Schultz int nrepeats; /* number of repeats of the last group */
8621ca178eSDavid Schultz };
8721ca178eSDavid Schultz
8821ca178eSDavid Schultz /*
8921ca178eSDavid Schultz * Initialize the thousands' grouping state in preparation to print a
9021ca178eSDavid Schultz * number with ndigits digits. This routine returns the total number
9121ca178eSDavid Schultz * of bytes that will be needed.
9221ca178eSDavid Schultz */
9321ca178eSDavid Schultz static int
grouping_init(struct grouping_state * gs,int ndigits,locale_t loc)943c87aa1dSDavid Chisnall grouping_init(struct grouping_state *gs, int ndigits, locale_t loc)
9521ca178eSDavid Schultz {
9621ca178eSDavid Schultz struct lconv *locale;
9721ca178eSDavid Schultz
983c87aa1dSDavid Chisnall locale = localeconv_l(loc);
9921ca178eSDavid Schultz gs->grouping = locale->grouping;
10021ca178eSDavid Schultz gs->thousands_sep = locale->thousands_sep;
10121ca178eSDavid Schultz gs->thousep_len = strlen(gs->thousands_sep);
10221ca178eSDavid Schultz
10321ca178eSDavid Schultz gs->nseps = gs->nrepeats = 0;
10421ca178eSDavid Schultz gs->lead = ndigits;
10521ca178eSDavid Schultz while (*gs->grouping != CHAR_MAX) {
10621ca178eSDavid Schultz if (gs->lead <= *gs->grouping)
10721ca178eSDavid Schultz break;
10821ca178eSDavid Schultz gs->lead -= *gs->grouping;
10921ca178eSDavid Schultz if (*(gs->grouping+1)) {
11021ca178eSDavid Schultz gs->nseps++;
11121ca178eSDavid Schultz gs->grouping++;
11221ca178eSDavid Schultz } else
11321ca178eSDavid Schultz gs->nrepeats++;
11421ca178eSDavid Schultz }
11521ca178eSDavid Schultz return ((gs->nseps + gs->nrepeats) * gs->thousep_len);
11621ca178eSDavid Schultz }
11721ca178eSDavid Schultz
11821ca178eSDavid Schultz /*
11921ca178eSDavid Schultz * Print a number with thousands' separators.
12021ca178eSDavid Schultz */
12121ca178eSDavid Schultz static int
grouping_print(struct grouping_state * gs,struct io_state * iop,const CHAR * cp,const CHAR * ep,locale_t locale)12221ca178eSDavid Schultz grouping_print(struct grouping_state *gs, struct io_state *iop,
1233c87aa1dSDavid Chisnall const CHAR *cp, const CHAR *ep, locale_t locale)
12421ca178eSDavid Schultz {
12521ca178eSDavid Schultz const CHAR *cp0 = cp;
12621ca178eSDavid Schultz
1273c87aa1dSDavid Chisnall if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
12821ca178eSDavid Schultz return (-1);
12921ca178eSDavid Schultz cp += gs->lead;
13021ca178eSDavid Schultz while (gs->nseps > 0 || gs->nrepeats > 0) {
13121ca178eSDavid Schultz if (gs->nrepeats > 0)
13221ca178eSDavid Schultz gs->nrepeats--;
13321ca178eSDavid Schultz else {
13421ca178eSDavid Schultz gs->grouping--;
13521ca178eSDavid Schultz gs->nseps--;
13621ca178eSDavid Schultz }
1373c87aa1dSDavid Chisnall if (io_print(iop, gs->thousands_sep, gs->thousep_len, locale))
13821ca178eSDavid Schultz return (-1);
1393c87aa1dSDavid Chisnall if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
14021ca178eSDavid Schultz return (-1);
14121ca178eSDavid Schultz cp += *gs->grouping;
14221ca178eSDavid Schultz }
14321ca178eSDavid Schultz if (cp > ep)
14421ca178eSDavid Schultz cp = ep;
14521ca178eSDavid Schultz return (cp - cp0);
14621ca178eSDavid Schultz }
14721ca178eSDavid Schultz
14858f0484fSRodney W. Grimes /*
14958f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio,
15058f0484fSRodney W. Grimes * then reset it so that it can be reused.
15158f0484fSRodney W. Grimes */
15258f0484fSRodney W. Grimes static int
__sprint(FILE * fp,struct __suio * uio,locale_t locale)1533c87aa1dSDavid Chisnall __sprint(FILE *fp, struct __suio *uio, locale_t locale)
15458f0484fSRodney W. Grimes {
155d201fe46SDaniel Eischen int err;
15658f0484fSRodney W. Grimes
15758f0484fSRodney W. Grimes if (uio->uio_resid == 0) {
15858f0484fSRodney W. Grimes uio->uio_iovcnt = 0;
15958f0484fSRodney W. Grimes return (0);
16058f0484fSRodney W. Grimes }
16158f0484fSRodney W. Grimes err = __sfvwrite(fp, uio);
16258f0484fSRodney W. Grimes uio->uio_resid = 0;
16358f0484fSRodney W. Grimes uio->uio_iovcnt = 0;
16458f0484fSRodney W. Grimes return (err);
16558f0484fSRodney W. Grimes }
16658f0484fSRodney W. Grimes
16758f0484fSRodney W. Grimes /*
16858f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a
16958f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids
17058f0484fSRodney W. Grimes * worries about ungetc buffers and so forth.
17158f0484fSRodney W. Grimes */
17258f0484fSRodney W. Grimes static int
__sbprintf(FILE * fp,locale_t locale,int serrno,const char * fmt,va_list ap)17374f1007fSDag-Erling Smørgrav __sbprintf(FILE *fp, locale_t locale, int serrno, const char *fmt, va_list ap)
17458f0484fSRodney W. Grimes {
17558f0484fSRodney W. Grimes int ret;
1761b0181dfSJohn Baldwin FILE fake = FAKE_FILE;
17758f0484fSRodney W. Grimes unsigned char buf[BUFSIZ];
17858f0484fSRodney W. Grimes
179a1805f7bSDavid Schultz /* XXX This is probably not needed. */
180a1805f7bSDavid Schultz if (prepwrite(fp) != 0)
181a1805f7bSDavid Schultz return (EOF);
182a1805f7bSDavid Schultz
18358f0484fSRodney W. Grimes /* copy the important variables */
18458f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF;
18558f0484fSRodney W. Grimes fake._file = fp->_file;
18658f0484fSRodney W. Grimes fake._cookie = fp->_cookie;
18758f0484fSRodney W. Grimes fake._write = fp->_write;
1881e98f887SJohn Baldwin fake._orientation = fp->_orientation;
1891e98f887SJohn Baldwin fake._mbstate = fp->_mbstate;
19058f0484fSRodney W. Grimes
19158f0484fSRodney W. Grimes /* set up the buffer */
19258f0484fSRodney W. Grimes fake._bf._base = fake._p = buf;
19358f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf);
19458f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */
19558f0484fSRodney W. Grimes
19658f0484fSRodney W. Grimes /* do the work, then copy any error status */
19774f1007fSDag-Erling Smørgrav ret = __vfprintf(&fake, locale, serrno, fmt, ap);
198d201fe46SDaniel Eischen if (ret >= 0 && __fflush(&fake))
19958f0484fSRodney W. Grimes ret = EOF;
20058f0484fSRodney W. Grimes if (fake._flags & __SERR)
20158f0484fSRodney W. Grimes fp->_flags |= __SERR;
20258f0484fSRodney W. Grimes return (ret);
20358f0484fSRodney W. Grimes }
20458f0484fSRodney W. Grimes
20558f0484fSRodney W. Grimes /*
206b9aac308STim J. Robbins * Convert a wide character string argument for the %ls format to a multibyte
207d48c77b5STim J. Robbins * string representation. If not -1, prec specifies the maximum number of
208d48c77b5STim J. Robbins * bytes to output, and also means that we can't assume that the wide char.
209d48c77b5STim J. Robbins * string ends is null-terminated.
210b9aac308STim J. Robbins */
211b9aac308STim J. Robbins static char *
__wcsconv(wchar_t * wcsarg,int prec)212b9aac308STim J. Robbins __wcsconv(wchar_t *wcsarg, int prec)
213b9aac308STim J. Robbins {
21493996f6dSTim J. Robbins static const mbstate_t initial;
21593996f6dSTim J. Robbins mbstate_t mbs;
216b9aac308STim J. Robbins char buf[MB_LEN_MAX];
217b9aac308STim J. Robbins wchar_t *p;
218d48c77b5STim J. Robbins char *convbuf;
219b9aac308STim J. Robbins size_t clen, nbytes;
220b9aac308STim J. Robbins
221d48c77b5STim J. Robbins /* Allocate space for the maximum number of bytes we could output. */
222d48c77b5STim J. Robbins if (prec < 0) {
223d48c77b5STim J. Robbins p = wcsarg;
224d48c77b5STim J. Robbins mbs = initial;
225d48c77b5STim J. Robbins nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
226d48c77b5STim J. Robbins if (nbytes == (size_t)-1)
227d48c77b5STim J. Robbins return (NULL);
228d48c77b5STim J. Robbins } else {
229b9aac308STim J. Robbins /*
230d48c77b5STim J. Robbins * Optimisation: if the output precision is small enough,
231d48c77b5STim J. Robbins * just allocate enough memory for the maximum instead of
232d48c77b5STim J. Robbins * scanning the string.
233b9aac308STim J. Robbins */
234d48c77b5STim J. Robbins if (prec < 128)
235d48c77b5STim J. Robbins nbytes = prec;
236d48c77b5STim J. Robbins else {
237b9aac308STim J. Robbins nbytes = 0;
238b9aac308STim J. Robbins p = wcsarg;
23993996f6dSTim J. Robbins mbs = initial;
240b9aac308STim J. Robbins for (;;) {
24193996f6dSTim J. Robbins clen = wcrtomb(buf, *p++, &mbs);
242b9aac308STim J. Robbins if (clen == 0 || clen == (size_t)-1 ||
243b9aac308STim J. Robbins nbytes + clen > prec)
244b9aac308STim J. Robbins break;
245b9aac308STim J. Robbins nbytes += clen;
246b9aac308STim J. Robbins }
247d48c77b5STim J. Robbins }
248b9aac308STim J. Robbins }
249b9aac308STim J. Robbins if ((convbuf = malloc(nbytes + 1)) == NULL)
250b9aac308STim J. Robbins return (NULL);
251b9aac308STim J. Robbins
252d48c77b5STim J. Robbins /* Fill the output buffer. */
253b9aac308STim J. Robbins p = wcsarg;
25493996f6dSTim J. Robbins mbs = initial;
255d48c77b5STim J. Robbins if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
256d48c77b5STim J. Robbins nbytes, &mbs)) == (size_t)-1) {
2576f098a48SAndrey A. Chernov free(convbuf);
258b9aac308STim J. Robbins return (NULL);
2596f098a48SAndrey A. Chernov }
260d48c77b5STim J. Robbins convbuf[nbytes] = '\0';
261b9aac308STim J. Robbins return (convbuf);
262b9aac308STim J. Robbins }
263b9aac308STim J. Robbins
264b9aac308STim J. Robbins /*
265d201fe46SDaniel Eischen * MT-safe version
266d201fe46SDaniel Eischen */
267d201fe46SDaniel Eischen int
vfprintf_l(FILE * __restrict fp,locale_t locale,const char * __restrict fmt0,va_list ap)2683c87aa1dSDavid Chisnall vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0,
2693c87aa1dSDavid Chisnall va_list ap)
270d201fe46SDaniel Eischen {
27174f1007fSDag-Erling Smørgrav int serrno = errno;
272d201fe46SDaniel Eischen int ret;
2733c87aa1dSDavid Chisnall FIX_LOCALE(locale);
274d201fe46SDaniel Eischen
275fda0a14fSKonstantin Belousov FLOCKFILE_CANCELSAFE(fp);
276a1805f7bSDavid Schultz /* optimise fprintf(stderr) (and other unbuffered Unix files) */
277a1805f7bSDavid Schultz if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
278a1805f7bSDavid Schultz fp->_file >= 0)
27974f1007fSDag-Erling Smørgrav ret = __sbprintf(fp, locale, serrno, fmt0, ap);
280a1805f7bSDavid Schultz else
28174f1007fSDag-Erling Smørgrav ret = __vfprintf(fp, locale, serrno, fmt0, ap);
282fda0a14fSKonstantin Belousov FUNLOCKFILE_CANCELSAFE();
283d201fe46SDaniel Eischen return (ret);
284d201fe46SDaniel Eischen }
2853c87aa1dSDavid Chisnall int
vfprintf(FILE * __restrict fp,const char * __restrict fmt0,va_list ap)2863c87aa1dSDavid Chisnall vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
2873c87aa1dSDavid Chisnall {
2883c87aa1dSDavid Chisnall return vfprintf_l(fp, __get_locale(), fmt0, ap);
2893c87aa1dSDavid Chisnall }
290d201fe46SDaniel Eischen
29138cac8f8SDavid Schultz /*
29238cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer
29321ca178eSDavid Schultz * conversions, among other things. We need enough space to
294*d4f9e326SAhmad Khalifa * write a uintmax_t in binary.
29538cac8f8SDavid Schultz */
296*d4f9e326SAhmad Khalifa #define BUF (sizeof(uintmax_t) * CHAR_BIT)
29738cac8f8SDavid Schultz
29858f0484fSRodney W. Grimes /*
299d201fe46SDaniel Eischen * Non-MT-safe version
300d201fe46SDaniel Eischen */
30158f0484fSRodney W. Grimes int
__vfprintf(FILE * fp,locale_t locale,int serrno,const char * fmt0,va_list ap)30274f1007fSDag-Erling Smørgrav __vfprintf(FILE *fp, locale_t locale, int serrno, const char *fmt0, va_list ap)
30358f0484fSRodney W. Grimes {
304d201fe46SDaniel Eischen char *fmt; /* format string */
305d201fe46SDaniel Eischen int ch; /* character from fmt */
306d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */
307d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */
308d201fe46SDaniel Eischen int flags; /* flags as above */
30958f0484fSRodney W. Grimes int ret; /* return value accumulator */
31058f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */
311ebbad5ecSDavid Schultz int prec; /* precision from format; <0 for N/A */
312f8876676SKonstantin Belousov int error;
313f8876676SKonstantin Belousov char errnomsg[NL_TEXTMAX];
31458f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */
31521ca178eSDavid Schultz struct grouping_state gs; /* thousands' grouping info */
316814d1bc9SDavid Schultz
3178de9e897SDavid Schultz #ifndef NO_FLOATING_POINT
318ebbad5ecSDavid Schultz /*
319ebbad5ecSDavid Schultz * We can decompose the printed representation of floating
320ebbad5ecSDavid Schultz * point numbers into several parts, some of which may be empty:
321ebbad5ecSDavid Schultz *
322ebbad5ecSDavid Schultz * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
323ebbad5ecSDavid Schultz * A B ---C--- D E F
324ebbad5ecSDavid Schultz *
325ebbad5ecSDavid Schultz * A: 'sign' holds this value if present; '\0' otherwise
326ebbad5ecSDavid Schultz * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
327ebbad5ecSDavid Schultz * C: cp points to the string MMMNNN. Leading and trailing
328ebbad5ecSDavid Schultz * zeros are not in the string and must be added.
329ebbad5ecSDavid Schultz * D: expchar holds this character; '\0' if no exponent, e.g. %f
330ebbad5ecSDavid Schultz * F: at least two digits for decimal, at least one digit for hex
331ebbad5ecSDavid Schultz */
3327ae5c679SAlexey Zelkin char *decimal_point; /* locale specific decimal point */
3335004a238SDavid Schultz int decpt_len; /* length of decimal_point */
334ebbad5ecSDavid Schultz int signflag; /* true if float is negative */
335ebbad5ecSDavid Schultz union { /* floating point arguments %[aAeEfFgG] */
336ebbad5ecSDavid Schultz double dbl;
337ebbad5ecSDavid Schultz long double ldbl;
338ebbad5ecSDavid Schultz } fparg;
33958f0484fSRodney W. Grimes int expt; /* integer value of exponent */
340ebbad5ecSDavid Schultz char expchar; /* exponent character: [eEpP\0] */
341ebbad5ecSDavid Schultz char *dtoaend; /* pointer to end of converted digits */
34258f0484fSRodney W. Grimes int expsize; /* character count for expstr */
343ebbad5ecSDavid Schultz int ndig; /* actual number of digits returned by dtoa */
344ebbad5ecSDavid Schultz char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
3452ffc61baSTor Egge char *dtoaresult; /* buffer allocated by dtoa */
34658f0484fSRodney W. Grimes #endif
34758f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */
3487735bb0fSBill Fenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
34958f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */
35058f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */
351261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */
35258f0484fSRodney W. Grimes int size; /* size of converted field or string */
35392e88f87SAndrey A. Chernov int prsize; /* max size of printed field */
354ebbad5ecSDavid Schultz const char *xdigs; /* digits for %[xX] conversion */
355814d1bc9SDavid Schultz struct io_state io; /* I/O buffering state */
35638cac8f8SDavid Schultz char buf[BUF]; /* buffer with space for digits of uintmax_t */
357ebbad5ecSDavid Schultz char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
358a387081cSDoug Rabson union arg *argtable; /* args, built due to positional arg */
359a387081cSDoug Rabson union arg statargtable [STATIC_ARG_TBL_SIZE];
360efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */
361efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */
362b9aac308STim J. Robbins char *convbuf; /* wide to multibyte conversion result */
3631bf6c5f1SAndrey A. Chernov int savserr;
36458f0484fSRodney W. Grimes
365ac9913a7SDavid Schultz static const char xdigs_lower[16] = "0123456789abcdef";
366ac9913a7SDavid Schultz static const char xdigs_upper[16] = "0123456789ABCDEF";
367ebbad5ecSDavid Schultz
368814d1bc9SDavid Schultz /* BEWARE, these `goto error' on error. */
36958f0484fSRodney W. Grimes #define PRINT(ptr, len) { \
3703c87aa1dSDavid Chisnall if (io_print(&io, (ptr), (len), locale)) \
37158f0484fSRodney W. Grimes goto error; \
37258f0484fSRodney W. Grimes }
37358f0484fSRodney W. Grimes #define PAD(howmany, with) { \
3743c87aa1dSDavid Chisnall if (io_pad(&io, (howmany), (with), locale)) \
37558f0484fSRodney W. Grimes goto error; \
376814d1bc9SDavid Schultz }
377814d1bc9SDavid Schultz #define PRINTANDPAD(p, ep, len, with) { \
3783c87aa1dSDavid Chisnall if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
379814d1bc9SDavid Schultz goto error; \
380814d1bc9SDavid Schultz }
381814d1bc9SDavid Schultz #define FLUSH() { \
3823c87aa1dSDavid Chisnall if (io_flush(&io, locale)) \
383814d1bc9SDavid Schultz goto error; \
38458f0484fSRodney W. Grimes }
38558f0484fSRodney W. Grimes
38658f0484fSRodney W. Grimes /*
387efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is
388efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next
389efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially).
390efb7e53dSJordan K. Hubbard */
391efb7e53dSJordan K. Hubbard #define GETARG(type) \
392a387081cSDoug Rabson ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
393efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type)))
394efb7e53dSJordan K. Hubbard
395efb7e53dSJordan K. Hubbard /*
39658f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned
39758f0484fSRodney W. Grimes * argument extraction methods.
39858f0484fSRodney W. Grimes */
39958f0484fSRodney W. Grimes #define SARG() \
400efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \
401efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \
4027735bb0fSBill Fenner flags&CHARINT ? (long)(signed char)GETARG(int) : \
403efb7e53dSJordan K. Hubbard (long)GETARG(int))
40458f0484fSRodney W. Grimes #define UARG() \
405efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \
406efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
4077735bb0fSBill Fenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
408efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int))
4097735bb0fSBill Fenner #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
4107735bb0fSBill Fenner #define SJARG() \
4117735bb0fSBill Fenner (flags&INTMAXT ? GETARG(intmax_t) : \
4120881683bSDavid Schultz flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
4137735bb0fSBill Fenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
4147735bb0fSBill Fenner (intmax_t)GETARG(long long))
4157735bb0fSBill Fenner #define UJARG() \
4167735bb0fSBill Fenner (flags&INTMAXT ? GETARG(uintmax_t) : \
4177735bb0fSBill Fenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \
4187735bb0fSBill Fenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
4197735bb0fSBill Fenner (uintmax_t)GETARG(unsigned long long))
420efb7e53dSJordan K. Hubbard
421efb7e53dSJordan K. Hubbard /*
422efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg
423efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined.
424efb7e53dSJordan K. Hubbard */
425efb7e53dSJordan K. Hubbard #define GETASTER(val) \
426efb7e53dSJordan K. Hubbard n2 = 0; \
427efb7e53dSJordan K. Hubbard cp = fmt; \
428efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \
429efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \
430efb7e53dSJordan K. Hubbard cp++; \
431efb7e53dSJordan K. Hubbard } \
432efb7e53dSJordan K. Hubbard if (*cp == '$') { \
433efb7e53dSJordan K. Hubbard int hold = nextarg; \
434efb7e53dSJordan K. Hubbard if (argtable == NULL) { \
435efb7e53dSJordan K. Hubbard argtable = statargtable; \
436e62e5ff9SDavid Schultz if (__find_arguments (fmt0, orgap, &argtable)) { \
437e62e5ff9SDavid Schultz ret = EOF; \
438e62e5ff9SDavid Schultz goto error; \
439e62e5ff9SDavid Schultz } \
440efb7e53dSJordan K. Hubbard } \
441efb7e53dSJordan K. Hubbard nextarg = n2; \
442efb7e53dSJordan K. Hubbard val = GETARG (int); \
443efb7e53dSJordan K. Hubbard nextarg = hold; \
444efb7e53dSJordan K. Hubbard fmt = ++cp; \
445efb7e53dSJordan K. Hubbard } else { \
446efb7e53dSJordan K. Hubbard val = GETARG (int); \
447efb7e53dSJordan K. Hubbard }
448efb7e53dSJordan K. Hubbard
44933bff5d3SDavid Schultz if (__use_xprintf > 0)
45033bff5d3SDavid Schultz return (__xvprintf(fp, fmt0, ap));
45158f0484fSRodney W. Grimes
45258f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
453450ead86SPedro F. Giffuni if (prepwrite(fp) != 0) {
454450ead86SPedro F. Giffuni errno = EBADF;
45558f0484fSRodney W. Grimes return (EOF);
456450ead86SPedro F. Giffuni }
45758f0484fSRodney W. Grimes
4581bf6c5f1SAndrey A. Chernov savserr = fp->_flags & __SERR;
4591bf6c5f1SAndrey A. Chernov fp->_flags &= ~__SERR;
4601bf6c5f1SAndrey A. Chernov
461e18701f4SDavid Schultz convbuf = NULL;
46258f0484fSRodney W. Grimes fmt = (char *)fmt0;
463efb7e53dSJordan K. Hubbard argtable = NULL;
464efb7e53dSJordan K. Hubbard nextarg = 1;
465d07090a8STim J. Robbins va_copy(orgap, ap);
466814d1bc9SDavid Schultz io_init(&io, fp);
46758f0484fSRodney W. Grimes ret = 0;
468e18701f4SDavid Schultz #ifndef NO_FLOATING_POINT
469e18701f4SDavid Schultz dtoaresult = NULL;
4703c87aa1dSDavid Chisnall decimal_point = localeconv_l(locale)->decimal_point;
4715004a238SDavid Schultz /* The overwhelmingly common case is decpt_len == 1. */
4725004a238SDavid Schultz decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
473e18701f4SDavid Schultz #endif
47458f0484fSRodney W. Grimes
47558f0484fSRodney W. Grimes /*
47658f0484fSRodney W. Grimes * Scan the format for conversions (`%' character).
47758f0484fSRodney W. Grimes */
47858f0484fSRodney W. Grimes for (;;) {
47958f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
48058f0484fSRodney W. Grimes /* void */;
48158f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) {
482b250f248SAndrey A. Chernov if ((unsigned)ret + n > INT_MAX) {
48392e88f87SAndrey A. Chernov ret = EOF;
484666d00d3SDavid Schultz errno = EOVERFLOW;
48592e88f87SAndrey A. Chernov goto error;
48692e88f87SAndrey A. Chernov }
48758f0484fSRodney W. Grimes PRINT(cp, n);
48858f0484fSRodney W. Grimes ret += n;
48958f0484fSRodney W. Grimes }
49058f0484fSRodney W. Grimes if (ch == '\0')
49158f0484fSRodney W. Grimes goto done;
49258f0484fSRodney W. Grimes fmt++; /* skip over '%' */
49358f0484fSRodney W. Grimes
49458f0484fSRodney W. Grimes flags = 0;
49558f0484fSRodney W. Grimes dprec = 0;
49658f0484fSRodney W. Grimes width = 0;
49758f0484fSRodney W. Grimes prec = -1;
49821ca178eSDavid Schultz gs.grouping = NULL;
49958f0484fSRodney W. Grimes sign = '\0';
500ebbad5ecSDavid Schultz ox[1] = '\0';
50158f0484fSRodney W. Grimes
50258f0484fSRodney W. Grimes rflag: ch = *fmt++;
50358f0484fSRodney W. Grimes reswitch: switch (ch) {
50458f0484fSRodney W. Grimes case ' ':
5052e394b2fSAlexey Zelkin /*-
50658f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space
50758f0484fSRodney W. Grimes * flag will be ignored.''
50858f0484fSRodney W. Grimes * -- ANSI X3J11
50958f0484fSRodney W. Grimes */
51058f0484fSRodney W. Grimes if (!sign)
51158f0484fSRodney W. Grimes sign = ' ';
51258f0484fSRodney W. Grimes goto rflag;
51358f0484fSRodney W. Grimes case '#':
51458f0484fSRodney W. Grimes flags |= ALT;
51558f0484fSRodney W. Grimes goto rflag;
51658f0484fSRodney W. Grimes case '*':
5172e394b2fSAlexey Zelkin /*-
51858f0484fSRodney W. Grimes * ``A negative field width argument is taken as a
51958f0484fSRodney W. Grimes * - flag followed by a positive field width.''
52058f0484fSRodney W. Grimes * -- ANSI X3J11
52158f0484fSRodney W. Grimes * They don't exclude field widths read from args.
52258f0484fSRodney W. Grimes */
523efb7e53dSJordan K. Hubbard GETASTER (width);
524efb7e53dSJordan K. Hubbard if (width >= 0)
52558f0484fSRodney W. Grimes goto rflag;
52658f0484fSRodney W. Grimes width = -width;
52758f0484fSRodney W. Grimes /* FALLTHROUGH */
52858f0484fSRodney W. Grimes case '-':
52958f0484fSRodney W. Grimes flags |= LADJUST;
53058f0484fSRodney W. Grimes goto rflag;
53158f0484fSRodney W. Grimes case '+':
53258f0484fSRodney W. Grimes sign = '+';
53358f0484fSRodney W. Grimes goto rflag;
5347735bb0fSBill Fenner case '\'':
53598ee7635SAlexey Zelkin flags |= GROUPING;
5367735bb0fSBill Fenner goto rflag;
53758f0484fSRodney W. Grimes case '.':
53858f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') {
5393b204b7dSDavid Schultz GETASTER (prec);
54058f0484fSRodney W. Grimes goto rflag;
54158f0484fSRodney W. Grimes }
5423b204b7dSDavid Schultz prec = 0;
54358f0484fSRodney W. Grimes while (is_digit(ch)) {
5443b204b7dSDavid Schultz prec = 10 * prec + to_digit(ch);
54558f0484fSRodney W. Grimes ch = *fmt++;
54658f0484fSRodney W. Grimes }
54758f0484fSRodney W. Grimes goto reswitch;
54858f0484fSRodney W. Grimes case '0':
5492e394b2fSAlexey Zelkin /*-
55058f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the
55158f0484fSRodney W. Grimes * beginning of a field width.''
55258f0484fSRodney W. Grimes * -- ANSI X3J11
55358f0484fSRodney W. Grimes */
55458f0484fSRodney W. Grimes flags |= ZEROPAD;
55558f0484fSRodney W. Grimes goto rflag;
55658f0484fSRodney W. Grimes case '1': case '2': case '3': case '4':
55758f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9':
55858f0484fSRodney W. Grimes n = 0;
55958f0484fSRodney W. Grimes do {
56058f0484fSRodney W. Grimes n = 10 * n + to_digit(ch);
56158f0484fSRodney W. Grimes ch = *fmt++;
56258f0484fSRodney W. Grimes } while (is_digit(ch));
563efb7e53dSJordan K. Hubbard if (ch == '$') {
564efb7e53dSJordan K. Hubbard nextarg = n;
565efb7e53dSJordan K. Hubbard if (argtable == NULL) {
566efb7e53dSJordan K. Hubbard argtable = statargtable;
567e62e5ff9SDavid Schultz if (__find_arguments (fmt0, orgap,
568e62e5ff9SDavid Schultz &argtable)) {
569e62e5ff9SDavid Schultz ret = EOF;
570e62e5ff9SDavid Schultz goto error;
571e62e5ff9SDavid Schultz }
572efb7e53dSJordan K. Hubbard }
573efb7e53dSJordan K. Hubbard goto rflag;
574efb7e53dSJordan K. Hubbard }
57558f0484fSRodney W. Grimes width = n;
57658f0484fSRodney W. Grimes goto reswitch;
5778de9e897SDavid Schultz #ifndef NO_FLOATING_POINT
57858f0484fSRodney W. Grimes case 'L':
57958f0484fSRodney W. Grimes flags |= LONGDBL;
58058f0484fSRodney W. Grimes goto rflag;
58158f0484fSRodney W. Grimes #endif
58258f0484fSRodney W. Grimes case 'h':
5837735bb0fSBill Fenner if (flags & SHORTINT) {
5847735bb0fSBill Fenner flags &= ~SHORTINT;
5857735bb0fSBill Fenner flags |= CHARINT;
5867735bb0fSBill Fenner } else
58758f0484fSRodney W. Grimes flags |= SHORTINT;
58858f0484fSRodney W. Grimes goto rflag;
5897735bb0fSBill Fenner case 'j':
5907735bb0fSBill Fenner flags |= INTMAXT;
5917735bb0fSBill Fenner goto rflag;
59258f0484fSRodney W. Grimes case 'l':
5937735bb0fSBill Fenner if (flags & LONGINT) {
5947735bb0fSBill Fenner flags &= ~LONGINT;
5957735bb0fSBill Fenner flags |= LLONGINT;
5967735bb0fSBill Fenner } else
59758f0484fSRodney W. Grimes flags |= LONGINT;
59858f0484fSRodney W. Grimes goto rflag;
59958f0484fSRodney W. Grimes case 'q':
6007735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */
6017735bb0fSBill Fenner goto rflag;
6027735bb0fSBill Fenner case 't':
6037735bb0fSBill Fenner flags |= PTRDIFFT;
6047735bb0fSBill Fenner goto rflag;
605bce0bef3SDag-Erling Smørgrav case 'w':
606bce0bef3SDag-Erling Smørgrav /*
607bce0bef3SDag-Erling Smørgrav * Fixed-width integer types. On all platforms we
608bce0bef3SDag-Erling Smørgrav * support, int8_t is equivalent to char, int16_t
609bce0bef3SDag-Erling Smørgrav * is equivalent to short, int32_t is equivalent
610bce0bef3SDag-Erling Smørgrav * to int, int64_t is equivalent to long long int.
611bce0bef3SDag-Erling Smørgrav * Furthermore, int_fast8_t, int_fast16_t and
612bce0bef3SDag-Erling Smørgrav * int_fast32_t are equivalent to int, and
613bce0bef3SDag-Erling Smørgrav * int_fast64_t is equivalent to long long int.
614bce0bef3SDag-Erling Smørgrav */
615bce0bef3SDag-Erling Smørgrav flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT);
616bce0bef3SDag-Erling Smørgrav if (fmt[0] == 'f') {
617bce0bef3SDag-Erling Smørgrav flags |= FASTINT;
618bce0bef3SDag-Erling Smørgrav fmt++;
619bce0bef3SDag-Erling Smørgrav } else {
620bce0bef3SDag-Erling Smørgrav flags &= ~FASTINT;
621bce0bef3SDag-Erling Smørgrav }
622bce0bef3SDag-Erling Smørgrav if (fmt[0] == '8') {
623bce0bef3SDag-Erling Smørgrav if (!(flags & FASTINT))
624bce0bef3SDag-Erling Smørgrav flags |= CHARINT;
625bce0bef3SDag-Erling Smørgrav else
626bce0bef3SDag-Erling Smørgrav /* no flag set = 32 */ ;
627bce0bef3SDag-Erling Smørgrav fmt += 1;
628bce0bef3SDag-Erling Smørgrav } else if (fmt[0] == '1' && fmt[1] == '6') {
629bce0bef3SDag-Erling Smørgrav if (!(flags & FASTINT))
630bce0bef3SDag-Erling Smørgrav flags |= SHORTINT;
631bce0bef3SDag-Erling Smørgrav else
632bce0bef3SDag-Erling Smørgrav /* no flag set = 32 */ ;
633bce0bef3SDag-Erling Smørgrav fmt += 2;
634bce0bef3SDag-Erling Smørgrav } else if (fmt[0] == '3' && fmt[1] == '2') {
635bce0bef3SDag-Erling Smørgrav /* no flag set = 32 */ ;
636bce0bef3SDag-Erling Smørgrav fmt += 2;
637bce0bef3SDag-Erling Smørgrav } else if (fmt[0] == '6' && fmt[1] == '4') {
638bce0bef3SDag-Erling Smørgrav flags |= LLONGINT;
639bce0bef3SDag-Erling Smørgrav fmt += 2;
640bce0bef3SDag-Erling Smørgrav } else {
641bce0bef3SDag-Erling Smørgrav if (flags & FASTINT) {
642bce0bef3SDag-Erling Smørgrav flags &= ~FASTINT;
643bce0bef3SDag-Erling Smørgrav fmt--;
644bce0bef3SDag-Erling Smørgrav }
645bce0bef3SDag-Erling Smørgrav goto invalid;
646bce0bef3SDag-Erling Smørgrav }
647bce0bef3SDag-Erling Smørgrav goto rflag;
6487735bb0fSBill Fenner case 'z':
6497735bb0fSBill Fenner flags |= SIZET;
65058f0484fSRodney W. Grimes goto rflag;
651d9dc1603SDag-Erling Smørgrav case 'B':
652d9dc1603SDag-Erling Smørgrav case 'b':
653d9dc1603SDag-Erling Smørgrav if (flags & INTMAX_SIZE)
654d9dc1603SDag-Erling Smørgrav ujval = UJARG();
655d9dc1603SDag-Erling Smørgrav else
656d9dc1603SDag-Erling Smørgrav ulval = UARG();
657d9dc1603SDag-Erling Smørgrav base = 2;
658d9dc1603SDag-Erling Smørgrav /* leading 0b/B only if non-zero */
659d9dc1603SDag-Erling Smørgrav if (flags & ALT &&
660d9dc1603SDag-Erling Smørgrav (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
661d9dc1603SDag-Erling Smørgrav ox[1] = ch;
662d9dc1603SDag-Erling Smørgrav goto nosign;
663d9dc1603SDag-Erling Smørgrav break;
664927ecbf3STim J. Robbins case 'C':
665927ecbf3STim J. Robbins flags |= LONGINT;
666927ecbf3STim J. Robbins /*FALLTHROUGH*/
66758f0484fSRodney W. Grimes case 'c':
668b9aac308STim J. Robbins if (flags & LONGINT) {
66993996f6dSTim J. Robbins static const mbstate_t initial;
67093996f6dSTim J. Robbins mbstate_t mbs;
671b9aac308STim J. Robbins size_t mbseqlen;
672b9aac308STim J. Robbins
67393996f6dSTim J. Robbins mbs = initial;
674b9aac308STim J. Robbins mbseqlen = wcrtomb(cp = buf,
67593996f6dSTim J. Robbins (wchar_t)GETARG(wint_t), &mbs);
6766180233fSTim J. Robbins if (mbseqlen == (size_t)-1) {
6776180233fSTim J. Robbins fp->_flags |= __SERR;
678b9aac308STim J. Robbins goto error;
6796180233fSTim J. Robbins }
680b9aac308STim J. Robbins size = (int)mbseqlen;
681b9aac308STim J. Robbins } else {
682efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int);
68358f0484fSRodney W. Grimes size = 1;
684b9aac308STim J. Robbins }
68558f0484fSRodney W. Grimes sign = '\0';
68658f0484fSRodney W. Grimes break;
68758f0484fSRodney W. Grimes case 'D':
68858f0484fSRodney W. Grimes flags |= LONGINT;
68958f0484fSRodney W. Grimes /*FALLTHROUGH*/
69058f0484fSRodney W. Grimes case 'd':
69158f0484fSRodney W. Grimes case 'i':
6927735bb0fSBill Fenner if (flags & INTMAX_SIZE) {
6937735bb0fSBill Fenner ujval = SJARG();
6947735bb0fSBill Fenner if ((intmax_t)ujval < 0) {
6957735bb0fSBill Fenner ujval = -ujval;
69658f0484fSRodney W. Grimes sign = '-';
69758f0484fSRodney W. Grimes }
69858f0484fSRodney W. Grimes } else {
69958f0484fSRodney W. Grimes ulval = SARG();
70058f0484fSRodney W. Grimes if ((long)ulval < 0) {
70158f0484fSRodney W. Grimes ulval = -ulval;
70258f0484fSRodney W. Grimes sign = '-';
70358f0484fSRodney W. Grimes }
70458f0484fSRodney W. Grimes }
70558f0484fSRodney W. Grimes base = 10;
70658f0484fSRodney W. Grimes goto number;
7078de9e897SDavid Schultz #ifndef NO_FLOATING_POINT
7087735bb0fSBill Fenner case 'a':
7097735bb0fSBill Fenner case 'A':
710ebbad5ecSDavid Schultz if (ch == 'a') {
711ebbad5ecSDavid Schultz ox[1] = 'x';
712ebbad5ecSDavid Schultz xdigs = xdigs_lower;
713ebbad5ecSDavid Schultz expchar = 'p';
714ebbad5ecSDavid Schultz } else {
715ebbad5ecSDavid Schultz ox[1] = 'X';
716ebbad5ecSDavid Schultz xdigs = xdigs_upper;
717ebbad5ecSDavid Schultz expchar = 'P';
718ebbad5ecSDavid Schultz }
719904322a5SDavid Schultz if (prec >= 0)
720904322a5SDavid Schultz prec++;
721904322a5SDavid Schultz if (dtoaresult != NULL)
722904322a5SDavid Schultz freedtoa(dtoaresult);
723ebbad5ecSDavid Schultz if (flags & LONGDBL) {
724904322a5SDavid Schultz fparg.ldbl = GETARG(long double);
725ebbad5ecSDavid Schultz dtoaresult = cp =
726ebbad5ecSDavid Schultz __hldtoa(fparg.ldbl, xdigs, prec,
727ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend);
728ebbad5ecSDavid Schultz } else {
729ebbad5ecSDavid Schultz fparg.dbl = GETARG(double);
730ebbad5ecSDavid Schultz dtoaresult = cp =
731ebbad5ecSDavid Schultz __hdtoa(fparg.dbl, xdigs, prec,
732ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend);
733ebbad5ecSDavid Schultz }
734904322a5SDavid Schultz if (prec < 0)
735904322a5SDavid Schultz prec = dtoaend - cp;
736904322a5SDavid Schultz if (expt == INT_MAX)
737904322a5SDavid Schultz ox[1] = '\0';
738904322a5SDavid Schultz goto fp_common;
739d26be6f0SBruce Evans case 'e':
74058f0484fSRodney W. Grimes case 'E':
741ebbad5ecSDavid Schultz expchar = ch;
742ebbad5ecSDavid Schultz if (prec < 0) /* account for digit before decpt */
743ebbad5ecSDavid Schultz prec = DEFPREC + 1;
744ebbad5ecSDavid Schultz else
745ebbad5ecSDavid Schultz prec++;
746ebbad5ecSDavid Schultz goto fp_begin;
747d26be6f0SBruce Evans case 'f':
7487735bb0fSBill Fenner case 'F':
749ebbad5ecSDavid Schultz expchar = '\0';
750d26be6f0SBruce Evans goto fp_begin;
75158f0484fSRodney W. Grimes case 'g':
75258f0484fSRodney W. Grimes case 'G':
753ebbad5ecSDavid Schultz expchar = ch - ('g' - 'e');
754d26be6f0SBruce Evans if (prec == 0)
755d26be6f0SBruce Evans prec = 1;
756ebbad5ecSDavid Schultz fp_begin:
757ebbad5ecSDavid Schultz if (prec < 0)
75858f0484fSRodney W. Grimes prec = DEFPREC;
759ebbad5ecSDavid Schultz if (dtoaresult != NULL)
760ebbad5ecSDavid Schultz freedtoa(dtoaresult);
761ebbad5ecSDavid Schultz if (flags & LONGDBL) {
762ebbad5ecSDavid Schultz fparg.ldbl = GETARG(long double);
763ebbad5ecSDavid Schultz dtoaresult = cp =
764ebbad5ecSDavid Schultz __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
765ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend);
766ebbad5ecSDavid Schultz } else {
767ebbad5ecSDavid Schultz fparg.dbl = GETARG(double);
768ebbad5ecSDavid Schultz dtoaresult = cp =
769ebbad5ecSDavid Schultz dtoa(fparg.dbl, expchar ? 2 : 3, prec,
770ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend);
771ebbad5ecSDavid Schultz if (expt == 9999)
772ebbad5ecSDavid Schultz expt = INT_MAX;
77358f0484fSRodney W. Grimes }
774904322a5SDavid Schultz fp_common:
775ebbad5ecSDavid Schultz if (signflag)
776ebbad5ecSDavid Schultz sign = '-';
777ebbad5ecSDavid Schultz if (expt == INT_MAX) { /* inf or nan */
778ebbad5ecSDavid Schultz if (*cp == 'N') {
779ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "nan" : "NAN";
780ebbad5ecSDavid Schultz sign = '\0';
781ebbad5ecSDavid Schultz } else
782ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "inf" : "INF";
78358f0484fSRodney W. Grimes size = 3;
784970a466cSDavid Schultz flags &= ~ZEROPAD;
78558f0484fSRodney W. Grimes break;
78658f0484fSRodney W. Grimes }
78758f0484fSRodney W. Grimes flags |= FPT;
788ebbad5ecSDavid Schultz ndig = dtoaend - cp;
78958f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') {
790ebbad5ecSDavid Schultz if (expt > -4 && expt <= prec) {
791ebbad5ecSDavid Schultz /* Make %[gG] smell like %[fF] */
792ebbad5ecSDavid Schultz expchar = '\0';
793ebbad5ecSDavid Schultz if (flags & ALT)
794ebbad5ecSDavid Schultz prec -= expt;
79558f0484fSRodney W. Grimes else
796ebbad5ecSDavid Schultz prec = ndig - expt;
797ebbad5ecSDavid Schultz if (prec < 0)
798ebbad5ecSDavid Schultz prec = 0;
7991f2a0cdfSDavid Schultz } else {
8001f2a0cdfSDavid Schultz /*
8011f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but
8021f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag.
8031f2a0cdfSDavid Schultz */
8041f2a0cdfSDavid Schultz if (!(flags & ALT))
8051f2a0cdfSDavid Schultz prec = ndig;
80658f0484fSRodney W. Grimes }
807ebbad5ecSDavid Schultz }
808ebbad5ecSDavid Schultz if (expchar) {
809ebbad5ecSDavid Schultz expsize = exponent(expstr, expt - 1, expchar);
810ebbad5ecSDavid Schultz size = expsize + prec;
8113b204b7dSDavid Schultz if (prec > 1 || flags & ALT)
8125004a238SDavid Schultz size += decpt_len;
813ebbad5ecSDavid Schultz } else {
81481ae2e9aSDavid Schultz /* space for digits before decimal point */
81581ae2e9aSDavid Schultz if (expt > 0)
81658f0484fSRodney W. Grimes size = expt;
81781ae2e9aSDavid Schultz else /* "0" */
81881ae2e9aSDavid Schultz size = 1;
81981ae2e9aSDavid Schultz /* space for decimal pt and following digits */
82058f0484fSRodney W. Grimes if (prec || flags & ALT)
8215004a238SDavid Schultz size += prec + decpt_len;
82221ca178eSDavid Schultz if ((flags & GROUPING) && expt > 0)
8233c87aa1dSDavid Chisnall size += grouping_init(&gs, expt, locale);
824ebbad5ecSDavid Schultz }
82558f0484fSRodney W. Grimes break;
8268de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */
827e95725feSKonstantin Belousov case 'm':
82874f1007fSDag-Erling Smørgrav error = __strerror_rl(serrno, errnomsg,
829f8876676SKonstantin Belousov sizeof(errnomsg), locale);
830f8876676SKonstantin Belousov cp = error == 0 ? errnomsg : "<strerror failure>";
831e95725feSKonstantin Belousov size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
832e95725feSKonstantin Belousov sign = '\0';
833e95725feSKonstantin Belousov break;
83458f0484fSRodney W. Grimes case 'n':
8357735bb0fSBill Fenner /*
8367735bb0fSBill Fenner * Assignment-like behavior is specified if the
8377735bb0fSBill Fenner * value overflows or is otherwise unrepresentable.
8387735bb0fSBill Fenner * C99 says to use `signed char' for %hhn conversions.
8397735bb0fSBill Fenner */
8407735bb0fSBill Fenner if (flags & LLONGINT)
8417735bb0fSBill Fenner *GETARG(long long *) = ret;
8427735bb0fSBill Fenner else if (flags & SIZET)
8437735bb0fSBill Fenner *GETARG(ssize_t *) = (ssize_t)ret;
8447735bb0fSBill Fenner else if (flags & PTRDIFFT)
8457735bb0fSBill Fenner *GETARG(ptrdiff_t *) = ret;
8467735bb0fSBill Fenner else if (flags & INTMAXT)
8477735bb0fSBill Fenner *GETARG(intmax_t *) = ret;
84858f0484fSRodney W. Grimes else if (flags & LONGINT)
8496e690ad4SAndrey A. Chernov *GETARG(long *) = ret;
85058f0484fSRodney W. Grimes else if (flags & SHORTINT)
8516e690ad4SAndrey A. Chernov *GETARG(short *) = ret;
8527735bb0fSBill Fenner else if (flags & CHARINT)
8537735bb0fSBill Fenner *GETARG(signed char *) = ret;
85458f0484fSRodney W. Grimes else
8556e690ad4SAndrey A. Chernov *GETARG(int *) = ret;
85658f0484fSRodney W. Grimes continue; /* no output */
85758f0484fSRodney W. Grimes case 'O':
85858f0484fSRodney W. Grimes flags |= LONGINT;
85958f0484fSRodney W. Grimes /*FALLTHROUGH*/
86058f0484fSRodney W. Grimes case 'o':
8617735bb0fSBill Fenner if (flags & INTMAX_SIZE)
8627735bb0fSBill Fenner ujval = UJARG();
86358f0484fSRodney W. Grimes else
86458f0484fSRodney W. Grimes ulval = UARG();
86558f0484fSRodney W. Grimes base = 8;
86658f0484fSRodney W. Grimes goto nosign;
86758f0484fSRodney W. Grimes case 'p':
8682e394b2fSAlexey Zelkin /*-
86958f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The
87058f0484fSRodney W. Grimes * value of the pointer is converted to a sequence
87158f0484fSRodney W. Grimes * of printable characters, in an implementation-
87258f0484fSRodney W. Grimes * defined manner.''
87358f0484fSRodney W. Grimes * -- ANSI X3J11
87458f0484fSRodney W. Grimes */
8757735bb0fSBill Fenner ujval = (uintmax_t)(uintptr_t)GETARG(void *);
87658f0484fSRodney W. Grimes base = 16;
877ebbad5ecSDavid Schultz xdigs = xdigs_lower;
878ebbad5ecSDavid Schultz flags = flags | INTMAXT;
879ebbad5ecSDavid Schultz ox[1] = 'x';
88058f0484fSRodney W. Grimes goto nosign;
881927ecbf3STim J. Robbins case 'S':
882927ecbf3STim J. Robbins flags |= LONGINT;
883927ecbf3STim J. Robbins /*FALLTHROUGH*/
88458f0484fSRodney W. Grimes case 's':
885b9aac308STim J. Robbins if (flags & LONGINT) {
886b9aac308STim J. Robbins wchar_t *wcp;
887b9aac308STim J. Robbins
888b9aac308STim J. Robbins if (convbuf != NULL)
889b9aac308STim J. Robbins free(convbuf);
890b9aac308STim J. Robbins if ((wcp = GETARG(wchar_t *)) == NULL)
891b9aac308STim J. Robbins cp = "(null)";
892b9aac308STim J. Robbins else {
893b9aac308STim J. Robbins convbuf = __wcsconv(wcp, prec);
8946180233fSTim J. Robbins if (convbuf == NULL) {
8956180233fSTim J. Robbins fp->_flags |= __SERR;
896b9aac308STim J. Robbins goto error;
8976180233fSTim J. Robbins }
898b9aac308STim J. Robbins cp = convbuf;
899b9aac308STim J. Robbins }
900b9aac308STim J. Robbins } else if ((cp = GETARG(char *)) == NULL)
90158f0484fSRodney W. Grimes cp = "(null)";
902353ce11cSDavid Schultz size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
90358f0484fSRodney W. Grimes sign = '\0';
90458f0484fSRodney W. Grimes break;
90558f0484fSRodney W. Grimes case 'U':
90658f0484fSRodney W. Grimes flags |= LONGINT;
90758f0484fSRodney W. Grimes /*FALLTHROUGH*/
90858f0484fSRodney W. Grimes case 'u':
9097735bb0fSBill Fenner if (flags & INTMAX_SIZE)
9107735bb0fSBill Fenner ujval = UJARG();
91158f0484fSRodney W. Grimes else
91258f0484fSRodney W. Grimes ulval = UARG();
91358f0484fSRodney W. Grimes base = 10;
91458f0484fSRodney W. Grimes goto nosign;
91558f0484fSRodney W. Grimes case 'X':
916ebbad5ecSDavid Schultz xdigs = xdigs_upper;
91758f0484fSRodney W. Grimes goto hex;
91858f0484fSRodney W. Grimes case 'x':
919ebbad5ecSDavid Schultz xdigs = xdigs_lower;
9207735bb0fSBill Fenner hex:
9217735bb0fSBill Fenner if (flags & INTMAX_SIZE)
9227735bb0fSBill Fenner ujval = UJARG();
92358f0484fSRodney W. Grimes else
92458f0484fSRodney W. Grimes ulval = UARG();
92558f0484fSRodney W. Grimes base = 16;
92658f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */
92758f0484fSRodney W. Grimes if (flags & ALT &&
9287735bb0fSBill Fenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
929ebbad5ecSDavid Schultz ox[1] = ch;
93058f0484fSRodney W. Grimes
93198ee7635SAlexey Zelkin flags &= ~GROUPING;
93258f0484fSRodney W. Grimes /* unsigned conversions */
93358f0484fSRodney W. Grimes nosign: sign = '\0';
9342e394b2fSAlexey Zelkin /*-
93558f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is
93658f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.''
93758f0484fSRodney W. Grimes * -- ANSI X3J11
93858f0484fSRodney W. Grimes */
93958f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0)
94058f0484fSRodney W. Grimes flags &= ~ZEROPAD;
94158f0484fSRodney W. Grimes
9422e394b2fSAlexey Zelkin /*-
94358f0484fSRodney W. Grimes * ``The result of converting a zero value with an
94458f0484fSRodney W. Grimes * explicit precision of zero is no characters.''
94558f0484fSRodney W. Grimes * -- ANSI X3J11
9461be5319aSDavid Schultz *
9471be5319aSDavid Schultz * ``The C Standard is clear enough as is. The call
9481be5319aSDavid Schultz * printf("%#.0o", 0) should print 0.''
9491be5319aSDavid Schultz * -- Defect Report #151
95058f0484fSRodney W. Grimes */
95158f0484fSRodney W. Grimes cp = buf + BUF;
9527735bb0fSBill Fenner if (flags & INTMAX_SIZE) {
9531be5319aSDavid Schultz if (ujval != 0 || prec != 0 ||
9541be5319aSDavid Schultz (flags & ALT && base == 8))
9557735bb0fSBill Fenner cp = __ujtoa(ujval, cp, base,
95621ca178eSDavid Schultz flags & ALT, xdigs);
95758f0484fSRodney W. Grimes } else {
9581be5319aSDavid Schultz if (ulval != 0 || prec != 0 ||
9591be5319aSDavid Schultz (flags & ALT && base == 8))
96058f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base,
96121ca178eSDavid Schultz flags & ALT, xdigs);
96258f0484fSRodney W. Grimes }
96358f0484fSRodney W. Grimes size = buf + BUF - cp;
96438cac8f8SDavid Schultz if (size > BUF) /* should never happen */
96538cac8f8SDavid Schultz abort();
96621ca178eSDavid Schultz if ((flags & GROUPING) && size != 0)
9673c87aa1dSDavid Chisnall size += grouping_init(&gs, size, locale);
96858f0484fSRodney W. Grimes break;
96958f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */
97058f0484fSRodney W. Grimes if (ch == '\0')
97158f0484fSRodney W. Grimes goto done;
972bce0bef3SDag-Erling Smørgrav invalid:
97358f0484fSRodney W. Grimes /* pretend it was %c with argument ch */
97458f0484fSRodney W. Grimes cp = buf;
97558f0484fSRodney W. Grimes *cp = ch;
97658f0484fSRodney W. Grimes size = 1;
97758f0484fSRodney W. Grimes sign = '\0';
97858f0484fSRodney W. Grimes break;
97958f0484fSRodney W. Grimes }
98058f0484fSRodney W. Grimes
98158f0484fSRodney W. Grimes /*
98258f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp'
98358f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be
98458f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should
98558f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise,
98658f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted.
98758f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes
98858f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the
98958f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover
99058f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks.
99158f0484fSRodney W. Grimes *
99258f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad.
993261a532aSBill Fenner * size excludes decimal prec; realsz includes it.
99458f0484fSRodney W. Grimes */
995261a532aSBill Fenner realsz = dprec > size ? dprec : size;
99658f0484fSRodney W. Grimes if (sign)
997261a532aSBill Fenner realsz++;
998904322a5SDavid Schultz if (ox[1])
999261a532aSBill Fenner realsz += 2;
100058f0484fSRodney W. Grimes
100192e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz;
1002b250f248SAndrey A. Chernov if ((unsigned)ret + prsize > INT_MAX) {
100392e88f87SAndrey A. Chernov ret = EOF;
1004666d00d3SDavid Schultz errno = EOVERFLOW;
100592e88f87SAndrey A. Chernov goto error;
100692e88f87SAndrey A. Chernov }
100792e88f87SAndrey A. Chernov
100858f0484fSRodney W. Grimes /* right-adjusting blank padding */
100958f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0)
101058f0484fSRodney W. Grimes PAD(width - realsz, blanks);
101158f0484fSRodney W. Grimes
101258f0484fSRodney W. Grimes /* prefix */
1013904322a5SDavid Schultz if (sign)
101458f0484fSRodney W. Grimes PRINT(&sign, 1);
1015904322a5SDavid Schultz
1016904322a5SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */
101758f0484fSRodney W. Grimes ox[0] = '0';
101858f0484fSRodney W. Grimes PRINT(ox, 2);
101958f0484fSRodney W. Grimes }
102058f0484fSRodney W. Grimes
102158f0484fSRodney W. Grimes /* right-adjusting zero padding */
102258f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
102358f0484fSRodney W. Grimes PAD(width - realsz, zeroes);
102458f0484fSRodney W. Grimes
102558f0484fSRodney W. Grimes /* the string or number proper */
10268de9e897SDavid Schultz #ifndef NO_FLOATING_POINT
102758f0484fSRodney W. Grimes if ((flags & FPT) == 0) {
102821ca178eSDavid Schultz #endif
102921ca178eSDavid Schultz /* leading zeroes from decimal precision */
103021ca178eSDavid Schultz PAD(dprec - size, zeroes);
103121ca178eSDavid Schultz if (gs.grouping) {
10323c87aa1dSDavid Chisnall if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
103321ca178eSDavid Schultz goto error;
103421ca178eSDavid Schultz } else {
103558f0484fSRodney W. Grimes PRINT(cp, size);
103621ca178eSDavid Schultz }
103721ca178eSDavid Schultz #ifndef NO_FLOATING_POINT
103858f0484fSRodney W. Grimes } else { /* glue together f_p fragments */
1039ebbad5ecSDavid Schultz if (!expchar) { /* %[fF] or sufficiently short %[gG] */
1040ebbad5ecSDavid Schultz if (expt <= 0) {
104181ae2e9aSDavid Schultz PRINT(zeroes, 1);
104281ae2e9aSDavid Schultz if (prec || flags & ALT)
10435004a238SDavid Schultz PRINT(decimal_point,decpt_len);
104458f0484fSRodney W. Grimes PAD(-expt, zeroes);
10453b204b7dSDavid Schultz /* already handled initial 0's */
10463b204b7dSDavid Schultz prec += expt;
104758f0484fSRodney W. Grimes } else {
104821ca178eSDavid Schultz if (gs.grouping) {
104921ca178eSDavid Schultz n = grouping_print(&gs, &io,
10503c87aa1dSDavid Chisnall cp, dtoaend, locale);
105121ca178eSDavid Schultz if (n < 0)
105221ca178eSDavid Schultz goto error;
105321ca178eSDavid Schultz cp += n;
105421ca178eSDavid Schultz } else {
10553b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend,
105621ca178eSDavid Schultz expt, zeroes);
105721ca178eSDavid Schultz cp += expt;
1058ebbad5ecSDavid Schultz }
1059ebbad5ecSDavid Schultz if (prec || flags & ALT)
10605004a238SDavid Schultz PRINT(decimal_point,decpt_len);
1061ebbad5ecSDavid Schultz }
10623b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend, prec, zeroes);
1063ebbad5ecSDavid Schultz } else { /* %[eE] or sufficiently long %[gG] */
10643b204b7dSDavid Schultz if (prec > 1 || flags & ALT) {
10655004a238SDavid Schultz PRINT(cp++, 1);
10665004a238SDavid Schultz PRINT(decimal_point, decpt_len);
106758f0484fSRodney W. Grimes PRINT(cp, ndig-1);
1068ebbad5ecSDavid Schultz PAD(prec - ndig, zeroes);
106958f0484fSRodney W. Grimes } else /* XeYYY */
107058f0484fSRodney W. Grimes PRINT(cp, 1);
107158f0484fSRodney W. Grimes PRINT(expstr, expsize);
107258f0484fSRodney W. Grimes }
107358f0484fSRodney W. Grimes }
107458f0484fSRodney W. Grimes #endif
107558f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */
107658f0484fSRodney W. Grimes if (flags & LADJUST)
107758f0484fSRodney W. Grimes PAD(width - realsz, blanks);
107858f0484fSRodney W. Grimes
107958f0484fSRodney W. Grimes /* finally, adjust ret */
108092e88f87SAndrey A. Chernov ret += prsize;
108158f0484fSRodney W. Grimes
108258f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */
108358f0484fSRodney W. Grimes }
108458f0484fSRodney W. Grimes done:
108558f0484fSRodney W. Grimes FLUSH();
108658f0484fSRodney W. Grimes error:
1087096ad104SDag-Erling Smørgrav va_end(orgap);
10888de9e897SDavid Schultz #ifndef NO_FLOATING_POINT
10892ffc61baSTor Egge if (dtoaresult != NULL)
1090ebbad5ecSDavid Schultz freedtoa(dtoaresult);
10912ffc61baSTor Egge #endif
1092b9aac308STim J. Robbins if (convbuf != NULL)
1093b9aac308STim J. Robbins free(convbuf);
1094f70177e7SJulian Elischer if (__sferror(fp))
1095f70177e7SJulian Elischer ret = EOF;
10961bf6c5f1SAndrey A. Chernov else
10971bf6c5f1SAndrey A. Chernov fp->_flags |= savserr;
1098efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable))
1099efb7e53dSJordan K. Hubbard free (argtable);
1100f70177e7SJulian Elischer return (ret);
110158f0484fSRodney W. Grimes /* NOTREACHED */
110258f0484fSRodney W. Grimes }
110358f0484fSRodney W. Grimes
1104