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