mirror of
https://github.com/Ed94/gencpp.git
synced 2024-12-23 00:04:45 -08:00
Ed_
5d7dfaf666
Isolating large macros to their own directory (components/temp). - Plan is to remove them soon with proper generation. Added additional component files, separating the old data_structures header for a set of ast headers. Header_end also had its inlines extracted out. Necessary to complete the macro isolation. ZPL parser dependencies were removed from the core library along with builder, its now generated in bootstrap as pare of making a gen_builder set of files. Singleheader will be changed in next few commits to reflect this as well (By making builder deps and components a conditional option). Tests are most likely all broken for now.
566 lines
11 KiB
C++
566 lines
11 KiB
C++
#pragma region Printing
|
|
|
|
enum
|
|
{
|
|
GEN_FMT_MINUS = bit( 0 ),
|
|
GEN_FMT_PLUS = bit( 1 ),
|
|
GEN_FMT_ALT = bit( 2 ),
|
|
GEN_FMT_SPACE = bit( 3 ),
|
|
GEN_FMT_ZERO = bit( 4 ),
|
|
|
|
GEN_FMT_CHAR = bit( 5 ),
|
|
GEN_FMT_SHORT = bit( 6 ),
|
|
GEN_FMT_INT = bit( 7 ),
|
|
GEN_FMT_LONG = bit( 8 ),
|
|
GEN_FMT_LLONG = bit( 9 ),
|
|
GEN_FMT_SIZE = bit( 10 ),
|
|
GEN_FMT_INTPTR = bit( 11 ),
|
|
|
|
GEN_FMT_UNSIGNED = bit( 12 ),
|
|
GEN_FMT_LOWER = bit( 13 ),
|
|
GEN_FMT_UPPER = bit( 14 ),
|
|
GEN_FMT_WIDTH = bit( 15 ),
|
|
|
|
GEN_FMT_DONE = bit( 30 ),
|
|
|
|
GEN_FMT_INTS = GEN_FMT_CHAR | GEN_FMT_SHORT | GEN_FMT_INT | GEN_FMT_LONG | GEN_FMT_LLONG | GEN_FMT_SIZE | GEN_FMT_INTPTR
|
|
};
|
|
|
|
struct _format_info
|
|
{
|
|
s32 base;
|
|
s32 flags;
|
|
s32 width;
|
|
s32 precision;
|
|
};
|
|
|
|
internal sw _print_string( char* text, sw max_len, _format_info* info, char const* str )
|
|
{
|
|
sw res = 0, len = 0;
|
|
sw remaining = max_len;
|
|
char* begin = text;
|
|
|
|
if ( str == NULL && max_len >= 6 )
|
|
{
|
|
res += str_copy_nulpad( text, "(null)", 6 );
|
|
return res;
|
|
}
|
|
|
|
if ( info && info->precision >= 0 )
|
|
len = str_len( str, info->precision );
|
|
else
|
|
len = str_len( str );
|
|
|
|
if ( info && ( info->width == 0 && info->flags & GEN_FMT_WIDTH ) )
|
|
{
|
|
return res;
|
|
}
|
|
|
|
if ( info && ( info->width == 0 || info->flags & GEN_FMT_MINUS ) )
|
|
{
|
|
if ( info->precision > 0 )
|
|
len = info->precision < len ? info->precision : len;
|
|
if ( res + len > max_len )
|
|
return res;
|
|
res += str_copy_nulpad( text, str, len );
|
|
text += res;
|
|
|
|
if ( info->width > res )
|
|
{
|
|
sw padding = info->width - len;
|
|
|
|
char pad = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' ';
|
|
while ( padding-- > 0 && remaining-- > 0 )
|
|
*text++ = pad, res++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( info && ( info->width > res ) )
|
|
{
|
|
sw padding = info->width - len;
|
|
char pad = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' ';
|
|
while ( padding-- > 0 && remaining-- > 0 )
|
|
*text++ = pad, res++;
|
|
}
|
|
|
|
if ( res + len > max_len )
|
|
return res;
|
|
res += str_copy_nulpad( text, str, len );
|
|
}
|
|
|
|
if ( info )
|
|
{
|
|
if ( info->flags & GEN_FMT_UPPER )
|
|
str_to_upper( begin );
|
|
else if ( info->flags & GEN_FMT_LOWER )
|
|
str_to_lower( begin );
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
internal sw _print_char( char* text, sw max_len, _format_info* info, char arg )
|
|
{
|
|
char str[ 2 ] = "";
|
|
str[ 0 ] = arg;
|
|
return _print_string( text, max_len, info, str );
|
|
}
|
|
|
|
internal sw _print_repeated_char( char* text, sw max_len, _format_info* info, char arg )
|
|
{
|
|
sw res = 0;
|
|
s32 rem = ( info ) ? ( info->width > 0 ) ? info->width : 1 : 1;
|
|
res = rem;
|
|
while ( rem-- > 0 )
|
|
*text++ = arg;
|
|
|
|
return res;
|
|
}
|
|
|
|
internal sw _print_i64( char* text, sw max_len, _format_info* info, s64 value )
|
|
{
|
|
char num[ 130 ];
|
|
i64_to_str( value, num, info ? info->base : 10 );
|
|
return _print_string( text, max_len, info, num );
|
|
}
|
|
|
|
internal sw _print_u64( char* text, sw max_len, _format_info* info, u64 value )
|
|
{
|
|
char num[ 130 ];
|
|
u64_to_str( value, num, info ? info->base : 10 );
|
|
return _print_string( text, max_len, info, num );
|
|
}
|
|
|
|
internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexadecimal, f64 arg )
|
|
{
|
|
// TODO: Handle exponent notation
|
|
sw width, len, remaining = max_len;
|
|
char* text_begin = text;
|
|
|
|
if ( arg )
|
|
{
|
|
u64 value;
|
|
if ( arg < 0 )
|
|
{
|
|
if ( remaining > 1 )
|
|
*text = '-', remaining--;
|
|
text++;
|
|
arg = -arg;
|
|
}
|
|
else if ( info->flags & GEN_FMT_MINUS )
|
|
{
|
|
if ( remaining > 1 )
|
|
*text = '+', remaining--;
|
|
text++;
|
|
}
|
|
|
|
value = zpl_cast( u64 ) arg;
|
|
len = _print_u64( text, remaining, NULL, value );
|
|
text += len;
|
|
|
|
if ( len >= remaining )
|
|
remaining = min( remaining, 1 );
|
|
else
|
|
remaining -= len;
|
|
arg -= value;
|
|
|
|
if ( info->precision < 0 )
|
|
info->precision = 6;
|
|
|
|
if ( ( info->flags & GEN_FMT_ALT ) || info->precision > 0 )
|
|
{
|
|
s64 mult = 10;
|
|
if ( remaining > 1 )
|
|
*text = '.', remaining--;
|
|
text++;
|
|
while ( info->precision-- > 0 )
|
|
{
|
|
value = zpl_cast( u64 )( arg * mult );
|
|
len = _print_u64( text, remaining, NULL, value );
|
|
text += len;
|
|
if ( len >= remaining )
|
|
remaining = min( remaining, 1 );
|
|
else
|
|
remaining -= len;
|
|
arg -= zpl_cast( f64 ) value / mult;
|
|
mult *= 10;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( remaining > 1 )
|
|
*text = '0', remaining--;
|
|
text++;
|
|
if ( info->flags & GEN_FMT_ALT )
|
|
{
|
|
if ( remaining > 1 )
|
|
*text = '.', remaining--;
|
|
text++;
|
|
}
|
|
}
|
|
|
|
width = info->width - ( text - text_begin );
|
|
if ( width > 0 )
|
|
{
|
|
char fill = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' ';
|
|
char* end = text + remaining - 1;
|
|
len = ( text - text_begin );
|
|
|
|
for ( len = ( text - text_begin ); len--; )
|
|
{
|
|
if ( ( text_begin + len + width ) < end )
|
|
*( text_begin + len + width ) = *( text_begin + len );
|
|
}
|
|
|
|
len = width;
|
|
text += len;
|
|
if ( len >= remaining )
|
|
remaining = min( remaining, 1 );
|
|
else
|
|
remaining -= len;
|
|
|
|
while ( len-- )
|
|
{
|
|
if ( text_begin + len < end )
|
|
text_begin[ len ] = fill;
|
|
}
|
|
}
|
|
|
|
return ( text - text_begin );
|
|
}
|
|
|
|
neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va )
|
|
{
|
|
char const* text_begin = text;
|
|
sw remaining = max_len, res;
|
|
|
|
while ( *fmt )
|
|
{
|
|
_format_info info = { 0 };
|
|
sw len = 0;
|
|
info.precision = -1;
|
|
|
|
while ( *fmt && *fmt != '%' && remaining )
|
|
*text++ = *fmt++;
|
|
|
|
if ( *fmt == '%' )
|
|
{
|
|
do
|
|
{
|
|
switch ( *++fmt )
|
|
{
|
|
case '-' :
|
|
{
|
|
info.flags |= GEN_FMT_MINUS;
|
|
break;
|
|
}
|
|
case '+' :
|
|
{
|
|
info.flags |= GEN_FMT_PLUS;
|
|
break;
|
|
}
|
|
case '#' :
|
|
{
|
|
info.flags |= GEN_FMT_ALT;
|
|
break;
|
|
}
|
|
case ' ' :
|
|
{
|
|
info.flags |= GEN_FMT_SPACE;
|
|
break;
|
|
}
|
|
case '0' :
|
|
{
|
|
info.flags |= ( GEN_FMT_ZERO | GEN_FMT_WIDTH );
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
info.flags |= GEN_FMT_DONE;
|
|
break;
|
|
}
|
|
}
|
|
} while ( ! ( info.flags & GEN_FMT_DONE ) );
|
|
}
|
|
|
|
// NOTE: Optional Width
|
|
if ( *fmt == '*' )
|
|
{
|
|
int width = va_arg( va, int );
|
|
if ( width < 0 )
|
|
{
|
|
info.flags |= GEN_FMT_MINUS;
|
|
info.width = -width;
|
|
}
|
|
else
|
|
{
|
|
info.width = width;
|
|
}
|
|
info.flags |= GEN_FMT_WIDTH;
|
|
fmt++;
|
|
}
|
|
else
|
|
{
|
|
info.width = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 );
|
|
if ( info.width != 0 )
|
|
{
|
|
info.flags |= GEN_FMT_WIDTH;
|
|
}
|
|
}
|
|
|
|
// NOTE: Optional Precision
|
|
if ( *fmt == '.' )
|
|
{
|
|
fmt++;
|
|
if ( *fmt == '*' )
|
|
{
|
|
info.precision = va_arg( va, int );
|
|
fmt++;
|
|
}
|
|
else
|
|
{
|
|
info.precision = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 );
|
|
}
|
|
info.flags &= ~GEN_FMT_ZERO;
|
|
}
|
|
|
|
switch ( *fmt++ )
|
|
{
|
|
case 'h' :
|
|
if ( *fmt == 'h' )
|
|
{ // hh => char
|
|
info.flags |= GEN_FMT_CHAR;
|
|
fmt++;
|
|
}
|
|
else
|
|
{ // h => short
|
|
info.flags |= GEN_FMT_SHORT;
|
|
}
|
|
break;
|
|
|
|
case 'l' :
|
|
if ( *fmt == 'l' )
|
|
{ // ll => long long
|
|
info.flags |= GEN_FMT_LLONG;
|
|
fmt++;
|
|
}
|
|
else
|
|
{ // l => long
|
|
info.flags |= GEN_FMT_LONG;
|
|
}
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'z' : // NOTE: zpl_usize
|
|
info.flags |= GEN_FMT_UNSIGNED;
|
|
// fallthrough
|
|
case 't' : // NOTE: zpl_isize
|
|
info.flags |= GEN_FMT_SIZE;
|
|
break;
|
|
|
|
default :
|
|
fmt--;
|
|
break;
|
|
}
|
|
|
|
switch ( *fmt )
|
|
{
|
|
case 'u' :
|
|
info.flags |= GEN_FMT_UNSIGNED;
|
|
// fallthrough
|
|
case 'd' :
|
|
case 'i' :
|
|
info.base = 10;
|
|
break;
|
|
|
|
case 'o' :
|
|
info.base = 8;
|
|
break;
|
|
|
|
case 'x' :
|
|
info.base = 16;
|
|
info.flags |= ( GEN_FMT_UNSIGNED | GEN_FMT_LOWER );
|
|
break;
|
|
|
|
case 'X' :
|
|
info.base = 16;
|
|
info.flags |= ( GEN_FMT_UNSIGNED | GEN_FMT_UPPER );
|
|
break;
|
|
|
|
case 'f' :
|
|
case 'F' :
|
|
case 'g' :
|
|
case 'G' :
|
|
len = _print_f64( text, remaining, &info, 0, va_arg( va, f64 ) );
|
|
break;
|
|
|
|
case 'a' :
|
|
case 'A' :
|
|
len = _print_f64( text, remaining, &info, 1, va_arg( va, f64 ) );
|
|
break;
|
|
|
|
case 'c' :
|
|
len = _print_char( text, remaining, &info, zpl_cast( char ) va_arg( va, int ) );
|
|
break;
|
|
|
|
case 's' :
|
|
len = _print_string( text, remaining, &info, va_arg( va, char* ) );
|
|
break;
|
|
|
|
case 'r' :
|
|
len = _print_repeated_char( text, remaining, &info, va_arg( va, int ) );
|
|
break;
|
|
|
|
case 'p' :
|
|
info.base = 16;
|
|
info.flags |= ( GEN_FMT_LOWER | GEN_FMT_UNSIGNED | GEN_FMT_ALT | GEN_FMT_INTPTR );
|
|
break;
|
|
|
|
case '%' :
|
|
len = _print_char( text, remaining, &info, '%' );
|
|
break;
|
|
|
|
default :
|
|
fmt--;
|
|
break;
|
|
}
|
|
|
|
fmt++;
|
|
|
|
if ( info.base != 0 )
|
|
{
|
|
if ( info.flags & GEN_FMT_UNSIGNED )
|
|
{
|
|
u64 value = 0;
|
|
switch ( info.flags & GEN_FMT_INTS )
|
|
{
|
|
case GEN_FMT_CHAR :
|
|
value = zpl_cast( u64 ) zpl_cast( u8 ) va_arg( va, int );
|
|
break;
|
|
case GEN_FMT_SHORT :
|
|
value = zpl_cast( u64 ) zpl_cast( u16 ) va_arg( va, int );
|
|
break;
|
|
case GEN_FMT_LONG :
|
|
value = zpl_cast( u64 ) va_arg( va, unsigned long );
|
|
break;
|
|
case GEN_FMT_LLONG :
|
|
value = zpl_cast( u64 ) va_arg( va, unsigned long long );
|
|
break;
|
|
case GEN_FMT_SIZE :
|
|
value = zpl_cast( u64 ) va_arg( va, uw );
|
|
break;
|
|
case GEN_FMT_INTPTR :
|
|
value = zpl_cast( u64 ) va_arg( va, uptr );
|
|
break;
|
|
default :
|
|
value = zpl_cast( u64 ) va_arg( va, unsigned int );
|
|
break;
|
|
}
|
|
|
|
len = _print_u64( text, remaining, &info, value );
|
|
}
|
|
else
|
|
{
|
|
s64 value = 0;
|
|
switch ( info.flags & GEN_FMT_INTS )
|
|
{
|
|
case GEN_FMT_CHAR :
|
|
value = zpl_cast( s64 ) zpl_cast( s8 ) va_arg( va, int );
|
|
break;
|
|
case GEN_FMT_SHORT :
|
|
value = zpl_cast( s64 ) zpl_cast( s16 ) va_arg( va, int );
|
|
break;
|
|
case GEN_FMT_LONG :
|
|
value = zpl_cast( s64 ) va_arg( va, long );
|
|
break;
|
|
case GEN_FMT_LLONG :
|
|
value = zpl_cast( s64 ) va_arg( va, long long );
|
|
break;
|
|
case GEN_FMT_SIZE :
|
|
value = zpl_cast( s64 ) va_arg( va, uw );
|
|
break;
|
|
case GEN_FMT_INTPTR :
|
|
value = zpl_cast( s64 ) va_arg( va, uptr );
|
|
break;
|
|
default :
|
|
value = zpl_cast( s64 ) va_arg( va, int );
|
|
break;
|
|
}
|
|
|
|
len = _print_i64( text, remaining, &info, value );
|
|
}
|
|
}
|
|
|
|
text += len;
|
|
if ( len >= remaining )
|
|
remaining = min( remaining, 1 );
|
|
else
|
|
remaining -= len;
|
|
}
|
|
|
|
*text++ = '\0';
|
|
res = ( text - text_begin );
|
|
return ( res >= max_len || res < 0 ) ? -1 : res;
|
|
}
|
|
|
|
char* str_fmt_buf_va( char const* fmt, va_list va )
|
|
{
|
|
local_persist thread_local char buffer[ GEN_PRINTF_MAXLEN ];
|
|
str_fmt_va( buffer, size_of( buffer ), fmt, va );
|
|
return buffer;
|
|
}
|
|
|
|
char* str_fmt_buf( char const* fmt, ... )
|
|
{
|
|
va_list va;
|
|
char* str;
|
|
va_start( va, fmt );
|
|
str = str_fmt_buf_va( fmt, va );
|
|
va_end( va );
|
|
return str;
|
|
}
|
|
|
|
sw str_fmt_file_va( struct FileInfo* f, char const* fmt, va_list va )
|
|
{
|
|
local_persist thread_local char buf[ GEN_PRINTF_MAXLEN ];
|
|
sw len = str_fmt_va( buf, size_of( buf ), fmt, va );
|
|
b32 res = file_write( f, buf, len - 1 ); // NOTE: prevent extra whitespace
|
|
return res ? len : -1;
|
|
}
|
|
|
|
sw str_fmt_file( struct FileInfo* f, char const* fmt, ... )
|
|
{
|
|
sw res;
|
|
va_list va;
|
|
va_start( va, fmt );
|
|
res = str_fmt_file_va( f, fmt, va );
|
|
va_end( va );
|
|
return res;
|
|
}
|
|
|
|
sw str_fmt_out_va( char const* fmt, va_list va )
|
|
{
|
|
return str_fmt_file_va( file_get_standard( EFileStandard_OUTPUT ), fmt, va );
|
|
}
|
|
|
|
sw str_fmt_out_err_va( char const* fmt, va_list va )
|
|
{
|
|
return str_fmt_file_va( file_get_standard( EFileStandard_ERROR ), fmt, va );
|
|
}
|
|
|
|
sw str_fmt_out_err( char const* fmt, ... )
|
|
{
|
|
sw res;
|
|
va_list va;
|
|
va_start( va, fmt );
|
|
res = str_fmt_out_err_va( fmt, va );
|
|
va_end( va );
|
|
return res;
|
|
}
|
|
|
|
#pragma endregion Printing
|
|
|