vfprintf.c revision 1.58 1 #if 0
2 /* Contains my POSITIONAL_PARAMS code */
3 /* $NetBSD: vfprintf.c,v 1.58 2009/10/14 21:25:52 dsl Exp $ */
4
5 /*-
6 * Copyright (c) 1990 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Chris Torek.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 #if defined(LIBC_SCCS) && !defined(lint)
39 #if 0
40 static char *sccsid = "@(#)vfprintf.c 5.50 (Berkeley) 12/16/92";
41 #else
42 __RCSID("$NetBSD: vfprintf.c,v 1.58 2009/10/14 21:25:52 dsl Exp $");
43 #endif
44 #endif /* LIBC_SCCS and not lint */
45
46 /*
47 * Actual printf innards.
48 *
49 * This code is large and complicated...
50 */
51
52 #include "namespace.h"
53 #include <sys/types.h>
54
55 #include <assert.h>
56 #include <errno.h>
57 #include <stdarg.h>
58 #include <stddef.h>
59 #include <stdint.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <wchar.h>
64
65 #include "reentrant.h"
66 #include "local.h"
67 #include "fvwrite.h"
68 #include "extern.h"
69
70 #ifdef FLOATING_POINT
71 #define POSITIONAL_PARAMS
72 #endif
73
74 static int __sprint __P((FILE *, struct __suio *));
75 static int __sbprintf __P((FILE *, const char *, va_list))
76 __attribute__((__format__(__printf__, 2, 0)));
77 #ifdef POSITIONAL_PARAMS
78 #define NL_ARGMAX 9 /* minimum required by IEEE Std 1003.1-2001 */
79
80 union parg {
81 int flags;
82 uintmax_t _uintmax;
83 void *_pointer;
84 double _double;
85 };
86 static void set_printf_args(union parg *, const char *, _BSD_VA_LIST_);
87 #endif
88
89 /*
90 * Flush out all the vectors defined by the given uio,
91 * then reset it so that it can be reused.
92 */
93 /* NB: async-signal-safe when fp->_flags & __SAFE */
94 static int
95 __sprint(fp, uio)
96 FILE *fp;
97 struct __suio *uio;
98 {
99 int err;
100
101 _DIAGASSERT(fp != NULL);
102 _DIAGASSERT(uio != NULL);
103
104 if (uio->uio_resid == 0) {
105 uio->uio_iovcnt = 0;
106 return (0);
107 }
108 err = __sfvwrite(fp, uio);
109 uio->uio_resid = 0;
110 uio->uio_iovcnt = 0;
111 return (err);
112 }
113
114 /*
115 * Helper function for `fprintf to unbuffered unix file': creates a
116 * temporary buffer. We only work on write-only files; this avoids
117 * worries about ungetc buffers and so forth.
118 */
119 static int
120 __sbprintf(fp, fmt, ap)
121 FILE *fp;
122 const char *fmt;
123 va_list ap;
124 {
125 int ret;
126 FILE fake;
127 struct __sfileext fakeext;
128 unsigned char buf[BUFSIZ];
129
130 _DIAGASSERT(fp != NULL);
131 _DIAGASSERT(fmt != NULL);
132
133 _FILEEXT_SETUP(&fake, &fakeext);
134
135 /* copy the important variables */
136 fake._flags = fp->_flags & ~__SNBF;
137 fake._file = fp->_file;
138 fake._cookie = fp->_cookie;
139 fake._write = fp->_write;
140
141 /* set up the buffer */
142 fake._bf._base = fake._p = buf;
143 fake._bf._size = fake._w = sizeof(buf);
144 fake._lbfsize = 0; /* not actually used, but Just In Case */
145
146 /* do the work, then copy any error status */
147 ret = vfprintf(&fake, fmt, ap);
148 if (ret >= 0 && fflush(&fake))
149 ret = -1;
150 if (fake._flags & __SERR)
151 fp->_flags |= __SERR;
152 return (ret);
153 }
154
155
156 #ifndef NO_FLOATING_POINT
157 #include <locale.h>
158 #include <math.h>
159 #include "floatio.h"
160
161 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
162 #define DEFPREC 6
163
164 static char *cvt __P((double, int, int, char *, int *, int, int *));
165 static int exponent __P((char *, int, int));
166
167 #else /* FLOATING_POINT */
168
169 #define BUF 40
170
171 #endif /* NO_FLOATING_POINT */
172
173 /*
174 * Macros for converting digits to letters and vice versa
175 */
176 #define to_digit(c) ((c) - '0')
177 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
178 #define to_char(n) ((char)((n) + '0'))
179
180 /*
181 * Flags used during conversion.
182 */
183 #define ALT 0x001 /* alternate form */
184 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
185 #define LADJUST 0x004 /* left adjustment */
186 #define LONGDBL 0x008 /* long double; unimplemented */
187 #define LONGINT 0x010 /* long integer */
188 #define QUADINT 0x020 /* quad integer */
189 #define SHORTINT 0x040 /* short integer */
190 #define MAXINT 0x080 /* (unsigned) intmax_t */
191 #define PTRINT 0x100 /* (unsigned) ptrdiff_t */
192 #define SIZEINT 0x200 /* (signed) size_t */
193 #define ZEROPAD 0x400 /* zero (as opposed to blank) pad */
194 #define FPT 0x800 /* Floating point number */
195 #ifdef POSITIONAL_PARAMS
196 #define POINTER 0x10000 /* Pointer to something */
197 #define SIGNED 0x20000 /* signed value */
198 #define CHARINT 0x40000 /* move above when %hhd implemented */
199 #endif
200
201 int
202 vfprintf(fp, fmt0, ap)
203 FILE *fp;
204 const char *fmt0;
205 _BSD_VA_LIST_ ap;
206 {
207 int ret;
208
209 FLOCKFILE(fp);
210 ret = __vfprintf_unlocked(fp, fmt0, ap);
211 FUNLOCKFILE(fp);
212
213 return ret;
214 }
215
216
217
218 /* NB: async-signal-safe when fp->_flags & __SAFE */
219 int
220 __vfprintf_unlocked(fp, fmt0, ap)
221 FILE *fp;
222 const char *fmt0;
223 _BSD_VA_LIST_ ap;
224 {
225 const char *fmt;/* format string */
226 int ch; /* character from fmt */
227 int n, m; /* handy integers (short term usage) */
228 const char *cp; /* handy char pointer (short term usage) */
229 char *bp; /* handy char pointer (short term usage) */
230 struct __siov *iovp;/* for PRINT macro */
231 int flags; /* flags as above */
232 int ret; /* return value accumulator */
233 int width; /* width from format (%8d), or 0 */
234 int prec; /* precision from format (%.3d), or -1 */
235 char sign; /* sign prefix (' ', '+', '-', or \0) */
236 wchar_t wc;
237 mbstate_t ps;
238 #ifndef NO_FLOATING_POINT
239 char *decimal_point = NULL;
240 char softsign; /* temporary negative sign for floats */
241 double _double; /* double precision arguments %[eEfgG] */
242 int expt; /* integer value of exponent */
243 int expsize = 0; /* character count for expstr */
244 int ndig; /* actual number of digits returned by cvt */
245 char expstr[7]; /* buffer for exponent string */
246 char *dtoaresult = NULL;
247 #endif
248
249 #ifdef __GNUC__ /* gcc has builtin quad type (long long) SOS */
250 #define quad_t long long
251 #define u_quad_t unsigned long long
252 #endif
253
254 #define INTMAX_T intmax_t
255 #define UINTMAX_T uintmax_t
256
257 UINTMAX_T _uintmax; /* integer arguments %[diouxX] */
258 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
259 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
260 int realsz; /* field size expanded by dprec */
261 int size; /* size of converted field or string */
262 const char *xdigs = NULL;/* digits for [xX] conversion */
263 #define NIOV 8
264 struct __suio uio; /* output information: summary */
265 struct __siov iov[NIOV];/* ... and individual io vectors */
266 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
267 char ox[2]; /* space for 0x hex-prefix */
268
269 /*
270 * Choose PADSIZE to trade efficiency vs. size. If larger printf
271 * fields occur frequently, increase PADSIZE and make the initialisers
272 * below longer.
273 */
274 #define PADSIZE 16 /* pad chunk size */
275 static const char blanks[PADSIZE] =
276 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
277 static const char zeroes[PADSIZE] =
278 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
279 #ifdef POSITIONAL_PARAMS /* %n$... */
280 union parg parg[1 + NL_ARGMAX];
281 int positional = 0;
282 int argnum = 0;
283
284 memset(&parg, 0, sizeof parg);
285 #endif
286
287 /*
288 * BEWARE, these `goto error' on error, and PAD uses `n'.
289 */
290 #define PRINT(ptr, len) do { \
291 iovp->iov_base = __UNCONST(ptr); \
292 iovp->iov_len = (len); \
293 uio.uio_resid += (len); \
294 iovp++; \
295 if (++uio.uio_iovcnt >= NIOV) { \
296 if (__sprint(fp, &uio)) \
297 goto error; \
298 iovp = iov; \
299 } \
300 } while (/*CONSTCOND*/0)
301
302 #define PAD(howmany, with) do { \
303 if ((n = (howmany)) > 0) { \
304 while (n > PADSIZE) { \
305 PRINT(with, PADSIZE); \
306 n -= PADSIZE; \
307 } \
308 PRINT(with, n); \
309 } \
310 } while (/*CONSTCOND*/0)
311
312 #define FLUSH() do { \
313 if (uio.uio_resid && __sprint(fp, &uio)) \
314 goto error; \
315 uio.uio_iovcnt = 0; \
316 iovp = iov; \
317 } while (/*CONSTCOND*/0)
318
319 /*
320 * To extend shorts properly, we need both signed and unsigned
321 * argument extraction methods.
322 */
323 #define SARG(flags, ap) \
324 (flags&MAXINT ? va_arg(ap, intmax_t) : \
325 flags&PTRINT ? va_arg(ap, ptrdiff_t) : \
326 flags&SIZEINT ? va_arg(ap, ssize_t) : /* XXX */ \
327 flags&QUADINT ? va_arg(ap, quad_t) : \
328 flags&LONGINT ? va_arg(ap, long) : \
329 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
330 (long)va_arg(ap, int))
331 #define UARG(flags, ap) \
332 (flags&MAXINT ? va_arg(ap, uintmax_t) : \
333 flags&PTRINT ? va_arg(ap, uintptr_t) : /* XXX */ \
334 flags&SIZEINT ? va_arg(ap, size_t) : \
335 flags&QUADINT ? va_arg(ap, u_quad_t) : \
336 flags&LONGINT ? va_arg(ap, u_long) : \
337 flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
338 (u_long)va_arg(ap, u_int))
339
340 _DIAGASSERT(fp != NULL);
341 _DIAGASSERT(fmt0 != NULL);
342
343 _SET_ORIENTATION(fp, -1);
344
345 /* sorry, fprintf(read_only_file, "") returns -1, not 0 */
346 if (cantwrite(fp)) {
347 errno = EBADF;
348 return (-1);
349 }
350
351 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
352 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
353 fp->_file >= 0) {
354 ret = __sbprintf(fp, fmt0, ap);
355 return (ret);
356 }
357
358 fmt = fmt0;
359 uio.uio_iov = iovp = iov;
360 uio.uio_resid = 0;
361 uio.uio_iovcnt = 0;
362 ret = 0;
363
364 memset(&ps, 0, sizeof(ps));
365
366 /*
367 * Scan the format for conversions (`%' character).
368 */
369 for (;;) {
370 cp = fmt;
371 if (fp->_flags & __SAFE) {
372 for (; *fmt && *fmt != '%'; fmt++)
373 continue;
374 n = *fmt == '%';
375 } else {
376 while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
377 fmt += n;
378 if (wc == '%') {
379 fmt--;
380 break;
381 }
382 }
383 }
384 if ((m = fmt - cp) != 0) {
385 PRINT(cp, m);
386 ret += m;
387 }
388 if (n <= 0)
389 goto done;
390 fmt0 = fmt; /* save pointer to the '%' */
391 fmt++; /* skip over '%' */
392
393 flags = 0;
394 dprec = 0;
395 width = 0;
396 prec = -1;
397 sign = '\0';
398
399 #ifdef POSITIONAL_PARAMS
400 ch = *fmt;
401 if (is_digit(ch) && fmt[1] == '$' && positional >= 0) {
402 fmt += 2;
403 if (positional == 0) {
404 set_printf_args(parg, fmt0, ap);
405 positional = 1;
406 }
407 argnum = to_digit(ch);
408 }
409 #endif
410
411
412 rflag: ch = *fmt++;
413 reswitch: switch (ch) {
414 case ' ':
415 /*
416 * ``If the space and + flags both appear, the space
417 * flag will be ignored.''
418 * -- ANSI X3J11
419 */
420 if (!sign)
421 sign = ' ';
422 goto rflag;
423 case '#':
424 flags |= ALT;
425 goto rflag;
426 case '*':
427 #ifdef POSITIONAL_PARAMS
428 if (positional > 0) {
429 ch = *fmt++;
430 if (!is_digit(ch))
431 goto invalid;
432 n = to_digit(ch);
433 ch = *fmt++;
434 if (n == 0 || ch != '$')
435 goto invalid;
436 width = (int)parg[n]._uintmax;
437 } else
438 #endif
439 width = va_arg(ap, int);
440 /*
441 * ``A negative field width argument is taken as a
442 * - flag followed by a positive field width.''
443 * -- ANSI X3J11
444 * They don't exclude field widths read from args.
445 */
446 if (width >= 0)
447 goto rflag;
448 width = -width;
449 /* FALLTHROUGH */
450 case '-':
451 flags |= LADJUST;
452 goto rflag;
453 case '+':
454 sign = '+';
455 goto rflag;
456 case '.':
457 if ((ch = *fmt++) == '*') {
458 #ifdef POSITIONAL_PARAMS
459 if (positional > 0) {
460 ch = *fmt++;
461 if (!is_digit(ch))
462 goto invalid;
463 n = to_digit(ch);
464 ch = *fmt++;
465 if (n == 0 || ch != '$')
466 goto invalid;
467 n = (int)parg[n]._uintmax;
468 } else
469 #endif
470 n = va_arg(ap, int);
471 prec = n < 0 ? -1 : n;
472 goto rflag;
473 }
474 n = 0;
475 while (is_digit(ch)) {
476 n = 10 * n + to_digit(ch);
477 ch = *fmt++;
478 }
479 prec = n < 0 ? -1 : n;
480 goto reswitch;
481 case '0':
482 /*
483 * ``Note that 0 is taken as a flag, not as the
484 * beginning of a field width.''
485 * -- ANSI X3J11
486 */
487 flags |= ZEROPAD;
488 goto rflag;
489 case '1': case '2': case '3': case '4':
490 case '5': case '6': case '7': case '8': case '9':
491 n = 0;
492 do {
493 n = 10 * n + to_digit(ch);
494 ch = *fmt++;
495 } while (is_digit(ch));
496 width = n;
497 goto reswitch;
498 #ifndef NO_FLOATING_POINT
499 case 'L':
500 flags |= LONGDBL;
501 goto rflag;
502 #endif
503 case 'h':
504 flags |= SHORTINT;
505 goto rflag;
506 case 'j':
507 flags |= MAXINT;
508 goto rflag;
509 case 'l':
510 if (*fmt == 'l') {
511 fmt++;
512 flags |= QUADINT;
513 } else {
514 flags |= LONGINT;
515 }
516 goto rflag;
517 case 'q':
518 flags |= QUADINT;
519 goto rflag;
520 case 't':
521 flags |= PTRINT;
522 goto rflag;
523 case 'z':
524 flags |= SIZEINT;
525 goto rflag;
526 case 'c':
527 #ifdef POSITIONAL_PARAMS
528 if (positional > 0)
529 *buf = (int)parg[argnum]._uintmax;
530 else
531 #endif
532 *buf = va_arg(ap, int);
533 cp = buf;
534 size = 1;
535 sign = '\0';
536 break;
537 case 'D':
538 flags |= LONGINT;
539 /*FALLTHROUGH*/
540 case 'd':
541 case 'i':
542 #ifdef POSITIONAL_PARAMS
543 if (positional > 0)
544 _uintmax = parg[argnum]._uintmax;
545 else
546 #endif
547 _uintmax = SARG(flags, ap);
548 if ((intmax_t)_uintmax < 0) {
549 _uintmax = -_uintmax;
550 sign = '-';
551 }
552 base = DEC;
553 goto number;
554 #ifndef NO_FLOATING_POINT
555 case 'e':
556 case 'E':
557 case 'f':
558 case 'F':
559 case 'g':
560 case 'G':
561 if (prec == -1) {
562 prec = DEFPREC;
563 } else if ((ch == 'g' || ch == 'G') && prec == 0) {
564 prec = 1;
565 }
566
567 #ifdef POSITIONAL_PARAMS
568 if (positional > 0)
569 _double = parg[argnum]._double;
570 else
571 #endif
572 if (flags & LONGDBL) {
573 _double = (double) va_arg(ap, long double);
574 } else {
575 _double = va_arg(ap, double);
576 }
577
578 /* do this before tricky precision changes */
579 if (isinf(_double)) {
580 if (_double < 0)
581 sign = '-';
582 if (ch == 'E' || ch == 'F' || ch == 'G')
583 cp = "INF";
584 else
585 cp = "inf";
586 size = 3;
587 break;
588 }
589 if (isnan(_double)) {
590 if (ch == 'E' || ch == 'F' || ch == 'G')
591 cp = "NAN";
592 else
593 cp = "nan";
594 size = 3;
595 break;
596 }
597 if (fp->_flags & __SAFE) {
598 if (ch == 'E' || ch == 'F' || ch == 'G')
599 cp = "UNK";
600 else
601 cp = "unk";
602 size = 3;
603 break;
604 }
605
606 flags |= FPT;
607 if (dtoaresult)
608 __freedtoa(dtoaresult);
609 cp = dtoaresult = cvt(_double, prec, flags, &softsign,
610 &expt, ch, &ndig);
611 if (ch == 'g' || ch == 'G') {
612 if (expt <= -4 || expt > prec)
613 ch = (ch == 'g') ? 'e' : 'E';
614 else
615 ch = 'g';
616 }
617 if (ch == 'e' || ch == 'E') {
618 --expt;
619 expsize = exponent(expstr, expt, ch);
620 size = expsize + ndig;
621 if (ndig > 1 || flags & ALT)
622 ++size;
623 } else if (ch == 'f' || ch == 'F') {
624 if (expt > 0) {
625 size = expt;
626 if (prec || flags & ALT)
627 size += prec + 1;
628 } else /* "0.X" */
629 size = prec + 2;
630 } else if (expt >= ndig) { /* fixed g fmt */
631 size = expt;
632 if (flags & ALT)
633 ++size;
634 } else
635 size = ndig + (expt > 0 ?
636 1 : 2 - expt);
637
638 if (softsign)
639 sign = '-';
640 break;
641 #endif /* NO_FLOATING_POINT */
642 case 'n':
643 #ifdef POSITIONAL_PARAMS
644 if (positional > 0)
645 /*
646 * This could be implemented, but it stinks
647 * of a security risk.
648 */
649 PRINT("(%n unassigned)", 15);
650 else
651 #endif
652 if (flags & MAXINT)
653 *va_arg(ap, intmax_t *) = ret;
654 else if (flags & PTRINT)
655 *va_arg(ap, ptrdiff_t *) = ret;
656 else if (flags & SIZEINT)
657 *va_arg(ap, ssize_t *) = ret; /* XXX */
658 else if (flags & QUADINT)
659 *va_arg(ap, quad_t *) = ret;
660 else if (flags & LONGINT)
661 *va_arg(ap, long *) = ret;
662 else if (flags & SHORTINT)
663 *va_arg(ap, short *) = ret;
664 else
665 *va_arg(ap, int *) = ret;
666 continue; /* no output */
667 case 'O':
668 flags |= LONGINT;
669 /*FALLTHROUGH*/
670 case 'o':
671 #ifdef POSITIONAL_PARAMS
672 if (positional > 0)
673 _uintmax = parg[argnum]._uintmax;
674 else
675 #endif
676 _uintmax = UARG(flags, ap);
677 base = OCT;
678 goto nosign;
679 case 'p':
680 /*
681 * ``The argument shall be a pointer to void. The
682 * value of the pointer is converted to a sequence
683 * of printable characters, in an implementation-
684 * defined manner.''
685 * -- ANSI X3J11
686 */
687 #ifdef POSITIONAL_PARAMS
688 if (positional > 0)
689 _uintmax = (uintptr_t)parg[argnum]._pointer;
690 else
691 #endif
692 /* NOSTRICT */
693 _uintmax = (uintptr_t)va_arg(ap, void *);
694 base = HEX;
695 xdigs = "0123456789abcdef";
696 flags |= HEXPREFIX;
697 ch = 'x';
698 goto nosign;
699 case 's':
700 #ifdef POSITIONAL_PARAMS
701 if (positional > 0)
702 cp = parg[argnum]._pointer;
703 else
704 #endif
705 cp = va_arg(ap, char *);
706 if (cp == NULL)
707 cp = "(null)";
708 if (prec >= 0) {
709 /*
710 * can't use strlen; can only look for the
711 * NUL in the first `prec' characters, and
712 * strlen() will go further.
713 */
714 char *p = memchr(cp, 0, (size_t)prec);
715
716 if (p != NULL) {
717 size = p - cp;
718 if (size > prec)
719 size = prec;
720 } else
721 size = prec;
722 } else
723 size = strlen(cp);
724 sign = '\0';
725 break;
726 case 'U':
727 flags |= LONGINT;
728 /*FALLTHROUGH*/
729 case 'u':
730 #ifdef POSITIONAL_PARAMS
731 if (positional > 0)
732 _uintmax = parg[argnum]._uintmax;
733 else
734 #endif
735 _uintmax = UARG(flags, ap);
736 base = DEC;
737 goto nosign;
738 case 'X':
739 xdigs = "0123456789ABCDEF";
740 goto hex;
741 case 'x':
742 xdigs = "0123456789abcdef";
743 hex:
744 #ifdef POSITIONAL_PARAMS
745 if (positional > 0)
746 _uintmax = parg[argnum]._uintmax;
747 else
748 #endif
749 _uintmax = UARG(flags, ap);
750 base = HEX;
751 /* leading 0x/X only if non-zero */
752 if (flags & ALT && _uintmax != 0)
753 flags |= HEXPREFIX;
754
755 /* unsigned conversions */
756 nosign: sign = '\0';
757 /*
758 * ``... diouXx conversions ... if a precision is
759 * specified, the 0 flag will be ignored.''
760 * -- ANSI X3J11
761 */
762 number: if ((dprec = prec) >= 0)
763 flags &= ~ZEROPAD;
764
765 /*
766 * ``The result of converting a zero value with an
767 * explicit precision of zero is no characters.''
768 * -- ANSI X3J11
769 */
770 bp = buf + BUF;
771 if (_uintmax != 0 || prec != 0) {
772 /*
773 * Unsigned mod is hard, and unsigned mod
774 * by a constant is easier than that by
775 * a variable; hence this switch.
776 */
777 switch (base) {
778 case OCT:
779 do {
780 *--bp = to_char(_uintmax & 7);
781 _uintmax >>= 3;
782 } while (_uintmax);
783 /* handle octal leading 0 */
784 if (flags & ALT && *bp != '0')
785 *--bp = '0';
786 break;
787
788 case DEC:
789 /* many numbers are 1 digit */
790 while (_uintmax >= 10) {
791 *--bp = to_char(_uintmax % 10);
792 _uintmax /= 10;
793 }
794 *--bp = to_char(_uintmax);
795 break;
796
797 case HEX:
798 do {
799 *--bp = xdigs[(size_t)
800 (_uintmax & 15)];
801 _uintmax >>= 4;
802 } while (_uintmax);
803 break;
804
805 default:
806 cp = "bug in vfprintf: bad base";
807 size = strlen(cp);
808 goto skipsize;
809 }
810 }
811 cp = bp;
812 size = buf + BUF - bp;
813 skipsize:
814 break;
815 default: /* "%?" prints ?, unless ? is NUL */
816 invalid:
817 if (ch == '\0')
818 goto done;
819 /* Back up so we output all of the errorous format */
820 fmt = fmt0 + 1;
821 /* FALLTHROUGH */
822 case '%':
823 if (fmt != fmt0 + 2)
824 goto invalid;
825 /* Output a single '%' */
826 *buf = '%';
827 cp = buf;
828 size = 1;
829 sign = '\0';
830 width = 0;
831 prec = -1;
832 #ifdef POSITIONAL_PARAMS
833 argnum = 1;
834 #endif
835 break;
836 }
837
838 #ifdef POSITIONAL_PARAMS
839 if (argnum == 0) {
840 if (positional == 0)
841 positional = -1;
842 if (positional > 0)
843 goto invalid;
844 }
845 argnum = 0;
846 #endif
847
848 /*
849 * All reasonable formats wind up here. At this point, `cp'
850 * points to a string which (if not flags&LADJUST) should be
851 * padded out to `width' places. If flags&ZEROPAD, it should
852 * first be prefixed by any sign or other prefix; otherwise,
853 * it should be blank padded before the prefix is emitted.
854 * After any left-hand padding and prefixing, emit zeroes
855 * required by a decimal [diouxX] precision, then print the
856 * string proper, then emit zeroes required by any leftover
857 * floating precision; finally, if LADJUST, pad with blanks.
858 *
859 * Compute actual size, so we know how much to pad.
860 * size excludes decimal prec; realsz includes it.
861 */
862 realsz = dprec > size ? dprec : size;
863 if (sign)
864 realsz++;
865 else if (flags & HEXPREFIX)
866 realsz+= 2;
867
868 /* right-adjusting blank padding */
869 if ((flags & (LADJUST|ZEROPAD)) == 0)
870 PAD(width - realsz, blanks);
871
872 /* prefix */
873 if (sign) {
874 PRINT(&sign, 1);
875 } else if (flags & HEXPREFIX) {
876 ox[0] = '0';
877 ox[1] = ch;
878 PRINT(ox, 2);
879 }
880
881 /* right-adjusting zero padding */
882 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
883 PAD(width - realsz, zeroes);
884
885 /* leading zeroes from decimal precision */
886 PAD(dprec - size, zeroes);
887
888 /* the string or number proper */
889 #ifndef NO_FLOATING_POINT
890 if ((flags & FPT) == 0) {
891 PRINT(cp, size);
892 } else { /* glue together f_p fragments */
893 if (ch >= 'f') { /* 'f' or 'g' */
894 if (decimal_point == NULL)
895 decimal_point =
896 localeconv()->decimal_point;
897 if (_double == 0) {
898 /* kludge for __dtoa irregularity */
899 PRINT("0", 1);
900 if (expt < ndig || (flags & ALT) != 0) {
901 PRINT(decimal_point, 1);
902 PAD(ndig - 1, zeroes);
903 }
904 } else if (expt <= 0) {
905 PRINT("0", 1);
906 PRINT(decimal_point, 1);
907 PAD(-expt, zeroes);
908 PRINT(cp, ndig);
909 } else if (expt >= ndig) {
910 PRINT(cp, ndig);
911 PAD(expt - ndig, zeroes);
912 if (flags & ALT)
913 PRINT(".", 1);
914 } else {
915 PRINT(cp, expt);
916 cp += expt;
917 PRINT(".", 1);
918 PRINT(cp, ndig-expt);
919 }
920 } else { /* 'e' or 'E' */
921 if (ndig > 1 || flags & ALT) {
922 ox[0] = *cp++;
923 ox[1] = '.';
924 PRINT(ox, 2);
925 if (_double) {
926 PRINT(cp, ndig-1);
927 } else /* 0.[0..] */
928 /* __dtoa irregularity */
929 PAD(ndig - 1, zeroes);
930 } else /* XeYYY */
931 PRINT(cp, 1);
932 PRINT(expstr, expsize);
933 }
934 }
935 #else
936 PRINT(cp, size);
937 #endif
938 /* left-adjusting padding (always blank) */
939 if (flags & LADJUST)
940 PAD(width - realsz, blanks);
941
942 /* finally, adjust ret */
943 ret += width > realsz ? width : realsz;
944
945 FLUSH(); /* copy out the I/O vectors */
946 }
947 done:
948 FLUSH();
949 error:
950 #ifndef NO_FLOATING_POINT
951 if (dtoaresult)
952 __freedtoa(dtoaresult);
953 #endif
954 if (__sferror(fp))
955 ret = -1;
956 return (ret);
957 }
958
959 #ifndef NO_FLOATING_POINT
960
961 static char *
962 cvt(value, ndigits, flags, sign, decpt, ch, length)
963 double value;
964 int ndigits, flags, *decpt, ch, *length;
965 char *sign;
966 {
967 int mode, dsgn;
968 char *digits, *bp, *rve;
969
970 _DIAGASSERT(decpt != NULL);
971 _DIAGASSERT(length != NULL);
972 _DIAGASSERT(sign != NULL);
973
974 if (ch == 'f') {
975 mode = 3; /* ndigits after the decimal point */
976 } else {
977 /* To obtain ndigits after the decimal point for the 'e'
978 * and 'E' formats, round to ndigits + 1 significant
979 * figures.
980 */
981 if (ch == 'e' || ch == 'E') {
982 ndigits++;
983 }
984 mode = 2; /* ndigits significant digits */
985 }
986
987 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
988 if (dsgn) {
989 value = -value;
990 *sign = '-';
991 } else
992 *sign = '\000';
993 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
994 bp = digits + ndigits;
995 if (ch == 'f') {
996 if (*digits == '0' && value)
997 *decpt = -ndigits + 1;
998 bp += *decpt;
999 }
1000 if (value == 0) /* kludge for __dtoa irregularity */
1001 rve = bp;
1002 while (rve < bp)
1003 *rve++ = '0';
1004 }
1005 *length = rve - digits;
1006 return (digits);
1007 }
1008
1009 static int
1010 exponent(p0, expon, fmtch)
1011 char *p0;
1012 int expon, fmtch;
1013 {
1014 char *p, *t;
1015 char expbuf[MAXEXP];
1016
1017 _DIAGASSERT(p0 != NULL);
1018
1019 p = p0;
1020 *p++ = fmtch;
1021 if (expon < 0) {
1022 expon = -expon;
1023 *p++ = '-';
1024 }
1025 else
1026 *p++ = '+';
1027 t = expbuf + MAXEXP;
1028 if (expon > 9) {
1029 do {
1030 *--t = to_char(expon % 10);
1031 } while ((expon /= 10) > 9);
1032 *--t = to_char(expon);
1033 for (; t < expbuf + MAXEXP; *p++ = *t++);
1034 }
1035 else {
1036 *p++ = '0';
1037 *p++ = to_char(expon);
1038 }
1039 return (p - p0);
1040 }
1041 #endif /* NO_FLOATING_POINT */
1042
1043 #ifdef POSITIONAL_PARAMS
1044 static void parse_fmt(union parg *, const char *);
1045
1046 static void
1047 set_printf_args(union parg *arg, const char *fmt, _BSD_VA_LIST_ ap)
1048 {
1049 int flags;
1050 int i;
1051
1052 /*
1053 * In order to set ap so that the n'th argument can be picked next
1054 * we have to know the type of all the arguments.
1055 */
1056 parse_fmt(arg, fmt);
1057
1058 /* Now walk ap along the arguments saving the values */
1059 for (i = 1; i <= NL_ARGMAX; i++) {
1060 flags = arg[i].flags;
1061 if (flags == 0)
1062 /* arg not used in format */
1063 break;
1064 if (flags & POINTER) {
1065 if (flags & CHARINT)
1066 arg[i]._pointer = va_arg(ap, char *);
1067 else
1068 arg[i]._pointer = va_arg(ap, void *);
1069 continue;
1070 }
1071 if (flags & FPT) {
1072 if (flags & LONGDBL)
1073 arg[i]._double = va_arg(ap, long double);
1074 else
1075 arg[i]._double = va_arg(ap, double);
1076 continue;
1077 }
1078 if (flags & SIGNED)
1079 arg[i]._uintmax = SARG(flags, ap);
1080 else
1081 arg[i]._uintmax = UARG(flags, ap);
1082 }
1083 return;
1084 }
1085
1086 static void
1087 parse_fmt(union parg *arg, const char *fmt)
1088 {
1089 int argnum;
1090 int flags;
1091 int n;
1092 char ch;
1093 wchar_t wc;
1094 mbstate_t ps;
1095
1096 mbrtowc(NULL, NULL, 0, &ps);
1097
1098 for (;;) {
1099 do {
1100 n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps);
1101 if (n <= 0)
1102 return;
1103 fmt += n;
1104 } while (wc != '%');
1105 /* Positional formats all start "%n$" */
1106 ch = *fmt++;
1107 if (ch < '1' || ch > '9' || *fmt != '$')
1108 continue;
1109 fmt++;
1110 argnum = to_digit(ch);
1111 flags = ALT; /* something non-zero that doesn't matter */
1112 for (;;) {
1113 ch = *fmt++;
1114 switch (ch) {
1115 case ' ': continue;
1116 case '#': continue;
1117 case '-': continue;
1118 case '+': continue;
1119 case '*': continue;
1120 case '0': continue;
1121 case '.': continue;
1122 case 'h': flags |= SHORTINT; continue;
1123 case 'j': flags |= MAXINT; continue;
1124 #ifdef FLOATING_POINT
1125 case 'L': flags |= LONGDBL; continue;
1126 #endif
1127 case 'q': flags |= QUADINT; continue;
1128 case 't': flags |= PTRINT; continue;
1129 case 'z': flags |= SIZEINT; continue;
1130 case 'l':
1131 if (fmt[0] == 'l') {
1132 fmt++;
1133 flags |= QUADINT;
1134 } else
1135 flags |= LONGINT;
1136 continue;
1137 case '1': case '2': case '3': case '4':
1138 case '5': case '6': case '7': case '8': case '9':
1139 if (*fmt == '$') {
1140 fmt++;
1141 arg[to_digit(ch)].flags = SIGNED;
1142 }
1143 continue;
1144 case 'D':
1145 flags |= LONGINT | SIGNED;
1146 break;
1147 case 'O': case 'U':
1148 flags |= LONGINT;
1149 break;
1150 case 'd': case 'i':
1151 flags |= SIGNED;
1152 break;
1153 case 'c': case 'o': case 'u': case 'X': case 'x':
1154 break;
1155 #ifdef FLOATING_POINT
1156 case 'e': case 'f': case 'g':
1157 case 'E': case 'F': case 'G':
1158 flags |= FPT;
1159 break;
1160 #endif /* FLOATING_POINT */
1161 case 's':
1162 flags |= CHARINT | POINTER;
1163 break;
1164 case 'n': case 'p':
1165 flags |= POINTER;
1166 break;
1167 default:
1168 /* Unexpected end of format */
1169 if (ch == 0)
1170 return;
1171 ch = 0;
1172 break;
1173 }
1174 if (argnum != 0)
1175 arg[argnum].flags = flags;
1176 break;
1177 }
1178 }
1179 }
1180 #endif
1181 #endif
1182 #define NARROW
1183 #include "vfwprintf.c"
1184