vfprintf.c revision 1.1.1.2 1 /*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93";
39 #endif /* LIBC_SCCS and not lint */
40
41 /*
42 * Actual printf innards.
43 *
44 * This code is large and complicated...
45 */
46
47 #include <sys/types.h>
48
49 #include <limits.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #if __STDC__
55 #include <stdarg.h>
56 #else
57 #include <varargs.h>
58 #endif
59
60 #include "local.h"
61 #include "fvwrite.h"
62
63 /* Define FLOATING_POINT to get floating point. */
64 #define FLOATING_POINT
65
66 /*
67 * Flush out all the vectors defined by the given uio,
68 * then reset it so that it can be reused.
69 */
70 static int
71 __sprint(fp, uio)
72 FILE *fp;
73 register struct __suio *uio;
74 {
75 register int err;
76
77 if (uio->uio_resid == 0) {
78 uio->uio_iovcnt = 0;
79 return (0);
80 }
81 err = __sfvwrite(fp, uio);
82 uio->uio_resid = 0;
83 uio->uio_iovcnt = 0;
84 return (err);
85 }
86
87 /*
88 * Helper function for `fprintf to unbuffered unix file': creates a
89 * temporary buffer. We only work on write-only files; this avoids
90 * worries about ungetc buffers and so forth.
91 */
92 static int
93 __sbprintf(fp, fmt, ap)
94 register FILE *fp;
95 const char *fmt;
96 va_list ap;
97 {
98 int ret;
99 FILE fake;
100 unsigned char buf[BUFSIZ];
101
102 /* copy the important variables */
103 fake._flags = fp->_flags & ~__SNBF;
104 fake._file = fp->_file;
105 fake._cookie = fp->_cookie;
106 fake._write = fp->_write;
107
108 /* set up the buffer */
109 fake._bf._base = fake._p = buf;
110 fake._bf._size = fake._w = sizeof(buf);
111 fake._lbfsize = 0; /* not actually used, but Just In Case */
112
113 /* do the work, then copy any error status */
114 ret = vfprintf(&fake, fmt, ap);
115 if (ret >= 0 && fflush(&fake))
116 ret = EOF;
117 if (fake._flags & __SERR)
118 fp->_flags |= __SERR;
119 return (ret);
120 }
121
122 /*
123 * Macros for converting digits to letters and vice versa
124 */
125 #define to_digit(c) ((c) - '0')
126 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
127 #define to_char(n) ((n) + '0')
128
129 /*
130 * Convert an unsigned long to ASCII for printf purposes, returning
131 * a pointer to the first character of the string representation.
132 * Octal numbers can be forced to have a leading zero; hex numbers
133 * use the given digits.
134 */
135 static char *
136 __ultoa(val, endp, base, octzero, xdigs)
137 register u_long val;
138 char *endp;
139 int base, octzero;
140 char *xdigs;
141 {
142 register char *cp = endp;
143 register long sval;
144
145 /*
146 * Handle the three cases separately, in the hope of getting
147 * better/faster code.
148 */
149 switch (base) {
150 case 10:
151 if (val < 10) { /* many numbers are 1 digit */
152 *--cp = to_char(val);
153 return (cp);
154 }
155 /*
156 * On many machines, unsigned arithmetic is harder than
157 * signed arithmetic, so we do at most one unsigned mod and
158 * divide; this is sufficient to reduce the range of
159 * the incoming value to where signed arithmetic works.
160 */
161 if (val > LONG_MAX) {
162 *--cp = to_char(val % 10);
163 sval = val / 10;
164 } else
165 sval = val;
166 do {
167 *--cp = to_char(sval % 10);
168 sval /= 10;
169 } while (sval != 0);
170 break;
171
172 case 8:
173 do {
174 *--cp = to_char(val & 7);
175 val >>= 3;
176 } while (val);
177 if (octzero && *cp != '0')
178 *--cp = '0';
179 break;
180
181 case 16:
182 do {
183 *--cp = xdigs[val & 15];
184 val >>= 4;
185 } while (val);
186 break;
187
188 default: /* oops */
189 abort();
190 }
191 return (cp);
192 }
193
194 /* Identical to __ultoa, but for quads. */
195 static char *
196 __uqtoa(val, endp, base, octzero, xdigs)
197 register u_quad_t val;
198 char *endp;
199 int base, octzero;
200 char *xdigs;
201 {
202 register char *cp = endp;
203 register quad_t sval;
204
205 /* quick test for small values; __ultoa is typically much faster */
206 /* (perhaps instead we should run until small, then call __ultoa?) */
207 if (val <= ULONG_MAX)
208 return (__ultoa((u_long)val, endp, base, octzero, xdigs));
209 switch (base) {
210 case 10:
211 if (val < 10) {
212 *--cp = to_char(val % 10);
213 return (cp);
214 }
215 if (val > QUAD_MAX) {
216 *--cp = to_char(val % 10);
217 sval = val / 10;
218 } else
219 sval = val;
220 do {
221 *--cp = to_char(sval % 10);
222 sval /= 10;
223 } while (sval != 0);
224 break;
225
226 case 8:
227 do {
228 *--cp = to_char(val & 7);
229 val >>= 3;
230 } while (val);
231 if (octzero && *cp != '0')
232 *--cp = '0';
233 break;
234
235 case 16:
236 do {
237 *--cp = xdigs[val & 15];
238 val >>= 4;
239 } while (val);
240 break;
241
242 default:
243 abort();
244 }
245 return (cp);
246 }
247
248 #ifdef FLOATING_POINT
249 #include <math.h>
250 #include "floatio.h"
251
252 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
253 #define DEFPREC 6
254
255 static char *cvt __P((double, int, int, char *, int *, int, int *));
256 static int exponent __P((char *, int, int));
257
258 #else /* no FLOATING_POINT */
259
260 #define BUF 68
261
262 #endif /* FLOATING_POINT */
263
264
265 /*
266 * Flags used during conversion.
267 */
268 #define ALT 0x001 /* alternate form */
269 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
270 #define LADJUST 0x004 /* left adjustment */
271 #define LONGDBL 0x008 /* long double; unimplemented */
272 #define LONGINT 0x010 /* long integer */
273 #define QUADINT 0x020 /* quad integer */
274 #define SHORTINT 0x040 /* short integer */
275 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
276 #define FPT 0x100 /* Floating point number */
277 int
278 vfprintf(fp, fmt0, ap)
279 FILE *fp;
280 const char *fmt0;
281 va_list ap;
282 {
283 register char *fmt; /* format string */
284 register int ch; /* character from fmt */
285 register int n; /* handy integer (short term usage) */
286 register char *cp; /* handy char pointer (short term usage) */
287 register struct __siov *iovp;/* for PRINT macro */
288 register int flags; /* flags as above */
289 int ret; /* return value accumulator */
290 int width; /* width from format (%8d), or 0 */
291 int prec; /* precision from format (%.3d), or -1 */
292 char sign; /* sign prefix (' ', '+', '-', or \0) */
293 #ifdef FLOATING_POINT
294 char softsign; /* temporary negative sign for floats */
295 double _double; /* double precision arguments %[eEfgG] */
296 int expt; /* integer value of exponent */
297 int expsize; /* character count for expstr */
298 int ndig; /* actual number of digits returned by cvt */
299 char expstr[7]; /* buffer for exponent string */
300 #endif
301 u_long ulval; /* integer arguments %[diouxX] */
302 u_quad_t uqval; /* %q integers */
303 int base; /* base for [diouxX] conversion */
304 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
305 int fieldsz; /* field size expanded by sign, etc */
306 int realsz; /* field size expanded by dprec */
307 int size; /* size of converted field or string */
308 char *xdigs; /* digits for [xX] conversion */
309 #define NIOV 8
310 struct __suio uio; /* output information: summary */
311 struct __siov iov[NIOV];/* ... and individual io vectors */
312 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
313 char ox[2]; /* space for 0x hex-prefix */
314
315 /*
316 * Choose PADSIZE to trade efficiency vs. size. If larger printf
317 * fields occur frequently, increase PADSIZE and make the initialisers
318 * below longer.
319 */
320 #define PADSIZE 16 /* pad chunk size */
321 static char blanks[PADSIZE] =
322 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
323 static char zeroes[PADSIZE] =
324 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
325
326 /*
327 * BEWARE, these `goto error' on error, and PAD uses `n'.
328 */
329 #define PRINT(ptr, len) { \
330 iovp->iov_base = (ptr); \
331 iovp->iov_len = (len); \
332 uio.uio_resid += (len); \
333 iovp++; \
334 if (++uio.uio_iovcnt >= NIOV) { \
335 if (__sprint(fp, &uio)) \
336 goto error; \
337 iovp = iov; \
338 } \
339 }
340 #define PAD(howmany, with) { \
341 if ((n = (howmany)) > 0) { \
342 while (n > PADSIZE) { \
343 PRINT(with, PADSIZE); \
344 n -= PADSIZE; \
345 } \
346 PRINT(with, n); \
347 } \
348 }
349 #define FLUSH() { \
350 if (uio.uio_resid && __sprint(fp, &uio)) \
351 goto error; \
352 uio.uio_iovcnt = 0; \
353 iovp = iov; \
354 }
355
356 /*
357 * To extend shorts properly, we need both signed and unsigned
358 * argument extraction methods.
359 */
360 #define SARG() \
361 (flags&LONGINT ? va_arg(ap, long) : \
362 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
363 (long)va_arg(ap, int))
364 #define UARG() \
365 (flags&LONGINT ? va_arg(ap, u_long) : \
366 flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
367 (u_long)va_arg(ap, u_int))
368
369 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
370 if (cantwrite(fp))
371 return (EOF);
372
373 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
374 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
375 fp->_file >= 0)
376 return (__sbprintf(fp, fmt0, ap));
377
378 fmt = (char *)fmt0;
379 uio.uio_iov = iovp = iov;
380 uio.uio_resid = 0;
381 uio.uio_iovcnt = 0;
382 ret = 0;
383
384 /*
385 * Scan the format for conversions (`%' character).
386 */
387 for (;;) {
388 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
389 /* void */;
390 if ((n = fmt - cp) != 0) {
391 PRINT(cp, n);
392 ret += n;
393 }
394 if (ch == '\0')
395 goto done;
396 fmt++; /* skip over '%' */
397
398 flags = 0;
399 dprec = 0;
400 width = 0;
401 prec = -1;
402 sign = '\0';
403
404 rflag: ch = *fmt++;
405 reswitch: switch (ch) {
406 case ' ':
407 /*
408 * ``If the space and + flags both appear, the space
409 * flag will be ignored.''
410 * -- ANSI X3J11
411 */
412 if (!sign)
413 sign = ' ';
414 goto rflag;
415 case '#':
416 flags |= ALT;
417 goto rflag;
418 case '*':
419 /*
420 * ``A negative field width argument is taken as a
421 * - flag followed by a positive field width.''
422 * -- ANSI X3J11
423 * They don't exclude field widths read from args.
424 */
425 if ((width = va_arg(ap, int)) >= 0)
426 goto rflag;
427 width = -width;
428 /* FALLTHROUGH */
429 case '-':
430 flags |= LADJUST;
431 goto rflag;
432 case '+':
433 sign = '+';
434 goto rflag;
435 case '.':
436 if ((ch = *fmt++) == '*') {
437 n = va_arg(ap, int);
438 prec = n < 0 ? -1 : n;
439 goto rflag;
440 }
441 n = 0;
442 while (is_digit(ch)) {
443 n = 10 * n + to_digit(ch);
444 ch = *fmt++;
445 }
446 prec = n < 0 ? -1 : n;
447 goto reswitch;
448 case '0':
449 /*
450 * ``Note that 0 is taken as a flag, not as the
451 * beginning of a field width.''
452 * -- ANSI X3J11
453 */
454 flags |= ZEROPAD;
455 goto rflag;
456 case '1': case '2': case '3': case '4':
457 case '5': case '6': case '7': case '8': case '9':
458 n = 0;
459 do {
460 n = 10 * n + to_digit(ch);
461 ch = *fmt++;
462 } while (is_digit(ch));
463 width = n;
464 goto reswitch;
465 #ifdef FLOATING_POINT
466 case 'L':
467 flags |= LONGDBL;
468 goto rflag;
469 #endif
470 case 'h':
471 flags |= SHORTINT;
472 goto rflag;
473 case 'l':
474 flags |= LONGINT;
475 goto rflag;
476 case 'q':
477 flags |= QUADINT;
478 goto rflag;
479 case 'c':
480 *(cp = buf) = va_arg(ap, int);
481 size = 1;
482 sign = '\0';
483 break;
484 case 'D':
485 flags |= LONGINT;
486 /*FALLTHROUGH*/
487 case 'd':
488 case 'i':
489 if (flags & QUADINT) {
490 uqval = va_arg(ap, quad_t);
491 if ((quad_t)uqval < 0) {
492 uqval = -uqval;
493 sign = '-';
494 }
495 } else {
496 ulval = SARG();
497 if ((long)ulval < 0) {
498 ulval = -ulval;
499 sign = '-';
500 }
501 }
502 base = 10;
503 goto number;
504 #ifdef FLOATING_POINT
505 case 'e': /* anomalous precision */
506 case 'E':
507 prec = (prec == -1) ?
508 DEFPREC + 1 : prec + 1;
509 /* FALLTHROUGH */
510 goto fp_begin;
511 case 'f': /* always print trailing zeroes */
512 if (prec != 0)
513 flags |= ALT;
514 case 'g':
515 case 'G':
516 if (prec == -1)
517 prec = DEFPREC;
518 fp_begin: _double = va_arg(ap, double);
519 /* do this before tricky precision changes */
520 if (isinf(_double)) {
521 if (_double < 0)
522 sign = '-';
523 cp = "Inf";
524 size = 3;
525 break;
526 }
527 if (isnan(_double)) {
528 cp = "NaN";
529 size = 3;
530 break;
531 }
532 flags |= FPT;
533 cp = cvt(_double, prec, flags, &softsign,
534 &expt, ch, &ndig);
535 if (ch == 'g' || ch == 'G') {
536 if (expt <= -4 || expt > prec)
537 ch = (ch == 'g') ? 'e' : 'E';
538 else
539 ch = 'g';
540 }
541 if (ch <= 'e') { /* 'e' or 'E' fmt */
542 --expt;
543 expsize = exponent(expstr, expt, ch);
544 size = expsize + ndig;
545 if (ndig > 1 || flags & ALT)
546 ++size;
547 } else if (ch == 'f') { /* f fmt */
548 if (expt > 0) {
549 size = expt;
550 if (prec || flags & ALT)
551 size += prec + 1;
552 } else /* "0.X" */
553 size = prec + 2;
554 } else if (expt >= ndig) { /* fixed g fmt */
555 size = expt;
556 if (flags & ALT)
557 ++size;
558 } else
559 size = ndig + (expt > 0 ?
560 1 : 2 - expt);
561
562 if (softsign)
563 sign = '-';
564 break;
565 #endif /* FLOATING_POINT */
566 case 'n':
567 if (flags & QUADINT)
568 *va_arg(ap, quad_t *) = ret;
569 else if (flags & LONGINT)
570 *va_arg(ap, long *) = ret;
571 else if (flags & SHORTINT)
572 *va_arg(ap, short *) = ret;
573 else
574 *va_arg(ap, int *) = ret;
575 continue; /* no output */
576 case 'O':
577 flags |= LONGINT;
578 /*FALLTHROUGH*/
579 case 'o':
580 if (flags & QUADINT)
581 uqval = va_arg(ap, u_quad_t);
582 else
583 ulval = UARG();
584 base = 8;
585 goto nosign;
586 case 'p':
587 /*
588 * ``The argument shall be a pointer to void. The
589 * value of the pointer is converted to a sequence
590 * of printable characters, in an implementation-
591 * defined manner.''
592 * -- ANSI X3J11
593 */
594 ulval = (u_long)va_arg(ap, void *);
595 base = 16;
596 xdigs = "0123456789abcdef";
597 flags = (flags & ~QUADINT) | HEXPREFIX;
598 ch = 'x';
599 goto nosign;
600 case 's':
601 if ((cp = va_arg(ap, char *)) == NULL)
602 cp = "(null)";
603 if (prec >= 0) {
604 /*
605 * can't use strlen; can only look for the
606 * NUL in the first `prec' characters, and
607 * strlen() will go further.
608 */
609 char *p = memchr(cp, 0, prec);
610
611 if (p != NULL) {
612 size = p - cp;
613 if (size > prec)
614 size = prec;
615 } else
616 size = prec;
617 } else
618 size = strlen(cp);
619 sign = '\0';
620 break;
621 case 'U':
622 flags |= LONGINT;
623 /*FALLTHROUGH*/
624 case 'u':
625 if (flags & QUADINT)
626 uqval = va_arg(ap, u_quad_t);
627 else
628 ulval = UARG();
629 base = 10;
630 goto nosign;
631 case 'X':
632 xdigs = "0123456789ABCDEF";
633 goto hex;
634 case 'x':
635 xdigs = "0123456789abcdef";
636 hex: if (flags & QUADINT)
637 uqval = va_arg(ap, u_quad_t);
638 else
639 ulval = UARG();
640 base = 16;
641 /* leading 0x/X only if non-zero */
642 if (flags & ALT &&
643 (flags & QUADINT ? uqval != 0 : ulval != 0))
644 flags |= HEXPREFIX;
645
646 /* unsigned conversions */
647 nosign: sign = '\0';
648 /*
649 * ``... diouXx conversions ... if a precision is
650 * specified, the 0 flag will be ignored.''
651 * -- ANSI X3J11
652 */
653 number: if ((dprec = prec) >= 0)
654 flags &= ~ZEROPAD;
655
656 /*
657 * ``The result of converting a zero value with an
658 * explicit precision of zero is no characters.''
659 * -- ANSI X3J11
660 */
661 cp = buf + BUF;
662 if (flags & QUADINT) {
663 if (uqval != 0 || prec != 0)
664 cp = __uqtoa(uqval, cp, base,
665 flags & ALT, xdigs);
666 } else {
667 if (ulval != 0 || prec != 0)
668 cp = __ultoa(ulval, cp, base,
669 flags & ALT, xdigs);
670 }
671 size = buf + BUF - cp;
672 break;
673 default: /* "%?" prints ?, unless ? is NUL */
674 if (ch == '\0')
675 goto done;
676 /* pretend it was %c with argument ch */
677 cp = buf;
678 *cp = ch;
679 size = 1;
680 sign = '\0';
681 break;
682 }
683
684 /*
685 * All reasonable formats wind up here. At this point, `cp'
686 * points to a string which (if not flags&LADJUST) should be
687 * padded out to `width' places. If flags&ZEROPAD, it should
688 * first be prefixed by any sign or other prefix; otherwise,
689 * it should be blank padded before the prefix is emitted.
690 * After any left-hand padding and prefixing, emit zeroes
691 * required by a decimal [diouxX] precision, then print the
692 * string proper, then emit zeroes required by any leftover
693 * floating precision; finally, if LADJUST, pad with blanks.
694 *
695 * Compute actual size, so we know how much to pad.
696 * fieldsz excludes decimal prec; realsz includes it.
697 */
698 fieldsz = size;
699 if (sign)
700 fieldsz++;
701 else if (flags & HEXPREFIX)
702 fieldsz += 2;
703 realsz = dprec > fieldsz ? dprec : fieldsz;
704
705 /* right-adjusting blank padding */
706 if ((flags & (LADJUST|ZEROPAD)) == 0)
707 PAD(width - realsz, blanks);
708
709 /* prefix */
710 if (sign) {
711 PRINT(&sign, 1);
712 } else if (flags & HEXPREFIX) {
713 ox[0] = '0';
714 ox[1] = ch;
715 PRINT(ox, 2);
716 }
717
718 /* right-adjusting zero padding */
719 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
720 PAD(width - realsz, zeroes);
721
722 /* leading zeroes from decimal precision */
723 PAD(dprec - fieldsz, zeroes);
724
725 /* the string or number proper */
726 #ifdef FLOATING_POINT
727 if ((flags & FPT) == 0) {
728 PRINT(cp, size);
729 } else { /* glue together f_p fragments */
730 if (ch >= 'f') { /* 'f' or 'g' */
731 if (_double == 0) {
732 /* kludge for __dtoa irregularity */
733 if (prec == 0 ||
734 (flags & ALT) == 0) {
735 PRINT("0", 1);
736 } else {
737 PRINT("0.", 2);
738 PAD(ndig - 1, zeroes);
739 }
740 } else if (expt <= 0) {
741 PRINT("0.", 2);
742 PAD(-expt, zeroes);
743 PRINT(cp, ndig);
744 } else if (expt >= ndig) {
745 PRINT(cp, ndig);
746 PAD(expt - ndig, zeroes);
747 if (flags & ALT)
748 PRINT(".", 1);
749 } else {
750 PRINT(cp, expt);
751 cp += expt;
752 PRINT(".", 1);
753 PRINT(cp, ndig-expt);
754 }
755 } else { /* 'e' or 'E' */
756 if (ndig > 1 || flags & ALT) {
757 ox[0] = *cp++;
758 ox[1] = '.';
759 PRINT(ox, 2);
760 if (_double || flags & ALT == 0) {
761 PRINT(cp, ndig-1);
762 } else /* 0.[0..] */
763 /* __dtoa irregularity */
764 PAD(ndig - 1, zeroes);
765 } else /* XeYYY */
766 PRINT(cp, 1);
767 PRINT(expstr, expsize);
768 }
769 }
770 #else
771 PRINT(cp, size);
772 #endif
773 /* left-adjusting padding (always blank) */
774 if (flags & LADJUST)
775 PAD(width - realsz, blanks);
776
777 /* finally, adjust ret */
778 ret += width > realsz ? width : realsz;
779
780 FLUSH(); /* copy out the I/O vectors */
781 }
782 done:
783 FLUSH();
784 error:
785 return (__sferror(fp) ? EOF : ret);
786 /* NOTREACHED */
787 }
788
789 #ifdef FLOATING_POINT
790
791 extern char *__dtoa __P((double, int, int, int *, int *, char **));
792
793 static char *
794 cvt(value, ndigits, flags, sign, decpt, ch, length)
795 double value;
796 int ndigits, flags, *decpt, ch, *length;
797 char *sign;
798 {
799 int mode, dsgn;
800 char *digits, *bp, *rve;
801
802 if (ch == 'f')
803 mode = 3;
804 else {
805 mode = 2;
806 }
807 if (value < 0) {
808 value = -value;
809 *sign = '-';
810 } else
811 *sign = '\000';
812 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
813 if (flags & ALT) { /* Print trailing zeros */
814 bp = digits + ndigits;
815 if (ch == 'f') {
816 if (*digits == '0' && value)
817 *decpt = -ndigits + 1;
818 bp += *decpt;
819 }
820 if (value == 0) /* kludge for __dtoa irregularity */
821 rve = bp;
822 while (rve < bp)
823 *rve++ = '0';
824 }
825 *length = rve - digits;
826 return (digits);
827 }
828
829 static int
830 exponent(p0, exp, fmtch)
831 char *p0;
832 int exp, fmtch;
833 {
834 register char *p, *t;
835 char expbuf[MAXEXP];
836
837 p = p0;
838 *p++ = fmtch;
839 if (exp < 0) {
840 exp = -exp;
841 *p++ = '-';
842 }
843 else
844 *p++ = '+';
845 t = expbuf + MAXEXP;
846 if (exp > 9) {
847 do {
848 *--t = to_char(exp % 10);
849 } while ((exp /= 10) > 9);
850 *--t = to_char(exp);
851 for (; t < expbuf + MAXEXP; *p++ = *t++);
852 }
853 else {
854 *p++ = '0';
855 *p++ = to_char(exp);
856 }
857 return (p - p0);
858 }
859 #endif /* FLOATING_POINT */
860