]> git.saurik.com Git - apple/libc.git/blob - stdio.subproj/vfprintf.c
f819e259b1313657f8394ea02b50ab71e024ec6f
[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 *));
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 #endif
326 u_long ulval = 0; /* integer arguments %[diouxX] */
327 u_quad_t uqval = 0; /* %q integers */
328 int base; /* base for [diouxX] conversion */
329 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
330 int realsz; /* field size expanded by dprec, sign, etc */
331 int size; /* size of converted field or string */
332 int prsize; /* max size of printed field */
333 char *xdigs = NULL; /* digits for [xX] conversion */
334 #define NIOV 8
335 struct __suio uio; /* output information: summary */
336 struct __siov iov[NIOV];/* ... and individual io vectors */
337 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
338 char ox[2]; /* space for 0x hex-prefix */
339 void **argtable; /* args, built due to positional arg */
340 void *statargtable [STATIC_ARG_TBL_SIZE];
341 int nextarg; /* 1-based argument index */
342 va_list orgap; /* original argument pointer */
343
344 /*
345 * Choose PADSIZE to trade efficiency vs. size. If larger printf
346 * fields occur frequently, increase PADSIZE and make the initialisers
347 * below longer.
348 */
349 #define PADSIZE 16 /* pad chunk size */
350 static char blanks[PADSIZE] =
351 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
352 static char zeroes[PADSIZE] =
353 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
354
355 /*
356 * BEWARE, these `goto error' on error, and PAD uses `n'.
357 */
358 #define PRINT(ptr, len) { \
359 iovp->iov_base = (ptr); \
360 iovp->iov_len = (len); \
361 uio.uio_resid += (len); \
362 iovp++; \
363 if (++uio.uio_iovcnt >= NIOV) { \
364 if (__sprint(fp, &uio)) \
365 goto error; \
366 iovp = iov; \
367 } \
368 }
369 #define PAD(howmany, with) { \
370 if ((n = (howmany)) > 0) { \
371 while (n > PADSIZE) { \
372 PRINT(with, PADSIZE); \
373 n -= PADSIZE; \
374 } \
375 PRINT(with, n); \
376 } \
377 }
378 #define FLUSH() { \
379 if (uio.uio_resid && __sprint(fp, &uio)) \
380 goto error; \
381 uio.uio_iovcnt = 0; \
382 iovp = iov; \
383 }
384
385 /*
386 * Get the argument indexed by nextarg. If the argument table is
387 * built, use it to get the argument. If its not, get the next
388 * argument (and arguments must be gotten sequentially).
389 */
390 #define GETARG(type) \
391 ((argtable != NULL) ? *((type*)(argtable[nextarg++])) : \
392 (nextarg++, va_arg(ap, type)))
393
394 /*
395 * To extend shorts properly, we need both signed and unsigned
396 * argument extraction methods.
397 */
398 #define SARG() \
399 (flags&LONGINT ? GETARG(long) : \
400 flags&SHORTINT ? (long)(short)GETARG(int) : \
401 (long)GETARG(int))
402 #define UARG() \
403 (flags&LONGINT ? GETARG(u_long) : \
404 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
405 (u_long)GETARG(u_int))
406
407 /*
408 * Get * arguments, including the form *nn$. Preserve the nextarg
409 * that the argument can be gotten once the type is determined.
410 */
411 #define GETASTER(val) \
412 n2 = 0; \
413 cp = fmt; \
414 while (is_digit(*cp)) { \
415 n2 = 10 * n2 + to_digit(*cp); \
416 cp++; \
417 } \
418 if (*cp == '$') { \
419 int hold = nextarg; \
420 if (argtable == NULL) { \
421 argtable = statargtable; \
422 __find_arguments (fmt0, orgap, &argtable); \
423 } \
424 nextarg = n2; \
425 val = GETARG (int); \
426 nextarg = hold; \
427 fmt = ++cp; \
428 } else { \
429 val = GETARG (int); \
430 }
431
432
433 /* FLOCKFILE(fp); */
434 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
435 if (cantwrite(fp)) {
436 /* FUNLOCKFILE(fp); */
437 return (EOF);
438 }
439
440 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
441 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
442 fp->_file >= 0) {
443 /* FUNLOCKFILE(fp); */
444 return (__sbprintf(fp, fmt0, ap));
445 }
446
447 fmt = (char *)fmt0;
448 argtable = NULL;
449 nextarg = 1;
450 orgap = ap;
451 uio.uio_iov = iovp = iov;
452 uio.uio_resid = 0;
453 uio.uio_iovcnt = 0;
454 ret = 0;
455
456 /*
457 * Scan the format for conversions (`%' character).
458 */
459 for (;;) {
460 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
461 /* void */;
462 if ((n = fmt - cp) != 0) {
463 if ((unsigned)ret + n > INT_MAX) {
464 ret = EOF;
465 goto error;
466 }
467 PRINT(cp, n);
468 ret += n;
469 }
470 if (ch == '\0')
471 goto done;
472 fmt++; /* skip over '%' */
473
474 flags = 0;
475 dprec = 0;
476 width = 0;
477 prec = -1;
478 sign = '\0';
479
480 rflag: ch = *fmt++;
481 reswitch: switch (ch) {
482 case ' ':
483 /*
484 * ``If the space and + flags both appear, the space
485 * flag will be ignored.''
486 * -- ANSI X3J11
487 */
488 if (!sign)
489 sign = ' ';
490 goto rflag;
491 case '#':
492 flags |= ALT;
493 goto rflag;
494 case '*':
495 /*
496 * ``A negative field width argument is taken as a
497 * - flag followed by a positive field width.''
498 * -- ANSI X3J11
499 * They don't exclude field widths read from args.
500 */
501 GETASTER (width);
502 if (width >= 0)
503 goto rflag;
504 width = -width;
505 /* FALLTHROUGH */
506 case '-':
507 flags |= LADJUST;
508 goto rflag;
509 case '+':
510 sign = '+';
511 goto rflag;
512 case '.':
513 if ((ch = *fmt++) == '*') {
514 GETASTER (n);
515 prec = n < 0 ? -1 : n;
516 goto rflag;
517 }
518 n = 0;
519 while (is_digit(ch)) {
520 n = 10 * n + to_digit(ch);
521 ch = *fmt++;
522 }
523 prec = n < 0 ? -1 : n;
524 goto reswitch;
525 case '0':
526 /*
527 * ``Note that 0 is taken as a flag, not as the
528 * beginning of a field width.''
529 * -- ANSI X3J11
530 */
531 flags |= ZEROPAD;
532 goto rflag;
533 case '1': case '2': case '3': case '4':
534 case '5': case '6': case '7': case '8': case '9':
535 n = 0;
536 do {
537 n = 10 * n + to_digit(ch);
538 ch = *fmt++;
539 } while (is_digit(ch));
540 if (ch == '$') {
541 nextarg = n;
542 if (argtable == NULL) {
543 argtable = statargtable;
544 __find_arguments (fmt0, orgap,
545 &argtable);
546 }
547 goto rflag;
548 }
549 width = n;
550 goto reswitch;
551 #ifdef FLOATING_POINT
552 case 'L':
553 flags |= LONGDBL;
554 goto rflag;
555 #endif
556 case 'h':
557 flags |= SHORTINT;
558 goto rflag;
559 case 'l':
560 if (flags & LONGINT)
561 flags |= QUADINT;
562 else
563 flags |= LONGINT;
564 goto rflag;
565 case 'q':
566 flags |= QUADINT;
567 goto rflag;
568 case 'c':
569 *(cp = buf) = GETARG(int);
570 size = 1;
571 sign = '\0';
572 break;
573 case 'D':
574 flags |= LONGINT;
575 /*FALLTHROUGH*/
576 case 'd':
577 case 'i':
578 if (flags & QUADINT) {
579 uqval = GETARG(quad_t);
580 if ((quad_t)uqval < 0) {
581 uqval = -uqval;
582 sign = '-';
583 }
584 } else {
585 ulval = SARG();
586 if ((long)ulval < 0) {
587 ulval = -ulval;
588 sign = '-';
589 }
590 }
591 base = 10;
592 goto number;
593 #ifdef FLOATING_POINT
594 case 'e':
595 case 'E':
596 case 'f':
597 goto fp_begin;
598 case 'g':
599 case 'G':
600 if (prec == 0)
601 prec = 1;
602 fp_begin: if (prec == -1)
603 prec = DEFPREC;
604 if (flags & LONGDBL)
605 /* XXX this loses precision. */
606 _double = (double)GETARG(long double);
607 else
608 _double = GETARG(double);
609 /* do this before tricky precision changes */
610 if (isinf(_double)) {
611 if (_double < 0)
612 sign = '-';
613 cp = "Inf";
614 size = 3;
615 break;
616 }
617 if (isnan(_double)) {
618 cp = "NaN";
619 size = 3;
620 break;
621 }
622 flags |= FPT;
623 cp = cvt(_double, prec, flags, &softsign,
624 &expt, ch, &ndig);
625 if (ch == 'g' || ch == 'G') {
626 if (expt <= -4 || expt > prec)
627 ch = (ch == 'g') ? 'e' : 'E';
628 else
629 ch = 'g';
630 }
631 if (ch <= 'e') { /* 'e' or 'E' fmt */
632 --expt;
633 expsize = exponent(expstr, expt, ch);
634 size = expsize + ndig;
635 if (ndig > 1 || flags & ALT)
636 ++size;
637 } else if (ch == 'f') { /* f fmt */
638 if (expt > 0) {
639 size = expt;
640 if (prec || flags & ALT)
641 size += prec + 1;
642 } else /* "0.X" */
643 size = prec + 2;
644 } else if (expt >= ndig) { /* fixed g fmt */
645 size = expt;
646 if (flags & ALT)
647 ++size;
648 } else
649 size = ndig + (expt > 0 ?
650 1 : 2 - expt);
651
652 if (softsign)
653 sign = '-';
654 break;
655 #endif /* FLOATING_POINT */
656 case 'n':
657 if (flags & QUADINT)
658 *GETARG(quad_t *) = ret;
659 else if (flags & LONGINT)
660 *GETARG(long *) = ret;
661 else if (flags & SHORTINT)
662 *GETARG(short *) = ret;
663 else
664 *GETARG(int *) = ret;
665 continue; /* no output */
666 case 'O':
667 flags |= LONGINT;
668 /*FALLTHROUGH*/
669 case 'o':
670 if (flags & QUADINT)
671 uqval = GETARG(u_quad_t);
672 else
673 ulval = UARG();
674 base = 8;
675 goto nosign;
676 case 'p':
677 /*
678 * ``The argument shall be a pointer to void. The
679 * value of the pointer is converted to a sequence
680 * of printable characters, in an implementation-
681 * defined manner.''
682 * -- ANSI X3J11
683 */
684 ulval = (u_long)GETARG(void *);
685 base = 16;
686 xdigs = "0123456789abcdef";
687 flags = (flags & ~QUADINT) | HEXPREFIX;
688 ch = 'x';
689 goto nosign;
690 case 's':
691 if ((cp = GETARG(char *)) == NULL)
692 cp = "(null)";
693 if (prec >= 0) {
694 /*
695 * can't use strlen; can only look for the
696 * NUL in the first `prec' characters, and
697 * strlen() will go further.
698 */
699 char *p = memchr(cp, 0, (size_t)prec);
700
701 if (p != NULL) {
702 size = p - cp;
703 if (size > prec)
704 size = prec;
705 } else
706 size = prec;
707 } else
708 size = strlen(cp);
709 sign = '\0';
710 break;
711 case 'U':
712 flags |= LONGINT;
713 /*FALLTHROUGH*/
714 case 'u':
715 if (flags & QUADINT)
716 uqval = GETARG(u_quad_t);
717 else
718 ulval = UARG();
719 base = 10;
720 goto nosign;
721 case 'X':
722 xdigs = "0123456789ABCDEF";
723 goto hex;
724 case 'x':
725 xdigs = "0123456789abcdef";
726 hex: if (flags & QUADINT)
727 uqval = GETARG(u_quad_t);
728 else
729 ulval = UARG();
730 base = 16;
731 /* leading 0x/X only if non-zero */
732 if (flags & ALT &&
733 (flags & QUADINT ? uqval != 0 : ulval != 0))
734 flags |= HEXPREFIX;
735
736 /* unsigned conversions */
737 nosign: sign = '\0';
738 /*
739 * ``... diouXx conversions ... if a precision is
740 * specified, the 0 flag will be ignored.''
741 * -- ANSI X3J11
742 */
743 number: if ((dprec = prec) >= 0)
744 flags &= ~ZEROPAD;
745
746 /*
747 * ``The result of converting a zero value with an
748 * explicit precision of zero is no characters.''
749 * -- ANSI X3J11
750 */
751 cp = buf + BUF;
752 if (flags & QUADINT) {
753 if (uqval != 0 || prec != 0)
754 cp = __uqtoa(uqval, cp, base,
755 flags & ALT, xdigs);
756 } else {
757 if (ulval != 0 || prec != 0)
758 cp = __ultoa(ulval, cp, base,
759 flags & ALT, xdigs);
760 }
761 size = buf + BUF - cp;
762 break;
763 default: /* "%?" prints ?, unless ? is NUL */
764 if (ch == '\0')
765 goto done;
766 /* pretend it was %c with argument ch */
767 cp = buf;
768 *cp = ch;
769 size = 1;
770 sign = '\0';
771 break;
772 }
773
774 /*
775 * All reasonable formats wind up here. At this point, `cp'
776 * points to a string which (if not flags&LADJUST) should be
777 * padded out to `width' places. If flags&ZEROPAD, it should
778 * first be prefixed by any sign or other prefix; otherwise,
779 * it should be blank padded before the prefix is emitted.
780 * After any left-hand padding and prefixing, emit zeroes
781 * required by a decimal [diouxX] precision, then print the
782 * string proper, then emit zeroes required by any leftover
783 * floating precision; finally, if LADJUST, pad with blanks.
784 *
785 * Compute actual size, so we know how much to pad.
786 * size excludes decimal prec; realsz includes it.
787 */
788 realsz = dprec > size ? dprec : size;
789 if (sign)
790 realsz++;
791 else if (flags & HEXPREFIX)
792 realsz += 2;
793
794 prsize = width > realsz ? width : realsz;
795 if ((unsigned)ret + prsize > INT_MAX) {
796 ret = EOF;
797 goto error;
798 }
799
800 /* right-adjusting blank padding */
801 if ((flags & (LADJUST|ZEROPAD)) == 0)
802 PAD(width - realsz, blanks);
803
804 /* prefix */
805 if (sign) {
806 PRINT(&sign, 1);
807 } else if (flags & HEXPREFIX) {
808 ox[0] = '0';
809 ox[1] = ch;
810 PRINT(ox, 2);
811 }
812
813 /* right-adjusting zero padding */
814 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
815 PAD(width - realsz, zeroes);
816
817 /* leading zeroes from decimal precision */
818 PAD(dprec - size, zeroes);
819
820 /* the string or number proper */
821 #ifdef FLOATING_POINT
822 if ((flags & FPT) == 0) {
823 PRINT(cp, size);
824 } else { /* glue together f_p fragments */
825 if (ch >= 'f') { /* 'f' or 'g' */
826 if (_double == 0) {
827 /* kludge for __dtoa irregularity */
828 if (expt >= ndig &&
829 (flags & ALT) == 0) {
830 PRINT("0", 1);
831 } else {
832 PRINT("0.", 2);
833 PAD(ndig - 1, zeroes);
834 }
835 } else if (expt <= 0) {
836 PRINT("0.", 2);
837 PAD(-expt, zeroes);
838 PRINT(cp, ndig);
839 } else if (expt >= ndig) {
840 PRINT(cp, ndig);
841 PAD(expt - ndig, zeroes);
842 if (flags & ALT)
843 PRINT(".", 1);
844 } else {
845 PRINT(cp, expt);
846 cp += expt;
847 PRINT(".", 1);
848 PRINT(cp, ndig-expt);
849 }
850 } else { /* 'e' or 'E' */
851 if (ndig > 1 || flags & ALT) {
852 ox[0] = *cp++;
853 ox[1] = '.';
854 PRINT(ox, 2);
855 if (_double) {
856 PRINT(cp, ndig-1);
857 } else /* 0.[0..] */
858 /* __dtoa irregularity */
859 PAD(ndig - 1, zeroes);
860 } else /* XeYYY */
861 PRINT(cp, 1);
862 PRINT(expstr, expsize);
863 }
864 }
865 #else
866 PRINT(cp, size);
867 #endif
868 /* left-adjusting padding (always blank) */
869 if (flags & LADJUST)
870 PAD(width - realsz, blanks);
871
872 /* finally, adjust ret */
873 ret += prsize;
874
875 FLUSH(); /* copy out the I/O vectors */
876 }
877 done:
878 FLUSH();
879 error:
880 if (__sferror(fp))
881 ret = EOF;
882 /* FUNLOCKFILE(fp); */
883 if ((argtable != NULL) && (argtable != statargtable))
884 free (argtable);
885 return (ret);
886 /* NOTREACHED */
887 }
888
889 /*
890 * Type ids for argument type table.
891 */
892 #define T_UNUSED 0
893 #define T_SHORT 1
894 #define T_U_SHORT 2
895 #define TP_SHORT 3
896 #define T_INT 4
897 #define T_U_INT 5
898 #define TP_INT 6
899 #define T_LONG 7
900 #define T_U_LONG 8
901 #define TP_LONG 9
902 #define T_QUAD 10
903 #define T_U_QUAD 11
904 #define TP_QUAD 12
905 #define T_DOUBLE 13
906 #define T_LONG_DOUBLE 14
907 #define TP_CHAR 15
908 #define TP_VOID 16
909
910 /*
911 * Find all arguments when a positional parameter is encountered. Returns a
912 * table, indexed by argument number, of pointers to each arguments. The
913 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
914 * It will be replaces with a malloc-ed on if it overflows.
915 */
916 static void
917 __find_arguments (fmt0, ap, argtable)
918 const char *fmt0;
919 va_list ap;
920 void ***argtable;
921 {
922 register char *fmt; /* format string */
923 register int ch; /* character from fmt */
924 register int n, n2; /* handy integer (short term usage) */
925 register char *cp; /* handy char pointer (short term usage) */
926 register int flags; /* flags as above */
927 int width; /* width from format (%8d), or 0 */
928 unsigned char *typetable; /* table of types */
929 unsigned char stattypetable [STATIC_ARG_TBL_SIZE];
930 int tablesize; /* current size of type table */
931 int tablemax; /* largest used index in table */
932 int nextarg; /* 1-based argument index */
933
934 /*
935 * Add an argument type to the table, expanding if necessary.
936 */
937 #define ADDTYPE(type) \
938 ((nextarg >= tablesize) ? \
939 __grow_type_table(nextarg, &typetable, &tablesize) : 0, \
940 typetable[nextarg++] = type, \
941 (nextarg > tablemax) ? tablemax = nextarg : 0)
942
943 #define ADDSARG() \
944 ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
945 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
946
947 #define ADDUARG() \
948 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
949 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
950
951 /*
952 * Add * arguments to the type array.
953 */
954 #define ADDASTER() \
955 n2 = 0; \
956 cp = fmt; \
957 while (is_digit(*cp)) { \
958 n2 = 10 * n2 + to_digit(*cp); \
959 cp++; \
960 } \
961 if (*cp == '$') { \
962 int hold = nextarg; \
963 nextarg = n2; \
964 ADDTYPE (T_INT); \
965 nextarg = hold; \
966 fmt = ++cp; \
967 } else { \
968 ADDTYPE (T_INT); \
969 }
970 fmt = (char *)fmt0;
971 typetable = stattypetable;
972 tablesize = STATIC_ARG_TBL_SIZE;
973 tablemax = 0;
974 nextarg = 1;
975 memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
976
977 /*
978 * Scan the format for conversions (`%' character).
979 */
980 for (;;) {
981 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
982 /* void */;
983 if (ch == '\0')
984 goto done;
985 fmt++; /* skip over '%' */
986
987 flags = 0;
988 width = 0;
989
990 rflag: ch = *fmt++;
991 reswitch: switch (ch) {
992 case ' ':
993 case '#':
994 goto rflag;
995 case '*':
996 ADDASTER ();
997 goto rflag;
998 case '-':
999 case '+':
1000 goto rflag;
1001 case '.':
1002 if ((ch = *fmt++) == '*') {
1003 ADDASTER ();
1004 goto rflag;
1005 }
1006 while (is_digit(ch)) {
1007 ch = *fmt++;
1008 }
1009 goto reswitch;
1010 case '0':
1011 goto rflag;
1012 case '1': case '2': case '3': case '4':
1013 case '5': case '6': case '7': case '8': case '9':
1014 n = 0;
1015 do {
1016 n = 10 * n + to_digit(ch);
1017 ch = *fmt++;
1018 } while (is_digit(ch));
1019 if (ch == '$') {
1020 nextarg = n;
1021 goto rflag;
1022 }
1023 width = n;
1024 goto reswitch;
1025 #ifdef FLOATING_POINT
1026 case 'L':
1027 flags |= LONGDBL;
1028 goto rflag;
1029 #endif
1030 case 'h':
1031 flags |= SHORTINT;
1032 goto rflag;
1033 case 'l':
1034 if (flags & LONGINT)
1035 flags |= QUADINT;
1036 else
1037 flags |= LONGINT;
1038 goto rflag;
1039 case 'q':
1040 flags |= QUADINT;
1041 goto rflag;
1042 case 'c':
1043 ADDTYPE(T_INT);
1044 break;
1045 case 'D':
1046 flags |= LONGINT;
1047 /*FALLTHROUGH*/
1048 case 'd':
1049 case 'i':
1050 if (flags & QUADINT) {
1051 ADDTYPE(T_QUAD);
1052 } else {
1053 ADDSARG();
1054 }
1055 break;
1056 #ifdef FLOATING_POINT
1057 case 'e':
1058 case 'E':
1059 case 'f':
1060 case 'g':
1061 case 'G':
1062 if (flags & LONGDBL)
1063 ADDTYPE(T_LONG_DOUBLE);
1064 else
1065 ADDTYPE(T_DOUBLE);
1066 break;
1067 #endif /* FLOATING_POINT */
1068 case 'n':
1069 if (flags & QUADINT)
1070 ADDTYPE(TP_QUAD);
1071 else if (flags & LONGINT)
1072 ADDTYPE(TP_LONG);
1073 else if (flags & SHORTINT)
1074 ADDTYPE(TP_SHORT);
1075 else
1076 ADDTYPE(TP_INT);
1077 continue; /* no output */
1078 case 'O':
1079 flags |= LONGINT;
1080 /*FALLTHROUGH*/
1081 case 'o':
1082 if (flags & QUADINT)
1083 ADDTYPE(T_U_QUAD);
1084 else
1085 ADDUARG();
1086 break;
1087 case 'p':
1088 ADDTYPE(TP_VOID);
1089 break;
1090 case 's':
1091 ADDTYPE(TP_CHAR);
1092 break;
1093 case 'U':
1094 flags |= LONGINT;
1095 /*FALLTHROUGH*/
1096 case 'u':
1097 if (flags & QUADINT)
1098 ADDTYPE(T_U_QUAD);
1099 else
1100 ADDUARG();
1101 break;
1102 case 'X':
1103 case 'x':
1104 if (flags & QUADINT)
1105 ADDTYPE(T_U_QUAD);
1106 else
1107 ADDUARG();
1108 break;
1109 default: /* "%?" prints ?, unless ? is NUL */
1110 if (ch == '\0')
1111 goto done;
1112 break;
1113 }
1114 }
1115 done:
1116 /*
1117 * Build the argument table.
1118 */
1119 if (tablemax >= STATIC_ARG_TBL_SIZE) {
1120 *argtable = (void **)
1121 malloc (sizeof (void *) * (tablemax + 1));
1122 }
1123
1124 (*argtable) [0] = NULL;
1125 for (n = 1; n <= tablemax; n++) {
1126 switch (typetable [n]) {
1127 case T_UNUSED:
1128 (*argtable) [n] = (void *) &va_arg (ap, int);
1129 break;
1130 case T_SHORT:
1131 (*argtable) [n] = (void *) &va_arg (ap, int);
1132 break;
1133 case T_U_SHORT:
1134 (*argtable) [n] = (void *) &va_arg (ap, int);
1135 break;
1136 case TP_SHORT:
1137 (*argtable) [n] = (void *) &va_arg (ap, short *);
1138 break;
1139 case T_INT:
1140 (*argtable) [n] = (void *) &va_arg (ap, int);
1141 break;
1142 case T_U_INT:
1143 (*argtable) [n] = (void *) &va_arg (ap, unsigned int);
1144 break;
1145 case TP_INT:
1146 (*argtable) [n] = (void *) &va_arg (ap, int *);
1147 break;
1148 case T_LONG:
1149 (*argtable) [n] = (void *) &va_arg (ap, long);
1150 break;
1151 case T_U_LONG:
1152 (*argtable) [n] = (void *) &va_arg (ap, unsigned long);
1153 break;
1154 case TP_LONG:
1155 (*argtable) [n] = (void *) &va_arg (ap, long *);
1156 break;
1157 case T_QUAD:
1158 (*argtable) [n] = (void *) &va_arg (ap, quad_t);
1159 break;
1160 case T_U_QUAD:
1161 (*argtable) [n] = (void *) &va_arg (ap, u_quad_t);
1162 break;
1163 case TP_QUAD:
1164 (*argtable) [n] = (void *) &va_arg (ap, quad_t *);
1165 break;
1166 case T_DOUBLE:
1167 (*argtable) [n] = (void *) &va_arg (ap, double);
1168 break;
1169 case T_LONG_DOUBLE:
1170 (*argtable) [n] = (void *) &va_arg (ap, long double);
1171 break;
1172 case TP_CHAR:
1173 (*argtable) [n] = (void *) &va_arg (ap, char *);
1174 break;
1175 case TP_VOID:
1176 (*argtable) [n] = (void *) &va_arg (ap, void *);
1177 break;
1178 }
1179 }
1180
1181 if ((typetable != NULL) && (typetable != stattypetable))
1182 free (typetable);
1183 }
1184
1185 /*
1186 * Increase the size of the type table.
1187 */
1188 static void
1189 __grow_type_table (nextarg, typetable, tablesize)
1190 int nextarg;
1191 unsigned char **typetable;
1192 int *tablesize;
1193 {
1194 unsigned char *oldtable = *typetable;
1195 int newsize = *tablesize * 2;
1196
1197 if (*tablesize == STATIC_ARG_TBL_SIZE) {
1198 *typetable = (unsigned char *)
1199 malloc (sizeof (unsigned char) * newsize);
1200 bcopy (oldtable, *typetable, *tablesize);
1201 } else {
1202 *typetable = (unsigned char *)
1203 realloc (typetable, sizeof (unsigned char) * newsize);
1204
1205 }
1206 memset (&typetable [*tablesize], T_UNUSED, (newsize - *tablesize));
1207
1208 *tablesize = newsize;
1209 }
1210
1211
1212 #ifdef FLOATING_POINT
1213
1214 extern char *__dtoa __P((double, int, int, int *, int *, char **));
1215
1216 static char *
1217 cvt(value, ndigits, flags, sign, decpt, ch, length)
1218 double value;
1219 int ndigits, flags, *decpt, ch, *length;
1220 char *sign;
1221 {
1222 int mode, dsgn;
1223 char *digits, *bp, *rve;
1224
1225 if (ch == 'f')
1226 mode = 3; /* ndigits after the decimal point */
1227 else {
1228 /*
1229 * To obtain ndigits after the decimal point for the 'e'
1230 * and 'E' formats, round to ndigits + 1 significant
1231 * figures.
1232 */
1233 if (ch == 'e' || ch == 'E')
1234 ndigits++;
1235 mode = 2; /* ndigits significant digits */
1236 }
1237 if (value < 0) {
1238 value = -value;
1239 *sign = '-';
1240 } else
1241 *sign = '\000';
1242 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
1243 if ((ch != 'g' && ch != 'G') || flags & ALT) {
1244 /* print trailing zeros */
1245 bp = digits + ndigits;
1246 if (ch == 'f') {
1247 if (*digits == '0' && value)
1248 *decpt = -ndigits + 1;
1249 bp += *decpt;
1250 }
1251 if (value == 0) /* kludge for __dtoa irregularity */
1252 rve = bp;
1253 while (rve < bp)
1254 *rve++ = '0';
1255 }
1256 *length = rve - digits;
1257 return (digits);
1258 }
1259
1260 static int
1261 exponent(p0, exp, fmtch)
1262 char *p0;
1263 int exp, fmtch;
1264 {
1265 register char *p, *t;
1266 char expbuf[MAXEXP];
1267
1268 p = p0;
1269 *p++ = fmtch;
1270 if (exp < 0) {
1271 exp = -exp;
1272 *p++ = '-';
1273 }
1274 else
1275 *p++ = '+';
1276 t = expbuf + MAXEXP;
1277 if (exp > 9) {
1278 do {
1279 *--t = to_char(exp % 10);
1280 } while ((exp /= 10) > 9);
1281 *--t = to_char(exp);
1282 for (; t < expbuf + MAXEXP; *p++ = *t++);
1283 }
1284 else {
1285 *p++ = '0';
1286 *p++ = to_char(exp);
1287 }
1288 return (p - p0);
1289 }
1290 #endif /* FLOATING_POINT */