]> sourceware.org Git - newlib-cygwin.git/blame - newlib/libc/stdio/vfprintf.c
2002-02-27 Jeff Johnston <jjohnstn@redhat.com>
[newlib-cygwin.git] / newlib / libc / stdio / vfprintf.c
CommitLineData
8a0efa53
CF
1/*
2FUNCTION
3<<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list
4
5INDEX
6 vprintf
7INDEX
8 vfprintf
9INDEX
10 vsprintf
11INDEX
12 vsnprintf
13
14ANSI_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]>);
21
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]>);
30
31TRAD_SYNOPSIS
32 #include <stdio.h>
33 #include <varargs.h>
34 int vprintf( <[fmt]>, <[list]>)
35 char *<[fmt]>;
36 va_list <[list]>;
37
38 int vfprintf(<[fp]>, <[fmt]>, <[list]>)
39 FILE *<[fp]>;
40 char *<[fmt]>;
41 va_list <[list]>;
42
43 int vsprintf(<[str]>, <[fmt]>, <[list]>)
44 char *<[str]>;
45 char *<[fmt]>;
46 va_list <[list]>;
47
48 int vsnprintf(<[str]>, <[size]>, <[fmt]>, <[list]>)
49 char *<[str]>;
50 size_t <[size]>;
51 char *<[fmt]>;
52 va_list <[list]>;
53
54 int _vprintf_r(<[reent]>, <[fmt]>, <[list]>)
55 char *<[reent]>;
56 char *<[fmt]>;
57 va_list <[list]>;
58
59 int _vfprintf_r(<[reent]>, <[fp]>, <[fmt]>, <[list]>)
60 char *<[reent]>;
61 FILE *<[fp]>;
62 char *<[fmt]>;
63 va_list <[list]>;
64
65 int _vsprintf_r(<[reent]>, <[str]>, <[fmt]>, <[list]>)
66 char *<[reent]>;
67 char *<[str]>;
68 char *<[fmt]>;
69 va_list <[list]>;
70
71 int _vsnprintf_r(<[reent]>, <[str]>, <[size]>, <[fmt]>, <[list]>)
72 char *<[reent]>;
73 char *<[str]>;
74 size_t <[size]>;
75 char *<[fmt]>;
76 va_list <[list]>;
77
78DESCRIPTION
79<<vprintf>>, <<vfprintf>>, <<vsprintf>> and <<vsnprintf>> are (respectively)
80variants of <<printf>>, <<fprintf>>, <<sprintf>> and <<snprintf>>. They differ
81only in allowing their caller to pass the variable argument list as a
82<<va_list>> object (initialized by <<va_start>>) rather than directly
83accepting a variable number of arguments.
84
85RETURNS
86The return values are consistent with the corresponding functions:
87<<vsprintf>> returns the number of bytes in the output string,
88save that the concluding <<NULL>> is not counted.
89<<vprintf>> and <<vfprintf>> return the number of characters transmitted.
90If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>>. No
91error returns occur for <<vsprintf>>.
92
93PORTABILITY
94ANSI C requires all three functions.
95
96Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
97<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
98*/
99
100/*-
101 * Copyright (c) 1990 The Regents of the University of California.
102 * All rights reserved.
103 *
104 * This code is derived from software contributed to Berkeley by
105 * Chris Torek.
106 *
107 * Redistribution and use in source and binary forms, with or without
108 * modification, are permitted provided that the following conditions
109 * are met:
110 * 1. Redistributions of source code must retain the above copyright
111 * notice, this list of conditions and the following disclaimer.
112 * 2. Redistributions in binary form must reproduce the above copyright
113 * notice, this list of conditions and the following disclaimer in the
114 * documentation and/or other materials provided with the distribution.
115 * 3. All advertising materials mentioning features or use of this software
116 * must display the following acknowledgement:
117 * This product includes software developed by the University of
118 * California, Berkeley and its contributors.
119 * 4. Neither the name of the University nor the names of its contributors
120 * may be used to endorse or promote products derived from this software
121 * without specific prior written permission.
122 *
123 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
124 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
125 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
126 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
127 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
128 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
129 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
130 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
131 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
132 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
133 * SUCH DAMAGE.
134 */
135
136#if defined(LIBC_SCCS) && !defined(lint)
137/*static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";*/
138static char *rcsid = "$Id$";
139#endif /* LIBC_SCCS and not lint */
140
141/*
142 * Actual printf innards.
143 *
144 * This code is large and complicated...
145 */
146
147#ifdef INTEGER_ONLY
148#define VFPRINTF vfiprintf
149#define _VFPRINTF_R _vfiprintf_r
150#else
151#define VFPRINTF vfprintf
152#define _VFPRINTF_R _vfprintf_r
afecf2fa 153#ifndef NO_FLOATING_POINT
8a0efa53
CF
154#define FLOATING_POINT
155#endif
afecf2fa 156#endif
8a0efa53
CF
157
158#define _NO_LONGLONG
159#if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
160# undef _NO_LONGLONG
161#endif
162
163#include <_ansi.h>
164#include <stdio.h>
165#include <stdlib.h>
166#include <string.h>
167#include <reent.h>
168
169#ifdef _HAVE_STDC
170#include <stdarg.h>
171#else
172#include <varargs.h>
173#endif
174
175#include "local.h"
176#include "fvwrite.h"
177#include "vfieeefp.h"
178
6bdac416
JJ
179/* Currently a test is made to see if long double processing is warranted.
180 This could be changed in the future should the _ldtoa_r code be
181 preferred over _dtoa_r. */
182#define _NO_LONGDBL
183#if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
184#undef _NO_LONGDBL
185#endif
186
8a0efa53
CF
187/*
188 * Flush out all the vectors defined by the given uio,
189 * then reset it so that it can be reused.
190 */
191static int
192__sprint(fp, uio)
193 FILE *fp;
194 register struct __suio *uio;
195{
196 register int err;
197
198 if (uio->uio_resid == 0) {
199 uio->uio_iovcnt = 0;
200 return (0);
201 }
202 err = __sfvwrite(fp, uio);
203 uio->uio_resid = 0;
204 uio->uio_iovcnt = 0;
205 return (err);
206}
207
208/*
209 * Helper function for `fprintf to unbuffered unix file': creates a
210 * temporary buffer. We only work on write-only files; this avoids
211 * worries about ungetc buffers and so forth.
212 */
213static int
214__sbprintf(fp, fmt, ap)
215 register FILE *fp;
216 const char *fmt;
217 va_list ap;
218{
219 int ret;
220 FILE fake;
221 unsigned char buf[BUFSIZ];
222
223 /* copy the important variables */
224 fake._data = fp->_data;
225 fake._flags = fp->_flags & ~__SNBF;
226 fake._file = fp->_file;
227 fake._cookie = fp->_cookie;
228 fake._write = fp->_write;
229
230 /* set up the buffer */
231 fake._bf._base = fake._p = buf;
232 fake._bf._size = fake._w = sizeof(buf);
233 fake._lbfsize = 0; /* not actually used, but Just In Case */
234
235 /* do the work, then copy any error status */
236 ret = VFPRINTF(&fake, fmt, ap);
237 if (ret >= 0 && fflush(&fake))
238 ret = EOF;
239 if (fake._flags & __SERR)
240 fp->_flags |= __SERR;
241 return (ret);
242}
243
244
245#ifdef FLOATING_POINT
246#include <locale.h>
247#include <math.h>
248#include "floatio.h"
249
250#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
251#define DEFPREC 6
252
6bdac416 253#ifdef _NO_LONGDBL
8a0efa53 254static char *cvt _PARAMS((struct _reent *, double, int, int, char *, int *, int, int *));
6bdac416
JJ
255#else
256static char *cvt _PARAMS((struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *));
b6182a09 257extern int _ldcheck _PARAMS((_LONG_DOUBLE *));
6bdac416
JJ
258#endif
259
8a0efa53
CF
260static int exponent _PARAMS((char *, int, int));
261
262#else /* no FLOATING_POINT */
263
264#define BUF 40
265
266#endif /* FLOATING_POINT */
267
268
269/*
270 * Macros for converting digits to letters and vice versa
271 */
272#define to_digit(c) ((c) - '0')
273#define is_digit(c) ((unsigned)to_digit(c) <= 9)
274#define to_char(n) ((n) + '0')
275
276/*
277 * Flags used during conversion.
278 */
279#define ALT 0x001 /* alternate form */
280#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
281#define LADJUST 0x004 /* left adjustment */
6bdac416 282#define LONGDBL 0x008 /* long double */
8a0efa53 283#define LONGINT 0x010 /* long integer */
6f637037 284#ifndef _NO_LONGLONG
8a0efa53 285#define QUADINT 0x020 /* quad integer */
6f637037
AO
286#else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
287 that %lld behaves the same as %ld, not as %d, as expected if:
288 sizeof (long long) = sizeof long > sizeof int */
289#define QUADINT LONGINT
290#endif
8a0efa53
CF
291#define SHORTINT 0x040 /* short integer */
292#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
293#define FPT 0x100 /* Floating point number */
294
295int
296_DEFUN (VFPRINTF, (fp, fmt0, ap),
297 FILE * fp _AND
298 _CONST char *fmt0 _AND
299 va_list ap)
300{
b0ba0ac2 301 CHECK_INIT (fp);
8a0efa53
CF
302 return _VFPRINTF_R (fp->_data, fp, fmt0, ap);
303}
304
305int
306_DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap),
307 struct _reent *data _AND
308 FILE * fp _AND
309 _CONST char *fmt0 _AND
310 va_list ap)
311{
312 register char *fmt; /* format string */
313 register int ch; /* character from fmt */
314 register int n, m; /* handy integers (short term usage) */
315 register char *cp; /* handy char pointer (short term usage) */
316 register struct __siov *iovp;/* for PRINT macro */
317 register int flags; /* flags as above */
318 int ret; /* return value accumulator */
319 int width; /* width from format (%8d), or 0 */
320 int prec; /* precision from format (%.3d), or -1 */
321 char sign; /* sign prefix (' ', '+', '-', or \0) */
322 wchar_t wc;
323#ifdef FLOATING_POINT
324 char *decimal_point = localeconv()->decimal_point;
325 char softsign; /* temporary negative sign for floats */
6bdac416 326#ifdef _NO_LONGDBL
b294082c
JJ
327 union { int i; double d; } _double_ = {0};
328 #define _fpvalue (_double_.d)
6bdac416 329#else
b294082c
JJ
330 union { int i; _LONG_DOUBLE ld; } _long_double_ = {0};
331 #define _fpvalue (_long_double_.ld)
b6182a09 332 int tmp;
6bdac416 333#endif
8a0efa53 334 int expt; /* integer value of exponent */
6bdac416 335 int expsize = 0; /* character count for expstr */
8a0efa53
CF
336 int ndig; /* actual number of digits returned by cvt */
337 char expstr[7]; /* buffer for exponent string */
338#endif
339
340#ifndef _NO_LONGLONG
341#define quad_t long long
342#define u_quad_t unsigned long long
343#endif
344
345#ifndef _NO_LONGLONG
346 u_quad_t _uquad; /* integer arguments %[diouxX] */
347#else
348 u_long _uquad;
349#endif
350 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
351 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
352 int realsz; /* field size expanded by dprec */
353 int size; /* size of converted field or string */
6bdac416 354 char *xdigs = NULL; /* digits for [xX] conversion */
8a0efa53
CF
355#define NIOV 8
356 struct __suio uio; /* output information: summary */
357 struct __siov iov[NIOV];/* ... and individual io vectors */
358 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
359 char ox[2]; /* space for 0x hex-prefix */
360 int state = 0; /* mbtowc calls from library must not change state */
361
362 /*
363 * Choose PADSIZE to trade efficiency vs. size. If larger printf
364 * fields occur frequently, increase PADSIZE and make the initialisers
365 * below longer.
366 */
367#define PADSIZE 16 /* pad chunk size */
368 static _CONST char blanks[PADSIZE] =
369 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
370 static _CONST char zeroes[PADSIZE] =
371 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
372
373 /*
374 * BEWARE, these `goto error' on error, and PAD uses `n'.
375 */
376#define PRINT(ptr, len) { \
377 iovp->iov_base = (ptr); \
378 iovp->iov_len = (len); \
379 uio.uio_resid += (len); \
380 iovp++; \
381 if (++uio.uio_iovcnt >= NIOV) { \
382 if (__sprint(fp, &uio)) \
383 goto error; \
384 iovp = iov; \
385 } \
386}
387#define PAD(howmany, with) { \
388 if ((n = (howmany)) > 0) { \
389 while (n > PADSIZE) { \
390 PRINT(with, PADSIZE); \
391 n -= PADSIZE; \
392 } \
393 PRINT(with, n); \
394 } \
395}
396#define FLUSH() { \
397 if (uio.uio_resid && __sprint(fp, &uio)) \
398 goto error; \
399 uio.uio_iovcnt = 0; \
400 iovp = iov; \
401}
402
403 /*
404 * To extend shorts properly, we need both signed and unsigned
405 * argument extraction methods.
406 */
407#ifndef _NO_LONGLONG
408#define SARG() \
409 (flags&QUADINT ? va_arg(ap, quad_t) : \
410 flags&LONGINT ? va_arg(ap, long) : \
411 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
412 (long)va_arg(ap, int))
413#define UARG() \
414 (flags&QUADINT ? va_arg(ap, u_quad_t) : \
415 flags&LONGINT ? va_arg(ap, u_long) : \
416 flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
417 (u_long)va_arg(ap, u_int))
418#else
419#define SARG() \
420 (flags&LONGINT ? va_arg(ap, long) : \
421 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
422 (long)va_arg(ap, int))
423#define UARG() \
424 (flags&LONGINT ? va_arg(ap, u_long) : \
425 flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
426 (u_long)va_arg(ap, u_int))
427#endif
428
8a0efa53
CF
429 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
430 if (cantwrite(fp))
431 return (EOF);
432
433 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
434 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
435 fp->_file >= 0)
436 return (__sbprintf(fp, fmt0, ap));
437
438 fmt = (char *)fmt0;
439 uio.uio_iov = iovp = iov;
440 uio.uio_resid = 0;
441 uio.uio_iovcnt = 0;
442 ret = 0;
443
444 /*
445 * Scan the format for conversions (`%' character).
446 */
447 for (;;) {
448 cp = fmt;
449 while ((n = _mbtowc_r(_REENT, &wc, fmt, MB_CUR_MAX, &state)) > 0) {
450 fmt += n;
451 if (wc == '%') {
452 fmt--;
453 break;
454 }
455 }
456 if ((m = fmt - cp) != 0) {
457 PRINT(cp, m);
458 ret += m;
459 }
460 if (n <= 0)
461 goto done;
462 fmt++; /* skip over '%' */
463
464 flags = 0;
465 dprec = 0;
466 width = 0;
467 prec = -1;
468 sign = '\0';
469
470rflag: ch = *fmt++;
471reswitch: switch (ch) {
472 case ' ':
473 /*
474 * ``If the space and + flags both appear, the space
475 * flag will be ignored.''
476 * -- ANSI X3J11
477 */
478 if (!sign)
479 sign = ' ';
480 goto rflag;
481 case '#':
482 flags |= ALT;
483 goto rflag;
484 case '*':
485 /*
486 * ``A negative field width argument is taken as a
487 * - flag followed by a positive field width.''
488 * -- ANSI X3J11
489 * They don't exclude field widths read from args.
490 */
491 if ((width = va_arg(ap, int)) >= 0)
492 goto rflag;
493 width = -width;
494 /* FALLTHROUGH */
495 case '-':
496 flags |= LADJUST;
497 goto rflag;
498 case '+':
499 sign = '+';
500 goto rflag;
501 case '.':
502 if ((ch = *fmt++) == '*') {
503 n = va_arg(ap, int);
504 prec = n < 0 ? -1 : n;
505 goto rflag;
506 }
507 n = 0;
508 while (is_digit(ch)) {
509 n = 10 * n + to_digit(ch);
510 ch = *fmt++;
511 }
512 prec = n < 0 ? -1 : n;
513 goto reswitch;
514 case '0':
515 /*
516 * ``Note that 0 is taken as a flag, not as the
517 * beginning of a field width.''
518 * -- ANSI X3J11
519 */
520 flags |= ZEROPAD;
521 goto rflag;
522 case '1': case '2': case '3': case '4':
523 case '5': case '6': case '7': case '8': case '9':
524 n = 0;
525 do {
526 n = 10 * n + to_digit(ch);
527 ch = *fmt++;
528 } while (is_digit(ch));
529 width = n;
530 goto reswitch;
531#ifdef FLOATING_POINT
532 case 'L':
533 flags |= LONGDBL;
534 goto rflag;
535#endif
536 case 'h':
537 flags |= SHORTINT;
538 goto rflag;
539 case 'l':
540 if (*fmt == 'l') {
541 fmt++;
542 flags |= QUADINT;
543 } else {
544 flags |= LONGINT;
545 }
546 goto rflag;
547 case 'q':
548 flags |= QUADINT;
549 goto rflag;
550 case 'c':
551 *(cp = buf) = va_arg(ap, int);
552 size = 1;
553 sign = '\0';
554 break;
555 case 'D':
556 flags |= LONGINT;
557 /*FALLTHROUGH*/
558 case 'd':
559 case 'i':
560 _uquad = SARG();
561#ifndef _NO_LONGLONG
562 if ((quad_t)_uquad < 0)
563#else
564 if ((long) _uquad < 0)
565#endif
566 {
567
568 _uquad = -_uquad;
569 sign = '-';
570 }
571 base = DEC;
572 goto number;
573#ifdef FLOATING_POINT
574 case 'e':
575 case 'E':
576 case 'f':
577 case 'g':
578 case 'G':
579 if (prec == -1) {
580 prec = DEFPREC;
581 } else if ((ch == 'g' || ch == 'G') && prec == 0) {
582 prec = 1;
583 }
584
6bdac416
JJ
585#ifdef _NO_LONGDBL
586 if (flags & LONGDBL) {
587 _fpvalue = (double) va_arg(ap, _LONG_DOUBLE);
588 } else {
589 _fpvalue = va_arg(ap, double);
590 }
591
592 /* do this before tricky precision changes */
593 if (isinf(_fpvalue)) {
594 if (_fpvalue < 0)
595 sign = '-';
596 cp = "Inf";
597 size = 3;
598 break;
599 }
600 if (isnan(_fpvalue)) {
601 cp = "NaN";
602 size = 3;
603 break;
604 }
605
606#else /* !_NO_LONGDBL */
607
8a0efa53 608 if (flags & LONGDBL) {
6bdac416 609 _fpvalue = va_arg(ap, _LONG_DOUBLE);
8a0efa53 610 } else {
6bdac416 611 _fpvalue = (_LONG_DOUBLE)va_arg(ap, double);
8a0efa53
CF
612 }
613
614 /* do this before tricky precision changes */
b6182a09
JJ
615 tmp = _ldcheck (&_fpvalue);
616 if (tmp == 2) {
6bdac416 617 if (_fpvalue < 0)
8a0efa53
CF
618 sign = '-';
619 cp = "Inf";
620 size = 3;
621 break;
622 }
b6182a09 623 if (tmp == 1) {
8a0efa53
CF
624 cp = "NaN";
625 size = 3;
626 break;
627 }
6bdac416 628#endif /* !_NO_LONGDBL */
8a0efa53
CF
629
630 flags |= FPT;
6bdac416
JJ
631
632 cp = cvt(data, _fpvalue, prec, flags, &softsign,
8a0efa53 633 &expt, ch, &ndig);
6bdac416 634
8a0efa53
CF
635 if (ch == 'g' || ch == 'G') {
636 if (expt <= -4 || expt > prec)
637 ch = (ch == 'g') ? 'e' : 'E';
638 else
639 ch = 'g';
640 }
641 if (ch <= 'e') { /* 'e' or 'E' fmt */
642 --expt;
643 expsize = exponent(expstr, expt, ch);
644 size = expsize + ndig;
645 if (ndig > 1 || flags & ALT)
646 ++size;
647 } else if (ch == 'f') { /* f fmt */
648 if (expt > 0) {
649 size = expt;
650 if (prec || flags & ALT)
651 size += prec + 1;
652 } else /* "0.X" */
653 size = prec + 2;
654 } else if (expt >= ndig) { /* fixed g fmt */
655 size = expt;
656 if (flags & ALT)
657 ++size;
658 } else
659 size = ndig + (expt > 0 ?
660 1 : 2 - expt);
661
662 if (softsign)
663 sign = '-';
664 break;
665#endif /* FLOATING_POINT */
666 case 'n':
667#ifndef _NO_LONGLONG
668 if (flags & QUADINT)
669 *va_arg(ap, quad_t *) = ret;
670 else
671#endif
672 if (flags & LONGINT)
673 *va_arg(ap, long *) = ret;
674 else if (flags & SHORTINT)
675 *va_arg(ap, short *) = ret;
676 else
677 *va_arg(ap, int *) = ret;
678 continue; /* no output */
679 case 'O':
680 flags |= LONGINT;
681 /*FALLTHROUGH*/
682 case 'o':
683 _uquad = UARG();
684 base = OCT;
685 goto nosign;
686 case 'p':
687 /*
688 * ``The argument shall be a pointer to void. The
689 * value of the pointer is converted to a sequence
690 * of printable characters, in an implementation-
691 * defined manner.''
692 * -- ANSI X3J11
693 */
694 /* NOSTRICT */
695 _uquad = (u_long)(unsigned _POINTER_INT)va_arg(ap, void *);
696 base = HEX;
697 xdigs = "0123456789abcdef";
698 flags |= HEXPREFIX;
699 ch = 'x';
700 goto nosign;
701 case 's':
702 if ((cp = va_arg(ap, char *)) == NULL)
703 cp = "(null)";
704 if (prec >= 0) {
705 /*
706 * can't use strlen; can only look for the
707 * NUL in the first `prec' characters, and
708 * strlen() will go further.
709 */
710 char *p = memchr(cp, 0, prec);
711
712 if (p != NULL) {
713 size = p - cp;
714 if (size > prec)
715 size = prec;
716 } else
717 size = prec;
718 } else
719 size = strlen(cp);
720 sign = '\0';
721 break;
722 case 'U':
723 flags |= LONGINT;
724 /*FALLTHROUGH*/
725 case 'u':
726 _uquad = UARG();
727 base = DEC;
728 goto nosign;
729 case 'X':
730 xdigs = "0123456789ABCDEF";
731 goto hex;
732 case 'x':
733 xdigs = "0123456789abcdef";
734hex: _uquad = UARG();
735 base = HEX;
736 /* leading 0x/X only if non-zero */
737 if (flags & ALT && _uquad != 0)
738 flags |= HEXPREFIX;
739
740 /* unsigned conversions */
741nosign: sign = '\0';
742 /*
743 * ``... diouXx conversions ... if a precision is
744 * specified, the 0 flag will be ignored.''
745 * -- ANSI X3J11
746 */
747number: if ((dprec = prec) >= 0)
748 flags &= ~ZEROPAD;
749
750 /*
751 * ``The result of converting a zero value with an
752 * explicit precision of zero is no characters.''
753 * -- ANSI X3J11
754 */
755 cp = buf + BUF;
756 if (_uquad != 0 || prec != 0) {
757 /*
758 * Unsigned mod is hard, and unsigned mod
759 * by a constant is easier than that by
760 * a variable; hence this switch.
761 */
762 switch (base) {
763 case OCT:
764 do {
765 *--cp = to_char(_uquad & 7);
766 _uquad >>= 3;
767 } while (_uquad);
768 /* handle octal leading 0 */
769 if (flags & ALT && *cp != '0')
770 *--cp = '0';
771 break;
772
773 case DEC:
774 /* many numbers are 1 digit */
775 while (_uquad >= 10) {
776 *--cp = to_char(_uquad % 10);
777 _uquad /= 10;
778 }
779 *--cp = to_char(_uquad);
780 break;
781
782 case HEX:
783 do {
784 *--cp = xdigs[_uquad & 15];
785 _uquad >>= 4;
786 } while (_uquad);
787 break;
788
789 default:
790 cp = "bug in vfprintf: bad base";
791 size = strlen(cp);
792 goto skipsize;
793 }
794 }
188bc140
NC
795 /*
796 * ...result is to be converted to an 'alternate form'.
797 * For o conversion, it increases the precision to force
798 * the first digit of the result to be a zero."
799 * -- ANSI X3J11
800 *
801 * To demonstrate this case, compile and run:
802 * printf ("%#.0o",0);
803 */
804 else if (base == OCT && (flags & ALT))
805 *--cp = '0';
806
8a0efa53
CF
807 size = buf + BUF - cp;
808 skipsize:
809 break;
810 default: /* "%?" prints ?, unless ? is NUL */
811 if (ch == '\0')
812 goto done;
813 /* pretend it was %c with argument ch */
814 cp = buf;
815 *cp = ch;
816 size = 1;
817 sign = '\0';
818 break;
819 }
820
821 /*
822 * All reasonable formats wind up here. At this point, `cp'
823 * points to a string which (if not flags&LADJUST) should be
824 * padded out to `width' places. If flags&ZEROPAD, it should
825 * first be prefixed by any sign or other prefix; otherwise,
826 * it should be blank padded before the prefix is emitted.
827 * After any left-hand padding and prefixing, emit zeroes
828 * required by a decimal [diouxX] precision, then print the
829 * string proper, then emit zeroes required by any leftover
830 * floating precision; finally, if LADJUST, pad with blanks.
831 *
832 * Compute actual size, so we know how much to pad.
833 * size excludes decimal prec; realsz includes it.
834 */
835 realsz = dprec > size ? dprec : size;
836 if (sign)
837 realsz++;
838 else if (flags & HEXPREFIX)
839 realsz+= 2;
840
841 /* right-adjusting blank padding */
842 if ((flags & (LADJUST|ZEROPAD)) == 0)
843 PAD(width - realsz, blanks);
844
845 /* prefix */
846 if (sign) {
847 PRINT(&sign, 1);
848 } else if (flags & HEXPREFIX) {
849 ox[0] = '0';
850 ox[1] = ch;
851 PRINT(ox, 2);
852 }
853
854 /* right-adjusting zero padding */
855 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
856 PAD(width - realsz, zeroes);
857
858 /* leading zeroes from decimal precision */
859 PAD(dprec - size, zeroes);
860
861 /* the string or number proper */
862#ifdef FLOATING_POINT
863 if ((flags & FPT) == 0) {
864 PRINT(cp, size);
865 } else { /* glue together f_p fragments */
866 if (ch >= 'f') { /* 'f' or 'g' */
6bdac416 867 if (_fpvalue == 0) {
8a0efa53
CF
868 /* kludge for __dtoa irregularity */
869 PRINT("0", 1);
870 if (expt < ndig || (flags & ALT) != 0) {
871 PRINT(decimal_point, 1);
872 PAD(ndig - 1, zeroes);
873 }
874 } else if (expt <= 0) {
875 PRINT("0", 1);
e9cd87b8 876 if(expt || ndig) {
5bacbf10
JJ
877 PRINT(decimal_point, 1);
878 PAD(-expt, zeroes);
879 PRINT(cp, ndig);
880 }
8a0efa53
CF
881 } else if (expt >= ndig) {
882 PRINT(cp, ndig);
883 PAD(expt - ndig, zeroes);
884 if (flags & ALT)
885 PRINT(".", 1);
886 } else {
887 PRINT(cp, expt);
888 cp += expt;
889 PRINT(".", 1);
890 PRINT(cp, ndig-expt);
891 }
892 } else { /* 'e' or 'E' */
893 if (ndig > 1 || flags & ALT) {
894 ox[0] = *cp++;
895 ox[1] = '.';
896 PRINT(ox, 2);
6bdac416 897 if (_fpvalue) {
8a0efa53
CF
898 PRINT(cp, ndig-1);
899 } else /* 0.[0..] */
900 /* __dtoa irregularity */
901 PAD(ndig - 1, zeroes);
902 } else /* XeYYY */
903 PRINT(cp, 1);
904 PRINT(expstr, expsize);
905 }
906 }
907#else
908 PRINT(cp, size);
909#endif
910 /* left-adjusting padding (always blank) */
911 if (flags & LADJUST)
912 PAD(width - realsz, blanks);
913
914 /* finally, adjust ret */
915 ret += width > realsz ? width : realsz;
916
917 FLUSH(); /* copy out the I/O vectors */
918 }
919done:
920 FLUSH();
921error:
922 return (__sferror(fp) ? EOF : ret);
923 /* NOTREACHED */
924}
925
926#ifdef FLOATING_POINT
927
6bdac416 928#ifdef _NO_LONGDBL
8a0efa53
CF
929extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
930 int, int *, int *, char **));
6bdac416
JJ
931#else
932extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
933 int, int *, int *, char **));
934#undef word0
935#define word0(x) ldword0(x)
6bdac416 936#endif
8a0efa53
CF
937
938static char *
939cvt(data, value, ndigits, flags, sign, decpt, ch, length)
940 struct _reent *data;
6bdac416 941#ifdef _NO_LONGDBL
8a0efa53 942 double value;
6bdac416
JJ
943#else
944 _LONG_DOUBLE value;
945#endif
8a0efa53
CF
946 int ndigits, flags, *decpt, ch, *length;
947 char *sign;
948{
949 int mode, dsgn;
950 char *digits, *bp, *rve;
6bdac416 951#ifdef _NO_LONGDBL
8a0efa53 952 union double_union tmp;
6bdac416
JJ
953#else
954 struct ldieee *ldptr;
955#endif
8a0efa53
CF
956
957 if (ch == 'f') {
958 mode = 3; /* ndigits after the decimal point */
959 } else {
960 /* To obtain ndigits after the decimal point for the 'e'
961 * and 'E' formats, round to ndigits + 1 significant
962 * figures.
963 */
964 if (ch == 'e' || ch == 'E') {
965 ndigits++;
966 }
967 mode = 2; /* ndigits significant digits */
968 }
969
6bdac416 970#ifdef _NO_LONGDBL
8a0efa53 971 tmp.d = value;
6bdac416 972
8a0efa53
CF
973 if (word0(tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
974 value = -value;
975 *sign = '-';
976 } else
977 *sign = '\000';
6bdac416 978
8a0efa53 979 digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
6bdac416
JJ
980#else /* !_NO_LONGDBL */
981 ldptr = (struct ldieee *)&value;
982 if (ldptr->sign) { /* this will check for < 0 and -0.0 */
983 value = -value;
984 *sign = '-';
985 } else
986 *sign = '\000';
987
988 digits = _ldtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
989#endif /* !_NO_LONGDBL */
990
8a0efa53
CF
991 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
992 bp = digits + ndigits;
993 if (ch == 'f') {
994 if (*digits == '0' && value)
995 *decpt = -ndigits + 1;
996 bp += *decpt;
997 }
998 if (value == 0) /* kludge for __dtoa irregularity */
999 rve = bp;
1000 while (rve < bp)
1001 *rve++ = '0';
1002 }
1003 *length = rve - digits;
1004 return (digits);
1005}
1006
1007static int
1008exponent(p0, exp, fmtch)
1009 char *p0;
1010 int exp, fmtch;
1011{
1012 register char *p, *t;
6bdac416 1013 char expbuf[40];
8a0efa53
CF
1014
1015 p = p0;
1016 *p++ = fmtch;
1017 if (exp < 0) {
1018 exp = -exp;
1019 *p++ = '-';
1020 }
1021 else
1022 *p++ = '+';
6bdac416 1023 t = expbuf + 40;
8a0efa53
CF
1024 if (exp > 9) {
1025 do {
1026 *--t = to_char(exp % 10);
1027 } while ((exp /= 10) > 9);
1028 *--t = to_char(exp);
6bdac416 1029 for (; t < expbuf + 40; *p++ = *t++);
8a0efa53
CF
1030 }
1031 else {
1032 *p++ = '0';
1033 *p++ = to_char(exp);
1034 }
1035 return (p - p0);
1036}
1037#endif /* FLOATING_POINT */
This page took 0.154128 seconds and 5 git commands to generate.