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