• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*	$OpenBSD: vfprintf.c,v 1.71 2016/01/04 15:47:47 schwarze Exp $	*/
2 /*-
3  * Copyright (c) 1990 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Chris Torek.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #define CHAR_TYPE char
35 #define FUNCTION_NAME __vfprintf
36 #define CHAR_TYPE_STRLEN strlen
37 #define CHAR_TYPE_STRNLEN strnlen
38 #define CHAR_TYPE_INF "INF"
39 #define CHAR_TYPE_inf "inf"
40 #define CHAR_TYPE_NAN "NAN"
41 #define CHAR_TYPE_nan "nan"
42 #define CHAR_TYPE_ORIENTATION ORIENT_BYTES
43 
44 #define PRINT(ptr, len)                          \
45   do {                                           \
46     iovp->iov_base = (ptr);                      \
47     iovp->iov_len = (len);                       \
48     uio.uio_resid += (len);                      \
49     iovp++;                                      \
50     if (++uio.uio_iovcnt >= NIOV) {              \
51       if (helpers::sprint(fp, &uio)) goto error; \
52       iovp = iov;                                \
53     }                                            \
54   } while (0)
55 
56 #define FLUSH()                                                 \
57   do {                                                          \
58     if (uio.uio_resid && helpers::sprint(fp, &uio)) goto error; \
59     uio.uio_iovcnt = 0;                                         \
60     iovp = iov;                                                 \
61   } while (0)
62 
63 #include "printf_common.h"
64 
FUNCTION_NAME(FILE * fp,const CHAR_TYPE * fmt0,va_list ap)65 int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) {
66   int caller_errno = errno;
67   int n, n2;
68   CHAR_TYPE* cp;            /* handy char pointer (short term usage) */
69   CHAR_TYPE sign;           /* sign prefix (' ', '+', '-', or \0) */
70   int flags;           /* flags as above */
71   int ret;             /* return value accumulator */
72   int width;           /* width from format (%8d), or 0 */
73   int prec;            /* precision from format; <0 for N/A */
74   /*
75    * We can decompose the printed representation of floating
76    * point numbers into several parts, some of which may be empty:
77    *
78    * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
79    *    A       B     ---C---      D       E   F
80    *
81    * A:	'sign' holds this value if present; '\0' otherwise
82    * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
83    * C:	cp points to the string MMMNNN.  Leading and trailing
84    *	zeros are not in the string and must be added.
85    * D:	expchar holds this character; '\0' if no exponent, e.g. %f
86    * F:	at least two digits for decimal, at least one digit for hex
87    */
88   char* decimal_point = nullptr;
89   int signflag; /* true if float is negative */
90   union {       /* floating point arguments %[aAeEfFgG] */
91     double dbl;
92     long double ldbl;
93   } fparg;
94   int expt;                   /* integer value of exponent */
95   char expchar;               /* exponent character: [eEpP\0] */
96   char* dtoaend;              /* pointer to end of converted digits */
97   int expsize;                /* character count for expstr */
98   int lead;                   /* sig figs before decimal or group sep */
99   int ndig;                   /* actual number of digits returned by dtoa */
100   CHAR_TYPE expstr[MAXEXPDIG + 2]; /* buffer for exponent string: e+ZZZ */
101   char* dtoaresult = nullptr;
102 
103   uintmax_t _umax;             /* integer arguments %[diouxX] */
104   enum { BIN, OCT, DEC, HEX } base; /* base for %[bBdiouxX] conversion */
105   int dprec;                   /* a copy of prec if %[bBdiouxX], 0 otherwise */
106   int realsz;                  /* field size expanded by dprec */
107   int size;                    /* size of converted field or string */
108   const char* xdigs;           /* digits for %[xX] conversion */
109 #define NIOV 8
110   struct __suio uio;       /* output information: summary */
111   struct __siov iov[NIOV]; /* ... and individual io vectors */
112   struct __siov* iovp; /* for PRINT macro */
113   CHAR_TYPE buf[BUF];           /* buffer with space for digits of uintmax_t */
114   CHAR_TYPE ox[2];              /* space for 0x; ox[1] is either x, X, or \0 */
115   union arg* argtable;     /* args, built due to positional arg */
116   union arg statargtable[STATIC_ARG_TBL_SIZE];
117   size_t argtablesiz;
118   int nextarg;   /* 1-based argument index */
119   va_list orgap; /* original argument pointer */
120   CHAR_TYPE* convbuf; /* buffer for wide/multibyte conversion */
121 
122   /*
123    * Choose PADSIZE to trade efficiency vs. size.  If larger printf
124    * fields occur frequently, increase PADSIZE and make the initialisers
125    * below longer.
126    */
127 #define PADSIZE 16 /* pad chunk size */
128   static CHAR_TYPE blanks[PADSIZE] = {
129     ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
130   };
131   static CHAR_TYPE zeroes[PADSIZE] = {
132     '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'
133   };
134 
135   static const char xdigs_lower[] = "0123456789abcdef";
136   static const char xdigs_upper[] = "0123456789ABCDEF";
137 
138   _SET_ORIENTATION(fp, CHAR_TYPE_ORIENTATION);
139 
140   // Writing "" to a read only file returns EOF, not 0.
141   if (cantwrite(fp)) {
142     errno = EBADF;
143     return EOF;
144   }
145 
146   // Optimize writes to stderr and other unbuffered files).
147   if ((fp->_flags & (__SNBF | __SWR | __SRW)) == (__SNBF | __SWR) && fp->_file >= 0) {
148     return (__sbprintf(fp, fmt0, ap));
149   }
150 
151   CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0);
152   argtable = nullptr;
153   nextarg = 1;
154   va_copy(orgap, ap);
155   uio.uio_iov = iovp = iov;
156   uio.uio_resid = 0;
157   uio.uio_iovcnt = 0;
158   ret = 0;
159   convbuf = nullptr;
160 
161   /*
162    * Scan the format for conversions (`%' character).
163    */
164   for (;;) {
165     int ch;
166     for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) continue;
167     if (fmt != cp) {
168       ptrdiff_t m = fmt - cp;
169       if (m < 0 || m > INT_MAX - ret) goto overflow;
170       PRINT(cp, m);
171       ret += m;
172     }
173     if (ch == '\0') goto done;
174     fmt++; /* skip over '%' */
175 
176     flags = 0;
177     dprec = 0;
178     width = 0;
179     prec = -1;
180     sign = '\0';
181     ox[1] = '\0';
182 
183   rflag:
184     ch = *fmt++;
185   reswitch:
186     switch (ch) {
187       case ' ':
188         /*
189          * ``If the space and + flags both appear, the space
190          * flag will be ignored.''
191          *	-- ANSI X3J11
192          */
193         if (!sign) sign = ' ';
194         goto rflag;
195       case '#':
196         flags |= ALT;
197         goto rflag;
198       case '\'':
199         /* grouping not implemented */
200         goto rflag;
201       case '*':
202         /*
203          * ``A negative field width argument is taken as a
204          * - flag followed by a positive field width.''
205          *	-- ANSI X3J11
206          * They don't exclude field widths read from args.
207          */
208         GETASTER(width);
209         if (width >= 0) goto rflag;
210         if (width == INT_MIN) goto overflow;
211         width = -width;
212         __BIONIC_FALLTHROUGH;
213       case '-':
214         flags |= LADJUST;
215         goto rflag;
216       case '+':
217         sign = '+';
218         goto rflag;
219       case '.':
220         if ((ch = *fmt++) == '*') {
221           GETASTER(n);
222           prec = n < 0 ? -1 : n;
223           goto rflag;
224         }
225         n = 0;
226         while (is_digit(ch)) {
227           APPEND_DIGIT(n, ch);
228           ch = *fmt++;
229         }
230         if (ch == '$') {
231           nextarg = n;
232           if (argtable == nullptr) {
233             argtable = statargtable;
234             if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) {
235               ret = -1;
236               goto error;
237             }
238           }
239           goto rflag;
240         }
241         prec = n;
242         goto reswitch;
243       case '0':
244         /*
245          * ``Note that 0 is taken as a flag, not as the
246          * beginning of a field width.''
247          *	-- ANSI X3J11
248          */
249         flags |= ZEROPAD;
250         goto rflag;
251       case '1':
252       case '2':
253       case '3':
254       case '4':
255       case '5':
256       case '6':
257       case '7':
258       case '8':
259       case '9':
260         n = 0;
261         do {
262           APPEND_DIGIT(n, ch);
263           ch = *fmt++;
264         } while (is_digit(ch));
265         if (ch == '$') {
266           nextarg = n;
267           if (argtable == nullptr) {
268             argtable = statargtable;
269             if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) {
270               ret = -1;
271               goto error;
272             }
273           }
274           goto rflag;
275         }
276         width = n;
277         goto reswitch;
278       case 'L':
279         flags |= LONGDBL;
280         goto rflag;
281       case 'h':
282         if (*fmt == 'h') {
283           fmt++;
284           flags |= CHARINT;
285         } else {
286           flags |= SHORTINT;
287         }
288         goto rflag;
289       case 'j':
290         flags |= MAXINT;
291         goto rflag;
292       case 'l':
293         if (*fmt == 'l') {
294           fmt++;
295           flags |= LLONGINT;
296         } else {
297           flags |= LONGINT;
298         }
299         goto rflag;
300       case 'q':
301         flags |= LLONGINT;
302         goto rflag;
303       case 't':
304         flags |= PTRINT;
305         goto rflag;
306       case 'z':
307         flags |= SIZEINT;
308         goto rflag;
309       case 'B':
310       case 'b':
311         _umax = UARG();
312         base = BIN;
313         if (flags & ALT && _umax != 0) ox[1] = ch;
314         goto nosign;
315       case 'C':
316         flags |= LONGINT;
317         __BIONIC_FALLTHROUGH;
318       case 'c':
319         if (flags & LONGINT) {
320           mbstate_t mbs;
321           size_t mbseqlen;
322 
323           memset(&mbs, 0, sizeof(mbs));
324           mbseqlen = wcrtomb(buf, (wchar_t)GETARG(wint_t), &mbs);
325           if (mbseqlen == (size_t)-1) {
326             ret = -1;
327             goto error;
328           }
329           cp = buf;
330           size = (int)mbseqlen;
331         } else {
332           *(cp = buf) = GETARG(int);
333           size = 1;
334         }
335         sign = '\0';
336         break;
337       case 'D':
338         flags |= LONGINT;
339         __BIONIC_FALLTHROUGH;
340       case 'd':
341       case 'i':
342         _umax = SARG();
343 signed_decimal:
344         if ((intmax_t)_umax < 0) {
345           _umax = -_umax;
346           sign = '-';
347         }
348         base = DEC;
349         goto number;
350       case 'a':
351       case 'A':
352         if (ch == 'a') {
353           ox[1] = 'x';
354           xdigs = xdigs_lower;
355           expchar = 'p';
356         } else {
357           ox[1] = 'X';
358           xdigs = xdigs_upper;
359           expchar = 'P';
360         }
361         if (prec >= 0) prec++;
362         if (dtoaresult) __freedtoa(dtoaresult);
363         if (flags & LONGDBL) {
364           fparg.ldbl = GETARG(long double);
365           dtoaresult = __hldtoa(fparg.ldbl, xdigs, prec, &expt, &signflag, &dtoaend);
366           if (dtoaresult == nullptr) {
367             errno = ENOMEM;
368             goto error;
369           }
370         } else {
371           fparg.dbl = GETARG(double);
372           dtoaresult = __hdtoa(fparg.dbl, xdigs, prec, &expt, &signflag, &dtoaend);
373           if (dtoaresult == nullptr) {
374             errno = ENOMEM;
375             goto error;
376           }
377         }
378         if (prec < 0) prec = dtoaend - dtoaresult;
379         if (expt == INT_MAX) ox[1] = '\0';
380         goto fp_common;
381       case 'e':
382       case 'E':
383         expchar = ch;
384         if (prec < 0) /* account for digit before decpt */
385           prec = DEFPREC + 1;
386         else
387           prec++;
388         goto fp_begin;
389       case 'f':
390       case 'F':
391         expchar = '\0';
392         goto fp_begin;
393       case 'g':
394       case 'G':
395         expchar = ch - ('g' - 'e');
396         if (prec == 0) prec = 1;
397       fp_begin:
398         if (prec < 0) prec = DEFPREC;
399         if (dtoaresult) __freedtoa(dtoaresult);
400         if (flags & LONGDBL) {
401           fparg.ldbl = GETARG(long double);
402           dtoaresult = __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, &expt, &signflag, &dtoaend);
403           if (dtoaresult == nullptr) {
404             errno = ENOMEM;
405             goto error;
406           }
407         } else {
408           fparg.dbl = GETARG(double);
409           dtoaresult = __dtoa(fparg.dbl, expchar ? 2 : 3, prec, &expt, &signflag, &dtoaend);
410           if (dtoaresult == nullptr) {
411             errno = ENOMEM;
412             goto error;
413           }
414           if (expt == 9999) expt = INT_MAX;
415         }
416       fp_common:
417 #if CHAR_TYPE_ORIENTATION == ORIENT_BYTES
418         cp = dtoaresult;
419 #else
420         free(convbuf);
421         cp = convbuf = helpers::mbsconv(dtoaresult, -1);
422         if (cp == nullptr) goto error;
423 #endif
424         if (signflag) sign = '-';
425         if (expt == INT_MAX) { /* inf or nan */
426           if (*cp == 'N') {
427             cp = const_cast<CHAR_TYPE*>((ch >= 'a') ? CHAR_TYPE_nan : CHAR_TYPE_NAN);
428           } else {
429             cp = const_cast<CHAR_TYPE*>((ch >= 'a') ? CHAR_TYPE_inf : CHAR_TYPE_INF);
430           }
431           size = 3;
432           flags &= ~ZEROPAD;
433           break;
434         }
435         flags |= FPT;
436         ndig = dtoaend - dtoaresult;
437         if (ch == 'g' || ch == 'G') {
438           if (expt > -4 && expt <= prec) {
439             /* Make %[gG] smell like %[fF] */
440             expchar = '\0';
441             if (flags & ALT)
442               prec -= expt;
443             else
444               prec = ndig - expt;
445             if (prec < 0) prec = 0;
446           } else {
447             /*
448              * Make %[gG] smell like %[eE], but
449              * trim trailing zeroes if no # flag.
450              */
451             if (!(flags & ALT)) prec = ndig;
452           }
453         }
454         if (expchar) {
455           expsize = exponent(expstr, expt - 1, expchar);
456           size = expsize + prec;
457           if (prec > 1 || flags & ALT) ++size;
458         } else {
459           /* space for digits before decimal point */
460           if (expt > 0)
461             size = expt;
462           else /* "0" */
463             size = 1;
464           /* space for decimal pt and following digits */
465           if (prec || flags & ALT) size += prec + 1;
466           lead = expt;
467         }
468         break;
469       case 'n':
470         __fortify_fatal("%%n not allowed on Android");
471       case 'm':
472         if (flags & ALT) {
473           cp = const_cast<char*>(strerrorname_np(caller_errno));
474           if (cp == nullptr) {
475             _umax = caller_errno;
476             goto signed_decimal;
477           }
478         } else {
479           cp = strerror_r(caller_errno, buf, sizeof(buf));
480         }
481         goto string;
482       case 'O':
483         flags |= LONGINT;
484         __BIONIC_FALLTHROUGH;
485       case 'o':
486         _umax = UARG();
487         base = OCT;
488         goto nosign;
489       case 'p':
490         /*
491          * ``The argument shall be a pointer to void.  The
492          * value of the pointer is converted to a sequence
493          * of printable characters, in an implementation-
494          * defined manner.''
495          *	-- ANSI X3J11
496          */
497         _umax = (u_long)GETARG(void*);
498         base = HEX;
499         xdigs = xdigs_lower;
500         ox[1] = 'x';
501         goto nosign;
502       case 'S':
503         flags |= LONGINT;
504         __BIONIC_FALLTHROUGH;
505       case 's':
506         if (flags & LONGINT) {
507           wchar_t* wcp;
508 
509           free(convbuf);
510           convbuf = nullptr;
511           if ((wcp = GETARG(wchar_t*)) == nullptr) {
512             cp = const_cast<char*>("(null)");
513           } else {
514             convbuf = helpers::wcsconv(wcp, prec);
515             if (convbuf == nullptr) {
516               ret = -1;
517               goto error;
518             }
519             cp = convbuf;
520           }
521         } else if ((cp = GETARG(char*)) == nullptr) {
522           cp = const_cast<char*>("(null)");
523         }
524   string:
525         if (prec >= 0) {
526           size = CHAR_TYPE_STRNLEN(cp, prec);
527         } else {
528           size_t len;
529 
530           if ((len = CHAR_TYPE_STRLEN(cp)) > INT_MAX) goto overflow;
531           size = (int)len;
532         }
533         sign = '\0';
534         break;
535       case 'U':
536         flags |= LONGINT;
537         __BIONIC_FALLTHROUGH;
538       case 'u':
539         _umax = UARG();
540         base = DEC;
541         goto nosign;
542       case 'w': {
543         n = 0;
544         bool fast = false;
545         ch = *fmt++;
546         if (ch == 'f') {
547           fast = true;
548           ch = *fmt++;
549         }
550         while (is_digit(ch)) {
551           APPEND_DIGIT(n, ch);
552           ch = *fmt++;
553         }
554         flags |= helpers::w_to_flag(n, fast);
555         goto reswitch;
556       }
557       case 'X':
558         xdigs = xdigs_upper;
559         goto hex;
560       case 'x':
561         xdigs = xdigs_lower;
562       hex:
563         _umax = UARG();
564         base = HEX;
565         /* leading 0x/X only if non-zero */
566         if (flags & ALT && _umax != 0) ox[1] = ch;
567 
568         /* unsigned conversions */
569       nosign:
570         sign = '\0';
571         /*
572          * ``... diouXx conversions ... if a precision is
573          * specified, the 0 flag will be ignored.''
574          *	-- ANSI X3J11
575          */
576       number:
577         if ((dprec = prec) >= 0) flags &= ~ZEROPAD;
578 
579         /*
580          * ``The result of converting a zero value with an
581          * explicit precision of zero is no characters.''
582          *	-- ANSI X3J11
583          */
584         cp = buf + BUF;
585         if (_umax != 0 || prec != 0) {
586           /*
587            * Unsigned mod is hard, and unsigned mod
588            * by a constant is easier than that by
589            * a variable; hence this switch.
590            */
591           switch (base) {
592             case BIN:
593               do {
594                 *--cp = to_char(_umax & 1);
595                 _umax >>= 1;
596               } while (_umax);
597               break;
598 
599             case OCT:
600               do {
601                 *--cp = to_char(_umax & 7);
602                 _umax >>= 3;
603               } while (_umax);
604               /* handle octal leading 0 */
605               if (flags & ALT && *cp != '0') *--cp = '0';
606               break;
607 
608             case DEC:
609               /* many numbers are 1 digit */
610               while (_umax >= 10) {
611                 *--cp = to_char(_umax % 10);
612                 _umax /= 10;
613               }
614               *--cp = to_char(_umax);
615               break;
616 
617             case HEX:
618               do {
619                 *--cp = xdigs[_umax & 15];
620                 _umax >>= 4;
621               } while (_umax);
622               break;
623 
624             default:
625               abort();
626           }
627         }
628         size = buf + BUF - cp;
629         if (size > BUF) abort(); /* should never happen */
630         break;
631       default: /* "%?" prints ?, unless ? is NUL */
632         if (ch == '\0') goto done;
633         /* pretend it was %c with argument ch */
634         cp = buf;
635         *cp = ch;
636         size = 1;
637         sign = '\0';
638         break;
639     }
640 
641     /*
642      * All reasonable formats wind up here.  At this point, `cp'
643      * points to a string which (if not flags&LADJUST) should be
644      * padded out to `width' places.  If flags&ZEROPAD, it should
645      * first be prefixed by any sign or other prefix; otherwise,
646      * it should be blank padded before the prefix is emitted.
647      * After any left-hand padding and prefixing, emit zeroes
648      * required by a decimal %[bBdiouxX] precision, then print the
649      * string proper, then emit zeroes required by any leftover
650      * floating precision; finally, if LADJUST, pad with blanks.
651      *
652      * Compute actual size, so we know how much to pad.
653      * size excludes decimal prec; realsz includes it.
654      */
655     realsz = dprec > size ? dprec : size;
656     if (sign) realsz++;
657     if (ox[1]) realsz += 2;
658 
659     /* right-adjusting blank padding */
660     if ((flags & (LADJUST | ZEROPAD)) == 0) PAD(width - realsz, blanks);
661 
662     /* prefix */
663     if (sign) PRINT(&sign, 1);
664     if (ox[1]) { /* ox[1] is either x, X, or \0 */
665       ox[0] = '0';
666       PRINT(ox, 2);
667     }
668 
669     /* right-adjusting zero padding */
670     if ((flags & (LADJUST | ZEROPAD)) == ZEROPAD) PAD(width - realsz, zeroes);
671 
672     /* leading zeroes from decimal precision */
673     PAD(dprec - size, zeroes);
674 
675     /* the string or number proper */
676     if ((flags & FPT) == 0) {
677       PRINT(cp, size);
678     } else { /* glue together f_p fragments */
679       if (decimal_point == nullptr) decimal_point = nl_langinfo(RADIXCHAR);
680       if (!expchar) { /* %[fF] or sufficiently short %[gG] */
681         CHAR_TYPE* end = cp + ndig;
682         if (expt <= 0) {
683           PRINT(zeroes, 1);
684           if (prec || flags & ALT) PRINT(decimal_point, 1);
685           PAD(-expt, zeroes);
686           /* already handled initial 0's */
687           prec += expt;
688         } else {
689           PRINTANDPAD(cp, end, lead, zeroes);
690           cp += lead;
691           if (prec || flags & ALT) PRINT(decimal_point, 1);
692         }
693         PRINTANDPAD(cp, end, prec, zeroes);
694       } else { /* %[eE] or sufficiently long %[gG] */
695         if (prec > 1 || flags & ALT) {
696           buf[0] = *cp++;
697           buf[1] = *decimal_point;
698           PRINT(buf, 2);
699           PRINT(cp, ndig - 1);
700           PAD(prec - ndig, zeroes);
701         } else { /* XeYYY */
702           PRINT(cp, 1);
703         }
704         PRINT(expstr, expsize);
705       }
706     }
707     /* left-adjusting padding (always blank) */
708     if (flags & LADJUST) PAD(width - realsz, blanks);
709 
710     /* finally, adjust ret */
711     if (width < realsz) width = realsz;
712     if (width > INT_MAX - ret) goto overflow;
713     ret += width;
714 
715     FLUSH(); /* copy out the I/O vectors */
716   }
717 done:
718   FLUSH();
719 error:
720   va_end(orgap);
721   if (__sferror(fp)) ret = -1;
722   goto finish;
723 
724 overflow:
725   errno = ENOMEM;
726   ret = -1;
727 
728 finish:
729   free(convbuf);
730   if (dtoaresult) __freedtoa(dtoaresult);
731   if (argtable != nullptr && argtable != statargtable) {
732     munmap(argtable, argtablesiz);
733     argtable = nullptr;
734   }
735   return (ret);
736 }
737