# 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)
# 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
@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)
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:
-@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..."
@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"
@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 $@
+
Implementations for parts of <stdlib.h>. Still missing are the floating
point conversions, and the wide-/multibyte-character functions.
+v0.4.1 - 2006-11-16
+With v0.5 (<stdio.h>) 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 <stdio.h>. Still no locale / wide-char
support. Enabled all GCC compiler warnings I could find, and fixed
/* $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 <stdio.h>
+#include <limits.h>
+#include <assert.h>
-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>
Permission is granted to use, modify, and / or redistribute at will.
*/
-#ifndef REGTEST
-
#include <stddef.h>
/* Helper function that parses the C-style mode string passed to fopen() into
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 );
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
+
#include <string.h>
#include <stdint.h>
-_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;
/* 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 == '+' );
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;
}
{
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 ( ;; )
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;
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 );
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;
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 );
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;
}
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;
}
-/* $Id$ */\r
-\r
-/* Auxiliary PDCLib code <_PDCLIB_aux.h>\r
-\r
- This file is part of the Public Domain C Library (PDCLib).\r
- Permission is granted to use, modify, and / or redistribute at will.\r
-*/\r
-\r
-/* -------------------------------------------------------------------------- */\r
-/* You should not have to edit anything in this file; if you DO have to, it */\r
-/* would be considered a bug / missing feature: notify the author(s). */\r
-/* -------------------------------------------------------------------------- */\r
-\r
-/* -------------------------------------------------------------------------- */\r
-/* Standard Version */\r
-/* -------------------------------------------------------------------------- */\r
-\r
-/* Many a compiler gets this wrong, so you might have to hardcode it instead. */\r
-\r
-#if __STDC__ != 1\r
-#error Compiler does not define _ _STDC_ _ to 1 (not standard-compliant)!\r
-#endif\r
-\r
-#ifndef __STDC_VERSION__\r
-#define _PDCLIB_C_VERSION 90\r
-#define _PDCLIB_restrict\r
-#define _PDCLIB_inline\r
-#elif __STDC_VERSION__ == 199409L\r
-#define _PDCLIB_C_VERSION 95\r
-#define _PDCLIB_restrict\r
-#define _PDCLIB_inline\r
-#elif __STDC_VERSION__ == 199901L\r
-#define _PDCLIB_C_VERSION 99\r
-#define _PDCLIB_restrict restrict\r
-#define _PDCLIB_inline inline\r
-#else\r
-#error Unsupported _ _STDC_VERSION_ _ (__STDC_VERSION__) (supported: ISO/IEC 9899:1990, 9899/AMD1:1995, and 9899:1999).\r
-#endif\r
-\r
-#ifndef __STDC_HOSTED__\r
-#error Compiler does not define _ _STDC_HOSTED_ _ (not standard-compliant)!\r
-#elif __STDC_HOSTED__ == 0\r
-#define _PDCLIB_HOSTED 0\r
-#elif __STDC_HOSTED__ == 1\r
-#define _PDCLIB_HOSTED 1\r
-#else\r
-#error Compiler does not define _ _STDC_HOSTED_ _ to 0 or 1 (not standard-compliant)!\r
-#endif\r
-\r
-#if _PDCLIB_C_VERSION != 99\r
-#error PDCLib might not be fully conforming to either C89 or C95 prior to v2.x.\r
-#endif\r
-\r
-/* -------------------------------------------------------------------------- */\r
-/* Helper macros: */\r
-/* _PDCLIB_cc( x, y ) concatenates two preprocessor tokens without extending */\r
-/* _PDCLIB_concat( x, y ) concatenates two preprocessor tokens with extending */\r
-/* -------------------------------------------------------------------------- */\r
-\r
-#define _PDCLIB_cc( x, y ) x ## y\r
-#define _PDCLIB_concat( x, y ) _PDCLIB_cc( x, y )\r
-\r
-#define _PDCLIB_symbol2value( x ) #x\r
-#define _PDCLIB_symbol2string( x ) _PDCLIB_symbol2value( x )\r
-#define _PDCLIB_symbol2identity( x ) x\r
+/* $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
+
/* 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
*/
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.
/* 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 );
/* Flags for representing mode (see fopen()). Note these must fit the same
status field as the _IO?BF flags in <stdio.h> 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
_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 */
};
/* 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[];
*/
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 );
+
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ int UNEXPECTED_RETURN = 0;
+ _PDCLIB_Exit( 0 );
+ TESTCASE( UNEXPECTED_RETURN );
return TEST_RESULTS;
}
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 )
}
#endif
+
*/
#include <_PDCLIB_glue.h>
+#include <unistd.h>
#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 <stdlib.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <errno.h>
+
+/* 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
+
/* Misc */
/* -------------------------------------------------------------------------- */
+/* By default, PDCLib does some rather strict checking of function usage, */
+/* especially in <stdio.h>. 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"
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) */
/* 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
#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
/* 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
+