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