summaryrefslogtreecommitdiff
path: root/usr/src/lib/libbc/libc/stdio/common/doprnt.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libbc/libc/stdio/common/doprnt.c')
-rw-r--r--usr/src/lib/libbc/libc/stdio/common/doprnt.c1279
1 files changed, 1279 insertions, 0 deletions
diff --git a/usr/src/lib/libbc/libc/stdio/common/doprnt.c b/usr/src/lib/libbc/libc/stdio/common/doprnt.c
new file mode 100644
index 0000000000..cc7324534c
--- /dev/null
+++ b/usr/src/lib/libbc/libc/stdio/common/doprnt.c
@@ -0,0 +1,1279 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1988-1995, by Sun Microsystems, Inc.
+ * All rights reserved
+ */
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * _doprnt: common code for printf, fprintf, sprintf
+ * Floating-point code is included or not, depending
+ * on whether the preprocessor variable FLOAT is 1 or 0.
+ */
+#define MAXARGS 50
+#ifndef FLOAT
+#define FLOAT 1 /* YES! we want floating */
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <varargs.h>
+#include <values.h>
+#include <locale.h>
+#include "doprnt.h"
+#include "stdiom.h"
+#include <string.h> /* strchr, strlen, strspn */
+
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+/* If this symbol is nonzero, allow '0' as a flag */
+/* If this symbol is nonzero, allow '0' as a flag */
+#define FZERO 1
+
+#if FLOAT
+/*
+ * libc/gen/common functions for floating-point conversion
+ */
+#include <floatingpoint.h>
+extern void _fourdigitsquick();
+#endif
+
+void _mkarglst();
+void _getarg();
+static char *_check_dol();
+
+
+#define emitchar(c) { if (--filecnt < 0) { \
+ register FILE *iop = file; \
+ if (((iop->_flag & (_IOLBF|_IONBF)) == 0 \
+ || -filecnt >= iop->_bufsiz)) { \
+ iop->_ptr = fileptr; \
+ if (iop->_flag & _IOSTRG) \
+ return iop->_ptr - iop->_base; \
+ else \
+ (void) _xflsbuf(iop); \
+ fileptr = iop->_ptr; \
+ filecnt = iop->_cnt; \
+ filecnt--; \
+ } \
+ } \
+ *fileptr++ = (unsigned)(c); \
+ count++; \
+ }
+
+static char *nullstr = "(null)";
+static char *lowerhex = "0123456789abcdef";
+static char *upperhex = "0123456789ABCDEF";
+
+/* stva_list is used to subvert C's restriction that a variable with an
+ * array type can not appear on the left hand side of an assignment operator.
+ * By putting the array inside a structure, the functionality of assigning to
+ * the whole array through a simple assignment is achieved..
+*/
+typedef struct stva_list {
+ va_list ap;
+} stva_list;
+
+_doprnt(format, in_args, file)
+ char *format;
+ va_list in_args;
+ FILE *file;
+{
+ char convertbuffer[1024] ;
+
+ /* Current position in format */
+ register char *cp;
+
+ /* Starting and ending points for value to be printed */
+ register char *bp;
+ char *p;
+
+ /* Pointer and count for I/O buffer */
+ register unsigned char *fileptr;
+ register int filecnt;
+
+ /* Field width and precision */
+ int width;
+ register int prec;
+
+ /* Format code */
+ char fcode;
+
+ /* Number of padding zeroes required on the left */
+ int lzero;
+
+ /* Flags - nonzero if corresponding character appears in format */
+ bool fplus; /* + */
+ bool fminus; /* - */
+ bool fblank; /* blank */
+ bool fsharp; /* # */
+#if FZERO
+ bool ansi_fzero; /* 0 for ansi-dictated formats */
+ bool compat_fzero; /* 0 for backward compatibility */
+#endif
+ bool Lsize; /* Capital L for size = long double = quadruple */
+
+ /* Pointer to sign, "0x", "0X", or empty */
+ char *prefix;
+
+ /* Scratch */
+ int nblank;
+
+#if FLOAT
+ /* Exponent or empty */
+ char *suffix;
+
+ /* Buffer to create exponent */
+ char expbuf[7]; /* "e+xxxx\0" */
+
+ /* Number of padding zeroes required on the right */
+ int rzero;
+
+ /* Length of exponent suffix. */
+ int suffixlength;
+
+ /* The value being converted, if real or quadruple */
+ double dval;
+ quadruple qval;
+
+ /* Output values from fconvert and econvert */
+ int decpt, sign;
+
+ /* Values are developed in this buffer */
+ char buf[1034]; /* Size of convertbuffer, plus some for exponent and sign. */
+
+ /* Current locale's decimal point */
+ char decpt_char = *(localeconv()->decimal_point);
+
+#else
+ /* Values are developed in this buffer */
+ char buf[MAXDIGS];
+#endif
+
+
+ /* The value being converted, if integer */
+ register unsigned long val;
+
+ /* Work variables */
+ register int n;
+ register char c;
+ char radix;
+ int svswitch = 0;
+ /* count of output characters */
+ register int count;
+
+ /* variables for positional parameters */
+ char *sformat = format; /* save the beginning of the format */
+ int fpos = 1; /* 1 if first positional parameter */
+ stva_list args, /* used to step through the argument list */
+ args_width, /* for width */
+ args_prec, /* for prec */
+ sargs; /* used to save the start of the argument list */
+ stva_list arglst[MAXARGS];/* array giving the approriate values
+ * for va_arg() to retrieve the
+ * corresponding argument:
+ * arglst[0] is the first argument
+ * arglst[1] is the second argument, etc.
+ */
+ int index = 0; /* argument placeolder */
+ /* Initialize args and sargs to the start of the argument list.
+ * Note that ANSI guarantees that the address of the first member of
+ * a structure will be the same as the address of the structure. */
+ args_width = args_prec = args = sargs = *(struct stva_list *)&in_args;
+
+
+/* initialize p an bp (starting and ending points) bugid 1141781 */
+
+ p = bp = NULL;
+
+ cp = format;
+ if ((c = *cp++) != '\0') {
+ /*
+ * We know we're going to write something; make sure
+ * we can write and set up buffers, etc..
+ */
+ if (_WRTCHK(file))
+ return(EOF);
+ } else
+ return(0); /* no fault, no error */
+
+ count = 0;
+ fileptr = file->_ptr;
+ filecnt = file->_cnt;
+
+ /*
+ * The main loop -- this loop goes through one iteration
+ * for each ordinary character or format specification.
+ */
+ do {
+ if (c != '%') {
+ /* Ordinary (non-%) character */
+ emitchar(c);
+ } else {
+ /*
+ * % has been spotted!
+ *
+ * First, try the 99% cases.
+ * then parse the format specification.
+ *
+ * Note that this code assumes the Sun
+ * Workstation environment (all params
+ * passed as int == long, no interrupts
+ * for fixed point overflow from negating
+ * the most negative number).
+ */
+ skipit:
+ switch(c = *cp++) {
+
+ case 'l':
+ case 'h':
+ /* Quickly ignore long & short specifiers */
+ goto skipit;
+
+ case 's':
+ bp = va_arg(args.ap, char *);
+ if (bp == NULL)
+ bp = nullstr;
+ while (c = *bp++)
+ emitchar(c);
+ p = bp;
+ continue;
+
+ case 'c':
+ c = va_arg(args.ap, int);
+ emitc:
+ emitchar(c);
+ continue;
+
+ case 'i':
+ case 'd':
+ case 'D':
+ val = va_arg(args.ap, int);
+ if ((long) val < 0) {
+ emitchar('-');
+ val = -val;
+ }
+ goto udcommon;
+
+ case 'U':
+ case 'u':
+ val = va_arg(args.ap, unsigned);
+ udcommon:
+ {
+ register char *stringp = lowerhex;
+ bp = buf+MAXDIGS;
+ stringp = lowerhex;
+ do {
+ *--bp = stringp[val%10];
+ val /= 10;
+ } while (val);
+ }
+ goto intout;
+
+ case 'X':
+ {
+ register char *stringp = upperhex;
+ val = va_arg(args.ap, unsigned);
+ bp = buf + MAXDIGS;
+ if (val == 0)
+ goto zero;
+ while (val) {
+ *--bp = stringp[val%16];
+ val /= 16;
+ }
+ }
+ goto intout;
+
+ case 'x':
+ case 'p':
+ {
+ register char *stringp = lowerhex;
+ val = va_arg(args.ap, unsigned);
+ bp = buf + MAXDIGS;
+ if (val == 0)
+ goto zero;
+ while (val) {
+ *--bp = stringp[val%16];
+ val /= 16;
+ }
+ }
+ goto intout;
+
+ case 'O':
+ case 'o':
+ {
+ register char *stringp = lowerhex;
+ val = va_arg(args.ap, unsigned);
+ bp = buf + MAXDIGS;
+ if (val == 0)
+ goto zero;
+ while (val) {
+ *--bp = stringp[val%8];
+ val /= 8;
+ }
+ }
+ /* Common code to output integers */
+ intout:
+ p = buf + MAXDIGS;
+ while (bp < p) {
+ c = *bp++;
+ emitchar(c);
+ }
+ continue;
+
+ zero:
+ c = '0';
+ goto emitc;
+
+ default:
+ /*
+ * let AT&T deal with it
+ */
+ cp-= 2;
+ }
+
+ Lsize = 0; /* Not long double unless we say so. */
+ /* Scan the <flags> */
+ fplus = 0;
+ fminus = 0;
+ fblank = 0;
+ fsharp = 0;
+#if FZERO
+ ansi_fzero = 0;
+ compat_fzero = 0;
+#endif
+ scan: switch (*++cp) {
+ case '+':
+ fplus = 1;
+ goto scan;
+ case '-':
+ fminus = 1;
+ goto scan;
+ case ' ':
+ fblank = 1;
+ goto scan;
+ case '#':
+ fsharp = 1;
+ goto scan;
+#if FZERO
+ case '0':
+ ansi_fzero = 1;
+ compat_fzero = 1;
+ goto scan;
+#endif
+ }
+
+ /* Scan the field width */
+ if (*cp == '*') {
+ char *p;
+ int val;
+
+ p = _check_dol(cp+1, &val);
+ if (p != (char *)NULL) {
+ /*
+ * argument re-order
+ */
+ if (fpos) {
+ _mkarglst(sformat, sargs, arglst);
+ fpos = 0;
+ }
+ if (val <= MAXARGS) {
+ args_width = arglst[val - 1];
+ } else {
+ args_width = arglst[MAXARGS - 1];
+ _getarg(sformat, &args_width, val);
+ }
+ width = va_arg(args_width.ap, int);
+ if (width < 0) {
+ width = -width;
+ fminus = 1;
+ }
+ cp = p;
+ }
+ else {
+ width = va_arg(args.ap, int);
+ if (width < 0) {
+ width = -width;
+ fminus = 1;
+ }
+ cp++;
+ }
+ } else {
+ index = width = 0;
+ while (isdigit(*cp)) {
+ n = tonumber(*cp++);
+ index = width = width * 10 + n;
+ }
+ }
+
+ /* Scan the precision */
+ if (*cp == '.') {
+
+ /* '*' instead of digits? */
+ if (*++cp == '*') {
+ char *p;
+ int val;
+
+ p = _check_dol(cp+1, &val);
+ if (p != (char *)NULL) {
+ /*
+ * argument re-order
+ */
+ if (fpos) {
+ _mkarglst(sformat, sargs, arglst);
+ fpos = 0;
+ }
+ if (val <= MAXARGS) {
+ args_prec = arglst[val - 1];
+ } else {
+ args_prec = arglst[MAXARGS - 1];
+ _getarg(sformat, &args_prec, val);
+ }
+ prec = va_arg(args_prec.ap, int);
+ cp = p;
+ }
+ else {
+ prec = va_arg(args.ap, int);
+ cp++;
+ }
+ } else {
+ prec = 0;
+ while (isdigit(*cp)) {
+ n = tonumber(*cp++);
+ prec = prec * 10 + n;
+ }
+ }
+ } else
+ prec = -1;
+
+ if (*cp == '$') {
+ if (fpos) {
+ _mkarglst(sformat, sargs, arglst);
+ fpos = 0;
+ }
+ if (index <= MAXARGS) {
+ args = arglst[index - 1];
+ } else {
+ args = arglst[MAXARGS - 1];
+ _getarg(sformat, &args, index);
+ }
+ goto scan;
+ }
+ /*
+ * The character addressed by cp must be the
+ * format letter -- there is nothing left for
+ * it to be.
+ *
+ * The status of the +, -, #, blank, and 0
+ * flags are reflected in the variables
+ * "fplus", "fminus", "fsharp", "fblank",
+ * and "ansi_fzero"/"compat_fzero", respectively.
+ * "width" and "prec" contain numbers
+ * corresponding to the digit strings
+ * before and after the decimal point,
+ * respectively. If there was no decimal
+ * point, "prec" is -1.
+ *
+ * The following switch sets things up
+ * for printing. What ultimately gets
+ * printed will be padding blanks, a prefix,
+ * left padding zeroes, a value, right padding
+ * zeroes, a suffix, and more padding
+ * blanks. Padding blanks will not appear
+ * simultaneously on both the left and the
+ * right. Each case in this switch will
+ * compute the value, and leave in several
+ * variables the information necessary to
+ * construct what is to be printed.
+ *
+ * The prefix is a sign, a blank, "0x", "0X",
+ * or null, and is addressed by "prefix".
+ *
+ * The suffix is either null or an exponent,
+ * and is addressed by "suffix".
+ *
+ * The value to be printed starts at "bp"
+ * and continues up to and not including "p".
+ *
+ * "lzero" and "rzero" will contain the number
+ * of padding zeroes required on the left
+ * and right, respectively. If either of
+ * these variables is negative, it will be
+ * treated as if it were zero.
+ *
+ * The number of padding blanks, and whether
+ * they go on the left or the right, will be
+ * computed on exit from the switch.
+ */
+
+ lzero = 0;
+ prefix = "";
+#if FLOAT
+ rzero = 0;
+ suffix = prefix;
+#endif
+
+#if FZERO
+ /* if both zero-padding and left-justify flags
+ * are used, ignore zero-padding, per ansi c
+ */
+ if (ansi_fzero & fminus) {
+ ansi_fzero = 0;
+ compat_fzero = 0;
+ }
+
+ /* if zero-padding and precision are specified,
+ * ignore zero-padding for ansi-dictated formats,
+ * per ansi c
+ */
+ if (ansi_fzero & (prec != -1)) ansi_fzero = 0;
+#endif
+
+ next:
+ switch (fcode = *cp++) {
+
+ /* toss the length modifier, if any */
+ case 'l':
+ case 'h':
+ goto next;
+
+ case 'L':
+ Lsize = 1; /* Remember long double size. */
+ goto next;
+
+ /*
+ * fixed point representations
+ *
+ * "radix" is the radix for the conversion.
+ * Conversion is unsigned unless fcode is 'd'.
+ * We assume a 2's complement machine and
+ * that fixed point overflow (from negating
+ * the largest negative int) is ignored.
+ */
+
+ case 'i':
+ case 'D':
+ case 'U':
+ case 'd':
+ case 'u':
+ radix = 10;
+ goto fixed;
+
+ case 'O':
+ case 'o':
+ radix = 8;
+ goto fixed;
+
+ case 'X':
+ case 'x':
+ radix = 16;
+
+ fixed:
+ /* Establish default precision */
+ if (prec < 0)
+ prec = 1;
+
+ /* Fetch the argument to be printed */
+ val = va_arg(args.ap, unsigned);
+
+ /* If signed conversion, establish sign */
+ if (fcode == 'd' || fcode == 'D' || fcode == 'i') {
+ if ((long) val < 0) {
+ prefix = "-";
+ val = -val;
+ } else if (fplus)
+ prefix = "+";
+ else if (fblank)
+ prefix = " ";
+ }
+ /* Set translate table for digits */
+ {
+ register char *stringp;
+ if (fcode == 'X')
+ stringp = upperhex;
+ else
+ stringp = lowerhex;
+
+ /* Develop the digits of the value */
+ bp = buf + MAXDIGS;
+ switch(radix) {
+ case 8: /*octal*/
+ while (val) {
+ *--bp = stringp[val%8];
+ val /= 8;
+ }
+ break;
+ case 16:/*hex*/
+ while (val) {
+ *--bp = stringp[val%16];
+ val /= 16;
+ }
+ break;
+ default:
+ while (val) {
+ *--bp = stringp[val%10];
+ val /= 10;
+ }
+ break;
+ } /* switch */
+ }
+
+ /* Calculate padding zero requirement */
+ p = buf + MAXDIGS;
+
+ /* Handle the # flag */
+ if (fsharp && bp != p) {
+ switch (fcode) {
+ case 'x':
+ prefix = "0x";
+ break;
+ case 'X':
+ prefix = "0X";
+ break;
+ }
+ }
+#if FZERO
+ if (ansi_fzero) {
+ n = width - strlen(prefix);
+ if (n > prec)
+ prec = n;
+ }
+#endif
+ lzero = bp - p + prec;
+
+ /* Handle the # flag for 'o' */
+ if (fsharp && bp != p && fcode == 'o' &&
+ lzero < 1) {
+ lzero = 1;
+ }
+ break;
+#if FLOAT
+
+#ifdef sparc
+#define GETQVAL /* Sun-4 macro to get a quad q from the argument list, passed as a pointer. */ \
+ { qval = *(va_arg(args.ap, quadruple*)) ; }
+#else
+#define GETQVAL /* Sun-3 macro to get a quad q from the argument list, passed as a value. */ \
+ { int iq ; unsigned long * pl = (unsigned long *) (&qval) ; for(iq=0;iq<4;iq++) pl[iq] = (unsigned long) va_arg(args.ap, unsigned long) ; }
+#endif
+
+ case 'E':
+ case 'e':
+ /*
+ * E-format. The general strategy
+ * here is fairly easy: we take
+ * what econvert gives us and re-format it.
+ */
+
+ /* Establish default precision */
+ if (prec < 0)
+ prec = 6;
+
+ /* Fetch the value */
+ if (Lsize == 0) { /* Double */
+ dval = va_arg(args.ap, double);
+ bp = econvert(dval, prec + 1, &decpt, &sign, convertbuffer);
+ } else { /* Long Double = quadruple */
+ GETQVAL;
+ bp = qeconvert(&qval, prec + 1, &decpt, &sign, convertbuffer);
+ }
+
+ /* Determine the prefix */
+ if (sign)
+ prefix = "-";
+ else if (fplus)
+ prefix = "+";
+ else if (fblank)
+ prefix = " ";
+ if (convertbuffer[0] > '9')
+ { /* handle infinity, nan */
+ bp = &convertbuffer[0];
+ for (p = bp+1 ; *p != 0 ; p++) ;
+ goto ebreak ;
+ }
+ {
+ register char *stringp;
+ /* Place the first digit in the buffer */
+ stringp = &buf[0];
+ *stringp++ = *bp != '\0'? *bp++: '0';
+
+ /* Put in a decimal point if needed */
+ if (prec != 0 || fsharp)
+ *stringp++ = decpt_char;
+
+ /* Create the rest of the mantissa */
+ rzero = prec;
+ while (rzero > 0 && *bp!= '\0') {
+ --rzero;
+ *stringp++ = *bp++;
+ }
+ p = stringp;
+ }
+
+ bp = &buf[0];
+
+ /* Create the exponent */
+ if (convertbuffer[0] != '0')
+ n = decpt - 1;
+ else
+ n = 0 ;
+ if (n < 0)
+ n = -n;
+ _fourdigitsquick( (short unsigned) n, &(expbuf[2]) ) ;
+ expbuf[6] = 0 ;
+ if (n < 100)
+ /*
+ * Normally two digit exponent field,
+ * three or four if required.
+ */
+ { suffix = &(expbuf[4]) ; suffixlength = 4 ; }
+ else if (n < 1000)
+ { suffix = &(expbuf[3]) ; suffixlength = 5 ; }
+ else
+ { suffix = &(expbuf[2]) ; suffixlength = 6 ; }
+ /* Put in the exponent sign */
+ *--suffix = (decpt > 0 || convertbuffer[0] == '0' )? '+': '-';
+
+ /* Put in the e; note kludge in 'g' format */
+ *--suffix = fcode;
+ebreak:
+#if FZERO
+ if (compat_fzero &! fminus)
+ /* Calculate padding zero requirement */
+ lzero = width - (strlen(prefix)
+ + (p - buf) + rzero + suffixlength);
+#endif
+ break;
+
+ case 'f':
+ /*
+ * F-format floating point. This is
+ * a good deal less simple than E-format.
+ * The overall strategy will be to call
+ * fconvert, reformat its result into buf,
+ * and calculate how many trailing
+ * zeroes will be required. There will
+ * never be any leading zeroes needed.
+ */
+
+ /* Establish default precision */
+ if (prec < 0)
+ prec = 6;
+
+ if (Lsize == 0) {
+ dval = va_arg(args.ap, double);
+ bp = fconvert(dval, prec, &decpt, &sign, convertbuffer);
+ } else {
+ GETQVAL ;
+ bp = qfconvert(&qval, prec, &decpt, &sign, convertbuffer);
+ }
+
+ /* Determine the prefix */
+ if (sign)
+ prefix = "-";
+ else if (fplus)
+ prefix = "+";
+ else if (fblank)
+ prefix = " ";
+ if (convertbuffer[0] > '9')
+ { /* handle infinity, nan */
+ bp = &convertbuffer[0];
+ for (p = bp+1 ; *p != 0 ; p++) ;
+ goto fbreak ;
+ }
+ {
+ register char *stringp;
+ /* Initialize buffer pointer */
+ stringp = &buf[0];
+
+ /* Emit the digits before the decimal point */
+ n = decpt;
+ if (n <= 0)
+ *stringp++ = '0';
+ else
+ do
+ if (*bp == '\0' )
+ *stringp++ = '0';
+ else {
+ *stringp++ = *bp++;
+ }
+ while (--n != 0);
+
+ /* Decide whether we need a decimal point */
+ if (fsharp || prec > 0)
+ *stringp++ = decpt_char;
+
+ /* Digits(if any) after the decimal point */
+ n = prec;
+ rzero = prec - n;
+ while (--n >= 0) {
+ if (++decpt <= 0 || *bp == '\0')
+ *stringp++ = '0';
+ else {
+ *stringp++ = *bp++;
+ }
+ }
+#if FZERO
+ if (compat_fzero &! fminus)
+ /* Calculate padding zero requirement */
+ lzero = width - (strlen(prefix)
+ + (stringp - buf) + rzero);
+#endif
+ p = stringp;
+ }
+
+ bp = &buf[0];
+fbreak:
+ break;
+
+ case 'G':
+ case 'g':
+ /*
+ * g-format. We play around a bit
+ * and then jump into e or f, as needed.
+ */
+
+ /* Establish default precision */
+ if (prec < 0)
+ prec = 6;
+ else if (prec == 0)
+ prec = 1;
+
+ if (Lsize == 0) {
+ dval = va_arg(args.ap, double);
+ bp = gconvert(dval, prec, fsharp, convertbuffer);
+ } else {
+ GETQVAL;
+ bp = qgconvert(&qval, prec, fsharp, convertbuffer);
+ }
+ bp = convertbuffer ;
+ if (convertbuffer[0] == '-') {
+ prefix = "-" ;
+ bp++;
+ }
+ else if (fplus)
+ prefix = "+";
+ else if (fblank)
+ prefix = " ";
+ if (isupper(fcode))
+ { /* Put in a big E for small minds. */
+ for (p = bp ; (*p != NULL) && (*p != 'e') ; p++) ;
+ if (*p == 'e') *p = 'E' ;
+ for (; (*p != NULL) ; p++) ;
+ /* Find end of string. */
+ }
+ else
+ for (p = bp ; *p != NULL ; p++) ;
+ /* Find end of string. */
+ rzero = 0;
+#if FZERO
+ if (compat_fzero & !fminus)
+ /* Calculate padding zero requirement */
+ lzero = width - (strlen(prefix)
+ + (p - bp) + rzero);
+#endif
+ break ;
+
+#endif
+ case 'c':
+ buf[0] = va_arg(args.ap, int);
+ bp = &buf[0];
+ p = bp + 1;
+ break;
+
+ case 's':
+ bp = va_arg(args.ap, char *);
+ if (prec < 0)
+ prec = MAXINT;
+ /* avoid *(0) */
+ if (bp == NULL)
+ bp = nullstr;
+ for (n=0; *bp++ != '\0' && n < prec; n++)
+ ;
+#if FZERO
+ if (compat_fzero &! fminus)
+ lzero = width - n;
+#endif
+ p = --bp;
+ bp -= n;
+ break;
+
+ case '\0':
+ /* well, what's the punch line? */
+ goto out;
+
+ case 'n':
+ svswitch = 1;
+ break;
+ default:
+ p = bp = &fcode;
+ p++;
+ break;
+
+ }
+ /* Calculate number of padding blanks */
+ nblank = width
+#if FLOAT
+ - (rzero < 0? 0: rzero)
+ - strlen(suffix)
+#endif
+ - (p - bp)
+ - (lzero < 0? 0: lzero)
+ - strlen(prefix);
+
+ /* Blanks on left if required */
+ if (!fminus)
+ while (--nblank >= 0)
+ emitchar(' ');
+
+ /* Prefix, if any */
+ while (*prefix != '\0') {
+ emitchar(*prefix);
+ prefix++;
+ }
+
+ /* Zeroes on the left */
+ while (--lzero >= 0)
+ emitchar('0');
+
+ /* The value itself */
+ while (bp < p) {
+ emitchar(*bp);
+ bp++;
+ }
+#if FLOAT
+ /* Zeroes on the right */
+ while (--rzero >= 0)
+ emitchar('0');
+
+ /* The suffix */
+ while (*suffix != '\0') {
+ emitchar(*suffix);
+ suffix++;
+ }
+#endif
+ /* Blanks on the right if required */
+ if (fminus)
+ while (--nblank >= 0)
+ emitchar(' ');
+ /* If %n is seen, save count in argument */
+ if (svswitch == 1) {
+ long *svcount;
+ svcount = va_arg (args.ap, long *);
+ *svcount = count;
+ svswitch = 0;
+ }
+ } /* else */
+ } while ((c = *cp++) != '\0'); /* do */
+out:
+ file->_ptr = fileptr;
+ file->_cnt = filecnt;
+ if (file->_flag & (_IONBF | _IOLBF) &&
+ (file->_flag & _IONBF ||
+ memchr((char *)file->_base, '\n', fileptr - file->_base) != NULL))
+ (void) _xflsbuf(file);
+ return (ferror(file)? EOF: count);
+}
+
+#ifdef sparc
+/*
+ * We use "double *" instead of "quadruple *" to skip over the pointer to
+ * long double on the argument list since a pointer is a pointer after all.
+ */
+#define SKIPQVAL { \
+ (void) va_arg(args.ap, double *); \
+}
+#else /* Sun-3 */
+#define SKIPQVAL { \
+ int iq; \
+ for (iq = 0; iq < 4; iq++) \
+ (void) va_arg(args.ap, unsigned long); \
+}
+#endif
+/* This function initializes arglst, to contain the appropriate va_list values
+ * for the first MAXARGS arguments. */
+void
+_mkarglst(fmt, args, arglst)
+char *fmt;
+stva_list args;
+stva_list arglst[];
+{
+ static char *digits = "01234567890", *skips = "# +-.0123456789h$";
+
+ enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR,
+ LONG_PTR, INT_PTR};
+ enum types typelst[MAXARGS], curtype;
+ int maxnum, n, curargno, flags;
+
+ /*
+ * Algorithm 1. set all argument types to zero.
+ * 2. walk through fmt putting arg types in typelst[].
+ * 3. walk through args using va_arg(args.ap, typelst[n])
+ * and set arglst[] to the appropriate values.
+ * Assumptions: Cannot use %*$... to specify variable position.
+ */
+
+ (void)memset((void *)typelst, 0, sizeof(typelst));
+ maxnum = -1;
+ curargno = 0;
+ while ((fmt = strchr(fmt, '%')) != 0)
+ {
+ fmt++; /* skip % */
+ if (fmt[n = strspn(fmt, digits)] == '$')
+ {
+ curargno = atoi(fmt) - 1; /* convert to zero base */
+ fmt += n + 1;
+ }
+ flags = 0;
+ again:;
+ fmt += strspn(fmt, skips);
+ switch (*fmt++)
+ {
+ case '%': /*there is no argument! */
+ continue;
+ case 'l':
+ flags |= 0x1;
+ goto again;
+ case 'L':
+ flags |= 0x8;
+ goto again;
+ case '*': /* int argument used for value */
+ flags |= 0x2;
+ curtype = INT;
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (flags & 0x8)
+ curtype = LONG_DOUBLE;
+ else
+ curtype = DOUBLE;
+ break;
+ case 's':
+ curtype = CHAR_PTR;
+ break;
+ case 'p':
+ curtype = VOID_PTR;
+ break;
+ case 'n':
+ if (flags & 0x1)
+ curtype = LONG_PTR;
+ else
+ curtype = INT_PTR;
+ break;
+ default:
+ if (flags & 0x1)
+ curtype = LONG;
+ else
+ curtype = INT;
+ break;
+ }
+ if (curargno >= 0 && curargno < MAXARGS)
+ {
+ typelst[curargno] = curtype;
+ if (maxnum < curargno)
+ maxnum = curargno;
+ }
+ curargno++; /* default to next in list */
+ if (flags & 0x2) /* took care of *, keep going */
+ {
+ flags ^= 0x2;
+ goto again;
+ }
+ }
+ for (n = 0 ; n <= maxnum; n++)
+ {
+ arglst[n] = args;
+ if (typelst[n] == 0)
+ typelst[n] = INT;
+
+ switch (typelst[n])
+ {
+ case INT:
+ va_arg(args.ap, int);
+ break;
+ case LONG:
+ va_arg(args.ap, long);
+ break;
+ case CHAR_PTR:
+ va_arg(args.ap, char *);
+ break;
+ case DOUBLE:
+ va_arg(args.ap, double);
+ break;
+ case LONG_DOUBLE:
+ SKIPQVAL
+ break;
+ case VOID_PTR:
+ va_arg(args.ap, void *);
+ break;
+ case LONG_PTR:
+ va_arg(args.ap, long *);
+ break;
+ case INT_PTR:
+ va_arg(args.ap, int *);
+ break;
+ }
+ }
+}
+
+/*
+ * This function is used to find the va_list value for arguments whose
+ * position is greater than MAXARGS. This function is slow, so hopefully
+ * MAXARGS will be big enough so that this function need only be called in
+ * unusual circumstances.
+ * pargs is assumed to contain the value of arglst[MAXARGS - 1].
+ */
+void
+_getarg(fmt, pargs, argno)
+char *fmt;
+stva_list *pargs;
+int argno;
+{
+ static char *digits = "01234567890", *skips = "# +-.0123456789h$";
+ int i, n, curargno, flags;
+ char *sfmt = fmt;
+ int found = 1;
+
+ curargno = i = MAXARGS;
+ while (found)
+ {
+ fmt = sfmt;
+ found = 0;
+ while ((i != argno) && (fmt = strchr(fmt, '%')) != 0)
+ {
+ fmt++; /* skip % */
+ if (fmt[n = strspn(fmt, digits)] == '$')
+ {
+ curargno = atoi(fmt);
+ fmt += n + 1;
+ }
+
+ /* find conversion specifier for next argument */
+ if (i != curargno)
+ {
+ curargno++;
+ continue;
+ } else
+ found = 1;
+ flags = 0;
+ again:;
+ fmt += strspn(fmt, skips);
+ switch (*fmt++)
+ {
+ case '%': /*there is no argument! */
+ continue;
+ case 'l':
+ flags |= 0x1;
+ goto again;
+ case 'L':
+ flags |= 0x8;
+ goto again;
+ case '*': /* int argument used for value */
+ flags |= 0x2;
+ (void)va_arg((*pargs).ap, int);
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (flags & 0x8) {
+#define args (*pargs)
+ SKIPQVAL
+#undef args
+ }
+ else
+ (void)va_arg((*pargs).ap, double);
+ break;
+ case 's':
+ (void)va_arg((*pargs).ap, char *);
+ break;
+ case 'p':
+ (void)va_arg((*pargs).ap, void *);
+ break;
+ case 'n':
+ if (flags & 0x1)
+ (void)va_arg((*pargs).ap, long *);
+ else
+ (void)va_arg((*pargs).ap, int *);
+ break;
+ default:
+ if (flags & 0x1)
+ (void)va_arg((*pargs).ap, long int);
+ else
+ (void)va_arg((*pargs).ap, int);
+ break;
+ }
+ i++;
+ curargno++; /* default to next in list */
+ if (flags & 0x2) /* took care of *, keep going */
+ {
+ flags ^= 0x2;
+ goto again;
+ }
+ }
+
+ /* missing specifier for parameter, assume parameter is an int */
+ if (!found && i != argno) {
+ (void)va_arg((*pargs).ap, int);
+ i++;
+ curargno++;
+ found = 1;
+ }
+ }
+}
+
+
+/*
+ * parse a string, mini parse
+ */
+static char *
+_check_dol(s, val)
+ char *s;
+ int *val;
+{
+ char *os; /* save old string */
+ int tmp_val = 0;
+ int flag = 0;
+
+ while (isdigit (*s)) {
+ ++flag;
+ tmp_val = tmp_val*10 + *s - '0';
+ s++;
+ }
+ if (flag == 0)
+ return ((char *)NULL);
+ if (*s == '$') {
+ *val = tmp_val;
+ return(++s);
+ }
+ return ((char *)NULL);
+}