| @@ -1,1898 +1,1904 @@ | | | @@ -1,1898 +1,1904 @@ |
1 | /* $NetBSD: vfwprintf.c,v 1.15 2009/02/20 09:23:37 roy Exp $ */ | | 1 | /* $NetBSD: vfwprintf.c,v 1.16 2009/08/05 20:46:01 dsl Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1990, 1993 | | 4 | * Copyright (c) 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Chris Torek. | | 8 | * Chris Torek. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors | | 18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software | | 19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. | | 20 | * without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. | | 32 | * SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | #if defined(LIBC_SCCS) && !defined(lint) | | 36 | #if defined(LIBC_SCCS) && !defined(lint) |
37 | #if 0 | | 37 | #if 0 |
38 | static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; | | 38 | static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; |
39 | __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.27 2007/01/09 00:28:08 imp Exp $"); | | 39 | __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.27 2007/01/09 00:28:08 imp Exp $"); |
40 | #else | | 40 | #else |
41 | __RCSID("$NetBSD: vfwprintf.c,v 1.15 2009/02/20 09:23:37 roy Exp $"); | | 41 | __RCSID("$NetBSD: vfwprintf.c,v 1.16 2009/08/05 20:46:01 dsl Exp $"); |
42 | #endif | | 42 | #endif |
43 | #endif /* LIBC_SCCS and not lint */ | | 43 | #endif /* LIBC_SCCS and not lint */ |
44 | | | 44 | |
45 | /* | | 45 | /* |
46 | * Actual {w,}printf innards. | | 46 | * Actual {w,}printf innards. |
47 | */ | | 47 | */ |
48 | | | 48 | |
49 | #include "namespace.h" | | 49 | #include "namespace.h" |
50 | #include <sys/types.h> | | 50 | #include <sys/types.h> |
51 | | | 51 | |
52 | #include <assert.h> | | 52 | #include <assert.h> |
53 | #include <ctype.h> | | 53 | #include <ctype.h> |
54 | #include <limits.h> | | 54 | #include <limits.h> |
55 | #include <locale.h> | | 55 | #include <locale.h> |
56 | #include <stdarg.h> | | 56 | #include <stdarg.h> |
57 | #include <stddef.h> | | 57 | #include <stddef.h> |
58 | #include <stdint.h> | | 58 | #include <stdint.h> |
59 | #include <stdio.h> | | 59 | #include <stdio.h> |
60 | #include <stdlib.h> | | 60 | #include <stdlib.h> |
61 | #include <string.h> | | 61 | #include <string.h> |
62 | #include <errno.h> | | 62 | #include <errno.h> |
63 | #include <wchar.h> | | 63 | #include <wchar.h> |
64 | #include <wctype.h> | | 64 | #include <wctype.h> |
65 | | | 65 | |
66 | #include "reentrant.h" | | 66 | #include "reentrant.h" |
67 | #include "local.h" | | 67 | #include "local.h" |
68 | #include "extern.h" | | 68 | #include "extern.h" |
69 | #include "fvwrite.h" | | 69 | #include "fvwrite.h" |
70 | | | 70 | |
71 | #ifndef NARROW | | 71 | #ifndef NARROW |
72 | #define MCHAR_T char | | 72 | #define MCHAR_T char |
73 | #define CHAR_T wchar_t | | 73 | #define CHAR_T wchar_t |
74 | #define STRLEN(a) wcslen(a) | | 74 | #define STRLEN(a) wcslen(a) |
75 | #define MEMCHR(a, b, c) wmemchr(a, b, c) | | 75 | #define MEMCHR(a, b, c) wmemchr(a, b, c) |
76 | #define SCONV(a, b) __mbsconv(a, b) | | 76 | #define SCONV(a, b) __mbsconv(a, b) |
77 | #define STRCONST(a) L ## a | | 77 | #define STRCONST(a) L ## a |
78 | #define WDECL(a, b) a ## w ## b | | 78 | #define WDECL(a, b) a ## w ## b |
79 | #define END_OF_FILE WEOF | | 79 | #define END_OF_FILE WEOF |
80 | #define MULTI 0 | | 80 | #define MULTI 0 |
81 | #else | | 81 | #else |
82 | #define MCHAR_T wchar_t | | 82 | #define MCHAR_T wchar_t |
83 | #define CHAR_T char | | 83 | #define CHAR_T char |
84 | #define STRLEN(a) strlen(a) | | 84 | #define STRLEN(a) strlen(a) |
85 | #define MEMCHR(a, b, c) memchr(a, b, c) | | 85 | #define MEMCHR(a, b, c) memchr(a, b, c) |
86 | #define SCONV(a, b) __wcsconv(a, b) | | 86 | #define SCONV(a, b) __wcsconv(a, b) |
87 | #define STRCONST(a) a | | 87 | #define STRCONST(a) a |
88 | #define WDECL(a, b) a ## b | | 88 | #define WDECL(a, b) a ## b |
89 | #define END_OF_FILE EOF | | 89 | #define END_OF_FILE EOF |
90 | #define MULTI LONGINT | | 90 | #define MULTI LONGINT |
91 | #endif | | 91 | #endif |
92 | | | 92 | |
93 | union arg { | | 93 | union arg { |
94 | int intarg; | | 94 | int intarg; |
95 | u_int uintarg; | | 95 | u_int uintarg; |
96 | long longarg; | | 96 | long longarg; |
97 | u_long ulongarg; | | 97 | u_long ulongarg; |
98 | long long longlongarg; | | 98 | long long longlongarg; |
99 | unsigned long long ulonglongarg; | | 99 | unsigned long long ulonglongarg; |
100 | ptrdiff_t ptrdiffarg; | | 100 | ptrdiff_t ptrdiffarg; |
101 | ssize_t ssizearg; | | 101 | ssize_t ssizearg; |
102 | size_t sizearg; | | 102 | size_t sizearg; |
103 | intmax_t intmaxarg; | | 103 | intmax_t intmaxarg; |
104 | uintmax_t uintmaxarg; | | 104 | uintmax_t uintmaxarg; |
105 | void *pvoidarg; | | 105 | void *pvoidarg; |
106 | char *pchararg; | | 106 | char *pchararg; |
107 | signed char *pschararg; | | 107 | signed char *pschararg; |
108 | short *pshortarg; | | 108 | short *pshortarg; |
109 | int *pintarg; | | 109 | int *pintarg; |
110 | long *plongarg; | | 110 | long *plongarg; |
111 | long long *plonglongarg; | | 111 | long long *plonglongarg; |
112 | ptrdiff_t *pptrdiffarg; | | 112 | ptrdiff_t *pptrdiffarg; |
113 | size_t *psizearg; | | 113 | size_t *psizearg; |
114 | intmax_t *pintmaxarg; | | 114 | intmax_t *pintmaxarg; |
115 | #ifndef NO_FLOATING_POINT | | 115 | #ifndef NO_FLOATING_POINT |
116 | double doublearg; | | 116 | double doublearg; |
117 | long double longdoublearg; | | 117 | long double longdoublearg; |
118 | #endif | | 118 | #endif |
119 | wint_t wintarg; | | 119 | wint_t wintarg; |
120 | wchar_t *pwchararg; | | 120 | wchar_t *pwchararg; |
121 | }; | | 121 | }; |
122 | | | 122 | |
123 | /* | | 123 | /* |
124 | * Type ids for argument type table. | | 124 | * Type ids for argument type table. |
125 | */ | | 125 | */ |
126 | enum typeid { | | 126 | enum typeid { |
127 | T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, | | 127 | T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, |
128 | T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, | | 128 | T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, |
129 | T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SIZET, | | 129 | T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SIZET, |
130 | T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, | | 130 | T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, |
131 | T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR | | 131 | T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR |
132 | }; | | 132 | }; |
133 | | | 133 | |
134 | static int __sbprintf(FILE *, const CHAR_T *, va_list); | | 134 | static int __sbprintf(FILE *, const CHAR_T *, va_list); |
135 | static CHAR_T *__ujtoa(uintmax_t, CHAR_T *, int, int, const char *, int, | | 135 | static CHAR_T *__ujtoa(uintmax_t, CHAR_T *, int, int, const char *, int, |
136 | char, const char *); | | 136 | char, const char *); |
137 | static CHAR_T *__ultoa(u_long, CHAR_T *, int, int, const char *, int, | | 137 | static CHAR_T *__ultoa(u_long, CHAR_T *, int, int, const char *, int, |
138 | char, const char *); | | 138 | char, const char *); |
139 | #ifndef NARROW | | 139 | #ifndef NARROW |
140 | static CHAR_T *__mbsconv(char *, int); | | 140 | static CHAR_T *__mbsconv(char *, int); |
141 | static wint_t __xfputwc(CHAR_T, FILE *); | | 141 | static wint_t __xfputwc(CHAR_T, FILE *); |
142 | #else | | 142 | #else |
143 | static char *__wcsconv(wchar_t *, int); | | 143 | static char *__wcsconv(wchar_t *, int); |
144 | static int __sprint(FILE *, struct __suio *); | | 144 | static int __sprint(FILE *, struct __suio *); |
145 | #endif | | 145 | #endif |
146 | static int __find_arguments(const CHAR_T *, va_list, union arg **); | | 146 | static int __find_arguments(const CHAR_T *, va_list, union arg **); |
147 | static int __grow_type_table(int, enum typeid **, int *); | | 147 | static int __grow_type_table(int, enum typeid **, int *); |
148 | | | 148 | |
149 | /* | | 149 | /* |
150 | * Helper function for `fprintf to unbuffered unix file': creates a | | 150 | * Helper function for `fprintf to unbuffered unix file': creates a |
151 | * temporary buffer. We only work on write-only files; this avoids | | 151 | * temporary buffer. We only work on write-only files; this avoids |
152 | * worries about ungetc buffers and so forth. | | 152 | * worries about ungetc buffers and so forth. |
153 | */ | | 153 | */ |
154 | static int | | 154 | static int |
155 | __sbprintf(FILE *fp, const CHAR_T *fmt, va_list ap) | | 155 | __sbprintf(FILE *fp, const CHAR_T *fmt, va_list ap) |
156 | { | | 156 | { |
157 | int ret; | | 157 | int ret; |
158 | FILE fake; | | 158 | FILE fake; |
159 | struct __sfileext fakeext; | | 159 | struct __sfileext fakeext; |
160 | unsigned char buf[BUFSIZ]; | | 160 | unsigned char buf[BUFSIZ]; |
161 | | | 161 | |
162 | _DIAGASSERT(fp != NULL); | | 162 | _DIAGASSERT(fp != NULL); |
163 | _DIAGASSERT(fmt != NULL); | | 163 | _DIAGASSERT(fmt != NULL); |
164 | | | 164 | |
165 | _FILEEXT_SETUP(&fake, &fakeext); | | 165 | _FILEEXT_SETUP(&fake, &fakeext); |
166 | | | 166 | |
167 | /* copy the important variables */ | | 167 | /* copy the important variables */ |
168 | fake._flags = fp->_flags & ~__SNBF; | | 168 | fake._flags = fp->_flags & ~__SNBF; |
169 | fake._file = fp->_file; | | 169 | fake._file = fp->_file; |
170 | fake._cookie = fp->_cookie; | | 170 | fake._cookie = fp->_cookie; |
171 | fake._write = fp->_write; | | 171 | fake._write = fp->_write; |
172 | | | 172 | |
173 | /* set up the buffer */ | | 173 | /* set up the buffer */ |
174 | fake._bf._base = fake._p = buf; | | 174 | fake._bf._base = fake._p = buf; |
175 | fake._bf._size = fake._w = sizeof(buf); | | 175 | fake._bf._size = fake._w = sizeof(buf); |
176 | fake._lbfsize = 0; /* not actually used, but Just In Case */ | | 176 | fake._lbfsize = 0; /* not actually used, but Just In Case */ |
177 | | | 177 | |
178 | /* do the work, then copy any error status */ | | 178 | /* do the work, then copy any error status */ |
179 | ret = WDECL(__vf,printf_unlocked)(&fake, fmt, ap); | | 179 | ret = WDECL(__vf,printf_unlocked)(&fake, fmt, ap); |
180 | if (ret >= 0 && fflush(&fake)) | | 180 | if (ret >= 0 && fflush(&fake)) |
181 | ret = END_OF_FILE; | | 181 | ret = END_OF_FILE; |
182 | if (fake._flags & __SERR) | | 182 | if (fake._flags & __SERR) |
183 | fp->_flags |= __SERR; | | 183 | fp->_flags |= __SERR; |
184 | return (ret); | | 184 | return (ret); |
185 | } | | 185 | } |
186 | | | 186 | |
187 | #ifndef NARROW | | 187 | #ifndef NARROW |
188 | /* | | 188 | /* |
189 | * Like __fputwc, but handles fake string (__SSTR) files properly. | | 189 | * Like __fputwc, but handles fake string (__SSTR) files properly. |
190 | * File must already be locked. | | 190 | * File must already be locked. |
191 | */ | | 191 | */ |
192 | static wint_t | | 192 | static wint_t |
193 | __xfputwc(wchar_t wc, FILE *fp) | | 193 | __xfputwc(wchar_t wc, FILE *fp) |
194 | { | | 194 | { |
195 | static const mbstate_t initial; | | 195 | static const mbstate_t initial; |
196 | mbstate_t mbs; | | 196 | mbstate_t mbs; |
197 | char buf[MB_LEN_MAX]; | | 197 | char buf[MB_LEN_MAX]; |
198 | struct __suio uio; | | 198 | struct __suio uio; |
199 | struct __siov iov; | | 199 | struct __siov iov; |
200 | size_t len; | | 200 | size_t len; |
201 | | | 201 | |
202 | if ((fp->_flags & __SSTR) == 0) | | 202 | if ((fp->_flags & __SSTR) == 0) |
203 | return (__fputwc_unlock(wc, fp)); | | 203 | return (__fputwc_unlock(wc, fp)); |
204 | | | 204 | |
205 | mbs = initial; | | 205 | mbs = initial; |
206 | if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) { | | 206 | if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) { |
207 | fp->_flags |= __SERR; | | 207 | fp->_flags |= __SERR; |
208 | return (END_OF_FILE); | | 208 | return (END_OF_FILE); |
209 | } | | 209 | } |
210 | uio.uio_iov = &iov; | | 210 | uio.uio_iov = &iov; |
211 | uio.uio_resid = len; | | 211 | uio.uio_resid = len; |
212 | uio.uio_iovcnt = 1; | | 212 | uio.uio_iovcnt = 1; |
213 | iov.iov_base = buf; | | 213 | iov.iov_base = buf; |
214 | iov.iov_len = len; | | 214 | iov.iov_len = len; |
215 | return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : END_OF_FILE); | | 215 | return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : END_OF_FILE); |
216 | } | | 216 | } |
217 | #else | | 217 | #else |
218 | /* | | 218 | /* |
219 | * Flush out all the vectors defined by the given uio, | | 219 | * Flush out all the vectors defined by the given uio, |
220 | * then reset it so that it can be reused. | | 220 | * then reset it so that it can be reused. |
221 | */ | | 221 | */ |
222 | static int | | 222 | static int |
223 | __sprint(FILE *fp, struct __suio *uio) | | 223 | __sprint(FILE *fp, struct __suio *uio) |
224 | { | | 224 | { |
225 | int err; | | 225 | int err; |
226 | | | 226 | |
227 | _DIAGASSERT(fp != NULL); | | 227 | _DIAGASSERT(fp != NULL); |
228 | _DIAGASSERT(uio != NULL); | | 228 | _DIAGASSERT(uio != NULL); |
229 | | | 229 | |
230 | if (uio->uio_resid == 0) { | | 230 | if (uio->uio_resid == 0) { |
231 | uio->uio_iovcnt = 0; | | 231 | uio->uio_iovcnt = 0; |
232 | return (0); | | 232 | return (0); |
233 | } | | 233 | } |
234 | err = __sfvwrite(fp, uio); | | 234 | err = __sfvwrite(fp, uio); |
235 | uio->uio_resid = 0; | | 235 | uio->uio_resid = 0; |
236 | uio->uio_iovcnt = 0; | | 236 | uio->uio_iovcnt = 0; |
237 | return (err); | | 237 | return (err); |
238 | } | | 238 | } |
239 | #endif | | 239 | #endif |
240 | | | 240 | |
241 | /* | | 241 | /* |
242 | * Macros for converting digits to letters and vice versa | | 242 | * Macros for converting digits to letters and vice versa |
243 | */ | | 243 | */ |
244 | #define to_digit(c) ((c) - '0') | | 244 | #define to_digit(c) ((c) - '0') |
245 | #define is_digit(c) ((unsigned)to_digit(c) <= 9) | | 245 | #define is_digit(c) ((unsigned)to_digit(c) <= 9) |
246 | #define to_char(n) (CHAR_T)((n) + '0') | | 246 | #define to_char(n) (CHAR_T)((n) + '0') |
247 | | | 247 | |
248 | /* | | 248 | /* |
249 | * Convert an unsigned long to ASCII for printf purposes, returning | | 249 | * Convert an unsigned long to ASCII for printf purposes, returning |
250 | * a pointer to the first character of the string representation. | | 250 | * a pointer to the first character of the string representation. |
251 | * Octal numbers can be forced to have a leading zero; hex numbers | | 251 | * Octal numbers can be forced to have a leading zero; hex numbers |
252 | * use the given digits. | | 252 | * use the given digits. |
253 | */ | | 253 | */ |
254 | static CHAR_T * | | 254 | static CHAR_T * |
255 | __ultoa(u_long val, CHAR_T *endp, int base, int octzero, const char *xdigs, | | 255 | __ultoa(u_long val, CHAR_T *endp, int base, int octzero, const char *xdigs, |
256 | int needgrp, char thousep, const char *grp) | | 256 | int needgrp, char thousep, const char *grp) |
257 | { | | 257 | { |
258 | CHAR_T *cp = endp; | | 258 | CHAR_T *cp = endp; |
259 | long sval; | | 259 | long sval; |
260 | int ndig; | | 260 | int ndig; |
261 | | | 261 | |
262 | /* | | 262 | /* |
263 | * Handle the three cases separately, in the hope of getting | | 263 | * Handle the three cases separately, in the hope of getting |
264 | * better/faster code. | | 264 | * better/faster code. |
265 | */ | | 265 | */ |
266 | switch (base) { | | 266 | switch (base) { |
267 | case 10: | | 267 | case 10: |
268 | if (val < 10) { /* many numbers are 1 digit */ | | 268 | if (val < 10) { /* many numbers are 1 digit */ |
269 | *--cp = to_char(val); | | 269 | *--cp = to_char(val); |
270 | return (cp); | | 270 | return (cp); |
271 | } | | 271 | } |
272 | ndig = 0; | | 272 | ndig = 0; |
273 | /* | | 273 | /* |
274 | * On many machines, unsigned arithmetic is harder than | | 274 | * On many machines, unsigned arithmetic is harder than |
275 | * signed arithmetic, so we do at most one unsigned mod and | | 275 | * signed arithmetic, so we do at most one unsigned mod and |
276 | * divide; this is sufficient to reduce the range of | | 276 | * divide; this is sufficient to reduce the range of |
277 | * the incoming value to where signed arithmetic works. | | 277 | * the incoming value to where signed arithmetic works. |
278 | */ | | 278 | */ |
279 | if (val > LONG_MAX) { | | 279 | if (val > LONG_MAX) { |
280 | *--cp = to_char(val % 10); | | 280 | *--cp = to_char(val % 10); |
281 | ndig++; | | 281 | ndig++; |
282 | sval = val / 10; | | 282 | sval = val / 10; |
283 | } else | | 283 | } else |
284 | sval = val; | | 284 | sval = val; |
285 | do { | | 285 | do { |
286 | *--cp = to_char(sval % 10); | | 286 | *--cp = to_char(sval % 10); |
287 | ndig++; | | 287 | ndig++; |
288 | /* | | 288 | /* |
289 | * If (*grp == CHAR_MAX) then no more grouping | | 289 | * If (*grp == CHAR_MAX) then no more grouping |
290 | * should be performed. | | 290 | * should be performed. |
291 | */ | | 291 | */ |
292 | if (needgrp && ndig == *grp && *grp != CHAR_MAX | | 292 | if (needgrp && ndig == *grp && *grp != CHAR_MAX |
293 | && sval > 9) { | | 293 | && sval > 9) { |
294 | *--cp = thousep; | | 294 | *--cp = thousep; |
295 | ndig = 0; | | 295 | ndig = 0; |
296 | /* | | 296 | /* |
297 | * If (*(grp+1) == '\0') then we have to | | 297 | * If (*(grp+1) == '\0') then we have to |
298 | * use *grp character (last grouping rule) | | 298 | * use *grp character (last grouping rule) |
299 | * for all next cases | | 299 | * for all next cases |
300 | */ | | 300 | */ |
301 | if (*(grp+1) != '\0') | | 301 | if (*(grp+1) != '\0') |
302 | grp++; | | 302 | grp++; |
303 | } | | 303 | } |
304 | sval /= 10; | | 304 | sval /= 10; |
305 | } while (sval != 0); | | 305 | } while (sval != 0); |
306 | break; | | 306 | break; |
307 | | | 307 | |
308 | case 8: | | 308 | case 8: |
309 | do { | | 309 | do { |
310 | *--cp = to_char(val & 7); | | 310 | *--cp = to_char(val & 7); |
311 | val >>= 3; | | 311 | val >>= 3; |
312 | } while (val); | | 312 | } while (val); |
313 | if (octzero && *cp != '0') | | 313 | if (octzero && *cp != '0') |
314 | *--cp = '0'; | | 314 | *--cp = '0'; |
315 | break; | | 315 | break; |
316 | | | 316 | |
317 | case 16: | | 317 | case 16: |
318 | do { | | 318 | do { |
319 | *--cp = xdigs[(size_t)val & 15]; | | 319 | *--cp = xdigs[(size_t)val & 15]; |
320 | val >>= 4; | | 320 | val >>= 4; |
321 | } while (val); | | 321 | } while (val); |
322 | break; | | 322 | break; |
323 | | | 323 | |
324 | default: /* oops */ | | 324 | default: /* oops */ |
325 | abort(); | | 325 | abort(); |
326 | } | | 326 | } |
327 | return (cp); | | 327 | return (cp); |
328 | } | | 328 | } |
329 | | | 329 | |
330 | /* Identical to __ultoa, but for intmax_t. */ | | 330 | /* Identical to __ultoa, but for intmax_t. */ |
331 | static CHAR_T * | | 331 | static CHAR_T * |
332 | __ujtoa(uintmax_t val, CHAR_T *endp, int base, int octzero, | | 332 | __ujtoa(uintmax_t val, CHAR_T *endp, int base, int octzero, |
333 | const char *xdigs, int needgrp, char thousep, const char *grp) | | 333 | const char *xdigs, int needgrp, char thousep, const char *grp) |
334 | { | | 334 | { |
335 | CHAR_T *cp = endp; | | 335 | CHAR_T *cp = endp; |
336 | intmax_t sval; | | 336 | intmax_t sval; |
337 | int ndig; | | 337 | int ndig; |
338 | | | 338 | |
339 | /* quick test for small values; __ultoa is typically much faster */ | | 339 | /* quick test for small values; __ultoa is typically much faster */ |
340 | /* (perhaps instead we should run until small, then call __ultoa?) */ | | 340 | /* (perhaps instead we should run until small, then call __ultoa?) */ |
341 | if (val <= ULONG_MAX) | | 341 | if (val <= ULONG_MAX) |
342 | return (__ultoa((u_long)val, endp, base, octzero, xdigs, | | 342 | return (__ultoa((u_long)val, endp, base, octzero, xdigs, |
343 | needgrp, thousep, grp)); | | 343 | needgrp, thousep, grp)); |
344 | switch (base) { | | 344 | switch (base) { |
345 | case 10: | | 345 | case 10: |
346 | if (val < 10) { | | 346 | if (val < 10) { |
347 | *--cp = to_char(val % 10); | | 347 | *--cp = to_char(val % 10); |
348 | return (cp); | | 348 | return (cp); |
349 | } | | 349 | } |
350 | ndig = 0; | | 350 | ndig = 0; |
351 | if (val > INTMAX_MAX) { | | 351 | if (val > INTMAX_MAX) { |
352 | *--cp = to_char(val % 10); | | 352 | *--cp = to_char(val % 10); |
353 | ndig++; | | 353 | ndig++; |
354 | sval = val / 10; | | 354 | sval = val / 10; |
355 | } else | | 355 | } else |
356 | sval = val; | | 356 | sval = val; |
357 | do { | | 357 | do { |
358 | *--cp = to_char(sval % 10); | | 358 | *--cp = to_char(sval % 10); |
359 | ndig++; | | 359 | ndig++; |
360 | /* | | 360 | /* |
361 | * If (*grp == CHAR_MAX) then no more grouping | | 361 | * If (*grp == CHAR_MAX) then no more grouping |
362 | * should be performed. | | 362 | * should be performed. |
363 | */ | | 363 | */ |
364 | if (needgrp && *grp != CHAR_MAX && ndig == *grp | | 364 | if (needgrp && *grp != CHAR_MAX && ndig == *grp |
365 | && sval > 9) { | | 365 | && sval > 9) { |
366 | *--cp = thousep; | | 366 | *--cp = thousep; |
367 | ndig = 0; | | 367 | ndig = 0; |
368 | /* | | 368 | /* |
369 | * If (*(grp+1) == '\0') then we have to | | 369 | * If (*(grp+1) == '\0') then we have to |
370 | * use *grp character (last grouping rule) | | 370 | * use *grp character (last grouping rule) |
371 | * for all next cases | | 371 | * for all next cases |
372 | */ | | 372 | */ |
373 | if (*(grp+1) != '\0') | | 373 | if (*(grp+1) != '\0') |
374 | grp++; | | 374 | grp++; |
375 | } | | 375 | } |
376 | sval /= 10; | | 376 | sval /= 10; |
377 | } while (sval != 0); | | 377 | } while (sval != 0); |
378 | break; | | 378 | break; |
379 | | | 379 | |
380 | case 8: | | 380 | case 8: |
381 | do { | | 381 | do { |
382 | *--cp = to_char(val & 7); | | 382 | *--cp = to_char(val & 7); |
383 | val >>= 3; | | 383 | val >>= 3; |
384 | } while (val); | | 384 | } while (val); |
385 | if (octzero && *cp != '0') | | 385 | if (octzero && *cp != '0') |
386 | *--cp = '0'; | | 386 | *--cp = '0'; |
387 | break; | | 387 | break; |
388 | | | 388 | |
389 | case 16: | | 389 | case 16: |
390 | do { | | 390 | do { |
391 | *--cp = xdigs[(size_t)val & 15]; | | 391 | *--cp = xdigs[(size_t)val & 15]; |
392 | val >>= 4; | | 392 | val >>= 4; |
393 | } while (val); | | 393 | } while (val); |
394 | break; | | 394 | break; |
395 | | | 395 | |
396 | default: | | 396 | default: |
397 | abort(); | | 397 | abort(); |
398 | } | | 398 | } |
399 | return (cp); | | 399 | return (cp); |
400 | } | | 400 | } |
401 | | | 401 | |
402 | #ifndef NARROW | | 402 | #ifndef NARROW |
403 | /* | | 403 | /* |
404 | * Convert a multibyte character string argument for the %s format to a wide | | 404 | * Convert a multibyte character string argument for the %s format to a wide |
405 | * string representation. ``prec'' specifies the maximum number of bytes | | 405 | * string representation. ``prec'' specifies the maximum number of bytes |
406 | * to output. If ``prec'' is greater than or equal to zero, we can't assume | | 406 | * to output. If ``prec'' is greater than or equal to zero, we can't assume |
407 | * that the multibyte char. string ends in a null character. | | 407 | * that the multibyte char. string ends in a null character. |
408 | */ | | 408 | */ |
409 | static wchar_t * | | 409 | static wchar_t * |
410 | __mbsconv(char *mbsarg, int prec) | | 410 | __mbsconv(char *mbsarg, int prec) |
411 | { | | 411 | { |
412 | static const mbstate_t initial; | | 412 | static const mbstate_t initial; |
413 | mbstate_t mbs; | | 413 | mbstate_t mbs; |
414 | wchar_t *convbuf, *wcp; | | 414 | wchar_t *convbuf, *wcp; |
415 | const char *p; | | 415 | const char *p; |
416 | size_t insize, nchars, nconv; | | 416 | size_t insize, nchars, nconv; |
417 | | | 417 | |
418 | if (mbsarg == NULL) | | 418 | if (mbsarg == NULL) |
419 | return (NULL); | | 419 | return (NULL); |
420 | | | 420 | |
421 | /* | | 421 | /* |
422 | * Supplied argument is a multibyte string; convert it to wide | | 422 | * Supplied argument is a multibyte string; convert it to wide |
423 | * characters first. | | 423 | * characters first. |
424 | */ | | 424 | */ |
425 | if (prec >= 0) { | | 425 | if (prec >= 0) { |
426 | /* | | 426 | /* |
427 | * String is not guaranteed to be NUL-terminated. Find the | | 427 | * String is not guaranteed to be NUL-terminated. Find the |
428 | * number of characters to print. | | 428 | * number of characters to print. |
429 | */ | | 429 | */ |
430 | p = mbsarg; | | 430 | p = mbsarg; |
431 | insize = nchars = nconv = 0; | | 431 | insize = nchars = nconv = 0; |
432 | mbs = initial; | | 432 | mbs = initial; |
433 | while (nchars != (size_t)prec) { | | 433 | while (nchars != (size_t)prec) { |
434 | nconv = mbrlen(p, MB_CUR_MAX, &mbs); | | 434 | nconv = mbrlen(p, MB_CUR_MAX, &mbs); |
435 | if (nconv == 0 || nconv == (size_t)-1 || | | 435 | if (nconv == 0 || nconv == (size_t)-1 || |
436 | nconv == (size_t)-2) | | 436 | nconv == (size_t)-2) |
437 | break; | | 437 | break; |
438 | p += nconv; | | 438 | p += nconv; |
439 | nchars++; | | 439 | nchars++; |
440 | insize += nconv; | | 440 | insize += nconv; |
441 | } | | 441 | } |
442 | if (nconv == (size_t)-1 || nconv == (size_t)-2) | | 442 | if (nconv == (size_t)-1 || nconv == (size_t)-2) |
443 | return (NULL); | | 443 | return (NULL); |
444 | } else | | 444 | } else |
445 | insize = strlen(mbsarg); | | 445 | insize = strlen(mbsarg); |
446 | | | 446 | |
447 | /* | | 447 | /* |
448 | * Allocate buffer for the result and perform the conversion, | | 448 | * Allocate buffer for the result and perform the conversion, |
449 | * converting at most `size' bytes of the input multibyte string to | | 449 | * converting at most `size' bytes of the input multibyte string to |
450 | * wide characters for printing. | | 450 | * wide characters for printing. |
451 | */ | | 451 | */ |
452 | convbuf = malloc((insize + 1) * sizeof(*convbuf)); | | 452 | convbuf = malloc((insize + 1) * sizeof(*convbuf)); |
453 | if (convbuf == NULL) | | 453 | if (convbuf == NULL) |
454 | return (NULL); | | 454 | return (NULL); |
455 | wcp = convbuf; | | 455 | wcp = convbuf; |
456 | p = mbsarg; | | 456 | p = mbsarg; |
457 | mbs = initial; | | 457 | mbs = initial; |
458 | nconv = 0; | | 458 | nconv = 0; |
459 | while (insize != 0) { | | 459 | while (insize != 0) { |
460 | nconv = mbrtowc(wcp, p, insize, &mbs); | | 460 | nconv = mbrtowc(wcp, p, insize, &mbs); |
461 | if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) | | 461 | if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) |
462 | break; | | 462 | break; |
463 | wcp++; | | 463 | wcp++; |
464 | p += nconv; | | 464 | p += nconv; |
465 | insize -= nconv; | | 465 | insize -= nconv; |
466 | } | | 466 | } |
467 | if (nconv == (size_t)-1 || nconv == (size_t)-2) { | | 467 | if (nconv == (size_t)-1 || nconv == (size_t)-2) { |
468 | free(convbuf); | | 468 | free(convbuf); |
469 | return (NULL); | | 469 | return (NULL); |
470 | } | | 470 | } |
471 | *wcp = L'\0'; | | 471 | *wcp = L'\0'; |
472 | | | 472 | |
473 | return (convbuf); | | 473 | return (convbuf); |
474 | } | | 474 | } |
475 | #else | | 475 | #else |
476 | /* | | 476 | /* |
477 | * Convert a wide character string argument for the %ls format to a multibyte | | 477 | * Convert a wide character string argument for the %ls format to a multibyte |
478 | * string representation. If not -1, prec specifies the maximum number of | | 478 | * string representation. If not -1, prec specifies the maximum number of |
479 | * bytes to output, and also means that we can't assume that the wide char. | | 479 | * bytes to output, and also means that we can't assume that the wide char. |
480 | * string ends is null-terminated. | | 480 | * string ends is null-terminated. |
481 | */ | | 481 | */ |
482 | static char * | | 482 | static char * |
483 | __wcsconv(wchar_t *wcsarg, int prec) | | 483 | __wcsconv(wchar_t *wcsarg, int prec) |
484 | { | | 484 | { |
485 | static const mbstate_t initial; | | 485 | static const mbstate_t initial; |
486 | mbstate_t mbs; | | 486 | mbstate_t mbs; |
487 | char buf[MB_LEN_MAX]; | | 487 | char buf[MB_LEN_MAX]; |
488 | wchar_t *p; | | 488 | wchar_t *p; |
489 | char *convbuf; | | 489 | char *convbuf; |
490 | size_t clen, nbytes; | | 490 | size_t clen, nbytes; |
491 | | | 491 | |
492 | /* Allocate space for the maximum number of bytes we could output. */ | | 492 | /* Allocate space for the maximum number of bytes we could output. */ |
493 | if (prec < 0) { | | 493 | if (prec < 0) { |
494 | p = wcsarg; | | 494 | p = wcsarg; |
495 | mbs = initial; | | 495 | mbs = initial; |
496 | nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); | | 496 | nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); |
497 | if (nbytes == (size_t)-1) | | 497 | if (nbytes == (size_t)-1) |
498 | return (NULL); | | 498 | return (NULL); |
499 | } else { | | 499 | } else { |
500 | /* | | 500 | /* |
501 | * Optimisation: if the output precision is small enough, | | 501 | * Optimisation: if the output precision is small enough, |
502 | * just allocate enough memory for the maximum instead of | | 502 | * just allocate enough memory for the maximum instead of |
503 | * scanning the string. | | 503 | * scanning the string. |
504 | */ | | 504 | */ |
505 | if (prec < 128) | | 505 | if (prec < 128) |
506 | nbytes = prec; | | 506 | nbytes = prec; |
507 | else { | | 507 | else { |
508 | nbytes = 0; | | 508 | nbytes = 0; |
509 | p = wcsarg; | | 509 | p = wcsarg; |
510 | mbs = initial; | | 510 | mbs = initial; |
511 | for (;;) { | | 511 | for (;;) { |
512 | clen = wcrtomb(buf, *p++, &mbs); | | 512 | clen = wcrtomb(buf, *p++, &mbs); |
513 | if (clen == 0 || clen == (size_t)-1 || | | 513 | if (clen == 0 || clen == (size_t)-1 || |
514 | nbytes + clen > (size_t)prec) | | 514 | nbytes + clen > (size_t)prec) |
515 | break; | | 515 | break; |
516 | nbytes += clen; | | 516 | nbytes += clen; |
517 | } | | 517 | } |
518 | } | | 518 | } |
519 | } | | 519 | } |
520 | if ((convbuf = malloc(nbytes + 1)) == NULL) | | 520 | if ((convbuf = malloc(nbytes + 1)) == NULL) |
521 | return (NULL); | | 521 | return (NULL); |
522 | | | 522 | |
523 | /* Fill the output buffer. */ | | 523 | /* Fill the output buffer. */ |
524 | p = wcsarg; | | 524 | p = wcsarg; |
525 | mbs = initial; | | 525 | mbs = initial; |
526 | if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, | | 526 | if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, |
527 | nbytes, &mbs)) == (size_t)-1) { | | 527 | nbytes, &mbs)) == (size_t)-1) { |
528 | free(convbuf); | | 528 | free(convbuf); |
529 | return (NULL); | | 529 | return (NULL); |
530 | } | | 530 | } |
531 | convbuf[nbytes] = '\0'; | | 531 | convbuf[nbytes] = '\0'; |
532 | return (convbuf); | | 532 | return (convbuf); |
533 | } | | 533 | } |
534 | #endif | | 534 | #endif |
535 | | | 535 | |
536 | /* | | 536 | /* |
537 | * MT-safe version | | 537 | * MT-safe version |
538 | */ | | 538 | */ |
539 | int | | 539 | int |
540 | WDECL(vf,printf)(FILE * __restrict fp, const CHAR_T * __restrict fmt0, va_list ap) | | 540 | WDECL(vf,printf)(FILE * __restrict fp, const CHAR_T * __restrict fmt0, va_list ap) |
541 | { | | 541 | { |
542 | int ret; | | 542 | int ret; |
543 | | | 543 | |
544 | FLOCKFILE(fp); | | 544 | FLOCKFILE(fp); |
545 | ret = WDECL(__vf,printf_unlocked)(fp, fmt0, ap); | | 545 | ret = WDECL(__vf,printf_unlocked)(fp, fmt0, ap); |
546 | FUNLOCKFILE(fp); | | 546 | FUNLOCKFILE(fp); |
547 | return (ret); | | 547 | return (ret); |
548 | } | | 548 | } |
549 | | | 549 | |
550 | #ifndef NO_FLOATING_POINT | | 550 | #ifndef NO_FLOATING_POINT |
551 | | | 551 | |
552 | #include <float.h> | | 552 | #include <float.h> |
553 | #include <math.h> | | 553 | #include <math.h> |
554 | #include "floatio.h" | | 554 | #include "floatio.h" |
555 | | | 555 | |
556 | #define DEFPREC 6 | | 556 | #define DEFPREC 6 |
557 | | | 557 | |
558 | static int exponent(CHAR_T *, int, int); | | 558 | static int exponent(CHAR_T *, int, int); |
559 | #ifndef WIDE_DOUBLE | | 559 | #ifndef WIDE_DOUBLE |
560 | static char *cvt(double, int, int, char *, int *, int, int *); | | 560 | static char *cvt(double, int, int, char *, int *, int, int *); |
561 | #endif | | 561 | #endif |
562 | | | 562 | |
563 | #endif /* !NO_FLOATING_POINT */ | | 563 | #endif /* !NO_FLOATING_POINT */ |
564 | | | 564 | |
565 | /* | | 565 | /* |
566 | * The size of the buffer we use as scratch space for integer | | 566 | * The size of the buffer we use as scratch space for integer |
567 | * conversions, among other things. Technically, we would need the | | 567 | * conversions, among other things. Technically, we would need the |
568 | * most space for base 10 conversions with thousands' grouping | | 568 | * most space for base 10 conversions with thousands' grouping |
569 | * characters between each pair of digits. 100 bytes is a | | 569 | * characters between each pair of digits. 100 bytes is a |
570 | * conservative overestimate even for a 128-bit uintmax_t. | | 570 | * conservative overestimate even for a 128-bit uintmax_t. |
571 | */ | | 571 | */ |
572 | #define BUF 100 | | 572 | #define BUF 100 |
573 | | | 573 | |
574 | #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ | | 574 | #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ |
575 | | | 575 | |
576 | /* | | 576 | /* |
577 | * Flags used during conversion. | | 577 | * Flags used during conversion. |
578 | */ | | 578 | */ |
579 | #define ALT 0x001 /* alternate form */ | | 579 | #define ALT 0x001 /* alternate form */ |
580 | #define LADJUST 0x004 /* left adjustment */ | | 580 | #define LADJUST 0x004 /* left adjustment */ |
581 | #define LONGDBL 0x008 /* long double */ | | 581 | #define LONGDBL 0x008 /* long double */ |
582 | #define LONGINT 0x010 /* long integer */ | | 582 | #define LONGINT 0x010 /* long integer */ |
583 | #define LLONGINT 0x020 /* long long integer */ | | 583 | #define LLONGINT 0x020 /* long long integer */ |
584 | #define SHORTINT 0x040 /* short integer */ | | 584 | #define SHORTINT 0x040 /* short integer */ |
585 | #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ | | 585 | #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ |
586 | #define FPT 0x100 /* Floating point number */ | | 586 | #define FPT 0x100 /* Floating point number */ |
587 | #define GROUPING 0x200 /* use grouping ("'" flag) */ | | 587 | #define GROUPING 0x200 /* use grouping ("'" flag) */ |
588 | /* C99 additional size modifiers: */ | | 588 | /* C99 additional size modifiers: */ |
589 | #define SIZET 0x400 /* size_t */ | | 589 | #define SIZET 0x400 /* size_t */ |
590 | #define PTRDIFFT 0x800 /* ptrdiff_t */ | | 590 | #define PTRDIFFT 0x800 /* ptrdiff_t */ |
591 | #define INTMAXT 0x1000 /* intmax_t */ | | 591 | #define INTMAXT 0x1000 /* intmax_t */ |
592 | #define CHARINT 0x2000 /* print char using int format */ | | 592 | #define CHARINT 0x2000 /* print char using int format */ |
593 | | | 593 | |
594 | /* | | 594 | /* |
595 | * Non-MT-safe version | | 595 | * Non-MT-safe version |
596 | */ | | 596 | */ |
597 | int | | 597 | int |
598 | WDECL(__vf,printf_unlocked)(FILE *fp, const CHAR_T *fmt0, va_list ap) | | 598 | WDECL(__vf,printf_unlocked)(FILE *fp, const CHAR_T *fmt0, va_list ap) |
599 | { | | 599 | { |
600 | CHAR_T *fmt; /* format string */ | | 600 | CHAR_T *fmt; /* format string */ |
601 | int ch; /* character from fmt */ | | 601 | int ch; /* character from fmt */ |
602 | int n, n2; /* handy integer (short term usage) */ | | 602 | int n, n2; /* handy integer (short term usage) */ |
603 | CHAR_T *cp; /* handy char pointer (short term usage) */ | | 603 | CHAR_T *cp; /* handy char pointer (short term usage) */ |
604 | int flags; /* flags as above */ | | 604 | int flags; /* flags as above */ |
605 | int ret; /* return value accumulator */ | | 605 | int ret; /* return value accumulator */ |
606 | int width; /* width from format (%8d), or 0 */ | | 606 | int width; /* width from format (%8d), or 0 */ |
607 | int prec; /* precision from format; <0 for N/A */ | | 607 | int prec; /* precision from format; <0 for N/A */ |
608 | CHAR_T sign; /* sign prefix (' ', '+', '-', or \0) */ | | 608 | CHAR_T sign; /* sign prefix (' ', '+', '-', or \0) */ |
609 | char thousands_sep; /* locale specific thousands separator */ | | 609 | char thousands_sep; /* locale specific thousands separator */ |
610 | const char *grouping; /* locale specific numeric grouping rules */ | | 610 | const char *grouping; /* locale specific numeric grouping rules */ |
611 | #ifndef NO_FLOATING_POINT | | 611 | #ifndef NO_FLOATING_POINT |
612 | /* | | 612 | /* |
613 | * We can decompose the printed representation of floating | | 613 | * We can decompose the printed representation of floating |
614 | * point numbers into several parts, some of which may be empty: | | 614 | * point numbers into several parts, some of which may be empty: |
615 | * | | 615 | * |
616 | * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ | | 616 | * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ |
617 | * A B ---C--- D E F | | 617 | * A B ---C--- D E F |
618 | * | | 618 | * |
619 | * A: 'sign' holds this value if present; '\0' otherwise | | 619 | * A: 'sign' holds this value if present; '\0' otherwise |
620 | * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal | | 620 | * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal |
621 | * C: cp points to the string MMMNNN. Leading and trailing | | 621 | * C: cp points to the string MMMNNN. Leading and trailing |
622 | * zeros are not in the string and must be added. | | 622 | * zeros are not in the string and must be added. |
623 | * D: expchar holds this character; '\0' if no exponent, e.g. %f | | 623 | * D: expchar holds this character; '\0' if no exponent, e.g. %f |
624 | * F: at least two digits for decimal, at least one digit for hex | | 624 | * F: at least two digits for decimal, at least one digit for hex |
625 | */ | | 625 | */ |
626 | char *decimal_point; /* locale specific decimal point */ | | 626 | char *decimal_point; /* locale specific decimal point */ |
627 | #ifdef WIDE_DOUBLE | | 627 | #ifdef WIDE_DOUBLE |
628 | int signflag; /* true if float is negative */ | | 628 | int signflag; /* true if float is negative */ |
629 | union { /* floating point arguments %[aAeEfFgG] */ | | 629 | union { /* floating point arguments %[aAeEfFgG] */ |
630 | double dbl; | | 630 | double dbl; |
631 | long double ldbl; | | 631 | long double ldbl; |
632 | } fparg; | | 632 | } fparg; |
633 | char *dtoaend; /* pointer to end of converted digits */ | | 633 | char *dtoaend; /* pointer to end of converted digits */ |
634 | #else | | 634 | #else |
635 | double _double; /* double precision arguments %[eEfgG] */ | | 635 | double _double; /* double precision arguments %[eEfgG] */ |
636 | char softsign; /* temporary negative sign for floats */ | | 636 | char softsign; /* temporary negative sign for floats */ |
637 | #endif | | 637 | #endif |
638 | char *dtoaresult; /* buffer allocated by dtoa */ | | 638 | char *dtoaresult; /* buffer allocated by dtoa */ |
639 | int expt; /* integer value of exponent */ | | 639 | int expt; /* integer value of exponent */ |
640 | char expchar; /* exponent character: [eEpP\0] */ | | 640 | char expchar; /* exponent character: [eEpP\0] */ |
641 | int expsize; /* character count for expstr */ | | 641 | int expsize; /* character count for expstr */ |
642 | int lead; /* sig figs before decimal or group sep */ | | 642 | int lead; /* sig figs before decimal or group sep */ |
643 | int ndig; /* actual number of digits returned by dtoa */ | | 643 | int ndig; /* actual number of digits returned by dtoa */ |
644 | CHAR_T expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ | | 644 | CHAR_T expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ |
645 | int nseps; /* number of group separators with ' */ | | 645 | int nseps; /* number of group separators with ' */ |
646 | int nrepeats; /* number of repeats of the last group */ | | 646 | int nrepeats; /* number of repeats of the last group */ |
647 | #endif | | 647 | #endif |
648 | u_long ulval; /* integer arguments %[diouxX] */ | | 648 | u_long ulval; /* integer arguments %[diouxX] */ |
649 | uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ | | 649 | uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ |
650 | int base; /* base for [diouxX] conversion */ | | 650 | int base; /* base for [diouxX] conversion */ |
651 | int dprec; /* a copy of prec if [diouxX], 0 otherwise */ | | 651 | int dprec; /* a copy of prec if [diouxX], 0 otherwise */ |
652 | int realsz; /* field size expanded by dprec, sign, etc */ | | 652 | int realsz; /* field size expanded by dprec, sign, etc */ |
653 | int size; /* size of converted field or string */ | | 653 | int size; /* size of converted field or string */ |
654 | int prsize; /* max size of printed field */ | | 654 | int prsize; /* max size of printed field */ |
655 | const char *xdigs; /* digits for %[xX] conversion */ | | 655 | const char *xdigs; /* digits for %[xX] conversion */ |
656 | #ifdef NARROW | | 656 | #ifdef NARROW |
657 | #define NIOV 8 | | 657 | #define NIOV 8 |
658 | struct __siov *iovp; /* for PRINT macro */ | | 658 | struct __siov *iovp; /* for PRINT macro */ |
659 | struct __suio uio; /* output information: summary */ | | 659 | struct __suio uio; /* output information: summary */ |
660 | struct __siov iov[NIOV];/* ... and individual io vectors */ | | 660 | struct __siov iov[NIOV];/* ... and individual io vectors */ |
661 | #else | | 661 | #else |
662 | int n3; | | 662 | int n3; |
663 | #endif | | 663 | #endif |
664 | CHAR_T buf[BUF]; /* buffer with space for digits of uintmax_t */ | | 664 | CHAR_T buf[BUF]; /* buffer with space for digits of uintmax_t */ |
665 | CHAR_T ox[2]; /* space for 0x hex-prefix */ | | 665 | CHAR_T ox[2]; /* space for 0x hex-prefix */ |
666 | union arg *argtable; /* args, built due to positional arg */ | | 666 | union arg *argtable; /* args, built due to positional arg */ |
667 | union arg statargtable [STATIC_ARG_TBL_SIZE]; | | 667 | union arg statargtable [STATIC_ARG_TBL_SIZE]; |
668 | int nextarg; /* 1-based argument index */ | | 668 | int nextarg; /* 1-based argument index */ |
669 | va_list orgap; /* original argument pointer */ | | 669 | va_list orgap; /* original argument pointer */ |
670 | CHAR_T *convbuf; /* multibyte to wide conversion result */ | | 670 | CHAR_T *convbuf; /* multibyte to wide conversion result */ |
671 | | | 671 | |
672 | /* | | 672 | /* |
673 | * Choose PADSIZE to trade efficiency vs. size. If larger printf | | 673 | * Choose PADSIZE to trade efficiency vs. size. If larger printf |
674 | * fields occur frequently, increase PADSIZE and make the initialisers | | 674 | * fields occur frequently, increase PADSIZE and make the initialisers |
675 | * below longer. | | 675 | * below longer. |
676 | */ | | 676 | */ |
677 | #define PADSIZE 16 /* pad chunk size */ | | 677 | #define PADSIZE 16 /* pad chunk size */ |
678 | static CHAR_T blanks[PADSIZE] = | | 678 | static CHAR_T blanks[PADSIZE] = |
679 | {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; | | 679 | {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; |
680 | static CHAR_T zeroes[PADSIZE] = | | 680 | static CHAR_T zeroes[PADSIZE] = |
681 | {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; | | 681 | {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; |
682 | | | 682 | |
683 | static const char xdigs_lower[16] = "0123456789abcdef"; | | 683 | static const char xdigs_lower[16] = "0123456789abcdef"; |
684 | static const char xdigs_upper[16] = "0123456789ABCDEF"; | | 684 | static const char xdigs_upper[16] = "0123456789ABCDEF"; |
685 | | | 685 | |
686 | /* | | 686 | /* |
687 | * BEWARE, these `goto error' on error, PRINT uses `n2' and | | 687 | * BEWARE, these `goto error' on error, PRINT uses `n2' and |
688 | * PAD uses `n'. | | 688 | * PAD uses `n'. |
689 | */ | | 689 | */ |
690 | #ifndef NARROW | | 690 | #ifndef NARROW |
691 | #define PRINT(ptr, len) do { \ | | 691 | #define PRINT(ptr, len) do { \ |
692 | for (n3 = 0; n3 < (len); n3++) \ | | 692 | for (n3 = 0; n3 < (len); n3++) \ |
693 | __xfputwc((ptr)[n3], fp); \ | | 693 | __xfputwc((ptr)[n3], fp); \ |
694 | } while (/*CONSTCOND*/0) | | 694 | } while (/*CONSTCOND*/0) |
695 | #define FLUSH() | | 695 | #define FLUSH() |
696 | #else | | 696 | #else |
697 | #define PRINT(ptr, len) do { \ | | 697 | #define PRINT(ptr, len) do { \ |
698 | iovp->iov_base = __UNCONST(ptr); \ | | 698 | iovp->iov_base = __UNCONST(ptr); \ |
699 | iovp->iov_len = (len); \ | | 699 | iovp->iov_len = (len); \ |
700 | uio.uio_resid += (len); \ | | 700 | uio.uio_resid += (len); \ |
701 | iovp++; \ | | 701 | iovp++; \ |
702 | if (++uio.uio_iovcnt >= NIOV) { \ | | 702 | if (++uio.uio_iovcnt >= NIOV) { \ |
703 | if (__sprint(fp, &uio)) \ | | 703 | if (__sprint(fp, &uio)) \ |
704 | goto error; \ | | 704 | goto error; \ |
705 | iovp = iov; \ | | 705 | iovp = iov; \ |
706 | } \ | | 706 | } \ |
707 | } while (/*CONSTCOND*/0) | | 707 | } while (/*CONSTCOND*/0) |
708 | #define FLUSH() do { \ | | 708 | #define FLUSH() do { \ |
709 | if (uio.uio_resid && __sprint(fp, &uio)) \ | | 709 | if (uio.uio_resid && __sprint(fp, &uio)) \ |
710 | goto error; \ | | 710 | goto error; \ |
711 | uio.uio_iovcnt = 0; \ | | 711 | uio.uio_iovcnt = 0; \ |
712 | iovp = iov; \ | | 712 | iovp = iov; \ |
713 | } while (/*CONSTCOND*/0) | | 713 | } while (/*CONSTCOND*/0) |
714 | #endif /* NARROW */ | | 714 | #endif /* NARROW */ |
715 | | | 715 | |
716 | #define PAD(howmany, with) do { \ | | 716 | #define PAD(howmany, with) do { \ |
717 | if ((n = (howmany)) > 0) { \ | | 717 | if ((n = (howmany)) > 0) { \ |
718 | while (n > PADSIZE) { \ | | 718 | while (n > PADSIZE) { \ |
719 | PRINT(with, PADSIZE); \ | | 719 | PRINT(with, PADSIZE); \ |
720 | n -= PADSIZE; \ | | 720 | n -= PADSIZE; \ |
721 | } \ | | 721 | } \ |
722 | PRINT(with, n); \ | | 722 | PRINT(with, n); \ |
723 | } \ | | 723 | } \ |
724 | } while (/*CONSTCOND*/0) | | 724 | } while (/*CONSTCOND*/0) |
725 | #define PRINTANDPAD(p, ep, len, with) do { \ | | 725 | #define PRINTANDPAD(p, ep, len, with) do { \ |
726 | n2 = (ep) - (p); \ | | 726 | n2 = (ep) - (p); \ |
727 | if (n2 > (len)) \ | | 727 | if (n2 > (len)) \ |
728 | n2 = (len); \ | | 728 | n2 = (len); \ |
729 | if (n2 > 0) \ | | 729 | if (n2 > 0) \ |
730 | PRINT((p), n2); \ | | 730 | PRINT((p), n2); \ |
731 | PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ | | 731 | PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ |
732 | } while(/*CONSTCOND*/0) | | 732 | } while(/*CONSTCOND*/0) |
733 | | | 733 | |
734 | /* | | 734 | /* |
735 | * Get the argument indexed by nextarg. If the argument table is | | 735 | * Get the argument indexed by nextarg. If the argument table is |
736 | * built, use it to get the argument. If its not, get the next | | 736 | * built, use it to get the argument. If its not, get the next |
737 | * argument (and arguments must be gotten sequentially). | | 737 | * argument (and arguments must be gotten sequentially). |
738 | */ | | 738 | */ |
739 | #define GETARG(type) \ | | 739 | #define GETARG(type) \ |
740 | ((/*CONSTCOND*/argtable != NULL) ? *((type*)(void*)(&argtable[nextarg++])) : \ | | 740 | ((/*CONSTCOND*/argtable != NULL) ? *((type*)(void*)(&argtable[nextarg++])) : \ |
741 | (nextarg++, va_arg(ap, type))) | | 741 | (nextarg++, va_arg(ap, type))) |
742 | | | 742 | |
743 | /* | | 743 | /* |
744 | * To extend shorts properly, we need both signed and unsigned | | 744 | * To extend shorts properly, we need both signed and unsigned |
745 | * argument extraction methods. | | 745 | * argument extraction methods. |
746 | */ | | 746 | */ |
747 | #define SARG() \ | | 747 | #define SARG() \ |
748 | (flags&LONGINT ? GETARG(long) : \ | | 748 | (flags&LONGINT ? GETARG(long) : \ |
749 | flags&SHORTINT ? (long)(short)GETARG(int) : \ | | 749 | flags&SHORTINT ? (long)(short)GETARG(int) : \ |
750 | flags&CHARINT ? (long)(signed char)GETARG(int) : \ | | 750 | flags&CHARINT ? (long)(signed char)GETARG(int) : \ |
751 | (long)GETARG(int)) | | 751 | (long)GETARG(int)) |
752 | #define UARG() \ | | 752 | #define UARG() \ |
753 | (flags&LONGINT ? GETARG(u_long) : \ | | 753 | (flags&LONGINT ? GETARG(u_long) : \ |
754 | flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ | | 754 | flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ |
755 | flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ | | 755 | flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ |
756 | (u_long)GETARG(u_int)) | | 756 | (u_long)GETARG(u_int)) |
757 | #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) | | 757 | #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) |
758 | #define SJARG() \ | | 758 | #define SJARG() \ |
759 | (flags&INTMAXT ? GETARG(intmax_t) : \ | | 759 | (flags&INTMAXT ? GETARG(intmax_t) : \ |
760 | flags&SIZET ? (intmax_t)GETARG(ssize_t) : \ | | 760 | flags&SIZET ? (intmax_t)GETARG(ssize_t) : \ |
761 | flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ | | 761 | flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ |
762 | (intmax_t)GETARG(long long)) | | 762 | (intmax_t)GETARG(long long)) |
763 | #define UJARG() \ | | 763 | #define UJARG() \ |
764 | (flags&INTMAXT ? GETARG(uintmax_t) : \ | | 764 | (flags&INTMAXT ? GETARG(uintmax_t) : \ |
765 | flags&SIZET ? (uintmax_t)GETARG(size_t) : \ | | 765 | flags&SIZET ? (uintmax_t)GETARG(size_t) : \ |
766 | flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ | | 766 | flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ |
767 | (uintmax_t)GETARG(unsigned long long)) | | 767 | (uintmax_t)GETARG(unsigned long long)) |
768 | | | 768 | |
769 | /* | | 769 | /* |
770 | * Get * arguments, including the form *nn$. Preserve the nextarg | | 770 | * Get * arguments, including the form *nn$. Preserve the nextarg |
771 | * that the argument can be gotten once the type is determined. | | 771 | * that the argument can be gotten once the type is determined. |
772 | */ | | 772 | */ |
773 | #define GETASTER(val) \ | | 773 | #define GETASTER(val) \ |
774 | n2 = 0; \ | | 774 | n2 = 0; \ |
775 | cp = fmt; \ | | 775 | cp = fmt; \ |
776 | while (is_digit(*cp)) { \ | | 776 | while (is_digit(*cp)) { \ |
777 | n2 = 10 * n2 + to_digit(*cp); \ | | 777 | n2 = 10 * n2 + to_digit(*cp); \ |
778 | cp++; \ | | 778 | cp++; \ |
779 | } \ | | 779 | } \ |
780 | if (*cp == '$') { \ | | 780 | if (*cp == '$') { \ |
781 | int hold = nextarg; \ | | 781 | int hold = nextarg; \ |
782 | if (argtable == NULL) { \ | | 782 | if (argtable == NULL) { \ |
783 | argtable = statargtable; \ | | 783 | argtable = statargtable; \ |
784 | if (__find_arguments(fmt0, orgap, &argtable) == -1) \ | | 784 | if (__find_arguments(fmt0, orgap, &argtable) == -1) \ |
785 | goto oomem; \ | | 785 | goto oomem; \ |
786 | } \ | | 786 | } \ |
787 | nextarg = n2; \ | | 787 | nextarg = n2; \ |
788 | val = GETARG (int); \ | | 788 | val = GETARG (int); \ |
789 | nextarg = hold; \ | | 789 | nextarg = hold; \ |
790 | fmt = ++cp; \ | | 790 | fmt = ++cp; \ |
791 | } else { \ | | 791 | } else { \ |
792 | val = GETARG (int); \ | | 792 | val = GETARG (int); \ |
793 | } | | 793 | } |
794 | | | 794 | |
795 | _DIAGASSERT(fp != NULL); | | 795 | _DIAGASSERT(fp != NULL); |
796 | _DIAGASSERT(fmt0 != NULL); | | 796 | _DIAGASSERT(fmt0 != NULL); |
797 | | | 797 | |
798 | _SET_ORIENTATION(fp, -1); | | 798 | _SET_ORIENTATION(fp, -1); |
799 | | | 799 | |
800 | ndig = -1; /* XXX gcc */ | | 800 | ndig = -1; /* XXX gcc */ |
801 | | | 801 | |
802 | thousands_sep = '\0'; | | 802 | thousands_sep = '\0'; |
803 | grouping = NULL; | | 803 | grouping = NULL; |
804 | #ifndef NO_FLOATING_POINT | | 804 | #ifndef NO_FLOATING_POINT |
805 | decimal_point = localeconv()->decimal_point; | | 805 | decimal_point = localeconv()->decimal_point; |
806 | expsize = 0; /* XXXGCC -Wuninitialized [sh3,m68000] */ | | 806 | expsize = 0; /* XXXGCC -Wuninitialized [sh3,m68000] */ |
807 | #endif | | 807 | #endif |
808 | convbuf = NULL; | | 808 | convbuf = NULL; |
809 | /* sorry, f{w,}printf(read_only_file, L"") returns {W,}EOF, not 0 */ | | 809 | /* sorry, f{w,}printf(read_only_file, L"") returns {W,}EOF, not 0 */ |
810 | if (cantwrite(fp)) { | | 810 | if (cantwrite(fp)) { |
811 | errno = EBADF; | | 811 | errno = EBADF; |
812 | return (END_OF_FILE); | | 812 | return (END_OF_FILE); |
813 | } | | 813 | } |
814 | | | 814 | |
815 | /* optimise fprintf(stderr) (and other unbuffered Unix files) */ | | 815 | /* optimise fprintf(stderr) (and other unbuffered Unix files) */ |
816 | if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && | | 816 | if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && |
817 | __sfileno(fp) != -1) | | 817 | __sfileno(fp) != -1) |
818 | return (__sbprintf(fp, fmt0, ap)); | | 818 | return (__sbprintf(fp, fmt0, ap)); |
819 | | | 819 | |
820 | fmt = (CHAR_T *)__UNCONST(fmt0); | | 820 | fmt = (CHAR_T *)__UNCONST(fmt0); |
821 | argtable = NULL; | | 821 | argtable = NULL; |
822 | nextarg = 1; | | 822 | nextarg = 1; |
823 | va_copy(orgap, ap); | | 823 | va_copy(orgap, ap); |
824 | #ifdef NARROW | | 824 | #ifdef NARROW |
825 | uio.uio_iov = iovp = iov; | | 825 | uio.uio_iov = iovp = iov; |
826 | uio.uio_resid = 0; | | 826 | uio.uio_resid = 0; |
827 | uio.uio_iovcnt = 0; | | 827 | uio.uio_iovcnt = 0; |
828 | #endif | | 828 | #endif |
829 | ret = 0; | | 829 | ret = 0; |
830 | | | 830 | |
831 | /* | | 831 | /* |
832 | * Scan the format for conversions (`%' character). | | 832 | * Scan the format for conversions (`%' character). |
833 | */ | | 833 | */ |
834 | for (;;) { | | 834 | for (;;) { |
835 | const CHAR_T *result; | | 835 | const CHAR_T *result; |
836 | | | 836 | |
837 | for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) | | 837 | for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) |
838 | continue; | | 838 | continue; |
839 | if ((n = fmt - cp) != 0) { | | 839 | if ((n = fmt - cp) != 0) { |
840 | if ((unsigned)ret + n > INT_MAX) { | | 840 | if ((unsigned)ret + n > INT_MAX) { |
841 | ret = END_OF_FILE; | | 841 | ret = END_OF_FILE; |
842 | goto error; | | 842 | goto error; |
843 | } | | 843 | } |
844 | PRINT(cp, n); | | 844 | PRINT(cp, n); |
845 | ret += n; | | 845 | ret += n; |
846 | } | | 846 | } |
847 | if (ch == '\0') | | 847 | if (ch == '\0') |
848 | goto done; | | 848 | goto done; |
849 | fmt++; /* skip over '%' */ | | 849 | fmt++; /* skip over '%' */ |
850 | | | 850 | |
851 | flags = 0; | | 851 | flags = 0; |
852 | dprec = 0; | | 852 | dprec = 0; |
853 | width = 0; | | 853 | width = 0; |
854 | prec = -1; | | 854 | prec = -1; |
855 | sign = '\0'; | | 855 | sign = '\0'; |
856 | ox[1] = '\0'; | | 856 | ox[1] = '\0'; |
857 | expchar = '\0'; | | 857 | expchar = '\0'; |
858 | lead = 0; | | 858 | lead = 0; |
859 | nseps = nrepeats = 0; | | 859 | nseps = nrepeats = 0; |
860 | ulval = 0; | | 860 | ulval = 0; |
861 | ujval = 0; | | 861 | ujval = 0; |
862 | xdigs = NULL; | | 862 | xdigs = NULL; |
863 | | | 863 | |
864 | rflag: ch = *fmt++; | | 864 | rflag: ch = *fmt++; |
865 | reswitch: switch (ch) { | | 865 | reswitch: switch (ch) { |
866 | case ' ': | | 866 | case ' ': |
867 | /*- | | 867 | /*- |
868 | * ``If the space and + flags both appear, the space | | 868 | * ``If the space and + flags both appear, the space |
869 | * flag will be ignored.'' | | 869 | * flag will be ignored.'' |
870 | * -- ANSI X3J11 | | 870 | * -- ANSI X3J11 |
871 | */ | | 871 | */ |
872 | if (!sign) | | 872 | if (!sign) |
873 | sign = ' '; | | 873 | sign = ' '; |
874 | goto rflag; | | 874 | goto rflag; |
875 | case '#': | | 875 | case '#': |
876 | flags |= ALT; | | 876 | flags |= ALT; |
877 | goto rflag; | | 877 | goto rflag; |
878 | case '*': | | 878 | case '*': |
879 | /*- | | 879 | /*- |
880 | * ``A negative field width argument is taken as a | | 880 | * ``A negative field width argument is taken as a |
881 | * - flag followed by a positive field width.'' | | 881 | * - flag followed by a positive field width.'' |
882 | * -- ANSI X3J11 | | 882 | * -- ANSI X3J11 |
883 | * They don't exclude field widths read from args. | | 883 | * They don't exclude field widths read from args. |
884 | */ | | 884 | */ |
885 | GETASTER (width); | | 885 | GETASTER (width); |
886 | if (width >= 0) | | 886 | if (width >= 0) |
887 | goto rflag; | | 887 | goto rflag; |
888 | width = -width; | | 888 | width = -width; |
889 | /* FALLTHROUGH */ | | 889 | /* FALLTHROUGH */ |
890 | case '-': | | 890 | case '-': |
891 | flags |= LADJUST; | | 891 | flags |= LADJUST; |
892 | goto rflag; | | 892 | goto rflag; |
893 | case '+': | | 893 | case '+': |
894 | sign = '+'; | | 894 | sign = '+'; |
895 | goto rflag; | | 895 | goto rflag; |
896 | case '\'': | | 896 | case '\'': |
897 | flags |= GROUPING; | | 897 | flags |= GROUPING; |
898 | thousands_sep = *(localeconv()->thousands_sep); | | 898 | thousands_sep = *(localeconv()->thousands_sep); |
899 | grouping = localeconv()->grouping; | | 899 | grouping = localeconv()->grouping; |
| | | 900 | /* If the locale doesn't define the above, use sane |
| | | 901 | * defaults - otherwise silly things happen! */ |
| | | 902 | if (thousands_sep == 0) |
| | | 903 | thousands_sep = ','; |
| | | 904 | if (!grouping || !*grouping) |
| | | 905 | grouping = "\3"; |
900 | goto rflag; | | 906 | goto rflag; |
901 | case '.': | | 907 | case '.': |
902 | if ((ch = *fmt++) == '*') { | | 908 | if ((ch = *fmt++) == '*') { |
903 | GETASTER (prec); | | 909 | GETASTER (prec); |
904 | goto rflag; | | 910 | goto rflag; |
905 | } | | 911 | } |
906 | prec = 0; | | 912 | prec = 0; |
907 | while (is_digit(ch)) { | | 913 | while (is_digit(ch)) { |
908 | prec = 10 * prec + to_digit(ch); | | 914 | prec = 10 * prec + to_digit(ch); |
909 | ch = *fmt++; | | 915 | ch = *fmt++; |
910 | } | | 916 | } |
911 | goto reswitch; | | 917 | goto reswitch; |
912 | case '0': | | 918 | case '0': |
913 | /*- | | 919 | /*- |
914 | * ``Note that 0 is taken as a flag, not as the | | 920 | * ``Note that 0 is taken as a flag, not as the |
915 | * beginning of a field width.'' | | 921 | * beginning of a field width.'' |
916 | * -- ANSI X3J11 | | 922 | * -- ANSI X3J11 |
917 | */ | | 923 | */ |
918 | flags |= ZEROPAD; | | 924 | flags |= ZEROPAD; |
919 | goto rflag; | | 925 | goto rflag; |
920 | case '1': case '2': case '3': case '4': | | 926 | case '1': case '2': case '3': case '4': |
921 | case '5': case '6': case '7': case '8': case '9': | | 927 | case '5': case '6': case '7': case '8': case '9': |
922 | n = 0; | | 928 | n = 0; |
923 | do { | | 929 | do { |
924 | n = 10 * n + to_digit(ch); | | 930 | n = 10 * n + to_digit(ch); |
925 | ch = *fmt++; | | 931 | ch = *fmt++; |
926 | } while (is_digit(ch)); | | 932 | } while (is_digit(ch)); |
927 | if (ch == '$') { | | 933 | if (ch == '$') { |
928 | nextarg = n; | | 934 | nextarg = n; |
929 | if (argtable == NULL) { | | 935 | if (argtable == NULL) { |
930 | argtable = statargtable; | | 936 | argtable = statargtable; |
931 | if (__find_arguments(fmt0, orgap, | | 937 | if (__find_arguments(fmt0, orgap, |
932 | &argtable) == -1) | | 938 | &argtable) == -1) |
933 | goto oomem; | | 939 | goto oomem; |
934 | } | | 940 | } |
935 | goto rflag; | | 941 | goto rflag; |
936 | } | | 942 | } |
937 | width = n; | | 943 | width = n; |
938 | goto reswitch; | | 944 | goto reswitch; |
939 | #ifndef NO_FLOATING_POINT | | 945 | #ifndef NO_FLOATING_POINT |
940 | case 'L': | | 946 | case 'L': |
941 | flags |= LONGDBL; | | 947 | flags |= LONGDBL; |
942 | goto rflag; | | 948 | goto rflag; |
943 | #endif | | 949 | #endif |
944 | case 'h': | | 950 | case 'h': |
945 | if (flags & SHORTINT) { | | 951 | if (flags & SHORTINT) { |
946 | flags &= ~SHORTINT; | | 952 | flags &= ~SHORTINT; |
947 | flags |= CHARINT; | | 953 | flags |= CHARINT; |
948 | } else | | 954 | } else |
949 | flags |= SHORTINT; | | 955 | flags |= SHORTINT; |
950 | goto rflag; | | 956 | goto rflag; |
951 | case 'j': | | 957 | case 'j': |
952 | flags |= INTMAXT; | | 958 | flags |= INTMAXT; |
953 | goto rflag; | | 959 | goto rflag; |
954 | case 'l': | | 960 | case 'l': |
955 | if (flags & LONGINT) { | | 961 | if (flags & LONGINT) { |
956 | flags &= ~LONGINT; | | 962 | flags &= ~LONGINT; |
957 | flags |= LLONGINT; | | 963 | flags |= LLONGINT; |
958 | } else | | 964 | } else |
959 | flags |= LONGINT; | | 965 | flags |= LONGINT; |
960 | goto rflag; | | 966 | goto rflag; |
961 | case 'q': | | 967 | case 'q': |
962 | flags |= LLONGINT; /* not necessarily */ | | 968 | flags |= LLONGINT; /* not necessarily */ |
963 | goto rflag; | | 969 | goto rflag; |
964 | case 't': | | 970 | case 't': |
965 | flags |= PTRDIFFT; | | 971 | flags |= PTRDIFFT; |
966 | goto rflag; | | 972 | goto rflag; |
967 | case 'z': | | 973 | case 'z': |
968 | flags |= SIZET; | | 974 | flags |= SIZET; |
969 | goto rflag; | | 975 | goto rflag; |
970 | case 'C': | | 976 | case 'C': |
971 | flags |= LONGINT; | | 977 | flags |= LONGINT; |
972 | /*FALLTHROUGH*/ | | 978 | /*FALLTHROUGH*/ |
973 | case 'c': | | 979 | case 'c': |
974 | #ifdef NARROW | | 980 | #ifdef NARROW |
975 | if (flags & LONGINT) { | | 981 | if (flags & LONGINT) { |
976 | static const mbstate_t initial; | | 982 | static const mbstate_t initial; |
977 | mbstate_t mbs; | | 983 | mbstate_t mbs; |
978 | size_t mbseqlen; | | 984 | size_t mbseqlen; |
979 | | | 985 | |
980 | mbs = initial; | | 986 | mbs = initial; |
981 | mbseqlen = wcrtomb(buf, | | 987 | mbseqlen = wcrtomb(buf, |
982 | (wchar_t)GETARG(wint_t), &mbs); | | 988 | (wchar_t)GETARG(wint_t), &mbs); |
983 | if (mbseqlen == (size_t)-1) { | | 989 | if (mbseqlen == (size_t)-1) { |
984 | fp->_flags |= __SERR; | | 990 | fp->_flags |= __SERR; |
985 | goto error; | | 991 | goto error; |
986 | } | | 992 | } |
987 | size = (int)mbseqlen; | | 993 | size = (int)mbseqlen; |
988 | } else { | | 994 | } else { |
989 | *buf = GETARG(int); | | 995 | *buf = GETARG(int); |
990 | size = 1; | | 996 | size = 1; |
991 | } | | 997 | } |
992 | #else | | 998 | #else |
993 | if (flags & LONGINT) | | 999 | if (flags & LONGINT) |
994 | *buf = (wchar_t)GETARG(wint_t); | | 1000 | *buf = (wchar_t)GETARG(wint_t); |
995 | else | | 1001 | else |
996 | *buf = (wchar_t)btowc(GETARG(int)); | | 1002 | *buf = (wchar_t)btowc(GETARG(int)); |
997 | size = 1; | | 1003 | size = 1; |
998 | #endif | | 1004 | #endif |
999 | result = buf; | | 1005 | result = buf; |
1000 | sign = '\0'; | | 1006 | sign = '\0'; |
1001 | break; | | 1007 | break; |
1002 | case 'D': | | 1008 | case 'D': |
1003 | flags |= LONGINT; | | 1009 | flags |= LONGINT; |
1004 | /*FALLTHROUGH*/ | | 1010 | /*FALLTHROUGH*/ |
1005 | case 'd': | | 1011 | case 'd': |
1006 | case 'i': | | 1012 | case 'i': |
1007 | if (flags & INTMAX_SIZE) { | | 1013 | if (flags & INTMAX_SIZE) { |
1008 | ujval = SJARG(); | | 1014 | ujval = SJARG(); |
1009 | if ((intmax_t)ujval < 0) { | | 1015 | if ((intmax_t)ujval < 0) { |
1010 | ujval = -ujval; | | 1016 | ujval = -ujval; |
1011 | sign = '-'; | | 1017 | sign = '-'; |
1012 | } | | 1018 | } |
1013 | } else { | | 1019 | } else { |
1014 | ulval = SARG(); | | 1020 | ulval = SARG(); |
1015 | if ((long)ulval < 0) { | | 1021 | if ((long)ulval < 0) { |
1016 | ulval = -ulval; | | 1022 | ulval = -ulval; |
1017 | sign = '-'; | | 1023 | sign = '-'; |
1018 | } | | 1024 | } |
1019 | } | | 1025 | } |
1020 | base = 10; | | 1026 | base = 10; |
1021 | goto number; | | 1027 | goto number; |
1022 | #ifndef NO_FLOATING_POINT | | 1028 | #ifndef NO_FLOATING_POINT |
1023 | #ifdef WIDE_DOUBLE | | 1029 | #ifdef WIDE_DOUBLE |
1024 | case 'a': | | 1030 | case 'a': |
1025 | case 'A': | | 1031 | case 'A': |
1026 | if (ch == 'a') { | | 1032 | if (ch == 'a') { |
1027 | ox[1] = 'x'; | | 1033 | ox[1] = 'x'; |
1028 | xdigs = xdigs_lower; | | 1034 | xdigs = xdigs_lower; |
1029 | expchar = 'p'; | | 1035 | expchar = 'p'; |
1030 | } else { | | 1036 | } else { |
1031 | ox[1] = 'X'; | | 1037 | ox[1] = 'X'; |
1032 | xdigs = xdigs_upper; | | 1038 | xdigs = xdigs_upper; |
1033 | expchar = 'P'; | | 1039 | expchar = 'P'; |
1034 | } | | 1040 | } |
1035 | if (prec >= 0) | | 1041 | if (prec >= 0) |
1036 | prec++; | | 1042 | prec++; |
1037 | if (flags & LONGDBL) { | | 1043 | if (flags & LONGDBL) { |
1038 | fparg.ldbl = GETARG(long double); | | 1044 | fparg.ldbl = GETARG(long double); |
1039 | dtoaresult = | | 1045 | dtoaresult = |
1040 | __hldtoa(fparg.ldbl, xdigs, prec, | | 1046 | __hldtoa(fparg.ldbl, xdigs, prec, |
1041 | &expt, &signflag, &dtoaend); | | 1047 | &expt, &signflag, &dtoaend); |
1042 | } else { | | 1048 | } else { |
1043 | fparg.dbl = GETARG(double); | | 1049 | fparg.dbl = GETARG(double); |
1044 | dtoaresult = | | 1050 | dtoaresult = |
1045 | __hdtoa(fparg.dbl, xdigs, prec, | | 1051 | __hdtoa(fparg.dbl, xdigs, prec, |
1046 | &expt, &signflag, &dtoaend); | | 1052 | &expt, &signflag, &dtoaend); |
1047 | } | | 1053 | } |
1048 | if (dtoaresult == NULL) | | 1054 | if (dtoaresult == NULL) |
1049 | goto oomem; | | 1055 | goto oomem; |
1050 | | | 1056 | |
1051 | if (prec < 0) | | 1057 | if (prec < 0) |
1052 | prec = dtoaend - dtoaresult; | | 1058 | prec = dtoaend - dtoaresult; |
1053 | if (expt == INT_MAX) | | 1059 | if (expt == INT_MAX) |
1054 | ox[1] = '\0'; | | 1060 | ox[1] = '\0'; |
1055 | ndig = dtoaend - dtoaresult; | | 1061 | ndig = dtoaend - dtoaresult; |
1056 | if (convbuf != NULL) | | 1062 | if (convbuf != NULL) |
1057 | free(convbuf); | | 1063 | free(convbuf); |
1058 | #ifndef NARROW | | 1064 | #ifndef NARROW |
1059 | result = convbuf = __mbsconv(dtoaresult, -1); | | 1065 | result = convbuf = __mbsconv(dtoaresult, -1); |
1060 | #else | | 1066 | #else |
1061 | /*XXX inefficient*/ | | 1067 | /*XXX inefficient*/ |
1062 | result = convbuf = strdup(dtoaresult); | | 1068 | result = convbuf = strdup(dtoaresult); |
1063 | #endif | | 1069 | #endif |
1064 | if (result == NULL) | | 1070 | if (result == NULL) |
1065 | goto oomem; | | 1071 | goto oomem; |
1066 | __freedtoa(dtoaresult); | | 1072 | __freedtoa(dtoaresult); |
1067 | goto fp_common; | | 1073 | goto fp_common; |
1068 | case 'e': | | 1074 | case 'e': |
1069 | case 'E': | | 1075 | case 'E': |
1070 | expchar = ch; | | 1076 | expchar = ch; |
1071 | if (prec < 0) /* account for digit before decpt */ | | 1077 | if (prec < 0) /* account for digit before decpt */ |
1072 | prec = DEFPREC + 1; | | 1078 | prec = DEFPREC + 1; |
1073 | else | | 1079 | else |
1074 | prec++; | | 1080 | prec++; |
1075 | goto fp_begin; | | 1081 | goto fp_begin; |
1076 | case 'f': | | 1082 | case 'f': |
1077 | case 'F': | | 1083 | case 'F': |
1078 | expchar = '\0'; | | 1084 | expchar = '\0'; |
1079 | goto fp_begin; | | 1085 | goto fp_begin; |
1080 | case 'g': | | 1086 | case 'g': |
1081 | case 'G': | | 1087 | case 'G': |
1082 | expchar = ch - ('g' - 'e'); | | 1088 | expchar = ch - ('g' - 'e'); |
1083 | if (prec == 0) | | 1089 | if (prec == 0) |
1084 | prec = 1; | | 1090 | prec = 1; |
1085 | fp_begin: | | 1091 | fp_begin: |
1086 | if (prec < 0) | | 1092 | if (prec < 0) |
1087 | prec = DEFPREC; | | 1093 | prec = DEFPREC; |
1088 | if (flags & LONGDBL) { | | 1094 | if (flags & LONGDBL) { |
1089 | fparg.ldbl = GETARG(long double); | | 1095 | fparg.ldbl = GETARG(long double); |
1090 | dtoaresult = | | 1096 | dtoaresult = |
1091 | __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, | | 1097 | __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, |
1092 | &expt, &signflag, &dtoaend); | | 1098 | &expt, &signflag, &dtoaend); |
1093 | } else { | | 1099 | } else { |
1094 | fparg.dbl = GETARG(double); | | 1100 | fparg.dbl = GETARG(double); |
1095 | dtoaresult = | | 1101 | dtoaresult = |
1096 | __dtoa(fparg.dbl, expchar ? 2 : 3, prec, | | 1102 | __dtoa(fparg.dbl, expchar ? 2 : 3, prec, |
1097 | &expt, &signflag, &dtoaend); | | 1103 | &expt, &signflag, &dtoaend); |
1098 | if (expt == 9999) | | 1104 | if (expt == 9999) |
1099 | expt = INT_MAX; | | 1105 | expt = INT_MAX; |
1100 | } | | 1106 | } |
1101 | if (dtoaresult == NULL) | | 1107 | if (dtoaresult == NULL) |
1102 | goto oomem; | | 1108 | goto oomem; |
1103 | ndig = dtoaend - dtoaresult; | | 1109 | ndig = dtoaend - dtoaresult; |
1104 | if (convbuf != NULL) | | 1110 | if (convbuf != NULL) |
1105 | free(convbuf); | | 1111 | free(convbuf); |
1106 | #ifndef NARROW | | 1112 | #ifndef NARROW |
1107 | result = convbuf = __mbsconv(dtoaresult, -1); | | 1113 | result = convbuf = __mbsconv(dtoaresult, -1); |
1108 | #else | | 1114 | #else |
1109 | /*XXX inefficient*/ | | 1115 | /*XXX inefficient*/ |
1110 | result = convbuf = strdup(dtoaresult); | | 1116 | result = convbuf = strdup(dtoaresult); |
1111 | #endif | | 1117 | #endif |
1112 | if (result == NULL) | | 1118 | if (result == NULL) |
1113 | goto oomem; | | 1119 | goto oomem; |
1114 | __freedtoa(dtoaresult); | | 1120 | __freedtoa(dtoaresult); |
1115 | fp_common: | | 1121 | fp_common: |
1116 | if (signflag) | | 1122 | if (signflag) |
1117 | sign = '-'; | | 1123 | sign = '-'; |
1118 | if (expt == INT_MAX) { /* inf or nan */ | | 1124 | if (expt == INT_MAX) { /* inf or nan */ |
1119 | if (*result == 'N') { | | 1125 | if (*result == 'N') { |
1120 | result = (ch >= 'a') ? STRCONST("nan") : | | 1126 | result = (ch >= 'a') ? STRCONST("nan") : |
1121 | STRCONST("NAN"); | | 1127 | STRCONST("NAN"); |
1122 | sign = '\0'; | | 1128 | sign = '\0'; |
1123 | } else | | 1129 | } else |
1124 | result = (ch >= 'a') ? STRCONST("inf") : | | 1130 | result = (ch >= 'a') ? STRCONST("inf") : |
1125 | STRCONST("INF"); | | 1131 | STRCONST("INF"); |
1126 | size = 3; | | 1132 | size = 3; |
1127 | break; | | 1133 | break; |
1128 | } | | 1134 | } |
1129 | #else | | 1135 | #else |
1130 | case 'e': | | 1136 | case 'e': |
1131 | case 'E': | | 1137 | case 'E': |
1132 | case 'f': | | 1138 | case 'f': |
1133 | case 'F': | | 1139 | case 'F': |
1134 | case 'g': | | 1140 | case 'g': |
1135 | case 'G': | | 1141 | case 'G': |
1136 | if (prec == -1) { | | 1142 | if (prec == -1) { |
1137 | prec = DEFPREC; | | 1143 | prec = DEFPREC; |
1138 | } else if ((ch == 'g' || ch == 'G') && prec == 0) { | | 1144 | } else if ((ch == 'g' || ch == 'G') && prec == 0) { |
1139 | prec = 1; | | 1145 | prec = 1; |
1140 | } | | 1146 | } |
1141 | | | 1147 | |
1142 | if (flags & LONGDBL) { | | 1148 | if (flags & LONGDBL) { |
1143 | _double = (double) GETARG(long double); | | 1149 | _double = (double) GETARG(long double); |
1144 | } else { | | 1150 | } else { |
1145 | _double = GETARG(double); | | 1151 | _double = GETARG(double); |
1146 | } | | 1152 | } |
1147 | | | 1153 | |
1148 | /* do this before tricky precision changes */ | | 1154 | /* do this before tricky precision changes */ |
1149 | if (isinf(_double)) { | | 1155 | if (isinf(_double)) { |
1150 | if (_double < 0) | | 1156 | if (_double < 0) |
1151 | sign = '-'; | | 1157 | sign = '-'; |
1152 | if (ch == 'E' || ch == 'F' || ch == 'G') | | 1158 | if (ch == 'E' || ch == 'F' || ch == 'G') |
1153 | result = STRCONST("INF"); | | 1159 | result = STRCONST("INF"); |
1154 | else | | 1160 | else |
1155 | result = STRCONST("inf"); | | 1161 | result = STRCONST("inf"); |
1156 | size = 3; | | 1162 | size = 3; |
1157 | break; | | 1163 | break; |
1158 | } | | 1164 | } |
1159 | if (isnan(_double)) { | | 1165 | if (isnan(_double)) { |
1160 | if (ch == 'E' || ch == 'F' || ch == 'G') | | 1166 | if (ch == 'E' || ch == 'F' || ch == 'G') |
1161 | result = STRCONST("NAN"); | | 1167 | result = STRCONST("NAN"); |
1162 | else | | 1168 | else |
1163 | result = STRCONST("nan"); | | 1169 | result = STRCONST("nan"); |
1164 | size = 3; | | 1170 | size = 3; |
1165 | break; | | 1171 | break; |
1166 | } | | 1172 | } |
1167 | | | 1173 | |
1168 | flags |= FPT; | | 1174 | flags |= FPT; |
1169 | dtoaresult = cvt(_double, prec, flags, &softsign, | | 1175 | dtoaresult = cvt(_double, prec, flags, &softsign, |
1170 | &expt, ch, &ndig); | | 1176 | &expt, ch, &ndig); |
1171 | if (dtoaresult == NULL) | | 1177 | if (dtoaresult == NULL) |
1172 | goto oomem; | | 1178 | goto oomem; |
1173 | if (convbuf != NULL) | | 1179 | if (convbuf != NULL) |
1174 | free(convbuf); | | 1180 | free(convbuf); |
1175 | #ifndef NARROW | | 1181 | #ifndef NARROW |
1176 | result = convbuf = __mbsconv(dtoaresult, -1); | | 1182 | result = convbuf = __mbsconv(dtoaresult, -1); |
1177 | #else | | 1183 | #else |
1178 | /*XXX inefficient*/ | | 1184 | /*XXX inefficient*/ |
1179 | result = convbuf = strdup(dtoaresult); | | 1185 | result = convbuf = strdup(dtoaresult); |
1180 | #endif | | 1186 | #endif |
1181 | if (result == NULL) | | 1187 | if (result == NULL) |
1182 | goto oomem; | | 1188 | goto oomem; |
1183 | __freedtoa(dtoaresult); | | 1189 | __freedtoa(dtoaresult); |
1184 | if (softsign) | | 1190 | if (softsign) |
1185 | sign = '-'; | | 1191 | sign = '-'; |
1186 | #endif | | 1192 | #endif |
1187 | flags |= FPT; | | 1193 | flags |= FPT; |
1188 | if (ch == 'g' || ch == 'G') { | | 1194 | if (ch == 'g' || ch == 'G') { |
1189 | if (expt > -4 && expt <= prec) { | | 1195 | if (expt > -4 && expt <= prec) { |
1190 | /* Make %[gG] smell like %[fF] */ | | 1196 | /* Make %[gG] smell like %[fF] */ |
1191 | expchar = '\0'; | | 1197 | expchar = '\0'; |
1192 | if (flags & ALT) | | 1198 | if (flags & ALT) |
1193 | prec -= expt; | | 1199 | prec -= expt; |
1194 | else | | 1200 | else |
1195 | prec = ndig - expt; | | 1201 | prec = ndig - expt; |
1196 | if (prec < 0) | | 1202 | if (prec < 0) |
1197 | prec = 0; | | 1203 | prec = 0; |
1198 | } else { | | 1204 | } else { |
1199 | /* | | 1205 | /* |
1200 | * Make %[gG] smell like %[eE], but | | 1206 | * Make %[gG] smell like %[eE], but |
1201 | * trim trailing zeroes if no # flag. | | 1207 | * trim trailing zeroes if no # flag. |
1202 | */ | | 1208 | */ |
1203 | if (!(flags & ALT)) | | 1209 | if (!(flags & ALT)) |
1204 | prec = ndig; | | 1210 | prec = ndig; |
1205 | } | | 1211 | } |
1206 | } | | 1212 | } |
1207 | if (expchar) { | | 1213 | if (expchar) { |
1208 | expsize = exponent(expstr, expt - 1, expchar); | | 1214 | expsize = exponent(expstr, expt - 1, expchar); |
1209 | size = expsize + prec; | | 1215 | size = expsize + prec; |
1210 | if (prec > 1 || flags & ALT) | | 1216 | if (prec > 1 || flags & ALT) |
1211 | ++size; | | 1217 | ++size; |
1212 | } else { | | 1218 | } else { |
1213 | /* space for digits before decimal point */ | | 1219 | /* space for digits before decimal point */ |
1214 | if (expt > 0) | | 1220 | if (expt > 0) |
1215 | size = expt; | | 1221 | size = expt; |
1216 | else /* "0" */ | | 1222 | else /* "0" */ |
1217 | size = 1; | | 1223 | size = 1; |
1218 | /* space for decimal pt and following digits */ | | 1224 | /* space for decimal pt and following digits */ |
1219 | if (prec || flags & ALT) | | 1225 | if (prec || flags & ALT) |
1220 | size += prec + 1; | | 1226 | size += prec + 1; |
1221 | if (grouping && expt > 0) { | | 1227 | if (grouping && expt > 0) { |
1222 | /* space for thousands' grouping */ | | 1228 | /* space for thousands' grouping */ |
1223 | nseps = nrepeats = 0; | | 1229 | nseps = nrepeats = 0; |
1224 | lead = expt; | | 1230 | lead = expt; |
1225 | while (*grouping != CHAR_MAX) { | | 1231 | while (*grouping != CHAR_MAX) { |
1226 | if (lead <= *grouping) | | 1232 | if (lead <= *grouping) |
1227 | break; | | 1233 | break; |
1228 | lead -= *grouping; | | 1234 | lead -= *grouping; |
1229 | if (*(grouping+1)) { | | 1235 | if (*(grouping+1)) { |
1230 | nseps++; | | 1236 | nseps++; |
1231 | grouping++; | | 1237 | grouping++; |
1232 | } else | | 1238 | } else |
1233 | nrepeats++; | | 1239 | nrepeats++; |
1234 | } | | 1240 | } |
1235 | size += nseps + nrepeats; | | 1241 | size += nseps + nrepeats; |
1236 | } else | | 1242 | } else |
1237 | lead = expt; | | 1243 | lead = expt; |
1238 | } | | 1244 | } |
1239 | break; | | 1245 | break; |
1240 | #endif /* !NO_FLOATING_POINT */ | | 1246 | #endif /* !NO_FLOATING_POINT */ |
1241 | case 'n': | | 1247 | case 'n': |
1242 | /* | | 1248 | /* |
1243 | * Assignment-like behavior is specified if the | | 1249 | * Assignment-like behavior is specified if the |
1244 | * value overflows or is otherwise unrepresentable. | | 1250 | * value overflows or is otherwise unrepresentable. |
1245 | * C99 says to use `signed char' for %hhn conversions. | | 1251 | * C99 says to use `signed char' for %hhn conversions. |
1246 | */ | | 1252 | */ |
1247 | if (flags & LLONGINT) | | 1253 | if (flags & LLONGINT) |
1248 | *GETARG(long long *) = ret; | | 1254 | *GETARG(long long *) = ret; |
1249 | else if (flags & SIZET) | | 1255 | else if (flags & SIZET) |
1250 | *GETARG(ssize_t *) = (ssize_t)ret; | | 1256 | *GETARG(ssize_t *) = (ssize_t)ret; |
1251 | else if (flags & PTRDIFFT) | | 1257 | else if (flags & PTRDIFFT) |
1252 | *GETARG(ptrdiff_t *) = ret; | | 1258 | *GETARG(ptrdiff_t *) = ret; |
1253 | else if (flags & INTMAXT) | | 1259 | else if (flags & INTMAXT) |
1254 | *GETARG(intmax_t *) = ret; | | 1260 | *GETARG(intmax_t *) = ret; |
1255 | else if (flags & LONGINT) | | 1261 | else if (flags & LONGINT) |
1256 | *GETARG(long *) = ret; | | 1262 | *GETARG(long *) = ret; |
1257 | else if (flags & SHORTINT) | | 1263 | else if (flags & SHORTINT) |
1258 | *GETARG(short *) = ret; | | 1264 | *GETARG(short *) = ret; |
1259 | else if (flags & CHARINT) | | 1265 | else if (flags & CHARINT) |
1260 | *GETARG(signed char *) = ret; | | 1266 | *GETARG(signed char *) = ret; |
1261 | else | | 1267 | else |
1262 | *GETARG(int *) = ret; | | 1268 | *GETARG(int *) = ret; |
1263 | continue; /* no output */ | | 1269 | continue; /* no output */ |
1264 | case 'O': | | 1270 | case 'O': |
1265 | flags |= LONGINT; | | 1271 | flags |= LONGINT; |
1266 | /*FALLTHROUGH*/ | | 1272 | /*FALLTHROUGH*/ |
1267 | case 'o': | | 1273 | case 'o': |
1268 | if (flags & INTMAX_SIZE) | | 1274 | if (flags & INTMAX_SIZE) |
1269 | ujval = UJARG(); | | 1275 | ujval = UJARG(); |
1270 | else | | 1276 | else |
1271 | ulval = UARG(); | | 1277 | ulval = UARG(); |
1272 | base = 8; | | 1278 | base = 8; |
1273 | goto nosign; | | 1279 | goto nosign; |
1274 | case 'p': | | 1280 | case 'p': |
1275 | /*- | | 1281 | /*- |
1276 | * ``The argument shall be a pointer to void. The | | 1282 | * ``The argument shall be a pointer to void. The |
1277 | * value of the pointer is converted to a sequence | | 1283 | * value of the pointer is converted to a sequence |
1278 | * of printable characters, in an implementation- | | 1284 | * of printable characters, in an implementation- |
1279 | * defined manner.'' | | 1285 | * defined manner.'' |
1280 | * -- ANSI X3J11 | | 1286 | * -- ANSI X3J11 |
1281 | */ | | 1287 | */ |
1282 | ujval = (uintmax_t)(uintptr_t)GETARG(void *); | | 1288 | ujval = (uintmax_t)(uintptr_t)GETARG(void *); |
1283 | base = 16; | | 1289 | base = 16; |
1284 | xdigs = xdigs_lower; | | 1290 | xdigs = xdigs_lower; |
1285 | flags = flags | INTMAXT; | | 1291 | flags = flags | INTMAXT; |
1286 | ox[1] = 'x'; | | 1292 | ox[1] = 'x'; |
1287 | goto nosign; | | 1293 | goto nosign; |
1288 | case 'S': | | 1294 | case 'S': |
1289 | flags |= LONGINT; | | 1295 | flags |= LONGINT; |
1290 | /*FALLTHROUGH*/ | | 1296 | /*FALLTHROUGH*/ |
1291 | case 's': | | 1297 | case 's': |
1292 | if ((flags & LONGINT) != MULTI) { | | 1298 | if ((flags & LONGINT) != MULTI) { |
1293 | if ((result = GETARG(CHAR_T *)) == NULL) | | 1299 | if ((result = GETARG(CHAR_T *)) == NULL) |
1294 | result = STRCONST("(null)"); | | 1300 | result = STRCONST("(null)"); |
1295 | } else { | | 1301 | } else { |
1296 | MCHAR_T *mc; | | 1302 | MCHAR_T *mc; |
1297 | | | 1303 | |
1298 | if (convbuf != NULL) | | 1304 | if (convbuf != NULL) |
1299 | free(convbuf); | | 1305 | free(convbuf); |
1300 | if ((mc = GETARG(MCHAR_T *)) == NULL) | | 1306 | if ((mc = GETARG(MCHAR_T *)) == NULL) |
1301 | result = STRCONST("(null)"); | | 1307 | result = STRCONST("(null)"); |
1302 | else { | | 1308 | else { |
1303 | convbuf = SCONV(mc, prec); | | 1309 | convbuf = SCONV(mc, prec); |
1304 | if (convbuf == NULL) { | | 1310 | if (convbuf == NULL) { |
1305 | fp->_flags |= __SERR; | | 1311 | fp->_flags |= __SERR; |
1306 | goto error; | | 1312 | goto error; |
1307 | } | | 1313 | } |
1308 | result = convbuf; | | 1314 | result = convbuf; |
1309 | } | | 1315 | } |
1310 | } | | 1316 | } |
1311 | | | 1317 | |
1312 | if (prec >= 0) { | | 1318 | if (prec >= 0) { |
1313 | /* | | 1319 | /* |
1314 | * can't use STRLEN; can only look for the | | 1320 | * can't use STRLEN; can only look for the |
1315 | * NUL in the first `prec' characters, and | | 1321 | * NUL in the first `prec' characters, and |
1316 | * STRLEN() will go further. | | 1322 | * STRLEN() will go further. |
1317 | */ | | 1323 | */ |
1318 | CHAR_T *p = MEMCHR(result, 0, (size_t)prec); | | 1324 | CHAR_T *p = MEMCHR(result, 0, (size_t)prec); |
1319 | | | 1325 | |
1320 | if (p != NULL) { | | 1326 | if (p != NULL) { |
1321 | size = p - result; | | 1327 | size = p - result; |
1322 | if (size > prec) | | 1328 | if (size > prec) |
1323 | size = prec; | | 1329 | size = prec; |
1324 | } else | | 1330 | } else |
1325 | size = prec; | | 1331 | size = prec; |
1326 | } else | | 1332 | } else |
1327 | size = STRLEN(result); | | 1333 | size = STRLEN(result); |
1328 | sign = '\0'; | | 1334 | sign = '\0'; |
1329 | break; | | 1335 | break; |
1330 | case 'U': | | 1336 | case 'U': |
1331 | flags |= LONGINT; | | 1337 | flags |= LONGINT; |
1332 | /*FALLTHROUGH*/ | | 1338 | /*FALLTHROUGH*/ |
1333 | case 'u': | | 1339 | case 'u': |
1334 | if (flags & INTMAX_SIZE) | | 1340 | if (flags & INTMAX_SIZE) |
1335 | ujval = UJARG(); | | 1341 | ujval = UJARG(); |
1336 | else | | 1342 | else |
1337 | ulval = UARG(); | | 1343 | ulval = UARG(); |
1338 | base = 10; | | 1344 | base = 10; |
1339 | goto nosign; | | 1345 | goto nosign; |
1340 | case 'X': | | 1346 | case 'X': |
1341 | xdigs = xdigs_upper; | | 1347 | xdigs = xdigs_upper; |
1342 | goto hex; | | 1348 | goto hex; |
1343 | case 'x': | | 1349 | case 'x': |
1344 | xdigs = xdigs_lower; | | 1350 | xdigs = xdigs_lower; |
1345 | hex: | | 1351 | hex: |
1346 | if (flags & INTMAX_SIZE) | | 1352 | if (flags & INTMAX_SIZE) |
1347 | ujval = UJARG(); | | 1353 | ujval = UJARG(); |
1348 | else | | 1354 | else |
1349 | ulval = UARG(); | | 1355 | ulval = UARG(); |
1350 | base = 16; | | 1356 | base = 16; |
1351 | /* leading 0x/X only if non-zero */ | | 1357 | /* leading 0x/X only if non-zero */ |
1352 | if (flags & ALT && | | 1358 | if (flags & ALT && |
1353 | (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) | | 1359 | (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) |
1354 | ox[1] = ch; | | 1360 | ox[1] = ch; |
1355 | | | 1361 | |
1356 | flags &= ~GROUPING; | | 1362 | flags &= ~GROUPING; |
1357 | /* unsigned conversions */ | | 1363 | /* unsigned conversions */ |
1358 | nosign: sign = '\0'; | | 1364 | nosign: sign = '\0'; |
1359 | /*- | | 1365 | /*- |
1360 | * ``... diouXx conversions ... if a precision is | | 1366 | * ``... diouXx conversions ... if a precision is |
1361 | * specified, the 0 flag will be ignored.'' | | 1367 | * specified, the 0 flag will be ignored.'' |
1362 | * -- ANSI X3J11 | | 1368 | * -- ANSI X3J11 |
1363 | */ | | 1369 | */ |
1364 | number: if ((dprec = prec) >= 0) | | 1370 | number: if ((dprec = prec) >= 0) |
1365 | flags &= ~ZEROPAD; | | 1371 | flags &= ~ZEROPAD; |
1366 | | | 1372 | |
1367 | /*- | | 1373 | /*- |
1368 | * ``The result of converting a zero value with an | | 1374 | * ``The result of converting a zero value with an |
1369 | * explicit precision of zero is no characters.'' | | 1375 | * explicit precision of zero is no characters.'' |
1370 | * -- ANSI X3J11 | | 1376 | * -- ANSI X3J11 |
1371 | * | | 1377 | * |
1372 | * ``The C Standard is clear enough as is. The call | | 1378 | * ``The C Standard is clear enough as is. The call |
1373 | * printf("%#.0o", 0) should print 0.'' | | 1379 | * printf("%#.0o", 0) should print 0.'' |
1374 | * -- Defect Report #151 | | 1380 | * -- Defect Report #151 |
1375 | */ | | 1381 | */ |
1376 | result = cp = buf + BUF; | | 1382 | result = cp = buf + BUF; |
1377 | if (flags & INTMAX_SIZE) { | | 1383 | if (flags & INTMAX_SIZE) { |
1378 | if (ujval != 0 || prec != 0 || | | 1384 | if (ujval != 0 || prec != 0 || |
1379 | (flags & ALT && base == 8)) | | 1385 | (flags & ALT && base == 8)) |
1380 | result = __ujtoa(ujval, cp, base, | | 1386 | result = __ujtoa(ujval, cp, base, |
1381 | flags & ALT, xdigs, | | 1387 | flags & ALT, xdigs, |
1382 | flags & GROUPING, thousands_sep, | | 1388 | flags & GROUPING, thousands_sep, |
1383 | grouping); | | 1389 | grouping); |
1384 | } else { | | 1390 | } else { |
1385 | if (ulval != 0 || prec != 0 || | | 1391 | if (ulval != 0 || prec != 0 || |
1386 | (flags & ALT && base == 8)) | | 1392 | (flags & ALT && base == 8)) |
1387 | result = __ultoa(ulval, cp, base, | | 1393 | result = __ultoa(ulval, cp, base, |
1388 | flags & ALT, xdigs, | | 1394 | flags & ALT, xdigs, |
1389 | flags & GROUPING, thousands_sep, | | 1395 | flags & GROUPING, thousands_sep, |
1390 | grouping); | | 1396 | grouping); |
1391 | } | | 1397 | } |
1392 | size = buf + BUF - result; | | 1398 | size = buf + BUF - result; |
1393 | if (size > BUF) /* should never happen */ | | 1399 | if (size > BUF) /* should never happen */ |
1394 | abort(); | | 1400 | abort(); |
1395 | break; | | 1401 | break; |
1396 | default: /* "%?" prints ?, unless ? is NUL */ | | 1402 | default: /* "%?" prints ?, unless ? is NUL */ |
1397 | if (ch == '\0') | | 1403 | if (ch == '\0') |
1398 | goto done; | | 1404 | goto done; |
1399 | /* pretend it was %c with argument ch */ | | 1405 | /* pretend it was %c with argument ch */ |
1400 | *buf = ch; | | 1406 | *buf = ch; |
1401 | result = buf; | | 1407 | result = buf; |
1402 | size = 1; | | 1408 | size = 1; |
1403 | sign = '\0'; | | 1409 | sign = '\0'; |
1404 | break; | | 1410 | break; |
1405 | } | | 1411 | } |
1406 | | | 1412 | |
1407 | /* | | 1413 | /* |
1408 | * All reasonable formats wind up here. At this point, `result' | | 1414 | * All reasonable formats wind up here. At this point, `result' |
1409 | * points to a string which (if not flags&LADJUST) should be | | 1415 | * points to a string which (if not flags&LADJUST) should be |
1410 | * padded out to `width' places. If flags&ZEROPAD, it should | | 1416 | * padded out to `width' places. If flags&ZEROPAD, it should |
1411 | * first be prefixed by any sign or other prefix; otherwise, | | 1417 | * first be prefixed by any sign or other prefix; otherwise, |
1412 | * it should be blank padded before the prefix is emitted. | | 1418 | * it should be blank padded before the prefix is emitted. |
1413 | * After any left-hand padding and prefixing, emit zeroes | | 1419 | * After any left-hand padding and prefixing, emit zeroes |
1414 | * required by a decimal [diouxX] precision, then print the | | 1420 | * required by a decimal [diouxX] precision, then print the |
1415 | * string proper, then emit zeroes required by any leftover | | 1421 | * string proper, then emit zeroes required by any leftover |
1416 | * floating precision; finally, if LADJUST, pad with blanks. | | 1422 | * floating precision; finally, if LADJUST, pad with blanks. |
1417 | * | | 1423 | * |
1418 | * Compute actual size, so we know how much to pad. | | 1424 | * Compute actual size, so we know how much to pad. |
1419 | * size excludes decimal prec; realsz includes it. | | 1425 | * size excludes decimal prec; realsz includes it. |
1420 | */ | | 1426 | */ |
1421 | realsz = dprec > size ? dprec : size; | | 1427 | realsz = dprec > size ? dprec : size; |
1422 | if (sign) | | 1428 | if (sign) |
1423 | realsz++; | | 1429 | realsz++; |
1424 | if (ox[1]) | | 1430 | if (ox[1]) |
1425 | realsz += 2; | | 1431 | realsz += 2; |
1426 | | | 1432 | |
1427 | prsize = width > realsz ? width : realsz; | | 1433 | prsize = width > realsz ? width : realsz; |
1428 | if ((unsigned)ret + prsize > INT_MAX) { | | 1434 | if ((unsigned)ret + prsize > INT_MAX) { |
1429 | ret = END_OF_FILE; | | 1435 | ret = END_OF_FILE; |
1430 | goto error; | | 1436 | goto error; |
1431 | } | | 1437 | } |
1432 | | | 1438 | |
1433 | /* right-adjusting blank padding */ | | 1439 | /* right-adjusting blank padding */ |
1434 | if ((flags & (LADJUST|ZEROPAD)) == 0) | | 1440 | if ((flags & (LADJUST|ZEROPAD)) == 0) |
1435 | PAD(width - realsz, blanks); | | 1441 | PAD(width - realsz, blanks); |
1436 | | | 1442 | |
1437 | /* prefix */ | | 1443 | /* prefix */ |
1438 | if (sign) | | 1444 | if (sign) |
1439 | PRINT(&sign, 1); | | 1445 | PRINT(&sign, 1); |
1440 | | | 1446 | |
1441 | if (ox[1]) { /* ox[1] is either x, X, or \0 */ | | 1447 | if (ox[1]) { /* ox[1] is either x, X, or \0 */ |
1442 | ox[0] = '0'; | | 1448 | ox[0] = '0'; |
1443 | PRINT(ox, 2); | | 1449 | PRINT(ox, 2); |
1444 | } | | 1450 | } |
1445 | | | 1451 | |
1446 | /* right-adjusting zero padding */ | | 1452 | /* right-adjusting zero padding */ |
1447 | if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) | | 1453 | if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) |
1448 | PAD(width - realsz, zeroes); | | 1454 | PAD(width - realsz, zeroes); |
1449 | | | 1455 | |
1450 | /* leading zeroes from decimal precision */ | | 1456 | /* leading zeroes from decimal precision */ |
1451 | PAD(dprec - size, zeroes); | | 1457 | PAD(dprec - size, zeroes); |
1452 | | | 1458 | |
1453 | /* the string or number proper */ | | 1459 | /* the string or number proper */ |
1454 | #ifndef NO_FLOATING_POINT | | 1460 | #ifndef NO_FLOATING_POINT |
1455 | if ((flags & FPT) == 0) { | | 1461 | if ((flags & FPT) == 0) { |
1456 | PRINT(result, size); | | 1462 | PRINT(result, size); |
1457 | } else { /* glue together f_p fragments */ | | 1463 | } else { /* glue together f_p fragments */ |
1458 | if (!expchar) { /* %[fF] or sufficiently short %[gG] */ | | 1464 | if (!expchar) { /* %[fF] or sufficiently short %[gG] */ |
1459 | if (expt <= 0) { | | 1465 | if (expt <= 0) { |
1460 | PRINT(zeroes, 1); | | 1466 | PRINT(zeroes, 1); |
1461 | if (prec || flags & ALT) | | 1467 | if (prec || flags & ALT) |
1462 | PRINT(decimal_point, 1); | | 1468 | PRINT(decimal_point, 1); |
1463 | PAD(-expt, zeroes); | | 1469 | PAD(-expt, zeroes); |
1464 | /* already handled initial 0's */ | | 1470 | /* already handled initial 0's */ |
1465 | prec += expt; | | 1471 | prec += expt; |
1466 | } else { | | 1472 | } else { |
1467 | PRINTANDPAD(result, convbuf + ndig, | | 1473 | PRINTANDPAD(result, convbuf + ndig, |
1468 | lead, zeroes); | | 1474 | lead, zeroes); |
1469 | result += lead; | | 1475 | result += lead; |
1470 | if (grouping) { | | 1476 | if (grouping) { |
1471 | while (nseps>0 || nrepeats>0) { | | 1477 | while (nseps>0 || nrepeats>0) { |
1472 | if (nrepeats > 0) | | 1478 | if (nrepeats > 0) |
1473 | nrepeats--; | | 1479 | nrepeats--; |
1474 | else { | | 1480 | else { |
1475 | grouping--; | | 1481 | grouping--; |
1476 | nseps--; | | 1482 | nseps--; |
1477 | } | | 1483 | } |
1478 | PRINT(&thousands_sep, | | 1484 | PRINT(&thousands_sep, |
1479 | 1); | | 1485 | 1); |
1480 | PRINTANDPAD(result, | | 1486 | PRINTANDPAD(result, |
1481 | convbuf + ndig, | | 1487 | convbuf + ndig, |
1482 | *grouping, zeroes); | | 1488 | *grouping, zeroes); |
1483 | result += *grouping; | | 1489 | result += *grouping; |
1484 | } | | 1490 | } |
1485 | if (result > convbuf + ndig) | | 1491 | if (result > convbuf + ndig) |
1486 | result = convbuf + ndig; | | 1492 | result = convbuf + ndig; |
1487 | } | | 1493 | } |
1488 | if (prec || flags & ALT) { | | 1494 | if (prec || flags & ALT) { |
1489 | buf[0] = *decimal_point; | | 1495 | buf[0] = *decimal_point; |
1490 | PRINT(buf, 1); | | 1496 | PRINT(buf, 1); |
1491 | } | | 1497 | } |
1492 | } | | 1498 | } |
1493 | PRINTANDPAD(result, convbuf + ndig, prec, | | 1499 | PRINTANDPAD(result, convbuf + ndig, prec, |
1494 | zeroes); | | 1500 | zeroes); |
1495 | } else { /* %[eE] or sufficiently long %[gG] */ | | 1501 | } else { /* %[eE] or sufficiently long %[gG] */ |
1496 | if (prec > 1 || flags & ALT) { | | 1502 | if (prec > 1 || flags & ALT) { |
1497 | buf[0] = *result++; | | 1503 | buf[0] = *result++; |
1498 | buf[1] = *decimal_point; | | 1504 | buf[1] = *decimal_point; |
1499 | PRINT(buf, 2); | | 1505 | PRINT(buf, 2); |
1500 | PRINT(result, ndig-1); | | 1506 | PRINT(result, ndig-1); |
1501 | PAD(prec - ndig, zeroes); | | 1507 | PAD(prec - ndig, zeroes); |
1502 | } else /* XeYYY */ | | 1508 | } else /* XeYYY */ |
1503 | PRINT(result, 1); | | 1509 | PRINT(result, 1); |
1504 | PRINT(expstr, expsize); | | 1510 | PRINT(expstr, expsize); |
1505 | } | | 1511 | } |
1506 | } | | 1512 | } |
1507 | #else | | 1513 | #else |
1508 | PRINT(result, size); | | 1514 | PRINT(result, size); |
1509 | #endif | | 1515 | #endif |
1510 | /* left-adjusting padding (always blank) */ | | 1516 | /* left-adjusting padding (always blank) */ |
1511 | if (flags & LADJUST) | | 1517 | if (flags & LADJUST) |
1512 | PAD(width - realsz, blanks); | | 1518 | PAD(width - realsz, blanks); |
1513 | | | 1519 | |
1514 | /* finally, adjust ret */ | | 1520 | /* finally, adjust ret */ |
1515 | ret += prsize; | | 1521 | ret += prsize; |
1516 | FLUSH(); | | 1522 | FLUSH(); |
1517 | } | | 1523 | } |
1518 | done: | | 1524 | done: |
1519 | FLUSH(); | | 1525 | FLUSH(); |
1520 | error: | | 1526 | error: |
1521 | va_end(orgap); | | 1527 | va_end(orgap); |
1522 | if (convbuf != NULL) | | 1528 | if (convbuf != NULL) |
1523 | free(convbuf); | | 1529 | free(convbuf); |
1524 | if (__sferror(fp)) | | 1530 | if (__sferror(fp)) |
1525 | ret = END_OF_FILE; | | 1531 | ret = END_OF_FILE; |
1526 | if ((argtable != NULL) && (argtable != statargtable)) | | 1532 | if ((argtable != NULL) && (argtable != statargtable)) |
1527 | free (argtable); | | 1533 | free (argtable); |
1528 | return (ret); | | 1534 | return (ret); |
1529 | /* NOTREACHED */ | | 1535 | /* NOTREACHED */ |
1530 | oomem: | | 1536 | oomem: |
1531 | errno = ENOMEM; | | 1537 | errno = ENOMEM; |
1532 | ret = END_OF_FILE; | | 1538 | ret = END_OF_FILE; |
1533 | goto error; | | 1539 | goto error; |
1534 | } | | 1540 | } |
1535 | | | 1541 | |
1536 | /* | | 1542 | /* |
1537 | * Find all arguments when a positional parameter is encountered. Returns a | | 1543 | * Find all arguments when a positional parameter is encountered. Returns a |
1538 | * table, indexed by argument number, of pointers to each arguments. The | | 1544 | * table, indexed by argument number, of pointers to each arguments. The |
1539 | * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. | | 1545 | * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. |
1540 | * It will be replaces with a malloc-ed one if it overflows. | | 1546 | * It will be replaces with a malloc-ed one if it overflows. |
1541 | */ | | 1547 | */ |
1542 | static int | | 1548 | static int |
1543 | __find_arguments(const CHAR_T *fmt0, va_list ap, union arg **argtable) | | 1549 | __find_arguments(const CHAR_T *fmt0, va_list ap, union arg **argtable) |
1544 | { | | 1550 | { |
1545 | CHAR_T *fmt; /* format string */ | | 1551 | CHAR_T *fmt; /* format string */ |
1546 | int ch; /* character from fmt */ | | 1552 | int ch; /* character from fmt */ |
1547 | int n, n2; /* handy integer (short term usage) */ | | 1553 | int n, n2; /* handy integer (short term usage) */ |
1548 | CHAR_T *cp; /* handy char pointer (short term usage) */ | | 1554 | CHAR_T *cp; /* handy char pointer (short term usage) */ |
1549 | int flags; /* flags as above */ | | 1555 | int flags; /* flags as above */ |
1550 | enum typeid *typetable; /* table of types */ | | 1556 | enum typeid *typetable; /* table of types */ |
1551 | enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; | | 1557 | enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; |
1552 | int tablesize; /* current size of type table */ | | 1558 | int tablesize; /* current size of type table */ |
1553 | int tablemax; /* largest used index in table */ | | 1559 | int tablemax; /* largest used index in table */ |
1554 | int nextarg; /* 1-based argument index */ | | 1560 | int nextarg; /* 1-based argument index */ |
1555 | | | 1561 | |
1556 | /* | | 1562 | /* |
1557 | * Add an argument type to the table, expanding if necessary. | | 1563 | * Add an argument type to the table, expanding if necessary. |
1558 | */ | | 1564 | */ |
1559 | #define ADDTYPE(type) \ | | 1565 | #define ADDTYPE(type) \ |
1560 | do { \ | | 1566 | do { \ |
1561 | if (nextarg >= tablesize) \ | | 1567 | if (nextarg >= tablesize) \ |
1562 | if (__grow_type_table(nextarg, &typetable, \ | | 1568 | if (__grow_type_table(nextarg, &typetable, \ |
1563 | &tablesize) == -1) \ | | 1569 | &tablesize) == -1) \ |
1564 | return -1; \ | | 1570 | return -1; \ |
1565 | if (nextarg > tablemax) \ | | 1571 | if (nextarg > tablemax) \ |
1566 | tablemax = nextarg; \ | | 1572 | tablemax = nextarg; \ |
1567 | typetable[nextarg++] = type; \ | | 1573 | typetable[nextarg++] = type; \ |
1568 | } while (/*CONSTCOND*/0) | | 1574 | } while (/*CONSTCOND*/0) |
1569 | | | 1575 | |
1570 | #define ADDSARG() \ | | 1576 | #define ADDSARG() \ |
1571 | do { \ | | 1577 | do { \ |
1572 | if (flags & INTMAXT) \ | | 1578 | if (flags & INTMAXT) \ |
1573 | ADDTYPE(T_INTMAXT); \ | | 1579 | ADDTYPE(T_INTMAXT); \ |
1574 | else if (flags & SIZET) \ | | 1580 | else if (flags & SIZET) \ |
1575 | ADDTYPE(T_SSIZET); \ | | 1581 | ADDTYPE(T_SSIZET); \ |
1576 | else if (flags & PTRDIFFT) \ | | 1582 | else if (flags & PTRDIFFT) \ |
1577 | ADDTYPE(T_PTRDIFFT); \ | | 1583 | ADDTYPE(T_PTRDIFFT); \ |
1578 | else if (flags & LLONGINT) \ | | 1584 | else if (flags & LLONGINT) \ |
1579 | ADDTYPE(T_LLONG); \ | | 1585 | ADDTYPE(T_LLONG); \ |
1580 | else if (flags & LONGINT) \ | | 1586 | else if (flags & LONGINT) \ |
1581 | ADDTYPE(T_LONG); \ | | 1587 | ADDTYPE(T_LONG); \ |
1582 | else \ | | 1588 | else \ |
1583 | ADDTYPE(T_INT); \ | | 1589 | ADDTYPE(T_INT); \ |
1584 | } while (/*CONSTCOND*/0) | | 1590 | } while (/*CONSTCOND*/0) |
1585 | | | 1591 | |
1586 | #define ADDUARG() \ | | 1592 | #define ADDUARG() \ |
1587 | do { \ | | 1593 | do { \ |
1588 | if (flags & INTMAXT) \ | | 1594 | if (flags & INTMAXT) \ |
1589 | ADDTYPE(T_UINTMAXT); \ | | 1595 | ADDTYPE(T_UINTMAXT); \ |
1590 | else if (flags & SIZET) \ | | 1596 | else if (flags & SIZET) \ |
1591 | ADDTYPE(T_SIZET); \ | | 1597 | ADDTYPE(T_SIZET); \ |
1592 | else if (flags & PTRDIFFT) \ | | 1598 | else if (flags & PTRDIFFT) \ |
1593 | ADDTYPE(T_PTRDIFFT); \ | | 1599 | ADDTYPE(T_PTRDIFFT); \ |
1594 | else if (flags & LLONGINT) \ | | 1600 | else if (flags & LLONGINT) \ |
1595 | ADDTYPE(T_U_LLONG); \ | | 1601 | ADDTYPE(T_U_LLONG); \ |
1596 | else if (flags & LONGINT) \ | | 1602 | else if (flags & LONGINT) \ |
1597 | ADDTYPE(T_U_LONG); \ | | 1603 | ADDTYPE(T_U_LONG); \ |
1598 | else \ | | 1604 | else \ |
1599 | ADDTYPE(T_U_INT); \ | | 1605 | ADDTYPE(T_U_INT); \ |
1600 | } while (/*CONSTCOND*/0) | | 1606 | } while (/*CONSTCOND*/0) |
1601 | /* | | 1607 | /* |
1602 | * Add * arguments to the type array. | | 1608 | * Add * arguments to the type array. |
1603 | */ | | 1609 | */ |
1604 | #define ADDASTER() \ | | 1610 | #define ADDASTER() \ |
1605 | n2 = 0; \ | | 1611 | n2 = 0; \ |
1606 | cp = fmt; \ | | 1612 | cp = fmt; \ |
1607 | while (is_digit(*cp)) { \ | | 1613 | while (is_digit(*cp)) { \ |
1608 | n2 = 10 * n2 + to_digit(*cp); \ | | 1614 | n2 = 10 * n2 + to_digit(*cp); \ |
1609 | cp++; \ | | 1615 | cp++; \ |
1610 | } \ | | 1616 | } \ |
1611 | if (*cp == '$') { \ | | 1617 | if (*cp == '$') { \ |
1612 | int hold = nextarg; \ | | 1618 | int hold = nextarg; \ |
1613 | nextarg = n2; \ | | 1619 | nextarg = n2; \ |
1614 | ADDTYPE(T_INT); \ | | 1620 | ADDTYPE(T_INT); \ |
1615 | nextarg = hold; \ | | 1621 | nextarg = hold; \ |
1616 | fmt = ++cp; \ | | 1622 | fmt = ++cp; \ |
1617 | } else { \ | | 1623 | } else { \ |
1618 | ADDTYPE(T_INT); \ | | 1624 | ADDTYPE(T_INT); \ |
1619 | } | | 1625 | } |
1620 | fmt = (CHAR_T *)__UNCONST(fmt0); | | 1626 | fmt = (CHAR_T *)__UNCONST(fmt0); |
1621 | typetable = stattypetable; | | 1627 | typetable = stattypetable; |
1622 | tablesize = STATIC_ARG_TBL_SIZE; | | 1628 | tablesize = STATIC_ARG_TBL_SIZE; |
1623 | tablemax = 0; | | 1629 | tablemax = 0; |
1624 | nextarg = 1; | | 1630 | nextarg = 1; |
1625 | for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) | | 1631 | for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) |
1626 | typetable[n] = T_UNUSED; | | 1632 | typetable[n] = T_UNUSED; |
1627 | | | 1633 | |
1628 | /* | | 1634 | /* |
1629 | * Scan the format for conversions (`%' character). | | 1635 | * Scan the format for conversions (`%' character). |
1630 | */ | | 1636 | */ |
1631 | for (;;) { | | 1637 | for (;;) { |
1632 | for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) | | 1638 | for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) |
1633 | /* void */; | | 1639 | /* void */; |
1634 | if (ch == '\0') | | 1640 | if (ch == '\0') |
1635 | goto done; | | 1641 | goto done; |
1636 | fmt++; /* skip over '%' */ | | 1642 | fmt++; /* skip over '%' */ |
1637 | | | 1643 | |
1638 | flags = 0; | | 1644 | flags = 0; |
1639 | | | 1645 | |
1640 | rflag: ch = *fmt++; | | 1646 | rflag: ch = *fmt++; |
1641 | reswitch: switch (ch) { | | 1647 | reswitch: switch (ch) { |
1642 | case ' ': | | 1648 | case ' ': |
1643 | case '#': | | 1649 | case '#': |
1644 | goto rflag; | | 1650 | goto rflag; |
1645 | case '*': | | 1651 | case '*': |
1646 | ADDASTER (); | | 1652 | ADDASTER (); |
1647 | goto rflag; | | 1653 | goto rflag; |
1648 | case '-': | | 1654 | case '-': |
1649 | case '+': | | 1655 | case '+': |
1650 | case '\'': | | 1656 | case '\'': |
1651 | goto rflag; | | 1657 | goto rflag; |
1652 | case '.': | | 1658 | case '.': |
1653 | if ((ch = *fmt++) == '*') { | | 1659 | if ((ch = *fmt++) == '*') { |
1654 | ADDASTER (); | | 1660 | ADDASTER (); |
1655 | goto rflag; | | 1661 | goto rflag; |
1656 | } | | 1662 | } |
1657 | while (is_digit(ch)) { | | 1663 | while (is_digit(ch)) { |
1658 | ch = *fmt++; | | 1664 | ch = *fmt++; |
1659 | } | | 1665 | } |
1660 | goto reswitch; | | 1666 | goto reswitch; |
1661 | case '0': | | 1667 | case '0': |
1662 | goto rflag; | | 1668 | goto rflag; |
1663 | case '1': case '2': case '3': case '4': | | 1669 | case '1': case '2': case '3': case '4': |
1664 | case '5': case '6': case '7': case '8': case '9': | | 1670 | case '5': case '6': case '7': case '8': case '9': |
1665 | n = 0; | | 1671 | n = 0; |
1666 | do { | | 1672 | do { |
1667 | n = 10 * n + to_digit(ch); | | 1673 | n = 10 * n + to_digit(ch); |
1668 | ch = *fmt++; | | 1674 | ch = *fmt++; |
1669 | } while (is_digit(ch)); | | 1675 | } while (is_digit(ch)); |
1670 | if (ch == '$') { | | 1676 | if (ch == '$') { |
1671 | nextarg = n; | | 1677 | nextarg = n; |
1672 | goto rflag; | | 1678 | goto rflag; |
1673 | } | | 1679 | } |
1674 | goto reswitch; | | 1680 | goto reswitch; |
1675 | #ifndef NO_FLOATING_POINT | | 1681 | #ifndef NO_FLOATING_POINT |
1676 | case 'L': | | 1682 | case 'L': |
1677 | flags |= LONGDBL; | | 1683 | flags |= LONGDBL; |
1678 | goto rflag; | | 1684 | goto rflag; |
1679 | #endif | | 1685 | #endif |
1680 | case 'h': | | 1686 | case 'h': |
1681 | if (flags & SHORTINT) { | | 1687 | if (flags & SHORTINT) { |
1682 | flags &= ~SHORTINT; | | 1688 | flags &= ~SHORTINT; |
1683 | flags |= CHARINT; | | 1689 | flags |= CHARINT; |
1684 | } else | | 1690 | } else |
1685 | flags |= SHORTINT; | | 1691 | flags |= SHORTINT; |
1686 | goto rflag; | | 1692 | goto rflag; |
1687 | case 'j': | | 1693 | case 'j': |
1688 | flags |= INTMAXT; | | 1694 | flags |= INTMAXT; |
1689 | goto rflag; | | 1695 | goto rflag; |
1690 | case 'l': | | 1696 | case 'l': |
1691 | if (flags & LONGINT) { | | 1697 | if (flags & LONGINT) { |
1692 | flags &= ~LONGINT; | | 1698 | flags &= ~LONGINT; |
1693 | flags |= LLONGINT; | | 1699 | flags |= LLONGINT; |
1694 | } else | | 1700 | } else |
1695 | flags |= LONGINT; | | 1701 | flags |= LONGINT; |
1696 | goto rflag; | | 1702 | goto rflag; |
1697 | case 'q': | | 1703 | case 'q': |
1698 | flags |= LLONGINT; /* not necessarily */ | | 1704 | flags |= LLONGINT; /* not necessarily */ |
1699 | goto rflag; | | 1705 | goto rflag; |
1700 | case 't': | | 1706 | case 't': |
1701 | flags |= PTRDIFFT; | | 1707 | flags |= PTRDIFFT; |
1702 | goto rflag; | | 1708 | goto rflag; |
1703 | case 'z': | | 1709 | case 'z': |
1704 | flags |= SIZET; | | 1710 | flags |= SIZET; |
1705 | goto rflag; | | 1711 | goto rflag; |
1706 | case 'C': | | 1712 | case 'C': |
1707 | flags |= LONGINT; | | 1713 | flags |= LONGINT; |
1708 | /*FALLTHROUGH*/ | | 1714 | /*FALLTHROUGH*/ |
1709 | case 'c': | | 1715 | case 'c': |
1710 | if (flags & LONGINT) | | 1716 | if (flags & LONGINT) |
1711 | ADDTYPE(T_WINT); | | 1717 | ADDTYPE(T_WINT); |
1712 | else | | 1718 | else |
1713 | ADDTYPE(T_INT); | | 1719 | ADDTYPE(T_INT); |
1714 | break; | | 1720 | break; |
1715 | case 'D': | | 1721 | case 'D': |
1716 | flags |= LONGINT; | | 1722 | flags |= LONGINT; |
1717 | /*FALLTHROUGH*/ | | 1723 | /*FALLTHROUGH*/ |
1718 | case 'd': | | 1724 | case 'd': |
1719 | case 'i': | | 1725 | case 'i': |
1720 | ADDSARG(); | | 1726 | ADDSARG(); |
1721 | break; | | 1727 | break; |
1722 | #ifndef NO_FLOATING_POINT | | 1728 | #ifndef NO_FLOATING_POINT |
1723 | case 'a': | | 1729 | case 'a': |
1724 | case 'A': | | 1730 | case 'A': |
1725 | case 'e': | | 1731 | case 'e': |
1726 | case 'E': | | 1732 | case 'E': |
1727 | case 'f': | | 1733 | case 'f': |
1728 | case 'g': | | 1734 | case 'g': |
1729 | case 'G': | | 1735 | case 'G': |
1730 | if (flags & LONGDBL) | | 1736 | if (flags & LONGDBL) |
1731 | ADDTYPE(T_LONG_DOUBLE); | | 1737 | ADDTYPE(T_LONG_DOUBLE); |
1732 | else | | 1738 | else |
1733 | ADDTYPE(T_DOUBLE); | | 1739 | ADDTYPE(T_DOUBLE); |
1734 | break; | | 1740 | break; |
1735 | #endif /* !NO_FLOATING_POINT */ | | 1741 | #endif /* !NO_FLOATING_POINT */ |
1736 | case 'n': | | 1742 | case 'n': |
1737 | if (flags & INTMAXT) | | 1743 | if (flags & INTMAXT) |
1738 | ADDTYPE(TP_INTMAXT); | | 1744 | ADDTYPE(TP_INTMAXT); |
1739 | else if (flags & PTRDIFFT) | | 1745 | else if (flags & PTRDIFFT) |
1740 | ADDTYPE(TP_PTRDIFFT); | | 1746 | ADDTYPE(TP_PTRDIFFT); |
1741 | else if (flags & SIZET) | | 1747 | else if (flags & SIZET) |
1742 | ADDTYPE(TP_SIZET); | | 1748 | ADDTYPE(TP_SIZET); |
1743 | else if (flags & LLONGINT) | | 1749 | else if (flags & LLONGINT) |
1744 | ADDTYPE(TP_LLONG); | | 1750 | ADDTYPE(TP_LLONG); |
1745 | else if (flags & LONGINT) | | 1751 | else if (flags & LONGINT) |
1746 | ADDTYPE(TP_LONG); | | 1752 | ADDTYPE(TP_LONG); |
1747 | else if (flags & SHORTINT) | | 1753 | else if (flags & SHORTINT) |
1748 | ADDTYPE(TP_SHORT); | | 1754 | ADDTYPE(TP_SHORT); |
1749 | else if (flags & CHARINT) | | 1755 | else if (flags & CHARINT) |
1750 | ADDTYPE(TP_SCHAR); | | 1756 | ADDTYPE(TP_SCHAR); |
1751 | else | | 1757 | else |
1752 | ADDTYPE(TP_INT); | | 1758 | ADDTYPE(TP_INT); |
1753 | continue; /* no output */ | | 1759 | continue; /* no output */ |
1754 | case 'O': | | 1760 | case 'O': |
1755 | flags |= LONGINT; | | 1761 | flags |= LONGINT; |
1756 | /*FALLTHROUGH*/ | | 1762 | /*FALLTHROUGH*/ |
1757 | case 'o': | | 1763 | case 'o': |
1758 | ADDUARG(); | | 1764 | ADDUARG(); |
1759 | break; | | 1765 | break; |
1760 | case 'p': | | 1766 | case 'p': |
1761 | ADDTYPE(TP_VOID); | | 1767 | ADDTYPE(TP_VOID); |
1762 | break; | | 1768 | break; |
1763 | case 'S': | | 1769 | case 'S': |
1764 | flags |= LONGINT; | | 1770 | flags |= LONGINT; |
1765 | /*FALLTHROUGH*/ | | 1771 | /*FALLTHROUGH*/ |
1766 | case 's': | | 1772 | case 's': |
1767 | if (flags & LONGINT) | | 1773 | if (flags & LONGINT) |
1768 | ADDTYPE(TP_WCHAR); | | 1774 | ADDTYPE(TP_WCHAR); |
1769 | else | | 1775 | else |
1770 | ADDTYPE(TP_CHAR); | | 1776 | ADDTYPE(TP_CHAR); |
1771 | break; | | 1777 | break; |
1772 | case 'U': | | 1778 | case 'U': |
1773 | flags |= LONGINT; | | 1779 | flags |= LONGINT; |
1774 | /*FALLTHROUGH*/ | | 1780 | /*FALLTHROUGH*/ |
1775 | case 'u': | | 1781 | case 'u': |
1776 | case 'X': | | 1782 | case 'X': |
1777 | case 'x': | | 1783 | case 'x': |
1778 | ADDUARG(); | | 1784 | ADDUARG(); |
1779 | break; | | 1785 | break; |
1780 | default: /* "%?" prints ?, unless ? is NUL */ | | 1786 | default: /* "%?" prints ?, unless ? is NUL */ |
1781 | if (ch == '\0') | | 1787 | if (ch == '\0') |
1782 | goto done; | | 1788 | goto done; |
1783 | break; | | 1789 | break; |
1784 | } | | 1790 | } |
1785 | } | | 1791 | } |
1786 | done: | | 1792 | done: |
1787 | /* | | 1793 | /* |
1788 | * Build the argument table. | | 1794 | * Build the argument table. |
1789 | */ | | 1795 | */ |
1790 | if (tablemax >= STATIC_ARG_TBL_SIZE) { | | 1796 | if (tablemax >= STATIC_ARG_TBL_SIZE) { |
1791 | *argtable = (union arg *) | | 1797 | *argtable = (union arg *) |
1792 | malloc (sizeof (union arg) * (tablemax + 1)); | | 1798 | malloc (sizeof (union arg) * (tablemax + 1)); |
1793 | if (*argtable == NULL) | | 1799 | if (*argtable == NULL) |
1794 | return -1; | | 1800 | return -1; |
1795 | } | | 1801 | } |
1796 | | | 1802 | |
1797 | (*argtable) [0].intarg = 0; | | 1803 | (*argtable) [0].intarg = 0; |
1798 | for (n = 1; n <= tablemax; n++) { | | 1804 | for (n = 1; n <= tablemax; n++) { |
1799 | switch (typetable [n]) { | | 1805 | switch (typetable [n]) { |
1800 | case T_UNUSED: /* whoops! */ | | 1806 | case T_UNUSED: /* whoops! */ |
1801 | (*argtable) [n].intarg = va_arg (ap, int); | | 1807 | (*argtable) [n].intarg = va_arg (ap, int); |
1802 | break; | | 1808 | break; |
1803 | case TP_SCHAR: | | 1809 | case TP_SCHAR: |
1804 | (*argtable) [n].pschararg = va_arg (ap, signed char *); | | 1810 | (*argtable) [n].pschararg = va_arg (ap, signed char *); |
1805 | break; | | 1811 | break; |
1806 | case TP_SHORT: | | 1812 | case TP_SHORT: |
1807 | (*argtable) [n].pshortarg = va_arg (ap, short *); | | 1813 | (*argtable) [n].pshortarg = va_arg (ap, short *); |
1808 | break; | | 1814 | break; |
1809 | case T_INT: | | 1815 | case T_INT: |
1810 | (*argtable) [n].intarg = va_arg (ap, int); | | 1816 | (*argtable) [n].intarg = va_arg (ap, int); |
1811 | break; | | 1817 | break; |
1812 | case T_U_INT: | | 1818 | case T_U_INT: |
1813 | (*argtable) [n].uintarg = va_arg (ap, unsigned int); | | 1819 | (*argtable) [n].uintarg = va_arg (ap, unsigned int); |
1814 | break; | | 1820 | break; |
1815 | case TP_INT: | | 1821 | case TP_INT: |
1816 | (*argtable) [n].pintarg = va_arg (ap, int *); | | 1822 | (*argtable) [n].pintarg = va_arg (ap, int *); |
1817 | break; | | 1823 | break; |
1818 | case T_LONG: | | 1824 | case T_LONG: |
1819 | (*argtable) [n].longarg = va_arg (ap, long); | | 1825 | (*argtable) [n].longarg = va_arg (ap, long); |
1820 | break; | | 1826 | break; |
1821 | case T_U_LONG: | | 1827 | case T_U_LONG: |
1822 | (*argtable) [n].ulongarg = va_arg (ap, unsigned long); | | 1828 | (*argtable) [n].ulongarg = va_arg (ap, unsigned long); |
1823 | break; | | 1829 | break; |
1824 | case TP_LONG: | | 1830 | case TP_LONG: |
1825 | (*argtable) [n].plongarg = va_arg (ap, long *); | | 1831 | (*argtable) [n].plongarg = va_arg (ap, long *); |
1826 | break; | | 1832 | break; |
1827 | case T_LLONG: | | 1833 | case T_LLONG: |
1828 | (*argtable) [n].longlongarg = va_arg (ap, long long); | | 1834 | (*argtable) [n].longlongarg = va_arg (ap, long long); |
1829 | break; | | 1835 | break; |
1830 | case T_U_LLONG: | | 1836 | case T_U_LLONG: |
1831 | (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); | | 1837 | (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); |
1832 | break; | | 1838 | break; |
1833 | case TP_LLONG: | | 1839 | case TP_LLONG: |
1834 | (*argtable) [n].plonglongarg = va_arg (ap, long long *); | | 1840 | (*argtable) [n].plonglongarg = va_arg (ap, long long *); |
1835 | break; | | 1841 | break; |
1836 | case T_PTRDIFFT: | | 1842 | case T_PTRDIFFT: |
1837 | (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); | | 1843 | (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); |
1838 | break; | | 1844 | break; |
1839 | case TP_PTRDIFFT: | | 1845 | case TP_PTRDIFFT: |
1840 | (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); | | 1846 | (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); |
1841 | break; | | 1847 | break; |
1842 | case T_SSIZET: | | 1848 | case T_SSIZET: |
1843 | (*argtable) [n].ssizearg = va_arg (ap, ssize_t); | | 1849 | (*argtable) [n].ssizearg = va_arg (ap, ssize_t); |
1844 | break; | | 1850 | break; |
1845 | case T_SIZET: | | 1851 | case T_SIZET: |
1846 | (*argtable) [n].sizearg = va_arg (ap, size_t); | | 1852 | (*argtable) [n].sizearg = va_arg (ap, size_t); |
1847 | break; | | 1853 | break; |
1848 | case TP_SIZET: | | 1854 | case TP_SIZET: |
1849 | (*argtable) [n].psizearg = va_arg (ap, size_t *); | | 1855 | (*argtable) [n].psizearg = va_arg (ap, size_t *); |
1850 | break; | | 1856 | break; |
1851 | case T_INTMAXT: | | 1857 | case T_INTMAXT: |
1852 | (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); | | 1858 | (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); |
1853 | break; | | 1859 | break; |
1854 | case T_UINTMAXT: | | 1860 | case T_UINTMAXT: |
1855 | (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); | | 1861 | (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); |
1856 | break; | | 1862 | break; |
1857 | case TP_INTMAXT: | | 1863 | case TP_INTMAXT: |
1858 | (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); | | 1864 | (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); |
1859 | break; | | 1865 | break; |
1860 | case T_DOUBLE: | | 1866 | case T_DOUBLE: |
1861 | #ifndef NO_FLOATING_POINT | | 1867 | #ifndef NO_FLOATING_POINT |
1862 | (*argtable) [n].doublearg = va_arg (ap, double); | | 1868 | (*argtable) [n].doublearg = va_arg (ap, double); |
1863 | #endif | | 1869 | #endif |
1864 | break; | | 1870 | break; |
1865 | case T_LONG_DOUBLE: | | 1871 | case T_LONG_DOUBLE: |
1866 | #ifndef NO_FLOATING_POINT | | 1872 | #ifndef NO_FLOATING_POINT |
1867 | (*argtable) [n].longdoublearg = va_arg (ap, long double); | | 1873 | (*argtable) [n].longdoublearg = va_arg (ap, long double); |
1868 | #endif | | 1874 | #endif |
1869 | break; | | 1875 | break; |
1870 | case TP_CHAR: | | 1876 | case TP_CHAR: |
1871 | (*argtable) [n].pchararg = va_arg (ap, char *); | | 1877 | (*argtable) [n].pchararg = va_arg (ap, char *); |
1872 | break; | | 1878 | break; |
1873 | case TP_VOID: | | 1879 | case TP_VOID: |
1874 | (*argtable) [n].pvoidarg = va_arg (ap, void *); | | 1880 | (*argtable) [n].pvoidarg = va_arg (ap, void *); |
1875 | break; | | 1881 | break; |
1876 | case T_WINT: | | 1882 | case T_WINT: |
1877 | (*argtable) [n].wintarg = va_arg (ap, wint_t); | | 1883 | (*argtable) [n].wintarg = va_arg (ap, wint_t); |
1878 | break; | | 1884 | break; |
1879 | case TP_WCHAR: | | 1885 | case TP_WCHAR: |
1880 | (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); | | 1886 | (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); |
1881 | break; | | 1887 | break; |
1882 | } | | 1888 | } |
1883 | } | | 1889 | } |
1884 | | | 1890 | |
1885 | if ((typetable != NULL) && (typetable != stattypetable)) | | 1891 | if ((typetable != NULL) && (typetable != stattypetable)) |
1886 | free (typetable); | | 1892 | free (typetable); |
1887 | return 0; | | 1893 | return 0; |
1888 | } | | 1894 | } |
1889 | | | 1895 | |
1890 | /* | | 1896 | /* |
1891 | * Increase the size of the type table. | | 1897 | * Increase the size of the type table. |
1892 | */ | | 1898 | */ |
1893 | static int | | 1899 | static int |
1894 | __grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) | | 1900 | __grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) |
1895 | { | | 1901 | { |
1896 | enum typeid *const oldtable = *typetable; | | 1902 | enum typeid *const oldtable = *typetable; |
1897 | const int oldsize = *tablesize; | | 1903 | const int oldsize = *tablesize; |
1898 | enum typeid *newtable; | | 1904 | enum typeid *newtable; |