/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* _doprnt: common code for printf, fprintf, sprintf
*/
#include "file64.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <values.h>
#include <nan.h>
#include <memory.h>
#include <string.h>
#include "print.h" /* parameters & macros for doprnt */
#include "stdiom.h"
#include <locale.h>
#include <stddef.h>
#include "_locale.h"
#include "libc.h"
} else { \
} \
}
}
/* bit positions for flags used in doprnt */
/*
* Positional Parameter information
*/
/*
* 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 {
} stva_list;
/*
* forward declarations
*/
static int _lowdigit(long *);
static int
{ /* This function computes the decimal low-order digit of the number */
/* pointed to by valptr, and returns this digit after dividing */
/* *valptr by ten. This function is called ONLY to compute the */
/* low-order digit of a long whose high-order bit is set. */
}
/* The function _dowrite carries out buffer pointer bookkeeping surrounding */
/* a call to fwrite. It is called only when the end of the file output */
/* buffer is approached or in other unusual situations. */
static void
{
} else
}
int
{
/* bufptr is used inside of doprnt instead of iop->_ptr; */
/* bufferend is a copy of _bufend(iop), if it exists. For */
/* dummy file descriptors (iop->_flag & _IOREAD), bufferend */
/* may be meaningless. Dummy file descriptors are used so that */
/* sprintf and vsprintf may share the _doprnt routine with the */
/* rest of the printf family. */
unsigned char *bufptr;
unsigned char *bufferend;
/* This variable counts output characters. */
int count = 0;
/* Starting and ending points for value to be printed */
char *bp;
char *p;
/* Field width and precision */
/* Format code */
int fcode;
/* Number of padding zeroes required on the left and right */
/* Flags - bit positions defined by LENGTH, FPLUS, FMINUS, FBLANK, */
/* and FSHARP are set if corresponding character is in format */
/* Bit position defined by PADZERO means extra space in the field */
/* should be padded with leading zeroes rather than with blanks */
int flagword;
/* Values are developed in this buffer */
/* Pointer to sign, "0x", "0X", or empty */
char *prefix;
/* Exponent or empty */
char *suffix;
/* Buffer to create exponent */
/* Length of prefix and of suffix */
/* Combined length of leading zeroes, trailing zeroes, and suffix */
int otherlength;
/* The value being converted, if integer */
long val;
/* The value being converted, if real */
double dval;
/* Output values from fcvt and ecvt */
/* Pointer to a translate table for digits of whatever radix */
char *tab;
/* Work variables */
/* Variables used to flag an infinities and nans, resp. */
/* Nan_flg is used with two purposes: to flag a NaN and */
/* as the length of the string ``NAN0X'' (``nan0x'') */
/* Pointer to string "NAN0X" or "nan0x" */
char *SNAN;
/* Flag for negative infinity or NaN */
int neg_in = 0;
/* variables for positional parameters */
/* used to save the start of the argument list */
/* used to restore args if positional width or precision */
/*
* array giving the appropriate values for va_arg() to
* retrieve the corresponding argument:
* arglst[0] is the first argument,
* arglst[1] is the second argument, etc.
*/
/*
* 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.
* See equivalent code in libc doprnt.c
*/
#endif
/* if first I/O to the stream get a buffer */
/* Note that iop->_base should not equal 0 for sprintf and vsprintf */
return (EOF);
/* initialize buffer pointer and buffer end pointer */
/*
* The main loop -- this loop goes through one iteration
* for each string of ordinary characters or format specification.
*/
for (;;) {
do {
format++;
/* pdiff = no. of non-% chars */
}
/*
* in case of interrupt during last
* several lines
*/
NULL))
}
/*
* % has been found.
* The following switch is used to parse the format
* specification and to perform the operation specified
* by the format letter. The program repeatedly goes
* back to this switch until the format letter is
* encountered.
*/
suffixlength = 0;
format++;
case '+':
goto charswitch;
case '-':
goto charswitch;
case ' ':
goto charswitch;
case '#':
goto charswitch;
/* Scan the field width and precision */
case '.':
prec = 0;
goto charswitch;
case '*':
starflg = 1;
goto charswitch;
}
if (width < 0) {
}
} else {
if (prec < 0)
prec = 0;
}
goto charswitch;
case '$':
{
int position;
if (fpos) {
fpos = 0;
}
prec = 0;
} else {
width = 0;
}
if (position <= 0) {
/* illegal position */
format--;
continue;
}
} else {
}
if (!starflg)
else {
starflg = 0;
else
}
goto charswitch;
}
case '0': /* obsolescent spec: leading zero in width */
/* means pad with leading zeros */
/* FALLTHROUGH */
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
format++;
}
else
goto charswitch;
}
/* Scan the length modifier */
case 'l':
goto charswitch;
case 'h':
goto charswitch;
case 'L':
goto charswitch;
/*
* The character addressed by format must be
* the format letter -- there is nothing
* left for it to be.
*
* The status of the +, -, #, and blank
* flags are reflected in the variable
* "flagword". "width" and "prec" contain
* numbers corresponding to the digit
* strings before and after the decimal
* point, respectively. If there was no
* decimal point, then flagword & DOTSEEN
* is false and the value of prec is meaningless.
*
* The following switch cases set 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 informa-
* tion 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".
* If there is a suffix, the flagword bit
* SUFFIX will be set.
*
* 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.
* The flagword bits LZERO and RZERO tell
* whether padding zeros are required.
*
* The number of padding blanks, and
* whether they go on the left or the
* right, will be computed on exit from
* the switch.
*/
/*
* decimal fixed point representations
*
* HIBITL is 100...000
* binary, and is equal to the maximum
* negative number.
* We assume a 2's complement machine
*/
case 'i':
case 'd':
/* Fetch the argument to be printed */
else
/* Set buffer pointer to last digit */
/* If signed conversion, make sign */
if (val < 0) {
prefix = "-";
prefixlength = 1;
/*
* Negate, checking in
* advance for possible
* overflow.
*/
else /* number is -HIBITL; convert last */
/* digit now and get positive number */
prefix = "+";
prefixlength = 1;
prefix = " ";
prefixlength = 1;
}
{
long saveq;
if (qval <= 9) {
} else {
do {
qval /= 10;
} while (qval > 9);
}
}
/* Calculate minimum padding zero requirement */
if (leadzeroes > 0) {
}
}
break;
case 'u':
/* Fetch the argument to be printed */
else
goto decimal;
/*
* non-decimal fixed point representations
* for radix equal to a power of two
*
* "mradix" is one less than the radix for the conversion.
* "lradix" is one less than the base 2 log
* of the radix for the conversion. Conversion is unsigned.
* HIBITL is 100...000
* binary, and is equal to the maximum
* negative number.
* We assume a 2's complement machine
*/
case 'o':
mradix = 7;
lradix = 2;
goto fixed;
case 'X':
case 'x':
case 'p':
mradix = 15;
lradix = 3;
/* Fetch the argument to be printed */
else
/* Set translate table for digits */
/* Entry point when printing a double which is a NaN */
/* Develop the digits of the value */
{
if (qval == 0) {
}
} else
do {
>> lradix;
} while (qval != 0);
}
/* Calculate minimum padding zero requirement */
if (leadzeroes > 0) {
}
}
/* Handle the # flag */
switch (fcode) {
case 'o':
}
break;
case 'x':
prefix = "0x";
prefixlength = 2;
break;
case 'X':
prefix = "0X";
prefixlength = 2;
break;
}
break;
case 'E':
case 'e':
/*
* E-format. The general strategy
* here is fairly easy: we take
* what ecvt gives us and re-format it.
*/
/* Establish default precision */
prec = 6;
/* Fetch the value */
/* Check for NaNs and Infinities */
if (IsNANorINF(dval)) {
neg_in = 1;
inf_nan = 1;
p = bp + 3;
break;
} else {
neg_in = 1;
inf_nan = 1;
mradix = 15;
lradix = 3;
if (fcode == 'E') {
} else {
}
goto put_pc;
}
}
/* Develop the mantissa */
/* Determine the prefix */
if (sign) {
prefix = "-";
prefixlength = 1;
prefix = "+";
prefixlength = 1;
prefix = " ";
prefixlength = 1;
}
/* Place the first digit in the buffer */
p = &buf[0];
/* Put in a decimal point if needed */
*p++ = _numeric[0];
/* Create the rest of the mantissa */
{
*p++ = *bp++;
if (rz > 0) {
}
}
/* Create the exponent */
if (dval != 0) {
if (nn < 0)
}
/* Prepend leading zeroes to the exponent */
*--suffix = '0';
/* Put in the exponent sign */
/* Put in the e */
/* compute size of suffix */
otherlength += (suffixlength =
break;
case 'f':
/*
* F-format floating point. This is a
* good deal less simple than E-format.
* The overall strategy will be to call
* fcvt, 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 */
prec = 6;
/* Fetch the value */
/* Check for NaNs and Infinities */
if (IsNANorINF(dval)) {
neg_in = 1;
inf_nan = 1;
p = bp + 3;
break;
} else {
neg_in = 1;
inf_nan = 1;
mradix = 15;
lradix = 3;
goto put_pc;
}
}
/* Do the conversion */
/* Determine the prefix */
if (sign) {
prefix = "-";
prefixlength = 1;
prefix = "+";
prefixlength = 1;
prefix = " ";
prefixlength = 1;
}
/* Initialize buffer pointer */
p = &buf[0];
{
/* Emit the digits before the decimal point */
k = 0;
do {
k >= MAXFSIG) ?
'0' : (k++, *bp++);
} while (--nn > 0);
/* Decide whether we need a decimal point */
*p++ = _numeric[0];
/* Digits (if any) after the decimal point */
}
while (--nn >= 0)
k >= MAXFSIG) ?
'0' : (k++, *bp++);
}
break;
case 'G':
case 'g':
/*
* g-format. We play around a bit
* and then jump into e or f, as needed.
*/
/* Establish default precision */
prec = 6;
else if (prec == 0)
prec = 1;
/* Fetch the value */
/* Check for NaN and Infinities */
if (IsNANorINF(dval)) {
neg_in = 1;
p = bp + 3;
inf_nan = 1;
break;
} else {
neg_in = 1;
inf_nan = 1;
mradix = 15;
lradix = 3;
if (fcode == 'G') {
} else {
}
goto put_pc;
}
}
/* Do the conversion */
if (dval == 0)
decpt = 1;
{
--kk;
}
goto e_merge;
}
goto f_merge;
}
case '%':
goto c_merge;
case 'c':
break;
case 's':
else { /* a strnlen function would be useful here! */
;
p = qp - 1;
}
break;
case 'n':
{
long *svcount;
short *svcount;
} else {
int *svcount;
}
continue;
}
default: /* this is technically an error; what we do is to */
/* back up the format pointer to the offending char */
/* and continue with the format scan */
format--;
continue;
}
if (inf_nan) {
if (neg_in) {
prefix = "-";
prefixlength = 1;
neg_in = 0;
prefix = "+";
prefixlength = 1;
prefix = " ";
prefixlength = 1;
}
inf_nan = 0;
}
/* Calculate number of padding blanks */
if (width <= k)
count += k;
else {
/* Set up for padding zeroes if requested */
/* Otherwise emit padding blanks unless output is */
/* to be left-justified. */
}
else
k = width; /* cancel padding blanks */
} else
/* Blanks on left if required */
}
/* Prefix, if any */
if (prefixlength != 0)
/* If value is NaN, put string NaN */
if (NaN_flg) {
NaN_flg = 0;
}
/* Zeroes on the left */
/* The value itself */
if (pdiff > 0)
/* Zeroes on the right */
/* The suffix */
/* Blanks on the right if required */
}
}
}
/*
* This function initializes arglst, to contain the appropriate va_list values
* for the first MAXARGS arguments.
*/
void
{
/*
* 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.
*/
maxnum = -1;
curargno = 0;
fmt++; /* skip % */
/* convert to zero base */
if (curargno < 0)
continue;
}
flags = 0;
again:;
switch (*fmt++) {
case '%': /* there is no argument! */
continue;
case 'l':
flags |= 0x1;
goto again;
case '*': /* int argument used for value */
/* check if there is a positional parameter */
int targno;
if (*fmt == '$')
fmt++; /* skip '$' */
}
goto again;
}
flags |= 0x2;
break;
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
break;
case 's':
break;
case 'p':
break;
case 'n':
if (flags & 0x1)
else
break;
default:
if (flags & 0x1)
else
break;
}
}
curargno++; /* default to next in list */
{
flags ^= 0x2;
goto again;
}
}
for (n = 0; n <= maxnum; n++) {
if (typelst[n] == 0)
switch (typelst[n]) {
case INT:
break;
case LONG:
break;
case CHAR_PTR:
break;
case DOUBLE:
break;
case LONG_DOUBLE:
break;
case VOID_PTR:
break;
case LONG_PTR:
break;
case INT_PTR:
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
{
size_t n;
i = MAXARGS;
curargno = 1;
while (found) {
found = 0;
fmt++; /* skip % */
if (curargno <= 0)
continue;
fmt += n + 1;
}
/* find conversion specifier for next argument */
if (i != curargno) {
curargno++;
continue;
} else
found = 1;
flags = 0;
again:;
switch (*fmt++) {
case '%': /* there is no argument! */
continue;
case 'l':
flags |= 0x1;
goto again;
case '*': /* int argument used for value */
/*
* check if there is a positional parameter;
* if so, just skip it; its size will be
* correctly determined by default
*/
if (*fmt == '$')
fmt++; /* skip '$' */
goto again;
}
flags |= 0x2;
break;
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
if (flags & 0x1)
else
break;
case 's':
break;
case 'p':
break;
case 'n':
if (flags & 0x1)
else
break;
default:
if (flags & 0x1)
else
break;
}
i++;
curargno++; /* default to next in list */
{
flags ^= 0x2;
goto again;
}
}
/*
* missing specifier for parameter, assume parameter is an int
*/
i++;
curargno = i;
found = 1;
}
}
}