From: solar Date: Wed, 28 May 2008 06:16:15 +0000 (+0000) Subject: Intermediate work, checked in for safekeeping as I pick up working on this again. X-Git-Tag: v0.5~131 X-Git-Url: https://pd.if.org/git/?p=pdclib;a=commitdiff_plain;h=f93d55176e4db9edfb1840054169003bcca4d1fb Intermediate work, checked in for safekeeping as I pick up working on this again. --- diff --git a/Makefile b/Makefile index ed78f42..bfd64b9 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,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 remove rename seed stdinit strtox_main strtox_prelim cleanstream fflush +INTFILES := _Exit atomax digits open print remove rename seed stdinit strtox_main strtox_prelim cleanstream fflush filemode # All object files in the library OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) # All test drivers (.t) @@ -27,9 +27,10 @@ PATCHFILES1 := $(shell ls platform/example/functions/_PDCLIB/*.c) # All files in platform/example/functions/stdlib (for development only) PATCHFILES2 := $(shell ls platform/example/functions/stdlib/*.c) -CFLAGS := -Wall -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wconversion -Wstrict-prototypes -fno-builtin +WARNINGS := -Wall -Wextra -pedantic -Wno-unused-parameter -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wconversion -fno-builtin +CFLAGS := -g -std=c99 -I./internals $(WARNINGS) $(USERFLAGS) -.PHONY: all clean dist test tests testdrivers regtests regtestdrivers todos fixmes find links unlink help +.PHONY: all clean srcdist bindist test tests testdrivers regtests regtestdrivers todos fixmes find links unlink help all: pdclib.a @@ -38,16 +39,16 @@ pdclib.a: $(OBJFILES) @ar rc pdclib.a $? @echo -test: $(FILE) - $(FILE) +test: functions/$(FILE) + functions/$(FILE) tests: testdrivers - -@rc=0; count=0; echo; for file in $(TSTFILES); do echo " TST $$file"; ./$$file; rc=`expr $$rc + $$?`; count=`expr $$count + 1`; done; echo; echo "Tests executed (linking PDCLib): $$count Tests failed: $$rc"; echo + -@rc=0; count=0; failed=""; echo; for file in $(TSTFILES); do echo " TST $$file"; ./$$file; test=$$?; if [ $$test != 0 ]; then rc=`expr $$rc + $$test`; failed="$$failed $$file"; fi; count=`expr $$count + 1`; done; echo; echo "Tests executed (linking PDCLib): $$count Tests failed: $$rc"; echo; for file in $$failed; do echo "Failed: $$file"; done; testdrivers: $(TSTFILES) regtests: regtestdrivers - -@rc=0; count=0; echo; for file in $(REGFILES); do echo " RTST $$file"; ./$$file; rc=`expr $$rc + $$?`; count=`expr $$count + 1`; done; echo; echo "Tests executed (linking system libc): $$count Tests failed: $$rc"; echo + -@rc=0; count=0; failed=""; echo; for file in $(REGFILES); do echo " RTST $$file"; ./$$file; test=$$?; if [ $$test != 0 ]; then rc=`expr $$rc + $$test`; failed="$$failed $$file"; fi; count=`expr $$count + 1`; done; echo; echo "Tests executed (linking system libc): $$count Tests failed: $$rc"; echo; for file in $$failed; do echo "Failed: $$file"; done; regtestdrivers: $(REGFILES) @@ -56,7 +57,7 @@ regtestdrivers: $(REGFILES) clean: @for file in $(OBJFILES) $(DEPFILES) $(TSTFILES) $(REGFILES) pdclib.a pdclib.tgz; do if [ -f $$file ]; then rm $$file; fi; done -dist: +srcdist: @tar czf pdclib.tgz $(ALLFILES) todos: @@ -66,7 +67,7 @@ fixmes: -@for file in $(ALLFILES); do grep -H FIXME $$file; done; true find: - @find functions/ includes/ internals/ platform/ -name "*\.[ch]" -type f | xargs grep $$FIND + @find functions/ includes/ internals/ platform/ old_stdio/ -name "*\.[ch]" -type f | xargs grep $$FIND links: @echo "Linking platform/example..." @@ -87,7 +88,7 @@ help: @echo @echo "all - build pdclib.a" @echo "clean - remove all object files, dependency files and test drivers" - @echo "dist - build pdclib.tgz (source tarball)" + @echo "srcdist - build pdclib.tgz (source tarball)" @echo "test - test a single testdriver (Usage: FILE=\"test.[rt]\" make test)" @echo "tests - build and run test drivers (link pdclib.a)" @echo " testdrivers - build but do not run test drivers" @@ -102,15 +103,19 @@ help: @echo "%.t - build an individual test driver" @echo "%.r - build an individual regression test driver" @echo "help - print this list" + @echo + @echo "Any additional compiler flags you want to use can be passed as USERFLAGS" + @echo "(Usage: USERFLAGS=\"flags\" make [...])." %.o: %.c Makefile @echo " CC $(patsubst functions/%,%,$@)" - @$(CC) $(CFLAGS) -DNDEBUG -MMD -MP -MT "$*.d $*.t" -g -std=c99 -I./includes -I./internals -c $< -o $@ + @$(CC) $(CFLAGS) -MMD -MP -MT "$*.d $*.t" -I./includes -c $< -o $@ %.t: %.c Makefile pdclib.a @echo " CC $(patsubst functions/%,%,$@)" - @$(CC) $(CFLAGS) -DTEST -g -std=c99 -I./includes -I./internals $< pdclib.a -o $@ + @$(CC) $(CFLAGS) -DTEST -I./includes $< pdclib.a -o $@ %.r: %.c Makefile @echo " CC $(patsubst functions/%,%,$@)" - @$(CC) $(CFLAGS) -Wno-format -DTEST -DREGTEST -g -std=c99 -I./internals $< -o $@ + @$(CC) $(CFLAGS) -Wno-format -DTEST -DREGTEST $< -o $@ + diff --git a/Readme.txt b/Readme.txt index 3bae131..36bdf93 100644 --- a/Readme.txt +++ b/Readme.txt @@ -170,6 +170,19 @@ v0.4 - 2005-02-06 Implementations for parts of . Still missing are the floating point conversions, and the wide-/multibyte-character functions. +v0.4.1 - 2006-11-16 +With v0.5 () taking longer than expected, v0.4.1 was set up as +a backport of bugfixes in the current development code. +- #1 realloc( NULL, size ) fails (fixed) +- #2 stdlib.h - insufficient documentation (fixed) +- #4 Misspelled name in credits (fixed) +- #5 malloc() splits off too-small nodes (fixed) +- #6 qsort() stack overflow (fixed) +- #7 malloc() bug in list handling (fixed) +- #8 strncmp() does not terminate at '\0' (fixed) +- #9 stdint.h dysfunctional (fixed) +- #10 NULL redefinition warnings (fixed) + v0.5 - unreleased Implementations for parts of . Still no locale / wide-char support. Enabled all GCC compiler warnings I could find, and fixed diff --git a/functions/_PDCLIB/fflush.c b/functions/_PDCLIB/fflush.c index 3d26b40..e8c99db 100644 --- a/functions/_PDCLIB/fflush.c +++ b/functions/_PDCLIB/fflush.c @@ -1,27 +1,55 @@ /* $Id$ */ -/* _PDCLIB_fflush( FILE * ) +/* _PDCLIB_flushbuffer( FILE * ) This file is part of the Public Domain C Library (PDCLib). Permission is granted to use, modify, and / or redistribute at will. */ #include +#include +#include -int _PDCLIB_fflush( struct _PDCLIB_file_t * stream ) +#include <_PDCLIB_glue.h> + +_PDCLIB_size_t _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream, _PDCLIB_size_t written, int retries ) { - if ( fwrite( stream->buffer, stream->bufidx, 1, stream ) == stream->bufidx ) - { - stream->bufidx = 0; - return 0; - } - else + _PDCLIB_size_t n = stream->bufidx - written; + int count = _PDCLIB_write( stream, stream->buffer + written, ( n <= INT_MAX ? (int)n : INT_MAX ) ); + written += count; /* if count is -1, we don't need written anyway */ + switch ( count ) { - stream->status |= _PDCLIB_ERRORFLAG; - return EOF; + case -1: + /* write error */ + stream->status |= _PDCLIB_ERRORFLAG; + /* FIXME: Map host errno to PDCLib errno */ + return 0; + case 0: + /* no characters written - retry */ + if ( retries == _PDCLIB_FLUSH_RETRIES ) + { + /* max. number of retries without characters being written */ + stream->status |= _PDCLIB_ERRORFLAG; + /* FIXME: Set errno */ + return 0; + } + _PDCLIB_FLUSH_RETRY_PREP; + return _PDCLIB_flushbuffer( stream, written, retries + 1 ); + default: + /* If the following assert fails, we wrote more characters than + available in the buffer. (???) + */ + assert( written <= stream->bufidx ); + if ( written == stream->bufidx ) + { + /* write complete */ + stream->bufidx = 0; + return written; + } + return _PDCLIB_flushbuffer( stream, written, 0 ); } } - + #ifdef TEST #include <_PDCLIB_test.h> diff --git a/functions/_PDCLIB/filemode.c b/functions/_PDCLIB/filemode.c index 460cc6e..fd734fc 100644 --- a/functions/_PDCLIB/filemode.c +++ b/functions/_PDCLIB/filemode.c @@ -6,8 +6,6 @@ Permission is granted to use, modify, and / or redistribute at will. */ -#ifndef REGTEST - #include /* Helper function that parses the C-style mode string passed to fopen() into @@ -56,14 +54,11 @@ unsigned int _PDCLIB_filemode( char const * const mode ) return 0; } -#endif - #ifdef TEST #include <_PDCLIB_test.h> int main( void ) { -#ifndef REGTEST TESTCASE( _PDCLIB_filemode( "r" ) == _PDCLIB_FREAD ); TESTCASE( _PDCLIB_filemode( "w" ) == _PDCLIB_FWRITE ); TESTCASE( _PDCLIB_filemode( "a" ) == _PDCLIB_FAPPEND ); @@ -79,10 +74,12 @@ int main( void ) TESTCASE( _PDCLIB_filemode( "rb+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "wb+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "ab+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FRW | _PDCLIB_FBIN ) ); -#else - puts( " NOTEST fopen() test driver is PDCLib-specific." ); -#endif + TESTCASE( _PDCLIB_filemode( "x" ) == 0 ); + TESTCASE( _PDCLIB_filemode( "r++" ) == 0 ); + TESTCASE( _PDCLIB_filemode( "wbb" ) == 0 ); + TESTCASE( _PDCLIB_filemode( "a+bx" ) == 0 ); return TEST_RESULTS; } #endif + diff --git a/functions/_PDCLIB/strtox_main.c b/functions/_PDCLIB/strtox_main.c index bc14811..fbdf8bb 100644 --- a/functions/_PDCLIB/strtox_main.c +++ b/functions/_PDCLIB/strtox_main.c @@ -13,7 +13,7 @@ #include #include -_PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, uintmax_t error, uintmax_t limval, uintmax_t limdigit, char * sign ) +_PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, uintmax_t error, uintmax_t limval, int limdigit, char * sign ) { _PDCLIB_uintmax_t rc = 0; int digit = -1; @@ -58,17 +58,17 @@ int main( void ) /* basic functionality */ p = test; errno = 0; - TESTCASE( _PDCLIB_strtox_main( &p, 10u, (uintmax_t)999, (uintmax_t)12, (uintmax_t)3, &sign ) == 123 ); + TESTCASE( _PDCLIB_strtox_main( &p, 10u, (uintmax_t)999, (uintmax_t)12, 3, &sign ) == 123 ); TESTCASE( errno == 0 ); TESTCASE( p == &test[3] ); /* proper functioning to smaller base */ p = test; - TESTCASE( _PDCLIB_strtox_main( &p, 8u, (uintmax_t)999, (uintmax_t)12, (uintmax_t)3, &sign ) == 0123 ); + TESTCASE( _PDCLIB_strtox_main( &p, 8u, (uintmax_t)999, (uintmax_t)12, 3, &sign ) == 0123 ); TESTCASE( errno == 0 ); TESTCASE( p == &test[3] ); /* overflowing subject sequence must still return proper endptr */ p = test; - TESTCASE( _PDCLIB_strtox_main( &p, 4u, (uintmax_t)999, (uintmax_t)1, (uintmax_t)2, &sign ) == 999 ); + TESTCASE( _PDCLIB_strtox_main( &p, 4u, (uintmax_t)999, (uintmax_t)1, 2, &sign ) == 999 ); TESTCASE( errno == ERANGE ); TESTCASE( p == &test[3] ); TESTCASE( sign == '+' ); @@ -76,7 +76,7 @@ int main( void ) errno = 0; p = fail; sign = '-'; - TESTCASE( _PDCLIB_strtox_main( &p, 10u, (uintmax_t)999, (uintmax_t)99, (uintmax_t)8, &sign ) == 0 ); + TESTCASE( _PDCLIB_strtox_main( &p, 10u, (uintmax_t)999, (uintmax_t)99, 8, &sign ) == 0 ); TESTCASE( p == NULL ); return TEST_RESULTS; } diff --git a/functions/stdlib/qsort.c b/functions/stdlib/qsort.c index 084cd3c..6bb636f 100644 --- a/functions/stdlib/qsort.c +++ b/functions/stdlib/qsort.c @@ -41,9 +41,9 @@ void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, { char * i; char * j; - size_t thresh = T * size; - char * base_ = (char *)base; - char * limit = base_ + nmemb * size; + _PDCLIB_ptrdiff_t thresh = T * size; + char * base_ = (char *)base; + char * limit = base_ + nmemb * size; PREPARE_STACK; for ( ;; ) diff --git a/functions/stdlib/strtol.c b/functions/stdlib/strtol.c index 4a3b5a6..04c8617 100644 --- a/functions/stdlib/strtol.c +++ b/functions/stdlib/strtol.c @@ -21,12 +21,12 @@ long int strtol( const char * s, char ** endptr, int base ) if ( base < 2 || base > 36 ) return 0; if ( sign == '+' ) { - rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MAX, (uintmax_t)( LONG_MAX / base ), (uintmax_t)( LONG_MAX % base ), &sign ); + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MAX, (uintmax_t)( LONG_MAX / base ), (int)( LONG_MAX % base ), &sign ); } else { /* FIXME: This breaks on some machines that round negatives wrongly */ - rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MIN, (uintmax_t)( LONG_MIN / -base ), (uintmax_t)( -( LONG_MIN % base ) ), &sign ); + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MIN, (uintmax_t)( LONG_MIN / -base ), (int)( -( LONG_MIN % base ) ), &sign ); } if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s; return ( sign == '+' ) ? rc : -rc; @@ -92,7 +92,7 @@ int main( void ) TESTCASE( strtol( "0x80000000", NULL, 0 ) == LONG_MAX ); TESTCASE( errno == ERANGE ); errno = 0; - TESTCASE( strtol( "-0x7FFFFFFF", NULL, 0 ) == 0x80000001 ); + TESTCASE( strtol( "-0x7FFFFFFF", NULL, 0 ) == (long)0x80000001 ); TESTCASE( errno == 0 ); TESTCASE( strtol( "-0x80000000", NULL, 0 ) == LONG_MIN ); TESTCASE( errno == 0 ); diff --git a/functions/stdlib/strtoll.c b/functions/stdlib/strtoll.c index 768da39..0eb8423 100644 --- a/functions/stdlib/strtoll.c +++ b/functions/stdlib/strtoll.c @@ -21,13 +21,13 @@ long long int strtoll( const char * s, char ** endptr, int base ) if ( base < 2 || base > 36 ) return 0; if ( sign == '+' ) { - rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MAX, (uintmax_t)( LLONG_MAX / base ), (uintmax_t)( LLONG_MAX % base ), &sign ); + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MAX, (uintmax_t)( LLONG_MAX / base ), (int)( LLONG_MAX % base ), &sign ); } else { /* FIXME: This breaks on some machines that round negatives wrongly */ /* FIXME: Sign error not caught by testdriver */ - rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MIN, (uintmax_t)( LLONG_MIN / -base ), (uintmax_t)( -( LLONG_MIN % base ) ), &sign ); + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MIN, (uintmax_t)( LLONG_MIN / -base ), (int)( -( LLONG_MIN % base ) ), &sign ); } if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s; return ( sign == '+' ) ? rc : -rc; @@ -93,7 +93,7 @@ int main( void ) TESTCASE( strtoll( "0x8000000000000000", NULL, 0 ) == LLONG_MAX ); TESTCASE( errno == ERANGE ); errno = 0; - TESTCASE( strtoll( "-0x7FFFFFFFFFFFFFFF", NULL, 0 ) == 0x8000000000000001 ); + TESTCASE( strtoll( "-0x7FFFFFFFFFFFFFFF", NULL, 0 ) == (long long)0x8000000000000001 ); TESTCASE( errno == 0 ); TESTCASE( strtoll( "-0x8000000000000000", NULL, 0 ) == LLONG_MIN ); TESTCASE( errno == 0 ); diff --git a/functions/stdlib/strtoul.c b/functions/stdlib/strtoul.c index 415aadf..68f790a 100644 --- a/functions/stdlib/strtoul.c +++ b/functions/stdlib/strtoul.c @@ -19,7 +19,7 @@ unsigned long int strtoul( const char * s, char ** endptr, int base ) char sign = '+'; const char * p = _PDCLIB_strtox_prelim( s, &sign, &base ); if ( base < 2 || base > 36 ) return 0; - rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)ULONG_MAX, (uintmax_t)( ULONG_MAX / base ), (uintmax_t)( ULONG_MAX % base ), &sign ); + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)ULONG_MAX, (uintmax_t)( ULONG_MAX / base ), (int)( ULONG_MAX % base ), &sign ); if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s; return ( sign == '+' ) ? rc : -rc; } diff --git a/functions/stdlib/strtoull.c b/functions/stdlib/strtoull.c index de48b0f..b4204e9 100644 --- a/functions/stdlib/strtoull.c +++ b/functions/stdlib/strtoull.c @@ -19,7 +19,7 @@ unsigned long long int strtoull( const char * s, char ** endptr, int base ) char sign = '+'; const char * p = _PDCLIB_strtox_prelim( s, &sign, &base ); if ( base < 2 || base > 36 ) return 0; - rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)ULLONG_MAX, (uintmax_t)( ULLONG_MAX / base ), (uintmax_t)( ULLONG_MAX % base ), &sign ); + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)ULLONG_MAX, (uintmax_t)( ULLONG_MAX / base ), (int)( ULLONG_MAX % base ), &sign ); if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s; return ( sign == '+' ) ? rc : -rc; } diff --git a/internals/_PDCLIB_aux.h b/internals/_PDCLIB_aux.h index 72e64cf..71196a5 100644 --- a/internals/_PDCLIB_aux.h +++ b/internals/_PDCLIB_aux.h @@ -1,65 +1,66 @@ -/* $Id$ */ - -/* Auxiliary PDCLib code <_PDCLIB_aux.h> - - This file is part of the Public Domain C Library (PDCLib). - Permission is granted to use, modify, and / or redistribute at will. -*/ - -/* -------------------------------------------------------------------------- */ -/* You should not have to edit anything in this file; if you DO have to, it */ -/* would be considered a bug / missing feature: notify the author(s). */ -/* -------------------------------------------------------------------------- */ - -/* -------------------------------------------------------------------------- */ -/* Standard Version */ -/* -------------------------------------------------------------------------- */ - -/* Many a compiler gets this wrong, so you might have to hardcode it instead. */ - -#if __STDC__ != 1 -#error Compiler does not define _ _STDC_ _ to 1 (not standard-compliant)! -#endif - -#ifndef __STDC_VERSION__ -#define _PDCLIB_C_VERSION 90 -#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 -#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__ -#error Compiler does not define _ _STDC_HOSTED_ _ (not standard-compliant)! -#elif __STDC_HOSTED__ == 0 -#define _PDCLIB_HOSTED 0 -#elif __STDC_HOSTED__ == 1 -#define _PDCLIB_HOSTED 1 -#else -#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 */ -/* -------------------------------------------------------------------------- */ - -#define _PDCLIB_cc( x, y ) x ## y -#define _PDCLIB_concat( x, y ) _PDCLIB_cc( x, y ) - -#define _PDCLIB_symbol2value( x ) #x -#define _PDCLIB_symbol2string( x ) _PDCLIB_symbol2value( x ) -#define _PDCLIB_symbol2identity( x ) x +/* $Id$ */ + +/* Auxiliary PDCLib code <_PDCLIB_aux.h> + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +/* -------------------------------------------------------------------------- */ +/* You should not have to edit anything in this file; if you DO have to, it */ +/* would be considered a bug / missing feature: notify the author(s). */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* Standard Version */ +/* -------------------------------------------------------------------------- */ + +/* Many a compiler gets this wrong, so you might have to hardcode it instead. */ + +#if __STDC__ != 1 +#error Compiler does not define _ _STDC_ _ to 1 (not standard-compliant)! +#endif + +#ifndef __STDC_VERSION__ +#define _PDCLIB_C_VERSION 90 +#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 +#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__ +#error Compiler does not define _ _STDC_HOSTED_ _ (not standard-compliant)! +#elif __STDC_HOSTED__ == 0 +#define _PDCLIB_HOSTED 0 +#elif __STDC_HOSTED__ == 1 +#define _PDCLIB_HOSTED 1 +#else +#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 */ +/* -------------------------------------------------------------------------- */ + +#define _PDCLIB_cc( x, y ) x ## y +#define _PDCLIB_concat( x, y ) _PDCLIB_cc( x, y ) + +#define _PDCLIB_symbol2value( x ) #x +#define _PDCLIB_symbol2string( x ) _PDCLIB_symbol2value( x ) +#define _PDCLIB_symbol2identity( x ) x + diff --git a/internals/_PDCLIB_glue.h b/internals/_PDCLIB_glue.h index 02ba7f9..db29f1e 100644 --- a/internals/_PDCLIB_glue.h +++ b/internals/_PDCLIB_glue.h @@ -15,7 +15,7 @@ /* OS "glue", part 2 */ /* These are the functions you will have to touch, as they are where PDCLib */ /* interfaces with the operating system. */ -/* They operate on data types partially defined by _PDCLIB_config.h. */ +/* Some operate on data types defined by _PDCLIB_config.h. */ /* -------------------------------------------------------------------------- */ /* A system call that terminates the calling process, returning a given status @@ -30,16 +30,18 @@ void _PDCLIB_Exit( int status ) _PDCLIB_NORETURN; */ void * _PDCLIB_allocpages( int n ); -/* A system call that opens a file identified by name in a given mode, and - returns a file descriptor uniquely identifying that file. +/* A system call that opens a file identified by name in a given mode. Return + a file descriptor uniquely identifying that file. + (The mode is the return value of the _PDCLIB_filemode() function.) */ _PDCLIB_fd_t _PDCLIB_open( char const * const filename, unsigned int mode ); -/* A system call that writes n characters to a file identified by given file - descriptor. Return the number of characters actually written, or zero if - an error occured. +/* A system call that writes up to n characters to a file identified by given + file descriptor. Return the number of characters actually written, or -1 + if an error occured. Note that the number of characters may well be lower + than n without an error having occured. */ -_PDCLIB_size_t _PDCLIB_write( _PDCLIB_fd_t fd, char const * buffer, _PDCLIB_size_t n ); +int _PDCLIB_write( struct _PDCLIB_file_t * stream, char const * buffer, int n ); /* A system call that reads n characters into a buffer, from a file identified by given file descriptor. Return the number of characters read. @@ -65,5 +67,5 @@ int _PDCLIB_rename( const char * old, const char * new ); /* A system call that returns one if the given file descriptor refers to an interactive device, and zero otherwise. */ -int _PDCLIB_isinteractive( _PDCLIB_fd_t fd ); +int _PDCLIB_interactive_stream( _PDCLIB_fd_t fd ); diff --git a/internals/_PDCLIB_int.h b/internals/_PDCLIB_int.h index 496f0e6..d4d0d9a 100644 --- a/internals/_PDCLIB_int.h +++ b/internals/_PDCLIB_int.h @@ -251,7 +251,7 @@ typedef unsigned _PDCLIB_intmax _PDCLIB_uintmax_t; /* Flags for representing mode (see fopen()). Note these must fit the same status field as the _IO?BF flags in and the internal flags below. */ -#define _PDCLIB_FREAD 8u +#define _PDCLIB_FREAD 8u #define _PDCLIB_FWRITE 16u #define _PDCLIB_FAPPEND 32u #define _PDCLIB_FRW 64u @@ -274,6 +274,7 @@ struct _PDCLIB_file_t _PDCLIB_size_t bufidx; /* index to point of action in buffer */ _PDCLIB_size_t bufend; /* index to end of pre-read buffer */ unsigned int status; /* misc. status bits */ + char * filename; /* name used in fopen() / freopen() */ struct _PDCLIB_file_t * next; /* provisions for linked list handling */ }; @@ -325,7 +326,7 @@ _PDCLIB_intmax_t _PDCLIB_atomax( const char * s ); /* Two helper functions used by strtol(), strtoul() and long long variants. */ const char * _PDCLIB_strtox_prelim( const char * p, char * sign, int * base ); -_PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, _PDCLIB_uintmax_t error, _PDCLIB_uintmax_t limval, _PDCLIB_uintmax_t limdigit, char * sign ); +_PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, _PDCLIB_uintmax_t error, _PDCLIB_uintmax_t limval, int limdigit, char * sign ); /* Digits arrays used by various integer conversion functions */ extern char _PDCLIB_digits[]; @@ -340,10 +341,16 @@ extern char _PDCLIB_Xdigits[]; */ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status ); +/* Common denominator of puts() and fputs() */ +int _PDCLIB_puts( const char * s, const char * endl, struct _PDCLIB_file_t * stream ); + /* Parsing any fopen() style filemode string into a number of flags. */ unsigned int _PDCLIB_filemode( const char * mode ); -/* Writing out unwritten buffers to file. Returns 0 if successful, EOF if error - occured. Sets error flag of stream in case of error. - */ -int _PDCLIB_fflush( struct _PDCLIB_file_t * stream ); +/* Writing out unwritten buffers of a specific stream. A NULL parameter (as is + possible with standard fflush()) is not supported. + Return 0 if successful, EOF if error occured. Set error flag of stream and + errno as appropriate in case of error. +*/ +_PDCLIB_size_t _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream, _PDCLIB_size_t written, int retries ); + diff --git a/platform/example/functions/_PDCLIB/_Exit.c b/platform/example/functions/_PDCLIB/_Exit.c index e90dfc6..c3ecfbc 100644 --- a/platform/example/functions/_PDCLIB/_Exit.c +++ b/platform/example/functions/_PDCLIB/_Exit.c @@ -30,7 +30,9 @@ void _PDCLIB_Exit( int status ) int main( void ) { - TESTCASE( NO_TESTDRIVER ); + int UNEXPECTED_RETURN = 0; + _PDCLIB_Exit( 0 ); + TESTCASE( UNEXPECTED_RETURN ); return TEST_RESULTS; } diff --git a/platform/example/functions/_PDCLIB/open.c b/platform/example/functions/_PDCLIB/open.c index 40d294f..fc82485 100644 --- a/platform/example/functions/_PDCLIB/open.c +++ b/platform/example/functions/_PDCLIB/open.c @@ -22,12 +22,10 @@ int _PDCLIB_open( char const * const filename, unsigned int mode ) { - /* FIXME: THIS IS NOT TO BE USED OUT-OF-THE-BOX. - It is a proof-of-concept implementation. E.g. a stream may only be fully - buffered IF IT CAN BE DETERMINED NOT TO REFER TO AN INTERACTIVE DEVICE. - This logic is not represented here, as this is the EXAMPLE platform, and - actual platform overlays may differ widely. Another point is the value - for permissions being hardcoded to 0664 for file creations. + /* This is an example implementation of _PDCLIB_open() fit for use with + POSIX kernels. + FIXME: The permissions of newly created files should not be hardcoded + here. */ int osmode; switch ( mode & ~_PDCLIB_FBIN ) @@ -133,3 +131,4 @@ int main( void ) } #endif + diff --git a/platform/example/functions/_PDCLIB/write.c b/platform/example/functions/_PDCLIB/write.c index d2841f6..67c833f 100644 --- a/platform/example/functions/_PDCLIB/write.c +++ b/platform/example/functions/_PDCLIB/write.c @@ -7,26 +7,69 @@ */ #include <_PDCLIB_glue.h> +#include #ifndef REGTEST -int write(int, const void *, unsigned int); - -_PDCLIB_size_t _PDCLIB_write( int fd, char const * buffer, _PDCLIB_size_t n ) +int _PDCLIB_write( struct _PDCLIB_file_t * stream, char const * buffer, int n ) { - /* FIXME: Might return value < n, might return -1 on error */ - return write( fd, buffer, n ); + /* CAUTION: We assume ssize_t <=> int here. We do so implicitly so a smart + compiler can throw a warning in case it does not (and you missed this + note). Somewhere we have to cast the return value of write() to that of + _PDCLIB_write() (since the latter cannot use a return type not defined + by the standard). It would perhaps have been syntactically cleaner to + use ssize_t here and make the cast in the return statement, but this + way we don't have to include yet another non-standard header. + */ + int rc; + if ( ( rc = write( stream->handle, buffer, (size_t)n ) ) == -1 ) + { + /* Error encountered */ + stream->status |= _PDCLIB_ERRORFLAG; + /* FIXME: Map the errno of the OS to PDCLib's errno */ + } + return rc; } #endif #ifdef TEST +/* TODO: Work around the following undef */ +#undef SEEK_SET #include <_PDCLIB_test.h> +#include +#include + +#include +#include + +#include + +/* TODO: This uses POSIX system calls for now, should use standard calls + once they are in place. Clumsy sunny-path testing. +*/ int main( void ) { - TESTCASE( NO_TESTDRIVER ); + /* See the code comment at the functions' return statement above. */ + int fd, r; + char * buffer = malloc( 13 ); + TESTCASE( buffer != NULL ); + strcpy( buffer, "Test output\n" ); + /* Writing string to file */ + TESTCASE( ( fd = open( "testfile", O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU ) ) != -1 ); + struct _PDCLIB_file_t file = { fd, { 0, 0 }, buffer, BUFSIZ, 12, 0, 0, NULL }; + TESTCASE( _PDCLIB_write( &file, file.buffer, 12 ) == 12 ); + TESTCASE( close( file.handle ) != -1 ); + /* Reading file back in */ + TESTCASE( ( fd = open( "testfile", O_RDONLY ) ) != -1 ); + memset( buffer, '\0', 13 ); + TESTCASE( ( r = read( file.handle, (void *)buffer, 12 ) ) == 12 ); + TESTCASE( strcmp( buffer, "Test output\n" ) == 0 ); + TESTCASE( close( fd ) != -1 ); + TESTCASE( unlink( "testfile" ) != -1 ); return TEST_RESULTS; } #endif + diff --git a/platform/example/internals/_PDCLIB_config.h b/platform/example/internals/_PDCLIB_config.h index c807a1b..0df1679 100644 --- a/platform/example/internals/_PDCLIB_config.h +++ b/platform/example/internals/_PDCLIB_config.h @@ -11,6 +11,14 @@ /* Misc */ /* -------------------------------------------------------------------------- */ +/* By default, PDCLib does some rather strict checking of function usage, */ +/* especially in . Things that are undefined by the standard - for */ +/* example, mixing byte / wide operations or read / write operations without */ +/* resetting the stream beforehand - are caught and handled graciously. This */ +/* adds some complexity, and eats a couple of clock cycles. If you want to */ +/* disable these checks, define _PDCLIB_STRICT to zero. */ +#define _PDCLIB_STRICT 1 + /* The character (sequence) your platform uses as newline. */ #define _PDCLIB_endl "\n" @@ -123,6 +131,7 @@ struct _PDCLIB_lldiv_t interrupts). The type itself is not defined in a freestanding environment, but its limits are. (Don't ask.) */ +#define _PDCLIB_sig_atomic int #define _PDCLIB_SIG_ATOMIC INT /* Result type of the 'sizeof' operator (must be unsigned) */ @@ -215,24 +224,25 @@ typedef char * _PDCLIB_va_list; /* Set this to the page size of your OS. If your OS does not support paging, set to an appropriate value. (Too small, and malloc() will call the kernel too - often. Too large, and you will waste memory. + often. Too large, and you will waste memory.) */ #define _PDCLIB_PAGESIZE 4096 -/* Set this to the minimum memory node size. Any malloc() for a smaller siz - will be satisfied by a malloc() of this size instead. +/* Set this to the minimum memory node size. Any malloc() for a smaller size + will be satisfied by a malloc() of this size instead (to avoid excessive + fragmentation). */ #define _PDCLIB_MINALLOC 8 /* I/O ---------------------------------------------------------------------- */ -/* The unique file descriptor returned by _PDCLIB_open(). */ +/* The type of the file descriptor returned by _PDCLIB_open(). */ typedef int _PDCLIB_fd_t; /* The value (of type _PDCLIB_fd_t) returned by _PDCLIB_open() if the operation failed. */ -#define _PDCLIB_NOHANDLE -1 +#define _PDCLIB_NOHANDLE ( (_PDCLIB_fd_t) -1 ) /* A type in which to store file offsets. See fgetpos() / fsetpos(). */ /* FIXME: The 'int' types here are placeholders. When changed, check out @@ -247,7 +257,8 @@ typedef struct #define _PDCLIB_BUFSIZ 1024 /* The minimum number of files the implementation can open simultaneously. Must - be at least 8. + be at least 8. Depends largely on how the bookkeeping is done by fopen() / + freopen() / fclose(). */ #define _PDCLIB_FOPEN_MAX 8 @@ -259,3 +270,14 @@ typedef struct /* Number of distinct file names that can be generated by tmpnam(). */ #define _PDCLIB_TMP_MAX 50 + +/* The number of times fflush() tries to write a file buffer before giving up + if no characters can be written. +*/ +#define _PDCLIB_FLUSH_RETRIES 3 +/* This macro is executed after each try to write characters that results in + no characters being written. You can define this to be empty, wait a short + period of time, or whatever suits your environment. +*/ +#define _PDCLIB_FLUSH_RETRY_PREP +