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