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