1219422Sdas/****************************************************************
2219422SdasCopyright (C) 1997, 1999, 2001 Lucent Technologies
3219422SdasAll Rights Reserved
4219422Sdas
5219422SdasPermission to use, copy, modify, and distribute this software and
6219422Sdasits documentation for any purpose and without fee is hereby
7219422Sdasgranted, provided that the above copyright notice appear in all
8219422Sdascopies and that both that the copyright notice and this
9219422Sdaspermission notice and warranty disclaimer appear in supporting
10219422Sdasdocumentation, and that the name of Lucent or any of its entities
11219422Sdasnot be used in advertising or publicity pertaining to
12219422Sdasdistribution of the software without specific, written prior
13219422Sdaspermission.
14219422Sdas
15219422SdasLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16219422SdasINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17219422SdasIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18219422SdasSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19219422SdasWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20219422SdasIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21219422SdasARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22219422SdasTHIS SOFTWARE.
23219422Sdas****************************************************************/
24219422Sdas
25219422Sdas/* This implements most of ANSI C's printf, fprintf, and sprintf,
26219422Sdas * omitting L, with %.0g and %.0G giving the shortest decimal string
27219422Sdas * that rounds to the number being converted, and with negative
28219422Sdas * precisions allowed for %f.
29219422Sdas */
30219422Sdas
31219422Sdas#ifdef KR_headers
32219422Sdas#include "varargs.h"
33219422Sdas#else
34219422Sdas#include "stddef.h"
35219422Sdas#include "stdarg.h"
36219422Sdas#include "stdlib.h"
37219422Sdas#endif
38219422Sdas
39219422Sdas#ifdef Use_GDTOA_for_i386_long_double /*{{*/
40219422Sdas#include "gdtoa.h"
41219422Sdas#else /*}{*/
42219422Sdas#ifndef NO_PRINTF_A_FMT /*{*/
43219422Sdas#include "gdtoa.h"
44219422Sdas#endif /*}*/
45219422Sdas#endif /*}}*/
46219422Sdas
47219422Sdas#ifdef __i386
48219422Sdas#define NO_GDTOA_i386_Quad
49219422Sdas#endif
50219422Sdas
51219422Sdas#ifdef Use_GDTOA_for_i386_long_double /*{*/
52219422Sdas#ifndef NO_GDTOA_i386_Quad /*{*/
53219422Sdas#define GDTOA_both
54219422Sdas#define Use_GDTOA_Qtype
55219422Sdas#ifdef __ICC__ /* or __INTEL_COMPILER__ or __INTEL_COMPILER ?? */
56219422Sdas#define GDTOA_Qtype _Quad
57219422Sdas#else
58219422Sdas#define GDTOA_Qtype __float128
59219422Sdas#endif
60219422Sdas#endif /*} NO_GDTOA_i386_Quad */
61219422Sdas#endif /*} Use_GDTOA_for_i386_long_double */
62219422Sdas
63219422Sdas#ifdef Use_GDTOA_Qtype /*{*/
64219422Sdas#ifndef GDTOA_H_INCLUDED
65219422Sdas#include "gdtoa.h"
66219422Sdas#endif
67219422Sdas#ifndef GDTOA_Qtype
68219422Sdas#define GDTOA_Qtype long double
69219422Sdas#endif
70219422Sdas#endif /*}*/
71219422Sdas
72219422Sdas#ifndef GDTOA_H_INCLUDED /*{*/
73219422Sdas
74219422Sdas enum {	/* return values from strtodg */
75219422Sdas	STRTOG_Zero	= 0,
76219422Sdas	STRTOG_Normal	= 1,
77219422Sdas	STRTOG_Denormal	= 2,
78219422Sdas	STRTOG_Infinite	= 3,
79219422Sdas	STRTOG_NaN	= 4,
80219422Sdas	STRTOG_NaNbits	= 5,
81219422Sdas	STRTOG_NoNumber	= 6,
82219422Sdas	STRTOG_Retmask	= 7};
83219422Sdas
84219422Sdas typedef struct
85219422SdasFPI {
86219422Sdas	int nbits;
87219422Sdas	int emin;
88219422Sdas	int emax;
89219422Sdas	int rounding;
90219422Sdas	int sudden_underflow;
91219422Sdas	} FPI;
92219422Sdas
93219422Sdasenum {	/* FPI.rounding values: same as FLT_ROUNDS */
94219422Sdas	FPI_Round_zero = 0,
95219422Sdas	FPI_Round_near = 1,
96219422Sdas	FPI_Round_up = 2,
97219422Sdas	FPI_Round_down = 3
98219422Sdas	};
99219422Sdas#endif /*}*/
100219422Sdas
101219422Sdas#ifdef NO_PRINTF_A_FMT /*{{*/
102219422Sdas#define WANT_A_FMT(x) /*nothing*/
103219422Sdas#else /*}{*/
104219422Sdas#define WANT_A_FMT(x) x
105219422Sdas#endif /*}}*/
106219422Sdas
107219422Sdas#include "stdio1.h"
108219422Sdas#include "string.h"
109219422Sdas#include "errno.h"
110219422Sdas
111219422Sdas typedef struct
112219422SdasFinfo {
113219422Sdas	union { FILE *cf; char *sf; } u;
114219422Sdas	char *ob0, *obe1;
115219422Sdas	size_t lastlen;
116219422Sdas	} Finfo;
117219422Sdas
118219422Sdas typedef char *(*pgdtoa) ANSI((FPI*, int be, ULong *bits, int *kind, int mode, int ndigits, int *decpt, char **rve));
119219422Sdas
120219422Sdas typedef struct
121219422SdasFPBits {
122219422Sdas	ULong bits[4];	/* sufficient for quad; modify if considering wider types */
123219422Sdas	FPI *fpi;
124219422Sdas	pgdtoa gdtoa;
125219422Sdas	int sign;
126219422Sdas	int ex;	/* exponent */
127219422Sdas	int kind;
128219422Sdas	} FPBits;
129219422Sdas
130219422Sdas typedef union U
131219422Sdas{
132219422Sdas	double d;
133219422Sdas	long double ld;
134219422Sdas#ifdef GDTOA_Qtype
135219422Sdas	GDTOA_Qtype Qd;
136219422Sdas#endif
137219422Sdas	unsigned int ui[4];
138219422Sdas	unsigned short us[5];
139219422Sdas	} U;
140219422Sdas
141219422Sdas typedef char *(*Putfunc) ANSI((Finfo*, int*));
142219422Sdas typedef void (*Fpbits) ANSI((U*, FPBits*));
143219422Sdas
144219422Sdas/* Would have preferred typedef void (*Fpbits)(va_list*, FPBits*)
145219422Sdas * but gcc is buggy in this regard.
146219422Sdas */
147219422Sdas
148219422Sdas#ifdef Use_GDTOA_for_i386_long_double /*{*/
149219422Sdas
150219422Sdas#ifdef IEEE_MC68k
151219422Sdas#define _0 0
152219422Sdas#define _1 1
153219422Sdas#define _2 2
154219422Sdas#define _3 3
155219422Sdas#define _4 4
156219422Sdas#endif
157219422Sdas#ifdef IEEE_8087
158219422Sdas#define _0 4
159219422Sdas#define _1 3
160219422Sdas#define _2 2
161219422Sdas#define _3 1
162219422Sdas#define _4 0
163219422Sdas#endif
164219422Sdas
165219422Sdas static void
166219422Sdasxfpbits(U *u, FPBits *b)
167219422Sdas{
168219422Sdas	ULong *bits;
169219422Sdas	int ex, i;
170219422Sdas	static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0 };
171219422Sdas
172219422Sdas	b->fpi = &fpi0;
173219422Sdas	b->gdtoa = gdtoa;
174219422Sdas	b->sign = u->us[_0] & 0x8000;
175219422Sdas	bits = b->bits;
176219422Sdas	bits[1] = (u->us[_1] << 16) | u->us[_2];
177219422Sdas	bits[0] = (u->us[_3] << 16) | u->us[_4];
178219422Sdas	if ( (ex = u->us[_0] & 0x7fff) !=0) {
179219422Sdas		i = STRTOG_Normal;
180219422Sdas		if (ex == 0x7fff)
181219422Sdas			/* Infinity or NaN */
182219422Sdas			i = bits[0] | bits[1] ? STRTOG_NaN : STRTOG_Infinite;
183219422Sdas		}
184219422Sdas	else if (bits[0] | bits[1]) {
185219422Sdas		i = STRTOG_Denormal;
186219422Sdas		ex = 1;
187219422Sdas		}
188219422Sdas	else
189219422Sdas		i = STRTOG_Zero;
190219422Sdas	b->kind = i;
191219422Sdas	b->ex = ex - (0x3fff + 63);
192219422Sdas	}
193219422Sdas
194219422Sdas#undef _0
195219422Sdas#undef _1
196219422Sdas#undef _2
197219422Sdas#undef _3
198219422Sdas#undef _4
199219422Sdas#define GDTOA_LD_fpbits xfpbits
200219422Sdas#endif /*} Use_GDTOA_for_i386_long_double */
201219422Sdas
202219422Sdas#ifdef Use_GDTOA_Qtype /*{*/
203219422Sdas#include "gdtoa.h"
204219422Sdas#ifndef GDTOA_Qtype
205219422Sdas#define GDTOA_Qtype long double
206219422Sdas#endif
207219422Sdas#ifdef GDTOA_LD_fpbits
208219422Sdas#define GDTOA_Q_fpbits Qfpbits
209219422Sdas#else
210219422Sdas#define GDTOA_LD_fpbits Qfpbits
211219422Sdas#endif
212219422Sdas
213219422Sdas#ifdef IEEE_MC68k
214219422Sdas#define _0 0
215219422Sdas#define _1 1
216219422Sdas#define _2 2
217219422Sdas#define _3 3
218219422Sdas#endif
219219422Sdas#ifdef IEEE_8087
220219422Sdas#define _0 3
221219422Sdas#define _1 2
222219422Sdas#define _2 1
223219422Sdas#define _3 0
224219422Sdas#endif
225219422Sdas
226219422Sdas static void
227219422SdasQfpbits(U *u, FPBits *b)
228219422Sdas{
229219422Sdas	ULong *bits;
230219422Sdas	int ex, i;
231219422Sdas	static FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, 0 };
232219422Sdas
233219422Sdas	b->fpi = &fpi0;
234219422Sdas	b->gdtoa = gdtoa;
235219422Sdas	b->sign = u->ui[_0] & 0x80000000L;
236219422Sdas	bits = b->bits;
237219422Sdas	bits[3] = u->ui[_0] & 0xffff;
238219422Sdas	bits[2] = u->ui[_1];
239219422Sdas	bits[1] = u->ui[_2];
240219422Sdas	bits[0] = u->ui[_3];
241219422Sdas	if ( (ex = (u->ui[_0] & 0x7fff0000L) >> 16) !=0) {
242219422Sdas		if (ex == 0x7fff) {
243219422Sdas			/* Infinity or NaN */
244219422Sdas			i = bits[0] | bits[1] | bits[2] | bits[3]
245219422Sdas				? STRTOG_NaN : STRTOG_Infinite;
246219422Sdas			}
247219422Sdas		else {
248219422Sdas			i = STRTOG_Normal;
249219422Sdas			bits[3] |= 0x10000;
250219422Sdas			}
251219422Sdas		}
252219422Sdas	else if (bits[0] | bits[1] | bits[2] | bits[3]) {
253219422Sdas		i = STRTOG_Denormal;
254219422Sdas		ex = 1;
255219422Sdas		}
256219422Sdas	else
257219422Sdas		i = STRTOG_Zero;
258219422Sdas	b->kind = i;
259219422Sdas	b->ex = ex - (0x3fff + 112);
260219422Sdas	}
261219422Sdas
262219422Sdas#undef _0
263219422Sdas#undef _1
264219422Sdas#undef _2
265219422Sdas#undef _3
266219422Sdas#endif /*} GDTOA_Qtype */
267219422Sdas
268219422Sdas#ifdef KR_headers
269219422Sdas#define Const /* const */
270219422Sdas#define Voidptr char*
271219422Sdas#ifndef size_t__
272219422Sdas#define size_t int
273219422Sdas#define size_t__
274219422Sdas#endif
275219422Sdas
276219422Sdas#else
277219422Sdas
278219422Sdas#define Const const
279219422Sdas#define Voidptr void*
280219422Sdas
281219422Sdas#endif
282219422Sdas
283219422Sdas#undef MESS
284219422Sdas#ifndef Stderr
285219422Sdas#define Stderr stderr
286219422Sdas#endif
287219422Sdas
288219422Sdas#ifdef _windows_
289219422Sdas#undef PF_BUF
290219422Sdas#define MESS
291219422Sdas#include "mux0.h"
292219422Sdas#define stdout_or_err(f) (f == stdout)
293219422Sdas#else
294219422Sdas#define stdout_or_err(f) (f == Stderr || f == stdout)
295219422Sdas#endif
296219422Sdas
297219422Sdas#ifdef __cplusplus
298219422Sdasextern "C" {
299219422Sdas#endif
300219422Sdas
301219422Sdas extern char *dtoa ANSI((double, int, int, int*, int*, char **));
302219422Sdas extern void freedtoa ANSI((char*));
303219422Sdas
304219422Sdas
305219422Sdas
306219422Sdas#ifdef USE_ULDIV
307219422Sdas/* This is for avoiding 64-bit divisions on the DEC Alpha, since */
308219422Sdas/* they are not portable among variants of OSF1 (DEC's Unix). */
309219422Sdas
310219422Sdas#define ULDIV(a,b) uldiv_ASL(a,(unsigned long)(b))
311219422Sdas
312219422Sdas#ifndef LLBITS
313219422Sdas#define LLBITS 6
314219422Sdas#endif
315219422Sdas#ifndef ULONG
316219422Sdas#define ULONG unsigned long
317219422Sdas#endif
318219422Sdas
319219422Sdas static int
320219422Sdasklog(ULONG x)
321219422Sdas{
322219422Sdas	int k, rv = 0;
323219422Sdas
324219422Sdas	if (x > 1L)
325219422Sdas	    for(k = 1 << LLBITS-1;;) {
326219422Sdas		if (x >= (1L << k)) {
327219422Sdas			rv |= k;
328219422Sdas			x >>= k;
329219422Sdas			}
330219422Sdas		if (!(k >>= 1))
331219422Sdas			break;
332219422Sdas		}
333219422Sdas	return rv;
334219422Sdas	}
335219422Sdas
336219422Sdas ULONG
337219422Sdasuldiv_ASL(ULONG a, ULONG b)
338219422Sdas{
339219422Sdas	int ka;
340219422Sdas	ULONG c, k;
341219422Sdas	static ULONG b0;
342219422Sdas	static int kb;
343219422Sdas
344219422Sdas	if (a < b)
345219422Sdas		return 0;
346219422Sdas	if (b != b0) {
347219422Sdas		b0 = b;
348219422Sdas		kb = klog(b);
349219422Sdas		}
350219422Sdas	k = 1;
351219422Sdas	if ((ka = klog(a) - kb) > 0) {
352219422Sdas		k <<= ka;
353219422Sdas		b <<= ka;
354219422Sdas		}
355219422Sdas	c = 0;
356219422Sdas	for(;;) {
357219422Sdas		if (a >= b) {
358219422Sdas			a -= b;
359219422Sdas			c |= k;
360219422Sdas			}
361219422Sdas		if (!(k >>= 1))
362219422Sdas			break;
363219422Sdas		a <<= 1;
364219422Sdas		}
365219422Sdas	return c;
366219422Sdas	}
367219422Sdas
368219422Sdas#else
369219422Sdas#define ULDIV(a,b) a / b
370219422Sdas#endif /* USE_ULDIV */
371219422Sdas
372219422Sdas#ifdef PF_BUF
373219422SdasFILE *stderr_ASL = (FILE*)&stderr_ASL;
374219422Sdasvoid (*pfbuf_print_ASL) ANSI((char*));
375219422Sdaschar *pfbuf_ASL;
376219422Sdasstatic char *pfbuf_next;
377219422Sdasstatic size_t pfbuf_len;
378219422Sdasextern Char *mymalloc_ASL ANSI((size_t));
379219422Sdasextern Char *myralloc_ASL ANSI((void *, size_t));
380219422Sdas
381219422Sdas#undef fflush
382219422Sdas#ifdef old_fflush_ASL
383219422Sdas#define fflush old_fflush_ASL
384219422Sdas#endif
385219422Sdas
386219422Sdas void
387219422Sdasfflush_ASL(FILE *f)
388219422Sdas{
389219422Sdas	if (f == stderr_ASL) {
390219422Sdas		if (pfbuf_ASL && pfbuf_print_ASL) {
391219422Sdas			(*pfbuf_print_ASL)(pfbuf_ASL);
392219422Sdas			free(pfbuf_ASL);
393219422Sdas			pfbuf_ASL = 0;
394219422Sdas			}
395219422Sdas		}
396219422Sdas	else
397219422Sdas		fflush(f);
398219422Sdas	}
399219422Sdas
400219422Sdas static void
401219422Sdaspf_put(char *buf, int len)
402219422Sdas{
403219422Sdas	size_t x, y;
404219422Sdas	if (!pfbuf_ASL) {
405219422Sdas		x = len + 256;
406219422Sdas		if (x < 512)
407219422Sdas			x = 512;
408219422Sdas		pfbuf_ASL = pfbuf_next = (char*)mymalloc_ASL(pfbuf_len = x);
409219422Sdas		}
410219422Sdas	else if ((y = (pfbuf_next - pfbuf_ASL) + len) >= pfbuf_len) {
411219422Sdas		x = pfbuf_len;
412219422Sdas		while((x <<= 1) <= y);
413219422Sdas		y = pfbuf_next - pfbuf_ASL;
414219422Sdas		pfbuf_ASL = (char*)myralloc_ASL(pfbuf_ASL, x);
415219422Sdas		pfbuf_next = pfbuf_ASL + y;
416219422Sdas		pfbuf_len = x;
417219422Sdas		}
418219422Sdas	memcpy(pfbuf_next, buf, len);
419219422Sdas	pfbuf_next += len;
420219422Sdas	*pfbuf_next = 0;
421219422Sdas	}
422219422Sdas
423219422Sdas static char *
424219422Sdaspfput(Finfo *f, int *rvp)
425219422Sdas{
426219422Sdas	int n;
427219422Sdas	char *ob0 = f->ob0;
428219422Sdas	*rvp += n = (int)(f->obe1 - ob0);
429219422Sdas	pf_put(ob0, n);
430219422Sdas	return ob0;
431219422Sdas	}
432219422Sdas#endif /* PF_BUF */
433219422Sdas
434219422Sdas static char *
435219422SdasFput
436219422Sdas#ifdef KR_headers
437219422Sdas	(f, rvp) Finfo *f; int *rvp;
438219422Sdas#else
439219422Sdas	(Finfo *f, int *rvp)
440219422Sdas#endif
441219422Sdas{
442219422Sdas	char *ob0 = f->ob0;
443219422Sdas
444219422Sdas	*rvp += f->obe1 - ob0;
445219422Sdas	*f->obe1 = 0;
446219422Sdas	fputs(ob0, f->u.cf);
447219422Sdas	return ob0;
448219422Sdas	}
449219422Sdas
450219422Sdas
451219422Sdas#ifdef _windows_
452219422Sdasint stdout_fileno_ASL = 1;
453219422Sdas
454219422Sdas static char *
455219422SdasWput
456219422Sdas#ifdef KR_headers
457219422Sdas	(f, rvp) Finfo *f; int *rvp;
458219422Sdas#else
459219422Sdas	(Finfo *f, int *rvp)
460219422Sdas#endif
461219422Sdas{
462219422Sdas	char *ob0 = f->ob0;
463219422Sdas
464219422Sdas	*rvp += f->obe1 - ob0;
465219422Sdas	*f->obe1 = 0;
466219422Sdas	mwrite(ob0, f->obe1 - ob0);
467219422Sdas	return ob0;
468219422Sdas	}
469219422Sdas#endif /*_windows_*/
470219422Sdas
471219422Sdas
472219422Sdas#ifdef IEEE_MC68k
473219422Sdas#define _0 0
474219422Sdas#define _1 1
475219422Sdas#endif
476219422Sdas#ifdef IEEE_8087
477219422Sdas#define _0 1
478219422Sdas#define _1 0
479219422Sdas#endif
480219422Sdas
481219422Sdas static void
482219422Sdasdfpbits(U *u, FPBits *b)
483219422Sdas{
484219422Sdas	ULong *bits;
485219422Sdas	int ex, i;
486219422Sdas	static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, 0 };
487219422Sdas
488219422Sdas	b->fpi = &fpi0;
489219422Sdas	b->gdtoa = gdtoa;
490219422Sdas	b->sign = u->ui[_0] & 0x80000000L;
491219422Sdas	bits = b->bits;
492219422Sdas	bits[1] = u->ui[_0] & 0xfffff;
493219422Sdas	bits[0] = u->ui[_1];
494219422Sdas	if ( (ex = (u->ui[_0] & 0x7ff00000L) >> 20) !=0) {
495219422Sdas		if (ex == 0x7ff) {
496219422Sdas			/* Infinity or NaN */
497219422Sdas			i = bits[0] | bits[1] ? STRTOG_NaN : STRTOG_Infinite;
498219422Sdas			}
499219422Sdas		else {
500219422Sdas			i = STRTOG_Normal;
501219422Sdas			bits[1] |= 0x100000;
502219422Sdas			}
503219422Sdas		}
504219422Sdas	else if (bits[0] | bits[1]) {
505219422Sdas		i = STRTOG_Denormal;
506219422Sdas		ex = 1;
507219422Sdas		}
508219422Sdas	else
509219422Sdas		i = STRTOG_Zero;
510219422Sdas	b->kind = i;
511219422Sdas	b->ex = ex - (0x3ff + 52);
512219422Sdas	}
513219422Sdas
514219422Sdas#undef _0
515219422Sdas#undef _1
516219422Sdas
517219422Sdas#ifdef Honor_FLT_ROUNDS /*{{*/
518219422Sdas#ifdef Trust_FLT_ROUNDS /*{{*/
519219422Sdas#define RoundCheck if (Rounding == -1) Rounding = Flt_Rounds; if (Rounding != 1){\
520219422Sdas	fpi1 = *fpb.fpi; fpi1.rounding = Rounding; fpb.fpi = &fpi1;}
521219422Sdas#else /*}{*/
522219422Sdas#define RoundCheck if (Rounding == -1) { Rounding = 1; switch((fegetround()) {\
523219422Sdas	  case FE_TOWARDZERO:	Rounding = 0; break;\
524219422Sdas	  case FE_UPWARD:	Rounding = 2; break;\
525219422Sdas	  case FE_DOWNWARD:	Rounding = 3; }}\
526219422Sdas	if (Rounding != 1){\
527219422Sdas	fpi1 = *fpb.fpi; fpi1.rounding = Rounding; fpb.fpi = &fpi1;}
528219422Sdas#endif /*}}*/
529219422Sdas#else /*}{*/
530219422Sdas#define RoundCheck /*nothing*/
531219422Sdas#endif /*}}*/
532219422Sdas
533219422Sdas#ifndef NO_PRINTF_A_FMT /*{*/
534219422Sdas static int
535219422Sdasfpiprec(FPBits *b)	/* return number of hex digits minus 1, or 0 for zero */
536219422Sdas{
537219422Sdas	FPI *fpi;
538219422Sdas	ULong *bits;
539219422Sdas	int i, j, k, m;
540219422Sdas
541219422Sdas	if (b->kind == STRTOG_Zero)
542219422Sdas		return b->ex = 0;
543219422Sdas	fpi = b->fpi;
544219422Sdas	bits = b->bits;
545219422Sdas	for(k = (fpi->nbits - 1) >> 2; k > 0; --k)
546219422Sdas		if ((bits[k >> 3] >> 4*(k & 7)) & 0xf) {
547219422Sdas			m = k >> 3;
548219422Sdas			for(i = 0; i <= m; ++i)
549219422Sdas				if (bits[i]) {
550219422Sdas					if (i > 0) {
551219422Sdas						k -= 8*i;
552219422Sdas						b->ex += 32*i;
553219422Sdas						for(j = i; j <= m; ++j)
554219422Sdas							bits[j-i] = bits[j];
555219422Sdas						}
556219422Sdas					break;
557219422Sdas					}
558219422Sdas			for(i = 0; i < 28 && !((bits[0] >> i) & 0xf); i += 4);
559219422Sdas			if (i) {
560219422Sdas				b->ex += i;
561219422Sdas				m = k >> 3;
562219422Sdas				k -= (i >> 2);
563219422Sdas				for(j = 0;;++j) {
564219422Sdas					bits[j] >>= i;
565219422Sdas					if (j == m)
566219422Sdas						break;
567219422Sdas					bits[j] |= bits[j+1] << (32 - i);
568219422Sdas					}
569219422Sdas				}
570219422Sdas			break;
571219422Sdas			}
572219422Sdas	return k;
573219422Sdas	}
574219422Sdas
575219422Sdas static int
576219422Sdasbround(FPBits *b, int prec, int prec1)	/* round to prec hex digits after the "." */
577219422Sdas{					/* prec1 = incoming precision (after ".") */
578219422Sdas	FPI *fpi = b->fpi;
579219422Sdas	ULong *bits, t;
580219422Sdas	int i, inc, j, k, m, n;
581219422Sdas#ifdef Honor_FLT_ROUNDS
582219422Sdas	int rounding = fpi->rounding;
583219422Sdas
584219422Sdas	if (rounding > FPI_Round_near && b->sign)
585219422Sdas		rounding = FPI_Round_up + FPI_Round_down - rounding;
586219422Sdas	if (rounding == FPI_Round_down)
587219422Sdas		rounding = FPI_Round_zero;
588219422Sdas#endif
589219422Sdas	m = prec1 - prec;
590219422Sdas	bits = b->bits;
591219422Sdas	inc = 0;
592219422Sdas#ifdef Honor_FLT_ROUNDS
593219422Sdas	switch(rounding) {
594219422Sdas		case FPI_Round_up:
595219422Sdas			for(i = 0; i < m; i += 8)
596219422Sdas				if (bits[i>>3])
597219422Sdas					goto inc1;
598219422Sdas			if ((j = i - m) > 0 && bits[(i-8)>>3] << j*4)
599219422Sdas				goto inc1;
600219422Sdas			break;
601219422Sdas		case FPI_Round_near:
602219422Sdas#endif
603219422Sdas			k = m - 1;
604219422Sdas			if ((t = bits[k >> 3] >> (j = (k&7)*4)) & 8) {
605219422Sdas				if (t & 7)
606219422Sdas					goto inc1;
607219422Sdas				if (j && bits[k >> 3] << (32 - j))
608219422Sdas					goto inc1;
609219422Sdas				while(k >= 8) {
610219422Sdas					k -= 8;
611219422Sdas					if (bits[k>>3]) {
612219422Sdas inc1:
613219422Sdas						inc = 1;
614219422Sdas						goto haveinc;
615219422Sdas						}
616219422Sdas					}
617219422Sdas				}
618219422Sdas#ifdef Honor_FLT_ROUNDS
619219422Sdas		}
620219422Sdas#endif
621219422Sdas haveinc:
622219422Sdas	b->ex += m*4;
623219422Sdas	i = m >> 3;
624219422Sdas	k = prec1 >> 3;
625219422Sdas	j = i;
626219422Sdas	if ((n = 4*(m & 7)))
627219422Sdas		for(;; ++j) {
628219422Sdas			bits[j-i] = bits[j] >> n;
629219422Sdas			if (j == k)
630219422Sdas				break;
631219422Sdas			bits[j-i] |= bits[j+1] << (32-n);
632219422Sdas			}
633219422Sdas	else
634219422Sdas		for(;; ++j) {
635219422Sdas			bits[j-i] = bits[j];
636219422Sdas			if (j == k)
637219422Sdas				break;
638219422Sdas			}
639219422Sdas	k = prec >> 3;
640219422Sdas	if (inc) {
641219422Sdas		for(j = 0; !(++bits[j] & 0xffffffff); ++j);
642219422Sdas		if (j > k) {
643219422Sdas onebit:
644219422Sdas			bits[0] = 1;
645219422Sdas			b->ex += 4*prec;
646219422Sdas			return 1;
647219422Sdas			}
648219422Sdas		if ((j = prec & 7) < 7 && bits[k] >> (j+1)*4)
649219422Sdas			goto onebit;
650219422Sdas		}
651219422Sdas	for(i = 0; !(bits[i >> 3] & (0xf << 4*(i&7))); ++i);
652219422Sdas	if (i) {
653219422Sdas		b->ex += 4*i;
654219422Sdas		prec -= i;
655219422Sdas		j = i >> 3;
656219422Sdas		i &= 7;
657219422Sdas		i *= 4;
658219422Sdas		for(m = j; ; ++m) {
659219422Sdas			bits[m-j] = bits[m] >> i;
660219422Sdas			if (m == k)
661219422Sdas				break;
662219422Sdas			bits[m-j] |= bits[m+1] << (32 - i);
663219422Sdas			}
664219422Sdas		}
665219422Sdas	return prec;
666219422Sdas	}
667219422Sdas#endif /*}NO_PRINTF_A_FMT*/
668219422Sdas
669219422Sdas#define put(x) { *outbuf++ = x; if (outbuf == obe) outbuf = (*fput)(f,&rv); }
670219422Sdas
671219422Sdas static int
672219422Sdasx_sprintf
673219422Sdas#ifdef KR_headers
674219422Sdas	(obe, fput, f, fmt, ap)
675219422Sdas	char *obe, *fmt; Finfo *f; Putfunc fput; va_list ap;
676219422Sdas#else
677219422Sdas	(char *obe, Putfunc fput, Finfo *f, const char *fmt, va_list ap)
678219422Sdas#endif
679219422Sdas{
680219422Sdas	FPBits fpb;
681219422Sdas	Fpbits fpbits;
682219422Sdas	U u;
683219422Sdas	char *digits, *ob0, *outbuf, *s, *s0, *se;
684219422Sdas	Const char *fmt0;
685219422Sdas	char buf[32];
686219422Sdas	long i;
687219422Sdas	unsigned long j, ul;
688219422Sdas	double x;
689219422Sdas	int alt, base, c, decpt, dot, conv, i1, k, lead0, left,
690219422Sdas		len, prec, prec1, psign, rv, sign, width;
691219422Sdas	long Ltmp, *ip;
692219422Sdas	short sh;
693219422Sdas	unsigned short us;
694219422Sdas	unsigned int ui;
695219422Sdas#ifdef Honor_FLT_ROUNDS
696219422Sdas	FPI fpi1;
697219422Sdas	int Rounding = -1;
698219422Sdas#endif
699219422Sdas#ifndef NO_PRINTF_A_FMT /*{*/
700219422Sdas	int bex, bw;
701219422Sdas#endif /*} NO_PRINTF_A_FMT */
702219422Sdas	static char hex[] = "0123456789abcdefpx";
703219422Sdas	static char Hex[] = "0123456789ABCDEFPX";
704219422Sdas
705219422Sdas	ob0 = outbuf = f->ob0;
706219422Sdas	rv = 0;
707219422Sdas	for(;;) {
708219422Sdas		for(;;) {
709219422Sdas			switch(c = *fmt++) {
710219422Sdas				case 0:
711219422Sdas					goto done;
712219422Sdas				case '%':
713219422Sdas					break;
714219422Sdas				default:
715219422Sdas					put(c)
716219422Sdas					continue;
717219422Sdas				}
718219422Sdas			break;
719219422Sdas			}
720219422Sdas		alt=dot=lead0=left=len=prec=psign=sign=width=0;
721219422Sdas		fpbits = dfpbits;
722219422Sdas		fmt0 = fmt;
723219422Sdas fmtloop:
724219422Sdas		switch(conv = *fmt++) {
725219422Sdas			case ' ':
726219422Sdas			case '+':
727219422Sdas				sign = conv;
728219422Sdas				goto fmtloop;
729219422Sdas			case '-':
730219422Sdas				if (dot)
731219422Sdas					psign = 1;
732219422Sdas				else
733219422Sdas					left = 1;
734219422Sdas				goto fmtloop;
735219422Sdas			case '#':
736219422Sdas				alt = 1;
737219422Sdas				goto fmtloop;
738219422Sdas			case '0':
739219422Sdas				if (!lead0 && !dot) {
740219422Sdas					lead0 = 1;
741219422Sdas					goto fmtloop;
742219422Sdas					}
743219422Sdas			case '1':
744219422Sdas			case '2':
745219422Sdas			case '3':
746219422Sdas			case '4':
747219422Sdas			case '5':
748219422Sdas			case '6':
749219422Sdas			case '7':
750219422Sdas			case '8':
751219422Sdas			case '9':
752219422Sdas				k = conv - '0';
753219422Sdas				while((c = *fmt) >= '0' && c <= '9') {
754219422Sdas					k = 10*k + c - '0';
755219422Sdas					fmt++;
756219422Sdas					}
757219422Sdas				if (dot)
758219422Sdas					prec = psign ? -k : k;
759219422Sdas				else
760219422Sdas					width = k;
761219422Sdas				goto fmtloop;
762219422Sdas			case 'h':
763219422Sdas				len = 2;
764219422Sdas				goto fmtloop;
765219422Sdas			case 'L':
766219422Sdas#ifdef GDTOA_LD_fpbits /*{*/
767219422Sdas				fpbits = GDTOA_LD_fpbits;
768219422Sdas#ifdef GDTOA_Q_fpbits
769219422Sdas				if (*fmt == 'q') {
770219422Sdas					++fmt;
771219422Sdas					fpbits = Qfpbits;
772219422Sdas					}
773219422Sdas#endif
774219422Sdas#endif /*}*/
775219422Sdas				goto fmtloop;
776219422Sdas			case 'l':
777219422Sdas				len = 1;
778219422Sdas				goto fmtloop;
779219422Sdas			case '.':
780219422Sdas				dot = 1;
781219422Sdas				goto fmtloop;
782219422Sdas			case '*':
783219422Sdas				k = va_arg(ap, int);
784219422Sdas				if (dot)
785219422Sdas					prec = k;
786219422Sdas				else {
787219422Sdas					if (k < 0) {
788219422Sdas						sign = '-';
789219422Sdas						k = -k;
790219422Sdas						}
791219422Sdas					width = k;
792219422Sdas					}
793219422Sdas				goto fmtloop;
794219422Sdas			case 'c':
795219422Sdas				c = va_arg(ap, int);
796219422Sdas				put(c)
797219422Sdas				continue;
798219422Sdas			case '%':
799219422Sdas				put(conv)
800219422Sdas				continue;
801219422Sdas			case 'u':
802219422Sdas				switch(len) {
803219422Sdas				  case 0:
804219422Sdas					ui = va_arg(ap, int);
805219422Sdas					i = ui;
806219422Sdas					break;
807219422Sdas				  case 1:
808219422Sdas					i = va_arg(ap, long);
809219422Sdas					break;
810219422Sdas				  case 2:
811219422Sdas					us = va_arg(ap, int);
812219422Sdas					i = us;
813219422Sdas				  }
814219422Sdas				sign = 0;
815219422Sdas				goto have_i;
816219422Sdas			case 'i':
817219422Sdas			case 'd':
818219422Sdas				switch(len) {
819219422Sdas				  case 0:
820219422Sdas					k = va_arg(ap, int);
821219422Sdas					i = k;
822219422Sdas					break;
823219422Sdas				  case 1:
824219422Sdas					i = va_arg(ap, long);
825219422Sdas					break;
826219422Sdas				  case 2:
827219422Sdas					sh = va_arg(ap, int);
828219422Sdas					i = sh;
829219422Sdas				  }
830219422Sdas				if (i < 0) {
831219422Sdas					sign = '-';
832219422Sdas					i = -i;
833219422Sdas					}
834219422Sdas have_i:
835219422Sdas				base = 10;
836219422Sdas				ul = i;
837219422Sdas				digits = hex;
838219422Sdas baseloop:
839219422Sdas				if (dot)
840219422Sdas					lead0 = 0;
841219422Sdas				s = buf;
842219422Sdas				if (!ul)
843219422Sdas					alt = 0;
844219422Sdas				do {
845219422Sdas					j = ULDIV(ul, base);
846219422Sdas					*s++ = digits[ul - base*j];
847219422Sdas					}
848219422Sdas					while((ul = j));
849219422Sdas				prec -= c = s - buf;
850219422Sdas				if (alt && conv == 'o' && prec <= 0)
851219422Sdas					prec = 1;
852219422Sdas				if ((width -= c) > 0) {
853219422Sdas					if (prec > 0)
854219422Sdas						width -= prec;
855219422Sdas					if (sign)
856219422Sdas						width--;
857219422Sdas					if (alt == 2)
858219422Sdas						width--;
859219422Sdas					}
860219422Sdas				if (left) {
861219422Sdas					if (alt == 2)
862219422Sdas						put('0') /* for 0x */
863219422Sdas					if (sign)
864219422Sdas						put(sign)
865219422Sdas					while(--prec >= 0)
866219422Sdas						put('0')
867219422Sdas					do put(*--s)
868219422Sdas						while(s > buf);
869219422Sdas					while(--width >= 0)
870219422Sdas						put(' ')
871219422Sdas					continue;
872219422Sdas					}
873219422Sdas				if (width > 0) {
874219422Sdas					if (lead0) {
875219422Sdas						if (alt == 2)
876219422Sdas							put('0')
877219422Sdas						if (sign)
878219422Sdas							put(sign)
879219422Sdas						while(--width >= 0)
880219422Sdas							put('0')
881219422Sdas						goto s_loop;
882219422Sdas						}
883219422Sdas					else
884219422Sdas						while(--width >= 0)
885219422Sdas							put(' ')
886219422Sdas					}
887219422Sdas				if (alt == 2)
888219422Sdas					put('0')
889219422Sdas				if (sign)
890219422Sdas					put(sign)
891219422Sdas s_loop:
892219422Sdas				while(--prec >= 0)
893219422Sdas					put('0')
894219422Sdas				do put(*--s)
895219422Sdas					while(s > buf);
896219422Sdas				continue;
897219422Sdas			case 'n':
898219422Sdas				ip = va_arg(ap, long*);
899219422Sdas				if (!ip)
900219422Sdas					ip = &Ltmp;
901219422Sdas				c = outbuf - ob0 + rv;
902219422Sdas				switch(len) {
903219422Sdas				  case 0:
904219422Sdas					*(int*)ip = c;
905219422Sdas					break;
906219422Sdas				  case 1:
907219422Sdas					*ip = c;
908219422Sdas					break;
909219422Sdas				  case 2:
910219422Sdas					*(short*)ip = c;
911219422Sdas				  }
912219422Sdas				break;
913219422Sdas			case 'p':
914219422Sdas				len = alt = 1;
915219422Sdas				/* no break */
916219422Sdas			case 'x':
917219422Sdas				digits = hex;
918219422Sdas				goto more_x;
919219422Sdas			case 'X':
920219422Sdas				digits = Hex;
921219422Sdas more_x:
922219422Sdas				if (alt) {
923219422Sdas					alt = 2;
924219422Sdas					sign = conv;
925219422Sdas					}
926219422Sdas				else
927219422Sdas					sign = 0;
928219422Sdas				base = 16;
929219422Sdas get_u:
930219422Sdas				switch(len) {
931219422Sdas				  case 0:
932219422Sdas					ui = va_arg(ap, int);
933219422Sdas					ul = ui;
934219422Sdas					break;
935219422Sdas				  case 1:
936219422Sdas					ul = va_arg(ap, long);
937219422Sdas					break;
938219422Sdas				  case 2:
939219422Sdas					us = va_arg(ap, int);
940219422Sdas					ul = us;
941219422Sdas				  }
942219422Sdas				if (!ul)
943219422Sdas					sign = alt = 0;
944219422Sdas				goto baseloop;
945219422Sdas			case 'o':
946219422Sdas				base = 8;
947219422Sdas				digits = hex;
948219422Sdas				goto get_u;
949219422Sdas			case 's':
950219422Sdas				s0 = 0;
951219422Sdas				s = va_arg(ap, char*);
952219422Sdas				if (!s)
953219422Sdas					s = "<NULL>";
954219422Sdas				if (prec < 0)
955219422Sdas					prec = 0;
956219422Sdas have_s:
957219422Sdas				if (dot) {
958219422Sdas					for(c = 0; c < prec; c++)
959219422Sdas						if (!s[c])
960219422Sdas							break;
961219422Sdas					prec = c;
962219422Sdas					}
963219422Sdas				else
964219422Sdas					prec = strlen(s);
965219422Sdas				width -= prec;
966219422Sdas				if (!left)
967219422Sdas					while(--width >= 0)
968219422Sdas						put(' ')
969219422Sdas				while(--prec >= 0)
970219422Sdas					put(*s++)
971219422Sdas				while(--width >= 0)
972219422Sdas					put(' ')
973219422Sdas				if (s0)
974219422Sdas					freedtoa(s0);
975219422Sdas				continue;
976219422Sdas			case 'f':
977219422Sdas				if (!dot)
978219422Sdas					prec = 6;
979219422Sdas#ifdef GDTOA_H_INCLUDED
980219422Sdas				if (fpbits == dfpbits) {
981219422Sdas#endif
982219422Sdas				x = va_arg(ap, double);
983219422Sdas				s = s0 = dtoa(x, 3, prec, &decpt, &fpb.sign, &se);
984219422Sdas#ifdef GDTOA_H_INCLUDED
985219422Sdas					}
986219422Sdas				else {
987219422Sdas#ifdef GDTOA_both
988219422Sdas					if (fpbits == GDTOA_LD_fpbits)
989219422Sdas						u.ld = va_arg(ap, long double);
990219422Sdas					else
991219422Sdas						u.Qd = va_arg(ap, GDTOA_Qtype);
992219422Sdas#else
993219422Sdas					u.ld = va_arg(ap, long double);
994219422Sdas#endif
995219422Sdas					fpbits(&u, &fpb);
996219422Sdas					RoundCheck
997219422Sdas					s = s0 = fpb.gdtoa(fpb.fpi, fpb.ex, fpb.bits,
998219422Sdas						&fpb.kind, 3, prec, &decpt, &se);
999219422Sdas					}
1000219422Sdas#endif
1001219422Sdas				if (decpt == 9999) {
1002219422Sdas fmt9999:
1003219422Sdas					dot = prec = alt = 0;
1004219422Sdas					if (*s == 'N')
1005219422Sdas						goto have_s;
1006219422Sdas					decpt = strlen(s);
1007219422Sdas					}
1008219422Sdas f_fmt:
1009219422Sdas				if (fpb.sign && (x||sign))
1010219422Sdas					sign = '-';
1011219422Sdas				if (prec > 0)
1012219422Sdas					width -= prec;
1013219422Sdas				if (width > 0) {
1014219422Sdas					if (sign)
1015219422Sdas						--width;
1016219422Sdas					if (decpt <= 0) {
1017219422Sdas						--width;
1018219422Sdas						if (prec > 0)
1019219422Sdas							--width;
1020219422Sdas						}
1021219422Sdas					else {
1022219422Sdas						if (s == se)
1023219422Sdas							decpt = 1;
1024219422Sdas						width -= decpt;
1025219422Sdas						if (prec > 0 || alt)
1026219422Sdas							--width;
1027219422Sdas						}
1028219422Sdas					}
1029219422Sdas				if (width > 0 && !left) {
1030219422Sdas					if (lead0) {
1031219422Sdas						if (sign)
1032219422Sdas							put(sign)
1033219422Sdas						sign = 0;
1034219422Sdas						do put('0')
1035219422Sdas							while(--width > 0);
1036219422Sdas						}
1037219422Sdas					else do put(' ')
1038219422Sdas						while(--width > 0);
1039219422Sdas					}
1040219422Sdas				if (sign)
1041219422Sdas					put(sign)
1042219422Sdas				if (decpt <= 0) {
1043219422Sdas					put('0')
1044219422Sdas					if (prec > 0 || alt)
1045219422Sdas						put('.')
1046219422Sdas					while(decpt < 0) {
1047219422Sdas						put('0')
1048219422Sdas						prec--;
1049219422Sdas						decpt++;
1050219422Sdas						}
1051219422Sdas					}
1052219422Sdas				else {
1053219422Sdas					do {
1054219422Sdas						if ((c = *s))
1055219422Sdas							s++;
1056219422Sdas						else
1057219422Sdas							c = '0';
1058219422Sdas						put(c)
1059219422Sdas						}
1060219422Sdas						while(--decpt > 0);
1061219422Sdas					if (prec > 0 || alt)
1062219422Sdas						put('.')
1063219422Sdas					}
1064219422Sdas				while(--prec >= 0) {
1065219422Sdas					if ((c = *s))
1066219422Sdas						s++;
1067219422Sdas					else
1068219422Sdas						c = '0';
1069219422Sdas					put(c)
1070219422Sdas					}
1071219422Sdas				while(--width >= 0)
1072219422Sdas					put(' ')
1073219422Sdas				if (s0)
1074219422Sdas					freedtoa(s0);
1075219422Sdas				continue;
1076219422Sdas			case 'G':
1077219422Sdas			case 'g':
1078219422Sdas				if (!dot)
1079219422Sdas					prec = 6;
1080219422Sdas				if (prec < 0)
1081219422Sdas					prec = 0;
1082219422Sdas#ifdef GDTOA_H_INCLUDED
1083219422Sdas				if (fpbits == dfpbits) {
1084219422Sdas#endif
1085219422Sdas					x = va_arg(ap, double);
1086219422Sdas					s = s0 = dtoa(x, prec ? 2 : 0, prec, &decpt,
1087219422Sdas						&fpb.sign, &se);
1088219422Sdas#ifdef GDTOA_H_INCLUDED
1089219422Sdas					}
1090219422Sdas				else {
1091219422Sdas#ifdef GDTOA_both
1092219422Sdas					if (fpbits == GDTOA_LD_fpbits)
1093219422Sdas						u.ld = va_arg(ap, long double);
1094219422Sdas					else
1095219422Sdas						u.Qd = va_arg(ap, GDTOA_Qtype);
1096219422Sdas#else
1097219422Sdas					u.ld = va_arg(ap, long double);
1098219422Sdas#endif
1099219422Sdas					fpbits(&u, &fpb);
1100219422Sdas					RoundCheck
1101219422Sdas					s = s0 = fpb.gdtoa(fpb.fpi, fpb.ex, fpb.bits,
1102219422Sdas						&fpb.kind, prec ? 2 : 0, prec, &decpt, &se);
1103219422Sdas					}
1104219422Sdas#endif
1105219422Sdas				if (decpt == 9999)
1106219422Sdas					goto fmt9999;
1107219422Sdas				c = se - s;
1108219422Sdas				prec1 = prec;
1109219422Sdas				if (!prec) {
1110219422Sdas					prec = c;
1111219422Sdas					prec1 = c + (s[1] || alt ? 5 : 4);
1112219422Sdas					/* %.0g gives 10 rather than 1e1 */
1113219422Sdas					}
1114219422Sdas				if (decpt > -4 && decpt <= prec1) {
1115219422Sdas					if (alt)
1116219422Sdas						prec -= decpt;
1117219422Sdas					else
1118219422Sdas						prec = c - decpt;
1119219422Sdas					if (prec < 0)
1120219422Sdas						prec = 0;
1121219422Sdas					goto f_fmt;
1122219422Sdas					}
1123219422Sdas				conv -= 2;
1124219422Sdas				if (!alt && prec > c)
1125219422Sdas					prec = c;
1126219422Sdas				--prec;
1127219422Sdas				goto e_fmt;
1128219422Sdas			case 'e':
1129219422Sdas			case 'E':
1130219422Sdas				if (!dot)
1131219422Sdas					prec = 6;
1132219422Sdas				if (prec < 0)
1133219422Sdas					prec = 0;
1134219422Sdas#ifdef GDTOA_H_INCLUDED
1135219422Sdas				if (fpbits == dfpbits) {
1136219422Sdas#endif
1137219422Sdas					x = va_arg(ap, double);
1138219422Sdas					s = s0 = dtoa(x, prec ? 2 : 0, prec+1, &decpt,
1139219422Sdas						&fpb.sign, &se);
1140219422Sdas#ifdef GDTOA_H_INCLUDED
1141219422Sdas					}
1142219422Sdas				else {
1143219422Sdas#ifdef GDTOA_both
1144219422Sdas					if (fpbits == GDTOA_LD_fpbits)
1145219422Sdas						u.ld = va_arg(ap, long double);
1146219422Sdas					else
1147219422Sdas						u.Qd = va_arg(ap, GDTOA_Qtype);
1148219422Sdas#else
1149219422Sdas					u.ld = va_arg(ap, long double);
1150219422Sdas#endif
1151219422Sdas					fpbits(&u, &fpb);
1152219422Sdas					RoundCheck
1153219422Sdas					s = s0 = fpb.gdtoa(fpb.fpi, fpb.ex, fpb.bits,
1154219422Sdas						&fpb.kind, prec ? 2 : 0, prec, &decpt, &se);
1155219422Sdas					}
1156219422Sdas#endif
1157219422Sdas				if (decpt == 9999)
1158219422Sdas					goto fmt9999;
1159219422Sdas e_fmt:
1160219422Sdas				if (fpb.sign && (x||sign))
1161219422Sdas					sign = '-';
1162219422Sdas				if ((width -= prec + 5) > 0) {
1163219422Sdas					if (sign)
1164219422Sdas						--width;
1165219422Sdas					if (prec || alt)
1166219422Sdas						--width;
1167219422Sdas					}
1168219422Sdas				if ((c = --decpt) < 0)
1169219422Sdas					c = -c;
1170219422Sdas				while(c >= 100) {
1171219422Sdas					--width;
1172219422Sdas					c /= 10;
1173219422Sdas					}
1174219422Sdas				if (width > 0 && !left) {
1175219422Sdas					if (lead0) {
1176219422Sdas						if (sign)
1177219422Sdas							put(sign)
1178219422Sdas						sign = 0;
1179219422Sdas						do put('0')
1180219422Sdas							while(--width > 0);
1181219422Sdas						}
1182219422Sdas					else do put(' ')
1183219422Sdas						while(--width > 0);
1184219422Sdas					}
1185219422Sdas				if (sign)
1186219422Sdas					put(sign)
1187219422Sdas				put(*s++)
1188219422Sdas				if (prec || alt)
1189219422Sdas					put('.')
1190219422Sdas				while(--prec >= 0) {
1191219422Sdas					if ((c = *s))
1192219422Sdas						s++;
1193219422Sdas					else
1194219422Sdas						c = '0';
1195219422Sdas					put(c)
1196219422Sdas					}
1197219422Sdas				put(conv)
1198219422Sdas				if (decpt < 0) {
1199219422Sdas					put('-')
1200219422Sdas					decpt = -decpt;
1201219422Sdas					}
1202219422Sdas				else
1203219422Sdas					put('+')
1204219422Sdas				for(c = 2, k = 10; 10*k <= decpt; c++, k *= 10);
1205219422Sdas				for(;;) {
1206219422Sdas					i1 = decpt / k;
1207219422Sdas					put(i1 + '0')
1208219422Sdas					if (--c <= 0)
1209219422Sdas						break;
1210219422Sdas					decpt -= i1*k;
1211219422Sdas					decpt *= 10;
1212219422Sdas					}
1213219422Sdas				while(--width >= 0)
1214219422Sdas					put(' ')
1215219422Sdas				freedtoa(s0);
1216219422Sdas				continue;
1217219422Sdas#ifndef NO_PRINTF_A_FMT
1218219422Sdas			case 'a':
1219219422Sdas				digits = hex;
1220219422Sdas				goto more_a;
1221219422Sdas			case 'A':
1222219422Sdas				digits = Hex;
1223219422Sdas more_a:
1224219422Sdas#ifdef GDTOA_H_INCLUDED /*{{*/
1225219422Sdas				if (fpbits == dfpbits)
1226219422Sdas					u.d = va_arg(ap, double);
1227219422Sdas#ifdef GDTOA_both /*{*/
1228219422Sdas				else if (fpbits == GDTOA_LD_fpbits)
1229219422Sdas					u.ld = va_arg(ap, long double);
1230219422Sdas				else
1231219422Sdas					u.Qd = va_arg(ap, GDTOA_Qtype);
1232219422Sdas#else
1233219422Sdas				else
1234219422Sdas					u.ld = va_arg(ap, long double);
1235219422Sdas#endif /*}*/
1236219422Sdas#else /*}{*/
1237219422Sdas				u.d = va_arg(ap, double);
1238219422Sdas#endif /*}}*/
1239219422Sdas				fpbits(&u, &fpb);
1240219422Sdas				if (fpb.kind == STRTOG_Infinite) {
1241219422Sdas					s = "Infinity";
1242219422Sdas					s0 = 0;
1243219422Sdas					goto fmt9999;
1244219422Sdas					}
1245219422Sdas				if (fpb.kind == STRTOG_NaN) {
1246219422Sdas					s = "NaN";
1247219422Sdas					s0 = 0;
1248219422Sdas					goto fmt9999;
1249219422Sdas					}
1250219422Sdas				prec1 = fpiprec(&fpb);
1251219422Sdas				if (dot && prec < prec1)
1252219422Sdas					prec1 = bround(&fpb, prec, prec1);
1253219422Sdas				bw = 1;
1254219422Sdas				bex = fpb.ex + 4*prec1;
1255219422Sdas				if (bex) {
1256219422Sdas					if ((i1 = bex) < 0)
1257219422Sdas						i1 = -i1;
1258219422Sdas					while(i1 >= 10) {
1259219422Sdas						++bw;
1260219422Sdas						i1 /= 10;
1261219422Sdas						}
1262219422Sdas					}
1263219422Sdas				if (fpb.sign && (sign || fpb.kind != STRTOG_Zero))
1264219422Sdas					sign = '-';
1265219422Sdas				if ((width -= bw + 5) > 0) {
1266219422Sdas					if (sign)
1267219422Sdas						--width;
1268219422Sdas					if (prec1 || alt)
1269219422Sdas						--width;
1270219422Sdas					}
1271219422Sdas				if ((width -= prec1) > 0 && !left && !lead0) {
1272219422Sdas					do put(' ')
1273219422Sdas						while(--width > 0);
1274219422Sdas					}
1275219422Sdas				if (sign)
1276219422Sdas					put(sign)
1277219422Sdas				put('0')
1278219422Sdas				put(digits[17])
1279219422Sdas				if (lead0 && width > 0 && !left) {
1280219422Sdas					do put('0')
1281219422Sdas						while(--width > 0);
1282219422Sdas					}
1283219422Sdas				i1 = prec1 & 7;
1284219422Sdas				k = prec1 >> 3;
1285219422Sdas				put(digits[(fpb.bits[k] >> 4*i1) & 0xf])
1286219422Sdas				if (prec1 > 0 || alt)
1287219422Sdas					put('.')
1288219422Sdas				if (prec1 > 0) {
1289219422Sdas					prec -= prec1;
1290219422Sdas					while(prec1 > 0) {
1291219422Sdas						if (--i1 < 0) {
1292219422Sdas							if (--k < 0)
1293219422Sdas								break;
1294219422Sdas							i1 = 7;
1295219422Sdas							}
1296219422Sdas						put(digits[(fpb.bits[k] >> 4*i1) & 0xf])
1297219422Sdas						--prec1;
1298219422Sdas						}
1299219422Sdas					if (alt && prec > 0)
1300219422Sdas						do put(0)
1301219422Sdas							while(--prec > 0);
1302219422Sdas					}
1303219422Sdas				put(digits[16])
1304219422Sdas				if (bex < 0) {
1305219422Sdas					put('-')
1306219422Sdas					bex = -bex;
1307219422Sdas					}
1308219422Sdas				else
1309219422Sdas					put('+')
1310219422Sdas				for(c = 1; 10*c <= bex; c *= 10);
1311219422Sdas				for(;;) {
1312219422Sdas					i1 = bex / c;
1313219422Sdas					put('0' + i1)
1314219422Sdas					if (!--bw)
1315219422Sdas						break;
1316219422Sdas					bex -= i1 * c;
1317219422Sdas					bex *= 10;
1318219422Sdas					}
1319219422Sdas				while(--width >= 0)
1320219422Sdas					put(' ')
1321219422Sdas				continue;
1322219422Sdas#endif /* NO_PRINTF_A_FMT */
1323219422Sdas			default:
1324219422Sdas				put('%')
1325219422Sdas				while(fmt0 < fmt)
1326219422Sdas					put(*fmt0++)
1327219422Sdas				continue;
1328219422Sdas			}
1329219422Sdas		}
1330219422Sdas done:
1331219422Sdas	*outbuf = 0;
1332219422Sdas	return (f->lastlen = outbuf - ob0) + rv;
1333219422Sdas	}
1334219422Sdas
1335219422Sdas#define Bsize 256
1336219422Sdas
1337219422Sdas int
1338219422SdasPrintf
1339219422Sdas#ifdef KR_headers
1340219422Sdas	(va_alist)
1341219422Sdas va_dcl
1342219422Sdas{
1343219422Sdas	char *fmt;
1344219422Sdas
1345219422Sdas	va_list ap;
1346219422Sdas	int rv;
1347219422Sdas	Finfo f;
1348219422Sdas	char buf[Bsize];
1349219422Sdas
1350219422Sdas	va_start(ap);
1351219422Sdas	fmt = va_arg(ap, char*);
1352219422Sdas	/*}*/
1353219422Sdas#else
1354219422Sdas	(const char *fmt, ...)
1355219422Sdas{
1356219422Sdas	va_list ap;
1357219422Sdas	int rv;
1358219422Sdas	Finfo f;
1359219422Sdas	char buf[Bsize];
1360219422Sdas
1361219422Sdas	va_start(ap, fmt);
1362219422Sdas#endif
1363219422Sdas	f.u.cf = stdout;
1364219422Sdas	f.ob0 = buf;
1365219422Sdas	f.obe1 = buf + Bsize - 1;
1366219422Sdas#ifdef _windows_
1367219422Sdas	if (fileno(stdout) == stdout_fileno_ASL) {
1368219422Sdas		rv = x_sprintf(f.obe1, Wput, &f, fmt, ap);
1369219422Sdas		mwrite(buf, f.lastlen);
1370219422Sdas		}
1371219422Sdas	else
1372219422Sdas#endif
1373219422Sdas#ifdef PF_BUF
1374219422Sdas	if (stdout == stderr_ASL) {
1375219422Sdas		rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
1376219422Sdas		pf_put(buf, f.lastlen);
1377219422Sdas		}
1378219422Sdas	else
1379219422Sdas#endif
1380219422Sdas		{
1381219422Sdas		rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
1382219422Sdas		fputs(buf, stdout);
1383219422Sdas		}
1384219422Sdas	va_end(ap);
1385219422Sdas	return rv;
1386219422Sdas	}
1387219422Sdas
1388219422Sdas static char *
1389219422SdasSput
1390219422Sdas#ifdef KR_headers
1391219422Sdas	(f, rvp) Finfo *f; int *rvp;
1392219422Sdas#else
1393219422Sdas	(Finfo *f, int *rvp)
1394219422Sdas#endif
1395219422Sdas{
1396219422Sdas	if (Printf("\nBUG! Sput called!\n", f, rvp))
1397219422Sdas		/* pass vp, rvp and return 0 to shut diagnostics off */
1398219422Sdas		exit(250);
1399219422Sdas	return 0;
1400219422Sdas	}
1401219422Sdas
1402219422Sdas int
1403219422SdasSprintf
1404219422Sdas#ifdef KR_headers
1405219422Sdas	(va_alist)
1406219422Sdas va_dcl
1407219422Sdas{
1408219422Sdas	char *s, *fmt;
1409219422Sdas	va_list ap;
1410219422Sdas	int rv;
1411219422Sdas	Finfo f;
1412219422Sdas
1413219422Sdas	va_start(ap);
1414219422Sdas	s = va_arg(ap, char*);
1415219422Sdas	fmt = va_arg(ap, char*);
1416219422Sdas	/*}*/
1417219422Sdas#else
1418219422Sdas	(char *s, const char *fmt, ...)
1419219422Sdas{
1420219422Sdas	va_list ap;
1421219422Sdas	int rv;
1422219422Sdas	Finfo f;
1423219422Sdas
1424219422Sdas	va_start(ap, fmt);
1425219422Sdas#endif
1426219422Sdas	f.ob0 = s;
1427219422Sdas	rv = x_sprintf(s, Sput, &f, fmt, ap);
1428219422Sdas	va_end(ap);
1429219422Sdas	return rv;
1430219422Sdas	}
1431219422Sdas
1432219422Sdas int
1433219422SdasFprintf
1434219422Sdas#ifdef KR_headers
1435219422Sdas	(va_alist)
1436219422Sdas va_dcl
1437219422Sdas{
1438219422Sdas	FILE *F;
1439219422Sdas	char *s, *fmt;
1440219422Sdas	va_list ap;
1441219422Sdas	int rv;
1442219422Sdas	Finfo f;
1443219422Sdas	char buf[Bsize];
1444219422Sdas
1445219422Sdas	va_start(ap);
1446219422Sdas	F = va_arg(ap, FILE*);
1447219422Sdas	fmt = va_arg(ap, char*);
1448219422Sdas	/*}*/
1449219422Sdas#else
1450219422Sdas	(FILE *F, const char *fmt, ...)
1451219422Sdas{
1452219422Sdas	va_list ap;
1453219422Sdas	int rv;
1454219422Sdas	Finfo f;
1455219422Sdas	char buf[Bsize];
1456219422Sdas
1457219422Sdas	va_start(ap, fmt);
1458219422Sdas#endif
1459219422Sdas	f.u.cf = F;
1460219422Sdas	f.ob0 = buf;
1461219422Sdas	f.obe1 = buf + Bsize - 1;
1462219422Sdas#ifdef MESS
1463219422Sdas	if (stdout_or_err(F)) {
1464219422Sdas#ifdef _windows_
1465219422Sdas		if (fileno(stdout) == stdout_fileno_ASL) {
1466219422Sdas			rv = x_sprintf(f.obe1, Wput, &f, fmt, ap);
1467219422Sdas			mwrite(buf, f.lastlen);
1468219422Sdas			}
1469219422Sdas		else
1470219422Sdas#endif
1471219422Sdas#ifdef PF_BUF
1472219422Sdas		if (F == stderr_ASL) {
1473219422Sdas			rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
1474219422Sdas			pf_put(buf, f.lastlen);
1475219422Sdas			}
1476219422Sdas		else
1477219422Sdas#endif
1478219422Sdas			{
1479219422Sdas			rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
1480219422Sdas			fputs(buf, F);
1481219422Sdas			}
1482219422Sdas		}
1483219422Sdas	else
1484219422Sdas#endif /*MESS*/
1485219422Sdas		{
1486219422Sdas#ifdef PF_BUF
1487219422Sdas		if (F == stderr_ASL) {
1488219422Sdas			rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
1489219422Sdas			pf_put(buf, f.lastlen);
1490219422Sdas			}
1491219422Sdas	else
1492219422Sdas#endif
1493219422Sdas			{
1494219422Sdas			rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
1495219422Sdas			fputs(buf, F);
1496219422Sdas			}
1497219422Sdas		}
1498219422Sdas	va_end(ap);
1499219422Sdas	return rv;
1500219422Sdas	}
1501219422Sdas
1502219422Sdas int
1503219422SdasVsprintf
1504219422Sdas#ifdef KR_headers
1505219422Sdas	(s, fmt, ap) char *s, *fmt; va_list ap;
1506219422Sdas#else
1507219422Sdas	(char *s, const char *fmt, va_list ap)
1508219422Sdas#endif
1509219422Sdas{
1510219422Sdas	Finfo f;
1511219422Sdas	return x_sprintf(f.ob0 = s, Sput, &f, fmt, ap);
1512219422Sdas	}
1513219422Sdas
1514219422Sdas int
1515219422SdasVfprintf
1516219422Sdas#ifdef KR_headers
1517219422Sdas	(F, fmt, ap) FILE *F; char *fmt; va_list ap;
1518219422Sdas#else
1519219422Sdas	(FILE *F, const char *fmt, va_list ap)
1520219422Sdas#endif
1521219422Sdas{
1522219422Sdas	char buf[Bsize];
1523219422Sdas	int rv;
1524219422Sdas	Finfo f;
1525219422Sdas
1526219422Sdas	f.u.cf = F;
1527219422Sdas	f.ob0 = buf;
1528219422Sdas	f.obe1 = buf + Bsize - 1;
1529219422Sdas#ifdef MESS
1530219422Sdas	if (stdout_or_err(F)) {
1531219422Sdas#ifdef _windows_
1532219422Sdas		if (fileno(stdout) == stdout_fileno_ASL) {
1533219422Sdas			rv = x_sprintf(f.obe1, Wput, &f, fmt, ap);
1534219422Sdas			mwrite(buf, f.lastlen);
1535219422Sdas			}
1536219422Sdas		else
1537219422Sdas#endif
1538219422Sdas#ifdef PF_BUF
1539219422Sdas		if (F == stderr_ASL) {
1540219422Sdas			rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
1541219422Sdas			pf_put(buf, f.lastlen);
1542219422Sdas			}
1543219422Sdas		else
1544219422Sdas#endif
1545219422Sdas			{
1546219422Sdas			rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
1547219422Sdas			fputs(buf, F);
1548219422Sdas			}
1549219422Sdas		}
1550219422Sdas	else
1551219422Sdas#endif /*MESS*/
1552219422Sdas		{
1553219422Sdas#ifdef PF_BUF
1554219422Sdas		if (F == stderr_ASL) {
1555219422Sdas			rv = x_sprintf(f.obe1, pfput, &f, fmt, ap);
1556219422Sdas			pf_put(buf, f.lastlen);
1557219422Sdas			}
1558219422Sdas		else
1559219422Sdas#endif
1560219422Sdas			{
1561219422Sdas			rv = x_sprintf(f.obe1, Fput, &f, fmt, ap);
1562219422Sdas			fputs(buf, F);
1563219422Sdas			}
1564219422Sdas		}
1565219422Sdas	va_end(ap);
1566219422Sdas	return rv;
1567219422Sdas	}
1568219422Sdas
1569219422Sdas void
1570219422SdasPerror
1571219422Sdas#ifdef KR_headers
1572219422Sdas	(s) char *s;
1573219422Sdas#else
1574219422Sdas	(const char *s)
1575219422Sdas#endif
1576219422Sdas{
1577219422Sdas	if (s && *s)
1578219422Sdas		Fprintf(Stderr, "%s: ", s);
1579219422Sdas	Fprintf(Stderr, "%s\n", strerror(errno));
1580219422Sdas	}
1581219422Sdas
1582219422Sdas static char *
1583219422SdasSnput
1584219422Sdas#ifdef KR_headers
1585219422Sdas	(f, rvp) Finfo *f; int *rvp;
1586219422Sdas#else
1587219422Sdas	(Finfo *f, int *rvp)
1588219422Sdas#endif
1589219422Sdas{
1590219422Sdas	char *s, *s0;
1591219422Sdas	size_t L;
1592219422Sdas
1593219422Sdas	*rvp += Bsize;
1594219422Sdas	s0 = f->ob0;
1595219422Sdas	s = f->u.sf;
1596219422Sdas	if ((L = f->obe1 - s) > Bsize) {
1597219422Sdas		L = Bsize;
1598219422Sdas		goto copy;
1599219422Sdas		}
1600219422Sdas	if (L > 0) {
1601219422Sdas copy:
1602219422Sdas		memcpy(s, s0, L);
1603219422Sdas		f->u.sf = s + L;
1604219422Sdas		}
1605219422Sdas	return s0;
1606219422Sdas	}
1607219422Sdas
1608219422Sdas int
1609219422SdasVsnprintf
1610219422Sdas#ifdef KR_headers
1611219422Sdas	(s, n, fmt, ap) char *s; size_t n; char *fmt; va_list ap;
1612219422Sdas#else
1613219422Sdas	(char *s, size_t n, const char *fmt, va_list ap)
1614219422Sdas#endif
1615219422Sdas{
1616219422Sdas	Finfo f;
1617219422Sdas	char buf[Bsize];
1618219422Sdas	int L, rv;
1619219422Sdas
1620219422Sdas	if (n <= 0 || !s) {
1621219422Sdas		n = 1;
1622219422Sdas		s = buf;
1623219422Sdas		}
1624219422Sdas	f.u.sf = s;
1625219422Sdas	f.ob0 = buf;
1626219422Sdas	f.obe1 = s + n - 1;
1627219422Sdas	rv = x_sprintf(buf + Bsize, Snput, &f, fmt, ap);
1628219422Sdas	if (f.lastlen > (L = f.obe1 - f.u.sf))
1629219422Sdas		f.lastlen = L;
1630219422Sdas	if (f.lastlen > 0) {
1631219422Sdas		memcpy(f.u.sf, buf, f.lastlen);
1632219422Sdas		f.u.sf += f.lastlen;
1633219422Sdas		}
1634219422Sdas	*f.u.sf = 0;
1635219422Sdas	return rv;
1636219422Sdas	}
1637219422Sdas int
1638219422SdasSnprintf
1639219422Sdas#ifdef KR_headers
1640219422Sdas	(va_alist)
1641219422Sdas va_dcl
1642219422Sdas{
1643219422Sdas	char *s, *fmt;
1644219422Sdas	int rv;
1645219422Sdas	size_t n;
1646219422Sdas	va_list ap;
1647219422Sdas
1648219422Sdas	va_start(ap);
1649219422Sdas	s = va_arg(ap, char*);
1650219422Sdas	n = va_arg(ap, size_t);
1651219422Sdas	fmt = va_arg(ap, char*);
1652219422Sdas	/*}*/
1653219422Sdas#else
1654219422Sdas	(char *s, size_t n, const char *fmt, ...)
1655219422Sdas{
1656219422Sdas	int rv;
1657219422Sdas	va_list ap;
1658219422Sdas
1659219422Sdas	va_start(ap, fmt);
1660219422Sdas#endif
1661219422Sdas	rv = Vsnprintf(s, n, fmt, ap);
1662219422Sdas	va_end(ap);
1663219422Sdas	return rv;
1664219422Sdas	}
1665219422Sdas
1666219422Sdas
1667219422Sdas#ifdef __cplusplus
1668219422Sdas}
1669219422Sdas#endif
1670