1c5604d0aSTim J. Robbins /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 4c5604d0aSTim J. Robbins * Copyright (c) 1990, 1993 5c5604d0aSTim J. Robbins * The Regents of the University of California. All rights reserved. 6c5604d0aSTim J. Robbins * 7c5604d0aSTim J. Robbins * This code is derived from software contributed to Berkeley by 8c5604d0aSTim J. Robbins * Chris Torek. 9c5604d0aSTim J. Robbins * 103c87aa1dSDavid Chisnall * Copyright (c) 2011 The FreeBSD Foundation 115b5fa75aSEd Maste * 123c87aa1dSDavid Chisnall * Portions of this software were developed by David Chisnall 133c87aa1dSDavid Chisnall * under sponsorship from the FreeBSD Foundation. 143c87aa1dSDavid Chisnall * 15c5604d0aSTim J. Robbins * Redistribution and use in source and binary forms, with or without 16c5604d0aSTim J. Robbins * modification, are permitted provided that the following conditions 17c5604d0aSTim J. Robbins * are met: 18c5604d0aSTim J. Robbins * 1. Redistributions of source code must retain the above copyright 19c5604d0aSTim J. Robbins * notice, this list of conditions and the following disclaimer. 20c5604d0aSTim J. Robbins * 2. Redistributions in binary form must reproduce the above copyright 21c5604d0aSTim J. Robbins * notice, this list of conditions and the following disclaimer in the 22c5604d0aSTim J. Robbins * documentation and/or other materials provided with the distribution. 231d8053c5SEd Maste * 3. Neither the name of the University nor the names of its contributors 24c5604d0aSTim J. Robbins * may be used to endorse or promote products derived from this software 25c5604d0aSTim J. Robbins * without specific prior written permission. 26c5604d0aSTim J. Robbins * 27c5604d0aSTim J. Robbins * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28c5604d0aSTim J. Robbins * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29c5604d0aSTim J. Robbins * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30c5604d0aSTim J. Robbins * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31c5604d0aSTim J. Robbins * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32c5604d0aSTim J. Robbins * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33c5604d0aSTim J. Robbins * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34c5604d0aSTim J. Robbins * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35c5604d0aSTim J. Robbins * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36c5604d0aSTim J. Robbins * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37c5604d0aSTim J. Robbins * SUCH DAMAGE. 38c5604d0aSTim J. Robbins */ 39c5604d0aSTim J. Robbins 40c5604d0aSTim J. Robbins #if 0 41c5604d0aSTim J. Robbins #if defined(LIBC_SCCS) && !defined(lint) 42c5604d0aSTim J. Robbins static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 43c5604d0aSTim J. Robbins #endif /* LIBC_SCCS and not lint */ 44c5604d0aSTim J. Robbins #endif 45af152640SDavid E. O'Brien #include <sys/cdefs.h> 46c5604d0aSTim J. Robbins /* 47c5604d0aSTim J. Robbins * Actual wprintf innards. 48c5604d0aSTim J. Robbins * 49c5604d0aSTim J. Robbins * Avoid making gratuitous changes to this source file; it should be kept 50c5604d0aSTim J. Robbins * as close as possible to vfprintf.c for ease of maintenance. 51c5604d0aSTim J. Robbins */ 52c5604d0aSTim J. Robbins 53c5604d0aSTim J. Robbins #include "namespace.h" 54c5604d0aSTim J. Robbins #include <sys/types.h> 55c5604d0aSTim J. Robbins 56c5604d0aSTim J. Robbins #include <ctype.h> 57666d00d3SDavid Schultz #include <errno.h> 58c5604d0aSTim J. Robbins #include <limits.h> 59c5604d0aSTim J. Robbins #include <locale.h> 60c5604d0aSTim J. Robbins #include <stdarg.h> 61c5604d0aSTim J. Robbins #include <stddef.h> 62c5604d0aSTim J. Robbins #include <stdint.h> 63c5604d0aSTim J. Robbins #include <stdio.h> 64c5604d0aSTim J. Robbins #include <stdlib.h> 65c5604d0aSTim J. Robbins #include <string.h> 66c5604d0aSTim J. Robbins #include <wchar.h> 67c5604d0aSTim J. Robbins #include <wctype.h> 68c5604d0aSTim J. Robbins #include "un-namespace.h" 69c5604d0aSTim J. Robbins 70c5604d0aSTim J. Robbins #include "libc_private.h" 71c5604d0aSTim J. Robbins #include "local.h" 72c5604d0aSTim J. Robbins #include "fvwrite.h" 732591efccSDavid Schultz #include "printflocal.h" 743c87aa1dSDavid Chisnall #include "xlocale_private.h" 75e5abb5e6SDavid Schultz 763c87aa1dSDavid Chisnall static int __sprint(FILE *, struct __suio *, locale_t); 773c87aa1dSDavid Chisnall static int __sbprintf(FILE *, locale_t, const wchar_t *, va_list) __noinline; 783c87aa1dSDavid Chisnall static wint_t __xfputwc(wchar_t, FILE *, locale_t); 79c5604d0aSTim J. Robbins static wchar_t *__mbsconv(char *, int); 80c5604d0aSTim J. Robbins 81814d1bc9SDavid Schultz #define CHAR wchar_t 82814d1bc9SDavid Schultz #include "printfcommon.h" 83814d1bc9SDavid Schultz 8421ca178eSDavid Schultz struct grouping_state { 8521ca178eSDavid Schultz wchar_t thousands_sep; /* locale-specific thousands separator */ 8621ca178eSDavid Schultz const char *grouping; /* locale-specific numeric grouping rules */ 8721ca178eSDavid Schultz int lead; /* sig figs before decimal or group sep */ 8821ca178eSDavid Schultz int nseps; /* number of group separators with ' */ 8921ca178eSDavid Schultz int nrepeats; /* number of repeats of the last group */ 9021ca178eSDavid Schultz }; 9121ca178eSDavid Schultz 925004a238SDavid Schultz static const mbstate_t initial_mbs; 935004a238SDavid Schultz 945004a238SDavid Schultz static inline wchar_t 953c87aa1dSDavid Chisnall get_decpt(locale_t locale) 965004a238SDavid Schultz { 975004a238SDavid Schultz mbstate_t mbs; 985004a238SDavid Schultz wchar_t decpt; 995004a238SDavid Schultz int nconv; 1005004a238SDavid Schultz 1015004a238SDavid Schultz mbs = initial_mbs; 1023c87aa1dSDavid Chisnall nconv = mbrtowc(&decpt, localeconv_l(locale)->decimal_point, MB_CUR_MAX, &mbs); 1035004a238SDavid Schultz if (nconv == (size_t)-1 || nconv == (size_t)-2) 1045004a238SDavid Schultz decpt = '.'; /* failsafe */ 1055004a238SDavid Schultz return (decpt); 1065004a238SDavid Schultz } 1075004a238SDavid Schultz 10821ca178eSDavid Schultz static inline wchar_t 1093c87aa1dSDavid Chisnall get_thousep(locale_t locale) 11021ca178eSDavid Schultz { 11121ca178eSDavid Schultz mbstate_t mbs; 11221ca178eSDavid Schultz wchar_t thousep; 11321ca178eSDavid Schultz int nconv; 11421ca178eSDavid Schultz 11521ca178eSDavid Schultz mbs = initial_mbs; 1163c87aa1dSDavid Chisnall nconv = mbrtowc(&thousep, localeconv_l(locale)->thousands_sep, 11721ca178eSDavid Schultz MB_CUR_MAX, &mbs); 11821ca178eSDavid Schultz if (nconv == (size_t)-1 || nconv == (size_t)-2) 11921ca178eSDavid Schultz thousep = '\0'; /* failsafe */ 12021ca178eSDavid Schultz return (thousep); 12121ca178eSDavid Schultz } 12221ca178eSDavid Schultz 12321ca178eSDavid Schultz /* 12421ca178eSDavid Schultz * Initialize the thousands' grouping state in preparation to print a 12521ca178eSDavid Schultz * number with ndigits digits. This routine returns the total number 12621ca178eSDavid Schultz * of wide characters that will be printed. 12721ca178eSDavid Schultz */ 12821ca178eSDavid Schultz static int 1293c87aa1dSDavid Chisnall grouping_init(struct grouping_state *gs, int ndigits, locale_t locale) 13021ca178eSDavid Schultz { 13121ca178eSDavid Schultz 1323c87aa1dSDavid Chisnall gs->grouping = localeconv_l(locale)->grouping; 1333c87aa1dSDavid Chisnall gs->thousands_sep = get_thousep(locale); 13421ca178eSDavid Schultz 13521ca178eSDavid Schultz gs->nseps = gs->nrepeats = 0; 13621ca178eSDavid Schultz gs->lead = ndigits; 13721ca178eSDavid Schultz while (*gs->grouping != CHAR_MAX) { 13821ca178eSDavid Schultz if (gs->lead <= *gs->grouping) 13921ca178eSDavid Schultz break; 14021ca178eSDavid Schultz gs->lead -= *gs->grouping; 14121ca178eSDavid Schultz if (*(gs->grouping+1)) { 14221ca178eSDavid Schultz gs->nseps++; 14321ca178eSDavid Schultz gs->grouping++; 14421ca178eSDavid Schultz } else 14521ca178eSDavid Schultz gs->nrepeats++; 14621ca178eSDavid Schultz } 14721ca178eSDavid Schultz return (gs->nseps + gs->nrepeats); 14821ca178eSDavid Schultz } 14921ca178eSDavid Schultz 15021ca178eSDavid Schultz /* 15121ca178eSDavid Schultz * Print a number with thousands' separators. 15221ca178eSDavid Schultz */ 15321ca178eSDavid Schultz static int 15421ca178eSDavid Schultz grouping_print(struct grouping_state *gs, struct io_state *iop, 1553c87aa1dSDavid Chisnall const CHAR *cp, const CHAR *ep, locale_t locale) 15621ca178eSDavid Schultz { 15721ca178eSDavid Schultz const CHAR *cp0 = cp; 15821ca178eSDavid Schultz 1593c87aa1dSDavid Chisnall if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale)) 16021ca178eSDavid Schultz return (-1); 16121ca178eSDavid Schultz cp += gs->lead; 16221ca178eSDavid Schultz while (gs->nseps > 0 || gs->nrepeats > 0) { 16321ca178eSDavid Schultz if (gs->nrepeats > 0) 16421ca178eSDavid Schultz gs->nrepeats--; 16521ca178eSDavid Schultz else { 16621ca178eSDavid Schultz gs->grouping--; 16721ca178eSDavid Schultz gs->nseps--; 16821ca178eSDavid Schultz } 1693c87aa1dSDavid Chisnall if (io_print(iop, &gs->thousands_sep, 1, locale)) 17021ca178eSDavid Schultz return (-1); 1713c87aa1dSDavid Chisnall if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale)) 17221ca178eSDavid Schultz return (-1); 17321ca178eSDavid Schultz cp += *gs->grouping; 17421ca178eSDavid Schultz } 17521ca178eSDavid Schultz if (cp > ep) 17621ca178eSDavid Schultz cp = ep; 17721ca178eSDavid Schultz return (cp - cp0); 17821ca178eSDavid Schultz } 17921ca178eSDavid Schultz 18021ca178eSDavid Schultz 181814d1bc9SDavid Schultz /* 182814d1bc9SDavid Schultz * Flush out all the vectors defined by the given uio, 183814d1bc9SDavid Schultz * then reset it so that it can be reused. 184814d1bc9SDavid Schultz * 185814d1bc9SDavid Schultz * XXX The fact that we do this a character at a time and convert to a 186814d1bc9SDavid Schultz * multibyte character sequence even if the destination is a wide 187814d1bc9SDavid Schultz * string eclipses the benefits of buffering. 188814d1bc9SDavid Schultz */ 189814d1bc9SDavid Schultz static int 1903c87aa1dSDavid Chisnall __sprint(FILE *fp, struct __suio *uio, locale_t locale) 191814d1bc9SDavid Schultz { 192814d1bc9SDavid Schultz struct __siov *iov; 193814d1bc9SDavid Schultz wchar_t *p; 194814d1bc9SDavid Schultz int i, len; 195814d1bc9SDavid Schultz 196814d1bc9SDavid Schultz iov = uio->uio_iov; 197814d1bc9SDavid Schultz for (; uio->uio_resid != 0; uio->uio_resid -= len, iov++) { 198814d1bc9SDavid Schultz p = (wchar_t *)iov->iov_base; 199814d1bc9SDavid Schultz len = iov->iov_len; 200814d1bc9SDavid Schultz for (i = 0; i < len; i++) { 2013c87aa1dSDavid Chisnall if (__xfputwc(p[i], fp, locale) == WEOF) 202814d1bc9SDavid Schultz return (-1); 203814d1bc9SDavid Schultz } 204814d1bc9SDavid Schultz } 205814d1bc9SDavid Schultz uio->uio_iovcnt = 0; 206814d1bc9SDavid Schultz return (0); 207814d1bc9SDavid Schultz } 208814d1bc9SDavid Schultz 209c5604d0aSTim J. Robbins /* 210c5604d0aSTim J. Robbins * Helper function for `fprintf to unbuffered unix file': creates a 211c5604d0aSTim J. Robbins * temporary buffer. We only work on write-only files; this avoids 212c5604d0aSTim J. Robbins * worries about ungetc buffers and so forth. 213c5604d0aSTim J. Robbins */ 214c5604d0aSTim J. Robbins static int 2153c87aa1dSDavid Chisnall __sbprintf(FILE *fp, locale_t locale, const wchar_t *fmt, va_list ap) 216c5604d0aSTim J. Robbins { 217c5604d0aSTim J. Robbins int ret; 218c5604d0aSTim J. Robbins FILE fake; 219c5604d0aSTim J. Robbins unsigned char buf[BUFSIZ]; 220c5604d0aSTim J. Robbins 221a1805f7bSDavid Schultz /* XXX This is probably not needed. */ 222a1805f7bSDavid Schultz if (prepwrite(fp) != 0) 223a1805f7bSDavid Schultz return (EOF); 224a1805f7bSDavid Schultz 225c5604d0aSTim J. Robbins /* copy the important variables */ 226c5604d0aSTim J. Robbins fake._flags = fp->_flags & ~__SNBF; 227c5604d0aSTim J. Robbins fake._file = fp->_file; 228c5604d0aSTim J. Robbins fake._cookie = fp->_cookie; 229c5604d0aSTim J. Robbins fake._write = fp->_write; 2301e98f887SJohn Baldwin fake._orientation = fp->_orientation; 2311e98f887SJohn Baldwin fake._mbstate = fp->_mbstate; 232c5604d0aSTim J. Robbins 233c5604d0aSTim J. Robbins /* set up the buffer */ 234c5604d0aSTim J. Robbins fake._bf._base = fake._p = buf; 235c5604d0aSTim J. Robbins fake._bf._size = fake._w = sizeof(buf); 236c5604d0aSTim J. Robbins fake._lbfsize = 0; /* not actually used, but Just In Case */ 237c5604d0aSTim J. Robbins 238c5604d0aSTim J. Robbins /* do the work, then copy any error status */ 2393c87aa1dSDavid Chisnall ret = __vfwprintf(&fake, locale, fmt, ap); 240c5604d0aSTim J. Robbins if (ret >= 0 && __fflush(&fake)) 241c5604d0aSTim J. Robbins ret = WEOF; 242c5604d0aSTim J. Robbins if (fake._flags & __SERR) 243c5604d0aSTim J. Robbins fp->_flags |= __SERR; 244c5604d0aSTim J. Robbins return (ret); 245c5604d0aSTim J. Robbins } 246c5604d0aSTim J. Robbins 247c5604d0aSTim J. Robbins /* 248909a17f4STim J. Robbins * Like __fputwc, but handles fake string (__SSTR) files properly. 249909a17f4STim J. Robbins * File must already be locked. 250909a17f4STim J. Robbins */ 251909a17f4STim J. Robbins static wint_t 2523c87aa1dSDavid Chisnall __xfputwc(wchar_t wc, FILE *fp, locale_t locale) 253909a17f4STim J. Robbins { 25493996f6dSTim J. Robbins mbstate_t mbs; 255909a17f4STim J. Robbins char buf[MB_LEN_MAX]; 256909a17f4STim J. Robbins struct __suio uio; 257909a17f4STim J. Robbins struct __siov iov; 25884d9142fSJacques Vidrine size_t len; 259909a17f4STim J. Robbins 260909a17f4STim J. Robbins if ((fp->_flags & __SSTR) == 0) 2613c87aa1dSDavid Chisnall return (__fputwc(wc, fp, locale)); 262909a17f4STim J. Robbins 2635004a238SDavid Schultz mbs = initial_mbs; 26493996f6dSTim J. Robbins if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) { 265909a17f4STim J. Robbins fp->_flags |= __SERR; 266909a17f4STim J. Robbins return (WEOF); 267909a17f4STim J. Robbins } 268909a17f4STim J. Robbins uio.uio_iov = &iov; 269909a17f4STim J. Robbins uio.uio_resid = len; 270909a17f4STim J. Robbins uio.uio_iovcnt = 1; 271909a17f4STim J. Robbins iov.iov_base = buf; 272909a17f4STim J. Robbins iov.iov_len = len; 273909a17f4STim J. Robbins return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF); 274909a17f4STim J. Robbins } 275909a17f4STim J. Robbins 276909a17f4STim J. Robbins /* 277c5604d0aSTim J. Robbins * Convert a multibyte character string argument for the %s format to a wide 278c5604d0aSTim J. Robbins * string representation. ``prec'' specifies the maximum number of bytes 279c5604d0aSTim J. Robbins * to output. If ``prec'' is greater than or equal to zero, we can't assume 280c5604d0aSTim J. Robbins * that the multibyte char. string ends in a null character. 281c5604d0aSTim J. Robbins */ 282c5604d0aSTim J. Robbins static wchar_t * 283c5604d0aSTim J. Robbins __mbsconv(char *mbsarg, int prec) 284c5604d0aSTim J. Robbins { 28593996f6dSTim J. Robbins mbstate_t mbs; 286c5604d0aSTim J. Robbins wchar_t *convbuf, *wcp; 287c5604d0aSTim J. Robbins const char *p; 288c5604d0aSTim J. Robbins size_t insize, nchars, nconv; 289c5604d0aSTim J. Robbins 290adfd6b31STim J. Robbins if (mbsarg == NULL) 291adfd6b31STim J. Robbins return (NULL); 292adfd6b31STim J. Robbins 293c5604d0aSTim J. Robbins /* 294c5604d0aSTim J. Robbins * Supplied argument is a multibyte string; convert it to wide 295c5604d0aSTim J. Robbins * characters first. 296c5604d0aSTim J. Robbins */ 297c5604d0aSTim J. Robbins if (prec >= 0) { 298c5604d0aSTim J. Robbins /* 299c5604d0aSTim J. Robbins * String is not guaranteed to be NUL-terminated. Find the 300c5604d0aSTim J. Robbins * number of characters to print. 301c5604d0aSTim J. Robbins */ 302c5604d0aSTim J. Robbins p = mbsarg; 303ab5b2fafSGarrett Wollman insize = nchars = nconv = 0; 3045004a238SDavid Schultz mbs = initial_mbs; 305c5604d0aSTim J. Robbins while (nchars != (size_t)prec) { 30693996f6dSTim J. Robbins nconv = mbrlen(p, MB_CUR_MAX, &mbs); 307c5604d0aSTim J. Robbins if (nconv == 0 || nconv == (size_t)-1 || 308c5604d0aSTim J. Robbins nconv == (size_t)-2) 309c5604d0aSTim J. Robbins break; 310c5604d0aSTim J. Robbins p += nconv; 311c5604d0aSTim J. Robbins nchars++; 312c5604d0aSTim J. Robbins insize += nconv; 313c5604d0aSTim J. Robbins } 314c5604d0aSTim J. Robbins if (nconv == (size_t)-1 || nconv == (size_t)-2) 315c5604d0aSTim J. Robbins return (NULL); 31622d725b5SColin Percival } else { 317c5604d0aSTim J. Robbins insize = strlen(mbsarg); 31822d725b5SColin Percival nconv = 0; 31922d725b5SColin Percival } 320c5604d0aSTim J. Robbins 321c5604d0aSTim J. Robbins /* 322c5604d0aSTim J. Robbins * Allocate buffer for the result and perform the conversion, 323c5604d0aSTim J. Robbins * converting at most `size' bytes of the input multibyte string to 324c5604d0aSTim J. Robbins * wide characters for printing. 325c5604d0aSTim J. Robbins */ 326c5604d0aSTim J. Robbins convbuf = malloc((insize + 1) * sizeof(*convbuf)); 327c5604d0aSTim J. Robbins if (convbuf == NULL) 328c5604d0aSTim J. Robbins return (NULL); 329c5604d0aSTim J. Robbins wcp = convbuf; 330c5604d0aSTim J. Robbins p = mbsarg; 3315004a238SDavid Schultz mbs = initial_mbs; 332c5604d0aSTim J. Robbins while (insize != 0) { 33393996f6dSTim J. Robbins nconv = mbrtowc(wcp, p, insize, &mbs); 334c5604d0aSTim J. Robbins if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) 335c5604d0aSTim J. Robbins break; 336c5604d0aSTim J. Robbins wcp++; 337c5604d0aSTim J. Robbins p += nconv; 338c5604d0aSTim J. Robbins insize -= nconv; 339c5604d0aSTim J. Robbins } 340c5604d0aSTim J. Robbins if (nconv == (size_t)-1 || nconv == (size_t)-2) { 341c5604d0aSTim J. Robbins free(convbuf); 342c5604d0aSTim J. Robbins return (NULL); 343c5604d0aSTim J. Robbins } 344c5604d0aSTim J. Robbins *wcp = L'\0'; 345c5604d0aSTim J. Robbins 346c5604d0aSTim J. Robbins return (convbuf); 347c5604d0aSTim J. Robbins } 348c5604d0aSTim J. Robbins 349c5604d0aSTim J. Robbins /* 350c5604d0aSTim J. Robbins * MT-safe version 351c5604d0aSTim J. Robbins */ 352c5604d0aSTim J. Robbins int 3533c87aa1dSDavid Chisnall vfwprintf_l(FILE * __restrict fp, locale_t locale, 3543c87aa1dSDavid Chisnall const wchar_t * __restrict fmt0, va_list ap) 355c5604d0aSTim J. Robbins 356c5604d0aSTim J. Robbins { 357c5604d0aSTim J. Robbins int ret; 3583c87aa1dSDavid Chisnall FIX_LOCALE(locale); 359fda0a14fSKonstantin Belousov FLOCKFILE_CANCELSAFE(fp); 360a1805f7bSDavid Schultz /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 361a1805f7bSDavid Schultz if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 362a1805f7bSDavid Schultz fp->_file >= 0) 3633c87aa1dSDavid Chisnall ret = __sbprintf(fp, locale, fmt0, ap); 364a1805f7bSDavid Schultz else 3653c87aa1dSDavid Chisnall ret = __vfwprintf(fp, locale, fmt0, ap); 366fda0a14fSKonstantin Belousov FUNLOCKFILE_CANCELSAFE(); 367c5604d0aSTim J. Robbins return (ret); 368c5604d0aSTim J. Robbins } 3693c87aa1dSDavid Chisnall int 3703c87aa1dSDavid Chisnall vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap) 3713c87aa1dSDavid Chisnall { 3723c87aa1dSDavid Chisnall return vfwprintf_l(fp, __get_locale(), fmt0, ap); 3733c87aa1dSDavid Chisnall } 374c5604d0aSTim J. Robbins 37538cac8f8SDavid Schultz /* 37638cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer 37721ca178eSDavid Schultz * conversions, among other things. We need enough space to 37821ca178eSDavid Schultz * write a uintmax_t in octal (plus one byte). 37938cac8f8SDavid Schultz */ 38021ca178eSDavid Schultz #if UINTMAX_MAX <= UINT64_MAX 38121ca178eSDavid Schultz #define BUF 32 38221ca178eSDavid Schultz #else 38321ca178eSDavid Schultz #error "BUF must be large enough to format a uintmax_t" 38421ca178eSDavid Schultz #endif 38538cac8f8SDavid Schultz 386c5604d0aSTim J. Robbins /* 387c5604d0aSTim J. Robbins * Non-MT-safe version 388c5604d0aSTim J. Robbins */ 389c5604d0aSTim J. Robbins int 3903c87aa1dSDavid Chisnall __vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap) 391c5604d0aSTim J. Robbins { 392c5604d0aSTim J. Robbins wchar_t *fmt; /* format string */ 393c5604d0aSTim J. Robbins wchar_t ch; /* character from fmt */ 394814d1bc9SDavid Schultz int n, n2; /* handy integer (short term usage) */ 395c5604d0aSTim J. Robbins wchar_t *cp; /* handy char pointer (short term usage) */ 396c5604d0aSTim J. Robbins int flags; /* flags as above */ 397c5604d0aSTim J. Robbins int ret; /* return value accumulator */ 398c5604d0aSTim J. Robbins int width; /* width from format (%8d), or 0 */ 399adfd6b31STim J. Robbins int prec; /* precision from format; <0 for N/A */ 400c5604d0aSTim J. Robbins wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */ 40121ca178eSDavid Schultz struct grouping_state gs; /* thousands' grouping info */ 402ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 403adfd6b31STim J. Robbins /* 404adfd6b31STim J. Robbins * We can decompose the printed representation of floating 405adfd6b31STim J. Robbins * point numbers into several parts, some of which may be empty: 406adfd6b31STim J. Robbins * 407adfd6b31STim J. Robbins * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 408adfd6b31STim J. Robbins * A B ---C--- D E F 409adfd6b31STim J. Robbins * 410adfd6b31STim J. Robbins * A: 'sign' holds this value if present; '\0' otherwise 411adfd6b31STim J. Robbins * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 412adfd6b31STim J. Robbins * C: cp points to the string MMMNNN. Leading and trailing 413adfd6b31STim J. Robbins * zeros are not in the string and must be added. 414adfd6b31STim J. Robbins * D: expchar holds this character; '\0' if no exponent, e.g. %f 415adfd6b31STim J. Robbins * F: at least two digits for decimal, at least one digit for hex 416adfd6b31STim J. Robbins */ 4175004a238SDavid Schultz wchar_t decimal_point; /* locale specific decimal point */ 418adfd6b31STim J. Robbins int signflag; /* true if float is negative */ 419adfd6b31STim J. Robbins union { /* floating point arguments %[aAeEfFgG] */ 420adfd6b31STim J. Robbins double dbl; 421adfd6b31STim J. Robbins long double ldbl; 422adfd6b31STim J. Robbins } fparg; 423c5604d0aSTim J. Robbins int expt; /* integer value of exponent */ 424adfd6b31STim J. Robbins char expchar; /* exponent character: [eEpP\0] */ 425adfd6b31STim J. Robbins char *dtoaend; /* pointer to end of converted digits */ 426c5604d0aSTim J. Robbins int expsize; /* character count for expstr */ 427adfd6b31STim J. Robbins int ndig; /* actual number of digits returned by dtoa */ 428adfd6b31STim J. Robbins wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 429adfd6b31STim J. Robbins char *dtoaresult; /* buffer allocated by dtoa */ 430c5604d0aSTim J. Robbins #endif 431c5604d0aSTim J. Robbins u_long ulval; /* integer arguments %[diouxX] */ 432c5604d0aSTim J. Robbins uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 433c5604d0aSTim J. Robbins int base; /* base for [diouxX] conversion */ 434c5604d0aSTim J. Robbins int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 435c5604d0aSTim J. Robbins int realsz; /* field size expanded by dprec, sign, etc */ 436c5604d0aSTim J. Robbins int size; /* size of converted field or string */ 437c5604d0aSTim J. Robbins int prsize; /* max size of printed field */ 4387b7e3509SDavid Schultz const char *xdigs; /* digits for [xX] conversion */ 439814d1bc9SDavid Schultz struct io_state io; /* I/O buffering state */ 44038cac8f8SDavid Schultz wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */ 441c5604d0aSTim J. Robbins wchar_t ox[2]; /* space for 0x hex-prefix */ 442c5604d0aSTim J. Robbins union arg *argtable; /* args, built due to positional arg */ 443c5604d0aSTim J. Robbins union arg statargtable [STATIC_ARG_TBL_SIZE]; 444c5604d0aSTim J. Robbins int nextarg; /* 1-based argument index */ 445c5604d0aSTim J. Robbins va_list orgap; /* original argument pointer */ 446c5604d0aSTim J. Robbins wchar_t *convbuf; /* multibyte to wide conversion result */ 4471bf6c5f1SAndrey A. Chernov int savserr; 448c5604d0aSTim J. Robbins 4497b7e3509SDavid Schultz static const char xdigs_lower[16] = "0123456789abcdef"; 4507b7e3509SDavid Schultz static const char xdigs_upper[16] = "0123456789ABCDEF"; 451adfd6b31STim J. Robbins 452814d1bc9SDavid Schultz /* BEWARE, these `goto error' on error. */ 453c5604d0aSTim J. Robbins #define PRINT(ptr, len) do { \ 4543c87aa1dSDavid Chisnall if (io_print(&io, (ptr), (len), locale)) \ 455814d1bc9SDavid Schultz goto error; \ 456c5604d0aSTim J. Robbins } while (0) 457814d1bc9SDavid Schultz #define PAD(howmany, with) { \ 4583c87aa1dSDavid Chisnall if (io_pad(&io, (howmany), (with), locale)) \ 459814d1bc9SDavid Schultz goto error; \ 460814d1bc9SDavid Schultz } 461814d1bc9SDavid Schultz #define PRINTANDPAD(p, ep, len, with) { \ 4623c87aa1dSDavid Chisnall if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \ 463814d1bc9SDavid Schultz goto error; \ 464814d1bc9SDavid Schultz } 465814d1bc9SDavid Schultz #define FLUSH() { \ 4663c87aa1dSDavid Chisnall if (io_flush(&io, locale)) \ 467814d1bc9SDavid Schultz goto error; \ 468814d1bc9SDavid Schultz } 469c5604d0aSTim J. Robbins 470c5604d0aSTim J. Robbins /* 471c5604d0aSTim J. Robbins * Get the argument indexed by nextarg. If the argument table is 472c5604d0aSTim J. Robbins * built, use it to get the argument. If its not, get the next 473c5604d0aSTim J. Robbins * argument (and arguments must be gotten sequentially). 474c5604d0aSTim J. Robbins */ 475c5604d0aSTim J. Robbins #define GETARG(type) \ 476c5604d0aSTim J. Robbins ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 477c5604d0aSTim J. Robbins (nextarg++, va_arg(ap, type))) 478c5604d0aSTim J. Robbins 479c5604d0aSTim J. Robbins /* 480c5604d0aSTim J. Robbins * To extend shorts properly, we need both signed and unsigned 481c5604d0aSTim J. Robbins * argument extraction methods. 482c5604d0aSTim J. Robbins */ 483c5604d0aSTim J. Robbins #define SARG() \ 484c5604d0aSTim J. Robbins (flags&LONGINT ? GETARG(long) : \ 485c5604d0aSTim J. Robbins flags&SHORTINT ? (long)(short)GETARG(int) : \ 486c5604d0aSTim J. Robbins flags&CHARINT ? (long)(signed char)GETARG(int) : \ 487c5604d0aSTim J. Robbins (long)GETARG(int)) 488c5604d0aSTim J. Robbins #define UARG() \ 489c5604d0aSTim J. Robbins (flags&LONGINT ? GETARG(u_long) : \ 490c5604d0aSTim J. Robbins flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 491c5604d0aSTim J. Robbins flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 492c5604d0aSTim J. Robbins (u_long)GETARG(u_int)) 493c5604d0aSTim J. Robbins #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 494c5604d0aSTim J. Robbins #define SJARG() \ 495c5604d0aSTim J. Robbins (flags&INTMAXT ? GETARG(intmax_t) : \ 4960881683bSDavid Schultz flags&SIZET ? (intmax_t)GETARG(ssize_t) : \ 497c5604d0aSTim J. Robbins flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 498c5604d0aSTim J. Robbins (intmax_t)GETARG(long long)) 499c5604d0aSTim J. Robbins #define UJARG() \ 500c5604d0aSTim J. Robbins (flags&INTMAXT ? GETARG(uintmax_t) : \ 501c5604d0aSTim J. Robbins flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 502c5604d0aSTim J. Robbins flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 503c5604d0aSTim J. Robbins (uintmax_t)GETARG(unsigned long long)) 504c5604d0aSTim J. Robbins 505c5604d0aSTim J. Robbins /* 506c5604d0aSTim J. Robbins * Get * arguments, including the form *nn$. Preserve the nextarg 507c5604d0aSTim J. Robbins * that the argument can be gotten once the type is determined. 508c5604d0aSTim J. Robbins */ 509c5604d0aSTim J. Robbins #define GETASTER(val) \ 510c5604d0aSTim J. Robbins n2 = 0; \ 511c5604d0aSTim J. Robbins cp = fmt; \ 512c5604d0aSTim J. Robbins while (is_digit(*cp)) { \ 513c5604d0aSTim J. Robbins n2 = 10 * n2 + to_digit(*cp); \ 514c5604d0aSTim J. Robbins cp++; \ 515c5604d0aSTim J. Robbins } \ 516c5604d0aSTim J. Robbins if (*cp == '$') { \ 517c5604d0aSTim J. Robbins int hold = nextarg; \ 518c5604d0aSTim J. Robbins if (argtable == NULL) { \ 519c5604d0aSTim J. Robbins argtable = statargtable; \ 520e62e5ff9SDavid Schultz if (__find_warguments (fmt0, orgap, &argtable)) { \ 521e62e5ff9SDavid Schultz ret = EOF; \ 522e62e5ff9SDavid Schultz goto error; \ 523e62e5ff9SDavid Schultz } \ 524c5604d0aSTim J. Robbins } \ 525c5604d0aSTim J. Robbins nextarg = n2; \ 526c5604d0aSTim J. Robbins val = GETARG (int); \ 527c5604d0aSTim J. Robbins nextarg = hold; \ 528c5604d0aSTim J. Robbins fmt = ++cp; \ 529c5604d0aSTim J. Robbins } else { \ 530c5604d0aSTim J. Robbins val = GETARG (int); \ 531c5604d0aSTim J. Robbins } 532c5604d0aSTim J. Robbins 533c5604d0aSTim J. Robbins 534c5604d0aSTim J. Robbins /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */ 535450ead86SPedro F. Giffuni if (prepwrite(fp) != 0) { 536450ead86SPedro F. Giffuni errno = EBADF; 537c5604d0aSTim J. Robbins return (EOF); 538450ead86SPedro F. Giffuni } 539c5604d0aSTim J. Robbins 5401bf6c5f1SAndrey A. Chernov savserr = fp->_flags & __SERR; 5411bf6c5f1SAndrey A. Chernov fp->_flags &= ~__SERR; 5421bf6c5f1SAndrey A. Chernov 543e18701f4SDavid Schultz convbuf = NULL; 544c5604d0aSTim J. Robbins fmt = (wchar_t *)fmt0; 545c5604d0aSTim J. Robbins argtable = NULL; 546c5604d0aSTim J. Robbins nextarg = 1; 547d07090a8STim J. Robbins va_copy(orgap, ap); 548814d1bc9SDavid Schultz io_init(&io, fp); 549c5604d0aSTim J. Robbins ret = 0; 550e18701f4SDavid Schultz #ifndef NO_FLOATING_POINT 5513c87aa1dSDavid Chisnall decimal_point = get_decpt(locale); 552e18701f4SDavid Schultz #endif 553c5604d0aSTim J. Robbins 554c5604d0aSTim J. Robbins /* 555c5604d0aSTim J. Robbins * Scan the format for conversions (`%' character). 556c5604d0aSTim J. Robbins */ 557c5604d0aSTim J. Robbins for (;;) { 558c5604d0aSTim J. Robbins for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 559c5604d0aSTim J. Robbins /* void */; 560c5604d0aSTim J. Robbins if ((n = fmt - cp) != 0) { 561c5604d0aSTim J. Robbins if ((unsigned)ret + n > INT_MAX) { 562c5604d0aSTim J. Robbins ret = EOF; 563666d00d3SDavid Schultz errno = EOVERFLOW; 564c5604d0aSTim J. Robbins goto error; 565c5604d0aSTim J. Robbins } 566c5604d0aSTim J. Robbins PRINT(cp, n); 567c5604d0aSTim J. Robbins ret += n; 568c5604d0aSTim J. Robbins } 569c5604d0aSTim J. Robbins if (ch == '\0') 570c5604d0aSTim J. Robbins goto done; 571c5604d0aSTim J. Robbins fmt++; /* skip over '%' */ 572c5604d0aSTim J. Robbins 573c5604d0aSTim J. Robbins flags = 0; 574c5604d0aSTim J. Robbins dprec = 0; 575c5604d0aSTim J. Robbins width = 0; 576c5604d0aSTim J. Robbins prec = -1; 57721ca178eSDavid Schultz gs.grouping = NULL; 578c5604d0aSTim J. Robbins sign = '\0'; 579adfd6b31STim J. Robbins ox[1] = '\0'; 580c5604d0aSTim J. Robbins 581c5604d0aSTim J. Robbins rflag: ch = *fmt++; 582c5604d0aSTim J. Robbins reswitch: switch (ch) { 583c5604d0aSTim J. Robbins case ' ': 584c5604d0aSTim J. Robbins /*- 585c5604d0aSTim J. Robbins * ``If the space and + flags both appear, the space 586c5604d0aSTim J. Robbins * flag will be ignored.'' 587c5604d0aSTim J. Robbins * -- ANSI X3J11 588c5604d0aSTim J. Robbins */ 589c5604d0aSTim J. Robbins if (!sign) 590c5604d0aSTim J. Robbins sign = ' '; 591c5604d0aSTim J. Robbins goto rflag; 592c5604d0aSTim J. Robbins case '#': 593c5604d0aSTim J. Robbins flags |= ALT; 594c5604d0aSTim J. Robbins goto rflag; 595c5604d0aSTim J. Robbins case '*': 596c5604d0aSTim J. Robbins /*- 597c5604d0aSTim J. Robbins * ``A negative field width argument is taken as a 598c5604d0aSTim J. Robbins * - flag followed by a positive field width.'' 599c5604d0aSTim J. Robbins * -- ANSI X3J11 600c5604d0aSTim J. Robbins * They don't exclude field widths read from args. 601c5604d0aSTim J. Robbins */ 602c5604d0aSTim J. Robbins GETASTER (width); 603c5604d0aSTim J. Robbins if (width >= 0) 604c5604d0aSTim J. Robbins goto rflag; 605c5604d0aSTim J. Robbins width = -width; 606c5604d0aSTim J. Robbins /* FALLTHROUGH */ 607c5604d0aSTim J. Robbins case '-': 608c5604d0aSTim J. Robbins flags |= LADJUST; 609c5604d0aSTim J. Robbins goto rflag; 610c5604d0aSTim J. Robbins case '+': 611c5604d0aSTim J. Robbins sign = '+'; 612c5604d0aSTim J. Robbins goto rflag; 613c5604d0aSTim J. Robbins case '\'': 614c5604d0aSTim J. Robbins flags |= GROUPING; 615c5604d0aSTim J. Robbins goto rflag; 616c5604d0aSTim J. Robbins case '.': 617c5604d0aSTim J. Robbins if ((ch = *fmt++) == '*') { 618adfd6b31STim J. Robbins GETASTER (prec); 619c5604d0aSTim J. Robbins goto rflag; 620c5604d0aSTim J. Robbins } 621adfd6b31STim J. Robbins prec = 0; 622c5604d0aSTim J. Robbins while (is_digit(ch)) { 623adfd6b31STim J. Robbins prec = 10 * prec + to_digit(ch); 624c5604d0aSTim J. Robbins ch = *fmt++; 625c5604d0aSTim J. Robbins } 626c5604d0aSTim J. Robbins goto reswitch; 627c5604d0aSTim J. Robbins case '0': 628c5604d0aSTim J. Robbins /*- 629c5604d0aSTim J. Robbins * ``Note that 0 is taken as a flag, not as the 630c5604d0aSTim J. Robbins * beginning of a field width.'' 631c5604d0aSTim J. Robbins * -- ANSI X3J11 632c5604d0aSTim J. Robbins */ 633c5604d0aSTim J. Robbins flags |= ZEROPAD; 634c5604d0aSTim J. Robbins goto rflag; 635c5604d0aSTim J. Robbins case '1': case '2': case '3': case '4': 636c5604d0aSTim J. Robbins case '5': case '6': case '7': case '8': case '9': 637c5604d0aSTim J. Robbins n = 0; 638c5604d0aSTim J. Robbins do { 639c5604d0aSTim J. Robbins n = 10 * n + to_digit(ch); 640c5604d0aSTim J. Robbins ch = *fmt++; 641c5604d0aSTim J. Robbins } while (is_digit(ch)); 642c5604d0aSTim J. Robbins if (ch == '$') { 643c5604d0aSTim J. Robbins nextarg = n; 644c5604d0aSTim J. Robbins if (argtable == NULL) { 645c5604d0aSTim J. Robbins argtable = statargtable; 646e62e5ff9SDavid Schultz if (__find_warguments (fmt0, orgap, 647e62e5ff9SDavid Schultz &argtable)) { 648e62e5ff9SDavid Schultz ret = EOF; 649e62e5ff9SDavid Schultz goto error; 650e62e5ff9SDavid Schultz } 651c5604d0aSTim J. Robbins } 652c5604d0aSTim J. Robbins goto rflag; 653c5604d0aSTim J. Robbins } 654c5604d0aSTim J. Robbins width = n; 655c5604d0aSTim J. Robbins goto reswitch; 656ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 657c5604d0aSTim J. Robbins case 'L': 658c5604d0aSTim J. Robbins flags |= LONGDBL; 659c5604d0aSTim J. Robbins goto rflag; 660c5604d0aSTim J. Robbins #endif 661c5604d0aSTim J. Robbins case 'h': 662c5604d0aSTim J. Robbins if (flags & SHORTINT) { 663c5604d0aSTim J. Robbins flags &= ~SHORTINT; 664c5604d0aSTim J. Robbins flags |= CHARINT; 665c5604d0aSTim J. Robbins } else 666c5604d0aSTim J. Robbins flags |= SHORTINT; 667c5604d0aSTim J. Robbins goto rflag; 668c5604d0aSTim J. Robbins case 'j': 669c5604d0aSTim J. Robbins flags |= INTMAXT; 670c5604d0aSTim J. Robbins goto rflag; 671c5604d0aSTim J. Robbins case 'l': 672c5604d0aSTim J. Robbins if (flags & LONGINT) { 673c5604d0aSTim J. Robbins flags &= ~LONGINT; 674c5604d0aSTim J. Robbins flags |= LLONGINT; 675c5604d0aSTim J. Robbins } else 676c5604d0aSTim J. Robbins flags |= LONGINT; 677c5604d0aSTim J. Robbins goto rflag; 678c5604d0aSTim J. Robbins case 'q': 679c5604d0aSTim J. Robbins flags |= LLONGINT; /* not necessarily */ 680c5604d0aSTim J. Robbins goto rflag; 681c5604d0aSTim J. Robbins case 't': 682c5604d0aSTim J. Robbins flags |= PTRDIFFT; 683c5604d0aSTim J. Robbins goto rflag; 684*bce0bef3SDag-Erling Smørgrav case 'w': 685*bce0bef3SDag-Erling Smørgrav /* 686*bce0bef3SDag-Erling Smørgrav * Fixed-width integer types. On all platforms we 687*bce0bef3SDag-Erling Smørgrav * support, int8_t is equivalent to char, int16_t 688*bce0bef3SDag-Erling Smørgrav * is equivalent to short, int32_t is equivalent 689*bce0bef3SDag-Erling Smørgrav * to int, int64_t is equivalent to long long int. 690*bce0bef3SDag-Erling Smørgrav * Furthermore, int_fast8_t, int_fast16_t and 691*bce0bef3SDag-Erling Smørgrav * int_fast32_t are equivalent to int, and 692*bce0bef3SDag-Erling Smørgrav * int_fast64_t is equivalent to long long int. 693*bce0bef3SDag-Erling Smørgrav */ 694*bce0bef3SDag-Erling Smørgrav flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT); 695*bce0bef3SDag-Erling Smørgrav if (fmt[0] == 'f') { 696*bce0bef3SDag-Erling Smørgrav flags |= FASTINT; 697*bce0bef3SDag-Erling Smørgrav fmt++; 698*bce0bef3SDag-Erling Smørgrav } else { 699*bce0bef3SDag-Erling Smørgrav flags &= ~FASTINT; 700*bce0bef3SDag-Erling Smørgrav } 701*bce0bef3SDag-Erling Smørgrav if (fmt[0] == '8') { 702*bce0bef3SDag-Erling Smørgrav if (!(flags & FASTINT)) 703*bce0bef3SDag-Erling Smørgrav flags |= CHARINT; 704*bce0bef3SDag-Erling Smørgrav else 705*bce0bef3SDag-Erling Smørgrav /* no flag set = 32 */ ; 706*bce0bef3SDag-Erling Smørgrav fmt += 1; 707*bce0bef3SDag-Erling Smørgrav } else if (fmt[0] == '1' && fmt[1] == '6') { 708*bce0bef3SDag-Erling Smørgrav if (!(flags & FASTINT)) 709*bce0bef3SDag-Erling Smørgrav flags |= SHORTINT; 710*bce0bef3SDag-Erling Smørgrav else 711*bce0bef3SDag-Erling Smørgrav /* no flag set = 32 */ ; 712*bce0bef3SDag-Erling Smørgrav fmt += 2; 713*bce0bef3SDag-Erling Smørgrav } else if (fmt[0] == '3' && fmt[1] == '2') { 714*bce0bef3SDag-Erling Smørgrav /* no flag set = 32 */ ; 715*bce0bef3SDag-Erling Smørgrav fmt += 2; 716*bce0bef3SDag-Erling Smørgrav } else if (fmt[0] == '6' && fmt[1] == '4') { 717*bce0bef3SDag-Erling Smørgrav flags |= LLONGINT; 718*bce0bef3SDag-Erling Smørgrav fmt += 2; 719*bce0bef3SDag-Erling Smørgrav } else { 720*bce0bef3SDag-Erling Smørgrav if (flags & FASTINT) { 721*bce0bef3SDag-Erling Smørgrav flags &= ~FASTINT; 722*bce0bef3SDag-Erling Smørgrav fmt--; 723*bce0bef3SDag-Erling Smørgrav } 724*bce0bef3SDag-Erling Smørgrav goto invalid; 725*bce0bef3SDag-Erling Smørgrav } 726*bce0bef3SDag-Erling Smørgrav goto rflag; 727c5604d0aSTim J. Robbins case 'z': 728c5604d0aSTim J. Robbins flags |= SIZET; 729c5604d0aSTim J. Robbins goto rflag; 730d9dc1603SDag-Erling Smørgrav case 'B': 731d9dc1603SDag-Erling Smørgrav case 'b': 732d9dc1603SDag-Erling Smørgrav if (flags & INTMAX_SIZE) 733d9dc1603SDag-Erling Smørgrav ujval = UJARG(); 734d9dc1603SDag-Erling Smørgrav else 735d9dc1603SDag-Erling Smørgrav ulval = UARG(); 736d9dc1603SDag-Erling Smørgrav base = 2; 737d9dc1603SDag-Erling Smørgrav /* leading 0b/B only if non-zero */ 738d9dc1603SDag-Erling Smørgrav if (flags & ALT && 739d9dc1603SDag-Erling Smørgrav (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 740d9dc1603SDag-Erling Smørgrav ox[1] = ch; 741d9dc1603SDag-Erling Smørgrav goto nosign; 742d9dc1603SDag-Erling Smørgrav break; 743927ecbf3STim J. Robbins case 'C': 744927ecbf3STim J. Robbins flags |= LONGINT; 745927ecbf3STim J. Robbins /*FALLTHROUGH*/ 746c5604d0aSTim J. Robbins case 'c': 747c5604d0aSTim J. Robbins if (flags & LONGINT) 748c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)GETARG(wint_t); 749c5604d0aSTim J. Robbins else 750c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)btowc(GETARG(int)); 751c5604d0aSTim J. Robbins size = 1; 752c5604d0aSTim J. Robbins sign = '\0'; 753c5604d0aSTim J. Robbins break; 754c5604d0aSTim J. Robbins case 'D': 755c5604d0aSTim J. Robbins flags |= LONGINT; 756c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 757c5604d0aSTim J. Robbins case 'd': 758c5604d0aSTim J. Robbins case 'i': 759c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 760c5604d0aSTim J. Robbins ujval = SJARG(); 761c5604d0aSTim J. Robbins if ((intmax_t)ujval < 0) { 762c5604d0aSTim J. Robbins ujval = -ujval; 763c5604d0aSTim J. Robbins sign = '-'; 764c5604d0aSTim J. Robbins } 765c5604d0aSTim J. Robbins } else { 766c5604d0aSTim J. Robbins ulval = SARG(); 767c5604d0aSTim J. Robbins if ((long)ulval < 0) { 768c5604d0aSTim J. Robbins ulval = -ulval; 769c5604d0aSTim J. Robbins sign = '-'; 770c5604d0aSTim J. Robbins } 771c5604d0aSTim J. Robbins } 772c5604d0aSTim J. Robbins base = 10; 773c5604d0aSTim J. Robbins goto number; 774ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 775c5604d0aSTim J. Robbins case 'a': 776c5604d0aSTim J. Robbins case 'A': 777adfd6b31STim J. Robbins if (ch == 'a') { 778adfd6b31STim J. Robbins ox[1] = 'x'; 779adfd6b31STim J. Robbins xdigs = xdigs_lower; 780adfd6b31STim J. Robbins expchar = 'p'; 781adfd6b31STim J. Robbins } else { 782adfd6b31STim J. Robbins ox[1] = 'X'; 783adfd6b31STim J. Robbins xdigs = xdigs_upper; 784adfd6b31STim J. Robbins expchar = 'P'; 785adfd6b31STim J. Robbins } 7867b7e3509SDavid Schultz if (prec >= 0) 7877b7e3509SDavid Schultz prec++; 788adfd6b31STim J. Robbins if (flags & LONGDBL) { 7897b7e3509SDavid Schultz fparg.ldbl = GETARG(long double); 790adfd6b31STim J. Robbins dtoaresult = 791adfd6b31STim J. Robbins __hldtoa(fparg.ldbl, xdigs, prec, 792adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 793adfd6b31STim J. Robbins } else { 794adfd6b31STim J. Robbins fparg.dbl = GETARG(double); 795adfd6b31STim J. Robbins dtoaresult = 796adfd6b31STim J. Robbins __hdtoa(fparg.dbl, xdigs, prec, 797adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 798adfd6b31STim J. Robbins } 7997b7e3509SDavid Schultz if (prec < 0) 8007b7e3509SDavid Schultz prec = dtoaend - dtoaresult; 8017b7e3509SDavid Schultz if (expt == INT_MAX) 8027b7e3509SDavid Schultz ox[1] = '\0'; 803adfd6b31STim J. Robbins if (convbuf != NULL) 804adfd6b31STim J. Robbins free(convbuf); 8057b7e3509SDavid Schultz ndig = dtoaend - dtoaresult; 806adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 807adfd6b31STim J. Robbins freedtoa(dtoaresult); 8087b7e3509SDavid Schultz goto fp_common; 809c5604d0aSTim J. Robbins case 'e': 810c5604d0aSTim J. Robbins case 'E': 811adfd6b31STim J. Robbins expchar = ch; 812adfd6b31STim J. Robbins if (prec < 0) /* account for digit before decpt */ 813adfd6b31STim J. Robbins prec = DEFPREC + 1; 814adfd6b31STim J. Robbins else 815adfd6b31STim J. Robbins prec++; 816adfd6b31STim J. Robbins goto fp_begin; 817c5604d0aSTim J. Robbins case 'f': 818c5604d0aSTim J. Robbins case 'F': 819adfd6b31STim J. Robbins expchar = '\0'; 820c5604d0aSTim J. Robbins goto fp_begin; 821c5604d0aSTim J. Robbins case 'g': 822c5604d0aSTim J. Robbins case 'G': 823adfd6b31STim J. Robbins expchar = ch - ('g' - 'e'); 824c5604d0aSTim J. Robbins if (prec == 0) 825c5604d0aSTim J. Robbins prec = 1; 826adfd6b31STim J. Robbins fp_begin: 827adfd6b31STim J. Robbins if (prec < 0) 828c5604d0aSTim J. Robbins prec = DEFPREC; 829adfd6b31STim J. Robbins if (convbuf != NULL) 830adfd6b31STim J. Robbins free(convbuf); 831adfd6b31STim J. Robbins if (flags & LONGDBL) { 832adfd6b31STim J. Robbins fparg.ldbl = GETARG(long double); 833adfd6b31STim J. Robbins dtoaresult = 834adfd6b31STim J. Robbins __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 835adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 836adfd6b31STim J. Robbins } else { 837adfd6b31STim J. Robbins fparg.dbl = GETARG(double); 838adfd6b31STim J. Robbins dtoaresult = 839adfd6b31STim J. Robbins dtoa(fparg.dbl, expchar ? 2 : 3, prec, 840adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 841adfd6b31STim J. Robbins if (expt == 9999) 842adfd6b31STim J. Robbins expt = INT_MAX; 843c5604d0aSTim J. Robbins } 844adfd6b31STim J. Robbins ndig = dtoaend - dtoaresult; 845adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 846adfd6b31STim J. Robbins freedtoa(dtoaresult); 8477b7e3509SDavid Schultz fp_common: 848adfd6b31STim J. Robbins if (signflag) 849adfd6b31STim J. Robbins sign = '-'; 850adfd6b31STim J. Robbins if (expt == INT_MAX) { /* inf or nan */ 851adfd6b31STim J. Robbins if (*cp == 'N') { 852adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"nan" : L"NAN"; 853adfd6b31STim J. Robbins sign = '\0'; 854adfd6b31STim J. Robbins } else 855adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"inf" : L"INF"; 856c5604d0aSTim J. Robbins size = 3; 8578da510f8SDavid Schultz flags &= ~ZEROPAD; 858c5604d0aSTim J. Robbins break; 859c5604d0aSTim J. Robbins } 860c5604d0aSTim J. Robbins flags |= FPT; 861c5604d0aSTim J. Robbins if (ch == 'g' || ch == 'G') { 862adfd6b31STim J. Robbins if (expt > -4 && expt <= prec) { 863adfd6b31STim J. Robbins /* Make %[gG] smell like %[fF] */ 864adfd6b31STim J. Robbins expchar = '\0'; 865adfd6b31STim J. Robbins if (flags & ALT) 866adfd6b31STim J. Robbins prec -= expt; 867c5604d0aSTim J. Robbins else 868adfd6b31STim J. Robbins prec = ndig - expt; 869adfd6b31STim J. Robbins if (prec < 0) 870adfd6b31STim J. Robbins prec = 0; 8711f2a0cdfSDavid Schultz } else { 8721f2a0cdfSDavid Schultz /* 8731f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but 8741f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag. 8751f2a0cdfSDavid Schultz */ 8761f2a0cdfSDavid Schultz if (!(flags & ALT)) 8771f2a0cdfSDavid Schultz prec = ndig; 878c5604d0aSTim J. Robbins } 879adfd6b31STim J. Robbins } 880adfd6b31STim J. Robbins if (expchar) { 881adfd6b31STim J. Robbins expsize = exponent(expstr, expt - 1, expchar); 882adfd6b31STim J. Robbins size = expsize + prec; 883adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) 884c5604d0aSTim J. Robbins ++size; 885adfd6b31STim J. Robbins } else { 886d73c448bSTim J. Robbins /* space for digits before decimal point */ 887d73c448bSTim J. Robbins if (expt > 0) 888c5604d0aSTim J. Robbins size = expt; 889d73c448bSTim J. Robbins else /* "0" */ 890d73c448bSTim J. Robbins size = 1; 891d73c448bSTim J. Robbins /* space for decimal pt and following digits */ 892c5604d0aSTim J. Robbins if (prec || flags & ALT) 893c5604d0aSTim J. Robbins size += prec + 1; 89421ca178eSDavid Schultz if ((flags & GROUPING) && expt > 0) 8953c87aa1dSDavid Chisnall size += grouping_init(&gs, expt, locale); 896adfd6b31STim J. Robbins } 897c5604d0aSTim J. Robbins break; 898ce2551adSDavid Schultz #endif /* !NO_FLOATING_POINT */ 899c5604d0aSTim J. Robbins case 'n': 900c5604d0aSTim J. Robbins /* 901c5604d0aSTim J. Robbins * Assignment-like behavior is specified if the 902c5604d0aSTim J. Robbins * value overflows or is otherwise unrepresentable. 903c5604d0aSTim J. Robbins * C99 says to use `signed char' for %hhn conversions. 904c5604d0aSTim J. Robbins */ 905c5604d0aSTim J. Robbins if (flags & LLONGINT) 906c5604d0aSTim J. Robbins *GETARG(long long *) = ret; 907c5604d0aSTim J. Robbins else if (flags & SIZET) 908c5604d0aSTim J. Robbins *GETARG(ssize_t *) = (ssize_t)ret; 909c5604d0aSTim J. Robbins else if (flags & PTRDIFFT) 910c5604d0aSTim J. Robbins *GETARG(ptrdiff_t *) = ret; 911c5604d0aSTim J. Robbins else if (flags & INTMAXT) 912c5604d0aSTim J. Robbins *GETARG(intmax_t *) = ret; 913c5604d0aSTim J. Robbins else if (flags & LONGINT) 914c5604d0aSTim J. Robbins *GETARG(long *) = ret; 915c5604d0aSTim J. Robbins else if (flags & SHORTINT) 916c5604d0aSTim J. Robbins *GETARG(short *) = ret; 917c5604d0aSTim J. Robbins else if (flags & CHARINT) 918c5604d0aSTim J. Robbins *GETARG(signed char *) = ret; 919c5604d0aSTim J. Robbins else 920c5604d0aSTim J. Robbins *GETARG(int *) = ret; 921c5604d0aSTim J. Robbins continue; /* no output */ 922c5604d0aSTim J. Robbins case 'O': 923c5604d0aSTim J. Robbins flags |= LONGINT; 924c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 925c5604d0aSTim J. Robbins case 'o': 926c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 927c5604d0aSTim J. Robbins ujval = UJARG(); 928c5604d0aSTim J. Robbins else 929c5604d0aSTim J. Robbins ulval = UARG(); 930c5604d0aSTim J. Robbins base = 8; 931c5604d0aSTim J. Robbins goto nosign; 932c5604d0aSTim J. Robbins case 'p': 933c5604d0aSTim J. Robbins /*- 934c5604d0aSTim J. Robbins * ``The argument shall be a pointer to void. The 935c5604d0aSTim J. Robbins * value of the pointer is converted to a sequence 936c5604d0aSTim J. Robbins * of printable characters, in an implementation- 937c5604d0aSTim J. Robbins * defined manner.'' 938c5604d0aSTim J. Robbins * -- ANSI X3J11 939c5604d0aSTim J. Robbins */ 940c5604d0aSTim J. Robbins ujval = (uintmax_t)(uintptr_t)GETARG(void *); 941c5604d0aSTim J. Robbins base = 16; 942adfd6b31STim J. Robbins xdigs = xdigs_lower; 943adfd6b31STim J. Robbins flags = flags | INTMAXT; 944adfd6b31STim J. Robbins ox[1] = 'x'; 945c5604d0aSTim J. Robbins goto nosign; 946927ecbf3STim J. Robbins case 'S': 947927ecbf3STim J. Robbins flags |= LONGINT; 948927ecbf3STim J. Robbins /*FALLTHROUGH*/ 949c5604d0aSTim J. Robbins case 's': 950c5604d0aSTim J. Robbins if (flags & LONGINT) { 951c5604d0aSTim J. Robbins if ((cp = GETARG(wchar_t *)) == NULL) 952c5604d0aSTim J. Robbins cp = L"(null)"; 953c5604d0aSTim J. Robbins } else { 954c5604d0aSTim J. Robbins char *mbp; 955c5604d0aSTim J. Robbins 956c5604d0aSTim J. Robbins if (convbuf != NULL) 957c5604d0aSTim J. Robbins free(convbuf); 958c5604d0aSTim J. Robbins if ((mbp = GETARG(char *)) == NULL) 959c5604d0aSTim J. Robbins cp = L"(null)"; 960c5604d0aSTim J. Robbins else { 961c5604d0aSTim J. Robbins convbuf = __mbsconv(mbp, prec); 9626180233fSTim J. Robbins if (convbuf == NULL) { 9636180233fSTim J. Robbins fp->_flags |= __SERR; 964c5604d0aSTim J. Robbins goto error; 9656180233fSTim J. Robbins } 966c5604d0aSTim J. Robbins cp = convbuf; 967c5604d0aSTim J. Robbins } 968c5604d0aSTim J. Robbins } 969353ce11cSDavid Schultz size = (prec >= 0) ? wcsnlen(cp, prec) : wcslen(cp); 970c5604d0aSTim J. Robbins sign = '\0'; 971c5604d0aSTim J. Robbins break; 972c5604d0aSTim J. Robbins case 'U': 973c5604d0aSTim J. Robbins flags |= LONGINT; 974c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 975c5604d0aSTim J. Robbins case 'u': 976c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 977c5604d0aSTim J. Robbins ujval = UJARG(); 978c5604d0aSTim J. Robbins else 979c5604d0aSTim J. Robbins ulval = UARG(); 980c5604d0aSTim J. Robbins base = 10; 981c5604d0aSTim J. Robbins goto nosign; 982c5604d0aSTim J. Robbins case 'X': 983adfd6b31STim J. Robbins xdigs = xdigs_upper; 984c5604d0aSTim J. Robbins goto hex; 985c5604d0aSTim J. Robbins case 'x': 986adfd6b31STim J. Robbins xdigs = xdigs_lower; 987c5604d0aSTim J. Robbins hex: 988c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 989c5604d0aSTim J. Robbins ujval = UJARG(); 990c5604d0aSTim J. Robbins else 991c5604d0aSTim J. Robbins ulval = UARG(); 992c5604d0aSTim J. Robbins base = 16; 993c5604d0aSTim J. Robbins /* leading 0x/X only if non-zero */ 994c5604d0aSTim J. Robbins if (flags & ALT && 995c5604d0aSTim J. Robbins (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 996adfd6b31STim J. Robbins ox[1] = ch; 997c5604d0aSTim J. Robbins 998c5604d0aSTim J. Robbins flags &= ~GROUPING; 999c5604d0aSTim J. Robbins /* unsigned conversions */ 1000c5604d0aSTim J. Robbins nosign: sign = '\0'; 1001c5604d0aSTim J. Robbins /*- 1002c5604d0aSTim J. Robbins * ``... diouXx conversions ... if a precision is 1003c5604d0aSTim J. Robbins * specified, the 0 flag will be ignored.'' 1004c5604d0aSTim J. Robbins * -- ANSI X3J11 1005c5604d0aSTim J. Robbins */ 1006c5604d0aSTim J. Robbins number: if ((dprec = prec) >= 0) 1007c5604d0aSTim J. Robbins flags &= ~ZEROPAD; 1008c5604d0aSTim J. Robbins 1009c5604d0aSTim J. Robbins /*- 1010c5604d0aSTim J. Robbins * ``The result of converting a zero value with an 1011c5604d0aSTim J. Robbins * explicit precision of zero is no characters.'' 1012c5604d0aSTim J. Robbins * -- ANSI X3J11 10131be5319aSDavid Schultz * 10141be5319aSDavid Schultz * ``The C Standard is clear enough as is. The call 10151be5319aSDavid Schultz * printf("%#.0o", 0) should print 0.'' 10161be5319aSDavid Schultz * -- Defect Report #151 1017c5604d0aSTim J. Robbins */ 1018c5604d0aSTim J. Robbins cp = buf + BUF; 1019c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 10201be5319aSDavid Schultz if (ujval != 0 || prec != 0 || 10211be5319aSDavid Schultz (flags & ALT && base == 8)) 1022c5604d0aSTim J. Robbins cp = __ujtoa(ujval, cp, base, 102321ca178eSDavid Schultz flags & ALT, xdigs); 1024c5604d0aSTim J. Robbins } else { 10251be5319aSDavid Schultz if (ulval != 0 || prec != 0 || 10261be5319aSDavid Schultz (flags & ALT && base == 8)) 1027c5604d0aSTim J. Robbins cp = __ultoa(ulval, cp, base, 102821ca178eSDavid Schultz flags & ALT, xdigs); 1029c5604d0aSTim J. Robbins } 1030c5604d0aSTim J. Robbins size = buf + BUF - cp; 103138cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 103238cac8f8SDavid Schultz abort(); 103321ca178eSDavid Schultz if ((flags & GROUPING) && size != 0) 10343c87aa1dSDavid Chisnall size += grouping_init(&gs, size, locale); 1035c5604d0aSTim J. Robbins break; 1036c5604d0aSTim J. Robbins default: /* "%?" prints ?, unless ? is NUL */ 1037c5604d0aSTim J. Robbins if (ch == '\0') 1038c5604d0aSTim J. Robbins goto done; 1039*bce0bef3SDag-Erling Smørgrav invalid: 1040c5604d0aSTim J. Robbins /* pretend it was %c with argument ch */ 1041c5604d0aSTim J. Robbins cp = buf; 1042c5604d0aSTim J. Robbins *cp = ch; 1043c5604d0aSTim J. Robbins size = 1; 1044c5604d0aSTim J. Robbins sign = '\0'; 1045c5604d0aSTim J. Robbins break; 1046c5604d0aSTim J. Robbins } 1047c5604d0aSTim J. Robbins 1048c5604d0aSTim J. Robbins /* 1049c5604d0aSTim J. Robbins * All reasonable formats wind up here. At this point, `cp' 1050c5604d0aSTim J. Robbins * points to a string which (if not flags&LADJUST) should be 1051c5604d0aSTim J. Robbins * padded out to `width' places. If flags&ZEROPAD, it should 1052c5604d0aSTim J. Robbins * first be prefixed by any sign or other prefix; otherwise, 1053c5604d0aSTim J. Robbins * it should be blank padded before the prefix is emitted. 1054c5604d0aSTim J. Robbins * After any left-hand padding and prefixing, emit zeroes 1055c5604d0aSTim J. Robbins * required by a decimal [diouxX] precision, then print the 1056c5604d0aSTim J. Robbins * string proper, then emit zeroes required by any leftover 1057c5604d0aSTim J. Robbins * floating precision; finally, if LADJUST, pad with blanks. 1058c5604d0aSTim J. Robbins * 1059c5604d0aSTim J. Robbins * Compute actual size, so we know how much to pad. 1060c5604d0aSTim J. Robbins * size excludes decimal prec; realsz includes it. 1061c5604d0aSTim J. Robbins */ 1062c5604d0aSTim J. Robbins realsz = dprec > size ? dprec : size; 1063c5604d0aSTim J. Robbins if (sign) 1064c5604d0aSTim J. Robbins realsz++; 10657b7e3509SDavid Schultz if (ox[1]) 1066c5604d0aSTim J. Robbins realsz += 2; 1067c5604d0aSTim J. Robbins 1068c5604d0aSTim J. Robbins prsize = width > realsz ? width : realsz; 1069c5604d0aSTim J. Robbins if ((unsigned)ret + prsize > INT_MAX) { 1070c5604d0aSTim J. Robbins ret = EOF; 1071666d00d3SDavid Schultz errno = EOVERFLOW; 1072c5604d0aSTim J. Robbins goto error; 1073c5604d0aSTim J. Robbins } 1074c5604d0aSTim J. Robbins 1075c5604d0aSTim J. Robbins /* right-adjusting blank padding */ 1076c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == 0) 1077c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1078c5604d0aSTim J. Robbins 1079c5604d0aSTim J. Robbins /* prefix */ 10807b7e3509SDavid Schultz if (sign) 1081c5604d0aSTim J. Robbins PRINT(&sign, 1); 10827b7e3509SDavid Schultz 10837b7e3509SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */ 1084c5604d0aSTim J. Robbins ox[0] = '0'; 1085c5604d0aSTim J. Robbins PRINT(ox, 2); 1086c5604d0aSTim J. Robbins } 1087c5604d0aSTim J. Robbins 1088c5604d0aSTim J. Robbins /* right-adjusting zero padding */ 1089c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 1090c5604d0aSTim J. Robbins PAD(width - realsz, zeroes); 1091c5604d0aSTim J. Robbins 1092c5604d0aSTim J. Robbins /* the string or number proper */ 1093ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 1094c5604d0aSTim J. Robbins if ((flags & FPT) == 0) { 109521ca178eSDavid Schultz #endif 109621ca178eSDavid Schultz /* leading zeroes from decimal precision */ 109721ca178eSDavid Schultz PAD(dprec - size, zeroes); 109821ca178eSDavid Schultz if (gs.grouping) { 10993c87aa1dSDavid Chisnall if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0) 110021ca178eSDavid Schultz goto error; 110121ca178eSDavid Schultz } else { 1102c5604d0aSTim J. Robbins PRINT(cp, size); 110321ca178eSDavid Schultz } 110421ca178eSDavid Schultz #ifndef NO_FLOATING_POINT 1105c5604d0aSTim J. Robbins } else { /* glue together f_p fragments */ 1106adfd6b31STim J. Robbins if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1107adfd6b31STim J. Robbins if (expt <= 0) { 1108d73c448bSTim J. Robbins PRINT(zeroes, 1); 11095004a238SDavid Schultz if (prec || flags & ALT) 11105004a238SDavid Schultz PRINT(&decimal_point, 1); 1111c5604d0aSTim J. Robbins PAD(-expt, zeroes); 1112adfd6b31STim J. Robbins /* already handled initial 0's */ 1113adfd6b31STim J. Robbins prec += expt; 1114c5604d0aSTim J. Robbins } else { 111521ca178eSDavid Schultz if (gs.grouping) { 111621ca178eSDavid Schultz n = grouping_print(&gs, &io, 11173c87aa1dSDavid Chisnall cp, convbuf + ndig, locale); 111821ca178eSDavid Schultz if (n < 0) 111921ca178eSDavid Schultz goto error; 112021ca178eSDavid Schultz cp += n; 112121ca178eSDavid Schultz } else { 112221ca178eSDavid Schultz PRINTANDPAD(cp, convbuf + ndig, 112321ca178eSDavid Schultz expt, zeroes); 112421ca178eSDavid Schultz cp += expt; 1125adfd6b31STim J. Robbins } 11265004a238SDavid Schultz if (prec || flags & ALT) 11275004a238SDavid Schultz PRINT(&decimal_point, 1); 1128adfd6b31STim J. Robbins } 1129adfd6b31STim J. Robbins PRINTANDPAD(cp, convbuf + ndig, prec, zeroes); 1130adfd6b31STim J. Robbins } else { /* %[eE] or sufficiently long %[gG] */ 1131adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) { 1132adfd6b31STim J. Robbins buf[0] = *cp++; 11335004a238SDavid Schultz buf[1] = decimal_point; 1134adfd6b31STim J. Robbins PRINT(buf, 2); 1135c5604d0aSTim J. Robbins PRINT(cp, ndig-1); 1136adfd6b31STim J. Robbins PAD(prec - ndig, zeroes); 1137c5604d0aSTim J. Robbins } else /* XeYYY */ 1138c5604d0aSTim J. Robbins PRINT(cp, 1); 1139c5604d0aSTim J. Robbins PRINT(expstr, expsize); 1140c5604d0aSTim J. Robbins } 1141c5604d0aSTim J. Robbins } 1142c5604d0aSTim J. Robbins #endif 1143c5604d0aSTim J. Robbins /* left-adjusting padding (always blank) */ 1144c5604d0aSTim J. Robbins if (flags & LADJUST) 1145c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1146c5604d0aSTim J. Robbins 1147c5604d0aSTim J. Robbins /* finally, adjust ret */ 1148c5604d0aSTim J. Robbins ret += prsize; 1149814d1bc9SDavid Schultz 1150814d1bc9SDavid Schultz FLUSH(); /* copy out the I/O vectors */ 1151c5604d0aSTim J. Robbins } 1152c5604d0aSTim J. Robbins done: 1153814d1bc9SDavid Schultz FLUSH(); 1154c5604d0aSTim J. Robbins error: 1155096ad104SDag-Erling Smørgrav va_end(orgap); 1156c5604d0aSTim J. Robbins if (convbuf != NULL) 1157c5604d0aSTim J. Robbins free(convbuf); 1158c5604d0aSTim J. Robbins if (__sferror(fp)) 1159c5604d0aSTim J. Robbins ret = EOF; 11601bf6c5f1SAndrey A. Chernov else 11611bf6c5f1SAndrey A. Chernov fp->_flags |= savserr; 1162c5604d0aSTim J. Robbins if ((argtable != NULL) && (argtable != statargtable)) 1163c5604d0aSTim J. Robbins free (argtable); 1164c5604d0aSTim J. Robbins return (ret); 1165c5604d0aSTim J. Robbins /* NOTREACHED */ 1166c5604d0aSTim J. Robbins } 1167