vfprintf.c revision 234531
11573Srgrimes/*- 21573Srgrimes * Copyright (c) 1990, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * This code is derived from software contributed to Berkeley by 61573Srgrimes * Chris Torek. 71573Srgrimes * 8227753Stheraven * Copyright (c) 2011 The FreeBSD Foundation 9227753Stheraven * All rights reserved. 10227753Stheraven * Portions of this software were developed by David Chisnall 11227753Stheraven * under sponsorship from the FreeBSD Foundation. 12227753Stheraven * 131573Srgrimes * Redistribution and use in source and binary forms, with or without 141573Srgrimes * modification, are permitted provided that the following conditions 151573Srgrimes * are met: 161573Srgrimes * 1. Redistributions of source code must retain the above copyright 171573Srgrimes * notice, this list of conditions and the following disclaimer. 181573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 191573Srgrimes * notice, this list of conditions and the following disclaimer in the 201573Srgrimes * documentation and/or other materials provided with the distribution. 211573Srgrimes * 4. Neither the name of the University nor the names of its contributors 221573Srgrimes * may be used to endorse or promote products derived from this software 231573Srgrimes * without specific prior written permission. 241573Srgrimes * 251573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351573Srgrimes * SUCH DAMAGE. 361573Srgrimes */ 371573Srgrimes 381573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 391573Srgrimesstatic char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 401573Srgrimes#endif /* LIBC_SCCS and not lint */ 4192986Sobrien#include <sys/cdefs.h> 4292986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdio/vfprintf.c 234531 2012-04-21 06:10:18Z das $"); 431573Srgrimes 441573Srgrimes/* 451573Srgrimes * Actual printf innards. 461573Srgrimes * 471573Srgrimes * This code is large and complicated... 481573Srgrimes */ 491573Srgrimes 5071579Sdeischen#include "namespace.h" 511573Srgrimes#include <sys/types.h> 521573Srgrimes 5387113Sfenner#include <ctype.h> 54234531Sdas#include <errno.h> 551573Srgrimes#include <limits.h> 5687490Sphantom#include <locale.h> 5787113Sfenner#include <stddef.h> 5887113Sfenner#include <stdint.h> 591573Srgrimes#include <stdio.h> 601573Srgrimes#include <stdlib.h> 611573Srgrimes#include <string.h> 62103633Stjr#include <wchar.h> 63153486Sphk#include <printf.h> 641573Srgrimes 651573Srgrimes#include <stdarg.h> 66227753Stheraven#include "xlocale_private.h" 6771579Sdeischen#include "un-namespace.h" 681573Srgrimes 6971579Sdeischen#include "libc_private.h" 701573Srgrimes#include "local.h" 711573Srgrimes#include "fvwrite.h" 72180104Sdas#include "printflocal.h" 731573Srgrimes 74227753Stheravenstatic int __sprint(FILE *, struct __suio *, locale_t); 75227753Stheravenstatic int __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0) 76187369Sdas __noinline; 77103633Stjrstatic char *__wcsconv(wchar_t *, int); 7816586Sjraynard 79187277Sdas#define CHAR char 80187277Sdas#include "printfcommon.h" 81187277Sdas 82187582Sdasstruct grouping_state { 83187582Sdas char *thousands_sep; /* locale-specific thousands separator */ 84187582Sdas int thousep_len; /* length of thousands_sep */ 85187582Sdas const char *grouping; /* locale-specific numeric grouping rules */ 86187582Sdas int lead; /* sig figs before decimal or group sep */ 87187582Sdas int nseps; /* number of group separators with ' */ 88187582Sdas int nrepeats; /* number of repeats of the last group */ 89187582Sdas}; 90187582Sdas 911573Srgrimes/* 92187582Sdas * Initialize the thousands' grouping state in preparation to print a 93187582Sdas * number with ndigits digits. This routine returns the total number 94187582Sdas * of bytes that will be needed. 95187582Sdas */ 96187582Sdasstatic int 97227753Stheravengrouping_init(struct grouping_state *gs, int ndigits, locale_t loc) 98187582Sdas{ 99187582Sdas struct lconv *locale; 100187582Sdas 101227753Stheraven locale = localeconv_l(loc); 102187582Sdas gs->grouping = locale->grouping; 103187582Sdas gs->thousands_sep = locale->thousands_sep; 104187582Sdas gs->thousep_len = strlen(gs->thousands_sep); 105187582Sdas 106187582Sdas gs->nseps = gs->nrepeats = 0; 107187582Sdas gs->lead = ndigits; 108187582Sdas while (*gs->grouping != CHAR_MAX) { 109187582Sdas if (gs->lead <= *gs->grouping) 110187582Sdas break; 111187582Sdas gs->lead -= *gs->grouping; 112187582Sdas if (*(gs->grouping+1)) { 113187582Sdas gs->nseps++; 114187582Sdas gs->grouping++; 115187582Sdas } else 116187582Sdas gs->nrepeats++; 117187582Sdas } 118187582Sdas return ((gs->nseps + gs->nrepeats) * gs->thousep_len); 119187582Sdas} 120187582Sdas 121187582Sdas/* 122187582Sdas * Print a number with thousands' separators. 123187582Sdas */ 124187582Sdasstatic int 125187582Sdasgrouping_print(struct grouping_state *gs, struct io_state *iop, 126227753Stheraven const CHAR *cp, const CHAR *ep, locale_t locale) 127187582Sdas{ 128187582Sdas const CHAR *cp0 = cp; 129187582Sdas 130227753Stheraven if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale)) 131187582Sdas return (-1); 132187582Sdas cp += gs->lead; 133187582Sdas while (gs->nseps > 0 || gs->nrepeats > 0) { 134187582Sdas if (gs->nrepeats > 0) 135187582Sdas gs->nrepeats--; 136187582Sdas else { 137187582Sdas gs->grouping--; 138187582Sdas gs->nseps--; 139187582Sdas } 140227753Stheraven if (io_print(iop, gs->thousands_sep, gs->thousep_len, locale)) 141187582Sdas return (-1); 142227753Stheraven if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale)) 143187582Sdas return (-1); 144187582Sdas cp += *gs->grouping; 145187582Sdas } 146187582Sdas if (cp > ep) 147187582Sdas cp = ep; 148187582Sdas return (cp - cp0); 149187582Sdas} 150187582Sdas 151187582Sdas/* 1521573Srgrimes * Flush out all the vectors defined by the given uio, 1531573Srgrimes * then reset it so that it can be reused. 1541573Srgrimes */ 1551573Srgrimesstatic int 156227753Stheraven__sprint(FILE *fp, struct __suio *uio, locale_t locale) 1571573Srgrimes{ 15871579Sdeischen int err; 1591573Srgrimes 1601573Srgrimes if (uio->uio_resid == 0) { 1611573Srgrimes uio->uio_iovcnt = 0; 1621573Srgrimes return (0); 1631573Srgrimes } 1641573Srgrimes err = __sfvwrite(fp, uio); 1651573Srgrimes uio->uio_resid = 0; 1661573Srgrimes uio->uio_iovcnt = 0; 1671573Srgrimes return (err); 1681573Srgrimes} 1691573Srgrimes 1701573Srgrimes/* 1711573Srgrimes * Helper function for `fprintf to unbuffered unix file': creates a 1721573Srgrimes * temporary buffer. We only work on write-only files; this avoids 1731573Srgrimes * worries about ungetc buffers and so forth. 1741573Srgrimes */ 1751573Srgrimesstatic int 176227753Stheraven__sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap) 1771573Srgrimes{ 1781573Srgrimes int ret; 179205021Sjhb FILE fake = FAKE_FILE; 1801573Srgrimes unsigned char buf[BUFSIZ]; 1811573Srgrimes 182187369Sdas /* XXX This is probably not needed. */ 183187369Sdas if (prepwrite(fp) != 0) 184187369Sdas return (EOF); 185187369Sdas 1861573Srgrimes /* copy the important variables */ 1871573Srgrimes fake._flags = fp->_flags & ~__SNBF; 1881573Srgrimes fake._file = fp->_file; 1891573Srgrimes fake._cookie = fp->_cookie; 1901573Srgrimes fake._write = fp->_write; 191178287Sjhb fake._orientation = fp->_orientation; 192178287Sjhb fake._mbstate = fp->_mbstate; 1931573Srgrimes 1941573Srgrimes /* set up the buffer */ 1951573Srgrimes fake._bf._base = fake._p = buf; 1961573Srgrimes fake._bf._size = fake._w = sizeof(buf); 1971573Srgrimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 1981573Srgrimes 1991573Srgrimes /* do the work, then copy any error status */ 200227753Stheraven ret = __vfprintf(&fake, locale, fmt, ap); 20171579Sdeischen if (ret >= 0 && __fflush(&fake)) 2021573Srgrimes ret = EOF; 2031573Srgrimes if (fake._flags & __SERR) 2041573Srgrimes fp->_flags |= __SERR; 2051573Srgrimes return (ret); 2061573Srgrimes} 2071573Srgrimes 2081573Srgrimes/* 209103633Stjr * Convert a wide character string argument for the %ls format to a multibyte 210148363Stjr * string representation. If not -1, prec specifies the maximum number of 211148363Stjr * bytes to output, and also means that we can't assume that the wide char. 212148363Stjr * string ends is null-terminated. 213103633Stjr */ 214103633Stjrstatic char * 215103633Stjr__wcsconv(wchar_t *wcsarg, int prec) 216103633Stjr{ 217128002Stjr static const mbstate_t initial; 218128002Stjr mbstate_t mbs; 219103633Stjr char buf[MB_LEN_MAX]; 220103633Stjr wchar_t *p; 221148363Stjr char *convbuf; 222103633Stjr size_t clen, nbytes; 223103633Stjr 224148363Stjr /* Allocate space for the maximum number of bytes we could output. */ 225148363Stjr if (prec < 0) { 226103633Stjr p = wcsarg; 227128002Stjr mbs = initial; 228128002Stjr nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 229103633Stjr if (nbytes == (size_t)-1) 230103633Stjr return (NULL); 231148363Stjr } else { 232148363Stjr /* 233148363Stjr * Optimisation: if the output precision is small enough, 234148363Stjr * just allocate enough memory for the maximum instead of 235148363Stjr * scanning the string. 236148363Stjr */ 237148363Stjr if (prec < 128) 238148363Stjr nbytes = prec; 239148363Stjr else { 240148363Stjr nbytes = 0; 241148363Stjr p = wcsarg; 242148363Stjr mbs = initial; 243148363Stjr for (;;) { 244148363Stjr clen = wcrtomb(buf, *p++, &mbs); 245148363Stjr if (clen == 0 || clen == (size_t)-1 || 246148363Stjr nbytes + clen > prec) 247148363Stjr break; 248148363Stjr nbytes += clen; 249148363Stjr } 250148363Stjr } 251103633Stjr } 252103633Stjr if ((convbuf = malloc(nbytes + 1)) == NULL) 253103633Stjr return (NULL); 254103633Stjr 255148363Stjr /* Fill the output buffer. */ 256103633Stjr p = wcsarg; 257128002Stjr mbs = initial; 258148363Stjr if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, 259148363Stjr nbytes, &mbs)) == (size_t)-1) { 260113196Sache free(convbuf); 261113196Sache return (NULL); 262113196Sache } 263148363Stjr convbuf[nbytes] = '\0'; 264103633Stjr return (convbuf); 265103633Stjr} 266103633Stjr 267103633Stjr/* 26871579Sdeischen * MT-safe version 26971579Sdeischen */ 27071579Sdeischenint 271227753Stheravenvfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0, 272227753Stheraven va_list ap) 27371579Sdeischen{ 27471579Sdeischen int ret; 275227753Stheraven FIX_LOCALE(locale); 27671579Sdeischen 27771579Sdeischen FLOCKFILE(fp); 278187369Sdas /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 279187369Sdas if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 280187369Sdas fp->_file >= 0) 281227753Stheraven ret = __sbprintf(fp, locale, fmt0, ap); 282187369Sdas else 283227753Stheraven ret = __vfprintf(fp, locale, fmt0, ap); 28471579Sdeischen FUNLOCKFILE(fp); 28571579Sdeischen return (ret); 28671579Sdeischen} 287227753Stheravenint 288227753Stheravenvfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) 289227753Stheraven{ 290227753Stheraven return vfprintf_l(fp, __get_locale(), fmt0, ap); 291227753Stheraven} 29271579Sdeischen 293113142Sdas/* 294113142Sdas * The size of the buffer we use as scratch space for integer 295187582Sdas * conversions, among other things. We need enough space to 296187582Sdas * write a uintmax_t in octal (plus one byte). 297113142Sdas */ 298187582Sdas#if UINTMAX_MAX <= UINT64_MAX 299187582Sdas#define BUF 32 300187582Sdas#else 301187582Sdas#error "BUF must be large enough to format a uintmax_t" 302187582Sdas#endif 3031573Srgrimes 3041573Srgrimes/* 30571579Sdeischen * Non-MT-safe version 30671579Sdeischen */ 3071573Srgrimesint 308227753Stheraven__vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) 3091573Srgrimes{ 31071579Sdeischen char *fmt; /* format string */ 31171579Sdeischen int ch; /* character from fmt */ 31271579Sdeischen int n, n2; /* handy integer (short term usage) */ 31371579Sdeischen char *cp; /* handy char pointer (short term usage) */ 31471579Sdeischen int flags; /* flags as above */ 3151573Srgrimes int ret; /* return value accumulator */ 3161573Srgrimes int width; /* width from format (%8d), or 0 */ 317113146Sdas int prec; /* precision from format; <0 for N/A */ 3181573Srgrimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 319187582Sdas struct grouping_state gs; /* thousands' grouping info */ 320187277Sdas 321128819Sdas#ifndef NO_FLOATING_POINT 322113146Sdas /* 323113146Sdas * We can decompose the printed representation of floating 324113146Sdas * point numbers into several parts, some of which may be empty: 325113146Sdas * 326113146Sdas * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 327113146Sdas * A B ---C--- D E F 328113146Sdas * 329113146Sdas * A: 'sign' holds this value if present; '\0' otherwise 330113146Sdas * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 331113146Sdas * C: cp points to the string MMMNNN. Leading and trailing 332113146Sdas * zeros are not in the string and must be added. 333113146Sdas * D: expchar holds this character; '\0' if no exponent, e.g. %f 334113146Sdas * F: at least two digits for decimal, at least one digit for hex 335113146Sdas */ 33687490Sphantom char *decimal_point; /* locale specific decimal point */ 337187421Sdas int decpt_len; /* length of decimal_point */ 338113146Sdas int signflag; /* true if float is negative */ 339113146Sdas union { /* floating point arguments %[aAeEfFgG] */ 340113146Sdas double dbl; 341113146Sdas long double ldbl; 342113146Sdas } fparg; 3431573Srgrimes int expt; /* integer value of exponent */ 344113146Sdas char expchar; /* exponent character: [eEpP\0] */ 345113146Sdas char *dtoaend; /* pointer to end of converted digits */ 3461573Srgrimes int expsize; /* character count for expstr */ 347113146Sdas int ndig; /* actual number of digits returned by dtoa */ 348113146Sdas char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 34972523Stegge char *dtoaresult; /* buffer allocated by dtoa */ 3501573Srgrimes#endif 3511573Srgrimes u_long ulval; /* integer arguments %[diouxX] */ 35287113Sfenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 3531573Srgrimes int base; /* base for [diouxX] conversion */ 3541573Srgrimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 35514727Sfenner int realsz; /* field size expanded by dprec, sign, etc */ 3561573Srgrimes int size; /* size of converted field or string */ 35731983Sache int prsize; /* max size of printed field */ 358113146Sdas const char *xdigs; /* digits for %[xX] conversion */ 359187277Sdas struct io_state io; /* I/O buffering state */ 360113142Sdas char buf[BUF]; /* buffer with space for digits of uintmax_t */ 361113146Sdas char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 362103399Stjr union arg *argtable; /* args, built due to positional arg */ 363103399Stjr union arg statargtable [STATIC_ARG_TBL_SIZE]; 364103399Stjr int nextarg; /* 1-based argument index */ 365103399Stjr va_list orgap; /* original argument pointer */ 366103633Stjr char *convbuf; /* wide to multibyte conversion result */ 3671573Srgrimes 368165742Sdas static const char xdigs_lower[16] = "0123456789abcdef"; 369165742Sdas static const char xdigs_upper[16] = "0123456789ABCDEF"; 370113146Sdas 371187277Sdas /* BEWARE, these `goto error' on error. */ 3721573Srgrimes#define PRINT(ptr, len) { \ 373227753Stheraven if (io_print(&io, (ptr), (len), locale)) \ 374187277Sdas goto error; \ 3751573Srgrimes} 3761573Srgrimes#define PAD(howmany, with) { \ 377227753Stheraven if (io_pad(&io, (howmany), (with), locale)) \ 378187277Sdas goto error; \ 3791573Srgrimes} 380187277Sdas#define PRINTANDPAD(p, ep, len, with) { \ 381227753Stheraven if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \ 382187277Sdas goto error; \ 383187277Sdas} 3841573Srgrimes#define FLUSH() { \ 385227753Stheraven if (io_flush(&io, locale)) \ 3861573Srgrimes goto error; \ 3871573Srgrimes} 3881573Srgrimes 389103399Stjr /* 390103399Stjr * Get the argument indexed by nextarg. If the argument table is 391103399Stjr * built, use it to get the argument. If its not, get the next 392103399Stjr * argument (and arguments must be gotten sequentially). 393103399Stjr */ 39421674Sjkh#define GETARG(type) \ 395103399Stjr ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 396103399Stjr (nextarg++, va_arg(ap, type))) 39721674Sjkh 3981573Srgrimes /* 3991573Srgrimes * To extend shorts properly, we need both signed and unsigned 4001573Srgrimes * argument extraction methods. 4011573Srgrimes */ 4021573Srgrimes#define SARG() \ 40321674Sjkh (flags&LONGINT ? GETARG(long) : \ 40421674Sjkh flags&SHORTINT ? (long)(short)GETARG(int) : \ 40587113Sfenner flags&CHARINT ? (long)(signed char)GETARG(int) : \ 40621674Sjkh (long)GETARG(int)) 4071573Srgrimes#define UARG() \ 40821674Sjkh (flags&LONGINT ? GETARG(u_long) : \ 40921674Sjkh flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 41087113Sfenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 41121674Sjkh (u_long)GETARG(u_int)) 41287113Sfenner#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 41387113Sfenner#define SJARG() \ 41487113Sfenner (flags&INTMAXT ? GETARG(intmax_t) : \ 415189131Sdas flags&SIZET ? (intmax_t)GETARG(ssize_t) : \ 41687113Sfenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 41787113Sfenner (intmax_t)GETARG(long long)) 41887113Sfenner#define UJARG() \ 41987113Sfenner (flags&INTMAXT ? GETARG(uintmax_t) : \ 42087113Sfenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 42187113Sfenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 42287113Sfenner (uintmax_t)GETARG(unsigned long long)) 4231573Srgrimes 424103399Stjr /* 425103399Stjr * Get * arguments, including the form *nn$. Preserve the nextarg 426103399Stjr * that the argument can be gotten once the type is determined. 427103399Stjr */ 42821674Sjkh#define GETASTER(val) \ 429103399Stjr n2 = 0; \ 430103399Stjr cp = fmt; \ 431103399Stjr while (is_digit(*cp)) { \ 432103399Stjr n2 = 10 * n2 + to_digit(*cp); \ 433103399Stjr cp++; \ 434103399Stjr } \ 435103399Stjr if (*cp == '$') { \ 436103399Stjr int hold = nextarg; \ 437103399Stjr if (argtable == NULL) { \ 438103399Stjr argtable = statargtable; \ 439180106Sdas if (__find_arguments (fmt0, orgap, &argtable)) { \ 440180106Sdas ret = EOF; \ 441180106Sdas goto error; \ 442180106Sdas } \ 443103399Stjr } \ 444103399Stjr nextarg = n2; \ 44521674Sjkh val = GETARG (int); \ 446103399Stjr nextarg = hold; \ 447103399Stjr fmt = ++cp; \ 448103399Stjr } else { \ 449103399Stjr val = GETARG (int); \ 450103399Stjr } 45187815Sphantom 452185825Sdas if (__use_xprintf == 0 && getenv("USE_XPRINTF")) 453185825Sdas __use_xprintf = 1; 454185825Sdas if (__use_xprintf > 0) 455185825Sdas return (__xvprintf(fp, fmt0, ap)); 45688057Sphantom 4571573Srgrimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 458130231Sdas if (prepwrite(fp) != 0) 4591573Srgrimes return (EOF); 4601573Srgrimes 461185904Sdas convbuf = NULL; 4621573Srgrimes fmt = (char *)fmt0; 463103399Stjr argtable = NULL; 464103399Stjr nextarg = 1; 465103876Stjr va_copy(orgap, ap); 466187277Sdas io_init(&io, fp); 4671573Srgrimes ret = 0; 468185904Sdas#ifndef NO_FLOATING_POINT 469185904Sdas dtoaresult = NULL; 470227753Stheraven decimal_point = localeconv_l(locale)->decimal_point; 471187421Sdas /* The overwhelmingly common case is decpt_len == 1. */ 472187421Sdas decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point)); 473185904Sdas#endif 4741573Srgrimes 4751573Srgrimes /* 4761573Srgrimes * Scan the format for conversions (`%' character). 4771573Srgrimes */ 4781573Srgrimes for (;;) { 4791573Srgrimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 4801573Srgrimes /* void */; 4811573Srgrimes if ((n = fmt - cp) != 0) { 48232253Sache if ((unsigned)ret + n > INT_MAX) { 48331983Sache ret = EOF; 484234531Sdas errno = EOVERFLOW; 48531983Sache goto error; 48631983Sache } 4871573Srgrimes PRINT(cp, n); 4881573Srgrimes ret += n; 4891573Srgrimes } 4901573Srgrimes if (ch == '\0') 4911573Srgrimes goto done; 4921573Srgrimes fmt++; /* skip over '%' */ 4931573Srgrimes 4941573Srgrimes flags = 0; 4951573Srgrimes dprec = 0; 4961573Srgrimes width = 0; 4971573Srgrimes prec = -1; 498187582Sdas gs.grouping = NULL; 4991573Srgrimes sign = '\0'; 500113146Sdas ox[1] = '\0'; 5011573Srgrimes 5021573Srgrimesrflag: ch = *fmt++; 5031573Srgrimesreswitch: switch (ch) { 5041573Srgrimes case ' ': 50588057Sphantom /*- 5061573Srgrimes * ``If the space and + flags both appear, the space 5071573Srgrimes * flag will be ignored.'' 5081573Srgrimes * -- ANSI X3J11 5091573Srgrimes */ 5101573Srgrimes if (!sign) 5111573Srgrimes sign = ' '; 5121573Srgrimes goto rflag; 5131573Srgrimes case '#': 5141573Srgrimes flags |= ALT; 5151573Srgrimes goto rflag; 5161573Srgrimes case '*': 51788057Sphantom /*- 5181573Srgrimes * ``A negative field width argument is taken as a 5191573Srgrimes * - flag followed by a positive field width.'' 5201573Srgrimes * -- ANSI X3J11 5211573Srgrimes * They don't exclude field widths read from args. 5221573Srgrimes */ 52321674Sjkh GETASTER (width); 52421674Sjkh if (width >= 0) 5251573Srgrimes goto rflag; 5261573Srgrimes width = -width; 5271573Srgrimes /* FALLTHROUGH */ 5281573Srgrimes case '-': 5291573Srgrimes flags |= LADJUST; 5301573Srgrimes goto rflag; 5311573Srgrimes case '+': 5321573Srgrimes sign = '+'; 5331573Srgrimes goto rflag; 53487113Sfenner case '\'': 53587815Sphantom flags |= GROUPING; 53687113Sfenner goto rflag; 5371573Srgrimes case '.': 5381573Srgrimes if ((ch = *fmt++) == '*') { 539113191Sdas GETASTER (prec); 5401573Srgrimes goto rflag; 5411573Srgrimes } 542113191Sdas prec = 0; 5431573Srgrimes while (is_digit(ch)) { 544113191Sdas prec = 10 * prec + to_digit(ch); 5451573Srgrimes ch = *fmt++; 5461573Srgrimes } 5471573Srgrimes goto reswitch; 5481573Srgrimes case '0': 54988057Sphantom /*- 5501573Srgrimes * ``Note that 0 is taken as a flag, not as the 5511573Srgrimes * beginning of a field width.'' 5521573Srgrimes * -- ANSI X3J11 5531573Srgrimes */ 5541573Srgrimes flags |= ZEROPAD; 5551573Srgrimes goto rflag; 5561573Srgrimes case '1': case '2': case '3': case '4': 5571573Srgrimes case '5': case '6': case '7': case '8': case '9': 5581573Srgrimes n = 0; 5591573Srgrimes do { 5601573Srgrimes n = 10 * n + to_digit(ch); 5611573Srgrimes ch = *fmt++; 5621573Srgrimes } while (is_digit(ch)); 56321674Sjkh if (ch == '$') { 56421674Sjkh nextarg = n; 565103399Stjr if (argtable == NULL) { 566103399Stjr argtable = statargtable; 567180106Sdas if (__find_arguments (fmt0, orgap, 568180106Sdas &argtable)) { 569180106Sdas ret = EOF; 570180106Sdas goto error; 571180106Sdas } 57221674Sjkh } 57321674Sjkh goto rflag; 574103399Stjr } 5751573Srgrimes width = n; 5761573Srgrimes goto reswitch; 577128819Sdas#ifndef NO_FLOATING_POINT 5781573Srgrimes case 'L': 5791573Srgrimes flags |= LONGDBL; 5801573Srgrimes goto rflag; 5811573Srgrimes#endif 5821573Srgrimes case 'h': 58387113Sfenner if (flags & SHORTINT) { 58487113Sfenner flags &= ~SHORTINT; 58587113Sfenner flags |= CHARINT; 58687113Sfenner } else 58787113Sfenner flags |= SHORTINT; 5881573Srgrimes goto rflag; 58987113Sfenner case 'j': 59087113Sfenner flags |= INTMAXT; 59187113Sfenner goto rflag; 5921573Srgrimes case 'l': 59387113Sfenner if (flags & LONGINT) { 59487113Sfenner flags &= ~LONGINT; 59587113Sfenner flags |= LLONGINT; 59687113Sfenner } else 59744674Sdfr flags |= LONGINT; 5981573Srgrimes goto rflag; 5991573Srgrimes case 'q': 60087113Sfenner flags |= LLONGINT; /* not necessarily */ 6011573Srgrimes goto rflag; 60287113Sfenner case 't': 60387113Sfenner flags |= PTRDIFFT; 60487113Sfenner goto rflag; 60587113Sfenner case 'z': 60687113Sfenner flags |= SIZET; 60787113Sfenner goto rflag; 608105204Stjr case 'C': 609105204Stjr flags |= LONGINT; 610105204Stjr /*FALLTHROUGH*/ 6111573Srgrimes case 'c': 612103633Stjr if (flags & LONGINT) { 613128002Stjr static const mbstate_t initial; 614128002Stjr mbstate_t mbs; 615103633Stjr size_t mbseqlen; 616103633Stjr 617128002Stjr mbs = initial; 618103633Stjr mbseqlen = wcrtomb(cp = buf, 619128002Stjr (wchar_t)GETARG(wint_t), &mbs); 620105234Stjr if (mbseqlen == (size_t)-1) { 621105234Stjr fp->_flags |= __SERR; 622103633Stjr goto error; 623105234Stjr } 624103633Stjr size = (int)mbseqlen; 625103633Stjr } else { 626103633Stjr *(cp = buf) = GETARG(int); 627103633Stjr size = 1; 628103633Stjr } 6291573Srgrimes sign = '\0'; 6301573Srgrimes break; 6311573Srgrimes case 'D': 6321573Srgrimes flags |= LONGINT; 6331573Srgrimes /*FALLTHROUGH*/ 6341573Srgrimes case 'd': 6351573Srgrimes case 'i': 63687113Sfenner if (flags & INTMAX_SIZE) { 63787113Sfenner ujval = SJARG(); 63887113Sfenner if ((intmax_t)ujval < 0) { 63987113Sfenner ujval = -ujval; 6401573Srgrimes sign = '-'; 6411573Srgrimes } 6421573Srgrimes } else { 6431573Srgrimes ulval = SARG(); 6441573Srgrimes if ((long)ulval < 0) { 6451573Srgrimes ulval = -ulval; 6461573Srgrimes sign = '-'; 6471573Srgrimes } 6481573Srgrimes } 6491573Srgrimes base = 10; 6501573Srgrimes goto number; 651128819Sdas#ifndef NO_FLOATING_POINT 65287113Sfenner case 'a': 65387113Sfenner case 'A': 654113146Sdas if (ch == 'a') { 655113146Sdas ox[1] = 'x'; 656113146Sdas xdigs = xdigs_lower; 657113146Sdas expchar = 'p'; 658113146Sdas } else { 659113146Sdas ox[1] = 'X'; 660113146Sdas xdigs = xdigs_upper; 661113146Sdas expchar = 'P'; 662113146Sdas } 663124657Sdas if (prec >= 0) 664124657Sdas prec++; 665124657Sdas if (dtoaresult != NULL) 666124657Sdas freedtoa(dtoaresult); 667113146Sdas if (flags & LONGDBL) { 668124657Sdas fparg.ldbl = GETARG(long double); 669113146Sdas dtoaresult = cp = 670113146Sdas __hldtoa(fparg.ldbl, xdigs, prec, 671113146Sdas &expt, &signflag, &dtoaend); 672113146Sdas } else { 673113146Sdas fparg.dbl = GETARG(double); 674113146Sdas dtoaresult = cp = 675113146Sdas __hdtoa(fparg.dbl, xdigs, prec, 676113146Sdas &expt, &signflag, &dtoaend); 677113146Sdas } 678124657Sdas if (prec < 0) 679124657Sdas prec = dtoaend - cp; 680124657Sdas if (expt == INT_MAX) 681124657Sdas ox[1] = '\0'; 682124657Sdas goto fp_common; 6837033Sbde case 'e': 6841573Srgrimes case 'E': 685113146Sdas expchar = ch; 686113146Sdas if (prec < 0) /* account for digit before decpt */ 687113146Sdas prec = DEFPREC + 1; 688113146Sdas else 689113146Sdas prec++; 690113146Sdas goto fp_begin; 6917033Sbde case 'f': 69287113Sfenner case 'F': 693113146Sdas expchar = '\0'; 6947033Sbde goto fp_begin; 6951573Srgrimes case 'g': 6961573Srgrimes case 'G': 697113146Sdas expchar = ch - ('g' - 'e'); 6987033Sbde if (prec == 0) 6997033Sbde prec = 1; 700113146Sdasfp_begin: 701113146Sdas if (prec < 0) 7021573Srgrimes prec = DEFPREC; 703113146Sdas if (dtoaresult != NULL) 704113146Sdas freedtoa(dtoaresult); 705113146Sdas if (flags & LONGDBL) { 706113146Sdas fparg.ldbl = GETARG(long double); 707113146Sdas dtoaresult = cp = 708113146Sdas __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 709113146Sdas &expt, &signflag, &dtoaend); 710113146Sdas } else { 711113146Sdas fparg.dbl = GETARG(double); 712113146Sdas dtoaresult = cp = 713113146Sdas dtoa(fparg.dbl, expchar ? 2 : 3, prec, 714113146Sdas &expt, &signflag, &dtoaend); 715113146Sdas if (expt == 9999) 716113146Sdas expt = INT_MAX; 7171573Srgrimes } 718124657Sdasfp_common: 719113146Sdas if (signflag) 720113146Sdas sign = '-'; 721113146Sdas if (expt == INT_MAX) { /* inf or nan */ 722113146Sdas if (*cp == 'N') { 723113146Sdas cp = (ch >= 'a') ? "nan" : "NAN"; 724113146Sdas sign = '\0'; 725113146Sdas } else 726113146Sdas cp = (ch >= 'a') ? "inf" : "INF"; 7271573Srgrimes size = 3; 728169355Sdas flags &= ~ZEROPAD; 7291573Srgrimes break; 7301573Srgrimes } 7311573Srgrimes flags |= FPT; 732113146Sdas ndig = dtoaend - cp; 7331573Srgrimes if (ch == 'g' || ch == 'G') { 734113146Sdas if (expt > -4 && expt <= prec) { 735113146Sdas /* Make %[gG] smell like %[fF] */ 736113146Sdas expchar = '\0'; 737113146Sdas if (flags & ALT) 738113146Sdas prec -= expt; 739113146Sdas else 740113146Sdas prec = ndig - expt; 741113146Sdas if (prec < 0) 742113146Sdas prec = 0; 743113723Sdas } else { 744113723Sdas /* 745113723Sdas * Make %[gG] smell like %[eE], but 746113723Sdas * trim trailing zeroes if no # flag. 747113723Sdas */ 748113723Sdas if (!(flags & ALT)) 749113723Sdas prec = ndig; 750113146Sdas } 7518870Srgrimes } 752113146Sdas if (expchar) { 753113146Sdas expsize = exponent(expstr, expt - 1, expchar); 754113146Sdas size = expsize + prec; 755113191Sdas if (prec > 1 || flags & ALT) 756187421Sdas size += decpt_len; 757113146Sdas } else { 758113468Sdas /* space for digits before decimal point */ 759113468Sdas if (expt > 0) 7601573Srgrimes size = expt; 761113468Sdas else /* "0" */ 762113468Sdas size = 1; 763113468Sdas /* space for decimal pt and following digits */ 764113468Sdas if (prec || flags & ALT) 765187421Sdas size += prec + decpt_len; 766187582Sdas if ((flags & GROUPING) && expt > 0) 767227753Stheraven size += grouping_init(&gs, expt, locale); 768113146Sdas } 7691573Srgrimes break; 770128819Sdas#endif /* !NO_FLOATING_POINT */ 7711573Srgrimes case 'n': 77287113Sfenner /* 77387113Sfenner * Assignment-like behavior is specified if the 77487113Sfenner * value overflows or is otherwise unrepresentable. 77587113Sfenner * C99 says to use `signed char' for %hhn conversions. 77687113Sfenner */ 77787113Sfenner if (flags & LLONGINT) 77887113Sfenner *GETARG(long long *) = ret; 77987113Sfenner else if (flags & SIZET) 78087113Sfenner *GETARG(ssize_t *) = (ssize_t)ret; 78187113Sfenner else if (flags & PTRDIFFT) 78287113Sfenner *GETARG(ptrdiff_t *) = ret; 78387113Sfenner else if (flags & INTMAXT) 78487113Sfenner *GETARG(intmax_t *) = ret; 7851573Srgrimes else if (flags & LONGINT) 78631980Sache *GETARG(long *) = ret; 7871573Srgrimes else if (flags & SHORTINT) 78831980Sache *GETARG(short *) = ret; 78987113Sfenner else if (flags & CHARINT) 79087113Sfenner *GETARG(signed char *) = ret; 7911573Srgrimes else 79231980Sache *GETARG(int *) = ret; 7931573Srgrimes continue; /* no output */ 7941573Srgrimes case 'O': 7951573Srgrimes flags |= LONGINT; 7961573Srgrimes /*FALLTHROUGH*/ 7971573Srgrimes case 'o': 79887113Sfenner if (flags & INTMAX_SIZE) 79987113Sfenner ujval = UJARG(); 8001573Srgrimes else 8011573Srgrimes ulval = UARG(); 8021573Srgrimes base = 8; 8031573Srgrimes goto nosign; 8041573Srgrimes case 'p': 80588057Sphantom /*- 8061573Srgrimes * ``The argument shall be a pointer to void. The 8071573Srgrimes * value of the pointer is converted to a sequence 8081573Srgrimes * of printable characters, in an implementation- 8091573Srgrimes * defined manner.'' 8101573Srgrimes * -- ANSI X3J11 8111573Srgrimes */ 81287113Sfenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 8131573Srgrimes base = 16; 814113146Sdas xdigs = xdigs_lower; 815113146Sdas flags = flags | INTMAXT; 816113146Sdas ox[1] = 'x'; 8171573Srgrimes goto nosign; 818105204Stjr case 'S': 819105204Stjr flags |= LONGINT; 820105204Stjr /*FALLTHROUGH*/ 8211573Srgrimes case 's': 822103633Stjr if (flags & LONGINT) { 823103633Stjr wchar_t *wcp; 824103633Stjr 825103633Stjr if (convbuf != NULL) 826103633Stjr free(convbuf); 827103633Stjr if ((wcp = GETARG(wchar_t *)) == NULL) 828103633Stjr cp = "(null)"; 829103633Stjr else { 830103633Stjr convbuf = __wcsconv(wcp, prec); 831105234Stjr if (convbuf == NULL) { 832105234Stjr fp->_flags |= __SERR; 833103633Stjr goto error; 834105234Stjr } 835103633Stjr cp = convbuf; 836103633Stjr } 837103633Stjr } else if ((cp = GETARG(char *)) == NULL) 8381573Srgrimes cp = "(null)"; 839189138Sdas size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp); 8401573Srgrimes sign = '\0'; 8411573Srgrimes break; 8421573Srgrimes case 'U': 8431573Srgrimes flags |= LONGINT; 8441573Srgrimes /*FALLTHROUGH*/ 8451573Srgrimes case 'u': 84687113Sfenner if (flags & INTMAX_SIZE) 84787113Sfenner ujval = UJARG(); 8481573Srgrimes else 8491573Srgrimes ulval = UARG(); 8501573Srgrimes base = 10; 8511573Srgrimes goto nosign; 8521573Srgrimes case 'X': 853113146Sdas xdigs = xdigs_upper; 8541573Srgrimes goto hex; 8551573Srgrimes case 'x': 856113146Sdas xdigs = xdigs_lower; 85787113Sfennerhex: 85887113Sfenner if (flags & INTMAX_SIZE) 85987113Sfenner ujval = UJARG(); 8601573Srgrimes else 8611573Srgrimes ulval = UARG(); 8621573Srgrimes base = 16; 8631573Srgrimes /* leading 0x/X only if non-zero */ 8641573Srgrimes if (flags & ALT && 86587113Sfenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 866113146Sdas ox[1] = ch; 8671573Srgrimes 86887815Sphantom flags &= ~GROUPING; 8691573Srgrimes /* unsigned conversions */ 8701573Srgrimesnosign: sign = '\0'; 87188057Sphantom /*- 8721573Srgrimes * ``... diouXx conversions ... if a precision is 8731573Srgrimes * specified, the 0 flag will be ignored.'' 8741573Srgrimes * -- ANSI X3J11 8751573Srgrimes */ 8761573Srgrimesnumber: if ((dprec = prec) >= 0) 8771573Srgrimes flags &= ~ZEROPAD; 8781573Srgrimes 87988057Sphantom /*- 8801573Srgrimes * ``The result of converting a zero value with an 8811573Srgrimes * explicit precision of zero is no characters.'' 8821573Srgrimes * -- ANSI X3J11 883145172Sdas * 884145172Sdas * ``The C Standard is clear enough as is. The call 885145172Sdas * printf("%#.0o", 0) should print 0.'' 886145172Sdas * -- Defect Report #151 8871573Srgrimes */ 8881573Srgrimes cp = buf + BUF; 88987113Sfenner if (flags & INTMAX_SIZE) { 890145172Sdas if (ujval != 0 || prec != 0 || 891145172Sdas (flags & ALT && base == 8)) 89287113Sfenner cp = __ujtoa(ujval, cp, base, 893187582Sdas flags & ALT, xdigs); 8941573Srgrimes } else { 895145172Sdas if (ulval != 0 || prec != 0 || 896145172Sdas (flags & ALT && base == 8)) 8971573Srgrimes cp = __ultoa(ulval, cp, base, 898187582Sdas flags & ALT, xdigs); 8991573Srgrimes } 9001573Srgrimes size = buf + BUF - cp; 901113142Sdas if (size > BUF) /* should never happen */ 902113142Sdas abort(); 903187582Sdas if ((flags & GROUPING) && size != 0) 904227753Stheraven size += grouping_init(&gs, size, locale); 9051573Srgrimes break; 9061573Srgrimes default: /* "%?" prints ?, unless ? is NUL */ 9071573Srgrimes if (ch == '\0') 9081573Srgrimes goto done; 9091573Srgrimes /* pretend it was %c with argument ch */ 9101573Srgrimes cp = buf; 9111573Srgrimes *cp = ch; 9121573Srgrimes size = 1; 9131573Srgrimes sign = '\0'; 9141573Srgrimes break; 9151573Srgrimes } 9161573Srgrimes 9171573Srgrimes /* 9181573Srgrimes * All reasonable formats wind up here. At this point, `cp' 9191573Srgrimes * points to a string which (if not flags&LADJUST) should be 9201573Srgrimes * padded out to `width' places. If flags&ZEROPAD, it should 9211573Srgrimes * first be prefixed by any sign or other prefix; otherwise, 9221573Srgrimes * it should be blank padded before the prefix is emitted. 9231573Srgrimes * After any left-hand padding and prefixing, emit zeroes 9241573Srgrimes * required by a decimal [diouxX] precision, then print the 9251573Srgrimes * string proper, then emit zeroes required by any leftover 9261573Srgrimes * floating precision; finally, if LADJUST, pad with blanks. 9271573Srgrimes * 9281573Srgrimes * Compute actual size, so we know how much to pad. 92914727Sfenner * size excludes decimal prec; realsz includes it. 9301573Srgrimes */ 93114727Sfenner realsz = dprec > size ? dprec : size; 9321573Srgrimes if (sign) 93314727Sfenner realsz++; 934124657Sdas if (ox[1]) 93514727Sfenner realsz += 2; 9361573Srgrimes 93731983Sache prsize = width > realsz ? width : realsz; 93832253Sache if ((unsigned)ret + prsize > INT_MAX) { 93931983Sache ret = EOF; 940234531Sdas errno = EOVERFLOW; 94131983Sache goto error; 94231983Sache } 94331983Sache 9441573Srgrimes /* right-adjusting blank padding */ 9451573Srgrimes if ((flags & (LADJUST|ZEROPAD)) == 0) 9461573Srgrimes PAD(width - realsz, blanks); 9471573Srgrimes 9481573Srgrimes /* prefix */ 949124657Sdas if (sign) 9501573Srgrimes PRINT(&sign, 1); 951124657Sdas 952124657Sdas if (ox[1]) { /* ox[1] is either x, X, or \0 */ 9531573Srgrimes ox[0] = '0'; 9541573Srgrimes PRINT(ox, 2); 9551573Srgrimes } 9561573Srgrimes 9571573Srgrimes /* right-adjusting zero padding */ 9581573Srgrimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 9591573Srgrimes PAD(width - realsz, zeroes); 9601573Srgrimes 9611573Srgrimes /* the string or number proper */ 962128819Sdas#ifndef NO_FLOATING_POINT 9631573Srgrimes if ((flags & FPT) == 0) { 964187582Sdas#endif 965187582Sdas /* leading zeroes from decimal precision */ 966187582Sdas PAD(dprec - size, zeroes); 967187582Sdas if (gs.grouping) { 968227753Stheraven if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0) 969187582Sdas goto error; 970187582Sdas } else { 971187582Sdas PRINT(cp, size); 972187582Sdas } 973187582Sdas#ifndef NO_FLOATING_POINT 9741573Srgrimes } else { /* glue together f_p fragments */ 975113146Sdas if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 976113146Sdas if (expt <= 0) { 977113468Sdas PRINT(zeroes, 1); 978113468Sdas if (prec || flags & ALT) 979187421Sdas PRINT(decimal_point,decpt_len); 9801573Srgrimes PAD(-expt, zeroes); 981113191Sdas /* already handled initial 0's */ 982113191Sdas prec += expt; 9831573Srgrimes } else { 984187582Sdas if (gs.grouping) { 985187582Sdas n = grouping_print(&gs, &io, 986227753Stheraven cp, dtoaend, locale); 987187582Sdas if (n < 0) 988187582Sdas goto error; 989187582Sdas cp += n; 990187582Sdas } else { 991187582Sdas PRINTANDPAD(cp, dtoaend, 992187582Sdas expt, zeroes); 993187582Sdas cp += expt; 994113146Sdas } 995113146Sdas if (prec || flags & ALT) 996187421Sdas PRINT(decimal_point,decpt_len); 9971573Srgrimes } 998113191Sdas PRINTANDPAD(cp, dtoaend, prec, zeroes); 999113146Sdas } else { /* %[eE] or sufficiently long %[gG] */ 1000113191Sdas if (prec > 1 || flags & ALT) { 1001187421Sdas PRINT(cp++, 1); 1002187421Sdas PRINT(decimal_point, decpt_len); 1003113146Sdas PRINT(cp, ndig-1); 1004113146Sdas PAD(prec - ndig, zeroes); 10051573Srgrimes } else /* XeYYY */ 10061573Srgrimes PRINT(cp, 1); 10071573Srgrimes PRINT(expstr, expsize); 10081573Srgrimes } 10091573Srgrimes } 10101573Srgrimes#endif 10111573Srgrimes /* left-adjusting padding (always blank) */ 10121573Srgrimes if (flags & LADJUST) 10131573Srgrimes PAD(width - realsz, blanks); 10141573Srgrimes 10151573Srgrimes /* finally, adjust ret */ 101631983Sache ret += prsize; 10171573Srgrimes 10181573Srgrimes FLUSH(); /* copy out the I/O vectors */ 10191573Srgrimes } 10201573Srgrimesdone: 10211573Srgrimes FLUSH(); 10221573Srgrimeserror: 1023134332Sdes va_end(orgap); 1024128819Sdas#ifndef NO_FLOATING_POINT 102572523Stegge if (dtoaresult != NULL) 1026113146Sdas freedtoa(dtoaresult); 102772523Stegge#endif 1028103633Stjr if (convbuf != NULL) 1029103633Stjr free(convbuf); 103013545Sjulian if (__sferror(fp)) 103113545Sjulian ret = EOF; 1032103399Stjr if ((argtable != NULL) && (argtable != statargtable)) 1033103399Stjr free (argtable); 103413545Sjulian return (ret); 10351573Srgrimes /* NOTREACHED */ 10361573Srgrimes} 10371573Srgrimes 1038