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