Cygwin: Add new APIs tc[gs]etwinsize()
[newlib-cygwin.git] / newlib / libc / machine / powerpc / vfprintf.c
bloba8af4c370385c11792e993ac3976754d1c21d69e
1 /*
2 FUNCTION
3 <<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list
5 INDEX
6 vprintf
7 INDEX
8 vfprintf
9 INDEX
10 vsprintf
11 INDEX
12 vsnprintf
14 SYNOPSIS
15 #include <stdio.h>
16 #include <stdarg.h>
17 int vprintf(const char *<[fmt]>, va_list <[list]>);
18 int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
19 int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
20 int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>, va_list <[list]>);
22 int _vprintf_r(void *<[reent]>, const char *<[fmt]>,
23 va_list <[list]>);
24 int _vfprintf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
25 va_list <[list]>);
26 int _vsprintf_r(void *<[reent]>, char *<[str]>, const char *<[fmt]>,
27 va_list <[list]>);
28 int _vsnprintf_r(void *<[reent]>, char *<[str]>, size_t <[size]>, const char *<[fmt]>,
29 va_list <[list]>);
31 DESCRIPTION
32 <<vprintf>>, <<vfprintf>>, <<vsprintf>> and <<vsnprintf>> are (respectively)
33 variants of <<printf>>, <<fprintf>>, <<sprintf>> and <<snprintf>>. They differ
34 only in allowing their caller to pass the variable argument list as a
35 <<va_list>> object (initialized by <<va_start>>) rather than directly
36 accepting a variable number of arguments.
38 RETURNS
39 The return values are consistent with the corresponding functions:
40 <<vsprintf>> returns the number of bytes in the output string,
41 save that the concluding <<NULL>> is not counted.
42 <<vprintf>> and <<vfprintf>> return the number of characters transmitted.
43 If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>>. No
44 error returns occur for <<vsprintf>>.
46 PORTABILITY
47 ANSI C requires all three functions.
49 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
50 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
53 /*-
54 * Copyright (c) 1990 The Regents of the University of California.
55 * All rights reserved.
57 * This code is derived from software contributed to Berkeley by
58 * Chris Torek.
60 * Redistribution and use in source and binary forms, with or without
61 * modification, are permitted provided that the following conditions
62 * are met:
63 * 1. Redistributions of source code must retain the above copyright
64 * notice, this list of conditions and the following disclaimer.
65 * 2. Redistributions in binary form must reproduce the above copyright
66 * notice, this list of conditions and the following disclaimer in the
67 * documentation and/or other materials provided with the distribution.
68 * 3. Neither the name of the University nor the names of its contributors
69 * may be used to endorse or promote products derived from this software
70 * without specific prior written permission.
72 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
73 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
74 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
75 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
76 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
77 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
78 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
79 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
80 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
81 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
82 * SUCH DAMAGE.
85 #if defined(LIBC_SCCS) && !defined(lint)
86 /*static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";*/
87 static char *rcsid = "$Id$";
88 #endif /* LIBC_SCCS and not lint */
91 * Actual printf innards.
93 * This code is large and complicated...
96 #ifdef INTEGER_ONLY
97 #define VFPRINTF vfiprintf
98 #define _VFPRINTF_R _vfiprintf_r
99 #else
100 #define VFPRINTF vfprintf
101 #define _VFPRINTF_R _vfprintf_r
102 #ifndef NO_FLOATING_POINT
103 #define FLOATING_POINT
104 #endif
105 #endif
107 #include <_ansi.h>
108 #include <limits.h>
109 #include <stdio.h>
110 #include <stdlib.h>
111 #include <string.h>
112 #include <reent.h>
113 #include <wchar.h>
114 #include <string.h>
115 #ifdef __ALTIVEC__
116 #include <altivec.h>
117 #endif
119 #include <stdarg.h>
121 #include "local.h"
122 #include "fvwrite.h"
123 #include "vfieeefp.h"
125 /* Currently a test is made to see if long double processing is warranted.
126 This could be changed in the future should the _ldtoa_r code be
127 preferred over _dtoa_r. */
128 #define _NO_LONGDBL
129 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
130 #undef _NO_LONGDBL
131 #endif
133 #define _NO_LONGLONG
134 #if defined _WANT_IO_LONG_LONG && defined __GNUC__
135 # undef _NO_LONGLONG
136 #endif
138 #ifdef __ALTIVEC__
139 typedef union
141 vector int v;
142 float f[4];
143 int i[16 / sizeof(int)];
144 long l[4];
145 short s[8];
146 signed char c[16];
147 } vec_16_byte_union;
148 #endif /* __ALTIVEC__ */
151 * Flush out all the vectors defined by the given uio,
152 * then reset it so that it can be reused.
154 static int
155 __sprint_r(rptr, fp, uio)
156 struct _reent *rptr;
157 FILE *fp;
158 register struct __suio *uio;
160 register int err;
162 if (uio->uio_resid == 0) {
163 uio->uio_iovcnt = 0;
164 return (0);
166 err = __sfvwrite_r(rptr, fp, uio);
167 uio->uio_resid = 0;
168 uio->uio_iovcnt = 0;
169 return (err);
173 * Helper function for `fprintf to unbuffered unix file': creates a
174 * temporary buffer. We only work on write-only files; this avoids
175 * worries about ungetc buffers and so forth.
177 static int
178 __sbprintf_r(rptr, fp, fmt, ap)
179 struct _reent *rptr;
180 register FILE *fp;
181 const char *fmt;
182 va_list ap;
184 int ret;
185 FILE fake;
186 unsigned char buf[BUFSIZ];
188 /* copy the important variables */
189 fake._flags = fp->_flags & ~__SNBF;
190 fake._file = fp->_file;
191 fake._cookie = fp->_cookie;
192 fake._write = fp->_write;
194 /* set up the buffer */
195 fake._bf._base = fake._p = buf;
196 fake._bf._size = fake._w = sizeof(buf);
197 fake._lbfsize = 0; /* not actually used, but Just In Case */
199 /* do the work, then copy any error status */
200 ret = _VFPRINTF_R(rptr, &fake, fmt, ap);
201 if (ret >= 0 && _fflush_r(rptr, &fake))
202 ret = EOF;
203 if (fake._flags & __SERR)
204 fp->_flags |= __SERR;
205 return (ret);
209 #ifdef FLOATING_POINT
210 #include <locale.h>
211 #include <math.h>
212 #include "floatio.h"
214 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
215 #define DEFPREC 6
217 #ifdef _NO_LONGDBL
218 static char *cvt (struct _reent *, double, int, int, char *, int *, int, int *);
219 #else
220 static char *cvt (struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *);
221 extern int _ldcheck (_LONG_DOUBLE *);
222 #endif
224 static int exponent (char *, int, int);
226 #ifdef __SPE__
227 static char *cvt_ufix64 (struct _reent *, unsigned long long, int, int *, int *);
228 #endif /* __SPE__ */
230 #else /* no FLOATING_POINT */
232 #define BUF 40
234 #endif /* FLOATING_POINT */
238 * Macros for converting digits to letters and vice versa
240 #define to_digit(c) ((c) - '0')
241 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
242 #define to_char(n) ((n) + '0')
245 * Flags used during conversion.
247 #define ALT 0x001 /* alternate form */
248 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
249 #define LADJUST 0x004 /* left adjustment */
250 #define LONGDBL 0x008 /* long double */
251 #define LONGINT 0x010 /* long integer */
252 #ifndef _NO_LONGLONG
253 #define QUADINT 0x020 /* quad integer */
254 #else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
255 that %lld behaves the same as %ld, not as %d, as expected if:
256 sizeof (long long) = sizeof long > sizeof int */
257 #define QUADINT LONGINT
258 #endif
259 #define SHORTINT 0x040 /* short integer */
260 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
261 #define FPT 0x100 /* Floating point number */
262 #define VECTOR 0x200 /* vector */
263 #define FIXEDPOINT 0x400 /* fixed-point */
265 int
266 VFPRINTF (FILE * fp,
267 const char *fmt0,
268 va_list ap)
270 CHECK_INIT (_REENT, fp);
271 return _VFPRINTF_R (_REENT, fp, fmt0, ap);
274 int
275 _VFPRINTF_R (struct _reent *data,
276 FILE * fp,
277 const char *fmt0,
278 va_list ap)
280 register char *fmt; /* format string */
281 register int ch; /* character from fmt */
282 register int n, m; /* handy integers (short term usage) */
283 register char *cp; /* handy char pointer (short term usage) */
284 register struct __siov *iovp;/* for PRINT macro */
285 register int flags; /* flags as above */
286 int ret; /* return value accumulator */
287 int width; /* width from format (%8d), or 0 */
288 int prec; /* precision from format (%.3d), or -1 */
289 char sign; /* sign prefix (' ', '+', '-', or \0) */
290 char old_sign; /* saved value of sign when looping for vectors */
291 int old_ch; /* saved value of ch when looping for vectors */
292 char *format_anchor; /* start of format to process */
293 wchar_t wc;
294 #ifdef FLOATING_POINT
295 char *decimal_point = localeconv()->decimal_point;
296 char softsign; /* temporary negative sign for floats */
297 #ifdef _NO_LONGDBL
298 union { int i; double d; } _double_ = {0};
299 #define _fpvalue (_double_.d)
300 #else
301 union { int i; _LONG_DOUBLE ld; } _long_double_ = {0};
302 #define _fpvalue (_long_double_.ld)
303 int tmp;
304 #endif
305 int expt; /* integer value of exponent */
306 int expsize = 0; /* character count for expstr */
307 int ndig; /* actual number of digits returned by cvt */
308 char expstr[7]; /* buffer for exponent string */
309 #endif
311 #ifndef _NO_LONGLONG
312 #define quad_t long long
313 #define u_quad_t unsigned long long
314 #else
315 #define quad_t long
316 #define u_quad_t u_long
317 #endif
319 u_quad_t _uquad; /* integer arguments %[diouxX] */
320 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
321 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
322 int realsz; /* field size expanded by dprec */
323 int size; /* size of converted field or string */
324 char *xdigs = NULL; /* digits for [xX] conversion */
325 #define NIOV 8
326 struct __suio uio; /* output information: summary */
327 struct __siov iov[NIOV];/* ... and individual io vectors */
328 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
329 char ox[2]; /* space for 0x hex-prefix */
330 #ifdef __ALTIVEC__
331 char vec_sep; /* vector separator char */
332 int vec_print_count; /* number of vector chunks remaining */
333 vec_16_byte_union vec_tmp;
334 #endif /* __ALTIVEC__ */
335 mbstate_t state; /* mbtowc calls from library must not change state */
338 * Choose PADSIZE to trade efficiency vs. size. If larger printf
339 * fields occur frequently, increase PADSIZE and make the initialisers
340 * below longer.
342 #define PADSIZE 16 /* pad chunk size */
343 static const char blanks[PADSIZE] =
344 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
345 static const char zeroes[PADSIZE] =
346 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
349 * BEWARE, these `goto error' on error, and PAD uses `n'.
351 #define PRINT(ptr, len) { \
352 iovp->iov_base = (ptr); \
353 iovp->iov_len = (len); \
354 uio.uio_resid += (len); \
355 iovp++; \
356 if (++uio.uio_iovcnt >= NIOV) { \
357 if (__sprint_r(data, fp, &uio)) \
358 goto error; \
359 iovp = iov; \
362 #define PAD(howmany, with) { \
363 if ((n = (howmany)) > 0) { \
364 while (n > PADSIZE) { \
365 PRINT(with, PADSIZE); \
366 n -= PADSIZE; \
368 PRINT(with, n); \
371 #define FLUSH() { \
372 if (uio.uio_resid && __sprint_r(data, fp, &uio)) \
373 goto error; \
374 uio.uio_iovcnt = 0; \
375 iovp = iov; \
378 #ifdef __ALTIVEC__
379 #define GET_SHORT(ap) \
380 (flags&VECTOR ? \
381 (vec_print_count < 8 ? (short)vec_tmp.s[8 - vec_print_count] : \
382 (vec_tmp.v = va_arg(ap, vector int), (short)vec_tmp.s[0])) : \
383 (short)va_arg(ap, int))
384 #define GET_USHORT(ap) \
385 (flags&VECTOR ? \
386 (vec_print_count < 8 ? (u_short)vec_tmp.s[8 - vec_print_count] : \
387 (vec_tmp.v = va_arg(ap, vector int), (u_short)vec_tmp.s[0])) : \
388 (u_short)va_arg(ap, int))
390 #define GET_LONG(ap) \
391 (flags&VECTOR ? \
392 (vec_print_count < 4 ? (long)vec_tmp.l[4 - vec_print_count] : \
393 (vec_tmp.v = va_arg(ap, vector int), vec_tmp.l[0])) : \
394 va_arg(ap, long int))
395 #define GET_ULONG(ap) \
396 (flags&VECTOR ? \
397 (vec_print_count < 4 ? (u_long)vec_tmp.l[4 - vec_print_count] : \
398 (vec_tmp.v = va_arg(ap, vector int), (u_long)vec_tmp.l[0])) : \
399 (u_long)va_arg(ap, unsigned long int))
401 #define GET_INT(ap) \
402 (flags&VECTOR ? \
403 (vec_print_count < 16 ? \
404 vec_tmp.c[16 - vec_print_count] : \
405 (vec_tmp.v = va_arg(ap, vector int), (int)vec_tmp.c[0])) : \
406 va_arg(ap, int))
407 #define GET_UINT(ap) \
408 (flags&VECTOR ? \
409 (vec_print_count < 16 ? \
410 (u_int)((unsigned char)vec_tmp.c[16 - vec_print_count]) : \
411 (vec_tmp.v = va_arg(ap, vector int), (u_int)((unsigned char)vec_tmp.c[0]))) : \
412 (u_int)va_arg(ap, unsigned int))
413 #else /* !__ALTIVEC__ */
414 #define GET_SHORT(ap) ((short)va_arg(ap, int))
415 #define GET_USHORT(ap) ((u_short)va_arg(ap, int))
416 #define GET_LONG(ap) (va_arg(ap, long int))
417 #define GET_ULONG(ap) ((u_long)va_arg(ap, unsigned long int))
418 #define GET_INT(ap) ((int)va_arg(ap, int))
419 #define GET_UINT(ap) ((u_int)va_arg(ap, unsigned int))
420 #endif /* !__ALTIVEC__ */
422 #ifndef _NO_LONGLONG
423 #define SARG() \
424 (flags&QUADINT ? va_arg(ap, quad_t) : \
425 flags&LONGINT ? GET_LONG(ap) : \
426 flags&SHORTINT ? (long)GET_SHORT(ap) : \
427 (long)GET_INT(ap))
428 #define UARG() \
429 (flags&QUADINT ? va_arg(ap, u_quad_t) : \
430 flags&LONGINT ? GET_ULONG(ap) : \
431 flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
432 (u_long)GET_UINT(ap))
433 #ifdef __SPE__
434 #define SFPARG() \
435 (flags&LONGINT ? va_arg(ap, quad_t) : \
436 flags&SHORTINT ? (long)GET_SHORT(ap) : \
437 (long)va_arg(ap, int))
438 #define UFPARG() \
439 (flags&LONGINT ? va_arg(ap, u_quad_t) : \
440 flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
441 (u_long)va_arg(ap, u_int))
442 #endif /* __SPE__ */
443 #else
444 #define SARG() \
445 (flags&LONGINT ? GET_LONG(ap) : \
446 flags&SHORTINT ? (long)GET_SHORT(ap) : \
447 (long)GET_INT(ap))
448 #define UARG() \
449 (flags&LONGINT ? GET_ULONG(ap) : \
450 flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
451 (u_long)GET_UINT(ap))
452 #ifdef __SPE__
453 #define SFPARG() \
454 (flags&LONGINT ? (va_arg(ap, long) << 32) : \
455 flags&SHORTINT ? (long)GET_SHORT(ap) : \
456 (long)va_arg(ap, int))
457 #define UFPARG() \
458 (flags&LONGINT ? (va_arg(ap, u_long) <<32) : \
459 flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
460 (u_long)va_arg(ap, u_int))
461 #endif /* __SPE__ */
462 #endif
464 memset (&state, '\0', sizeof (state));
466 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
467 if (cantwrite (data, fp)) {
468 _funlockfile (fp);
469 return (EOF);
472 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
473 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
474 fp->_file >= 0)
475 return (__sbprintf_r(data, fp, fmt0, ap));
477 fmt = (char *)fmt0;
478 uio.uio_iov = iovp = iov;
479 uio.uio_resid = 0;
480 uio.uio_iovcnt = 0;
481 ret = 0;
484 * Scan the format for conversions (`%' character).
487 for (;;) {
488 cp = fmt;
489 while ((n = _mbtowc_r(data, &wc, fmt, MB_CUR_MAX, &state)) > 0) {
490 fmt += n;
491 if (wc == '%') {
492 fmt--;
493 break;
496 if ((m = fmt - cp) != 0) {
497 PRINT(cp, m);
498 ret += m;
500 if (n <= 0)
501 goto done;
502 fmt++; /* skip over '%' */
504 flags = 0;
505 dprec = 0;
506 width = 0;
507 prec = -1;
508 sign = '\0';
509 old_sign = '\0';
510 #ifdef __ALTIVEC__
511 vec_print_count = 0;
512 vec_sep = ' ';
513 #endif /* __ALTIVEC__ */
515 format_anchor = fmt;
516 rflag: ch = *fmt++;
517 old_ch = ch;
518 reswitch: switch (ch) {
519 case ' ':
521 * ``If the space and + flags both appear, the space
522 * flag will be ignored.''
523 * -- ANSI X3J11
525 if (!sign)
526 sign = ' ';
527 goto rflag;
528 case '#':
529 flags |= ALT;
530 goto rflag;
531 case '*':
533 * ``A negative field width argument is taken as a
534 * - flag followed by a positive field width.''
535 * -- ANSI X3J11
536 * They don't exclude field widths read from args.
538 if ((width = va_arg(ap, int)) >= 0)
539 goto rflag;
540 width = -width;
541 /* FALLTHROUGH */
542 case '-':
543 flags |= LADJUST;
544 goto rflag;
545 case '+':
546 sign = '+';
547 goto rflag;
548 #ifdef __ALTIVEC__
549 case ',':
550 case ';':
551 case ':':
552 case '_':
553 if (vec_sep != ' ')
555 fmt = format_anchor;
556 continue;
558 vec_sep = ch;
559 goto rflag;
560 #endif /* __ALTIVEC__ */
561 case '.':
562 if ((ch = *fmt++) == '*') {
563 n = va_arg(ap, int);
564 prec = n < 0 ? -1 : n;
565 goto rflag;
567 n = 0;
568 while (is_digit(ch)) {
569 n = 10 * n + to_digit(ch);
570 ch = *fmt++;
572 prec = n < 0 ? -1 : n;
573 goto reswitch;
574 case '0':
576 * ``Note that 0 is taken as a flag, not as the
577 * beginning of a field width.''
578 * -- ANSI X3J11
580 flags |= ZEROPAD;
581 goto rflag;
582 case '1': case '2': case '3': case '4':
583 case '5': case '6': case '7': case '8': case '9':
584 n = 0;
585 do {
586 n = 10 * n + to_digit(ch);
587 ch = *fmt++;
588 } while (is_digit(ch));
589 width = n;
590 goto reswitch;
591 #ifdef FLOATING_POINT
592 case 'L':
593 #ifdef __ALTIVEC__
594 if (flags & VECTOR)
596 fmt = format_anchor;
597 continue;
599 #endif /* __ALTIVEC__ */
600 flags |= LONGDBL;
601 goto rflag;
602 #endif
603 case 'h':
604 if (flags & LONGINT)
606 fmt = format_anchor;
607 continue;
609 flags |= SHORTINT;
610 #ifdef __ALTIVEC__
611 if (flags & VECTOR)
612 vec_print_count = 8;
613 #endif
614 goto rflag;
615 case 'l':
616 if (flags & SHORTINT)
618 fmt = format_anchor;
619 continue;
621 if (*fmt == 'l') {
622 fmt++;
623 flags |= QUADINT;
624 flags &= ~VECTOR;
625 } else {
626 flags |= LONGINT;
627 #ifdef __ALTIVEC__
628 if (flags & VECTOR)
629 vec_print_count = 4;
630 #endif
632 goto rflag;
633 #ifdef __ALTIVEC__
634 case 'v':
635 if (flags & VECTOR)
637 fmt = format_anchor;
638 continue;
640 flags |= VECTOR;
641 vec_print_count = (flags & SHORTINT) ? 8 :
642 ((flags & LONGINT) ? 4 : 16);
643 goto rflag;
644 #endif
645 case 'q':
646 #ifdef __ALTIVEC__
647 if (flags & VECTOR)
649 fmt = format_anchor;
650 continue;
652 #endif /* __ALTIVEC__ */
653 flags |= QUADINT;
654 goto rflag;
655 case 'c':
656 #ifdef __ALTIVEC__
657 if (flags & VECTOR)
659 int k;
660 vec_16_byte_union tmp;
661 if (flags & (SHORTINT | LONGINT))
663 fmt = format_anchor;
664 continue;
666 tmp.v = va_arg(ap, vector int);
667 cp = buf;
668 for (k = 0; k < 15; ++k)
670 *cp++ = tmp.c[k];
671 if (vec_sep != ' ')
672 *cp++ = vec_sep;
674 *cp++ = tmp.c[15];
675 size = cp - buf;
676 cp = buf;
677 vec_print_count = 0;
679 else
680 #endif /* __ALTIVEC__ */
682 *(cp = buf) = va_arg(ap, int);
683 size = 1;
685 sign = '\0';
686 break;
687 case 'D':
688 flags |= LONGINT;
689 /*FALLTHROUGH*/
690 case 'd':
691 case 'i':
692 #ifdef __ALTIVEC__
693 if (!(flags & VECTOR) && vec_sep != ' ')
695 fmt = format_anchor;
696 continue;
698 #endif /* __ALTIVEC__ */
699 _uquad = SARG();
700 if ((quad_t)_uquad < 0)
702 _uquad = -(quad_t)_uquad;
703 old_sign = sign;
704 sign = '-';
706 base = DEC;
707 goto number;
708 #ifdef FLOATING_POINT
709 case 'e':
710 case 'E':
711 case 'f':
712 case 'g':
713 case 'G':
714 if (prec == -1) {
715 prec = DEFPREC;
716 } else if ((ch == 'g' || ch == 'G') && prec == 0) {
717 prec = 1;
720 #ifdef _NO_LONGDBL
721 if (flags & LONGDBL) {
722 _fpvalue = (double) va_arg(ap, _LONG_DOUBLE);
723 #ifdef __ALTIVEC__
724 } else if (flags & VECTOR) {
725 if (vec_print_count >= 4)
727 vec_print_count = 4;
728 vec_tmp.v = va_arg(ap, vector int);
730 _fpvalue = (double)vec_tmp.f[4 - vec_print_count];
731 } else if (vec_sep != ' ') {
732 fmt = format_anchor;
733 continue;
735 #endif /* __ALTIVEC__ */
736 } else {
737 _fpvalue = va_arg(ap, double);
740 /* do this before tricky precision changes */
741 if (isinf(_fpvalue)) {
742 if (_fpvalue < 0)
744 old_sign = sign;
745 sign = '-';
748 cp = "Inf";
749 size = 3;
750 break;
752 if (isnan(_fpvalue)) {
753 cp = "NaN";
754 size = 3;
755 break;
758 #else /* !_NO_LONGDBL */
760 if (flags & LONGDBL) {
761 _fpvalue = va_arg(ap, _LONG_DOUBLE);
762 #ifdef __ALTIVEC__
763 } else if (flags & VECTOR) {
764 if (vec_print_count >= 4)
766 vec_print_count = 4;
767 vec_tmp.v = va_arg(ap, vector int);
769 _fpvalue = (_LONG_DOUBLE)k.f[4 - vec_print_count];
770 #endif /* __ALTIVEC__ */
771 } else {
772 _fpvalue = (_LONG_DOUBLE)va_arg(ap, double);
775 /* do this before tricky precision changes */
776 tmp = _ldcheck (&_fpvalue);
777 if (tmp == 2) {
778 if (_fpvalue < 0)
780 old_sign = sign;
781 sign = '-';
783 cp = "Inf";
784 size = 3;
785 break;
787 if (tmp == 1) {
788 cp = "NaN";
789 size = 3;
790 break;
792 #endif /* !_NO_LONGDBL */
794 flags |= FPT;
796 cp = cvt(data, _fpvalue, prec, flags, &softsign,
797 &expt, ch, &ndig);
799 if (ch == 'g' || ch == 'G') {
800 if (expt <= -4 || expt > prec)
802 old_ch = ch;
803 ch = (ch == 'g') ? 'e' : 'E';
805 else
806 ch = 'g';
808 if (ch <= 'e') { /* 'e' or 'E' fmt */
809 --expt;
810 expsize = exponent(expstr, expt, ch);
811 size = expsize + ndig;
812 if (ndig > 1 || flags & ALT)
813 ++size;
814 } else if (ch == 'f') { /* f fmt */
815 if (expt > 0) {
816 size = expt;
817 if (prec || flags & ALT)
818 size += prec + 1;
819 } else /* "0.X" */
820 size = (prec || flags & ALT)
821 ? prec + 2
822 : 1;
823 } else if (expt >= ndig) { /* fixed g fmt */
824 size = expt;
825 if (flags & ALT)
826 ++size;
827 } else
828 size = ndig + (expt > 0 ?
829 1 : 2 - expt);
831 if (softsign)
833 old_sign = sign;
834 sign = '-';
836 break;
837 #endif /* FLOATING_POINT */
838 #ifdef __SPE__
839 case 'r':
840 flags |= FIXEDPOINT;
841 _uquad = SFPARG();
842 if ((quad_t)_uquad < 0)
844 sign = '-';
845 _uquad = -(quad_t)_uquad;
847 if (flags & SHORTINT)
848 _uquad <<= (sizeof(quad_t) - sizeof(short)) * 8 + 1;
849 else if (flags & LONGINT)
850 _uquad <<= 1;
851 else
852 _uquad <<= (sizeof(quad_t) - sizeof(long)) * 8 + 1;
854 if (_uquad == 0 && sign)
856 /* we have -1.0 which has to be handled special */
857 cp = "100000";
858 expt = 1;
859 ndig = 6;
860 break;
863 goto fixed_nosign;
864 case 'R':
865 flags |= FIXEDPOINT;
866 _uquad = UFPARG();
867 if (flags & SHORTINT)
868 _uquad <<= (sizeof(quad_t) - sizeof(short)) * 8;
869 else if (!(flags & LONGINT))
870 _uquad <<= (sizeof(quad_t) - sizeof(long)) * 8;
872 fixed_nosign:
873 if (prec == -1)
874 prec = DEFPREC;
876 #ifndef _NO_LONGLONG
877 cp = cvt_ufix64 (data, _uquad, prec, &expt, &ndig);
878 #else
879 cp = cvs_ufix32 (data, _uquad, prec, &expt, &ndig);
880 #endif
882 /* act like %f of format "0.X" */
883 size = prec + 2;
885 break;
886 #endif /* __SPE__ */
887 case 'n':
888 #ifdef __ALTIVEC__
889 if (flags & VECTOR)
891 fmt = format_anchor;
892 continue;
894 #endif /* __ALTIVEC__ */
895 #ifndef _NO_LONGLONG
896 if (flags & QUADINT)
897 *va_arg(ap, quad_t *) = ret;
898 else
899 #endif
900 if (flags & LONGINT)
901 *va_arg(ap, long *) = ret;
902 else if (flags & SHORTINT)
903 *va_arg(ap, short *) = ret;
904 else
905 *va_arg(ap, int *) = ret;
906 continue; /* no output */
907 case 'O':
908 flags |= LONGINT;
909 /*FALLTHROUGH*/
910 case 'o':
911 #ifdef __ALTIVEC__
912 if (!(flags & VECTOR) && vec_sep != ' ')
914 fmt = format_anchor;
915 continue;
917 #endif /* __ALTIVEC__ */
918 _uquad = UARG();
919 base = OCT;
920 goto nosign;
921 case 'p':
923 * ``The argument shall be a pointer to void. The
924 * value of the pointer is converted to a sequence
925 * of printable characters, in an implementation-
926 * defined manner.''
927 * -- ANSI X3J11
929 /* NOSTRICT */
930 #ifdef __ALTIVEC__
931 if (flags & VECTOR)
932 _uquad = UARG();
933 else if (vec_sep != ' ')
935 fmt = format_anchor;
936 continue;
938 else
939 #endif /* __ALTIVEC__ */
940 _uquad = (u_long)(unsigned _POINTER_INT)va_arg(ap, void *);
941 base = HEX;
942 xdigs = "0123456789abcdef";
943 flags |= HEXPREFIX;
944 ch = 'x';
945 goto nosign;
946 case 's':
947 #ifdef __ALTIVEC__
948 if (flags & VECTOR)
950 fmt = format_anchor;
951 continue;
953 #endif /* __ALTIVEC__ */
954 if ((cp = va_arg(ap, char *)) == NULL)
955 cp = "(null)";
956 if (prec >= 0) {
958 * can't use strlen; can only look for the
959 * NUL in the first `prec' characters, and
960 * strlen() will go further.
962 char *p = memchr(cp, 0, prec);
964 if (p != NULL) {
965 size = p - cp;
966 if (size > prec)
967 size = prec;
968 } else
969 size = prec;
970 } else
971 size = strlen(cp);
972 sign = '\0';
973 break;
974 case 'U':
975 flags |= LONGINT;
976 /*FALLTHROUGH*/
977 case 'u':
978 #ifdef __ALTIVEC__
979 if (!(flags & VECTOR) && vec_sep != ' ')
981 fmt = format_anchor;
982 continue;
984 #endif /* __ALTIVEC__ */
985 _uquad = UARG();
986 base = DEC;
987 goto nosign;
988 case 'X':
989 xdigs = "0123456789ABCDEF";
990 goto hex;
991 case 'x':
992 xdigs = "0123456789abcdef";
993 #ifdef __ALTIVEC__
994 if (!(flags & VECTOR) && vec_sep != ' ')
996 fmt = format_anchor;
997 continue;
999 #endif /* __ALTIVEC__ */
1000 hex: _uquad = UARG();
1001 base = HEX;
1002 /* leading 0x/X only if non-zero */
1003 if (flags & ALT && _uquad != 0)
1004 flags |= HEXPREFIX;
1006 /* unsigned conversions */
1007 nosign: sign = '\0';
1009 * ``... diouXx conversions ... if a precision is
1010 * specified, the 0 flag will be ignored.''
1011 * -- ANSI X3J11
1013 number: if ((dprec = prec) >= 0)
1014 flags &= ~ZEROPAD;
1017 * ``The result of converting a zero value with an
1018 * explicit precision of zero is no characters.''
1019 * -- ANSI X3J11
1021 cp = buf + BUF;
1022 if (_uquad != 0 || prec != 0) {
1024 * Unsigned mod is hard, and unsigned mod
1025 * by a constant is easier than that by
1026 * a variable; hence this switch.
1028 switch (base) {
1029 case OCT:
1030 do {
1031 *--cp = to_char(_uquad & 7);
1032 _uquad >>= 3;
1033 } while (_uquad);
1034 /* handle octal leading 0 */
1035 if (flags & ALT && *cp != '0')
1036 *--cp = '0';
1037 break;
1039 case DEC:
1040 /* many numbers are 1 digit */
1041 while (_uquad >= 10) {
1042 *--cp = to_char(_uquad % 10);
1043 _uquad /= 10;
1045 *--cp = to_char(_uquad);
1046 break;
1048 case HEX:
1049 do {
1050 *--cp = xdigs[_uquad & 15];
1051 _uquad >>= 4;
1052 } while (_uquad);
1053 break;
1055 default:
1056 cp = "bug in vfprintf: bad base";
1057 size = strlen(cp);
1058 goto skipsize;
1062 * ...result is to be converted to an 'alternate form'.
1063 * For o conversion, it increases the precision to force
1064 * the first digit of the result to be a zero."
1065 * -- ANSI X3J11
1067 * To demonstrate this case, compile and run:
1068 * printf ("%#.0o",0);
1070 else if (base == OCT && (flags & ALT))
1071 *--cp = '0';
1073 size = buf + BUF - cp;
1074 skipsize:
1075 break;
1076 default: /* "%?" prints ?, unless ? is NUL */
1077 flags &= ~VECTOR;
1078 if (ch == '\0')
1079 goto done;
1080 /* pretend it was %c with argument ch */
1081 cp = buf;
1082 *cp = ch;
1083 size = 1;
1084 sign = '\0';
1085 break;
1089 * All reasonable formats wind up here. At this point, `cp'
1090 * points to a string which (if not flags&LADJUST) should be
1091 * padded out to `width' places. If flags&ZEROPAD, it should
1092 * first be prefixed by any sign or other prefix; otherwise,
1093 * it should be blank padded before the prefix is emitted.
1094 * After any left-hand padding and prefixing, emit zeroes
1095 * required by a decimal [diouxX] precision, then print the
1096 * string proper, then emit zeroes required by any leftover
1097 * floating precision; finally, if LADJUST, pad with blanks.
1099 * Compute actual size, so we know how much to pad.
1100 * size excludes decimal prec; realsz includes it.
1102 realsz = dprec > size ? dprec : size;
1103 if (sign)
1104 realsz++;
1105 else if (flags & HEXPREFIX)
1106 realsz+= 2;
1108 /* right-adjusting blank padding */
1109 if ((flags & (LADJUST|ZEROPAD)) == 0)
1110 PAD(width - realsz, blanks);
1112 /* prefix */
1113 if (sign) {
1114 PRINT(&sign, 1);
1115 } else if (flags & HEXPREFIX) {
1116 ox[0] = '0';
1117 ox[1] = ch;
1118 PRINT(ox, 2);
1121 /* right-adjusting zero padding */
1122 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1123 PAD(width - realsz, zeroes);
1125 /* leading zeroes from decimal precision */
1126 PAD(dprec - size, zeroes);
1128 /* the string or number proper */
1129 #ifdef FLOATING_POINT
1130 if ((flags & FPT) == 0) {
1131 #ifdef __SPE__
1132 if (flags & FIXEDPOINT) {
1133 if (_uquad == 0 && !sign) {
1134 /* kludge for __dtoa irregularity */
1135 PRINT("0", 1);
1136 if (expt < ndig || (flags & ALT) != 0) {
1137 PRINT(decimal_point, 1);
1138 PAD(ndig - 1, zeroes);
1140 } else if (expt <= 0) {
1141 PRINT("0", 1);
1142 if(expt || ndig) {
1143 PRINT(decimal_point, 1);
1144 PAD(-expt, zeroes);
1145 PRINT(cp, ndig);
1147 } else if (expt >= ndig) {
1148 PRINT(cp, ndig);
1149 PAD(expt - ndig, zeroes);
1150 if (flags & ALT)
1151 PRINT(".", 1);
1152 } else {
1153 PRINT(cp, expt);
1154 cp += expt;
1155 PRINT(".", 1);
1156 PRINT(cp, ndig-expt);
1158 } else
1159 #endif /* __SPE__ */
1160 PRINT(cp, size);
1161 } else { /* glue together f_p fragments */
1162 if (ch >= 'f') { /* 'f' or 'g' */
1163 if (_fpvalue == 0) {
1164 /* kludge for __dtoa irregularity */
1165 PRINT("0", 1);
1166 if (expt < ndig || (flags & ALT) != 0) {
1167 PRINT(decimal_point, 1);
1168 PAD(ndig - 1, zeroes);
1170 } else if (expt <= 0) {
1171 PRINT("0", 1);
1172 if(expt || ndig) {
1173 PRINT(decimal_point, 1);
1174 PAD(-expt, zeroes);
1175 PRINT(cp, ndig);
1177 } else if (expt >= ndig) {
1178 PRINT(cp, ndig);
1179 PAD(expt - ndig, zeroes);
1180 if (flags & ALT)
1181 PRINT(".", 1);
1182 } else {
1183 PRINT(cp, expt);
1184 cp += expt;
1185 PRINT(".", 1);
1186 PRINT(cp, ndig-expt);
1188 } else { /* 'e' or 'E' */
1189 if (ndig > 1 || flags & ALT) {
1190 ox[0] = *cp++;
1191 ox[1] = '.';
1192 PRINT(ox, 2);
1193 if (_fpvalue) {
1194 PRINT(cp, ndig-1);
1195 } else /* 0.[0..] */
1196 /* __dtoa irregularity */
1197 PAD(ndig - 1, zeroes);
1198 } else /* XeYYY */
1199 PRINT(cp, 1);
1200 PRINT(expstr, expsize);
1203 #else
1204 PRINT(cp, size);
1205 #endif
1206 /* left-adjusting padding (always blank) */
1207 if (flags & LADJUST)
1208 PAD(width - realsz, blanks);
1210 /* finally, adjust ret */
1211 ret += width > realsz ? width : realsz;
1213 #ifdef __ALTIVEC__
1214 if ((flags & VECTOR) && vec_print_count-- > 1)
1216 /* add vector separator */
1217 if (ch != 'c' || vec_sep != ' ')
1219 PRINT(&vec_sep, 1);
1220 ret += 1;
1222 FLUSH();
1223 sign = old_sign;
1224 ch = old_ch;
1225 goto reswitch;
1227 #endif /* __ALTIVEC__ */
1228 FLUSH(); /* copy out the I/O vectors */
1230 done:
1231 FLUSH();
1232 error:
1233 return (__sferror(fp) ? EOF : ret);
1234 /* NOTREACHED */
1237 #ifdef FLOATING_POINT
1239 #ifdef _NO_LONGDBL
1240 extern char *_dtoa_r (struct _reent *, double, int,
1241 int, int *, int *, char **);
1242 #else
1243 extern char *_ldtoa_r (struct _reent *, _LONG_DOUBLE, int,
1244 int, int *, int *, char **);
1245 #undef word0
1246 #define word0(x) ldword0(x)
1247 #endif
1249 static char *
1250 cvt(data, value, ndigits, flags, sign, decpt, ch, length)
1251 struct _reent *data;
1252 #ifdef _NO_LONGDBL
1253 double value;
1254 #else
1255 _LONG_DOUBLE value;
1256 #endif
1257 int ndigits, flags, *decpt, ch, *length;
1258 char *sign;
1260 int mode, dsgn;
1261 char *digits, *bp, *rve;
1262 #ifdef _NO_LONGDBL
1263 union double_union tmp;
1264 #else
1265 struct ldieee *ldptr;
1266 #endif
1268 if (ch == 'f') {
1269 mode = 3; /* ndigits after the decimal point */
1270 } else {
1271 /* To obtain ndigits after the decimal point for the 'e'
1272 * and 'E' formats, round to ndigits + 1 significant
1273 * figures.
1275 if (ch == 'e' || ch == 'E') {
1276 ndigits++;
1278 mode = 2; /* ndigits significant digits */
1281 #ifdef _NO_LONGDBL
1282 tmp.d = value;
1284 if (word0(tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
1285 value = -value;
1286 *sign = '-';
1287 } else
1288 *sign = '\000';
1290 digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
1291 #else /* !_NO_LONGDBL */
1292 ldptr = (struct ldieee *)&value;
1293 if (ldptr->sign) { /* this will check for < 0 and -0.0 */
1294 value = -value;
1295 *sign = '-';
1296 } else
1297 *sign = '\000';
1299 digits = _ldtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
1300 #endif /* !_NO_LONGDBL */
1302 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
1303 bp = digits + ndigits;
1304 if (ch == 'f') {
1305 if (*digits == '0' && value)
1306 *decpt = -ndigits + 1;
1307 bp += *decpt;
1309 if (value == 0) /* kludge for __dtoa irregularity */
1310 rve = bp;
1311 while (rve < bp)
1312 *rve++ = '0';
1314 *length = rve - digits;
1315 return (digits);
1318 static int
1319 exponent(p0, exp, fmtch)
1320 char *p0;
1321 int exp, fmtch;
1323 register char *p, *t;
1324 char expbuf[40];
1326 p = p0;
1327 *p++ = fmtch;
1328 if (exp < 0) {
1329 exp = -exp;
1330 *p++ = '-';
1332 else
1333 *p++ = '+';
1334 t = expbuf + 40;
1335 if (exp > 9) {
1336 do {
1337 *--t = to_char(exp % 10);
1338 } while ((exp /= 10) > 9);
1339 *--t = to_char(exp);
1340 for (; t < expbuf + 40; *p++ = *t++);
1342 else {
1343 *p++ = '0';
1344 *p++ = to_char(exp);
1346 return (p - p0);
1348 #endif /* FLOATING_POINT */
1350 #ifdef __SPE__
1351 extern char *_ufix64toa_r (struct _reent *, unsigned long long, int,
1352 int, int *, int *, char **);
1353 static char *
1354 cvt_ufix64 (data, value, ndigits, decpt, length)
1355 struct _reent *data;
1356 unsigned long long value;
1357 int ndigits, *decpt, *length;
1359 int dsgn;
1360 char *digits, *bp, *rve;
1362 /* treat the same as %f format and use mode=3 */
1363 digits = _ufix64toa_r (data, value, 3, ndigits, decpt, &dsgn, &rve);
1365 /* print trailing zeroes */
1366 bp = digits + ndigits;
1367 if (*digits == '0' && value)
1368 *decpt = -ndigits + 1;
1369 bp += *decpt;
1370 if (value == 0) /* kludge for __dtoa irregularity */
1371 rve = bp;
1372 while (rve < bp)
1373 *rve++ = '0';
1374 *length = rve - digits;
1375 return (digits);
1377 #endif /* __SPE__ */