Thread: Custom "sprintf" type function

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,735
    Edit: Figured out why I was getting an empty string, was an issue with when I was incrementing term, I'd also forgot to increment arg.text, replaced the offending code near the top of markTextv, getting buffer overflow somewhere now, I'll take a look myself before I post it (if at all)

    Original post:
    k, finished splitting markTextv up into smaller parts, I'm not sure it's possible to make the function smaller at this point, since there where some updates to previously posted code I've decided to just post the lot again, I've split them into sections to make it easier to find the section your after, despite all the logic I've put in I'm somehow getting blank strings so any help is welcome
    Code:
    dint specify_type( dint c )
    {
    	switch ( c )
    	{
    	case 't': /* ptrdiff_t */
    	case 'z': /* size_t */
    	case 'j': /* intmax_t/uintmax_t/dmax/umax */
    	case 'p': /* intptr_t/uintptr_t/dptr/uptr */
    	case 'I': /* int8_t etc */
    	case 'L': /* ldnum */
    	case 'l': /* long/ulong/wchs/wch */
    	case 'h': /* char/short */
    		return c;
    	}
    	return 0;
    }
    
    dint specify_integer( dint c )
    {
    	switch ( c )
    	{
    	case 'd': case 'i': /* signed decimal */
    		return 'd';
    	case 'n': /* pointer to integer */
    	case 'b': /* unsigned binary */
    	case 'o': /* unsigned octal */
    	case 'u': /* unsigned decimal */
    	case 'x': /* unsigned lower case hexedecimal */
    	case 'X': /* unsigned upper case hexadecimal */
    		return c;
    	}
    	return 0;
    }
    
    dint specify_double( dint c )
    {
    	switch ( c )
    	{
    	case 'f': case 'F':
    	case 'g': case 'G':
    	case 'e': case 'E':
    	case 'a': case 'A':
    		return c;
    	}
    	return 0;
    }
    
    dint specify_text( dint c )
    {
    	switch ( c )
    	{
    	case 'c': /* single character */
    	case 's': /* string */
    	}
    	return 0;
    }
    Code:
    typedef struct _ARG
    {
    	uint i;
    	bool addr;
    	uint opts;
    	/* Prefix length */
    	uint pfxl;
    	/* Suffix length */
    	uint sfxl;
    	/* Precision */
    	uint prec;
    	/* Min Count */
    	uint minc;
    	/* Prefix string */
    	achs pfxs;
    	/* Specified type: signed, unsigned, floating point, string, etc */
    	dint spec;
    	/* Variant of type: char, short, long, long long, etc*/
    	dint type;
    	/* Suffix string */
    	achs sfxs;
    	dint const *text;
    } ARG;
    
    typedef enum _ARG_O
    {
    	ARG_O_ALIGN_LEFT = 0,
    	ARG_O_BOTH_SIGNS,
    	ARG_O_PLUS2SPACE,
    	ARG_O_ADD_PREFIX,
    	ARG_O_ADD_SUFFIX,
    	ARG_O_PAD_WITH_0,
    	ARG_O_COUNT,
    	ARG_O_DECIMALDIG = ARG_O_COUNT
    } ARG_O;
    Code:
    BASIC_EXP void optsofArg( ARG *arg )
    {
    static char const opts[ARG_O_COUNT] = { '-', '+', ' ', '#', '~', '0' };
    	uint i, opt;
    	arg->opts = 0;
    	for ( i = 0; i < ARG_O_COUNT; ++i )
    	{
    		opt = (arg->text[0] == opts[i]);
    		arg->opts |= opt << i;
    		arg->text += opt;
    		arg->i += opt;
    	}
    }
    
    BASIC_EXP bool mincofArg( ARG *arg )
    {
    	arg->minc = 0;
    	if ( arg->text[0] == '*' )
    	{
    		arg->text++;
    		arg->i++;
    		return true;
    	}
    
    	if ( isdigit( arg->text[0] ) )
    	{
    		uint i;
    		for ( i = 0; i < bitsof(uint); ++i )
    		{
    			if ( !isdigit( arg->text[0] ) )
    				break;
    			arg->minc *= 10;
    			arg->minc += (arg->text[0] - '0');
    			arg->text++;
    			arg->i++;
    		}
    	}
    
    	return false;
    }
    
    BASIC_EXP bool precofArg( ARG *arg )
    {
    	arg->prec = 0;
    	if ( arg->text[0] == '.' )
    	{
    		uint i;
    		arg->i++;
    		arg->text++;
    		if ( arg->text[0] == '*' )
    		{
    			arg->i++;
    			arg->text++;
    			arg->opts |= (1u << ARG_O_DECIMALDIG);
    			return true;
    		}
    		for ( i = 0; i < bitsof(uint); ++i )
    		{
    			if ( !isdigit( arg->text[0] ) )
    				break;
    			arg->prec *= 10;
    			arg->prec += (arg->text[0] - '0');
    			arg->text++;
    			arg->i++;
    		}
    		arg->opts |= (!!i << ARG_O_DECIMALDIG);
    	}
    	return false;
    }
    
    BASIC_EXP void typeofArg( ARG *arg )
    {
    	dint type;
    	arg->type = specify_type( arg->text[0] );
    	switch ( arg->type )
    	{
    	case 'p':
    		arg->spec = specify_integer( arg->text[1] );
    		if ( !(arg->spec) )
    		{
    			arg->opts |= (1u << ARG_O_ADD_PREFIX);
    			arg->pfxs = "0x";
    			arg->spec = 'X';
    			arg->type = 0;
    			return;
    		}
    		break;
    	case 'L':
    		arg->spec = specify_double( arg->text[1] );
    		if ( !(arg->spec) )
    			arg->spec = 'g';
    		else
    		{
    			arg->text++;
    			arg->i++;
    		}
    		return;
    	default:
    		if ( !(arg->type) )
    		{
    			do
    			{
    				arg->spec = specify_integer( arg->text[0] );
    				if ( arg->spec )
    					break;
    				arg->spec = specify_double( arg->text[0] );
    				if ( arg->spec )
    					break;
    				arg->spec = specify_text( arg->text[0] );
    					break;
    				return;
    			}
    			while (0);
    			arg->text++;
    			arg->i++;
    			return;
    		}
    	}
    	type = specify_type( arg->text[1] );
    	if ( type )
    	{
    		if ( type != arg->type )
    		{
    			arg->spec = 'd';
    			return;
    		}
    		switch ( type )
    		{
    		case 'l':
    			arg->type = 'L';
    			arg->text++;
    			arg->i++;
    			break;
    		case 'h':
    			arg->type = 'H';
    			arg->text++;
    			arg->i++;
    			break;
    		default:
    			arg->spec = 'd';
    			return;
    		}
    	}
    	arg->spec = specify_integer( arg->text[1] );
    	if ( arg->spec )
    	{
    		arg->i++;
    		arg->text++;
    		return;
    	}
    	arg->spec = specify_text( arg->text[1] );
    	if ( arg->spec )
    	{
    		arg->i++;
    		arg->text++;
    		return;
    	}
    	arg->spec = 'd';
    }
    
    /* Extend length */
    BASIC_EXP void extlenArg( ARG *arg )
    {
    	arg->pfxl = 0;
    	arg->sfxl = 0;
    	if ( specify_text( arg->spec ) )
    	{
    		arg->pfxl = 1 + (arg->type == 'l');
    		arg->sfxl = 1;
    		return;
    	}
    	switch ( arg->spec )
    	{
    	case 'b': case 'x': case 'X': case 'a': case 'A':
    		arg->pfxl = 2;
    		break;
    	case 'o':
    		arg->pfxl = 1;
    		break;
    	case 'u':
    		arg->sfxl = 1;
    		break;
    	}
    	switch ( arg->type )
    	{
    	case 'h': case 'l': arg->sfxl += 1; break;
    	case 'H': case 'L': arg->sfxl += 2; break;
    	}
    }
    Code:
    BASIC_EXP uint addpfx( DINTS *Text, ARG *arg, uint j )
    {
    	dint *text = Text->array;
    	if ( arg->pfxl )
    	{
    		switch ( arg->spec )
    		{
    		case 'o': text[j++] = '0'; break;
    		case 'b': text[j++] = '0'; text[j++] = 'b'; break;
    		case 'x': case 'a': text[j++] = '0'; text[j++] = 'x'; break;
    		case 'X': case 'A': text[j++] = '0'; text[j++] = 'X'; break;
    		case 'c':
    			text[j] = 'L';
    			j += (arg->type == 'l');
    			text[j++] = '\'';
    			break;
    		case 's':
    			text[j] = 'L';
    			j += (arg->type == 'l');
    			text[j++] = '"';
    		}
    	}
    	return j;
    }
    BASIC_EXP uint addsfx( DINTS *Text, ARG *arg, uint j )
    {
    	dint *text = Text->array;
    	if ( arg->sfxl )
    	{
    		switch ( arg->spec )
    		{
    		case 'u': text[j++] = 'U'; break;
    		case 'c': text[j++] = '\''; return j;
    		case 's': text[j++] = '"'; return j;
    		}
    		if ( specify_double( arg->spec ) )
    			return j;
    		switch ( arg->type )
    		{
    		case 'L': case 'H':
    			text[j++] = arg->type;
    			text[j++] = arg->type;
    			break;
    		case 'l': text[j++] = 'L'; break;
    		case 'h': text[j++] = 'H'; break;
    		case 'j': text[j++] = 'J'; break;
    		case 'p': text[j++] = 'P'; break;
    		case 'z': text[j++] = 'Z'; break;
    		case 't': text[j++] = 'T';
    		}
    	}
    	return j;
    }
    achs baseofArg( ARG *arg )
    {
    	switch ( arg->spec )
    	{
    	case 'X': case 'A': case 'p':
    		arg->pfxs = "0x";
    		return ACHS_0TO9 "ABCDEF";
    	case 'x': case 'a':
    		arg->pfxs = "0x";
    		return ACHS_0TO9 "abcdef";
    	case 'o':
    		arg->pfxs = "0";
    		return "01234567";
    	case 'b':
    		arg->pfxs = "0b";
    		return "01";
    	}
    	arg->pfxs = "";
    	return ACHS_0TO9;
    }
    Code:
    BASIC_EXP dint addWcs( void *ud, DINTS *Text, wchs str, uint not0 )
    {
    	dint *text;
    	uint i, b4;
    	dint err;
    	if ( str )
    		not0 = not0 ? not0 : wchsnot0(str);
    	else
    	{
    		str = L"(null)";
    		not0 = wchsnot0(str);
    	}
    	b4 = Text->count;
    	err = growTextc( ud, Text, not0 );
    	if ( err )
    	{
    		ECHO_ERRNO( stdout, err );
    		return err;
    	}
    	text = Text->array;
    	text += (b4 - !!b4);
    	for ( i = 0; i < not0; ++i )
    		text[i] = str[i];
    	return 0;
    }
    
    BASIC_EXP dint addStr( void *ud, DINTS *Text, achs str, uint not0 )
    {
    	dint *text;
    	uint i, b4;
    	dint err;
    	if ( str )
    		not0 = not0 ? not0 : achsnot0(str);
    	else
    	{
    		str = "(null)";
    		not0 = achsnot0(str);
    	}
    	b4 = Text->count;
    	err = growTextc( ud, Text, not0 );
    	if ( err )
    	{
    		ECHO_ERRNO( stdout, err );
    		return err;
    	}
    	text = Text->array;
    	text += (b4 - !!b4);
    	for ( i = 0; i < not0; ++i )
    		text[i] = str[i];
    	return 0;
    }
    
    BASIC_EXP dint addChar( void *ud, DINTS *Text, dint c, uint num )
    {
    	dint *text;
    	uint i, b4;
    	dint err;
    	num += !num;
    	b4 = Text->count;
    	err = growTextc( ud, Text, num );
    	if ( err )
    	{
    		ECHO_ERRNO( stdout, err );
    		return err;
    	}
    	text = Text->array;
    	text += (b4 - !!b4);
    	for ( i = 0; i < num; ++i )
    		text[i] = c;
    	return 0;
    }
    Code:
    BASIC_EXP dint addUint( void *ud, DINTS *Text, ARG *arg, umax val )
    {
    	dint err;
    	ACHN num = {0};
    	uint minc = (arg->opts & (1u << ARG_O_PAD_WITH_0)) ? arg->minc : 0;
    	uint apfx =
    		(arg->opts & (1u << ARG_O_ADD_PREFIX))
    		? achsnot0( arg->pfxs ) : 0;
    	uint both = !!(arg->opts & (1u << ARG_O_BOTH_SIGNS));
    	umax2achs( &num, val, baseofArg(arg) );
    	if ( both )
    	{
    		err = addChar( ud, Text, '+', 1 );
    		if ( err )
    		{
    			ECHO_ERROR( stdout, err );
    			return err;
    		}
    	}
    	if ( apfx )
    	{
    		err = addStr( ud, Text, arg->pfxs, apfx );
    		if ( err )
    		{
    			ECHO_ERROR( stdout, err );
    			return err;
    		}
    	}
    	if ( num.not0 < minc )
    	{
    		addChar( ud, Text, '0', minc - num.not0 );
    		if ( err )
    		{
    			ECHO_ERROR( stdout, err );
    			return err;
    		}
    	}
    	return addStr( ud, Text, num.text, num.not0 );
    }
    
    BASIC_EXP dint addDint( void *ud, DINTS *Text, ARG *arg, dmax val )
    {
    	dint err;
    	ACHN num = {0};
    	uint not0 = 0;
    	uint minc = (arg->opts & (1u << ARG_O_PAD_WITH_0)) ? arg->minc : 0;
    	uint apfx =
    		(arg->opts & (1u << ARG_O_ADD_PREFIX))
    		? achsnot0( arg->pfxs ) : 0;
    	uint both = !!(arg->opts & (1u << ARG_O_BOTH_SIGNS));
    	dmax2achs( &num, val, baseofArg(arg) );
    	not0 = both + num.not0 + apfx;
    	if ( num.sign[0] == '-' || both )
    	{
    		if ( !minc && arg->minc > not0 )
    		{
    			err = addChar( ud, Text, ' ', arg->minc - not0 );
    			if ( err )
    			{
    				ECHO_ERROR( stdout, err );
    				return err;
    			}
    		}
    		err = addChar( ud, Text, num.sign[0], 1 );
    		if ( err )
    		{
    			ECHO_ERROR( stdout, err );
    			return err;
    		}
    	}
    	if ( apfx )
    	{
    		err = addStr( ud, Text, arg->pfxs, apfx );
    		if ( err )
    		{
    			ECHO_ERROR( stdout, err );
    			return err;
    		}
    	}
    	if ( not0 < minc )
    	{
    		addChar( ud, Text, '0', minc - not0 );
    		if ( err )
    		{
    			ECHO_ERROR( stdout, err );
    			return err;
    		}
    	}
    	return addStr( ud, Text, num.text, num.not0 );
    }
    
    BASIC_EXP dint addPtr( void *ud, DINTS *Text, ARG *arg, ptr val )
    {
    	ARG tmp = *arg;
    	tmp.opts &= ~(1u << ARG_O_BOTH_SIGNS);
    	tmp.opts |=  (1u << ARG_O_ADD_PREFIX);
    	tmp.pfxs = "0x";
    	tmp.type = 'p';
    	tmp.spec = 'X';
    	return addUint( ud, Text, &tmp, (uptr)val );
    }
    
    BASIC_EXP dint addFloat( void *ud, DINTS *Text, ARG *arg, ldnum val )
    {
    	ARG tmp = {0};
    	uint not0, prec, expl;
    	ACHF num;
    	dint err;
    	dint spec = tolower( arg->spec );
    	bool pad0 = !!(arg->opts & (1u << ARG_O_PAD_WITH_0));
    	bool both = !!(arg->opts & (1u << ARG_O_BOTH_SIGNS));
    	ldnum2achs( &num, val, baseofArg( arg ) );
    	/* Exponent, examples: e+10 e-10 */
    	expl = num.exp.not0 + !!(num.exp.not0) + !!(num.exp.not0);
    	prec = (arg->opts & (1u << ARG_O_DECIMALDIG)) ? arg->prec : num.dec.not0;
    	not0 = prec + num.num.not0 + arg->pfxl + expl;
    	tmp.spec = 'd';
    	tmp.pfxs = arg->pfxs;
    	if ( arg->minc > not0 )
    	{
    		if ( pad0 )
    			tmp.minc = arg->minc - not0;
    		else
    		{
    			err = addChar( ud, Text, ' ', arg->minc - not0 );
    			if ( err )
    			{
    				ECHO_ERRNO( stdout, err );
    				return err;
    			}
    		}
    	}
    	if ( num.num.sign[0] == '-' || both )
    	{
    		err = addChar( ud, Text, num.num.sign[0], 1 );
    		if ( err )
    		{
    			ECHO_ERRNO( stdout, err );
    			return err;
    		}
    	}
    	if ( pad0 && tmp.minc )
    	{
    		err = addChar( ud, Text, '0', tmp.minc );
    		if ( err )
    		{
    			ECHO_ERRNO( stdout, err );
    			return err;
    		}
    	}
    	err = addStr( ud, Text, num.num.text, num.num.not0 );
    	if ( err )
    	{
    		ECHO_ERRNO( stdout, err );
    		return err;
    	}
    	if ( prec && num.zero )
    	{
    		not0 = (num.zero < prec) ? num.zero : prec;
    		err = addChar( ud, Text, '0', not0 );
    		if ( err )
    		{
    			ECHO_ERRNO( stdout, err );
    			return err;
    		}
    		prec -= not0;
    	}
    	if ( prec && num.dec.not0 )
    	{
    		not0 = (num.dec.not0 < prec) ? num.dec.not0 : prec;
    		err = addStr( ud, Text, num.dec.text, not0 );
    		if ( err )
    		{
    			ECHO_ERRNO( stdout, err );
    			return err;
    		}
    		prec -= not0;
    	}
    	if ( prec )
    	{
    		err  = addChar( ud, Text, '0', prec );
    		if ( err )
    		{
    			ECHO_ERRNO( stdout, err );
    			return err;
    		}
    	}
    	if ( num.exp.not0 && spec != 'f' )
    	{
    		ach exp[] = { 0, num.exp.sign[0], 0 };
    		switch ( arg->spec )
    		{
    		case 'e': case 'g': exp[0] = 'e'; break;
    		case 'E': case 'G': exp[0] = 'E'; break;
    		case 'a': exp[0] = 'p'; break;
    		case 'A': exp[0] = 'P'; break;
    		}
    		err = addStr( ud, Text, exp, 2 );
    		if ( err )
    		{
    			ECHO_ERRNO( stdout, err );
    			return err;
    		}
    		err = addStr( ud, Text, num.exp.text, num.exp.not0 );
    		if ( err )
    		{
    			ECHO_ERRNO( stdout, err );
    			return err;
    		}
    	}
    	return 0;
    }
    Code:
    BASIC_EXP dint markTextv( void *ud, DINTS *Text, dint const *args, va_list va )
    {
    	dint err = 0;
    	uint i, j, init = 0, term = 0, not0;
    	ACHN num = {0};
    	ACHF fpn = {0};
    	ARG arg = {0};
    
    	/* Get a rough total number of potential characters */
    	for ( i = 0, j = 0; args[i]; ++i, ++j )
    		j += bitsof(umax) * (args[i] == '%');
    
    	/* Reduce the number of allocations needed to print text */
    	err = initTextt( ud, Text, sizeof(dint), j );
    	if ( err )
    	{
    		ECHO_ERRNO( stdout, err );
    		return err;
    	}
    
    	/* Actually process the arguments this time */
    	for ( arg.text = args; args[arg.i]; )
    	{
    		if ( arg.text[0] != '%' )
    		{
    			++term;
    			arg.i++;
    			arg.text++;
    			continue;
    		}
    
    		if ( term )
    		{
    			err = growTextn( ud, Text, args + init, term - init );
    			if ( err )
    			{
    				ECHO_ERRNO( stdout, err );
    				return err;
    			}
    			init = i;
    			term = i;
    		}
    
    		arg.i++;
    		arg.text++;
    		optsofArg( &arg );
    
    		if ( mincofArg( &arg ) )
    			arg.minc = va_arg( va, uint );
    
    		if ( precofArg(&arg) )
    			arg.prec = va_arg( va, uint );
    		typeofArg(&arg);
    		extlenArg(&arg);
    		if ( !(arg.opts & (1u << ARG_O_ADD_PREFIX)) )
    		{
    			arg.pfxl = 0;
    			arg.sfxl =
    			(
    				!(arg.opts & (1u << ARG_O_ADD_SUFFIX))
    				|| specify_text( arg.spec )
    				|| specify_double( arg.spec )
    			) ? 0 : arg.sfxl;
    		}
    		else if ( !(arg.opts & (1u << ARG_O_ADD_SUFFIX)) )
    		{
    			arg.sfxl = 0;
    			arg.pfxl = specify_text( arg.spec ) ? 0 : arg.pfxl;
    		}
    
    		memset( &num, 0, sizeof(ACHN) );
    		memset( &fpn, 0, sizeof(ACHN) );
    
    		if ( specify_double( arg.spec ) )
    		{
    			err = addFloat
    			(
    				ud, Text, &arg,
    				(arg.type == 'L')
    					? va_arg( va, ldnum )
    					: va_arg( va, dnum )
    			);
    			if ( err )
    			{
    				ECHO_ERRNO( stdout, err );
    				return err;
    			}
    			continue;
    		}
    
    		switch ( arg.spec )
    		{
    		case 'c':
    			err = addChar( ud, Text, va_arg( va, dint ), arg.prec );
    			if ( err )
    			{
    				ECHO_ERRNO( stdout, err );
    				return err;
    			}
    			continue;
    		case 's':
    			not0 = arg.prec;
    			err = ( arg.type == 'l' )
    				? addWcs( ud, Text, va_arg( va, wchs ), not0 )
    				: addStr( ud, Text, va_arg( va, achs ), not0 );
    			if ( err )
    			{
    				ECHO_ERRNO( stdout, err );
    				return err;
    			}
    			continue;
    		case 'p':
    			err = addPtr( ud, Text, &arg, va_arg( va, ptr ) );
    			if ( err )
    			{
    				ECHO_ERRNO( stdout, err );
    				return err;
    			}
    			continue;
    		case 'd':
    			switch ( arg.type )
    			{
    			case 't': err = addDint( ud, Text, &arg, va_arg( va, ptrdiff_t ) );	break;
    			case 'z': err = addDint( ud, Text, &arg, va_arg( va, size_t ) );	break;
    			case 'p': err = addDint( ud, Text, &arg, va_arg( va, dptr ) );		break;
    			case 'j': err = addDint( ud, Text, &arg, va_arg( va, dmax ) );		break;
    			case 'l': err = addDint( ud, Text, &arg, va_arg( va, dlong ) );		break;
    			default:  err = addDint( ud, Text, &arg, va_arg( va, dint ) ); 		break;
    			}
    			continue;
    		default:
    			switch ( arg.type )
    			{
    			case 't': err = addUint( ud, Text, &arg, va_arg( va, ptrdiff_t ) );	break;
    			case 'z': err = addUint( ud, Text, &arg, va_arg( va, size_t ) );	break;
    			case 'p': err = addUint( ud, Text, &arg, va_arg( va, uptr ) );		break;
    			case 'j': err = addUint( ud, Text, &arg, va_arg( va, umax ) );		break;
    			case 'l': err = addUint( ud, Text, &arg, va_arg( va, ulong ) );		break;
    			default:  err = addUint( ud, Text, &arg, va_arg( va, uint ) );		break;
    			}
    			continue;
    		}
    	}
    	return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 06-17-2020, 09:30 AM
  2. Not atoi, not sprintf, but "int coded into char*"
    By Mariano L Gappa in forum C Programming
    Replies: 5
    Last Post: 11-26-2005, 01:53 AM
  3. error with custom "chomp" function
    By kinghajj in forum C Programming
    Replies: 12
    Last Post: 01-05-2004, 08:52 AM
  4. "CWnd"-"HWnd","CBitmap"-"HBitmap"...., What is mean by "
    By L.O.K. in forum Windows Programming
    Replies: 2
    Last Post: 12-04-2002, 07:59 AM

Tags for this Thread