1c5604d0aSTim J. Robbins /*- 2c5604d0aSTim J. Robbins * Copyright (c) 1990, 1993 3c5604d0aSTim J. Robbins * The Regents of the University of California. All rights reserved. 4c5604d0aSTim J. Robbins * 5c5604d0aSTim J. Robbins * This code is derived from software contributed to Berkeley by 6c5604d0aSTim J. Robbins * Chris Torek. 7c5604d0aSTim J. Robbins * 83c87aa1dSDavid Chisnall * Copyright (c) 2011 The FreeBSD Foundation 93c87aa1dSDavid Chisnall * All rights reserved. 103c87aa1dSDavid Chisnall * Portions of this software were developed by David Chisnall 113c87aa1dSDavid Chisnall * under sponsorship from the FreeBSD Foundation. 123c87aa1dSDavid Chisnall * 13c5604d0aSTim J. Robbins * Redistribution and use in source and binary forms, with or without 14c5604d0aSTim J. Robbins * modification, are permitted provided that the following conditions 15c5604d0aSTim J. Robbins * are met: 16c5604d0aSTim J. Robbins * 1. Redistributions of source code must retain the above copyright 17c5604d0aSTim J. Robbins * notice, this list of conditions and the following disclaimer. 18c5604d0aSTim J. Robbins * 2. Redistributions in binary form must reproduce the above copyright 19c5604d0aSTim J. Robbins * notice, this list of conditions and the following disclaimer in the 20c5604d0aSTim J. Robbins * documentation and/or other materials provided with the distribution. 211d8053c5SEd Maste * 3. Neither the name of the University nor the names of its contributors 22c5604d0aSTim J. Robbins * may be used to endorse or promote products derived from this software 23c5604d0aSTim J. Robbins * without specific prior written permission. 24c5604d0aSTim J. Robbins * 25c5604d0aSTim J. Robbins * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26c5604d0aSTim J. Robbins * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27c5604d0aSTim J. Robbins * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28c5604d0aSTim J. Robbins * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29c5604d0aSTim J. Robbins * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30c5604d0aSTim J. Robbins * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31c5604d0aSTim J. Robbins * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32c5604d0aSTim J. Robbins * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33c5604d0aSTim J. Robbins * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34c5604d0aSTim J. Robbins * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35c5604d0aSTim J. Robbins * SUCH DAMAGE. 36c5604d0aSTim J. Robbins */ 37c5604d0aSTim J. Robbins 38c5604d0aSTim J. Robbins #if 0 39c5604d0aSTim J. Robbins #if defined(LIBC_SCCS) && !defined(lint) 40c5604d0aSTim J. Robbins static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 41c5604d0aSTim J. Robbins #endif /* LIBC_SCCS and not lint */ 42c5604d0aSTim J. Robbins #endif 43af152640SDavid E. O'Brien #include <sys/cdefs.h> 44c5604d0aSTim J. Robbins __FBSDID("$FreeBSD$"); 45c5604d0aSTim J. Robbins 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); 359*fda0a14fSKonstantin 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); 366*fda0a14fSKonstantin 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; 684c5604d0aSTim J. Robbins case 'z': 685c5604d0aSTim J. Robbins flags |= SIZET; 686c5604d0aSTim J. Robbins goto rflag; 687927ecbf3STim J. Robbins case 'C': 688927ecbf3STim J. Robbins flags |= LONGINT; 689927ecbf3STim J. Robbins /*FALLTHROUGH*/ 690c5604d0aSTim J. Robbins case 'c': 691c5604d0aSTim J. Robbins if (flags & LONGINT) 692c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)GETARG(wint_t); 693c5604d0aSTim J. Robbins else 694c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)btowc(GETARG(int)); 695c5604d0aSTim J. Robbins size = 1; 696c5604d0aSTim J. Robbins sign = '\0'; 697c5604d0aSTim J. Robbins break; 698c5604d0aSTim J. Robbins case 'D': 699c5604d0aSTim J. Robbins flags |= LONGINT; 700c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 701c5604d0aSTim J. Robbins case 'd': 702c5604d0aSTim J. Robbins case 'i': 703c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 704c5604d0aSTim J. Robbins ujval = SJARG(); 705c5604d0aSTim J. Robbins if ((intmax_t)ujval < 0) { 706c5604d0aSTim J. Robbins ujval = -ujval; 707c5604d0aSTim J. Robbins sign = '-'; 708c5604d0aSTim J. Robbins } 709c5604d0aSTim J. Robbins } else { 710c5604d0aSTim J. Robbins ulval = SARG(); 711c5604d0aSTim J. Robbins if ((long)ulval < 0) { 712c5604d0aSTim J. Robbins ulval = -ulval; 713c5604d0aSTim J. Robbins sign = '-'; 714c5604d0aSTim J. Robbins } 715c5604d0aSTim J. Robbins } 716c5604d0aSTim J. Robbins base = 10; 717c5604d0aSTim J. Robbins goto number; 718ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 719c5604d0aSTim J. Robbins case 'a': 720c5604d0aSTim J. Robbins case 'A': 721adfd6b31STim J. Robbins if (ch == 'a') { 722adfd6b31STim J. Robbins ox[1] = 'x'; 723adfd6b31STim J. Robbins xdigs = xdigs_lower; 724adfd6b31STim J. Robbins expchar = 'p'; 725adfd6b31STim J. Robbins } else { 726adfd6b31STim J. Robbins ox[1] = 'X'; 727adfd6b31STim J. Robbins xdigs = xdigs_upper; 728adfd6b31STim J. Robbins expchar = 'P'; 729adfd6b31STim J. Robbins } 7307b7e3509SDavid Schultz if (prec >= 0) 7317b7e3509SDavid Schultz prec++; 732adfd6b31STim J. Robbins if (flags & LONGDBL) { 7337b7e3509SDavid Schultz fparg.ldbl = GETARG(long double); 734adfd6b31STim J. Robbins dtoaresult = 735adfd6b31STim J. Robbins __hldtoa(fparg.ldbl, xdigs, prec, 736adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 737adfd6b31STim J. Robbins } else { 738adfd6b31STim J. Robbins fparg.dbl = GETARG(double); 739adfd6b31STim J. Robbins dtoaresult = 740adfd6b31STim J. Robbins __hdtoa(fparg.dbl, xdigs, prec, 741adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 742adfd6b31STim J. Robbins } 7437b7e3509SDavid Schultz if (prec < 0) 7447b7e3509SDavid Schultz prec = dtoaend - dtoaresult; 7457b7e3509SDavid Schultz if (expt == INT_MAX) 7467b7e3509SDavid Schultz ox[1] = '\0'; 747adfd6b31STim J. Robbins if (convbuf != NULL) 748adfd6b31STim J. Robbins free(convbuf); 7497b7e3509SDavid Schultz ndig = dtoaend - dtoaresult; 750adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 751adfd6b31STim J. Robbins freedtoa(dtoaresult); 7527b7e3509SDavid Schultz goto fp_common; 753c5604d0aSTim J. Robbins case 'e': 754c5604d0aSTim J. Robbins case 'E': 755adfd6b31STim J. Robbins expchar = ch; 756adfd6b31STim J. Robbins if (prec < 0) /* account for digit before decpt */ 757adfd6b31STim J. Robbins prec = DEFPREC + 1; 758adfd6b31STim J. Robbins else 759adfd6b31STim J. Robbins prec++; 760adfd6b31STim J. Robbins goto fp_begin; 761c5604d0aSTim J. Robbins case 'f': 762c5604d0aSTim J. Robbins case 'F': 763adfd6b31STim J. Robbins expchar = '\0'; 764c5604d0aSTim J. Robbins goto fp_begin; 765c5604d0aSTim J. Robbins case 'g': 766c5604d0aSTim J. Robbins case 'G': 767adfd6b31STim J. Robbins expchar = ch - ('g' - 'e'); 768c5604d0aSTim J. Robbins if (prec == 0) 769c5604d0aSTim J. Robbins prec = 1; 770adfd6b31STim J. Robbins fp_begin: 771adfd6b31STim J. Robbins if (prec < 0) 772c5604d0aSTim J. Robbins prec = DEFPREC; 773adfd6b31STim J. Robbins if (convbuf != NULL) 774adfd6b31STim J. Robbins free(convbuf); 775adfd6b31STim J. Robbins if (flags & LONGDBL) { 776adfd6b31STim J. Robbins fparg.ldbl = GETARG(long double); 777adfd6b31STim J. Robbins dtoaresult = 778adfd6b31STim J. Robbins __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 779adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 780adfd6b31STim J. Robbins } else { 781adfd6b31STim J. Robbins fparg.dbl = GETARG(double); 782adfd6b31STim J. Robbins dtoaresult = 783adfd6b31STim J. Robbins dtoa(fparg.dbl, expchar ? 2 : 3, prec, 784adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 785adfd6b31STim J. Robbins if (expt == 9999) 786adfd6b31STim J. Robbins expt = INT_MAX; 787c5604d0aSTim J. Robbins } 788adfd6b31STim J. Robbins ndig = dtoaend - dtoaresult; 789adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 790adfd6b31STim J. Robbins freedtoa(dtoaresult); 7917b7e3509SDavid Schultz fp_common: 792adfd6b31STim J. Robbins if (signflag) 793adfd6b31STim J. Robbins sign = '-'; 794adfd6b31STim J. Robbins if (expt == INT_MAX) { /* inf or nan */ 795adfd6b31STim J. Robbins if (*cp == 'N') { 796adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"nan" : L"NAN"; 797adfd6b31STim J. Robbins sign = '\0'; 798adfd6b31STim J. Robbins } else 799adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"inf" : L"INF"; 800c5604d0aSTim J. Robbins size = 3; 8018da510f8SDavid Schultz flags &= ~ZEROPAD; 802c5604d0aSTim J. Robbins break; 803c5604d0aSTim J. Robbins } 804c5604d0aSTim J. Robbins flags |= FPT; 805c5604d0aSTim J. Robbins if (ch == 'g' || ch == 'G') { 806adfd6b31STim J. Robbins if (expt > -4 && expt <= prec) { 807adfd6b31STim J. Robbins /* Make %[gG] smell like %[fF] */ 808adfd6b31STim J. Robbins expchar = '\0'; 809adfd6b31STim J. Robbins if (flags & ALT) 810adfd6b31STim J. Robbins prec -= expt; 811c5604d0aSTim J. Robbins else 812adfd6b31STim J. Robbins prec = ndig - expt; 813adfd6b31STim J. Robbins if (prec < 0) 814adfd6b31STim J. Robbins prec = 0; 8151f2a0cdfSDavid Schultz } else { 8161f2a0cdfSDavid Schultz /* 8171f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but 8181f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag. 8191f2a0cdfSDavid Schultz */ 8201f2a0cdfSDavid Schultz if (!(flags & ALT)) 8211f2a0cdfSDavid Schultz prec = ndig; 822c5604d0aSTim J. Robbins } 823adfd6b31STim J. Robbins } 824adfd6b31STim J. Robbins if (expchar) { 825adfd6b31STim J. Robbins expsize = exponent(expstr, expt - 1, expchar); 826adfd6b31STim J. Robbins size = expsize + prec; 827adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) 828c5604d0aSTim J. Robbins ++size; 829adfd6b31STim J. Robbins } else { 830d73c448bSTim J. Robbins /* space for digits before decimal point */ 831d73c448bSTim J. Robbins if (expt > 0) 832c5604d0aSTim J. Robbins size = expt; 833d73c448bSTim J. Robbins else /* "0" */ 834d73c448bSTim J. Robbins size = 1; 835d73c448bSTim J. Robbins /* space for decimal pt and following digits */ 836c5604d0aSTim J. Robbins if (prec || flags & ALT) 837c5604d0aSTim J. Robbins size += prec + 1; 83821ca178eSDavid Schultz if ((flags & GROUPING) && expt > 0) 8393c87aa1dSDavid Chisnall size += grouping_init(&gs, expt, locale); 840adfd6b31STim J. Robbins } 841c5604d0aSTim J. Robbins break; 842ce2551adSDavid Schultz #endif /* !NO_FLOATING_POINT */ 843c5604d0aSTim J. Robbins case 'n': 844c5604d0aSTim J. Robbins /* 845c5604d0aSTim J. Robbins * Assignment-like behavior is specified if the 846c5604d0aSTim J. Robbins * value overflows or is otherwise unrepresentable. 847c5604d0aSTim J. Robbins * C99 says to use `signed char' for %hhn conversions. 848c5604d0aSTim J. Robbins */ 849c5604d0aSTim J. Robbins if (flags & LLONGINT) 850c5604d0aSTim J. Robbins *GETARG(long long *) = ret; 851c5604d0aSTim J. Robbins else if (flags & SIZET) 852c5604d0aSTim J. Robbins *GETARG(ssize_t *) = (ssize_t)ret; 853c5604d0aSTim J. Robbins else if (flags & PTRDIFFT) 854c5604d0aSTim J. Robbins *GETARG(ptrdiff_t *) = ret; 855c5604d0aSTim J. Robbins else if (flags & INTMAXT) 856c5604d0aSTim J. Robbins *GETARG(intmax_t *) = ret; 857c5604d0aSTim J. Robbins else if (flags & LONGINT) 858c5604d0aSTim J. Robbins *GETARG(long *) = ret; 859c5604d0aSTim J. Robbins else if (flags & SHORTINT) 860c5604d0aSTim J. Robbins *GETARG(short *) = ret; 861c5604d0aSTim J. Robbins else if (flags & CHARINT) 862c5604d0aSTim J. Robbins *GETARG(signed char *) = ret; 863c5604d0aSTim J. Robbins else 864c5604d0aSTim J. Robbins *GETARG(int *) = ret; 865c5604d0aSTim J. Robbins continue; /* no output */ 866c5604d0aSTim J. Robbins case 'O': 867c5604d0aSTim J. Robbins flags |= LONGINT; 868c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 869c5604d0aSTim J. Robbins case 'o': 870c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 871c5604d0aSTim J. Robbins ujval = UJARG(); 872c5604d0aSTim J. Robbins else 873c5604d0aSTim J. Robbins ulval = UARG(); 874c5604d0aSTim J. Robbins base = 8; 875c5604d0aSTim J. Robbins goto nosign; 876c5604d0aSTim J. Robbins case 'p': 877c5604d0aSTim J. Robbins /*- 878c5604d0aSTim J. Robbins * ``The argument shall be a pointer to void. The 879c5604d0aSTim J. Robbins * value of the pointer is converted to a sequence 880c5604d0aSTim J. Robbins * of printable characters, in an implementation- 881c5604d0aSTim J. Robbins * defined manner.'' 882c5604d0aSTim J. Robbins * -- ANSI X3J11 883c5604d0aSTim J. Robbins */ 884c5604d0aSTim J. Robbins ujval = (uintmax_t)(uintptr_t)GETARG(void *); 885c5604d0aSTim J. Robbins base = 16; 886adfd6b31STim J. Robbins xdigs = xdigs_lower; 887adfd6b31STim J. Robbins flags = flags | INTMAXT; 888adfd6b31STim J. Robbins ox[1] = 'x'; 889c5604d0aSTim J. Robbins goto nosign; 890927ecbf3STim J. Robbins case 'S': 891927ecbf3STim J. Robbins flags |= LONGINT; 892927ecbf3STim J. Robbins /*FALLTHROUGH*/ 893c5604d0aSTim J. Robbins case 's': 894c5604d0aSTim J. Robbins if (flags & LONGINT) { 895c5604d0aSTim J. Robbins if ((cp = GETARG(wchar_t *)) == NULL) 896c5604d0aSTim J. Robbins cp = L"(null)"; 897c5604d0aSTim J. Robbins } else { 898c5604d0aSTim J. Robbins char *mbp; 899c5604d0aSTim J. Robbins 900c5604d0aSTim J. Robbins if (convbuf != NULL) 901c5604d0aSTim J. Robbins free(convbuf); 902c5604d0aSTim J. Robbins if ((mbp = GETARG(char *)) == NULL) 903c5604d0aSTim J. Robbins cp = L"(null)"; 904c5604d0aSTim J. Robbins else { 905c5604d0aSTim J. Robbins convbuf = __mbsconv(mbp, prec); 9066180233fSTim J. Robbins if (convbuf == NULL) { 9076180233fSTim J. Robbins fp->_flags |= __SERR; 908c5604d0aSTim J. Robbins goto error; 9096180233fSTim J. Robbins } 910c5604d0aSTim J. Robbins cp = convbuf; 911c5604d0aSTim J. Robbins } 912c5604d0aSTim J. Robbins } 913353ce11cSDavid Schultz size = (prec >= 0) ? wcsnlen(cp, prec) : wcslen(cp); 914c5604d0aSTim J. Robbins sign = '\0'; 915c5604d0aSTim J. Robbins break; 916c5604d0aSTim J. Robbins case 'U': 917c5604d0aSTim J. Robbins flags |= LONGINT; 918c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 919c5604d0aSTim J. Robbins case 'u': 920c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 921c5604d0aSTim J. Robbins ujval = UJARG(); 922c5604d0aSTim J. Robbins else 923c5604d0aSTim J. Robbins ulval = UARG(); 924c5604d0aSTim J. Robbins base = 10; 925c5604d0aSTim J. Robbins goto nosign; 926c5604d0aSTim J. Robbins case 'X': 927adfd6b31STim J. Robbins xdigs = xdigs_upper; 928c5604d0aSTim J. Robbins goto hex; 929c5604d0aSTim J. Robbins case 'x': 930adfd6b31STim J. Robbins xdigs = xdigs_lower; 931c5604d0aSTim J. Robbins hex: 932c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 933c5604d0aSTim J. Robbins ujval = UJARG(); 934c5604d0aSTim J. Robbins else 935c5604d0aSTim J. Robbins ulval = UARG(); 936c5604d0aSTim J. Robbins base = 16; 937c5604d0aSTim J. Robbins /* leading 0x/X only if non-zero */ 938c5604d0aSTim J. Robbins if (flags & ALT && 939c5604d0aSTim J. Robbins (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 940adfd6b31STim J. Robbins ox[1] = ch; 941c5604d0aSTim J. Robbins 942c5604d0aSTim J. Robbins flags &= ~GROUPING; 943c5604d0aSTim J. Robbins /* unsigned conversions */ 944c5604d0aSTim J. Robbins nosign: sign = '\0'; 945c5604d0aSTim J. Robbins /*- 946c5604d0aSTim J. Robbins * ``... diouXx conversions ... if a precision is 947c5604d0aSTim J. Robbins * specified, the 0 flag will be ignored.'' 948c5604d0aSTim J. Robbins * -- ANSI X3J11 949c5604d0aSTim J. Robbins */ 950c5604d0aSTim J. Robbins number: if ((dprec = prec) >= 0) 951c5604d0aSTim J. Robbins flags &= ~ZEROPAD; 952c5604d0aSTim J. Robbins 953c5604d0aSTim J. Robbins /*- 954c5604d0aSTim J. Robbins * ``The result of converting a zero value with an 955c5604d0aSTim J. Robbins * explicit precision of zero is no characters.'' 956c5604d0aSTim J. Robbins * -- ANSI X3J11 9571be5319aSDavid Schultz * 9581be5319aSDavid Schultz * ``The C Standard is clear enough as is. The call 9591be5319aSDavid Schultz * printf("%#.0o", 0) should print 0.'' 9601be5319aSDavid Schultz * -- Defect Report #151 961c5604d0aSTim J. Robbins */ 962c5604d0aSTim J. Robbins cp = buf + BUF; 963c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 9641be5319aSDavid Schultz if (ujval != 0 || prec != 0 || 9651be5319aSDavid Schultz (flags & ALT && base == 8)) 966c5604d0aSTim J. Robbins cp = __ujtoa(ujval, cp, base, 96721ca178eSDavid Schultz flags & ALT, xdigs); 968c5604d0aSTim J. Robbins } else { 9691be5319aSDavid Schultz if (ulval != 0 || prec != 0 || 9701be5319aSDavid Schultz (flags & ALT && base == 8)) 971c5604d0aSTim J. Robbins cp = __ultoa(ulval, cp, base, 97221ca178eSDavid Schultz flags & ALT, xdigs); 973c5604d0aSTim J. Robbins } 974c5604d0aSTim J. Robbins size = buf + BUF - cp; 97538cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 97638cac8f8SDavid Schultz abort(); 97721ca178eSDavid Schultz if ((flags & GROUPING) && size != 0) 9783c87aa1dSDavid Chisnall size += grouping_init(&gs, size, locale); 979c5604d0aSTim J. Robbins break; 980c5604d0aSTim J. Robbins default: /* "%?" prints ?, unless ? is NUL */ 981c5604d0aSTim J. Robbins if (ch == '\0') 982c5604d0aSTim J. Robbins goto done; 983c5604d0aSTim J. Robbins /* pretend it was %c with argument ch */ 984c5604d0aSTim J. Robbins cp = buf; 985c5604d0aSTim J. Robbins *cp = ch; 986c5604d0aSTim J. Robbins size = 1; 987c5604d0aSTim J. Robbins sign = '\0'; 988c5604d0aSTim J. Robbins break; 989c5604d0aSTim J. Robbins } 990c5604d0aSTim J. Robbins 991c5604d0aSTim J. Robbins /* 992c5604d0aSTim J. Robbins * All reasonable formats wind up here. At this point, `cp' 993c5604d0aSTim J. Robbins * points to a string which (if not flags&LADJUST) should be 994c5604d0aSTim J. Robbins * padded out to `width' places. If flags&ZEROPAD, it should 995c5604d0aSTim J. Robbins * first be prefixed by any sign or other prefix; otherwise, 996c5604d0aSTim J. Robbins * it should be blank padded before the prefix is emitted. 997c5604d0aSTim J. Robbins * After any left-hand padding and prefixing, emit zeroes 998c5604d0aSTim J. Robbins * required by a decimal [diouxX] precision, then print the 999c5604d0aSTim J. Robbins * string proper, then emit zeroes required by any leftover 1000c5604d0aSTim J. Robbins * floating precision; finally, if LADJUST, pad with blanks. 1001c5604d0aSTim J. Robbins * 1002c5604d0aSTim J. Robbins * Compute actual size, so we know how much to pad. 1003c5604d0aSTim J. Robbins * size excludes decimal prec; realsz includes it. 1004c5604d0aSTim J. Robbins */ 1005c5604d0aSTim J. Robbins realsz = dprec > size ? dprec : size; 1006c5604d0aSTim J. Robbins if (sign) 1007c5604d0aSTim J. Robbins realsz++; 10087b7e3509SDavid Schultz if (ox[1]) 1009c5604d0aSTim J. Robbins realsz += 2; 1010c5604d0aSTim J. Robbins 1011c5604d0aSTim J. Robbins prsize = width > realsz ? width : realsz; 1012c5604d0aSTim J. Robbins if ((unsigned)ret + prsize > INT_MAX) { 1013c5604d0aSTim J. Robbins ret = EOF; 1014666d00d3SDavid Schultz errno = EOVERFLOW; 1015c5604d0aSTim J. Robbins goto error; 1016c5604d0aSTim J. Robbins } 1017c5604d0aSTim J. Robbins 1018c5604d0aSTim J. Robbins /* right-adjusting blank padding */ 1019c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == 0) 1020c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1021c5604d0aSTim J. Robbins 1022c5604d0aSTim J. Robbins /* prefix */ 10237b7e3509SDavid Schultz if (sign) 1024c5604d0aSTim J. Robbins PRINT(&sign, 1); 10257b7e3509SDavid Schultz 10267b7e3509SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */ 1027c5604d0aSTim J. Robbins ox[0] = '0'; 1028c5604d0aSTim J. Robbins PRINT(ox, 2); 1029c5604d0aSTim J. Robbins } 1030c5604d0aSTim J. Robbins 1031c5604d0aSTim J. Robbins /* right-adjusting zero padding */ 1032c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 1033c5604d0aSTim J. Robbins PAD(width - realsz, zeroes); 1034c5604d0aSTim J. Robbins 1035c5604d0aSTim J. Robbins /* the string or number proper */ 1036ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 1037c5604d0aSTim J. Robbins if ((flags & FPT) == 0) { 103821ca178eSDavid Schultz #endif 103921ca178eSDavid Schultz /* leading zeroes from decimal precision */ 104021ca178eSDavid Schultz PAD(dprec - size, zeroes); 104121ca178eSDavid Schultz if (gs.grouping) { 10423c87aa1dSDavid Chisnall if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0) 104321ca178eSDavid Schultz goto error; 104421ca178eSDavid Schultz } else { 1045c5604d0aSTim J. Robbins PRINT(cp, size); 104621ca178eSDavid Schultz } 104721ca178eSDavid Schultz #ifndef NO_FLOATING_POINT 1048c5604d0aSTim J. Robbins } else { /* glue together f_p fragments */ 1049adfd6b31STim J. Robbins if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1050adfd6b31STim J. Robbins if (expt <= 0) { 1051d73c448bSTim J. Robbins PRINT(zeroes, 1); 10525004a238SDavid Schultz if (prec || flags & ALT) 10535004a238SDavid Schultz PRINT(&decimal_point, 1); 1054c5604d0aSTim J. Robbins PAD(-expt, zeroes); 1055adfd6b31STim J. Robbins /* already handled initial 0's */ 1056adfd6b31STim J. Robbins prec += expt; 1057c5604d0aSTim J. Robbins } else { 105821ca178eSDavid Schultz if (gs.grouping) { 105921ca178eSDavid Schultz n = grouping_print(&gs, &io, 10603c87aa1dSDavid Chisnall cp, convbuf + ndig, locale); 106121ca178eSDavid Schultz if (n < 0) 106221ca178eSDavid Schultz goto error; 106321ca178eSDavid Schultz cp += n; 106421ca178eSDavid Schultz } else { 106521ca178eSDavid Schultz PRINTANDPAD(cp, convbuf + ndig, 106621ca178eSDavid Schultz expt, zeroes); 106721ca178eSDavid Schultz cp += expt; 1068adfd6b31STim J. Robbins } 10695004a238SDavid Schultz if (prec || flags & ALT) 10705004a238SDavid Schultz PRINT(&decimal_point, 1); 1071adfd6b31STim J. Robbins } 1072adfd6b31STim J. Robbins PRINTANDPAD(cp, convbuf + ndig, prec, zeroes); 1073adfd6b31STim J. Robbins } else { /* %[eE] or sufficiently long %[gG] */ 1074adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) { 1075adfd6b31STim J. Robbins buf[0] = *cp++; 10765004a238SDavid Schultz buf[1] = decimal_point; 1077adfd6b31STim J. Robbins PRINT(buf, 2); 1078c5604d0aSTim J. Robbins PRINT(cp, ndig-1); 1079adfd6b31STim J. Robbins PAD(prec - ndig, zeroes); 1080c5604d0aSTim J. Robbins } else /* XeYYY */ 1081c5604d0aSTim J. Robbins PRINT(cp, 1); 1082c5604d0aSTim J. Robbins PRINT(expstr, expsize); 1083c5604d0aSTim J. Robbins } 1084c5604d0aSTim J. Robbins } 1085c5604d0aSTim J. Robbins #endif 1086c5604d0aSTim J. Robbins /* left-adjusting padding (always blank) */ 1087c5604d0aSTim J. Robbins if (flags & LADJUST) 1088c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1089c5604d0aSTim J. Robbins 1090c5604d0aSTim J. Robbins /* finally, adjust ret */ 1091c5604d0aSTim J. Robbins ret += prsize; 1092814d1bc9SDavid Schultz 1093814d1bc9SDavid Schultz FLUSH(); /* copy out the I/O vectors */ 1094c5604d0aSTim J. Robbins } 1095c5604d0aSTim J. Robbins done: 1096814d1bc9SDavid Schultz FLUSH(); 1097c5604d0aSTim J. Robbins error: 1098096ad104SDag-Erling Smørgrav va_end(orgap); 1099c5604d0aSTim J. Robbins if (convbuf != NULL) 1100c5604d0aSTim J. Robbins free(convbuf); 1101c5604d0aSTim J. Robbins if (__sferror(fp)) 1102c5604d0aSTim J. Robbins ret = EOF; 11031bf6c5f1SAndrey A. Chernov else 11041bf6c5f1SAndrey A. Chernov fp->_flags |= savserr; 1105c5604d0aSTim J. Robbins if ((argtable != NULL) && (argtable != statargtable)) 1106c5604d0aSTim J. Robbins free (argtable); 1107c5604d0aSTim J. Robbins return (ret); 1108c5604d0aSTim J. Robbins /* NOTREACHED */ 1109c5604d0aSTim J. Robbins } 1110