From 56bacb39160e13397fde32a36329461f3ae56ec1 Mon Sep 17 00:00:00 2001 From: Martin Baute Date: Wed, 16 Mar 2016 07:30:16 +0100 Subject: [PATCH] Various updates. Made assert() no longer rely on standard version. Removed _PDCLIB_C_VERSION indirection. Removed gets(). Synced _PDCLIB_config.h. Added some static_assert(). --- functions/_PDCLIB/assert.c | 8 +-- functions/stdio/gets.c | 69 ------------------- includes/assert.h | 29 ++++---- includes/stdio.h | 8 --- internals/_PDCLIB_aux.h | 21 ++---- internals/_PDCLIB_int.h | 18 +++++ platform/example/internals/_PDCLIB_config.h | 16 ++--- .../example_64/internals/_PDCLIB_config.h | 68 ++++++++++++++++++ .../example_cygwin/internals/_PDCLIB_config.h | 68 +++++++++++++++++- 9 files changed, 183 insertions(+), 122 deletions(-) delete mode 100644 functions/stdio/gets.c diff --git a/functions/_PDCLIB/assert.c b/functions/_PDCLIB/assert.c index c568d04..3ca4c47 100644 --- a/functions/_PDCLIB/assert.c +++ b/functions/_PDCLIB/assert.c @@ -12,21 +12,19 @@ #include <_PDCLIB_aux.h> -#if _PDCLIB_C_VERSION == 99 -void _PDCLIB_assert( char const * const message1, char const * const function, char const * const message2 ) +void _PDCLIB_assert99( char const * const message1, char const * const function, char const * const message2 ) { fputs( message1, stderr ); fputs( function, stderr ); fputs( message2, stderr ); abort(); } -#else -void _PDCLIB_assert( char const * const message ) + +void _PDCLIB_assert89( char const * const message ) { fputs( message, stderr ); abort(); } -#endif #endif diff --git a/functions/stdio/gets.c b/functions/stdio/gets.c deleted file mode 100644 index 486509d..0000000 --- a/functions/stdio/gets.c +++ /dev/null @@ -1,69 +0,0 @@ -/* gets( char * ) - - 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 - -#include <_PDCLIB_glue.h> - -char * gets( char * s ) -{ - if ( _PDCLIB_prepread( stdin ) == EOF ) - { - return NULL; - } - char * dest = s; - while ( ( *dest = stdin->buffer[stdin->bufidx++] ) != '\n' ) - { - ++dest; - if ( stdin->bufidx == stdin->bufend ) - { - if ( _PDCLIB_fillbuffer( stdin ) == EOF ) - { - break; - } - } - } - *dest = '\0'; - return ( dest == s ) ? NULL : s; -} - -#endif - -#ifdef TEST -#include <_PDCLIB_test.h> -#include - -int main( void ) -{ - FILE * fh; - char buffer[10]; - char const * gets_test = "foo\nbar\0baz\nweenie"; - TESTCASE( ( fh = fopen( testfile, "wb" ) ) != NULL ); - TESTCASE( fwrite( gets_test, 1, 18, fh ) == 18 ); - TESTCASE( fclose( fh ) == 0 ); - TESTCASE( ( fh = freopen( testfile, "rb", stdin ) ) != NULL ); - TESTCASE( gets( buffer ) == buffer ); - TESTCASE( strcmp( buffer, "foo" ) == 0 ); - TESTCASE( gets( buffer ) == buffer ); - TESTCASE( memcmp( buffer, "bar\0baz\0", 8 ) == 0 ); - TESTCASE( gets( buffer ) == buffer ); - TESTCASE( strcmp( buffer, "weenie" ) == 0 ); - TESTCASE( feof( fh ) ); - TESTCASE( fseek( fh, -1, SEEK_END ) == 0 ); - TESTCASE( gets( buffer ) == buffer ); - TESTCASE( strcmp( buffer, "e" ) == 0 ); - TESTCASE( feof( fh ) ); - TESTCASE( fseek( fh, 0, SEEK_END ) == 0 ); - TESTCASE( gets( buffer ) == NULL ); - TESTCASE( fclose( fh ) == 0 ); - TESTCASE( remove( testfile ) == 0 ); - return TEST_RESULTS; -} - -#endif - diff --git a/includes/assert.h b/includes/assert.h index ce5f7e6..c6054e9 100644 --- a/includes/assert.h +++ b/includes/assert.h @@ -5,15 +5,11 @@ */ #include <_PDCLIB_aux.h> -#include <_PDCLIB_config.h> #ifndef _PDCLIB_ASSERT_H #define _PDCLIB_ASSERT_H _PDCLIB_ASSERT_H -#if _PDCLIB_C_VERSION == 99 -void _PDCLIB_assert( char const * const, char const * const, char const * const ); -#else -void _PDCLIB_assert( char const * const ); -#endif +void _PDCLIB_assert99( char const * const, char const * const, char const * const ); +void _PDCLIB_assert89( char const * const ); #endif /* If NDEBUG is set, assert() is a null operation. */ @@ -22,19 +18,18 @@ void _PDCLIB_assert( char const * const ); #ifdef NDEBUG #define assert( ignore ) ( (void) 0 ) #else -#if _PDCLIB_C_VERSION == 99 +#if __STDC_VERSION__ >= 199901L #define assert( expression ) ( ( expression ) ? (void) 0 \ - : _PDCLIB_assert( "Assertion failed: " #expression \ - ", function ", __func__, \ - ", file " __FILE__ \ - ", line " _PDCLIB_symbol2string( __LINE__ ) \ - "." _PDCLIB_endl ) ) + : _PDCLIB_assert99( "Assertion failed: " #expression \ + ", function ", __func__, \ + ", file " __FILE__ \ + ", line " _PDCLIB_symbol2string( __LINE__ ) \ + "." _PDCLIB_endl ) ) #else #define assert( expression ) ( ( expression ) ? (void) 0 \ - : _PDCLIB_assert( "Assertion failed: " #expression \ - ", file " __FILE__ \ - ", line " _PDCLIB_symbol2string( __LINE__ ) \ - "." _PDCLIB_endl ) ) + : _PDCLIB_assert89( "Assertion failed: " #expression \ + ", file " __FILE__ \ + ", line " _PDCLIB_symbol2string( __LINE__ ) \ + "." _PDCLIB_endl ) ) #endif #endif - diff --git a/includes/stdio.h b/includes/stdio.h index 7616474..d85af17 100644 --- a/includes/stdio.h +++ b/includes/stdio.h @@ -657,14 +657,6 @@ int getc( FILE * stream ); /* Equivalent to fgetc( stdin ). */ int getchar( void ); -/* Read characters from given stream into the array s, stopping at \n or EOF. - The string read is terminated with \0. Returns s if successful. If EOF is - encountered before any characters are read, the contents of s are unchanged, - and NULL is returned. If a read error occurs, the contents of s are indeter- - minate, and NULL is returned. -*/ -char * gets( char * s ); - /* Equivalent to fputc( c, stream ), but may be overloaded by a macro that evaluates its parameter more than once. */ diff --git a/internals/_PDCLIB_aux.h b/internals/_PDCLIB_aux.h index f71fd47..d09c9e7 100644 --- a/internals/_PDCLIB_aux.h +++ b/internals/_PDCLIB_aux.h @@ -22,20 +22,13 @@ #error Compiler does not define _ _STDC_ _ to 1 (not standard-compliant)! #endif -#ifndef __STDC_VERSION__ -#define _PDCLIB_C_VERSION 90 +#if __STDC_VERSION__ < 199901L #define _PDCLIB_restrict #define _PDCLIB_inline -#elif __STDC_VERSION__ == 199409L -#define _PDCLIB_C_VERSION 95 -#define _PDCLIB_restrict -#define _PDCLIB_inline -#elif __STDC_VERSION__ == 199901L -#define _PDCLIB_C_VERSION 99 +#error PDCLib might not be fully conforming to either C89 or C95 prior to v2.x. +#else #define _PDCLIB_restrict restrict #define _PDCLIB_inline inline -#else -#error Unsupported _ _STDC_VERSION_ _ (__STDC_VERSION__) (supported: ISO/IEC 9899:1990, 9899/AMD1:1995, and 9899:1999). #endif #ifndef __STDC_HOSTED__ @@ -48,19 +41,19 @@ #error Compiler does not define _ _STDC_HOSTED_ _ to 0 or 1 (not standard-compliant)! #endif -#if _PDCLIB_C_VERSION != 99 -#error PDCLib might not be fully conforming to either C89 or C95 prior to v2.x. -#endif - /* -------------------------------------------------------------------------- */ /* Helper macros: */ /* _PDCLIB_cc( x, y ) concatenates two preprocessor tokens without extending */ /* _PDCLIB_concat( x, y ) concatenates two preprocessor tokens with extending */ +/* _PDCLIB_static_assert( e, m ) does a compile-time assertion of expression */ +/* e, with m as the failure message. */ /* -------------------------------------------------------------------------- */ #define _PDCLIB_cc( x, y ) x ## y #define _PDCLIB_concat( x, y ) _PDCLIB_cc( x, y ) +#define _PDCLIB_static_assert( e, m ) enum { _PDCLIB_concat( _PDCLIB_assert_, __LINE__ ) = 1 / ( !!(e) ) } + #define _PDCLIB_symbol2value( x ) #x #define _PDCLIB_symbol2string( x ) _PDCLIB_symbol2value( x ) diff --git a/internals/_PDCLIB_int.h b/internals/_PDCLIB_int.h index 77f5286..56eb538 100644 --- a/internals/_PDCLIB_int.h +++ b/internals/_PDCLIB_int.h @@ -436,4 +436,22 @@ struct _PDCLIB_ctype_t unsigned char collation; }; +/* -------------------------------------------------------------------------- */ +/* Configuration asserts */ +/* -------------------------------------------------------------------------- */ + +_PDCLIB_static_assert( _PDCLIB_CHAR_BIT == 8, "CHAR_BIT != 8 not supported." ); + +_PDCLIB_static_assert( sizeof( short ) == _PDCLIB_SHRT_BYTES, "Compiler disagrees on _PDCLIB_SHRT_BYTES." ); +_PDCLIB_static_assert( sizeof( int ) == _PDCLIB_INT_BYTES, "Compiler disagrees on _PDCLIB_INT_BYTES." ); +_PDCLIB_static_assert( sizeof( long ) == _PDCLIB_LONG_BYTES, "Compiler disagrees on _PDCLIB_LONG_BYTES." ); +_PDCLIB_static_assert( sizeof( long long ) == _PDCLIB_LLONG_BYTES, "Compiler disagrees on _PDCLIB_LLONG_BYTES." ); + +_PDCLIB_static_assert( ( (char)-1 < 0 ) == _PDCLIB_CHAR_SIGNED, "Compiler disagrees on _PDCLIB_CHAR_SIGNED." ); +_PDCLIB_static_assert( sizeof( sizeof( int ) ) == sizeof( _PDCLIB_size ), "Compiler disagrees on _PDCLIB_size." ); + +int _PDCLIB_assert_array[2]; + +_PDCLIB_static_assert( sizeof( &_PDCLIB_assert_array[1] - &_PDCLIB_assert_array[0] ) == sizeof( _PDCLIB_ptrdiff ), "Compiler disagrees on _PDCLIB_ptrdiff." ); + #endif diff --git a/platform/example/internals/_PDCLIB_config.h b/platform/example/internals/_PDCLIB_config.h index 88f8a15..843653a 100644 --- a/platform/example/internals/_PDCLIB_config.h +++ b/platform/example/internals/_PDCLIB_config.h @@ -33,14 +33,6 @@ /* to nothing. (This is to avoid warnings with the exit functions under GCC.) */ #define _PDCLIB_NORETURN __attribute__(( noreturn )) -/* The maximum value that errno can be set to. This is used to set the size */ -/* of the array in struct lconv () holding error messages for the */ -/* strerror() and perror() functions. (If you change this value because you */ -/* are using additional errno values, you *HAVE* to provide appropriate error */ -/* messages for *ALL* locales.) */ -/* Default is 4 (0, ERANGE, EDOM, EILSEQ). */ -#define _PDCLIB_ERRNO_MAX 4 - /* -------------------------------------------------------------------------- */ /* Integers */ /* -------------------------------------------------------------------------- */ @@ -355,4 +347,12 @@ typedef int _PDCLIB_fd_t; */ #define _PDCLIB_ERROR 4 +/* The maximum value that errno can be set to. This is used to set the size */ +/* of the array in struct lconv () holding error messages for the */ +/* strerror() and perror() functions. (If you change this value because you */ +/* are using additional errno values, you *HAVE* to provide appropriate error */ +/* messages for *ALL* locales.) */ +/* Default is 4 (0, ERANGE, EDOM, EILSEQ). */ +#define _PDCLIB_ERRNO_MAX 4 + #endif diff --git a/platform/example_64/internals/_PDCLIB_config.h b/platform/example_64/internals/_PDCLIB_config.h index 2a4979b..dc05f4a 100644 --- a/platform/example_64/internals/_PDCLIB_config.h +++ b/platform/example_64/internals/_PDCLIB_config.h @@ -280,4 +280,72 @@ typedef int _PDCLIB_fd_t; */ #define _PDCLIB_UNGETCBUFSIZE 1 +/* errno -------------------------------------------------------------------- */ + +/* These are the values that _PDCLIB_errno can be set to by the library. + + By keeping PDCLib's errno in the _PDCLIB_* namespace, the library is capable + to "translate" between errno values used by the hosting operating system and + those used and passed out by the library. + + Example: In the example platform, the remove() function uses the unlink() + system call as backend. Linux sets its errno to EISDIR if you try to unlink() + a directory, but POSIX demands EPERM. Within the remove() function, you can + catch the 'errno == EISDIR', and set '_PDCLIB_errno = _PDCLIB_EPERM'. Anyone + using PDCLib's will "see" EPERM instead of EISDIR (the _PDCLIB_* + prefix removed by mechanics). + + If you do not want that kind of translation, you might want to "match" the + values used by PDCLib with those used by the host OS, as to avoid confusion. + + The standard only defines three distinct errno values: ERANGE, EDOM, and + EILSEQ. The standard leaves it up to "the implementation" whether there are + any more beyond those three. There is some controversy as to whether errno is + such a good idea at all, so you might want to come up with a different error + reporting facility for your platform. Since errno values beyond the three + defined by the standard are not portable anyway (unless you look at POSIX), + having your own error reporting facility would not hurt anybody either. +*/ +#define _PDCLIB_ERANGE 1 +#define _PDCLIB_EDOM 2 +#define _PDCLIB_EILSEQ 3 + +/* The following is not strictly "configuration", but there is no better place + to explain it than here. + + PDCLib strives to be as generic as possible, so by default it does NOT define + any values beyond the three standard ones above, even where it would have + been prudent and convenient to do so. Any errno "caught" from the host OS, + and some internal error conditions as well, are all lumped together into the + value of '_PDCLIB_ERROR'. + + '_PDCLIB_ERROR' is STRICLY meant as a PLACEHOLDER only. + + You should NEVER ship an adaption of PDCLib still using that particular + value. You should NEVER write code that *tests* for that value. Indeed it is + not even conforming, since errno values should be defined as beginning with + an uppercase 'E', and there is no mechanics in to unmask that + particular value (for exactly that reason). + + There also is no error message available for this value through either the + strerror() or perror() functions. It is being reported as "unknown" error. + + The idea is that you scan the source of PDCLib for occurrences of this macro + and replace _PDCLIB_ERROR with whatever additional errno value you came up + with for your platform. + + If you cannot find it within you to do that, tell your clients to check for + an errno value larger than zero. That, at least, would be standard compliant + (and fully portable). +*/ +#define _PDCLIB_ERROR 4 + +/* The maximum value that errno can be set to. This is used to set the size */ +/* of the array in struct lconv () holding error messages for the */ +/* strerror() and perror() functions. (If you change this value because you */ +/* are using additional errno values, you *HAVE* to provide appropriate error */ +/* messages for *ALL* locales.) */ +/* Default is 4 (0, ERANGE, EDOM, EILSEQ). */ +#define _PDCLIB_ERRNO_MAX 4 + #endif diff --git a/platform/example_cygwin/internals/_PDCLIB_config.h b/platform/example_cygwin/internals/_PDCLIB_config.h index 383a6f9..843653a 100644 --- a/platform/example_cygwin/internals/_PDCLIB_config.h +++ b/platform/example_cygwin/internals/_PDCLIB_config.h @@ -287,6 +287,72 @@ typedef int _PDCLIB_fd_t; */ #define _PDCLIB_UNGETCBUFSIZE 1 -typedef long wint_t; +/* errno -------------------------------------------------------------------- */ + +/* These are the values that _PDCLIB_errno can be set to by the library. + + By keeping PDCLib's errno in the _PDCLIB_* namespace, the library is capable + to "translate" between errno values used by the hosting operating system and + those used and passed out by the library. + + Example: In the example platform, the remove() function uses the unlink() + system call as backend. Linux sets its errno to EISDIR if you try to unlink() + a directory, but POSIX demands EPERM. Within the remove() function, you can + catch the 'errno == EISDIR', and set '_PDCLIB_errno = _PDCLIB_EPERM'. Anyone + using PDCLib's will "see" EPERM instead of EISDIR (the _PDCLIB_* + prefix removed by mechanics). + + If you do not want that kind of translation, you might want to "match" the + values used by PDCLib with those used by the host OS, as to avoid confusion. + + The standard only defines three distinct errno values: ERANGE, EDOM, and + EILSEQ. The standard leaves it up to "the implementation" whether there are + any more beyond those three. There is some controversy as to whether errno is + such a good idea at all, so you might want to come up with a different error + reporting facility for your platform. Since errno values beyond the three + defined by the standard are not portable anyway (unless you look at POSIX), + having your own error reporting facility would not hurt anybody either. +*/ +#define _PDCLIB_ERANGE 1 +#define _PDCLIB_EDOM 2 +#define _PDCLIB_EILSEQ 3 + +/* The following is not strictly "configuration", but there is no better place + to explain it than here. + + PDCLib strives to be as generic as possible, so by default it does NOT define + any values beyond the three standard ones above, even where it would have + been prudent and convenient to do so. Any errno "caught" from the host OS, + and some internal error conditions as well, are all lumped together into the + value of '_PDCLIB_ERROR'. + + '_PDCLIB_ERROR' is STRICLY meant as a PLACEHOLDER only. + + You should NEVER ship an adaption of PDCLib still using that particular + value. You should NEVER write code that *tests* for that value. Indeed it is + not even conforming, since errno values should be defined as beginning with + an uppercase 'E', and there is no mechanics in to unmask that + particular value (for exactly that reason). + + There also is no error message available for this value through either the + strerror() or perror() functions. It is being reported as "unknown" error. + + The idea is that you scan the source of PDCLib for occurrences of this macro + and replace _PDCLIB_ERROR with whatever additional errno value you came up + with for your platform. + + If you cannot find it within you to do that, tell your clients to check for + an errno value larger than zero. That, at least, would be standard compliant + (and fully portable). +*/ +#define _PDCLIB_ERROR 4 + +/* The maximum value that errno can be set to. This is used to set the size */ +/* of the array in struct lconv () holding error messages for the */ +/* strerror() and perror() functions. (If you change this value because you */ +/* are using additional errno values, you *HAVE* to provide appropriate error */ +/* messages for *ALL* locales.) */ +/* Default is 4 (0, ERANGE, EDOM, EILSEQ). */ +#define _PDCLIB_ERRNO_MAX 4 #endif -- 2.40.0