/*
ax_printf - public domain
Last update: 2015-02-27 Aaron Miller
TODO
- Convert to proper single-source header form (like STB)
- Add proper %g and %e support.
- Test %f more, and add support for #INF, #NAN, etc.
LICENSE
This software is in the public domain. Where that dedication is not
recognized, you are granted a perpetual, irrevocable license to copy
and modify this file as you see fit.
*/
#include <stdio.h>
#include <stdlib.h>
/* -------------------------------------------------------------------------- */
/* axpf() (printf) implementation */
#include <errno.h>
#include <assert.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#ifdef _MSC_VER
typedef signed __int8 int8;
typedef signed __int16 int16;
typedef signed __int32 int32;
typedef signed __int64 int64;
typedef unsigned __int8 uint8;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;
#else
# include <stdint.h>
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
#endif
/*
See: http://w...content-available-to-author-only...s.com/reference/cstdio/printf/
See: http://w...content-available-to-author-only...x.com/man-page/FreeBSD/9/printf/
See: http://w...content-available-to-author-only...x.com/man-page/freebsd/3/syslog/
*/
typedef ptrdiff_t( *axpf_write_fn_t )( void *, const char *, const char * );
struct axpf__write_mem_data_
{
char *p;
size_t i;
size_t n;
};
static ptrdiff_t axpf__write_mem_f( void *data, const char *s, const char *e )
{
struct axpf__write_mem_data_ *md;
size_t n;
md = ( struct axpf__write_mem_data_ * )data;
n = ( size_t )( e - s );
if( !n ) {
return 0;
}
if( md->i + n > md->n ) {
n = md->n - md->i;
}
memcpy( ( void * )&md
->p
[ md
->i
], ( const void * )s
, n
); return n;
}
static ptrdiff_t axpf__write_fp_f( void *data, const char *s, const char *e )
{
if( !fwrite( ( const void * )s
, ( size_t )( e
- s
), 1, ( FILE
* )data
) ) { return ( ptrdiff_t )-1;
}
return ( ptrdiff_t )( e - s );
}
enum
{
/* "-" Left-justify within the given field width */
kPF_Left = 1<<0,
/* "+" Result will be preceeded by either a - or + */
kPF_Sign = 1<<1,
/* " " Result will be preceeded by either a - or a space */
kPF_Space = 1<<2,
/* "#" Insert an appropriate radix (0, 0x, 0X) */
kPF_Radix = 1<<3,
/* "0" Left-pad the number with zeroes instead of spaces */
kPF_Zero = 1<<4,
/* "'" Use a digit separator */
kPF_Group = 1<<5,
/* [Internal] Printing an array */
kPF_Array = 1<<11,
/* [Internal] Uppercase */
kPF_Upper = 1<<12,
/* [Internal] Width directive was specified */
kPF_Width = 1<<13,
/* [Internal] Precision directive was specified */
kPF_Precision = 1<<14,
/* [Internal] Use a lower-case radix (for pointer printing) */
kPF_Pointer = 1<<15
};
typedef enum
{
kLS_None,
kLS_hh,
kLS_h,
kLS_l,
kLS_ll,
kLS_j,
kLS_z,
kLS_t,
kLS_L,
kLS_I,
kLS_I32,
kLS_I64
} axpf__lengthSpecifier_t;
#define AXPF__MAX_ARRAY_PRINT 4
struct axpf__state_
{
axpf_write_fn_t pfn_write;
void *write_data;
size_t num_written;
int diderror;
unsigned repeats;
size_t arraysize;
char arrayprint[ AXPF__MAX_ARRAY_PRINT ];
unsigned flags;
int width;
int precision;
axpf__lengthSpecifier_t lenspec;
unsigned radix;
va_list args;
const char *s;
const char *e;
const char *p;
};
static char axpf__read( struct axpf__state_ *s )
{
return s->p < s->e ? *s->p++ : '\0';
}
static char axpf__look( struct axpf__state_ *s )
{
return s->p < s->e ? *s->p : '\0';
}
static void axpf__skip( struct axpf__state_ *s )
{
if( s->p < s->e ) {
s->p++;
}
}
static int axpf__check( struct axpf__state_ *s, int ch )
{
if( s->p < s->e && *s->p == ch ) {
++s->p;
return 1;
}
return 0;
}
static int axpf__checks( struct axpf__state_ *s, const char *p )
{
if( s->p < s->e && *s->p == *p ) {
const char *q;
q = s->p + 1;
while( *q++ == *++p ) {
if( !*p ) {
break;
}
}
if( !*p ) {
s->p = q;
return 1;
}
}
return 0;
}
static int axpf__write( struct axpf__state_ *s, const char *p, const char *e )
{
ptrdiff_t r;
r = s->pfn_write( s->write_data, p, e );
if( r == -1 ) {
s->diderror = 1;
return 0;
}
if( s->num_written + ( size_t )r >= s->num_written ) {
s->num_written += ( size_t )r;
} else {
s->num_written = ( ~( size_t )0 ) - 1;
}
return 1;
}
static int axpf__writech( struct axpf__state_ *s, char ch )
{
char txt[ 2 ];
txt[ 0 ] = ch;
txt[ 1 ] = '\0';
return axpf__write( s, &txt[ 0 ], &txt[ 1 ] );
}
static char *axpf__utoa( char *end, uintmax_t i, unsigned radix, int flags )
{
static const char *lower = "0123456789abcdefghijklmnopqrstuvwxyz";
static const char *upper = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char *digits;
unsigned groupingdist, groupingbase;
char groupingchar;
char *p;
if( radix < 2 ) { radix = 2; }
if( radix > 36 ) { radix = 36; }
digits = ( flags & 1 ) ? upper : lower;
/* TODO: Grab information from locale */
groupingbase = ( flags & 4 ) ? 3 : 9999;
groupingdist = groupingbase + 1;
groupingchar = ',';
p = end - 1;
*p = '\0';
while( i > 0 ) {
if( !--groupingdist ) {
groupingdist = groupingbase;
*--p = groupingchar;
}
*--p = digits[ i%radix ];
i /= radix;
}
if( *p == '\0' && ( ~flags & 2 ) ) {
*--p = '0';
}
return p;
}
static int axpf__dtoax( char *buf, char *outsign, double f, int usescinot,
unsigned maxdigits, unsigned radix )
{
/*
ORIGINAL: http://w...content-available-to-author-only...d.com/thread5585.html (by cb30)
*/
union {
int64 i;
double f;
} x;
int64 mantissa, whole, fract;
int16 exp2;
( void )usescinot;
if( !f ) {
*buf++ = '0';
*buf++ = '.';
*buf++ = '0';
*buf = '\0';
return 0;
}
x.f = f;
if( x.i < 0 ) {
x.i &= ~( 1ULL<<63 );
*outsign = '-';
} else {
*outsign = '+';
}
exp2 = ( ( int16 )( ( x.i>>52 ) & 0x7FF ) ) - 1023;
mantissa = ( x.i & 0x1FFFFFFFFFFFFF ) | 0x10000000000000;
whole = 0;
fract = 0;
if( exp2 >= 63 ) {
*buf = '\0';
return 1;
}
if( exp2 < -52 ) {
*buf = '\0';
return -1;
}
if( exp2 >= 52 ) {
whole = mantissa << ( exp2 - 52 );
} else if( exp2 >= 0 ) {
whole = mantissa >> ( 52 - exp2 );
fract = ( mantissa << ( exp2 + 1 ) ) & 0x1FFFFFFFFFFFFF;
} else {
fract = ( mantissa & 0x1FFFFFFFFFFFFF ) >> -( exp2 + 1 );
}
if( !whole ) {
*buf++ = '0';
} else {
char tmp[ 32 ];
char *p;
p = axpf__utoa( &tmp[ sizeof( tmp ) - 1 ], whole, radix, 0 );
while( *p != '\0' ) {
*buf++ = *p++;
}
}
*buf++ = '.';
if( !fract ) {
*buf++ = '0';
} else {
unsigned numdigits = 0;
if( maxdigits > 32 ) {
maxdigits = 32;
}
for( numdigits = 0; numdigits < maxdigits; ++numdigits ) {
fract *= 10;
*buf++ = ( fract >> 53 ) + '0';
fract &= 0x1FFFFFFFFFFFFF;
}
}
*buf = '\0';
return 0;
}
static int axpf__pad( struct axpf__state_ *s, unsigned num, char ch )
{
static const char spaces[] = " ";
static const char zeroes[] = "0000000000000000";
const char *p;
p = ( ch == ' ' ? &spaces[0] : ( ch == '0' ? &zeroes[0] : NULL ) );
if( !p ) {
while( num-- > 0 ) {
if( !axpf__writech( s, ch ) ) {
return 0;
}
}
return 1;
}
while( num > 0 ) {
unsigned n = num;
if( n > sizeof( spaces ) - 1 ) {
n = sizeof( spaces ) - 1;
}
if( !axpf__write( s, p, p + n ) ) {
return 0;
}
num -= n;
}
return 1;
}
static int axpf__write_uintx( struct axpf__state_ *s, uintmax_t i, char sign )
{
const char *prefix;
unsigned prefixlen;
unsigned numberlen, numbersignlen;
unsigned numpadzeroes;
unsigned numpadspaces;
unsigned padinfringe;
char buf[ 128 ];
char *p;
int f;
f = 0;
if( s->flags & kPF_Upper ) { f |= 1; }
if( ( s->flags & kPF_Precision ) && s->precision == 0 ) { f |= 2; }
if( s->flags & kPF_Group ) { f |= 4; }
p = axpf__utoa( &buf[ sizeof( buf ) ], i, s->radix, f );
prefix = NULL;
prefixlen = 0;
if( s->flags & ( kPF_Radix | kPF_Pointer ) ) {
int useupper;
if( ( s->flags & kPF_Pointer ) || ( ~s->flags & kPF_Upper ) ) {
useupper = 0;
} else {
useupper = 1;
}
switch( s->radix ) {
case 2:
prefixlen = 2;
prefix = useupper ? "0B" : "0b";
break;
case 8:
prefixlen = 1;
prefix = "0";
break;
case 16:
prefixlen = 2;
prefix = useupper ? "0X" : "0x";
break;
default:
break;
}
}
numberlen = ( unsigned )( size_t )( &buf[ sizeof( buf ) - 1 ] - p );
if( !sign ) {
if( s->flags & kPF_Sign ) {
sign = '+';
} else if( s->flags & kPF_Space ) {
sign = ' ';
}
}
numbersignlen = numberlen + +( sign != '\0' );
numpadzeroes = 0;
if( ( s->flags & kPF_Precision ) &&
( unsigned )s->precision > numbersignlen ) {
numpadzeroes = s->precision - numbersignlen;
}
numpadspaces = 0;
padinfringe = numbersignlen + prefixlen + numpadzeroes;
if( ( s->flags & kPF_Width ) && ( unsigned )s->width > padinfringe ) {
if( s->flags & kPF_Zero ) {
numpadzeroes += s->width - padinfringe;
} else {
numpadspaces += s->width - padinfringe;
}
}
#if 0 /* debugging */
printf( "\n[numpadspaces=%u;numpadzeroes=%u;;%s(%i)%s(%i)::%u;%s]\n", numpadspaces, numpadzeroes,
( s->flags & kPF_Width ) ? "w" : "_", s->width,
( s->flags & kPF_Precision ) ? "p" : "_", s->precision,
prefixlen, prefix != NULL ? prefix : "(null)" );
#endif
if( ~s->flags & kPF_Left ) {
if( !axpf__pad( s, numpadspaces, ' ' ) ) {
return 0;
}
}
if( sign ) {
if( !axpf__writech( s, sign ) ) {
return 0;
}
}
if( prefix != NULL && prefixlen > 0 ) {
if( !axpf__write( s, prefix, prefix + prefixlen ) ) {
return 0;
}
}
axpf__pad( s, numpadzeroes, '0' );
if( !axpf__write( s, p, &buf[ sizeof( buf ) - 1 ] ) ) {
return 0;
}
if( s->flags & kPF_Left ) {
if( !axpf__pad( s, numpadspaces, ' ' ) ) {
return 0;
}
}
return 1;
}
static int axpf__write_int( struct axpf__state_ *s, intmax_t i )
{
while( s->repeats-- > 0 ) {
if( i < 0 ) {
if( !axpf__write_uintx( s, ( uintmax_t )-i, '-' ) ) {
return 0;
}
} else if( !axpf__write_uintx( s, ( uintmax_t )i, '\0' ) ) {
return 0;
}
}
return 1;
}
static int axpf__write_uint( struct axpf__state_ *s, uintmax_t i )
{
while( s->repeats-- > 0 ) {
if( !axpf__write_uintx( s, i, '\0' ) ) {
return 0;
}
}
return 1;
}
static int axpf__write_floatd( struct axpf__state_ *s, double f, char spec )
{
unsigned maxdigits;
char buf[ 128 ], *p, *end, *dec;
char sign;
int r;
maxdigits = ( s->flags & kPF_Precision ) ? s->precision : 6;
sign = '\0';
p = &buf[ sizeof( buf )/2 ];
r = axpf__dtoax( p, &sign, ( double )f, 0, maxdigits, s->radix );
if( r < 0 ) {
buf[ 0 ] = '#'; buf[ 1 ] = 'S'; buf[ 2 ] = '\0';
p = &buf[ 0 ];
} else if( r > 0 ) {
buf[ 0 ] = '#'; buf[ 1 ] = 'L'; buf[ 2 ] = '\0';
p = &buf[ 0 ];
}
if( sign != '-' && ( ~s->flags & kPF_Sign ) ) {
sign = '\0';
}
if( spec == 'g' ) {
while( end > &buf[ 0 ] && *( end - 1 ) == '0' ) {
*--end = '\0';
}
if( end > &buf[ 0 ] && *( end - 1 ) == '.' ) {
*--end = '\0';
}
}
if( !dec ) {
dec = end;
}
if( ( s->flags & kPF_Precision ) && s->precision > 0 && r == 0 ) {
unsigned numdigits;
if( *dec != '.' ) {
dec[ 0 ] = '.';
dec[ 1 ] = '\0';
end = &dec[ 1 ];
}
numdigits = ( unsigned )( size_t )( end - dec ) - 1;
while( ( int )numdigits < s->precision && numdigits < 32 ) {
*end++ = '0';
}
*end = '\0';
}
if( ( s->flags & kPF_Width ) && s->width > 0 && r == 0 ) {
unsigned numwidth;
char ch;
ch = ( s->flags & kPF_Zero ) ? '0' : ' ';
numwidth = ( unsigned )( size_t )( dec - p );
if( ch != '0' && sign != '\0' ) {
*--p = sign;
sign = '\0';
++numwidth;
}
while( ( int )numwidth < s->width && numwidth < 32 ) {
*--p = ch;
++numwidth;
}
}
if( sign != '\0' ) {
*--p = sign;
}
while( s->repeats-- > 0 ) {
if( !axpf__write( s, p, end ) ) {
return 0;
}
}
return 1;
}
static int axpf__write_char( struct axpf__state_ *s, int ch )
{
while( s->repeats-- > 0 ) {
if( !axpf__writech( s, ch ) ) {
return 0;
}
}
return 1;
}
static int axpf__writewch( struct axpf__state_ *s, wchar_t ch )
{
( void )s;
( void )ch;
return 0;
}
static int axpf__write_wchar( struct axpf__state_ *s, wchar_t ch )
{
while( s->repeats-- > 0 ) {
if( !axpf__writewch( s, ch ) ) {
return 0;
}
}
return 1;
}
static int axpf__write_str( struct axpf__state_ *s, const char *p )
{
const char *e;
if( !p ) {
p = "(null)";
e = p + 6;
} else if( s->flags & kPF_Precision ) {
e = &p[ s->precision ];
} else {
}
while( s->repeats-- > 0 ) {
if( !axpf__write( s, p, e ) ) {
return 0;
}
}
return 1;
}
static int axpf__write_wstr( struct axpf__state_ *s, const wchar_t *p )
{
const wchar_t *e;
if( !p ) {
p = L"(null)";
e = p + 6;
} else if( s->flags & kPF_Precision ) {
e = &p[ s->precision ];
} else {
}
while( s->repeats-- > 0 ) {
while( p < e ) {
if( !axpf__writewch( s, *p++ ) ) {
return 0;
}
}
}
return 1;
}
static int axpf__write_syserr( struct axpf__state_ *s, int err )
{
char errbuf[ 128 ];
#if defined( _MSC_VER ) && defined( __STDC_WANT_SECURE_LIB__ )
if( strerror_s( errbuf, sizeof( errbuf ), err ) != 0 ) {
errbuf[ 0 ] = '('; errbuf[ 1 ] = 'n'; errbuf[ 2 ] = 'u';
errbuf[ 3 ] = 'l'; errbuf[ 4 ] = 'l'; errbuf[ 5 ] = ')';
errbuf[ 6 ] = '\0';
}
#else
#endif
errbuf[ sizeof( errbuf ) - 1 ] = '\0';
while( s->repeats-- > 0 ) {
if( !axpf__write
( s
, errbuf
, strchr( errbuf
, '\0' ) ) ) { return 0;
}
}
return 1;
}
static int axpf__write_bitfield( struct axpf__state_ *s, int bits,
const char *names )
{
int needcomma;
if( !names || !*names ) {
return 0;
}
if( !s->repeats ) {
return 1;
}
s->radix = *( const unsigned char * )names;
if( s->radix == 1 ) {
s->radix = 10;
}
++names;
if( !axpf__write_uint( s, ( unsigned )bits ) ) {
return 0;
}
if( !axpf__writech( s, ' ' ) || !axpf__writech( s, '<' ) ) {
return 0;
}
needcomma = 0;
while( *names && bits ) {
unsigned bit;
bit = ( ( unsigned )*names++ ) - 1;
if( bits & ( 1<<bit ) ) {
const char *p;
bits &= ~( 1<<bit );
if( needcomma ) {
axpf__writech( s, ',' );
}
p = names;
while( *names > ' ' ) {
++names;
}
if( !axpf__write( s, p, names ) ) {
return 0;
}
needcomma = 1;
}
}
if( !axpf__writech( s, '>' ) ) {
return 0;
}
return 1;
}
static int axpf__write_hex_dump( struct axpf__state_ *s, const unsigned char *p,
const char *delimiter )
{
const char *delimend;
unsigned count = 16;
unsigned n;
unsigned i;
if( !s->repeats ) {
return 1;
}
if( !delimiter || !*delimiter ) {
delimiter = " ";
}
delimend
= strchr( delimiter
, '\0' ); n = ( unsigned )( size_t )( delimend - delimiter );
s->radix = 16;
if( ( s->flags & kPF_Width ) && s->width > 0 ) {
count = s->width;
}
s->flags = kPF_Precision;
s->precision = 2;
for( i = 0; i < count; ++i ) {
if( i > 0 && !axpf__writech( s, delimiter[ ( i - 1 )%n ] ) ) {
return 0;
}
if( !axpf__write_uintx( s, p[ i ], '\0' ) ) {
return 0;
}
}
return 1;
}
static int axpf__find( struct axpf__state_ *s, int ch, int doflush )
{
const char *p;
size_t n;
n = ( size_t )( s->e - s->p );
if( !n ) {
return 0;
}
p
= ( const char * )memchr( ( const void * )s
->p
, ch
, n
); if( !p ) {
return 0;
}
if( doflush && s->p != p ) {
if( !axpf__write( s, s->p, p ) ) {
return 0;
}
}
s->p = p;
return 1;
}
static int axpf__getdigit( int ch, unsigned radix )
{
unsigned rlo, rhi;
unsigned c;
rlo = radix < 10 ? radix : 10;
rhi = radix > 10 ? radix - 10 : 0;
c = ( unsigned )ch;
if( c >= '0' && c < '0' + rlo ) {
return ch - '0';
}
if( c >= 'a' && c < 'a' + rhi ) {
return ch - 'a' + 10;
}
if( c >= 'A' && c < 'A' + rhi ) {
return ch - 'A' + 10;
}
return -1;
}
static unsigned axpf__step_uint( struct axpf__state_ *s )
{
unsigned r = 0;
for(;;) {
int n;
n = axpf__getdigit( axpf__look( s ), 10 );
if( n < 0 ) {
break;
}
if( r < ( 1L<<( sizeof( int )*8 - 2 ) ) ) {
r *= 10;
r += n;
}
axpf__skip( s );
}
return r;
}
static int axpf__step_int( struct axpf__state_ *s )
{
int m = 1;
if( axpf__check( s, '-' ) ) {
m = -1;
}
return m*( int )axpf__step_uint( s );
}
static int axpf__step( struct axpf__state_ *s )
{
char spec;
if( !axpf__find( s, '%', 1 ) ) {
axpf__write( s, s->p, s->e );
return 0;
}
axpf__skip( s );
if( axpf__check( s, '%' ) ) {
axpf__writech( s, '%' );
return 1;
}
s->repeats = 1;
s->arraysize = 0;
s->arrayprint[ 0 ] = '{';
s->arrayprint[ 1 ] = ',';
s->arrayprint[ 2 ] = ' ';
s->arrayprint[ 3 ] = '}';
s->flags = 0;
s->width = 0;
s->precision = 0;
s->lenspec = kLS_None;
s->radix = 10;
/* repeats */
if( axpf__check( s, '{' ) ) {
if( axpf__check( s, '*' ) ) {
s
->repeats
= va_arg( s
->args
, unsigned ); } else {
s->repeats = axpf__step_uint( s );
}
( void )axpf__check( s, '}' );
}
/* array */
if( axpf__check( s, '[' ) ) {
unsigned n = 0;
if( axpf__check( s, '*' ) ) {
s
->arraysize
= va_arg( s
->args
, size_t ); } else {
s->arraysize = axpf__step_uint( s );
}
s->flags |= kPF_Array;
while( n < AXPF__MAX_ARRAY_PRINT ) {
if( axpf__check( s, ']' ) ) {
break;
}
s->arrayprint[ n++ ] = axpf__read( s );
}
if( n == AXPF__MAX_ARRAY_PRINT ) {
( void )axpf__check( s, ']' );
} else if( n > 0 ) {
/* the last character specified is the closing value */
s->arrayprint[ AXPF__MAX_ARRAY_PRINT - 1 ] = s->arrayprint[ n - 1 ];
/* if a space was omitted then don't space elements out */
if( n < 4 ) {
s->arrayprint[ 2 ] = '\0';
}
/* if a delimiter was omitted then assume a comma */
if( n < 3 ) {
s->arrayprint[ 1 ] = ',';
}
}
}
/* flags */
unsigned fcount;
do {
fcount = 0;
if( axpf__check( s, '-' ) ) {
s->flags |= kPF_Left;
++fcount;
}
if( axpf__check( s, '+' ) ) {
s->flags |= kPF_Sign;
++fcount;
}
if( axpf__check( s, ' ' ) ) {
s->flags |= kPF_Space;
++fcount;
}
if( axpf__check( s, '#' ) ) {
s->flags |= kPF_Radix;
++fcount;
}
if( axpf__check( s, '0' ) ) {
s->flags |= kPF_Zero;
++fcount;
}
if( axpf__check( s, '\'' ) ) {
s->flags |= kPF_Group;
++fcount;
}
} while( fcount > 0 );
/* width */
if( axpf__check( s, '*' ) ) {
s
->width
= va_arg( s
->args
, int ); s->flags |= kPF_Width;
} else if( axpf__getdigit( axpf__look( s ), 10 ) >= 0 ) {
s->width = axpf__step_int( s );
s->flags |= kPF_Width;
}
/* precision */
if( axpf__check( s, '.' ) ) {
if( axpf__check( s, '*' ) ) {
s
->precision
= va_arg( s
->args
, int ); s->flags |= kPF_Precision;
} else if( axpf__getdigit( axpf__look( s ), 10 ) >= 0 ) {
s->precision = axpf__step_int( s );
s->flags |= kPF_Precision;
}
}
/* length specifier */
if( axpf__check( s, 'h' ) ) {
if( axpf__check( s, 'h' ) ) {
s->lenspec = kLS_hh;
} else {
s->lenspec = kLS_h;
}
} else if( axpf__check( s, 'l' ) ) {
if( axpf__check( s, 'l' ) ) {
s->lenspec = kLS_ll;
} else {
s->lenspec = kLS_l;
}
} else if( axpf__check( s, 'j' ) ) {
s->lenspec = kLS_j;
} else if( axpf__check( s, 'z' ) ) {
s->lenspec = kLS_z;
} else if( axpf__check( s, 't' ) ) {
s->lenspec = kLS_t;
} else if( axpf__check( s, 'L' ) ) {
s->lenspec = kLS_L;
} else if( axpf__check( s, 'q' ) ) {
s->lenspec = kLS_I64;
} else if( axpf__check( s, 'w' ) ) {
s->lenspec = kLS_l;
} else if( axpf__check( s, 'I' ) ) {
if( axpf__checks( s, "32" ) ) {
s->lenspec = kLS_I32;
} else if( axpf__checks( s, "64" ) ) {
s->lenspec = kLS_I64;
} else {
s->lenspec = kLS_I;
}
}
spec = axpf__read( s );
if( spec >= 'A' && spec <= 'Z' && spec!='C' && spec!='D' && spec!='S' ) {
s->flags |= kPF_Upper;
spec = spec - 'A' + 'a';
}
/* arrays require special handling */
if( s->flags & kPF_Array ) {
const void *ptrbase;
unsigned repeats;
if( spec == 'r' ) {
s
->radix
= va_arg( s
->args
, unsigned int ); }
ptrbase
= va_arg( s
->args
, const void * );
if( spec == 'a' ) {
spec = 'f';
s->radix = 16;
}
repeats = s->repeats;
while( repeats-- > 0 ) {
union {
const void *p;
const int *i; const unsigned int *u;
const signed char *sc; const unsigned char *usc;
const short int *si; const unsigned short int *usi;
const long int *li; const unsigned long int *uli;
#ifdef _MSC_VER
const __int64 *lli; const unsigned __int64 *ulli;
#else
const long long int *lli; const unsigned long long int *ulli;
#endif
const intmax_t *im; const uintmax_t *uim;
const size_t *sz;
const ptrdiff_t *pd;
const int32 *i32; const uint32 *ui32;
const int64 *i64; const uint64 *ui64;
const float *f;
const double *d;
const long double *ld;
const char *c;
const wchar_t *wc;
const char *const *s;
const wchar_t *const *ws;
} x;
size_t i;
if( !ptrbase ) {
const char buf[] = "(null)";
axpf__write( s, buf, buf + sizeof(buf) - 1 );
continue;
}
axpf__writech( s, s->arrayprint[ 0 ] );
x.p = ptrbase;
for( i = 0; i < s->arraysize; ++i ) {
if( i > 0 ) {
axpf__writech( s, s->arrayprint[ 1 ] );
}
if( s->arrayprint[ 2 ] == ' ' ) {
axpf__writech( s, ' ' );
}
s->repeats = 1;
switch( spec ) {
case 'd':
case 'i':
switch( s->lenspec ) {
#define P_(F_) axpf__write_int( s, x.F_[i] ); break
case kLS_None: P_( i );
case kLS_hh: P_( sc );
case kLS_h: P_( si );
case kLS_l:
case kLS_L: P_( li );
case kLS_ll: P_( lli );
case kLS_j: P_( im );
case kLS_z: P_( sz );
case kLS_I:
case kLS_t: P_( pd );
case kLS_I32: P_( i32 );
case kLS_I64: P_( i64 );
#undef P_
}
break;
case 'u':
case 'o':
case 'x':
case 'r':
if( spec == 'o' ) {
s->radix = 8;
} else if( spec == 'x' ) {
s->radix = 16;
} else if( spec == 'r' ) {
s
->radix
= va_arg( s
->args
, unsigned int ); }
switch( s->lenspec ) {
#define P_(F_) axpf__write_uint( s, x.F_[i] ); break
case kLS_None: P_( u );
case kLS_hh: P_( usc );
case kLS_h: P_( usi );
case kLS_l:
case kLS_L: P_( uli );
case kLS_ll: P_( ulli );
case kLS_j: P_( uim );
case kLS_I:
case kLS_z: P_( sz );
case kLS_t: P_( pd );
case kLS_I32: P_( ui32 );
case kLS_I64: P_( ui64 );
#undef P_
}
break;
case 'f':
case 'e':
case 'g':
if( s->lenspec == kLS_None ) {
axpf__write_floatd( s, ( double )x.f[ i ], spec );
} else if( s->lenspec == kLS_l ) {
axpf__write_floatd( s, x.d[ i ], spec );
} else if( s->lenspec == kLS_L ) {
axpf__write_floatd( s, ( double )x.ld[ i ], spec );
}
break;
case 'c':
case 'C':
if( s->lenspec == kLS_None && spec != 'C' ) {
axpf__write_char( s, x.c[ i ] );
} else if( s->lenspec == kLS_l || spec == 'C' ) {
axpf__write_wchar( s, x.wc[ i ] );
}
break;
case 's':
case 'S':
if( s->lenspec == kLS_None && spec != 'S' ) {
axpf__write_str( s, x.s[ i ] );
} else if( s->lenspec == kLS_l || spec == 'S' ) {
axpf__write_wstr( s, x.ws[ i ] );
}
break;
case 'p':
s->radix = 16;
s->flags |= kPF_Radix | kPF_Pointer | kPF_Precision;
s->precision = sizeof( void * )*2;
axpf__write_uint( s, x.sz[ i ] );
break;
}
}
if( s->arrayprint[ 2 ] == ' ' ) {
axpf__writech( s, ' ' );
}
axpf__writech( s, s->arrayprint[ 3 ] );
}
return !s->diderror;
}
/* check the specifier */
switch( spec ) {
case 'd':
case 'i':
if( s->lenspec == kLS_l ) {
axpf__write_int
( s
, va_arg( s
->args
, long int ) ); } else if( s->lenspec == kLS_ll || s->lenspec == kLS_L ) {
#ifdef _MSC_VER
axpf__write_int
( s
, va_arg( s
->args
, __int64
) );#else
axpf__write_int
( s
, va_arg( s
->args
, long long int ) );#endif
} else if( s->lenspec == kLS_t || s->lenspec == kLS_I ) {
axpf__write_int
( s
, va_arg( s
->args
, ptrdiff_t
) ); } else if( s->lenspec == kLS_z ) {
axpf__write_int
( s
, va_arg( s
->args
, size_t ) ); } else if( s->lenspec == kLS_j ) {
axpf__write_int
( s
, va_arg( s
->args
, intmax_t ) ); } else if( s->lenspec == kLS_I32 ) {
axpf__write_int
( s
, va_arg( s
->args
, int32 ) ); } else if( s->lenspec == kLS_I64 ) {
axpf__write_int
( s
, va_arg( s
->args
, int64 ) ); } else {
axpf__write_int
( s
, va_arg( s
->args
, int ) ); }
break;
case 'u':
case 'o':
case 'x':
case 'r':
if( spec == 'o' ) {
s->radix = 8;
} else if( spec == 'x' ) {
s->radix = 16;
} else if( spec == 'r' ) {
s
->radix
= va_arg( s
->args
, unsigned int ); }
if( s->lenspec == kLS_l ) {
axpf__write_uint
( s
, va_arg( s
->args
, unsigned long int ) ); } else if( s->lenspec == kLS_ll || s->lenspec == kLS_L ) {
#ifdef _MSC_VER
axpf__write_uint
( s
, va_arg( s
->args
, unsigned __int64
) );#else
axpf__write_uint
( s
, va_arg( s
->args
, unsigned long long int ) );#endif
} else if( s->lenspec == kLS_t ) {
axpf__write_uint
( s
, va_arg( s
->args
, ptrdiff_t
) ); } else if( s->lenspec == kLS_z || s->lenspec == kLS_I ) {
axpf__write_uint
( s
, va_arg( s
->args
, size_t ) ); } else if( s->lenspec == kLS_j ) {
axpf__write_uint
( s
, va_arg( s
->args
, uintmax_t ) ); } else if( s->lenspec == kLS_I32 ) {
axpf__write_uint
( s
, va_arg( s
->args
, uint32 ) ); } else if( s->lenspec == kLS_I64 ) {
axpf__write_uint
( s
, va_arg( s
->args
, uint64 ) ); } else {
axpf__write_uint
( s
, va_arg( s
->args
, unsigned int ) ); }
break;
case 'f':
case 'e':
case 'g':
case 'a':
if( spec == 'a' ) {
spec = 'f';
s->radix = 16;
}
if( s->lenspec == kLS_None ) {
axpf__write_floatd
( s
, va_arg( s
->args
, double ), spec
); } else if( s->lenspec == kLS_l || s->lenspec == kLS_L ) {
axpf__write_floatd
( s
, ( double )va_arg( s
->args
, long double ), spec );
}
break;
case 'c':
case 'C':
if( s->lenspec == kLS_None && spec != 'C' ) {
axpf__write_char
( s
, va_arg( s
->args
, int ) ); } else if( s->lenspec == kLS_l || spec == 'C' ) {
axpf__write_wchar
( s
, va_arg( s
->args
, int/*wint_t*/ ) ); }
break;
case 's':
case 'S':
if( s->lenspec == kLS_None && spec != 'S' ) {
axpf__write_str
( s
, va_arg( s
->args
, const char * ) ); } else if( s->lenspec == kLS_l || spec == 'S' ) {
axpf__write_wstr
( s
, va_arg( s
->args
, const wchar_t * ) ); }
break;
case 'p':
s->radix = 16;
s->flags |= kPF_Radix | kPF_Pointer | kPF_Precision;
s->precision = sizeof( void * )*2;
axpf__write_uint
( s
, va_arg( s
->args
, size_t ) ); break;
case 'n':
switch( s->lenspec ) {
#define P_(Ty_) *va_arg( s->args, Ty_ * ) = ( Ty_ )s->num_written; break
case kLS_None: P_( int );
case kLS_hh: P_( signed char );
case kLS_h: P_( short int );
case kLS_l:
case kLS_L: P_( long int );
#ifdef _MSC_VER
case kLS_ll: P_( __int64 );
#else
case kLS_ll: P_( long long int );
#endif
case kLS_j: P_( intmax_t );
case kLS_z: P_( size_t );
case kLS_I:
case kLS_t: P_( ptrdiff_t );
case kLS_I32: P_( int32 );
case kLS_I64: P_( int64 );
#undef P_
}
break;
case 'm':
axpf__write_syserr( s, s->width != 0 ? s->width : ( int )errno );
break;
case 'b':
{
int bits;
const char *names;
bits
= va_arg( s
->args
, int ); names
= va_arg( s
->args
, const char * );
axpf__write_bitfield( s, bits, names );
}
break;
case 'D':
{
const unsigned char *data;
const char *delm;
data
= va_arg( s
->args
, const unsigned char * ); delm
= va_arg( s
->args
, const char * );
axpf__write_hex_dump( s, data, delm );
}
break;
}
return !s->diderror;
}
static ptrdiff_t axpf__main( struct axpf__state_ *s, const char *fmt,
const char *fmte, va_list args )
{
s->s = fmt;
s->p = fmt;
s
->e
= !fmte
? strchr( fmt
, '\0' ) : fmte
;
s->num_written = 0;
s->args = args;
s->diderror = 0;
while( axpf__step( s ) ) {
}
if( s->diderror ) {
return -1;
}
return ( ptrdiff_t )s->num_written;
}
ptrdiff_t axfpfev( FILE *fp, const char *fmt, const char *fmte, va_list args )
{
struct axpf__state_ s;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )fp;
return axpf__main( &s, fmt, fmte, args );
}
ptrdiff_t axfpfv( FILE *fp, const char *fmt, va_list args )
{
struct axpf__state_ s;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )fp;
return axpf__main( &s, fmt, ( const char * )0, args );
}
ptrdiff_t axfpfe( FILE *fp, const char *fmt, const char *fmte, ... )
{
struct axpf__state_ s;
ptrdiff_t r;
va_list args;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )fp;
r = axpf__main( &s, fmt, fmte, args );
return r;
}
ptrdiff_t axfpf( FILE *fp, const char *fmt, ... )
{
struct axpf__state_ s;
ptrdiff_t r;
va_list args;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )fp;
r = axpf__main( &s, fmt, ( const char * )0, args );
return r;
}
ptrdiff_t axerrfev( const char *fmt, const char *fmte, va_list args )
{
struct axpf__state_ s;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )stderr;
return axpf__main( &s, fmt, fmte, args );
}
ptrdiff_t axerrfv( const char *fmt, va_list args )
{
struct axpf__state_ s;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )stderr;
return axpf__main( &s, fmt, ( const char * )0, args );
}
ptrdiff_t axerrfe( const char *fmt, const char *fmte, ... )
{
struct axpf__state_ s;
ptrdiff_t r;
va_list args;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )stderr;
r = axpf__main( &s, fmt, fmte, args );
return r;
}
ptrdiff_t axerrf( const char *fmt, ... )
{
struct axpf__state_ s;
ptrdiff_t r;
va_list args;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )stderr;
r = axpf__main( &s, fmt, ( const char * )0, args );
return r;
}
ptrdiff_t axpfev( const char *fmt, const char *fmte, va_list args )
{
struct axpf__state_ s;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )stdout;
return axpf__main( &s, fmt, fmte, args );
}
ptrdiff_t axpfv( const char *fmt, va_list args )
{
struct axpf__state_ s;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )stdout;
return axpf__main( &s, fmt, ( const char * )0, args );
}
ptrdiff_t axpfe( const char *fmt, const char *fmte, ... )
{
struct axpf__state_ s;
ptrdiff_t r;
va_list args;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )stdout;
r = axpf__main( &s, fmt, fmte, args );
return r;
}
ptrdiff_t axpf( const char *fmt, ... )
{
struct axpf__state_ s;
ptrdiff_t r;
va_list args;
s.pfn_write = &axpf__write_fp_f;
s.write_data = ( void * )stdout;
r = axpf__main( &s, fmt, ( const char * )0, args );
return r;
}
ptrdiff_t axspfev( char *buf, size_t nbuf, const char *fmt, const char *fmte,
va_list args )
{
struct axpf__write_mem_data_ m;
struct axpf__state_ s;
ptrdiff_t r;
m.p = buf;
m.i = 0;
m.n = nbuf;
s.pfn_write = &axpf__write_mem_f;
s.write_data = ( void * )&m;
r = axpf__main( &s, fmt, fmte, args );
if( m.n > 0 ) {
m.p[ m.i < m.n ? m.i : m.n - 1 ] = '\0';
}
return r;
}
ptrdiff_t axspfv( char *buf, size_t nbuf, const char *fmt, va_list args )
{
return axspfev( buf, nbuf, fmt, ( const char * )0, args );
}
ptrdiff_t axspfe( char *buf, size_t nbuf, const char *fmt, const char *fmte,
... )
{
ptrdiff_t r;
va_list args;
r = axspfev( buf, nbuf, fmt, fmte, args );
return r;
}
ptrdiff_t axspf( char *buf, size_t nbuf, const char *fmt, ... )
{
ptrdiff_t r;
va_list args;
r = axspfev( buf, nbuf, fmt, ( const char * )0, args );
return r;
}
#ifdef __cplusplus
template< size_t tMaxBuf >
ptrdiff_t axspfev( char( &buf )[ tMaxBuf ], const char *fmt, const char *fmte,
va_list args )
{
return axspfev( buf, tMaxBuf, fmt, fmte, args );
}
template< size_t tMaxBuf >
ptrdiff_t axspfv( char( &buf )[ tMaxBuf ], const char *fmt, va_list args )
{
return axspfev( buf, tMaxBuf, fmt, ( const char * )0, args );
}
template< size_t tMaxBuf >
ptrdiff_t axspfe( char( &buf )[ tMaxBuf ], const char *fmt, const char *fmte,
... )
{
ptrdiff_t r;
va_list args;
r = axspfev( buf, tMaxBuf, fmt, fmte, args );
return r;
}
template< size_t tMaxBuf >
ptrdiff_t axspf( char( &buf )[ tMaxBuf ], const char *fmt, ... )
{
ptrdiff_t r;
va_list args;
r = axspfev( buf, tMaxBuf, fmt, ( const char * )0, args );
return r;
}
#endif
/* -------------------------------------------------------------------------- */
int main()
{
float arr_f[ 4 ];
int arr_i[ 4 ];
arr_i[ 0 ] = 1;
arr_i[ 1 ] = 2;
arr_i[ 2 ] = 3;
arr_i[ 3 ] = 4;
axpf( "Hello, world!\n" );
axpf( "Test string: \"%s\"\n", "This is a test" );
axpf( "Test integer: %d\n", 100 );
axpf( "Test signed integer: %d\n", -123 );
axpf( "Test hex: %X\n", 0xFACE );
axpf( "Test hex two: %#X\n", 0xFACE );
axpf( "Test pointer: %p\n", ( const void * )"Yo" );
axpf( "Hex: %4D\n", "ABCD", ":" );
axpf( "Bits: %b\n", 3, "\20\3Three\2Two\1One" );
axpf( "String: %.*s\n", 4, "Hey!XXXXXXXX" );
axpf( "String: %.2s\n", "YoXXXXX" );
axpf( "Errno: %2m\n" ); /* No such file or directory */
axpf( "Grouping: %'d ;; %'d ;; %'d ;; %'d\n", 12345, 1234, 123, 1234567 );
axpf( "Binary: %r\n", 2, 10 );
axpf( "Binary-pre: %#r\n", 2, 127 );
axpf( "Repeat: %{5}s\n", "A" );
axpf( "Repeat: %{*}sYo\n", 4, " " );
axpf( "Repeat: %{1}i\n", 1234 );
axpf( "Repeat: %{0}i\n", 1234 );
axpf( "Array: %[3]d\n", &arr_i[0] );
axpf( "Array: %[*]d\n", 4, arr_i );
axpf( "Repeat-array: %{3}[2]d\n", arr_i );
arr_i[ 0 ] = 1234;
arr_i[ 1 ] = 5678;
arr_i[ 2 ] = 1593;
axpf( "Custom-array: %[3<;>]'d\n", arr_i );
axpf( "Float: %f\n", 3.1415926535 );
arr_f[ 0 ] = -1.5f;
arr_f[ 1 ] = 95.235f;
arr_f[ 2 ] = -127.127f;
axpf( "Float-array: %[3].2f\n", arr_f );
return EXIT_SUCCESS;
}