X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=functions%2F_PDCLIB%2Fscan.c;h=0d46f9ecfd53efe0f8a13fdd901487f482198c55;hb=8203e6d8264b7b9918e4b105e3f523c1d1152a7e;hp=c392a5393727dabd7ebf36a15ae4ccc1c78d3ee5;hpb=2fc69672e41cb819b9c51b676190c1b02b05ec49;p=pdclib.old diff --git a/functions/_PDCLIB/scan.c b/functions/_PDCLIB/scan.c index c392a53..0d46f9e 100644 --- a/functions/_PDCLIB/scan.c +++ b/functions/_PDCLIB/scan.c @@ -14,6 +14,7 @@ #include #include #include +#include /* Using an integer's bits as flags for both the conversion flags and length modifiers. @@ -37,7 +38,7 @@ type: integer type, used to get the correct type from the parameter stack as well as for cast target. */ -#define ASSIGN( case_cond, type ) \ +#define ASSIGN_VALUE_TO( case_cond, type ) \ case case_cond: \ *( va_arg( status->arg, type * ) ) = (type)( value * sign ); \ break @@ -316,7 +317,9 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) if ( status->base != -1 ) { /* integer conversion */ - uintmax_t value = 0; + uintmax_t value = 0; /* absolute value read */ + uintmax_t limit; /* max. value allowed */ + uintmax_t threshold; /* overflow threshold */ bool prefix_parsed = false; int sign = 0; while ( ( status->this < status->width ) && @@ -353,6 +356,53 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) UNGET( rc, status ); break; } + switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_intmax | E_size | E_ptrdiff | E_unsigned ) ) + { + case E_char: + limit = ( sign == 1 ) ? CHAR_MAX : ( CHAR_MIN * sign ); + break; + case E_char | E_unsigned: + limit = UCHAR_MAX; + break; + case E_short: + limit = ( sign == 1 ) ? SHRT_MAX : ( SHRT_MIN * sign ); + break; + case E_short | E_unsigned: + limit = USHRT_MAX; + break; + case E_long: + limit = ( sign == 1 ) ? LONG_MAX : ( LONG_MIN * sign ); + break; + case E_long | E_unsigned: + limit = ULONG_MAX; + break; + case E_llong: + limit = ( sign == 1 ) ? LLONG_MAX : ( LLONG_MIN * sign ); + break; + case E_llong | E_unsigned: + limit = ULLONG_MAX; + break; + case E_intmax: + limit = ( sign == 1 ) ? INTMAX_MAX : ( INTMAX_MIN * sign ); + break; + case E_intmax | E_unsigned: + limit = UINTMAX_MAX; + break; + case E_size: + case E_size | E_unsigned: + limit = SIZE_MAX; + break; + case E_ptrdiff: + case E_ptrdiff | E_unsigned: + limit = ( sign == 1 ) ? PTRDIFF_MAX : ( PTRDIFF_MIN * sign ); + break; + case E_unsigned: + limit = UINT_MAX; + break; + default: + limit = ( sign == 1 ) ? INT_MAX : ( INT_MIN * sign ); + break; + } } else if ( ! prefix_parsed ) { @@ -418,9 +468,20 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) UNGET( rc, status ); break; } - value *= status->base; - value += digitptr - _PDCLIB_digits; - value_parsed = true; + // SOLAR + // if ( ( ( limit - ( digitptr - _PDCLIB_digits ) ) / status->base ) >= value ) + //if ( ( ( limit / status->base ) >= value ) && ( ( limit - ( digitptr - _PDCLIB_digits ) ) >= ( value * status->base ) ) ) + { + /* no overflow */ + value *= status->base; + value += digitptr - _PDCLIB_digits; + value_parsed = true; + } + //else + //{ + // value = limit; + // threshold = 0; + //} } } /* width or input exhausted, or non-matching character */ @@ -428,7 +489,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) { /* out of input before anything could be parsed - input error */ /* FIXME: if first character does not match, value_parsed is not set - but it is NOT an input error */ - if ( status->n == 0 ) + if ( ( status->n == 0 ) && ( rc == EOF ) ) { status->n = -1; } @@ -439,22 +500,22 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) E_intmax | E_size | E_ptrdiff | E_unsigned ) ) { - ASSIGN( E_char, char ); - ASSIGN( E_char | E_unsigned, unsigned char ); - ASSIGN( E_short, short ); - ASSIGN( E_short | E_unsigned, unsigned short ); - ASSIGN( 0, int ); - ASSIGN( E_unsigned, unsigned int ); - ASSIGN( E_long, long ); - ASSIGN( E_long | E_unsigned, unsigned long ); - ASSIGN( E_llong, long long ); - ASSIGN( E_llong | E_unsigned, unsigned long long ); - ASSIGN( E_intmax, intmax_t ); - ASSIGN( E_intmax | E_unsigned, uintmax_t ); - ASSIGN( E_size, size_t ); - /* ASSIGN( E_size | E_unsigned, unsigned size_t ); */ - ASSIGN( E_ptrdiff, ptrdiff_t ); - /* ASSIGN( E_ptrdiff | E_unsigned, unsigned ptrdiff_t ); */ + ASSIGN_VALUE_TO( E_char, char ); + ASSIGN_VALUE_TO( E_char | E_unsigned, unsigned char ); + ASSIGN_VALUE_TO( E_short, short ); + ASSIGN_VALUE_TO( E_short | E_unsigned, unsigned short ); + ASSIGN_VALUE_TO( 0, int ); + ASSIGN_VALUE_TO( E_unsigned, unsigned int ); + ASSIGN_VALUE_TO( E_long, long ); + ASSIGN_VALUE_TO( E_long | E_unsigned, unsigned long ); + ASSIGN_VALUE_TO( E_llong, long long ); + ASSIGN_VALUE_TO( E_llong | E_unsigned, unsigned long long ); + ASSIGN_VALUE_TO( E_intmax, intmax_t ); + ASSIGN_VALUE_TO( E_intmax | E_unsigned, uintmax_t ); + ASSIGN_VALUE_TO( E_size, size_t ); + /* ASSIGN_VALUE_TO( E_size | E_unsigned, unsigned size_t ); */ + ASSIGN_VALUE_TO( E_ptrdiff, ptrdiff_t ); + /* ASSIGN_VALUE_TO( E_ptrdiff | E_unsigned, unsigned ptrdiff_t ); */ default: puts( "UNSUPPORTED SCANF FLAG COMBINATION" ); return NULL; /* behaviour unspecified */