]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libc/stdio/vfprintf.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libc / stdio / vfprintf.c
1 /*-
2  * Copyright (c) 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * Copyright (c) 2011 The FreeBSD Foundation
9  * All rights reserved.
10  * Portions of this software were developed by David Chisnall
11  * under sponsorship from the FreeBSD Foundation.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37
38 #if defined(LIBC_SCCS) && !defined(lint)
39 static char sccsid[] = "@(#)vfprintf.c  8.1 (Berkeley) 6/4/93";
40 #endif /* LIBC_SCCS and not lint */
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 /*
45  * Actual printf innards.
46  *
47  * This code is large and complicated...
48  */
49
50 #include "namespace.h"
51 #include <sys/types.h>
52
53 #include <ctype.h>
54 #include <limits.h>
55 #include <locale.h>
56 #include <stddef.h>
57 #include <stdint.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <wchar.h>
62 #include <printf.h>
63
64 #include <stdarg.h>
65 #include "xlocale_private.h"
66 #include "un-namespace.h"
67
68 #include "libc_private.h"
69 #include "local.h"
70 #include "fvwrite.h"
71 #include "printflocal.h"
72
73 static int      __sprint(FILE *, struct __suio *, locale_t);
74 static int      __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0)
75         __noinline;
76 static char     *__wcsconv(wchar_t *, int);
77
78 #define CHAR    char
79 #include "printfcommon.h"
80
81 struct grouping_state {
82         char *thousands_sep;    /* locale-specific thousands separator */
83         int thousep_len;        /* length of thousands_sep */
84         const char *grouping;   /* locale-specific numeric grouping rules */
85         int lead;               /* sig figs before decimal or group sep */
86         int nseps;              /* number of group separators with ' */
87         int nrepeats;           /* number of repeats of the last group */
88 };
89
90 /*
91  * Initialize the thousands' grouping state in preparation to print a
92  * number with ndigits digits. This routine returns the total number
93  * of bytes that will be needed.
94  */
95 static int
96 grouping_init(struct grouping_state *gs, int ndigits, locale_t loc)
97 {
98         struct lconv *locale;
99
100         locale = localeconv_l(loc);
101         gs->grouping = locale->grouping;
102         gs->thousands_sep = locale->thousands_sep;
103         gs->thousep_len = strlen(gs->thousands_sep);
104
105         gs->nseps = gs->nrepeats = 0;
106         gs->lead = ndigits;
107         while (*gs->grouping != CHAR_MAX) {
108                 if (gs->lead <= *gs->grouping)
109                         break;
110                 gs->lead -= *gs->grouping;
111                 if (*(gs->grouping+1)) {
112                         gs->nseps++;
113                         gs->grouping++;
114                 } else
115                         gs->nrepeats++;
116         }
117         return ((gs->nseps + gs->nrepeats) * gs->thousep_len);
118 }
119
120 /*
121  * Print a number with thousands' separators.
122  */
123 static int
124 grouping_print(struct grouping_state *gs, struct io_state *iop,
125                const CHAR *cp, const CHAR *ep, locale_t locale)
126 {
127         const CHAR *cp0 = cp;
128
129         if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
130                 return (-1);
131         cp += gs->lead;
132         while (gs->nseps > 0 || gs->nrepeats > 0) {
133                 if (gs->nrepeats > 0)
134                         gs->nrepeats--;
135                 else {
136                         gs->grouping--;
137                         gs->nseps--;
138                 }
139                 if (io_print(iop, gs->thousands_sep, gs->thousep_len, locale))
140                         return (-1);
141                 if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
142                         return (-1);
143                 cp += *gs->grouping;
144         }
145         if (cp > ep)
146                 cp = ep;
147         return (cp - cp0);
148 }
149
150 /*
151  * Flush out all the vectors defined by the given uio,
152  * then reset it so that it can be reused.
153  */
154 static int
155 __sprint(FILE *fp, struct __suio *uio, locale_t locale)
156 {
157         int err;
158
159         if (uio->uio_resid == 0) {
160                 uio->uio_iovcnt = 0;
161                 return (0);
162         }
163         err = __sfvwrite(fp, uio);
164         uio->uio_resid = 0;
165         uio->uio_iovcnt = 0;
166         return (err);
167 }
168
169 /*
170  * Helper function for `fprintf to unbuffered unix file': creates a
171  * temporary buffer.  We only work on write-only files; this avoids
172  * worries about ungetc buffers and so forth.
173  */
174 static int
175 __sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap)
176 {
177         int ret;
178         FILE fake = FAKE_FILE;
179         unsigned char buf[BUFSIZ];
180
181         /* XXX This is probably not needed. */
182         if (prepwrite(fp) != 0)
183                 return (EOF);
184
185         /* copy the important variables */
186         fake._flags = fp->_flags & ~__SNBF;
187         fake._file = fp->_file;
188         fake._cookie = fp->_cookie;
189         fake._write = fp->_write;
190         fake._orientation = fp->_orientation;
191         fake._mbstate = fp->_mbstate;
192
193         /* set up the buffer */
194         fake._bf._base = fake._p = buf;
195         fake._bf._size = fake._w = sizeof(buf);
196         fake._lbfsize = 0;      /* not actually used, but Just In Case */
197
198         /* do the work, then copy any error status */
199         ret = __vfprintf(&fake, locale, fmt, ap);
200         if (ret >= 0 && __fflush(&fake))
201                 ret = EOF;
202         if (fake._flags & __SERR)
203                 fp->_flags |= __SERR;
204         return (ret);
205 }
206
207 /*
208  * Convert a wide character string argument for the %ls format to a multibyte
209  * string representation. If not -1, prec specifies the maximum number of
210  * bytes to output, and also means that we can't assume that the wide char.
211  * string ends is null-terminated.
212  */
213 static char *
214 __wcsconv(wchar_t *wcsarg, int prec)
215 {
216         static const mbstate_t initial;
217         mbstate_t mbs;
218         char buf[MB_LEN_MAX];
219         wchar_t *p;
220         char *convbuf;
221         size_t clen, nbytes;
222
223         /* Allocate space for the maximum number of bytes we could output. */
224         if (prec < 0) {
225                 p = wcsarg;
226                 mbs = initial;
227                 nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
228                 if (nbytes == (size_t)-1)
229                         return (NULL);
230         } else {
231                 /*
232                  * Optimisation: if the output precision is small enough,
233                  * just allocate enough memory for the maximum instead of
234                  * scanning the string.
235                  */
236                 if (prec < 128)
237                         nbytes = prec;
238                 else {
239                         nbytes = 0;
240                         p = wcsarg;
241                         mbs = initial;
242                         for (;;) {
243                                 clen = wcrtomb(buf, *p++, &mbs);
244                                 if (clen == 0 || clen == (size_t)-1 ||
245                                     nbytes + clen > prec)
246                                         break;
247                                 nbytes += clen;
248                         }
249                 }
250         }
251         if ((convbuf = malloc(nbytes + 1)) == NULL)
252                 return (NULL);
253
254         /* Fill the output buffer. */
255         p = wcsarg;
256         mbs = initial;
257         if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
258             nbytes, &mbs)) == (size_t)-1) {
259                 free(convbuf);
260                 return (NULL);
261         }
262         convbuf[nbytes] = '\0';
263         return (convbuf);
264 }
265
266 /*
267  * MT-safe version
268  */
269 int
270 vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0,
271                 va_list ap)
272 {
273         int ret;
274         FIX_LOCALE(locale);
275
276         FLOCKFILE(fp);
277         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
278         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
279             fp->_file >= 0)
280                 ret = __sbprintf(fp, locale, fmt0, ap);
281         else
282                 ret = __vfprintf(fp, locale, fmt0, ap);
283         FUNLOCKFILE(fp);
284         return (ret);
285 }
286 int
287 vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
288 {
289         return vfprintf_l(fp, __get_locale(), fmt0, ap);
290 }
291
292 /*
293  * The size of the buffer we use as scratch space for integer
294  * conversions, among other things.  We need enough space to
295  * write a uintmax_t in octal (plus one byte).
296  */
297 #if UINTMAX_MAX <= UINT64_MAX
298 #define BUF     32
299 #else
300 #error "BUF must be large enough to format a uintmax_t"
301 #endif
302
303 /*
304  * Non-MT-safe version
305  */
306 int
307 __vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
308 {
309         char *fmt;              /* format string */
310         int ch;                 /* character from fmt */
311         int n, n2;              /* handy integer (short term usage) */
312         char *cp;               /* handy char pointer (short term usage) */
313         int flags;              /* flags as above */
314         int ret;                /* return value accumulator */
315         int width;              /* width from format (%8d), or 0 */
316         int prec;               /* precision from format; <0 for N/A */
317         char sign;              /* sign prefix (' ', '+', '-', or \0) */
318         struct grouping_state gs; /* thousands' grouping info */
319
320 #ifndef NO_FLOATING_POINT
321         /*
322          * We can decompose the printed representation of floating
323          * point numbers into several parts, some of which may be empty:
324          *
325          * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
326          *    A       B     ---C---      D       E   F
327          *
328          * A:   'sign' holds this value if present; '\0' otherwise
329          * B:   ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
330          * C:   cp points to the string MMMNNN.  Leading and trailing
331          *      zeros are not in the string and must be added.
332          * D:   expchar holds this character; '\0' if no exponent, e.g. %f
333          * F:   at least two digits for decimal, at least one digit for hex
334          */
335         char *decimal_point;    /* locale specific decimal point */
336         int decpt_len;          /* length of decimal_point */
337         int signflag;           /* true if float is negative */
338         union {                 /* floating point arguments %[aAeEfFgG] */
339                 double dbl;
340                 long double ldbl;
341         } fparg;
342         int expt;               /* integer value of exponent */
343         char expchar;           /* exponent character: [eEpP\0] */
344         char *dtoaend;          /* pointer to end of converted digits */
345         int expsize;            /* character count for expstr */
346         int ndig;               /* actual number of digits returned by dtoa */
347         char expstr[MAXEXPDIG+2];       /* buffer for exponent string: e+ZZZ */
348         char *dtoaresult;       /* buffer allocated by dtoa */
349 #endif
350         u_long  ulval;          /* integer arguments %[diouxX] */
351         uintmax_t ujval;        /* %j, %ll, %q, %t, %z integers */
352         int base;               /* base for [diouxX] conversion */
353         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
354         int realsz;             /* field size expanded by dprec, sign, etc */
355         int size;               /* size of converted field or string */
356         int prsize;             /* max size of printed field */
357         const char *xdigs;      /* digits for %[xX] conversion */
358         struct io_state io;     /* I/O buffering state */
359         char buf[BUF];          /* buffer with space for digits of uintmax_t */
360         char ox[2];             /* space for 0x; ox[1] is either x, X, or \0 */
361         union arg *argtable;    /* args, built due to positional arg */
362         union arg statargtable [STATIC_ARG_TBL_SIZE];
363         int nextarg;            /* 1-based argument index */
364         va_list orgap;          /* original argument pointer */
365         char *convbuf;          /* wide to multibyte conversion result */
366
367         static const char xdigs_lower[16] = "0123456789abcdef";
368         static const char xdigs_upper[16] = "0123456789ABCDEF";
369
370         /* BEWARE, these `goto error' on error. */
371 #define PRINT(ptr, len) { \
372         if (io_print(&io, (ptr), (len), locale))        \
373                 goto error; \
374 }
375 #define PAD(howmany, with) { \
376         if (io_pad(&io, (howmany), (with), locale)) \
377                 goto error; \
378 }
379 #define PRINTANDPAD(p, ep, len, with) { \
380         if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
381                 goto error; \
382 }
383 #define FLUSH() { \
384         if (io_flush(&io, locale)) \
385                 goto error; \
386 }
387
388         /*
389          * Get the argument indexed by nextarg.   If the argument table is
390          * built, use it to get the argument.  If its not, get the next
391          * argument (and arguments must be gotten sequentially).
392          */
393 #define GETARG(type) \
394         ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
395             (nextarg++, va_arg(ap, type)))
396
397         /*
398          * To extend shorts properly, we need both signed and unsigned
399          * argument extraction methods.
400          */
401 #define SARG() \
402         (flags&LONGINT ? GETARG(long) : \
403             flags&SHORTINT ? (long)(short)GETARG(int) : \
404             flags&CHARINT ? (long)(signed char)GETARG(int) : \
405             (long)GETARG(int))
406 #define UARG() \
407         (flags&LONGINT ? GETARG(u_long) : \
408             flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
409             flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
410             (u_long)GETARG(u_int))
411 #define INTMAX_SIZE     (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
412 #define SJARG() \
413         (flags&INTMAXT ? GETARG(intmax_t) : \
414             flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
415             flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
416             (intmax_t)GETARG(long long))
417 #define UJARG() \
418         (flags&INTMAXT ? GETARG(uintmax_t) : \
419             flags&SIZET ? (uintmax_t)GETARG(size_t) : \
420             flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
421             (uintmax_t)GETARG(unsigned long long))
422
423         /*
424          * Get * arguments, including the form *nn$.  Preserve the nextarg
425          * that the argument can be gotten once the type is determined.
426          */
427 #define GETASTER(val) \
428         n2 = 0; \
429         cp = fmt; \
430         while (is_digit(*cp)) { \
431                 n2 = 10 * n2 + to_digit(*cp); \
432                 cp++; \
433         } \
434         if (*cp == '$') { \
435                 int hold = nextarg; \
436                 if (argtable == NULL) { \
437                         argtable = statargtable; \
438                         if (__find_arguments (fmt0, orgap, &argtable)) { \
439                                 ret = EOF; \
440                                 goto error; \
441                         } \
442                 } \
443                 nextarg = n2; \
444                 val = GETARG (int); \
445                 nextarg = hold; \
446                 fmt = ++cp; \
447         } else { \
448                 val = GETARG (int); \
449         }
450
451         if (__use_xprintf == 0 && getenv("USE_XPRINTF"))
452                 __use_xprintf = 1;
453         if (__use_xprintf > 0)
454                 return (__xvprintf(fp, fmt0, ap));
455
456         /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
457         if (prepwrite(fp) != 0)
458                 return (EOF);
459
460         convbuf = NULL;
461         fmt = (char *)fmt0;
462         argtable = NULL;
463         nextarg = 1;
464         va_copy(orgap, ap);
465         io_init(&io, fp);
466         ret = 0;
467 #ifndef NO_FLOATING_POINT
468         dtoaresult = NULL;
469         decimal_point = localeconv_l(locale)->decimal_point;
470         /* The overwhelmingly common case is decpt_len == 1. */
471         decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
472 #endif
473
474         /*
475          * Scan the format for conversions (`%' character).
476          */
477         for (;;) {
478                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
479                         /* void */;
480                 if ((n = fmt - cp) != 0) {
481                         if ((unsigned)ret + n > INT_MAX) {
482                                 ret = EOF;
483                                 goto error;
484                         }
485                         PRINT(cp, n);
486                         ret += n;
487                 }
488                 if (ch == '\0')
489                         goto done;
490                 fmt++;          /* skip over '%' */
491
492                 flags = 0;
493                 dprec = 0;
494                 width = 0;
495                 prec = -1;
496                 gs.grouping = NULL;
497                 sign = '\0';
498                 ox[1] = '\0';
499
500 rflag:          ch = *fmt++;
501 reswitch:       switch (ch) {
502                 case ' ':
503                         /*-
504                          * ``If the space and + flags both appear, the space
505                          * flag will be ignored.''
506                          *      -- ANSI X3J11
507                          */
508                         if (!sign)
509                                 sign = ' ';
510                         goto rflag;
511                 case '#':
512                         flags |= ALT;
513                         goto rflag;
514                 case '*':
515                         /*-
516                          * ``A negative field width argument is taken as a
517                          * - flag followed by a positive field width.''
518                          *      -- ANSI X3J11
519                          * They don't exclude field widths read from args.
520                          */
521                         GETASTER (width);
522                         if (width >= 0)
523                                 goto rflag;
524                         width = -width;
525                         /* FALLTHROUGH */
526                 case '-':
527                         flags |= LADJUST;
528                         goto rflag;
529                 case '+':
530                         sign = '+';
531                         goto rflag;
532                 case '\'':
533                         flags |= GROUPING;
534                         goto rflag;
535                 case '.':
536                         if ((ch = *fmt++) == '*') {
537                                 GETASTER (prec);
538                                 goto rflag;
539                         }
540                         prec = 0;
541                         while (is_digit(ch)) {
542                                 prec = 10 * prec + to_digit(ch);
543                                 ch = *fmt++;
544                         }
545                         goto reswitch;
546                 case '0':
547                         /*-
548                          * ``Note that 0 is taken as a flag, not as the
549                          * beginning of a field width.''
550                          *      -- ANSI X3J11
551                          */
552                         flags |= ZEROPAD;
553                         goto rflag;
554                 case '1': case '2': case '3': case '4':
555                 case '5': case '6': case '7': case '8': case '9':
556                         n = 0;
557                         do {
558                                 n = 10 * n + to_digit(ch);
559                                 ch = *fmt++;
560                         } while (is_digit(ch));
561                         if (ch == '$') {
562                                 nextarg = n;
563                                 if (argtable == NULL) {
564                                         argtable = statargtable;
565                                         if (__find_arguments (fmt0, orgap,
566                                                               &argtable)) {
567                                                 ret = EOF;
568                                                 goto error;
569                                         }
570                                 }
571                                 goto rflag;
572                         }
573                         width = n;
574                         goto reswitch;
575 #ifndef NO_FLOATING_POINT
576                 case 'L':
577                         flags |= LONGDBL;
578                         goto rflag;
579 #endif
580                 case 'h':
581                         if (flags & SHORTINT) {
582                                 flags &= ~SHORTINT;
583                                 flags |= CHARINT;
584                         } else
585                                 flags |= SHORTINT;
586                         goto rflag;
587                 case 'j':
588                         flags |= INTMAXT;
589                         goto rflag;
590                 case 'l':
591                         if (flags & LONGINT) {
592                                 flags &= ~LONGINT;
593                                 flags |= LLONGINT;
594                         } else
595                                 flags |= LONGINT;
596                         goto rflag;
597                 case 'q':
598                         flags |= LLONGINT;      /* not necessarily */
599                         goto rflag;
600                 case 't':
601                         flags |= PTRDIFFT;
602                         goto rflag;
603                 case 'z':
604                         flags |= SIZET;
605                         goto rflag;
606                 case 'C':
607                         flags |= LONGINT;
608                         /*FALLTHROUGH*/
609                 case 'c':
610                         if (flags & LONGINT) {
611                                 static const mbstate_t initial;
612                                 mbstate_t mbs;
613                                 size_t mbseqlen;
614
615                                 mbs = initial;
616                                 mbseqlen = wcrtomb(cp = buf,
617                                     (wchar_t)GETARG(wint_t), &mbs);
618                                 if (mbseqlen == (size_t)-1) {
619                                         fp->_flags |= __SERR;
620                                         goto error;
621                                 }
622                                 size = (int)mbseqlen;
623                         } else {
624                                 *(cp = buf) = GETARG(int);
625                                 size = 1;
626                         }
627                         sign = '\0';
628                         break;
629                 case 'D':
630                         flags |= LONGINT;
631                         /*FALLTHROUGH*/
632                 case 'd':
633                 case 'i':
634                         if (flags & INTMAX_SIZE) {
635                                 ujval = SJARG();
636                                 if ((intmax_t)ujval < 0) {
637                                         ujval = -ujval;
638                                         sign = '-';
639                                 }
640                         } else {
641                                 ulval = SARG();
642                                 if ((long)ulval < 0) {
643                                         ulval = -ulval;
644                                         sign = '-';
645                                 }
646                         }
647                         base = 10;
648                         goto number;
649 #ifndef NO_FLOATING_POINT
650                 case 'a':
651                 case 'A':
652                         if (ch == 'a') {
653                                 ox[1] = 'x';
654                                 xdigs = xdigs_lower;
655                                 expchar = 'p';
656                         } else {
657                                 ox[1] = 'X';
658                                 xdigs = xdigs_upper;
659                                 expchar = 'P';
660                         }
661                         if (prec >= 0)
662                                 prec++;
663                         if (dtoaresult != NULL)
664                                 freedtoa(dtoaresult);
665                         if (flags & LONGDBL) {
666                                 fparg.ldbl = GETARG(long double);
667                                 dtoaresult = cp =
668                                     __hldtoa(fparg.ldbl, xdigs, prec,
669                                     &expt, &signflag, &dtoaend);
670                         } else {
671                                 fparg.dbl = GETARG(double);
672                                 dtoaresult = cp =
673                                     __hdtoa(fparg.dbl, xdigs, prec,
674                                     &expt, &signflag, &dtoaend);
675                         }
676                         if (prec < 0)
677                                 prec = dtoaend - cp;
678                         if (expt == INT_MAX)
679                                 ox[1] = '\0';
680                         goto fp_common;
681                 case 'e':
682                 case 'E':
683                         expchar = ch;
684                         if (prec < 0)   /* account for digit before decpt */
685                                 prec = DEFPREC + 1;
686                         else
687                                 prec++;
688                         goto fp_begin;
689                 case 'f':
690                 case 'F':
691                         expchar = '\0';
692                         goto fp_begin;
693                 case 'g':
694                 case 'G':
695                         expchar = ch - ('g' - 'e');
696                         if (prec == 0)
697                                 prec = 1;
698 fp_begin:
699                         if (prec < 0)
700                                 prec = DEFPREC;
701                         if (dtoaresult != NULL)
702                                 freedtoa(dtoaresult);
703                         if (flags & LONGDBL) {
704                                 fparg.ldbl = GETARG(long double);
705                                 dtoaresult = cp =
706                                     __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
707                                     &expt, &signflag, &dtoaend);
708                         } else {
709                                 fparg.dbl = GETARG(double);
710                                 dtoaresult = cp =
711                                     dtoa(fparg.dbl, expchar ? 2 : 3, prec,
712                                     &expt, &signflag, &dtoaend);
713                                 if (expt == 9999)
714                                         expt = INT_MAX;
715                         }
716 fp_common:
717                         if (signflag)
718                                 sign = '-';
719                         if (expt == INT_MAX) {  /* inf or nan */
720                                 if (*cp == 'N') {
721                                         cp = (ch >= 'a') ? "nan" : "NAN";
722                                         sign = '\0';
723                                 } else
724                                         cp = (ch >= 'a') ? "inf" : "INF";
725                                 size = 3;
726                                 flags &= ~ZEROPAD;
727                                 break;
728                         }
729                         flags |= FPT;
730                         ndig = dtoaend - cp;
731                         if (ch == 'g' || ch == 'G') {
732                                 if (expt > -4 && expt <= prec) {
733                                         /* Make %[gG] smell like %[fF] */
734                                         expchar = '\0';
735                                         if (flags & ALT)
736                                                 prec -= expt;
737                                         else
738                                                 prec = ndig - expt;
739                                         if (prec < 0)
740                                                 prec = 0;
741                                 } else {
742                                         /*
743                                          * Make %[gG] smell like %[eE], but
744                                          * trim trailing zeroes if no # flag.
745                                          */
746                                         if (!(flags & ALT))
747                                                 prec = ndig;
748                                 }
749                         }
750                         if (expchar) {
751                                 expsize = exponent(expstr, expt - 1, expchar);
752                                 size = expsize + prec;
753                                 if (prec > 1 || flags & ALT)
754                                         size += decpt_len;
755                         } else {
756                                 /* space for digits before decimal point */
757                                 if (expt > 0)
758                                         size = expt;
759                                 else    /* "0" */
760                                         size = 1;
761                                 /* space for decimal pt and following digits */
762                                 if (prec || flags & ALT)
763                                         size += prec + decpt_len;
764                                 if ((flags & GROUPING) && expt > 0)
765                                         size += grouping_init(&gs, expt, locale);
766                         }
767                         break;
768 #endif /* !NO_FLOATING_POINT */
769                 case 'n':
770                         /*
771                          * Assignment-like behavior is specified if the
772                          * value overflows or is otherwise unrepresentable.
773                          * C99 says to use `signed char' for %hhn conversions.
774                          */
775                         if (flags & LLONGINT)
776                                 *GETARG(long long *) = ret;
777                         else if (flags & SIZET)
778                                 *GETARG(ssize_t *) = (ssize_t)ret;
779                         else if (flags & PTRDIFFT)
780                                 *GETARG(ptrdiff_t *) = ret;
781                         else if (flags & INTMAXT)
782                                 *GETARG(intmax_t *) = ret;
783                         else if (flags & LONGINT)
784                                 *GETARG(long *) = ret;
785                         else if (flags & SHORTINT)
786                                 *GETARG(short *) = ret;
787                         else if (flags & CHARINT)
788                                 *GETARG(signed char *) = ret;
789                         else
790                                 *GETARG(int *) = ret;
791                         continue;       /* no output */
792                 case 'O':
793                         flags |= LONGINT;
794                         /*FALLTHROUGH*/
795                 case 'o':
796                         if (flags & INTMAX_SIZE)
797                                 ujval = UJARG();
798                         else
799                                 ulval = UARG();
800                         base = 8;
801                         goto nosign;
802                 case 'p':
803                         /*-
804                          * ``The argument shall be a pointer to void.  The
805                          * value of the pointer is converted to a sequence
806                          * of printable characters, in an implementation-
807                          * defined manner.''
808                          *      -- ANSI X3J11
809                          */
810                         ujval = (uintmax_t)(uintptr_t)GETARG(void *);
811                         base = 16;
812                         xdigs = xdigs_lower;
813                         flags = flags | INTMAXT;
814                         ox[1] = 'x';
815                         goto nosign;
816                 case 'S':
817                         flags |= LONGINT;
818                         /*FALLTHROUGH*/
819                 case 's':
820                         if (flags & LONGINT) {
821                                 wchar_t *wcp;
822
823                                 if (convbuf != NULL)
824                                         free(convbuf);
825                                 if ((wcp = GETARG(wchar_t *)) == NULL)
826                                         cp = "(null)";
827                                 else {
828                                         convbuf = __wcsconv(wcp, prec);
829                                         if (convbuf == NULL) {
830                                                 fp->_flags |= __SERR;
831                                                 goto error;
832                                         }
833                                         cp = convbuf;
834                                 }
835                         } else if ((cp = GETARG(char *)) == NULL)
836                                 cp = "(null)";
837                         size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
838                         sign = '\0';
839                         break;
840                 case 'U':
841                         flags |= LONGINT;
842                         /*FALLTHROUGH*/
843                 case 'u':
844                         if (flags & INTMAX_SIZE)
845                                 ujval = UJARG();
846                         else
847                                 ulval = UARG();
848                         base = 10;
849                         goto nosign;
850                 case 'X':
851                         xdigs = xdigs_upper;
852                         goto hex;
853                 case 'x':
854                         xdigs = xdigs_lower;
855 hex:
856                         if (flags & INTMAX_SIZE)
857                                 ujval = UJARG();
858                         else
859                                 ulval = UARG();
860                         base = 16;
861                         /* leading 0x/X only if non-zero */
862                         if (flags & ALT &&
863                             (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
864                                 ox[1] = ch;
865
866                         flags &= ~GROUPING;
867                         /* unsigned conversions */
868 nosign:                 sign = '\0';
869                         /*-
870                          * ``... diouXx conversions ... if a precision is
871                          * specified, the 0 flag will be ignored.''
872                          *      -- ANSI X3J11
873                          */
874 number:                 if ((dprec = prec) >= 0)
875                                 flags &= ~ZEROPAD;
876
877                         /*-
878                          * ``The result of converting a zero value with an
879                          * explicit precision of zero is no characters.''
880                          *      -- ANSI X3J11
881                          *
882                          * ``The C Standard is clear enough as is.  The call
883                          * printf("%#.0o", 0) should print 0.''
884                          *      -- Defect Report #151
885                          */
886                         cp = buf + BUF;
887                         if (flags & INTMAX_SIZE) {
888                                 if (ujval != 0 || prec != 0 ||
889                                     (flags & ALT && base == 8))
890                                         cp = __ujtoa(ujval, cp, base,
891                                             flags & ALT, xdigs);
892                         } else {
893                                 if (ulval != 0 || prec != 0 ||
894                                     (flags & ALT && base == 8))
895                                         cp = __ultoa(ulval, cp, base,
896                                             flags & ALT, xdigs);
897                         }
898                         size = buf + BUF - cp;
899                         if (size > BUF) /* should never happen */
900                                 abort();
901                         if ((flags & GROUPING) && size != 0)
902                                 size += grouping_init(&gs, size, locale);
903                         break;
904                 default:        /* "%?" prints ?, unless ? is NUL */
905                         if (ch == '\0')
906                                 goto done;
907                         /* pretend it was %c with argument ch */
908                         cp = buf;
909                         *cp = ch;
910                         size = 1;
911                         sign = '\0';
912                         break;
913                 }
914
915                 /*
916                  * All reasonable formats wind up here.  At this point, `cp'
917                  * points to a string which (if not flags&LADJUST) should be
918                  * padded out to `width' places.  If flags&ZEROPAD, it should
919                  * first be prefixed by any sign or other prefix; otherwise,
920                  * it should be blank padded before the prefix is emitted.
921                  * After any left-hand padding and prefixing, emit zeroes
922                  * required by a decimal [diouxX] precision, then print the
923                  * string proper, then emit zeroes required by any leftover
924                  * floating precision; finally, if LADJUST, pad with blanks.
925                  *
926                  * Compute actual size, so we know how much to pad.
927                  * size excludes decimal prec; realsz includes it.
928                  */
929                 realsz = dprec > size ? dprec : size;
930                 if (sign)
931                         realsz++;
932                 if (ox[1])
933                         realsz += 2;
934
935                 prsize = width > realsz ? width : realsz;
936                 if ((unsigned)ret + prsize > INT_MAX) {
937                         ret = EOF;
938                         goto error;
939                 }
940
941                 /* right-adjusting blank padding */
942                 if ((flags & (LADJUST|ZEROPAD)) == 0)
943                         PAD(width - realsz, blanks);
944
945                 /* prefix */
946                 if (sign)
947                         PRINT(&sign, 1);
948
949                 if (ox[1]) {    /* ox[1] is either x, X, or \0 */
950                         ox[0] = '0';
951                         PRINT(ox, 2);
952                 }
953
954                 /* right-adjusting zero padding */
955                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
956                         PAD(width - realsz, zeroes);
957
958                 /* the string or number proper */
959 #ifndef NO_FLOATING_POINT
960                 if ((flags & FPT) == 0) {
961 #endif
962                         /* leading zeroes from decimal precision */
963                         PAD(dprec - size, zeroes);
964                         if (gs.grouping) {
965                                 if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
966                                         goto error;
967                         } else {
968                                 PRINT(cp, size);
969                         }
970 #ifndef NO_FLOATING_POINT
971                 } else {        /* glue together f_p fragments */
972                         if (!expchar) { /* %[fF] or sufficiently short %[gG] */
973                                 if (expt <= 0) {
974                                         PRINT(zeroes, 1);
975                                         if (prec || flags & ALT)
976                                                 PRINT(decimal_point,decpt_len);
977                                         PAD(-expt, zeroes);
978                                         /* already handled initial 0's */
979                                         prec += expt;
980                                 } else {
981                                         if (gs.grouping) {
982                                                 n = grouping_print(&gs, &io,
983                                                     cp, dtoaend, locale);
984                                                 if (n < 0)
985                                                         goto error;
986                                                 cp += n;
987                                         } else {
988                                                 PRINTANDPAD(cp, dtoaend,
989                                                     expt, zeroes);
990                                                 cp += expt;
991                                         }
992                                         if (prec || flags & ALT)
993                                                 PRINT(decimal_point,decpt_len);
994                                 }
995                                 PRINTANDPAD(cp, dtoaend, prec, zeroes);
996                         } else {        /* %[eE] or sufficiently long %[gG] */
997                                 if (prec > 1 || flags & ALT) {
998                                         PRINT(cp++, 1);
999                                         PRINT(decimal_point, decpt_len);
1000                                         PRINT(cp, ndig-1);
1001                                         PAD(prec - ndig, zeroes);
1002                                 } else  /* XeYYY */
1003                                         PRINT(cp, 1);
1004                                 PRINT(expstr, expsize);
1005                         }
1006                 }
1007 #endif
1008                 /* left-adjusting padding (always blank) */
1009                 if (flags & LADJUST)
1010                         PAD(width - realsz, blanks);
1011
1012                 /* finally, adjust ret */
1013                 ret += prsize;
1014
1015                 FLUSH();        /* copy out the I/O vectors */
1016         }
1017 done:
1018         FLUSH();
1019 error:
1020         va_end(orgap);
1021 #ifndef NO_FLOATING_POINT
1022         if (dtoaresult != NULL)
1023                 freedtoa(dtoaresult);
1024 #endif
1025         if (convbuf != NULL)
1026                 free(convbuf);
1027         if (__sferror(fp))
1028                 ret = EOF;
1029         if ((argtable != NULL) && (argtable != statargtable))
1030                 free (argtable);
1031         return (ret);
1032         /* NOTREACHED */
1033 }
1034