OSDN Git Service

Fix a bug: Could not extract 2G over files.
[lha/lha.git] / src / vsnprintf.c
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 /*
38  * IMPORTANT NOTE:
39  * --------------
40  * From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
41  * paragraph 3 above is now null and void.
42  */
43
44 /* SNPRINTF.C  
45  * fjc 7-31-97 Modified by Mib Software to be a standalone snprintf.c module.
46  *      http://www.mibsoftware.com
47  * Mib Software does not warrant this software any differently than the
48  * University of California, Berkeley as described above.  All warranties
49  * are disclaimed.  Use this software at your own risk.
50  *
51  *      All code referencing FILE * functions was eliminated, since it could
52  *      never be called.  All header files and necessary files are collapsed
53  *      into one file, internal functions are declared static.  This should
54  *      allow inclusion into libraries with less chance of namespace collisions.
55  *
56  *      snprintf should be the only externally visible item.
57  *     
58  *      As of 7-31-97 FLOATING_POINT is NOT provided.  The code is somewhat
59  *        non-portable, so it is disabled.
60  */
61
62 /* Define FLOATING_POINT to get floating point. */
63 /*
64 #define FLOATING_POINT
65 */
66
67 #include <sys/types.h>
68 #define u_long unsigned long
69 #define u_short unsigned short
70 #define u_int unsigned int
71
72 #undef __P
73 #if defined(__STDC__)
74 # include <stdarg.h>
75 # if !defined(__P)
76 #  define __P(x) x
77 # endif
78 #else
79 # define __P(x) ()
80 # if !defined(const)
81 #  define const
82 # endif
83 # include <varargs.h>
84 #endif
85 #ifndef _BSD_VA_LIST_ 
86 #define _BSD_VA_LIST_ va_list
87 #endif
88
89 #ifdef __STDC__
90 # include <limits.h>
91 #else
92 # ifndef LONG_MAX
93 #  ifdef HAVE_LIMITS_H
94 #   include <limits.h>
95 #  else
96     /* assuming 32bit(2's compliment) long */
97 #   define LONG_MAX 2147483647
98 #  endif
99 # endif
100 #endif
101
102 #if defined(__hpux) && !defined(__GNUC__)
103 #define const
104 #endif
105
106 #if defined(sgi)
107 #undef __const
108 #define __const
109 #endif /* People who don't like const sys_error */
110
111 #include <stddef.h>
112
113 #ifndef NULL
114 #define NULL    0
115 #endif
116
117 /*
118  * NB: to fit things in six character monocase externals, the stdio
119  * code uses the prefix `__s' for stdio objects, typically followed
120  * by a three-character attempt at a mnemonic.
121  */
122
123 /* stdio buffers */
124 struct __sbuf {
125         unsigned char *_base;
126         int     _size;
127 };
128
129
130 /*
131  * stdio state variables.
132  *
133  * The following always hold:
134  *
135  *      if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
136  *              _lbfsize is -_bf._size, else _lbfsize is 0
137  *      if _flags&__SRD, _w is 0
138  *      if _flags&__SWR, _r is 0
139  *
140  * This ensures that the getc and putc macros (or inline functions) never
141  * try to write or read from a file that is in `read' or `write' mode.
142  * (Moreover, they can, and do, automatically switch from read mode to
143  * write mode, and back, on "r+" and "w+" files.)
144  *
145  * _lbfsize is used only to make the inline line-buffered output stream
146  * code as compact as possible.
147  *
148  * _ub, _up, and _ur are used when ungetc() pushes back more characters
149  * than fit in the current _bf, or when ungetc() pushes back a character
150  * that does not match the previous one in _bf.  When this happens,
151  * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
152  * _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
153  *
154  * NB: see WARNING above before changing the layout of this structure!
155  */
156 typedef struct __sFILE {
157         unsigned char *_p;      /* current position in (some) buffer */
158         int     _r;             /* read space left for getc() */
159         int     _w;             /* write space left for putc() */
160         short   _flags;         /* flags, below; this FILE is free if 0 */
161         short   _file;          /* fileno, if Unix descriptor, else -1 */
162         struct  __sbuf _bf;     /* the buffer (at least 1 byte, if !NULL) */
163         int     _lbfsize;       /* 0 or -_bf._size, for inline putc */
164 } FILE;
165
166
167 #define __SLBF  0x0001          /* line buffered */
168 #define __SNBF  0x0002          /* unbuffered */
169 #define __SRD   0x0004          /* OK to read */
170 #define __SWR   0x0008          /* OK to write */
171         /* RD and WR are never simultaneously asserted */
172 #define __SRW   0x0010          /* open for reading & writing */
173 #define __SEOF  0x0020          /* found EOF */
174 #define __SERR  0x0040          /* found error */
175 #define __SMBF  0x0080          /* _buf is from malloc */
176 #define __SAPP  0x0100          /* fdopen()ed in append mode */
177 #define __SSTR  0x0200          /* this is an sprintf/snprintf string */
178 #define __SOPT  0x0400          /* do fseek() optimisation */
179 #define __SNPT  0x0800          /* do not do fseek() optimisation */
180 #define __SOFF  0x1000          /* set iff _offset is in fact correct */
181 #define __SMOD  0x2000          /* true => fgetln modified _p text */
182
183
184 #define EOF     (-1)
185
186
187 #define __sfeof(p)      (((p)->_flags & __SEOF) != 0)
188 #define __sferror(p)    (((p)->_flags & __SERR) != 0)
189 #define __sclearerr(p)  ((void)((p)->_flags &= ~(__SERR|__SEOF)))
190 #define __sfileno(p)    ((p)->_file)
191
192 #define feof(p)         __sfeof(p)
193 #define ferror(p)       __sferror(p)
194 #define clearerr(p)     __sclearerr(p)
195
196 #ifndef _ANSI_SOURCE
197 #define fileno(p)       __sfileno(p)
198 #endif
199
200
201 #if defined(__hpux) && !defined(__GNUC__) || defined(__DECC) || defined(__DJGPP__)
202 #include <string.h>
203 #endif
204
205 /*
206  * I/O descriptors for __sfvwrite().
207  */
208 struct __siov {
209         void    *iov_base;
210         size_t  iov_len;
211 };
212 struct __suio {
213         struct  __siov *uio_iov;
214         int     uio_iovcnt;
215         int     uio_resid;
216 };
217
218 /*
219  * Write some memory regions.  Return zero on success, EOF on error.
220  *
221  * This routine is large and unsightly, but most of the ugliness due
222  * to the three different kinds of output buffering is handled here.
223  */
224 static BSD__sfvwrite(fp, uio)
225         register FILE *fp;
226         register struct __suio *uio;
227 {
228         register size_t len;
229         register char *p;
230         register struct __siov *iov;
231         register int w;
232
233         if ((len = uio->uio_resid) == 0)
234                 return (0);
235 #ifndef __hpux
236 #define MIN(a, b) ((a) < (b) ? (a) : (b))
237 #endif
238 #define COPY(n)   (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
239
240         iov = uio->uio_iov;
241         p = iov->iov_base;
242         len = iov->iov_len;
243         iov++;
244 #define GETIOV(extra_work) \
245         while (len == 0) { \
246                 extra_work; \
247                 p = iov->iov_base; \
248                 len = iov->iov_len; \
249                 iov++; \
250         }
251         if (fp->_flags & __SNBF) {
252         /* fjc 7-31-97 Will never happen.  We are working with
253                                            strings only
254         */
255         } else if ((fp->_flags & __SLBF) == 0) {
256         /*
257                  * Fully buffered: fill partially full buffer, if any,
258                  * and then flush.  If there is no partial buffer, write
259                  * one _bf._size byte chunk directly (without copying).
260                  *
261                  * String output is a special case: write as many bytes
262                  * as fit, but pretend we wrote everything.  This makes
263                  * snprintf() return the number of bytes needed, rather
264                  * than the number used, and avoids its write function
265                  * (so that the write function can be invalid).
266                  */
267                 do {
268                         GETIOV(;);
269                         w = fp->_w;
270                         if (fp->_flags & __SSTR) {
271                                 if (len < w)
272                                         w = len;
273                                 COPY(w);        /* copy MIN(fp->_w,len), */
274                                 fp->_w -= w;
275                                 fp->_p += w;
276                                 w = len;        /* but pretend copied all */
277                         } else {
278                                 /* fjc 7-31-97 Will never happen.  We are working with
279                                                                    strings only
280                                 */
281                         }
282                         p += w;
283                         len -= w;
284                 } while ((uio->uio_resid -= w) != 0);
285         } else {
286                 /* fjc 7-31-97 Will never happen.  We are working with
287                                                    strings only
288                 */
289         }
290         return (0);
291
292 err:
293         fp->_flags |= __SERR;
294         return (EOF);
295 }
296
297 /*
298  * Actual printf innards.
299  *
300  * This code is large and complicated...
301  */
302
303 #if !defined(__CYGWIN32__) && defined(__hpux) && !defined(__GNUC__)
304 #include <stdlib.h>
305 #endif
306
307 /*
308  * Flush out all the vectors defined by the given uio,
309  * then reset it so that it can be reused.
310  */
311 static int
312 BSD__sprint(fp, uio)
313         FILE *fp;
314         register struct __suio *uio;
315 {
316         register int err;
317
318         if (uio->uio_resid == 0) {
319                 uio->uio_iovcnt = 0;
320                 return (0);
321         }
322         err = BSD__sfvwrite(fp, uio);
323         uio->uio_resid = 0;
324         uio->uio_iovcnt = 0;
325         return (err);
326 }
327
328
329 /*
330  * Helper function for `fprintf to unbuffered unix file': creates a
331  * temporary buffer.  We only work on write-only files; this avoids
332  * worries about ungetc buffers and so forth.
333  */
334 static int
335 BSD__sbprintf(fp, fmt, ap)
336         register FILE *fp;
337         const char *fmt;
338         va_list ap;
339 {
340 /* We don't support files. */
341         return 0;
342 }
343
344
345 /*
346  * Macros for converting digits to letters and vice versa
347  */
348 #define to_digit(c)     ((c) - '0')
349 #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
350 #define to_char(n)      ((n) + '0')
351
352 /*
353  * Convert an unsigned long to ASCII for printf purposes, returning
354  * a pointer to the first character of the string representation.
355  * Octal numbers can be forced to have a leading zero; hex numbers
356  * use the given digits.
357  */
358 static char *
359 BSD__ultoa(val, endp, base, octzero, xdigs)
360         register u_long val;
361         char *endp;
362         int base, octzero;
363         char *xdigs;
364 {
365         register char *cp = endp;
366         register long sval;
367
368         /*
369          * Handle the three cases separately, in the hope of getting
370          * better/faster code.
371          */
372         switch (base) {
373         case 10:
374                 if (val < 10) { /* many numbers are 1 digit */
375                         *--cp = to_char(val);
376                         return (cp);
377                 }
378                 /*
379                  * On many machines, unsigned arithmetic is harder than
380                  * signed arithmetic, so we do at most one unsigned mod and
381                  * divide; this is sufficient to reduce the range of
382                  * the incoming value to where signed arithmetic works.
383                  */
384                 if (val > LONG_MAX) {
385                         *--cp = to_char(val % 10);
386                         sval = val / 10;
387                 } else
388                         sval = val;
389                 do {
390                         *--cp = to_char(sval % 10);
391                         sval /= 10;
392                 } while (sval != 0);
393                 break;
394
395         case 8:
396                 do {
397                         *--cp = to_char(val & 7);
398                         val >>= 3;
399                 } while (val);
400                 if (octzero && *cp != '0')
401                         *--cp = '0';
402                 break;
403
404         case 16:
405                 do {
406                         *--cp = xdigs[val & 15];
407                         val >>= 4;
408                 } while (val);
409                 break;
410
411         default:                        /* oops */
412                 /* 
413                 abort();
414                 */
415                 break;  /* fjc 7-31-97.  Don't reference abort() here */
416         }
417         return (cp);
418 }
419
420 #ifdef FLOATING_POINT
421 #include <math.h>
422 /* #include "floatio.h" */
423
424 #ifndef MAXEXP
425 # define MAXEXP 1024
426 #endif
427
428 #ifndef MAXFRACT
429 # define MAXFRACT 64
430 #endif
431
432 #define BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
433 #define DEFPREC         6
434
435 static char *cvt __P((double, int, int, char *, int *, int, int *));
436 static int exponent __P((char *, int, int));
437
438 #else /* no FLOATING_POINT */
439
440 #define BUF             68
441
442 #endif /* FLOATING_POINT */
443
444
445 /*
446  * Flags used during conversion.
447  */
448 #define ALT             0x001           /* alternate form */
449 #define HEXPREFIX       0x002           /* add 0x or 0X prefix */
450 #define LADJUST         0x004           /* left adjustment */
451 #define LONGDBL         0x008           /* long double; unimplemented */
452 #define LONGINT         0x010           /* long integer */
453
454 #ifdef _HAVE_SANE_QUAD_
455 #define QUADINT         0x020           /* quad integer */
456 #endif /* _HAVE_SANE_QUAD_ */
457
458 #define SHORTINT        0x040           /* short integer */
459 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
460 #define FPT             0x100           /* Floating point number */
461 static int
462 BSD_vfprintf(fp, fmt0, ap)
463         FILE *fp;
464         const char *fmt0;
465         va_list ap;
466 {
467         register char *fmt;     /* format string */
468         register int ch;        /* character from fmt */
469         register int n;         /* handy integer (short term usage) */
470         register char *cp;      /* handy char pointer (short term usage) */
471         register struct __siov *iovp;/* for PRINT macro */
472         register int flags;     /* flags as above */
473         int ret;                /* return value accumulator */
474         int width;              /* width from format (%8d), or 0 */
475         int prec;               /* precision from format (%.3d), or -1 */
476         char sign;              /* sign prefix (' ', '+', '-', or \0) */
477 #ifdef FLOATING_POINT
478         char softsign;          /* temporary negative sign for floats */
479         double _double;         /* double precision arguments %[eEfgG] */
480         int expt;               /* integer value of exponent */
481         int expsize;            /* character count for expstr */
482         int ndig;               /* actual number of digits returned by cvt */
483         char expstr[7];         /* buffer for exponent string */
484 #endif
485         u_long  ulval;          /* integer arguments %[diouxX] */
486 #ifdef _HAVE_SANE_QUAD_
487         u_quad_t uqval;         /* %q integers */
488 #endif /* _HAVE_SANE_QUAD_ */
489         int base;               /* base for [diouxX] conversion */
490         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
491         int fieldsz;            /* field size expanded by sign, etc */
492         int realsz;             /* field size expanded by dprec */
493         int size;               /* size of converted field or string */
494         char *xdigs;            /* digits for [xX] conversion */
495 #define NIOV 8
496         struct __suio uio;      /* output information: summary */
497         struct __siov iov[NIOV];/* ... and individual io vectors */
498         char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
499         char ox[2];             /* space for 0x hex-prefix */
500
501         /*
502          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
503          * fields occur frequently, increase PADSIZE and make the initialisers
504          * below longer.
505          */
506 #define PADSIZE 16              /* pad chunk size */
507         static char blanks[PADSIZE] =
508          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
509         static char zeroes[PADSIZE] =
510          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
511
512         /*
513          * BEWARE, these `goto error' on error, and PAD uses `n'.
514          */
515 #define PRINT(ptr, len) { \
516         iovp->iov_base = (ptr); \
517         iovp->iov_len = (len); \
518         uio.uio_resid += (len); \
519         iovp++; \
520         if (++uio.uio_iovcnt >= NIOV) { \
521                 if (BSD__sprint(fp, &uio)) \
522                         goto error; \
523                 iovp = iov; \
524         } \
525 }
526 #define PAD(howmany, with) { \
527         if ((n = (howmany)) > 0) { \
528                 while (n > PADSIZE) { \
529                         PRINT(with, PADSIZE); \
530                         n -= PADSIZE; \
531                 } \
532                 PRINT(with, n); \
533         } \
534 }
535 #define FLUSH() { \
536         if (uio.uio_resid && BSD__sprint(fp, &uio)) \
537                 goto error; \
538         uio.uio_iovcnt = 0; \
539         iovp = iov; \
540 }
541
542         /*
543          * To extend shorts properly, we need both signed and unsigned
544          * argument extraction methods.
545          */
546 #define SARG() \
547         (flags&LONGINT ? va_arg(ap, long) : \
548             flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
549             (long)va_arg(ap, int))
550 #define UARG() \
551         (flags&LONGINT ? va_arg(ap, u_long) : \
552             flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
553             (u_long)va_arg(ap, u_int))
554
555         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
556         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
557             fp->_file >= 0)
558                 return (BSD__sbprintf(fp, fmt0, ap));
559
560         fmt = (char *)fmt0;
561         uio.uio_iov = iovp = iov;
562         uio.uio_resid = 0;
563         uio.uio_iovcnt = 0;
564         ret = 0;
565
566         /*
567          * Scan the format for conversions (`%' character).
568          */
569         for (;;) {
570                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
571                         /* void */;
572                 if ((n = fmt - cp) != 0) {
573                         PRINT(cp, n);
574                         ret += n;
575                 }
576                 if (ch == '\0')
577                         goto done;
578                 fmt++;          /* skip over '%' */
579
580                 flags = 0;
581                 dprec = 0;
582                 width = 0;
583                 prec = -1;
584                 sign = '\0';
585
586 rflag:          ch = *fmt++;
587 reswitch:       switch (ch) {
588                 case ' ':
589                         /*
590                          * ``If the space and + flags both appear, the space
591                          * flag will be ignored.''
592                          *      -- ANSI X3J11
593                          */
594                         if (!sign)
595                                 sign = ' ';
596                         goto rflag;
597                 case '#':
598                         flags |= ALT;
599                         goto rflag;
600                 case '*':
601                         /*
602                          * ``A negative field width argument is taken as a
603                          * - flag followed by a positive field width.''
604                          *      -- ANSI X3J11
605                          * They don't exclude field widths read from args.
606                          */
607                         if ((width = va_arg(ap, int)) >= 0)
608                                 goto rflag;
609                         width = -width;
610                         /* FALLTHROUGH */
611                 case '-':
612                         flags |= LADJUST;
613                         goto rflag;
614                 case '+':
615                         sign = '+';
616                         goto rflag;
617                 case '.':
618                         if ((ch = *fmt++) == '*') {
619                                 n = va_arg(ap, int);
620                                 prec = n < 0 ? -1 : n;
621                                 goto rflag;
622                         }
623                         n = 0;
624                         while (is_digit(ch)) {
625                                 n = 10 * n + to_digit(ch);
626                                 ch = *fmt++;
627                         }
628                         prec = n < 0 ? -1 : n;
629                         goto reswitch;
630                 case '0':
631                         /*
632                          * ``Note that 0 is taken as a flag, not as the
633                          * beginning of a field width.''
634                          *      -- ANSI X3J11
635                          */
636                         flags |= ZEROPAD;
637                         goto rflag;
638                 case '1': case '2': case '3': case '4':
639                 case '5': case '6': case '7': case '8': case '9':
640                         n = 0;
641                         do {
642                                 n = 10 * n + to_digit(ch);
643                                 ch = *fmt++;
644                         } while (is_digit(ch));
645                         width = n;
646                         goto reswitch;
647 #ifdef FLOATING_POINT
648                 case 'L':
649                         flags |= LONGDBL;
650                         goto rflag;
651 #endif
652                 case 'h':
653                         flags |= SHORTINT;
654                         goto rflag;
655                 case 'l':
656                         flags |= LONGINT;
657                         goto rflag;
658 #ifdef _HAVE_SANE_QUAD_
659                 case 'q':
660                         flags |= QUADINT;
661                         goto rflag;
662 #endif /* _HAVE_SANE_QUAD_ */
663                 case 'c':
664                         *(cp = buf) = va_arg(ap, int);
665                         size = 1;
666                         sign = '\0';
667                         break;
668                 case 'D':
669                         flags |= LONGINT;
670                         /*FALLTHROUGH*/
671                 case 'd':
672                 case 'i':
673 #ifdef _HAVE_SANE_QUAD_
674                         if (flags & QUADINT) {
675                                 uqval = va_arg(ap, quad_t);
676                                 if ((quad_t)uqval < 0) {
677                                         uqval = -uqval;
678                                         sign = '-';
679                                 }
680                         } else {
681 #else /* _HAVE_SANE_QUAD_ */
682                         {
683 #endif /* _HAVE_SANE_QUAD_ */
684                                 ulval = SARG();
685                                 if ((long)ulval < 0) {
686                                         ulval = -ulval;
687                                         sign = '-';
688                                 }
689                         }
690                         base = 10;
691                         goto number;
692 #ifdef FLOATING_POINT
693                 case 'e':               /* anomalous precision */
694                 case 'E':
695                         prec = (prec == -1) ?
696                                 DEFPREC + 1 : prec + 1;
697                         /* FALLTHROUGH */
698                         goto fp_begin;
699                 case 'f':               /* always print trailing zeroes */
700                         if (prec != 0)
701                                 flags |= ALT;
702                 case 'g':
703                 case 'G':
704                         if (prec == -1)
705                                 prec = DEFPREC;
706 fp_begin:               _double = va_arg(ap, double);
707                         /* do this before tricky precision changes */
708                         if (isinf(_double)) {
709                                 if (_double < 0)
710                                         sign = '-';
711                                 cp = "Inf";
712                                 size = 3;
713                                 break;
714                         }
715                         if (isnan(_double)) {
716                                 cp = "NaN";
717                                 size = 3;
718                                 break;
719                         }
720                         flags |= FPT;
721                         cp = cvt(_double, prec, flags, &softsign,
722                                 &expt, ch, &ndig);
723                         if (ch == 'g' || ch == 'G') {
724                                 if (expt <= -4 || expt > prec)
725                                         ch = (ch == 'g') ? 'e' : 'E';
726                                 else
727                                         ch = 'g';
728                         } 
729                         if (ch <= 'e') {        /* 'e' or 'E' fmt */
730                                 --expt;
731                                 expsize = exponent(expstr, expt, ch);
732                                 size = expsize + ndig;
733                                 if (ndig > 1 || flags & ALT)
734                                         ++size;
735                         } else if (ch == 'f') {         /* f fmt */
736                                 if (expt > 0) {
737                                         size = expt;
738                                         if (prec || flags & ALT)
739                                                 size += prec + 1;
740                                 } else  /* "0.X" */
741                                         size = prec + 2;
742                         } else if (expt >= ndig) {      /* fixed g fmt */
743                                 size = expt;
744                                 if (flags & ALT)
745                                         ++size;
746                         } else
747                                 size = ndig + (expt > 0 ?
748                                         1 : 2 - expt);
749
750                         if (softsign)
751                                 sign = '-';
752                         break;
753 #endif /* FLOATING_POINT */
754                 case 'n':
755 #ifdef _HAVE_SANE_QUAD_
756                         if (flags & QUADINT)
757                                 *va_arg(ap, quad_t *) = ret;
758                         else if (flags & LONGINT)
759 #else /* _HAVE_SANE_QUAD_ */
760                         if (flags & LONGINT)
761 #endif /* _HAVE_SANE_QUAD_ */
762                                 *va_arg(ap, long *) = ret;
763                         else if (flags & SHORTINT)
764                                 *va_arg(ap, short *) = ret;
765                         else
766                                 *va_arg(ap, int *) = ret;
767                         continue;       /* no output */
768                 case 'O':
769                         flags |= LONGINT;
770                         /*FALLTHROUGH*/
771                 case 'o':
772 #ifdef _HAVE_SANE_QUAD_
773                         if (flags & QUADINT)
774                                 uqval = va_arg(ap, u_quad_t);
775                         else
776 #endif /* _HAVE_SANE_QUAD_ */
777                                 ulval = UARG();
778                         base = 8;
779                         goto nosign;
780                 case 'p':
781                         /*
782                          * ``The argument shall be a pointer to void.  The
783                          * value of the pointer is converted to a sequence
784                          * of printable characters, in an implementation-
785                          * defined manner.''
786                          *      -- ANSI X3J11
787                          */
788                         ulval = (u_long)va_arg(ap, void *);
789                         base = 16;
790                         xdigs = "0123456789abcdef";
791 #ifdef _HAVE_SANE_QUAD_
792                         flags = (flags & ~QUADINT) | HEXPREFIX;
793 #else /* _HAVE_SANE_QUAD_ */
794                         flags = (flags) | HEXPREFIX;
795 #endif /* _HAVE_SANE_QUAD_ */
796                         ch = 'x';
797                         goto nosign;
798                 case 's':
799                         if ((cp = va_arg(ap, char *)) == NULL)
800                                 cp = "(null)";
801                         if (prec >= 0) {
802                                 /*
803                                  * can't use strlen; can only look for the
804                                  * NUL in the first `prec' characters, and
805                                  * strlen() will go further.
806                                  */
807                                 char *p = (char *)memchr(cp, 0, prec);
808
809                                 if (p != NULL) {
810                                         size = p - cp;
811                                         if (size > prec)
812                                                 size = prec;
813                                 } else
814                                         size = prec;
815                         } else
816                                 size = strlen(cp);
817                         sign = '\0';
818                         break;
819                 case 'U':
820                         flags |= LONGINT;
821                         /*FALLTHROUGH*/
822                 case 'u':
823 #ifdef _HAVE_SANE_QUAD_
824                         if (flags & QUADINT)
825                                 uqval = va_arg(ap, u_quad_t);
826                         else
827 #endif /* _HAVE_SANE_QUAD_ */
828                                 ulval = UARG();
829                         base = 10;
830                         goto nosign;
831                 case 'X':
832                         xdigs = "0123456789ABCDEF";
833                         goto hex;
834                 case 'x':
835                         xdigs = "0123456789abcdef";
836 hex:
837 #ifdef _HAVE_SANE_QUAD_
838                         if (flags & QUADINT)
839                                 uqval = va_arg(ap, u_quad_t);
840                         else
841 #endif /* _HAVE_SANE_QUAD_ */
842                                 ulval = UARG();
843                         base = 16;
844                         /* leading 0x/X only if non-zero */
845                         if (flags & ALT &&
846 #ifdef _HAVE_SANE_QUAD_
847                             (flags & QUADINT ? uqval != 0 : ulval != 0))
848 #else /* _HAVE_SANE_QUAD_ */
849                             ulval != 0)
850 #endif /* _HAVE_SANE_QUAD_ */
851                                 flags |= HEXPREFIX;
852
853                         /* unsigned conversions */
854 nosign:                 sign = '\0';
855                         /*
856                          * ``... diouXx conversions ... if a precision is
857                          * specified, the 0 flag will be ignored.''
858                          *      -- ANSI X3J11
859                          */
860 number:                 if ((dprec = prec) >= 0)
861                                 flags &= ~ZEROPAD;
862
863                         /*
864                          * ``The result of converting a zero value with an
865                          * explicit precision of zero is no characters.''
866                          *      -- ANSI X3J11
867                          */
868                         cp = buf + BUF;
869 #ifdef _HAVE_SANE_QUAD_
870                         if (flags & QUADINT) {
871                                 if (uqval != 0 || prec != 0)
872                                         cp = __uqtoa(uqval, cp, base,
873                                             flags & ALT, xdigs);
874                         } else {
875 #else /* _HAVE_SANE_QUAD_ */
876                         {
877 #endif /* _HAVE_SANE_QUAD_ */
878                                 if (ulval != 0 || prec != 0)
879                                         cp = BSD__ultoa(ulval, cp, base,
880                                             flags & ALT, xdigs);
881                         }
882                         size = buf + BUF - cp;
883                         break;
884                 default:        /* "%?" prints ?, unless ? is NUL */
885                         if (ch == '\0')
886                                 goto done;
887                         /* pretend it was %c with argument ch */
888                         cp = buf;
889                         *cp = ch;
890                         size = 1;
891                         sign = '\0';
892                         break;
893                 }
894
895                 /*
896                  * All reasonable formats wind up here.  At this point, `cp'
897                  * points to a string which (if not flags&LADJUST) should be
898                  * padded out to `width' places.  If flags&ZEROPAD, it should
899                  * first be prefixed by any sign or other prefix; otherwise,
900                  * it should be blank padded before the prefix is emitted.
901                  * After any left-hand padding and prefixing, emit zeroes
902                  * required by a decimal [diouxX] precision, then print the
903                  * string proper, then emit zeroes required by any leftover
904                  * floating precision; finally, if LADJUST, pad with blanks.
905                  *
906                  * Compute actual size, so we know how much to pad.
907                  * fieldsz excludes decimal prec; realsz includes it.
908                  */
909                 fieldsz = size;
910                 if (sign)
911                         fieldsz++;
912                 else if (flags & HEXPREFIX)
913                         fieldsz += 2;
914                 realsz = dprec > fieldsz ? dprec : fieldsz;
915
916                 /* right-adjusting blank padding */
917                 if ((flags & (LADJUST|ZEROPAD)) == 0)
918                         PAD(width - realsz, blanks);
919
920                 /* prefix */
921                 if (sign) {
922                         PRINT(&sign, 1);
923                 } else if (flags & HEXPREFIX) {
924                         ox[0] = '0';
925                         ox[1] = ch;
926                         PRINT(ox, 2);
927                 }
928
929                 /* right-adjusting zero padding */
930                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
931                         PAD(width - realsz, zeroes);
932
933                 /* leading zeroes from decimal precision */
934                 PAD(dprec - fieldsz, zeroes);
935
936                 /* the string or number proper */
937 #ifdef FLOATING_POINT
938                 if ((flags & FPT) == 0) {
939                         PRINT(cp, size);
940                 } else {        /* glue together f_p fragments */
941                         if (ch >= 'f') {        /* 'f' or 'g' */
942                                 if (_double == 0) {
943                                 /* kludge for __dtoa irregularity */
944                                         if (prec == 0 ||
945                                             (flags & ALT) == 0) {
946                                                 PRINT("0", 1);
947                                         } else {
948                                                 PRINT("0.", 2);
949                                                 PAD(ndig - 1, zeroes);
950                                         }
951                                 } else if (expt <= 0) {
952                                         PRINT("0.", 2);
953                                         PAD(-expt, zeroes);
954                                         PRINT(cp, ndig);
955                                 } else if (expt >= ndig) {
956                                         PRINT(cp, ndig);
957                                         PAD(expt - ndig, zeroes);
958                                         if (flags & ALT)
959                                                 PRINT(".", 1);
960                                 } else {
961                                         PRINT(cp, expt);
962                                         cp += expt;
963                                         PRINT(".", 1);
964                                         PRINT(cp, ndig-expt);
965                                 }
966                         } else {        /* 'e' or 'E' */
967                                 if (ndig > 1 || flags & ALT) {
968                                         ox[0] = *cp++;
969                                         ox[1] = '.';
970                                         PRINT(ox, 2);
971                                         if (_double || flags & ALT == 0) {
972                                                 PRINT(cp, ndig-1);
973                                         } else  /* 0.[0..] */
974                                                 /* __dtoa irregularity */
975                                                 PAD(ndig - 1, zeroes);
976                                 } else  /* XeYYY */
977                                         PRINT(cp, 1);
978                                 PRINT(expstr, expsize);
979                         }
980                 }
981 #else
982                 PRINT(cp, size);
983 #endif
984                 /* left-adjusting padding (always blank) */
985                 if (flags & LADJUST)
986                         PAD(width - realsz, blanks);
987
988                 /* finally, adjust ret */
989                 ret += width > realsz ? width : realsz;
990
991                 FLUSH();        /* copy out the I/O vectors */
992         }
993 done:
994         FLUSH();
995 error:
996         return (__sferror(fp) ? EOF : ret);
997         /* NOTREACHED */
998 }
999
1000 #ifdef FLOATING_POINT
1001
1002 extern char *BSD__dtoa __P((double, int, int, int *, int *, char **));
1003
1004 static char *
1005 cvt(value, ndigits, flags, sign, decpt, ch, length)
1006         double value;
1007         int ndigits, flags, *decpt, ch, *length;
1008         char *sign;
1009 {
1010         int mode, dsgn;
1011         char *digits, *bp, *rve;
1012
1013         if (ch == 'f')
1014                 mode = 3;
1015         else {
1016                 mode = 2;
1017         }
1018         if (value < 0) {
1019                 value = -value;
1020                 *sign = '-';
1021         } else
1022                 *sign = '\000';
1023         digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
1024         if (flags & ALT) {      /* Print trailing zeros */
1025                 bp = digits + ndigits;
1026                 if (ch == 'f') {
1027                         if (*digits == '0' && value)
1028                                 *decpt = -ndigits + 1;
1029                         bp += *decpt;
1030                 }
1031                 if (value == 0) /* kludge for __dtoa irregularity */
1032                         rve = bp;
1033                 while (rve < bp)
1034                         *rve++ = '0';
1035         }
1036         *length = rve - digits;
1037         return (digits);
1038 }
1039
1040 static int
1041 exponent(p0, exp, fmtch)
1042         char *p0;
1043         int exp, fmtch;
1044 {
1045         register char *p, *t;
1046         char expbuf[MAXEXP];
1047
1048         p = p0;
1049         *p++ = fmtch;
1050         if (exp < 0) {
1051                 exp = -exp;
1052                 *p++ = '-';
1053         }
1054         else
1055                 *p++ = '+';
1056         t = expbuf + MAXEXP;
1057         if (exp > 9) {
1058                 do {
1059                         *--t = to_char(exp % 10);
1060                 } while ((exp /= 10) > 9);
1061                 *--t = to_char(exp);
1062                 for (; t < expbuf + MAXEXP; *p++ = *t++);
1063         }
1064         else {
1065                 *p++ = '0';
1066                 *p++ = to_char(exp);
1067         }
1068         return (p - p0);
1069 }
1070 #endif /* FLOATING_POINT */
1071
1072 int
1073 vsnprintf(str, n, fmt, ap)
1074         char *str;
1075         size_t n;
1076         const char *fmt;
1077         _BSD_VA_LIST_ ap;
1078 {
1079         int ret;
1080         FILE f;
1081
1082         if ((int)n < 1)
1083                 return (EOF);
1084         f._flags = __SWR | __SSTR;
1085         f._bf._base = f._p = (unsigned char *)str;
1086         f._bf._size = f._w = n - 1;
1087         ret = BSD_vfprintf(&f, fmt, ap);
1088         *f._p = 0;
1089         return (ret);
1090 }
1091
1092 #if defined(LIBC_SCCS) && !defined(lint)
1093 static char sccsid[] = "@(#)snprintf.c  8.1 (Berkeley) 6/4/93";
1094 #endif /* LIBC_SCCS and not lint */
1095
1096 #if defined(__STDC__)
1097 # include <stdarg.h>
1098 #else
1099 # include <varargs.h>
1100 #endif
1101
1102 int
1103 #if defined(__STDC__)
1104 snprintf(char *str, size_t n, char const *fmt, ...)
1105 #else
1106 snprintf(str, n, fmt, va_alist)
1107 char *str, *fmt;
1108 size_t n;
1109 va_dcl
1110 #endif
1111 {
1112         int ret;
1113         va_list ap;
1114         FILE f;
1115
1116         if ((int)n < 1)
1117                 return (EOF);
1118
1119 #if defined(__STDC__)
1120         va_start(ap, fmt);
1121 #else
1122         va_start(ap);
1123 #endif
1124         f._flags = __SWR | __SSTR;
1125         f._bf._base = f._p = (unsigned char *)str;
1126         f._bf._size = f._w = n - 1;
1127         ret = BSD_vfprintf(&f, fmt, ap);
1128         *f._p = 0;
1129         va_end(ap);
1130         return (ret);
1131 }