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