mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-11-03 15:26:12 -08:00 
			
		
		
		
	WIP: Restructuring project
This commit is contained in:
		
							
								
								
									
										601
									
								
								base/dependencies/printing.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										601
									
								
								base/dependencies/printing.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,601 @@
 | 
			
		||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
 | 
			
		||||
#	pragma once
 | 
			
		||||
#	include "filesystem.hpp"
 | 
			
		||||
#	include "strings.hpp"
 | 
			
		||||
#	include "string_ops.cpp"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct _format_info _format_info;
 | 
			
		||||
struct _format_info
 | 
			
		||||
{
 | 
			
		||||
	s32 base;
 | 
			
		||||
	s32 flags;
 | 
			
		||||
	s32 width;
 | 
			
		||||
	s32 precision;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
internal ssize _print_string( char* text, ssize max_len, _format_info* info, char const* str )
 | 
			
		||||
{
 | 
			
		||||
	ssize res = 0, len = 0;
 | 
			
		||||
	ssize 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 )
 | 
			
		||||
		// Made the design decision for this library that precision is the length of the string.
 | 
			
		||||
		len = 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 )
 | 
			
		||||
		{
 | 
			
		||||
			ssize 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 ) )
 | 
			
		||||
		{
 | 
			
		||||
			ssize   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 ssize _print_char( char* text, ssize max_len, _format_info* info, char arg )
 | 
			
		||||
{
 | 
			
		||||
	char str[ 2 ] = "";
 | 
			
		||||
	str[ 0 ]      = arg;
 | 
			
		||||
	return _print_string( text, max_len, info, str );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal ssize _print_repeated_char( char* text, ssize max_len, _format_info* info, char arg )
 | 
			
		||||
{
 | 
			
		||||
	ssize  res = 0;
 | 
			
		||||
	s32 rem = ( info ) ? ( info->width > 0 ) ? info->width : 1 : 1;
 | 
			
		||||
	res     = rem;
 | 
			
		||||
	while ( rem-- > 0 )
 | 
			
		||||
		*text++ = arg;
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal ssize _print_i64( char* text, ssize 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 ssize _print_u64( char* text, ssize 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 ssize _print_f64( char* text, ssize max_len, _format_info* info, b32 is_hexadecimal, f64 arg )
 | 
			
		||||
{
 | 
			
		||||
	// TODO: Handle exponent notation
 | 
			
		||||
	ssize    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  = scast( 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  = scast( u64, arg * mult );
 | 
			
		||||
				len    = _print_u64( text, remaining, NULL, value );
 | 
			
		||||
				text  += len;
 | 
			
		||||
				if ( len >= remaining )
 | 
			
		||||
					remaining = min( remaining, 1 );
 | 
			
		||||
				else
 | 
			
		||||
					remaining -= len;
 | 
			
		||||
				arg  -= scast( 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 ssize str_fmt_va( char* text, ssize max_len, char const* fmt, va_list va )
 | 
			
		||||
{
 | 
			
		||||
	char const* text_begin = text;
 | 
			
		||||
	ssize          remaining  = max_len, res;
 | 
			
		||||
 | 
			
		||||
	while ( *fmt )
 | 
			
		||||
	{
 | 
			
		||||
		_format_info info = { 0 };
 | 
			
		||||
		ssize        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 = scast( s32, str_to_i64( fmt, ccast( 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 = scast( s32, str_to_i64( fmt, ccast( 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, scast( char, va_arg( va, int ) ));
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 's' :
 | 
			
		||||
				len = _print_string( text, remaining, &info, va_arg( va, char* ) );
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 'S':
 | 
			
		||||
			{
 | 
			
		||||
				if ( *(fmt + 1) == 'C' )
 | 
			
		||||
				{
 | 
			
		||||
					++ fmt;
 | 
			
		||||
					StrC gen_str   = va_arg( va, StrC);
 | 
			
		||||
					info.precision = gen_str.Len;
 | 
			
		||||
					len            = _print_string( text, remaining, &info, gen_str.Ptr );
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				String gen_str = { va_arg( va, char*) };
 | 
			
		||||
 | 
			
		||||
				info.precision = string_length(gen_str);
 | 
			
		||||
				len            = _print_string( text, remaining, &info, gen_str );
 | 
			
		||||
			}
 | 
			
		||||
			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 = scast( u64, scast( u8, va_arg( va, int )));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_SHORT :
 | 
			
		||||
						value = scast( u64, scast( u16, va_arg( va, int )));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_LONG:
 | 
			
		||||
						value = scast( u64, va_arg( va, unsigned long ));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_LLONG :
 | 
			
		||||
						value = scast( u64, va_arg( va, unsigned long long ));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_SIZE :
 | 
			
		||||
						value = scast( u64, va_arg( va, usize ));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_INTPTR :
 | 
			
		||||
						value = scast( u64, va_arg( va, uptr ));
 | 
			
		||||
						break;
 | 
			
		||||
					default :
 | 
			
		||||
						value = scast( 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 = scast( s64, scast( s8, va_arg( va, int )));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_SHORT :
 | 
			
		||||
						value = scast( s64, scast( s16, va_arg( va, int )));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_LONG :
 | 
			
		||||
						value = scast( s64, va_arg( va, long ));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_LLONG :
 | 
			
		||||
						value = scast( s64, va_arg( va, long long ));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_SIZE :
 | 
			
		||||
						value = scast( s64, va_arg( va, usize ));
 | 
			
		||||
						break;
 | 
			
		||||
					case GEN_FMT_INTPTR :
 | 
			
		||||
						value = scast( s64, va_arg( va, uptr ));
 | 
			
		||||
						break;
 | 
			
		||||
					default :
 | 
			
		||||
						value = scast( 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize str_fmt_file_va( FileInfo* f, char const* fmt, va_list va )
 | 
			
		||||
{
 | 
			
		||||
	local_persist thread_local char buf[ GEN_PRINTF_MAXLEN ];
 | 
			
		||||
	ssize                              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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize str_fmt_file( FileInfo* f, char const* fmt, ... )
 | 
			
		||||
{
 | 
			
		||||
	ssize      res;
 | 
			
		||||
	va_list va;
 | 
			
		||||
	va_start( va, fmt );
 | 
			
		||||
	res = str_fmt_file_va( f, fmt, va );
 | 
			
		||||
	va_end( va );
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize str_fmt( char* str, ssize n, char const* fmt, ... )
 | 
			
		||||
{
 | 
			
		||||
	ssize      res;
 | 
			
		||||
	va_list va;
 | 
			
		||||
	va_start( va, fmt );
 | 
			
		||||
	res = str_fmt_va( str, n, fmt, va );
 | 
			
		||||
	va_end( va );
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize str_fmt_out_va( char const* fmt, va_list va )
 | 
			
		||||
{
 | 
			
		||||
	return str_fmt_file_va( file_get_standard( EFileStandard_OUTPUT ), fmt, va );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize str_fmt_out_err_va( char const* fmt, va_list va )
 | 
			
		||||
{
 | 
			
		||||
	return str_fmt_file_va( file_get_standard( EFileStandard_ERROR ), fmt, va );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize str_fmt_out_err( char const* fmt, ... )
 | 
			
		||||
{
 | 
			
		||||
	ssize      res;
 | 
			
		||||
	va_list va;
 | 
			
		||||
	va_start( va, fmt );
 | 
			
		||||
	res = str_fmt_out_err_va( fmt, va );
 | 
			
		||||
	va_end( va );
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma endregion Printing
 | 
			
		||||
		Reference in New Issue
	
	Block a user