doprnt.c revision 1219:f89f56c2d9ac
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*
24 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29/*	  All Rights Reserved  	*/
30
31/*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
41#pragma ident	"%Z%%M%	%I%	%E% SMI"
42
43/*LINTLIBRARY*/
44
45/*
46 *	_doprnt: common code for printf, fprintf, sprintf
47 */
48
49#include "../../../lib/common/inc/c_synonyms.h"
50#include <sys/types.h>
51#include "file64.h"
52#include <stdio.h>
53#include <stdlib.h>
54#include <ctype.h>
55#include <stdarg.h>
56#include <values.h>
57#include <nan.h>
58#include <memory.h>
59#include <string.h>
60#include "print.h"	/* parameters & macros for doprnt */
61#include "stdiom.h"
62#include <locale.h>
63#include <stddef.h>
64#include "_locale.h"
65#include "libc.h"
66
67#define	PUT(p, n)	{ unsigned char *newbufptr; \
68			if ((newbufptr = bufptr + (n)) > bufferend) { \
69				_dowrite((p), (n), iop, &bufptr); \
70			} else { \
71				(void) memcpy(bufptr, (p), (n)); \
72				bufptr = newbufptr; \
73			} \
74			}
75#define	PAD(s, n)	{ int nn; \
76			for (nn = (n); nn > 20; nn -= 20) \
77				_dowrite((s), 20, iop, &bufptr); \
78			PUT((s), nn); \
79			}
80
81#define	SNLEN	5	/* Length of string used when printing a NaN */
82
83/* bit positions for flags used in doprnt */
84
85#define	LENGTH	1	/* l */
86#define	FPLUS	2	/* + */
87#define	FMINUS	  4	/* - */
88#define	FBLANK	  8	/* blank */
89#define	FSHARP	 16	/* # */
90#define	PADZERO  32	/* padding zeroes requested via '0' */
91#define	DOTSEEN  64	/* dot appeared in format specification */
92#define	SUFFIX	128	/* a suffix is to appear in the output */
93#define	RZERO	256	/* there will be trailing zeros in output */
94#define	LZERO	512	/* there will be leading zeroes in output */
95#define	SHORT  1024	/* h */
96
97/*
98 *	Positional Parameter information
99 */
100#define	MAXARGS	30	/* max. number of args for fast positional paramters */
101
102/*
103 * stva_list is used to subvert C's restriction that a variable with an
104 * array type can not appear on the left hand side of an assignment operator.
105 * By putting the array inside a structure, the functionality of assigning to
106 * the whole array through a simple assignment is achieved..
107 */
108typedef struct stva_list {
109	va_list	ap;
110} stva_list;
111
112static char _blanks[] = "                    ";
113static char _zeroes[] = "00000000000000000000";
114static char uc_digs[] = "0123456789ABCDEF";
115static char lc_digs[] = "0123456789abcdef";
116static char  lc_nan[] = "nan0x";
117static char  uc_nan[] = "NAN0X";
118static char  lc_inf[] = "inf";
119static char  uc_inf[] = "INF";
120
121/*
122 * forward declarations
123 */
124void _mkarglst(char *, stva_list, stva_list []);
125void _getarg(char *, stva_list *, int);
126static int _lowdigit(long *);
127static void _dowrite(char *, ssize_t, FILE *, unsigned char **);
128
129static int
130_lowdigit(long *valptr)
131{	/* This function computes the decimal low-order digit of the number */
132	/* pointed to by valptr, and returns this digit after dividing   */
133	/* *valptr by ten.  This function is called ONLY to compute the */
134	/* low-order digit of a long whose high-order bit is set. */
135
136	int lowbit = (int)(*valptr & 1);
137	long value = (*valptr >> 1) & ~HIBITL;
138
139	*valptr = value / 5;
140	return ((int)(value % 5 * 2 + lowbit + '0'));
141}
142
143/* The function _dowrite carries out buffer pointer bookkeeping surrounding */
144/* a call to fwrite.  It is called only when the end of the file output */
145/* buffer is approached or in other unusual situations. */
146static void
147_dowrite(char *p, ssize_t n, FILE *iop, unsigned char **ptrptr)
148{
149	if (!(iop->_flag & _IOREAD)) {
150		iop->_cnt -= (*ptrptr - iop->_ptr);
151		iop->_ptr = *ptrptr;
152		_bufsync(iop, _bufend(iop));
153		(void) fwrite(p, 1, n, iop);
154		*ptrptr = iop->_ptr;
155	} else
156		*ptrptr = (unsigned char *) memcpy(*ptrptr, p, n) + n;
157}
158
159int
160_doprnt(char *format, va_list in_args, FILE *iop)
161{
162
163	/* bufptr is used inside of doprnt instead of iop->_ptr; */
164	/* bufferend is a copy of _bufend(iop), if it exists.  For */
165	/* dummy file descriptors (iop->_flag & _IOREAD), bufferend */
166	/* may be meaningless. Dummy file descriptors are used so that */
167	/* sprintf and vsprintf may share the _doprnt routine with the */
168	/* rest of the printf family. */
169
170	unsigned char *bufptr;
171	unsigned char *bufferend;
172
173	/* This variable counts output characters. */
174	int	count = 0;
175
176	/* Starting and ending points for value to be printed */
177	char	*bp;
178	char	*p;
179
180	/* Field width and precision */
181	int	width, prec;
182
183	/* Format code */
184	int	fcode;
185
186	/* Number of padding zeroes required on the left and right */
187	int	lzero, rzero;
188
189	/* Flags - bit positions defined by LENGTH, FPLUS, FMINUS, FBLANK, */
190	/* and FSHARP are set if corresponding character is in format */
191	/* Bit position defined by PADZERO means extra space in the field */
192	/* should be padded with leading zeroes rather than with blanks */
193	int	flagword;
194
195	/* Values are developed in this buffer */
196	char	buf[max(MAXDIGS, 1+max(MAXFCVT+MAXEXP, MAXECVT))];
197
198	/* Pointer to sign, "0x", "0X", or empty */
199	char	*prefix;
200
201	/* Exponent or empty */
202	char	*suffix;
203
204	/* Buffer to create exponent */
205	char	expbuf[MAXESIZ + 1];
206
207	/* Length of prefix and of suffix */
208	int	prefixlength, suffixlength;
209
210	/* Combined length of leading zeroes, trailing zeroes, and suffix */
211	int 	otherlength;
212
213	/* The value being converted, if integer */
214	long	val;
215
216	/* The value being converted, if real */
217	double	dval;
218
219	/* Output values from fcvt and ecvt */
220	int	decpt, sign;
221
222	/* Pointer to a translate table for digits of whatever radix */
223	char	*tab;
224
225	/* Work variables */
226	int	k, lradix, mradix;
227
228	/* Variables used to flag an infinities and nans, resp. */
229	/* Nan_flg is used with two purposes: to flag a NaN and */
230	/* as the length of the string ``NAN0X'' (``nan0x'') */
231	int	 inf_nan = 0, NaN_flg = 0;
232
233	/* Pointer to string "NAN0X" or "nan0x" */
234	char	 *SNAN;
235
236	/* Flag for negative infinity or NaN */
237	int neg_in = 0;
238
239	/* variables for positional parameters */
240	char	*sformat = format;	/* save the beginning of the format */
241	int	fpos = 1;		/* 1 if first positional parameter */
242	stva_list args;		/* used to step through the argument list */
243	stva_list sargs;
244		/* used to save the start of the argument list */
245	stva_list bargs;
246		/* used to restore args if positional width or precision */
247	stva_list arglst[MAXARGS];
248		/*
249		 * array giving the appropriate values for va_arg() to
250		 * retrieve the corresponding argument:
251		 * arglst[0] is the first argument,
252		 * arglst[1] is the second argument, etc.
253		 */
254	int	starflg = 0;	/* set to 1 if * format specifier seen */
255	/*
256	 * Initialize args and sargs to the start of the argument list.
257	 * Note that ANSI guarantees that the address of the first member of
258	 * a structure will be the same as the address of the structure.
259	 * See equivalent code in libc doprnt.c
260	 */
261
262#if !(defined(__amd64) && defined(__GNUC__))	/* XX64 - fix me */
263	va_copy(args.ap, in_args);
264#endif
265	sargs = args;
266
267	/* if first I/O to the stream get a buffer */
268	/* Note that iop->_base should not equal 0 for sprintf and vsprintf */
269	if (iop->_base == 0 && _findbuf(iop) == 0)
270		return (EOF);
271
272	/* initialize buffer pointer and buffer end pointer */
273	bufptr = iop->_ptr;
274	bufferend = (iop->_flag & _IOREAD) ?
275		(unsigned char *)((long)bufptr | (-1L & ~HIBITL))
276		: _bufend(iop);
277
278	/*
279	 *	The main loop -- this loop goes through one iteration
280	 *	for each string of ordinary characters or format specification.
281	 */
282	for (;;) {
283		ptrdiff_t pdiff;
284
285		if ((fcode = *format) != '\0' && fcode != '%') {
286			bp = format;
287			do {
288				format++;
289			} while ((fcode = *format) != '\0' && fcode != '%');
290
291			pdiff = format - bp;
292				/* pdiff = no. of non-% chars */
293			count += pdiff;
294			PUT(bp, pdiff);
295		}
296		if (fcode == '\0') {  /* end of format; return */
297			ptrdiff_t d = bufptr - iop->_ptr;
298			iop->_cnt -= d;
299			iop->_ptr = bufptr;
300			if (bufptr + iop->_cnt > bufferend &&
301			    !(iop->_flag & _IOREAD))
302				_bufsync(iop, bufferend);
303				/*
304				 * in case of interrupt during last
305				 * several lines
306				 */
307			if (iop->_flag & (_IONBF | _IOLBF) &&
308			    (iop->_flag & _IONBF ||
309			    memchr((char *)(bufptr-count), '\n', count) !=
310			    NULL))
311				(void) _xflsbuf(iop);
312			return (ferror(iop) ? EOF : count);
313		}
314
315		/*
316		 *	% has been found.
317		 *	The following switch is used to parse the format
318		 *	specification and to perform the operation specified
319		 *	by the format letter.  The program repeatedly goes
320		 *	back to this switch until the format letter is
321		 *	encountered.
322		 */
323		width = prefixlength = otherlength = flagword =
324			suffixlength = 0;
325		format++;
326
327	charswitch:
328
329		switch (fcode = *format++) {
330
331		case '+':
332			flagword |= FPLUS;
333			goto charswitch;
334		case '-':
335			flagword |= FMINUS;
336			flagword &= ~PADZERO; /* ignore 0 flag */
337			goto charswitch;
338		case ' ':
339			flagword |= FBLANK;
340			goto charswitch;
341		case '#':
342			flagword |= FSHARP;
343			goto charswitch;
344
345		/* Scan the field width and precision */
346		case '.':
347			flagword |= DOTSEEN;
348			prec = 0;
349			goto charswitch;
350
351		case '*':
352			if (isdigit(*format)) {
353				starflg = 1;
354				bargs = args;
355				goto charswitch;
356			}
357			if (!(flagword & DOTSEEN)) {
358				width = va_arg(args.ap, int);
359				if (width < 0) {
360					width = -width;
361					flagword ^= FMINUS;
362				}
363			} else {
364				prec = va_arg(args.ap, int);
365				if (prec < 0)
366					prec = 0;
367			}
368			goto charswitch;
369
370		case '$':
371			{
372			int		position;
373			stva_list	targs;
374			if (fpos) {
375				_mkarglst(sformat, sargs, arglst);
376				fpos = 0;
377			}
378			if (flagword & DOTSEEN) {
379				position = prec;
380				prec = 0;
381			} else {
382				position = width;
383				width = 0;
384			}
385			if (position <= 0) {
386				/* illegal position */
387				format--;
388				continue;
389			}
390			if (position <= MAXARGS) {
391				targs = arglst[position - 1];
392			} else {
393				targs = arglst[MAXARGS - 1];
394				_getarg(sformat, &targs, position);
395			}
396			if (!starflg)
397				args = targs;
398			else {
399				starflg = 0;
400				args = bargs;
401				if (flagword & DOTSEEN)
402					prec = va_arg(targs.ap, int);
403				else
404					width = va_arg(targs.ap, int);
405			}
406			goto charswitch;
407			}
408
409		case '0':	/* obsolescent spec:  leading zero in width */
410				/* means pad with leading zeros */
411			if (!(flagword & (DOTSEEN | FMINUS)))
412				flagword |= PADZERO;
413			/* FALLTHROUGH */
414		case '1':
415		case '2':
416		case '3':
417		case '4':
418		case '5':
419		case '6':
420		case '7':
421		case '8':
422		case '9':
423			{ 	int num = fcode - '0';
424				while (isdigit(fcode = *format)) {
425					num = num * 10 + fcode - '0';
426					format++;
427				}
428				if (flagword & DOTSEEN)
429					prec = num;
430				else
431					width = num;
432				goto charswitch;
433			}
434
435		/* Scan the length modifier */
436		case 'l':
437			flagword |= LENGTH;
438			goto charswitch;
439		case 'h':
440			flagword |= SHORT;
441			goto charswitch;
442		case 'L':
443			goto charswitch;
444
445		/*
446		 *	The character addressed by format must be
447		 *	the format letter -- there is nothing
448		 *	left for it to be.
449		 *
450		 *	The status of the +, -, #, and blank
451		 *	flags are reflected in the variable
452		 *	"flagword".  "width" and "prec" contain
453		 *	numbers corresponding to the digit
454		 *	strings before and after the decimal
455		 *	point, respectively. If there was no
456		 *	decimal point, then flagword & DOTSEEN
457		 *	is false and the value of prec is meaningless.
458		 *
459		 *	The following switch cases set things up
460		 *	for printing.  What ultimately gets
461		 *	printed will be padding blanks, a
462		 *	prefix, left padding zeroes, a value,
463		 *	right padding zeroes, a suffix, and
464		 *	more padding blanks.  Padding blanks
465		 *	will not appear simultaneously on both
466		 *	the left and the right.  Each case in
467		 *	this switch will compute the value, and
468		 *	leave in several variables the informa-
469		 *	tion necessary to construct what is to
470		 *	be printed.
471		 *
472		 *	The prefix is a sign, a blank, "0x",
473		 *	"0X", or null, and is addressed by
474		 *	"prefix".
475		 *
476		 *	The suffix is either null or an
477		 *	exponent, and is addressed by "suffix".
478		 *	If there is a suffix, the flagword bit
479		 *	SUFFIX will be set.
480		 *
481		 *	The value to be printed starts at "bp"
482		 *	and continues up to and not including
483		 *	"p".
484		 *
485		 *	"lzero" and "rzero" will contain the
486		 *	number of padding zeroes required on
487		 *	the left and right, respectively.
488		 *	The flagword bits LZERO and RZERO tell
489		 *	whether padding zeros are required.
490		 *
491		 *	The number of padding blanks, and
492		 *	whether they go on the left or the
493		 *	right, will be computed on exit from
494		 *	the switch.
495		 */
496
497
498
499
500		/*
501		 *	decimal fixed point representations
502		 *
503		 *	HIBITL is 100...000
504		 *	binary, and is equal to	the maximum
505		 *	negative number.
506		 *	We assume a 2's complement machine
507		 */
508
509		case 'i':
510		case 'd':
511			/* Fetch the argument to be printed */
512			if (flagword & LENGTH)
513				val = va_arg(args.ap, long);
514			else
515				val = va_arg(args.ap, int);
516
517			if (flagword & SHORT)
518				val = (short)val;
519
520			/* Set buffer pointer to last digit */
521			p = bp = buf + MAXDIGS;
522
523			/* If signed conversion, make sign */
524			if (val < 0) {
525				prefix = "-";
526				prefixlength = 1;
527				/*
528				 * Negate, checking in
529				 * advance for possible
530				 * overflow.
531				 */
532				if (val != HIBITL)
533					val = -val;
534				else	/* number is -HIBITL; convert last */
535					/* digit now and get positive number */
536					*--bp = _lowdigit(&val);
537			} else if (flagword & FPLUS) {
538				prefix = "+";
539				prefixlength = 1;
540			} else if (flagword & FBLANK) {
541				prefix = " ";
542				prefixlength = 1;
543			}
544
545		decimal:
546			{	long qval = val;
547				long saveq;
548
549				if (qval <= 9) {
550					if (qval != 0 || !(flagword & DOTSEEN))
551						*--bp = (char)(qval + '0');
552				} else {
553					do {
554						saveq = qval;
555						qval /= 10;
556						*--bp = (char)(saveq -
557							qval * 10 + '0');
558					} while (qval > 9);
559					*--bp = (char)(qval + '0');
560					pdiff = (ptrdiff_t)saveq;
561				}
562			}
563
564			/* Calculate minimum padding zero requirement */
565			if (flagword & DOTSEEN) {
566				int leadzeroes = prec - (int)(p - bp);
567				if (leadzeroes > 0) {
568					otherlength = lzero = leadzeroes;
569					flagword |= LZERO;
570				}
571			}
572
573			break;
574
575		case 'u':
576			/* Fetch the argument to be printed */
577			if (flagword & LENGTH)
578				val = va_arg(args.ap, long);
579			else
580				val = va_arg(args.ap, unsigned);
581
582			if (flagword & SHORT)
583				val = (unsigned short)val;
584
585			p = bp = buf + MAXDIGS;
586
587			if (val & HIBITL)
588				*--bp = _lowdigit(&val);
589
590			goto decimal;
591
592		/*
593		 *	non-decimal fixed point representations
594		 *	for radix equal to a power of two
595		 *
596		 *	"mradix" is one less than the radix for the conversion.
597		 *	"lradix" is one less than the base 2 log
598		 *	of the radix for the conversion. Conversion is unsigned.
599		 *	HIBITL is 100...000
600		 *	binary, and is equal to	the maximum
601		 *	negative number.
602		 *	We assume a 2's complement machine
603		 */
604
605		case 'o':
606			mradix = 7;
607			lradix = 2;
608			goto fixed;
609
610		case 'X':
611		case 'x':
612		case 'p':
613			mradix = 15;
614			lradix = 3;
615
616		fixed:
617			/* Fetch the argument to be printed */
618			if (flagword & LENGTH)
619				val = va_arg(args.ap, long);
620			else
621				val = va_arg(args.ap, unsigned);
622
623			if (flagword & SHORT)
624				val = (unsigned short)val;
625
626			/* Set translate table for digits */
627			tab = (fcode == 'X') ? uc_digs : lc_digs;
628
629			/* Entry point when printing a double which is a NaN */
630		put_pc:
631			/* Develop the digits of the value */
632			p = bp = buf + MAXDIGS;
633			{	long qval = val;
634				if (qval == 0) {
635					if (!(flagword & DOTSEEN)) {
636						otherlength = lzero = 1;
637						flagword |= LZERO;
638					}
639				} else
640					do {
641						*--bp = tab[qval & mradix];
642						qval = ((qval >> 1) & ~HIBITL)
643								>> lradix;
644					} while (qval != 0);
645			}
646
647			/* Calculate minimum padding zero requirement */
648			if (flagword & DOTSEEN) {
649				int leadzeroes = prec - (int)(p - bp);
650				if (leadzeroes > 0) {
651					otherlength = lzero = leadzeroes;
652					flagword |= LZERO;
653				}
654			}
655
656			/* Handle the # flag */
657			if (flagword & FSHARP && val != 0)
658				switch (fcode) {
659				case 'o':
660					if (!(flagword & LZERO)) {
661						otherlength = lzero = 1;
662						flagword |= LZERO;
663					}
664					break;
665				case 'x':
666					prefix = "0x";
667					prefixlength = 2;
668					break;
669				case 'X':
670					prefix = "0X";
671					prefixlength = 2;
672					break;
673				}
674
675			break;
676
677		case 'E':
678		case 'e':
679			/*
680			 * E-format.  The general strategy
681			 * here is fairly easy: we take
682			 * what ecvt gives us and re-format it.
683			 */
684
685			/* Establish default precision */
686			if (!(flagword & DOTSEEN))
687				prec = 6;
688
689			/* Fetch the value */
690			dval = va_arg(args.ap, double);
691
692			/* Check for NaNs and Infinities */
693			if (IsNANorINF(dval)) {
694				if (IsINF(dval)) {
695					if (IsNegNAN(dval))
696						neg_in = 1;
697					inf_nan = 1;
698					bp = (fcode == 'E')? uc_inf: lc_inf;
699					p = bp + 3;
700					break;
701				} else {
702					if (IsNegNAN(dval))
703						neg_in = 1;
704					inf_nan = 1;
705					val = GETNaNPC(dval);
706					NaN_flg = SNLEN;
707					mradix = 15;
708					lradix = 3;
709					if (fcode == 'E') {
710						SNAN = uc_nan;
711						tab =  uc_digs;
712					} else {
713						SNAN =  lc_nan;
714						tab =  lc_digs;
715					}
716					goto put_pc;
717				}
718			}
719			/* Develop the mantissa */
720			bp = ecvt(dval, min(prec + 1, MAXECVT), &decpt, &sign);
721
722			/* Determine the prefix */
723		e_merge:
724			if (sign) {
725				prefix = "-";
726				prefixlength = 1;
727			} else if (flagword & FPLUS) {
728				prefix = "+";
729				prefixlength = 1;
730			} else if (flagword & FBLANK) {
731				prefix = " ";
732				prefixlength = 1;
733			}
734
735			/* Place the first digit in the buffer */
736			p = &buf[0];
737			*p++ = (*bp != '\0') ? *bp++ : '0';
738
739			/* Put in a decimal point if needed */
740			if (prec != 0 || (flagword & FSHARP))
741				*p++ = _numeric[0];
742
743			/* Create the rest of the mantissa */
744			{	int rz = prec;
745				for (; rz > 0 && *bp != '\0'; --rz)
746					*p++ = *bp++;
747				if (rz > 0) {
748					otherlength = rzero = rz;
749					flagword |= RZERO;
750				}
751			}
752
753			bp = &buf[0];
754
755			/* Create the exponent */
756			*(suffix = &expbuf[MAXESIZ]) = '\0';
757			if (dval != 0) {
758				int nn = decpt - 1;
759				if (nn < 0)
760				    nn = -nn;
761				for (; nn > 9; nn /= 10)
762					*--suffix = todigit(nn % 10);
763				*--suffix = todigit(nn);
764			}
765
766			/* Prepend leading zeroes to the exponent */
767			while (suffix > &expbuf[MAXESIZ - 2])
768				*--suffix = '0';
769
770			/* Put in the exponent sign */
771			*--suffix = (decpt > 0 || dval == 0) ? '+' : '-';
772
773			/* Put in the e */
774			*--suffix = isupper(fcode) ? 'E'  : 'e';
775
776			/* compute size of suffix */
777			otherlength += (suffixlength =
778				(int)(&expbuf[MAXESIZ] - suffix));
779			flagword |= SUFFIX;
780
781			break;
782
783		case 'f':
784			/*
785			 * F-format floating point.  This is a
786			 * good deal less simple than E-format.
787			 * The overall strategy will be to call
788			 * fcvt, reformat its result into buf,
789			 * and calculate how many trailing
790			 * zeroes will be required.  There will
791			 * never be any leading zeroes needed.
792			 */
793
794			/* Establish default precision */
795			if (!(flagword & DOTSEEN))
796				prec = 6;
797
798			/* Fetch the value */
799			dval = va_arg(args.ap, double);
800
801			/* Check for NaNs and Infinities  */
802			if (IsNANorINF(dval)) {
803				if (IsINF(dval)) {
804					if (IsNegNAN(dval))
805						neg_in = 1;
806					inf_nan = 1;
807					bp = lc_inf;
808					p = bp + 3;
809					break;
810				} else {
811					if (IsNegNAN(dval))
812						neg_in = 1;
813					inf_nan = 1;
814					val  = GETNaNPC(dval);
815					NaN_flg = SNLEN;
816					mradix = 15;
817					lradix = 3;
818					tab =  lc_digs;
819					SNAN = lc_nan;
820					goto put_pc;
821				}
822			}
823			/* Do the conversion */
824			bp = fcvt(dval, min(prec, MAXFCVT), &decpt, &sign);
825
826			/* Determine the prefix */
827		f_merge:
828			if (sign) {
829				prefix = "-";
830				prefixlength = 1;
831			} else if (flagword & FPLUS) {
832				prefix = "+";
833				prefixlength = 1;
834			} else if (flagword & FBLANK) {
835				prefix = " ";
836				prefixlength = 1;
837			}
838
839			/* Initialize buffer pointer */
840			p = &buf[0];
841
842			{	int nn = decpt;
843
844				/* Emit the digits before the decimal point */
845				k = 0;
846				do {
847					*p++ = (nn <= 0 || *bp == '\0' ||
848						k >= MAXFSIG) ?
849						'0' : (k++, *bp++);
850				} while (--nn > 0);
851
852				/* Decide whether we need a decimal point */
853				if ((flagword & FSHARP) || prec > 0)
854					*p++ = _numeric[0];
855
856				/* Digits (if any) after the decimal point */
857				nn = min(prec, MAXFCVT);
858				if (prec > nn) {
859					flagword |= RZERO;
860					otherlength = rzero = prec - nn;
861				}
862				while (--nn >= 0)
863					*p++ = (++decpt <= 0 || *bp == '\0' ||
864						k >= MAXFSIG) ?
865						'0' : (k++, *bp++);
866			}
867
868			bp = &buf[0];
869
870			break;
871
872		case 'G':
873		case 'g':
874			/*
875			 * g-format.  We play around a bit
876			 * and then jump into e or f, as needed.
877			 */
878
879			/* Establish default precision */
880			if (!(flagword & DOTSEEN))
881				prec = 6;
882			else if (prec == 0)
883				prec = 1;
884
885			/* Fetch the value */
886			dval = va_arg(args.ap, double);
887
888			/* Check for NaN and Infinities  */
889			if (IsNANorINF(dval)) {
890				if (IsINF(dval)) {
891					if (IsNegNAN(dval))
892						neg_in = 1;
893					bp = (fcode == 'G') ? uc_inf : lc_inf;
894					p = bp + 3;
895					inf_nan = 1;
896					break;
897				} else {
898					if (IsNegNAN(dval))
899						neg_in = 1;
900					inf_nan = 1;
901					val  = GETNaNPC(dval);
902					NaN_flg = SNLEN;
903					mradix = 15;
904					lradix = 3;
905					if (fcode == 'G') {
906						SNAN = uc_nan;
907						tab = uc_digs;
908					} else {
909						SNAN = lc_nan;
910						tab =  lc_digs;
911					}
912					goto put_pc;
913				}
914			}
915
916			/* Do the conversion */
917			bp = ecvt(dval, min(prec, MAXECVT), &decpt, &sign);
918			if (dval == 0)
919				decpt = 1;
920
921			{	int kk = prec;
922				size_t sz;
923
924				if (!(flagword & FSHARP)) {
925					sz = strlen(bp);
926					if (sz < kk)
927						kk = (int)sz;
928					while (kk >= 1 && bp[kk-1] == '0')
929						--kk;
930				}
931
932				if (decpt < -3 || decpt > prec) {
933					prec = kk - 1;
934					goto e_merge;
935				}
936				prec = kk - decpt;
937				goto f_merge;
938			}
939
940		case '%':
941			buf[0] = (char)fcode;
942			goto c_merge;
943
944		case 'c':
945			buf[0] = va_arg(args.ap, int);
946		c_merge:
947			p = (bp = &buf[0]) + 1;
948			break;
949
950		case 's':
951			bp = va_arg(args.ap, char *);
952			if (!(flagword & DOTSEEN))
953				p = bp + strlen(bp);
954			else { /* a strnlen function would  be useful here! */
955				char *qp = bp;
956				while (*qp++ != '\0' && --prec >= 0)
957					;
958				p = qp - 1;
959			}
960			break;
961
962		case 'n':
963			{
964				if (flagword & LENGTH) {
965					long *svcount;
966					svcount = va_arg(args.ap, long *);
967					*svcount = count;
968				} else if (flagword & SHORT) {
969					short *svcount;
970					svcount = va_arg(args.ap, short *);
971					*svcount = (short)count;
972				} else {
973					int *svcount;
974					svcount = va_arg(args.ap, int *);
975					*svcount = count;
976				}
977				continue;
978			}
979
980		default: /* this is technically an error; what we do is to */
981			/* back up the format pointer to the offending char */
982			/* and continue with the format scan */
983			format--;
984			continue;
985
986		}
987
988		if (inf_nan) {
989			if (neg_in) {
990				prefix = "-";
991				prefixlength = 1;
992				neg_in = 0;
993			} else if (flagword & FPLUS) {
994				prefix = "+";
995				prefixlength = 1;
996			} else if (flagword & FBLANK) {
997				prefix = " ";
998				prefixlength = 1;
999			}
1000			inf_nan = 0;
1001		}
1002
1003		/* Calculate number of padding blanks */
1004		k = (int)(pdiff = p - bp) + prefixlength + otherlength +
1005			NaN_flg;
1006		if (width <= k)
1007			count += k;
1008		else {
1009			count += width;
1010
1011			/* Set up for padding zeroes if requested */
1012			/* Otherwise emit padding blanks unless output is */
1013			/* to be left-justified.  */
1014
1015			if (flagword & PADZERO) {
1016				if (!(flagword & LZERO)) {
1017					flagword |= LZERO;
1018					lzero = width - k;
1019				}
1020				else
1021					lzero += width - k;
1022				k = width; /* cancel padding blanks */
1023			} else
1024				/* Blanks on left if required */
1025				if (!(flagword & FMINUS))
1026					PAD(_blanks, width - k);
1027		}
1028
1029		/* Prefix, if any */
1030		if (prefixlength != 0)
1031			PUT(prefix, prefixlength);
1032
1033		/* If value is NaN, put string NaN */
1034		if (NaN_flg) {
1035			PUT(SNAN, SNLEN);
1036			NaN_flg = 0;
1037		}
1038
1039		/* Zeroes on the left */
1040		if (flagword & LZERO)
1041			PAD(_zeroes, lzero);
1042
1043		/* The value itself */
1044		if (pdiff > 0)
1045			PUT(bp, pdiff);
1046
1047		if (flagword & (RZERO | SUFFIX | FMINUS)) {
1048			/* Zeroes on the right */
1049			if (flagword & RZERO)
1050				PAD(_zeroes, rzero);
1051
1052			/* The suffix */
1053			if (flagword & SUFFIX)
1054				PUT(suffix, suffixlength);
1055
1056			/* Blanks on the right if required */
1057			if (flagword & FMINUS && width > k)
1058				PAD(_blanks, width - k);
1059		}
1060	}
1061}
1062
1063/*
1064 * This function initializes arglst, to contain the appropriate va_list values
1065 * for the first MAXARGS arguments.
1066 */
1067void
1068_mkarglst(char *fmt, stva_list args, stva_list arglst[])
1069{
1070	static char digits[] = "01234567890", skips[] = "# +-.0123456789hL$";
1071
1072	enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR,
1073		LONG_PTR, INT_PTR};
1074	enum types typelst[MAXARGS], curtype;
1075	int maxnum, n, curargno, flags;
1076
1077	/*
1078	 * Algorithm	1. set all argument types to zero.
1079	 *		2. walk through fmt putting arg types in typelst[].
1080	 *		3. walk through args using va_arg(args.ap, typelst[n])
1081	 *		   and set arglst[] to the appropriate values.
1082	 * Assumptions:	Cannot use %*$... to specify variable position.
1083	 */
1084
1085	(void) memset((void *)typelst, 0, sizeof (typelst));
1086	maxnum = -1;
1087	curargno = 0;
1088	while ((fmt = strchr(fmt, '%')) != 0) {
1089		size_t sz;
1090
1091		fmt++;	/* skip % */
1092		if (fmt[sz = strspn(fmt, digits)] == '$') {
1093			curargno = atoi(fmt) - 1;
1094				/* convert to zero base */
1095			if (curargno < 0)
1096				continue;
1097			fmt += sz + 1;
1098		}
1099		flags = 0;
1100	again:;
1101		fmt += strspn(fmt, skips);
1102		switch (*fmt++) {
1103		case '%':	/* there is no argument! */
1104			continue;
1105		case 'l':
1106			flags |= 0x1;
1107			goto again;
1108		case '*':	/* int argument used for value */
1109			/* check if there is a positional parameter */
1110			if (isdigit(*fmt)) {
1111				int	targno;
1112				targno = atoi(fmt) - 1;
1113				fmt += strspn(fmt, digits);
1114				if (*fmt == '$')
1115					fmt++; /* skip '$' */
1116				if (targno >= 0 && targno < MAXARGS) {
1117					typelst[targno] = INT;
1118					if (maxnum < targno)
1119						maxnum = targno;
1120				}
1121				goto again;
1122			}
1123			flags |= 0x2;
1124			curtype = INT;
1125			break;
1126		case 'e':
1127		case 'E':
1128		case 'f':
1129		case 'g':
1130		case 'G':
1131			curtype = DOUBLE;
1132			break;
1133		case 's':
1134			curtype = CHAR_PTR;
1135			break;
1136		case 'p':
1137			curtype = VOID_PTR;
1138			break;
1139		case 'n':
1140			if (flags & 0x1)
1141				curtype = LONG_PTR;
1142			else
1143				curtype = INT_PTR;
1144			break;
1145		default:
1146			if (flags & 0x1)
1147				curtype = LONG;
1148			else
1149				curtype = INT;
1150			break;
1151		}
1152		if (curargno >= 0 && curargno < MAXARGS) {
1153			typelst[curargno] = curtype;
1154			if (maxnum < curargno)
1155				maxnum = curargno;
1156		}
1157		curargno++;	/* default to next in list */
1158		if (flags & 0x2)	/* took care of *, keep going */
1159		{
1160			flags ^= 0x2;
1161			goto again;
1162		}
1163	}
1164	for (n = 0; n <= maxnum; n++) {
1165		arglst[n] = args;
1166		if (typelst[n] == 0)
1167			typelst[n] = INT;
1168
1169		switch (typelst[n]) {
1170		case INT:
1171			(void) va_arg(args.ap, int);
1172			break;
1173		case LONG:
1174			(void) va_arg(args.ap, long);
1175			break;
1176		case CHAR_PTR:
1177			(void) va_arg(args.ap, char *);
1178			break;
1179		case DOUBLE:
1180			(void) va_arg(args.ap, double);
1181			break;
1182		case LONG_DOUBLE:
1183			(void) va_arg(args.ap, double);
1184			break;
1185		case VOID_PTR:
1186			(void) va_arg(args.ap, void *);
1187			break;
1188		case LONG_PTR:
1189			(void) va_arg(args.ap, long *);
1190			break;
1191		case INT_PTR:
1192			(void) va_arg(args.ap, int *);
1193			break;
1194		}
1195	}
1196}
1197
1198/*
1199 * This function is used to find the va_list value for arguments whose
1200 * position is greater than MAXARGS.  This function is slow, so hopefully
1201 * MAXARGS will be big enough so that this function need only be called in
1202 * unusual circumstances.
1203 * pargs is assumed to contain the value of arglst[MAXARGS - 1].
1204 */
1205void
1206_getarg(char *fmt, stva_list *pargs, int argno)
1207{
1208	static char digits[] = "01234567890", skips[] = "# +-.0123456789h$";
1209	int i, curargno, flags;
1210	size_t n;
1211	char	*sfmt = fmt;
1212	int	found = 1;
1213
1214	i = MAXARGS;
1215	curargno = 1;
1216	while (found) {
1217		fmt = sfmt;
1218		found = 0;
1219		while ((i != argno) && (fmt = strchr(fmt, '%')) != 0) {
1220			fmt++;	/* skip % */
1221			if (fmt[n = strspn(fmt, digits)] == '$') {
1222				curargno = atoi(fmt);
1223				if (curargno <= 0)
1224					continue;
1225				fmt += n + 1;
1226			}
1227
1228			/* find conversion specifier for next argument */
1229			if (i != curargno) {
1230				curargno++;
1231				continue;
1232			} else
1233				found = 1;
1234			flags = 0;
1235		again:;
1236			fmt += strspn(fmt, skips);
1237			switch (*fmt++) {
1238			case '%':	/* there is no argument! */
1239				continue;
1240			case 'l':
1241				flags |= 0x1;
1242				goto again;
1243			case '*':	/* int argument used for value */
1244				/*
1245				 * check if there is a positional parameter;
1246				 * if so, just skip it; its size will be
1247				 * correctly determined by default
1248				 */
1249				if (isdigit(*fmt)) {
1250					fmt += strspn(fmt, digits);
1251					if (*fmt == '$')
1252						fmt++; /* skip '$' */
1253					goto again;
1254				}
1255				flags |= 0x2;
1256				(void) va_arg((*pargs).ap, int);
1257				break;
1258			case 'e':
1259			case 'E':
1260			case 'f':
1261			case 'g':
1262			case 'G':
1263				if (flags & 0x1)
1264					(void) va_arg((*pargs).ap, double);
1265				else
1266					(void) va_arg((*pargs).ap, double);
1267				break;
1268			case 's':
1269				(void) va_arg((*pargs).ap, char *);
1270				break;
1271			case 'p':
1272				(void) va_arg((*pargs).ap, void *);
1273				break;
1274			case 'n':
1275				if (flags & 0x1)
1276					(void) va_arg((*pargs).ap, long *);
1277				else
1278					(void) va_arg((*pargs).ap, int *);
1279				break;
1280			default:
1281				if (flags & 0x1)
1282					(void) va_arg((*pargs).ap, long int);
1283				else
1284					(void) va_arg((*pargs).ap, int);
1285				break;
1286			}
1287			i++;
1288			curargno++;	/* default to next in list */
1289			if (flags & 0x2)	/* took care of *, keep going */
1290			{
1291				flags ^= 0x2;
1292				goto again;
1293			}
1294		}
1295
1296		/*
1297		 * missing specifier for parameter, assume parameter is an int
1298		 */
1299		if (!found && i != argno) {
1300			(void) va_arg((*pargs).ap, int);
1301			i++;
1302			curargno = i;
1303			found = 1;
1304		}
1305	}
1306}
1307