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); 713c87aa1dSDavid Chisnall static int __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0) 72a1805f7bSDavid Schultz __noinline; 73b9aac308STim J. Robbins static char *__wcsconv(wchar_t *, int); 74ce51cf03SJames Raynard 75814d1bc9SDavid Schultz #define CHAR char 76814d1bc9SDavid Schultz #include "printfcommon.h" 77814d1bc9SDavid Schultz 7821ca178eSDavid Schultz struct grouping_state { 7921ca178eSDavid Schultz char *thousands_sep; /* locale-specific thousands separator */ 8021ca178eSDavid Schultz int thousep_len; /* length of thousands_sep */ 8121ca178eSDavid Schultz const char *grouping; /* locale-specific numeric grouping rules */ 8221ca178eSDavid Schultz int lead; /* sig figs before decimal or group sep */ 8321ca178eSDavid Schultz int nseps; /* number of group separators with ' */ 8421ca178eSDavid Schultz int nrepeats; /* number of repeats of the last group */ 8521ca178eSDavid Schultz }; 8621ca178eSDavid Schultz 8721ca178eSDavid Schultz /* 8821ca178eSDavid Schultz * Initialize the thousands' grouping state in preparation to print a 8921ca178eSDavid Schultz * number with ndigits digits. This routine returns the total number 9021ca178eSDavid Schultz * of bytes that will be needed. 9121ca178eSDavid Schultz */ 9221ca178eSDavid Schultz static int 933c87aa1dSDavid Chisnall grouping_init(struct grouping_state *gs, int ndigits, locale_t loc) 9421ca178eSDavid Schultz { 9521ca178eSDavid Schultz struct lconv *locale; 9621ca178eSDavid Schultz 973c87aa1dSDavid Chisnall locale = localeconv_l(loc); 9821ca178eSDavid Schultz gs->grouping = locale->grouping; 9921ca178eSDavid Schultz gs->thousands_sep = locale->thousands_sep; 10021ca178eSDavid Schultz gs->thousep_len = strlen(gs->thousands_sep); 10121ca178eSDavid Schultz 10221ca178eSDavid Schultz gs->nseps = gs->nrepeats = 0; 10321ca178eSDavid Schultz gs->lead = ndigits; 10421ca178eSDavid Schultz while (*gs->grouping != CHAR_MAX) { 10521ca178eSDavid Schultz if (gs->lead <= *gs->grouping) 10621ca178eSDavid Schultz break; 10721ca178eSDavid Schultz gs->lead -= *gs->grouping; 10821ca178eSDavid Schultz if (*(gs->grouping+1)) { 10921ca178eSDavid Schultz gs->nseps++; 11021ca178eSDavid Schultz gs->grouping++; 11121ca178eSDavid Schultz } else 11221ca178eSDavid Schultz gs->nrepeats++; 11321ca178eSDavid Schultz } 11421ca178eSDavid Schultz return ((gs->nseps + gs->nrepeats) * gs->thousep_len); 11521ca178eSDavid Schultz } 11621ca178eSDavid Schultz 11721ca178eSDavid Schultz /* 11821ca178eSDavid Schultz * Print a number with thousands' separators. 11921ca178eSDavid Schultz */ 12021ca178eSDavid Schultz static int 12121ca178eSDavid Schultz grouping_print(struct grouping_state *gs, struct io_state *iop, 1223c87aa1dSDavid Chisnall const CHAR *cp, const CHAR *ep, locale_t locale) 12321ca178eSDavid Schultz { 12421ca178eSDavid Schultz const CHAR *cp0 = cp; 12521ca178eSDavid Schultz 1263c87aa1dSDavid Chisnall if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale)) 12721ca178eSDavid Schultz return (-1); 12821ca178eSDavid Schultz cp += gs->lead; 12921ca178eSDavid Schultz while (gs->nseps > 0 || gs->nrepeats > 0) { 13021ca178eSDavid Schultz if (gs->nrepeats > 0) 13121ca178eSDavid Schultz gs->nrepeats--; 13221ca178eSDavid Schultz else { 13321ca178eSDavid Schultz gs->grouping--; 13421ca178eSDavid Schultz gs->nseps--; 13521ca178eSDavid Schultz } 1363c87aa1dSDavid Chisnall if (io_print(iop, gs->thousands_sep, gs->thousep_len, locale)) 13721ca178eSDavid Schultz return (-1); 1383c87aa1dSDavid Chisnall if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale)) 13921ca178eSDavid Schultz return (-1); 14021ca178eSDavid Schultz cp += *gs->grouping; 14121ca178eSDavid Schultz } 14221ca178eSDavid Schultz if (cp > ep) 14321ca178eSDavid Schultz cp = ep; 14421ca178eSDavid Schultz return (cp - cp0); 14521ca178eSDavid Schultz } 14621ca178eSDavid Schultz 14758f0484fSRodney W. Grimes /* 14858f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio, 14958f0484fSRodney W. Grimes * then reset it so that it can be reused. 15058f0484fSRodney W. Grimes */ 15158f0484fSRodney W. Grimes static int 1523c87aa1dSDavid Chisnall __sprint(FILE *fp, struct __suio *uio, locale_t locale) 15358f0484fSRodney W. Grimes { 154d201fe46SDaniel Eischen int err; 15558f0484fSRodney W. Grimes 15658f0484fSRodney W. Grimes if (uio->uio_resid == 0) { 15758f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 15858f0484fSRodney W. Grimes return (0); 15958f0484fSRodney W. Grimes } 16058f0484fSRodney W. Grimes err = __sfvwrite(fp, uio); 16158f0484fSRodney W. Grimes uio->uio_resid = 0; 16258f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 16358f0484fSRodney W. Grimes return (err); 16458f0484fSRodney W. Grimes } 16558f0484fSRodney W. Grimes 16658f0484fSRodney W. Grimes /* 16758f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a 16858f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids 16958f0484fSRodney W. Grimes * worries about ungetc buffers and so forth. 17058f0484fSRodney W. Grimes */ 17158f0484fSRodney W. Grimes static int 1723c87aa1dSDavid Chisnall __sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap) 17358f0484fSRodney W. Grimes { 17458f0484fSRodney W. Grimes int ret; 1751b0181dfSJohn Baldwin FILE fake = FAKE_FILE; 17658f0484fSRodney W. Grimes unsigned char buf[BUFSIZ]; 17758f0484fSRodney W. Grimes 178a1805f7bSDavid Schultz /* XXX This is probably not needed. */ 179a1805f7bSDavid Schultz if (prepwrite(fp) != 0) 180a1805f7bSDavid Schultz return (EOF); 181a1805f7bSDavid Schultz 18258f0484fSRodney W. Grimes /* copy the important variables */ 18358f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF; 18458f0484fSRodney W. Grimes fake._file = fp->_file; 18558f0484fSRodney W. Grimes fake._cookie = fp->_cookie; 18658f0484fSRodney W. Grimes fake._write = fp->_write; 1871e98f887SJohn Baldwin fake._orientation = fp->_orientation; 1881e98f887SJohn Baldwin fake._mbstate = fp->_mbstate; 18958f0484fSRodney W. Grimes 19058f0484fSRodney W. Grimes /* set up the buffer */ 19158f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 19258f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 19358f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 19458f0484fSRodney W. Grimes 19558f0484fSRodney W. Grimes /* do the work, then copy any error status */ 1963c87aa1dSDavid Chisnall ret = __vfprintf(&fake, locale, fmt, ap); 197d201fe46SDaniel Eischen if (ret >= 0 && __fflush(&fake)) 19858f0484fSRodney W. Grimes ret = EOF; 19958f0484fSRodney W. Grimes if (fake._flags & __SERR) 20058f0484fSRodney W. Grimes fp->_flags |= __SERR; 20158f0484fSRodney W. Grimes return (ret); 20258f0484fSRodney W. Grimes } 20358f0484fSRodney W. Grimes 20458f0484fSRodney W. Grimes /* 205b9aac308STim J. Robbins * Convert a wide character string argument for the %ls format to a multibyte 206d48c77b5STim J. Robbins * string representation. If not -1, prec specifies the maximum number of 207d48c77b5STim J. Robbins * bytes to output, and also means that we can't assume that the wide char. 208d48c77b5STim J. Robbins * string ends is null-terminated. 209b9aac308STim J. Robbins */ 210b9aac308STim J. Robbins static char * 211b9aac308STim J. Robbins __wcsconv(wchar_t *wcsarg, int prec) 212b9aac308STim J. Robbins { 21393996f6dSTim J. Robbins static const mbstate_t initial; 21493996f6dSTim J. Robbins mbstate_t mbs; 215b9aac308STim J. Robbins char buf[MB_LEN_MAX]; 216b9aac308STim J. Robbins wchar_t *p; 217d48c77b5STim J. Robbins char *convbuf; 218b9aac308STim J. Robbins size_t clen, nbytes; 219b9aac308STim J. Robbins 220d48c77b5STim J. Robbins /* Allocate space for the maximum number of bytes we could output. */ 221d48c77b5STim J. Robbins if (prec < 0) { 222d48c77b5STim J. Robbins p = wcsarg; 223d48c77b5STim J. Robbins mbs = initial; 224d48c77b5STim J. Robbins nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 225d48c77b5STim J. Robbins if (nbytes == (size_t)-1) 226d48c77b5STim J. Robbins return (NULL); 227d48c77b5STim J. Robbins } else { 228b9aac308STim J. Robbins /* 229d48c77b5STim J. Robbins * Optimisation: if the output precision is small enough, 230d48c77b5STim J. Robbins * just allocate enough memory for the maximum instead of 231d48c77b5STim J. Robbins * scanning the string. 232b9aac308STim J. Robbins */ 233d48c77b5STim J. Robbins if (prec < 128) 234d48c77b5STim J. Robbins nbytes = prec; 235d48c77b5STim J. Robbins else { 236b9aac308STim J. Robbins nbytes = 0; 237b9aac308STim J. Robbins p = wcsarg; 23893996f6dSTim J. Robbins mbs = initial; 239b9aac308STim J. Robbins for (;;) { 24093996f6dSTim J. Robbins clen = wcrtomb(buf, *p++, &mbs); 241b9aac308STim J. Robbins if (clen == 0 || clen == (size_t)-1 || 242b9aac308STim J. Robbins nbytes + clen > prec) 243b9aac308STim J. Robbins break; 244b9aac308STim J. Robbins nbytes += clen; 245b9aac308STim J. Robbins } 246d48c77b5STim J. Robbins } 247b9aac308STim J. Robbins } 248b9aac308STim J. Robbins if ((convbuf = malloc(nbytes + 1)) == NULL) 249b9aac308STim J. Robbins return (NULL); 250b9aac308STim J. Robbins 251d48c77b5STim J. Robbins /* Fill the output buffer. */ 252b9aac308STim J. Robbins p = wcsarg; 25393996f6dSTim J. Robbins mbs = initial; 254d48c77b5STim J. Robbins if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, 255d48c77b5STim J. Robbins nbytes, &mbs)) == (size_t)-1) { 2566f098a48SAndrey A. Chernov free(convbuf); 257b9aac308STim J. Robbins return (NULL); 2586f098a48SAndrey A. Chernov } 259d48c77b5STim J. Robbins convbuf[nbytes] = '\0'; 260b9aac308STim J. Robbins return (convbuf); 261b9aac308STim J. Robbins } 262b9aac308STim J. Robbins 263b9aac308STim J. Robbins /* 264d201fe46SDaniel Eischen * MT-safe version 265d201fe46SDaniel Eischen */ 266d201fe46SDaniel Eischen int 2673c87aa1dSDavid Chisnall vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0, 2683c87aa1dSDavid Chisnall va_list ap) 269d201fe46SDaniel Eischen { 270d201fe46SDaniel Eischen int ret; 2713c87aa1dSDavid Chisnall FIX_LOCALE(locale); 272d201fe46SDaniel Eischen 273fda0a14fSKonstantin Belousov FLOCKFILE_CANCELSAFE(fp); 274a1805f7bSDavid Schultz /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 275a1805f7bSDavid Schultz if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 276a1805f7bSDavid Schultz fp->_file >= 0) 2773c87aa1dSDavid Chisnall ret = __sbprintf(fp, locale, fmt0, ap); 278a1805f7bSDavid Schultz else 2793c87aa1dSDavid Chisnall ret = __vfprintf(fp, locale, fmt0, ap); 280fda0a14fSKonstantin Belousov FUNLOCKFILE_CANCELSAFE(); 281d201fe46SDaniel Eischen return (ret); 282d201fe46SDaniel Eischen } 2833c87aa1dSDavid Chisnall int 2843c87aa1dSDavid Chisnall vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) 2853c87aa1dSDavid Chisnall { 2863c87aa1dSDavid Chisnall return vfprintf_l(fp, __get_locale(), fmt0, ap); 2873c87aa1dSDavid Chisnall } 288d201fe46SDaniel Eischen 28938cac8f8SDavid Schultz /* 29038cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer 29121ca178eSDavid Schultz * conversions, among other things. We need enough space to 29221ca178eSDavid Schultz * write a uintmax_t in octal (plus one byte). 29338cac8f8SDavid Schultz */ 29421ca178eSDavid Schultz #if UINTMAX_MAX <= UINT64_MAX 29521ca178eSDavid Schultz #define BUF 32 29621ca178eSDavid Schultz #else 29721ca178eSDavid Schultz #error "BUF must be large enough to format a uintmax_t" 29821ca178eSDavid Schultz #endif 29938cac8f8SDavid Schultz 30058f0484fSRodney W. Grimes /* 301d201fe46SDaniel Eischen * Non-MT-safe version 302d201fe46SDaniel Eischen */ 30358f0484fSRodney W. Grimes int 3043c87aa1dSDavid Chisnall __vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) 30558f0484fSRodney W. Grimes { 306d201fe46SDaniel Eischen char *fmt; /* format string */ 307d201fe46SDaniel Eischen int ch; /* character from fmt */ 308d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 309d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 310d201fe46SDaniel Eischen int flags; /* flags as above */ 31158f0484fSRodney W. Grimes int ret; /* return value accumulator */ 31258f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 313ebbad5ecSDavid Schultz int prec; /* precision from format; <0 for N/A */ 314e95725feSKonstantin Belousov int saved_errno; 315*f8876676SKonstantin Belousov int error; 316*f8876676SKonstantin Belousov char errnomsg[NL_TEXTMAX]; 31758f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 31821ca178eSDavid Schultz struct grouping_state gs; /* thousands' grouping info */ 319814d1bc9SDavid Schultz 3208de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 321ebbad5ecSDavid Schultz /* 322ebbad5ecSDavid Schultz * We can decompose the printed representation of floating 323ebbad5ecSDavid Schultz * point numbers into several parts, some of which may be empty: 324ebbad5ecSDavid Schultz * 325ebbad5ecSDavid Schultz * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 326ebbad5ecSDavid Schultz * A B ---C--- D E F 327ebbad5ecSDavid Schultz * 328ebbad5ecSDavid Schultz * A: 'sign' holds this value if present; '\0' otherwise 329ebbad5ecSDavid Schultz * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 330ebbad5ecSDavid Schultz * C: cp points to the string MMMNNN. Leading and trailing 331ebbad5ecSDavid Schultz * zeros are not in the string and must be added. 332ebbad5ecSDavid Schultz * D: expchar holds this character; '\0' if no exponent, e.g. %f 333ebbad5ecSDavid Schultz * F: at least two digits for decimal, at least one digit for hex 334ebbad5ecSDavid Schultz */ 3357ae5c679SAlexey Zelkin char *decimal_point; /* locale specific decimal point */ 3365004a238SDavid Schultz int decpt_len; /* length of decimal_point */ 337ebbad5ecSDavid Schultz int signflag; /* true if float is negative */ 338ebbad5ecSDavid Schultz union { /* floating point arguments %[aAeEfFgG] */ 339ebbad5ecSDavid Schultz double dbl; 340ebbad5ecSDavid Schultz long double ldbl; 341ebbad5ecSDavid Schultz } fparg; 34258f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 343ebbad5ecSDavid Schultz char expchar; /* exponent character: [eEpP\0] */ 344ebbad5ecSDavid Schultz char *dtoaend; /* pointer to end of converted digits */ 34558f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 346ebbad5ecSDavid Schultz int ndig; /* actual number of digits returned by dtoa */ 347ebbad5ecSDavid Schultz char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 3482ffc61baSTor Egge char *dtoaresult; /* buffer allocated by dtoa */ 34958f0484fSRodney W. Grimes #endif 35058f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 3517735bb0fSBill Fenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 35258f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 35358f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 354261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 35558f0484fSRodney W. Grimes int size; /* size of converted field or string */ 35692e88f87SAndrey A. Chernov int prsize; /* max size of printed field */ 357ebbad5ecSDavid Schultz const char *xdigs; /* digits for %[xX] conversion */ 358814d1bc9SDavid Schultz struct io_state io; /* I/O buffering state */ 35938cac8f8SDavid Schultz char buf[BUF]; /* buffer with space for digits of uintmax_t */ 360ebbad5ecSDavid Schultz char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 361a387081cSDoug Rabson union arg *argtable; /* args, built due to positional arg */ 362a387081cSDoug Rabson union arg statargtable [STATIC_ARG_TBL_SIZE]; 363efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 364efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 365b9aac308STim J. Robbins char *convbuf; /* wide to multibyte conversion result */ 3661bf6c5f1SAndrey A. Chernov int savserr; 36758f0484fSRodney W. Grimes 368ac9913a7SDavid Schultz static const char xdigs_lower[16] = "0123456789abcdef"; 369ac9913a7SDavid Schultz static const char xdigs_upper[16] = "0123456789ABCDEF"; 370ebbad5ecSDavid Schultz 371814d1bc9SDavid Schultz /* BEWARE, these `goto error' on error. */ 37258f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 3733c87aa1dSDavid Chisnall if (io_print(&io, (ptr), (len), locale)) \ 37458f0484fSRodney W. Grimes goto error; \ 37558f0484fSRodney W. Grimes } 37658f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 3773c87aa1dSDavid Chisnall if (io_pad(&io, (howmany), (with), locale)) \ 37858f0484fSRodney W. Grimes goto error; \ 379814d1bc9SDavid Schultz } 380814d1bc9SDavid Schultz #define PRINTANDPAD(p, ep, len, with) { \ 3813c87aa1dSDavid Chisnall if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \ 382814d1bc9SDavid Schultz goto error; \ 383814d1bc9SDavid Schultz } 384814d1bc9SDavid Schultz #define FLUSH() { \ 3853c87aa1dSDavid Chisnall if (io_flush(&io, locale)) \ 386814d1bc9SDavid Schultz goto error; \ 38758f0484fSRodney W. Grimes } 38858f0484fSRodney W. Grimes 38958f0484fSRodney W. Grimes /* 390efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 391efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 392efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 393efb7e53dSJordan K. Hubbard */ 394efb7e53dSJordan K. Hubbard #define GETARG(type) \ 395a387081cSDoug Rabson ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 396efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 397efb7e53dSJordan K. Hubbard 398efb7e53dSJordan K. Hubbard /* 39958f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 40058f0484fSRodney W. Grimes * argument extraction methods. 40158f0484fSRodney W. Grimes */ 40258f0484fSRodney W. Grimes #define SARG() \ 403efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 404efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 4057735bb0fSBill Fenner flags&CHARINT ? (long)(signed char)GETARG(int) : \ 406efb7e53dSJordan K. Hubbard (long)GETARG(int)) 40758f0484fSRodney W. Grimes #define UARG() \ 408efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 409efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 4107735bb0fSBill Fenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 411efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 4127735bb0fSBill Fenner #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 4137735bb0fSBill Fenner #define SJARG() \ 4147735bb0fSBill Fenner (flags&INTMAXT ? GETARG(intmax_t) : \ 4150881683bSDavid Schultz flags&SIZET ? (intmax_t)GETARG(ssize_t) : \ 4167735bb0fSBill Fenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 4177735bb0fSBill Fenner (intmax_t)GETARG(long long)) 4187735bb0fSBill Fenner #define UJARG() \ 4197735bb0fSBill Fenner (flags&INTMAXT ? GETARG(uintmax_t) : \ 4207735bb0fSBill Fenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 4217735bb0fSBill Fenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 4227735bb0fSBill Fenner (uintmax_t)GETARG(unsigned long long)) 423efb7e53dSJordan K. Hubbard 424efb7e53dSJordan K. Hubbard /* 425efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 426efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 427efb7e53dSJordan K. Hubbard */ 428efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 429efb7e53dSJordan K. Hubbard n2 = 0; \ 430efb7e53dSJordan K. Hubbard cp = fmt; \ 431efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 432efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 433efb7e53dSJordan K. Hubbard cp++; \ 434efb7e53dSJordan K. Hubbard } \ 435efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 436efb7e53dSJordan K. Hubbard int hold = nextarg; \ 437efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 438efb7e53dSJordan K. Hubbard argtable = statargtable; \ 439e62e5ff9SDavid Schultz if (__find_arguments (fmt0, orgap, &argtable)) { \ 440e62e5ff9SDavid Schultz ret = EOF; \ 441e62e5ff9SDavid Schultz goto error; \ 442e62e5ff9SDavid Schultz } \ 443efb7e53dSJordan K. Hubbard } \ 444efb7e53dSJordan K. Hubbard nextarg = n2; \ 445efb7e53dSJordan K. Hubbard val = GETARG (int); \ 446efb7e53dSJordan K. Hubbard nextarg = hold; \ 447efb7e53dSJordan K. Hubbard fmt = ++cp; \ 448efb7e53dSJordan K. Hubbard } else { \ 449efb7e53dSJordan K. Hubbard val = GETARG (int); \ 450efb7e53dSJordan K. Hubbard } 451efb7e53dSJordan K. Hubbard 45233bff5d3SDavid Schultz if (__use_xprintf == 0 && getenv("USE_XPRINTF")) 45333bff5d3SDavid Schultz __use_xprintf = 1; 45433bff5d3SDavid Schultz if (__use_xprintf > 0) 45533bff5d3SDavid Schultz return (__xvprintf(fp, fmt0, ap)); 45658f0484fSRodney W. Grimes 45758f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 458450ead86SPedro F. Giffuni if (prepwrite(fp) != 0) { 459450ead86SPedro F. Giffuni errno = EBADF; 46058f0484fSRodney W. Grimes return (EOF); 461450ead86SPedro F. Giffuni } 46258f0484fSRodney W. Grimes 4631bf6c5f1SAndrey A. Chernov savserr = fp->_flags & __SERR; 4641bf6c5f1SAndrey A. Chernov fp->_flags &= ~__SERR; 4651bf6c5f1SAndrey A. Chernov 466e95725feSKonstantin Belousov saved_errno = errno; 467e18701f4SDavid Schultz convbuf = NULL; 46858f0484fSRodney W. Grimes fmt = (char *)fmt0; 469efb7e53dSJordan K. Hubbard argtable = NULL; 470efb7e53dSJordan K. Hubbard nextarg = 1; 471d07090a8STim J. Robbins va_copy(orgap, ap); 472814d1bc9SDavid Schultz io_init(&io, fp); 47358f0484fSRodney W. Grimes ret = 0; 474e18701f4SDavid Schultz #ifndef NO_FLOATING_POINT 475e18701f4SDavid Schultz dtoaresult = NULL; 4763c87aa1dSDavid Chisnall decimal_point = localeconv_l(locale)->decimal_point; 4775004a238SDavid Schultz /* The overwhelmingly common case is decpt_len == 1. */ 4785004a238SDavid Schultz decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point)); 479e18701f4SDavid Schultz #endif 48058f0484fSRodney W. Grimes 48158f0484fSRodney W. Grimes /* 48258f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 48358f0484fSRodney W. Grimes */ 48458f0484fSRodney W. Grimes for (;;) { 48558f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 48658f0484fSRodney W. Grimes /* void */; 48758f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 488b250f248SAndrey A. Chernov if ((unsigned)ret + n > INT_MAX) { 48992e88f87SAndrey A. Chernov ret = EOF; 490666d00d3SDavid Schultz errno = EOVERFLOW; 49192e88f87SAndrey A. Chernov goto error; 49292e88f87SAndrey A. Chernov } 49358f0484fSRodney W. Grimes PRINT(cp, n); 49458f0484fSRodney W. Grimes ret += n; 49558f0484fSRodney W. Grimes } 49658f0484fSRodney W. Grimes if (ch == '\0') 49758f0484fSRodney W. Grimes goto done; 49858f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 49958f0484fSRodney W. Grimes 50058f0484fSRodney W. Grimes flags = 0; 50158f0484fSRodney W. Grimes dprec = 0; 50258f0484fSRodney W. Grimes width = 0; 50358f0484fSRodney W. Grimes prec = -1; 50421ca178eSDavid Schultz gs.grouping = NULL; 50558f0484fSRodney W. Grimes sign = '\0'; 506ebbad5ecSDavid Schultz ox[1] = '\0'; 50758f0484fSRodney W. Grimes 50858f0484fSRodney W. Grimes rflag: ch = *fmt++; 50958f0484fSRodney W. Grimes reswitch: switch (ch) { 51058f0484fSRodney W. Grimes case ' ': 5112e394b2fSAlexey Zelkin /*- 51258f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 51358f0484fSRodney W. Grimes * flag will be ignored.'' 51458f0484fSRodney W. Grimes * -- ANSI X3J11 51558f0484fSRodney W. Grimes */ 51658f0484fSRodney W. Grimes if (!sign) 51758f0484fSRodney W. Grimes sign = ' '; 51858f0484fSRodney W. Grimes goto rflag; 51958f0484fSRodney W. Grimes case '#': 52058f0484fSRodney W. Grimes flags |= ALT; 52158f0484fSRodney W. Grimes goto rflag; 52258f0484fSRodney W. Grimes case '*': 5232e394b2fSAlexey Zelkin /*- 52458f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 52558f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 52658f0484fSRodney W. Grimes * -- ANSI X3J11 52758f0484fSRodney W. Grimes * They don't exclude field widths read from args. 52858f0484fSRodney W. Grimes */ 529efb7e53dSJordan K. Hubbard GETASTER (width); 530efb7e53dSJordan K. Hubbard if (width >= 0) 53158f0484fSRodney W. Grimes goto rflag; 53258f0484fSRodney W. Grimes width = -width; 53358f0484fSRodney W. Grimes /* FALLTHROUGH */ 53458f0484fSRodney W. Grimes case '-': 53558f0484fSRodney W. Grimes flags |= LADJUST; 53658f0484fSRodney W. Grimes goto rflag; 53758f0484fSRodney W. Grimes case '+': 53858f0484fSRodney W. Grimes sign = '+'; 53958f0484fSRodney W. Grimes goto rflag; 5407735bb0fSBill Fenner case '\'': 54198ee7635SAlexey Zelkin flags |= GROUPING; 5427735bb0fSBill Fenner goto rflag; 54358f0484fSRodney W. Grimes case '.': 54458f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 5453b204b7dSDavid Schultz GETASTER (prec); 54658f0484fSRodney W. Grimes goto rflag; 54758f0484fSRodney W. Grimes } 5483b204b7dSDavid Schultz prec = 0; 54958f0484fSRodney W. Grimes while (is_digit(ch)) { 5503b204b7dSDavid Schultz prec = 10 * prec + to_digit(ch); 55158f0484fSRodney W. Grimes ch = *fmt++; 55258f0484fSRodney W. Grimes } 55358f0484fSRodney W. Grimes goto reswitch; 55458f0484fSRodney W. Grimes case '0': 5552e394b2fSAlexey Zelkin /*- 55658f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 55758f0484fSRodney W. Grimes * beginning of a field width.'' 55858f0484fSRodney W. Grimes * -- ANSI X3J11 55958f0484fSRodney W. Grimes */ 56058f0484fSRodney W. Grimes flags |= ZEROPAD; 56158f0484fSRodney W. Grimes goto rflag; 56258f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 56358f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 56458f0484fSRodney W. Grimes n = 0; 56558f0484fSRodney W. Grimes do { 56658f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 56758f0484fSRodney W. Grimes ch = *fmt++; 56858f0484fSRodney W. Grimes } while (is_digit(ch)); 569efb7e53dSJordan K. Hubbard if (ch == '$') { 570efb7e53dSJordan K. Hubbard nextarg = n; 571efb7e53dSJordan K. Hubbard if (argtable == NULL) { 572efb7e53dSJordan K. Hubbard argtable = statargtable; 573e62e5ff9SDavid Schultz if (__find_arguments (fmt0, orgap, 574e62e5ff9SDavid Schultz &argtable)) { 575e62e5ff9SDavid Schultz ret = EOF; 576e62e5ff9SDavid Schultz goto error; 577e62e5ff9SDavid Schultz } 578efb7e53dSJordan K. Hubbard } 579efb7e53dSJordan K. Hubbard goto rflag; 580efb7e53dSJordan K. Hubbard } 58158f0484fSRodney W. Grimes width = n; 58258f0484fSRodney W. Grimes goto reswitch; 5838de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 58458f0484fSRodney W. Grimes case 'L': 58558f0484fSRodney W. Grimes flags |= LONGDBL; 58658f0484fSRodney W. Grimes goto rflag; 58758f0484fSRodney W. Grimes #endif 58858f0484fSRodney W. Grimes case 'h': 5897735bb0fSBill Fenner if (flags & SHORTINT) { 5907735bb0fSBill Fenner flags &= ~SHORTINT; 5917735bb0fSBill Fenner flags |= CHARINT; 5927735bb0fSBill Fenner } else 59358f0484fSRodney W. Grimes flags |= SHORTINT; 59458f0484fSRodney W. Grimes goto rflag; 5957735bb0fSBill Fenner case 'j': 5967735bb0fSBill Fenner flags |= INTMAXT; 5977735bb0fSBill Fenner goto rflag; 59858f0484fSRodney W. Grimes case 'l': 5997735bb0fSBill Fenner if (flags & LONGINT) { 6007735bb0fSBill Fenner flags &= ~LONGINT; 6017735bb0fSBill Fenner flags |= LLONGINT; 6027735bb0fSBill Fenner } else 60358f0484fSRodney W. Grimes flags |= LONGINT; 60458f0484fSRodney W. Grimes goto rflag; 60558f0484fSRodney W. Grimes case 'q': 6067735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 6077735bb0fSBill Fenner goto rflag; 6087735bb0fSBill Fenner case 't': 6097735bb0fSBill Fenner flags |= PTRDIFFT; 6107735bb0fSBill Fenner goto rflag; 611bce0bef3SDag-Erling Smørgrav case 'w': 612bce0bef3SDag-Erling Smørgrav /* 613bce0bef3SDag-Erling Smørgrav * Fixed-width integer types. On all platforms we 614bce0bef3SDag-Erling Smørgrav * support, int8_t is equivalent to char, int16_t 615bce0bef3SDag-Erling Smørgrav * is equivalent to short, int32_t is equivalent 616bce0bef3SDag-Erling Smørgrav * to int, int64_t is equivalent to long long int. 617bce0bef3SDag-Erling Smørgrav * Furthermore, int_fast8_t, int_fast16_t and 618bce0bef3SDag-Erling Smørgrav * int_fast32_t are equivalent to int, and 619bce0bef3SDag-Erling Smørgrav * int_fast64_t is equivalent to long long int. 620bce0bef3SDag-Erling Smørgrav */ 621bce0bef3SDag-Erling Smørgrav flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT); 622bce0bef3SDag-Erling Smørgrav if (fmt[0] == 'f') { 623bce0bef3SDag-Erling Smørgrav flags |= FASTINT; 624bce0bef3SDag-Erling Smørgrav fmt++; 625bce0bef3SDag-Erling Smørgrav } else { 626bce0bef3SDag-Erling Smørgrav flags &= ~FASTINT; 627bce0bef3SDag-Erling Smørgrav } 628bce0bef3SDag-Erling Smørgrav if (fmt[0] == '8') { 629bce0bef3SDag-Erling Smørgrav if (!(flags & FASTINT)) 630bce0bef3SDag-Erling Smørgrav flags |= CHARINT; 631bce0bef3SDag-Erling Smørgrav else 632bce0bef3SDag-Erling Smørgrav /* no flag set = 32 */ ; 633bce0bef3SDag-Erling Smørgrav fmt += 1; 634bce0bef3SDag-Erling Smørgrav } else if (fmt[0] == '1' && fmt[1] == '6') { 635bce0bef3SDag-Erling Smørgrav if (!(flags & FASTINT)) 636bce0bef3SDag-Erling Smørgrav flags |= SHORTINT; 637bce0bef3SDag-Erling Smørgrav else 638bce0bef3SDag-Erling Smørgrav /* no flag set = 32 */ ; 639bce0bef3SDag-Erling Smørgrav fmt += 2; 640bce0bef3SDag-Erling Smørgrav } else if (fmt[0] == '3' && fmt[1] == '2') { 641bce0bef3SDag-Erling Smørgrav /* no flag set = 32 */ ; 642bce0bef3SDag-Erling Smørgrav fmt += 2; 643bce0bef3SDag-Erling Smørgrav } else if (fmt[0] == '6' && fmt[1] == '4') { 644bce0bef3SDag-Erling Smørgrav flags |= LLONGINT; 645bce0bef3SDag-Erling Smørgrav fmt += 2; 646bce0bef3SDag-Erling Smørgrav } else { 647bce0bef3SDag-Erling Smørgrav if (flags & FASTINT) { 648bce0bef3SDag-Erling Smørgrav flags &= ~FASTINT; 649bce0bef3SDag-Erling Smørgrav fmt--; 650bce0bef3SDag-Erling Smørgrav } 651bce0bef3SDag-Erling Smørgrav goto invalid; 652bce0bef3SDag-Erling Smørgrav } 653bce0bef3SDag-Erling Smørgrav goto rflag; 6547735bb0fSBill Fenner case 'z': 6557735bb0fSBill Fenner flags |= SIZET; 65658f0484fSRodney W. Grimes goto rflag; 657d9dc1603SDag-Erling Smørgrav case 'B': 658d9dc1603SDag-Erling Smørgrav case 'b': 659d9dc1603SDag-Erling Smørgrav if (flags & INTMAX_SIZE) 660d9dc1603SDag-Erling Smørgrav ujval = UJARG(); 661d9dc1603SDag-Erling Smørgrav else 662d9dc1603SDag-Erling Smørgrav ulval = UARG(); 663d9dc1603SDag-Erling Smørgrav base = 2; 664d9dc1603SDag-Erling Smørgrav /* leading 0b/B only if non-zero */ 665d9dc1603SDag-Erling Smørgrav if (flags & ALT && 666d9dc1603SDag-Erling Smørgrav (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 667d9dc1603SDag-Erling Smørgrav ox[1] = ch; 668d9dc1603SDag-Erling Smørgrav goto nosign; 669d9dc1603SDag-Erling Smørgrav break; 670927ecbf3STim J. Robbins case 'C': 671927ecbf3STim J. Robbins flags |= LONGINT; 672927ecbf3STim J. Robbins /*FALLTHROUGH*/ 67358f0484fSRodney W. Grimes case 'c': 674b9aac308STim J. Robbins if (flags & LONGINT) { 67593996f6dSTim J. Robbins static const mbstate_t initial; 67693996f6dSTim J. Robbins mbstate_t mbs; 677b9aac308STim J. Robbins size_t mbseqlen; 678b9aac308STim J. Robbins 67993996f6dSTim J. Robbins mbs = initial; 680b9aac308STim J. Robbins mbseqlen = wcrtomb(cp = buf, 68193996f6dSTim J. Robbins (wchar_t)GETARG(wint_t), &mbs); 6826180233fSTim J. Robbins if (mbseqlen == (size_t)-1) { 6836180233fSTim J. Robbins fp->_flags |= __SERR; 684b9aac308STim J. Robbins goto error; 6856180233fSTim J. Robbins } 686b9aac308STim J. Robbins size = (int)mbseqlen; 687b9aac308STim J. Robbins } else { 688efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 68958f0484fSRodney W. Grimes size = 1; 690b9aac308STim J. Robbins } 69158f0484fSRodney W. Grimes sign = '\0'; 69258f0484fSRodney W. Grimes break; 69358f0484fSRodney W. Grimes case 'D': 69458f0484fSRodney W. Grimes flags |= LONGINT; 69558f0484fSRodney W. Grimes /*FALLTHROUGH*/ 69658f0484fSRodney W. Grimes case 'd': 69758f0484fSRodney W. Grimes case 'i': 6987735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 6997735bb0fSBill Fenner ujval = SJARG(); 7007735bb0fSBill Fenner if ((intmax_t)ujval < 0) { 7017735bb0fSBill Fenner ujval = -ujval; 70258f0484fSRodney W. Grimes sign = '-'; 70358f0484fSRodney W. Grimes } 70458f0484fSRodney W. Grimes } else { 70558f0484fSRodney W. Grimes ulval = SARG(); 70658f0484fSRodney W. Grimes if ((long)ulval < 0) { 70758f0484fSRodney W. Grimes ulval = -ulval; 70858f0484fSRodney W. Grimes sign = '-'; 70958f0484fSRodney W. Grimes } 71058f0484fSRodney W. Grimes } 71158f0484fSRodney W. Grimes base = 10; 71258f0484fSRodney W. Grimes goto number; 7138de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 7147735bb0fSBill Fenner case 'a': 7157735bb0fSBill Fenner case 'A': 716ebbad5ecSDavid Schultz if (ch == 'a') { 717ebbad5ecSDavid Schultz ox[1] = 'x'; 718ebbad5ecSDavid Schultz xdigs = xdigs_lower; 719ebbad5ecSDavid Schultz expchar = 'p'; 720ebbad5ecSDavid Schultz } else { 721ebbad5ecSDavid Schultz ox[1] = 'X'; 722ebbad5ecSDavid Schultz xdigs = xdigs_upper; 723ebbad5ecSDavid Schultz expchar = 'P'; 724ebbad5ecSDavid Schultz } 725904322a5SDavid Schultz if (prec >= 0) 726904322a5SDavid Schultz prec++; 727904322a5SDavid Schultz if (dtoaresult != NULL) 728904322a5SDavid Schultz freedtoa(dtoaresult); 729ebbad5ecSDavid Schultz if (flags & LONGDBL) { 730904322a5SDavid Schultz fparg.ldbl = GETARG(long double); 731ebbad5ecSDavid Schultz dtoaresult = cp = 732ebbad5ecSDavid Schultz __hldtoa(fparg.ldbl, xdigs, prec, 733ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 734ebbad5ecSDavid Schultz } else { 735ebbad5ecSDavid Schultz fparg.dbl = GETARG(double); 736ebbad5ecSDavid Schultz dtoaresult = cp = 737ebbad5ecSDavid Schultz __hdtoa(fparg.dbl, xdigs, prec, 738ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 739ebbad5ecSDavid Schultz } 740904322a5SDavid Schultz if (prec < 0) 741904322a5SDavid Schultz prec = dtoaend - cp; 742904322a5SDavid Schultz if (expt == INT_MAX) 743904322a5SDavid Schultz ox[1] = '\0'; 744904322a5SDavid Schultz goto fp_common; 745d26be6f0SBruce Evans case 'e': 74658f0484fSRodney W. Grimes case 'E': 747ebbad5ecSDavid Schultz expchar = ch; 748ebbad5ecSDavid Schultz if (prec < 0) /* account for digit before decpt */ 749ebbad5ecSDavid Schultz prec = DEFPREC + 1; 750ebbad5ecSDavid Schultz else 751ebbad5ecSDavid Schultz prec++; 752ebbad5ecSDavid Schultz goto fp_begin; 753d26be6f0SBruce Evans case 'f': 7547735bb0fSBill Fenner case 'F': 755ebbad5ecSDavid Schultz expchar = '\0'; 756d26be6f0SBruce Evans goto fp_begin; 75758f0484fSRodney W. Grimes case 'g': 75858f0484fSRodney W. Grimes case 'G': 759ebbad5ecSDavid Schultz expchar = ch - ('g' - 'e'); 760d26be6f0SBruce Evans if (prec == 0) 761d26be6f0SBruce Evans prec = 1; 762ebbad5ecSDavid Schultz fp_begin: 763ebbad5ecSDavid Schultz if (prec < 0) 76458f0484fSRodney W. Grimes prec = DEFPREC; 765ebbad5ecSDavid Schultz if (dtoaresult != NULL) 766ebbad5ecSDavid Schultz freedtoa(dtoaresult); 767ebbad5ecSDavid Schultz if (flags & LONGDBL) { 768ebbad5ecSDavid Schultz fparg.ldbl = GETARG(long double); 769ebbad5ecSDavid Schultz dtoaresult = cp = 770ebbad5ecSDavid Schultz __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 771ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 772ebbad5ecSDavid Schultz } else { 773ebbad5ecSDavid Schultz fparg.dbl = GETARG(double); 774ebbad5ecSDavid Schultz dtoaresult = cp = 775ebbad5ecSDavid Schultz dtoa(fparg.dbl, expchar ? 2 : 3, prec, 776ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 777ebbad5ecSDavid Schultz if (expt == 9999) 778ebbad5ecSDavid Schultz expt = INT_MAX; 77958f0484fSRodney W. Grimes } 780904322a5SDavid Schultz fp_common: 781ebbad5ecSDavid Schultz if (signflag) 782ebbad5ecSDavid Schultz sign = '-'; 783ebbad5ecSDavid Schultz if (expt == INT_MAX) { /* inf or nan */ 784ebbad5ecSDavid Schultz if (*cp == 'N') { 785ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "nan" : "NAN"; 786ebbad5ecSDavid Schultz sign = '\0'; 787ebbad5ecSDavid Schultz } else 788ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "inf" : "INF"; 78958f0484fSRodney W. Grimes size = 3; 790970a466cSDavid Schultz flags &= ~ZEROPAD; 79158f0484fSRodney W. Grimes break; 79258f0484fSRodney W. Grimes } 79358f0484fSRodney W. Grimes flags |= FPT; 794ebbad5ecSDavid Schultz ndig = dtoaend - cp; 79558f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 796ebbad5ecSDavid Schultz if (expt > -4 && expt <= prec) { 797ebbad5ecSDavid Schultz /* Make %[gG] smell like %[fF] */ 798ebbad5ecSDavid Schultz expchar = '\0'; 799ebbad5ecSDavid Schultz if (flags & ALT) 800ebbad5ecSDavid Schultz prec -= expt; 80158f0484fSRodney W. Grimes else 802ebbad5ecSDavid Schultz prec = ndig - expt; 803ebbad5ecSDavid Schultz if (prec < 0) 804ebbad5ecSDavid Schultz prec = 0; 8051f2a0cdfSDavid Schultz } else { 8061f2a0cdfSDavid Schultz /* 8071f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but 8081f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag. 8091f2a0cdfSDavid Schultz */ 8101f2a0cdfSDavid Schultz if (!(flags & ALT)) 8111f2a0cdfSDavid Schultz prec = ndig; 81258f0484fSRodney W. Grimes } 813ebbad5ecSDavid Schultz } 814ebbad5ecSDavid Schultz if (expchar) { 815ebbad5ecSDavid Schultz expsize = exponent(expstr, expt - 1, expchar); 816ebbad5ecSDavid Schultz size = expsize + prec; 8173b204b7dSDavid Schultz if (prec > 1 || flags & ALT) 8185004a238SDavid Schultz size += decpt_len; 819ebbad5ecSDavid Schultz } else { 82081ae2e9aSDavid Schultz /* space for digits before decimal point */ 82181ae2e9aSDavid Schultz if (expt > 0) 82258f0484fSRodney W. Grimes size = expt; 82381ae2e9aSDavid Schultz else /* "0" */ 82481ae2e9aSDavid Schultz size = 1; 82581ae2e9aSDavid Schultz /* space for decimal pt and following digits */ 82658f0484fSRodney W. Grimes if (prec || flags & ALT) 8275004a238SDavid Schultz size += prec + decpt_len; 82821ca178eSDavid Schultz if ((flags & GROUPING) && expt > 0) 8293c87aa1dSDavid Chisnall size += grouping_init(&gs, expt, locale); 830ebbad5ecSDavid Schultz } 83158f0484fSRodney W. Grimes break; 8328de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 833e95725feSKonstantin Belousov case 'm': 834*f8876676SKonstantin Belousov error = __strerror_rl(saved_errno, errnomsg, 835*f8876676SKonstantin Belousov sizeof(errnomsg), locale); 836*f8876676SKonstantin Belousov cp = error == 0 ? errnomsg : "<strerror failure>"; 837e95725feSKonstantin Belousov size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp); 838e95725feSKonstantin Belousov sign = '\0'; 839e95725feSKonstantin Belousov break; 84058f0484fSRodney W. Grimes case 'n': 8417735bb0fSBill Fenner /* 8427735bb0fSBill Fenner * Assignment-like behavior is specified if the 8437735bb0fSBill Fenner * value overflows or is otherwise unrepresentable. 8447735bb0fSBill Fenner * C99 says to use `signed char' for %hhn conversions. 8457735bb0fSBill Fenner */ 8467735bb0fSBill Fenner if (flags & LLONGINT) 8477735bb0fSBill Fenner *GETARG(long long *) = ret; 8487735bb0fSBill Fenner else if (flags & SIZET) 8497735bb0fSBill Fenner *GETARG(ssize_t *) = (ssize_t)ret; 8507735bb0fSBill Fenner else if (flags & PTRDIFFT) 8517735bb0fSBill Fenner *GETARG(ptrdiff_t *) = ret; 8527735bb0fSBill Fenner else if (flags & INTMAXT) 8537735bb0fSBill Fenner *GETARG(intmax_t *) = ret; 85458f0484fSRodney W. Grimes else if (flags & LONGINT) 8556e690ad4SAndrey A. Chernov *GETARG(long *) = ret; 85658f0484fSRodney W. Grimes else if (flags & SHORTINT) 8576e690ad4SAndrey A. Chernov *GETARG(short *) = ret; 8587735bb0fSBill Fenner else if (flags & CHARINT) 8597735bb0fSBill Fenner *GETARG(signed char *) = ret; 86058f0484fSRodney W. Grimes else 8616e690ad4SAndrey A. Chernov *GETARG(int *) = ret; 86258f0484fSRodney W. Grimes continue; /* no output */ 86358f0484fSRodney W. Grimes case 'O': 86458f0484fSRodney W. Grimes flags |= LONGINT; 86558f0484fSRodney W. Grimes /*FALLTHROUGH*/ 86658f0484fSRodney W. Grimes case 'o': 8677735bb0fSBill Fenner if (flags & INTMAX_SIZE) 8687735bb0fSBill Fenner ujval = UJARG(); 86958f0484fSRodney W. Grimes else 87058f0484fSRodney W. Grimes ulval = UARG(); 87158f0484fSRodney W. Grimes base = 8; 87258f0484fSRodney W. Grimes goto nosign; 87358f0484fSRodney W. Grimes case 'p': 8742e394b2fSAlexey Zelkin /*- 87558f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 87658f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 87758f0484fSRodney W. Grimes * of printable characters, in an implementation- 87858f0484fSRodney W. Grimes * defined manner.'' 87958f0484fSRodney W. Grimes * -- ANSI X3J11 88058f0484fSRodney W. Grimes */ 8817735bb0fSBill Fenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 88258f0484fSRodney W. Grimes base = 16; 883ebbad5ecSDavid Schultz xdigs = xdigs_lower; 884ebbad5ecSDavid Schultz flags = flags | INTMAXT; 885ebbad5ecSDavid Schultz ox[1] = 'x'; 88658f0484fSRodney W. Grimes goto nosign; 887927ecbf3STim J. Robbins case 'S': 888927ecbf3STim J. Robbins flags |= LONGINT; 889927ecbf3STim J. Robbins /*FALLTHROUGH*/ 89058f0484fSRodney W. Grimes case 's': 891b9aac308STim J. Robbins if (flags & LONGINT) { 892b9aac308STim J. Robbins wchar_t *wcp; 893b9aac308STim J. Robbins 894b9aac308STim J. Robbins if (convbuf != NULL) 895b9aac308STim J. Robbins free(convbuf); 896b9aac308STim J. Robbins if ((wcp = GETARG(wchar_t *)) == NULL) 897b9aac308STim J. Robbins cp = "(null)"; 898b9aac308STim J. Robbins else { 899b9aac308STim J. Robbins convbuf = __wcsconv(wcp, prec); 9006180233fSTim J. Robbins if (convbuf == NULL) { 9016180233fSTim J. Robbins fp->_flags |= __SERR; 902b9aac308STim J. Robbins goto error; 9036180233fSTim J. Robbins } 904b9aac308STim J. Robbins cp = convbuf; 905b9aac308STim J. Robbins } 906b9aac308STim J. Robbins } else if ((cp = GETARG(char *)) == NULL) 90758f0484fSRodney W. Grimes cp = "(null)"; 908353ce11cSDavid Schultz size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp); 90958f0484fSRodney W. Grimes sign = '\0'; 91058f0484fSRodney W. Grimes break; 91158f0484fSRodney W. Grimes case 'U': 91258f0484fSRodney W. Grimes flags |= LONGINT; 91358f0484fSRodney W. Grimes /*FALLTHROUGH*/ 91458f0484fSRodney W. Grimes case 'u': 9157735bb0fSBill Fenner if (flags & INTMAX_SIZE) 9167735bb0fSBill Fenner ujval = UJARG(); 91758f0484fSRodney W. Grimes else 91858f0484fSRodney W. Grimes ulval = UARG(); 91958f0484fSRodney W. Grimes base = 10; 92058f0484fSRodney W. Grimes goto nosign; 92158f0484fSRodney W. Grimes case 'X': 922ebbad5ecSDavid Schultz xdigs = xdigs_upper; 92358f0484fSRodney W. Grimes goto hex; 92458f0484fSRodney W. Grimes case 'x': 925ebbad5ecSDavid Schultz xdigs = xdigs_lower; 9267735bb0fSBill Fenner hex: 9277735bb0fSBill Fenner if (flags & INTMAX_SIZE) 9287735bb0fSBill Fenner ujval = UJARG(); 92958f0484fSRodney W. Grimes else 93058f0484fSRodney W. Grimes ulval = UARG(); 93158f0484fSRodney W. Grimes base = 16; 93258f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 93358f0484fSRodney W. Grimes if (flags & ALT && 9347735bb0fSBill Fenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 935ebbad5ecSDavid Schultz ox[1] = ch; 93658f0484fSRodney W. Grimes 93798ee7635SAlexey Zelkin flags &= ~GROUPING; 93858f0484fSRodney W. Grimes /* unsigned conversions */ 93958f0484fSRodney W. Grimes nosign: sign = '\0'; 9402e394b2fSAlexey Zelkin /*- 94158f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 94258f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 94358f0484fSRodney W. Grimes * -- ANSI X3J11 94458f0484fSRodney W. Grimes */ 94558f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 94658f0484fSRodney W. Grimes flags &= ~ZEROPAD; 94758f0484fSRodney W. Grimes 9482e394b2fSAlexey Zelkin /*- 94958f0484fSRodney W. Grimes * ``The result of converting a zero value with an 95058f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 95158f0484fSRodney W. Grimes * -- ANSI X3J11 9521be5319aSDavid Schultz * 9531be5319aSDavid Schultz * ``The C Standard is clear enough as is. The call 9541be5319aSDavid Schultz * printf("%#.0o", 0) should print 0.'' 9551be5319aSDavid Schultz * -- Defect Report #151 95658f0484fSRodney W. Grimes */ 95758f0484fSRodney W. Grimes cp = buf + BUF; 9587735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 9591be5319aSDavid Schultz if (ujval != 0 || prec != 0 || 9601be5319aSDavid Schultz (flags & ALT && base == 8)) 9617735bb0fSBill Fenner cp = __ujtoa(ujval, cp, base, 96221ca178eSDavid Schultz flags & ALT, xdigs); 96358f0484fSRodney W. Grimes } else { 9641be5319aSDavid Schultz if (ulval != 0 || prec != 0 || 9651be5319aSDavid Schultz (flags & ALT && base == 8)) 96658f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 96721ca178eSDavid Schultz flags & ALT, xdigs); 96858f0484fSRodney W. Grimes } 96958f0484fSRodney W. Grimes size = buf + BUF - cp; 97038cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 97138cac8f8SDavid Schultz abort(); 97221ca178eSDavid Schultz if ((flags & GROUPING) && size != 0) 9733c87aa1dSDavid Chisnall size += grouping_init(&gs, size, locale); 97458f0484fSRodney W. Grimes break; 97558f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 97658f0484fSRodney W. Grimes if (ch == '\0') 97758f0484fSRodney W. Grimes goto done; 978bce0bef3SDag-Erling Smørgrav invalid: 97958f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 98058f0484fSRodney W. Grimes cp = buf; 98158f0484fSRodney W. Grimes *cp = ch; 98258f0484fSRodney W. Grimes size = 1; 98358f0484fSRodney W. Grimes sign = '\0'; 98458f0484fSRodney W. Grimes break; 98558f0484fSRodney W. Grimes } 98658f0484fSRodney W. Grimes 98758f0484fSRodney W. Grimes /* 98858f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 98958f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 99058f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 99158f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 99258f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 99358f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 99458f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 99558f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 99658f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 99758f0484fSRodney W. Grimes * 99858f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 999261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 100058f0484fSRodney W. Grimes */ 1001261a532aSBill Fenner realsz = dprec > size ? dprec : size; 100258f0484fSRodney W. Grimes if (sign) 1003261a532aSBill Fenner realsz++; 1004904322a5SDavid Schultz if (ox[1]) 1005261a532aSBill Fenner realsz += 2; 100658f0484fSRodney W. Grimes 100792e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz; 1008b250f248SAndrey A. Chernov if ((unsigned)ret + prsize > INT_MAX) { 100992e88f87SAndrey A. Chernov ret = EOF; 1010666d00d3SDavid Schultz errno = EOVERFLOW; 101192e88f87SAndrey A. Chernov goto error; 101292e88f87SAndrey A. Chernov } 101392e88f87SAndrey A. Chernov 101458f0484fSRodney W. Grimes /* right-adjusting blank padding */ 101558f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 101658f0484fSRodney W. Grimes PAD(width - realsz, blanks); 101758f0484fSRodney W. Grimes 101858f0484fSRodney W. Grimes /* prefix */ 1019904322a5SDavid Schultz if (sign) 102058f0484fSRodney W. Grimes PRINT(&sign, 1); 1021904322a5SDavid Schultz 1022904322a5SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */ 102358f0484fSRodney W. Grimes ox[0] = '0'; 102458f0484fSRodney W. Grimes PRINT(ox, 2); 102558f0484fSRodney W. Grimes } 102658f0484fSRodney W. Grimes 102758f0484fSRodney W. Grimes /* right-adjusting zero padding */ 102858f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 102958f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 103058f0484fSRodney W. Grimes 103158f0484fSRodney W. Grimes /* the string or number proper */ 10328de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 103358f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 103421ca178eSDavid Schultz #endif 103521ca178eSDavid Schultz /* leading zeroes from decimal precision */ 103621ca178eSDavid Schultz PAD(dprec - size, zeroes); 103721ca178eSDavid Schultz if (gs.grouping) { 10383c87aa1dSDavid Chisnall if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0) 103921ca178eSDavid Schultz goto error; 104021ca178eSDavid Schultz } else { 104158f0484fSRodney W. Grimes PRINT(cp, size); 104221ca178eSDavid Schultz } 104321ca178eSDavid Schultz #ifndef NO_FLOATING_POINT 104458f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 1045ebbad5ecSDavid Schultz if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1046ebbad5ecSDavid Schultz if (expt <= 0) { 104781ae2e9aSDavid Schultz PRINT(zeroes, 1); 104881ae2e9aSDavid Schultz if (prec || flags & ALT) 10495004a238SDavid Schultz PRINT(decimal_point,decpt_len); 105058f0484fSRodney W. Grimes PAD(-expt, zeroes); 10513b204b7dSDavid Schultz /* already handled initial 0's */ 10523b204b7dSDavid Schultz prec += expt; 105358f0484fSRodney W. Grimes } else { 105421ca178eSDavid Schultz if (gs.grouping) { 105521ca178eSDavid Schultz n = grouping_print(&gs, &io, 10563c87aa1dSDavid Chisnall cp, dtoaend, locale); 105721ca178eSDavid Schultz if (n < 0) 105821ca178eSDavid Schultz goto error; 105921ca178eSDavid Schultz cp += n; 106021ca178eSDavid Schultz } else { 10613b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend, 106221ca178eSDavid Schultz expt, zeroes); 106321ca178eSDavid Schultz cp += expt; 1064ebbad5ecSDavid Schultz } 1065ebbad5ecSDavid Schultz if (prec || flags & ALT) 10665004a238SDavid Schultz PRINT(decimal_point,decpt_len); 1067ebbad5ecSDavid Schultz } 10683b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend, prec, zeroes); 1069ebbad5ecSDavid Schultz } else { /* %[eE] or sufficiently long %[gG] */ 10703b204b7dSDavid Schultz if (prec > 1 || flags & ALT) { 10715004a238SDavid Schultz PRINT(cp++, 1); 10725004a238SDavid Schultz PRINT(decimal_point, decpt_len); 107358f0484fSRodney W. Grimes PRINT(cp, ndig-1); 1074ebbad5ecSDavid Schultz PAD(prec - ndig, zeroes); 107558f0484fSRodney W. Grimes } else /* XeYYY */ 107658f0484fSRodney W. Grimes PRINT(cp, 1); 107758f0484fSRodney W. Grimes PRINT(expstr, expsize); 107858f0484fSRodney W. Grimes } 107958f0484fSRodney W. Grimes } 108058f0484fSRodney W. Grimes #endif 108158f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 108258f0484fSRodney W. Grimes if (flags & LADJUST) 108358f0484fSRodney W. Grimes PAD(width - realsz, blanks); 108458f0484fSRodney W. Grimes 108558f0484fSRodney W. Grimes /* finally, adjust ret */ 108692e88f87SAndrey A. Chernov ret += prsize; 108758f0484fSRodney W. Grimes 108858f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 108958f0484fSRodney W. Grimes } 109058f0484fSRodney W. Grimes done: 109158f0484fSRodney W. Grimes FLUSH(); 109258f0484fSRodney W. Grimes error: 1093096ad104SDag-Erling Smørgrav va_end(orgap); 10948de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 10952ffc61baSTor Egge if (dtoaresult != NULL) 1096ebbad5ecSDavid Schultz freedtoa(dtoaresult); 10972ffc61baSTor Egge #endif 1098b9aac308STim J. Robbins if (convbuf != NULL) 1099b9aac308STim J. Robbins free(convbuf); 1100f70177e7SJulian Elischer if (__sferror(fp)) 1101f70177e7SJulian Elischer ret = EOF; 11021bf6c5f1SAndrey A. Chernov else 11031bf6c5f1SAndrey A. Chernov fp->_flags |= savserr; 1104efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 1105efb7e53dSJordan K. Hubbard free (argtable); 1106f70177e7SJulian Elischer return (ret); 110758f0484fSRodney W. Grimes /* NOTREACHED */ 110858f0484fSRodney W. Grimes } 110958f0484fSRodney W. Grimes 1110