xref: /titanic_41/usr/src/lib/libbc/libc/stdio/common/doprnt.c (revision c037192b037119c9fd354732fc29b38ce097d356)
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  * Copyright 2005 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 /*
33  *	_doprnt: common code for printf, fprintf, sprintf
34  *	Floating-point code is included or not, depending
35  *	on whether the preprocessor variable FLOAT is 1 or 0.
36  */
37 #define MAXARGS 50
38 #ifndef FLOAT
39 #define	FLOAT	1	/* YES! we want floating */
40 #endif
41 
42 #include <stdio.h>
43 #include <ctype.h>
44 #include <stdarg.h>
45 #include <values.h>
46 #include <locale.h>
47 #include "doprnt.h"
48 #include "stdiom.h"
49 #include <string.h>	/* strchr, strlen, strspn */
50 
51 #define max(a,b)	((a) > (b) ? (a) : (b))
52 #define min(a,b)	((a) < (b) ? (a) : (b))
53 
54 /* If this symbol is nonzero, allow '0' as a flag */
55 /* If this symbol is nonzero, allow '0' as a flag */
56 #define FZERO 1
57 
58 #if FLOAT
59 /*
60  *	libc/gen/common functions for floating-point conversion
61  */
62 #include <floatingpoint.h>
63 extern void _fourdigitsquick();
64 #endif
65 
66 #define emitchar(c)   { if (--filecnt < 0) { \
67 				FILE *iop = file; \
68 				if (((iop->_flag & (_IOLBF|_IONBF)) == 0 \
69 				    || -filecnt >= iop->_bufsiz)) { \
70 					iop->_ptr = fileptr; \
71 					if (iop->_flag & _IOSTRG) \
72 						return iop->_ptr - iop->_base; \
73 					else \
74 						(void) _xflsbuf(iop); \
75 					fileptr = iop->_ptr; \
76 					filecnt = iop->_cnt; \
77 					filecnt--; \
78 				    } \
79 			} \
80 			*fileptr++ = (unsigned)(c); \
81 			count++; \
82                       }
83 
84 static char *nullstr = "(null)";
85 static char *lowerhex = "0123456789abcdef";
86 static char *upperhex = "0123456789ABCDEF";
87 
88 /* stva_list is used to subvert C's restriction that a variable with an
89  * array type can not appear on the left hand side of an assignment operator.
90  * By putting the array inside a structure, the functionality of assigning to
91  * the whole array through a simple assignment is achieved..
92 */
93 typedef struct stva_list {
94 	va_list ap;
95 } stva_list;
96 
97 void	_mkarglst(char *, stva_list, stva_list []);
98 void	_getarg(char *, stva_list *, int);
99 static char	*_check_dol(char *, int *);
100 
101 int
102 _doprnt(char *format, va_list in_args, FILE *file)
103 {
104 	char convertbuffer[1024] ;
105 
106 	/* Current position in format */
107 	char *cp;
108 
109 	/* Starting and ending points for value to be printed */
110 	char *bp;
111 	char *p;
112 
113 	/* Pointer and count for I/O buffer */
114 	unsigned char *fileptr;
115 	int filecnt;
116 
117 	/* Field width and precision */
118 	int width;
119 	int prec;
120 
121 	/* Format code */
122 	char fcode;
123 
124 	/* Number of padding zeroes required on the left */
125 	int lzero;
126 
127 	/* Flags - nonzero if corresponding character appears in format */
128 	bool fplus;		/* + */
129 	bool fminus;		/* - */
130 	bool fblank;		/* blank */
131 	bool fsharp;		/* # */
132 #if FZERO
133 	bool ansi_fzero;	/* 0 for ansi-dictated formats */
134 	bool compat_fzero;	/* 0 for backward compatibility */
135 #endif
136 	bool Lsize;             /* Capital L for size = long double = quadruple */
137 
138 	/* Pointer to sign, "0x", "0X", or empty */
139 	char *prefix;
140 
141 	/* Scratch */
142 	int nblank;
143 
144 #if FLOAT
145 	/* Exponent or empty */
146 	char *suffix;
147 
148 	/* Buffer to create exponent */
149 	char expbuf[7];  /* "e+xxxx\0" */
150 
151 	/* Number of padding zeroes required on the right */
152 	int rzero;
153 
154 	/* Length of exponent suffix. */
155 	int suffixlength;
156 
157 	/* The value being converted, if real or quadruple */
158 	double dval;
159 	quadruple qval;
160 
161 	/* Output values from fconvert and econvert */
162 	int decpt, sign;
163 
164 	/* Values are developed in this buffer */
165 	char buf[1034];		/* Size of convertbuffer, plus some for exponent and sign. */
166 
167 	/* Current locale's decimal point */
168 	char decpt_char = *(localeconv()->decimal_point);
169 
170 #else
171 	/* Values are developed in this buffer */
172 	char buf[MAXDIGS];
173 #endif
174 
175 
176 	/* The value being converted, if integer */
177 	unsigned long val;
178 
179 	/* Work variables */
180 	int n;
181 	char c;
182 	char radix;
183 	int svswitch = 0;
184 	/* count of output characters */
185 	int count;
186 
187 	/* variables for positional parameters */
188 	char    *sformat = format;      /* save the beginning of the format */
189 	int     fpos = 1;               /* 1 if first positional parameter */
190 	stva_list       args,   /* used to step through the argument list */
191 			args_width, 	/* for width */
192 			args_prec, 	/* for prec */
193 			sargs;  /* used to save the start of the argument list */
194 	stva_list       arglst[MAXARGS];/* array giving the approriate values
195 					 * for va_arg() to retrieve the
196 				  	 * corresponding argument:
197 					 * arglst[0] is the first argument
198 				         * arglst[1] is the second argument, etc.
199 				         */
200 											      int index = 0;			/* argument placeolder */
201 											     /* Initialize args and sargs to the start of the argument list.
202         * Note that ANSI guarantees that the address of the first member of
203         * a structure will be the same as the address of the structure. */
204 											       args_width = args_prec = args = sargs = *(struct stva_list *)&in_args;
205 
206 
207 /*  initialize p an bp (starting and ending points)  bugid 1141781 */
208 
209 	p = bp = NULL;
210 
211 	cp = format;
212 	if ((c = *cp++) != '\0') {
213 		/*
214 		 * We know we're going to write something; make sure
215 		 * we can write and set up buffers, etc..
216 		 */
217 		if (_WRTCHK(file))
218 			return(EOF);
219 	} else
220 		return(0);	/* no fault, no error */
221 
222 	count = 0;
223 	fileptr = file->_ptr;
224 	filecnt = file->_cnt;
225 
226 	/*
227 	 *	The main loop -- this loop goes through one iteration
228 	 *	for each ordinary character or format specification.
229 	 */
230 	do {
231 		if (c != '%') {
232 			/* Ordinary (non-%) character */
233 			emitchar(c);
234 		} else {
235 			/*
236 			 *	% has been spotted!
237 			 *
238 			 *	First, try the 99% cases.
239 			 *	then parse the format specification.
240 			 *
241 			 *	Note that this code assumes the Sun
242 			 *	Workstation environment (all params
243 			 *	passed as int == long, no interrupts
244 			 *	for fixed point overflow from negating
245 			 *	the most negative number).
246 			 */
247 		skipit:
248 			switch(c = *cp++) {
249 
250 			case 'l':
251 			case 'h':
252 				/* Quickly ignore long & short specifiers */
253 				goto skipit;
254 
255 			case 's':
256 				bp = va_arg(args.ap, char *);
257 				if (bp == NULL)
258 					bp = nullstr;
259 				while (c = *bp++)
260 					emitchar(c);
261 				p = bp;
262 				continue;
263 
264 			case 'c':
265 				c = va_arg(args.ap, int);
266 			emitc:
267 				emitchar(c);
268 				continue;
269 
270 			case 'i':
271 			case 'd':
272 			case 'D':
273 				val = va_arg(args.ap, int);
274 				if ((long) val < 0) {
275 					emitchar('-');
276 					val = -val;
277 				}
278 				goto udcommon;
279 
280 			case 'U':
281 			case 'u':
282 				val = va_arg(args.ap, unsigned);
283 			udcommon:
284                                 {
285                                 char *stringp = lowerhex;
286                                 bp = buf+MAXDIGS;
287                                 stringp = lowerhex;
288                                 do {
289                                         *--bp = stringp[val%10];
290                                         val /= 10;
291                                 } while (val);
292 				}
293                                 goto intout;
294 
295 			case 'X':
296 				{
297 				char *stringp = upperhex;
298 				val = va_arg(args.ap, unsigned);
299 				bp = buf + MAXDIGS;
300 				if (val == 0)
301 					goto zero;
302 				while (val) {
303 					*--bp = stringp[val%16];
304 					val /= 16;
305 				}
306 				}
307 				goto intout;
308 
309 			case 'x':
310 			case 'p':
311 				{
312 				char *stringp = lowerhex;
313 				val = va_arg(args.ap, unsigned);
314 				bp = buf + MAXDIGS;
315 				if (val == 0)
316 					goto zero;
317 				while (val) {
318 					*--bp = stringp[val%16];
319 					val /= 16;
320 				}
321 				}
322 				goto intout;
323 
324 			case 'O':
325 			case 'o':
326 				{
327 				char *stringp = lowerhex;
328 				val = va_arg(args.ap, unsigned);
329 				bp = buf + MAXDIGS;
330 				if (val == 0)
331 					goto zero;
332 				while (val) {
333 					*--bp = stringp[val%8];
334 					val /= 8;
335 				}
336 				}
337 				/* Common code to output integers */
338 			intout:
339 				p = buf + MAXDIGS;
340 				while (bp < p) {
341 					c = *bp++;
342 					emitchar(c);
343 				}
344 				continue;
345 
346 			zero:
347 				c = '0';
348 				goto emitc;
349 
350 			default:
351 				/*
352 				 * let AT&T deal with it
353 				 */
354 				cp-= 2;
355 			}
356 
357 			Lsize = 0;      /* Not long double unless we say so. */
358                         /* Scan the <flags> */
359 			fplus = 0;
360 			fminus = 0;
361 			fblank = 0;
362 			fsharp = 0;
363 #if FZERO
364 			ansi_fzero = 0;
365 			compat_fzero = 0;
366 #endif
367 		scan:	switch (*++cp) {
368 			case '+':
369 				fplus = 1;
370 				goto scan;
371 			case '-':
372 				fminus = 1;
373 				goto scan;
374 			case ' ':
375 				fblank = 1;
376 				goto scan;
377 			case '#':
378 				fsharp = 1;
379 				goto scan;
380 #if FZERO
381 			case '0':
382 				ansi_fzero = 1;
383 				compat_fzero = 1;
384 				goto scan;
385 #endif
386 			}
387 
388 			/* Scan the field width */
389 			if (*cp == '*') {
390 				char *p;
391 				int val;
392 
393 				p = _check_dol(cp+1, &val);
394 				if (p != (char *)NULL) {
395 					/*
396 					 * argument re-order
397 					 */
398 					if (fpos) {
399 						_mkarglst(sformat, sargs, arglst);
400 						fpos = 0;
401 					}
402 					if (val <= MAXARGS) {
403 						args_width = arglst[val - 1];
404 					} else {
405 						args_width = arglst[MAXARGS - 1];
406 						_getarg(sformat, &args_width, val);
407 					}
408 					width = va_arg(args_width.ap, int);
409 					if (width < 0) {
410 						width = -width;
411 						fminus = 1;
412 					}
413 					cp = p;
414 				}
415 				else {
416 					width = va_arg(args.ap, int);
417 					if (width < 0) {
418 						width = -width;
419 						fminus = 1;
420 					}
421 					cp++;
422 				}
423 			} else {
424 				index = width = 0;
425 				while (isdigit(*cp)) {
426 					n = tonumber(*cp++);
427 					index = width = width * 10 + n;
428 				}
429 			}
430 
431 			/* Scan the precision */
432 			if (*cp == '.') {
433 
434 				/* '*' instead of digits? */
435 				if (*++cp == '*') {
436 					char *p;
437 					int val;
438 
439 					p = _check_dol(cp+1, &val);
440 					if (p != (char *)NULL) {
441 						/*
442 						 * argument re-order
443 						 */
444 						if (fpos) {
445 							_mkarglst(sformat, sargs, arglst);
446 							fpos = 0;
447 						}
448 						if (val <= MAXARGS) {
449 							args_prec = arglst[val - 1];
450 						} else {
451 							args_prec = arglst[MAXARGS - 1];
452 							_getarg(sformat, &args_prec, val);
453 						}
454 						prec = va_arg(args_prec.ap, int);
455 						cp = p;
456 					}
457 					else {
458 						prec = va_arg(args.ap, int);
459 						cp++;
460 					}
461 				} else {
462 					prec = 0;
463 					while (isdigit(*cp)) {
464 						n = tonumber(*cp++);
465 						prec = prec * 10 + n;
466 					}
467 				}
468 			} else
469 				prec = -1;
470 
471 			if (*cp == '$') {
472 				if (fpos) {
473 					_mkarglst(sformat, sargs, arglst);
474 					fpos = 0;
475 				}
476 				if (index <= MAXARGS) {
477 					args = arglst[index - 1];
478 				} else {
479 					args = arglst[MAXARGS - 1];
480 					_getarg(sformat, &args, index);
481 				}
482 				goto scan;
483 			}
484 			/*
485 			 *	The character addressed by cp must be the
486 			 *	format letter -- there is nothing left for
487 			 *	it to be.
488 			 *
489 			 *	The status of the +, -, #, blank, and 0
490 			 *	flags are reflected in the variables
491 			 *	"fplus", "fminus", "fsharp", "fblank",
492 			 *	and "ansi_fzero"/"compat_fzero", respectively.
493 			 *	"width" and "prec" contain numbers
494 			 *	corresponding to the digit strings
495 			 *	before and after the decimal point,
496 			 *	respectively. If there was no decimal
497 			 *	point, "prec" is -1.
498 			 *
499 			 *	The following switch sets things up
500 			 *	for printing.  What ultimately gets
501 			 *	printed will be padding blanks, a prefix,
502 			 *	left padding zeroes, a value, right padding
503 			 *	zeroes, a suffix, and more padding
504 			 *	blanks.  Padding blanks will not appear
505 			 *	simultaneously on both the left and the
506 			 *	right.  Each case in this switch will
507 			 *	compute the value, and leave in several
508 			 *	variables the information necessary to
509 			 *	construct what is to be printed.
510 			 *
511 			 *	The prefix is a sign, a blank, "0x", "0X",
512 			 *	or null, and is addressed by "prefix".
513 			 *
514 			 *	The suffix is either null or an exponent,
515 			 *	and is addressed by "suffix".
516 			 *
517 			 *	The value to be printed starts at "bp"
518 			 *	and continues up to and not including "p".
519 			 *
520 			 *	"lzero" and "rzero" will contain the number
521 			 *	of padding zeroes required on the left
522 			 *	and right, respectively.  If either of
523 			 *	these variables is negative, it will be
524 			 *	treated as if it were zero.
525 			 *
526 			 *	The number of padding blanks, and whether
527 			 *	they go on the left or the right, will be
528 			 *	computed on exit from the switch.
529 			 */
530 
531 			lzero = 0;
532 			prefix = "";
533 #if FLOAT
534 			rzero = 0;
535 			suffix = prefix;
536 #endif
537 
538 #if FZERO
539 		  	/* if both zero-padding and left-justify flags
540 			 * are used, ignore zero-padding, per ansi c
541 			 */
542 		  	if (ansi_fzero & fminus) {
543 				ansi_fzero = 0;
544 				compat_fzero = 0;
545 			}
546 
547 		  	/* if zero-padding and precision are specified,
548 			 * ignore zero-padding for ansi-dictated formats,
549 			 * per ansi c
550 			 */
551 		  	if (ansi_fzero & (prec != -1)) ansi_fzero = 0;
552 #endif
553 
554 		next:
555 			switch (fcode = *cp++) {
556 
557 			/* toss the length modifier, if any */
558 			case 'l':
559 			case 'h':
560 				goto next;
561 
562                        	case 'L':
563                       		Lsize = 1;      /* Remember long double size. */
564                          	goto next;
565 
566 			/*
567 			 *	fixed point representations
568 			 *
569 			 *	"radix" is the radix for the conversion.
570 			 *	Conversion is unsigned unless fcode is 'd'.
571 			 *	We assume a 2's complement machine and
572 			 *	that fixed point overflow (from negating
573 			 *	the largest negative int) is ignored.
574 			 */
575 
576 			case 'i':
577 			case 'D':
578 			case 'U':
579 			case 'd':
580 			case 'u':
581 				radix = 10;
582 				goto fixed;
583 
584 			case 'O':
585 			case 'o':
586 				radix = 8;
587 				goto fixed;
588 
589 			case 'X':
590 			case 'x':
591 				radix = 16;
592 
593 			fixed:
594 				/* Establish default precision */
595 				if (prec < 0)
596 					prec = 1;
597 
598 				/* Fetch the argument to be printed */
599 				val = va_arg(args.ap, unsigned);
600 
601 				/* If signed conversion, establish sign */
602 				if (fcode == 'd' || fcode == 'D' || fcode == 'i') {
603 					if ((long) val < 0) {
604 						prefix = "-";
605 						val = -val;
606 					} else if (fplus)
607 						prefix = "+";
608 					else if (fblank)
609 						prefix = " ";
610 				}
611 				/* Set translate table for digits */
612 				{
613 				char *stringp;
614 				if (fcode == 'X')
615 					stringp = upperhex;
616 				else
617 					stringp = lowerhex;
618 
619 				/* Develop the digits of the value */
620 				bp = buf + MAXDIGS;
621 				switch(radix) {
622 				case 8:	/*octal*/
623 					while (val) {
624 						*--bp = stringp[val%8];
625 						val /= 8;
626 					}
627 					break;
628 				case 16:/*hex*/
629 					while (val) {
630 						*--bp = stringp[val%16];
631 						val /= 16;
632 					}
633 					break;
634 				default:
635 					while (val) {
636 						*--bp = stringp[val%10];
637 						val /= 10;
638 					}
639 					break;
640 				} /* switch */
641 				}
642 
643 				/* Calculate padding zero requirement */
644 				p = buf + MAXDIGS;
645 
646 				/* Handle the # flag */
647 				if (fsharp && bp != p) {
648 					switch (fcode) {
649 					case 'x':
650 						prefix = "0x";
651 						break;
652 					case 'X':
653 						prefix = "0X";
654 						break;
655 					}
656 				}
657 #if FZERO
658 				if (ansi_fzero) {
659 					n = width - strlen(prefix);
660 					if (n > prec)
661 						prec = n;
662 				}
663 #endif
664 				lzero = bp - p + prec;
665 
666 				/* Handle the # flag for 'o' */
667 				if (fsharp && bp != p && fcode == 'o' &&
668 				    lzero < 1) {
669 					lzero = 1;
670 				}
671 				break;
672 #if FLOAT
673 
674 #if	defined(__sparc)
675 #define GETQVAL /* Sun-4 macro to get a quad q from the argument list, passed as a pointer. */ \
676       { qval = *(va_arg(args.ap, quadruple*)) ; }
677 #else
678 #define GETQVAL /* Sun-3 macro to get a quad q from the argument list, passed as a value. */ \
679       { int iq ; unsigned long * pl = (unsigned long *) (&qval) ; for(iq=0;iq<4;iq++) pl[iq] = (unsigned long) va_arg(args.ap, unsigned long) ; }
680 #endif
681 
682 			case 'E':
683 			case 'e':
684 				/*
685 				 *	E-format.  The general strategy
686 				 *	here is fairly easy: we take
687 				 *	what econvert gives us and re-format it.
688 				 */
689 
690 				/* Establish default precision */
691 				if (prec < 0)
692 					prec = 6;
693 
694 				/* Fetch the value */
695                                if (Lsize == 0) { /* Double */
696                                 dval = va_arg(args.ap, double);
697                                 bp = econvert(dval, prec + 1, &decpt, &sign, convertbuffer);
698                                } else { /* Long Double = quadruple */
699                                GETQVAL;
700                                bp = qeconvert(&qval, prec + 1, &decpt, &sign, convertbuffer);
701                                }
702 
703 				/* Determine the prefix */
704 				if (sign)
705 					prefix = "-";
706 				else if (fplus)
707 					prefix = "+";
708 				else if (fblank)
709 					prefix = " ";
710 				if (convertbuffer[0] > '9')
711 					{ /* handle infinity, nan */
712 					bp = &convertbuffer[0];
713 					for (p = bp+1 ; *p != 0 ; p++) ;
714 					goto ebreak ;
715 					}
716 				{
717 				char *stringp;
718 				/* Place the first digit in the buffer */
719 				stringp = &buf[0];
720 				*stringp++ = *bp != '\0'? *bp++: '0';
721 
722 				/* Put in a decimal point if needed */
723 				if (prec != 0 || fsharp)
724 					*stringp++ = decpt_char;
725 
726 				/* Create the rest of the mantissa */
727 				rzero = prec;
728 				while (rzero > 0 && *bp!= '\0') {
729 					--rzero;
730 					*stringp++ = *bp++;
731 				}
732 				p = stringp;
733 				}
734 
735 				bp = &buf[0];
736 
737 				/* Create the exponent */
738 				if (convertbuffer[0] != '0')
739 					n = decpt - 1;
740 				else
741 					n = 0 ;
742 				if (n < 0)
743 					n = -n;
744 				_fourdigitsquick( (short unsigned) n, &(expbuf[2]) ) ;
745 				expbuf[6] = 0 ;
746 				if (n < 100)
747 					/*
748                                          * Normally two digit exponent field,
749                                          * three or four if required.
750 					 */
751 					{ suffix = &(expbuf[4]) ; suffixlength = 4 ; }
752                                 else if (n < 1000)
753                                         { suffix = &(expbuf[3]) ; suffixlength = 5 ; }
754                                 else
755                                         { suffix = &(expbuf[2]) ; suffixlength = 6 ; }
756 				/* Put in the exponent sign */
757 				*--suffix = (decpt > 0 || convertbuffer[0] == '0' )? '+': '-';
758 
759 				/* Put in the e; note kludge in 'g' format */
760 				*--suffix = fcode;
761 ebreak:
762 #if FZERO
763 				if (compat_fzero &! fminus)
764 					/* Calculate padding zero requirement */
765 					lzero = width - (strlen(prefix)
766 					    + (p - buf) + rzero + suffixlength);
767 #endif
768 				break;
769 
770 			case 'f':
771 				/*
772 				 *	F-format floating point.  This is
773 				 *	a good deal less simple than E-format.
774 				 *	The overall strategy will be to call
775 				 *	fconvert, reformat its result into buf,
776 				 *	and calculate how many trailing
777 				 *	zeroes will be required.  There will
778 				 *	never be any leading zeroes needed.
779 				 */
780 
781 				/* Establish default precision */
782 				if (prec < 0)
783 					prec = 6;
784 
785                                 if (Lsize == 0) {
786                                 dval = va_arg(args.ap, double);
787                                 bp = fconvert(dval, prec, &decpt, &sign, convertbuffer);
788                                 } else {
789                                 GETQVAL ;
790                                 bp = qfconvert(&qval, prec, &decpt, &sign, convertbuffer);
791                                 }
792 
793 				/* Determine the prefix */
794 				if (sign)
795 					prefix = "-";
796 				else if (fplus)
797 					prefix = "+";
798 				else if (fblank)
799 					prefix = " ";
800 				if (convertbuffer[0] > '9')
801 					{ /* handle infinity, nan */
802 					bp = &convertbuffer[0];
803 					for (p = bp+1 ; *p != 0 ; p++) ;
804 					goto fbreak ;
805 					}
806 				{
807 				char *stringp;
808 				/* Initialize buffer pointer */
809 				stringp = &buf[0];
810 
811 				/* Emit the digits before the decimal point */
812 				n = decpt;
813 				if (n <= 0)
814 					*stringp++ = '0';
815 				else
816 					do
817 						if (*bp == '\0' )
818 							*stringp++ = '0';
819 						else {
820 							*stringp++ = *bp++;
821 						}
822 					while (--n != 0);
823 
824 				/* Decide whether we need a decimal point */
825 				if (fsharp || prec > 0)
826 					*stringp++ = decpt_char;
827 
828 				/* Digits(if any) after the decimal point */
829 				n = prec;
830 				rzero = prec - n;
831 				while (--n >= 0) {
832 					if (++decpt <= 0 || *bp == '\0')
833 						*stringp++ = '0';
834 					else {
835 						*stringp++ = *bp++;
836 					}
837 				}
838 #if FZERO
839 				if (compat_fzero &! fminus)
840 					/* Calculate padding zero requirement */
841 					lzero = width - (strlen(prefix)
842 					    + (stringp - buf) + rzero);
843 #endif
844 				p = stringp;
845 				}
846 
847 				bp = &buf[0];
848 fbreak:
849 				break;
850 
851 			case 'G':
852 			case 'g':
853 				/*
854 				 *	g-format.  We play around a bit
855 				 *	and then jump into e or f, as needed.
856 				 */
857 
858 				/* Establish default precision */
859 				if (prec < 0)
860 					prec = 6;
861 				else if (prec == 0)
862 					prec = 1;
863 
864                                 if (Lsize == 0) {
865                                 dval = va_arg(args.ap, double);
866                                 bp = gconvert(dval, prec, fsharp, convertbuffer);
867                                 } else {
868                                 GETQVAL;
869                                 bp = qgconvert(&qval, prec, fsharp, convertbuffer);
870                                 }
871 				bp = convertbuffer ;
872 				if (convertbuffer[0] == '-') {
873 					prefix = "-" ;
874 					bp++;
875 					}
876 				else if (fplus)
877 					prefix = "+";
878 				else if (fblank)
879 					prefix = " ";
880 				if (isupper(fcode))
881 				        { /* Put in a big E for small minds. */
882 				        for (p = bp ; (*p != NULL) && (*p != 'e') ; p++) ;
883 				        if (*p == 'e') *p = 'E' ;
884 				        for (; (*p != NULL) ; p++) ;
885 				                                /* Find end of string. */
886 			                }
887 				else
888 				        for (p = bp ; *p != NULL ; p++) ;
889 				                                /* Find end of string. */
890 				rzero = 0;
891 #if FZERO
892 				if (compat_fzero & !fminus)
893 					/* Calculate padding zero requirement */
894 					lzero = width - (strlen(prefix)
895 					    + (p - bp) + rzero);
896 #endif
897 				break ;
898 
899 #endif
900 			case 'c':
901 				buf[0] = va_arg(args.ap, int);
902 				bp = &buf[0];
903 				p = bp + 1;
904 				break;
905 
906                         case 's':
907 				bp = va_arg(args.ap, char *);
908 				if (prec < 0)
909 					prec = MAXINT;
910 				/* avoid *(0) */
911 				if (bp == NULL)
912 					bp = nullstr;
913 				for (n=0; *bp++ != '\0' && n < prec; n++)
914 					;
915 #if FZERO
916 				if (compat_fzero &! fminus)
917 				        lzero = width - n;
918 #endif
919 				p = --bp;
920 				bp -= n;
921 				break;
922 
923 			case '\0':
924 				/* well, what's the punch line? */
925 				goto out;
926 
927 			case 'n':
928 				svswitch = 1;
929 				break;
930 			default:
931 				p = bp = &fcode;
932 				p++;
933 				break;
934 
935 			}
936 			/* Calculate number of padding blanks */
937 			nblank = width
938 #if FLOAT
939 				- (rzero < 0? 0: rzero)
940 				- strlen(suffix)
941 #endif
942 				- (p - bp)
943 				- (lzero < 0? 0: lzero)
944 				- strlen(prefix);
945 
946 			/* Blanks on left if required */
947 			if (!fminus)
948 				while (--nblank >= 0)
949 					emitchar(' ');
950 
951 			/* Prefix, if any */
952 			while (*prefix != '\0') {
953 				emitchar(*prefix);
954 				prefix++;
955 			}
956 
957 			/* Zeroes on the left */
958 			while (--lzero >= 0)
959 				emitchar('0');
960 
961 			/* The value itself */
962 			while (bp < p) {
963 				emitchar(*bp);
964 				bp++;
965 			}
966 #if FLOAT
967 			/* Zeroes on the right */
968 			while (--rzero >= 0)
969 				emitchar('0');
970 
971 			/* The suffix */
972 			while (*suffix != '\0') {
973 				emitchar(*suffix);
974 				suffix++;
975 			}
976 #endif
977 			/* Blanks on the right if required */
978 			if (fminus)
979 				while (--nblank >= 0)
980 					emitchar(' ');
981 			/* If %n is seen, save count in argument */
982 			if (svswitch == 1) {
983 				long *svcount;
984 				svcount = va_arg (args.ap, long *);
985 				*svcount = count;
986 				svswitch = 0;
987 			}
988 		} /* else */
989 	} while ((c = *cp++) != '\0');	/* do */
990 out:
991 	file->_ptr = fileptr;
992 	file->_cnt = filecnt;
993 	if (file->_flag & (_IONBF | _IOLBF) &&
994 	    (file->_flag & _IONBF ||
995 	     memchr((char *)file->_base, '\n', fileptr - file->_base) != NULL))
996 		(void) _xflsbuf(file);
997 	return (ferror(file)? EOF: count);
998 }
999 
1000 #if	defined(__sparc)
1001 /*
1002  * We use "double *" instead of "quadruple *" to skip over the pointer to
1003  * long double on the argument list since a pointer is a pointer after all.
1004  */
1005 #define SKIPQVAL { \
1006 	(void) va_arg(args.ap, double *); \
1007 }
1008 #else	/* Sun-3 */
1009 #define SKIPQVAL { \
1010 	int iq; \
1011 	for (iq = 0; iq < 4; iq++) \
1012 		(void) va_arg(args.ap, unsigned long); \
1013 }
1014 #endif
1015 /*
1016  * This function initializes arglst, to contain the appropriate va_list values
1017  * for the first MAXARGS arguments.
1018  */
1019 void
1020 _mkarglst(char *fmt, stva_list args, stva_list arglst[])
1021 {
1022 	static char *digits = "01234567890", *skips = "# +-.0123456789h$";
1023 
1024 	enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR,
1025 		LONG_PTR, INT_PTR};
1026 	enum types typelst[MAXARGS], curtype;
1027 	int maxnum, n, curargno, flags;
1028 
1029 	/*
1030 	* Algorithm	1. set all argument types to zero.
1031 	*		2. walk through fmt putting arg types in typelst[].
1032 	*		3. walk through args using va_arg(args.ap, typelst[n])
1033 	*		   and set arglst[] to the appropriate values.
1034 	* Assumptions:	Cannot use %*$... to specify variable position.
1035 	*/
1036 
1037 	(void)memset((void *)typelst, 0, sizeof(typelst));
1038 	maxnum = -1;
1039 	curargno = 0;
1040 	while ((fmt = strchr(fmt, '%')) != 0)
1041 	{
1042 		fmt++;	/* skip % */
1043 		if (fmt[n = strspn(fmt, digits)] == '$')
1044 		{
1045 			curargno = atoi(fmt) - 1;	/* convert to zero base */
1046 			fmt += n + 1;
1047 		}
1048 		flags = 0;
1049 	again:;
1050 		fmt += strspn(fmt, skips);
1051 		switch (*fmt++)
1052 		{
1053 		case '%':	/*there is no argument! */
1054 			continue;
1055 		case 'l':
1056 			flags |= 0x1;
1057 			goto again;
1058 		case 'L':
1059 			flags |= 0x8;
1060 			goto again;
1061 		case '*':	/* int argument used for value */
1062 			flags |= 0x2;
1063 			curtype = INT;
1064 			break;
1065 		case 'e':
1066 		case 'E':
1067 		case 'f':
1068 		case 'g':
1069 		case 'G':
1070 			if (flags & 0x8)
1071 				curtype = LONG_DOUBLE;
1072 			else
1073 				curtype = DOUBLE;
1074 			break;
1075 		case 's':
1076 			curtype = CHAR_PTR;
1077 			break;
1078 		case 'p':
1079 			curtype = VOID_PTR;
1080 			break;
1081 		case 'n':
1082 			if (flags & 0x1)
1083 				curtype = LONG_PTR;
1084 			else
1085 				curtype = INT_PTR;
1086 			break;
1087 		default:
1088 			if (flags & 0x1)
1089 				curtype = LONG;
1090 			else
1091 				curtype = INT;
1092 			break;
1093 		}
1094 		if (curargno >= 0 && curargno < MAXARGS)
1095 		{
1096 			typelst[curargno] = curtype;
1097 			if (maxnum < curargno)
1098 				maxnum = curargno;
1099 		}
1100 		curargno++;	/* default to next in list */
1101 		if (flags & 0x2)	/* took care of *, keep going */
1102 		{
1103 			flags ^= 0x2;
1104 			goto again;
1105 		}
1106 	}
1107 	for (n = 0 ; n <= maxnum; n++)
1108 	{
1109 		arglst[n] = args;
1110 		if (typelst[n] == 0)
1111 			typelst[n] = INT;
1112 
1113 		switch (typelst[n])
1114 		{
1115 		case INT:
1116 			va_arg(args.ap, int);
1117 			break;
1118 		case LONG:
1119 			va_arg(args.ap, long);
1120 			break;
1121 		case CHAR_PTR:
1122 			va_arg(args.ap, char *);
1123 			break;
1124 		case DOUBLE:
1125 			va_arg(args.ap, double);
1126 			break;
1127 		case LONG_DOUBLE:
1128 			SKIPQVAL
1129 			break;
1130 		case VOID_PTR:
1131 			va_arg(args.ap, void *);
1132 			break;
1133 		case LONG_PTR:
1134 			va_arg(args.ap, long *);
1135 			break;
1136 		case INT_PTR:
1137 			va_arg(args.ap, int *);
1138 			break;
1139 		}
1140 	}
1141 }
1142 
1143 /*
1144  * This function is used to find the va_list value for arguments whose
1145  * position is greater than MAXARGS.  This function is slow, so hopefully
1146  * MAXARGS will be big enough so that this function need only be called in
1147  * unusual circumstances.
1148  * pargs is assumed to contain the value of arglst[MAXARGS - 1].
1149  */
1150 void
1151 _getarg(char *fmt, stva_list *pargs, int argno)
1152 {
1153 	static char *digits = "01234567890", *skips = "# +-.0123456789h$";
1154 	int i, n, curargno, flags;
1155 	char	*sfmt = fmt;
1156 	int	found = 1;
1157 
1158 	curargno = i = MAXARGS;
1159 	while (found)
1160 	{
1161 		fmt = sfmt;
1162 		found = 0;
1163 		while ((i != argno) && (fmt = strchr(fmt, '%')) != 0)
1164 		{
1165 			fmt++;	/* skip % */
1166 			if (fmt[n = strspn(fmt, digits)] == '$')
1167 			{
1168 				curargno = atoi(fmt);
1169 				fmt += n + 1;
1170 			}
1171 
1172 			/* find conversion specifier for next argument */
1173 			if (i != curargno)
1174 			{
1175 				curargno++;
1176 				continue;
1177 			} else
1178 				found = 1;
1179 			flags = 0;
1180 		again:;
1181 			fmt += strspn(fmt, skips);
1182 			switch (*fmt++)
1183 			{
1184 			case '%':	/*there is no argument! */
1185 				continue;
1186 			case 'l':
1187 				flags |= 0x1;
1188 				goto again;
1189 			case 'L':
1190 				flags |= 0x8;
1191 				goto again;
1192 			case '*':	/* int argument used for value */
1193 				flags |= 0x2;
1194 				(void)va_arg((*pargs).ap, int);
1195 				break;
1196 			case 'e':
1197 			case 'E':
1198 			case 'f':
1199 			case 'g':
1200 			case 'G':
1201 				if (flags & 0x8) {
1202 #define	args	(*pargs)
1203 					SKIPQVAL
1204 #undef	args
1205 				}
1206 				else
1207 					(void)va_arg((*pargs).ap, double);
1208 				break;
1209 			case 's':
1210 				(void)va_arg((*pargs).ap, char *);
1211 				break;
1212 			case 'p':
1213 				(void)va_arg((*pargs).ap, void *);
1214 				break;
1215 			case 'n':
1216 				if (flags & 0x1)
1217 					(void)va_arg((*pargs).ap, long *);
1218 				else
1219 					(void)va_arg((*pargs).ap, int *);
1220 				break;
1221 			default:
1222 				if (flags & 0x1)
1223 					(void)va_arg((*pargs).ap, long int);
1224 				else
1225 					(void)va_arg((*pargs).ap, int);
1226 				break;
1227 			}
1228 			i++;
1229 			curargno++;	/* default to next in list */
1230 			if (flags & 0x2)	/* took care of *, keep going */
1231 			{
1232 				flags ^= 0x2;
1233 				goto again;
1234 			}
1235 		}
1236 
1237 		/* missing specifier for parameter, assume parameter is an int */
1238 		if (!found && i != argno) {
1239 			(void)va_arg((*pargs).ap, int);
1240 			i++;
1241 			curargno++;
1242 			found = 1;
1243 		}
1244 	}
1245 }
1246 
1247 
1248 /*
1249  * parse a string, mini parse
1250  */
1251 static char *
1252 _check_dol(char *s, int *val)
1253 {
1254 	char *os;	/* save old string */
1255 	int tmp_val = 0;
1256 	int flag = 0;
1257 
1258 	while (isdigit (*s)) {
1259 		++flag;
1260 		tmp_val = tmp_val*10 + *s - '0';
1261 		s++;
1262 	}
1263 	if (flag == 0)
1264 		return ((char *)NULL);
1265 	if (*s == '$') {
1266 		*val = tmp_val;
1267 		return(++s);
1268 	}
1269 	return ((char *)NULL);
1270 }
1271