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 * 3. All advertising materials mentioning features or use of this software 17c5604d0aSTim J. Robbins * must display the following acknowledgement: 18c5604d0aSTim J. Robbins * This product includes software developed by the University of 19c5604d0aSTim J. Robbins * California, Berkeley and its contributors. 20c5604d0aSTim J. Robbins * 4. Neither the name of the University nor the names of its contributors 21c5604d0aSTim J. Robbins * may be used to endorse or promote products derived from this software 22c5604d0aSTim J. Robbins * without specific prior written permission. 23c5604d0aSTim J. Robbins * 24c5604d0aSTim J. Robbins * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25c5604d0aSTim J. Robbins * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26c5604d0aSTim J. Robbins * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27c5604d0aSTim J. Robbins * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28c5604d0aSTim J. Robbins * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29c5604d0aSTim J. Robbins * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30c5604d0aSTim J. Robbins * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31c5604d0aSTim J. Robbins * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32c5604d0aSTim J. Robbins * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33c5604d0aSTim J. Robbins * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34c5604d0aSTim J. Robbins * SUCH DAMAGE. 35c5604d0aSTim J. Robbins */ 36c5604d0aSTim J. Robbins 37c5604d0aSTim J. Robbins #include <sys/cdefs.h> 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 */ 427b7e3509SDavid Schultz __FBSDID("FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.62 2004/01/18 10:32:49 das Exp"); 43c5604d0aSTim J. Robbins #endif 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> 57c5604d0aSTim J. Robbins #include <limits.h> 58c5604d0aSTim J. Robbins #include <locale.h> 59c5604d0aSTim J. Robbins #include <stdarg.h> 60c5604d0aSTim J. Robbins #include <stddef.h> 61c5604d0aSTim J. Robbins #include <stdint.h> 62c5604d0aSTim J. Robbins #include <stdio.h> 63c5604d0aSTim J. Robbins #include <stdlib.h> 64c5604d0aSTim J. Robbins #include <string.h> 65c5604d0aSTim J. Robbins #include <wchar.h> 66c5604d0aSTim J. Robbins #include <wctype.h> 67c5604d0aSTim J. Robbins #include "un-namespace.h" 68c5604d0aSTim J. Robbins 69c5604d0aSTim J. Robbins #include "libc_private.h" 70c5604d0aSTim J. Robbins #include "local.h" 71c5604d0aSTim J. Robbins #include "fvwrite.h" 72c5604d0aSTim J. Robbins 737b7e3509SDavid Schultz /* Define FLOATING_POINT to get floating point, HEXFLOAT to get %a. */ 74c5604d0aSTim J. Robbins #define FLOATING_POINT 757b7e3509SDavid Schultz #define HEXFLOAT 76c5604d0aSTim J. Robbins 77c5604d0aSTim J. Robbins union arg { 78c5604d0aSTim J. Robbins int intarg; 79c5604d0aSTim J. Robbins u_int uintarg; 80c5604d0aSTim J. Robbins long longarg; 81c5604d0aSTim J. Robbins u_long ulongarg; 82c5604d0aSTim J. Robbins long long longlongarg; 83c5604d0aSTim J. Robbins unsigned long long ulonglongarg; 84c5604d0aSTim J. Robbins ptrdiff_t ptrdiffarg; 85c5604d0aSTim J. Robbins size_t sizearg; 86c5604d0aSTim J. Robbins intmax_t intmaxarg; 87c5604d0aSTim J. Robbins uintmax_t uintmaxarg; 88c5604d0aSTim J. Robbins void *pvoidarg; 89c5604d0aSTim J. Robbins char *pchararg; 90c5604d0aSTim J. Robbins signed char *pschararg; 91c5604d0aSTim J. Robbins short *pshortarg; 92c5604d0aSTim J. Robbins int *pintarg; 93c5604d0aSTim J. Robbins long *plongarg; 94c5604d0aSTim J. Robbins long long *plonglongarg; 95c5604d0aSTim J. Robbins ptrdiff_t *pptrdiffarg; 96c5604d0aSTim J. Robbins size_t *psizearg; 97c5604d0aSTim J. Robbins intmax_t *pintmaxarg; 98c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 99c5604d0aSTim J. Robbins double doublearg; 100c5604d0aSTim J. Robbins long double longdoublearg; 101c5604d0aSTim J. Robbins #endif 102c5604d0aSTim J. Robbins wint_t wintarg; 103c5604d0aSTim J. Robbins wchar_t *pwchararg; 104c5604d0aSTim J. Robbins }; 105c5604d0aSTim J. Robbins 106c5604d0aSTim J. Robbins /* 107c5604d0aSTim J. Robbins * Type ids for argument type table. 108c5604d0aSTim J. Robbins */ 109c5604d0aSTim J. Robbins enum typeid { 110c5604d0aSTim J. Robbins T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, 111c5604d0aSTim J. Robbins T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, 112c5604d0aSTim J. Robbins T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, 113c5604d0aSTim J. Robbins T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, 114c5604d0aSTim J. Robbins T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR 115c5604d0aSTim J. Robbins }; 116c5604d0aSTim J. Robbins 117c5604d0aSTim J. Robbins static int __sbprintf(FILE *, const wchar_t *, va_list); 118909a17f4STim J. Robbins static wint_t __xfputwc(wchar_t, FILE *); 1197b7e3509SDavid Schultz static wchar_t *__ujtoa(uintmax_t, wchar_t *, int, int, const char *, int, 120adfd6b31STim J. Robbins char, const char *); 1217b7e3509SDavid Schultz static wchar_t *__ultoa(u_long, wchar_t *, int, int, const char *, int, 122adfd6b31STim J. Robbins char, const char *); 123c5604d0aSTim J. Robbins static wchar_t *__mbsconv(char *, int); 124c5604d0aSTim J. Robbins static void __find_arguments(const wchar_t *, va_list, union arg **); 125c5604d0aSTim J. Robbins static void __grow_type_table(int, enum typeid **, int *); 126c5604d0aSTim J. Robbins 127c5604d0aSTim J. Robbins /* 128c5604d0aSTim J. Robbins * Helper function for `fprintf to unbuffered unix file': creates a 129c5604d0aSTim J. Robbins * temporary buffer. We only work on write-only files; this avoids 130c5604d0aSTim J. Robbins * worries about ungetc buffers and so forth. 131c5604d0aSTim J. Robbins */ 132c5604d0aSTim J. Robbins static int 133c5604d0aSTim J. Robbins __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) 134c5604d0aSTim J. Robbins { 135c5604d0aSTim J. Robbins int ret; 136c5604d0aSTim J. Robbins FILE fake; 137c5604d0aSTim J. Robbins unsigned char buf[BUFSIZ]; 138c5604d0aSTim J. Robbins 139c5604d0aSTim J. Robbins /* copy the important variables */ 140c5604d0aSTim J. Robbins fake._flags = fp->_flags & ~__SNBF; 141c5604d0aSTim J. Robbins fake._file = fp->_file; 142c5604d0aSTim J. Robbins fake._cookie = fp->_cookie; 143c5604d0aSTim J. Robbins fake._write = fp->_write; 144c5604d0aSTim J. Robbins fake._extra = fp->_extra; 145c5604d0aSTim J. Robbins 146c5604d0aSTim J. Robbins /* set up the buffer */ 147c5604d0aSTim J. Robbins fake._bf._base = fake._p = buf; 148c5604d0aSTim J. Robbins fake._bf._size = fake._w = sizeof(buf); 149c5604d0aSTim J. Robbins fake._lbfsize = 0; /* not actually used, but Just In Case */ 150c5604d0aSTim J. Robbins 151c5604d0aSTim J. Robbins /* do the work, then copy any error status */ 152c5604d0aSTim J. Robbins ret = __vfwprintf(&fake, fmt, ap); 153c5604d0aSTim J. Robbins if (ret >= 0 && __fflush(&fake)) 154c5604d0aSTim J. Robbins ret = WEOF; 155c5604d0aSTim J. Robbins if (fake._flags & __SERR) 156c5604d0aSTim J. Robbins fp->_flags |= __SERR; 157c5604d0aSTim J. Robbins return (ret); 158c5604d0aSTim J. Robbins } 159c5604d0aSTim J. Robbins 160c5604d0aSTim J. Robbins /* 161909a17f4STim J. Robbins * Like __fputwc, but handles fake string (__SSTR) files properly. 162909a17f4STim J. Robbins * File must already be locked. 163909a17f4STim J. Robbins */ 164909a17f4STim J. Robbins static wint_t 165909a17f4STim J. Robbins __xfputwc(wchar_t wc, FILE *fp) 166909a17f4STim J. Robbins { 16793996f6dSTim J. Robbins static const mbstate_t initial; 16893996f6dSTim J. Robbins mbstate_t mbs; 169909a17f4STim J. Robbins char buf[MB_LEN_MAX]; 170909a17f4STim J. Robbins struct __suio uio; 171909a17f4STim J. Robbins struct __siov iov; 17284d9142fSJacques Vidrine size_t len; 173909a17f4STim J. Robbins 174909a17f4STim J. Robbins if ((fp->_flags & __SSTR) == 0) 175909a17f4STim J. Robbins return (__fputwc(wc, fp)); 176909a17f4STim J. Robbins 17793996f6dSTim J. Robbins mbs = initial; 17893996f6dSTim J. Robbins if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) { 179909a17f4STim J. Robbins fp->_flags |= __SERR; 180909a17f4STim J. Robbins return (WEOF); 181909a17f4STim J. Robbins } 182909a17f4STim J. Robbins uio.uio_iov = &iov; 183909a17f4STim J. Robbins uio.uio_resid = len; 184909a17f4STim J. Robbins uio.uio_iovcnt = 1; 185909a17f4STim J. Robbins iov.iov_base = buf; 186909a17f4STim J. Robbins iov.iov_len = len; 187909a17f4STim J. Robbins return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF); 188909a17f4STim J. Robbins } 189909a17f4STim J. Robbins 190909a17f4STim J. Robbins /* 191c5604d0aSTim J. Robbins * Macros for converting digits to letters and vice versa 192c5604d0aSTim J. Robbins */ 193c5604d0aSTim J. Robbins #define to_digit(c) ((c) - '0') 194c5604d0aSTim J. Robbins #define is_digit(c) ((unsigned)to_digit(c) <= 9) 195c5604d0aSTim J. Robbins #define to_char(n) ((n) + '0') 196c5604d0aSTim J. Robbins 197c5604d0aSTim J. Robbins /* 198c5604d0aSTim J. Robbins * Convert an unsigned long to ASCII for printf purposes, returning 199c5604d0aSTim J. Robbins * a pointer to the first character of the string representation. 200c5604d0aSTim J. Robbins * Octal numbers can be forced to have a leading zero; hex numbers 201c5604d0aSTim J. Robbins * use the given digits. 202c5604d0aSTim J. Robbins */ 203c5604d0aSTim J. Robbins static wchar_t * 2047b7e3509SDavid Schultz __ultoa(u_long val, wchar_t *endp, int base, int octzero, const char *xdigs, 205c5604d0aSTim J. Robbins int needgrp, char thousep, const char *grp) 206c5604d0aSTim J. Robbins { 207c5604d0aSTim J. Robbins wchar_t *cp = endp; 208c5604d0aSTim J. Robbins long sval; 209c5604d0aSTim J. Robbins int ndig; 210c5604d0aSTim J. Robbins 211c5604d0aSTim J. Robbins /* 212c5604d0aSTim J. Robbins * Handle the three cases separately, in the hope of getting 213c5604d0aSTim J. Robbins * better/faster code. 214c5604d0aSTim J. Robbins */ 215c5604d0aSTim J. Robbins switch (base) { 216c5604d0aSTim J. Robbins case 10: 217c5604d0aSTim J. Robbins if (val < 10) { /* many numbers are 1 digit */ 218c5604d0aSTim J. Robbins *--cp = to_char(val); 219c5604d0aSTim J. Robbins return (cp); 220c5604d0aSTim J. Robbins } 221c5604d0aSTim J. Robbins ndig = 0; 222c5604d0aSTim J. Robbins /* 223c5604d0aSTim J. Robbins * On many machines, unsigned arithmetic is harder than 224c5604d0aSTim J. Robbins * signed arithmetic, so we do at most one unsigned mod and 225c5604d0aSTim J. Robbins * divide; this is sufficient to reduce the range of 226c5604d0aSTim J. Robbins * the incoming value to where signed arithmetic works. 227c5604d0aSTim J. Robbins */ 228c5604d0aSTim J. Robbins if (val > LONG_MAX) { 229c5604d0aSTim J. Robbins *--cp = to_char(val % 10); 230c5604d0aSTim J. Robbins ndig++; 231c5604d0aSTim J. Robbins sval = val / 10; 232c5604d0aSTim J. Robbins } else 233c5604d0aSTim J. Robbins sval = val; 234c5604d0aSTim J. Robbins do { 235c5604d0aSTim J. Robbins *--cp = to_char(sval % 10); 236c5604d0aSTim J. Robbins ndig++; 237c5604d0aSTim J. Robbins /* 238c5604d0aSTim J. Robbins * If (*grp == CHAR_MAX) then no more grouping 239c5604d0aSTim J. Robbins * should be performed. 240c5604d0aSTim J. Robbins */ 241c5604d0aSTim J. Robbins if (needgrp && ndig == *grp && *grp != CHAR_MAX 242c5604d0aSTim J. Robbins && sval > 9) { 243c5604d0aSTim J. Robbins *--cp = thousep; 244c5604d0aSTim J. Robbins ndig = 0; 245c5604d0aSTim J. Robbins /* 246c5604d0aSTim J. Robbins * If (*(grp+1) == '\0') then we have to 247c5604d0aSTim J. Robbins * use *grp character (last grouping rule) 248c5604d0aSTim J. Robbins * for all next cases 249c5604d0aSTim J. Robbins */ 250c5604d0aSTim J. Robbins if (*(grp+1) != '\0') 251c5604d0aSTim J. Robbins grp++; 252c5604d0aSTim J. Robbins } 253c5604d0aSTim J. Robbins sval /= 10; 254c5604d0aSTim J. Robbins } while (sval != 0); 255c5604d0aSTim J. Robbins break; 256c5604d0aSTim J. Robbins 257c5604d0aSTim J. Robbins case 8: 258c5604d0aSTim J. Robbins do { 259c5604d0aSTim J. Robbins *--cp = to_char(val & 7); 260c5604d0aSTim J. Robbins val >>= 3; 261c5604d0aSTim J. Robbins } while (val); 262c5604d0aSTim J. Robbins if (octzero && *cp != '0') 263c5604d0aSTim J. Robbins *--cp = '0'; 264c5604d0aSTim J. Robbins break; 265c5604d0aSTim J. Robbins 266c5604d0aSTim J. Robbins case 16: 267c5604d0aSTim J. Robbins do { 268c5604d0aSTim J. Robbins *--cp = xdigs[val & 15]; 269c5604d0aSTim J. Robbins val >>= 4; 270c5604d0aSTim J. Robbins } while (val); 271c5604d0aSTim J. Robbins break; 272c5604d0aSTim J. Robbins 273c5604d0aSTim J. Robbins default: /* oops */ 274c5604d0aSTim J. Robbins abort(); 275c5604d0aSTim J. Robbins } 276c5604d0aSTim J. Robbins return (cp); 277c5604d0aSTim J. Robbins } 278c5604d0aSTim J. Robbins 279c5604d0aSTim J. Robbins /* Identical to __ultoa, but for intmax_t. */ 280c5604d0aSTim J. Robbins static wchar_t * 281adfd6b31STim J. Robbins __ujtoa(uintmax_t val, wchar_t *endp, int base, int octzero, 2827b7e3509SDavid Schultz const char *xdigs, int needgrp, char thousep, const char *grp) 283c5604d0aSTim J. Robbins { 284c5604d0aSTim J. Robbins wchar_t *cp = endp; 285c5604d0aSTim J. Robbins intmax_t sval; 286c5604d0aSTim J. Robbins int ndig; 287c5604d0aSTim J. Robbins 288c5604d0aSTim J. Robbins /* quick test for small values; __ultoa is typically much faster */ 289c5604d0aSTim J. Robbins /* (perhaps instead we should run until small, then call __ultoa?) */ 290c5604d0aSTim J. Robbins if (val <= ULONG_MAX) 291c5604d0aSTim J. Robbins return (__ultoa((u_long)val, endp, base, octzero, xdigs, 292c5604d0aSTim J. Robbins needgrp, thousep, grp)); 293c5604d0aSTim J. Robbins switch (base) { 294c5604d0aSTim J. Robbins case 10: 295c5604d0aSTim J. Robbins if (val < 10) { 296c5604d0aSTim J. Robbins *--cp = to_char(val % 10); 297c5604d0aSTim J. Robbins return (cp); 298c5604d0aSTim J. Robbins } 299c5604d0aSTim J. Robbins ndig = 0; 300c5604d0aSTim J. Robbins if (val > INTMAX_MAX) { 301c5604d0aSTim J. Robbins *--cp = to_char(val % 10); 302c5604d0aSTim J. Robbins ndig++; 303c5604d0aSTim J. Robbins sval = val / 10; 304c5604d0aSTim J. Robbins } else 305c5604d0aSTim J. Robbins sval = val; 306c5604d0aSTim J. Robbins do { 307c5604d0aSTim J. Robbins *--cp = to_char(sval % 10); 308c5604d0aSTim J. Robbins ndig++; 309c5604d0aSTim J. Robbins /* 310c5604d0aSTim J. Robbins * If (*grp == CHAR_MAX) then no more grouping 311c5604d0aSTim J. Robbins * should be performed. 312c5604d0aSTim J. Robbins */ 313c5604d0aSTim J. Robbins if (needgrp && *grp != CHAR_MAX && ndig == *grp 314c5604d0aSTim J. Robbins && sval > 9) { 315c5604d0aSTim J. Robbins *--cp = thousep; 316c5604d0aSTim J. Robbins ndig = 0; 317c5604d0aSTim J. Robbins /* 318c5604d0aSTim J. Robbins * If (*(grp+1) == '\0') then we have to 319c5604d0aSTim J. Robbins * use *grp character (last grouping rule) 320c5604d0aSTim J. Robbins * for all next cases 321c5604d0aSTim J. Robbins */ 322c5604d0aSTim J. Robbins if (*(grp+1) != '\0') 323c5604d0aSTim J. Robbins grp++; 324c5604d0aSTim J. Robbins } 325c5604d0aSTim J. Robbins sval /= 10; 326c5604d0aSTim J. Robbins } while (sval != 0); 327c5604d0aSTim J. Robbins break; 328c5604d0aSTim J. Robbins 329c5604d0aSTim J. Robbins case 8: 330c5604d0aSTim J. Robbins do { 331c5604d0aSTim J. Robbins *--cp = to_char(val & 7); 332c5604d0aSTim J. Robbins val >>= 3; 333c5604d0aSTim J. Robbins } while (val); 334c5604d0aSTim J. Robbins if (octzero && *cp != '0') 335c5604d0aSTim J. Robbins *--cp = '0'; 336c5604d0aSTim J. Robbins break; 337c5604d0aSTim J. Robbins 338c5604d0aSTim J. Robbins case 16: 339c5604d0aSTim J. Robbins do { 340c5604d0aSTim J. Robbins *--cp = xdigs[val & 15]; 341c5604d0aSTim J. Robbins val >>= 4; 342c5604d0aSTim J. Robbins } while (val); 343c5604d0aSTim J. Robbins break; 344c5604d0aSTim J. Robbins 345c5604d0aSTim J. Robbins default: 346c5604d0aSTim J. Robbins abort(); 347c5604d0aSTim J. Robbins } 348c5604d0aSTim J. Robbins return (cp); 349c5604d0aSTim J. Robbins } 350c5604d0aSTim J. Robbins 351c5604d0aSTim J. Robbins /* 352c5604d0aSTim J. Robbins * Convert a multibyte character string argument for the %s format to a wide 353c5604d0aSTim J. Robbins * string representation. ``prec'' specifies the maximum number of bytes 354c5604d0aSTim J. Robbins * to output. If ``prec'' is greater than or equal to zero, we can't assume 355c5604d0aSTim J. Robbins * that the multibyte char. string ends in a null character. 356c5604d0aSTim J. Robbins */ 357c5604d0aSTim J. Robbins static wchar_t * 358c5604d0aSTim J. Robbins __mbsconv(char *mbsarg, int prec) 359c5604d0aSTim J. Robbins { 36093996f6dSTim J. Robbins static const mbstate_t initial; 36193996f6dSTim J. Robbins mbstate_t mbs; 362c5604d0aSTim J. Robbins wchar_t *convbuf, *wcp; 363c5604d0aSTim J. Robbins const char *p; 364c5604d0aSTim J. Robbins size_t insize, nchars, nconv; 365c5604d0aSTim J. Robbins 366adfd6b31STim J. Robbins if (mbsarg == NULL) 367adfd6b31STim J. Robbins return (NULL); 368adfd6b31STim J. Robbins 369c5604d0aSTim J. Robbins /* 370c5604d0aSTim J. Robbins * Supplied argument is a multibyte string; convert it to wide 371c5604d0aSTim J. Robbins * characters first. 372c5604d0aSTim J. Robbins */ 373c5604d0aSTim J. Robbins if (prec >= 0) { 374c5604d0aSTim J. Robbins /* 375c5604d0aSTim J. Robbins * String is not guaranteed to be NUL-terminated. Find the 376c5604d0aSTim J. Robbins * number of characters to print. 377c5604d0aSTim J. Robbins */ 378c5604d0aSTim J. Robbins p = mbsarg; 379c5604d0aSTim J. Robbins insize = nchars = 0; 38093996f6dSTim J. Robbins mbs = initial; 381c5604d0aSTim J. Robbins while (nchars != (size_t)prec) { 38293996f6dSTim J. Robbins nconv = mbrlen(p, MB_CUR_MAX, &mbs); 383c5604d0aSTim J. Robbins if (nconv == 0 || nconv == (size_t)-1 || 384c5604d0aSTim J. Robbins nconv == (size_t)-2) 385c5604d0aSTim J. Robbins break; 386c5604d0aSTim J. Robbins p += nconv; 387c5604d0aSTim J. Robbins nchars++; 388c5604d0aSTim J. Robbins insize += nconv; 389c5604d0aSTim J. Robbins } 390c5604d0aSTim J. Robbins if (nconv == (size_t)-1 || nconv == (size_t)-2) 391c5604d0aSTim J. Robbins return (NULL); 392c5604d0aSTim J. Robbins } else 393c5604d0aSTim J. Robbins insize = strlen(mbsarg); 394c5604d0aSTim J. Robbins 395c5604d0aSTim J. Robbins /* 396c5604d0aSTim J. Robbins * Allocate buffer for the result and perform the conversion, 397c5604d0aSTim J. Robbins * converting at most `size' bytes of the input multibyte string to 398c5604d0aSTim J. Robbins * wide characters for printing. 399c5604d0aSTim J. Robbins */ 400c5604d0aSTim J. Robbins convbuf = malloc((insize + 1) * sizeof(*convbuf)); 401c5604d0aSTim J. Robbins if (convbuf == NULL) 402c5604d0aSTim J. Robbins return (NULL); 403c5604d0aSTim J. Robbins wcp = convbuf; 404c5604d0aSTim J. Robbins p = mbsarg; 40593996f6dSTim J. Robbins mbs = initial; 406c5604d0aSTim J. Robbins while (insize != 0) { 40793996f6dSTim J. Robbins nconv = mbrtowc(wcp, p, insize, &mbs); 408c5604d0aSTim J. Robbins if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) 409c5604d0aSTim J. Robbins break; 410c5604d0aSTim J. Robbins wcp++; 411c5604d0aSTim J. Robbins p += nconv; 412c5604d0aSTim J. Robbins insize -= nconv; 413c5604d0aSTim J. Robbins } 414c5604d0aSTim J. Robbins if (nconv == (size_t)-1 || nconv == (size_t)-2) { 415c5604d0aSTim J. Robbins free(convbuf); 416c5604d0aSTim J. Robbins return (NULL); 417c5604d0aSTim J. Robbins } 418c5604d0aSTim J. Robbins *wcp = L'\0'; 419c5604d0aSTim J. Robbins 420c5604d0aSTim J. Robbins return (convbuf); 421c5604d0aSTim J. Robbins } 422c5604d0aSTim J. Robbins 423c5604d0aSTim J. Robbins /* 424c5604d0aSTim J. Robbins * MT-safe version 425c5604d0aSTim J. Robbins */ 426c5604d0aSTim J. Robbins int 427c5604d0aSTim J. Robbins vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap) 428c5604d0aSTim J. Robbins 429c5604d0aSTim J. Robbins { 430c5604d0aSTim J. Robbins int ret; 431c5604d0aSTim J. Robbins 432c5604d0aSTim J. Robbins FLOCKFILE(fp); 433c5604d0aSTim J. Robbins ret = __vfwprintf(fp, fmt0, ap); 434c5604d0aSTim J. Robbins FUNLOCKFILE(fp); 435c5604d0aSTim J. Robbins return (ret); 436c5604d0aSTim J. Robbins } 437c5604d0aSTim J. Robbins 438c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 439adfd6b31STim J. Robbins 440adfd6b31STim J. Robbins #define dtoa __dtoa 441adfd6b31STim J. Robbins #define freedtoa __freedtoa 442adfd6b31STim J. Robbins 443b936664eSDavid Schultz #include <float.h> 444c5604d0aSTim J. Robbins #include <math.h> 445c5604d0aSTim J. Robbins #include "floatio.h" 446adfd6b31STim J. Robbins #include "gdtoa.h" 447c5604d0aSTim J. Robbins 448c5604d0aSTim J. Robbins #define DEFPREC 6 449c5604d0aSTim J. Robbins 450c5604d0aSTim J. Robbins static int exponent(wchar_t *, int, wchar_t); 451c5604d0aSTim J. Robbins 452c5604d0aSTim J. Robbins #endif /* FLOATING_POINT */ 453c5604d0aSTim J. Robbins 45438cac8f8SDavid Schultz /* 45538cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer 45638cac8f8SDavid Schultz * conversions, among other things. Technically, we would need the 45738cac8f8SDavid Schultz * most space for base 10 conversions with thousands' grouping 45838cac8f8SDavid Schultz * characters between each pair of digits. 100 bytes is a 45938cac8f8SDavid Schultz * conservative overestimate even for a 128-bit uintmax_t. 46038cac8f8SDavid Schultz */ 46138cac8f8SDavid Schultz #define BUF 100 46238cac8f8SDavid Schultz 463c5604d0aSTim J. Robbins #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 464c5604d0aSTim J. Robbins 465c5604d0aSTim J. Robbins /* 466c5604d0aSTim J. Robbins * Flags used during conversion. 467c5604d0aSTim J. Robbins */ 468c5604d0aSTim J. Robbins #define ALT 0x001 /* alternate form */ 469c5604d0aSTim J. Robbins #define LADJUST 0x004 /* left adjustment */ 470c5604d0aSTim J. Robbins #define LONGDBL 0x008 /* long double */ 471c5604d0aSTim J. Robbins #define LONGINT 0x010 /* long integer */ 472c5604d0aSTim J. Robbins #define LLONGINT 0x020 /* long long integer */ 473c5604d0aSTim J. Robbins #define SHORTINT 0x040 /* short integer */ 474c5604d0aSTim J. Robbins #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 475c5604d0aSTim J. Robbins #define FPT 0x100 /* Floating point number */ 476c5604d0aSTim J. Robbins #define GROUPING 0x200 /* use grouping ("'" flag) */ 477c5604d0aSTim J. Robbins /* C99 additional size modifiers: */ 478c5604d0aSTim J. Robbins #define SIZET 0x400 /* size_t */ 479c5604d0aSTim J. Robbins #define PTRDIFFT 0x800 /* ptrdiff_t */ 480c5604d0aSTim J. Robbins #define INTMAXT 0x1000 /* intmax_t */ 481c5604d0aSTim J. Robbins #define CHARINT 0x2000 /* print char using int format */ 482c5604d0aSTim J. Robbins 483c5604d0aSTim J. Robbins /* 484c5604d0aSTim J. Robbins * Non-MT-safe version 485c5604d0aSTim J. Robbins */ 486c5604d0aSTim J. Robbins int 487c5604d0aSTim J. Robbins __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) 488c5604d0aSTim J. Robbins { 489c5604d0aSTim J. Robbins wchar_t *fmt; /* format string */ 490c5604d0aSTim J. Robbins wchar_t ch; /* character from fmt */ 491adfd6b31STim J. Robbins int n, n2, n3; /* handy integer (short term usage) */ 492c5604d0aSTim J. Robbins wchar_t *cp; /* handy char pointer (short term usage) */ 493c5604d0aSTim J. Robbins int flags; /* flags as above */ 494c5604d0aSTim J. Robbins int ret; /* return value accumulator */ 495c5604d0aSTim J. Robbins int width; /* width from format (%8d), or 0 */ 496adfd6b31STim J. Robbins int prec; /* precision from format; <0 for N/A */ 497c5604d0aSTim J. Robbins wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */ 498c5604d0aSTim J. Robbins char thousands_sep; /* locale specific thousands separator */ 499c5604d0aSTim J. Robbins const char *grouping; /* locale specific numeric grouping rules */ 500c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 501adfd6b31STim J. Robbins /* 502adfd6b31STim J. Robbins * We can decompose the printed representation of floating 503adfd6b31STim J. Robbins * point numbers into several parts, some of which may be empty: 504adfd6b31STim J. Robbins * 505adfd6b31STim J. Robbins * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 506adfd6b31STim J. Robbins * A B ---C--- D E F 507adfd6b31STim J. Robbins * 508adfd6b31STim J. Robbins * A: 'sign' holds this value if present; '\0' otherwise 509adfd6b31STim J. Robbins * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 510adfd6b31STim J. Robbins * C: cp points to the string MMMNNN. Leading and trailing 511adfd6b31STim J. Robbins * zeros are not in the string and must be added. 512adfd6b31STim J. Robbins * D: expchar holds this character; '\0' if no exponent, e.g. %f 513adfd6b31STim J. Robbins * F: at least two digits for decimal, at least one digit for hex 514adfd6b31STim J. Robbins */ 515c5604d0aSTim J. Robbins char *decimal_point; /* locale specific decimal point */ 516adfd6b31STim J. Robbins int signflag; /* true if float is negative */ 517adfd6b31STim J. Robbins union { /* floating point arguments %[aAeEfFgG] */ 518adfd6b31STim J. Robbins double dbl; 519adfd6b31STim J. Robbins long double ldbl; 520adfd6b31STim J. Robbins } fparg; 521c5604d0aSTim J. Robbins int expt; /* integer value of exponent */ 522adfd6b31STim J. Robbins char expchar; /* exponent character: [eEpP\0] */ 523adfd6b31STim J. Robbins char *dtoaend; /* pointer to end of converted digits */ 524c5604d0aSTim J. Robbins int expsize; /* character count for expstr */ 525adfd6b31STim J. Robbins int lead; /* sig figs before decimal or group sep */ 526adfd6b31STim J. Robbins int ndig; /* actual number of digits returned by dtoa */ 527adfd6b31STim J. Robbins wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 528adfd6b31STim J. Robbins char *dtoaresult; /* buffer allocated by dtoa */ 529adfd6b31STim J. Robbins int nseps; /* number of group separators with ' */ 530adfd6b31STim J. Robbins int nrepeats; /* number of repeats of the last group */ 531c5604d0aSTim J. Robbins #endif 532c5604d0aSTim J. Robbins u_long ulval; /* integer arguments %[diouxX] */ 533c5604d0aSTim J. Robbins uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 534c5604d0aSTim J. Robbins int base; /* base for [diouxX] conversion */ 535c5604d0aSTim J. Robbins int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 536c5604d0aSTim J. Robbins int realsz; /* field size expanded by dprec, sign, etc */ 537c5604d0aSTim J. Robbins int size; /* size of converted field or string */ 538c5604d0aSTim J. Robbins int prsize; /* max size of printed field */ 5397b7e3509SDavid Schultz const char *xdigs; /* digits for [xX] conversion */ 54038cac8f8SDavid Schultz wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */ 541c5604d0aSTim J. Robbins wchar_t ox[2]; /* space for 0x hex-prefix */ 542c5604d0aSTim J. Robbins union arg *argtable; /* args, built due to positional arg */ 543c5604d0aSTim J. Robbins union arg statargtable [STATIC_ARG_TBL_SIZE]; 544c5604d0aSTim J. Robbins int nextarg; /* 1-based argument index */ 545c5604d0aSTim J. Robbins va_list orgap; /* original argument pointer */ 546c5604d0aSTim J. Robbins wchar_t *convbuf; /* multibyte to wide conversion result */ 547c5604d0aSTim J. Robbins 548c5604d0aSTim J. Robbins /* 549c5604d0aSTim J. Robbins * Choose PADSIZE to trade efficiency vs. size. If larger printf 550c5604d0aSTim J. Robbins * fields occur frequently, increase PADSIZE and make the initialisers 551c5604d0aSTim J. Robbins * below longer. 552c5604d0aSTim J. Robbins */ 553c5604d0aSTim J. Robbins #define PADSIZE 16 /* pad chunk size */ 554c5604d0aSTim J. Robbins static wchar_t blanks[PADSIZE] = 555c5604d0aSTim J. Robbins {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 556c5604d0aSTim J. Robbins static wchar_t zeroes[PADSIZE] = 557c5604d0aSTim J. Robbins {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 558c5604d0aSTim J. Robbins 5597b7e3509SDavid Schultz static const char xdigs_lower[16] = "0123456789abcdef"; 5607b7e3509SDavid Schultz static const char xdigs_upper[16] = "0123456789ABCDEF"; 561adfd6b31STim J. Robbins 562c5604d0aSTim J. Robbins /* 563c5604d0aSTim J. Robbins * BEWARE, these `goto error' on error, PRINT uses `n2' and 564c5604d0aSTim J. Robbins * PAD uses `n'. 565c5604d0aSTim J. Robbins */ 566c5604d0aSTim J. Robbins #define PRINT(ptr, len) do { \ 567adfd6b31STim J. Robbins for (n3 = 0; n3 < (len); n3++) \ 568909a17f4STim J. Robbins __xfputwc((ptr)[n3], fp); \ 569c5604d0aSTim J. Robbins } while (0) 570c5604d0aSTim J. Robbins #define PAD(howmany, with) do { \ 571c5604d0aSTim J. Robbins if ((n = (howmany)) > 0) { \ 572c5604d0aSTim J. Robbins while (n > PADSIZE) { \ 573c5604d0aSTim J. Robbins PRINT(with, PADSIZE); \ 574c5604d0aSTim J. Robbins n -= PADSIZE; \ 575c5604d0aSTim J. Robbins } \ 576c5604d0aSTim J. Robbins PRINT(with, n); \ 577c5604d0aSTim J. Robbins } \ 578c5604d0aSTim J. Robbins } while (0) 579adfd6b31STim J. Robbins #define PRINTANDPAD(p, ep, len, with) do { \ 580adfd6b31STim J. Robbins n2 = (ep) - (p); \ 581adfd6b31STim J. Robbins if (n2 > (len)) \ 582adfd6b31STim J. Robbins n2 = (len); \ 583adfd6b31STim J. Robbins if (n2 > 0) \ 584adfd6b31STim J. Robbins PRINT((p), n2); \ 585adfd6b31STim J. Robbins PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ 586adfd6b31STim J. Robbins } while(0) 587c5604d0aSTim J. Robbins 588c5604d0aSTim J. Robbins /* 589c5604d0aSTim J. Robbins * Get the argument indexed by nextarg. If the argument table is 590c5604d0aSTim J. Robbins * built, use it to get the argument. If its not, get the next 591c5604d0aSTim J. Robbins * argument (and arguments must be gotten sequentially). 592c5604d0aSTim J. Robbins */ 593c5604d0aSTim J. Robbins #define GETARG(type) \ 594c5604d0aSTim J. Robbins ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 595c5604d0aSTim J. Robbins (nextarg++, va_arg(ap, type))) 596c5604d0aSTim J. Robbins 597c5604d0aSTim J. Robbins /* 598c5604d0aSTim J. Robbins * To extend shorts properly, we need both signed and unsigned 599c5604d0aSTim J. Robbins * argument extraction methods. 600c5604d0aSTim J. Robbins */ 601c5604d0aSTim J. Robbins #define SARG() \ 602c5604d0aSTim J. Robbins (flags&LONGINT ? GETARG(long) : \ 603c5604d0aSTim J. Robbins flags&SHORTINT ? (long)(short)GETARG(int) : \ 604c5604d0aSTim J. Robbins flags&CHARINT ? (long)(signed char)GETARG(int) : \ 605c5604d0aSTim J. Robbins (long)GETARG(int)) 606c5604d0aSTim J. Robbins #define UARG() \ 607c5604d0aSTim J. Robbins (flags&LONGINT ? GETARG(u_long) : \ 608c5604d0aSTim J. Robbins flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 609c5604d0aSTim J. Robbins flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 610c5604d0aSTim J. Robbins (u_long)GETARG(u_int)) 611c5604d0aSTim J. Robbins #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 612c5604d0aSTim J. Robbins #define SJARG() \ 613c5604d0aSTim J. Robbins (flags&INTMAXT ? GETARG(intmax_t) : \ 614c5604d0aSTim J. Robbins flags&SIZET ? (intmax_t)GETARG(size_t) : \ 615c5604d0aSTim J. Robbins flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 616c5604d0aSTim J. Robbins (intmax_t)GETARG(long long)) 617c5604d0aSTim J. Robbins #define UJARG() \ 618c5604d0aSTim J. Robbins (flags&INTMAXT ? GETARG(uintmax_t) : \ 619c5604d0aSTim J. Robbins flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 620c5604d0aSTim J. Robbins flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 621c5604d0aSTim J. Robbins (uintmax_t)GETARG(unsigned long long)) 622c5604d0aSTim J. Robbins 623c5604d0aSTim J. Robbins /* 624c5604d0aSTim J. Robbins * Get * arguments, including the form *nn$. Preserve the nextarg 625c5604d0aSTim J. Robbins * that the argument can be gotten once the type is determined. 626c5604d0aSTim J. Robbins */ 627c5604d0aSTim J. Robbins #define GETASTER(val) \ 628c5604d0aSTim J. Robbins n2 = 0; \ 629c5604d0aSTim J. Robbins cp = fmt; \ 630c5604d0aSTim J. Robbins while (is_digit(*cp)) { \ 631c5604d0aSTim J. Robbins n2 = 10 * n2 + to_digit(*cp); \ 632c5604d0aSTim J. Robbins cp++; \ 633c5604d0aSTim J. Robbins } \ 634c5604d0aSTim J. Robbins if (*cp == '$') { \ 635c5604d0aSTim J. Robbins int hold = nextarg; \ 636c5604d0aSTim J. Robbins if (argtable == NULL) { \ 637c5604d0aSTim J. Robbins argtable = statargtable; \ 638c5604d0aSTim J. Robbins __find_arguments (fmt0, orgap, &argtable); \ 639c5604d0aSTim J. Robbins } \ 640c5604d0aSTim J. Robbins nextarg = n2; \ 641c5604d0aSTim J. Robbins val = GETARG (int); \ 642c5604d0aSTim J. Robbins nextarg = hold; \ 643c5604d0aSTim J. Robbins fmt = ++cp; \ 644c5604d0aSTim J. Robbins } else { \ 645c5604d0aSTim J. Robbins val = GETARG (int); \ 646c5604d0aSTim J. Robbins } 647c5604d0aSTim J. Robbins 648c5604d0aSTim J. Robbins 649c5604d0aSTim J. Robbins thousands_sep = '\0'; 650c5604d0aSTim J. Robbins grouping = NULL; 651c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 652c5604d0aSTim J. Robbins decimal_point = localeconv()->decimal_point; 653c5604d0aSTim J. Robbins #endif 654c5604d0aSTim J. Robbins convbuf = NULL; 655c5604d0aSTim J. Robbins /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */ 656c5604d0aSTim J. Robbins if (cantwrite(fp)) 657c5604d0aSTim J. Robbins return (EOF); 658c5604d0aSTim J. Robbins 659c5604d0aSTim J. Robbins /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 660c5604d0aSTim J. Robbins if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 661c5604d0aSTim J. Robbins fp->_file >= 0) 662c5604d0aSTim J. Robbins return (__sbprintf(fp, fmt0, ap)); 663c5604d0aSTim J. Robbins 664c5604d0aSTim J. Robbins fmt = (wchar_t *)fmt0; 665c5604d0aSTim J. Robbins argtable = NULL; 666c5604d0aSTim J. Robbins nextarg = 1; 667d07090a8STim J. Robbins va_copy(orgap, ap); 668c5604d0aSTim J. Robbins ret = 0; 669c5604d0aSTim J. Robbins 670c5604d0aSTim J. Robbins /* 671c5604d0aSTim J. Robbins * Scan the format for conversions (`%' character). 672c5604d0aSTim J. Robbins */ 673c5604d0aSTim J. Robbins for (;;) { 674c5604d0aSTim J. Robbins for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 675c5604d0aSTim J. Robbins /* void */; 676c5604d0aSTim J. Robbins if ((n = fmt - cp) != 0) { 677c5604d0aSTim J. Robbins if ((unsigned)ret + n > INT_MAX) { 678c5604d0aSTim J. Robbins ret = EOF; 679c5604d0aSTim J. Robbins goto error; 680c5604d0aSTim J. Robbins } 681c5604d0aSTim J. Robbins PRINT(cp, n); 682c5604d0aSTim J. Robbins ret += n; 683c5604d0aSTim J. Robbins } 684c5604d0aSTim J. Robbins if (ch == '\0') 685c5604d0aSTim J. Robbins goto done; 686c5604d0aSTim J. Robbins fmt++; /* skip over '%' */ 687c5604d0aSTim J. Robbins 688c5604d0aSTim J. Robbins flags = 0; 689c5604d0aSTim J. Robbins dprec = 0; 690c5604d0aSTim J. Robbins width = 0; 691c5604d0aSTim J. Robbins prec = -1; 692c5604d0aSTim J. Robbins sign = '\0'; 693adfd6b31STim J. Robbins ox[1] = '\0'; 694c5604d0aSTim J. Robbins 695c5604d0aSTim J. Robbins rflag: ch = *fmt++; 696c5604d0aSTim J. Robbins reswitch: switch (ch) { 697c5604d0aSTim J. Robbins case ' ': 698c5604d0aSTim J. Robbins /*- 699c5604d0aSTim J. Robbins * ``If the space and + flags both appear, the space 700c5604d0aSTim J. Robbins * flag will be ignored.'' 701c5604d0aSTim J. Robbins * -- ANSI X3J11 702c5604d0aSTim J. Robbins */ 703c5604d0aSTim J. Robbins if (!sign) 704c5604d0aSTim J. Robbins sign = ' '; 705c5604d0aSTim J. Robbins goto rflag; 706c5604d0aSTim J. Robbins case '#': 707c5604d0aSTim J. Robbins flags |= ALT; 708c5604d0aSTim J. Robbins goto rflag; 709c5604d0aSTim J. Robbins case '*': 710c5604d0aSTim J. Robbins /*- 711c5604d0aSTim J. Robbins * ``A negative field width argument is taken as a 712c5604d0aSTim J. Robbins * - flag followed by a positive field width.'' 713c5604d0aSTim J. Robbins * -- ANSI X3J11 714c5604d0aSTim J. Robbins * They don't exclude field widths read from args. 715c5604d0aSTim J. Robbins */ 716c5604d0aSTim J. Robbins GETASTER (width); 717c5604d0aSTim J. Robbins if (width >= 0) 718c5604d0aSTim J. Robbins goto rflag; 719c5604d0aSTim J. Robbins width = -width; 720c5604d0aSTim J. Robbins /* FALLTHROUGH */ 721c5604d0aSTim J. Robbins case '-': 722c5604d0aSTim J. Robbins flags |= LADJUST; 723c5604d0aSTim J. Robbins goto rflag; 724c5604d0aSTim J. Robbins case '+': 725c5604d0aSTim J. Robbins sign = '+'; 726c5604d0aSTim J. Robbins goto rflag; 727c5604d0aSTim J. Robbins case '\'': 728c5604d0aSTim J. Robbins flags |= GROUPING; 729c5604d0aSTim J. Robbins thousands_sep = *(localeconv()->thousands_sep); 730c5604d0aSTim J. Robbins grouping = localeconv()->grouping; 731c5604d0aSTim J. Robbins goto rflag; 732c5604d0aSTim J. Robbins case '.': 733c5604d0aSTim J. Robbins if ((ch = *fmt++) == '*') { 734adfd6b31STim J. Robbins GETASTER (prec); 735c5604d0aSTim J. Robbins goto rflag; 736c5604d0aSTim J. Robbins } 737adfd6b31STim J. Robbins prec = 0; 738c5604d0aSTim J. Robbins while (is_digit(ch)) { 739adfd6b31STim J. Robbins prec = 10 * prec + to_digit(ch); 740c5604d0aSTim J. Robbins ch = *fmt++; 741c5604d0aSTim J. Robbins } 742c5604d0aSTim J. Robbins goto reswitch; 743c5604d0aSTim J. Robbins case '0': 744c5604d0aSTim J. Robbins /*- 745c5604d0aSTim J. Robbins * ``Note that 0 is taken as a flag, not as the 746c5604d0aSTim J. Robbins * beginning of a field width.'' 747c5604d0aSTim J. Robbins * -- ANSI X3J11 748c5604d0aSTim J. Robbins */ 749c5604d0aSTim J. Robbins flags |= ZEROPAD; 750c5604d0aSTim J. Robbins goto rflag; 751c5604d0aSTim J. Robbins case '1': case '2': case '3': case '4': 752c5604d0aSTim J. Robbins case '5': case '6': case '7': case '8': case '9': 753c5604d0aSTim J. Robbins n = 0; 754c5604d0aSTim J. Robbins do { 755c5604d0aSTim J. Robbins n = 10 * n + to_digit(ch); 756c5604d0aSTim J. Robbins ch = *fmt++; 757c5604d0aSTim J. Robbins } while (is_digit(ch)); 758c5604d0aSTim J. Robbins if (ch == '$') { 759c5604d0aSTim J. Robbins nextarg = n; 760c5604d0aSTim J. Robbins if (argtable == NULL) { 761c5604d0aSTim J. Robbins argtable = statargtable; 762c5604d0aSTim J. Robbins __find_arguments (fmt0, orgap, 763c5604d0aSTim J. Robbins &argtable); 764c5604d0aSTim J. Robbins } 765c5604d0aSTim J. Robbins goto rflag; 766c5604d0aSTim J. Robbins } 767c5604d0aSTim J. Robbins width = n; 768c5604d0aSTim J. Robbins goto reswitch; 769c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 770c5604d0aSTim J. Robbins case 'L': 771c5604d0aSTim J. Robbins flags |= LONGDBL; 772c5604d0aSTim J. Robbins goto rflag; 773c5604d0aSTim J. Robbins #endif 774c5604d0aSTim J. Robbins case 'h': 775c5604d0aSTim J. Robbins if (flags & SHORTINT) { 776c5604d0aSTim J. Robbins flags &= ~SHORTINT; 777c5604d0aSTim J. Robbins flags |= CHARINT; 778c5604d0aSTim J. Robbins } else 779c5604d0aSTim J. Robbins flags |= SHORTINT; 780c5604d0aSTim J. Robbins goto rflag; 781c5604d0aSTim J. Robbins case 'j': 782c5604d0aSTim J. Robbins flags |= INTMAXT; 783c5604d0aSTim J. Robbins goto rflag; 784c5604d0aSTim J. Robbins case 'l': 785c5604d0aSTim J. Robbins if (flags & LONGINT) { 786c5604d0aSTim J. Robbins flags &= ~LONGINT; 787c5604d0aSTim J. Robbins flags |= LLONGINT; 788c5604d0aSTim J. Robbins } else 789c5604d0aSTim J. Robbins flags |= LONGINT; 790c5604d0aSTim J. Robbins goto rflag; 791c5604d0aSTim J. Robbins case 'q': 792c5604d0aSTim J. Robbins flags |= LLONGINT; /* not necessarily */ 793c5604d0aSTim J. Robbins goto rflag; 794c5604d0aSTim J. Robbins case 't': 795c5604d0aSTim J. Robbins flags |= PTRDIFFT; 796c5604d0aSTim J. Robbins goto rflag; 797c5604d0aSTim J. Robbins case 'z': 798c5604d0aSTim J. Robbins flags |= SIZET; 799c5604d0aSTim J. Robbins goto rflag; 800927ecbf3STim J. Robbins case 'C': 801927ecbf3STim J. Robbins flags |= LONGINT; 802927ecbf3STim J. Robbins /*FALLTHROUGH*/ 803c5604d0aSTim J. Robbins case 'c': 804c5604d0aSTim J. Robbins if (flags & LONGINT) 805c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)GETARG(wint_t); 806c5604d0aSTim J. Robbins else 807c5604d0aSTim J. Robbins *(cp = buf) = (wchar_t)btowc(GETARG(int)); 808c5604d0aSTim J. Robbins size = 1; 809c5604d0aSTim J. Robbins sign = '\0'; 810c5604d0aSTim J. Robbins break; 811c5604d0aSTim J. Robbins case 'D': 812c5604d0aSTim J. Robbins flags |= LONGINT; 813c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 814c5604d0aSTim J. Robbins case 'd': 815c5604d0aSTim J. Robbins case 'i': 816c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 817c5604d0aSTim J. Robbins ujval = SJARG(); 818c5604d0aSTim J. Robbins if ((intmax_t)ujval < 0) { 819c5604d0aSTim J. Robbins ujval = -ujval; 820c5604d0aSTim J. Robbins sign = '-'; 821c5604d0aSTim J. Robbins } 822c5604d0aSTim J. Robbins } else { 823c5604d0aSTim J. Robbins ulval = SARG(); 824c5604d0aSTim J. Robbins if ((long)ulval < 0) { 825c5604d0aSTim J. Robbins ulval = -ulval; 826c5604d0aSTim J. Robbins sign = '-'; 827c5604d0aSTim J. Robbins } 828c5604d0aSTim J. Robbins } 829c5604d0aSTim J. Robbins base = 10; 830c5604d0aSTim J. Robbins goto number; 831c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 832c5604d0aSTim J. Robbins #ifdef HEXFLOAT 833c5604d0aSTim J. Robbins case 'a': 834c5604d0aSTim J. Robbins case 'A': 835adfd6b31STim J. Robbins if (ch == 'a') { 836adfd6b31STim J. Robbins ox[1] = 'x'; 837adfd6b31STim J. Robbins xdigs = xdigs_lower; 838adfd6b31STim J. Robbins expchar = 'p'; 839adfd6b31STim J. Robbins } else { 840adfd6b31STim J. Robbins ox[1] = 'X'; 841adfd6b31STim J. Robbins xdigs = xdigs_upper; 842adfd6b31STim J. Robbins expchar = 'P'; 843adfd6b31STim J. Robbins } 8447b7e3509SDavid Schultz if (prec >= 0) 8457b7e3509SDavid Schultz prec++; 846adfd6b31STim J. Robbins if (flags & LONGDBL) { 8477b7e3509SDavid Schultz fparg.ldbl = GETARG(long double); 848adfd6b31STim J. Robbins dtoaresult = 849adfd6b31STim J. Robbins __hldtoa(fparg.ldbl, xdigs, prec, 850adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 851adfd6b31STim J. Robbins } else { 852adfd6b31STim J. Robbins fparg.dbl = GETARG(double); 853adfd6b31STim J. Robbins dtoaresult = 854adfd6b31STim J. Robbins __hdtoa(fparg.dbl, xdigs, prec, 855adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 856adfd6b31STim J. Robbins } 8577b7e3509SDavid Schultz if (prec < 0) 8587b7e3509SDavid Schultz prec = dtoaend - dtoaresult; 8597b7e3509SDavid Schultz if (expt == INT_MAX) 8607b7e3509SDavid Schultz ox[1] = '\0'; 861adfd6b31STim J. Robbins if (convbuf != NULL) 862adfd6b31STim J. Robbins free(convbuf); 8637b7e3509SDavid Schultz ndig = dtoaend - dtoaresult; 864adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 865adfd6b31STim J. Robbins freedtoa(dtoaresult); 8667b7e3509SDavid Schultz goto fp_common; 8677b7e3509SDavid Schultz #endif /* HEXFLOAT */ 868c5604d0aSTim J. Robbins case 'e': 869c5604d0aSTim J. Robbins case 'E': 870adfd6b31STim J. Robbins expchar = ch; 871adfd6b31STim J. Robbins if (prec < 0) /* account for digit before decpt */ 872adfd6b31STim J. Robbins prec = DEFPREC + 1; 873adfd6b31STim J. Robbins else 874adfd6b31STim J. Robbins prec++; 875adfd6b31STim J. Robbins goto fp_begin; 876c5604d0aSTim J. Robbins case 'f': 877c5604d0aSTim J. Robbins case 'F': 878adfd6b31STim J. Robbins expchar = '\0'; 879c5604d0aSTim J. Robbins goto fp_begin; 880c5604d0aSTim J. Robbins case 'g': 881c5604d0aSTim J. Robbins case 'G': 882adfd6b31STim J. Robbins expchar = ch - ('g' - 'e'); 883c5604d0aSTim J. Robbins if (prec == 0) 884c5604d0aSTim J. Robbins prec = 1; 885adfd6b31STim J. Robbins fp_begin: 886adfd6b31STim J. Robbins if (prec < 0) 887c5604d0aSTim J. Robbins prec = DEFPREC; 888adfd6b31STim J. Robbins if (convbuf != NULL) 889adfd6b31STim J. Robbins free(convbuf); 890adfd6b31STim J. Robbins if (flags & LONGDBL) { 891adfd6b31STim J. Robbins fparg.ldbl = GETARG(long double); 892adfd6b31STim J. Robbins dtoaresult = 893adfd6b31STim J. Robbins __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 894adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 895adfd6b31STim J. Robbins } else { 896adfd6b31STim J. Robbins fparg.dbl = GETARG(double); 897adfd6b31STim J. Robbins dtoaresult = 898adfd6b31STim J. Robbins dtoa(fparg.dbl, expchar ? 2 : 3, prec, 899adfd6b31STim J. Robbins &expt, &signflag, &dtoaend); 900adfd6b31STim J. Robbins if (expt == 9999) 901adfd6b31STim J. Robbins expt = INT_MAX; 902c5604d0aSTim J. Robbins } 903adfd6b31STim J. Robbins ndig = dtoaend - dtoaresult; 904adfd6b31STim J. Robbins cp = convbuf = __mbsconv(dtoaresult, -1); 905adfd6b31STim J. Robbins freedtoa(dtoaresult); 9067b7e3509SDavid Schultz fp_common: 907adfd6b31STim J. Robbins if (signflag) 908adfd6b31STim J. Robbins sign = '-'; 909adfd6b31STim J. Robbins if (expt == INT_MAX) { /* inf or nan */ 910adfd6b31STim J. Robbins if (*cp == 'N') { 911adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"nan" : L"NAN"; 912adfd6b31STim J. Robbins sign = '\0'; 913adfd6b31STim J. Robbins } else 914adfd6b31STim J. Robbins cp = (ch >= 'a') ? L"inf" : L"INF"; 915c5604d0aSTim J. Robbins size = 3; 916c5604d0aSTim J. Robbins break; 917c5604d0aSTim J. Robbins } 918c5604d0aSTim J. Robbins flags |= FPT; 919c5604d0aSTim J. Robbins if (ch == 'g' || ch == 'G') { 920adfd6b31STim J. Robbins if (expt > -4 && expt <= prec) { 921adfd6b31STim J. Robbins /* Make %[gG] smell like %[fF] */ 922adfd6b31STim J. Robbins expchar = '\0'; 923adfd6b31STim J. Robbins if (flags & ALT) 924adfd6b31STim J. Robbins prec -= expt; 925c5604d0aSTim J. Robbins else 926adfd6b31STim J. Robbins prec = ndig - expt; 927adfd6b31STim J. Robbins if (prec < 0) 928adfd6b31STim J. Robbins prec = 0; 9291f2a0cdfSDavid Schultz } else { 9301f2a0cdfSDavid Schultz /* 9311f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but 9321f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag. 9331f2a0cdfSDavid Schultz */ 9341f2a0cdfSDavid Schultz if (!(flags & ALT)) 9351f2a0cdfSDavid Schultz prec = ndig; 936c5604d0aSTim J. Robbins } 937adfd6b31STim J. Robbins } 938adfd6b31STim J. Robbins if (expchar) { 939adfd6b31STim J. Robbins expsize = exponent(expstr, expt - 1, expchar); 940adfd6b31STim J. Robbins size = expsize + prec; 941adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) 942c5604d0aSTim J. Robbins ++size; 943adfd6b31STim J. Robbins } else { 944d73c448bSTim J. Robbins /* space for digits before decimal point */ 945d73c448bSTim J. Robbins if (expt > 0) 946c5604d0aSTim J. Robbins size = expt; 947d73c448bSTim J. Robbins else /* "0" */ 948d73c448bSTim J. Robbins size = 1; 949d73c448bSTim J. Robbins /* space for decimal pt and following digits */ 950c5604d0aSTim J. Robbins if (prec || flags & ALT) 951c5604d0aSTim J. Robbins size += prec + 1; 952adfd6b31STim J. Robbins if (grouping && expt > 0) { 953adfd6b31STim J. Robbins /* space for thousands' grouping */ 954adfd6b31STim J. Robbins nseps = nrepeats = 0; 955adfd6b31STim J. Robbins lead = expt; 956adfd6b31STim J. Robbins while (*grouping != CHAR_MAX) { 957adfd6b31STim J. Robbins if (lead <= *grouping) 958adfd6b31STim J. Robbins break; 959adfd6b31STim J. Robbins lead -= *grouping; 960adfd6b31STim J. Robbins if (*(grouping+1)) { 961adfd6b31STim J. Robbins nseps++; 962adfd6b31STim J. Robbins grouping++; 963c5604d0aSTim J. Robbins } else 964adfd6b31STim J. Robbins nrepeats++; 965adfd6b31STim J. Robbins } 966adfd6b31STim J. Robbins size += nseps + nrepeats; 967adfd6b31STim J. Robbins } else 968adfd6b31STim J. Robbins lead = expt; 969adfd6b31STim J. Robbins } 970c5604d0aSTim J. Robbins break; 971c5604d0aSTim J. Robbins #endif /* FLOATING_POINT */ 972c5604d0aSTim J. Robbins case 'n': 973c5604d0aSTim J. Robbins /* 974c5604d0aSTim J. Robbins * Assignment-like behavior is specified if the 975c5604d0aSTim J. Robbins * value overflows or is otherwise unrepresentable. 976c5604d0aSTim J. Robbins * C99 says to use `signed char' for %hhn conversions. 977c5604d0aSTim J. Robbins */ 978c5604d0aSTim J. Robbins if (flags & LLONGINT) 979c5604d0aSTim J. Robbins *GETARG(long long *) = ret; 980c5604d0aSTim J. Robbins else if (flags & SIZET) 981c5604d0aSTim J. Robbins *GETARG(ssize_t *) = (ssize_t)ret; 982c5604d0aSTim J. Robbins else if (flags & PTRDIFFT) 983c5604d0aSTim J. Robbins *GETARG(ptrdiff_t *) = ret; 984c5604d0aSTim J. Robbins else if (flags & INTMAXT) 985c5604d0aSTim J. Robbins *GETARG(intmax_t *) = ret; 986c5604d0aSTim J. Robbins else if (flags & LONGINT) 987c5604d0aSTim J. Robbins *GETARG(long *) = ret; 988c5604d0aSTim J. Robbins else if (flags & SHORTINT) 989c5604d0aSTim J. Robbins *GETARG(short *) = ret; 990c5604d0aSTim J. Robbins else if (flags & CHARINT) 991c5604d0aSTim J. Robbins *GETARG(signed char *) = ret; 992c5604d0aSTim J. Robbins else 993c5604d0aSTim J. Robbins *GETARG(int *) = ret; 994c5604d0aSTim J. Robbins continue; /* no output */ 995c5604d0aSTim J. Robbins case 'O': 996c5604d0aSTim J. Robbins flags |= LONGINT; 997c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 998c5604d0aSTim J. Robbins case 'o': 999c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 1000c5604d0aSTim J. Robbins ujval = UJARG(); 1001c5604d0aSTim J. Robbins else 1002c5604d0aSTim J. Robbins ulval = UARG(); 1003c5604d0aSTim J. Robbins base = 8; 1004c5604d0aSTim J. Robbins goto nosign; 1005c5604d0aSTim J. Robbins case 'p': 1006c5604d0aSTim J. Robbins /*- 1007c5604d0aSTim J. Robbins * ``The argument shall be a pointer to void. The 1008c5604d0aSTim J. Robbins * value of the pointer is converted to a sequence 1009c5604d0aSTim J. Robbins * of printable characters, in an implementation- 1010c5604d0aSTim J. Robbins * defined manner.'' 1011c5604d0aSTim J. Robbins * -- ANSI X3J11 1012c5604d0aSTim J. Robbins */ 1013c5604d0aSTim J. Robbins ujval = (uintmax_t)(uintptr_t)GETARG(void *); 1014c5604d0aSTim J. Robbins base = 16; 1015adfd6b31STim J. Robbins xdigs = xdigs_lower; 1016adfd6b31STim J. Robbins flags = flags | INTMAXT; 1017adfd6b31STim J. Robbins ox[1] = 'x'; 1018c5604d0aSTim J. Robbins goto nosign; 1019927ecbf3STim J. Robbins case 'S': 1020927ecbf3STim J. Robbins flags |= LONGINT; 1021927ecbf3STim J. Robbins /*FALLTHROUGH*/ 1022c5604d0aSTim J. Robbins case 's': 1023c5604d0aSTim J. Robbins if (flags & LONGINT) { 1024c5604d0aSTim J. Robbins if ((cp = GETARG(wchar_t *)) == NULL) 1025c5604d0aSTim J. Robbins cp = L"(null)"; 1026c5604d0aSTim J. Robbins } else { 1027c5604d0aSTim J. Robbins char *mbp; 1028c5604d0aSTim J. Robbins 1029c5604d0aSTim J. Robbins if (convbuf != NULL) 1030c5604d0aSTim J. Robbins free(convbuf); 1031c5604d0aSTim J. Robbins if ((mbp = GETARG(char *)) == NULL) 1032c5604d0aSTim J. Robbins cp = L"(null)"; 1033c5604d0aSTim J. Robbins else { 1034c5604d0aSTim J. Robbins convbuf = __mbsconv(mbp, prec); 10356180233fSTim J. Robbins if (convbuf == NULL) { 10366180233fSTim J. Robbins fp->_flags |= __SERR; 1037c5604d0aSTim J. Robbins goto error; 10386180233fSTim J. Robbins } 1039c5604d0aSTim J. Robbins cp = convbuf; 1040c5604d0aSTim J. Robbins } 1041c5604d0aSTim J. Robbins } 1042c5604d0aSTim J. Robbins 1043c5604d0aSTim J. Robbins if (prec >= 0) { 1044c5604d0aSTim J. Robbins /* 1045c5604d0aSTim J. Robbins * can't use wcslen; can only look for the 1046c5604d0aSTim J. Robbins * NUL in the first `prec' characters, and 1047c5604d0aSTim J. Robbins * wcslen() will go further. 1048c5604d0aSTim J. Robbins */ 1049c5604d0aSTim J. Robbins wchar_t *p = wmemchr(cp, 0, (size_t)prec); 1050c5604d0aSTim J. Robbins 1051c5604d0aSTim J. Robbins if (p != NULL) { 1052c5604d0aSTim J. Robbins size = p - cp; 1053c5604d0aSTim J. Robbins if (size > prec) 1054c5604d0aSTim J. Robbins size = prec; 1055c5604d0aSTim J. Robbins } else 1056c5604d0aSTim J. Robbins size = prec; 1057c5604d0aSTim J. Robbins } else 1058c5604d0aSTim J. Robbins size = wcslen(cp); 1059c5604d0aSTim J. Robbins sign = '\0'; 1060c5604d0aSTim J. Robbins break; 1061c5604d0aSTim J. Robbins case 'U': 1062c5604d0aSTim J. Robbins flags |= LONGINT; 1063c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 1064c5604d0aSTim J. Robbins case 'u': 1065c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 1066c5604d0aSTim J. Robbins ujval = UJARG(); 1067c5604d0aSTim J. Robbins else 1068c5604d0aSTim J. Robbins ulval = UARG(); 1069c5604d0aSTim J. Robbins base = 10; 1070c5604d0aSTim J. Robbins goto nosign; 1071c5604d0aSTim J. Robbins case 'X': 1072adfd6b31STim J. Robbins xdigs = xdigs_upper; 1073c5604d0aSTim J. Robbins goto hex; 1074c5604d0aSTim J. Robbins case 'x': 1075adfd6b31STim J. Robbins xdigs = xdigs_lower; 1076c5604d0aSTim J. Robbins hex: 1077c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) 1078c5604d0aSTim J. Robbins ujval = UJARG(); 1079c5604d0aSTim J. Robbins else 1080c5604d0aSTim J. Robbins ulval = UARG(); 1081c5604d0aSTim J. Robbins base = 16; 1082c5604d0aSTim J. Robbins /* leading 0x/X only if non-zero */ 1083c5604d0aSTim J. Robbins if (flags & ALT && 1084c5604d0aSTim J. Robbins (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 1085adfd6b31STim J. Robbins ox[1] = ch; 1086c5604d0aSTim J. Robbins 1087c5604d0aSTim J. Robbins flags &= ~GROUPING; 1088c5604d0aSTim J. Robbins /* unsigned conversions */ 1089c5604d0aSTim J. Robbins nosign: sign = '\0'; 1090c5604d0aSTim J. Robbins /*- 1091c5604d0aSTim J. Robbins * ``... diouXx conversions ... if a precision is 1092c5604d0aSTim J. Robbins * specified, the 0 flag will be ignored.'' 1093c5604d0aSTim J. Robbins * -- ANSI X3J11 1094c5604d0aSTim J. Robbins */ 1095c5604d0aSTim J. Robbins number: if ((dprec = prec) >= 0) 1096c5604d0aSTim J. Robbins flags &= ~ZEROPAD; 1097c5604d0aSTim J. Robbins 1098c5604d0aSTim J. Robbins /*- 1099c5604d0aSTim J. Robbins * ``The result of converting a zero value with an 1100c5604d0aSTim J. Robbins * explicit precision of zero is no characters.'' 1101c5604d0aSTim J. Robbins * -- ANSI X3J11 1102c5604d0aSTim J. Robbins */ 1103c5604d0aSTim J. Robbins cp = buf + BUF; 1104c5604d0aSTim J. Robbins if (flags & INTMAX_SIZE) { 1105c5604d0aSTim J. Robbins if (ujval != 0 || prec != 0) 1106c5604d0aSTim J. Robbins cp = __ujtoa(ujval, cp, base, 1107c5604d0aSTim J. Robbins flags & ALT, xdigs, 1108c5604d0aSTim J. Robbins flags & GROUPING, thousands_sep, 1109c5604d0aSTim J. Robbins grouping); 1110c5604d0aSTim J. Robbins } else { 1111c5604d0aSTim J. Robbins if (ulval != 0 || prec != 0) 1112c5604d0aSTim J. Robbins cp = __ultoa(ulval, cp, base, 1113c5604d0aSTim J. Robbins flags & ALT, xdigs, 1114c5604d0aSTim J. Robbins flags & GROUPING, thousands_sep, 1115c5604d0aSTim J. Robbins grouping); 1116c5604d0aSTim J. Robbins } 1117c5604d0aSTim J. Robbins size = buf + BUF - cp; 111838cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 111938cac8f8SDavid Schultz abort(); 1120c5604d0aSTim J. Robbins break; 1121c5604d0aSTim J. Robbins default: /* "%?" prints ?, unless ? is NUL */ 1122c5604d0aSTim J. Robbins if (ch == '\0') 1123c5604d0aSTim J. Robbins goto done; 1124c5604d0aSTim J. Robbins /* pretend it was %c with argument ch */ 1125c5604d0aSTim J. Robbins cp = buf; 1126c5604d0aSTim J. Robbins *cp = ch; 1127c5604d0aSTim J. Robbins size = 1; 1128c5604d0aSTim J. Robbins sign = '\0'; 1129c5604d0aSTim J. Robbins break; 1130c5604d0aSTim J. Robbins } 1131c5604d0aSTim J. Robbins 1132c5604d0aSTim J. Robbins /* 1133c5604d0aSTim J. Robbins * All reasonable formats wind up here. At this point, `cp' 1134c5604d0aSTim J. Robbins * points to a string which (if not flags&LADJUST) should be 1135c5604d0aSTim J. Robbins * padded out to `width' places. If flags&ZEROPAD, it should 1136c5604d0aSTim J. Robbins * first be prefixed by any sign or other prefix; otherwise, 1137c5604d0aSTim J. Robbins * it should be blank padded before the prefix is emitted. 1138c5604d0aSTim J. Robbins * After any left-hand padding and prefixing, emit zeroes 1139c5604d0aSTim J. Robbins * required by a decimal [diouxX] precision, then print the 1140c5604d0aSTim J. Robbins * string proper, then emit zeroes required by any leftover 1141c5604d0aSTim J. Robbins * floating precision; finally, if LADJUST, pad with blanks. 1142c5604d0aSTim J. Robbins * 1143c5604d0aSTim J. Robbins * Compute actual size, so we know how much to pad. 1144c5604d0aSTim J. Robbins * size excludes decimal prec; realsz includes it. 1145c5604d0aSTim J. Robbins */ 1146c5604d0aSTim J. Robbins realsz = dprec > size ? dprec : size; 1147c5604d0aSTim J. Robbins if (sign) 1148c5604d0aSTim J. Robbins realsz++; 11497b7e3509SDavid Schultz if (ox[1]) 1150c5604d0aSTim J. Robbins realsz += 2; 1151c5604d0aSTim J. Robbins 1152c5604d0aSTim J. Robbins prsize = width > realsz ? width : realsz; 1153c5604d0aSTim J. Robbins if ((unsigned)ret + prsize > INT_MAX) { 1154c5604d0aSTim J. Robbins ret = EOF; 1155c5604d0aSTim J. Robbins goto error; 1156c5604d0aSTim J. Robbins } 1157c5604d0aSTim J. Robbins 1158c5604d0aSTim J. Robbins /* right-adjusting blank padding */ 1159c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == 0) 1160c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1161c5604d0aSTim J. Robbins 1162c5604d0aSTim J. Robbins /* prefix */ 11637b7e3509SDavid Schultz if (sign) 1164c5604d0aSTim J. Robbins PRINT(&sign, 1); 11657b7e3509SDavid Schultz 11667b7e3509SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */ 1167c5604d0aSTim J. Robbins ox[0] = '0'; 1168c5604d0aSTim J. Robbins PRINT(ox, 2); 1169c5604d0aSTim J. Robbins } 1170c5604d0aSTim J. Robbins 1171c5604d0aSTim J. Robbins /* right-adjusting zero padding */ 1172c5604d0aSTim J. Robbins if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 1173c5604d0aSTim J. Robbins PAD(width - realsz, zeroes); 1174c5604d0aSTim J. Robbins 1175c5604d0aSTim J. Robbins /* leading zeroes from decimal precision */ 1176c5604d0aSTim J. Robbins PAD(dprec - size, zeroes); 1177c5604d0aSTim J. Robbins 1178c5604d0aSTim J. Robbins /* the string or number proper */ 1179c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 1180c5604d0aSTim J. Robbins if ((flags & FPT) == 0) { 1181c5604d0aSTim J. Robbins PRINT(cp, size); 1182c5604d0aSTim J. Robbins } else { /* glue together f_p fragments */ 1183adfd6b31STim J. Robbins if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1184adfd6b31STim J. Robbins if (expt <= 0) { 1185d73c448bSTim J. Robbins PRINT(zeroes, 1); 1186d73c448bSTim J. Robbins if (prec || flags & ALT) 1187d73c448bSTim J. Robbins PRINT(decimal_point, 1); 1188c5604d0aSTim J. Robbins PAD(-expt, zeroes); 1189adfd6b31STim J. Robbins /* already handled initial 0's */ 1190adfd6b31STim J. Robbins prec += expt; 1191c5604d0aSTim J. Robbins } else { 1192adfd6b31STim J. Robbins PRINTANDPAD(cp, convbuf + ndig, lead, zeroes); 1193adfd6b31STim J. Robbins cp += lead; 1194adfd6b31STim J. Robbins if (grouping) { 1195adfd6b31STim J. Robbins while (nseps>0 || nrepeats>0) { 1196adfd6b31STim J. Robbins if (nrepeats > 0) 1197adfd6b31STim J. Robbins nrepeats--; 1198adfd6b31STim J. Robbins else { 1199adfd6b31STim J. Robbins grouping--; 1200adfd6b31STim J. Robbins nseps--; 1201c5604d0aSTim J. Robbins } 1202adfd6b31STim J. Robbins PRINT(&thousands_sep, 1203adfd6b31STim J. Robbins 1); 1204adfd6b31STim J. Robbins PRINTANDPAD(cp, 1205adfd6b31STim J. Robbins convbuf + ndig, 1206adfd6b31STim J. Robbins *grouping, zeroes); 1207adfd6b31STim J. Robbins cp += *grouping; 1208adfd6b31STim J. Robbins } 1209adfd6b31STim J. Robbins if (cp > convbuf + ndig) 1210adfd6b31STim J. Robbins cp = convbuf + ndig; 1211adfd6b31STim J. Robbins } 1212adfd6b31STim J. Robbins if (prec || flags & ALT) { 1213adfd6b31STim J. Robbins buf[0] = *decimal_point; 1214adfd6b31STim J. Robbins PRINT(buf, 1); 1215adfd6b31STim J. Robbins } 1216adfd6b31STim J. Robbins } 1217adfd6b31STim J. Robbins PRINTANDPAD(cp, convbuf + ndig, prec, zeroes); 1218adfd6b31STim J. Robbins } else { /* %[eE] or sufficiently long %[gG] */ 1219adfd6b31STim J. Robbins if (prec > 1 || flags & ALT) { 1220adfd6b31STim J. Robbins buf[0] = *cp++; 1221adfd6b31STim J. Robbins buf[1] = *decimal_point; 1222adfd6b31STim J. Robbins PRINT(buf, 2); 1223c5604d0aSTim J. Robbins PRINT(cp, ndig-1); 1224adfd6b31STim J. Robbins PAD(prec - ndig, zeroes); 1225c5604d0aSTim J. Robbins } else /* XeYYY */ 1226c5604d0aSTim J. Robbins PRINT(cp, 1); 1227c5604d0aSTim J. Robbins PRINT(expstr, expsize); 1228c5604d0aSTim J. Robbins } 1229c5604d0aSTim J. Robbins } 1230c5604d0aSTim J. Robbins #else 1231c5604d0aSTim J. Robbins PRINT(cp, size); 1232c5604d0aSTim J. Robbins #endif 1233c5604d0aSTim J. Robbins /* left-adjusting padding (always blank) */ 1234c5604d0aSTim J. Robbins if (flags & LADJUST) 1235c5604d0aSTim J. Robbins PAD(width - realsz, blanks); 1236c5604d0aSTim J. Robbins 1237c5604d0aSTim J. Robbins /* finally, adjust ret */ 1238c5604d0aSTim J. Robbins ret += prsize; 1239c5604d0aSTim J. Robbins } 1240c5604d0aSTim J. Robbins done: 1241c5604d0aSTim J. Robbins error: 1242c5604d0aSTim J. Robbins if (convbuf != NULL) 1243c5604d0aSTim J. Robbins free(convbuf); 1244c5604d0aSTim J. Robbins if (__sferror(fp)) 1245c5604d0aSTim J. Robbins ret = EOF; 1246c5604d0aSTim J. Robbins if ((argtable != NULL) && (argtable != statargtable)) 1247c5604d0aSTim J. Robbins free (argtable); 1248c5604d0aSTim J. Robbins return (ret); 1249c5604d0aSTim J. Robbins /* NOTREACHED */ 1250c5604d0aSTim J. Robbins } 1251c5604d0aSTim J. Robbins 1252c5604d0aSTim J. Robbins /* 1253c5604d0aSTim J. Robbins * Find all arguments when a positional parameter is encountered. Returns a 1254c5604d0aSTim J. Robbins * table, indexed by argument number, of pointers to each arguments. The 1255c5604d0aSTim J. Robbins * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 1256c5604d0aSTim J. Robbins * It will be replaces with a malloc-ed one if it overflows. 1257c5604d0aSTim J. Robbins */ 1258c5604d0aSTim J. Robbins static void 1259c5604d0aSTim J. Robbins __find_arguments (const wchar_t *fmt0, va_list ap, union arg **argtable) 1260c5604d0aSTim J. Robbins { 1261c5604d0aSTim J. Robbins wchar_t *fmt; /* format string */ 1262c5604d0aSTim J. Robbins wchar_t ch; /* character from fmt */ 1263c5604d0aSTim J. Robbins int n, n2; /* handy integer (short term usage) */ 1264c5604d0aSTim J. Robbins wchar_t *cp; /* handy char pointer (short term usage) */ 1265c5604d0aSTim J. Robbins int flags; /* flags as above */ 1266c5604d0aSTim J. Robbins int width; /* width from format (%8d), or 0 */ 1267c5604d0aSTim J. Robbins enum typeid *typetable; /* table of types */ 1268c5604d0aSTim J. Robbins enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; 1269c5604d0aSTim J. Robbins int tablesize; /* current size of type table */ 1270c5604d0aSTim J. Robbins int tablemax; /* largest used index in table */ 1271c5604d0aSTim J. Robbins int nextarg; /* 1-based argument index */ 1272c5604d0aSTim J. Robbins 1273c5604d0aSTim J. Robbins /* 1274c5604d0aSTim J. Robbins * Add an argument type to the table, expanding if necessary. 1275c5604d0aSTim J. Robbins */ 1276c5604d0aSTim J. Robbins #define ADDTYPE(type) \ 1277c5604d0aSTim J. Robbins ((nextarg >= tablesize) ? \ 1278c5604d0aSTim J. Robbins __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ 1279c5604d0aSTim J. Robbins (nextarg > tablemax) ? tablemax = nextarg : 0, \ 1280c5604d0aSTim J. Robbins typetable[nextarg++] = type) 1281c5604d0aSTim J. Robbins 1282c5604d0aSTim J. Robbins #define ADDSARG() \ 1283c5604d0aSTim J. Robbins ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ 1284c5604d0aSTim J. Robbins ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 1285c5604d0aSTim J. Robbins ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 1286c5604d0aSTim J. Robbins ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 1287c5604d0aSTim J. Robbins ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) 1288c5604d0aSTim J. Robbins 1289c5604d0aSTim J. Robbins #define ADDUARG() \ 1290c5604d0aSTim J. Robbins ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ 1291c5604d0aSTim J. Robbins ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 1292c5604d0aSTim J. Robbins ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 1293c5604d0aSTim J. Robbins ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 1294c5604d0aSTim J. Robbins ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) 1295c5604d0aSTim J. Robbins 1296c5604d0aSTim J. Robbins /* 1297c5604d0aSTim J. Robbins * Add * arguments to the type array. 1298c5604d0aSTim J. Robbins */ 1299c5604d0aSTim J. Robbins #define ADDASTER() \ 1300c5604d0aSTim J. Robbins n2 = 0; \ 1301c5604d0aSTim J. Robbins cp = fmt; \ 1302c5604d0aSTim J. Robbins while (is_digit(*cp)) { \ 1303c5604d0aSTim J. Robbins n2 = 10 * n2 + to_digit(*cp); \ 1304c5604d0aSTim J. Robbins cp++; \ 1305c5604d0aSTim J. Robbins } \ 1306c5604d0aSTim J. Robbins if (*cp == '$') { \ 1307c5604d0aSTim J. Robbins int hold = nextarg; \ 1308c5604d0aSTim J. Robbins nextarg = n2; \ 1309c5604d0aSTim J. Robbins ADDTYPE (T_INT); \ 1310c5604d0aSTim J. Robbins nextarg = hold; \ 1311c5604d0aSTim J. Robbins fmt = ++cp; \ 1312c5604d0aSTim J. Robbins } else { \ 1313c5604d0aSTim J. Robbins ADDTYPE (T_INT); \ 1314c5604d0aSTim J. Robbins } 1315c5604d0aSTim J. Robbins fmt = (wchar_t *)fmt0; 1316c5604d0aSTim J. Robbins typetable = stattypetable; 1317c5604d0aSTim J. Robbins tablesize = STATIC_ARG_TBL_SIZE; 1318c5604d0aSTim J. Robbins tablemax = 0; 1319c5604d0aSTim J. Robbins nextarg = 1; 1320c5604d0aSTim J. Robbins memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 1321c5604d0aSTim J. Robbins 1322c5604d0aSTim J. Robbins /* 1323c5604d0aSTim J. Robbins * Scan the format for conversions (`%' character). 1324c5604d0aSTim J. Robbins */ 1325c5604d0aSTim J. Robbins for (;;) { 1326c5604d0aSTim J. Robbins for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 1327c5604d0aSTim J. Robbins /* void */; 1328c5604d0aSTim J. Robbins if (ch == '\0') 1329c5604d0aSTim J. Robbins goto done; 1330c5604d0aSTim J. Robbins fmt++; /* skip over '%' */ 1331c5604d0aSTim J. Robbins 1332c5604d0aSTim J. Robbins flags = 0; 1333c5604d0aSTim J. Robbins width = 0; 1334c5604d0aSTim J. Robbins 1335c5604d0aSTim J. Robbins rflag: ch = *fmt++; 1336c5604d0aSTim J. Robbins reswitch: switch (ch) { 1337c5604d0aSTim J. Robbins case ' ': 1338c5604d0aSTim J. Robbins case '#': 1339c5604d0aSTim J. Robbins goto rflag; 1340c5604d0aSTim J. Robbins case '*': 1341c5604d0aSTim J. Robbins ADDASTER (); 1342c5604d0aSTim J. Robbins goto rflag; 1343c5604d0aSTim J. Robbins case '-': 1344c5604d0aSTim J. Robbins case '+': 1345c5604d0aSTim J. Robbins case '\'': 1346c5604d0aSTim J. Robbins goto rflag; 1347c5604d0aSTim J. Robbins case '.': 1348c5604d0aSTim J. Robbins if ((ch = *fmt++) == '*') { 1349c5604d0aSTim J. Robbins ADDASTER (); 1350c5604d0aSTim J. Robbins goto rflag; 1351c5604d0aSTim J. Robbins } 1352c5604d0aSTim J. Robbins while (is_digit(ch)) { 1353c5604d0aSTim J. Robbins ch = *fmt++; 1354c5604d0aSTim J. Robbins } 1355c5604d0aSTim J. Robbins goto reswitch; 1356c5604d0aSTim J. Robbins case '0': 1357c5604d0aSTim J. Robbins goto rflag; 1358c5604d0aSTim J. Robbins case '1': case '2': case '3': case '4': 1359c5604d0aSTim J. Robbins case '5': case '6': case '7': case '8': case '9': 1360c5604d0aSTim J. Robbins n = 0; 1361c5604d0aSTim J. Robbins do { 1362c5604d0aSTim J. Robbins n = 10 * n + to_digit(ch); 1363c5604d0aSTim J. Robbins ch = *fmt++; 1364c5604d0aSTim J. Robbins } while (is_digit(ch)); 1365c5604d0aSTim J. Robbins if (ch == '$') { 1366c5604d0aSTim J. Robbins nextarg = n; 1367c5604d0aSTim J. Robbins goto rflag; 1368c5604d0aSTim J. Robbins } 1369c5604d0aSTim J. Robbins width = n; 1370c5604d0aSTim J. Robbins goto reswitch; 1371c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 1372c5604d0aSTim J. Robbins case 'L': 1373c5604d0aSTim J. Robbins flags |= LONGDBL; 1374c5604d0aSTim J. Robbins goto rflag; 1375c5604d0aSTim J. Robbins #endif 1376c5604d0aSTim J. Robbins case 'h': 1377c5604d0aSTim J. Robbins if (flags & SHORTINT) { 1378c5604d0aSTim J. Robbins flags &= ~SHORTINT; 1379c5604d0aSTim J. Robbins flags |= CHARINT; 1380c5604d0aSTim J. Robbins } else 1381c5604d0aSTim J. Robbins flags |= SHORTINT; 1382c5604d0aSTim J. Robbins goto rflag; 1383c5604d0aSTim J. Robbins case 'j': 1384c5604d0aSTim J. Robbins flags |= INTMAXT; 1385c5604d0aSTim J. Robbins goto rflag; 1386c5604d0aSTim J. Robbins case 'l': 1387c5604d0aSTim J. Robbins if (flags & LONGINT) { 1388c5604d0aSTim J. Robbins flags &= ~LONGINT; 1389c5604d0aSTim J. Robbins flags |= LLONGINT; 1390c5604d0aSTim J. Robbins } else 1391c5604d0aSTim J. Robbins flags |= LONGINT; 1392c5604d0aSTim J. Robbins goto rflag; 1393c5604d0aSTim J. Robbins case 'q': 1394c5604d0aSTim J. Robbins flags |= LLONGINT; /* not necessarily */ 1395c5604d0aSTim J. Robbins goto rflag; 1396c5604d0aSTim J. Robbins case 't': 1397c5604d0aSTim J. Robbins flags |= PTRDIFFT; 1398c5604d0aSTim J. Robbins goto rflag; 1399c5604d0aSTim J. Robbins case 'z': 1400c5604d0aSTim J. Robbins flags |= SIZET; 1401c5604d0aSTim J. Robbins goto rflag; 1402927ecbf3STim J. Robbins case 'C': 1403927ecbf3STim J. Robbins flags |= LONGINT; 1404927ecbf3STim J. Robbins /*FALLTHROUGH*/ 1405c5604d0aSTim J. Robbins case 'c': 1406c5604d0aSTim J. Robbins if (flags & LONGINT) 1407c5604d0aSTim J. Robbins ADDTYPE(T_WINT); 1408c5604d0aSTim J. Robbins else 1409c5604d0aSTim J. Robbins ADDTYPE(T_INT); 1410c5604d0aSTim J. Robbins break; 1411c5604d0aSTim J. Robbins case 'D': 1412c5604d0aSTim J. Robbins flags |= LONGINT; 1413c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 1414c5604d0aSTim J. Robbins case 'd': 1415c5604d0aSTim J. Robbins case 'i': 1416c5604d0aSTim J. Robbins ADDSARG(); 1417c5604d0aSTim J. Robbins break; 1418c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 1419c5604d0aSTim J. Robbins #ifdef HEXFLOAT 1420c5604d0aSTim J. Robbins case 'a': 1421c5604d0aSTim J. Robbins case 'A': 1422c5604d0aSTim J. Robbins #endif 1423c5604d0aSTim J. Robbins case 'e': 1424c5604d0aSTim J. Robbins case 'E': 1425c5604d0aSTim J. Robbins case 'f': 1426c5604d0aSTim J. Robbins case 'g': 1427c5604d0aSTim J. Robbins case 'G': 1428c5604d0aSTim J. Robbins if (flags & LONGDBL) 1429c5604d0aSTim J. Robbins ADDTYPE(T_LONG_DOUBLE); 1430c5604d0aSTim J. Robbins else 1431c5604d0aSTim J. Robbins ADDTYPE(T_DOUBLE); 1432c5604d0aSTim J. Robbins break; 1433c5604d0aSTim J. Robbins #endif /* FLOATING_POINT */ 1434c5604d0aSTim J. Robbins case 'n': 1435c5604d0aSTim J. Robbins if (flags & INTMAXT) 1436c5604d0aSTim J. Robbins ADDTYPE(TP_INTMAXT); 1437c5604d0aSTim J. Robbins else if (flags & PTRDIFFT) 1438c5604d0aSTim J. Robbins ADDTYPE(TP_PTRDIFFT); 1439c5604d0aSTim J. Robbins else if (flags & SIZET) 1440c5604d0aSTim J. Robbins ADDTYPE(TP_SIZET); 1441c5604d0aSTim J. Robbins else if (flags & LLONGINT) 1442c5604d0aSTim J. Robbins ADDTYPE(TP_LLONG); 1443c5604d0aSTim J. Robbins else if (flags & LONGINT) 1444c5604d0aSTim J. Robbins ADDTYPE(TP_LONG); 1445c5604d0aSTim J. Robbins else if (flags & SHORTINT) 1446c5604d0aSTim J. Robbins ADDTYPE(TP_SHORT); 1447c5604d0aSTim J. Robbins else if (flags & CHARINT) 1448c5604d0aSTim J. Robbins ADDTYPE(TP_SCHAR); 1449c5604d0aSTim J. Robbins else 1450c5604d0aSTim J. Robbins ADDTYPE(TP_INT); 1451c5604d0aSTim J. Robbins continue; /* no output */ 1452c5604d0aSTim J. Robbins case 'O': 1453c5604d0aSTim J. Robbins flags |= LONGINT; 1454c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 1455c5604d0aSTim J. Robbins case 'o': 1456c5604d0aSTim J. Robbins ADDUARG(); 1457c5604d0aSTim J. Robbins break; 1458c5604d0aSTim J. Robbins case 'p': 1459c5604d0aSTim J. Robbins ADDTYPE(TP_VOID); 1460c5604d0aSTim J. Robbins break; 1461927ecbf3STim J. Robbins case 'S': 1462927ecbf3STim J. Robbins flags |= LONGINT; 1463927ecbf3STim J. Robbins /*FALLTHROUGH*/ 1464c5604d0aSTim J. Robbins case 's': 1465c5604d0aSTim J. Robbins if (flags & LONGINT) 1466c5604d0aSTim J. Robbins ADDTYPE(TP_WCHAR); 1467c5604d0aSTim J. Robbins else 1468c5604d0aSTim J. Robbins ADDTYPE(TP_CHAR); 1469c5604d0aSTim J. Robbins break; 1470c5604d0aSTim J. Robbins case 'U': 1471c5604d0aSTim J. Robbins flags |= LONGINT; 1472c5604d0aSTim J. Robbins /*FALLTHROUGH*/ 1473c5604d0aSTim J. Robbins case 'u': 1474c5604d0aSTim J. Robbins case 'X': 1475c5604d0aSTim J. Robbins case 'x': 1476c5604d0aSTim J. Robbins ADDUARG(); 1477c5604d0aSTim J. Robbins break; 1478c5604d0aSTim J. Robbins default: /* "%?" prints ?, unless ? is NUL */ 1479c5604d0aSTim J. Robbins if (ch == '\0') 1480c5604d0aSTim J. Robbins goto done; 1481c5604d0aSTim J. Robbins break; 1482c5604d0aSTim J. Robbins } 1483c5604d0aSTim J. Robbins } 1484c5604d0aSTim J. Robbins done: 1485c5604d0aSTim J. Robbins /* 1486c5604d0aSTim J. Robbins * Build the argument table. 1487c5604d0aSTim J. Robbins */ 1488c5604d0aSTim J. Robbins if (tablemax >= STATIC_ARG_TBL_SIZE) { 1489c5604d0aSTim J. Robbins *argtable = (union arg *) 1490c5604d0aSTim J. Robbins malloc (sizeof (union arg) * (tablemax + 1)); 1491c5604d0aSTim J. Robbins } 1492c5604d0aSTim J. Robbins 1493c5604d0aSTim J. Robbins (*argtable) [0].intarg = 0; 1494c5604d0aSTim J. Robbins for (n = 1; n <= tablemax; n++) { 1495c5604d0aSTim J. Robbins switch (typetable [n]) { 1496c5604d0aSTim J. Robbins case T_UNUSED: /* whoops! */ 1497c5604d0aSTim J. Robbins (*argtable) [n].intarg = va_arg (ap, int); 1498c5604d0aSTim J. Robbins break; 1499c5604d0aSTim J. Robbins case TP_SCHAR: 1500c5604d0aSTim J. Robbins (*argtable) [n].pschararg = va_arg (ap, signed char *); 1501c5604d0aSTim J. Robbins break; 1502c5604d0aSTim J. Robbins case TP_SHORT: 1503c5604d0aSTim J. Robbins (*argtable) [n].pshortarg = va_arg (ap, short *); 1504c5604d0aSTim J. Robbins break; 1505c5604d0aSTim J. Robbins case T_INT: 1506c5604d0aSTim J. Robbins (*argtable) [n].intarg = va_arg (ap, int); 1507c5604d0aSTim J. Robbins break; 1508c5604d0aSTim J. Robbins case T_U_INT: 1509c5604d0aSTim J. Robbins (*argtable) [n].uintarg = va_arg (ap, unsigned int); 1510c5604d0aSTim J. Robbins break; 1511c5604d0aSTim J. Robbins case TP_INT: 1512c5604d0aSTim J. Robbins (*argtable) [n].pintarg = va_arg (ap, int *); 1513c5604d0aSTim J. Robbins break; 1514c5604d0aSTim J. Robbins case T_LONG: 1515c5604d0aSTim J. Robbins (*argtable) [n].longarg = va_arg (ap, long); 1516c5604d0aSTim J. Robbins break; 1517c5604d0aSTim J. Robbins case T_U_LONG: 1518c5604d0aSTim J. Robbins (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 1519c5604d0aSTim J. Robbins break; 1520c5604d0aSTim J. Robbins case TP_LONG: 1521c5604d0aSTim J. Robbins (*argtable) [n].plongarg = va_arg (ap, long *); 1522c5604d0aSTim J. Robbins break; 1523c5604d0aSTim J. Robbins case T_LLONG: 1524c5604d0aSTim J. Robbins (*argtable) [n].longlongarg = va_arg (ap, long long); 1525c5604d0aSTim J. Robbins break; 1526c5604d0aSTim J. Robbins case T_U_LLONG: 1527c5604d0aSTim J. Robbins (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); 1528c5604d0aSTim J. Robbins break; 1529c5604d0aSTim J. Robbins case TP_LLONG: 1530c5604d0aSTim J. Robbins (*argtable) [n].plonglongarg = va_arg (ap, long long *); 1531c5604d0aSTim J. Robbins break; 1532c5604d0aSTim J. Robbins case T_PTRDIFFT: 1533c5604d0aSTim J. Robbins (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); 1534c5604d0aSTim J. Robbins break; 1535c5604d0aSTim J. Robbins case TP_PTRDIFFT: 1536c5604d0aSTim J. Robbins (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); 1537c5604d0aSTim J. Robbins break; 1538c5604d0aSTim J. Robbins case T_SIZET: 1539c5604d0aSTim J. Robbins (*argtable) [n].sizearg = va_arg (ap, size_t); 1540c5604d0aSTim J. Robbins break; 1541c5604d0aSTim J. Robbins case TP_SIZET: 1542c5604d0aSTim J. Robbins (*argtable) [n].psizearg = va_arg (ap, ssize_t *); 1543c5604d0aSTim J. Robbins break; 1544c5604d0aSTim J. Robbins case T_INTMAXT: 1545c5604d0aSTim J. Robbins (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); 1546c5604d0aSTim J. Robbins break; 1547c5604d0aSTim J. Robbins case T_UINTMAXT: 1548c5604d0aSTim J. Robbins (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); 1549c5604d0aSTim J. Robbins break; 1550c5604d0aSTim J. Robbins case TP_INTMAXT: 1551c5604d0aSTim J. Robbins (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); 1552c5604d0aSTim J. Robbins break; 1553c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 1554c5604d0aSTim J. Robbins case T_DOUBLE: 1555c5604d0aSTim J. Robbins (*argtable) [n].doublearg = va_arg (ap, double); 1556c5604d0aSTim J. Robbins break; 1557c5604d0aSTim J. Robbins case T_LONG_DOUBLE: 1558c5604d0aSTim J. Robbins (*argtable) [n].longdoublearg = va_arg (ap, long double); 1559c5604d0aSTim J. Robbins break; 1560c5604d0aSTim J. Robbins #endif 1561c5604d0aSTim J. Robbins case TP_CHAR: 1562c5604d0aSTim J. Robbins (*argtable) [n].pchararg = va_arg (ap, char *); 1563c5604d0aSTim J. Robbins break; 1564c5604d0aSTim J. Robbins case TP_VOID: 1565c5604d0aSTim J. Robbins (*argtable) [n].pvoidarg = va_arg (ap, void *); 1566c5604d0aSTim J. Robbins break; 1567c5604d0aSTim J. Robbins case T_WINT: 1568c5604d0aSTim J. Robbins (*argtable) [n].wintarg = va_arg (ap, wint_t); 1569c5604d0aSTim J. Robbins break; 1570c5604d0aSTim J. Robbins case TP_WCHAR: 1571c5604d0aSTim J. Robbins (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); 1572c5604d0aSTim J. Robbins break; 1573c5604d0aSTim J. Robbins } 1574c5604d0aSTim J. Robbins } 1575c5604d0aSTim J. Robbins 1576c5604d0aSTim J. Robbins if ((typetable != NULL) && (typetable != stattypetable)) 1577c5604d0aSTim J. Robbins free (typetable); 1578c5604d0aSTim J. Robbins } 1579c5604d0aSTim J. Robbins 1580c5604d0aSTim J. Robbins /* 1581c5604d0aSTim J. Robbins * Increase the size of the type table. 1582c5604d0aSTim J. Robbins */ 1583c5604d0aSTim J. Robbins static void 1584c5604d0aSTim J. Robbins __grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) 1585c5604d0aSTim J. Robbins { 1586c5604d0aSTim J. Robbins enum typeid *const oldtable = *typetable; 1587c5604d0aSTim J. Robbins const int oldsize = *tablesize; 1588c5604d0aSTim J. Robbins enum typeid *newtable; 1589c5604d0aSTim J. Robbins int newsize = oldsize * 2; 1590c5604d0aSTim J. Robbins 1591c5604d0aSTim J. Robbins if (newsize < nextarg + 1) 1592c5604d0aSTim J. Robbins newsize = nextarg + 1; 1593c5604d0aSTim J. Robbins if (oldsize == STATIC_ARG_TBL_SIZE) { 1594c5604d0aSTim J. Robbins if ((newtable = malloc(newsize)) == NULL) 1595c5604d0aSTim J. Robbins abort(); /* XXX handle better */ 1596c5604d0aSTim J. Robbins bcopy(oldtable, newtable, oldsize); 1597c5604d0aSTim J. Robbins } else { 1598c5604d0aSTim J. Robbins if ((newtable = reallocf(oldtable, newsize)) == NULL) 1599c5604d0aSTim J. Robbins abort(); /* XXX handle better */ 1600c5604d0aSTim J. Robbins } 1601c5604d0aSTim J. Robbins memset(&newtable[oldsize], T_UNUSED, newsize - oldsize); 1602c5604d0aSTim J. Robbins 1603c5604d0aSTim J. Robbins *typetable = newtable; 1604c5604d0aSTim J. Robbins *tablesize = newsize; 1605c5604d0aSTim J. Robbins } 1606c5604d0aSTim J. Robbins 1607c5604d0aSTim J. Robbins 1608c5604d0aSTim J. Robbins #ifdef FLOATING_POINT 1609c5604d0aSTim J. Robbins 1610c5604d0aSTim J. Robbins static int 1611c5604d0aSTim J. Robbins exponent(wchar_t *p0, int exp, wchar_t fmtch) 1612c5604d0aSTim J. Robbins { 1613c5604d0aSTim J. Robbins wchar_t *p, *t; 161438cac8f8SDavid Schultz wchar_t expbuf[MAXEXPDIG]; 1615c5604d0aSTim J. Robbins 1616c5604d0aSTim J. Robbins p = p0; 1617c5604d0aSTim J. Robbins *p++ = fmtch; 1618c5604d0aSTim J. Robbins if (exp < 0) { 1619c5604d0aSTim J. Robbins exp = -exp; 1620c5604d0aSTim J. Robbins *p++ = '-'; 1621c5604d0aSTim J. Robbins } 1622c5604d0aSTim J. Robbins else 1623c5604d0aSTim J. Robbins *p++ = '+'; 162438cac8f8SDavid Schultz t = expbuf + MAXEXPDIG; 1625c5604d0aSTim J. Robbins if (exp > 9) { 1626c5604d0aSTim J. Robbins do { 1627c5604d0aSTim J. Robbins *--t = to_char(exp % 10); 1628c5604d0aSTim J. Robbins } while ((exp /= 10) > 9); 1629c5604d0aSTim J. Robbins *--t = to_char(exp); 163038cac8f8SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 1631c5604d0aSTim J. Robbins } 1632c5604d0aSTim J. Robbins else { 1633adfd6b31STim J. Robbins /* 1634adfd6b31STim J. Robbins * Exponents for decimal floating point conversions 1635adfd6b31STim J. Robbins * (%[eEgG]) must be at least two characters long, 1636adfd6b31STim J. Robbins * whereas exponents for hexadecimal conversions can 1637adfd6b31STim J. Robbins * be only one character long. 1638adfd6b31STim J. Robbins */ 1639adfd6b31STim J. Robbins if (fmtch == 'e' || fmtch == 'E') 1640c5604d0aSTim J. Robbins *p++ = '0'; 1641c5604d0aSTim J. Robbins *p++ = to_char(exp); 1642c5604d0aSTim J. Robbins } 1643c5604d0aSTim J. Robbins return (p - p0); 1644c5604d0aSTim J. Robbins } 1645c5604d0aSTim J. Robbins #endif /* FLOATING_POINT */ 1646