xref: /titanic_52/usr/src/lib/libc/port/print/doprnt.c (revision 69112edd987c28fa551d4f8d9362a84a45365f17)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1988 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  *	_doprnt: common code for printf, fprintf, sprintf
32  */
33 
34 #include "lint.h"
35 #include "mtlib.h"
36 #include "print.h"	/* parameters & macros for doprnt */
37 #include <wchar.h>
38 #include "libc.h"
39 #include <stdlib.h>
40 #include <limits.h>
41 #include <ctype.h>
42 #include <stdarg.h>
43 #include <values.h>
44 #include <memory.h>
45 #include <string.h>
46 #include <locale.h>
47 #include <widec.h>
48 #include "../i18n/_locale.h"
49 #include <errno.h>
50 #include <sys/types.h>
51 #include <libw.h>
52 #include "mse.h"
53 #include "xpg6.h"
54 
55 static const char nullstr[] = "(null)";
56 static const wchar_t widenullstr[] = L"(null)";
57 
58 #if defined(__i386) || defined(__amd64) || defined(__sparcv9)
59 #define	GETQVAL(arg)	(va_arg(arg, long double))
60 #else /* !defined(__i386) && !defined(__sparcv9) */
61 #define	GETQVAL(arg)	*(va_arg(arg, long double *))
62 #endif /* !defined(__i386) && !defined(__sparcv9) */
63 
64 #ifdef	_WIDE
65 #define	STRCHR	wcschr
66 #define	STRSPN	wcsspn
67 #define	ATOI(x)	_watoi((wchar_t *)x)
68 #define	_P_HYPHEN	L"-"
69 #define	_P_PLUS		L"+"
70 #define	_P_BLANK	L" "
71 #define	_P_ZEROx	L"0x"
72 #define	_P_ZEROX	L"0X"
73 #define	_M_ISDIGIT(c)	(((c) >= 0) && ((c) < 256) && isdigit((c)))
74 #define	_M_ISUPPER(c)	(((c) >= 0) && ((c) < 256) && isupper((c)))
75 #else  /* _WIDE */
76 #define	STRCHR	strchr
77 #define	STRSPN	strspn
78 #define	ATOI(x)	atoi(x)
79 #define	_P_HYPHEN	"-"
80 #define	_P_PLUS		"+"
81 #define	_P_BLANK	" "
82 #define	_P_ZEROx	"0x"
83 #define	_P_ZEROX	"0X"
84 #define	_M_ISDIGIT(c)	isdigit((c))
85 #define	_M_ISUPPER(c)	isupper((c))
86 #endif /* _WIDE */
87 
88 #ifdef	_WIDE
89 #define	PUT(p, n) \
90 	{ \
91 		int	retp; \
92 		retp = put_wide(iop, &bufptr, bufferend, p, n, sflag, lc, fp); \
93 		if (retp == EOF) { \
94 			return ((ssize_t)EOF); \
95 		} \
96 	}
97 
98 #define	PAD(s, n) \
99 	{ \
100 		int	retp; \
101 		retp = pad_wide(iop, &bufptr, bufferend, s, n, sflag); \
102 		if (retp == EOF) { \
103 			return ((ssize_t)EOF); \
104 		} \
105 	}
106 
107 #define	FPCONV(func, val, prec, decpt, sign, cvtbuf) \
108 	{ \
109 		char	cb[DECIMAL_STRING_LENGTH]; \
110 		wchar_t	*wp; \
111 		char	*cp; \
112 		(void) func(val, prec, decpt, sign, cb); \
113 		wp = cvtbuf; \
114 		cp = cb; \
115 		while (*cp) { \
116 			*wp++ = (wchar_t)*cp++; \
117 		} \
118 		*wp = L'\0'; \
119 	}
120 
121 #else  /* _WIDE */
122 #define	PUT(p, n)	\
123 	{\
124 		/*\
125 		 * When _doprnt() is called by [v]snprintf, we need to \
126 		 * always call _dowrite().  We also need to call _dowrite() \
127 		 * if the bufptr lies beyond the end of the buffer.  This \
128 		 * is possible due to known off-by-one errors in __flsbuf() \
129 		 * and _fwrite_unlocked().  See 1235867 and 1231720 for the \
130 		 * sordid details. \
131 		 */\
132 		if (snflag || bufptr > bufferend ||\
133 		    (unsigned long)(bufferend - bufptr) < (n)) {\
134 			if (!_dowrite(p, n, iop, &bufptr)) {\
135 				return (EOF);\
136 			}\
137 		} else {\
138 			unsigned char	*fbp = bufptr;\
139 			switch (n) {\
140 			case 4:\
141 				*fbp = *p;\
142 				*(fbp + 1) = *(p + 1);\
143 				*(fbp + 2) = *(p + 2);\
144 				*(fbp + 3) = *(p + 3);\
145 				bufptr += 4;\
146 				break;\
147 			case 3:\
148 				*fbp = *p;\
149 				*(fbp + 1) = *(p + 1);\
150 				*(fbp + 2) = *(p + 2);\
151 				bufptr += 3;\
152 				break;\
153 			case 2:\
154 				*fbp = *p;\
155 				*(fbp + 1) = *(p + 1);\
156 				bufptr += 2;\
157 				break;\
158 			case 1:\
159 				*bufptr++ = *p;\
160 				break;\
161 			default:\
162 				bufptr = (unsigned char *)memcpy(fbp, p, n)\
163 					+ (n);\
164 			}\
165 		}\
166 	}
167 
168 #define	PAD(s, n)    { ssize_t nn; \
169 		    for (nn = n; nn > PAD_LEN; nn -= PAD_LEN) \
170 			if (!_dowrite(s, PAD_LEN, iop, &bufptr)) \
171 				return (EOF); \
172 			PUT(s, nn); \
173 		}
174 
175 #define	FPCONV(func, val, prec, decpt, sign, cvtbuf) \
176 		(void) func(val, prec, decpt, sign, cvtbuf);
177 
178 #endif /* _WIDE */
179 
180 /* bit positions for flags used in doprnt */
181 
182 #define	LENGTH	0x1	/* l */
183 #define	FPLUS	0x2	/* + */
184 #define	FMINUS	0x4	/* - */
185 #define	FBLANK	0x8	/* blank */
186 #define	FSHARP	0x10	/* # */
187 #define	PADZERO 0x20	/* padding zeroes requested via '0' */
188 #define	DOTSEEN 0x40	/* dot appeared in format specification */
189 #define	SUFFIX	0x80	/* a suffix is to appear in the output */
190 #define	RZERO	0x100	/* there will be trailing zeros in output */
191 #define	LZERO	0x200	/* there will be leading zeroes in output */
192 #define	SHORT   0x400	/* h */
193 #define	QUAD    0x800	/* Q for long double */
194 #define	XLONG   0x1000	/* ll for long long */
195 #define	CHAR    0x2000	/* hh for char */
196 
197 #ifdef	_WIDE
198 static wchar_t *
199 insert_thousands_sep(wchar_t *bp, wchar_t *ep);
200 #else  /* _WIDE */
201 static char *
202 insert_thousands_sep(char *bp, char *ep);
203 #endif /* _WIDE */
204 
205 static int	_rec_scrswidth(wchar_t *, ssize_t);
206 
207 /*
208  *	Positional Parameter information
209  */
210 #define	MAXARGS	30	/* max. number of args for fast positional paramters */
211 
212 static ssize_t
213 _dowrite(const char *p, ssize_t n, FILE *iop, unsigned char **ptrptr);
214 
215 /*
216  * stva_list is used to subvert C's restriction that a variable with an
217  * array type can not appear on the left hand side of an assignment operator.
218  * By putting the array inside a structure, the functionality of assigning to
219  * the whole array through a simple assignment is achieved..
220  */
221 typedef struct stva_list {
222 	va_list	ap;
223 } stva_list;
224 
225 #ifdef	_WIDE
226 static void _wmkarglst(wchar_t *, stva_list, stva_list [], int);
227 static void _wgetarg(wchar_t *, stva_list *, long, int);
228 #else  /* _WIDE */
229 static void _mkarglst(char *, stva_list, stva_list [], int);
230 void _getarg(char *, stva_list *, long, int);
231 #endif /* _WIDE */
232 
233 
234 
235 
236 static int
237 _lowdigit(ssize_t *valptr)
238 {
239 	/* This function computes the decimal low-order digit of the number */
240 	/* pointed to by valptr, and returns this digit after dividing   */
241 	/* *valptr by ten.  This function is called ONLY to compute the */
242 	/* low-order digit of a long whose high-order bit is set. */
243 
244 	ssize_t lowbit = *valptr & 1;
245 	long value = (*valptr >> 1) & ~HIBITL;
246 
247 	*valptr = value / 5;
248 	value = value % 5 * 2 + lowbit + '0';
249 	return ((int)value);
250 }
251 
252 static int
253 _lowlldigit(long long *valptr)
254 {
255 	ssize_t lowbit = *valptr & 1;
256 	long long value = (*valptr >> 1) & ~HIBITLL;
257 		*valptr = value / 5;
258 		value = value % 5 * 2 + lowbit + '0';
259 		return ((int)value);
260 }
261 
262 /* The function _dowrite carries out buffer pointer bookkeeping surrounding */
263 /* a call to fwrite.  It is called only when the end of the file output */
264 /* buffer is approached or in other unusual situations. */
265 
266 static ssize_t
267 _dowrite(const char *p, ssize_t n, FILE *iop, unsigned char **ptrptr)
268 {
269 	if (!(iop->_flag & _IOREAD)) {
270 		iop->_cnt -= (*ptrptr - iop->_ptr);
271 		iop->_ptr = *ptrptr;
272 		_bufsync(iop, _bufend(iop));
273 		if (_FWRITE(p, 1, n, iop) != n) {
274 			return (0);
275 		}
276 		*ptrptr = iop->_ptr;
277 	} else {
278 		if (n > iop->_cnt)
279 			n = iop->_cnt;
280 		iop->_cnt -= n;
281 		*ptrptr = (unsigned char *)memcpy((char *)*ptrptr, p, n) + n;
282 		iop->_ptr = *ptrptr;
283 	}
284 	return (1);
285 }
286 
287 #define	PAD_LEN	20
288 	static const char _blanks[] = "                    ";
289 	static const char _zeroes[] = "00000000000000000000";
290 #ifdef	_WIDE
291 	static const wchar_t uc_digs[] = L"0123456789ABCDEF";
292 	static const wchar_t lc_digs[] = L"0123456789abcdef";
293 #else /* _WIDE */
294 	static const char uc_digs[] = "0123456789ABCDEF";
295 	static const char lc_digs[] = "0123456789abcdef";
296 #endif /* _WIDE */
297 
298 #ifdef	_WIDE
299 static int
300 put_wide(FILE *iop, unsigned char **bufptr,
301 	unsigned char *bufferend, wchar_t *p, size_t n,
302 	int sflag, void *lc, int (*fp_wctomb)(void *, char *, wchar_t))
303 {
304 	unsigned char	*newbufptr;
305 	wchar_t	*q;
306 	int	r;
307 	size_t	len, i;
308 
309 	if (sflag) {
310 		len = (wchar_t *)bufferend - (wchar_t *)*bufptr;
311 		if (n > len) {
312 			(void) wmemcpy((wchar_t *)*bufptr, p, len);
313 			iop->_ptr = bufferend;
314 			return (EOF);
315 		} else {
316 			(void) wmemcpy((wchar_t *)*bufptr, p, n);
317 			*bufptr = (unsigned char *)((wchar_t *)*bufptr + n);
318 			return (0);
319 		}
320 	} else {
321 		char *tmpp, *tmpq;
322 		size_t tsize;
323 
324 		tsize = (n + 1) * MB_LEN_MAX;
325 		tmpp = lmalloc(tsize);
326 		if (tmpp == NULL) {
327 			errno = ENOMEM;
328 			return (EOF);
329 		}
330 		q = p;
331 		tmpq = tmpp;
332 		for (len = 0, i = 0; i < n; i++) {
333 			r = fp_wctomb(lc, tmpq, *q++);
334 			if (r == -1) {
335 				lfree(tmpp, tsize);
336 				errno = EILSEQ;
337 				return (EOF);
338 			}
339 			len += r;
340 			tmpq += r;
341 		}
342 		tmpq = tmpp;
343 		newbufptr = *bufptr + len;
344 		if (newbufptr > bufferend) {
345 			if (!_dowrite(tmpp, len, iop, bufptr)) {
346 				lfree(tmpp, tsize);
347 				return (EOF);
348 			}
349 		} else {
350 			(void) memcpy(*bufptr, tmpp, len);
351 			*bufptr = newbufptr;
352 		}
353 		lfree(tmpp, tsize);
354 		return (0);
355 	}
356 }
357 
358 static int
359 pad_wide(FILE *iop, unsigned char **bufptr,
360 	unsigned char *bufferend, const char *s, size_t n,
361 	int sflag)
362 {
363 	unsigned char	*newbufptr;
364 	ssize_t	nn;
365 	size_t	len;
366 	wchar_t	ps;
367 
368 	if (sflag) {
369 		/* for swprintf */
370 		ps = (wchar_t)s[0];
371 		len = (wchar_t *)bufferend - (wchar_t *)*bufptr;
372 		if (n > len) {
373 			(void) wmemset((wchar_t *)*bufptr, ps, len);
374 			iop->_ptr = bufferend;
375 			return (EOF);
376 		} else {
377 			(void) wmemset((wchar_t *)*bufptr, ps, n);
378 			*bufptr = (unsigned char *)((wchar_t *)*bufptr + n);
379 			return (0);
380 		}
381 	} else {
382 		for (nn = n; nn > PAD_LEN; nn -= PAD_LEN) {
383 			if (!_dowrite(s, PAD_LEN, iop, bufptr))
384 				return (EOF);
385 		}
386 		newbufptr = *bufptr + nn;
387 		if (newbufptr > bufferend) {
388 			if (!_dowrite(s, nn, iop, bufptr))
389 				return (EOF);
390 		} else {
391 			(void) memcpy(*bufptr, s, nn);
392 			*bufptr = newbufptr;
393 		}
394 		return (0);
395 	}
396 }
397 #endif /* _WIDE */
398 
399 #ifdef	_WIDE
400 ssize_t
401 _wdoprnt(const wchar_t *format, va_list in_args, FILE *iop)
402 {
403 	return (_wndoprnt(format, in_args, iop, 0));
404 }
405 #else	/* _WIDE */
406 ssize_t
407 _doprnt(const char *format, va_list in_args, FILE *iop)
408 {
409 	return (_ndoprnt(format, in_args, iop, 0));
410 }
411 #endif	/* _WIDE */
412 
413 
414 #ifdef	_WIDE
415 ssize_t
416 _wndoprnt(const wchar_t *format, va_list in_args, FILE *iop, int prflag)
417 #else  /* _WIDE */
418 ssize_t
419 _ndoprnt(const char *format, va_list in_args, FILE *iop, int prflag)
420 #endif /* _WIDE */
421 {
422 
423 #ifdef	_WIDE
424 	int	sflag = 0;
425 	size_t	maxcount;
426 	mbstate_t	*mbst;
427 	void	*lc;
428 	int	(*fp)(void *, char *, wchar_t);
429 #else
430 	int	snflag = 0;
431 #endif /* _WIDE */
432 	/* bufptr is used inside of doprnt instead of iop->_ptr; */
433 	/* bufferend is a copy of _bufend(iop), if it exists.  For */
434 	/* dummy file descriptors (iop->_flag & _IOREAD), bufferend */
435 	/* may be meaningless. Dummy file descriptors are used so that */
436 	/* sprintf and vsprintf may share the _doprnt routine with the */
437 	/* rest of the printf family. */
438 
439 	unsigned char *bufptr;
440 	unsigned char *bufferend;
441 
442 #ifdef	_WIDE
443 	/* This variable counts output characters. */
444 	size_t	count = 0;
445 #else  /* _WIDE */
446 	/* This variable counts output characters. */
447 	int	count = 0;
448 #endif /* _WIDE */
449 
450 #ifdef	_WIDE
451 	wchar_t	*bp;
452 	size_t bpsize;
453 	wchar_t	*p;
454 	char	*cbp;
455 	char	*cp;
456 
457 #else  /* _WIDE */
458 	/* Starting and ending points for value to be printed */
459 	char	*bp;
460 	char *p;
461 #endif /* _WIDE */
462 	/* Field width and precision */
463 	int	prec = 0;
464 	ssize_t width;
465 	ssize_t num;
466 	ssize_t sec_display;
467 	wchar_t *wp;
468 	ssize_t preco;
469 	ssize_t wcount = 0;
470 	char tmpbuf[10];
471 	char wflag;
472 	char lflag;
473 	int quote;		/* ' */
474 	int	retcode;
475 
476 
477 #ifdef	_WIDE
478 	/* Format code */
479 	wchar_t	fcode;
480 #else  /* _WIDE */
481 	/* Format code */
482 	char	fcode;
483 #endif /* _WIDE */
484 
485 	/* Number of padding zeroes required on the left and right */
486 	ssize_t	lzero, rzero, rz, leadzeroes;
487 
488 
489 	/* Flags - bit positions defined by LENGTH, FPLUS, FMINUS, FBLANK, */
490 	/* and FSHARP are set if corresponding character is in format */
491 	/* Bit position defined by PADZERO means extra space in the field */
492 	/* should be padded with leading zeroes rather than with blanks */
493 
494 	ssize_t	flagword;
495 
496 #ifdef	_WIDE
497 	/* Values are developed in this buffer */
498 	wchar_t	buf[max(MAXLLDIGS, 1034)];
499 	wchar_t	cvtbuf[512 + DECIMAL_STRING_LENGTH];
500 
501 	/* Pointer to sign, "0x", "0X", or empty */
502 	wchar_t	*prefix;
503 	wchar_t	prefixbuf[4];
504 
505 	/* Exponent or empty */
506 	wchar_t	*suffix;
507 
508 	/* Buffer to create exponent */
509 	wchar_t	expbuf[MAXESIZ + 1];
510 #else  /* _WIDE */
511 	/* Values are developed in this buffer */
512 	char	buf[max(MAXLLDIGS, 1034)];
513 	char	cvtbuf[512 + DECIMAL_STRING_LENGTH];
514 
515 	/* Pointer to sign, "0x", "0X", or empty */
516 	char	*prefix;
517 	char	prefixbuf[4];
518 
519 	/* Exponent or empty */
520 	char	*suffix;
521 
522 	/* Buffer to create exponent */
523 	char	expbuf[MAXESIZ + 1];
524 #endif /* _WIDE */
525 
526 	/* Length of prefix and of suffix */
527 	ssize_t	prefixlength, suffixlength;
528 
529 	/* Combined length of leading zeroes, trailing zeroes, and suffix */
530 	ssize_t 	otherlength;
531 
532 	/* The value being converted, if integer */
533 	ssize_t	val;
534 
535 	/* The value being converted, if long long */
536 	long long ll = 0LL;
537 
538 	/* Output value from aconvert */
539 	int	exp;
540 
541 	/* Output values from fcvt and ecvt */
542 	int	decpt, sign;
543 
544 #ifdef	_WIDE
545 	/* Pointer to a translate table for digits of whatever radix */
546 	const wchar_t *tab;
547 #else  /* _WIDE */
548 	/* Pointer to a translate table for digits of whatever radix */
549 	const char *tab;
550 #endif /* _WIDE */
551 
552 	/* Work variables */
553 	ssize_t	k, lradix, mradix;
554 
555 	int	inf_nan = 0;
556 	int	inf_nan_mixed_case = 0;
557 
558 #ifdef	_WIDE
559 	/* variables for positional parameters */
560 	/* save the beginning of the format */
561 	wchar_t *sformat = (wchar_t *)format;
562 #else  /* _WIDE */
563 	/* variables for positional parameters */
564 	char *sformat = (char *)format; /* save the beginning of the format */
565 #endif
566 
567 	int	fpos = 1;		/* 1 if first positional parameter */
568 	stva_list	args,	/* used to step through the argument list */
569 			sargs;	/* used to save the start of the arg list */
570 	stva_list	bargs;	/* used to restore args if positional width */
571 				/* or precision */
572 	stva_list	arglst[MAXARGS]; /* array giving appropriate values */
573 					/* for va_arg() to retrieve the */
574 					/* corresponding argument: */
575 					/* arglst[0] is the first arg */
576 					/* arglst[1] is the second arg, etc */
577 
578 	int	starflg = 0;	/* set to 1 if * format specifier seen */
579 	/*
580 	 * Initialize args and sargs to the start of the argument list.
581 	 * We don't know any portable way to copy an arbitrary C object
582 	 * so we use a system-specific routine (probably a macro) from
583 	 * stdarg.h.  (Remember that if va_list is an array, in_args will
584 	 * be a pointer and &in_args won't be what we would want for
585 	 * memcpy.)
586 	 */
587 	va_copy(args.ap, in_args);
588 	sargs = args;
589 
590 #ifdef	_WIDE
591 	if (iop->_flag == _IOREAD)
592 		sflag = 1;
593 
594 	if (!sflag) {
595 		mbst = _getmbstate(iop);
596 		if (mbst == NULL) {
597 			errno = EBADF;
598 			return (EOF);
599 		}
600 		lc = __mbst_get_lc_and_fp((const mbstate_t *)mbst,
601 		    (void (*(*))(void))&fp, FP_WCTOMB);
602 #endif /* _WIDE */
603 	/* if first I/O to the stream get a buffer */
604 	/* Note that iop->_base should not equal 0 for sprintf and vsprintf */
605 	if (iop->_base == 0)  {
606 	    if (_findbuf(iop) == 0)
607 		return (EOF);
608 	    /* _findbuf leaves _cnt set to 0 which is the wrong thing to do */
609 	    /* for fully buffered files */
610 	    if (!(iop->_flag & (_IOLBF|_IONBF)))
611 		iop->_cnt = _bufend(iop) - iop->_base;
612 	}
613 #ifdef	_WIDE
614 	}
615 #endif /* _WIDE */
616 
617 #ifdef	_WIDE
618 	bufptr = iop->_ptr;
619 	if (sflag) {
620 		maxcount = (size_t)iop->_cnt;
621 		bufferend = (unsigned char *)(((wchar_t *)iop->_ptr) +
622 			maxcount);
623 	} else {
624 		bufferend = _bufend(iop);
625 	}
626 #else  /* _WIDE */
627 	/* initialize buffer pointer and buffer end pointer */
628 	bufptr = iop->_ptr;
629 	if (iop->_flag & _IOREAD) {
630 		/*
631 		 * [v]sprintf or [v]snprintf
632 		 */
633 		if (iop->_cnt == MAXINT) {
634 			/*
635 			 * [v]sprintf (no boundschecking)
636 			 */
637 			bufferend =
638 			    (unsigned char *)((long)bufptr | (-1L & ~HIBITL));
639 		} else {
640 			/*
641 			 * [v]snprintf (with boundschecking) or
642 			 * iop with _IORW has been read.
643 			 */
644 			bufferend = _bufend(iop);
645 			if (bufferend == NULL) {
646 				/*
647 				 * [v]snprintf
648 				 *
649 				 * [v]snprint() needs to be always handled by
650 				 * _dowrite().
651 				 */
652 				snflag = 1;
653 			}
654 		}
655 	} else {
656 		/*
657 		 * [v]printf or [v]fprintf
658 		 */
659 		bufferend = _bufend(iop);
660 	}
661 #endif /* _WIDE */
662 
663 	/*
664 	 *	The main loop -- this loop goes through one iteration
665 	 *	for each string of ordinary characters or format specification.
666 	 */
667 	for (; ; ) {
668 		ssize_t n;
669 
670 		if ((fcode = *format) != '\0' && fcode != '%') {
671 #ifdef	_WIDE
672 			bp = (wchar_t *)format;
673 #else  /* _WIDE */
674 			bp = (char *)format;
675 #endif /* _WIDE */
676 			do {
677 				format++;
678 			} while ((fcode = *format) != '\0' && fcode != '%');
679 
680 			count += (n = format - bp); /* n = no. of non-% chars */
681 			PUT(bp, n);
682 		}
683 		if (fcode == '\0') {  /* end of format; return */
684 			ssize_t nn = bufptr - iop->_ptr;
685 
686 #ifdef	_WIDE
687 			if (sflag) {
688 				iop->_ptr = bufptr;
689 				return ((ssize_t)count);
690 			}
691 #endif /* _WIDE */
692 
693 			iop->_cnt -= nn;
694 			iop->_ptr = bufptr;
695 			/* in case of interrupt during last several lines */
696 			if ((bufptr + iop->_cnt) > bufferend && !(iop->_flag \
697 			    & _IOREAD))
698 				_bufsync(iop, bufferend);
699 			if (iop->_flag & (_IONBF | _IOLBF) && \
700 			    (iop->_flag & _IONBF || \
701 			    memchr((char *)(bufptr+iop->_cnt), \
702 			    '\n', -iop->_cnt) != NULL))
703 				(void) _xflsbuf(iop);
704 #ifdef	_WIDE
705 			return (FERROR(iop) ? EOF : (ssize_t)count);
706 #else  /* _WIDE */
707 			return (FERROR(iop) ? EOF : (int)count);
708 #endif /* _WIDE */
709 		}
710 
711 		/*
712 		 *	% has been found.
713 		 *	The following switch is used to parse the format
714 		 *	specification and to perform the operation specified
715 		 *	by the format letter.  The program repeatedly goes
716 		 *	back to this switch until the format letter is
717 		 *	encountered.
718 		 */
719 		width = prefixlength = otherlength = 0;
720 		flagword = suffixlength = 0;
721 		format++;
722 		wflag = 0;
723 		lflag = 0;
724 		sec_display = 0;
725 		quote = 0;
726 
727 	charswitch:
728 
729 		switch (fcode = *format++) {
730 
731 		case '+':
732 			flagword |= FPLUS;
733 			goto charswitch;
734 		case '-':
735 			flagword |= FMINUS;
736 			flagword &= ~PADZERO; /* ignore 0 flag */
737 			goto charswitch;
738 		case ' ':
739 			flagword |= FBLANK;
740 			goto charswitch;
741 		case '\'':	/* XSH4 */
742 			quote++;
743 			goto charswitch;
744 		case '#':
745 			flagword |= FSHARP;
746 			goto charswitch;
747 
748 		/* Scan the field width and precision */
749 		case '.':
750 			flagword |= DOTSEEN;
751 			prec = 0;
752 			goto charswitch;
753 
754 		case '*':
755 			if (_M_ISDIGIT(*format)) {
756 				starflg = 1;
757 				bargs = args;
758 				goto charswitch;
759 			}
760 			if (!(flagword & DOTSEEN)) {
761 				width = va_arg(args.ap, int);
762 				if (width < 0) {
763 					width = -width;
764 					flagword |= FMINUS;
765 				}
766 			} else {
767 				prec = va_arg(args.ap, int);
768 				if (prec < 0) {
769 					prec = 0;
770 					flagword ^= DOTSEEN; /* ANSI sez so */
771 				}
772 			}
773 			goto charswitch;
774 
775 		case '$':
776 			{
777 			ssize_t		position;
778 			stva_list	targs;
779 			if (fpos) {
780 #ifdef	_WIDE
781 				_wmkarglst(sformat, sargs, arglst, prflag);
782 #else  /* _WIDE */
783 				_mkarglst(sformat, sargs, arglst, prflag);
784 #endif /* _WIDE */
785 				fpos = 0;
786 			}
787 			if (flagword & DOTSEEN) {
788 				position = prec;
789 				prec = 0;
790 			} else {
791 				position = width;
792 				width = 0;
793 			}
794 			if (position <= 0) {
795 				/* illegal position */
796 				format--;
797 				continue;
798 			}
799 			if (position <= MAXARGS) {
800 				targs = arglst[position - 1];
801 			} else {
802 				targs = arglst[MAXARGS - 1];
803 #ifdef	_WIDE
804 				_wgetarg(sformat, &targs, position, prflag);
805 #else  /* _WIDE */
806 				_getarg(sformat, &targs, position, prflag);
807 #endif /* _WIDE */
808 			}
809 			if (!starflg)
810 				args = targs;
811 			else {
812 				starflg = 0;
813 				args = bargs;
814 				if (flagword & DOTSEEN) {
815 					prec = va_arg(targs.ap, int);
816 					if (prec < 0) {
817 						prec = 0;
818 						flagword ^= DOTSEEN; /* XSH */
819 					}
820 				} else {
821 					width = va_arg(targs.ap, int);
822 					if (width < 0) {
823 						width = -width;
824 						flagword |= FMINUS;
825 					}
826 				}
827 			}
828 			goto charswitch;
829 			}
830 
831 		case '0':	/* obsolescent spec:  leading zero in width */
832 				/* means pad with leading zeros */
833 			if (!(flagword & (DOTSEEN | FMINUS)))
834 				flagword |= PADZERO;
835 			/* FALLTHROUGH */
836 		case '1':
837 		case '2':
838 		case '3':
839 		case '4':
840 		case '5':
841 		case '6':
842 		case '7':
843 		case '8':
844 		case '9':
845 			{ num = fcode - '0';
846 			while (_M_ISDIGIT(fcode = *format)) {
847 				num = num * 10 + fcode - '0';
848 				format++;
849 			}
850 			if (flagword & DOTSEEN)
851 				prec = num;
852 			else
853 				width = num;
854 			goto charswitch;
855 			}
856 
857 		/* Scan the length modifier */
858 		case 'l':
859 			if (!(flagword & XLONG)) {
860 				if (lflag) {
861 					/* long long */
862 					flagword &= ~LENGTH;
863 					flagword |= XLONG;
864 				} else	{
865 					/* long */
866 					flagword |= LENGTH;
867 				}
868 			}
869 			lflag++;
870 			goto charswitch;
871 
872 		case 'L':			/* long double */
873 			flagword |= QUAD;
874 			goto charswitch;
875 
876 		case 'h':
877 			if (!(flagword & CHAR)) {
878 				if (flagword & SHORT) {
879 					/* char - hh */
880 					flagword &= ~SHORT;
881 					flagword |= CHAR;
882 				} else {
883 					/* short */
884 					flagword |= SHORT;
885 				}
886 			}
887 			goto charswitch;
888 		case 'j':
889 #ifndef _LP64
890 			/*
891 			 * *printf_c89() in 32-bit libc uses
892 			 * 32-bit intmax_t; otherwise intmax_t
893 			 * is 64-bits.
894 			 */
895 			if (!(prflag & _F_INTMAX32)) {
896 #endif
897 				flagword |= XLONG;	/* [u]intmax_t (64) */
898 #ifndef _LP64
899 			}
900 #endif
901 			goto charswitch;
902 
903 		case 't':
904 			/*
905 			 * LENGTH is shared by l, t, z specifiers; protect
906 			 * against (destructive) undefined behavior (eg:
907 			 * avoid %llt setting XLONG and LENGTH) with invalid
908 			 * combinations of specifiers
909 			 */
910 			if (!(flagword & XLONG)) {
911 				flagword |= LENGTH;	/* ptrdiff_t */
912 			}
913 			goto charswitch;
914 
915 		case 'z':
916 			if (!(flagword & XLONG)) {
917 				flagword |= LENGTH;	/* [s]size_t */
918 			}
919 			goto charswitch;
920 
921 		/*
922 		 *	The character addressed by format must be
923 		 *	the format letter -- there is nothing
924 		 *	left for it to be.
925 		 *
926 		 *	The status of the +, -, #, and blank
927 		 *	flags are reflected in the variable
928 		 *	"flagword".  "width" and "prec" contain
929 		 *	numbers corresponding to the digit
930 		 *	strings before and after the decimal
931 		 *	point, respectively. If there was no
932 		 *	decimal point, then flagword & DOTSEEN
933 		 *	is false and the value of prec is meaningless.
934 		 *
935 		 *	The following switch cases set things up
936 		 *	for printing.  What ultimately gets
937 		 *	printed will be padding blanks, a
938 		 *	prefix, left padding zeroes, a value,
939 		 *	right padding zeroes, a suffix, and
940 		 *	more padding blanks.  Padding blanks
941 		 *	will not appear simultaneously on both
942 		 *	the left and the right.  Each case in
943 		 *	this switch will compute the value, and
944 		 *	leave in several variables the informa-
945 		 *	tion necessary to construct what is to
946 		 *	be printed.
947 		 *
948 		 *	The prefix is a sign, a blank, "0x",
949 		 *	"0X", a sign or a blank followed by "0x"
950 		 *	or "0X", or nothing, and is addressed by
951 		 *	"prefix".
952 		 *
953 		 *	The suffix is either null or an
954 		 *	exponent, and is addressed by "suffix".
955 		 *	If there is a suffix, the flagword bit
956 		 *	SUFFIX will be set.
957 		 *
958 		 *	The value to be printed starts at "bp"
959 		 *	and continues up to and not including
960 		 *	"p".
961 		 *
962 		 *	"lzero" and "rzero" will contain the
963 		 *	number of padding zeroes required on
964 		 *	the left and right, respectively.
965 		 *	The flagword bits LZERO and RZERO tell
966 		 *	whether padding zeros are required.
967 		 *
968 		 *	The number of padding blanks, and
969 		 *	whether they go on the left or the
970 		 *	right, will be computed on exit from
971 		 *	the switch.
972 		 */
973 
974 
975 
976 		/*
977 		 *	decimal fixed point representations
978 		 *
979 		 *	HIBITL is 100...000
980 		 *	binary, and is equal to	the maximum
981 		 *	negative number.
982 		 *	We assume a 2's complement machine
983 		 */
984 		case 'i':
985 		case 'd':
986 			if ((flagword & PADZERO) && (flagword & DOTSEEN))
987 				flagword &= ~PADZERO; /* ignore 0 flag */
988 			/* Set buffer pointer to last digit */
989 			p = bp = buf + MAXLLDIGS;
990 
991 			/* Fetch the argument to be printed */
992 			if (flagword & XLONG) {		/* long long */
993 				ll = va_arg(args.ap, long long);
994 
995 				/* If signed conversion, make sign */
996 				if (ll < 0) {
997 					prefix = _P_HYPHEN;
998 					prefixlength = 1;
999 					/*
1000 					 * Negate, checking in advance for
1001 					 * possible overflow.
1002 					 */
1003 					if (ll != HIBITLL)
1004 						ll = -ll;
1005 					else
1006 					/* number is -HIBITLL; convert last */
1007 					/* digit now and get positive number */
1008 						*--bp = _lowlldigit(&ll);
1009 				} else if (flagword & FPLUS) {
1010 					prefix = _P_PLUS;
1011 					prefixlength = 1;
1012 				} else if (flagword & FBLANK) {
1013 					prefix = _P_BLANK;
1014 					prefixlength = 1;
1015 				}
1016 			} else {		/* not long long */
1017 				if (flagword & LENGTH)
1018 					val = va_arg(args.ap, long);
1019 				else
1020 					val = va_arg(args.ap, int);
1021 
1022 				if (flagword & SHORT)
1023 					val = (short)val;
1024 				else if (flagword & CHAR)
1025 					val = (char)val;
1026 
1027 				/* If signed conversion, make sign */
1028 				if (val < 0) {
1029 					prefix = _P_HYPHEN;
1030 					prefixlength = 1;
1031 					/*
1032 					 * Negate, checking in advance
1033 					 * for possible overflow.
1034 					 */
1035 					if (val != HIBITL)
1036 						val = -val;
1037 					/*
1038 					 * number is -HIBITL; convert
1039 					 * last digit now and get
1040 					 * positive number
1041 					 */
1042 					else
1043 						*--bp = _lowdigit(&val);
1044 				} else if (flagword & FPLUS) {
1045 					prefix = _P_PLUS;
1046 					prefixlength = 1;
1047 				} else if (flagword & FBLANK) {
1048 					prefix = _P_BLANK;
1049 					prefixlength = 1;
1050 				}
1051 			}
1052 
1053 		decimal:
1054 			{
1055 			long qval = val;
1056 			long long lll = ll;
1057 			long long tll;
1058 			if (flagword & XLONG) {
1059 				if (lll < 10LL) {
1060 #ifdef	_WIDE
1061 					if (lll != 0LL || !(flagword & DOTSEEN))
1062 						*--bp = (wchar_t)lll + L'0';
1063 #else  /* _WIDE */
1064 					if (lll != 0LL || !(flagword & DOTSEEN))
1065 						*--bp = (char)lll + '0';
1066 #endif /* _WIDE */
1067 				} else {
1068 					do {
1069 						tll = lll;
1070 						lll /= 10;
1071 #ifdef	_WIDE
1072 						*--bp = (wchar_t)
1073 							(tll - lll * 10 + '0');
1074 #else  /* _WIDE */
1075 						*--bp = (char) \
1076 						    (tll - lll * 10 + '0');
1077 #endif /* _WIDE */
1078 					} while (lll >= 10);
1079 #ifdef	_WIDE
1080 					*--bp = (wchar_t)lll + '0';
1081 #else  /* _WIDE */
1082 					*--bp = (char)lll + '0';
1083 #endif /* _WIDE */
1084 				}
1085 			} else {
1086 				if (qval <= 9) {
1087 #ifdef	_WIDE
1088 					if (qval != 0 || !(flagword & DOTSEEN))
1089 						*--bp = (wchar_t)qval + '0';
1090 #else  /* _WIDE */
1091 					if (qval != 0 || !(flagword & DOTSEEN))
1092 						*--bp = (char)qval + '0';
1093 #endif /* _WIDE */
1094 				} else {
1095 					do {
1096 						n = qval;
1097 						qval /= 10;
1098 #ifdef	_WIDE
1099 						*--bp = (wchar_t) \
1100 						    (n - qval * 10 + '0');
1101 #else  /* _WIDE */
1102 						*--bp = (char) \
1103 						    (n - qval * 10 + '0');
1104 #endif /* _WIDE */
1105 					} while (qval > 9);
1106 #ifdef	_WIDE
1107 					*--bp = (wchar_t)qval + '0';
1108 #else  /* _WIDE */
1109 					*--bp = (char)qval + '0';
1110 #endif /* _WIDE */
1111 				}
1112 			}
1113 			}
1114 			/* Handle the ' flag */
1115 			if (quote) {
1116 				p = insert_thousands_sep(bp, p);
1117 			}
1118 
1119 			/* Calculate minimum padding zero requirement */
1120 			if (flagword & DOTSEEN) {
1121 				leadzeroes = prec - (p - bp);
1122 				if (leadzeroes > 0) {
1123 					otherlength = lzero = leadzeroes;
1124 					flagword |= LZERO;
1125 				}
1126 			}
1127 			break;
1128 
1129 		case 'u':
1130 			if ((flagword & PADZERO) && (flagword & DOTSEEN))
1131 				flagword &= ~PADZERO; /* ignore 0 flag */
1132 			p = bp = buf + MAXLLDIGS;
1133 
1134 			/* Fetch the argument to be printed */
1135 			if (flagword & XLONG) {
1136 				ll = va_arg(args.ap, long long);
1137 
1138 				if (ll & HIBITLL)
1139 					*--bp = _lowlldigit(&ll);
1140 			} else {
1141 				if (flagword & LENGTH)
1142 					val = va_arg(args.ap, long);
1143 				else
1144 					val = va_arg(args.ap, unsigned);
1145 
1146 				if (flagword & SHORT)
1147 					val = (unsigned short)val;
1148 				else if (flagword & CHAR)
1149 					val = (unsigned char)val;
1150 
1151 				if (val & HIBITL)
1152 					*--bp = _lowdigit(&val);
1153 			}
1154 
1155 			goto decimal;
1156 
1157 		/*
1158 		 *	non-decimal fixed point representations
1159 		 *	for radix equal to a power of two
1160 		 *
1161 		 *	"mradix" is one less than the radix for the conversion.
1162 		 *	"lradix" is one less than the base 2 log
1163 		 *	of the radix for the conversion. Conversion is unsigned.
1164 		 *	HIBITL is 100...000
1165 		 *	binary, and is equal to	the maximum
1166 		 *	negative number.
1167 		 *	We assume a 2's complement machine
1168 		 */
1169 
1170 		case 'o':
1171 			mradix = 7;
1172 			lradix = 2;
1173 			/*
1174 			 * DR151 and clarification in C90
1175 			 * presence of '#' increases precision to first
1176 			 * digit of the result to be zero
1177 			 */
1178 			if ((flagword & DOTSEEN) && (flagword & FSHARP) &&
1179 			    prec == 0)
1180 				prec = 1;
1181 
1182 			goto fixed;
1183 
1184 		case 'p':
1185 			flagword &= ~(XLONG | SHORT);
1186 			flagword |= LENGTH;
1187 
1188 			/* FALLTHRU */
1189 		case 'X':
1190 		case 'x':
1191 			mradix = 15;
1192 			lradix = 3;
1193 
1194 		fixed:
1195 			if ((flagword & PADZERO) && (flagword & DOTSEEN))
1196 				flagword &= ~PADZERO; /* ignore 0 flag */
1197 
1198 #ifdef	_WIDE
1199 			/* Set translate table for digits */
1200 			tab = (wchar_t *)((fcode == 'X') ? uc_digs : lc_digs);
1201 #else  /* _WIDE */
1202 			/* Set translate table for digits */
1203 			tab = (fcode == 'X') ? uc_digs : lc_digs;
1204 #endif /* _WIDE */
1205 
1206 			/* Fetch the argument to be printed */
1207 			if (flagword & XLONG) {
1208 				ll = va_arg(args.ap, long long);
1209 			} else {
1210 				if (flagword & LENGTH)
1211 					val = va_arg(args.ap, long);
1212 				else
1213 					val = va_arg(args.ap, unsigned);
1214 
1215 				if (flagword & SHORT)
1216 					val = (unsigned short) val;
1217 				else if (flagword & CHAR)
1218 					val = (unsigned char) val;
1219 			}
1220 			p = bp = buf + MAXLLDIGS;
1221 
1222 			/* Develop the digits of the value */
1223 			if (flagword & XLONG) {
1224 				long long lll = ll;
1225 
1226 				if (lll == 0LL) {
1227 					if (!(flagword & DOTSEEN)) {
1228 						otherlength = lzero = 1;
1229 						flagword |= LZERO;
1230 					}
1231 				} else do {
1232 					*--bp = tab[(ssize_t)(lll & mradix)];
1233 					lll = ((lll >> 1) & ~HIBITLL) \
1234 					    >> lradix;
1235 				} while (lll != 0LL);
1236 			} else {
1237 				long qval = val;
1238 
1239 				if (qval == 0) {
1240 					if (!(flagword & DOTSEEN)) {
1241 						otherlength = lzero = 1;
1242 						flagword |= LZERO;
1243 					}
1244 				} else do {
1245 					*--bp = tab[qval & mradix];
1246 					qval = ((qval >> 1) & ~HIBITL) \
1247 					    >> lradix;
1248 				} while (qval != 0);
1249 			}
1250 
1251 			/* Calculate minimum padding zero requirement */
1252 			if (flagword & DOTSEEN) {
1253 				leadzeroes = prec - (p - bp);
1254 				if (leadzeroes > 0) {
1255 					otherlength = lzero = leadzeroes;
1256 					flagword |= LZERO;
1257 				}
1258 			}
1259 
1260 			/* Handle the # flag, (val != 0) for int and long */
1261 			/* (ll!= 0) handles long long case */
1262 			if ((flagword & FSHARP) &&
1263 			    (((flagword & XLONG) == 0 && val != 0) ||
1264 			    ((flagword & XLONG) == XLONG && ll != 0)))
1265 				switch (fcode) {
1266 				case 'o':
1267 					if (!(flagword & LZERO)) {
1268 						otherlength = lzero = 1;
1269 						flagword |= LZERO;
1270 					}
1271 					break;
1272 				case 'x':
1273 					prefix = _P_ZEROx;
1274 					prefixlength = 2;
1275 					break;
1276 				case 'X':
1277 					prefix = _P_ZEROX;
1278 					prefixlength = 2;
1279 					break;
1280 				}
1281 
1282 			break;
1283 
1284 		case 'A':
1285 		case 'a':
1286 			/* A format */
1287 			if (flagword & QUAD) {
1288 				long double	qval = GETQVAL(args.ap);
1289 
1290 				/* establish default precision */
1291 				if (!(flagword & DOTSEEN))
1292 #if defined(__sparc)
1293 					prec = HEXFP_QUAD_DIG - 1;
1294 #elif defined(__i386) || defined(__amd64)
1295 					prec = HEXFP_EXTENDED_DIG - 1;
1296 #else
1297 #error Unknown architecture
1298 #endif
1299 
1300 				FPCONV(__qaconvert, &qval,
1301 				    min(prec + 1, MAXECVT), &exp, &sign,
1302 				    cvtbuf);
1303 			} else {
1304 				double	dval = va_arg(args.ap, double);
1305 
1306 				/* establish default precision */
1307 				if (!(flagword & DOTSEEN))
1308 					prec = HEXFP_DOUBLE_DIG - 1;
1309 
1310 				FPCONV(__aconvert, dval,
1311 				    min(prec + 1, MAXECVT), &exp, &sign,
1312 				    cvtbuf);
1313 			}
1314 			bp = cvtbuf;
1315 
1316 			/*
1317 			 * The following is wide-character safe because
1318 			 * __aconvert and __qaconvert only produce ASCII
1319 			 * characters.
1320 			 */
1321 			if (!isxdigit((unsigned char)*bp)) {
1322 				inf_nan = 1;
1323 				break;
1324 			}
1325 
1326 			/*
1327 			 * Create the prefix.  We ought to use the strings
1328 			 * defined above (_P_HYPHEN, etc.), but that would
1329 			 * be awkward: we'd either have to define six more
1330 			 * of them or we'd have to use strcpy/strcat to
1331 			 * assemble the ones already defined.  So instead,
1332 			 * we just build the prefix character by character.
1333 			 */
1334 			p = prefix = prefixbuf;
1335 			if (sign) {
1336 				*p++ = '-';
1337 				prefixlength = 1;
1338 			} else if (flagword & FPLUS) {
1339 				*p++ = '+';
1340 				prefixlength = 1;
1341 			} else if (flagword & FBLANK) {
1342 				*p++ = ' ';
1343 				prefixlength = 1;
1344 			}
1345 			*p++ = '0';
1346 			*p++ = (fcode == 'A') ? 'X' : 'x';
1347 			*p = '\0';
1348 			prefixlength += 2;
1349 
1350 			/* put the first digit in the buffer */
1351 			p = &buf[0];
1352 			*p++ = (*bp != '\0') ? *bp++ : '0';
1353 
1354 			/* put in a decimal point if needed */
1355 			if (prec != 0 || (flagword & FSHARP))
1356 				*p++ = _numeric[0];
1357 
1358 			/* create the rest of the mantissa */
1359 			rz = prec;
1360 			if (fcode == 'A') {
1361 				for (; rz > 0 && *bp != '\0'; --rz) {
1362 					*p++ = ('a' <= *bp && *bp <= 'f')?
1363 					    *bp - 32 : *bp;
1364 					bp++;
1365 				}
1366 			} else {
1367 				for (; rz > 0 && *bp != '\0'; --rz)
1368 					*p++ = *bp++;
1369 			}
1370 			if (rz > 0) {
1371 				otherlength = rzero = rz;
1372 				flagword |= RZERO;
1373 			}
1374 
1375 			bp = &buf[0];
1376 
1377 			/*
1378 			 * Create the exponent in right-to-left order.
1379 			 * buf[0] == '0' if and only if the value being
1380 			 * converted is exactly zero, in which case the
1381 			 * exponent should be +0 regardless of exp.
1382 			 */
1383 			suffix = &expbuf[MAXESIZ];
1384 			*suffix = '\0';
1385 			if (buf[0] != '0') {
1386 				int	nn;
1387 
1388 				nn = exp;
1389 				if (nn < 0)
1390 				    nn = -nn;
1391 				for (; nn > 9; nn /= 10)
1392 					*--suffix = todigit(nn % 10);
1393 				*--suffix = todigit(nn);
1394 				*--suffix = (exp >= 0) ? '+' : '-';
1395 			} else {
1396 				*--suffix = '0';
1397 				*--suffix = '+';
1398 			}
1399 
1400 			/* put in the p */
1401 			*--suffix = (fcode == 'A') ? 'P' : 'p';
1402 
1403 			/* compute size of suffix */
1404 			suffixlength = &expbuf[MAXESIZ] - suffix;
1405 			otherlength += suffixlength;
1406 			flagword |= SUFFIX;
1407 			break;
1408 
1409 		case 'E':
1410 		case 'e':
1411 			/*
1412 			 * E-format.  The general strategy
1413 			 * here is fairly easy: we take what
1414 			 * econvert gives us and re-format it.
1415 			 * (qeconvert for long double)
1416 			 */
1417 
1418 			/* Establish default precision */
1419 			if (!(flagword & DOTSEEN))
1420 				prec = 6;
1421 
1422 			if (flagword & QUAD) {	/* long double */
1423 				long double	qval = GETQVAL(args.ap);
1424 
1425 				FPCONV(qeconvert, &qval,
1426 				    min(prec + 1, MAXECVT), &decpt, &sign,
1427 				    cvtbuf);
1428 			} else {	/* double */
1429 				double	dval = va_arg(args.ap, double);
1430 
1431 				FPCONV(econvert, dval,
1432 				    min(prec + 1, MAXECVT), &decpt, &sign,
1433 				    cvtbuf);
1434 			}
1435 			bp = cvtbuf;
1436 			if (*bp > '9') {
1437 				inf_nan = 1;
1438 				inf_nan_mixed_case = (__xpg6 &
1439 				    _C99SUSv3_mixed_case_Inf_and_NaN);
1440 				break;
1441 			}
1442 
1443 			/* Determine the prefix */
1444 		e_merge:
1445 			if (sign) {
1446 				prefix = _P_HYPHEN;
1447 				prefixlength = 1;
1448 			} else if (flagword & FPLUS) {
1449 				prefix = _P_PLUS;
1450 				prefixlength = 1;
1451 			} else if (flagword & FBLANK) {
1452 				prefix = _P_BLANK;
1453 				prefixlength = 1;
1454 			}
1455 
1456 			/* Place the first digit in the buffer */
1457 			p = &buf[0];
1458 			*p++ = (*bp != '\0') ? *bp++ : '0';
1459 
1460 			/* Put in a decimal point if needed */
1461 			if (prec != 0 || (flagword & FSHARP))
1462 				*p++ = _numeric[0];
1463 
1464 			/* Create the rest of the mantissa */
1465 			rz = prec;
1466 			for (; rz > 0 && *bp != '\0'; --rz)
1467 				*p++ = *bp++;
1468 			if (rz > 0) {
1469 				otherlength = rzero = rz;
1470 				flagword |= RZERO;
1471 			}
1472 
1473 			bp = &buf[0];
1474 
1475 			/*
1476 			 * Create the exponent.  buf[0] == '0' if and
1477 			 * only if the value being converted is exactly
1478 			 * zero, in which case the exponent should be
1479 			 * +0 regardless of decpt.
1480 			 */
1481 			*(suffix = &expbuf[MAXESIZ]) = '\0';
1482 			if (buf[0] != '0') {
1483 				int nn = decpt - 1;
1484 				if (nn < 0)
1485 				    nn = -nn;
1486 				for (; nn > 9; nn /= 10)
1487 					*--suffix = todigit(nn % 10);
1488 				*--suffix = todigit(nn);
1489 			}
1490 
1491 			/* Prepend leading zeroes to the exponent */
1492 			while (suffix > &expbuf[MAXESIZ - 2])
1493 				*--suffix = '0';
1494 
1495 			/* Put in the exponent sign */
1496 			*--suffix = (decpt > 0 || buf[0] == '0') ? '+' : '-';
1497 
1498 			/* Put in the e */
1499 			*--suffix = _M_ISUPPER(fcode) ? 'E'  : 'e';
1500 
1501 			/* compute size of suffix */
1502 			otherlength += (suffixlength = &expbuf[MAXESIZ] \
1503 			    - suffix);
1504 			flagword |= SUFFIX;
1505 			break;
1506 
1507 		case 'F':
1508 		case 'f':
1509 			/*
1510 			 * F-format floating point.  This is a
1511 			 * good deal less simple than E-format.
1512 			 * The overall strategy will be to call
1513 			 * fconvert, reformat its result into buf,
1514 			 * and calculate how many trailing
1515 			 * zeroes will be required.  There will
1516 			 * never be any leading zeroes needed.
1517 			 * (qfconvert for long double)
1518 			 */
1519 
1520 			/* Establish default precision */
1521 			if (!(flagword & DOTSEEN))
1522 				prec = 6;
1523 
1524 			if (flagword & QUAD) {	/* long double */
1525 				long double	qval = GETQVAL(args.ap);
1526 
1527 				FPCONV(qfconvert, &qval, min(prec, MAXFCVT),
1528 				    &decpt, &sign, cvtbuf);
1529 				bp = cvtbuf;
1530 				if (*bp == 0) {
1531 					/*
1532 					 * qfconvert would have required
1533 					 * too many characters; use qeconvert
1534 					 * instead
1535 					 */
1536 					FPCONV(qeconvert, &qval,
1537 					    min(prec + 1, MAXECVT), &decpt,
1538 					    &sign, cvtbuf);
1539 					goto e_merge;
1540 				}
1541 			} else {	/* double */
1542 				double	dval = va_arg(args.ap, double);
1543 
1544 				FPCONV(fconvert, dval, min(prec, MAXFCVT),
1545 				    &decpt, &sign, cvtbuf);
1546 			}
1547 			bp = cvtbuf;
1548 			if (*bp > '9') {
1549 				inf_nan = 1;
1550 				if (fcode == 'f')
1551 					inf_nan_mixed_case = (__xpg6 &
1552 					    _C99SUSv3_mixed_case_Inf_and_NaN);
1553 				break;
1554 			}
1555 
1556 			/* Determine the prefix */
1557 		f_merge:
1558 			if (sign) {
1559 				prefix = _P_HYPHEN;
1560 				prefixlength = 1;
1561 			} else if (flagword & FPLUS) {
1562 				prefix = _P_PLUS;
1563 				prefixlength = 1;
1564 			} else if (flagword & FBLANK) {
1565 				prefix = _P_BLANK;
1566 				prefixlength = 1;
1567 			}
1568 
1569 			/* Initialize buffer pointer */
1570 			p = &buf[0];
1571 
1572 			{
1573 				ssize_t nn = decpt;
1574 
1575 				/* Emit the digits before the decimal point */
1576 				k = 0;
1577 				do {
1578 					*p++ = (nn <= 0 || *bp == '\0' || \
1579 					    k >= MAXFSIG) ? '0' : (k++, *bp++);
1580 				} while (--nn > 0);
1581 
1582 				if (quote)
1583 					p = insert_thousands_sep(buf, p);
1584 
1585 				/* Decide whether we need a decimal point */
1586 				if ((flagword & FSHARP) || prec > 0)
1587 					*p++ = _numeric[0];
1588 
1589 				/* Digits (if any) after the decimal point */
1590 				nn = min(prec, MAXFCVT);
1591 				if (prec > nn) {
1592 					flagword |= RZERO;
1593 					otherlength = rzero = prec - nn;
1594 				}
1595 				while (--nn >= 0)
1596 					*p++ = (++decpt <= 0 || *bp == '\0' || \
1597 					    k >= MAXFSIG) ? '0' : (k++, *bp++);
1598 			}
1599 
1600 			bp = &buf[0];
1601 
1602 			break;
1603 
1604 		case 'G':
1605 		case 'g':
1606 			/*
1607 			 * g-format.  We play around a bit
1608 			 * and then jump into e or f, as needed.
1609 			 */
1610 
1611 			/* Establish default precision */
1612 			if (!(flagword & DOTSEEN))
1613 				prec = 6;
1614 			else if (prec == 0)
1615 				prec = 1;
1616 
1617 			if (flagword & QUAD) {	/* long double */
1618 				long double	qval = GETQVAL(args.ap);
1619 
1620 				FPCONV(qeconvert, &qval, min(prec, MAXECVT),
1621 				    &decpt, &sign, cvtbuf);
1622 			} else {	/* double */
1623 				double	dval = va_arg(args.ap, double);
1624 
1625 				FPCONV(econvert, dval, min(prec, MAXECVT),
1626 				    &decpt, &sign, cvtbuf);
1627 			}
1628 			bp = cvtbuf;
1629 			if (*bp > '9') {
1630 				inf_nan = 1;
1631 				inf_nan_mixed_case = (__xpg6 &
1632 				    _C99SUSv3_mixed_case_Inf_and_NaN);
1633 				break;
1634 			}
1635 			if (*bp == '0')	/* the value converted is zero */
1636 				decpt = 1;
1637 
1638 			{
1639 				int kk = prec;
1640 				if (!(flagword & FSHARP)) {
1641 #ifdef	_WIDE
1642 					n = wcslen(bp);
1643 #else  /* _WIDE */
1644 					n = strlen(bp);
1645 #endif /* _WIDE */
1646 					if (n < kk)
1647 						kk = (int)n;
1648 					while (kk >= 1 && bp[kk-1] == '0')
1649 						--kk;
1650 				}
1651 				if (decpt < -3 || decpt > prec) {
1652 					prec = kk - 1;
1653 					goto e_merge;
1654 				}
1655 				prec = kk - decpt;
1656 				goto f_merge;
1657 			}
1658 
1659 		case '%':
1660 			buf[0] = fcode;
1661 			goto c_merge;
1662 
1663 #ifndef	_WIDE
1664 		case 'w':
1665 			wflag = 1;
1666 			goto charswitch;
1667 #endif /* _WIDE */
1668 
1669 
1670 		case 'C': /* XPG XSH4 extention */
1671 wide_C:
1672 			{
1673 				wchar_t	temp;
1674 
1675 				temp = va_arg(args.ap, wchar_t);
1676 #ifdef	_WIDE
1677 				if (temp) {
1678 					buf[0] = temp;
1679 					p = (bp = buf) + 1;
1680 				} else {
1681 					buf[0] = 0;
1682 					p = (bp = buf) + 1;
1683 				}
1684 				wcount = 1;
1685 				wflag = 1;
1686 #else  /* _WIDE */
1687 				if (temp) {
1688 					if ((retcode = wctomb(buf, temp))
1689 						== -1) {
1690 						errno = EILSEQ;
1691 						return (EOF);
1692 					} else {
1693 						p = (bp = buf) + retcode;
1694 					}
1695 				} else { /* NULL character */
1696 					buf[0] = 0;
1697 					p = (bp = buf) + 1;
1698 				}
1699 				wcount = p - bp;
1700 #endif /* _WIDE */
1701 			}
1702 			break;
1703 		case 'c':
1704 			if (lflag) {
1705 				goto wide_C;
1706 			}
1707 #ifndef	_WIDE
1708 			if (wflag) {
1709 				wchar_t	temp;
1710 
1711 				temp = va_arg(args.ap, wchar_t);
1712 				if (temp) {
1713 					if ((retcode = wctomb(buf, temp))
1714 						== -1) {
1715 						p = (bp = buf) + 1;
1716 					} else {
1717 						p = (bp = buf) + retcode;
1718 					}
1719 				} else { /* NULL character */
1720 					buf[0] = 0;
1721 					p = (bp = buf) + 1;
1722 				}
1723 				wcount = p - bp;
1724 			} else {
1725 #endif /* _WIDE */
1726 				if (flagword & XLONG) {
1727 					long long temp;
1728 					temp = va_arg(args.ap, long long);
1729 #ifdef	_WIDE
1730 					buf[0] = (wchar_t)temp;
1731 #else  /* _WIDE */
1732 					buf[0] = (char)temp;
1733 #endif /* _WIDE */
1734 				} else
1735 					buf[0] = va_arg(args.ap, int);
1736 			c_merge:
1737 				p = (bp = &buf[0]) + 1;
1738 #ifdef	_WIDE
1739 				wcount = 1;
1740 				wflag = 1;
1741 #endif /* _WIDE */
1742 #ifndef	_WIDE
1743 			}
1744 #endif /* _WIDE */
1745 			break;
1746 
1747 		case 'S': /* XPG XSH4 extention */
1748 wide_S:
1749 #ifdef	_WIDE
1750 			if (!lflag) {
1751 				lflag++;
1752 			}
1753 			bp = va_arg(args.ap, wchar_t *);
1754 			if (bp == NULL)
1755 				bp = (wchar_t *)widenullstr;
1756 			if (!(flagword & DOTSEEN)) {
1757 				/* wide character handling */
1758 				prec = MAXINT;
1759 			}
1760 
1761 			wp = bp;
1762 			wcount = 0;
1763 			while (*wp) {
1764 				if ((prec - wcount - 1) >= 0) {
1765 					wcount++;
1766 					wp++;
1767 				} else {
1768 					break;
1769 				}
1770 			}
1771 			p = wp;
1772 			wflag = 1;
1773 			break;
1774 #else  /* _WIDE */
1775 			if (!wflag)
1776 				wflag++;
1777 			bp = va_arg(args.ap, char *);
1778 			if (bp == NULL)
1779 				bp = (char *)widenullstr;
1780 			if (!(flagword & DOTSEEN)) {
1781 				/* wide character handling */
1782 				prec = MAXINT;
1783 			}
1784 
1785 			wp = (wchar_t *)(uintptr_t)bp;
1786 			wcount = 0;
1787 			while (*wp) {
1788 				int nbytes;
1789 
1790 				nbytes = wctomb(tmpbuf, *wp);
1791 				if (nbytes < 0) {
1792 					errno = EILSEQ;
1793 					return (EOF);
1794 				}
1795 				if ((prec - (wcount + nbytes)) >= 0) {
1796 					wcount += nbytes;
1797 					wp++;
1798 				} else {
1799 					break;
1800 				}
1801 			}
1802 			sec_display = wcount;
1803 			p = (char *)wp;
1804 			break;
1805 #endif /* _WIDE */
1806 		case 's':
1807 			if (lflag) {
1808 				goto wide_S;
1809 			}
1810 #ifdef	_WIDE
1811 			cbp = va_arg(args.ap, char *);
1812 			if (cbp == NULL)
1813 				cbp = (char *)nullstr;
1814 			if (!(flagword & DOTSEEN)) {
1815 				size_t	nwc;
1816 				wchar_t	*wstr;
1817 
1818 				nwc = mbstowcs(NULL, cbp, 0);
1819 				if (nwc == (size_t)-1) {
1820 					errno = EILSEQ;
1821 					return (EOF);
1822 				}
1823 				bpsize = sizeof (wchar_t) * (nwc + 1);
1824 				wstr = (wchar_t *)lmalloc(bpsize);
1825 				if (wstr == NULL) {
1826 					errno = EILSEQ;
1827 					return (EOF);
1828 				}
1829 				nwc = mbstowcs(wstr, cbp, MAXINT);
1830 				wcount = nwc;
1831 				bp = wstr;
1832 				p = wstr + nwc;
1833 			} else {
1834 				size_t	nwc;
1835 				wchar_t	*wstr;
1836 
1837 				nwc = mbstowcs(NULL, cbp, 0);
1838 				if (nwc == (size_t)-1) {
1839 					errno = EILSEQ;
1840 					return (EOF);
1841 				}
1842 				if (prec > nwc) {
1843 					bpsize = sizeof (wchar_t) * nwc;
1844 					wstr = (wchar_t *)lmalloc(bpsize);
1845 					if (wstr == NULL) {
1846 						errno = ENOMEM;
1847 						return (EOF);
1848 					}
1849 					nwc = mbstowcs(wstr, cbp, nwc);
1850 					cp = cbp + strlen(cbp);
1851 					wcount = nwc;
1852 					bp = wstr;
1853 					p = wstr + nwc;
1854 				} else {
1855 					size_t	nnwc;
1856 					int	len;
1857 					char	*s;
1858 					wchar_t	*wstr;
1859 
1860 					bpsize = sizeof (wchar_t) * prec;
1861 					wstr = (wchar_t *)lmalloc(bpsize);
1862 					if (wstr == NULL) {
1863 						errno = ENOMEM;
1864 						return (EOF);
1865 					}
1866 					nwc = mbstowcs(wstr, cbp, prec);
1867 					wcount = prec;
1868 					bp = wstr;
1869 					p = wstr + nwc;
1870 				}
1871 			}
1872 			wflag = 1;
1873 #else  /* _WIDE */
1874 			bp = va_arg(args.ap, char *);
1875 			if (bp == NULL)
1876 				bp = (char *)nullstr;
1877 			if (!(flagword & DOTSEEN)) {
1878 				if (wflag) {
1879 					/* wide character handling */
1880 					prec = MAXINT;
1881 					goto wide_hand;
1882 				}
1883 
1884 
1885 				p = bp + strlen(bp);
1886 
1887 				/*
1888 				 * sec_display only needed if width
1889 				 * is specified (ie, "%<width>s")
1890 				 * Solaris behavior counts <width> in
1891 				 * screen column width.  (If XPG4 behavior,
1892 				 * <width> is counted in bytes.)
1893 				 */
1894 				if (width > 0 && __xpg4 == 0 &&
1895 				    MB_CUR_MAX > 1) {
1896 #define	NW	256
1897 					wchar_t wbuff[NW];
1898 					wchar_t *wp, *wptr;
1899 					size_t wpsize;
1900 					size_t nwc;
1901 
1902 					wp = NULL;
1903 					if ((nwc = mbstowcs(wbuff, bp,
1904 					    NW)) == (size_t)-1) {
1905 						/* Estimate width */
1906 						sec_display = strlen(bp);
1907 						goto mbs_err;
1908 					}
1909 					if (nwc < NW) {
1910 						wptr = wbuff;
1911 					} else {
1912 						/*
1913 						 * If widechar does not fit into
1914 						 * wbuff, allocate larger buffer
1915 						 */
1916 						if ((nwc =
1917 						    mbstowcs(NULL, bp, NULL)) ==
1918 						    (size_t)-1) {
1919 							sec_display =
1920 							    strlen(bp);
1921 							goto mbs_err;
1922 						}
1923 						wpsize = (nwc + 1) *
1924 						    sizeof (wchar_t);
1925 						if ((wp = lmalloc(wpsize))
1926 						    == NULL) {
1927 							errno = ENOMEM;
1928 							return (EOF);
1929 						}
1930 						if ((nwc = mbstowcs(wp,
1931 						    bp, nwc)) == (size_t)-1) {
1932 							sec_display = \
1933 							    strlen(bp);
1934 							goto mbs_err;
1935 						}
1936 						wptr = wp;
1937 					}
1938 					if ((sec_display = wcswidth(wptr, nwc))
1939 					    == -1) {
1940 						sec_display =
1941 							_rec_scrswidth
1942 								(wptr, nwc);
1943 					}
1944 				mbs_err:
1945 					if (wp)
1946 						lfree(wp, wpsize);
1947 				}
1948 			} else { /* a strnlen function would be useful here! */
1949 				/*
1950 				 * If we've seen a dot, and count has been set
1951 				 * to 0, then we don't output in any cases
1952 				 * below. prec should be always >= 0. So we only
1953 				 * check to see if it's zero.
1954 				 */
1955 				if (prec == 0) {
1956 					p = bp;
1957 					break;
1958 				}
1959 
1960 				if (wflag) {
1961 					/* wide character handling */
1962 
1963 				wide_hand:
1964 					wp = (wchar_t *)(uintptr_t)bp;
1965 					preco = prec;
1966 					wcount = 0;
1967 					while (*wp &&
1968 					    (prec -= _scrwidth(*wp)) >= 0) {
1969 						if ((retcode =
1970 						    wctomb(tmpbuf, *wp)) < 0)
1971 							wcount++;
1972 						else
1973 							wcount += retcode;
1974 						wp++;
1975 					}
1976 					if (*wp)
1977 						prec += _scrwidth(*wp);
1978 					p = (char *)wp;
1979 					sec_display = preco - prec;
1980 				} else if (__xpg4 == 0 && MB_CUR_MAX > 1) {
1981 					/*
1982 					 * Solaris behavior - count
1983 					 * precision as screen column width
1984 					 */
1985 					char *qp = bp;
1986 					int ncol, nbytes;
1987 					wchar_t wc;
1988 
1989 					ncol = 0;
1990 					preco = prec;
1991 					while (*qp) {
1992 						if (isascii(*qp)) {
1993 							qp++;
1994 							if (--prec == 0)
1995 								break;
1996 							continue;
1997 						}
1998 						if ((nbytes = mbtowc(&wc, qp,
1999 							MB_LEN_MAX)) == -1) {
2000 							/* print illegal char */
2001 							nbytes = 1;
2002 							ncol = 1;
2003 						} else {
2004 							if ((ncol =
2005 							_scrwidth(wc))
2006 								== 0) {
2007 								ncol = 1;
2008 							}
2009 						}
2010 
2011 						if ((prec -= ncol) >= 0) {
2012 							qp += nbytes;
2013 							if (prec == 0)
2014 								break;
2015 						} else {
2016 							break;
2017 						}
2018 					}
2019 					if (prec < 0)
2020 						prec += ncol;
2021 					p = qp;
2022 					sec_display = preco - prec;
2023 				} else {
2024 					/*
2025 					 * XPG4 behavior - count
2026 					 * precision as bytes.
2027 					 * We don't use strlen() because
2028 					 * the given char string may not
2029 					 * be null-terminated.
2030 					 */
2031 					char *qp;
2032 
2033 					qp = memchr(bp, '\0', prec);
2034 					if (qp == NULL) {
2035 						p = bp + prec;
2036 					} else {
2037 						p = qp;
2038 					}
2039 				}
2040 			}
2041 #endif /* _WIDE */
2042 			break;
2043 
2044 		case 'n':
2045 			{
2046 			if (flagword & XLONG) {
2047 				long long *svcount;
2048 				svcount = va_arg(args.ap, long long *);
2049 				*svcount = (long long)count;
2050 			} else if (flagword & LENGTH) {
2051 				long *svcount;
2052 				svcount = va_arg(args.ap, long *);
2053 				*svcount = (long)count;
2054 			} else if (flagword & SHORT) {
2055 				short *svcount;
2056 				svcount = va_arg(args.ap, short *);
2057 				*svcount = (short)count;
2058 			} else if (flagword & CHAR) {
2059 				char *svcount;
2060 				svcount = va_arg(args.ap, char *);
2061 				*svcount = (char)count;
2062 			} else {
2063 				int *svcount;
2064 				svcount = va_arg(args.ap, int *);
2065 				*svcount = count;
2066 			}
2067 			continue;
2068 		}
2069 		default: /* this is technically an error; what we do is to */
2070 			/* back up the format pointer to the offending char */
2071 			/* and continue with the format scan */
2072 			format--;
2073 			continue;
2074 		}
2075 
2076 		if (inf_nan) {
2077 			if (inf_nan_mixed_case) {
2078 				/* advance p */
2079 				for (p = bp + 1; *p != '\0'; p++)
2080 					;
2081 			} else {
2082 				int upper;
2083 
2084 				/* advance p and make output all one case */
2085 				upper = _M_ISUPPER(fcode);
2086 				for (p = bp; *p != '\0'; p++)
2087 					*p = upper? toupper(*p) : tolower(*p);
2088 			}
2089 			if (sign) {
2090 				prefix = _P_HYPHEN;
2091 				prefixlength = 1;
2092 			} else if (flagword & FPLUS) {
2093 				prefix = _P_PLUS;
2094 				prefixlength = 1;
2095 			} else if (flagword & FBLANK) {
2096 				prefix = _P_BLANK;
2097 				prefixlength = 1;
2098 			}
2099 			inf_nan = 0;
2100 			inf_nan_mixed_case = 0;
2101 			flagword &= ~PADZERO; /* ignore 0 flag */
2102 		}
2103 
2104 		/* Calculate number of padding blanks */
2105 		n = p - bp; /* n == size of the converted value (in bytes) */
2106 
2107 #ifdef	_WIDE
2108 		k = n;
2109 #else  /* _WIDE */
2110 		if (sec_display) /* when format is %s or %ws or %S */
2111 			k = sec_display;
2112 		else
2113 			k = n;
2114 #endif /* _WIDE */
2115 		/*
2116 		 * k is the (screen) width or # of bytes of the converted value
2117 		 */
2118 		k += prefixlength + otherlength;
2119 
2120 #ifdef	_WIDE
2121 		if (wflag) {
2122 			count += wcount;
2123 		} else {
2124 			count += n;
2125 		}
2126 #else  /* _WIDE */
2127 		/*
2128 		 * update count which is the overall size of the output data
2129 		 * and passed to memchr()
2130 		 */
2131 		if (wflag)
2132 			/*
2133 			 * when wflag != 0 (i.e. %ws or %wc), the size of the
2134 			 * converted value is wcount bytes
2135 			 */
2136 			count += wcount;
2137 		else
2138 			/*
2139 			 * when wflag == 0, the size of the converted
2140 			 * value is n (= p-bp) bytes
2141 			 */
2142 			count += n;
2143 #endif /* _WIDE */
2144 		count += prefixlength + otherlength;
2145 
2146 		if (width > k) {
2147 			count += (width - k);
2148 			/*
2149 			 * Set up for padding zeroes if requested
2150 			 * Otherwise emit padding blanks unless output is
2151 			 * to be left-justified.
2152 			 */
2153 
2154 			if (flagword & PADZERO) {
2155 				if (!(flagword & LZERO)) {
2156 					flagword |= LZERO;
2157 					lzero = width - k;
2158 				} else
2159 					lzero += width - k;
2160 				k = width; /* cancel padding blanks */
2161 			} else
2162 				/* Blanks on left if required */
2163 				if (!(flagword & FMINUS))
2164 					PAD(_blanks, width - k);
2165 		}
2166 
2167 		/* Prefix, if any */
2168 		if (prefixlength != 0)
2169 			PUT(prefix, prefixlength);
2170 
2171 		/* Zeroes on the left */
2172 		if ((flagword & LZERO)) /* && */
2173 			/* (!(flagword & SHORT) || !(flagword & FMINUS)) */
2174 			PAD(_zeroes, lzero);
2175 
2176 #ifdef	_WIDE
2177 		if (n > 0)
2178 			PUT(bp, n);
2179 		if ((fcode == 's') && !lflag) {
2180 			if (bp)
2181 				lfree(bp, bpsize);
2182 		}
2183 #else  /* _WIDE */
2184 		/* The value itself */
2185 		if ((fcode == 's' || fcode == 'S') && wflag) {
2186 			/* wide character handling */
2187 			wchar_t *wp = (wchar_t *)(uintptr_t)bp;
2188 			int cnt;
2189 			char *bufp;
2190 			long printn;
2191 			printn = (wchar_t *)(uintptr_t)p -
2192 				(wchar_t *)(uintptr_t)bp;
2193 			bufp = buf;
2194 			while (printn > 0) {
2195 				if ((cnt = wctomb(buf, *wp)) < 0)
2196 					cnt = 1;
2197 			PUT(bufp, cnt);
2198 				wp++;
2199 				printn--;
2200 			}
2201 		} else {	/* non wide character value */
2202 			if (n > 0)
2203 				PUT(bp, n);
2204 		}
2205 #endif /* _WIDE */
2206 
2207 		if (flagword & (RZERO | SUFFIX | FMINUS)) {
2208 			/* Zeroes on the right */
2209 			if (flagword & RZERO)
2210 				PAD(_zeroes, rzero);
2211 
2212 			/* The suffix */
2213 			if (flagword & SUFFIX)
2214 				PUT(suffix, suffixlength);
2215 
2216 			/* Blanks on the right if required */
2217 			if (flagword & FMINUS && width > k)
2218 				PAD(_blanks, width - k);
2219 		}
2220 	}
2221 }
2222 
2223 #ifdef	_WIDE
2224 static int
2225 _watoi(wchar_t *fmt)
2226 {
2227 	int	n = 0;
2228 	wchar_t	ch;
2229 
2230 	ch = *fmt;
2231 	if (_M_ISDIGIT(ch)) {
2232 		n = ch - '0';
2233 		ch = *++fmt;
2234 		while (_M_ISDIGIT(ch)) {
2235 			n *= 10;
2236 			n += ch - '0';
2237 			ch = *++fmt;
2238 		}
2239 	}
2240 	return (n);
2241 }
2242 #endif /* _WIDE */
2243 
2244 /*
2245  * This function initializes arglst, to contain the appropriate va_list values
2246  * for the first MAXARGS arguments.
2247  */
2248 
2249 /*
2250  * Type modifier flags:
2251  *  0x01	for long
2252  *  0x02	for int
2253  *  0x04	for long long
2254  *  0x08	for long double
2255  */
2256 
2257 #define	FLAG_LONG	0x01
2258 #define	FLAG_INT	0x02
2259 #define	FLAG_LONG_LONG	0x04
2260 #define	FLAG_LONG_DBL	0x08
2261 
2262 /* ARGSUSED3 */
2263 #ifdef	_WIDE
2264 static void
2265 _wmkarglst(wchar_t *fmt, stva_list args, stva_list arglst[], int prflag)
2266 #else  /* _WIDE */
2267 static void
2268 _mkarglst(char *fmt, stva_list args, stva_list arglst[], int prflag)
2269 #endif /* _WIDE */
2270 {
2271 #ifdef	_WIDE
2272 	static const wchar_t	digits[] = L"01234567890";
2273 	static const wchar_t	skips[] = L"# +-.'0123456789h$";
2274 #else  /* _WIDE */
2275 	static const char digits[] = "01234567890";
2276 	static const char skips[] = "# +-.'0123456789h$";
2277 #endif /* _WIDE */
2278 	enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR,
2279 		LONG_PTR, INT_PTR, LONG_LONG, LONG_LONG_PTR};
2280 	enum types typelst[MAXARGS], curtype;
2281 	ssize_t n;
2282 	int  maxnum, curargno, flags;
2283 
2284 	/*
2285 	 * Algorithm	1. set all argument types to zero.
2286 	 *		2. walk through fmt putting arg types in typelst[].
2287 	 *		3. walk through args using va_arg(args.ap, typelst[n])
2288 	 *		   and set arglst[] to the appropriate values.
2289 	 * Assumptions:	Cannot use %*$... to specify variable position.
2290 	 */
2291 
2292 	(void) memset((void *) typelst, 0, sizeof (typelst));
2293 	maxnum = -1;
2294 	curargno = 0;
2295 	while ((fmt = STRCHR(fmt, '%')) != 0) {
2296 		fmt++;	/* skip % */
2297 		if (fmt[n = STRSPN(fmt, digits)] == '$') {
2298 			/* convert to zero base */
2299 			curargno = ATOI(fmt) - 1;
2300 			if (curargno < 0)
2301 				continue;
2302 			fmt += n + 1;
2303 		}
2304 		flags = 0;
2305 	again:;
2306 		fmt += STRSPN(fmt, skips);
2307 		switch (*fmt++) {
2308 		case '%':	/* there is no argument! */
2309 			continue;
2310 		case 'l':
2311 			if (flags & (FLAG_LONG | FLAG_LONG_LONG)) {
2312 				flags |= FLAG_LONG_LONG;
2313 				flags &= ~FLAG_LONG;
2314 			} else {
2315 				flags |= FLAG_LONG;
2316 			}
2317 			goto again;
2318 		case 'j':
2319 #ifndef _LP64
2320 			/*
2321 			 * *printf_c89() in 32-bit libc uses
2322 			 * 32-bit intmax_t; otherwise intmax_t
2323 			 * is 64-bits.
2324 			 */
2325 			if (!(prflag & _F_INTMAX32)) {
2326 #endif
2327 				flags |= FLAG_LONG_LONG;	/* 64-bit */
2328 #ifndef _LP64
2329 			}
2330 #endif
2331 			goto again;
2332 		case 't':
2333 			flags |= FLAG_LONG;
2334 			goto again;
2335 		case 'z':
2336 			flags |= FLAG_LONG;
2337 			goto again;
2338 		case 'L':
2339 			flags |= FLAG_LONG_DBL;
2340 			goto again;
2341 		case '*':	/* int argument used for value */
2342 			/* check if there is a positional parameter */
2343 #ifdef	_WIDE
2344 			if ((*fmt >= 0) && (*fmt < 256) &&
2345 				isdigit(*fmt))
2346 #else  /* _WIDE */
2347 			if (isdigit(*fmt))
2348 #endif /* _WIDE */
2349 			{
2350 				int	targno;
2351 				targno = ATOI(fmt) - 1;
2352 				fmt += STRSPN(fmt, digits);
2353 				if (*fmt == '$')
2354 					fmt++; /* skip '$' */
2355 				if (targno >= 0 && targno < MAXARGS) {
2356 					typelst[targno] = INT;
2357 					if (maxnum < targno)
2358 						maxnum = targno;
2359 				}
2360 				goto again;
2361 			}
2362 			flags |= FLAG_INT;
2363 			curtype = INT;
2364 			break;
2365 		case 'a':
2366 		case 'A':
2367 		case 'e':
2368 		case 'E':
2369 		case 'f':
2370 		case 'F':
2371 		case 'g':
2372 		case 'G':
2373 			if (flags & FLAG_LONG_DBL)
2374 				curtype = LONG_DOUBLE;
2375 			else
2376 				curtype = DOUBLE;
2377 			break;
2378 		case 's':
2379 			curtype = CHAR_PTR;
2380 			break;
2381 		case 'p':
2382 			curtype = VOID_PTR;
2383 			break;
2384 		case 'n':
2385 			if (flags & FLAG_LONG_LONG)
2386 				curtype = LONG_LONG_PTR;
2387 			else if (flags & FLAG_LONG)
2388 				curtype = LONG_PTR;
2389 			else
2390 				curtype = INT_PTR;
2391 			break;
2392 		default:
2393 			if (flags & FLAG_LONG_LONG)
2394 				curtype = LONG_LONG;
2395 			else if (flags & FLAG_LONG)
2396 				curtype = LONG;
2397 			else
2398 				curtype = INT;
2399 			break;
2400 		}
2401 		if (curargno >= 0 && curargno < MAXARGS) {
2402 			typelst[curargno] = curtype;
2403 			if (maxnum < curargno)
2404 				maxnum = curargno;
2405 		}
2406 		curargno++;	/* default to next in list */
2407 		if (flags & FLAG_INT)	/* took care of *, keep going */
2408 		{
2409 			flags ^= FLAG_INT;
2410 			goto again;
2411 		}
2412 	}
2413 	for (n = 0; n <= maxnum; n++) {
2414 		arglst[n] = args;
2415 		if (typelst[n] == 0)
2416 			typelst[n] = INT;
2417 
2418 		switch (typelst[n]) {
2419 		case INT:
2420 			(void) va_arg(args.ap, int);
2421 			break;
2422 		case LONG:
2423 			(void) va_arg(args.ap, long);
2424 			break;
2425 		case CHAR_PTR:
2426 			(void) va_arg(args.ap, char *);
2427 			break;
2428 		case DOUBLE:
2429 			(void) va_arg(args.ap, double);
2430 			break;
2431 		case LONG_DOUBLE:
2432 			(void) GETQVAL(args.ap);
2433 			break;
2434 		case VOID_PTR:
2435 			(void) va_arg(args.ap, void *);
2436 			break;
2437 		case LONG_PTR:
2438 			(void) va_arg(args.ap, long *);
2439 			break;
2440 		case INT_PTR:
2441 			(void) va_arg(args.ap, int *);
2442 			break;
2443 		case LONG_LONG:
2444 			(void) va_arg(args.ap, long long);
2445 			break;
2446 		case LONG_LONG_PTR:
2447 			(void) va_arg(args.ap, long long *);
2448 			break;
2449 		}
2450 	}
2451 }
2452 
2453 /*
2454  * This function is used to find the va_list value for arguments whose
2455  * position is greater than MAXARGS.  This function is slow, so hopefully
2456  * MAXARGS will be big enough so that this function need only be called in
2457  * unusual circumstances.
2458  * pargs is assumed to contain the value of arglst[MAXARGS - 1].
2459  */
2460 /* ARGSUSED3 */
2461 #ifdef	_WIDE
2462 static void
2463 _wgetarg(wchar_t *fmt, stva_list *pargs, long argno, int prflag)
2464 #else  /* _WIDE */
2465 void
2466 _getarg(char *fmt, stva_list *pargs, long argno, int prflag)
2467 #endif /* _WIDE */
2468 {
2469 
2470 #ifdef	_WIDE
2471 	static const wchar_t	digits[] = L"01234567890";
2472 	static const wchar_t	skips[] = L"# +-.'0123456789h$";
2473 	wchar_t	*sfmt = fmt;
2474 #else  /* _WIDE */
2475 	static const char digits[] = "01234567890";
2476 	static const char skips[] = "# +-.'0123456789h$";
2477 	char	*sfmt = fmt;
2478 #endif /* _WIDE */
2479 	ssize_t n;
2480 	int i, curargno, flags;
2481 	int	found = 1;
2482 
2483 	i = MAXARGS;
2484 	curargno = 1;
2485 	while (found) {
2486 		fmt = sfmt;
2487 		found = 0;
2488 		while ((i != argno) && (fmt = STRCHR(fmt, '%')) != 0) {
2489 			fmt++;	/* skip % */
2490 			if (fmt[n = STRSPN(fmt, digits)] == '$') {
2491 				curargno = ATOI(fmt);
2492 				if (curargno <= 0)
2493 					continue;
2494 				fmt += n + 1;
2495 			}
2496 
2497 			/* find conversion specifier for next argument */
2498 			if (i != curargno) {
2499 				curargno++;
2500 				continue;
2501 			} else
2502 				found = 1;
2503 			flags = 0;
2504 		again:;
2505 			fmt += STRSPN(fmt, skips);
2506 			switch (*fmt++) {
2507 			case '%':	/* there is no argument! */
2508 				continue;
2509 			case 'l':
2510 				if (flags & (FLAG_LONG | FLAG_LONG_LONG)) {
2511 					flags |= FLAG_LONG_LONG;
2512 					flags &= ~FLAG_LONG;
2513 				} else {
2514 					flags |= FLAG_LONG;
2515 				}
2516 				goto again;
2517 			case 'j':
2518 #ifndef _LP64
2519 				/*
2520 				 * *printf_c89() in 32-bit libc uses
2521 				 * 32-bit intmax_t; otherwise intmax_t
2522 				 * is 64-bits.
2523 				 */
2524 				if (!(prflag & _F_INTMAX32)) {
2525 #endif
2526 					flags |= FLAG_LONG_LONG;  /* 64-bit */
2527 #ifndef _LP64
2528 				}
2529 #endif
2530 				goto again;
2531 			case 't':
2532 				flags |= FLAG_LONG;
2533 				goto again;
2534 			case 'z':
2535 				flags |= FLAG_LONG;
2536 				goto again;
2537 			case 'L':
2538 				flags |= FLAG_LONG_DBL;
2539 				goto again;
2540 			case '*':	/* int argument used for value */
2541 				/*
2542 				 * check if there is a positional parameter;
2543 				 * if so, just skip it; its size will be
2544 				 * correctly determined by default
2545 				 */
2546 				if (_M_ISDIGIT(*fmt)) {
2547 					fmt += STRSPN(fmt, digits);
2548 					if (*fmt == '$')
2549 						fmt++; /* skip '$' */
2550 					goto again;
2551 				}
2552 				flags |= FLAG_INT;
2553 				(void) va_arg((*pargs).ap, int);
2554 				break;
2555 			case 'a':
2556 			case 'A':
2557 			case 'e':
2558 			case 'E':
2559 			case 'f':
2560 			case 'F':
2561 			case 'g':
2562 			case 'G':
2563 				if (flags & FLAG_LONG_DBL)
2564 					(void) GETQVAL((*pargs).ap);
2565 				else
2566 					(void) va_arg((*pargs).ap, double);
2567 				break;
2568 			case 's':
2569 				(void) va_arg((*pargs).ap, char *);
2570 				break;
2571 			case 'p':
2572 				(void) va_arg((*pargs).ap, void *);
2573 				break;
2574 			case 'n':
2575 				if (flags & FLAG_LONG_LONG)
2576 					(void) va_arg((*pargs).ap, long long *);
2577 				else if (flags & FLAG_LONG)
2578 					(void) va_arg((*pargs).ap, long *);
2579 				else
2580 					(void) va_arg((*pargs).ap, int *);
2581 				break;
2582 			default:
2583 				if (flags & FLAG_LONG_LONG)
2584 					(void) va_arg((*pargs).ap, long long);
2585 				else if (flags & FLAG_LONG)
2586 					(void) va_arg((*pargs).ap, long int);
2587 				else
2588 					(void) va_arg((*pargs).ap, int);
2589 				break;
2590 			}
2591 			i++;
2592 			curargno++;	/* default to next in list */
2593 			if (flags & FLAG_INT)	/* took care of *, keep going */
2594 			{
2595 				flags ^= FLAG_INT;
2596 				goto again;
2597 			}
2598 		}
2599 
2600 		/* missing specifier for parameter, assume param is an int */
2601 		if (!found && i != argno) {
2602 			(void) va_arg((*pargs).ap, int);
2603 			i++;
2604 			curargno = i;
2605 			found = 1;
2606 		}
2607 	}
2608 }
2609 
2610 #ifdef	_WIDE
2611 static wchar_t *
2612 insert_thousands_sep(wchar_t *bp, wchar_t *ep)
2613 #else  /* _WIDE */
2614 static char *
2615 insert_thousands_sep(char *bp, char *ep)
2616 #endif /* _WIDE */
2617 {
2618 	char thousep;
2619 	struct lconv *locptr;
2620 	ssize_t buf_index;
2621 	int i;
2622 #ifdef	_WIDE
2623 	wchar_t *obp = bp;
2624 	wchar_t buf[371];
2625 	wchar_t *bufptr = buf;
2626 #else  /* _WIDE */
2627 	char *obp = bp;
2628 	char buf[371];
2629 	char *bufptr = buf;
2630 #endif /* _WIDE */
2631 	char *grp_ptr;
2632 
2633 	/* get the thousands sep. from the current locale */
2634 	locptr = localeconv();
2635 	thousep	= *locptr->thousands_sep;
2636 	grp_ptr = locptr->grouping;
2637 
2638 	/* thousands sep. not use in this locale or no grouping required */
2639 	if (!thousep || (*grp_ptr == '\0'))
2640 		return (ep);
2641 
2642 	buf_index = ep - bp;
2643 	for (;;) {
2644 		if (*grp_ptr == CHAR_MAX) {
2645 			for (i = 0; i < buf_index--; i++)
2646 				*bufptr++ = *(bp + buf_index);
2647 			break;
2648 		}
2649 		for (i = 0; i < *grp_ptr && buf_index-- > 0; i++)
2650 			*bufptr++ = *(bp + buf_index);
2651 
2652 		if (buf_index > 0) {
2653 #ifdef	_WIDE
2654 			*bufptr++ = (wchar_t)thousep;
2655 #else  /* _WIDE */
2656 			*bufptr++ = thousep;
2657 #endif /* _WIDE */
2658 			ep++;
2659 		}
2660 		else
2661 			break;
2662 		if (*(grp_ptr + 1) != '\0')
2663 			++grp_ptr;
2664 	}
2665 
2666 	/* put the string in the caller's buffer in reverse order */
2667 	--bufptr;
2668 	while (buf <= bufptr)
2669 		*obp++ = *bufptr--;
2670 	return (ep);
2671 }
2672 
2673 
2674 /*
2675  *  Recovery scrswidth function -
2676  *  this variant of wcswidth() accepts non-printable or illegal
2677  *  widechar characters.
2678  */
2679 static int
2680 _rec_scrswidth(wchar_t *wp, ssize_t n)
2681 {
2682 	int col;
2683 	int i;
2684 
2685 	col = 0;
2686 	while (*wp && (n-- > 0)) {
2687 		if ((i = _scrwidth(*wp++)) == 0)
2688 			i = 1;
2689 		col += i;
2690 	}
2691 	return (col);
2692 }
2693