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 * 8c5604d0aSTim J. Robbins * Redistribution and use in source and binary forms, with or without 9c5604d0aSTim J. Robbins * modification, are permitted provided that the following conditions 10c5604d0aSTim J. Robbins * are met: 11c5604d0aSTim J. Robbins * 1. Redistributions of source code must retain the above copyright 12c5604d0aSTim J. Robbins * notice, this list of conditions and the following disclaimer. 13c5604d0aSTim J. Robbins * 2. Redistributions in binary form must reproduce the above copyright 14c5604d0aSTim J. Robbins * notice, this list of conditions and the following disclaimer in the 15c5604d0aSTim J. Robbins * documentation and/or other materials provided with the distribution. 16c5604d0aSTim J. Robbins * 4. Neither the name of the University nor the names of its contributors 17c5604d0aSTim J. Robbins * may be used to endorse or promote products derived from this software 18c5604d0aSTim J. Robbins * without specific prior written permission. 19c5604d0aSTim J. Robbins * 20c5604d0aSTim J. Robbins * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21c5604d0aSTim J. Robbins * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22c5604d0aSTim J. Robbins * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23c5604d0aSTim J. Robbins * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24c5604d0aSTim J. Robbins * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25c5604d0aSTim J. Robbins * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26c5604d0aSTim J. Robbins * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27c5604d0aSTim J. Robbins * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28c5604d0aSTim J. Robbins * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29c5604d0aSTim J. Robbins * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30c5604d0aSTim J. Robbins * SUCH DAMAGE. 31c5604d0aSTim J. Robbins */ 32c5604d0aSTim J. Robbins 33c5604d0aSTim J. Robbins #if 0 34c5604d0aSTim J. Robbins #if defined(LIBC_SCCS) && !defined(lint) 35c5604d0aSTim J. Robbins static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 36c5604d0aSTim J. Robbins #endif /* LIBC_SCCS and not lint */ 37c5604d0aSTim J. Robbins #endif 38af152640SDavid E. O'Brien #include <sys/cdefs.h> 39c5604d0aSTim J. Robbins __FBSDID("$FreeBSD$"); 40c5604d0aSTim J. Robbins 41c5604d0aSTim J. Robbins /* 42c5604d0aSTim J. Robbins * Actual wprintf innards. 43c5604d0aSTim J. Robbins * 44c5604d0aSTim J. Robbins * Avoid making gratuitous changes to this source file; it should be kept 45c5604d0aSTim J. Robbins * as close as possible to vfprintf.c for ease of maintenance. 46c5604d0aSTim J. Robbins */ 47c5604d0aSTim J. Robbins 48c5604d0aSTim J. Robbins #include "namespace.h" 49c5604d0aSTim J. Robbins #include <sys/types.h> 50c5604d0aSTim J. Robbins 51c5604d0aSTim J. Robbins #include <ctype.h> 52c5604d0aSTim J. Robbins #include <limits.h> 53c5604d0aSTim J. Robbins #include <locale.h> 54c5604d0aSTim J. Robbins #include <stdarg.h> 55c5604d0aSTim J. Robbins #include <stddef.h> 56c5604d0aSTim J. Robbins #include <stdint.h> 57c5604d0aSTim J. Robbins #include <stdio.h> 58c5604d0aSTim J. Robbins #include <stdlib.h> 59c5604d0aSTim J. Robbins #include <string.h> 60c5604d0aSTim J. Robbins #include <wchar.h> 61c5604d0aSTim J. Robbins #include <wctype.h> 62c5604d0aSTim J. Robbins #include "un-namespace.h" 63c5604d0aSTim J. Robbins 64c5604d0aSTim J. Robbins #include "libc_private.h" 65c5604d0aSTim J. Robbins #include "local.h" 66c5604d0aSTim J. Robbins #include "fvwrite.h" 672591efccSDavid Schultz #include "printflocal.h" 68e5abb5e6SDavid Schultz 69c5604d0aSTim J. Robbins static int __sbprintf(FILE *, const wchar_t *, va_list); 70909a17f4STim J. Robbins static wint_t __xfputwc(wchar_t, FILE *); 717b7e3509SDavid Schultz static wchar_t *__ujtoa(uintmax_t, wchar_t *, int, int, const char *, int, 72adfd6b31STim J. Robbins char, const char *); 737b7e3509SDavid Schultz static wchar_t *__ultoa(u_long, wchar_t *, int, int, const char *, int, 74adfd6b31STim J. Robbins char, const char *); 75c5604d0aSTim J. Robbins static wchar_t *__mbsconv(char *, int); 76c5604d0aSTim J. Robbins 77c5604d0aSTim J. Robbins /* 78c5604d0aSTim J. Robbins * Helper function for `fprintf to unbuffered unix file': creates a 79c5604d0aSTim J. Robbins * temporary buffer. We only work on write-only files; this avoids 80c5604d0aSTim J. Robbins * worries about ungetc buffers and so forth. 81c5604d0aSTim J. Robbins */ 82c5604d0aSTim J. Robbins static int 83c5604d0aSTim J. Robbins __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) 84c5604d0aSTim J. Robbins { 85c5604d0aSTim J. Robbins int ret; 86c5604d0aSTim J. Robbins FILE fake; 87c5604d0aSTim J. Robbins unsigned char buf[BUFSIZ]; 88c5604d0aSTim J. Robbins 89c5604d0aSTim J. Robbins /* copy the important variables */ 90c5604d0aSTim J. Robbins fake._flags = fp->_flags & ~__SNBF; 91c5604d0aSTim J. Robbins fake._file = fp->_file; 92c5604d0aSTim J. Robbins fake._cookie = fp->_cookie; 93c5604d0aSTim J. Robbins fake._write = fp->_write; 941e98f887SJohn Baldwin fake._orientation = fp->_orientation; 951e98f887SJohn Baldwin fake._mbstate = fp->_mbstate; 96c5604d0aSTim J. Robbins 97c5604d0aSTim J. Robbins /* set up the buffer */ 98c5604d0aSTim J. Robbins fake._bf._base = fake._p = buf; 99c5604d0aSTim J. Robbins fake._bf._size = fake._w = sizeof(buf); 100c5604d0aSTim J. Robbins fake._lbfsize = 0; /* not actually used, but Just In Case */ 101c5604d0aSTim J. Robbins 102c5604d0aSTim J. Robbins /* do the work, then copy any error status */ 103c5604d0aSTim J. Robbins ret = __vfwprintf(&fake, fmt, ap); 104c5604d0aSTim J. Robbins if (ret >= 0 && __fflush(&fake)) 105c5604d0aSTim J. Robbins ret = WEOF; 106c5604d0aSTim J. Robbins if (fake._flags & __SERR) 107c5604d0aSTim J. Robbins fp->_flags |= __SERR; 108c5604d0aSTim J. Robbins return (ret); 109c5604d0aSTim J. Robbins } 110c5604d0aSTim J. Robbins 111c5604d0aSTim J. Robbins /* 112909a17f4STim J. Robbins * Like __fputwc, but handles fake string (__SSTR) files properly. 113909a17f4STim J. Robbins * File must already be locked. 114909a17f4STim J. Robbins */ 115909a17f4STim J. Robbins static wint_t 116909a17f4STim J. Robbins __xfputwc(wchar_t wc, FILE *fp) 117909a17f4STim J. Robbins { 11893996f6dSTim J. Robbins static const mbstate_t initial; 11993996f6dSTim J. Robbins mbstate_t mbs; 120909a17f4STim J. Robbins char buf[MB_LEN_MAX]; 121909a17f4STim J. Robbins struct __suio uio; 122909a17f4STim J. Robbins struct __siov iov; 12384d9142fSJacques Vidrine size_t len; 124909a17f4STim J. Robbins 125909a17f4STim J. Robbins if ((fp->_flags & __SSTR) == 0) 126909a17f4STim J. Robbins return (__fputwc(wc, fp)); 127909a17f4STim J. Robbins 12893996f6dSTim J. Robbins mbs = initial; 12993996f6dSTim J. Robbins if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) { 130909a17f4STim J. Robbins fp->_flags |= __SERR; 131909a17f4STim J. Robbins return (WEOF); 132909a17f4STim J. Robbins } 133909a17f4STim J. Robbins uio.uio_iov = &iov; 134909a17f4STim J. Robbins uio.uio_resid = len; 135909a17f4STim J. Robbins uio.uio_iovcnt = 1; 136909a17f4STim J. Robbins iov.iov_base = buf; 137909a17f4STim J. Robbins iov.iov_len = len; 138909a17f4STim J. Robbins return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF); 139909a17f4STim J. Robbins } 140909a17f4STim J. Robbins 141909a17f4STim J. Robbins /* 142c5604d0aSTim J. Robbins * Convert an unsigned long to ASCII for printf purposes, returning 143c5604d0aSTim J. Robbins * a pointer to the first character of the string representation. 144c5604d0aSTim J. Robbins * Octal numbers can be forced to have a leading zero; hex numbers 145c5604d0aSTim J. Robbins * use the given digits. 146c5604d0aSTim J. Robbins */ 147c5604d0aSTim J. Robbins static wchar_t * 1487b7e3509SDavid Schultz __ultoa(u_long val, wchar_t *endp, int base, int octzero, const char *xdigs, 149c5604d0aSTim J. Robbins int needgrp, char thousep, const char *grp) 150c5604d0aSTim J. Robbins { 151c5604d0aSTim J. Robbins wchar_t *cp = endp; 152c5604d0aSTim J. Robbins long sval; 153c5604d0aSTim J. Robbins int ndig; 154c5604d0aSTim J. Robbins 155c5604d0aSTim J. Robbins /* 156c5604d0aSTim J. Robbins * Handle the three cases separately, in the hope of getting 157c5604d0aSTim J. Robbins * better/faster code. 158c5604d0aSTim J. Robbins */ 159c5604d0aSTim J. Robbins switch (base) { 160c5604d0aSTim J. Robbins case 10: 161c5604d0aSTim J. Robbins if (val < 10) { /* many numbers are 1 digit */ 162c5604d0aSTim J. Robbins *--cp = to_char(val); 163c5604d0aSTim J. Robbins return (cp); 164c5604d0aSTim J. Robbins } 165c5604d0aSTim J. Robbins ndig = 0; 166c5604d0aSTim J. Robbins /* 167c5604d0aSTim J. Robbins * On many machines, unsigned arithmetic is harder than 168c5604d0aSTim J. Robbins * signed arithmetic, so we do at most one unsigned mod and 169c5604d0aSTim J. Robbins * divide; this is sufficient to reduce the range of 170c5604d0aSTim J. Robbins * the incoming value to where signed arithmetic works. 171c5604d0aSTim J. Robbins */ 172c5604d0aSTim J. Robbins if (val > LONG_MAX) { 173c5604d0aSTim J. Robbins *--cp = to_char(val % 10); 174c5604d0aSTim J. Robbins ndig++; 175c5604d0aSTim J. Robbins sval = val / 10; 176c5604d0aSTim J. Robbins } else 177c5604d0aSTim J. Robbins sval = val; 178c5604d0aSTim J. Robbins do { 179c5604d0aSTim J. Robbins *--cp = to_char(sval % 10); 180c5604d0aSTim J. Robbins ndig++; 181c5604d0aSTim J. Robbins /* 182c5604d0aSTim J. Robbins * If (*grp == CHAR_MAX) then no more grouping 183c5604d0aSTim J. Robbins * should be performed. 184c5604d0aSTim J. Robbins */ 185c5604d0aSTim J. Robbins if (needgrp && ndig == *grp && *grp != CHAR_MAX 186c5604d0aSTim J. Robbins && sval > 9) { 187c5604d0aSTim J. Robbins *--cp = thousep; 188c5604d0aSTim J. Robbins ndig = 0; 189c5604d0aSTim J. Robbins /* 190c5604d0aSTim J. Robbins * If (*(grp+1) == '\0') then we have to 191c5604d0aSTim J. Robbins * use *grp character (last grouping rule) 192c5604d0aSTim J. Robbins * for all next cases 193c5604d0aSTim J. Robbins */ 194c5604d0aSTim J. Robbins if (*(grp+1) != '\0') 195c5604d0aSTim J. Robbins grp++; 196c5604d0aSTim J. Robbins } 197c5604d0aSTim J. Robbins sval /= 10; 198c5604d0aSTim J. Robbins } while (sval != 0); 199c5604d0aSTim J. Robbins break; 200c5604d0aSTim J. Robbins 201c5604d0aSTim J. Robbins case 8: 202c5604d0aSTim J. Robbins do { 203c5604d0aSTim J. Robbins *--cp = to_char(val & 7); 204c5604d0aSTim J. Robbins val >>= 3; 205c5604d0aSTim J. Robbins } while (val); 206c5604d0aSTim J. Robbins if (octzero && *cp != '0') 207c5604d0aSTim J. Robbins *--cp = '0'; 208c5604d0aSTim J. Robbins break; 209c5604d0aSTim J. Robbins 210c5604d0aSTim J. Robbins case 16: 211c5604d0aSTim J. Robbins do { 212c5604d0aSTim J. Robbins *--cp = xdigs[val & 15]; 213c5604d0aSTim J. Robbins val >>= 4; 214c5604d0aSTim J. Robbins } while (val); 215c5604d0aSTim J. Robbins break; 216c5604d0aSTim J. Robbins 217c5604d0aSTim J. Robbins default: /* oops */ 218c5604d0aSTim J. Robbins abort(); 219c5604d0aSTim J. Robbins } 220c5604d0aSTim J. Robbins return (cp); 221c5604d0aSTim J. Robbins } 222c5604d0aSTim J. Robbins 223c5604d0aSTim J. Robbins /* Identical to __ultoa, but for intmax_t. */ 224c5604d0aSTim J. Robbins static wchar_t * 225adfd6b31STim J. Robbins __ujtoa(uintmax_t val, wchar_t *endp, int base, int octzero, 2267b7e3509SDavid Schultz const char *xdigs, int needgrp, char thousep, const char *grp) 227c5604d0aSTim J. Robbins { 228c5604d0aSTim J. Robbins wchar_t *cp = endp; 229c5604d0aSTim J. Robbins intmax_t sval; 230c5604d0aSTim J. Robbins int ndig; 231c5604d0aSTim J. Robbins 232c5604d0aSTim J. Robbins /* quick test for small values; __ultoa is typically much faster */ 233c5604d0aSTim J. Robbins /* (perhaps instead we should run until small, then call __ultoa?) */ 234c5604d0aSTim J. Robbins if (val <= ULONG_MAX) 235c5604d0aSTim J. Robbins return (__ultoa((u_long)val, endp, base, octzero, xdigs, 236c5604d0aSTim J. Robbins needgrp, thousep, grp)); 237c5604d0aSTim J. Robbins switch (base) { 238c5604d0aSTim J. Robbins case 10: 239c5604d0aSTim J. Robbins if (val < 10) { 240c5604d0aSTim J. Robbins *--cp = to_char(val % 10); 241c5604d0aSTim J. Robbins return (cp); 242c5604d0aSTim J. Robbins } 243c5604d0aSTim J. Robbins ndig = 0; 244c5604d0aSTim J. Robbins if (val > INTMAX_MAX) { 245c5604d0aSTim J. Robbins *--cp = to_char(val % 10); 246c5604d0aSTim J. Robbins ndig++; 247c5604d0aSTim J. Robbins sval = val / 10; 248c5604d0aSTim J. Robbins } else 249c5604d0aSTim J. Robbins sval = val; 250c5604d0aSTim J. Robbins do { 251c5604d0aSTim J. Robbins *--cp = to_char(sval % 10); 252c5604d0aSTim J. Robbins ndig++; 253c5604d0aSTim J. Robbins /* 254c5604d0aSTim J. Robbins * If (*grp == CHAR_MAX) then no more grouping 255c5604d0aSTim J. Robbins * should be performed. 256c5604d0aSTim J. Robbins */ 257c5604d0aSTim J. Robbins if (needgrp && *grp != CHAR_MAX && ndig == *grp 258c5604d0aSTim J. Robbins && sval > 9) { 259c5604d0aSTim J. Robbins *--cp = thousep; 260c5604d0aSTim J. Robbins ndig = 0; 261c5604d0aSTim J. Robbins /* 262c5604d0aSTim J. Robbins * If (*(grp+1) == '\0') then we have to 263c5604d0aSTim J. Robbins * use *grp character (last grouping rule) 264c5604d0aSTim J. Robbins * for all next cases 265c5604d0aSTim J. Robbins */ 266c5604d0aSTim J. Robbins if (*(grp+1) != '\0') 267c5604d0aSTim J. Robbins grp++; 268c5604d0aSTim J. Robbins } 269c5604d0aSTim J. Robbins sval /= 10; 270c5604d0aSTim J. Robbins } while (sval != 0); 271c5604d0aSTim J. Robbins break; 272c5604d0aSTim J. Robbins 273c5604d0aSTim J. Robbins case 8: 274c5604d0aSTim J. Robbins do { 275c5604d0aSTim J. Robbins *--cp = to_char(val & 7); 276c5604d0aSTim J. Robbins val >>= 3; 277c5604d0aSTim J. Robbins } while (val); 278c5604d0aSTim J. Robbins if (octzero && *cp != '0') 279c5604d0aSTim J. Robbins *--cp = '0'; 280c5604d0aSTim J. Robbins break; 281c5604d0aSTim J. Robbins 282c5604d0aSTim J. Robbins case 16: 283c5604d0aSTim J. Robbins do { 284c5604d0aSTim J. Robbins *--cp = xdigs[val & 15]; 285c5604d0aSTim J. Robbins val >>= 4; 286c5604d0aSTim J. Robbins } while (val); 287c5604d0aSTim J. Robbins break; 288c5604d0aSTim J. Robbins 289c5604d0aSTim J. Robbins default: 290c5604d0aSTim J. Robbins abort(); 291c5604d0aSTim J. Robbins } 292c5604d0aSTim J. Robbins return (cp); 293c5604d0aSTim J. Robbins } 294c5604d0aSTim J. Robbins 295c5604d0aSTim J. Robbins /* 296c5604d0aSTim J. Robbins * Convert a multibyte character string argument for the %s format to a wide 297c5604d0aSTim J. Robbins * string representation. ``prec'' specifies the maximum number of bytes 298c5604d0aSTim J. Robbins * to output. If ``prec'' is greater than or equal to zero, we can't assume 299c5604d0aSTim J. Robbins * that the multibyte char. string ends in a null character. 300c5604d0aSTim J. Robbins */ 301c5604d0aSTim J. Robbins static wchar_t * 302c5604d0aSTim J. Robbins __mbsconv(char *mbsarg, int prec) 303c5604d0aSTim J. Robbins { 30493996f6dSTim J. Robbins static const mbstate_t initial; 30593996f6dSTim J. Robbins mbstate_t mbs; 306c5604d0aSTim J. Robbins wchar_t *convbuf, *wcp; 307c5604d0aSTim J. Robbins const char *p; 308c5604d0aSTim J. Robbins size_t insize, nchars, nconv; 309c5604d0aSTim J. Robbins 310adfd6b31STim J. Robbins if (mbsarg == NULL) 311adfd6b31STim J. Robbins return (NULL); 312adfd6b31STim J. Robbins 313c5604d0aSTim J. Robbins /* 314c5604d0aSTim J. Robbins * Supplied argument is a multibyte string; convert it to wide 315c5604d0aSTim J. Robbins * characters first. 316c5604d0aSTim J. Robbins */ 317c5604d0aSTim J. Robbins if (prec >= 0) { 318c5604d0aSTim J. Robbins /* 319c5604d0aSTim J. Robbins * String is not guaranteed to be NUL-terminated. Find the 320c5604d0aSTim J. Robbins * number of characters to print. 321c5604d0aSTim J. Robbins */ 322c5604d0aSTim J. Robbins p = mbsarg; 323c5604d0aSTim J. Robbins insize = nchars = 0; 32493996f6dSTim J. Robbins mbs = initial; 325c5604d0aSTim J. Robbins while (nchars != (size_t)prec) { 32693996f6dSTim J. Robbins nconv = mbrlen(p, MB_CUR_MAX, &mbs); 327c5604d0aSTim J. Robbins if (nconv == 0 || nconv == (size_t)-1 || 328c5604d0aSTim J. Robbins nconv == (size_t)-2) 329c5604d0aSTim J. Robbins break; 330c5604d0aSTim J. Robbins p += nconv; 331c5604d0aSTim J. Robbins nchars++; 332c5604d0aSTim J. Robbins insize += nconv; 333c5604d0aSTim J. Robbins } 334c5604d0aSTim J. Robbins if (nconv == (size_t)-1 || nconv == (size_t)-2) 335c5604d0aSTim J. Robbins return (NULL); 336c5604d0aSTim J. Robbins } else 337c5604d0aSTim J. Robbins insize = strlen(mbsarg); 338c5604d0aSTim J. Robbins 339c5604d0aSTim J. Robbins /* 340c5604d0aSTim J. Robbins * Allocate buffer for the result and perform the conversion, 341c5604d0aSTim J. Robbins * converting at most `size' bytes of the input multibyte string to 342c5604d0aSTim J. Robbins * wide characters for printing. 343c5604d0aSTim J. Robbins */ 344c5604d0aSTim J. Robbins convbuf = malloc((insize + 1) * sizeof(*convbuf)); 345c5604d0aSTim J. Robbins if (convbuf == NULL) 346c5604d0aSTim J. Robbins return (NULL); 347c5604d0aSTim J. Robbins wcp = convbuf; 348c5604d0aSTim J. Robbins p = mbsarg; 34993996f6dSTim J. Robbins mbs = initial; 350c5604d0aSTim J. Robbins while (insize != 0) { 35193996f6dSTim J. Robbins nconv = mbrtowc(wcp, p, insize, &mbs); 352c5604d0aSTim J. Robbins if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) 353c5604d0aSTim J. Robbins break; 354c5604d0aSTim J. Robbins wcp++; 355c5604d0aSTim J. Robbins p += nconv; 356c5604d0aSTim J. Robbins insize -= nconv; 357c5604d0aSTim J. Robbins } 358c5604d0aSTim J. Robbins if (nconv == (size_t)-1 || nconv == (size_t)-2) { 359c5604d0aSTim J. Robbins free(convbuf); 360c5604d0aSTim J. Robbins return (NULL); 361c5604d0aSTim J. Robbins } 362c5604d0aSTim J. Robbins *wcp = L'\0'; 363c5604d0aSTim J. Robbins 364c5604d0aSTim J. Robbins return (convbuf); 365c5604d0aSTim J. Robbins } 366c5604d0aSTim J. Robbins 367c5604d0aSTim J. Robbins /* 368c5604d0aSTim J. Robbins * MT-safe version 369c5604d0aSTim J. Robbins */ 370c5604d0aSTim J. Robbins int 371c5604d0aSTim J. Robbins vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap) 372c5604d0aSTim J. Robbins 373c5604d0aSTim J. Robbins { 374c5604d0aSTim J. Robbins int ret; 375c5604d0aSTim J. Robbins 376c5604d0aSTim J. Robbins FLOCKFILE(fp); 377c5604d0aSTim J. Robbins ret = __vfwprintf(fp, fmt0, ap); 378c5604d0aSTim J. Robbins FUNLOCKFILE(fp); 379c5604d0aSTim J. Robbins return (ret); 380c5604d0aSTim J. Robbins } 381c5604d0aSTim J. Robbins 382ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 383adfd6b31STim J. Robbins 384adfd6b31STim J. Robbins #define dtoa __dtoa 385adfd6b31STim J. Robbins #define freedtoa __freedtoa 386adfd6b31STim J. Robbins 387b936664eSDavid Schultz #include <float.h> 388c5604d0aSTim J. Robbins #include <math.h> 389c5604d0aSTim J. Robbins #include "floatio.h" 390adfd6b31STim J. Robbins #include "gdtoa.h" 391c5604d0aSTim J. Robbins 392c5604d0aSTim J. Robbins #define DEFPREC 6 393c5604d0aSTim J. Robbins 394c5604d0aSTim J. Robbins static int exponent(wchar_t *, int, wchar_t); 395c5604d0aSTim J. Robbins 396ce2551adSDavid Schultz #endif /* !NO_FLOATING_POINT */ 397c5604d0aSTim J. Robbins 39838cac8f8SDavid Schultz /* 39938cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer 40038cac8f8SDavid Schultz * conversions, among other things. Technically, we would need the 40138cac8f8SDavid Schultz * most space for base 10 conversions with thousands' grouping 40238cac8f8SDavid Schultz * characters between each pair of digits. 100 bytes is a 40338cac8f8SDavid Schultz * conservative overestimate even for a 128-bit uintmax_t. 40438cac8f8SDavid Schultz */ 40538cac8f8SDavid Schultz #define BUF 100 40638cac8f8SDavid Schultz 407c5604d0aSTim J. Robbins /* 408c5604d0aSTim J. Robbins * Non-MT-safe version 409c5604d0aSTim J. Robbins */ 410c5604d0aSTim J. Robbins int 411c5604d0aSTim J. Robbins __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) 412c5604d0aSTim J. Robbins { 413c5604d0aSTim J. Robbins wchar_t *fmt; /* format string */ 414c5604d0aSTim J. Robbins wchar_t ch; /* character from fmt */ 415adfd6b31STim J. Robbins int n, n2, n3; /* handy integer (short term usage) */ 416c5604d0aSTim J. Robbins wchar_t *cp; /* handy char pointer (short term usage) */ 417c5604d0aSTim J. Robbins int flags; /* flags as above */ 418c5604d0aSTim J. Robbins int ret; /* return value accumulator */ 419c5604d0aSTim J. Robbins int width; /* width from format (%8d), or 0 */ 420adfd6b31STim J. Robbins int prec; /* precision from format; <0 for N/A */ 421c5604d0aSTim J. Robbins wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */ 422c5604d0aSTim J. Robbins char thousands_sep; /* locale specific thousands separator */ 423c5604d0aSTim J. Robbins const char *grouping; /* locale specific numeric grouping rules */ 424ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 425adfd6b31STim J. Robbins /* 426adfd6b31STim J. Robbins * We can decompose the printed representation of floating 427adfd6b31STim J. Robbins * point numbers into several parts, some of which may be empty: 428adfd6b31STim J. Robbins * 429adfd6b31STim J. Robbins * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 430adfd6b31STim J. Robbins * A B ---C--- D E F 431adfd6b31STim J. Robbins * 432adfd6b31STim J. Robbins * A: 'sign' holds this value if present; '\0' otherwise 433adfd6b31STim J. Robbins * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 434adfd6b31STim J. Robbins * C: cp points to the string MMMNNN. Leading and trailing 435adfd6b31STim J. Robbins * zeros are not in the string and must be added. 436adfd6b31STim J. Robbins * D: expchar holds this character; '\0' if no exponent, e.g. %f 437adfd6b31STim J. Robbins * F: at least two digits for decimal, at least one digit for hex 438adfd6b31STim J. Robbins */ 439c5604d0aSTim J. Robbins char *decimal_point; /* locale specific decimal point */ 440adfd6b31STim J. Robbins int signflag; /* true if float is negative */ 441adfd6b31STim J. Robbins union { /* floating point arguments %[aAeEfFgG] */ 442adfd6b31STim J. Robbins double dbl; 443adfd6b31STim J. Robbins long double ldbl; 444adfd6b31STim J. Robbins } fparg; 445c5604d0aSTim J. Robbins int expt; /* integer value of exponent */ 446adfd6b31STim J. Robbins char expchar; /* exponent character: [eEpP\0] */ 447adfd6b31STim J. Robbins char *dtoaend; /* pointer to end of converted digits */ 448c5604d0aSTim J. Robbins int expsize; /* character count for expstr */ 449adfd6b31STim J. Robbins int lead; /* sig figs before decimal or group sep */ 450adfd6b31STim J. Robbins int ndig; /* actual number of digits returned by dtoa */ 451adfd6b31STim J. Robbins wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 452adfd6b31STim J. Robbins char *dtoaresult; /* buffer allocated by dtoa */ 453adfd6b31STim J. Robbins int nseps; /* number of group separators with ' */ 454adfd6b31STim J. Robbins int nrepeats; /* number of repeats of the last group */ 455c5604d0aSTim J. Robbins #endif 456c5604d0aSTim J. Robbins u_long ulval; /* integer arguments %[diouxX] */ 457c5604d0aSTim J. Robbins uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 458c5604d0aSTim J. Robbins int base; /* base for [diouxX] conversion */ 459c5604d0aSTim J. Robbins int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 460c5604d0aSTim J. Robbins int realsz; /* field size expanded by dprec, sign, etc */ 461c5604d0aSTim J. Robbins int size; /* size of converted field or string */ 462c5604d0aSTim J. Robbins int prsize; /* max size of printed field */ 4637b7e3509SDavid Schultz const char *xdigs; /* digits for [xX] conversion */ 46438cac8f8SDavid Schultz wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */ 465c5604d0aSTim J. Robbins wchar_t ox[2]; /* space for 0x hex-prefix */ 466c5604d0aSTim J. Robbins union arg *argtable; /* args, built due to positional arg */ 467c5604d0aSTim J. Robbins union arg statargtable [STATIC_ARG_TBL_SIZE]; 468c5604d0aSTim J. Robbins int nextarg; /* 1-based argument index */ 469c5604d0aSTim J. Robbins va_list orgap; /* original argument pointer */ 470c5604d0aSTim J. Robbins wchar_t *convbuf; /* multibyte to wide conversion result */ 471c5604d0aSTim J. Robbins 472c5604d0aSTim J. Robbins /* 473c5604d0aSTim J. Robbins * Choose PADSIZE to trade efficiency vs. size. If larger printf 474c5604d0aSTim J. Robbins * fields occur frequently, increase PADSIZE and make the initialisers 475c5604d0aSTim J. Robbins * below longer. 476c5604d0aSTim J. Robbins */ 477c5604d0aSTim J. Robbins #define PADSIZE 16 /* pad chunk size */ 478c5604d0aSTim J. Robbins static wchar_t blanks[PADSIZE] = 479c5604d0aSTim J. Robbins {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 480c5604d0aSTim J. Robbins static wchar_t zeroes[PADSIZE] = 481c5604d0aSTim J. Robbins {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 482c5604d0aSTim J. Robbins 4837b7e3509SDavid Schultz static const char xdigs_lower[16] = "0123456789abcdef"; 4847b7e3509SDavid Schultz static const char xdigs_upper[16] = "0123456789ABCDEF"; 485adfd6b31STim J. Robbins 486c5604d0aSTim J. Robbins /* 487c5604d0aSTim J. Robbins * BEWARE, these `goto error' on error, PRINT uses `n2' and 488c5604d0aSTim J. Robbins * PAD uses `n'. 489c5604d0aSTim J. Robbins */ 490c5604d0aSTim J. Robbins #define PRINT(ptr, len) do { \ 491adfd6b31STim J. Robbins for (n3 = 0; n3 < (len); n3++) \ 492909a17f4STim J. Robbins __xfputwc((ptr)[n3], fp); \ 493c5604d0aSTim J. Robbins } while (0) 494c5604d0aSTim J. Robbins #define PAD(howmany, with) do { \ 495c5604d0aSTim J. Robbins if ((n = (howmany)) > 0) { \ 496c5604d0aSTim J. Robbins while (n > PADSIZE) { \ 497c5604d0aSTim J. Robbins PRINT(with, PADSIZE); \ 498c5604d0aSTim J. Robbins n -= PADSIZE; \ 499c5604d0aSTim J. Robbins } \ 500c5604d0aSTim J. Robbins PRINT(with, n); \ 501c5604d0aSTim J. Robbins } \ 502c5604d0aSTim J. Robbins } while (0) 503adfd6b31STim J. Robbins #define PRINTANDPAD(p, ep, len, with) do { \ 504adfd6b31STim J. Robbins n2 = (ep) - (p); \ 505adfd6b31STim J. Robbins if (n2 > (len)) \ 506adfd6b31STim J. Robbins n2 = (len); \ 507adfd6b31STim J. Robbins if (n2 > 0) \ 508adfd6b31STim J. Robbins PRINT((p), n2); \ 509adfd6b31STim J. Robbins PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ 510adfd6b31STim J. Robbins } while(0) 511c5604d0aSTim J. Robbins 512c5604d0aSTim J. Robbins /* 513c5604d0aSTim J. Robbins * Get the argument indexed by nextarg. If the argument table is 514c5604d0aSTim J. Robbins * built, use it to get the argument. If its not, get the next 515c5604d0aSTim J. Robbins * argument (and arguments must be gotten sequentially). 516c5604d0aSTim J. Robbins */ 517c5604d0aSTim J. Robbins #define GETARG(type) \ 518c5604d0aSTim J. Robbins ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 519c5604d0aSTim J. Robbins (nextarg++, va_arg(ap, type))) 520c5604d0aSTim J. Robbins 521c5604d0aSTim J. Robbins /* 522c5604d0aSTim J. Robbins * To extend shorts properly, we need both signed and unsigned 523c5604d0aSTim J. Robbins * argument extraction methods. 524c5604d0aSTim J. Robbins */ 525c5604d0aSTim J. Robbins #define SARG() \ 526c5604d0aSTim J. Robbins (flags&LONGINT ? GETARG(long) : \ 527c5604d0aSTim J. Robbins flags&SHORTINT ? (long)(short)GETARG(int) : \ 528c5604d0aSTim J. Robbins flags&CHARINT ? (long)(signed char)GETARG(int) : \ 529c5604d0aSTim J. Robbins (long)GETARG(int)) 530c5604d0aSTim J. Robbins #define UARG() \ 531c5604d0aSTim J. Robbins (flags&LONGINT ? GETARG(u_long) : \ 532c5604d0aSTim J. Robbins flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 533c5604d0aSTim J. Robbins flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 534c5604d0aSTim J. Robbins (u_long)GETARG(u_int)) 535c5604d0aSTim J. Robbins #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 536c5604d0aSTim J. Robbins #define SJARG() \ 537c5604d0aSTim J. Robbins (flags&INTMAXT ? GETARG(intmax_t) : \ 538c5604d0aSTim J. Robbins flags&SIZET ? (intmax_t)GETARG(size_t) : \ 539c5604d0aSTim J. Robbins flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 540c5604d0aSTim J. Robbins (intmax_t)GETARG(long long)) 541c5604d0aSTim J. Robbins #define UJARG() \ 542c5604d0aSTim J. Robbins (flags&INTMAXT ? GETARG(uintmax_t) : \ 543c5604d0aSTim J. Robbins flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 544c5604d0aSTim J. Robbins flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 545c5604d0aSTim J. Robbins (uintmax_t)GETARG(unsigned long long)) 546c5604d0aSTim J. Robbins 547c5604d0aSTim J. Robbins /* 548c5604d0aSTim J. Robbins * Get * arguments, including the form *nn$. Preserve the nextarg 549c5604d0aSTim J. Robbins * that the argument can be gotten once the type is determined. 550c5604d0aSTim J. Robbins */ 551c5604d0aSTim J. Robbins #define GETASTER(val) \ 552c5604d0aSTim J. Robbins n2 = 0; \ 553c5604d0aSTim J. Robbins cp = fmt; \ 554c5604d0aSTim J. Robbins while (is_digit(*cp)) { \ 555c5604d0aSTim J. Robbins n2 = 10 * n2 + to_digit(*cp); \ 556c5604d0aSTim J. Robbins cp++; \ 557c5604d0aSTim J. Robbins } \ 558c5604d0aSTim J. Robbins if (*cp == '$') { \ 559c5604d0aSTim J. Robbins int hold = nextarg; \ 560c5604d0aSTim J. Robbins if (argtable == NULL) { \ 561c5604d0aSTim J. Robbins argtable = statargtable; \ 562e62e5ff9SDavid Schultz if (__find_warguments (fmt0, orgap, &argtable)) { \ 563e62e5ff9SDavid Schultz ret = EOF; \ 564e62e5ff9SDavid Schultz goto error; \ 565e62e5ff9SDavid Schultz } \ 566c5604d0aSTim J. Robbins } \ 567c5604d0aSTim J. Robbins nextarg = n2; \ 568c5604d0aSTim J. Robbins val = GETARG (int); \ 569c5604d0aSTim J. Robbins nextarg = hold; \ 570c5604d0aSTim J. Robbins fmt = ++cp; \ 571c5604d0aSTim J. Robbins } else { \ 572c5604d0aSTim J. Robbins val = GETARG (int); \ 573c5604d0aSTim J. Robbins } 574c5604d0aSTim J. Robbins 575c5604d0aSTim J. Robbins 576c5604d0aSTim J. Robbins thousands_sep = '\0'; 577c5604d0aSTim J. Robbins grouping = NULL; 578ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 579c5604d0aSTim J. Robbins decimal_point = localeconv()->decimal_point; 580c5604d0aSTim J. Robbins #endif 581c5604d0aSTim J. Robbins convbuf = NULL; 582c5604d0aSTim J. Robbins /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */ 58352183d46SDavid Schultz if (prepwrite(fp) != 0) 584c5604d0aSTim J. Robbins return (EOF); 585c5604d0aSTim J. Robbins 586c5604d0aSTim J. Robbins /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 587c5604d0aSTim J. Robbins if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 588c5604d0aSTim J. Robbins fp->_file >= 0) 589c5604d0aSTim J. Robbins return (__sbprintf(fp, fmt0, ap)); 590c5604d0aSTim J. Robbins 591c5604d0aSTim J. Robbins fmt = (wchar_t *)fmt0; 592c5604d0aSTim J. Robbins argtable = NULL; 593c5604d0aSTim J. Robbins nextarg = 1; 594d07090a8STim J. Robbins va_copy(orgap, ap); 595c5604d0aSTim J. Robbins ret = 0; 596c5604d0aSTim J. Robbins 597c5604d0aSTim J. Robbins /* 598c5604d0aSTim J. Robbins * Scan the format for conversions (`%' character). 599c5604d0aSTim J. Robbins */ 600c5604d0aSTim J. Robbins for (;;) { 601c5604d0aSTim J. Robbins for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 602c5604d0aSTim J. Robbins /* void */; 603c5604d0aSTim J. Robbins if ((n = fmt - cp) != 0) { 604c5604d0aSTim J. Robbins if ((unsigned)ret + n > INT_MAX) { 605c5604d0aSTim J. Robbins ret = EOF; 606c5604d0aSTim J. Robbins goto error; 607c5604d0aSTim J. Robbins } 608c5604d0aSTim J. Robbins PRINT(cp, n); 609c5604d0aSTim J. Robbins ret += n; 610c5604d0aSTim J. Robbins } 611c5604d0aSTim J. Robbins if (ch == '\0') 612c5604d0aSTim J. Robbins goto done; 613c5604d0aSTim J. Robbins fmt++; /* skip over '%' */ 614c5604d0aSTim J. Robbins 615c5604d0aSTim J. Robbins flags = 0; 616c5604d0aSTim J. Robbins dprec = 0; 617c5604d0aSTim J. Robbins width = 0; 618c5604d0aSTim J. Robbins prec = -1; 619c5604d0aSTim J. Robbins sign = '\0'; 620adfd6b31STim J. Robbins ox[1] = '\0'; 621c5604d0aSTim J. Robbins 622c5604d0aSTim J. Robbins rflag: ch = *fmt++; 623c5604d0aSTim J. Robbins reswitch: switch (ch) { 624c5604d0aSTim J. Robbins case ' ': 625c5604d0aSTim J. Robbins /*- 626c5604d0aSTim J. Robbins * ``If the space and + flags both appear, the space 627c5604d0aSTim J. Robbins * flag will be ignored.'' 628c5604d0aSTim J. Robbins * -- ANSI X3J11 629c5604d0aSTim J. Robbins */ 630c5604d0aSTim J. Robbins if (!sign) 631c5604d0aSTim J. Robbins sign = ' '; 632c5604d0aSTim J. Robbins goto rflag; 633c5604d0aSTim J. Robbins case '#': 634c5604d0aSTim J. Robbins flags |= ALT; 635c5604d0aSTim J. Robbins goto rflag; 636c5604d0aSTim J. Robbins case '*': 637c5604d0aSTim J. Robbins /*- 638c5604d0aSTim J. Robbins * ``A negative field width argument is taken as a 639c5604d0aSTim J. Robbins * - flag followed by a positive field width.'' 640c5604d0aSTim J. Robbins * -- ANSI X3J11 641c5604d0aSTim J. Robbins * They don't exclude field widths read from args. 642c5604d0aSTim J. Robbins */ 643c5604d0aSTim J. Robbins GETASTER (width); 644c5604d0aSTim J. Robbins if (width >= 0) 645c5604d0aSTim J. Robbins goto rflag; 646c5604d0aSTim J. Robbins width = -width; 647c5604d0aSTim J. Robbins /* FALLTHROUGH */ 648c5604d0aSTim J. Robbins case '-': 649c5604d0aSTim J. Robbins flags |= LADJUST; 650c5604d0aSTim J. Robbins goto rflag; 651c5604d0aSTim J. Robbins case '+': 652c5604d0aSTim J. Robbins sign = '+'; 653c5604d0aSTim J. Robbins goto rflag; 654c5604d0aSTim J. Robbins case '\'': 655c5604d0aSTim J. Robbins flags |= GROUPING; 656c5604d0aSTim J. Robbins thousands_sep = *(localeconv()->thousands_sep); 657c5604d0aSTim J. Robbins grouping = localeconv()->grouping; 658c5604d0aSTim J. Robbins goto rflag; 659c5604d0aSTim J. Robbins case '.': 660c5604d0aSTim J. Robbins if ((ch = *fmt++) == '*') { 661adfd6b31STim J. Robbins GETASTER (prec); 662c5604d0aSTim J. Robbins goto rflag; 663c5604d0aSTim J. Robbins } 664adfd6b31STim J. Robbins prec = 0; 665c5604d0aSTim J. Robbins while (is_digit(ch)) { 666adfd6b31STim J. Robbins prec = 10 * prec + to_digit(ch); 667c5604d0aSTim J. Robbins ch = *fmt++; 668c5604d0aSTim J. Robbins } 669c5604d0aSTim J. Robbins goto reswitch; 670c5604d0aSTim J. Robbins case '0': 671c5604d0aSTim J. Robbins /*- 672c5604d0aSTim J. Robbins * ``Note that 0 is taken as a flag, not as the 673c5604d0aSTim J. Robbins * beginning of a field width.'' 674c5604d0aSTim J. Robbins * -- ANSI X3J11 675c5604d0aSTim J. Robbins */ 676c5604d0aSTim J. Robbins flags |= ZEROPAD; 677c5604d0aSTim J. Robbins goto rflag; 678c5604d0aSTim J. Robbins case '1': case '2': case '3': case '4': 679c5604d0aSTim J. Robbins case '5': case '6': case '7': case '8': case '9': 680c5604d0aSTim J. Robbins n = 0; 681c5604d0aSTim J. Robbins do { 682c5604d0aSTim J. Robbins n = 10 * n + to_digit(ch); 683c5604d0aSTim J. Robbins ch = *fmt++; 684c5604d0aSTim J. Robbins } while (is_digit(ch)); 685c5604d0aSTim J. Robbins if (ch == '$') { 686c5604d0aSTim J. Robbins nextarg = n; 687c5604d0aSTim J. Robbins if (argtable == NULL) { 688c5604d0aSTim J. Robbins argtable = statargtable; 689e62e5ff9SDavid Schultz if (__find_warguments (fmt0, orgap, 690e62e5ff9SDavid Schultz &argtable)) { 691e62e5ff9SDavid Schultz ret = EOF; 692e62e5ff9SDavid Schultz goto error; 693e62e5ff9SDavid Schultz } 694c5604d0aSTim J. Robbins } 695c5604d0aSTim J. Robbins goto rflag; 696c5604d0aSTim J. Robbins } 697c5604d0aSTim J. Robbins width = n; 698c5604d0aSTim J. Robbins goto reswitch; 699ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 700c5604d0aSTim J. Robbins case 'L': 701c5604d0aSTim J. Robbins flags |= LONGDBL; 702c5604d0aSTim J. Robbins goto rflag; 703c5604d0aSTim J. Robbins #endif 704c5604d0aSTim J. Robbins case 'h': 705c5604d0aSTim J. Robbins if (flags & SHORTINT) { 706c5604d0aSTim J. Robbins flags &= ~SHORTINT; 707c5604d0aSTim J. Robbins flags |= CHARINT; 708c5604d0aSTim J. Robbins } else 709c5604d0aSTim J. Robbins flags |= SHORTINT; 710c5604d0aSTim J. Robbins goto rflag; 711c5604d0aSTim J. Robbins case 'j': 712c5604d0aSTim J. Robbins flags |= INTMAXT; 713c5604d0aSTim J. Robbins goto rflag; 714c5604d0aSTim J. Robbins case 'l': 715c5604d0aSTim J. Robbins if (flags & LONGINT) { 716c5604d0aSTim J. Robbins flags &= ~LONGINT; 717c5604d0aSTim J. Robbins flags |= LLONGINT; 718c5604d0aSTim J. Robbins } else 719c5604d0aSTim J. Robbins flags |= LONGINT; 720c5604d0aSTim J. Robbins goto rflag; 721c5604d0aSTim J. Robbins case 'q': 722c5604d0aSTim J. Robbins flags |= LLONGINT; /* not necessarily */ 723c5604d0aSTim J. Robbins goto rflag; 724c5604d0aSTim J. Robbins case 't': 725c5604d0aSTim J. Robbins flags |= PTRDIFFT; 726c5604d0aSTim J. Robbins goto rflag; 727c5604d0aSTim J. Robbins case 'z': 728c5604d0aSTim J. Robbins flags |= SIZET; 729c5604d0aSTim J. Robbins goto rflag; 730927ecbf3STim J. Robbins case 'C': 731927ecbf3STim J. Robbins flags |= LONGINT; 732927ecbf3STim J. Robbins /*FALLTHROUGH*/ 733c5604d0aSTim J. Robbins case 'c': 734c5604d0aSTim J. Robbins if (flags & LONGINT) 735c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)GETARG(wint_t); 736c5604d0aSTim J. Robbins else 737c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)btowc(GETARG(int)); 738c5604d0aSTim J. Robbins size = 1; 739c5604d0aSTim J. Robbins sign = '\0'; 740c5604d0aSTim J. Robbins break; 741c5604d0aSTim J. Robbins case 'D': 742c5604d0aSTim J. Robbins flags |= LONGINT; 743c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 744c5604d0aSTim J. Robbins case 'd': 745c5604d0aSTim J. Robbins case 'i': 746c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 747c5604d0aSTim J. Robbins ujval = SJARG(); 748c5604d0aSTim J. Robbins if ((intmax_t)ujval < 0) { 749c5604d0aSTim J. Robbins ujval = -ujval; 750c5604d0aSTim J. Robbins sign = '-'; 751c5604d0aSTim J. Robbins } 752c5604d0aSTim J. Robbins } else { 753c5604d0aSTim J. Robbins ulval = SARG(); 754c5604d0aSTim J. Robbins if ((long)ulval < 0) { 755c5604d0aSTim J. Robbins ulval = -ulval; 756c5604d0aSTim J. Robbins sign = '-'; 757c5604d0aSTim J. Robbins } 758c5604d0aSTim J. Robbins } 759c5604d0aSTim J. Robbins base = 10; 760c5604d0aSTim J. Robbins goto number; 761ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 762c5604d0aSTim J. Robbins case 'a': 763c5604d0aSTim J. Robbins case 'A': 764adfd6b31STim J. Robbins if (ch == 'a') { 765adfd6b31STim J. Robbins ox[1] = 'x'; 766adfd6b31STim J. Robbins xdigs = xdigs_lower; 767adfd6b31STim J. Robbins expchar = 'p'; 768adfd6b31STim J. Robbins } else { 769adfd6b31STim J. Robbins ox[1] = 'X'; 770adfd6b31STim J. Robbins xdigs = xdigs_upper; 771adfd6b31STim J. Robbins expchar = 'P'; 772adfd6b31STim J. Robbins } 7737b7e3509SDavid Schultz if (prec >= 0) 7747b7e3509SDavid Schultz prec++; 775adfd6b31STim J. Robbins if (flags & LONGDBL) { 7767b7e3509SDavid Schultz fparg.ldbl = GETARG(long double); 777adfd6b31STim J. Robbins dtoaresult = 778adfd6b31STim J. Robbins __hldtoa(fparg.ldbl, xdigs, 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 __hdtoa(fparg.dbl, xdigs, prec, 784adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 785adfd6b31STim J. Robbins } 7867b7e3509SDavid Schultz if (prec < 0) 7877b7e3509SDavid Schultz prec = dtoaend - dtoaresult; 7887b7e3509SDavid Schultz if (expt == INT_MAX) 7897b7e3509SDavid Schultz ox[1] = '\0'; 790adfd6b31STim J. Robbins if (convbuf != NULL) 791adfd6b31STim J. Robbins free(convbuf); 7927b7e3509SDavid Schultz ndig = dtoaend - dtoaresult; 793adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 794adfd6b31STim J. Robbins freedtoa(dtoaresult); 7957b7e3509SDavid Schultz goto fp_common; 796c5604d0aSTim J. Robbins case 'e': 797c5604d0aSTim J. Robbins case 'E': 798adfd6b31STim J. Robbins expchar = ch; 799adfd6b31STim J. Robbins if (prec < 0) /* account for digit before decpt */ 800adfd6b31STim J. Robbins prec = DEFPREC + 1; 801adfd6b31STim J. Robbins else 802adfd6b31STim J. Robbins prec++; 803adfd6b31STim J. Robbins goto fp_begin; 804c5604d0aSTim J. Robbins case 'f': 805c5604d0aSTim J. Robbins case 'F': 806adfd6b31STim J. Robbins expchar = '\0'; 807c5604d0aSTim J. Robbins goto fp_begin; 808c5604d0aSTim J. Robbins case 'g': 809c5604d0aSTim J. Robbins case 'G': 810adfd6b31STim J. Robbins expchar = ch - ('g' - 'e'); 811c5604d0aSTim J. Robbins if (prec == 0) 812c5604d0aSTim J. Robbins prec = 1; 813adfd6b31STim J. Robbins fp_begin: 814adfd6b31STim J. Robbins if (prec < 0) 815c5604d0aSTim J. Robbins prec = DEFPREC; 816adfd6b31STim J. Robbins if (convbuf != NULL) 817adfd6b31STim J. Robbins free(convbuf); 818adfd6b31STim J. Robbins if (flags & LONGDBL) { 819adfd6b31STim J. Robbins fparg.ldbl = GETARG(long double); 820adfd6b31STim J. Robbins dtoaresult = 821adfd6b31STim J. Robbins __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 822adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 823adfd6b31STim J. Robbins } else { 824adfd6b31STim J. Robbins fparg.dbl = GETARG(double); 825adfd6b31STim J. Robbins dtoaresult = 826adfd6b31STim J. Robbins dtoa(fparg.dbl, expchar ? 2 : 3, prec, 827adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 828adfd6b31STim J. Robbins if (expt == 9999) 829adfd6b31STim J. Robbins expt = INT_MAX; 830c5604d0aSTim J. Robbins } 831adfd6b31STim J. Robbins ndig = dtoaend - dtoaresult; 832adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 833adfd6b31STim J. Robbins freedtoa(dtoaresult); 8347b7e3509SDavid Schultz fp_common: 835adfd6b31STim J. Robbins if (signflag) 836adfd6b31STim J. Robbins sign = '-'; 837adfd6b31STim J. Robbins if (expt == INT_MAX) { /* inf or nan */ 838adfd6b31STim J. Robbins if (*cp == 'N') { 839adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"nan" : L"NAN"; 840adfd6b31STim J. Robbins sign = '\0'; 841adfd6b31STim J. Robbins } else 842adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"inf" : L"INF"; 843c5604d0aSTim J. Robbins size = 3; 8448da510f8SDavid Schultz flags &= ~ZEROPAD; 845c5604d0aSTim J. Robbins break; 846c5604d0aSTim J. Robbins } 847c5604d0aSTim J. Robbins flags |= FPT; 848c5604d0aSTim J. Robbins if (ch == 'g' || ch == 'G') { 849adfd6b31STim J. Robbins if (expt > -4 && expt <= prec) { 850adfd6b31STim J. Robbins /* Make %[gG] smell like %[fF] */ 851adfd6b31STim J. Robbins expchar = '\0'; 852adfd6b31STim J. Robbins if (flags & ALT) 853adfd6b31STim J. Robbins prec -= expt; 854c5604d0aSTim J. Robbins else 855adfd6b31STim J. Robbins prec = ndig - expt; 856adfd6b31STim J. Robbins if (prec < 0) 857adfd6b31STim J. Robbins prec = 0; 8581f2a0cdfSDavid Schultz } else { 8591f2a0cdfSDavid Schultz /* 8601f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but 8611f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag. 8621f2a0cdfSDavid Schultz */ 8631f2a0cdfSDavid Schultz if (!(flags & ALT)) 8641f2a0cdfSDavid Schultz prec = ndig; 865c5604d0aSTim J. Robbins } 866adfd6b31STim J. Robbins } 867adfd6b31STim J. Robbins if (expchar) { 868adfd6b31STim J. Robbins expsize = exponent(expstr, expt - 1, expchar); 869adfd6b31STim J. Robbins size = expsize + prec; 870adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) 871c5604d0aSTim J. Robbins ++size; 872adfd6b31STim J. Robbins } else { 873d73c448bSTim J. Robbins /* space for digits before decimal point */ 874d73c448bSTim J. Robbins if (expt > 0) 875c5604d0aSTim J. Robbins size = expt; 876d73c448bSTim J. Robbins else /* "0" */ 877d73c448bSTim J. Robbins size = 1; 878d73c448bSTim J. Robbins /* space for decimal pt and following digits */ 879c5604d0aSTim J. Robbins if (prec || flags & ALT) 880c5604d0aSTim J. Robbins size += prec + 1; 881adfd6b31STim J. Robbins if (grouping && expt > 0) { 882adfd6b31STim J. Robbins /* space for thousands' grouping */ 883adfd6b31STim J. Robbins nseps = nrepeats = 0; 884adfd6b31STim J. Robbins lead = expt; 885adfd6b31STim J. Robbins while (*grouping != CHAR_MAX) { 886adfd6b31STim J. Robbins if (lead <= *grouping) 887adfd6b31STim J. Robbins break; 888adfd6b31STim J. Robbins lead -= *grouping; 889adfd6b31STim J. Robbins if (*(grouping+1)) { 890adfd6b31STim J. Robbins nseps++; 891adfd6b31STim J. Robbins grouping++; 892c5604d0aSTim J. Robbins } else 893adfd6b31STim J. Robbins nrepeats++; 894adfd6b31STim J. Robbins } 895adfd6b31STim J. Robbins size += nseps + nrepeats; 896adfd6b31STim J. Robbins } else 897adfd6b31STim J. Robbins lead = expt; 898adfd6b31STim J. Robbins } 899c5604d0aSTim J. Robbins break; 900ce2551adSDavid Schultz #endif /* !NO_FLOATING_POINT */ 901c5604d0aSTim J. Robbins case 'n': 902c5604d0aSTim J. Robbins /* 903c5604d0aSTim J. Robbins * Assignment-like behavior is specified if the 904c5604d0aSTim J. Robbins * value overflows or is otherwise unrepresentable. 905c5604d0aSTim J. Robbins * C99 says to use `signed char' for %hhn conversions. 906c5604d0aSTim J. Robbins */ 907c5604d0aSTim J. Robbins if (flags & LLONGINT) 908c5604d0aSTim J. Robbins *GETARG(long long *) = ret; 909c5604d0aSTim J. Robbins else if (flags & SIZET) 910c5604d0aSTim J. Robbins *GETARG(ssize_t *) = (ssize_t)ret; 911c5604d0aSTim J. Robbins else if (flags & PTRDIFFT) 912c5604d0aSTim J. Robbins *GETARG(ptrdiff_t *) = ret; 913c5604d0aSTim J. Robbins else if (flags & INTMAXT) 914c5604d0aSTim J. Robbins *GETARG(intmax_t *) = ret; 915c5604d0aSTim J. Robbins else if (flags & LONGINT) 916c5604d0aSTim J. Robbins *GETARG(long *) = ret; 917c5604d0aSTim J. Robbins else if (flags & SHORTINT) 918c5604d0aSTim J. Robbins *GETARG(short *) = ret; 919c5604d0aSTim J. Robbins else if (flags & CHARINT) 920c5604d0aSTim J. Robbins *GETARG(signed char *) = ret; 921c5604d0aSTim J. Robbins else 922c5604d0aSTim J. Robbins *GETARG(int *) = ret; 923c5604d0aSTim J. Robbins continue; /* no output */ 924c5604d0aSTim J. Robbins case 'O': 925c5604d0aSTim J. Robbins flags |= LONGINT; 926c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 927c5604d0aSTim J. Robbins case 'o': 928c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 929c5604d0aSTim J. Robbins ujval = UJARG(); 930c5604d0aSTim J. Robbins else 931c5604d0aSTim J. Robbins ulval = UARG(); 932c5604d0aSTim J. Robbins base = 8; 933c5604d0aSTim J. Robbins goto nosign; 934c5604d0aSTim J. Robbins case 'p': 935c5604d0aSTim J. Robbins /*- 936c5604d0aSTim J. Robbins * ``The argument shall be a pointer to void. The 937c5604d0aSTim J. Robbins * value of the pointer is converted to a sequence 938c5604d0aSTim J. Robbins * of printable characters, in an implementation- 939c5604d0aSTim J. Robbins * defined manner.'' 940c5604d0aSTim J. Robbins * -- ANSI X3J11 941c5604d0aSTim J. Robbins */ 942c5604d0aSTim J. Robbins ujval = (uintmax_t)(uintptr_t)GETARG(void *); 943c5604d0aSTim J. Robbins base = 16; 944adfd6b31STim J. Robbins xdigs = xdigs_lower; 945adfd6b31STim J. Robbins flags = flags | INTMAXT; 946adfd6b31STim J. Robbins ox[1] = 'x'; 947c5604d0aSTim J. Robbins goto nosign; 948927ecbf3STim J. Robbins case 'S': 949927ecbf3STim J. Robbins flags |= LONGINT; 950927ecbf3STim J. Robbins /*FALLTHROUGH*/ 951c5604d0aSTim J. Robbins case 's': 952c5604d0aSTim J. Robbins if (flags & LONGINT) { 953c5604d0aSTim J. Robbins if ((cp = GETARG(wchar_t *)) == NULL) 954c5604d0aSTim J. Robbins cp = L"(null)"; 955c5604d0aSTim J. Robbins } else { 956c5604d0aSTim J. Robbins char *mbp; 957c5604d0aSTim J. Robbins 958c5604d0aSTim J. Robbins if (convbuf != NULL) 959c5604d0aSTim J. Robbins free(convbuf); 960c5604d0aSTim J. Robbins if ((mbp = GETARG(char *)) == NULL) 961c5604d0aSTim J. Robbins cp = L"(null)"; 962c5604d0aSTim J. Robbins else { 963c5604d0aSTim J. Robbins convbuf = __mbsconv(mbp, prec); 9646180233fSTim J. Robbins if (convbuf == NULL) { 9656180233fSTim J. Robbins fp->_flags |= __SERR; 966c5604d0aSTim J. Robbins goto error; 9676180233fSTim J. Robbins } 968c5604d0aSTim J. Robbins cp = convbuf; 969c5604d0aSTim J. Robbins } 970c5604d0aSTim J. Robbins } 971c5604d0aSTim J. Robbins 972c5604d0aSTim J. Robbins if (prec >= 0) { 973c5604d0aSTim J. Robbins /* 974c5604d0aSTim J. Robbins * can't use wcslen; can only look for the 975c5604d0aSTim J. Robbins * NUL in the first `prec' characters, and 976c5604d0aSTim J. Robbins * wcslen() will go further. 977c5604d0aSTim J. Robbins */ 978c5604d0aSTim J. Robbins wchar_t *p = wmemchr(cp, 0, (size_t)prec); 979c5604d0aSTim J. Robbins 980c5604d0aSTim J. Robbins if (p != NULL) { 981c5604d0aSTim J. Robbins size = p - cp; 982c5604d0aSTim J. Robbins if (size > prec) 983c5604d0aSTim J. Robbins size = prec; 984c5604d0aSTim J. Robbins } else 985c5604d0aSTim J. Robbins size = prec; 986c5604d0aSTim J. Robbins } else 987c5604d0aSTim J. Robbins size = wcslen(cp); 988c5604d0aSTim J. Robbins sign = '\0'; 989c5604d0aSTim J. Robbins break; 990c5604d0aSTim J. Robbins case 'U': 991c5604d0aSTim J. Robbins flags |= LONGINT; 992c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 993c5604d0aSTim J. Robbins case 'u': 994c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 995c5604d0aSTim J. Robbins ujval = UJARG(); 996c5604d0aSTim J. Robbins else 997c5604d0aSTim J. Robbins ulval = UARG(); 998c5604d0aSTim J. Robbins base = 10; 999c5604d0aSTim J. Robbins goto nosign; 1000c5604d0aSTim J. Robbins case 'X': 1001adfd6b31STim J. Robbins xdigs = xdigs_upper; 1002c5604d0aSTim J. Robbins goto hex; 1003c5604d0aSTim J. Robbins case 'x': 1004adfd6b31STim J. Robbins xdigs = xdigs_lower; 1005c5604d0aSTim J. Robbins hex: 1006c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 1007c5604d0aSTim J. Robbins ujval = UJARG(); 1008c5604d0aSTim J. Robbins else 1009c5604d0aSTim J. Robbins ulval = UARG(); 1010c5604d0aSTim J. Robbins base = 16; 1011c5604d0aSTim J. Robbins /* leading 0x/X only if non-zero */ 1012c5604d0aSTim J. Robbins if (flags & ALT && 1013c5604d0aSTim J. Robbins (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 1014adfd6b31STim J. Robbins ox[1] = ch; 1015c5604d0aSTim J. Robbins 1016c5604d0aSTim J. Robbins flags &= ~GROUPING; 1017c5604d0aSTim J. Robbins /* unsigned conversions */ 1018c5604d0aSTim J. Robbins nosign: sign = '\0'; 1019c5604d0aSTim J. Robbins /*- 1020c5604d0aSTim J. Robbins * ``... diouXx conversions ... if a precision is 1021c5604d0aSTim J. Robbins * specified, the 0 flag will be ignored.'' 1022c5604d0aSTim J. Robbins * -- ANSI X3J11 1023c5604d0aSTim J. Robbins */ 1024c5604d0aSTim J. Robbins number: if ((dprec = prec) >= 0) 1025c5604d0aSTim J. Robbins flags &= ~ZEROPAD; 1026c5604d0aSTim J. Robbins 1027c5604d0aSTim J. Robbins /*- 1028c5604d0aSTim J. Robbins * ``The result of converting a zero value with an 1029c5604d0aSTim J. Robbins * explicit precision of zero is no characters.'' 1030c5604d0aSTim J. Robbins * -- ANSI X3J11 10311be5319aSDavid Schultz * 10321be5319aSDavid Schultz * ``The C Standard is clear enough as is. The call 10331be5319aSDavid Schultz * printf("%#.0o", 0) should print 0.'' 10341be5319aSDavid Schultz * -- Defect Report #151 1035c5604d0aSTim J. Robbins */ 1036c5604d0aSTim J. Robbins cp = buf + BUF; 1037c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 10381be5319aSDavid Schultz if (ujval != 0 || prec != 0 || 10391be5319aSDavid Schultz (flags & ALT && base == 8)) 1040c5604d0aSTim J. Robbins cp = __ujtoa(ujval, cp, base, 1041c5604d0aSTim J. Robbins flags & ALT, xdigs, 1042c5604d0aSTim J. Robbins flags & GROUPING, thousands_sep, 1043c5604d0aSTim J. Robbins grouping); 1044c5604d0aSTim J. Robbins } else { 10451be5319aSDavid Schultz if (ulval != 0 || prec != 0 || 10461be5319aSDavid Schultz (flags & ALT && base == 8)) 1047c5604d0aSTim J. Robbins cp = __ultoa(ulval, cp, base, 1048c5604d0aSTim J. Robbins flags & ALT, xdigs, 1049c5604d0aSTim J. Robbins flags & GROUPING, thousands_sep, 1050c5604d0aSTim J. Robbins grouping); 1051c5604d0aSTim J. Robbins } 1052c5604d0aSTim J. Robbins size = buf + BUF - cp; 105338cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 105438cac8f8SDavid Schultz abort(); 1055c5604d0aSTim J. Robbins break; 1056c5604d0aSTim J. Robbins default: /* "%?" prints ?, unless ? is NUL */ 1057c5604d0aSTim J. Robbins if (ch == '\0') 1058c5604d0aSTim J. Robbins goto done; 1059c5604d0aSTim J. Robbins /* pretend it was %c with argument ch */ 1060c5604d0aSTim J. Robbins cp = buf; 1061c5604d0aSTim J. Robbins *cp = ch; 1062c5604d0aSTim J. Robbins size = 1; 1063c5604d0aSTim J. Robbins sign = '\0'; 1064c5604d0aSTim J. Robbins break; 1065c5604d0aSTim J. Robbins } 1066c5604d0aSTim J. Robbins 1067c5604d0aSTim J. Robbins /* 1068c5604d0aSTim J. Robbins * All reasonable formats wind up here. At this point, `cp' 1069c5604d0aSTim J. Robbins * points to a string which (if not flags&LADJUST) should be 1070c5604d0aSTim J. Robbins * padded out to `width' places. If flags&ZEROPAD, it should 1071c5604d0aSTim J. Robbins * first be prefixed by any sign or other prefix; otherwise, 1072c5604d0aSTim J. Robbins * it should be blank padded before the prefix is emitted. 1073c5604d0aSTim J. Robbins * After any left-hand padding and prefixing, emit zeroes 1074c5604d0aSTim J. Robbins * required by a decimal [diouxX] precision, then print the 1075c5604d0aSTim J. Robbins * string proper, then emit zeroes required by any leftover 1076c5604d0aSTim J. Robbins * floating precision; finally, if LADJUST, pad with blanks. 1077c5604d0aSTim J. Robbins * 1078c5604d0aSTim J. Robbins * Compute actual size, so we know how much to pad. 1079c5604d0aSTim J. Robbins * size excludes decimal prec; realsz includes it. 1080c5604d0aSTim J. Robbins */ 1081c5604d0aSTim J. Robbins realsz = dprec > size ? dprec : size; 1082c5604d0aSTim J. Robbins if (sign) 1083c5604d0aSTim J. Robbins realsz++; 10847b7e3509SDavid Schultz if (ox[1]) 1085c5604d0aSTim J. Robbins realsz += 2; 1086c5604d0aSTim J. Robbins 1087c5604d0aSTim J. Robbins prsize = width > realsz ? width : realsz; 1088c5604d0aSTim J. Robbins if ((unsigned)ret + prsize > INT_MAX) { 1089c5604d0aSTim J. Robbins ret = EOF; 1090c5604d0aSTim J. Robbins goto error; 1091c5604d0aSTim J. Robbins } 1092c5604d0aSTim J. Robbins 1093c5604d0aSTim J. Robbins /* right-adjusting blank padding */ 1094c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == 0) 1095c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1096c5604d0aSTim J. Robbins 1097c5604d0aSTim J. Robbins /* prefix */ 10987b7e3509SDavid Schultz if (sign) 1099c5604d0aSTim J. Robbins PRINT(&sign, 1); 11007b7e3509SDavid Schultz 11017b7e3509SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */ 1102c5604d0aSTim J. Robbins ox[0] = '0'; 1103c5604d0aSTim J. Robbins PRINT(ox, 2); 1104c5604d0aSTim J. Robbins } 1105c5604d0aSTim J. Robbins 1106c5604d0aSTim J. Robbins /* right-adjusting zero padding */ 1107c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 1108c5604d0aSTim J. Robbins PAD(width - realsz, zeroes); 1109c5604d0aSTim J. Robbins 1110c5604d0aSTim J. Robbins /* leading zeroes from decimal precision */ 1111c5604d0aSTim J. Robbins PAD(dprec - size, zeroes); 1112c5604d0aSTim J. Robbins 1113c5604d0aSTim J. Robbins /* the string or number proper */ 1114ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 1115c5604d0aSTim J. Robbins if ((flags & FPT) == 0) { 1116c5604d0aSTim J. Robbins PRINT(cp, size); 1117c5604d0aSTim J. Robbins } else { /* glue together f_p fragments */ 1118adfd6b31STim J. Robbins if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1119adfd6b31STim J. Robbins if (expt <= 0) { 1120d73c448bSTim J. Robbins PRINT(zeroes, 1); 1121d73c448bSTim J. Robbins if (prec || flags & ALT) 1122d73c448bSTim J. Robbins PRINT(decimal_point, 1); 1123c5604d0aSTim J. Robbins PAD(-expt, zeroes); 1124adfd6b31STim J. Robbins /* already handled initial 0's */ 1125adfd6b31STim J. Robbins prec += expt; 1126c5604d0aSTim J. Robbins } else { 1127adfd6b31STim J. Robbins PRINTANDPAD(cp, convbuf + ndig, lead, zeroes); 1128adfd6b31STim J. Robbins cp += lead; 1129adfd6b31STim J. Robbins if (grouping) { 1130adfd6b31STim J. Robbins while (nseps>0 || nrepeats>0) { 1131adfd6b31STim J. Robbins if (nrepeats > 0) 1132adfd6b31STim J. Robbins nrepeats--; 1133adfd6b31STim J. Robbins else { 1134adfd6b31STim J. Robbins grouping--; 1135adfd6b31STim J. Robbins nseps--; 1136c5604d0aSTim J. Robbins } 1137adfd6b31STim J. Robbins PRINT(&thousands_sep, 1138adfd6b31STim J. Robbins 1); 1139adfd6b31STim J. Robbins PRINTANDPAD(cp, 1140adfd6b31STim J. Robbins convbuf + ndig, 1141adfd6b31STim J. Robbins *grouping, zeroes); 1142adfd6b31STim J. Robbins cp += *grouping; 1143adfd6b31STim J. Robbins } 1144adfd6b31STim J. Robbins if (cp > convbuf + ndig) 1145adfd6b31STim J. Robbins cp = convbuf + ndig; 1146adfd6b31STim J. Robbins } 1147adfd6b31STim J. Robbins if (prec || flags & ALT) { 1148adfd6b31STim J. Robbins buf[0] = *decimal_point; 1149adfd6b31STim J. Robbins PRINT(buf, 1); 1150adfd6b31STim J. Robbins } 1151adfd6b31STim J. Robbins } 1152adfd6b31STim J. Robbins PRINTANDPAD(cp, convbuf + ndig, prec, zeroes); 1153adfd6b31STim J. Robbins } else { /* %[eE] or sufficiently long %[gG] */ 1154adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) { 1155adfd6b31STim J. Robbins buf[0] = *cp++; 1156adfd6b31STim J. Robbins buf[1] = *decimal_point; 1157adfd6b31STim J. Robbins PRINT(buf, 2); 1158c5604d0aSTim J. Robbins PRINT(cp, ndig-1); 1159adfd6b31STim J. Robbins PAD(prec - ndig, zeroes); 1160c5604d0aSTim J. Robbins } else /* XeYYY */ 1161c5604d0aSTim J. Robbins PRINT(cp, 1); 1162c5604d0aSTim J. Robbins PRINT(expstr, expsize); 1163c5604d0aSTim J. Robbins } 1164c5604d0aSTim J. Robbins } 1165c5604d0aSTim J. Robbins #else 1166c5604d0aSTim J. Robbins PRINT(cp, size); 1167c5604d0aSTim J. Robbins #endif 1168c5604d0aSTim J. Robbins /* left-adjusting padding (always blank) */ 1169c5604d0aSTim J. Robbins if (flags & LADJUST) 1170c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1171c5604d0aSTim J. Robbins 1172c5604d0aSTim J. Robbins /* finally, adjust ret */ 1173c5604d0aSTim J. Robbins ret += prsize; 1174c5604d0aSTim J. Robbins } 1175c5604d0aSTim J. Robbins done: 1176c5604d0aSTim J. Robbins error: 1177096ad104SDag-Erling Smørgrav va_end(orgap); 1178c5604d0aSTim J. Robbins if (convbuf != NULL) 1179c5604d0aSTim J. Robbins free(convbuf); 1180c5604d0aSTim J. Robbins if (__sferror(fp)) 1181c5604d0aSTim J. Robbins ret = EOF; 1182c5604d0aSTim J. Robbins if ((argtable != NULL) && (argtable != statargtable)) 1183c5604d0aSTim J. Robbins free (argtable); 1184c5604d0aSTim J. Robbins return (ret); 1185c5604d0aSTim J. Robbins /* NOTREACHED */ 1186c5604d0aSTim J. Robbins } 1187c5604d0aSTim J. Robbins 1188c5604d0aSTim J. Robbins 1189ce2551adSDavid Schultz #ifndef NO_FLOATING_POINT 1190c5604d0aSTim J. Robbins 1191c5604d0aSTim J. Robbins static int 1192c5604d0aSTim J. Robbins exponent(wchar_t *p0, int exp, wchar_t fmtch) 1193c5604d0aSTim J. Robbins { 1194c5604d0aSTim J. Robbins wchar_t *p, *t; 119538cac8f8SDavid Schultz wchar_t expbuf[MAXEXPDIG]; 1196c5604d0aSTim J. Robbins 1197c5604d0aSTim J. Robbins p = p0; 1198c5604d0aSTim J. Robbins *p++ = fmtch; 1199c5604d0aSTim J. Robbins if (exp < 0) { 1200c5604d0aSTim J. Robbins exp = -exp; 1201c5604d0aSTim J. Robbins *p++ = '-'; 1202c5604d0aSTim J. Robbins } 1203c5604d0aSTim J. Robbins else 1204c5604d0aSTim J. Robbins *p++ = '+'; 120538cac8f8SDavid Schultz t = expbuf + MAXEXPDIG; 1206c5604d0aSTim J. Robbins if (exp > 9) { 1207c5604d0aSTim J. Robbins do { 1208c5604d0aSTim J. Robbins *--t = to_char(exp % 10); 1209c5604d0aSTim J. Robbins } while ((exp /= 10) > 9); 1210c5604d0aSTim J. Robbins *--t = to_char(exp); 121138cac8f8SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 1212c5604d0aSTim J. Robbins } 1213c5604d0aSTim J. Robbins else { 1214adfd6b31STim J. Robbins /* 1215adfd6b31STim J. Robbins * Exponents for decimal floating point conversions 1216adfd6b31STim J. Robbins * (%[eEgG]) must be at least two characters long, 1217adfd6b31STim J. Robbins * whereas exponents for hexadecimal conversions can 1218adfd6b31STim J. Robbins * be only one character long. 1219adfd6b31STim J. Robbins */ 1220adfd6b31STim J. Robbins if (fmtch == 'e' || fmtch == 'E') 1221c5604d0aSTim J. Robbins *p++ = '0'; 1222c5604d0aSTim J. Robbins *p++ = to_char(exp); 1223c5604d0aSTim J. Robbins } 1224c5604d0aSTim J. Robbins return (p - p0); 1225c5604d0aSTim J. Robbins } 1226ce2551adSDavid Schultz #endif /* !NO_FLOATING_POINT */ 1227