#include <sys/types.h>
#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"
#include "stdiom.h"
#include <locale.h>
#include <stddef.h>
#include "_locale.h"
#include "libc.h"
#define PUT(p, n) { unsigned char *newbufptr; \
if ((newbufptr = bufptr + (n)) > bufferend) { \
_dowrite((p), (n), iop, &bufptr); \
} else { \
(void) memcpy(bufptr, (p), (n)); \
bufptr = newbufptr; \
} \
}
#define PAD(s, n) { int nn; \
for (nn = (n); nn > 20; nn -= 20) \
_dowrite((s), 20, iop, &bufptr); \
PUT((s), nn); \
}
#define SNLEN 5
#define LENGTH 1
#define FPLUS 2
#define FMINUS 4
#define FBLANK 8
#define FSHARP 16
#define PADZERO 32
#define DOTSEEN 64
#define SUFFIX 128
#define RZERO 256
#define LZERO 512
#define SHORT 1024
#define MAXARGS 30
typedef struct stva_list {
va_list ap;
} stva_list;
static char _blanks[] = " ";
static char _zeroes[] = "00000000000000000000";
static char uc_digs[] = "0123456789ABCDEF";
static char lc_digs[] = "0123456789abcdef";
static char lc_nan[] = "nan0x";
static char uc_nan[] = "NAN0X";
static char lc_inf[] = "inf";
static char uc_inf[] = "INF";
void _mkarglst(char *, stva_list, stva_list []);
void _getarg(char *, stva_list *, int);
static int _lowdigit(long *);
static void _dowrite(char *, ssize_t, FILE *, unsigned char **);
static int
_lowdigit(long *valptr)
{
int lowbit = (int)(*valptr & 1);
long value = (*valptr >> 1) & ~HIBITL;
*valptr = value / 5;
return ((int)(value % 5 * 2 + lowbit + '0'));
}
static void
_dowrite(char *p, ssize_t n, FILE *iop, unsigned char **ptrptr)
{
if (!(iop->_flag & _IOREAD)) {
iop->_cnt -= (*ptrptr - iop->_ptr);
iop->_ptr = *ptrptr;
_bufsync(iop, _bufend(iop));
(void) fwrite(p, 1, n, iop);
*ptrptr = iop->_ptr;
} else
*ptrptr = (unsigned char *) memcpy(*ptrptr, p, n) + n;
}
int
_doprnt(char *format, va_list in_args, FILE *iop)
{
unsigned char *bufptr;
unsigned char *bufferend;
int count = 0;
char *bp;
char *p;
int width, prec;
int fcode;
int lzero, rzero;
int flagword;
char buf[max(MAXDIGS, 1+max(MAXFCVT+MAXEXP, MAXECVT))];
char *prefix;
char *suffix;
char expbuf[MAXESIZ + 1];
int prefixlength, suffixlength;
int otherlength;
long val;
double dval;
int decpt, sign;
char *tab;
int k, lradix, mradix;
int inf_nan = 0, NaN_flg = 0;
char *SNAN;
int neg_in = 0;
char *sformat = format;
int fpos = 1;
stva_list args;
stva_list sargs;
stva_list bargs;
stva_list arglst[MAXARGS];
int starflg = 0;
#if !(defined(__amd64) && defined(__GNUC__))
va_copy(args.ap, in_args);
#endif
sargs = args;
if (iop->_base == 0 && _findbuf(iop) == 0)
return (EOF);
bufptr = iop->_ptr;
bufferend = (iop->_flag & _IOREAD) ?
(unsigned char *)((long)bufptr | (-1L & ~HIBITL))
: _bufend(iop);
for (;;) {
ptrdiff_t pdiff;
if ((fcode = *format) != '\0' && fcode != '%') {
bp = format;
do {
format++;
} while ((fcode = *format) != '\0' && fcode != '%');
pdiff = format - bp;
count += pdiff;
PUT(bp, pdiff);
}
if (fcode == '\0') {
ptrdiff_t d = bufptr - iop->_ptr;
iop->_cnt -= d;
iop->_ptr = bufptr;
if (bufptr + iop->_cnt > bufferend &&
!(iop->_flag & _IOREAD))
_bufsync(iop, bufferend);
if (iop->_flag & (_IONBF | _IOLBF) &&
(iop->_flag & _IONBF ||
memchr((char *)(bufptr-count), '\n', count) !=
NULL))
(void) _xflsbuf(iop);
return (ferror(iop) ? EOF : count);
}
width = prefixlength = otherlength = flagword =
suffixlength = 0;
format++;
charswitch:
switch (fcode = *format++) {
case '+':
flagword |= FPLUS;
goto charswitch;
case '-':
flagword |= FMINUS;
flagword &= ~PADZERO;
goto charswitch;
case ' ':
flagword |= FBLANK;
goto charswitch;
case '#':
flagword |= FSHARP;
goto charswitch;
case '.':
flagword |= DOTSEEN;
prec = 0;
goto charswitch;
case '*':
if (isdigit(*format)) {
starflg = 1;
bargs = args;
goto charswitch;
}
if (!(flagword & DOTSEEN)) {
width = va_arg(args.ap, int);
if (width < 0) {
width = -width;
flagword ^= FMINUS;
}
} else {
prec = va_arg(args.ap, int);
if (prec < 0)
prec = 0;
}
goto charswitch;
case '$':
{
int position;
stva_list targs;
if (fpos) {
_mkarglst(sformat, sargs, arglst);
fpos = 0;
}
if (flagword & DOTSEEN) {
position = prec;
prec = 0;
} else {
position = width;
width = 0;
}
if (position <= 0) {
format--;
continue;
}
if (position <= MAXARGS) {
targs = arglst[position - 1];
} else {
targs = arglst[MAXARGS - 1];
_getarg(sformat, &targs, position);
}
if (!starflg)
args = targs;
else {
starflg = 0;
args = bargs;
if (flagword & DOTSEEN)
prec = va_arg(targs.ap, int);
else
width = va_arg(targs.ap, int);
}
goto charswitch;
}
case '0':
if (!(flagword & (DOTSEEN | FMINUS)))
flagword |= PADZERO;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
int num = fcode - '0';
while (isdigit(fcode = *format)) {
num = num * 10 + fcode - '0';
format++;
}
if (flagword & DOTSEEN)
prec = num;
else
width = num;
goto charswitch;
}
case 'l':
flagword |= LENGTH;
goto charswitch;
case 'h':
flagword |= SHORT;
goto charswitch;
case 'L':
goto charswitch;
case 'i':
case 'd':
if (flagword & LENGTH)
val = va_arg(args.ap, long);
else
val = va_arg(args.ap, int);
if (flagword & SHORT)
val = (short)val;
p = bp = buf + MAXDIGS;
if (val < 0) {
prefix = "-";
prefixlength = 1;
if (val != HIBITL)
val = -val;
else
*--bp = _lowdigit(&val);
} else if (flagword & FPLUS) {
prefix = "+";
prefixlength = 1;
} else if (flagword & FBLANK) {
prefix = " ";
prefixlength = 1;
}
decimal:
{
long qval = val;
long saveq;
if (qval <= 9) {
if (qval != 0 || !(flagword & DOTSEEN))
*--bp = (char)(qval + '0');
} else {
do {
saveq = qval;
qval /= 10;
*--bp = (char)(saveq -
qval * 10 + '0');
} while (qval > 9);
*--bp = (char)(qval + '0');
pdiff = (ptrdiff_t)saveq;
}
}
if (flagword & DOTSEEN) {
int leadzeroes = prec - (int)(p - bp);
if (leadzeroes > 0) {
otherlength = lzero = leadzeroes;
flagword |= LZERO;
}
}
break;
case 'u':
if (flagword & LENGTH)
val = va_arg(args.ap, long);
else
val = va_arg(args.ap, unsigned);
if (flagword & SHORT)
val = (unsigned short)val;
p = bp = buf + MAXDIGS;
if (val & HIBITL)
*--bp = _lowdigit(&val);
goto decimal;
case 'o':
mradix = 7;
lradix = 2;
goto fixed;
case 'X':
case 'x':
case 'p':
mradix = 15;
lradix = 3;
fixed:
if (flagword & LENGTH)
val = va_arg(args.ap, long);
else
val = va_arg(args.ap, unsigned);
if (flagword & SHORT)
val = (unsigned short)val;
tab = (fcode == 'X') ? uc_digs : lc_digs;
put_pc:
p = bp = buf + MAXDIGS;
{
long qval = val;
if (qval == 0) {
if (!(flagword & DOTSEEN)) {
otherlength = lzero = 1;
flagword |= LZERO;
}
} else
do {
*--bp = tab[qval & mradix];
qval = ((qval >> 1) & ~HIBITL)
>> lradix;
} while (qval != 0);
}
if (flagword & DOTSEEN) {
int leadzeroes = prec - (int)(p - bp);
if (leadzeroes > 0) {
otherlength = lzero = leadzeroes;
flagword |= LZERO;
}
}
if (flagword & FSHARP && val != 0)
switch (fcode) {
case 'o':
if (!(flagword & LZERO)) {
otherlength = lzero = 1;
flagword |= LZERO;
}
break;
case 'x':
prefix = "0x";
prefixlength = 2;
break;
case 'X':
prefix = "0X";
prefixlength = 2;
break;
}
break;
case 'E':
case 'e':
if (!(flagword & DOTSEEN))
prec = 6;
dval = va_arg(args.ap, double);
if (IsNANorINF(dval)) {
if (IsINF(dval)) {
if (IsNegNAN(dval))
neg_in = 1;
inf_nan = 1;
bp = (fcode == 'E')? uc_inf: lc_inf;
p = bp + 3;
break;
} else {
if (IsNegNAN(dval))
neg_in = 1;
inf_nan = 1;
val = GETNaNPC(dval);
NaN_flg = SNLEN;
mradix = 15;
lradix = 3;
if (fcode == 'E') {
SNAN = uc_nan;
tab = uc_digs;
} else {
SNAN = lc_nan;
tab = lc_digs;
}
goto put_pc;
}
}
bp = ecvt(dval, min(prec + 1, MAXECVT), &decpt, &sign);
e_merge:
if (sign) {
prefix = "-";
prefixlength = 1;
} else if (flagword & FPLUS) {
prefix = "+";
prefixlength = 1;
} else if (flagword & FBLANK) {
prefix = " ";
prefixlength = 1;
}
p = &buf[0];
*p++ = (*bp != '\0') ? *bp++ : '0';
if (prec != 0 || (flagword & FSHARP))
*p++ = _numeric[0];
{
int rz = prec;
for (; rz > 0 && *bp != '\0'; --rz)
*p++ = *bp++;
if (rz > 0) {
otherlength = rzero = rz;
flagword |= RZERO;
}
}
bp = &buf[0];
*(suffix = &expbuf[MAXESIZ]) = '\0';
if (dval != 0) {
int nn = decpt - 1;
if (nn < 0)
nn = -nn;
for (; nn > 9; nn /= 10)
*--suffix = todigit(nn % 10);
*--suffix = todigit(nn);
}
while (suffix > &expbuf[MAXESIZ - 2])
*--suffix = '0';
*--suffix = (decpt > 0 || dval == 0) ? '+' : '-';
*--suffix = isupper(fcode) ? 'E' : 'e';
otherlength += (suffixlength =
(int)(&expbuf[MAXESIZ] - suffix));
flagword |= SUFFIX;
break;
case 'f':
if (!(flagword & DOTSEEN))
prec = 6;
dval = va_arg(args.ap, double);
if (IsNANorINF(dval)) {
if (IsINF(dval)) {
if (IsNegNAN(dval))
neg_in = 1;
inf_nan = 1;
bp = lc_inf;
p = bp + 3;
break;
} else {
if (IsNegNAN(dval))
neg_in = 1;
inf_nan = 1;
val = GETNaNPC(dval);
NaN_flg = SNLEN;
mradix = 15;
lradix = 3;
tab = lc_digs;
SNAN = lc_nan;
goto put_pc;
}
}
bp = fcvt(dval, min(prec, MAXFCVT), &decpt, &sign);
f_merge:
if (sign) {
prefix = "-";
prefixlength = 1;
} else if (flagword & FPLUS) {
prefix = "+";
prefixlength = 1;
} else if (flagword & FBLANK) {
prefix = " ";
prefixlength = 1;
}
p = &buf[0];
{
int nn = decpt;
k = 0;
do {
*p++ = (nn <= 0 || *bp == '\0' ||
k >= MAXFSIG) ?
'0' : (k++, *bp++);
} while (--nn > 0);
if ((flagword & FSHARP) || prec > 0)
*p++ = _numeric[0];
nn = min(prec, MAXFCVT);
if (prec > nn) {
flagword |= RZERO;
otherlength = rzero = prec - nn;
}
while (--nn >= 0)
*p++ = (++decpt <= 0 || *bp == '\0' ||
k >= MAXFSIG) ?
'0' : (k++, *bp++);
}
bp = &buf[0];
break;
case 'G':
case 'g':
if (!(flagword & DOTSEEN))
prec = 6;
else if (prec == 0)
prec = 1;
dval = va_arg(args.ap, double);
if (IsNANorINF(dval)) {
if (IsINF(dval)) {
if (IsNegNAN(dval))
neg_in = 1;
bp = (fcode == 'G') ? uc_inf : lc_inf;
p = bp + 3;
inf_nan = 1;
break;
} else {
if (IsNegNAN(dval))
neg_in = 1;
inf_nan = 1;
val = GETNaNPC(dval);
NaN_flg = SNLEN;
mradix = 15;
lradix = 3;
if (fcode == 'G') {
SNAN = uc_nan;
tab = uc_digs;
} else {
SNAN = lc_nan;
tab = lc_digs;
}
goto put_pc;
}
}
bp = ecvt(dval, min(prec, MAXECVT), &decpt, &sign);
if (dval == 0)
decpt = 1;
{
int kk = prec;
size_t sz;
if (!(flagword & FSHARP)) {
sz = strlen(bp);
if (sz < kk)
kk = (int)sz;
while (kk >= 1 && bp[kk-1] == '0')
--kk;
}
if (decpt < -3 || decpt > prec) {
prec = kk - 1;
goto e_merge;
}
prec = kk - decpt;
goto f_merge;
}
case '%':
buf[0] = (char)fcode;
goto c_merge;
case 'c':
buf[0] = va_arg(args.ap, int);
c_merge:
p = (bp = &buf[0]) + 1;
break;
case 's':
bp = va_arg(args.ap, char *);
if (!(flagword & DOTSEEN))
p = bp + strlen(bp);
else {
char *qp = bp;
while (*qp++ != '\0' && --prec >= 0)
;
p = qp - 1;
}
break;
case 'n':
{
if (flagword & LENGTH) {
long *svcount;
svcount = va_arg(args.ap, long *);
*svcount = count;
} else if (flagword & SHORT) {
short *svcount;
svcount = va_arg(args.ap, short *);
*svcount = (short)count;
} else {
int *svcount;
svcount = va_arg(args.ap, int *);
*svcount = count;
}
continue;
}
default:
format--;
continue;
}
if (inf_nan) {
if (neg_in) {
prefix = "-";
prefixlength = 1;
neg_in = 0;
} else if (flagword & FPLUS) {
prefix = "+";
prefixlength = 1;
} else if (flagword & FBLANK) {
prefix = " ";
prefixlength = 1;
}
inf_nan = 0;
}
k = (int)(pdiff = p - bp) + prefixlength + otherlength +
NaN_flg;
if (width <= k)
count += k;
else {
count += width;
if (flagword & PADZERO) {
if (!(flagword & LZERO)) {
flagword |= LZERO;
lzero = width - k;
}
else
lzero += width - k;
k = width;
} else
if (!(flagword & FMINUS))
PAD(_blanks, width - k);
}
if (prefixlength != 0)
PUT(prefix, prefixlength);
if (NaN_flg) {
PUT(SNAN, SNLEN);
NaN_flg = 0;
}
if (flagword & LZERO)
PAD(_zeroes, lzero);
if (pdiff > 0)
PUT(bp, pdiff);
if (flagword & (RZERO | SUFFIX | FMINUS)) {
if (flagword & RZERO)
PAD(_zeroes, rzero);
if (flagword & SUFFIX)
PUT(suffix, suffixlength);
if (flagword & FMINUS && width > k)
PAD(_blanks, width - k);
}
}
}
void
_mkarglst(char *fmt, stva_list args, stva_list arglst[])
{
static char digits[] = "01234567890", skips[] = "# +-.0123456789hL$";
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;
(void) memset((void *)typelst, 0, sizeof (typelst));
maxnum = -1;
curargno = 0;
while ((fmt = strchr(fmt, '%')) != 0) {
size_t sz;
fmt++;
if (fmt[sz = strspn(fmt, digits)] == '$') {
curargno = atoi(fmt) - 1;
if (curargno < 0)
continue;
fmt += sz + 1;
}
flags = 0;
again:;
fmt += strspn(fmt, skips);
switch (*fmt++) {
case '%':
continue;
case 'l':
flags |= 0x1;
goto again;
case '*':
if (isdigit(*fmt)) {
int targno;
targno = atoi(fmt) - 1;
fmt += strspn(fmt, digits);
if (*fmt == '$')
fmt++;
if (targno >= 0 && targno < MAXARGS) {
typelst[targno] = INT;
if (maxnum < targno)
maxnum = targno;
}
goto again;
}
flags |= 0x2;
curtype = INT;
break;
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
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++;
if (flags & 0x2)
{
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:
(void) va_arg(args.ap, int);
break;
case LONG:
(void) va_arg(args.ap, long);
break;
case CHAR_PTR:
(void) va_arg(args.ap, char *);
break;
case DOUBLE:
(void) va_arg(args.ap, double);
break;
case LONG_DOUBLE:
(void) va_arg(args.ap, double);
break;
case VOID_PTR:
(void) va_arg(args.ap, void *);
break;
case LONG_PTR:
(void) va_arg(args.ap, long *);
break;
case INT_PTR:
(void) va_arg(args.ap, int *);
break;
}
}
}
void
_getarg(char *fmt, stva_list *pargs, int argno)
{
static char digits[] = "01234567890", skips[] = "# +-.0123456789h$";
int i, curargno, flags;
size_t n;
char *sfmt = fmt;
int found = 1;
i = MAXARGS;
curargno = 1;
while (found) {
fmt = sfmt;
found = 0;
while ((i != argno) && (fmt = strchr(fmt, '%')) != 0) {
fmt++;
if (fmt[n = strspn(fmt, digits)] == '$') {
curargno = atoi(fmt);
if (curargno <= 0)
continue;
fmt += n + 1;
}
if (i != curargno) {
curargno++;
continue;
} else
found = 1;
flags = 0;
again:;
fmt += strspn(fmt, skips);
switch (*fmt++) {
case '%':
continue;
case 'l':
flags |= 0x1;
goto again;
case '*':
if (isdigit(*fmt)) {
fmt += strspn(fmt, digits);
if (*fmt == '$')
fmt++;
goto again;
}
flags |= 0x2;
(void) va_arg((*pargs).ap, int);
break;
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
if (flags & 0x1)
(void) va_arg((*pargs).ap, double);
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++;
if (flags & 0x2)
{
flags ^= 0x2;
goto again;
}
}
if (!found && i != argno) {
(void) va_arg((*pargs).ap, int);
i++;
curargno = i;
found = 1;
}
}
}