158f0484fSRodney W. Grimes /*- 258f0484fSRodney W. Grimes * Copyright (c) 1990, 1993 358f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 458f0484fSRodney W. Grimes * 558f0484fSRodney W. Grimes * This code is derived from software contributed to Berkeley by 658f0484fSRodney W. Grimes * Chris Torek. 758f0484fSRodney W. Grimes * 858f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 958f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 1058f0484fSRodney W. Grimes * are met: 1158f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1258f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1358f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1458f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1558f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1658f0484fSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 1758f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1858f0484fSRodney W. Grimes * without specific prior written permission. 1958f0484fSRodney W. Grimes * 2058f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2158f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2258f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2358f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2458f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2558f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2658f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2758f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2858f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2958f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3058f0484fSRodney W. Grimes * SUCH DAMAGE. 3158f0484fSRodney W. Grimes */ 3258f0484fSRodney W. Grimes 3358f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 3458f0484fSRodney W. Grimes static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 3558f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 36333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 37333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 3858f0484fSRodney W. Grimes 3958f0484fSRodney W. Grimes /* 4058f0484fSRodney W. Grimes * Actual printf innards. 4158f0484fSRodney W. Grimes * 4258f0484fSRodney W. Grimes * This code is large and complicated... 4358f0484fSRodney W. Grimes */ 4458f0484fSRodney W. Grimes 45d201fe46SDaniel Eischen #include "namespace.h" 4658f0484fSRodney W. Grimes #include <sys/types.h> 4758f0484fSRodney W. Grimes 487735bb0fSBill Fenner #include <ctype.h> 4958f0484fSRodney W. Grimes #include <limits.h> 507ae5c679SAlexey Zelkin #include <locale.h> 517735bb0fSBill Fenner #include <stddef.h> 527735bb0fSBill Fenner #include <stdint.h> 5358f0484fSRodney W. Grimes #include <stdio.h> 5458f0484fSRodney W. Grimes #include <stdlib.h> 5558f0484fSRodney W. Grimes #include <string.h> 56b9aac308STim J. Robbins #include <wchar.h> 5775067f4fSPoul-Henning Kamp #include <printf.h> 5858f0484fSRodney W. Grimes 5958f0484fSRodney W. Grimes #include <stdarg.h> 60d201fe46SDaniel Eischen #include "un-namespace.h" 6158f0484fSRodney W. Grimes 62d201fe46SDaniel Eischen #include "libc_private.h" 6358f0484fSRodney W. Grimes #include "local.h" 6458f0484fSRodney W. Grimes #include "fvwrite.h" 652591efccSDavid Schultz #include "printflocal.h" 66e5abb5e6SDavid Schultz 67c05ac53bSDavid E. O'Brien static int __sprint(FILE *, struct __suio *); 681372519bSDavid E. O'Brien static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0); 69ebbad5ecSDavid Schultz static char *__ujtoa(uintmax_t, char *, int, int, const char *, int, char, 701372519bSDavid E. O'Brien const char *); 71ebbad5ecSDavid Schultz static char *__ultoa(u_long, char *, int, int, const char *, int, char, 721372519bSDavid E. O'Brien const char *); 73b9aac308STim J. Robbins static char *__wcsconv(wchar_t *, int); 74ce51cf03SJames Raynard 7558f0484fSRodney W. Grimes /* 7658f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio, 7758f0484fSRodney W. Grimes * then reset it so that it can be reused. 7858f0484fSRodney W. Grimes */ 7958f0484fSRodney W. Grimes static int 80d201fe46SDaniel Eischen __sprint(FILE *fp, struct __suio *uio) 8158f0484fSRodney W. Grimes { 82d201fe46SDaniel Eischen int err; 8358f0484fSRodney W. Grimes 8458f0484fSRodney W. Grimes if (uio->uio_resid == 0) { 8558f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 8658f0484fSRodney W. Grimes return (0); 8758f0484fSRodney W. Grimes } 8858f0484fSRodney W. Grimes err = __sfvwrite(fp, uio); 8958f0484fSRodney W. Grimes uio->uio_resid = 0; 9058f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 9158f0484fSRodney W. Grimes return (err); 9258f0484fSRodney W. Grimes } 9358f0484fSRodney W. Grimes 9458f0484fSRodney W. Grimes /* 9558f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a 9658f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids 9758f0484fSRodney W. Grimes * worries about ungetc buffers and so forth. 9858f0484fSRodney W. Grimes */ 9958f0484fSRodney W. Grimes static int 100d201fe46SDaniel Eischen __sbprintf(FILE *fp, const char *fmt, va_list ap) 10158f0484fSRodney W. Grimes { 10258f0484fSRodney W. Grimes int ret; 10358f0484fSRodney W. Grimes FILE fake; 10458f0484fSRodney W. Grimes unsigned char buf[BUFSIZ]; 10558f0484fSRodney W. Grimes 10658f0484fSRodney W. Grimes /* copy the important variables */ 10758f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF; 10858f0484fSRodney W. Grimes fake._file = fp->_file; 10958f0484fSRodney W. Grimes fake._cookie = fp->_cookie; 11058f0484fSRodney W. Grimes fake._write = fp->_write; 1111e98f887SJohn Baldwin fake._orientation = fp->_orientation; 1121e98f887SJohn Baldwin fake._mbstate = fp->_mbstate; 11358f0484fSRodney W. Grimes 11458f0484fSRodney W. Grimes /* set up the buffer */ 11558f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 11658f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 11758f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 11858f0484fSRodney W. Grimes 11958f0484fSRodney W. Grimes /* do the work, then copy any error status */ 120d201fe46SDaniel Eischen ret = __vfprintf(&fake, fmt, ap); 121d201fe46SDaniel Eischen if (ret >= 0 && __fflush(&fake)) 12258f0484fSRodney W. Grimes ret = EOF; 12358f0484fSRodney W. Grimes if (fake._flags & __SERR) 12458f0484fSRodney W. Grimes fp->_flags |= __SERR; 12558f0484fSRodney W. Grimes return (ret); 12658f0484fSRodney W. Grimes } 12758f0484fSRodney W. Grimes 12858f0484fSRodney W. Grimes /* 12958f0484fSRodney W. Grimes * Convert an unsigned long to ASCII for printf purposes, returning 13058f0484fSRodney W. Grimes * a pointer to the first character of the string representation. 13158f0484fSRodney W. Grimes * Octal numbers can be forced to have a leading zero; hex numbers 13258f0484fSRodney W. Grimes * use the given digits. 13358f0484fSRodney W. Grimes */ 13458f0484fSRodney W. Grimes static char * 135ebbad5ecSDavid Schultz __ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs, 13698ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 13758f0484fSRodney W. Grimes { 1388fb3f3f6SDavid E. O'Brien char *cp = endp; 1398fb3f3f6SDavid E. O'Brien long sval; 1407735bb0fSBill Fenner int ndig; 14158f0484fSRodney W. Grimes 14258f0484fSRodney W. Grimes /* 14358f0484fSRodney W. Grimes * Handle the three cases separately, in the hope of getting 14458f0484fSRodney W. Grimes * better/faster code. 14558f0484fSRodney W. Grimes */ 14658f0484fSRodney W. Grimes switch (base) { 14758f0484fSRodney W. Grimes case 10: 14858f0484fSRodney W. Grimes if (val < 10) { /* many numbers are 1 digit */ 14958f0484fSRodney W. Grimes *--cp = to_char(val); 15058f0484fSRodney W. Grimes return (cp); 15158f0484fSRodney W. Grimes } 1527735bb0fSBill Fenner ndig = 0; 15358f0484fSRodney W. Grimes /* 15458f0484fSRodney W. Grimes * On many machines, unsigned arithmetic is harder than 15558f0484fSRodney W. Grimes * signed arithmetic, so we do at most one unsigned mod and 15658f0484fSRodney W. Grimes * divide; this is sufficient to reduce the range of 15758f0484fSRodney W. Grimes * the incoming value to where signed arithmetic works. 15858f0484fSRodney W. Grimes */ 15958f0484fSRodney W. Grimes if (val > LONG_MAX) { 16058f0484fSRodney W. Grimes *--cp = to_char(val % 10); 1617735bb0fSBill Fenner ndig++; 16258f0484fSRodney W. Grimes sval = val / 10; 16358f0484fSRodney W. Grimes } else 16458f0484fSRodney W. Grimes sval = val; 16558f0484fSRodney W. Grimes do { 16658f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 16798ee7635SAlexey Zelkin ndig++; 16898ee7635SAlexey Zelkin /* 16998ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 17098ee7635SAlexey Zelkin * should be performed. 17198ee7635SAlexey Zelkin */ 172243e90d6SAlexey Zelkin if (needgrp && ndig == *grp && *grp != CHAR_MAX 173243e90d6SAlexey Zelkin && sval > 9) { 17498ee7635SAlexey Zelkin *--cp = thousep; 1757735bb0fSBill Fenner ndig = 0; 17698ee7635SAlexey Zelkin /* 17798ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 17898ee7635SAlexey Zelkin * use *grp character (last grouping rule) 17998ee7635SAlexey Zelkin * for all next cases 18098ee7635SAlexey Zelkin */ 1812e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 1822e394b2fSAlexey Zelkin grp++; 1837735bb0fSBill Fenner } 18458f0484fSRodney W. Grimes sval /= 10; 18558f0484fSRodney W. Grimes } while (sval != 0); 18658f0484fSRodney W. Grimes break; 18758f0484fSRodney W. Grimes 18858f0484fSRodney W. Grimes case 8: 18958f0484fSRodney W. Grimes do { 19058f0484fSRodney W. Grimes *--cp = to_char(val & 7); 19158f0484fSRodney W. Grimes val >>= 3; 19258f0484fSRodney W. Grimes } while (val); 19358f0484fSRodney W. Grimes if (octzero && *cp != '0') 19458f0484fSRodney W. Grimes *--cp = '0'; 19558f0484fSRodney W. Grimes break; 19658f0484fSRodney W. Grimes 19758f0484fSRodney W. Grimes case 16: 19858f0484fSRodney W. Grimes do { 19958f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 20058f0484fSRodney W. Grimes val >>= 4; 20158f0484fSRodney W. Grimes } while (val); 20258f0484fSRodney W. Grimes break; 20358f0484fSRodney W. Grimes 20458f0484fSRodney W. Grimes default: /* oops */ 20558f0484fSRodney W. Grimes abort(); 20658f0484fSRodney W. Grimes } 20758f0484fSRodney W. Grimes return (cp); 20858f0484fSRodney W. Grimes } 20958f0484fSRodney W. Grimes 2107735bb0fSBill Fenner /* Identical to __ultoa, but for intmax_t. */ 21158f0484fSRodney W. Grimes static char * 212ebbad5ecSDavid Schultz __ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs, 21398ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 21458f0484fSRodney W. Grimes { 215d201fe46SDaniel Eischen char *cp = endp; 2167735bb0fSBill Fenner intmax_t sval; 2177735bb0fSBill Fenner int ndig; 21858f0484fSRodney W. Grimes 21958f0484fSRodney W. Grimes /* quick test for small values; __ultoa is typically much faster */ 22058f0484fSRodney W. Grimes /* (perhaps instead we should run until small, then call __ultoa?) */ 22158f0484fSRodney W. Grimes if (val <= ULONG_MAX) 2227735bb0fSBill Fenner return (__ultoa((u_long)val, endp, base, octzero, xdigs, 22398ee7635SAlexey Zelkin needgrp, thousep, grp)); 22458f0484fSRodney W. Grimes switch (base) { 22558f0484fSRodney W. Grimes case 10: 22658f0484fSRodney W. Grimes if (val < 10) { 22758f0484fSRodney W. Grimes *--cp = to_char(val % 10); 22858f0484fSRodney W. Grimes return (cp); 22958f0484fSRodney W. Grimes } 2307735bb0fSBill Fenner ndig = 0; 2317735bb0fSBill Fenner if (val > INTMAX_MAX) { 23258f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2337735bb0fSBill Fenner ndig++; 23458f0484fSRodney W. Grimes sval = val / 10; 23558f0484fSRodney W. Grimes } else 23658f0484fSRodney W. Grimes sval = val; 23758f0484fSRodney W. Grimes do { 23858f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 23998ee7635SAlexey Zelkin ndig++; 24098ee7635SAlexey Zelkin /* 24198ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 24298ee7635SAlexey Zelkin * should be performed. 24398ee7635SAlexey Zelkin */ 244243e90d6SAlexey Zelkin if (needgrp && *grp != CHAR_MAX && ndig == *grp 245243e90d6SAlexey Zelkin && sval > 9) { 24698ee7635SAlexey Zelkin *--cp = thousep; 2477735bb0fSBill Fenner ndig = 0; 24898ee7635SAlexey Zelkin /* 24998ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 25098ee7635SAlexey Zelkin * use *grp character (last grouping rule) 25198ee7635SAlexey Zelkin * for all next cases 25298ee7635SAlexey Zelkin */ 2532e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 2542e394b2fSAlexey Zelkin grp++; 2557735bb0fSBill Fenner } 25658f0484fSRodney W. Grimes sval /= 10; 25758f0484fSRodney W. Grimes } while (sval != 0); 25858f0484fSRodney W. Grimes break; 25958f0484fSRodney W. Grimes 26058f0484fSRodney W. Grimes case 8: 26158f0484fSRodney W. Grimes do { 26258f0484fSRodney W. Grimes *--cp = to_char(val & 7); 26358f0484fSRodney W. Grimes val >>= 3; 26458f0484fSRodney W. Grimes } while (val); 26558f0484fSRodney W. Grimes if (octzero && *cp != '0') 26658f0484fSRodney W. Grimes *--cp = '0'; 26758f0484fSRodney W. Grimes break; 26858f0484fSRodney W. Grimes 26958f0484fSRodney W. Grimes case 16: 27058f0484fSRodney W. Grimes do { 27158f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 27258f0484fSRodney W. Grimes val >>= 4; 27358f0484fSRodney W. Grimes } while (val); 27458f0484fSRodney W. Grimes break; 27558f0484fSRodney W. Grimes 27658f0484fSRodney W. Grimes default: 27758f0484fSRodney W. Grimes abort(); 27858f0484fSRodney W. Grimes } 27958f0484fSRodney W. Grimes return (cp); 28058f0484fSRodney W. Grimes } 28158f0484fSRodney W. Grimes 282d201fe46SDaniel Eischen /* 283b9aac308STim J. Robbins * Convert a wide character string argument for the %ls format to a multibyte 284d48c77b5STim J. Robbins * string representation. If not -1, prec specifies the maximum number of 285d48c77b5STim J. Robbins * bytes to output, and also means that we can't assume that the wide char. 286d48c77b5STim J. Robbins * string ends is null-terminated. 287b9aac308STim J. Robbins */ 288b9aac308STim J. Robbins static char * 289b9aac308STim J. Robbins __wcsconv(wchar_t *wcsarg, int prec) 290b9aac308STim J. Robbins { 29193996f6dSTim J. Robbins static const mbstate_t initial; 29293996f6dSTim J. Robbins mbstate_t mbs; 293b9aac308STim J. Robbins char buf[MB_LEN_MAX]; 294b9aac308STim J. Robbins wchar_t *p; 295d48c77b5STim J. Robbins char *convbuf; 296b9aac308STim J. Robbins size_t clen, nbytes; 297b9aac308STim J. Robbins 298d48c77b5STim J. Robbins /* Allocate space for the maximum number of bytes we could output. */ 299d48c77b5STim J. Robbins if (prec < 0) { 300d48c77b5STim J. Robbins p = wcsarg; 301d48c77b5STim J. Robbins mbs = initial; 302d48c77b5STim J. Robbins nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 303d48c77b5STim J. Robbins if (nbytes == (size_t)-1) 304d48c77b5STim J. Robbins return (NULL); 305d48c77b5STim J. Robbins } else { 306b9aac308STim J. Robbins /* 307d48c77b5STim J. Robbins * Optimisation: if the output precision is small enough, 308d48c77b5STim J. Robbins * just allocate enough memory for the maximum instead of 309d48c77b5STim J. Robbins * scanning the string. 310b9aac308STim J. Robbins */ 311d48c77b5STim J. Robbins if (prec < 128) 312d48c77b5STim J. Robbins nbytes = prec; 313d48c77b5STim J. Robbins else { 314b9aac308STim J. Robbins nbytes = 0; 315b9aac308STim J. Robbins p = wcsarg; 31693996f6dSTim J. Robbins mbs = initial; 317b9aac308STim J. Robbins for (;;) { 31893996f6dSTim J. Robbins clen = wcrtomb(buf, *p++, &mbs); 319b9aac308STim J. Robbins if (clen == 0 || clen == (size_t)-1 || 320b9aac308STim J. Robbins nbytes + clen > prec) 321b9aac308STim J. Robbins break; 322b9aac308STim J. Robbins nbytes += clen; 323b9aac308STim J. Robbins } 324d48c77b5STim J. Robbins } 325b9aac308STim J. Robbins } 326b9aac308STim J. Robbins if ((convbuf = malloc(nbytes + 1)) == NULL) 327b9aac308STim J. Robbins return (NULL); 328b9aac308STim J. Robbins 329d48c77b5STim J. Robbins /* Fill the output buffer. */ 330b9aac308STim J. Robbins p = wcsarg; 33193996f6dSTim J. Robbins mbs = initial; 332d48c77b5STim J. Robbins if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, 333d48c77b5STim J. Robbins nbytes, &mbs)) == (size_t)-1) { 3346f098a48SAndrey A. Chernov free(convbuf); 335b9aac308STim J. Robbins return (NULL); 3366f098a48SAndrey A. Chernov } 337d48c77b5STim J. Robbins convbuf[nbytes] = '\0'; 338b9aac308STim J. Robbins return (convbuf); 339b9aac308STim J. Robbins } 340b9aac308STim J. Robbins 341b9aac308STim J. Robbins /* 342d201fe46SDaniel Eischen * MT-safe version 343d201fe46SDaniel Eischen */ 344d201fe46SDaniel Eischen int 345f8418db7SRobert Drehmel vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) 346f8418db7SRobert Drehmel 347d201fe46SDaniel Eischen { 348d201fe46SDaniel Eischen int ret; 349d201fe46SDaniel Eischen 350d201fe46SDaniel Eischen FLOCKFILE(fp); 351d201fe46SDaniel Eischen ret = __vfprintf(fp, fmt0, ap); 352d201fe46SDaniel Eischen FUNLOCKFILE(fp); 353d201fe46SDaniel Eischen return (ret); 354d201fe46SDaniel Eischen } 355d201fe46SDaniel Eischen 3568de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 357ebbad5ecSDavid Schultz 358ebbad5ecSDavid Schultz #define dtoa __dtoa 359ebbad5ecSDavid Schultz #define freedtoa __freedtoa 360ebbad5ecSDavid Schultz 361ebbad5ecSDavid Schultz #include <float.h> 36258f0484fSRodney W. Grimes #include <math.h> 36358f0484fSRodney W. Grimes #include "floatio.h" 364ebbad5ecSDavid Schultz #include "gdtoa.h" 36558f0484fSRodney W. Grimes 36658f0484fSRodney W. Grimes #define DEFPREC 6 36758f0484fSRodney W. Grimes 368c05ac53bSDavid E. O'Brien static int exponent(char *, int, int); 36958f0484fSRodney W. Grimes 3708de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 37158f0484fSRodney W. Grimes 37238cac8f8SDavid Schultz /* 37338cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer 37438cac8f8SDavid Schultz * conversions, among other things. Technically, we would need the 37538cac8f8SDavid Schultz * most space for base 10 conversions with thousands' grouping 37638cac8f8SDavid Schultz * characters between each pair of digits. 100 bytes is a 37738cac8f8SDavid Schultz * conservative overestimate even for a 128-bit uintmax_t. 37838cac8f8SDavid Schultz */ 37938cac8f8SDavid Schultz #define BUF 100 38038cac8f8SDavid Schultz 38158f0484fSRodney W. Grimes /* 382d201fe46SDaniel Eischen * Non-MT-safe version 383d201fe46SDaniel Eischen */ 38458f0484fSRodney W. Grimes int 385d201fe46SDaniel Eischen __vfprintf(FILE *fp, const char *fmt0, va_list ap) 38658f0484fSRodney W. Grimes { 387d201fe46SDaniel Eischen char *fmt; /* format string */ 388d201fe46SDaniel Eischen int ch; /* character from fmt */ 389d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 390d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 391d201fe46SDaniel Eischen struct __siov *iovp; /* for PRINT macro */ 392d201fe46SDaniel Eischen int flags; /* flags as above */ 39358f0484fSRodney W. Grimes int ret; /* return value accumulator */ 39458f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 395ebbad5ecSDavid Schultz int prec; /* precision from format; <0 for N/A */ 39658f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 39798ee7635SAlexey Zelkin char thousands_sep; /* locale specific thousands separator */ 39898ee7635SAlexey Zelkin const char *grouping; /* locale specific numeric grouping rules */ 3998de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 400ebbad5ecSDavid Schultz /* 401ebbad5ecSDavid Schultz * We can decompose the printed representation of floating 402ebbad5ecSDavid Schultz * point numbers into several parts, some of which may be empty: 403ebbad5ecSDavid Schultz * 404ebbad5ecSDavid Schultz * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 405ebbad5ecSDavid Schultz * A B ---C--- D E F 406ebbad5ecSDavid Schultz * 407ebbad5ecSDavid Schultz * A: 'sign' holds this value if present; '\0' otherwise 408ebbad5ecSDavid Schultz * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 409ebbad5ecSDavid Schultz * C: cp points to the string MMMNNN. Leading and trailing 410ebbad5ecSDavid Schultz * zeros are not in the string and must be added. 411ebbad5ecSDavid Schultz * D: expchar holds this character; '\0' if no exponent, e.g. %f 412ebbad5ecSDavid Schultz * F: at least two digits for decimal, at least one digit for hex 413ebbad5ecSDavid Schultz */ 4147ae5c679SAlexey Zelkin char *decimal_point; /* locale specific decimal point */ 415ebbad5ecSDavid Schultz int signflag; /* true if float is negative */ 416ebbad5ecSDavid Schultz union { /* floating point arguments %[aAeEfFgG] */ 417ebbad5ecSDavid Schultz double dbl; 418ebbad5ecSDavid Schultz long double ldbl; 419ebbad5ecSDavid Schultz } fparg; 42058f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 421ebbad5ecSDavid Schultz char expchar; /* exponent character: [eEpP\0] */ 422ebbad5ecSDavid Schultz char *dtoaend; /* pointer to end of converted digits */ 42358f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 424ebbad5ecSDavid Schultz int lead; /* sig figs before decimal or group sep */ 425ebbad5ecSDavid Schultz int ndig; /* actual number of digits returned by dtoa */ 426ebbad5ecSDavid Schultz char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 4272ffc61baSTor Egge char *dtoaresult; /* buffer allocated by dtoa */ 428ebbad5ecSDavid Schultz int nseps; /* number of group separators with ' */ 429ebbad5ecSDavid Schultz int nrepeats; /* number of repeats of the last group */ 43058f0484fSRodney W. Grimes #endif 43158f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 4327735bb0fSBill Fenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 43358f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 43458f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 435261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 43658f0484fSRodney W. Grimes int size; /* size of converted field or string */ 43792e88f87SAndrey A. Chernov int prsize; /* max size of printed field */ 438ebbad5ecSDavid Schultz const char *xdigs; /* digits for %[xX] conversion */ 43958f0484fSRodney W. Grimes #define NIOV 8 44058f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 44158f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 44238cac8f8SDavid Schultz char buf[BUF]; /* buffer with space for digits of uintmax_t */ 443ebbad5ecSDavid Schultz char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 444a387081cSDoug Rabson union arg *argtable; /* args, built due to positional arg */ 445a387081cSDoug Rabson union arg statargtable [STATIC_ARG_TBL_SIZE]; 446efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 447efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 448b9aac308STim J. Robbins char *convbuf; /* wide to multibyte conversion result */ 44958f0484fSRodney W. Grimes 45058f0484fSRodney W. Grimes /* 45158f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 45258f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 45358f0484fSRodney W. Grimes * below longer. 45458f0484fSRodney W. Grimes */ 45558f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 45658f0484fSRodney W. Grimes static char blanks[PADSIZE] = 45758f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 45858f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 45958f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 46058f0484fSRodney W. Grimes 461ac9913a7SDavid Schultz static const char xdigs_lower[16] = "0123456789abcdef"; 462ac9913a7SDavid Schultz static const char xdigs_upper[16] = "0123456789ABCDEF"; 463ebbad5ecSDavid Schultz 46458f0484fSRodney W. Grimes /* 46558f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 46658f0484fSRodney W. Grimes */ 46758f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 46858f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 46958f0484fSRodney W. Grimes iovp->iov_len = (len); \ 47058f0484fSRodney W. Grimes uio.uio_resid += (len); \ 47158f0484fSRodney W. Grimes iovp++; \ 47258f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 47358f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 47458f0484fSRodney W. Grimes goto error; \ 47558f0484fSRodney W. Grimes iovp = iov; \ 47658f0484fSRodney W. Grimes } \ 47758f0484fSRodney W. Grimes } 47858f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 47958f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 48058f0484fSRodney W. Grimes while (n > PADSIZE) { \ 48158f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 48258f0484fSRodney W. Grimes n -= PADSIZE; \ 48358f0484fSRodney W. Grimes } \ 48458f0484fSRodney W. Grimes PRINT(with, n); \ 48558f0484fSRodney W. Grimes } \ 48658f0484fSRodney W. Grimes } 4873b204b7dSDavid Schultz #define PRINTANDPAD(p, ep, len, with) do { \ 4883b204b7dSDavid Schultz n2 = (ep) - (p); \ 4893b204b7dSDavid Schultz if (n2 > (len)) \ 4903b204b7dSDavid Schultz n2 = (len); \ 4913b204b7dSDavid Schultz if (n2 > 0) \ 4923b204b7dSDavid Schultz PRINT((p), n2); \ 4933b204b7dSDavid Schultz PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ 4943b204b7dSDavid Schultz } while(0) 49558f0484fSRodney W. Grimes #define FLUSH() { \ 49658f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 49758f0484fSRodney W. Grimes goto error; \ 49858f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 49958f0484fSRodney W. Grimes iovp = iov; \ 50058f0484fSRodney W. Grimes } 50158f0484fSRodney W. Grimes 50258f0484fSRodney W. Grimes /* 503efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 504efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 505efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 506efb7e53dSJordan K. Hubbard */ 507efb7e53dSJordan K. Hubbard #define GETARG(type) \ 508a387081cSDoug Rabson ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 509efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 510efb7e53dSJordan K. Hubbard 511efb7e53dSJordan K. Hubbard /* 51258f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 51358f0484fSRodney W. Grimes * argument extraction methods. 51458f0484fSRodney W. Grimes */ 51558f0484fSRodney W. Grimes #define SARG() \ 516efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 517efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 5187735bb0fSBill Fenner flags&CHARINT ? (long)(signed char)GETARG(int) : \ 519efb7e53dSJordan K. Hubbard (long)GETARG(int)) 52058f0484fSRodney W. Grimes #define UARG() \ 521efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 522efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 5237735bb0fSBill Fenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 524efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 5257735bb0fSBill Fenner #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 5267735bb0fSBill Fenner #define SJARG() \ 5277735bb0fSBill Fenner (flags&INTMAXT ? GETARG(intmax_t) : \ 5287735bb0fSBill Fenner flags&SIZET ? (intmax_t)GETARG(size_t) : \ 5297735bb0fSBill Fenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 5307735bb0fSBill Fenner (intmax_t)GETARG(long long)) 5317735bb0fSBill Fenner #define UJARG() \ 5327735bb0fSBill Fenner (flags&INTMAXT ? GETARG(uintmax_t) : \ 5337735bb0fSBill Fenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 5347735bb0fSBill Fenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 5357735bb0fSBill Fenner (uintmax_t)GETARG(unsigned long long)) 536efb7e53dSJordan K. Hubbard 537efb7e53dSJordan K. Hubbard /* 538efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 539efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 540efb7e53dSJordan K. Hubbard */ 541efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 542efb7e53dSJordan K. Hubbard n2 = 0; \ 543efb7e53dSJordan K. Hubbard cp = fmt; \ 544efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 545efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 546efb7e53dSJordan K. Hubbard cp++; \ 547efb7e53dSJordan K. Hubbard } \ 548efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 549efb7e53dSJordan K. Hubbard int hold = nextarg; \ 550efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 551efb7e53dSJordan K. Hubbard argtable = statargtable; \ 552e62e5ff9SDavid Schultz if (__find_arguments (fmt0, orgap, &argtable)) { \ 553e62e5ff9SDavid Schultz ret = EOF; \ 554e62e5ff9SDavid Schultz goto error; \ 555e62e5ff9SDavid Schultz } \ 556efb7e53dSJordan K. Hubbard } \ 557efb7e53dSJordan K. Hubbard nextarg = n2; \ 558efb7e53dSJordan K. Hubbard val = GETARG (int); \ 559efb7e53dSJordan K. Hubbard nextarg = hold; \ 560efb7e53dSJordan K. Hubbard fmt = ++cp; \ 561efb7e53dSJordan K. Hubbard } else { \ 562efb7e53dSJordan K. Hubbard val = GETARG (int); \ 563efb7e53dSJordan K. Hubbard } 564efb7e53dSJordan K. Hubbard 56533bff5d3SDavid Schultz if (__use_xprintf == 0 && getenv("USE_XPRINTF")) 56633bff5d3SDavid Schultz __use_xprintf = 1; 56733bff5d3SDavid Schultz if (__use_xprintf > 0) 56833bff5d3SDavid Schultz return (__xvprintf(fp, fmt0, ap)); 56958f0484fSRodney W. Grimes 57098ee7635SAlexey Zelkin thousands_sep = '\0'; 57198ee7635SAlexey Zelkin grouping = NULL; 572b9aac308STim J. Robbins convbuf = NULL; 5738de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 5742ffc61baSTor Egge dtoaresult = NULL; 5757735bb0fSBill Fenner decimal_point = localeconv()->decimal_point; 5762ffc61baSTor Egge #endif 57758f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 57852183d46SDavid Schultz if (prepwrite(fp) != 0) 57958f0484fSRodney W. Grimes return (EOF); 58058f0484fSRodney W. Grimes 58158f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 58258f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 583d201fe46SDaniel Eischen fp->_file >= 0) 58458f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 58558f0484fSRodney W. Grimes 58658f0484fSRodney W. Grimes fmt = (char *)fmt0; 587efb7e53dSJordan K. Hubbard argtable = NULL; 588efb7e53dSJordan K. Hubbard nextarg = 1; 589d07090a8STim J. Robbins va_copy(orgap, ap); 59058f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 59158f0484fSRodney W. Grimes uio.uio_resid = 0; 59258f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 59358f0484fSRodney W. Grimes ret = 0; 59458f0484fSRodney W. Grimes 59558f0484fSRodney W. Grimes /* 59658f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 59758f0484fSRodney W. Grimes */ 59858f0484fSRodney W. Grimes for (;;) { 59958f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 60058f0484fSRodney W. Grimes /* void */; 60158f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 602b250f248SAndrey A. Chernov if ((unsigned)ret + n > INT_MAX) { 60392e88f87SAndrey A. Chernov ret = EOF; 60492e88f87SAndrey A. Chernov goto error; 60592e88f87SAndrey A. Chernov } 60658f0484fSRodney W. Grimes PRINT(cp, n); 60758f0484fSRodney W. Grimes ret += n; 60858f0484fSRodney W. Grimes } 60958f0484fSRodney W. Grimes if (ch == '\0') 61058f0484fSRodney W. Grimes goto done; 61158f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 61258f0484fSRodney W. Grimes 61358f0484fSRodney W. Grimes flags = 0; 61458f0484fSRodney W. Grimes dprec = 0; 61558f0484fSRodney W. Grimes width = 0; 61658f0484fSRodney W. Grimes prec = -1; 61758f0484fSRodney W. Grimes sign = '\0'; 618ebbad5ecSDavid Schultz ox[1] = '\0'; 61958f0484fSRodney W. Grimes 62058f0484fSRodney W. Grimes rflag: ch = *fmt++; 62158f0484fSRodney W. Grimes reswitch: switch (ch) { 62258f0484fSRodney W. Grimes case ' ': 6232e394b2fSAlexey Zelkin /*- 62458f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 62558f0484fSRodney W. Grimes * flag will be ignored.'' 62658f0484fSRodney W. Grimes * -- ANSI X3J11 62758f0484fSRodney W. Grimes */ 62858f0484fSRodney W. Grimes if (!sign) 62958f0484fSRodney W. Grimes sign = ' '; 63058f0484fSRodney W. Grimes goto rflag; 63158f0484fSRodney W. Grimes case '#': 63258f0484fSRodney W. Grimes flags |= ALT; 63358f0484fSRodney W. Grimes goto rflag; 63458f0484fSRodney W. Grimes case '*': 6352e394b2fSAlexey Zelkin /*- 63658f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 63758f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 63858f0484fSRodney W. Grimes * -- ANSI X3J11 63958f0484fSRodney W. Grimes * They don't exclude field widths read from args. 64058f0484fSRodney W. Grimes */ 641efb7e53dSJordan K. Hubbard GETASTER (width); 642efb7e53dSJordan K. Hubbard if (width >= 0) 64358f0484fSRodney W. Grimes goto rflag; 64458f0484fSRodney W. Grimes width = -width; 64558f0484fSRodney W. Grimes /* FALLTHROUGH */ 64658f0484fSRodney W. Grimes case '-': 64758f0484fSRodney W. Grimes flags |= LADJUST; 64858f0484fSRodney W. Grimes goto rflag; 64958f0484fSRodney W. Grimes case '+': 65058f0484fSRodney W. Grimes sign = '+'; 65158f0484fSRodney W. Grimes goto rflag; 6527735bb0fSBill Fenner case '\'': 65398ee7635SAlexey Zelkin flags |= GROUPING; 65498ee7635SAlexey Zelkin thousands_sep = *(localeconv()->thousands_sep); 65598ee7635SAlexey Zelkin grouping = localeconv()->grouping; 6567735bb0fSBill Fenner goto rflag; 65758f0484fSRodney W. Grimes case '.': 65858f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 6593b204b7dSDavid Schultz GETASTER (prec); 66058f0484fSRodney W. Grimes goto rflag; 66158f0484fSRodney W. Grimes } 6623b204b7dSDavid Schultz prec = 0; 66358f0484fSRodney W. Grimes while (is_digit(ch)) { 6643b204b7dSDavid Schultz prec = 10 * prec + to_digit(ch); 66558f0484fSRodney W. Grimes ch = *fmt++; 66658f0484fSRodney W. Grimes } 66758f0484fSRodney W. Grimes goto reswitch; 66858f0484fSRodney W. Grimes case '0': 6692e394b2fSAlexey Zelkin /*- 67058f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 67158f0484fSRodney W. Grimes * beginning of a field width.'' 67258f0484fSRodney W. Grimes * -- ANSI X3J11 67358f0484fSRodney W. Grimes */ 67458f0484fSRodney W. Grimes flags |= ZEROPAD; 67558f0484fSRodney W. Grimes goto rflag; 67658f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 67758f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 67858f0484fSRodney W. Grimes n = 0; 67958f0484fSRodney W. Grimes do { 68058f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 68158f0484fSRodney W. Grimes ch = *fmt++; 68258f0484fSRodney W. Grimes } while (is_digit(ch)); 683efb7e53dSJordan K. Hubbard if (ch == '$') { 684efb7e53dSJordan K. Hubbard nextarg = n; 685efb7e53dSJordan K. Hubbard if (argtable == NULL) { 686efb7e53dSJordan K. Hubbard argtable = statargtable; 687e62e5ff9SDavid Schultz if (__find_arguments (fmt0, orgap, 688e62e5ff9SDavid Schultz &argtable)) { 689e62e5ff9SDavid Schultz ret = EOF; 690e62e5ff9SDavid Schultz goto error; 691e62e5ff9SDavid Schultz } 692efb7e53dSJordan K. Hubbard } 693efb7e53dSJordan K. Hubbard goto rflag; 694efb7e53dSJordan K. Hubbard } 69558f0484fSRodney W. Grimes width = n; 69658f0484fSRodney W. Grimes goto reswitch; 6978de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 69858f0484fSRodney W. Grimes case 'L': 69958f0484fSRodney W. Grimes flags |= LONGDBL; 70058f0484fSRodney W. Grimes goto rflag; 70158f0484fSRodney W. Grimes #endif 70258f0484fSRodney W. Grimes case 'h': 7037735bb0fSBill Fenner if (flags & SHORTINT) { 7047735bb0fSBill Fenner flags &= ~SHORTINT; 7057735bb0fSBill Fenner flags |= CHARINT; 7067735bb0fSBill Fenner } else 70758f0484fSRodney W. Grimes flags |= SHORTINT; 70858f0484fSRodney W. Grimes goto rflag; 7097735bb0fSBill Fenner case 'j': 7107735bb0fSBill Fenner flags |= INTMAXT; 7117735bb0fSBill Fenner goto rflag; 71258f0484fSRodney W. Grimes case 'l': 7137735bb0fSBill Fenner if (flags & LONGINT) { 7147735bb0fSBill Fenner flags &= ~LONGINT; 7157735bb0fSBill Fenner flags |= LLONGINT; 7167735bb0fSBill Fenner } else 71758f0484fSRodney W. Grimes flags |= LONGINT; 71858f0484fSRodney W. Grimes goto rflag; 71958f0484fSRodney W. Grimes case 'q': 7207735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 7217735bb0fSBill Fenner goto rflag; 7227735bb0fSBill Fenner case 't': 7237735bb0fSBill Fenner flags |= PTRDIFFT; 7247735bb0fSBill Fenner goto rflag; 7257735bb0fSBill Fenner case 'z': 7267735bb0fSBill Fenner flags |= SIZET; 72758f0484fSRodney W. Grimes goto rflag; 728927ecbf3STim J. Robbins case 'C': 729927ecbf3STim J. Robbins flags |= LONGINT; 730927ecbf3STim J. Robbins /*FALLTHROUGH*/ 73158f0484fSRodney W. Grimes case 'c': 732b9aac308STim J. Robbins if (flags & LONGINT) { 73393996f6dSTim J. Robbins static const mbstate_t initial; 73493996f6dSTim J. Robbins mbstate_t mbs; 735b9aac308STim J. Robbins size_t mbseqlen; 736b9aac308STim J. Robbins 73793996f6dSTim J. Robbins mbs = initial; 738b9aac308STim J. Robbins mbseqlen = wcrtomb(cp = buf, 73993996f6dSTim J. Robbins (wchar_t)GETARG(wint_t), &mbs); 7406180233fSTim J. Robbins if (mbseqlen == (size_t)-1) { 7416180233fSTim J. Robbins fp->_flags |= __SERR; 742b9aac308STim J. Robbins goto error; 7436180233fSTim J. Robbins } 744b9aac308STim J. Robbins size = (int)mbseqlen; 745b9aac308STim J. Robbins } else { 746efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 74758f0484fSRodney W. Grimes size = 1; 748b9aac308STim J. Robbins } 74958f0484fSRodney W. Grimes sign = '\0'; 75058f0484fSRodney W. Grimes break; 75158f0484fSRodney W. Grimes case 'D': 75258f0484fSRodney W. Grimes flags |= LONGINT; 75358f0484fSRodney W. Grimes /*FALLTHROUGH*/ 75458f0484fSRodney W. Grimes case 'd': 75558f0484fSRodney W. Grimes case 'i': 7567735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 7577735bb0fSBill Fenner ujval = SJARG(); 7587735bb0fSBill Fenner if ((intmax_t)ujval < 0) { 7597735bb0fSBill Fenner ujval = -ujval; 76058f0484fSRodney W. Grimes sign = '-'; 76158f0484fSRodney W. Grimes } 76258f0484fSRodney W. Grimes } else { 76358f0484fSRodney W. Grimes ulval = SARG(); 76458f0484fSRodney W. Grimes if ((long)ulval < 0) { 76558f0484fSRodney W. Grimes ulval = -ulval; 76658f0484fSRodney W. Grimes sign = '-'; 76758f0484fSRodney W. Grimes } 76858f0484fSRodney W. Grimes } 76958f0484fSRodney W. Grimes base = 10; 77058f0484fSRodney W. Grimes goto number; 7718de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 7727735bb0fSBill Fenner case 'a': 7737735bb0fSBill Fenner case 'A': 774ebbad5ecSDavid Schultz if (ch == 'a') { 775ebbad5ecSDavid Schultz ox[1] = 'x'; 776ebbad5ecSDavid Schultz xdigs = xdigs_lower; 777ebbad5ecSDavid Schultz expchar = 'p'; 778ebbad5ecSDavid Schultz } else { 779ebbad5ecSDavid Schultz ox[1] = 'X'; 780ebbad5ecSDavid Schultz xdigs = xdigs_upper; 781ebbad5ecSDavid Schultz expchar = 'P'; 782ebbad5ecSDavid Schultz } 783904322a5SDavid Schultz if (prec >= 0) 784904322a5SDavid Schultz prec++; 785904322a5SDavid Schultz if (dtoaresult != NULL) 786904322a5SDavid Schultz freedtoa(dtoaresult); 787ebbad5ecSDavid Schultz if (flags & LONGDBL) { 788904322a5SDavid Schultz fparg.ldbl = GETARG(long double); 789ebbad5ecSDavid Schultz dtoaresult = cp = 790ebbad5ecSDavid Schultz __hldtoa(fparg.ldbl, xdigs, prec, 791ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 792ebbad5ecSDavid Schultz } else { 793ebbad5ecSDavid Schultz fparg.dbl = GETARG(double); 794ebbad5ecSDavid Schultz dtoaresult = cp = 795ebbad5ecSDavid Schultz __hdtoa(fparg.dbl, xdigs, prec, 796ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 797ebbad5ecSDavid Schultz } 798904322a5SDavid Schultz if (prec < 0) 799904322a5SDavid Schultz prec = dtoaend - cp; 800904322a5SDavid Schultz if (expt == INT_MAX) 801904322a5SDavid Schultz ox[1] = '\0'; 802904322a5SDavid Schultz goto fp_common; 803d26be6f0SBruce Evans case 'e': 80458f0484fSRodney W. Grimes case 'E': 805ebbad5ecSDavid Schultz expchar = ch; 806ebbad5ecSDavid Schultz if (prec < 0) /* account for digit before decpt */ 807ebbad5ecSDavid Schultz prec = DEFPREC + 1; 808ebbad5ecSDavid Schultz else 809ebbad5ecSDavid Schultz prec++; 810ebbad5ecSDavid Schultz goto fp_begin; 811d26be6f0SBruce Evans case 'f': 8127735bb0fSBill Fenner case 'F': 813ebbad5ecSDavid Schultz expchar = '\0'; 814d26be6f0SBruce Evans goto fp_begin; 81558f0484fSRodney W. Grimes case 'g': 81658f0484fSRodney W. Grimes case 'G': 817ebbad5ecSDavid Schultz expchar = ch - ('g' - 'e'); 818d26be6f0SBruce Evans if (prec == 0) 819d26be6f0SBruce Evans prec = 1; 820ebbad5ecSDavid Schultz fp_begin: 821ebbad5ecSDavid Schultz if (prec < 0) 82258f0484fSRodney W. Grimes prec = DEFPREC; 823ebbad5ecSDavid Schultz if (dtoaresult != NULL) 824ebbad5ecSDavid Schultz freedtoa(dtoaresult); 825ebbad5ecSDavid Schultz if (flags & LONGDBL) { 826ebbad5ecSDavid Schultz fparg.ldbl = GETARG(long double); 827ebbad5ecSDavid Schultz dtoaresult = cp = 828ebbad5ecSDavid Schultz __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 829ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 830ebbad5ecSDavid Schultz } else { 831ebbad5ecSDavid Schultz fparg.dbl = GETARG(double); 832ebbad5ecSDavid Schultz dtoaresult = cp = 833ebbad5ecSDavid Schultz dtoa(fparg.dbl, expchar ? 2 : 3, prec, 834ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 835ebbad5ecSDavid Schultz if (expt == 9999) 836ebbad5ecSDavid Schultz expt = INT_MAX; 83758f0484fSRodney W. Grimes } 838904322a5SDavid Schultz fp_common: 839ebbad5ecSDavid Schultz if (signflag) 840ebbad5ecSDavid Schultz sign = '-'; 841ebbad5ecSDavid Schultz if (expt == INT_MAX) { /* inf or nan */ 842ebbad5ecSDavid Schultz if (*cp == 'N') { 843ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "nan" : "NAN"; 844ebbad5ecSDavid Schultz sign = '\0'; 845ebbad5ecSDavid Schultz } else 846ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "inf" : "INF"; 84758f0484fSRodney W. Grimes size = 3; 848970a466cSDavid Schultz flags &= ~ZEROPAD; 84958f0484fSRodney W. Grimes break; 85058f0484fSRodney W. Grimes } 85158f0484fSRodney W. Grimes flags |= FPT; 852ebbad5ecSDavid Schultz ndig = dtoaend - cp; 85358f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 854ebbad5ecSDavid Schultz if (expt > -4 && expt <= prec) { 855ebbad5ecSDavid Schultz /* Make %[gG] smell like %[fF] */ 856ebbad5ecSDavid Schultz expchar = '\0'; 857ebbad5ecSDavid Schultz if (flags & ALT) 858ebbad5ecSDavid Schultz prec -= expt; 85958f0484fSRodney W. Grimes else 860ebbad5ecSDavid Schultz prec = ndig - expt; 861ebbad5ecSDavid Schultz if (prec < 0) 862ebbad5ecSDavid Schultz prec = 0; 8631f2a0cdfSDavid Schultz } else { 8641f2a0cdfSDavid Schultz /* 8651f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but 8661f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag. 8671f2a0cdfSDavid Schultz */ 8681f2a0cdfSDavid Schultz if (!(flags & ALT)) 8691f2a0cdfSDavid Schultz prec = ndig; 87058f0484fSRodney W. Grimes } 871ebbad5ecSDavid Schultz } 872ebbad5ecSDavid Schultz if (expchar) { 873ebbad5ecSDavid Schultz expsize = exponent(expstr, expt - 1, expchar); 874ebbad5ecSDavid Schultz size = expsize + prec; 8753b204b7dSDavid Schultz if (prec > 1 || flags & ALT) 87658f0484fSRodney W. Grimes ++size; 877ebbad5ecSDavid Schultz } else { 87881ae2e9aSDavid Schultz /* space for digits before decimal point */ 87981ae2e9aSDavid Schultz if (expt > 0) 88058f0484fSRodney W. Grimes size = expt; 88181ae2e9aSDavid Schultz else /* "0" */ 88281ae2e9aSDavid Schultz size = 1; 88381ae2e9aSDavid Schultz /* space for decimal pt and following digits */ 88458f0484fSRodney W. Grimes if (prec || flags & ALT) 88558f0484fSRodney W. Grimes size += prec + 1; 886ebbad5ecSDavid Schultz if (grouping && expt > 0) { 887ebbad5ecSDavid Schultz /* space for thousands' grouping */ 888ebbad5ecSDavid Schultz nseps = nrepeats = 0; 889ebbad5ecSDavid Schultz lead = expt; 890ebbad5ecSDavid Schultz while (*grouping != CHAR_MAX) { 891ebbad5ecSDavid Schultz if (lead <= *grouping) 892ebbad5ecSDavid Schultz break; 893ebbad5ecSDavid Schultz lead -= *grouping; 894ebbad5ecSDavid Schultz if (*(grouping+1)) { 895ebbad5ecSDavid Schultz nseps++; 896ebbad5ecSDavid Schultz grouping++; 89758f0484fSRodney W. Grimes } else 898ebbad5ecSDavid Schultz nrepeats++; 899ebbad5ecSDavid Schultz } 900ebbad5ecSDavid Schultz size += nseps + nrepeats; 901ebbad5ecSDavid Schultz } else 902d890afb8SDavid Schultz lead = expt; 903ebbad5ecSDavid Schultz } 90458f0484fSRodney W. Grimes break; 9058de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 90658f0484fSRodney W. Grimes case 'n': 9077735bb0fSBill Fenner /* 9087735bb0fSBill Fenner * Assignment-like behavior is specified if the 9097735bb0fSBill Fenner * value overflows or is otherwise unrepresentable. 9107735bb0fSBill Fenner * C99 says to use `signed char' for %hhn conversions. 9117735bb0fSBill Fenner */ 9127735bb0fSBill Fenner if (flags & LLONGINT) 9137735bb0fSBill Fenner *GETARG(long long *) = ret; 9147735bb0fSBill Fenner else if (flags & SIZET) 9157735bb0fSBill Fenner *GETARG(ssize_t *) = (ssize_t)ret; 9167735bb0fSBill Fenner else if (flags & PTRDIFFT) 9177735bb0fSBill Fenner *GETARG(ptrdiff_t *) = ret; 9187735bb0fSBill Fenner else if (flags & INTMAXT) 9197735bb0fSBill Fenner *GETARG(intmax_t *) = ret; 92058f0484fSRodney W. Grimes else if (flags & LONGINT) 9216e690ad4SAndrey A. Chernov *GETARG(long *) = ret; 92258f0484fSRodney W. Grimes else if (flags & SHORTINT) 9236e690ad4SAndrey A. Chernov *GETARG(short *) = ret; 9247735bb0fSBill Fenner else if (flags & CHARINT) 9257735bb0fSBill Fenner *GETARG(signed char *) = ret; 92658f0484fSRodney W. Grimes else 9276e690ad4SAndrey A. Chernov *GETARG(int *) = ret; 92858f0484fSRodney W. Grimes continue; /* no output */ 92958f0484fSRodney W. Grimes case 'O': 93058f0484fSRodney W. Grimes flags |= LONGINT; 93158f0484fSRodney W. Grimes /*FALLTHROUGH*/ 93258f0484fSRodney W. Grimes case 'o': 9337735bb0fSBill Fenner if (flags & INTMAX_SIZE) 9347735bb0fSBill Fenner ujval = UJARG(); 93558f0484fSRodney W. Grimes else 93658f0484fSRodney W. Grimes ulval = UARG(); 93758f0484fSRodney W. Grimes base = 8; 93858f0484fSRodney W. Grimes goto nosign; 93958f0484fSRodney W. Grimes case 'p': 9402e394b2fSAlexey Zelkin /*- 94158f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 94258f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 94358f0484fSRodney W. Grimes * of printable characters, in an implementation- 94458f0484fSRodney W. Grimes * defined manner.'' 94558f0484fSRodney W. Grimes * -- ANSI X3J11 94658f0484fSRodney W. Grimes */ 9477735bb0fSBill Fenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 94858f0484fSRodney W. Grimes base = 16; 949ebbad5ecSDavid Schultz xdigs = xdigs_lower; 950ebbad5ecSDavid Schultz flags = flags | INTMAXT; 951ebbad5ecSDavid Schultz ox[1] = 'x'; 95258f0484fSRodney W. Grimes goto nosign; 953927ecbf3STim J. Robbins case 'S': 954927ecbf3STim J. Robbins flags |= LONGINT; 955927ecbf3STim J. Robbins /*FALLTHROUGH*/ 95658f0484fSRodney W. Grimes case 's': 957b9aac308STim J. Robbins if (flags & LONGINT) { 958b9aac308STim J. Robbins wchar_t *wcp; 959b9aac308STim J. Robbins 960b9aac308STim J. Robbins if (convbuf != NULL) 961b9aac308STim J. Robbins free(convbuf); 962b9aac308STim J. Robbins if ((wcp = GETARG(wchar_t *)) == NULL) 963b9aac308STim J. Robbins cp = "(null)"; 964b9aac308STim J. Robbins else { 965b9aac308STim J. Robbins convbuf = __wcsconv(wcp, prec); 9666180233fSTim J. Robbins if (convbuf == NULL) { 9676180233fSTim J. Robbins fp->_flags |= __SERR; 968b9aac308STim J. Robbins goto error; 9696180233fSTim J. Robbins } 970b9aac308STim J. Robbins cp = convbuf; 971b9aac308STim J. Robbins } 972b9aac308STim J. Robbins } else if ((cp = GETARG(char *)) == NULL) 97358f0484fSRodney W. Grimes cp = "(null)"; 97458f0484fSRodney W. Grimes if (prec >= 0) { 97558f0484fSRodney W. Grimes /* 97658f0484fSRodney W. Grimes * can't use strlen; can only look for the 97758f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 97858f0484fSRodney W. Grimes * strlen() will go further. 97958f0484fSRodney W. Grimes */ 980ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 98158f0484fSRodney W. Grimes 98258f0484fSRodney W. Grimes if (p != NULL) { 98358f0484fSRodney W. Grimes size = p - cp; 98458f0484fSRodney W. Grimes if (size > prec) 98558f0484fSRodney W. Grimes size = prec; 98658f0484fSRodney W. Grimes } else 98758f0484fSRodney W. Grimes size = prec; 98858f0484fSRodney W. Grimes } else 98958f0484fSRodney W. Grimes size = strlen(cp); 99058f0484fSRodney W. Grimes sign = '\0'; 99158f0484fSRodney W. Grimes break; 99258f0484fSRodney W. Grimes case 'U': 99358f0484fSRodney W. Grimes flags |= LONGINT; 99458f0484fSRodney W. Grimes /*FALLTHROUGH*/ 99558f0484fSRodney W. Grimes case 'u': 9967735bb0fSBill Fenner if (flags & INTMAX_SIZE) 9977735bb0fSBill Fenner ujval = UJARG(); 99858f0484fSRodney W. Grimes else 99958f0484fSRodney W. Grimes ulval = UARG(); 100058f0484fSRodney W. Grimes base = 10; 100158f0484fSRodney W. Grimes goto nosign; 100258f0484fSRodney W. Grimes case 'X': 1003ebbad5ecSDavid Schultz xdigs = xdigs_upper; 100458f0484fSRodney W. Grimes goto hex; 100558f0484fSRodney W. Grimes case 'x': 1006ebbad5ecSDavid Schultz xdigs = xdigs_lower; 10077735bb0fSBill Fenner hex: 10087735bb0fSBill Fenner if (flags & INTMAX_SIZE) 10097735bb0fSBill Fenner ujval = UJARG(); 101058f0484fSRodney W. Grimes else 101158f0484fSRodney W. Grimes ulval = UARG(); 101258f0484fSRodney W. Grimes base = 16; 101358f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 101458f0484fSRodney W. Grimes if (flags & ALT && 10157735bb0fSBill Fenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 1016ebbad5ecSDavid Schultz ox[1] = ch; 101758f0484fSRodney W. Grimes 101898ee7635SAlexey Zelkin flags &= ~GROUPING; 101958f0484fSRodney W. Grimes /* unsigned conversions */ 102058f0484fSRodney W. Grimes nosign: sign = '\0'; 10212e394b2fSAlexey Zelkin /*- 102258f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 102358f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 102458f0484fSRodney W. Grimes * -- ANSI X3J11 102558f0484fSRodney W. Grimes */ 102658f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 102758f0484fSRodney W. Grimes flags &= ~ZEROPAD; 102858f0484fSRodney W. Grimes 10292e394b2fSAlexey Zelkin /*- 103058f0484fSRodney W. Grimes * ``The result of converting a zero value with an 103158f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 103258f0484fSRodney W. Grimes * -- ANSI X3J11 10331be5319aSDavid Schultz * 10341be5319aSDavid Schultz * ``The C Standard is clear enough as is. The call 10351be5319aSDavid Schultz * printf("%#.0o", 0) should print 0.'' 10361be5319aSDavid Schultz * -- Defect Report #151 103758f0484fSRodney W. Grimes */ 103858f0484fSRodney W. Grimes cp = buf + BUF; 10397735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 10401be5319aSDavid Schultz if (ujval != 0 || prec != 0 || 10411be5319aSDavid Schultz (flags & ALT && base == 8)) 10427735bb0fSBill Fenner cp = __ujtoa(ujval, cp, base, 104398ee7635SAlexey Zelkin flags & ALT, xdigs, 104498ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 104598ee7635SAlexey Zelkin grouping); 104658f0484fSRodney W. Grimes } else { 10471be5319aSDavid Schultz if (ulval != 0 || prec != 0 || 10481be5319aSDavid Schultz (flags & ALT && base == 8)) 104958f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 105098ee7635SAlexey Zelkin flags & ALT, xdigs, 105198ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 105298ee7635SAlexey Zelkin grouping); 105358f0484fSRodney W. Grimes } 105458f0484fSRodney W. Grimes size = buf + BUF - cp; 105538cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 105638cac8f8SDavid Schultz abort(); 105758f0484fSRodney W. Grimes break; 105858f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 105958f0484fSRodney W. Grimes if (ch == '\0') 106058f0484fSRodney W. Grimes goto done; 106158f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 106258f0484fSRodney W. Grimes cp = buf; 106358f0484fSRodney W. Grimes *cp = ch; 106458f0484fSRodney W. Grimes size = 1; 106558f0484fSRodney W. Grimes sign = '\0'; 106658f0484fSRodney W. Grimes break; 106758f0484fSRodney W. Grimes } 106858f0484fSRodney W. Grimes 106958f0484fSRodney W. Grimes /* 107058f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 107158f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 107258f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 107358f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 107458f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 107558f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 107658f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 107758f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 107858f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 107958f0484fSRodney W. Grimes * 108058f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 1081261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 108258f0484fSRodney W. Grimes */ 1083261a532aSBill Fenner realsz = dprec > size ? dprec : size; 108458f0484fSRodney W. Grimes if (sign) 1085261a532aSBill Fenner realsz++; 1086904322a5SDavid Schultz if (ox[1]) 1087261a532aSBill Fenner realsz += 2; 108858f0484fSRodney W. Grimes 108992e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz; 1090b250f248SAndrey A. Chernov if ((unsigned)ret + prsize > INT_MAX) { 109192e88f87SAndrey A. Chernov ret = EOF; 109292e88f87SAndrey A. Chernov goto error; 109392e88f87SAndrey A. Chernov } 109492e88f87SAndrey A. Chernov 109558f0484fSRodney W. Grimes /* right-adjusting blank padding */ 109658f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 109758f0484fSRodney W. Grimes PAD(width - realsz, blanks); 109858f0484fSRodney W. Grimes 109958f0484fSRodney W. Grimes /* prefix */ 1100904322a5SDavid Schultz if (sign) 110158f0484fSRodney W. Grimes PRINT(&sign, 1); 1102904322a5SDavid Schultz 1103904322a5SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */ 110458f0484fSRodney W. Grimes ox[0] = '0'; 110558f0484fSRodney W. Grimes PRINT(ox, 2); 110658f0484fSRodney W. Grimes } 110758f0484fSRodney W. Grimes 110858f0484fSRodney W. Grimes /* right-adjusting zero padding */ 110958f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 111058f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 111158f0484fSRodney W. Grimes 111258f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 1113261a532aSBill Fenner PAD(dprec - size, zeroes); 111458f0484fSRodney W. Grimes 111558f0484fSRodney W. Grimes /* the string or number proper */ 11168de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 111758f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 111858f0484fSRodney W. Grimes PRINT(cp, size); 111958f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 1120ebbad5ecSDavid Schultz if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1121ebbad5ecSDavid Schultz if (expt <= 0) { 112281ae2e9aSDavid Schultz PRINT(zeroes, 1); 112381ae2e9aSDavid Schultz if (prec || flags & ALT) 112481ae2e9aSDavid Schultz PRINT(decimal_point, 1); 112558f0484fSRodney W. Grimes PAD(-expt, zeroes); 11263b204b7dSDavid Schultz /* already handled initial 0's */ 11273b204b7dSDavid Schultz prec += expt; 112858f0484fSRodney W. Grimes } else { 11293b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend, lead, zeroes); 1130ebbad5ecSDavid Schultz cp += lead; 1131ebbad5ecSDavid Schultz if (grouping) { 1132ebbad5ecSDavid Schultz while (nseps>0 || nrepeats>0) { 1133ebbad5ecSDavid Schultz if (nrepeats > 0) 1134ebbad5ecSDavid Schultz nrepeats--; 1135ebbad5ecSDavid Schultz else { 1136ebbad5ecSDavid Schultz grouping--; 1137ebbad5ecSDavid Schultz nseps--; 113858f0484fSRodney W. Grimes } 1139ebbad5ecSDavid Schultz PRINT(&thousands_sep, 1140ebbad5ecSDavid Schultz 1); 11413b204b7dSDavid Schultz PRINTANDPAD(cp,dtoaend, 11423b204b7dSDavid Schultz *grouping, zeroes); 1143ebbad5ecSDavid Schultz cp += *grouping; 1144ebbad5ecSDavid Schultz } 11453b204b7dSDavid Schultz if (cp > dtoaend) 11463b204b7dSDavid Schultz cp = dtoaend; 1147ebbad5ecSDavid Schultz } 1148ebbad5ecSDavid Schultz if (prec || flags & ALT) 1149ebbad5ecSDavid Schultz PRINT(decimal_point,1); 1150ebbad5ecSDavid Schultz } 11513b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend, prec, zeroes); 1152ebbad5ecSDavid Schultz } else { /* %[eE] or sufficiently long %[gG] */ 11533b204b7dSDavid Schultz if (prec > 1 || flags & ALT) { 1154ebbad5ecSDavid Schultz buf[0] = *cp++; 1155ebbad5ecSDavid Schultz buf[1] = *decimal_point; 1156ebbad5ecSDavid Schultz PRINT(buf, 2); 115758f0484fSRodney W. Grimes PRINT(cp, ndig-1); 1158ebbad5ecSDavid Schultz PAD(prec - ndig, zeroes); 115958f0484fSRodney W. Grimes } else /* XeYYY */ 116058f0484fSRodney W. Grimes PRINT(cp, 1); 116158f0484fSRodney W. Grimes PRINT(expstr, expsize); 116258f0484fSRodney W. Grimes } 116358f0484fSRodney W. Grimes } 116458f0484fSRodney W. Grimes #else 116558f0484fSRodney W. Grimes PRINT(cp, size); 116658f0484fSRodney W. Grimes #endif 116758f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 116858f0484fSRodney W. Grimes if (flags & LADJUST) 116958f0484fSRodney W. Grimes PAD(width - realsz, blanks); 117058f0484fSRodney W. Grimes 117158f0484fSRodney W. Grimes /* finally, adjust ret */ 117292e88f87SAndrey A. Chernov ret += prsize; 117358f0484fSRodney W. Grimes 117458f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 117558f0484fSRodney W. Grimes } 117658f0484fSRodney W. Grimes done: 117758f0484fSRodney W. Grimes FLUSH(); 117858f0484fSRodney W. Grimes error: 1179096ad104SDag-Erling Smørgrav va_end(orgap); 11808de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 11812ffc61baSTor Egge if (dtoaresult != NULL) 1182ebbad5ecSDavid Schultz freedtoa(dtoaresult); 11832ffc61baSTor Egge #endif 1184b9aac308STim J. Robbins if (convbuf != NULL) 1185b9aac308STim J. Robbins free(convbuf); 1186f70177e7SJulian Elischer if (__sferror(fp)) 1187f70177e7SJulian Elischer ret = EOF; 1188efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 1189efb7e53dSJordan K. Hubbard free (argtable); 1190f70177e7SJulian Elischer return (ret); 119158f0484fSRodney W. Grimes /* NOTREACHED */ 119258f0484fSRodney W. Grimes } 119358f0484fSRodney W. Grimes 1194efb7e53dSJordan K. Hubbard 11958de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 119658f0484fSRodney W. Grimes 119758f0484fSRodney W. Grimes static int 1198d201fe46SDaniel Eischen exponent(char *p0, int exp, int fmtch) 119958f0484fSRodney W. Grimes { 1200d201fe46SDaniel Eischen char *p, *t; 120138cac8f8SDavid Schultz char expbuf[MAXEXPDIG]; 120258f0484fSRodney W. Grimes 120358f0484fSRodney W. Grimes p = p0; 120458f0484fSRodney W. Grimes *p++ = fmtch; 120558f0484fSRodney W. Grimes if (exp < 0) { 120658f0484fSRodney W. Grimes exp = -exp; 120758f0484fSRodney W. Grimes *p++ = '-'; 120858f0484fSRodney W. Grimes } 120958f0484fSRodney W. Grimes else 121058f0484fSRodney W. Grimes *p++ = '+'; 121138cac8f8SDavid Schultz t = expbuf + MAXEXPDIG; 121258f0484fSRodney W. Grimes if (exp > 9) { 121358f0484fSRodney W. Grimes do { 121458f0484fSRodney W. Grimes *--t = to_char(exp % 10); 121558f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 121658f0484fSRodney W. Grimes *--t = to_char(exp); 121738cac8f8SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 121858f0484fSRodney W. Grimes } 121958f0484fSRodney W. Grimes else { 1220ebbad5ecSDavid Schultz /* 1221ebbad5ecSDavid Schultz * Exponents for decimal floating point conversions 1222ebbad5ecSDavid Schultz * (%[eEgG]) must be at least two characters long, 1223ebbad5ecSDavid Schultz * whereas exponents for hexadecimal conversions can 1224ebbad5ecSDavid Schultz * be only one character long. 1225ebbad5ecSDavid Schultz */ 1226ebbad5ecSDavid Schultz if (fmtch == 'e' || fmtch == 'E') 122758f0484fSRodney W. Grimes *p++ = '0'; 122858f0484fSRodney W. Grimes *p++ = to_char(exp); 122958f0484fSRodney W. Grimes } 123058f0484fSRodney W. Grimes return (p - p0); 123158f0484fSRodney W. Grimes } 12328de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 1233