#include "lint.h"
#include "mtlib.h"
#include "print.h"
#include <wchar.h>
#include "libc.h"
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#include <stdarg.h>
#include <values.h>
#include <memory.h>
#include <string.h>
#include <locale.h>
#include <widec.h>
#include "../i18n/_locale.h"
#include <errno.h>
#include <sys/types.h>
#include <libw.h>
#include "mse.h"
#include "xpg6.h"
static const char nullstr[] = "(null)";
static const wchar_t widenullstr[] = L"(null)";
#if defined(__i386) || defined(__amd64) || defined(__sparcv9)
#define GETQVAL(arg) (va_arg(arg, long double))
#else
#define GETQVAL(arg) *(va_arg(arg, long double *))
#endif
#ifdef _WIDE
#define L(x) L##x
#define STRCHR(s, c) wcschr(s, c)
#define STRSPN(s1, s2) wcsspn(s1, s2)
#define STRLEN(s) wcslen(s)
#define ATOI(x) _watoi((wchar_t *)x)
#define _M_ISDIGIT(c) (((c) >= 0) && ((c) < 256) && isdigit((c)))
#define _M_ISUPPER(c) (((c) >= 0) && ((c) < 256) && isupper((c)))
#else
#define L(x) x
#define STRCHR(s, c) strchr(s, c)
#define STRSPN(s1, s2) strspn(s1, s2)
#define STRLEN(s) strlen(s)
#define ATOI(x) atoi(x)
#define _M_ISDIGIT(c) isdigit((c))
#define _M_ISUPPER(c) isupper((c))
#endif
#define _P_HYPHEN L("-")
#define _P_PLUS L("+")
#define _P_BLANK L(" ")
#define _P_ZEROx L("0x")
#define _P_ZEROX L("0X")
#ifdef _WIDE
#define PUT(p, n) \
{ \
int retp; \
retp = put_wide(iop, &bufptr, bufferend, p, n, sflag); \
if (retp == EOF) { \
return ((ssize_t)EOF); \
} \
}
#define PAD(s, n) \
{ \
int retp; \
retp = pad_wide(iop, &bufptr, bufferend, s, n, sflag); \
if (retp == EOF) { \
return ((ssize_t)EOF); \
} \
}
#define FPCONV(func, val, prec, decpt, sign, cvtbuf) \
{ \
char cb[DECIMAL_STRING_LENGTH]; \
wchar_t *wp; \
char *cp; \
(void) func(val, prec, decpt, sign, cb); \
wp = cvtbuf; \
cp = cb; \
while (*cp) { \
*wp++ = (wchar_t)*cp++; \
} \
*wp = L('\0'); \
}
#else
#define PUT(p, n) \
{\
\
if (snflag || bufptr > bufferend ||\
(unsigned long)(bufferend - bufptr) < (n)) {\
if (!_dowrite(p, n, iop, &bufptr)) {\
return (EOF);\
}\
} else {\
unsigned char *fbp = bufptr;\
switch (n) {\
case 4:\
*fbp = *p;\
*(fbp + 1) = *(p + 1);\
*(fbp + 2) = *(p + 2);\
*(fbp + 3) = *(p + 3);\
bufptr += 4;\
break;\
case 3:\
*fbp = *p;\
*(fbp + 1) = *(p + 1);\
*(fbp + 2) = *(p + 2);\
bufptr += 3;\
break;\
case 2:\
*fbp = *p;\
*(fbp + 1) = *(p + 1);\
bufptr += 2;\
break;\
case 1:\
*bufptr++ = *p;\
break;\
default:\
bufptr = (unsigned char *)memcpy(fbp, p, n)\
+ (n);\
}\
}\
}
#define PAD(s, n) { ssize_t nn; \
for (nn = n; nn > PAD_LEN; nn -= PAD_LEN) \
if (!_dowrite(s, PAD_LEN, iop, &bufptr)) \
return (EOF); \
PUT(s, nn); \
}
#define FPCONV(func, val, prec, decpt, sign, cvtbuf) \
(void) func(val, prec, decpt, sign, cvtbuf);
#endif
#define LENGTH 0x1
#define FPLUS 0x2
#define FMINUS 0x4
#define FBLANK 0x8
#define FSHARP 0x10
#define PADZERO 0x20
#define DOTSEEN 0x40
#define SUFFIX 0x80
#define RZERO 0x100
#define LZERO 0x200
#define SHORT 0x400
#define QUAD 0x800
#define XLONG 0x1000
#define CHAR 0x2000
static CHAR_T *insert_decimal_point(CHAR_T *ep);
static CHAR_T *insert_thousands_sep(CHAR_T *bp, CHAR_T *ep);
static int _rec_scrswidth(wchar_t *, ssize_t);
#define MAXARGS 30
static ssize_t
_dowrite(const char *p, ssize_t n, FILE *iop, unsigned char **ptrptr);
typedef struct stva_list {
va_list ap;
} stva_list;
static void _mkarglst(CHAR_T *, stva_list, stva_list [], int);
#ifdef _WIDE
static
#endif
void _getarg(CHAR_T *, stva_list *, long, int);
static int
_lowdigit(ssize_t *valptr)
{
ssize_t lowbit = *valptr & 1;
long value = (*valptr >> 1) & ~HIBITL;
*valptr = value / 5;
value = value % 5 * 2 + lowbit + '0';
return ((int)value);
}
static int
_lowlldigit(long long *valptr)
{
ssize_t lowbit = *valptr & 1;
long long value = (*valptr >> 1) & ~HIBITLL;
*valptr = value / 5;
value = value % 5 * 2 + lowbit + '0';
return ((int)value);
}
static ssize_t
_dowrite(const 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));
if (_FWRITE(p, 1, n, iop) != n) {
return (0);
}
*ptrptr = iop->_ptr;
} else {
if (n > iop->_cnt)
n = iop->_cnt;
iop->_cnt -= n;
*ptrptr = (unsigned char *)memcpy((char *)*ptrptr, p, n) + n;
iop->_ptr = *ptrptr;
}
return (1);
}
#define PAD_LEN 20
static const char _blanks[] = " ";
static const char _zeroes[] = "00000000000000000000";
static const CHAR_T uc_digs[] = L("0123456789ABCDEF");
static const CHAR_T lc_digs[] = L("0123456789abcdef");
static const CHAR_T digits[] = L("01234567890");
static const CHAR_T skips[] = L("# +-.'0123456789h$");
#ifdef _WIDE
static int
put_wide(FILE *iop, unsigned char **bufptr,
unsigned char *bufferend, wchar_t *p, size_t n,
int sflag)
{
unsigned char *newbufptr;
wchar_t *q;
int r;
size_t len, i;
if (sflag) {
len = (wchar_t *)bufferend - (wchar_t *)*bufptr;
if (n > len) {
(void) wmemcpy((wchar_t *)*bufptr, p, len);
iop->_ptr = bufferend;
return (EOF);
} else {
(void) wmemcpy((wchar_t *)*bufptr, p, n);
*bufptr = (unsigned char *)((wchar_t *)*bufptr + n);
return (0);
}
} else {
char *tmpp, *tmpq;
size_t tsize;
tsize = (n + 1) * MB_LEN_MAX;
tmpp = lmalloc(tsize);
if (tmpp == NULL) {
errno = ENOMEM;
return (EOF);
}
q = p;
tmpq = tmpp;
for (len = 0, i = 0; i < n; i++) {
r = wctomb(tmpq, *q++);
if (r == -1) {
lfree(tmpp, tsize);
errno = EILSEQ;
return (EOF);
}
len += r;
tmpq += r;
}
tmpq = tmpp;
newbufptr = *bufptr + len;
if (newbufptr > bufferend) {
if (!_dowrite(tmpp, len, iop, bufptr)) {
lfree(tmpp, tsize);
return (EOF);
}
} else {
(void) memcpy(*bufptr, tmpp, len);
*bufptr = newbufptr;
}
lfree(tmpp, tsize);
return (0);
}
}
static int
pad_wide(FILE *iop, unsigned char **bufptr,
unsigned char *bufferend, const char *s, size_t n,
int sflag)
{
unsigned char *newbufptr;
ssize_t nn;
size_t len;
wchar_t ps;
if (sflag) {
ps = (wchar_t)s[0];
len = (wchar_t *)bufferend - (wchar_t *)*bufptr;
if (n > len) {
(void) wmemset((wchar_t *)*bufptr, ps, len);
iop->_ptr = bufferend;
return (EOF);
} else {
(void) wmemset((wchar_t *)*bufptr, ps, n);
*bufptr = (unsigned char *)((wchar_t *)*bufptr + n);
return (0);
}
} else {
for (nn = n; nn > PAD_LEN; nn -= PAD_LEN) {
if (!_dowrite(s, PAD_LEN, iop, bufptr))
return (EOF);
}
newbufptr = *bufptr + nn;
if (newbufptr > bufferend) {
if (!_dowrite(s, nn, iop, bufptr))
return (EOF);
} else {
(void) memcpy(*bufptr, s, nn);
*bufptr = newbufptr;
}
return (0);
}
}
#endif
ssize_t
_doprnt(const CHAR_T *format, va_list in_args, FILE *iop)
{
return (_ndoprnt(format, in_args, iop, 0));
}
ssize_t
_ndoprnt(const CHAR_T *format, va_list in_args, FILE *iop, int prflag)
{
#ifdef _WIDE
int sflag = 0;
size_t maxcount;
#else
int snflag = 0;
#endif
unsigned char *bufptr;
unsigned char *bufferend;
#ifdef _WIDE
size_t count = 0;
#else
int count = 0;
#endif
CHAR_T *bp;
CHAR_T *p;
#ifdef _WIDE
size_t bpsize;
char *cbp;
#endif
int prec = 0;
ssize_t width;
ssize_t num;
wchar_t *wp;
ssize_t wcount = 0;
char wflag;
char lflag;
int quote;
int retcode;
#ifndef _WIDE
ssize_t preco;
char tmpbuf[10];
#endif
CHAR_T fcode;
#ifndef _WIDE
ssize_t sec_display;
#endif
ssize_t lzero, rzero, rz, leadzeroes;
ssize_t flagword;
CHAR_T buf[max(MAXLLDIGS, 1034)];
CHAR_T cvtbuf[512 + DECIMAL_STRING_LENGTH];
CHAR_T *prefix;
CHAR_T prefixbuf[4];
CHAR_T *suffix;
CHAR_T expbuf[MAXESIZ + 1];
ssize_t prefixlength, suffixlength;
ssize_t otherlength;
ssize_t val;
long long ll = 0LL;
int exp;
int decpt, sign;
const CHAR_T *tab;
ssize_t k, lradix, mradix;
int inf_nan = 0;
int inf_nan_mixed_case = 0;
CHAR_T *sformat = (CHAR_T *)format;
int fpos = 1;
stva_list args,
sargs;
stva_list bargs;
stva_list arglst[MAXARGS];
int starflg = 0;
va_copy(args.ap, in_args);
sargs = args;
#ifdef _WIDE
if (iop->_flag == _IOREAD)
sflag = 1;
if (!sflag) {
#endif
if (iop->_base == 0) {
if (_findbuf(iop) == 0)
return (EOF);
if (!(iop->_flag & (_IOLBF|_IONBF)))
iop->_cnt = _bufend(iop) - iop->_base;
}
#ifdef _WIDE
}
#endif
#ifdef _WIDE
bufptr = iop->_ptr;
if (sflag) {
maxcount = (size_t)iop->_cnt;
bufferend = (unsigned char *)(((wchar_t *)iop->_ptr) +
maxcount);
} else {
bufferend = _bufend(iop);
}
#else
bufptr = iop->_ptr;
if (iop->_flag & _IOREAD) {
if (iop->_cnt == MAXINT) {
bufferend =
(unsigned char *)((long)bufptr | (-1L & ~HIBITL));
} else {
bufferend = _bufend(iop);
if (bufferend == NULL) {
snflag = 1;
}
}
} else {
bufferend = _bufend(iop);
}
#endif
for (; ; ) {
ssize_t n;
if ((fcode = *format) != '\0' && fcode != '%') {
bp = (CHAR_T *)format;
do {
format++;
} while ((fcode = *format) != '\0' && fcode != '%');
count += (n = format - bp);
PUT(bp, n);
}
if (fcode == '\0') {
ssize_t nn = bufptr - iop->_ptr;
#ifdef _WIDE
if (sflag) {
iop->_ptr = bufptr;
return ((ssize_t)count);
}
#endif
iop->_cnt -= nn;
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+iop->_cnt), \
'\n', -iop->_cnt) != NULL))
(void) _xflsbuf(iop);
#ifdef _WIDE
return (FERROR(iop) ? EOF : (ssize_t)count);
#else
return (FERROR(iop) ? EOF : (int)count);
#endif
}
width = prefixlength = otherlength = 0;
flagword = suffixlength = 0;
format++;
wflag = 0;
lflag = 0;
quote = 0;
#ifndef _WIDE
sec_display = 0;
#endif
charswitch:
switch (fcode = *format++) {
case '+':
flagword |= FPLUS;
goto charswitch;
case '-':
flagword |= FMINUS;
flagword &= ~PADZERO;
goto charswitch;
case ' ':
flagword |= FBLANK;
goto charswitch;
case '\'':
quote++;
goto charswitch;
case '#':
flagword |= FSHARP;
goto charswitch;
case '.':
flagword |= DOTSEEN;
prec = 0;
goto charswitch;
case '*':
if (_M_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;
flagword ^= DOTSEEN;
}
}
goto charswitch;
case '$':
{
ssize_t position;
stva_list targs;
if (fpos) {
_mkarglst(sformat, sargs, arglst, prflag);
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, prflag);
}
if (!starflg)
args = targs;
else {
starflg = 0;
args = bargs;
if (flagword & DOTSEEN) {
prec = va_arg(targs.ap, int);
if (prec < 0) {
prec = 0;
flagword ^= DOTSEEN;
}
} else {
width = va_arg(targs.ap, int);
if (width < 0) {
width = -width;
flagword |= FMINUS;
}
}
}
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':
num = fcode - '0';
while (_M_ISDIGIT(fcode = *format)) {
num = num * 10 + fcode - '0';
format++;
}
if (flagword & DOTSEEN)
prec = num;
else
width = num;
goto charswitch;
case 'l':
if (!(flagword & XLONG)) {
if (lflag) {
flagword &= ~LENGTH;
flagword |= XLONG;
} else {
flagword |= LENGTH;
}
}
lflag++;
goto charswitch;
case 'L':
flagword |= QUAD;
goto charswitch;
case 'h':
if (!(flagword & CHAR)) {
if (flagword & SHORT) {
flagword &= ~SHORT;
flagword |= CHAR;
} else {
flagword |= SHORT;
}
}
goto charswitch;
case 'j':
#ifndef _LP64
if (!(prflag & _F_INTMAX32)) {
#endif
flagword |= XLONG;
#ifndef _LP64
}
#endif
goto charswitch;
case 't':
if (!(flagword & XLONG)) {
flagword |= LENGTH;
}
goto charswitch;
case 'z':
if (!(flagword & XLONG)) {
flagword |= LENGTH;
}
goto charswitch;
case 'i':
case 'd':
if ((flagword & PADZERO) && (flagword & DOTSEEN))
flagword &= ~PADZERO;
p = bp = buf + MAXLLDIGS;
if (flagword & XLONG) {
ll = va_arg(args.ap, long long);
if (ll < 0) {
prefix = _P_HYPHEN;
prefixlength = 1;
if (ll != HIBITLL)
ll = -ll;
else
*--bp = _lowlldigit(&ll);
} else if (flagword & FPLUS) {
prefix = _P_PLUS;
prefixlength = 1;
} else if (flagword & FBLANK) {
prefix = _P_BLANK;
prefixlength = 1;
}
} else {
if (flagword & LENGTH)
val = va_arg(args.ap, long);
else
val = va_arg(args.ap, int);
if (flagword & SHORT)
val = (short)val;
else if (flagword & CHAR)
val = (char)val;
if (val < 0) {
prefix = _P_HYPHEN;
prefixlength = 1;
if (val != HIBITL)
val = -val;
else
*--bp = _lowdigit(&val);
} else if (flagword & FPLUS) {
prefix = _P_PLUS;
prefixlength = 1;
} else if (flagword & FBLANK) {
prefix = _P_BLANK;
prefixlength = 1;
}
}
decimal:
{
long qval = val;
long long lll = ll;
long long tll;
if (flagword & XLONG) {
if (lll < 10LL) {
if (lll != 0LL || !(flagword & DOTSEEN))
*--bp = (CHAR_T)lll + L('0');
} else {
do {
tll = lll;
lll /= 10;
*--bp = (CHAR_T)
(tll - lll * 10 + '0');
} while (lll >= 10);
*--bp = (CHAR_T)lll + '0';
}
} else {
if (qval <= 9) {
if (qval != 0 || !(flagword & DOTSEEN))
*--bp = (CHAR_T)qval + '0';
} else {
do {
n = qval;
qval /= 10;
*--bp = (CHAR_T) \
(n - qval * 10 + '0');
} while (qval > 9);
*--bp = (CHAR_T)qval + '0';
}
}
}
if (quote) {
p = insert_thousands_sep(bp, p);
}
if (flagword & DOTSEEN) {
leadzeroes = prec - (p - bp);
if (leadzeroes > 0) {
otherlength = lzero = leadzeroes;
flagword |= LZERO;
}
}
break;
case 'u':
if ((flagword & PADZERO) && (flagword & DOTSEEN))
flagword &= ~PADZERO;
p = bp = buf + MAXLLDIGS;
if (flagword & XLONG) {
ll = va_arg(args.ap, long long);
if (ll & HIBITLL)
*--bp = _lowlldigit(&ll);
} else {
if (flagword & LENGTH)
val = va_arg(args.ap, long);
else
val = va_arg(args.ap, unsigned);
if (flagword & SHORT)
val = (unsigned short)val;
else if (flagword & CHAR)
val = (unsigned char)val;
if (val & HIBITL)
*--bp = _lowdigit(&val);
}
goto decimal;
case 'o':
mradix = 7;
lradix = 2;
if ((flagword & DOTSEEN) && (flagword & FSHARP) &&
prec == 0)
prec = 1;
goto fixed;
case 'p':
flagword &= ~(XLONG | SHORT);
flagword |= LENGTH;
case 'X':
case 'x':
mradix = 15;
lradix = 3;
fixed:
if ((flagword & PADZERO) && (flagword & DOTSEEN))
flagword &= ~PADZERO;
tab = (fcode == 'X') ? uc_digs : lc_digs;
if (flagword & XLONG) {
ll = va_arg(args.ap, long long);
} else {
if (flagword & LENGTH)
val = va_arg(args.ap, long);
else
val = va_arg(args.ap, unsigned);
if (flagword & SHORT)
val = (unsigned short) val;
else if (flagword & CHAR)
val = (unsigned char) val;
}
p = bp = buf + MAXLLDIGS;
if (flagword & XLONG) {
long long lll = ll;
if (lll == 0LL) {
if (!(flagword & DOTSEEN)) {
otherlength = lzero = 1;
flagword |= LZERO;
}
} else do {
*--bp = tab[(ssize_t)(lll & mradix)];
lll = ((lll >> 1) & ~HIBITLL) \
>> lradix;
} while (lll != 0LL);
} else {
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) {
leadzeroes = prec - (p - bp);
if (leadzeroes > 0) {
otherlength = lzero = leadzeroes;
flagword |= LZERO;
}
}
if ((flagword & FSHARP) &&
(((flagword & XLONG) == 0 && val != 0) ||
((flagword & XLONG) == XLONG && ll != 0)))
switch (fcode) {
case 'o':
if (!(flagword & LZERO)) {
otherlength = lzero = 1;
flagword |= LZERO;
}
break;
case 'x':
prefix = _P_ZEROx;
prefixlength = 2;
break;
case 'X':
prefix = _P_ZEROX;
prefixlength = 2;
break;
}
break;
case 'A':
case 'a':
if (flagword & QUAD) {
long double qval = GETQVAL(args.ap);
if (!(flagword & DOTSEEN))
#if defined(__sparc)
prec = HEXFP_QUAD_DIG - 1;
#elif defined(__i386) || defined(__amd64)
prec = HEXFP_EXTENDED_DIG - 1;
#else
#error Unknown architecture
#endif
FPCONV(__qaconvert, &qval,
min(prec + 1, MAXECVT), &exp, &sign,
cvtbuf);
} else {
double dval = va_arg(args.ap, double);
if (!(flagword & DOTSEEN))
prec = HEXFP_DOUBLE_DIG - 1;
FPCONV(__aconvert, dval,
min(prec + 1, MAXECVT), &exp, &sign,
cvtbuf);
}
bp = cvtbuf;
if (!isxdigit((unsigned char)*bp)) {
inf_nan = 1;
break;
}
p = prefix = prefixbuf;
if (sign) {
*p++ = '-';
prefixlength = 1;
} else if (flagword & FPLUS) {
*p++ = '+';
prefixlength = 1;
} else if (flagword & FBLANK) {
*p++ = ' ';
prefixlength = 1;
}
*p++ = '0';
*p++ = (fcode == 'A') ? 'X' : 'x';
*p = '\0';
prefixlength += 2;
p = &buf[0];
*p++ = (*bp != '\0') ? *bp++ : '0';
if (prec != 0 || (flagword & FSHARP))
p = insert_decimal_point(p);
rz = prec;
if (fcode == 'A') {
for (; rz > 0 && *bp != '\0'; --rz) {
*p++ = ('a' <= *bp && *bp <= 'f')?
*bp - 32 : *bp;
bp++;
}
} else {
for (; rz > 0 && *bp != '\0'; --rz)
*p++ = *bp++;
}
if (rz > 0) {
otherlength = rzero = rz;
flagword |= RZERO;
}
bp = &buf[0];
suffix = &expbuf[MAXESIZ];
*suffix = '\0';
if (buf[0] != '0') {
int nn;
nn = exp;
if (nn < 0)
nn = -nn;
for (; nn > 9; nn /= 10)
*--suffix = todigit(nn % 10);
*--suffix = todigit(nn);
*--suffix = (exp >= 0) ? '+' : '-';
} else {
*--suffix = '0';
*--suffix = '+';
}
*--suffix = (fcode == 'A') ? 'P' : 'p';
suffixlength = &expbuf[MAXESIZ] - suffix;
otherlength += suffixlength;
flagword |= SUFFIX;
break;
case 'E':
case 'e':
if (!(flagword & DOTSEEN))
prec = 6;
if (flagword & QUAD) {
long double qval = GETQVAL(args.ap);
FPCONV(qeconvert, &qval,
min(prec + 1, MAXECVT), &decpt, &sign,
cvtbuf);
} else {
double dval = va_arg(args.ap, double);
FPCONV(econvert, dval,
min(prec + 1, MAXECVT), &decpt, &sign,
cvtbuf);
}
bp = cvtbuf;
if (*bp > '9') {
inf_nan = 1;
inf_nan_mixed_case = (__xpg6 &
_C99SUSv3_mixed_case_Inf_and_NaN);
break;
}
e_merge:
if (sign) {
prefix = _P_HYPHEN;
prefixlength = 1;
} else if (flagword & FPLUS) {
prefix = _P_PLUS;
prefixlength = 1;
} else if (flagword & FBLANK) {
prefix = _P_BLANK;
prefixlength = 1;
}
p = &buf[0];
*p++ = (*bp != '\0') ? *bp++ : '0';
if (prec != 0 || (flagword & FSHARP))
p = insert_decimal_point(p);
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 (buf[0] != '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 || buf[0] == '0') ? '+' : '-';
*--suffix = _M_ISUPPER(fcode) ? 'E' : 'e';
otherlength += (suffixlength = &expbuf[MAXESIZ] \
- suffix);
flagword |= SUFFIX;
break;
case 'F':
case 'f':
if (!(flagword & DOTSEEN))
prec = 6;
if (flagword & QUAD) {
long double qval = GETQVAL(args.ap);
FPCONV(qfconvert, &qval, min(prec, MAXFCVT),
&decpt, &sign, cvtbuf);
bp = cvtbuf;
if (*bp == 0) {
FPCONV(qeconvert, &qval,
min(prec + 1, MAXECVT), &decpt,
&sign, cvtbuf);
goto e_merge;
}
} else {
double dval = va_arg(args.ap, double);
FPCONV(fconvert, dval, min(prec, MAXFCVT),
&decpt, &sign, cvtbuf);
}
bp = cvtbuf;
if (*bp > '9') {
inf_nan = 1;
if (fcode == 'f')
inf_nan_mixed_case = (__xpg6 &
_C99SUSv3_mixed_case_Inf_and_NaN);
break;
}
f_merge:
if (sign) {
prefix = _P_HYPHEN;
prefixlength = 1;
} else if (flagword & FPLUS) {
prefix = _P_PLUS;
prefixlength = 1;
} else if (flagword & FBLANK) {
prefix = _P_BLANK;
prefixlength = 1;
}
p = &buf[0];
{
ssize_t nn = decpt;
k = 0;
do {
*p++ = (nn <= 0 || *bp == '\0' || \
k >= MAXFSIG) ? '0' : (k++, *bp++);
} while (--nn > 0);
if (quote)
p = insert_thousands_sep(buf, p);
if (prec > 0 || (flagword & FSHARP))
p = insert_decimal_point(p);
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;
if (flagword & QUAD) {
long double qval = GETQVAL(args.ap);
FPCONV(qeconvert, &qval, min(prec, MAXECVT),
&decpt, &sign, cvtbuf);
} else {
double dval = va_arg(args.ap, double);
FPCONV(econvert, dval, min(prec, MAXECVT),
&decpt, &sign, cvtbuf);
}
bp = cvtbuf;
if (*bp > '9') {
inf_nan = 1;
inf_nan_mixed_case = (__xpg6 &
_C99SUSv3_mixed_case_Inf_and_NaN);
break;
}
if (*bp == '0')
decpt = 1;
{
int kk = prec;
if (!(flagword & FSHARP)) {
n = STRLEN(bp);
if (n < kk)
kk = (int)n;
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] = fcode;
goto c_merge;
#ifndef _WIDE
case 'w':
wflag = 1;
goto charswitch;
#endif
case 'C':
wide_C:
{
wchar_t temp;
temp = va_arg(args.ap, wchar_t);
if (temp) {
#ifdef _WIDE
retcode = 1;
buf[0] = temp;
#else
retcode = wctomb(buf, temp);
if (retcode == -1) {
errno = EILSEQ;
return (EOF);
}
#endif
p = (bp = buf) + retcode;
} else {
buf[0] = 0;
p = (bp = buf) + 1;
}
wcount = p - bp;
#ifdef _WIDE
wflag = 1;
#endif
}
break;
case 'c':
if (lflag) {
goto wide_C;
}
#ifndef _WIDE
if (wflag) {
wchar_t temp;
temp = va_arg(args.ap, wchar_t);
if (temp) {
retcode = wctomb(buf, temp);
if (retcode == -1) {
p = (bp = buf) + 1;
} else {
p = (bp = buf) + retcode;
}
} else {
buf[0] = 0;
p = (bp = buf) + 1;
}
wcount = p - bp;
} else {
#endif
if (flagword & XLONG) {
long long temp;
temp = va_arg(args.ap, long long);
buf[0] = (CHAR_T)temp;
} else
buf[0] = va_arg(args.ap, int);
c_merge:
p = (bp = &buf[0]) + 1;
#ifdef _WIDE
wcount = 1;
wflag = 1;
#endif
#ifndef _WIDE
}
#endif
break;
case 'S':
wide_S:
#ifdef _WIDE
if (!lflag) {
lflag++;
}
#else
if (!wflag)
wflag++;
#endif
bp = va_arg(args.ap, CHAR_T *);
if (bp == NULL)
bp = (CHAR_T *)widenullstr;
if (!(flagword & DOTSEEN)) {
prec = MAXINT;
}
wp = (wchar_t *)(uintptr_t)bp;
wcount = 0;
while (*wp) {
int nbytes;
#ifdef _WIDE
nbytes = 1;
#else
nbytes = wctomb(tmpbuf, *wp);
if (nbytes < 0) {
errno = EILSEQ;
return (EOF);
}
#endif
if ((prec - (wcount + nbytes)) >= 0) {
wcount += nbytes;
wp++;
} else {
break;
}
}
#ifndef _WIDE
sec_display = wcount;
#else
wflag = 1;
#endif
p = (CHAR_T *)wp;
break;
case 's':
if (lflag) {
goto wide_S;
}
#ifdef _WIDE
cbp = va_arg(args.ap, char *);
if (cbp == NULL)
cbp = (char *)nullstr;
if (!(flagword & DOTSEEN)) {
size_t nwc;
wchar_t *wstr;
nwc = mbstowcs(NULL, cbp, 0);
if (nwc == (size_t)-1) {
errno = EILSEQ;
return (EOF);
}
bpsize = sizeof (wchar_t) * (nwc + 1);
wstr = (wchar_t *)lmalloc(bpsize);
if (wstr == NULL) {
errno = EILSEQ;
return (EOF);
}
nwc = mbstowcs(wstr, cbp, MAXINT);
wcount = nwc;
bp = wstr;
p = wstr + nwc;
} else {
size_t nwc;
wchar_t *wstr;
nwc = mbstowcs(NULL, cbp, 0);
if (nwc == (size_t)-1) {
errno = EILSEQ;
return (EOF);
}
if (prec > nwc) {
bpsize = sizeof (wchar_t) * nwc;
wstr = (wchar_t *)lmalloc(bpsize);
if (wstr == NULL) {
errno = ENOMEM;
return (EOF);
}
nwc = mbstowcs(wstr, cbp, nwc);
wcount = nwc;
bp = wstr;
p = wstr + nwc;
} else {
wchar_t *wstr;
bpsize = sizeof (wchar_t) * prec;
wstr = (wchar_t *)lmalloc(bpsize);
if (wstr == NULL) {
errno = ENOMEM;
return (EOF);
}
nwc = mbstowcs(wstr, cbp, prec);
wcount = prec;
bp = wstr;
p = wstr + nwc;
}
}
wflag = 1;
#else
bp = va_arg(args.ap, char *);
if (bp == NULL)
bp = (char *)nullstr;
if (!(flagword & DOTSEEN)) {
if (wflag) {
prec = MAXINT;
goto wide_hand;
}
p = bp + strlen(bp);
if (width > 0 && __xpg4 == 0 &&
MB_CUR_MAX > 1) {
#define NW 256
wchar_t wbuff[NW];
wchar_t *wp, *wptr;
size_t wpsize;
size_t nwc;
wp = NULL;
if ((nwc = mbstowcs(wbuff, bp,
NW)) == (size_t)-1) {
sec_display = strlen(bp);
goto mbs_err;
}
if (nwc < NW) {
wptr = wbuff;
} else {
if ((nwc =
mbstowcs(NULL, bp, 0)) ==
(size_t)-1) {
sec_display =
strlen(bp);
goto mbs_err;
}
wpsize = (nwc + 1) *
sizeof (wchar_t);
if ((wp = lmalloc(wpsize))
== NULL) {
errno = ENOMEM;
return (EOF);
}
if ((nwc = mbstowcs(wp,
bp, nwc)) == (size_t)-1) {
sec_display = \
strlen(bp);
goto mbs_err;
}
wptr = wp;
}
sec_display = wcswidth(wptr, nwc);
if (sec_display == -1) {
sec_display =
_rec_scrswidth(wptr, nwc);
}
mbs_err:
if (wp)
lfree(wp, wpsize);
}
} else {
if (prec == 0) {
p = bp;
break;
}
if (wflag) {
wide_hand:
wp = (wchar_t *)(uintptr_t)bp;
preco = prec;
wcount = 0;
while (*wp &&
(prec -= _scrwidth(*wp)) >= 0) {
if ((retcode =
wctomb(tmpbuf, *wp)) < 0)
wcount++;
else
wcount += retcode;
wp++;
}
if (*wp)
prec += _scrwidth(*wp);
p = (char *)wp;
sec_display = preco - prec;
} else if (__xpg4 == 0 && MB_CUR_MAX > 1) {
char *qp = bp;
int ncol, nbytes;
wchar_t wc;
ncol = 0;
preco = prec;
while (*qp) {
if (isascii(*qp)) {
qp++;
if (--prec == 0)
break;
continue;
}
if ((nbytes = mbtowc(&wc, qp,
MB_LEN_MAX)) == -1) {
nbytes = 1;
ncol = 1;
} else {
ncol = _scrwidth(wc);
if (ncol == 0) {
ncol = 1;
}
}
if ((prec -= ncol) >= 0) {
qp += nbytes;
if (prec == 0)
break;
} else {
break;
}
}
if (prec < 0)
prec += ncol;
p = qp;
sec_display = preco - prec;
} else {
char *qp;
qp = memchr(bp, '\0', prec);
if (qp == NULL) {
p = bp + prec;
} else {
p = qp;
}
}
}
#endif
break;
case 'n':
{
if (flagword & XLONG) {
long long *svcount;
svcount = va_arg(args.ap, long long *);
*svcount = (long long)count;
} else if (flagword & LENGTH) {
long *svcount;
svcount = va_arg(args.ap, long *);
*svcount = (long)count;
} else if (flagword & SHORT) {
short *svcount;
svcount = va_arg(args.ap, short *);
*svcount = (short)count;
} else if (flagword & CHAR) {
char *svcount;
svcount = va_arg(args.ap, char *);
*svcount = (char)count;
} else {
int *svcount;
svcount = va_arg(args.ap, int *);
*svcount = count;
}
continue;
}
default:
format--;
continue;
}
if (inf_nan) {
if (inf_nan_mixed_case) {
for (p = bp + 1; *p != '\0'; p++)
;
} else {
int upper;
upper = _M_ISUPPER(fcode);
for (p = bp; *p != '\0'; p++)
*p = upper? toupper(*p) : tolower(*p);
}
if (sign) {
prefix = _P_HYPHEN;
prefixlength = 1;
} else if (flagword & FPLUS) {
prefix = _P_PLUS;
prefixlength = 1;
} else if (flagword & FBLANK) {
prefix = _P_BLANK;
prefixlength = 1;
}
inf_nan = 0;
inf_nan_mixed_case = 0;
flagword &= ~PADZERO;
}
n = p - bp;
#ifndef _WIDE
if (sec_display)
k = sec_display;
else
#endif
{
k = n;
}
k += prefixlength + otherlength;
if (wflag)
count += wcount;
else
count += n;
count += prefixlength + otherlength;
if (width > k) {
count += (width - k);
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 ((flagword & LZERO))
PAD(_zeroes, lzero);
#ifndef _WIDE
if ((fcode == 's' || fcode == 'S') && wflag) {
wchar_t *wp = (wchar_t *)(uintptr_t)bp;
int cnt;
char *bufp;
long printn;
printn = (wchar_t *)(uintptr_t)p -
(wchar_t *)(uintptr_t)bp;
bufp = buf;
while (printn > 0) {
if ((cnt = wctomb(buf, *wp)) < 0)
cnt = 1;
PUT(bufp, cnt);
wp++;
printn--;
}
} else {
#endif
if (n > 0)
PUT(bp, n);
#ifdef _WIDE
if ((fcode == 's') && !lflag) {
if (bp)
lfree(bp, bpsize);
}
#else
}
#endif
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);
}
}
}
#ifdef _WIDE
static int
_watoi(wchar_t *fmt)
{
int n = 0;
wchar_t ch;
ch = *fmt;
if (_M_ISDIGIT(ch)) {
n = ch - '0';
ch = *++fmt;
while (_M_ISDIGIT(ch)) {
n *= 10;
n += ch - '0';
ch = *++fmt;
}
}
return (n);
}
#endif
#define FLAG_LONG 0x01
#define FLAG_INT 0x02
#define FLAG_LONG_LONG 0x04
#define FLAG_LONG_DBL 0x08
static void
_mkarglst(CHAR_T *fmt, stva_list args, stva_list arglst[], int prflag __unused)
{
enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR,
LONG_PTR, INT_PTR, LONG_LONG, LONG_LONG_PTR};
enum types typelst[MAXARGS], curtype;
ssize_t n;
int maxnum, curargno, flags;
(void) memset((void *) typelst, 0, sizeof (typelst));
maxnum = -1;
curargno = 0;
while ((fmt = STRCHR(fmt, '%')) != 0) {
fmt++;
if (fmt[n = STRSPN(fmt, digits)] == '$') {
curargno = ATOI(fmt) - 1;
if (curargno < 0)
continue;
fmt += n + 1;
}
flags = 0;
again:;
fmt += STRSPN(fmt, skips);
switch (*fmt++) {
case '%':
continue;
case 'l':
if (flags & (FLAG_LONG | FLAG_LONG_LONG)) {
flags |= FLAG_LONG_LONG;
flags &= ~FLAG_LONG;
} else {
flags |= FLAG_LONG;
}
goto again;
case 'j':
#ifndef _LP64
if (!(prflag & _F_INTMAX32)) {
#endif
flags |= FLAG_LONG_LONG;
#ifndef _LP64
}
#endif
goto again;
case 't':
flags |= FLAG_LONG;
goto again;
case 'z':
flags |= FLAG_LONG;
goto again;
case 'L':
flags |= FLAG_LONG_DBL;
goto again;
case '*':
if (_M_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 |= FLAG_INT;
curtype = INT;
break;
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
if (flags & FLAG_LONG_DBL)
curtype = LONG_DOUBLE;
else
curtype = DOUBLE;
break;
case 's':
curtype = CHAR_PTR;
break;
case 'p':
curtype = VOID_PTR;
break;
case 'n':
if (flags & FLAG_LONG_LONG)
curtype = LONG_LONG_PTR;
else if (flags & FLAG_LONG)
curtype = LONG_PTR;
else
curtype = INT_PTR;
break;
default:
if (flags & FLAG_LONG_LONG)
curtype = LONG_LONG;
else if (flags & FLAG_LONG)
curtype = LONG;
else
curtype = INT;
break;
}
if (curargno >= 0 && curargno < MAXARGS) {
typelst[curargno] = curtype;
if (maxnum < curargno)
maxnum = curargno;
}
curargno++;
if (flags & FLAG_INT)
{
flags ^= FLAG_INT;
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) GETQVAL(args.ap);
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;
case LONG_LONG:
(void) va_arg(args.ap, long long);
break;
case LONG_LONG_PTR:
(void) va_arg(args.ap, long long *);
break;
}
}
}
#ifdef _WIDE
static
#endif
void
_getarg(CHAR_T *fmt, stva_list *pargs, long argno, int prflag __unused)
{
CHAR_T *sfmt = fmt;
ssize_t n;
int i, curargno, flags;
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':
if (flags & (FLAG_LONG | FLAG_LONG_LONG)) {
flags |= FLAG_LONG_LONG;
flags &= ~FLAG_LONG;
} else {
flags |= FLAG_LONG;
}
goto again;
case 'j':
#ifndef _LP64
if (!(prflag & _F_INTMAX32)) {
#endif
flags |= FLAG_LONG_LONG;
#ifndef _LP64
}
#endif
goto again;
case 't':
flags |= FLAG_LONG;
goto again;
case 'z':
flags |= FLAG_LONG;
goto again;
case 'L':
flags |= FLAG_LONG_DBL;
goto again;
case '*':
if (_M_ISDIGIT(*fmt)) {
fmt += STRSPN(fmt, digits);
if (*fmt == '$')
fmt++;
goto again;
}
flags |= FLAG_INT;
(void) va_arg((*pargs).ap, int);
break;
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
if (flags & FLAG_LONG_DBL)
(void) GETQVAL((*pargs).ap);
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 & FLAG_LONG_LONG)
(void) va_arg((*pargs).ap, long long *);
else if (flags & FLAG_LONG)
(void) va_arg((*pargs).ap, long *);
else
(void) va_arg((*pargs).ap, int *);
break;
default:
if (flags & FLAG_LONG_LONG)
(void) va_arg((*pargs).ap, long long);
else if (flags & FLAG_LONG)
(void) va_arg((*pargs).ap, long int);
else
(void) va_arg((*pargs).ap, int);
break;
}
i++;
curargno++;
if (flags & FLAG_INT)
{
flags ^= FLAG_INT;
goto again;
}
}
if (!found && i != argno) {
(void) va_arg((*pargs).ap, int);
i++;
curargno = i;
found = 1;
}
}
}
static CHAR_T *
insert_thousands_sep(CHAR_T *bp, CHAR_T *ep)
{
char thousep;
struct lconv *locptr;
ssize_t buf_index;
int i;
CHAR_T *obp = bp;
CHAR_T buf[371];
CHAR_T *bufptr = buf;
char *grp_ptr;
locptr = localeconv();
thousep = *locptr->thousands_sep;
grp_ptr = locptr->grouping;
if (!thousep || (*grp_ptr == '\0'))
return (ep);
buf_index = ep - bp;
for (;;) {
if (*grp_ptr == CHAR_MAX) {
for (i = 0; i < buf_index--; i++)
*bufptr++ = *(bp + buf_index);
break;
}
for (i = 0; i < *grp_ptr && buf_index-- > 0; i++)
*bufptr++ = *(bp + buf_index);
if (buf_index > 0) {
*bufptr++ = (CHAR_T)thousep;
ep++;
}
else
break;
if (*(grp_ptr + 1) != '\0')
++grp_ptr;
}
--bufptr;
while (buf <= bufptr)
*obp++ = *bufptr--;
return (ep);
}
static CHAR_T *
insert_decimal_point(CHAR_T *ep)
{
struct lconv *locptr = localeconv();
char *dp = locptr->decimal_point;
#ifdef _WIDE
wchar_t wdp;
(void) mbtowc(&wdp, dp, MB_CUR_MAX);
*ep = wdp;
return (ep + 1);
#else
(void) memcpy(ep, dp, strlen(dp));
return (ep + strlen(dp));
#endif
}
static int
_rec_scrswidth(wchar_t *wp, ssize_t n)
{
int col;
int i;
col = 0;
while (*wp && (n-- > 0)) {
if ((i = _scrwidth(*wp++)) == 0)
i = 1;
col += i;
}
return (col);
}