1 /*
2 FUNCTION
3 <<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list
4
5 INDEX
6 vprintf
7 INDEX
8 vfprintf
9 INDEX
10 vsprintf
11 INDEX
12 vsnprintf
13
14 ANSI_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
31 TRAD_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
78 DESCRIPTION
79 <<vprintf>>, <<vfprintf>>, <<vsprintf>> and <<vsnprintf>> are (respectively)
80 variants of <<printf>>, <<fprintf>>, <<sprintf>> and <<snprintf>>. They differ
81 only in allowing their caller to pass the variable argument list as a
82 <<va_list>> object (initialized by <<va_start>>) rather than directly
83 accepting a variable number of arguments.
84
85 RETURNS
86 The return values are consistent with the corresponding functions:
87 <<vsprintf>> returns the number of bytes in the output string,
88 save that the concluding <<NULL>> is not counted.
89 <<vprintf>> and <<vfprintf>> return the number of characters transmitted.
90 If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>>. No
91 error returns occur for <<vsprintf>>.
92
93 PORTABILITY
94 ANSI C requires all three functions.
95
96 Supporting 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";*/
138 static 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
153 #ifndef NO_FLOATING_POINT
154 #define FLOATING_POINT
155 #endif
156 #endif
157
158 #include <_ansi.h>
159 #include <limits.h>
160 #include <stdio.h>
161 #include <stdlib.h>
162 #include <string.h>
163 #include <reent.h>
164 #include <wchar.h>
165 #include <string.h>
166 #ifdef __ALTIVEC__
167 #include <altivec.h>
168 #endif
169
170 #ifdef _HAVE_STDC
171 #include <stdarg.h>
172 #else
173 #include <varargs.h>
174 #endif
175
176 #include "local.h"
177 #include "fvwrite.h"
178 #include "vfieeefp.h"
179
180 /* Currently a test is made to see if long double processing is warranted.
181 This could be changed in the future should the _ldtoa_r code be
182 preferred over _dtoa_r. */
183 #define _NO_LONGDBL
184 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
185 #undef _NO_LONGDBL
186 #endif
187
188 #define _NO_LONGLONG
189 #if defined _WANT_IO_LONG_LONG && defined __GNUC__
190 # undef _NO_LONGLONG
191 #endif
192
193 #ifdef __ALTIVEC__
194 typedef union
195 {
196 vector int v;
197 float f[4];
198 int i[16 / sizeof(int)];
199 long l[4];
200 short s[8];
201 signed char c[16];
202 } vec_16_byte_union;
203 #endif /* __ALTIVEC__ */
204
205 /*
206 * Flush out all the vectors defined by the given uio,
207 * then reset it so that it can be reused.
208 */
209 static int
__sprint_r(rptr,fp,uio)210 __sprint_r(rptr, fp, uio)
211 struct _reent *rptr;
212 FILE *fp;
213 register struct __suio *uio;
214 {
215 register int err;
216
217 if (uio->uio_resid == 0) {
218 uio->uio_iovcnt = 0;
219 return (0);
220 }
221 err = __sfvwrite_r(rptr, fp, uio);
222 uio->uio_resid = 0;
223 uio->uio_iovcnt = 0;
224 return (err);
225 }
226
227 /*
228 * Helper function for `fprintf to unbuffered unix file': creates a
229 * temporary buffer. We only work on write-only files; this avoids
230 * worries about ungetc buffers and so forth.
231 */
232 static int
__sbprintf_r(rptr,fp,fmt,ap)233 __sbprintf_r(rptr, fp, fmt, ap)
234 struct _reent *rptr;
235 register FILE *fp;
236 const char *fmt;
237 va_list ap;
238 {
239 int ret;
240 FILE fake;
241 unsigned char buf[BUFSIZ];
242
243 /* copy the important variables */
244 fake._flags = fp->_flags & ~__SNBF;
245 fake._file = fp->_file;
246 fake._cookie = fp->_cookie;
247 fake._write = fp->_write;
248
249 /* set up the buffer */
250 fake._bf._base = fake._p = buf;
251 fake._bf._size = fake._w = sizeof(buf);
252 fake._lbfsize = 0; /* not actually used, but Just In Case */
253
254 /* do the work, then copy any error status */
255 ret = _VFPRINTF_R(rptr, &fake, fmt, ap);
256 if (ret >= 0 && _fflush_r(rptr, &fake))
257 ret = EOF;
258 if (fake._flags & __SERR)
259 fp->_flags |= __SERR;
260 return (ret);
261 }
262
263
264 #ifdef FLOATING_POINT
265 #include <locale.h>
266 #include <math.h>
267 #include "floatio.h"
268
269 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
270 #define DEFPREC 6
271
272 #ifdef _NO_LONGDBL
273 static char *cvt _PARAMS((struct _reent *, double, int, int, char *, int *, int, int *));
274 #else
275 static char *cvt _PARAMS((struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *));
276 extern int _ldcheck _PARAMS((_LONG_DOUBLE *));
277 #endif
278
279 static int exponent _PARAMS((char *, int, int));
280
281 #ifdef __SPE__
282 static char *cvt_ufix64 _PARAMS((struct _reent *, unsigned long long, int, int *, int *));
283 #endif /* __SPE__ */
284
285 #else /* no FLOATING_POINT */
286
287 #define BUF 40
288
289 #endif /* FLOATING_POINT */
290
291
292 /*
293 * Macros for converting digits to letters and vice versa
294 */
295 #define to_digit(c) ((c) - '0')
296 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
297 #define to_char(n) ((n) + '0')
298
299 /*
300 * Flags used during conversion.
301 */
302 #define ALT 0x001 /* alternate form */
303 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
304 #define LADJUST 0x004 /* left adjustment */
305 #define LONGDBL 0x008 /* long double */
306 #define LONGINT 0x010 /* long integer */
307 #ifndef _NO_LONGLONG
308 #define QUADINT 0x020 /* quad integer */
309 #else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
310 that %lld behaves the same as %ld, not as %d, as expected if:
311 sizeof (long long) = sizeof long > sizeof int */
312 #define QUADINT LONGINT
313 #endif
314 #define SHORTINT 0x040 /* short integer */
315 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
316 #define FPT 0x100 /* Floating point number */
317 #define VECTOR 0x200 /* vector */
318 #define FIXEDPOINT 0x400 /* fixed-point */
319
320 int
321 _DEFUN (VFPRINTF, (fp, fmt0, ap),
322 FILE * fp _AND
323 _CONST char *fmt0 _AND
324 va_list ap)
325 {
326 CHECK_INIT (_REENT, fp);
327 return _VFPRINTF_R (_REENT, fp, fmt0, ap);
328 }
329
330 int
331 _DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap),
332 struct _reent *data _AND
333 FILE * fp _AND
334 _CONST char *fmt0 _AND
335 va_list ap)
336 {
337 register char *fmt; /* format string */
338 register int ch; /* character from fmt */
339 register int n, m; /* handy integers (short term usage) */
340 register char *cp; /* handy char pointer (short term usage) */
341 register struct __siov *iovp;/* for PRINT macro */
342 register int flags; /* flags as above */
343 int ret; /* return value accumulator */
344 int width; /* width from format (%8d), or 0 */
345 int prec; /* precision from format (%.3d), or -1 */
346 char sign; /* sign prefix (' ', '+', '-', or \0) */
347 char old_sign; /* saved value of sign when looping for vectors */
348 int old_ch; /* saved value of ch when looping for vectors */
349 char *format_anchor; /* start of format to process */
350 wchar_t wc;
351 #ifdef FLOATING_POINT
352 char *decimal_point = localeconv()->decimal_point;
353 char softsign; /* temporary negative sign for floats */
354 #ifdef _NO_LONGDBL
355 union { int i; double d; } _double_ = {0};
356 #define _fpvalue (_double_.d)
357 #else
358 union { int i; _LONG_DOUBLE ld; } _long_double_ = {0};
359 #define _fpvalue (_long_double_.ld)
360 int tmp;
361 #endif
362 int expt; /* integer value of exponent */
363 int expsize = 0; /* character count for expstr */
364 int ndig; /* actual number of digits returned by cvt */
365 char expstr[7]; /* buffer for exponent string */
366 #endif
367
368 #ifndef _NO_LONGLONG
369 #define quad_t long long
370 #define u_quad_t unsigned long long
371 #else
372 #define quad_t long
373 #define u_quad_t u_long
374 #endif
375
376 u_quad_t _uquad; /* integer arguments %[diouxX] */
377 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
378 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
379 int realsz; /* field size expanded by dprec */
380 int size; /* size of converted field or string */
381 char *xdigs = NULL; /* digits for [xX] conversion */
382 #define NIOV 8
383 struct __suio uio; /* output information: summary */
384 struct __siov iov[NIOV];/* ... and individual io vectors */
385 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
386 char ox[2]; /* space for 0x hex-prefix */
387 #ifdef __ALTIVEC__
388 char vec_sep; /* vector separator char */
389 int vec_print_count; /* number of vector chunks remaining */
390 vec_16_byte_union vec_tmp;
391 #endif /* __ALTIVEC__ */
392 mbstate_t state; /* mbtowc calls from library must not change state */
393
394 /*
395 * Choose PADSIZE to trade efficiency vs. size. If larger printf
396 * fields occur frequently, increase PADSIZE and make the initialisers
397 * below longer.
398 */
399 #define PADSIZE 16 /* pad chunk size */
400 static _CONST char blanks[PADSIZE] =
401 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
402 static _CONST char zeroes[PADSIZE] =
403 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
404
405 /*
406 * BEWARE, these `goto error' on error, and PAD uses `n'.
407 */
408 #define PRINT(ptr, len) { \
409 iovp->iov_base = (ptr); \
410 iovp->iov_len = (len); \
411 uio.uio_resid += (len); \
412 iovp++; \
413 if (++uio.uio_iovcnt >= NIOV) { \
414 if (__sprint_r(data, fp, &uio)) \
415 goto error; \
416 iovp = iov; \
417 } \
418 }
419 #define PAD(howmany, with) { \
420 if ((n = (howmany)) > 0) { \
421 while (n > PADSIZE) { \
422 PRINT(with, PADSIZE); \
423 n -= PADSIZE; \
424 } \
425 PRINT(with, n); \
426 } \
427 }
428 #define FLUSH() { \
429 if (uio.uio_resid && __sprint_r(data, fp, &uio)) \
430 goto error; \
431 uio.uio_iovcnt = 0; \
432 iovp = iov; \
433 }
434
435 #ifdef __ALTIVEC__
436 #define GET_SHORT(ap) \
437 (flags&VECTOR ? \
438 (vec_print_count < 8 ? (short)vec_tmp.s[8 - vec_print_count] : \
439 (vec_tmp.v = va_arg(ap, vector int), (short)vec_tmp.s[0])) : \
440 (short)va_arg(ap, int))
441 #define GET_USHORT(ap) \
442 (flags&VECTOR ? \
443 (vec_print_count < 8 ? (u_short)vec_tmp.s[8 - vec_print_count] : \
444 (vec_tmp.v = va_arg(ap, vector int), (u_short)vec_tmp.s[0])) : \
445 (u_short)va_arg(ap, int))
446
447 #define GET_LONG(ap) \
448 (flags&VECTOR ? \
449 (vec_print_count < 4 ? (long)vec_tmp.l[4 - vec_print_count] : \
450 (vec_tmp.v = va_arg(ap, vector int), vec_tmp.l[0])) : \
451 va_arg(ap, long int))
452 #define GET_ULONG(ap) \
453 (flags&VECTOR ? \
454 (vec_print_count < 4 ? (u_long)vec_tmp.l[4 - vec_print_count] : \
455 (vec_tmp.v = va_arg(ap, vector int), (u_long)vec_tmp.l[0])) : \
456 (u_long)va_arg(ap, unsigned long int))
457
458 #define GET_INT(ap) \
459 (flags&VECTOR ? \
460 (vec_print_count < 16 ? \
461 vec_tmp.c[16 - vec_print_count] : \
462 (vec_tmp.v = va_arg(ap, vector int), (int)vec_tmp.c[0])) : \
463 va_arg(ap, int))
464 #define GET_UINT(ap) \
465 (flags&VECTOR ? \
466 (vec_print_count < 16 ? \
467 (u_int)((unsigned char)vec_tmp.c[16 - vec_print_count]) : \
468 (vec_tmp.v = va_arg(ap, vector int), (u_int)((unsigned char)vec_tmp.c[0]))) : \
469 (u_int)va_arg(ap, unsigned int))
470 #else /* !__ALTIVEC__ */
471 #define GET_SHORT(ap) ((short)va_arg(ap, int))
472 #define GET_USHORT(ap) ((u_short)va_arg(ap, int))
473 #define GET_LONG(ap) (va_arg(ap, long int))
474 #define GET_ULONG(ap) ((u_long)va_arg(ap, unsigned long int))
475 #define GET_INT(ap) ((int)va_arg(ap, int))
476 #define GET_UINT(ap) ((u_int)va_arg(ap, unsigned int))
477 #endif /* !__ALTIVEC__ */
478
479 #ifndef _NO_LONGLONG
480 #define SARG() \
481 (flags&QUADINT ? va_arg(ap, quad_t) : \
482 flags&LONGINT ? GET_LONG(ap) : \
483 flags&SHORTINT ? (long)GET_SHORT(ap) : \
484 (long)GET_INT(ap))
485 #define UARG() \
486 (flags&QUADINT ? va_arg(ap, u_quad_t) : \
487 flags&LONGINT ? GET_ULONG(ap) : \
488 flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
489 (u_long)GET_UINT(ap))
490 #ifdef __SPE__
491 #define SFPARG() \
492 (flags&LONGINT ? va_arg(ap, quad_t) : \
493 flags&SHORTINT ? (long)GET_SHORT(ap) : \
494 (long)va_arg(ap, int))
495 #define UFPARG() \
496 (flags&LONGINT ? va_arg(ap, u_quad_t) : \
497 flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
498 (u_long)va_arg(ap, u_int))
499 #endif /* __SPE__ */
500 #else
501 #define SARG() \
502 (flags&LONGINT ? GET_LONG(ap) : \
503 flags&SHORTINT ? (long)GET_SHORT(ap) : \
504 (long)GET_INT(ap))
505 #define UARG() \
506 (flags&LONGINT ? GET_ULONG(ap) : \
507 flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
508 (u_long)GET_UINT(ap))
509 #ifdef __SPE__
510 #define SFPARG() \
511 (flags&LONGINT ? (va_arg(ap, long) << 32) : \
512 flags&SHORTINT ? (long)GET_SHORT(ap) : \
513 (long)va_arg(ap, int))
514 #define UFPARG() \
515 (flags&LONGINT ? (va_arg(ap, u_long) <<32) : \
516 flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
517 (u_long)va_arg(ap, u_int))
518 #endif /* __SPE__ */
519 #endif
520
521 memset (&state, '\0', sizeof (state));
522
523 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
524 if (cantwrite (data, fp)) {
525 _funlockfile (fp);
526 return (EOF);
527 }
528
529 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
530 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
531 fp->_file >= 0)
532 return (__sbprintf_r(data, fp, fmt0, ap));
533
534 fmt = (char *)fmt0;
535 uio.uio_iov = iovp = iov;
536 uio.uio_resid = 0;
537 uio.uio_iovcnt = 0;
538 ret = 0;
539
540 /*
541 * Scan the format for conversions (`%' character).
542 */
543
544 for (;;) {
545 cp = fmt;
546 while ((n = _mbtowc_r(data, &wc, fmt, MB_CUR_MAX, &state)) > 0) {
547 fmt += n;
548 if (wc == '%') {
549 fmt--;
550 break;
551 }
552 }
553 if ((m = fmt - cp) != 0) {
554 PRINT(cp, m);
555 ret += m;
556 }
557 if (n <= 0)
558 goto done;
559 fmt++; /* skip over '%' */
560
561 flags = 0;
562 dprec = 0;
563 width = 0;
564 prec = -1;
565 sign = '\0';
566 old_sign = '\0';
567 #ifdef __ALTIVEC__
568 vec_print_count = 0;
569 vec_sep = ' ';
570 #endif /* __ALTIVEC__ */
571
572 format_anchor = fmt;
573 rflag: ch = *fmt++;
574 old_ch = ch;
575 reswitch: switch (ch) {
576 case ' ':
577 /*
578 * ``If the space and + flags both appear, the space
579 * flag will be ignored.''
580 * -- ANSI X3J11
581 */
582 if (!sign)
583 sign = ' ';
584 goto rflag;
585 case '#':
586 flags |= ALT;
587 goto rflag;
588 case '*':
589 /*
590 * ``A negative field width argument is taken as a
591 * - flag followed by a positive field width.''
592 * -- ANSI X3J11
593 * They don't exclude field widths read from args.
594 */
595 if ((width = va_arg(ap, int)) >= 0)
596 goto rflag;
597 width = -width;
598 /* FALLTHROUGH */
599 case '-':
600 flags |= LADJUST;
601 goto rflag;
602 case '+':
603 sign = '+';
604 goto rflag;
605 #ifdef __ALTIVEC__
606 case ',':
607 case ';':
608 case ':':
609 case '_':
610 if (vec_sep != ' ')
611 {
612 fmt = format_anchor;
613 continue;
614 }
615 vec_sep = ch;
616 goto rflag;
617 #endif /* __ALTIVEC__ */
618 case '.':
619 if ((ch = *fmt++) == '*') {
620 n = va_arg(ap, int);
621 prec = n < 0 ? -1 : n;
622 goto rflag;
623 }
624 n = 0;
625 while (is_digit(ch)) {
626 n = 10 * n + to_digit(ch);
627 ch = *fmt++;
628 }
629 prec = n < 0 ? -1 : n;
630 goto reswitch;
631 case '0':
632 /*
633 * ``Note that 0 is taken as a flag, not as the
634 * beginning of a field width.''
635 * -- ANSI X3J11
636 */
637 flags |= ZEROPAD;
638 goto rflag;
639 case '1': case '2': case '3': case '4':
640 case '5': case '6': case '7': case '8': case '9':
641 n = 0;
642 do {
643 n = 10 * n + to_digit(ch);
644 ch = *fmt++;
645 } while (is_digit(ch));
646 width = n;
647 goto reswitch;
648 #ifdef FLOATING_POINT
649 case 'L':
650 #ifdef __ALTIVEC__
651 if (flags & VECTOR)
652 {
653 fmt = format_anchor;
654 continue;
655 }
656 #endif /* __ALTIVEC__ */
657 flags |= LONGDBL;
658 goto rflag;
659 #endif
660 case 'h':
661 if (flags & LONGINT)
662 {
663 fmt = format_anchor;
664 continue;
665 }
666 flags |= SHORTINT;
667 #ifdef __ALTIVEC__
668 if (flags & VECTOR)
669 vec_print_count = 8;
670 #endif
671 goto rflag;
672 case 'l':
673 if (flags & SHORTINT)
674 {
675 fmt = format_anchor;
676 continue;
677 }
678 if (*fmt == 'l') {
679 fmt++;
680 flags |= QUADINT;
681 flags &= ~VECTOR;
682 } else {
683 flags |= LONGINT;
684 #ifdef __ALTIVEC__
685 if (flags & VECTOR)
686 vec_print_count = 4;
687 #endif
688 }
689 goto rflag;
690 #ifdef __ALTIVEC__
691 case 'v':
692 if (flags & VECTOR)
693 {
694 fmt = format_anchor;
695 continue;
696 }
697 flags |= VECTOR;
698 vec_print_count = (flags & SHORTINT) ? 8 :
699 ((flags & LONGINT) ? 4 : 16);
700 goto rflag;
701 #endif
702 case 'q':
703 #ifdef __ALTIVEC__
704 if (flags & VECTOR)
705 {
706 fmt = format_anchor;
707 continue;
708 }
709 #endif /* __ALTIVEC__ */
710 flags |= QUADINT;
711 goto rflag;
712 case 'c':
713 #ifdef __ALTIVEC__
714 if (flags & VECTOR)
715 {
716 int k;
717 vec_16_byte_union tmp;
718 if (flags & (SHORTINT | LONGINT))
719 {
720 fmt = format_anchor;
721 continue;
722 }
723 tmp.v = va_arg(ap, vector int);
724 cp = buf;
725 for (k = 0; k < 15; ++k)
726 {
727 *cp++ = tmp.c[k];
728 if (vec_sep != ' ')
729 *cp++ = vec_sep;
730 }
731 *cp++ = tmp.c[15];
732 size = cp - buf;
733 cp = buf;
734 vec_print_count = 0;
735 }
736 else
737 #endif /* __ALTIVEC__ */
738 {
739 *(cp = buf) = va_arg(ap, int);
740 size = 1;
741 }
742 sign = '\0';
743 break;
744 case 'D':
745 flags |= LONGINT;
746 /*FALLTHROUGH*/
747 case 'd':
748 case 'i':
749 #ifdef __ALTIVEC__
750 if (!(flags & VECTOR) && vec_sep != ' ')
751 {
752 fmt = format_anchor;
753 continue;
754 }
755 #endif /* __ALTIVEC__ */
756 _uquad = SARG();
757 if ((quad_t)_uquad < 0)
758 {
759 _uquad = -(quad_t)_uquad;
760 old_sign = sign;
761 sign = '-';
762 }
763 base = DEC;
764 goto number;
765 #ifdef FLOATING_POINT
766 case 'e':
767 case 'E':
768 case 'f':
769 case 'g':
770 case 'G':
771 if (prec == -1) {
772 prec = DEFPREC;
773 } else if ((ch == 'g' || ch == 'G') && prec == 0) {
774 prec = 1;
775 }
776
777 #ifdef _NO_LONGDBL
778 if (flags & LONGDBL) {
779 _fpvalue = (double) va_arg(ap, _LONG_DOUBLE);
780 #ifdef __ALTIVEC__
781 } else if (flags & VECTOR) {
782 if (vec_print_count >= 4)
783 {
784 vec_print_count = 4;
785 vec_tmp.v = va_arg(ap, vector int);
786 }
787 _fpvalue = (double)vec_tmp.f[4 - vec_print_count];
788 } else if (vec_sep != ' ') {
789 fmt = format_anchor;
790 continue;
791
792 #endif /* __ALTIVEC__ */
793 } else {
794 _fpvalue = va_arg(ap, double);
795 }
796
797 /* do this before tricky precision changes */
798 if (isinf(_fpvalue)) {
799 if (_fpvalue < 0)
800 {
801 old_sign = sign;
802 sign = '-';
803 }
804
805 cp = "Inf";
806 size = 3;
807 break;
808 }
809 if (isnan(_fpvalue)) {
810 cp = "NaN";
811 size = 3;
812 break;
813 }
814
815 #else /* !_NO_LONGDBL */
816
817 if (flags & LONGDBL) {
818 _fpvalue = va_arg(ap, _LONG_DOUBLE);
819 #ifdef __ALTIVEC__
820 } else if (flags & VECTOR) {
821 if (vec_print_count >= 4)
822 {
823 vec_print_count = 4;
824 vec_tmp.v = va_arg(ap, vector int);
825 }
826 _fpvalue = (_LONG_DOUBLE)k.f[4 - vec_print_count];
827 #endif /* __ALTIVEC__ */
828 } else {
829 _fpvalue = (_LONG_DOUBLE)va_arg(ap, double);
830 }
831
832 /* do this before tricky precision changes */
833 tmp = _ldcheck (&_fpvalue);
834 if (tmp == 2) {
835 if (_fpvalue < 0)
836 {
837 old_sign = sign;
838 sign = '-';
839 }
840 cp = "Inf";
841 size = 3;
842 break;
843 }
844 if (tmp == 1) {
845 cp = "NaN";
846 size = 3;
847 break;
848 }
849 #endif /* !_NO_LONGDBL */
850
851 flags |= FPT;
852
853 cp = cvt(data, _fpvalue, prec, flags, &softsign,
854 &expt, ch, &ndig);
855
856 if (ch == 'g' || ch == 'G') {
857 if (expt <= -4 || expt > prec)
858 {
859 old_ch = ch;
860 ch = (ch == 'g') ? 'e' : 'E';
861 }
862 else
863 ch = 'g';
864 }
865 if (ch <= 'e') { /* 'e' or 'E' fmt */
866 --expt;
867 expsize = exponent(expstr, expt, ch);
868 size = expsize + ndig;
869 if (ndig > 1 || flags & ALT)
870 ++size;
871 } else if (ch == 'f') { /* f fmt */
872 if (expt > 0) {
873 size = expt;
874 if (prec || flags & ALT)
875 size += prec + 1;
876 } else /* "0.X" */
877 size = (prec || flags & ALT)
878 ? prec + 2
879 : 1;
880 } else if (expt >= ndig) { /* fixed g fmt */
881 size = expt;
882 if (flags & ALT)
883 ++size;
884 } else
885 size = ndig + (expt > 0 ?
886 1 : 2 - expt);
887
888 if (softsign)
889 {
890 old_sign = sign;
891 sign = '-';
892 }
893 break;
894 #endif /* FLOATING_POINT */
895 #ifdef __SPE__
896 case 'r':
897 flags |= FIXEDPOINT;
898 _uquad = SFPARG();
899 if ((quad_t)_uquad < 0)
900 {
901 sign = '-';
902 _uquad = -(quad_t)_uquad;
903 }
904 if (flags & SHORTINT)
905 _uquad <<= (sizeof(quad_t) - sizeof(short)) * 8 + 1;
906 else if (flags & LONGINT)
907 _uquad <<= 1;
908 else
909 _uquad <<= (sizeof(quad_t) - sizeof(long)) * 8 + 1;
910
911 if (_uquad == 0 && sign)
912 {
913 /* we have -1.0 which has to be handled special */
914 cp = "100000";
915 expt = 1;
916 ndig = 6;
917 break;
918 }
919
920 goto fixed_nosign;
921 case 'R':
922 flags |= FIXEDPOINT;
923 _uquad = UFPARG();
924 if (flags & SHORTINT)
925 _uquad <<= (sizeof(quad_t) - sizeof(short)) * 8;
926 else if (!(flags & LONGINT))
927 _uquad <<= (sizeof(quad_t) - sizeof(long)) * 8;
928
929 fixed_nosign:
930 if (prec == -1)
931 prec = DEFPREC;
932
933 #ifndef _NO_LONGLONG
934 cp = cvt_ufix64 (data, _uquad, prec, &expt, &ndig);
935 #else
936 cp = cvs_ufix32 (data, _uquad, prec, &expt, &ndig);
937 #endif
938
939 /* act like %f of format "0.X" */
940 size = prec + 2;
941
942 break;
943 #endif /* __SPE__ */
944 case 'n':
945 #ifdef __ALTIVEC__
946 if (flags & VECTOR)
947 {
948 fmt = format_anchor;
949 continue;
950 }
951 #endif /* __ALTIVEC__ */
952 #ifndef _NO_LONGLONG
953 if (flags & QUADINT)
954 *va_arg(ap, quad_t *) = ret;
955 else
956 #endif
957 if (flags & LONGINT)
958 *va_arg(ap, long *) = ret;
959 else if (flags & SHORTINT)
960 *va_arg(ap, short *) = ret;
961 else
962 *va_arg(ap, int *) = ret;
963 continue; /* no output */
964 case 'O':
965 flags |= LONGINT;
966 /*FALLTHROUGH*/
967 case 'o':
968 #ifdef __ALTIVEC__
969 if (!(flags & VECTOR) && vec_sep != ' ')
970 {
971 fmt = format_anchor;
972 continue;
973 }
974 #endif /* __ALTIVEC__ */
975 _uquad = UARG();
976 base = OCT;
977 goto nosign;
978 case 'p':
979 /*
980 * ``The argument shall be a pointer to void. The
981 * value of the pointer is converted to a sequence
982 * of printable characters, in an implementation-
983 * defined manner.''
984 * -- ANSI X3J11
985 */
986 /* NOSTRICT */
987 #ifdef __ALTIVEC__
988 if (flags & VECTOR)
989 _uquad = UARG();
990 else if (vec_sep != ' ')
991 {
992 fmt = format_anchor;
993 continue;
994 }
995 else
996 #endif /* __ALTIVEC__ */
997 _uquad = (u_long)(unsigned _POINTER_INT)va_arg(ap, void *);
998 base = HEX;
999 xdigs = "0123456789abcdef";
1000 flags |= HEXPREFIX;
1001 ch = 'x';
1002 goto nosign;
1003 case 's':
1004 #ifdef __ALTIVEC__
1005 if (flags & VECTOR)
1006 {
1007 fmt = format_anchor;
1008 continue;
1009 }
1010 #endif /* __ALTIVEC__ */
1011 if ((cp = va_arg(ap, char *)) == NULL)
1012 cp = "(null)";
1013 if (prec >= 0) {
1014 /*
1015 * can't use strlen; can only look for the
1016 * NUL in the first `prec' characters, and
1017 * strlen() will go further.
1018 */
1019 char *p = memchr(cp, 0, prec);
1020
1021 if (p != NULL) {
1022 size = p - cp;
1023 if (size > prec)
1024 size = prec;
1025 } else
1026 size = prec;
1027 } else
1028 size = strlen(cp);
1029 sign = '\0';
1030 break;
1031 case 'U':
1032 flags |= LONGINT;
1033 /*FALLTHROUGH*/
1034 case 'u':
1035 #ifdef __ALTIVEC__
1036 if (!(flags & VECTOR) && vec_sep != ' ')
1037 {
1038 fmt = format_anchor;
1039 continue;
1040 }
1041 #endif /* __ALTIVEC__ */
1042 _uquad = UARG();
1043 base = DEC;
1044 goto nosign;
1045 case 'X':
1046 xdigs = "0123456789ABCDEF";
1047 goto hex;
1048 case 'x':
1049 xdigs = "0123456789abcdef";
1050 #ifdef __ALTIVEC__
1051 if (!(flags & VECTOR) && vec_sep != ' ')
1052 {
1053 fmt = format_anchor;
1054 continue;
1055 }
1056 #endif /* __ALTIVEC__ */
1057 hex: _uquad = UARG();
1058 base = HEX;
1059 /* leading 0x/X only if non-zero */
1060 if (flags & ALT && _uquad != 0)
1061 flags |= HEXPREFIX;
1062
1063 /* unsigned conversions */
1064 nosign: sign = '\0';
1065 /*
1066 * ``... diouXx conversions ... if a precision is
1067 * specified, the 0 flag will be ignored.''
1068 * -- ANSI X3J11
1069 */
1070 number: if ((dprec = prec) >= 0)
1071 flags &= ~ZEROPAD;
1072
1073 /*
1074 * ``The result of converting a zero value with an
1075 * explicit precision of zero is no characters.''
1076 * -- ANSI X3J11
1077 */
1078 cp = buf + BUF;
1079 if (_uquad != 0 || prec != 0) {
1080 /*
1081 * Unsigned mod is hard, and unsigned mod
1082 * by a constant is easier than that by
1083 * a variable; hence this switch.
1084 */
1085 switch (base) {
1086 case OCT:
1087 do {
1088 *--cp = to_char(_uquad & 7);
1089 _uquad >>= 3;
1090 } while (_uquad);
1091 /* handle octal leading 0 */
1092 if (flags & ALT && *cp != '0')
1093 *--cp = '0';
1094 break;
1095
1096 case DEC:
1097 /* many numbers are 1 digit */
1098 while (_uquad >= 10) {
1099 *--cp = to_char(_uquad % 10);
1100 _uquad /= 10;
1101 }
1102 *--cp = to_char(_uquad);
1103 break;
1104
1105 case HEX:
1106 do {
1107 *--cp = xdigs[_uquad & 15];
1108 _uquad >>= 4;
1109 } while (_uquad);
1110 break;
1111
1112 default:
1113 cp = "bug in vfprintf: bad base";
1114 size = strlen(cp);
1115 goto skipsize;
1116 }
1117 }
1118 /*
1119 * ...result is to be converted to an 'alternate form'.
1120 * For o conversion, it increases the precision to force
1121 * the first digit of the result to be a zero."
1122 * -- ANSI X3J11
1123 *
1124 * To demonstrate this case, compile and run:
1125 * printf ("%#.0o",0);
1126 */
1127 else if (base == OCT && (flags & ALT))
1128 *--cp = '0';
1129
1130 size = buf + BUF - cp;
1131 skipsize:
1132 break;
1133 default: /* "%?" prints ?, unless ? is NUL */
1134 flags &= ~VECTOR;
1135 if (ch == '\0')
1136 goto done;
1137 /* pretend it was %c with argument ch */
1138 cp = buf;
1139 *cp = ch;
1140 size = 1;
1141 sign = '\0';
1142 break;
1143 }
1144
1145 /*
1146 * All reasonable formats wind up here. At this point, `cp'
1147 * points to a string which (if not flags&LADJUST) should be
1148 * padded out to `width' places. If flags&ZEROPAD, it should
1149 * first be prefixed by any sign or other prefix; otherwise,
1150 * it should be blank padded before the prefix is emitted.
1151 * After any left-hand padding and prefixing, emit zeroes
1152 * required by a decimal [diouxX] precision, then print the
1153 * string proper, then emit zeroes required by any leftover
1154 * floating precision; finally, if LADJUST, pad with blanks.
1155 *
1156 * Compute actual size, so we know how much to pad.
1157 * size excludes decimal prec; realsz includes it.
1158 */
1159 realsz = dprec > size ? dprec : size;
1160 if (sign)
1161 realsz++;
1162 else if (flags & HEXPREFIX)
1163 realsz+= 2;
1164
1165 /* right-adjusting blank padding */
1166 if ((flags & (LADJUST|ZEROPAD)) == 0)
1167 PAD(width - realsz, blanks);
1168
1169 /* prefix */
1170 if (sign) {
1171 PRINT(&sign, 1);
1172 } else if (flags & HEXPREFIX) {
1173 ox[0] = '0';
1174 ox[1] = ch;
1175 PRINT(ox, 2);
1176 }
1177
1178 /* right-adjusting zero padding */
1179 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1180 PAD(width - realsz, zeroes);
1181
1182 /* leading zeroes from decimal precision */
1183 PAD(dprec - size, zeroes);
1184
1185 /* the string or number proper */
1186 #ifdef FLOATING_POINT
1187 if ((flags & FPT) == 0) {
1188 #ifdef __SPE__
1189 if (flags & FIXEDPOINT) {
1190 if (_uquad == 0 && !sign) {
1191 /* kludge for __dtoa irregularity */
1192 PRINT("0", 1);
1193 if (expt < ndig || (flags & ALT) != 0) {
1194 PRINT(decimal_point, 1);
1195 PAD(ndig - 1, zeroes);
1196 }
1197 } else if (expt <= 0) {
1198 PRINT("0", 1);
1199 if(expt || ndig) {
1200 PRINT(decimal_point, 1);
1201 PAD(-expt, zeroes);
1202 PRINT(cp, ndig);
1203 }
1204 } else if (expt >= ndig) {
1205 PRINT(cp, ndig);
1206 PAD(expt - ndig, zeroes);
1207 if (flags & ALT)
1208 PRINT(".", 1);
1209 } else {
1210 PRINT(cp, expt);
1211 cp += expt;
1212 PRINT(".", 1);
1213 PRINT(cp, ndig-expt);
1214 }
1215 } else
1216 #endif /* __SPE__ */
1217 PRINT(cp, size);
1218 } else { /* glue together f_p fragments */
1219 if (ch >= 'f') { /* 'f' or 'g' */
1220 if (_fpvalue == 0) {
1221 /* kludge for __dtoa irregularity */
1222 PRINT("0", 1);
1223 if (expt < ndig || (flags & ALT) != 0) {
1224 PRINT(decimal_point, 1);
1225 PAD(ndig - 1, zeroes);
1226 }
1227 } else if (expt <= 0) {
1228 PRINT("0", 1);
1229 if(expt || ndig) {
1230 PRINT(decimal_point, 1);
1231 PAD(-expt, zeroes);
1232 PRINT(cp, ndig);
1233 }
1234 } else if (expt >= ndig) {
1235 PRINT(cp, ndig);
1236 PAD(expt - ndig, zeroes);
1237 if (flags & ALT)
1238 PRINT(".", 1);
1239 } else {
1240 PRINT(cp, expt);
1241 cp += expt;
1242 PRINT(".", 1);
1243 PRINT(cp, ndig-expt);
1244 }
1245 } else { /* 'e' or 'E' */
1246 if (ndig > 1 || flags & ALT) {
1247 ox[0] = *cp++;
1248 ox[1] = '.';
1249 PRINT(ox, 2);
1250 if (_fpvalue) {
1251 PRINT(cp, ndig-1);
1252 } else /* 0.[0..] */
1253 /* __dtoa irregularity */
1254 PAD(ndig - 1, zeroes);
1255 } else /* XeYYY */
1256 PRINT(cp, 1);
1257 PRINT(expstr, expsize);
1258 }
1259 }
1260 #else
1261 PRINT(cp, size);
1262 #endif
1263 /* left-adjusting padding (always blank) */
1264 if (flags & LADJUST)
1265 PAD(width - realsz, blanks);
1266
1267 /* finally, adjust ret */
1268 ret += width > realsz ? width : realsz;
1269
1270 #ifdef __ALTIVEC__
1271 if ((flags & VECTOR) && vec_print_count-- > 1)
1272 {
1273 /* add vector separator */
1274 if (ch != 'c' || vec_sep != ' ')
1275 {
1276 PRINT(&vec_sep, 1);
1277 ret += 1;
1278 }
1279 FLUSH();
1280 sign = old_sign;
1281 ch = old_ch;
1282 goto reswitch;
1283 }
1284 #endif /* __ALTIVEC__ */
1285 FLUSH(); /* copy out the I/O vectors */
1286 }
1287 done:
1288 FLUSH();
1289 error:
1290 return (__sferror(fp) ? EOF : ret);
1291 /* NOTREACHED */
1292 }
1293
1294 #ifdef FLOATING_POINT
1295
1296 #ifdef _NO_LONGDBL
1297 extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
1298 int, int *, int *, char **));
1299 #else
1300 extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
1301 int, int *, int *, char **));
1302 #undef word0
1303 #define word0(x) ldword0(x)
1304 #endif
1305
1306 static char *
cvt(data,value,ndigits,flags,sign,decpt,ch,length)1307 cvt(data, value, ndigits, flags, sign, decpt, ch, length)
1308 struct _reent *data;
1309 #ifdef _NO_LONGDBL
1310 double value;
1311 #else
1312 _LONG_DOUBLE value;
1313 #endif
1314 int ndigits, flags, *decpt, ch, *length;
1315 char *sign;
1316 {
1317 int mode, dsgn;
1318 char *digits, *bp, *rve;
1319 #ifdef _NO_LONGDBL
1320 union double_union tmp;
1321 #else
1322 struct ldieee *ldptr;
1323 #endif
1324
1325 if (ch == 'f') {
1326 mode = 3; /* ndigits after the decimal point */
1327 } else {
1328 /* To obtain ndigits after the decimal point for the 'e'
1329 * and 'E' formats, round to ndigits + 1 significant
1330 * figures.
1331 */
1332 if (ch == 'e' || ch == 'E') {
1333 ndigits++;
1334 }
1335 mode = 2; /* ndigits significant digits */
1336 }
1337
1338 #ifdef _NO_LONGDBL
1339 tmp.d = value;
1340
1341 if (word0(tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
1342 value = -value;
1343 *sign = '-';
1344 } else
1345 *sign = '\000';
1346
1347 digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
1348 #else /* !_NO_LONGDBL */
1349 ldptr = (struct ldieee *)&value;
1350 if (ldptr->sign) { /* this will check for < 0 and -0.0 */
1351 value = -value;
1352 *sign = '-';
1353 } else
1354 *sign = '\000';
1355
1356 digits = _ldtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
1357 #endif /* !_NO_LONGDBL */
1358
1359 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
1360 bp = digits + ndigits;
1361 if (ch == 'f') {
1362 if (*digits == '0' && value)
1363 *decpt = -ndigits + 1;
1364 bp += *decpt;
1365 }
1366 if (value == 0) /* kludge for __dtoa irregularity */
1367 rve = bp;
1368 while (rve < bp)
1369 *rve++ = '0';
1370 }
1371 *length = rve - digits;
1372 return (digits);
1373 }
1374
1375 static int
exponent(p0,exp,fmtch)1376 exponent(p0, exp, fmtch)
1377 char *p0;
1378 int exp, fmtch;
1379 {
1380 register char *p, *t;
1381 char expbuf[40];
1382
1383 p = p0;
1384 *p++ = fmtch;
1385 if (exp < 0) {
1386 exp = -exp;
1387 *p++ = '-';
1388 }
1389 else
1390 *p++ = '+';
1391 t = expbuf + 40;
1392 if (exp > 9) {
1393 do {
1394 *--t = to_char(exp % 10);
1395 } while ((exp /= 10) > 9);
1396 *--t = to_char(exp);
1397 for (; t < expbuf + 40; *p++ = *t++);
1398 }
1399 else {
1400 *p++ = '0';
1401 *p++ = to_char(exp);
1402 }
1403 return (p - p0);
1404 }
1405 #endif /* FLOATING_POINT */
1406
1407 #ifdef __SPE__
1408 extern char *_ufix64toa_r _PARAMS((struct _reent *, unsigned long long, int,
1409 int, int *, int *, char **));
1410 static char *
cvt_ufix64(data,value,ndigits,decpt,length)1411 cvt_ufix64 (data, value, ndigits, decpt, length)
1412 struct _reent *data;
1413 unsigned long long value;
1414 int ndigits, *decpt, *length;
1415 {
1416 int dsgn;
1417 char *digits, *bp, *rve;
1418
1419 /* treat the same as %f format and use mode=3 */
1420 digits = _ufix64toa_r (data, value, 3, ndigits, decpt, &dsgn, &rve);
1421
1422 /* print trailing zeroes */
1423 bp = digits + ndigits;
1424 if (*digits == '0' && value)
1425 *decpt = -ndigits + 1;
1426 bp += *decpt;
1427 if (value == 0) /* kludge for __dtoa irregularity */
1428 rve = bp;
1429 while (rve < bp)
1430 *rve++ = '0';
1431 *length = rve - digits;
1432 return (digits);
1433 }
1434 #endif /* __SPE__ */
1435