/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* Phong Vo <kpv@research.att.com> *
* *
***********************************************************************/
#include "sfhdr.h"
/* The engine for formatting data.
** 1. Argument positioning is done in sftable.c so any changes
** made here should be reflected in sftable.c as well.
** 2. For internationalization, Sfio only supports I/O of multibyte strings.
** However, this code does provide minimal support so that Stdio functions
**
** Written by Kiem-Phong Vo.
*/
#if _PACKAGE_ast
#include <ccode.h>
#else
/* characters when using ebcdic or ascii */
#if _chr_ebcdic
#else
#endif /* _chr_ebcdic */
#endif /* _PACKAGE_ast */
#if __STD_C
#else
char* buf;
int v;
#endif
{
if(isprint(v) && v != '\\')
{ *buf++ = v;
return 1;
}
else
{ *buf++ = '\\';
switch(v)
return 4;
}
}
}
/* On some platform(s), large functions are not compilable.
** In such a case, the below macro should be defined non-zero so that
** some in-lined macros will be made smaller, trading time for space.
*/
#if !defined(_sffmt_small) && defined(_UTS)
#endif
#if __STD_C
#else
Sfio_t* f; /* file to print to */
char* form; /* format to use */
#endif
{
#if _PACKAGE_ast
int scale;
#endif
#if _has_multibyte
#ifdef mbwidth
char* osp;
#endif
#endif
/* local io system */
int o, n_output;
}
}
}
#if _sffmt_small /* these macros are made smaller at some performance cost */
#define SFBUF(f)
#define SFEND(f)
#else
}
}
}
#endif /* _sffmt_small */
SFMTXDECL(f);
SFCVINIT(); /* initialize conversion tables */
SFMTXENTER(f,-1);
if(!form)
SFMTXRETURN(f, -1);
/* make sure stream is in write mode and buffer is not NULL */
SFMTXRETURN(f, -1);
SFLOCK(f,0);
}
SFINIT(f);
argn = -1;
loop_fmt :
while((n = *form) )
{ if(n != '%') /* collect the non-pattern chars */
do
{ n = 1;
}
continue;
}
else form += 1;
flags = 0;
#if _PACKAGE_ast
scale = 0;
#endif
loop_flags: /* LOOP FOR \0, %, FLAGS, WIDTH, PRECISION, BASE, TYPE */
{
case '\0':
SFputc(f,'%');
goto pop_fmt;
case '%' :
SFputc(f,'%');
continue;
case LEFTP : /* get the type enclosed in balanced parens */
for(v = 1;;)
{ switch(*form++)
{
case 0 : /* not balancable, retract */
n_str = 0;
goto loop_flags;
case LEFTP : /* increasing nested level */
v += 1;
continue;
case RIGHTP : /* decreasing nested level */
if((v -= 1) != 0)
continue;
if(*t_str != '*' )
else
if(*t_str == '$')
{ if(!fp &&
goto pop_fmt;
}
if(fp)
}
LEFTP, 0, 0, 0,0,0,
NIL(char*),0);
if(n < 0)
goto pop_fmt;
goto t_arg;
}
else
{ t_arg:
}
}
goto loop_flags;
}
}
case '-' :
if(dot == 1)
{ dot = 0;
precis = -1;
flags |= SFFMT_CHOP;
}
else
goto loop_flags;
case '0' :
flags |= SFFMT_ZERO;
goto loop_flags;
case ' ' :
if(!(flags&SFFMT_SIGN) )
flags |= SFFMT_BLANK;
goto loop_flags;
case '+' :
goto loop_flags;
case '=' :
goto loop_flags;
case '#' :
flags |= SFFMT_ALTER;
goto loop_flags;
case QUOTE:
if(thousand > 0)
flags |= SFFMT_THOUSAND;
goto loop_flags;
case ',':
if(thousand < 0)
flags |= SFFMT_THOUSAND;
goto loop_flags;
case '.':
dot += 1;
if(dot == 1)
{ /* so base can be defined without setting precis */
precis = 0;
}
else if(dot == 2)
{ base = 0; /* for %s,%c */
if(v == 'c' || v == 'C' || v == 's' || v == 'S')
goto loop_flags;
if(v == 'c' || v == 'C' || v == 's' || v == 'S')
{ if(*form == '*')
goto do_star;
else
goto loop_flags;
}
}
}
}
goto dot_size;
}
else if(*form != '*')
goto loop_flags;
case '*' :
if(*form == '$')
{ form += 1;
goto pop_fmt;
}
if(fp)
goto pop_fmt;
v = argv.i;
}
goto dot_set;
case '1' : case '2' : case '3' :
case '4' : case '5' : case '6' :
case '7' : case '8' : case '9' :
dot_size :
if(*form == '$')
{ form += 1;
goto pop_fmt;
argp = v-1;
goto loop_flags;
}
dot_set :
if(dot == 0)
{ if((width = v) < 0)
}
}
else if(dot == 1)
precis = v;
else if(dot == 2)
base = v;
goto loop_flags;
/* 2012-06-27 I* will be deprecated and POSIX will probably settle on one of L* or z* */
case 'L' : /* long double or L* sizeof object length */
case 'z' : /* ssize_t or z* sizeof object length */
case 'I' : /* object length */
if(*form == '*')
if(*form == '$')
{ form += 1;
if(!fp &&
goto pop_fmt;
}
if(fp) /* use position list */
NIL(char*), 0);
goto pop_fmt;
}
}
else if (fmt == 'L')
else if (fmt == 'z')
}
goto loop_flags;
case 'l' :
if(*form == 'l')
{ form += 1;
flags |= SFFMT_LLONG;
}
else flags |= SFFMT_LONG;
goto loop_flags;
case 'h' :
if(*form == 'h')
{ form += 1;
flags |= SFFMT_SSHORT;
}
else flags |= SFFMT_SHORT;
goto loop_flags;
case 'j' :
goto loop_flags;
case 't' :
goto loop_flags;
default:
break;
}
/* set object size for scalars */
if(flags & SFFMT_TYPES)
{ if(flags&SFFMT_LONG)
size = sizeof(long);
else if(flags&SFFMT_SHORT)
size = sizeof(short);
else if(flags&SFFMT_SSHORT)
size = sizeof(char);
else if(flags&SFFMT_TFLAG)
else if(flags&SFFMT_ZFLAG)
else if(flags&SFFMT_IFLAG)
{ if(size <= 0 ||
}
else if(size < 0)
size = sizeof(int);
}
{ if(flags&SFFMT_LDOUBLE)
size = sizeof(Sfdouble_t);
size = sizeof(double);
else if(flags&SFFMT_IFLAG)
{ if(size <= 0)
size = sizeof(Sfdouble_t);
}
else if(size < 0)
size = sizeof(float);
}
{
#if _has_multibyte
sizeof(wchar_t) : sizeof(int);
} else
#endif
if(size < 0)
size = sizeof(int);
}
}
if(fp)
}
if(v < 0) /* no further processing */
goto pop_fmt;
else if(v > 0) /* extf output v bytes */
{ n_output += v;
continue;
}
else /* extf did not output */
goto arg_list;
{ if(size == sizeof(short))
}
else if(size == sizeof(char))
}
}
{ if(size == sizeof(float) )
}
{ if(base < 0)
}
}
}
else
{ arg_list:
{ case SFFMT_INT:
case SFFMT_UINT:
#if !_ast_intmax_long
else
#endif
if(size == sizeof(long) )
break;
case SFFMT_FLOAT:
#if !_ast_fltmax_double
if(size == sizeof(Sfdouble_t))
else
#endif
break;
case SFFMT_POINTER:
break;
case SFFMT_CHAR:
if(base >= 0)
#if _has_multibyte
}
#endif
break;
default: /* unknown pattern */
break;
}
}
switch(fmt) /* PRINTF DIRECTIVES */
{
default : /* unknown directive */
form -= 1;
argn -= 1;
continue;
case '!' : /* stacking a new environment */
if(!fp)
else goto pop_fmt;
goto pop_fmt;
continue;
}
else /* stack a new environment */
goto done;
argn = -1;
}
}
continue;
case 'S':
case 's':
#if _has_multibyte && defined(mbwidth)
#endif
if(base >= 0) /* list of strings */
continue;
}
else
{ sp = "(null)";
flags &= ~SFFMT_LONG;
}
#if _PACKAGE_ast
if(scale)
flags &= ~SFFMT_LONG;
}
#endif
}
{ /* v: number of bytes w: print width of those v bytes */
#if _has_multibyte
if(flags & SFFMT_LONG)
{ v = 0;
#ifdef mbwidth
w = 0;
#endif
break;
break;
#ifdef mbwidth
if(wc)
break;
w += n_w;
}
else
#endif
break;
v += n_s;
}
#ifdef mbwidth
if(!wc)
w = v;
#endif
}
#ifdef mbwidth
else if (wc)
{ w = 0;
for(;;)
break;
break;
w += n_w;
}
}
#endif
else
#endif
{ if((v = size) < 0)
v = precis;
w = v;
}
{ if(flags&SFFMT_CENTER)
{ n -= (k = n/2);
SFnputc(f, ' ', k);
}
else
{ SFnputc(f, ' ', n);
n = 0;
}
}
{
#if _has_multibyte
if(flags & SFFMT_LONG)
while(n < 0)
{
#ifdef mbwidth
#else
n++;
#endif
wsp++;
w--;
}
}
else if (wc)
while(n < 0)
break;
}
#ifdef mbwidth
n += mbwidth(k);
#else
n++;
#endif
}
}
else
#endif
{ sp += -n;
v += n;
}
n = 0;
}
#if _has_multibyte
if(flags & SFFMT_LONG)
break;
}
}
else
#endif
if(n > 0)
{ SFnputc(f,' ',n); }
break;
else if(base > 0)
}
continue;
case 'C':
case 'c':
#if _has_multibyte && defined(mbwidth)
#endif
if(precis <= 0) /* # of times to repeat a character */
precis = 1;
#if _has_multibyte
if(flags & SFFMT_LONG)
{ if(base >= 0)
continue;
;
}
else
size = 1;
}
}
else
#endif
{ if(base >= 0)
continue;
}
else
size = 1;
}
}
while(size > 0)
{
#if _has_multibyte
if(flags&SFFMT_LONG)
break;
#ifdef mbwidth
if(wc)
#endif
}
else
#endif
if(flags&SFFMT_ALTER)
}
else
}
if(n > 0 && !(flags&SFFMT_LEFT) )
{ if(flags&SFFMT_CENTER)
{ n -= (k = n/2);
SFnputc(f, ' ', k);
}
else
{ SFnputc(f, ' ', n);
n = 0;
}
}
v = precis; /* need this because SFnputc may clear it */
#if _has_multibyte
if(flags&SFFMT_LONG)
{ for(; v > 0; --v)
}
else
#endif
if(flags&SFFMT_ALTER)
{ for(; v > 0; --v)
}
else
}
if(n > 0)
{ SFnputc(f,' ',n); };
}
continue;
case 'n': /* return current output length */
SFEND(f);
#if !_ast_intmax_long
else
#endif
if(size == sizeof(long))
else if(size == sizeof(short) )
continue;
case 'p': /* pointer value */
fmt = 'x';
#if _more_void_int
goto long_cvt;
#else
goto int_cvt;
#endif
case 'o':
goto int_arg;
case 'X':
ssp = "0123456789ABCDEF";
case 'x':
goto int_arg;
case 'i':
#if _PACKAGE_ast
{ flags &= ~SFFMT_ALTER;
scale = 1024;
}
#endif
fmt = 'd';
goto d_format;
case 'u':
case 'd':
#if _PACKAGE_ast
{ flags &= ~SFFMT_ALTER;
scale = 1000;
}
#endif
base = 10;
{ if(base < 8)
else if(base < 32)
}
goto long_cvt;
}
{ if(fmt == 'd')
#if _PACKAGE_ast
if(scale)
#if _has_multibyte && defined(mbwidth)
wc = 0;
#endif
goto str_cvt;
}
#endif
break;
{ flags |= SFFMT_MINUS;
}
}
if(n_s < 0) /* base 10 */
}
else if(n_s > 0) /* base power-of-2 */
{ do
}
else /* general base */
{ do
}
} else
#endif
if(sizeof(short) < sizeof(int) && size == sizeof(short) )
{ if(fmt == 'd')
v = (int)((short)argv.i);
goto int_cvt;
}
else if(size == sizeof(char))
{ if(fmt != 'd')
else
{
#if _key_signed
v = (int)((signed char)argv.i);
#else
if(argv.i < 0)
v = -((int)((char)(-argv.i)));
else v = ((int)((char)( argv.i)));
#endif
}
goto int_cvt;
}
else
{ v = argv.i;
#if _PACKAGE_ast
if(scale)
#if _has_multibyte && defined(mbwidth)
wc = 0;
#endif
goto str_cvt;
}
#endif
if(v == 0 && precis == 0)
break;
if(v < 0 && fmt == 'd' )
{ flags |= SFFMT_MINUS;
if(v == HIGHBITI) /* avoid overflow */
}
else v = -v;
}
if(n_s < 0) /* base 10 */
}
else if(n_s > 0) /* base power-of-2 */
{ do
} while((v = ((uint)v) >> n) );
}
else /* n_s == 0, general base */
{ do
}
}
{ if((n %= 3) == 0)
n = 3;
break;
}
}
/* zero padding for precision if have room in buffer */
while(precis-- > 0)
*--sp = '0';
{ if(fmt == 'o')
{ if(*sp != '0')
*--sp = '0';
}
else
{ /* do 0 padding first */
n = 0;
else if(dot < 2)
n = width;
1 : 0;
while(n-- > 0)
*--sp = '0';
}
*--sp = '0';
}
else if(dot >= 2)
{ /* base#value notation */
*--sp = '#';
if(base < 10)
else
}
}
}
}
break;
case 'g': case 'G': /* these ultimately become %e or %f */
case 'a': case 'A':
case 'e': case 'E':
case 'f': case 'F':
#if !_ast_fltmax_double
if(size == sizeof(Sfdouble_t) )
{ v = SFFMT_LDOUBLE;
}
else
#endif
{ v = 0;
}
{ v |= SFFMT_EFORMAT;
goto e_format;
}
goto f_format;
}
{ v |= SFFMT_AFORMAT;
if(precis < 0)
{ if(v & SFFMT_LDOUBLE)
}
n = precis + 1;
*endsp++ = '0';
goto infinite;
if (base < 0)
base = 0;
goto a_format;
}
else /* 'g' or 'G' format */
if(fmt == 'G')
v |= SFFMT_UPPER;
v |= SFFMT_EFORMAT;
if(dval == 0.)
decpt = 1;
else if(*ep == 'I')
goto infinite;
if(!(flags&SFFMT_ALTER))
{ /* zap trailing 0s */
n = precis;
;
n += 1;
}
else n = precis;
{ precis = n-1;
goto e_format;
}
else
goto f_format;
}
}
e_format: /* build the x.yyyy string */
goto infinite;
if (base <= 0)
base = 2;
;
/* build the exponent */
if(dval != 0.)
{ if((n = decpt - 1) < 0)
n = -n;
while(n > 9)
{ v = n; n /= 10;
}
}
else n = 0;
*--ep = (char)('0' + n);
*--ep = '0';
goto end_aefg;
f_format: /* data before the decimal point */
{
flags &= ~SFFMT_ZERO;
precis = 0;
goto end_aefg;
}
{ if((n = decpt%3) == 0)
n = 3;
n = 3;
}
}
}
else
;
}
*endsp++ = '0';
if((n = -decpt) > 0)
{ /* output zeros for negative exponent */
precis -= n;
*endsp++ = '0';
}
;
flags |= SFFMT_FLOAT;
if(sign)
flags |= SFFMT_MINUS;
break;
}
goto do_output;
if(flags&SFFMT_PREFIX)
if((v = width-n) <= 0)
v = 0;
{ if(flags&SFFMT_LEFT)
v = -v;
flags &= ~SFFMT_PREFIX;
}
}
if(fmt != ' ')
flags |= SFFMT_ZERO;
}
if((n = v) > 0) /* left padding */
SFnputc(f,v,n);
}
{ /* padding for integer precision */
SFnputc(f,'0',n);
precis = 0;
}
{ /* SFFMT_FLOAT: right padding for float precision */
if((n = precis) > 0)
SFnputc(f,'0',n);
/* SFFMT_FLOAT: the exponent of %eE */
/* SFFMT_LEFT: right padding */
if((n = -v) > 0)
{ SFnputc(f,' ',n); }
}
}
if(fp)
}
goto loop_fmt;
}
}
goto loop_fmt;
}
done:
if(fp)
}
SFEND(f);
else f->next += n;
SFOPEN(f,0);
SFMTXRETURN(f, n_output);
}