1c5604d0aSTim J. Robbins /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro 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 113c87aa1dSDavid Chisnall * All rights reserved. 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 __FBSDID("$FreeBSD$"); 47c5604d0aSTim J. Robbins 48c5604d0aSTim J. Robbins /* 49c5604d0aSTim J. Robbins * Actual wprintf innards. 50c5604d0aSTim J. Robbins * 51c5604d0aSTim J. Robbins * Avoid making gratuitous changes to this source file; it should be kept 52c5604d0aSTim J. Robbins * as close as possible to vfprintf.c for ease of maintenance. 53c5604d0aSTim J. Robbins */ 54c5604d0aSTim J. Robbins 55c5604d0aSTim J. Robbins #include "namespace.h" 56c5604d0aSTim J. Robbins #include <sys/types.h> 57c5604d0aSTim J. Robbins 58c5604d0aSTim J. Robbins #include <ctype.h> 59666d00d3SDavid Schultz #include <errno.h> 60c5604d0aSTim J. Robbins #include <limits.h> 61c5604d0aSTim J. Robbins #include <locale.h> 62c5604d0aSTim J. Robbins #include <stdarg.h> 63c5604d0aSTim J. Robbins #include <stddef.h> 64c5604d0aSTim J. Robbins #include <stdint.h> 65c5604d0aSTim J. Robbins #include <stdio.h> 66c5604d0aSTim J. Robbins #include <stdlib.h> 67c5604d0aSTim J. Robbins #include <string.h> 68c5604d0aSTim J. Robbins #include <wchar.h> 69c5604d0aSTim J. Robbins #include <wctype.h> 70c5604d0aSTim J. Robbins #include "un-namespace.h" 71c5604d0aSTim J. Robbins 72c5604d0aSTim J. Robbins #include "libc_private.h" 73c5604d0aSTim J. Robbins #include "local.h" 74c5604d0aSTim J. Robbins #include "fvwrite.h" 752591efccSDavid Schultz #include "printflocal.h" 763c87aa1dSDavid Chisnall #include "xlocale_private.h" 77e5abb5e6SDavid Schultz 783c87aa1dSDavid Chisnall static int __sprint(FILE *, struct __suio *, locale_t); 793c87aa1dSDavid Chisnall static int __sbprintf(FILE *, locale_t, const wchar_t *, va_list) __noinline; 803c87aa1dSDavid Chisnall static wint_t __xfputwc(wchar_t, FILE *, locale_t); 81c5604d0aSTim J. Robbins static wchar_t *__mbsconv(char *, int); 82c5604d0aSTim J. Robbins 83814d1bc9SDavid Schultz #define CHAR wchar_t 84814d1bc9SDavid Schultz #include "printfcommon.h" 85814d1bc9SDavid Schultz 8621ca178eSDavid Schultz struct grouping_state { 8721ca178eSDavid Schultz wchar_t thousands_sep; /* locale-specific thousands separator */ 8821ca178eSDavid Schultz const char *grouping; /* locale-specific numeric grouping rules */ 8921ca178eSDavid Schultz int lead; /* sig figs before decimal or group sep */ 9021ca178eSDavid Schultz int nseps; /* number of group separators with ' */ 9121ca178eSDavid Schultz int nrepeats; /* number of repeats of the last group */ 9221ca178eSDavid Schultz }; 9321ca178eSDavid Schultz 945004a238SDavid Schultz static const mbstate_t initial_mbs; 955004a238SDavid Schultz 965004a238SDavid Schultz static inline wchar_t 973c87aa1dSDavid Chisnall get_decpt(locale_t locale) 985004a238SDavid Schultz { 995004a238SDavid Schultz mbstate_t mbs; 1005004a238SDavid Schultz wchar_t decpt; 1015004a238SDavid Schultz int nconv; 1025004a238SDavid Schultz 1035004a238SDavid Schultz mbs = initial_mbs; 1043c87aa1dSDavid Chisnall nconv = mbrtowc(&decpt, localeconv_l(locale)->decimal_point, MB_CUR_MAX, &mbs); 1055004a238SDavid Schultz if (nconv == (size_t)-1 || nconv == (size_t)-2) 1065004a238SDavid Schultz decpt = '.'; /* failsafe */ 1075004a238SDavid Schultz return (decpt); 1085004a238SDavid Schultz } 1095004a238SDavid Schultz 11021ca178eSDavid Schultz static inline wchar_t 1113c87aa1dSDavid Chisnall get_thousep(locale_t locale) 11221ca178eSDavid Schultz { 11321ca178eSDavid Schultz mbstate_t mbs; 11421ca178eSDavid Schultz wchar_t thousep; 11521ca178eSDavid Schultz int nconv; 11621ca178eSDavid Schultz 11721ca178eSDavid Schultz mbs = initial_mbs; 1183c87aa1dSDavid Chisnall nconv = mbrtowc(&thousep, localeconv_l(locale)->thousands_sep, 11921ca178eSDavid Schultz MB_CUR_MAX, &mbs); 12021ca178eSDavid Schultz if (nconv == (size_t)-1 || nconv == (size_t)-2) 12121ca178eSDavid Schultz thousep = '\0'; /* failsafe */ 12221ca178eSDavid Schultz return (thousep); 12321ca178eSDavid Schultz } 12421ca178eSDavid Schultz 12521ca178eSDavid Schultz /* 12621ca178eSDavid Schultz * Initialize the thousands' grouping state in preparation to print a 12721ca178eSDavid Schultz * number with ndigits digits. This routine returns the total number 12821ca178eSDavid Schultz * of wide characters that will be printed. 12921ca178eSDavid Schultz */ 13021ca178eSDavid Schultz static int 1313c87aa1dSDavid Chisnall grouping_init(struct grouping_state *gs, int ndigits, locale_t locale) 13221ca178eSDavid Schultz { 13321ca178eSDavid Schultz 1343c87aa1dSDavid Chisnall gs->grouping = localeconv_l(locale)->grouping; 1353c87aa1dSDavid Chisnall gs->thousands_sep = get_thousep(locale); 13621ca178eSDavid Schultz 13721ca178eSDavid Schultz gs->nseps = gs->nrepeats = 0; 13821ca178eSDavid Schultz gs->lead = ndigits; 13921ca178eSDavid Schultz while (*gs->grouping != CHAR_MAX) { 14021ca178eSDavid Schultz if (gs->lead <= *gs->grouping) 14121ca178eSDavid Schultz break; 14221ca178eSDavid Schultz gs->lead -= *gs->grouping; 14321ca178eSDavid Schultz if (*(gs->grouping+1)) { 14421ca178eSDavid Schultz gs->nseps++; 14521ca178eSDavid Schultz gs->grouping++; 14621ca178eSDavid Schultz } else 14721ca178eSDavid Schultz gs->nrepeats++; 14821ca178eSDavid Schultz } 14921ca178eSDavid Schultz return (gs->nseps + gs->nrepeats); 15021ca178eSDavid Schultz } 15121ca178eSDavid Schultz 15221ca178eSDavid Schultz /* 15321ca178eSDavid Schultz * Print a number with thousands' separators. 15421ca178eSDavid Schultz */ 15521ca178eSDavid Schultz static int 15621ca178eSDavid Schultz grouping_print(struct grouping_state *gs, struct io_state *iop, 1573c87aa1dSDavid Chisnall const CHAR *cp, const CHAR *ep, locale_t locale) 15821ca178eSDavid Schultz { 15921ca178eSDavid Schultz const CHAR *cp0 = cp; 16021ca178eSDavid Schultz 1613c87aa1dSDavid Chisnall if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale)) 16221ca178eSDavid Schultz return (-1); 16321ca178eSDavid Schultz cp += gs->lead; 16421ca178eSDavid Schultz while (gs->nseps > 0 || gs->nrepeats > 0) { 16521ca178eSDavid Schultz if (gs->nrepeats > 0) 16621ca178eSDavid Schultz gs->nrepeats--; 16721ca178eSDavid Schultz else { 16821ca178eSDavid Schultz gs->grouping--; 16921ca178eSDavid Schultz gs->nseps--; 17021ca178eSDavid Schultz } 1713c87aa1dSDavid Chisnall if (io_print(iop, &gs->thousands_sep, 1, locale)) 17221ca178eSDavid Schultz return (-1); 1733c87aa1dSDavid Chisnall if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale)) 17421ca178eSDavid Schultz return (-1); 17521ca178eSDavid Schultz cp += *gs->grouping; 17621ca178eSDavid Schultz } 17721ca178eSDavid Schultz if (cp > ep) 17821ca178eSDavid Schultz cp = ep; 17921ca178eSDavid Schultz return (cp - cp0); 18021ca178eSDavid Schultz } 18121ca178eSDavid Schultz 18221ca178eSDavid Schultz 183814d1bc9SDavid Schultz /* 184814d1bc9SDavid Schultz * Flush out all the vectors defined by the given uio, 185814d1bc9SDavid Schultz * then reset it so that it can be reused. 186814d1bc9SDavid Schultz * 187814d1bc9SDavid Schultz * XXX The fact that we do this a character at a time and convert to a 188814d1bc9SDavid Schultz * multibyte character sequence even if the destination is a wide 189814d1bc9SDavid Schultz * string eclipses the benefits of buffering. 190814d1bc9SDavid Schultz */ 191814d1bc9SDavid Schultz static int 1923c87aa1dSDavid Chisnall __sprint(FILE *fp, struct __suio *uio, locale_t locale) 193814d1bc9SDavid Schultz { 194814d1bc9SDavid Schultz struct __siov *iov; 195814d1bc9SDavid Schultz wchar_t *p; 196814d1bc9SDavid Schultz int i, len; 197814d1bc9SDavid Schultz 198814d1bc9SDavid Schultz iov = uio->uio_iov; 199814d1bc9SDavid Schultz for (; uio->uio_resid != 0; uio->uio_resid -= len, iov++) { 200814d1bc9SDavid Schultz p = (wchar_t *)iov->iov_base; 201814d1bc9SDavid Schultz len = iov->iov_len; 202814d1bc9SDavid Schultz for (i = 0; i < len; i++) { 2033c87aa1dSDavid Chisnall if (__xfputwc(p[i], fp, locale) == WEOF) 204814d1bc9SDavid Schultz return (-1); 205814d1bc9SDavid Schultz } 206814d1bc9SDavid Schultz } 207814d1bc9SDavid Schultz uio->uio_iovcnt = 0; 208814d1bc9SDavid Schultz return (0); 209814d1bc9SDavid Schultz } 210814d1bc9SDavid Schultz 211c5604d0aSTim J. Robbins /* 212c5604d0aSTim J. Robbins * Helper function for `fprintf to unbuffered unix file': creates a 213c5604d0aSTim J. Robbins * temporary buffer. We only work on write-only files; this avoids 214c5604d0aSTim J. Robbins * worries about ungetc buffers and so forth. 215c5604d0aSTim J. Robbins */ 216c5604d0aSTim J. Robbins static int 2173c87aa1dSDavid Chisnall __sbprintf(FILE *fp, locale_t locale, const wchar_t *fmt, va_list ap) 218c5604d0aSTim J. Robbins { 219c5604d0aSTim J. Robbins int ret; 220c5604d0aSTim J. Robbins FILE fake; 221c5604d0aSTim J. Robbins unsigned char buf[BUFSIZ]; 222c5604d0aSTim J. Robbins 223a1805f7bSDavid Schultz /* XXX This is probably not needed. */ 224a1805f7bSDavid Schultz if (prepwrite(fp) != 0) 225a1805f7bSDavid Schultz return (EOF); 226a1805f7bSDavid Schultz 227c5604d0aSTim J. Robbins /* copy the important variables */ 228c5604d0aSTim J. Robbins fake._flags = fp->_flags & ~__SNBF; 229c5604d0aSTim J. Robbins fake._file = fp->_file; 230c5604d0aSTim J. Robbins fake._cookie = fp->_cookie; 231c5604d0aSTim J. Robbins fake._write = fp->_write; 2321e98f887SJohn Baldwin fake._orientation = fp->_orientation; 2331e98f887SJohn Baldwin fake._mbstate = fp->_mbstate; 234c5604d0aSTim J. Robbins 235c5604d0aSTim J. Robbins /* set up the buffer */ 236c5604d0aSTim J. Robbins fake._bf._base = fake._p = buf; 237c5604d0aSTim J. Robbins fake._bf._size = fake._w = sizeof(buf); 238c5604d0aSTim J. Robbins fake._lbfsize = 0; /* not actually used, but Just In Case */ 239c5604d0aSTim J. Robbins 240c5604d0aSTim J. Robbins /* do the work, then copy any error status */ 2413c87aa1dSDavid Chisnall ret = __vfwprintf(&fake, locale, fmt, ap); 242c5604d0aSTim J. Robbins if (ret >= 0 && __fflush(&fake)) 243c5604d0aSTim J. Robbins ret = WEOF; 244c5604d0aSTim J. Robbins if (fake._flags & __SERR) 245c5604d0aSTim J. Robbins fp->_flags |= __SERR; 246c5604d0aSTim J. Robbins return (ret); 247c5604d0aSTim J. Robbins } 248c5604d0aSTim J. Robbins 249c5604d0aSTim J. Robbins /* 250909a17f4STim J. Robbins * Like __fputwc, but handles fake string (__SSTR) files properly. 251909a17f4STim J. Robbins * File must already be locked. 252909a17f4STim J. Robbins */ 253909a17f4STim J. Robbins static wint_t 2543c87aa1dSDavid Chisnall __xfputwc(wchar_t wc, FILE *fp, locale_t locale) 255909a17f4STim J. Robbins { 25693996f6dSTim J. Robbins mbstate_t mbs; 257909a17f4STim J. Robbins char buf[MB_LEN_MAX]; 258909a17f4STim J. Robbins struct __suio uio; 259909a17f4STim J. Robbins struct __siov iov; 26084d9142fSJacques Vidrine size_t len; 261909a17f4STim J. Robbins 262909a17f4STim J. Robbins if ((fp->_flags & __SSTR) == 0) 2633c87aa1dSDavid Chisnall return (__fputwc(wc, fp, locale)); 264909a17f4STim J. Robbins 2655004a238SDavid Schultz mbs = initial_mbs; 26693996f6dSTim J. Robbins if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) { 267909a17f4STim J. Robbins fp->_flags |= __SERR; 268909a17f4STim J. Robbins return (WEOF); 269909a17f4STim J. Robbins } 270909a17f4STim J. Robbins uio.uio_iov = &iov; 271909a17f4STim J. Robbins uio.uio_resid = len; 272909a17f4STim J. Robbins uio.uio_iovcnt = 1; 273909a17f4STim J. Robbins iov.iov_base = buf; 274909a17f4STim J. Robbins iov.iov_len = len; 275909a17f4STim J. Robbins return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF); 276909a17f4STim J. Robbins } 277909a17f4STim J. Robbins 278909a17f4STim J. Robbins /* 279c5604d0aSTim J. Robbins * Convert a multibyte character string argument for the %s format to a wide 280c5604d0aSTim J. Robbins * string representation. ``prec'' specifies the maximum number of bytes 281c5604d0aSTim J. Robbins * to output. If ``prec'' is greater than or equal to zero, we can't assume 282c5604d0aSTim J. Robbins * that the multibyte char. string ends in a null character. 283c5604d0aSTim J. Robbins */ 284c5604d0aSTim J. Robbins static wchar_t * 285c5604d0aSTim J. Robbins __mbsconv(char *mbsarg, int prec) 286c5604d0aSTim J. Robbins { 28793996f6dSTim J. Robbins mbstate_t mbs; 288c5604d0aSTim J. Robbins wchar_t *convbuf, *wcp; 289c5604d0aSTim J. Robbins const char *p; 290c5604d0aSTim J. Robbins size_t insize, nchars, nconv; 291c5604d0aSTim J. Robbins 292adfd6b31STim J. Robbins if (mbsarg == NULL) 293adfd6b31STim J. Robbins return (NULL); 294adfd6b31STim J. Robbins 295c5604d0aSTim J. Robbins /* 296c5604d0aSTim J. Robbins * Supplied argument is a multibyte string; convert it to wide 297c5604d0aSTim J. Robbins * characters first. 298c5604d0aSTim J. Robbins */ 299c5604d0aSTim J. Robbins if (prec >= 0) { 300c5604d0aSTim J. Robbins /* 301c5604d0aSTim J. Robbins * String is not guaranteed to be NUL-terminated. Find the 302c5604d0aSTim J. Robbins * number of characters to print. 303c5604d0aSTim J. Robbins */ 304c5604d0aSTim J. Robbins p = mbsarg; 305ab5b2fafSGarrett Wollman insize = nchars = nconv = 0; 3065004a238SDavid Schultz mbs = initial_mbs; 307c5604d0aSTim J. Robbins while (nchars != (size_t)prec) { 30893996f6dSTim J. Robbins nconv = mbrlen(p, MB_CUR_MAX, &mbs); 309c5604d0aSTim J. Robbins if (nconv == 0 || nconv == (size_t)-1 || 310c5604d0aSTim J. Robbins nconv == (size_t)-2) 311c5604d0aSTim J. Robbins break; 312c5604d0aSTim J. Robbins p += nconv; 313c5604d0aSTim J. Robbins nchars++; 314c5604d0aSTim J. Robbins insize += nconv; 315c5604d0aSTim J. Robbins } 316c5604d0aSTim J. Robbins if (nconv == (size_t)-1 || nconv == (size_t)-2) 317c5604d0aSTim J. Robbins return (NULL); 31822d725b5SColin Percival } else { 319c5604d0aSTim J. Robbins insize = strlen(mbsarg); 32022d725b5SColin Percival nconv = 0; 32122d725b5SColin Percival } 322c5604d0aSTim J. Robbins 323c5604d0aSTim J. Robbins /* 324c5604d0aSTim J. Robbins * Allocate buffer for the result and perform the conversion, 325c5604d0aSTim J. Robbins * converting at most `size' bytes of the input multibyte string to 326c5604d0aSTim J. Robbins * wide characters for printing. 327c5604d0aSTim J. Robbins */ 328c5604d0aSTim J. Robbins convbuf = malloc((insize + 1) * sizeof(*convbuf)); 329c5604d0aSTim J. Robbins if (convbuf == NULL) 330c5604d0aSTim J. Robbins return (NULL); 331c5604d0aSTim J. Robbins wcp = convbuf; 332c5604d0aSTim J. Robbins p = mbsarg; 3335004a238SDavid Schultz mbs = initial_mbs; 334c5604d0aSTim J. Robbins while (insize != 0) { 33593996f6dSTim J. Robbins nconv = mbrtowc(wcp, p, insize, &mbs); 336c5604d0aSTim J. Robbins if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) 337c5604d0aSTim J. Robbins break; 338c5604d0aSTim J. Robbins wcp++; 339c5604d0aSTim J. Robbins p += nconv; 340c5604d0aSTim J. Robbins insize -= nconv; 341c5604d0aSTim J. Robbins } 342c5604d0aSTim J. Robbins if (nconv == (size_t)-1 || nconv == (size_t)-2) { 343c5604d0aSTim J. Robbins free(convbuf); 344c5604d0aSTim J. Robbins return (NULL); 345c5604d0aSTim J. Robbins } 346c5604d0aSTim J. Robbins *wcp = L'\0'; 347c5604d0aSTim J. Robbins 348c5604d0aSTim J. Robbins return (convbuf); 349c5604d0aSTim J. Robbins } 350c5604d0aSTim J. Robbins 351c5604d0aSTim J. Robbins /* 352c5604d0aSTim J. Robbins * MT-safe version 353c5604d0aSTim J. Robbins */ 354c5604d0aSTim J. Robbins int 3553c87aa1dSDavid Chisnall vfwprintf_l(FILE * __restrict fp, locale_t locale, 3563c87aa1dSDavid Chisnall const wchar_t * __restrict fmt0, va_list ap) 357c5604d0aSTim J. Robbins 358c5604d0aSTim J. Robbins { 359c5604d0aSTim J. Robbins int ret; 3603c87aa1dSDavid Chisnall FIX_LOCALE(locale); 361fda0a14fSKonstantin Belousov FLOCKFILE_CANCELSAFE(fp); 362a1805f7bSDavid Schultz /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 363a1805f7bSDavid Schultz if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 364a1805f7bSDavid Schultz fp->_file >= 0) 3653c87aa1dSDavid Chisnall ret = __sbprintf(fp, locale, fmt0, ap); 366a1805f7bSDavid Schultz else 3673c87aa1dSDavid Chisnall ret = __vfwprintf(fp, locale, fmt0, ap); 368fda0a14fSKonstantin Belousov FUNLOCKFILE_CANCELSAFE(); 369c5604d0aSTim J. Robbins return (ret); 370c5604d0aSTim J. Robbins } 3713c87aa1dSDavid Chisnall int 3723c87aa1dSDavid Chisnall vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap) 3733c87aa1dSDavid Chisnall { 3743c87aa1dSDavid Chisnall return vfwprintf_l(fp, __get_locale(), fmt0, ap); 3753c87aa1dSDavid Chisnall } 376c5604d0aSTim J. Robbins 37738cac8f8SDavid Schultz /* 37838cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer 37921ca178eSDavid Schultz * conversions, among other things. We need enough space to 38021ca178eSDavid Schultz * write a uintmax_t in octal (plus one byte). 38138cac8f8SDavid Schultz */ 38221ca178eSDavid Schultz #if UINTMAX_MAX <= UINT64_MAX 38321ca178eSDavid Schultz #define BUF 32 38421ca178eSDavid Schultz #else 38521ca178eSDavid Schultz #error "BUF must be large enough to format a uintmax_t" 38621ca178eSDavid Schultz #endif 38738cac8f8SDavid Schultz 388c5604d0aSTim J. Robbins /* 389c5604d0aSTim J. Robbins * Non-MT-safe version 390c5604d0aSTim J. Robbins */ 391c5604d0aSTim J. Robbins int 3923c87aa1dSDavid Chisnall __vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap) 393c5604d0aSTim J. Robbins { 394c5604d0aSTim J. Robbins wchar_t *fmt; /* format string */ 395c5604d0aSTim J. Robbins wchar_t ch; /* character from fmt */ 396814d1bc9SDavid Schultz int n, n2; /* handy integer (short term usage) */ 397c5604d0aSTim J. Robbins wchar_t *cp; /* handy char pointer (short term usage) */ 398c5604d0aSTim J. Robbins int flags; /* flags as above */ 399c5604d0aSTim J. Robbins int ret; /* return value accumulator */ 400c5604d0aSTim J. Robbins int width; /* width from format (%8d), or 0 */ 401adfd6b31STim J. Robbins int prec; /* precision from format; <0 for N/A */ 402c5604d0aSTim J. Robbins wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */ 40321ca178eSDavid Schultz struct grouping_state gs; /* thousands' grouping info */ 404ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 405adfd6b31STim J. Robbins /* 406adfd6b31STim J. Robbins * We can decompose the printed representation of floating 407adfd6b31STim J. Robbins * point numbers into several parts, some of which may be empty: 408adfd6b31STim J. Robbins * 409adfd6b31STim J. Robbins * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 410adfd6b31STim J. Robbins * A B ---C--- D E F 411adfd6b31STim J. Robbins * 412adfd6b31STim J. Robbins * A: 'sign' holds this value if present; '\0' otherwise 413adfd6b31STim J. Robbins * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 414adfd6b31STim J. Robbins * C: cp points to the string MMMNNN. Leading and trailing 415adfd6b31STim J. Robbins * zeros are not in the string and must be added. 416adfd6b31STim J. Robbins * D: expchar holds this character; '\0' if no exponent, e.g. %f 417adfd6b31STim J. Robbins * F: at least two digits for decimal, at least one digit for hex 418adfd6b31STim J. Robbins */ 4195004a238SDavid Schultz wchar_t decimal_point; /* locale specific decimal point */ 420adfd6b31STim J. Robbins int signflag; /* true if float is negative */ 421adfd6b31STim J. Robbins union { /* floating point arguments %[aAeEfFgG] */ 422adfd6b31STim J. Robbins double dbl; 423adfd6b31STim J. Robbins long double ldbl; 424adfd6b31STim J. Robbins } fparg; 425c5604d0aSTim J. Robbins int expt; /* integer value of exponent */ 426adfd6b31STim J. Robbins char expchar; /* exponent character: [eEpP\0] */ 427adfd6b31STim J. Robbins char *dtoaend; /* pointer to end of converted digits */ 428c5604d0aSTim J. Robbins int expsize; /* character count for expstr */ 429adfd6b31STim J. Robbins int ndig; /* actual number of digits returned by dtoa */ 430adfd6b31STim J. Robbins wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 431adfd6b31STim J. Robbins char *dtoaresult; /* buffer allocated by dtoa */ 432c5604d0aSTim J. Robbins #endif 433c5604d0aSTim J. Robbins u_long ulval; /* integer arguments %[diouxX] */ 434c5604d0aSTim J. Robbins uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 435c5604d0aSTim J. Robbins int base; /* base for [diouxX] conversion */ 436c5604d0aSTim J. Robbins int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 437c5604d0aSTim J. Robbins int realsz; /* field size expanded by dprec, sign, etc */ 438c5604d0aSTim J. Robbins int size; /* size of converted field or string */ 439c5604d0aSTim J. Robbins int prsize; /* max size of printed field */ 4407b7e3509SDavid Schultz const char *xdigs; /* digits for [xX] conversion */ 441814d1bc9SDavid Schultz struct io_state io; /* I/O buffering state */ 44238cac8f8SDavid Schultz wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */ 443c5604d0aSTim J. Robbins wchar_t ox[2]; /* space for 0x hex-prefix */ 444c5604d0aSTim J. Robbins union arg *argtable; /* args, built due to positional arg */ 445c5604d0aSTim J. Robbins union arg statargtable [STATIC_ARG_TBL_SIZE]; 446c5604d0aSTim J. Robbins int nextarg; /* 1-based argument index */ 447c5604d0aSTim J. Robbins va_list orgap; /* original argument pointer */ 448c5604d0aSTim J. Robbins wchar_t *convbuf; /* multibyte to wide conversion result */ 4491bf6c5f1SAndrey A. Chernov int savserr; 450c5604d0aSTim J. Robbins 4517b7e3509SDavid Schultz static const char xdigs_lower[16] = "0123456789abcdef"; 4527b7e3509SDavid Schultz static const char xdigs_upper[16] = "0123456789ABCDEF"; 453adfd6b31STim J. Robbins 454814d1bc9SDavid Schultz /* BEWARE, these `goto error' on error. */ 455c5604d0aSTim J. Robbins #define PRINT(ptr, len) do { \ 4563c87aa1dSDavid Chisnall if (io_print(&io, (ptr), (len), locale)) \ 457814d1bc9SDavid Schultz goto error; \ 458c5604d0aSTim J. Robbins } while (0) 459814d1bc9SDavid Schultz #define PAD(howmany, with) { \ 4603c87aa1dSDavid Chisnall if (io_pad(&io, (howmany), (with), locale)) \ 461814d1bc9SDavid Schultz goto error; \ 462814d1bc9SDavid Schultz } 463814d1bc9SDavid Schultz #define PRINTANDPAD(p, ep, len, with) { \ 4643c87aa1dSDavid Chisnall if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \ 465814d1bc9SDavid Schultz goto error; \ 466814d1bc9SDavid Schultz } 467814d1bc9SDavid Schultz #define FLUSH() { \ 4683c87aa1dSDavid Chisnall if (io_flush(&io, locale)) \ 469814d1bc9SDavid Schultz goto error; \ 470814d1bc9SDavid Schultz } 471c5604d0aSTim J. Robbins 472c5604d0aSTim J. Robbins /* 473c5604d0aSTim J. Robbins * Get the argument indexed by nextarg. If the argument table is 474c5604d0aSTim J. Robbins * built, use it to get the argument. If its not, get the next 475c5604d0aSTim J. Robbins * argument (and arguments must be gotten sequentially). 476c5604d0aSTim J. Robbins */ 477c5604d0aSTim J. Robbins #define GETARG(type) \ 478c5604d0aSTim J. Robbins ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 479c5604d0aSTim J. Robbins (nextarg++, va_arg(ap, type))) 480c5604d0aSTim J. Robbins 481c5604d0aSTim J. Robbins /* 482c5604d0aSTim J. Robbins * To extend shorts properly, we need both signed and unsigned 483c5604d0aSTim J. Robbins * argument extraction methods. 484c5604d0aSTim J. Robbins */ 485c5604d0aSTim J. Robbins #define SARG() \ 486c5604d0aSTim J. Robbins (flags&LONGINT ? GETARG(long) : \ 487c5604d0aSTim J. Robbins flags&SHORTINT ? (long)(short)GETARG(int) : \ 488c5604d0aSTim J. Robbins flags&CHARINT ? (long)(signed char)GETARG(int) : \ 489c5604d0aSTim J. Robbins (long)GETARG(int)) 490c5604d0aSTim J. Robbins #define UARG() \ 491c5604d0aSTim J. Robbins (flags&LONGINT ? GETARG(u_long) : \ 492c5604d0aSTim J. Robbins flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 493c5604d0aSTim J. Robbins flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 494c5604d0aSTim J. Robbins (u_long)GETARG(u_int)) 495c5604d0aSTim J. Robbins #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 496c5604d0aSTim J. Robbins #define SJARG() \ 497c5604d0aSTim J. Robbins (flags&INTMAXT ? GETARG(intmax_t) : \ 4980881683bSDavid Schultz flags&SIZET ? (intmax_t)GETARG(ssize_t) : \ 499c5604d0aSTim J. Robbins flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 500c5604d0aSTim J. Robbins (intmax_t)GETARG(long long)) 501c5604d0aSTim J. Robbins #define UJARG() \ 502c5604d0aSTim J. Robbins (flags&INTMAXT ? GETARG(uintmax_t) : \ 503c5604d0aSTim J. Robbins flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 504c5604d0aSTim J. Robbins flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 505c5604d0aSTim J. Robbins (uintmax_t)GETARG(unsigned long long)) 506c5604d0aSTim J. Robbins 507c5604d0aSTim J. Robbins /* 508c5604d0aSTim J. Robbins * Get * arguments, including the form *nn$. Preserve the nextarg 509c5604d0aSTim J. Robbins * that the argument can be gotten once the type is determined. 510c5604d0aSTim J. Robbins */ 511c5604d0aSTim J. Robbins #define GETASTER(val) \ 512c5604d0aSTim J. Robbins n2 = 0; \ 513c5604d0aSTim J. Robbins cp = fmt; \ 514c5604d0aSTim J. Robbins while (is_digit(*cp)) { \ 515c5604d0aSTim J. Robbins n2 = 10 * n2 + to_digit(*cp); \ 516c5604d0aSTim J. Robbins cp++; \ 517c5604d0aSTim J. Robbins } \ 518c5604d0aSTim J. Robbins if (*cp == '$') { \ 519c5604d0aSTim J. Robbins int hold = nextarg; \ 520c5604d0aSTim J. Robbins if (argtable == NULL) { \ 521c5604d0aSTim J. Robbins argtable = statargtable; \ 522e62e5ff9SDavid Schultz if (__find_warguments (fmt0, orgap, &argtable)) { \ 523e62e5ff9SDavid Schultz ret = EOF; \ 524e62e5ff9SDavid Schultz goto error; \ 525e62e5ff9SDavid Schultz } \ 526c5604d0aSTim J. Robbins } \ 527c5604d0aSTim J. Robbins nextarg = n2; \ 528c5604d0aSTim J. Robbins val = GETARG (int); \ 529c5604d0aSTim J. Robbins nextarg = hold; \ 530c5604d0aSTim J. Robbins fmt = ++cp; \ 531c5604d0aSTim J. Robbins } else { \ 532c5604d0aSTim J. Robbins val = GETARG (int); \ 533c5604d0aSTim J. Robbins } 534c5604d0aSTim J. Robbins 535c5604d0aSTim J. Robbins 536c5604d0aSTim J. Robbins /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */ 537450ead86SPedro F. Giffuni if (prepwrite(fp) != 0) { 538450ead86SPedro F. Giffuni errno = EBADF; 539c5604d0aSTim J. Robbins return (EOF); 540450ead86SPedro F. Giffuni } 541c5604d0aSTim J. Robbins 5421bf6c5f1SAndrey A. Chernov savserr = fp->_flags & __SERR; 5431bf6c5f1SAndrey A. Chernov fp->_flags &= ~__SERR; 5441bf6c5f1SAndrey A. Chernov 545e18701f4SDavid Schultz convbuf = NULL; 546c5604d0aSTim J. Robbins fmt = (wchar_t *)fmt0; 547c5604d0aSTim J. Robbins argtable = NULL; 548c5604d0aSTim J. Robbins nextarg = 1; 549d07090a8STim J. Robbins va_copy(orgap, ap); 550814d1bc9SDavid Schultz io_init(&io, fp); 551c5604d0aSTim J. Robbins ret = 0; 552e18701f4SDavid Schultz #ifndef NO_FLOATING_POINT 5533c87aa1dSDavid Chisnall decimal_point = get_decpt(locale); 554e18701f4SDavid Schultz #endif 555c5604d0aSTim J. Robbins 556c5604d0aSTim J. Robbins /* 557c5604d0aSTim J. Robbins * Scan the format for conversions (`%' character). 558c5604d0aSTim J. Robbins */ 559c5604d0aSTim J. Robbins for (;;) { 560c5604d0aSTim J. Robbins for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 561c5604d0aSTim J. Robbins /* void */; 562c5604d0aSTim J. Robbins if ((n = fmt - cp) != 0) { 563c5604d0aSTim J. Robbins if ((unsigned)ret + n > INT_MAX) { 564c5604d0aSTim J. Robbins ret = EOF; 565666d00d3SDavid Schultz errno = EOVERFLOW; 566c5604d0aSTim J. Robbins goto error; 567c5604d0aSTim J. Robbins } 568c5604d0aSTim J. Robbins PRINT(cp, n); 569c5604d0aSTim J. Robbins ret += n; 570c5604d0aSTim J. Robbins } 571c5604d0aSTim J. Robbins if (ch == '\0') 572c5604d0aSTim J. Robbins goto done; 573c5604d0aSTim J. Robbins fmt++; /* skip over '%' */ 574c5604d0aSTim J. Robbins 575c5604d0aSTim J. Robbins flags = 0; 576c5604d0aSTim J. Robbins dprec = 0; 577c5604d0aSTim J. Robbins width = 0; 578c5604d0aSTim J. Robbins prec = -1; 57921ca178eSDavid Schultz gs.grouping = NULL; 580c5604d0aSTim J. Robbins sign = '\0'; 581adfd6b31STim J. Robbins ox[1] = '\0'; 582c5604d0aSTim J. Robbins 583c5604d0aSTim J. Robbins rflag: ch = *fmt++; 584c5604d0aSTim J. Robbins reswitch: switch (ch) { 585c5604d0aSTim J. Robbins case ' ': 586c5604d0aSTim J. Robbins /*- 587c5604d0aSTim J. Robbins * ``If the space and + flags both appear, the space 588c5604d0aSTim J. Robbins * flag will be ignored.'' 589c5604d0aSTim J. Robbins * -- ANSI X3J11 590c5604d0aSTim J. Robbins */ 591c5604d0aSTim J. Robbins if (!sign) 592c5604d0aSTim J. Robbins sign = ' '; 593c5604d0aSTim J. Robbins goto rflag; 594c5604d0aSTim J. Robbins case '#': 595c5604d0aSTim J. Robbins flags |= ALT; 596c5604d0aSTim J. Robbins goto rflag; 597c5604d0aSTim J. Robbins case '*': 598c5604d0aSTim J. Robbins /*- 599c5604d0aSTim J. Robbins * ``A negative field width argument is taken as a 600c5604d0aSTim J. Robbins * - flag followed by a positive field width.'' 601c5604d0aSTim J. Robbins * -- ANSI X3J11 602c5604d0aSTim J. Robbins * They don't exclude field widths read from args. 603c5604d0aSTim J. Robbins */ 604c5604d0aSTim J. Robbins GETASTER (width); 605c5604d0aSTim J. Robbins if (width >= 0) 606c5604d0aSTim J. Robbins goto rflag; 607c5604d0aSTim J. Robbins width = -width; 608c5604d0aSTim J. Robbins /* FALLTHROUGH */ 609c5604d0aSTim J. Robbins case '-': 610c5604d0aSTim J. Robbins flags |= LADJUST; 611c5604d0aSTim J. Robbins goto rflag; 612c5604d0aSTim J. Robbins case '+': 613c5604d0aSTim J. Robbins sign = '+'; 614c5604d0aSTim J. Robbins goto rflag; 615c5604d0aSTim J. Robbins case '\'': 616c5604d0aSTim J. Robbins flags |= GROUPING; 617c5604d0aSTim J. Robbins goto rflag; 618c5604d0aSTim J. Robbins case '.': 619c5604d0aSTim J. Robbins if ((ch = *fmt++) == '*') { 620adfd6b31STim J. Robbins GETASTER (prec); 621c5604d0aSTim J. Robbins goto rflag; 622c5604d0aSTim J. Robbins } 623adfd6b31STim J. Robbins prec = 0; 624c5604d0aSTim J. Robbins while (is_digit(ch)) { 625adfd6b31STim J. Robbins prec = 10 * prec + to_digit(ch); 626c5604d0aSTim J. Robbins ch = *fmt++; 627c5604d0aSTim J. Robbins } 628c5604d0aSTim J. Robbins goto reswitch; 629c5604d0aSTim J. Robbins case '0': 630c5604d0aSTim J. Robbins /*- 631c5604d0aSTim J. Robbins * ``Note that 0 is taken as a flag, not as the 632c5604d0aSTim J. Robbins * beginning of a field width.'' 633c5604d0aSTim J. Robbins * -- ANSI X3J11 634c5604d0aSTim J. Robbins */ 635c5604d0aSTim J. Robbins flags |= ZEROPAD; 636c5604d0aSTim J. Robbins goto rflag; 637c5604d0aSTim J. Robbins case '1': case '2': case '3': case '4': 638c5604d0aSTim J. Robbins case '5': case '6': case '7': case '8': case '9': 639c5604d0aSTim J. Robbins n = 0; 640c5604d0aSTim J. Robbins do { 641c5604d0aSTim J. Robbins n = 10 * n + to_digit(ch); 642c5604d0aSTim J. Robbins ch = *fmt++; 643c5604d0aSTim J. Robbins } while (is_digit(ch)); 644c5604d0aSTim J. Robbins if (ch == '$') { 645c5604d0aSTim J. Robbins nextarg = n; 646c5604d0aSTim J. Robbins if (argtable == NULL) { 647c5604d0aSTim J. Robbins argtable = statargtable; 648e62e5ff9SDavid Schultz if (__find_warguments (fmt0, orgap, 649e62e5ff9SDavid Schultz &argtable)) { 650e62e5ff9SDavid Schultz ret = EOF; 651e62e5ff9SDavid Schultz goto error; 652e62e5ff9SDavid Schultz } 653c5604d0aSTim J. Robbins } 654c5604d0aSTim J. Robbins goto rflag; 655c5604d0aSTim J. Robbins } 656c5604d0aSTim J. Robbins width = n; 657c5604d0aSTim J. Robbins goto reswitch; 658ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 659c5604d0aSTim J. Robbins case 'L': 660c5604d0aSTim J. Robbins flags |= LONGDBL; 661c5604d0aSTim J. Robbins goto rflag; 662c5604d0aSTim J. Robbins #endif 663c5604d0aSTim J. Robbins case 'h': 664c5604d0aSTim J. Robbins if (flags & SHORTINT) { 665c5604d0aSTim J. Robbins flags &= ~SHORTINT; 666c5604d0aSTim J. Robbins flags |= CHARINT; 667c5604d0aSTim J. Robbins } else 668c5604d0aSTim J. Robbins flags |= SHORTINT; 669c5604d0aSTim J. Robbins goto rflag; 670c5604d0aSTim J. Robbins case 'j': 671c5604d0aSTim J. Robbins flags |= INTMAXT; 672c5604d0aSTim J. Robbins goto rflag; 673c5604d0aSTim J. Robbins case 'l': 674c5604d0aSTim J. Robbins if (flags & LONGINT) { 675c5604d0aSTim J. Robbins flags &= ~LONGINT; 676c5604d0aSTim J. Robbins flags |= LLONGINT; 677c5604d0aSTim J. Robbins } else 678c5604d0aSTim J. Robbins flags |= LONGINT; 679c5604d0aSTim J. Robbins goto rflag; 680c5604d0aSTim J. Robbins case 'q': 681c5604d0aSTim J. Robbins flags |= LLONGINT; /* not necessarily */ 682c5604d0aSTim J. Robbins goto rflag; 683c5604d0aSTim J. Robbins case 't': 684c5604d0aSTim J. Robbins flags |= PTRDIFFT; 685c5604d0aSTim J. Robbins goto rflag; 686c5604d0aSTim J. Robbins case 'z': 687c5604d0aSTim J. Robbins flags |= SIZET; 688c5604d0aSTim J. Robbins goto rflag; 689927ecbf3STim J. Robbins case 'C': 690927ecbf3STim J. Robbins flags |= LONGINT; 691927ecbf3STim J. Robbins /*FALLTHROUGH*/ 692c5604d0aSTim J. Robbins case 'c': 693c5604d0aSTim J. Robbins if (flags & LONGINT) 694c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)GETARG(wint_t); 695c5604d0aSTim J. Robbins else 696c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)btowc(GETARG(int)); 697c5604d0aSTim J. Robbins size = 1; 698c5604d0aSTim J. Robbins sign = '\0'; 699c5604d0aSTim J. Robbins break; 700c5604d0aSTim J. Robbins case 'D': 701c5604d0aSTim J. Robbins flags |= LONGINT; 702c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 703c5604d0aSTim J. Robbins case 'd': 704c5604d0aSTim J. Robbins case 'i': 705c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 706c5604d0aSTim J. Robbins ujval = SJARG(); 707c5604d0aSTim J. Robbins if ((intmax_t)ujval < 0) { 708c5604d0aSTim J. Robbins ujval = -ujval; 709c5604d0aSTim J. Robbins sign = '-'; 710c5604d0aSTim J. Robbins } 711c5604d0aSTim J. Robbins } else { 712c5604d0aSTim J. Robbins ulval = SARG(); 713c5604d0aSTim J. Robbins if ((long)ulval < 0) { 714c5604d0aSTim J. Robbins ulval = -ulval; 715c5604d0aSTim J. Robbins sign = '-'; 716c5604d0aSTim J. Robbins } 717c5604d0aSTim J. Robbins } 718c5604d0aSTim J. Robbins base = 10; 719c5604d0aSTim J. Robbins goto number; 720ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 721c5604d0aSTim J. Robbins case 'a': 722c5604d0aSTim J. Robbins case 'A': 723adfd6b31STim J. Robbins if (ch == 'a') { 724adfd6b31STim J. Robbins ox[1] = 'x'; 725adfd6b31STim J. Robbins xdigs = xdigs_lower; 726adfd6b31STim J. Robbins expchar = 'p'; 727adfd6b31STim J. Robbins } else { 728adfd6b31STim J. Robbins ox[1] = 'X'; 729adfd6b31STim J. Robbins xdigs = xdigs_upper; 730adfd6b31STim J. Robbins expchar = 'P'; 731adfd6b31STim J. Robbins } 7327b7e3509SDavid Schultz if (prec >= 0) 7337b7e3509SDavid Schultz prec++; 734adfd6b31STim J. Robbins if (flags & LONGDBL) { 7357b7e3509SDavid Schultz fparg.ldbl = GETARG(long double); 736adfd6b31STim J. Robbins dtoaresult = 737adfd6b31STim J. Robbins __hldtoa(fparg.ldbl, xdigs, prec, 738adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 739adfd6b31STim J. Robbins } else { 740adfd6b31STim J. Robbins fparg.dbl = GETARG(double); 741adfd6b31STim J. Robbins dtoaresult = 742adfd6b31STim J. Robbins __hdtoa(fparg.dbl, xdigs, prec, 743adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 744adfd6b31STim J. Robbins } 7457b7e3509SDavid Schultz if (prec < 0) 7467b7e3509SDavid Schultz prec = dtoaend - dtoaresult; 7477b7e3509SDavid Schultz if (expt == INT_MAX) 7487b7e3509SDavid Schultz ox[1] = '\0'; 749adfd6b31STim J. Robbins if (convbuf != NULL) 750adfd6b31STim J. Robbins free(convbuf); 7517b7e3509SDavid Schultz ndig = dtoaend - dtoaresult; 752adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 753adfd6b31STim J. Robbins freedtoa(dtoaresult); 7547b7e3509SDavid Schultz goto fp_common; 755c5604d0aSTim J. Robbins case 'e': 756c5604d0aSTim J. Robbins case 'E': 757adfd6b31STim J. Robbins expchar = ch; 758adfd6b31STim J. Robbins if (prec < 0) /* account for digit before decpt */ 759adfd6b31STim J. Robbins prec = DEFPREC + 1; 760adfd6b31STim J. Robbins else 761adfd6b31STim J. Robbins prec++; 762adfd6b31STim J. Robbins goto fp_begin; 763c5604d0aSTim J. Robbins case 'f': 764c5604d0aSTim J. Robbins case 'F': 765adfd6b31STim J. Robbins expchar = '\0'; 766c5604d0aSTim J. Robbins goto fp_begin; 767c5604d0aSTim J. Robbins case 'g': 768c5604d0aSTim J. Robbins case 'G': 769adfd6b31STim J. Robbins expchar = ch - ('g' - 'e'); 770c5604d0aSTim J. Robbins if (prec == 0) 771c5604d0aSTim J. Robbins prec = 1; 772adfd6b31STim J. Robbins fp_begin: 773adfd6b31STim J. Robbins if (prec < 0) 774c5604d0aSTim J. Robbins prec = DEFPREC; 775adfd6b31STim J. Robbins if (convbuf != NULL) 776adfd6b31STim J. Robbins free(convbuf); 777adfd6b31STim J. Robbins if (flags & LONGDBL) { 778adfd6b31STim J. Robbins fparg.ldbl = GETARG(long double); 779adfd6b31STim J. Robbins dtoaresult = 780adfd6b31STim J. Robbins __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 781adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 782adfd6b31STim J. Robbins } else { 783adfd6b31STim J. Robbins fparg.dbl = GETARG(double); 784adfd6b31STim J. Robbins dtoaresult = 785adfd6b31STim J. Robbins dtoa(fparg.dbl, expchar ? 2 : 3, prec, 786adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 787adfd6b31STim J. Robbins if (expt == 9999) 788adfd6b31STim J. Robbins expt = INT_MAX; 789c5604d0aSTim J. Robbins } 790adfd6b31STim J. Robbins ndig = dtoaend - dtoaresult; 791adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 792adfd6b31STim J. Robbins freedtoa(dtoaresult); 7937b7e3509SDavid Schultz fp_common: 794adfd6b31STim J. Robbins if (signflag) 795adfd6b31STim J. Robbins sign = '-'; 796adfd6b31STim J. Robbins if (expt == INT_MAX) { /* inf or nan */ 797adfd6b31STim J. Robbins if (*cp == 'N') { 798adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"nan" : L"NAN"; 799adfd6b31STim J. Robbins sign = '\0'; 800adfd6b31STim J. Robbins } else 801adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"inf" : L"INF"; 802c5604d0aSTim J. Robbins size = 3; 8038da510f8SDavid Schultz flags &= ~ZEROPAD; 804c5604d0aSTim J. Robbins break; 805c5604d0aSTim J. Robbins } 806c5604d0aSTim J. Robbins flags |= FPT; 807c5604d0aSTim J. Robbins if (ch == 'g' || ch == 'G') { 808adfd6b31STim J. Robbins if (expt > -4 && expt <= prec) { 809adfd6b31STim J. Robbins /* Make %[gG] smell like %[fF] */ 810adfd6b31STim J. Robbins expchar = '\0'; 811adfd6b31STim J. Robbins if (flags & ALT) 812adfd6b31STim J. Robbins prec -= expt; 813c5604d0aSTim J. Robbins else 814adfd6b31STim J. Robbins prec = ndig - expt; 815adfd6b31STim J. Robbins if (prec < 0) 816adfd6b31STim J. Robbins prec = 0; 8171f2a0cdfSDavid Schultz } else { 8181f2a0cdfSDavid Schultz /* 8191f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but 8201f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag. 8211f2a0cdfSDavid Schultz */ 8221f2a0cdfSDavid Schultz if (!(flags & ALT)) 8231f2a0cdfSDavid Schultz prec = ndig; 824c5604d0aSTim J. Robbins } 825adfd6b31STim J. Robbins } 826adfd6b31STim J. Robbins if (expchar) { 827adfd6b31STim J. Robbins expsize = exponent(expstr, expt - 1, expchar); 828adfd6b31STim J. Robbins size = expsize + prec; 829adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) 830c5604d0aSTim J. Robbins ++size; 831adfd6b31STim J. Robbins } else { 832d73c448bSTim J. Robbins /* space for digits before decimal point */ 833d73c448bSTim J. Robbins if (expt > 0) 834c5604d0aSTim J. Robbins size = expt; 835d73c448bSTim J. Robbins else /* "0" */ 836d73c448bSTim J. Robbins size = 1; 837d73c448bSTim J. Robbins /* space for decimal pt and following digits */ 838c5604d0aSTim J. Robbins if (prec || flags & ALT) 839c5604d0aSTim J. Robbins size += prec + 1; 84021ca178eSDavid Schultz if ((flags & GROUPING) && expt > 0) 8413c87aa1dSDavid Chisnall size += grouping_init(&gs, expt, locale); 842adfd6b31STim J. Robbins } 843c5604d0aSTim J. Robbins break; 844ce2551adSDavid Schultz #endif /* !NO_FLOATING_POINT */ 845c5604d0aSTim J. Robbins case 'n': 846c5604d0aSTim J. Robbins /* 847c5604d0aSTim J. Robbins * Assignment-like behavior is specified if the 848c5604d0aSTim J. Robbins * value overflows or is otherwise unrepresentable. 849c5604d0aSTim J. Robbins * C99 says to use `signed char' for %hhn conversions. 850c5604d0aSTim J. Robbins */ 851c5604d0aSTim J. Robbins if (flags & LLONGINT) 852c5604d0aSTim J. Robbins *GETARG(long long *) = ret; 853c5604d0aSTim J. Robbins else if (flags & SIZET) 854c5604d0aSTim J. Robbins *GETARG(ssize_t *) = (ssize_t)ret; 855c5604d0aSTim J. Robbins else if (flags & PTRDIFFT) 856c5604d0aSTim J. Robbins *GETARG(ptrdiff_t *) = ret; 857c5604d0aSTim J. Robbins else if (flags & INTMAXT) 858c5604d0aSTim J. Robbins *GETARG(intmax_t *) = ret; 859c5604d0aSTim J. Robbins else if (flags & LONGINT) 860c5604d0aSTim J. Robbins *GETARG(long *) = ret; 861c5604d0aSTim J. Robbins else if (flags & SHORTINT) 862c5604d0aSTim J. Robbins *GETARG(short *) = ret; 863c5604d0aSTim J. Robbins else if (flags & CHARINT) 864c5604d0aSTim J. Robbins *GETARG(signed char *) = ret; 865c5604d0aSTim J. Robbins else 866c5604d0aSTim J. Robbins *GETARG(int *) = ret; 867c5604d0aSTim J. Robbins continue; /* no output */ 868c5604d0aSTim J. Robbins case 'O': 869c5604d0aSTim J. Robbins flags |= LONGINT; 870c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 871c5604d0aSTim J. Robbins case 'o': 872c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 873c5604d0aSTim J. Robbins ujval = UJARG(); 874c5604d0aSTim J. Robbins else 875c5604d0aSTim J. Robbins ulval = UARG(); 876c5604d0aSTim J. Robbins base = 8; 877c5604d0aSTim J. Robbins goto nosign; 878c5604d0aSTim J. Robbins case 'p': 879c5604d0aSTim J. Robbins /*- 880c5604d0aSTim J. Robbins * ``The argument shall be a pointer to void. The 881c5604d0aSTim J. Robbins * value of the pointer is converted to a sequence 882c5604d0aSTim J. Robbins * of printable characters, in an implementation- 883c5604d0aSTim J. Robbins * defined manner.'' 884c5604d0aSTim J. Robbins * -- ANSI X3J11 885c5604d0aSTim J. Robbins */ 886c5604d0aSTim J. Robbins ujval = (uintmax_t)(uintptr_t)GETARG(void *); 887c5604d0aSTim J. Robbins base = 16; 888adfd6b31STim J. Robbins xdigs = xdigs_lower; 889adfd6b31STim J. Robbins flags = flags | INTMAXT; 890adfd6b31STim J. Robbins ox[1] = 'x'; 891c5604d0aSTim J. Robbins goto nosign; 892927ecbf3STim J. Robbins case 'S': 893927ecbf3STim J. Robbins flags |= LONGINT; 894927ecbf3STim J. Robbins /*FALLTHROUGH*/ 895c5604d0aSTim J. Robbins case 's': 896c5604d0aSTim J. Robbins if (flags & LONGINT) { 897c5604d0aSTim J. Robbins if ((cp = GETARG(wchar_t *)) == NULL) 898c5604d0aSTim J. Robbins cp = L"(null)"; 899c5604d0aSTim J. Robbins } else { 900c5604d0aSTim J. Robbins char *mbp; 901c5604d0aSTim J. Robbins 902c5604d0aSTim J. Robbins if (convbuf != NULL) 903c5604d0aSTim J. Robbins free(convbuf); 904c5604d0aSTim J. Robbins if ((mbp = GETARG(char *)) == NULL) 905c5604d0aSTim J. Robbins cp = L"(null)"; 906c5604d0aSTim J. Robbins else { 907c5604d0aSTim J. Robbins convbuf = __mbsconv(mbp, prec); 9086180233fSTim J. Robbins if (convbuf == NULL) { 9096180233fSTim J. Robbins fp->_flags |= __SERR; 910c5604d0aSTim J. Robbins goto error; 9116180233fSTim J. Robbins } 912c5604d0aSTim J. Robbins cp = convbuf; 913c5604d0aSTim J. Robbins } 914c5604d0aSTim J. Robbins } 915353ce11cSDavid Schultz size = (prec >= 0) ? wcsnlen(cp, prec) : wcslen(cp); 916c5604d0aSTim J. Robbins sign = '\0'; 917c5604d0aSTim J. Robbins break; 918c5604d0aSTim J. Robbins case 'U': 919c5604d0aSTim J. Robbins flags |= LONGINT; 920c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 921c5604d0aSTim J. Robbins case 'u': 922c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 923c5604d0aSTim J. Robbins ujval = UJARG(); 924c5604d0aSTim J. Robbins else 925c5604d0aSTim J. Robbins ulval = UARG(); 926c5604d0aSTim J. Robbins base = 10; 927c5604d0aSTim J. Robbins goto nosign; 928c5604d0aSTim J. Robbins case 'X': 929adfd6b31STim J. Robbins xdigs = xdigs_upper; 930c5604d0aSTim J. Robbins goto hex; 931c5604d0aSTim J. Robbins case 'x': 932adfd6b31STim J. Robbins xdigs = xdigs_lower; 933c5604d0aSTim J. Robbins hex: 934c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 935c5604d0aSTim J. Robbins ujval = UJARG(); 936c5604d0aSTim J. Robbins else 937c5604d0aSTim J. Robbins ulval = UARG(); 938c5604d0aSTim J. Robbins base = 16; 939c5604d0aSTim J. Robbins /* leading 0x/X only if non-zero */ 940c5604d0aSTim J. Robbins if (flags & ALT && 941c5604d0aSTim J. Robbins (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 942adfd6b31STim J. Robbins ox[1] = ch; 943c5604d0aSTim J. Robbins 944c5604d0aSTim J. Robbins flags &= ~GROUPING; 945c5604d0aSTim J. Robbins /* unsigned conversions */ 946c5604d0aSTim J. Robbins nosign: sign = '\0'; 947c5604d0aSTim J. Robbins /*- 948c5604d0aSTim J. Robbins * ``... diouXx conversions ... if a precision is 949c5604d0aSTim J. Robbins * specified, the 0 flag will be ignored.'' 950c5604d0aSTim J. Robbins * -- ANSI X3J11 951c5604d0aSTim J. Robbins */ 952c5604d0aSTim J. Robbins number: if ((dprec = prec) >= 0) 953c5604d0aSTim J. Robbins flags &= ~ZEROPAD; 954c5604d0aSTim J. Robbins 955c5604d0aSTim J. Robbins /*- 956c5604d0aSTim J. Robbins * ``The result of converting a zero value with an 957c5604d0aSTim J. Robbins * explicit precision of zero is no characters.'' 958c5604d0aSTim J. Robbins * -- ANSI X3J11 9591be5319aSDavid Schultz * 9601be5319aSDavid Schultz * ``The C Standard is clear enough as is. The call 9611be5319aSDavid Schultz * printf("%#.0o", 0) should print 0.'' 9621be5319aSDavid Schultz * -- Defect Report #151 963c5604d0aSTim J. Robbins */ 964c5604d0aSTim J. Robbins cp = buf + BUF; 965c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 9661be5319aSDavid Schultz if (ujval != 0 || prec != 0 || 9671be5319aSDavid Schultz (flags & ALT && base == 8)) 968c5604d0aSTim J. Robbins cp = __ujtoa(ujval, cp, base, 96921ca178eSDavid Schultz flags & ALT, xdigs); 970c5604d0aSTim J. Robbins } else { 9711be5319aSDavid Schultz if (ulval != 0 || prec != 0 || 9721be5319aSDavid Schultz (flags & ALT && base == 8)) 973c5604d0aSTim J. Robbins cp = __ultoa(ulval, cp, base, 97421ca178eSDavid Schultz flags & ALT, xdigs); 975c5604d0aSTim J. Robbins } 976c5604d0aSTim J. Robbins size = buf + BUF - cp; 97738cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 97838cac8f8SDavid Schultz abort(); 97921ca178eSDavid Schultz if ((flags & GROUPING) && size != 0) 9803c87aa1dSDavid Chisnall size += grouping_init(&gs, size, locale); 981c5604d0aSTim J. Robbins break; 982c5604d0aSTim J. Robbins default: /* "%?" prints ?, unless ? is NUL */ 983c5604d0aSTim J. Robbins if (ch == '\0') 984c5604d0aSTim J. Robbins goto done; 985c5604d0aSTim J. Robbins /* pretend it was %c with argument ch */ 986c5604d0aSTim J. Robbins cp = buf; 987c5604d0aSTim J. Robbins *cp = ch; 988c5604d0aSTim J. Robbins size = 1; 989c5604d0aSTim J. Robbins sign = '\0'; 990c5604d0aSTim J. Robbins break; 991c5604d0aSTim J. Robbins } 992c5604d0aSTim J. Robbins 993c5604d0aSTim J. Robbins /* 994c5604d0aSTim J. Robbins * All reasonable formats wind up here. At this point, `cp' 995c5604d0aSTim J. Robbins * points to a string which (if not flags&LADJUST) should be 996c5604d0aSTim J. Robbins * padded out to `width' places. If flags&ZEROPAD, it should 997c5604d0aSTim J. Robbins * first be prefixed by any sign or other prefix; otherwise, 998c5604d0aSTim J. Robbins * it should be blank padded before the prefix is emitted. 999c5604d0aSTim J. Robbins * After any left-hand padding and prefixing, emit zeroes 1000c5604d0aSTim J. Robbins * required by a decimal [diouxX] precision, then print the 1001c5604d0aSTim J. Robbins * string proper, then emit zeroes required by any leftover 1002c5604d0aSTim J. Robbins * floating precision; finally, if LADJUST, pad with blanks. 1003c5604d0aSTim J. Robbins * 1004c5604d0aSTim J. Robbins * Compute actual size, so we know how much to pad. 1005c5604d0aSTim J. Robbins * size excludes decimal prec; realsz includes it. 1006c5604d0aSTim J. Robbins */ 1007c5604d0aSTim J. Robbins realsz = dprec > size ? dprec : size; 1008c5604d0aSTim J. Robbins if (sign) 1009c5604d0aSTim J. Robbins realsz++; 10107b7e3509SDavid Schultz if (ox[1]) 1011c5604d0aSTim J. Robbins realsz += 2; 1012c5604d0aSTim J. Robbins 1013c5604d0aSTim J. Robbins prsize = width > realsz ? width : realsz; 1014c5604d0aSTim J. Robbins if ((unsigned)ret + prsize > INT_MAX) { 1015c5604d0aSTim J. Robbins ret = EOF; 1016666d00d3SDavid Schultz errno = EOVERFLOW; 1017c5604d0aSTim J. Robbins goto error; 1018c5604d0aSTim J. Robbins } 1019c5604d0aSTim J. Robbins 1020c5604d0aSTim J. Robbins /* right-adjusting blank padding */ 1021c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == 0) 1022c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1023c5604d0aSTim J. Robbins 1024c5604d0aSTim J. Robbins /* prefix */ 10257b7e3509SDavid Schultz if (sign) 1026c5604d0aSTim J. Robbins PRINT(&sign, 1); 10277b7e3509SDavid Schultz 10287b7e3509SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */ 1029c5604d0aSTim J. Robbins ox[0] = '0'; 1030c5604d0aSTim J. Robbins PRINT(ox, 2); 1031c5604d0aSTim J. Robbins } 1032c5604d0aSTim J. Robbins 1033c5604d0aSTim J. Robbins /* right-adjusting zero padding */ 1034c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 1035c5604d0aSTim J. Robbins PAD(width - realsz, zeroes); 1036c5604d0aSTim J. Robbins 1037c5604d0aSTim J. Robbins /* the string or number proper */ 1038ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 1039c5604d0aSTim J. Robbins if ((flags & FPT) == 0) { 104021ca178eSDavid Schultz #endif 104121ca178eSDavid Schultz /* leading zeroes from decimal precision */ 104221ca178eSDavid Schultz PAD(dprec - size, zeroes); 104321ca178eSDavid Schultz if (gs.grouping) { 10443c87aa1dSDavid Chisnall if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0) 104521ca178eSDavid Schultz goto error; 104621ca178eSDavid Schultz } else { 1047c5604d0aSTim J. Robbins PRINT(cp, size); 104821ca178eSDavid Schultz } 104921ca178eSDavid Schultz #ifndef NO_FLOATING_POINT 1050c5604d0aSTim J. Robbins } else { /* glue together f_p fragments */ 1051adfd6b31STim J. Robbins if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1052adfd6b31STim J. Robbins if (expt <= 0) { 1053d73c448bSTim J. Robbins PRINT(zeroes, 1); 10545004a238SDavid Schultz if (prec || flags & ALT) 10555004a238SDavid Schultz PRINT(&decimal_point, 1); 1056c5604d0aSTim J. Robbins PAD(-expt, zeroes); 1057adfd6b31STim J. Robbins /* already handled initial 0's */ 1058adfd6b31STim J. Robbins prec += expt; 1059c5604d0aSTim J. Robbins } else { 106021ca178eSDavid Schultz if (gs.grouping) { 106121ca178eSDavid Schultz n = grouping_print(&gs, &io, 10623c87aa1dSDavid Chisnall cp, convbuf + ndig, locale); 106321ca178eSDavid Schultz if (n < 0) 106421ca178eSDavid Schultz goto error; 106521ca178eSDavid Schultz cp += n; 106621ca178eSDavid Schultz } else { 106721ca178eSDavid Schultz PRINTANDPAD(cp, convbuf + ndig, 106821ca178eSDavid Schultz expt, zeroes); 106921ca178eSDavid Schultz cp += expt; 1070adfd6b31STim J. Robbins } 10715004a238SDavid Schultz if (prec || flags & ALT) 10725004a238SDavid Schultz PRINT(&decimal_point, 1); 1073adfd6b31STim J. Robbins } 1074adfd6b31STim J. Robbins PRINTANDPAD(cp, convbuf + ndig, prec, zeroes); 1075adfd6b31STim J. Robbins } else { /* %[eE] or sufficiently long %[gG] */ 1076adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) { 1077adfd6b31STim J. Robbins buf[0] = *cp++; 10785004a238SDavid Schultz buf[1] = decimal_point; 1079adfd6b31STim J. Robbins PRINT(buf, 2); 1080c5604d0aSTim J. Robbins PRINT(cp, ndig-1); 1081adfd6b31STim J. Robbins PAD(prec - ndig, zeroes); 1082c5604d0aSTim J. Robbins } else /* XeYYY */ 1083c5604d0aSTim J. Robbins PRINT(cp, 1); 1084c5604d0aSTim J. Robbins PRINT(expstr, expsize); 1085c5604d0aSTim J. Robbins } 1086c5604d0aSTim J. Robbins } 1087c5604d0aSTim J. Robbins #endif 1088c5604d0aSTim J. Robbins /* left-adjusting padding (always blank) */ 1089c5604d0aSTim J. Robbins if (flags & LADJUST) 1090c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1091c5604d0aSTim J. Robbins 1092c5604d0aSTim J. Robbins /* finally, adjust ret */ 1093c5604d0aSTim J. Robbins ret += prsize; 1094814d1bc9SDavid Schultz 1095814d1bc9SDavid Schultz FLUSH(); /* copy out the I/O vectors */ 1096c5604d0aSTim J. Robbins } 1097c5604d0aSTim J. Robbins done: 1098814d1bc9SDavid Schultz FLUSH(); 1099c5604d0aSTim J. Robbins error: 1100096ad104SDag-Erling Smørgrav va_end(orgap); 1101c5604d0aSTim J. Robbins if (convbuf != NULL) 1102c5604d0aSTim J. Robbins free(convbuf); 1103c5604d0aSTim J. Robbins if (__sferror(fp)) 1104c5604d0aSTim J. Robbins ret = EOF; 11051bf6c5f1SAndrey A. Chernov else 11061bf6c5f1SAndrey A. Chernov fp->_flags |= savserr; 1107c5604d0aSTim J. Robbins if ((argtable != NULL) && (argtable != statargtable)) 1108c5604d0aSTim J. Robbins free (argtable); 1109c5604d0aSTim J. Robbins return (ret); 1110c5604d0aSTim J. Robbins /* NOTREACHED */ 1111c5604d0aSTim J. Robbins } 1112