From 9f0fa47bae580e41b5b4bc507a0409c1978a262f Mon Sep 17 00:00:00 2001 From: solar Date: Wed, 7 Apr 2010 13:22:00 +0000 Subject: [PATCH 01/16] Cleanup. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6abc696..9c5b977 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SRCFILES := $(shell find $(PROJDIRS) -mindepth 1 -maxdepth 3 -name "*.c") # All header files of the project HDRFILES := $(shell find $(PROJDIRS) -mindepth 1 -maxdepth 3 -name "*.h") # All .c files in functions/_PDCLIB that do not have a regression test driver -INTFILES := _Exit atomax digits open print scan remove rename seed stdinit strtox_main strtox_prelim cleanstream fflush filemode eol errno seek prepread prepwrite allocpages +INTFILES := _Exit atomax digits open print scan remove rename seed stdinit strtox_main strtox_prelim filemode eol errno seek prepread prepwrite allocpages # All object files in the library OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) # All test drivers (.t) -- 2.40.0 From 5125969b57fe4d64874b2633adcf007bda2a1847 Mon Sep 17 00:00:00 2001 From: solar Date: Wed, 7 Apr 2010 13:22:18 +0000 Subject: [PATCH 02/16] Only the character groups still missing... --- functions/_PDCLIB/scan.c | 105 +++++++++++++++++++++++------- functions/stdio/sscanf.c | 133 +++++++++++++++++++++++++------------- functions/stdio/vsscanf.c | 5 -- 3 files changed, 171 insertions(+), 72 deletions(-) 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 */ diff --git a/functions/stdio/sscanf.c b/functions/stdio/sscanf.c index b701108..343f8ec 100644 --- a/functions/stdio/sscanf.c +++ b/functions/stdio/sscanf.c @@ -29,13 +29,10 @@ int sscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict forma #include #include -#define symbol2value( x ) #x -#define symbol2string( x ) symbol2value( x ) - -#define CHECK_TRUE( a ) do { if ( a == 0 ) { fprintf( stderr, "Unexpected failure in " symbol2string( __LINE__ ) ": '" #a "' evaluated to false.\n" ); rc += 1; } } while ( 0 ) -#define CHECK_FALSE( a ) do { if ( a != 0 ) { fprintf( stderr, "Unexpected failure in " symbol2string( __LINE__ ) ": '" #a "' evaluated to true.\n" ); rc += 1; } } while ( 0 ) -#define CHECK_EQUAL( a, b ) do { int x = a; int y = b; if ( x != y ) { fprintf( stderr, "Mismatch in " symbol2string( __LINE__ ) ": result is %d, expected %d.\n", x, y ); rc += 1; } } while ( 0 ) -#define CHECK_FEQUAL( a, b, T, F ) do { T x = a; T y = b; if ( x != y ) { fprintf( stderr, "Mismatch in " symbol2string( __LINE__ ) ": result is " F ", expected " F ".\n", x, y ); rc += 1; } } while ( 0 ) +#define CHECK_TRUE( a ) TESTCASE( a != 0 ) +#define CHECK_FALSE( a ) TESTCASE( a == 0 ) +#define CHECK_EQUAL( a, b ) do { int x = a; int y = b; TESTCASE( x == y ); } while ( 0 ) +#define CHECK_FEQUAL( a, b, T, F ) do { T x = a; T y = b; TESTCASE( x == y ); } while ( 0 ) // literal matches, character matches, and basic integer matches void suite_one( void ); @@ -47,6 +44,8 @@ void suite_three( void ); void suite_four( void ); // string matches void suite_five( void ); +// 0xz special case +void suite_six( void ); int main() { @@ -55,6 +54,11 @@ int main() suite_three(); suite_four(); suite_five(); +#ifndef REGTEST + // This test driver fails for many common libraries, so it's disabled for + // regression testing. See the function for explanation. + suite_six(); +#endif } // literal matches, character matches, and basic integer matches @@ -1017,8 +1021,8 @@ void suite_three() char const * string = "-0x0 -0x000 -0x7f 0x80 0xff -0x7fff 0x8000\n" "0xffff -0x7fffffff 0x80000000 0xffffffff\n" "-0x7fffffffffffffff 0x8000000000000000\n" - "0xffffffffffffffff -0x\n"; - CHECK_EQUAL( string[145], '\n' ); + "0xffffffffffffffff\n"; + CHECK_EQUAL( string[141], '\n' ); { // reading 0, x unsigned char i = -1; @@ -1036,14 +1040,6 @@ void suite_three() CHECK_EQUAL( n, 4 ); } { - // reading -0x, x - unsigned char i = -1; - int n; - CHECK_EQUAL( sscanf( string + 142, "%hhx%n", &i, &n ), 1 ); - CHECK_EQUAL( i, 0 ); - CHECK_EQUAL( n, 3 ); - } - { // reading 0x000, x unsigned char i = -1; int n; @@ -1080,7 +1076,7 @@ void suite_three() signed char i = -1; int n; CHECK_EQUAL( sscanf( string + 18, "%hhi%n", &i, &n ), 1 ); - CHECK_FEQUAL( i, -128, signed char, "%hd" ); + CHECK_FEQUAL( i, -128, signed char, "%hhd" ); CHECK_EQUAL( n, 4 ); } { @@ -1124,14 +1120,6 @@ void suite_three() CHECK_EQUAL( n, 4 ); } { - // reading -0x, x - unsigned short i = -1; - int n; - CHECK_EQUAL( sscanf( string + 142, "%hx%n", &i, &n ), 1 ); - CHECK_EQUAL( i, 0 ); - CHECK_EQUAL( n, 3 ); - } - { // reading 0x000, x unsigned short i = -1; int n; @@ -1212,14 +1200,6 @@ void suite_three() CHECK_EQUAL( n, 4 ); } { - // reading -0x, x - unsigned int i = -1; - int n; - CHECK_EQUAL( sscanf( string + 142, "%x%n", &i, &n ), 1 ); - CHECK_EQUAL( i, 0 ); - CHECK_EQUAL( n, 3 ); - } - { // reading 0x000, x unsigned int i = -1; int n; @@ -1255,9 +1235,10 @@ void suite_three() // reading 0x80000000, i signed int i = -1; int n; - CHECK_EQUAL( sscanf( string + 62, "%i%n", &i, &n ), 1 ); - CHECK_FEQUAL( i, 2147483647, signed int, "%d" ); // NOT overflowing, see strtol() specs. - CHECK_EQUAL( n, 10 ); + //CHECK_EQUAL( sscanf( string + 62, "%i%n", &i, &n ), 1 ); + CHECK_EQUAL( sscanf( "-0x80000000", "%i%n", &i, &n ), 1 ); + CHECK_FEQUAL( i, -2147483648, signed int, "%d" ); + CHECK_EQUAL( n, 11 ); } { // reading ffffffff, x @@ -1275,14 +1256,6 @@ void suite_three() CHECK_FEQUAL( i, 4294967295, unsigned int, "%d" ); CHECK_EQUAL( n, 10 ); } - { - // reading 0xffffffff, i - signed int i = 0; - int n; - CHECK_EQUAL( sscanf( string + 73, "%i%n", &i, &n ), 1 ); - CHECK_FEQUAL( i, 2147483647, signed int, "%d" ); // NOT overflowing; see strtol() specs. - CHECK_EQUAL( n, 10 ); - } } // octal integer matches @@ -1599,4 +1572,74 @@ void suite_five() } } +void suite_six() +{ + char const * string = "-0xz\n"; + CHECK_EQUAL( string[4], '\n' ); + { + // reading -0x, x + unsigned char i = 1; + int n = -1; + /* Most existing libraries disagree with this test driver, so a little + explanation of why PDCLib chose the implementation it did might be + necessary. All references are from ISO/IEC 9899:1999 "Programming + languages - C". Wording critical to the explanation is in UPPERCASE. + 6.4.4.1 Integer constants - states that '0' is a valid (hexa)decimal + constant, whereas '0x' IS NOT. + 7.19.6.2 The fscanf function - states... + ...in paragraph 9 that "an INPUT ITEM is defined as the longest + sequence of input characters [...] which is, OR IS A PREFIX OF, + a matching input sequence". + ...in paragraph 10 that "if the INPUT ITEM is not a matching + sequence, the execution of THE DIRECTIVE FAILS; this condition + is a matching failure". + ...in footnote 242) that "fscanf pushes back AT MOST ONE input + character onto the input stream." + ...in paragraph 12 that either of the conversion specifiers d, i, + o, u, or x "matches an [...] integer whose format is the same as + expected for THE SUBJECT SEQUENCE of the [strtol|strtoul] + function". + 7.20.1.4 The strtol, strtoll, strtoul, and strtoull functions - states + in paragraph 3 that "the EXPECTED FORM OF THE SUBJECT SEQUENCE is + that of an integer constant AS DESCRIBED IN 6.4.4.1". + These parts of the standard result in the following reasoning: + - The longest sequence of input characters which is a prefix of a + matching input sequence is "-0x" (negative sign, hexadecimal-prefix). + The 'z' is the first character remaining unread as "-0xz" is not a + (prefix of a) matching input sequence. This is according to 7.19.6.2 + paragraph 9. + - "0x", without a valid hexadecimal digit following it, is not a valid + integer constant according to 6.4.4.1. + - "0x" is thus also not of the expected form for a strto[u]l subject + sequence according to 7.20.1.4 paragraph 3. (strto[u]l() would parse + it as zero, but leave the "x" in the final string, i.e. outside the + subject sequence.) + - "0x" is therefore also not a matching sequence to the i or x + conversion specifier according to 7.19.6.2 paragraph 12. + - The conversion should therefore result in a matching failure + according to 7.19.6.2 paragraph 10. + */ + CHECK_EQUAL( sscanf( string, "%hhx%n", &i, &n ), 0 ); + CHECK_EQUAL( i, 1 ); + CHECK_EQUAL( n, -1 ); + } + { + // reading -0x, x + unsigned short i = 1; + int n = -1; + CHECK_EQUAL( sscanf( string, "%hx%n", &i, &n ), 0 ); + CHECK_EQUAL( i, 1 ); + CHECK_EQUAL( n, -1 ); + } + { + // reading -0x, x + unsigned int i = 1; + int n = -1; + CHECK_EQUAL( sscanf( string, "%x%n", &i, &n ), 0 ); + CHECK_EQUAL( i, 1 ); + CHECK_EQUAL( n, -1 ); + } +} + #endif + diff --git a/functions/stdio/vsscanf.c b/functions/stdio/vsscanf.c index fd35889..5126bae 100644 --- a/functions/stdio/vsscanf.c +++ b/functions/stdio/vsscanf.c @@ -62,11 +62,6 @@ int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict form /* NULL return code indicates input error */ if ( rc == NULL ) { - if ( status.n == 0 ) - { - /* input error before any conversion returns EOF */ - status.n = EOF; - } break; } /* Continue parsing after conversion specifier */ -- 2.40.0 From 5e28858ef21764bf55824bab8f55ae45ef6d0b7f Mon Sep 17 00:00:00 2001 From: solar Date: Wed, 7 Apr 2010 19:51:27 +0000 Subject: [PATCH 03/16] Cleanup of artifacts. --- functions/_PDCLIB/scan.c | 69 ++++------------------------------------ 1 file changed, 6 insertions(+), 63 deletions(-) diff --git a/functions/_PDCLIB/scan.c b/functions/_PDCLIB/scan.c index 0d46f9e..82e99fa 100644 --- a/functions/_PDCLIB/scan.c +++ b/functions/_PDCLIB/scan.c @@ -299,6 +299,9 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) return NULL; } } + case '[': + // TODO: SOLAR + break; case 'p': status->base = 16; status->flags |= E_unsigned; @@ -318,8 +321,6 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) { /* integer conversion */ 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 ) && @@ -356,53 +357,6 @@ 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 ) { @@ -468,20 +422,9 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) UNGET( rc, status ); break; } - // 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; - //} + value *= status->base; + value += digitptr - _PDCLIB_digits; + value_parsed = true; } } /* width or input exhausted, or non-matching character */ -- 2.40.0 From 519fc78c528a1d4e07fbd5f8353d5c3f81b8e99b Mon Sep 17 00:00:00 2001 From: solar Date: Wed, 7 Apr 2010 21:28:41 +0000 Subject: [PATCH 04/16] Some fixes to string scanning. First half of scanset scanning. --- functions/_PDCLIB/scan.c | 60 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/functions/_PDCLIB/scan.c b/functions/_PDCLIB/scan.c index 82e99fa..63afff2 100644 --- a/functions/_PDCLIB/scan.c +++ b/functions/_PDCLIB/scan.c @@ -87,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 */ @@ -264,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; } @@ -300,8 +311,47 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) } } case '[': - // TODO: SOLAR - break; + { + 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; -- 2.40.0 From c07ec996170cb522e4ac8179c332dfbca2d8de5b Mon Sep 17 00:00:00 2001 From: solar Date: Thu, 8 Apr 2010 08:37:21 +0000 Subject: [PATCH 05/16] No more errors from _PDCLIB_scan tests. Yay... --- functions/_PDCLIB/scan.c | 52 ++++++++++++++++++++++++++++++++++++---- functions/stdio/sscanf.c | 4 +++- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/functions/_PDCLIB/scan.c b/functions/_PDCLIB/scan.c index 63afff2..8aaabfb 100644 --- a/functions/_PDCLIB/scan.c +++ b/functions/_PDCLIB/scan.c @@ -88,10 +88,40 @@ 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 ) +static bool IN_SCANSET( const char * scanlist, const char * end_scanlist, int rc ) { // SOLAR - return true; + int previous = -1; + while ( scanlist != end_scanlist ) + { + if ( ( *scanlist == '-' ) && ( previous != -1 ) ) + { + /* possible scangroup ("a-z") */ + if ( ++scanlist == end_scanlist ) + { + /* '-' at end of scanlist does not describe a scangroup */ + return rc == '-'; + } + while ( ++previous <= (unsigned char)*scanlist ) + { + if ( previous == rc ) + { + return true; + } + } + previous = -1; + } + else + { + /* not a scangroup, check verbatim */ + if ( rc == (unsigned char)*scanlist ) + { + return true; + } + previous = (unsigned char)(*scanlist++); + } + } + return false; } @@ -330,9 +360,21 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) while ( ( status->this < status->width ) && ( ( rc = GET( status ) ) != EOF ) ) { - if ( NOT_IN_SCANSET( spec, endspec, negative_scanlist, rc ) ) + if ( negative_scanlist ) { - break; + if ( IN_SCANSET( spec, endspec, rc ) ) + { + UNGET( rc, status ); + break; + } + } + else + { + if ( ! IN_SCANSET( spec, endspec, rc ) ) + { + UNGET( rc, status ); + break; + } } value_parsed = true; *(c++) = rc; @@ -345,7 +387,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) } else { - if ( status->n == 0 ) + if ( rc == EOF ) { status->n = -1; } diff --git a/functions/stdio/sscanf.c b/functions/stdio/sscanf.c index 343f8ec..477ed67 100644 --- a/functions/stdio/sscanf.c +++ b/functions/stdio/sscanf.c @@ -1544,7 +1544,9 @@ void suite_five() // missing on first character memset( buffer, '\0', BUFSIZE ); int n; - CHECK_EQUAL( sscanf( string + 0, "%[b]%n", buffer, &n ), 0 ); + int rc_ = sscanf( string + 0, "%[b]%n", buffer, &n ); + CHECK_EQUAL( rc_, 0 ); + //CHECK_EQUAL( sscanf( string + 0, "%[b]%n", buffer, &n ), 0 ); CHECK_FALSE( memcmp( buffer, "", 1 ) ); } { -- 2.40.0 From ebeb585aade62e51dc7b7ddd5de66473f81febfd Mon Sep 17 00:00:00 2001 From: solar Date: Fri, 14 May 2010 03:55:01 +0000 Subject: [PATCH 06/16] Bug #36, covered by testdriver but not yet fixed. --- functions/string/strtok.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/functions/string/strtok.c b/functions/string/strtok.c index c586b97..691c640 100644 --- a/functions/string/strtok.c +++ b/functions/string/strtok.c @@ -91,6 +91,16 @@ int main( void ) TESTCASE( s[7] == 'd' ); TESTCASE( s[8] == '\0' ); TESTCASE( strtok( NULL, "_" ) == NULL ); + strcpy( s, "ab_cd" ); + TESTCASE( strtok( s, "_" ) == &s[0] ); + TESTCASE( s[0] == 'a' ); + TESTCASE( s[1] == 'b' ); + TESTCASE( s[2] == '\0' ); + TESTCASE( strtok( NULL, "_" ) == &s[3] ); + TESTCASE( s[3] == 'c' ); + TESTCASE( s[4] == 'd' ); + TESTCASE( s[5] == '\0' ); + TESTCASE( strtok( NULL, "_" ) == NULL ); return TEST_RESULTS; } #endif -- 2.40.0 From e9a6658165caf38491a04d17a04accec11a3696c Mon Sep 17 00:00:00 2001 From: solar Date: Fri, 14 May 2010 03:59:27 +0000 Subject: [PATCH 07/16] s/stdin/stream to make function actually work. Thanks to Kevin of OSDev.org for pointing this out. --- functions/stdio/fgets.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/functions/stdio/fgets.c b/functions/stdio/fgets.c index f763e33..a3c41e9 100644 --- a/functions/stdio/fgets.c +++ b/functions/stdio/fgets.c @@ -21,16 +21,16 @@ char * fgets( char * _PDCLIB_restrict s, int size, struct _PDCLIB_file_t * _PDCL *s = '\0'; return s; } - if ( _PDCLIB_prepread( stdin ) == EOF ) + if ( _PDCLIB_prepread( stream ) == EOF ) { return NULL; } char * dest = s; - while ( ( ( *dest = stdin->buffer[stdin->bufidx++] ) != '\n' ) && --size > 0 ) + while ( ( ( *dest = stream->buffer[stream->bufidx++] ) != '\n' ) && --size > 0 ) { - if ( stdin->bufidx == stdin->bufend ) + if ( stream->bufidx == stream->bufend ) { - if ( _PDCLIB_fillbuffer( stdin ) == EOF ) + if ( _PDCLIB_fillbuffer( stream ) == EOF ) { /* EOF adds \0, error leaves target indeterminate, so we can just add the \0 anyway. -- 2.40.0 From de813f064004aa2d9c13256af1b075e3b8942b02 Mon Sep 17 00:00:00 2001 From: solar Date: Fri, 14 May 2010 04:12:04 +0000 Subject: [PATCH 08/16] Bug #36 (strtok does not return last token if string does not end with delimiter) fixed. --- functions/string/strtok.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/functions/string/strtok.c b/functions/string/strtok.c index 691c640..b922085 100644 --- a/functions/string/strtok.c +++ b/functions/string/strtok.c @@ -68,7 +68,8 @@ char * strtok( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 ) } /* parsed to end of string */ - return ( tmp = NULL ); + tmp = NULL; + return s1; } #endif -- 2.40.0 From 6089d8ab77f6f7bacbfa6354e8cfecab1b00c8bc Mon Sep 17 00:00:00 2001 From: solar Date: Fri, 14 May 2010 04:17:25 +0000 Subject: [PATCH 09/16] Renamed status->this to status->current to allow for use with C++ compilers. --- functions/_PDCLIB/print.c | 26 +++++++++++++------------- functions/_PDCLIB/scan.c | 18 +++++++++--------- functions/stdio/vfprintf.c | 4 ++-- functions/stdio/vfscanf.c | 2 +- functions/stdio/vsnprintf.c | 4 ++-- internals/_PDCLIB_int.h | 20 ++++++++++---------- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/functions/_PDCLIB/print.c b/functions/_PDCLIB/print.c index c36b009..e131cbb 100644 --- a/functions/_PDCLIB/print.c +++ b/functions/_PDCLIB/print.c @@ -67,7 +67,7 @@ static void int2base( intmax_t value, struct _PDCLIB_status_t * status ) already so it will be taken into account when the deepestmost recursion does the prefix / padding stuff. */ - ++(status->this); + ++(status->current); if ( ( value / status->base ) != 0 ) { /* More digits to be done - recurse deeper */ @@ -110,7 +110,7 @@ static void int2base( intmax_t value, struct _PDCLIB_status_t * status ) } } { - size_t prec_pads = ( status->prec > status->this ) ? ( status->prec - status->this ) : 0; + size_t prec_pads = ( status->prec > status->current ) ? ( status->prec - status->current ) : 0; if ( ! ( status->flags & ( E_minus | E_zero ) ) ) { /* Space padding is only done if no zero padding or left alignment @@ -121,7 +121,7 @@ static void int2base( intmax_t value, struct _PDCLIB_status_t * status ) I've ever perpetrated. Greetings to Samface, DevL, and all sceners at Breakpoint 2006. */ - size_t characters = preidx + ( ( status->this > status->prec ) ? status->this : status->prec ); + size_t characters = preidx + ( ( status->current > status->prec ) ? status->current : status->prec ); if ( status->width > characters ) { for ( size_t i = 0; i < status->width - characters; ++i ) @@ -147,7 +147,7 @@ static void int2base( intmax_t value, struct _PDCLIB_status_t * status ) ++(status->i); } while ( 0 ); */ - ++(status->this); + ++(status->current); } } } @@ -156,17 +156,17 @@ static void int2base( intmax_t value, struct _PDCLIB_status_t * status ) while ( preface[ preidx ] != '\0' ) { DELIVER( preface[ preidx++ ] ); - ++(status->this); + ++(status->current); } if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) ) { /* If field is not left aligned, and zero padding is requested, do so. */ - while ( status->this < status->width ) + while ( status->current < status->width ) { DELIVER( '0' ); - ++(status->this); + ++(status->current); } } /* Do the precision padding if necessary. */ @@ -208,7 +208,7 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status /* Initializing status structure */ status->flags = 0; status->base = 0; - status->this = 0; + status->current = 0; status->width = 0; status->prec = 0; @@ -458,7 +458,7 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status value = (uintmax_t)va_arg( status->arg, size_t ); break; } - ++(status->this); + ++(status->current); if ( ( value / status->base ) != 0 ) { int2base( (intmax_t)(value / status->base), status ); @@ -506,10 +506,10 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status } if ( status->flags & E_minus ) { - while ( status->this < status->width ) + while ( status->current < status->width ) { DELIVER( ' ' ); - ++(status->this); + ++(status->current); } } if ( status->i >= status->n ) @@ -528,13 +528,13 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status static int testprintf( char * buffer, size_t n, const char * format, ... ) { - /* Members: base, flags, n, i, this, s, width, prec, stream, arg */ + /* Members: base, flags, n, i, current, s, width, prec, stream, arg */ struct _PDCLIB_status_t status; status.base = 0; status.flags = 0; status.n = n; status.i = 0; - status.this = 0; + status.current = 0; status.s = buffer; status.width = 0; status.prec = 0; diff --git a/functions/_PDCLIB/scan.c b/functions/_PDCLIB/scan.c index 8aaabfb..ce1dac7 100644 --- a/functions/_PDCLIB/scan.c +++ b/functions/_PDCLIB/scan.c @@ -63,7 +63,7 @@ static int GET( struct _PDCLIB_status_t * status ) if ( rc != EOF ) { ++(status->i); - ++(status->this); + ++(status->current); } return rc; } @@ -83,7 +83,7 @@ static void UNGET( int c, struct _PDCLIB_status_t * status ) --(status->s); } --(status->i); - --(status->this); + --(status->current); } @@ -153,7 +153,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) /* Initializing status structure */ status->flags = 0; status->base = -1; - status->this = 0; + status->current = 0; status->width = 0; status->prec = 0; @@ -272,7 +272,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) status->width = 1; } /* reading until width reached or input exhausted */ - while ( ( status->this < status->width ) && + while ( ( status->current < status->width ) && ( ( rc = GET( status ) ) != EOF ) ) { *(c++) = rc; @@ -297,7 +297,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) case 's': { char * c = va_arg( status->arg, char * ); - while ( ( status->this < status->width ) && + while ( ( status->current < status->width ) && ( ( rc = GET( status ) ) != EOF ) ) { if ( isspace( rc ) ) @@ -357,7 +357,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) } while ( *endspec != ']' ); // read according to scanlist, equiv. to %s above char * c = va_arg( status->arg, char * ); - while ( ( status->this < status->width ) && + while ( ( status->current < status->width ) && ( ( rc = GET( status ) ) != EOF ) ) { if ( negative_scanlist ) @@ -415,7 +415,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) uintmax_t value = 0; /* absolute value read */ bool prefix_parsed = false; int sign = 0; - while ( ( status->this < status->width ) && + while ( ( status->current < status->width ) && ( ( rc = GET( status ) ) != EOF ) ) { if ( isspace( rc ) ) @@ -429,7 +429,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) else { /* leading whitespace not counted against width */ - status->this--; + status->current--; } } else if ( ! sign ) @@ -467,7 +467,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) { /* starts with zero, so it might be a prefix. */ /* check what follows next (might be 0x...) */ - if ( ( status->this < status->width ) && + if ( ( status->current < status->width ) && ( ( rc = GET( status ) ) != EOF ) ) { if ( tolower( rc ) == 'x' ) diff --git a/functions/stdio/vfprintf.c b/functions/stdio/vfprintf.c index 3390533..626ad51 100644 --- a/functions/stdio/vfprintf.c +++ b/functions/stdio/vfprintf.c @@ -15,13 +15,13 @@ int vfprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg ) { /* TODO: This function should interpret format as multibyte characters. */ - /* Members: base, flags, n, i, this, s, width, prec, stream, arg */ + /* Members: base, flags, n, i, current, s, width, prec, stream, arg */ struct _PDCLIB_status_t status; status.base = 0; status.flags = 0; status.n = SIZE_MAX; status.i = 0; - status.this = 0; + status.current = 0; status.s = NULL; status.width = 0; status.prec = 0; diff --git a/functions/stdio/vfscanf.c b/functions/stdio/vfscanf.c index f5b1f3f..8b3a8f7 100644 --- a/functions/stdio/vfscanf.c +++ b/functions/stdio/vfscanf.c @@ -19,7 +19,7 @@ int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict forma status.flags = 0; status.n = 0; status.i = 0; - status.this = 0; + status.current = 0; status.s = NULL; status.width = 0; status.prec = 0; diff --git a/functions/stdio/vsnprintf.c b/functions/stdio/vsnprintf.c index 21e76b1..4dbd7c2 100644 --- a/functions/stdio/vsnprintf.c +++ b/functions/stdio/vsnprintf.c @@ -14,13 +14,13 @@ int vsnprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) { /* TODO: This function should interpret format as multibyte characters. */ - /* Members: base, flags, n, i, this, s, width, prec, stream, arg */ + /* Members: base, flags, n, i, current, s, width, prec, stream, arg */ struct _PDCLIB_status_t status; status.base = 0; status.flags = 0; status.n = n; status.i = 0; - status.this = 0; + status.current = 0; status.s = s; status.width = 0; status.prec = 0; diff --git a/internals/_PDCLIB_int.h b/internals/_PDCLIB_int.h index a950cf2..b5ac49e 100644 --- a/internals/_PDCLIB_int.h +++ b/internals/_PDCLIB_int.h @@ -315,18 +315,18 @@ struct _PDCLIB_memnode_t /* Status structure required by _PDCLIB_print(). */ struct _PDCLIB_status_t { - int base; /* base to which the value shall be converted */ + int base; /* base to which the value shall be converted */ _PDCLIB_int_fast32_t flags; /* flags and length modifiers */ - _PDCLIB_size_t n; /* print: maximum characters to be written */ - /* scan: number matched conversion specifiers */ - _PDCLIB_size_t i; /* number of characters read/written */ - _PDCLIB_size_t this; /* chars read/written in the CURRENT conversion */ - char * s; /* *sprintf(): target buffer */ - /* *sscanf(): source string */ - _PDCLIB_size_t width; /* specified field width */ - _PDCLIB_size_t prec; /* specified field precision */ + _PDCLIB_size_t n; /* print: maximum characters to be written */ + /* scan: number matched conversion specifiers */ + _PDCLIB_size_t i; /* number of characters read/written */ + _PDCLIB_size_t current;/* chars read/written in the CURRENT conversion */ + char * s; /* *sprintf(): target buffer */ + /* *sscanf(): source string */ + _PDCLIB_size_t width; /* specified field width */ + _PDCLIB_size_t prec; /* specified field precision */ struct _PDCLIB_file_t * stream; /* *fprintf() / *fscanf() stream */ - _PDCLIB_va_list arg; /* argument stack */ + _PDCLIB_va_list arg; /* argument stack */ }; /* -------------------------------------------------------------------------- */ -- 2.40.0 From b2570eda3e6ad9685e404465b154c92260da22a0 Mon Sep 17 00:00:00 2001 From: solar Date: Fri, 14 May 2010 04:18:01 +0000 Subject: [PATCH 10/16] Renamed status->this to status->current to allow for use with C++ compilers. --- functions/stdio/vsscanf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/stdio/vsscanf.c b/functions/stdio/vsscanf.c index 5126bae..b494da1 100644 --- a/functions/stdio/vsscanf.c +++ b/functions/stdio/vsscanf.c @@ -19,7 +19,7 @@ int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict form status.flags = 0; status.n = 0; status.i = 0; - status.this = 0; + status.current = 0; status.s = (char *)s; status.width = 0; status.prec = 0; -- 2.40.0 From fb746c58bc267696133020d78116d52e7546a560 Mon Sep 17 00:00:00 2001 From: solar Date: Fri, 14 May 2010 21:13:04 +0000 Subject: [PATCH 11/16] Copy & paste error having sscanf code in there. Fixed. --- functions/stdio/vfscanf.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/functions/stdio/vfscanf.c b/functions/stdio/vfscanf.c index 8b3a8f7..bf09226 100644 --- a/functions/stdio/vfscanf.c +++ b/functions/stdio/vfscanf.c @@ -24,35 +24,39 @@ int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict forma status.width = 0; status.prec = 0; status.stream = stream; + // = { 0, 0, 0, 0, 0, NULL, 0, 0, stream } va_copy( status.arg, arg ); - // FIXME: This whole shebang should operate on STREAM, not S... while ( *format != '\0' ) { const char * rc; if ( ( *format != '%' ) || ( ( rc = _PDCLIB_scan( format, &status ) ) == format ) ) { + int c; /* No conversion specifier, match verbatim */ if ( isspace( *format ) ) { /* Whitespace char in format string: Skip all whitespaces */ - /* No whitespaces in input do not result in matching error */ - while ( isspace( *status.s ) ) + /* No whitespaces in input does not result in matching error */ + while ( isspace( c = getc( stream ) ) ) { - ++status.s; ++status.i; } + if ( c != EOF ) + { + ungetc( c, stream ); + } } else { /* Non-whitespace char in format string: Match verbatim */ - if ( *status.s != *format ) + if ( ( c = getc( stream ) ) != *format ) { /* Matching error */ + ungetc( c, stream ); return status.n; } else { - ++status.s; ++status.i; } } @@ -80,6 +84,7 @@ int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict forma int main( void ) { + /* TODO: Check whitespace / EOF / ungetc handling */ TESTCASE( NO_TESTDRIVER ); return TEST_RESULTS; } -- 2.40.0 From 268c42b566c2be8deaf4c9c8571d3d2e23bae92d Mon Sep 17 00:00:00 2001 From: solar Date: Fri, 14 May 2010 22:07:08 +0000 Subject: [PATCH 12/16] Compacted initializing of status struct. --- functions/stdio/vfprintf.c | 14 +++----------- functions/stdio/vfscanf.c | 13 ++----------- functions/stdio/vsnprintf.c | 16 +++------------- functions/stdio/vsscanf.c | 13 +++---------- 4 files changed, 11 insertions(+), 45 deletions(-) diff --git a/functions/stdio/vfprintf.c b/functions/stdio/vfprintf.c index 626ad51..14e666a 100644 --- a/functions/stdio/vfprintf.c +++ b/functions/stdio/vfprintf.c @@ -15,18 +15,10 @@ int vfprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg ) { /* TODO: This function should interpret format as multibyte characters. */ - /* Members: base, flags, n, i, current, s, width, prec, stream, arg */ - struct _PDCLIB_status_t status; - status.base = 0; - status.flags = 0; - status.n = SIZE_MAX; - status.i = 0; - status.current = 0; - status.s = NULL; - status.width = 0; - status.prec = 0; - status.stream = stream; + /* base, flags, n, i, current, s, width, prec, stream, arg */ + struct _PDCLIB_status_t status = { 0, 0, SIZE_MAX, 0, 0, NULL, 0, 0, stream, NULL }; va_copy( status.arg, arg ); + while ( *format != '\0' ) { const char * rc; diff --git a/functions/stdio/vfscanf.c b/functions/stdio/vfscanf.c index bf09226..16ea592 100644 --- a/functions/stdio/vfscanf.c +++ b/functions/stdio/vfscanf.c @@ -14,17 +14,8 @@ int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg ) { - struct _PDCLIB_status_t status; - status.base = 0; - status.flags = 0; - status.n = 0; - status.i = 0; - status.current = 0; - status.s = NULL; - status.width = 0; - status.prec = 0; - status.stream = stream; - // = { 0, 0, 0, 0, 0, NULL, 0, 0, stream } + /* base, flags, n, i, current, s, width, prec, stream, arg */ + struct _PDCLIB_status_t status = { 0, 0, 0, 0, 0, NULL, 0, 0, stream, NULL }; va_copy( status.arg, arg ); while ( *format != '\0' ) { diff --git a/functions/stdio/vsnprintf.c b/functions/stdio/vsnprintf.c index 4dbd7c2..dee30dc 100644 --- a/functions/stdio/vsnprintf.c +++ b/functions/stdio/vsnprintf.c @@ -13,20 +13,10 @@ int vsnprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) { - /* TODO: This function should interpret format as multibyte characters. */ - /* Members: base, flags, n, i, current, s, width, prec, stream, arg */ - struct _PDCLIB_status_t status; - status.base = 0; - status.flags = 0; - status.n = n; - status.i = 0; - status.current = 0; - status.s = s; - status.width = 0; - status.prec = 0; - status.stream = NULL; + /* base, flags, n, i, current, s, width, prec, stream, arg */ + struct _PDCLIB_status_t status = { 0, 0, n, 0, 0, s, 0, 0, NULL, NULL }; va_copy( status.arg, arg ); - // = { 0, 0, n, 0, 0, s, 0, 0, NULL }; + while ( *format != '\0' ) { const char * rc; diff --git a/functions/stdio/vsscanf.c b/functions/stdio/vsscanf.c index b494da1..20893c9 100644 --- a/functions/stdio/vsscanf.c +++ b/functions/stdio/vsscanf.c @@ -14,17 +14,10 @@ int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg ) { - struct _PDCLIB_status_t status; - status.base = 0; - status.flags = 0; - status.n = 0; - status.i = 0; - status.current = 0; - status.s = (char *)s; - status.width = 0; - status.prec = 0; - status.stream = NULL; + /* base, flag, n, i, current, s, width, prec, stream, arg */ + struct _PDCLIB_status_t status = { 0, 0, 0, 0, 0, (char *)s, 0, 0, NULL, NULL }; va_copy( status.arg, arg ); + while ( *format != '\0' ) { const char * rc; -- 2.40.0 From fde75f89eae541144585db53ce3f7c29d069b4d2 Mon Sep 17 00:00:00 2001 From: solar Date: Sat, 15 May 2010 00:26:39 +0000 Subject: [PATCH 13/16] Added inttypes.h --- functions/inttypes/imaxabs.c | 32 +++++++++ functions/inttypes/imaxdiv.c | 41 +++++++++++ functions/inttypes/strtoimax.c | 126 +++++++++++++++++++++++++++++++++ functions/inttypes/strtoumax.c | 81 +++++++++++++++++++++ includes/inttypes.h | 117 ++++++++++++++++++++++++++++++ includes/stdlib.h | 3 + 6 files changed, 400 insertions(+) create mode 100755 functions/inttypes/imaxabs.c create mode 100755 functions/inttypes/imaxdiv.c create mode 100755 functions/inttypes/strtoimax.c create mode 100755 functions/inttypes/strtoumax.c create mode 100755 includes/inttypes.h diff --git a/functions/inttypes/imaxabs.c b/functions/inttypes/imaxabs.c new file mode 100755 index 0000000..9beda2b --- /dev/null +++ b/functions/inttypes/imaxabs.c @@ -0,0 +1,32 @@ +/* $Id$ */ + +/* imaxabs( intmax_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include + +#ifndef REGTEST + +intmax_t imaxabs( intmax_t j ) +{ + return ( j >= 0 ) ? j : -j; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> +#include + +int main( void ) +{ + TESTCASE( imaxabs( (intmax_t)0 ) == 0 ); + TESTCASE( imaxabs( INTMAX_MAX ) == INTMAX_MAX ); + TESTCASE( imaxabs( INTMAX_MIN + 1 ) == -( INTMAX_MIN + 1 ) ); + return TEST_RESULTS; +} + +#endif diff --git a/functions/inttypes/imaxdiv.c b/functions/inttypes/imaxdiv.c new file mode 100755 index 0000000..be93b99 --- /dev/null +++ b/functions/inttypes/imaxdiv.c @@ -0,0 +1,41 @@ +/* $Id$ */ + +/* lldiv( long long int, long long int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include + +#ifndef REGTEST + +imaxdiv_t imaxdiv( intmax_t numer, intmax_t denom ) +{ + imaxdiv_t rc; + rc.quot = numer / denom; + rc.rem = numer % denom; + /* TODO: pre-C99 compilers might require modulus corrections */ + return rc; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + imaxdiv_t result; + result = imaxdiv( (intmax_t)5, (intmax_t)2 ); + TESTCASE( result.quot == 2 && result.rem == 1 ); + result = imaxdiv( (intmax_t)-5, (intmax_t)2 ); + TESTCASE( result.quot == -2 && result.rem == -1 ); + result = imaxdiv( (intmax_t)5, (intmax_t)-2 ); + TESTCASE( result.quot == -2 && result.rem == 1 ); + TESTCASE( sizeof( result.quot ) == sizeof( intmax_t ) ); + TESTCASE( sizeof( result.rem ) == sizeof( intmax_t ) ); + return TEST_RESULTS; +} + +#endif diff --git a/functions/inttypes/strtoimax.c b/functions/inttypes/strtoimax.c new file mode 100755 index 0000000..af29d3d --- /dev/null +++ b/functions/inttypes/strtoimax.c @@ -0,0 +1,126 @@ +/* $Id$ */ + +/* strtoimax( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include + +#ifndef REGTEST + +#include + +intmax_t strtoimax( const char * _PDCLIB_restrict nptr, char ** _PDCLIB_restrict endptr, int base ) +{ + intmax_t rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( nptr, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + if ( sign == '+' ) + { + rc = (intmax_t)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)INTMAX_MAX, (uintmax_t)( INTMAX_MAX / base ), (int)( INTMAX_MAX % base ), &sign ); + } + else + { + /* FIXME: This breaks on some machines that round negatives wrongly */ + /* FIXME: Sign error not caught by testdriver */ + rc = (intmax_t)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)INTMAX_MIN, (uintmax_t)( INTMAX_MIN / -base ), (int)( -( INTMAX_MIN % base ) ), &sign ); + } + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) nptr; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +#include + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtoimax( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtoimax( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtoimax( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtoimax( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtoimax( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtoimax( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtoimax( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtoimax( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtoimax( overflow, &endptr, 36 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtoimax( overflow + 1, &endptr, 36 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtoimax( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtoimax( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtoimax( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + /* These tests assume two-complement, but conversion should work for */ + /* one-complement and signed magnitude just as well. Anyone having a */ + /* platform to test this on? */ + errno = 0; +#if INTMAX_MAX == 0x7fffffffffffffffLL + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoimax( "0x7FFFFFFFFFFFFFFF", NULL, 0 ) == 0x7fffffffffffffff ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "0x8000000000000000", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoimax( "-0x7FFFFFFFFFFFFFFF", NULL, 0 ) == (long long)0x8000000000000001 ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x8000000000000000", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x8000000000000001", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#elif INTMAX_MAX == 0x7fffffffffffffffffffffffffffffffLL + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoimax( "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NULL, 0 ) == 0x7fffffffffffffffffffffffffffffff ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "0x80000000000000000000000000000000", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoimax( "-0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NULL, 0 ) == -0x80000000000000000000000000000001 ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x80000000000000000000000000000000", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x80000000000000000000000000000001", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#else +#error Unsupported width of 'long long' (neither 64 nor 128 bit). +#endif + return TEST_RESULTS; +} + +#endif diff --git a/functions/inttypes/strtoumax.c b/functions/inttypes/strtoumax.c new file mode 100755 index 0000000..063e7ab --- /dev/null +++ b/functions/inttypes/strtoumax.c @@ -0,0 +1,81 @@ +/* $Id$ */ + +/* strtoumax( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include + +#ifndef REGTEST + +#include + +uintmax_t strtoumax( const char * _PDCLIB_restrict nptr, char ** _PDCLIB_restrict endptr, int base ) +{ + uintmax_t rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( nptr, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)UINTMAX_MAX, (uintmax_t)( UINTMAX_MAX / base ), (int)( UINTMAX_MAX % base ), &sign ); + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) nptr; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> +#include + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtoumax( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtoumax( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtoumax( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtoumax( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtoumax( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtoumax( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtoumax( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtoumax( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtoumax( overflow, &endptr, 36 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtoumax( overflow + 1, &endptr, 36 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtoumax( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtoumax( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtoumax( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + return TEST_RESULTS; +} + +#endif diff --git a/includes/inttypes.h b/includes/inttypes.h new file mode 100755 index 0000000..5b86807 --- /dev/null +++ b/includes/inttypes.h @@ -0,0 +1,117 @@ +/* $Id$ */ + +/* 7.8 Format conversion of integer types + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_INTTYPES_H +#define _PDCLIB_INTTYPES_H _PDCLIB_INTTYPES_H + +#include + +typedef struct _PDCLIB_imaxdiv_t imaxdiv_t; + +/* TODO: Print / Scan Macros */ +/* +PRId8 PRIdLEAST8 PRIdFAST8 PRIdMAX +PRId16 PRIdLEAST16 PRIdFAST16 PRIdPTR +PRId32 PRIdLEAST32 PRIdFAST32 +PRId64 PRIdLEAST64 PRIdFAST64 + +PRIi8 PRIiLEAST8 PRIiFAST8 PRIiMAX +PRIi16 PRIiLEAST16 PRIiFAST16 PRIdPTR +PRIi32 PRIiLEAST32 PRIiFAST32 +PRIi64 PRIiLEAST64 PRIiFAST64 + +PRIo8 PRIoLEAST8 PRIoFAST8 PRIoMAX +PRIo16 PRIoLEAST16 PRIoFAST16 PRIoPTR +PRIo32 PRIoLEAST32 PRIoFAST32 +PRIo64 PRIoLEAST64 PRIoFAST64 + +PRIu8 PRIuLEAST8 PRIuFAST8 PRIuMAX +PRIu16 PRIuLEAST16 PRIuFAST16 PRIuPTR +PRIu32 PRIuLEAST32 PRIuFAST32 +PRIu64 PRIuLEAST64 PRIuFAST64 + +PRIx8 PRIxLEAST8 PRIxFAST8 PRIxMAX +PRIx16 PRIxLEAST16 PRIxFAST16 PRIxPTR +PRIx32 PRIxLEAST32 PRIxFAST32 +PRIx64 PRIxLEAST64 PRIxFAST64 + +PRIX8 PRIXLEAST8 PRIXFAST8 PRIXMAX +PRIX16 PRIXLEAST16 PRIXFAST16 PRIXPTR +PRIX32 PRIXLEAST32 PRIXFAST32 +PRIX64 PRIXLEAST64 PRIXFAST64 + +SCNd8 SCNdLEAST8 SCNdFAST8 SCNdMAX +SCNd16 SCNdLEAST16 SCNdFAST16 SCNdPTR +SCNd32 SCNdLEAST32 SCNdFAST32 +SCNd64 SCNdLEAST64 SCNdFAST64 + +SCNi8 SCNiLEAST8 SCNiFAST8 SCNiMAX +SCNi16 SCNiLEAST16 SCNiFAST16 SCNdPTR +SCNi32 SCNiLEAST32 SCNiFAST32 +SCNi64 SCNiLEAST64 SCNiFAST64 + +SCNo8 SCNoLEAST8 SCNoFAST8 SCNoMAX +SCNo16 SCNoLEAST16 SCNoFAST16 SCNoPTR +SCNo32 SCNoLEAST32 SCNoFAST32 +SCNo64 SCNoLEAST64 SCNoFAST64 + +SCNu8 SCNuLEAST8 SCNuFAST8 SCNuMAX +SCNu16 SCNuLEAST16 SCNuFAST16 SCNuPTR +SCNu32 SCNuLEAST32 SCNuFAST32 +SCNu64 SCNuLEAST64 SCNuFAST64 + +SCNx8 SCNxLEAST8 SCNxFAST8 SCNxMAX +SCNx16 SCNxLEAST16 SCNxFAST16 SCNxPTR +SCNx32 SCNxLEAST32 SCNxFAST32 +SCNx64 SCNxLEAST64 SCNxFAST64 + +SCNX8 SCNXLEAST8 SCNXFAST8 SCNXMAX +SCNX16 SCNXLEAST16 SCNXFAST16 SCNXPTR +SCNX32 SCNXLEAST32 SCNXFAST32 +SCNX64 SCNXLEAST64 SCNXFAST64 +*/ + +/* 7.8.2 Functions for greatest-width integer types */ + +/* Calculate the absolute value of j */ +intmax_t imaxabs( intmax_t j ); + +/* Return quotient (quot) and remainder (rem) of an integer division in the + imaxdiv_t struct. +*/ +imaxdiv_t imaxdiv( intmax_t numer, intmax_t denom ); + +/* Seperate the character array nptr into three parts: A (possibly empty) + sequence of whitespace characters, a character representation of an integer + to the given base, and trailing invalid characters (including the terminating + null character). If base is 0, assume it to be 10, unless the integer + representation starts with 0x / 0X (setting base to 16) or 0 (setting base to + 8). If given, base can be anything from 0 to 36, using the 26 letters of the + base alphabet (both lowercase and uppercase) as digits 10 through 35. + The integer representation is then converted into the return type of the + function. It can start with a '+' or '-' sign. If the sign is '-', the result + of the conversion is negated. + If the conversion is successful, the converted value is returned. If endptr + is not a NULL pointer, a pointer to the first trailing invalid character is + returned in *endptr. + If no conversion could be performed, zero is returned (and nptr in *endptr, + if endptr is not a NULL pointer). If the converted value does not fit into + the return type, the functions return INTMAX_MIN, INTMAX_MAX, or UINTMAX_MAX, + respectively, depending on the sign of the integer representation and the + return type, and errno is set to ERANGE. +*/ +/* This function is equivalent to strtol() / strtoul() in , but on + the potentially larger type. +*/ +intmax_t strtoimax( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); +uintmax_t strtoumax( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); + +/* TODO: wcstoimax(), wcstoumax() */ + +#endif + diff --git a/includes/stdlib.h b/includes/stdlib.h index 06eb9ce..f84851b 100644 --- a/includes/stdlib.h +++ b/includes/stdlib.h @@ -52,6 +52,9 @@ long double strtold( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restri LLONG_MIN, LLONG_MAX, or ULLONG_MAX respectively, depending on the sign of the integer representation and the return type, and errno is set to ERANGE. */ +/* There is strtoimax() and strtoumax() in operating on intmax_t / + uintmax_t, if the long long versions do not suit your needs. +*/ long int strtol( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); long long int strtoll( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); unsigned long int strtoul( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); -- 2.40.0 From 8a292a8d4b146cc31c81ed21a1925aa10fb6c206 Mon Sep 17 00:00:00 2001 From: solar Date: Sat, 15 May 2010 00:28:09 +0000 Subject: [PATCH 14/16] Minor touches. --- functions/_PDCLIB/print.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/functions/_PDCLIB/print.c b/functions/_PDCLIB/print.c index e131cbb..d0476be 100644 --- a/functions/_PDCLIB/print.c +++ b/functions/_PDCLIB/print.c @@ -15,7 +15,9 @@ /* Using an integer's bits as flags for both the conversion flags and length modifiers. */ -/* FIXME: one too many flags to work on a 16-bit machine */ +/* FIXME: one too many flags to work on a 16-bit machine, join some (e.g. the + width flags) into a combined field. +*/ #define E_minus 1<<0 #define E_plus 1<<1 #define E_alt 1<<2 @@ -40,7 +42,7 @@ i - pointer to number of characters already delivered in this call n - pointer to maximum number of characters to be delivered in this call s - the buffer into which the character shall be delivered - FIXME: ref. fputs() for a better way to buffer handling + TODO: ref. fputs() for a better way to buffer handling */ #define DELIVER( x ) \ do { \ @@ -253,7 +255,6 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status if ( *spec == '*' ) { /* Retrieve width value from argument stack */ -#if 1 int width = va_arg( status->arg, int ); if ( width < 0 ) { @@ -264,15 +265,6 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status { status->width = width; } -#else - /* FIXME: Old version - with unsigned status->width, condition <0 is never true */ - if ( ( status->width = va_arg( status->arg, int ) ) < 0 ) - { - /* Negative value is '-' flag plus absolute value */ - status->flags |= E_minus; - status->width *= -1; - } -#endif ++spec; } else -- 2.40.0 From 2a95d5ad6ffda611e091a718218170d25b82b408 Mon Sep 17 00:00:00 2001 From: solar Date: Sat, 15 May 2010 00:29:42 +0000 Subject: [PATCH 15/16] Minor touches. --- functions/stdio/fclose.c | 1 - 1 file changed, 1 deletion(-) diff --git a/functions/stdio/fclose.c b/functions/stdio/fclose.c index 3f7ce19..8a9301a 100644 --- a/functions/stdio/fclose.c +++ b/functions/stdio/fclose.c @@ -14,7 +14,6 @@ extern struct _PDCLIB_file_t * _PDCLIB_filelist; -/* FIXME: Last file not removed from list. */ int fclose( struct _PDCLIB_file_t * stream ) { struct _PDCLIB_file_t * current = _PDCLIB_filelist; -- 2.40.0 From 73f56e467627b9799275872a7635d9aa15584169 Mon Sep 17 00:00:00 2001 From: solar Date: Sat, 15 May 2010 00:32:23 +0000 Subject: [PATCH 16/16] Added imaxdiv_t (for inttypes.h). --- platform/example/internals/_PDCLIB_config.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/platform/example/internals/_PDCLIB_config.h b/platform/example/internals/_PDCLIB_config.h index d851df5..4251522 100644 --- a/platform/example/internals/_PDCLIB_config.h +++ b/platform/example/internals/_PDCLIB_config.h @@ -145,6 +145,15 @@ struct _PDCLIB_lldiv_t /* You are also required to state the literal suffix for the intmax type */ #define _PDCLIB_INTMAX_LITERAL ll +/* defines imaxdiv(), which is equivalent to the div() function */ +/* family (see further above) with intmax_t as basis. */ + +struct _PDCLIB_imaxdiv_t +{ + _PDCLIB_intmax quot; + _PDCLIB_intmax rem; +}; + /* -------------------------------------------------------------------------- */ /* Floating Point */ /* -------------------------------------------------------------------------- */ -- 2.40.0