X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=functions%2F_PDCLIB%2Fscan.c;h=63afff235e25281778b4bdc584ca42b1e8952596;hb=519fc78c528a1d4e07fbd5f8353d5c3f81b8e99b;hp=c392a5393727dabd7ebf36a15ae4ccc1c78d3ee5;hpb=5522316811fdce2216c4d1320af68dd54909aed5;p=pdclib diff --git a/functions/_PDCLIB/scan.c b/functions/_PDCLIB/scan.c index c392a53..63afff2 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 @@ -86,6 +87,14 @@ static void UNGET( int c, struct _PDCLIB_status_t * status ) } +/* Helper function to check if a character is part of a given scanset */ +static bool NOT_IN_SCANSET( const char * start_scanlist, const char * end_scanlist, bool negate_scanlist, int rc ) +{ + // SOLAR + return true; +} + + const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) { /* generic input character */ @@ -263,20 +272,23 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) { if ( isspace( rc ) ) { + UNGET( rc, status ); if ( value_parsed ) { /* matching sequence terminated by whitespace */ *c = '\0'; - return spec; + ++status->n; + return ++spec; } else { - /* leading whitespace not counted against width */ - --(status->this); + /* matching error */ + return NULL; } } else { + /* match */ value_parsed = true; *(c++) = rc; } @@ -298,6 +310,48 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) return NULL; } } + case '[': + { + const char * endspec = spec; + bool negative_scanlist = false; + if ( *(++endspec) == '^' ) + { + negative_scanlist = true; + ++endspec; + } + spec = endspec; + do + { + // TODO: This can run beyond a malformed format string + ++endspec; + } while ( *endspec != ']' ); + // read according to scanlist, equiv. to %s above + char * c = va_arg( status->arg, char * ); + while ( ( status->this < status->width ) && + ( ( rc = GET( status ) ) != EOF ) ) + { + if ( NOT_IN_SCANSET( spec, endspec, negative_scanlist, rc ) ) + { + break; + } + value_parsed = true; + *(c++) = rc; + } + if ( value_parsed ) + { + *c = '\0'; + ++status->n; + return ++endspec; + } + else + { + if ( status->n == 0 ) + { + status->n = -1; + } + return NULL; + } + } case 'p': status->base = 16; status->flags |= E_unsigned; @@ -316,7 +370,7 @@ 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 */ bool prefix_parsed = false; int sign = 0; while ( ( status->this < status->width ) && @@ -428,7 +482,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 +493,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 */