# 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 filemode
+INTFILES := _Exit atomax digits open print remove rename seed stdinit strtox_main strtox_prelim cleanstream fflush filemode eol errno seek prepread prepwrite
# All object files in the library
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
# All test drivers (.t)
PATCHFILES1 := $(shell ls platform/$(PLATFORM)/functions/_PDCLIB/*.c)
# All files in platform/$(PLATFORM)/functions/stdlib (for development only)
PATCHFILES2 := $(shell ls platform/$(PLATFORM)/functions/stdlib/*.c)
+# All files in platform/$(PLATFORM)/functions/stdio (for development only)
+PATCHFILES3 := $(shell ls platform/$(PLATFORM)/functions/stdio/*.c)
-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
+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 -fno-builtin
CFLAGS := -g -std=c99 -I./internals $(WARNINGS) $(USERFLAGS)
.PHONY: all clean srcdist bindist test tests testdrivers regtests regtestdrivers todos fixmes find links unlink help
-all: pdclib.a
+all: pdclib.a testdrivers regtestdrivers
+ @echo
+ @echo "========================"
+ @echo "Executing library tests:"
+ @echo "========================"
+ @echo
+ @$(MAKE) tests | grep -v "^ TST" | grep -v "^Failed"
+ @echo
+ @echo "==========================="
+ @echo "Executing regression tests:"
+ @echo "==========================="
+ @echo
+ @$(MAKE) regtests | grep -v "^ RTST" | grep -v "^Failed"
pdclib.a: $(OBJFILES)
@echo " AR $@"
functions/$(FILE)
tests: testdrivers
- -@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;
+ -@rc=0; count=0; failed=""; 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; echo
testdrivers: $(TSTFILES)
+ @echo
regtests: regtestdrivers
- -@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;
+ -@rc=0; count=0; failed=""; 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; echo
regtestdrivers: $(REGFILES)
+ @echo
-include $(DEPFILES)
-@for file in $(ALLFILES); do grep -H FIXME $$file; done; true
find:
- @find functions/ includes/ internals/ platform/ old_stdio/ -name "*\.[ch]" -type f | xargs grep $$FIND
+ @find functions/ includes/ internals/ platform/ -name "*\.[ch]" -type f | xargs grep $$FIND
links:
@echo "Linking platform/$(PLATFORM)..."
@cd includes && ln -s ../platform/$(PLATFORM)/includes/float.h
@cd functions/_PDCLIB && for file in $(PATCHFILES1); do basfile=`basename $$file`; if [ ! -f $$basfile ]; then ln -s `ls ../../$$file` .; fi; done
@cd functions/stdlib && for file in $(PATCHFILES2); do basfile=`basename $$file`; if [ ! -f $$basfile ]; then ln -s `ls ../../$$file` .; fi; done
+ @cd functions/stdio && for file in $(PATCHFILES3); do basfile=`basename $$file`; if [ ! -f $$basfile ]; then ln -s `ls ../../$$file` .; fi; done
unlink:
@echo "Unlinking platform files..."
@if [ -f includes/float.h ]; then rm includes/float.h; fi
@cd functions/_PDCLIB && for file in $(PATCHFILES1); do basfile=`basename $$file`; if [ -f $$basfile ]; then rm $$basfile; fi; done
@cd functions/stdlib && for file in $(PATCHFILES2); do basfile=`basename $$file`; if [ -f $$basfile ]; then rm $$basfile; fi; done
+ @cd functions/stdio && for file in $(PATCHFILES3); do basfile=`basename $$file`; if [ -f $$basfile ]; then rm $$basfile; fi; done
help:
@echo "Available make targets:"
Everyone involved in the first, "public" attempt at PDCLib, for bearing with me
when I restarted from scratch, thanks.
-Everyone bearing with me during the "stdio block", a period of many months in
+Everyone bearing with me during the "stdio block", a period of many years in
which PDCLib received not a single update because I was stuck and could not
-find the energy to work it out.
+find the time and energy to work it out.
-Lennart Fridén and Sammy Nordström, who have been great pals even after I sunk
+Lennart Frid�n and Sammy Nordstr�m, who have been great pals even after I sunk
some other project that had eaten countless hours of work between the three of
us, thanks.
does not adhere to them, that's a bug worth reporting. I mean it. I am a bit
obsessive when it comes to coding style. ;-)
-- all the stuff that is not part of the standard specification is "hidden" in
+- All the stuff that is not part of the standard specification is "hidden" in
the _PDCLIB_* namespace - functions, variables, macros, files, directories.
This is to make it easier to distinguish between what the standard dictates
and what I added to make PDCLib work.
-- any internal includes (i.e. those not specified by the standard) have their
- header guards defined in the *including* file, for a tiny bit of performance.
+- Any internal includes (i.e. those not specified by the standard) have their
+ header guards defined in the *including* file, for a tiny bit of compile-time
+ performance.
- I always try to minimize the use of local variables. Wherever possible I used
parameters passed by-value directly, and deferred declaration of locals to the
when the library is compiled with a compiler that is not that great at
optimization.
-- every function, every static data item that could possibly be shared, got its
+- Every function, every static data item that could possibly be shared, got its
own implementation file. This means the library itself is probably larger than
strictly necessary, and might take a couple of clock cycles longer to link,
but it reduces size of object files and executables.
-- where possible, I tried to share functionality between similar functions (as
+- Where possible, I tried to share functionality between similar functions (as
can be seen in the atoi() and strtol() function families). This means one or
two additional function calls, but again reduces memory footprint and eases
maintenance of the library.
-- function arguments are named exactly as in the standard document.
+- Function arguments are named exactly as in the standard document.
-- the standard is taken quite literally in places. For example, memcpy() really
- copies char-wise. This runs contrary to earlier claims of performance, but is
- consistent with the *letter* of the standard, and you will probably use your
- compiler builtins (through a platform overlay) anyhow.
+- The standard is taken quite literally in places. For example, the default
+ implementations of memcpy() really copies char-wise. This runs contrary to
+ earlier claims of performance, but is consistent with the *letter* of the
+ standard, and you will probably use your compiler builtins (through a platform
+ overlay) anyhow.
-- every file has an Id tag, so that it is on file for *every* code file.
+- Every file has an Id tag, so that it is on file for *every* code file.
- PDCLib code has no bias towards POSIX; indeed the absence of POSIX tidbits is
one of its hallmarks. However, PDCLib also has no bias *against* POSIX, and
sheer familiarity. (This is mainly referring to naming and parameter lists of
OS "glue" functions.)
-- identifiers are tersely named, but not cryptically abbreviated, and should be
+- Identifiers are tersely named, but not cryptically abbreviated, and should be
intuitive enough to allow easy understanding of PDCLib inner workings.
- I disagree with the notion that good code needs no comments. Code tells you
char _PDCLIB_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+/* For _PDCLIB/print.c only; obsolete with ctype.h */
+char _PDCLIB_Xdigits[] = "0123456789ABCDEF";
+
#ifdef TEST
#include <_PDCLIB_test.h>
int main( void )
{
TESTCASE( strcmp( _PDCLIB_digits, "0123456789abcdefghijklmnopqrstuvwxyz" ) == 0 );
+ TESTCASE( strcmp( _PDCLIB_Xdigits, "0123456789ABCDEF" ) == 0 );
return TEST_RESULTS;
}
--- /dev/null
+/* $Id$ */
+
+/* _PDCLIB_eol
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef _PDCLIB_CONFIG_H
+#define _PDCLIB_CONFIG_H _PDCLIB_CONFIG_H
+#include <_PDCLIB_config.h>
+#endif
+
+const char * _PDCLIB_eol = _PDCLIB_endl;
+
--- /dev/null
+/* $Id$ */
+
+/* _PDCLIB_errno
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#define _PDCLIB_INT_H _PDCLIB_INT_H
+#include <_PDCLIB_int.h>
+
+#ifndef REGTEST
+
+int _PDCLIB_errno = 0;
+
+int * _PDCLIB_errno_func()
+{
+ return &_PDCLIB_errno;
+}
+
+#endif
+
+#ifdef TEST
+#include <_PDCLIB_test.h>
+
+#include <errno.h>
+
+int main()
+{
+ errno = 0;
+ TESTCASE( errno == 0 );
+ errno = EDOM;
+ TESTCASE( errno == EDOM );
+ errno = ERANGE;
+ TESTCASE( errno == ERANGE );
+ return TEST_RESULTS;
+}
+
+#endif
+
+++ /dev/null
-/* $Id$ */
-
-/* _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>
-
-#include <_PDCLIB_glue.h>
-
-_PDCLIB_size_t _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream, _PDCLIB_size_t written, int retries )
-{
- _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 )
- {
- 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>
-
-int main( void )
-{
- TESTCASE( NO_TESTDRIVER );
- return TEST_RESULTS;
-}
-
-#endif
-
*/
unsigned int _PDCLIB_filemode( char const * const mode )
{
- int rc = 0;
+ unsigned rc = 0;
switch ( mode[0] )
{
case 'r':
rc |= _PDCLIB_FWRITE;
break;
case 'a':
- rc |= _PDCLIB_FAPPEND;
+ rc |= _PDCLIB_FAPPEND | _PDCLIB_FWRITE;
break;
default:
/* Other than read, write, or append - invalid */
{
TESTCASE( _PDCLIB_filemode( "r" ) == _PDCLIB_FREAD );
TESTCASE( _PDCLIB_filemode( "w" ) == _PDCLIB_FWRITE );
- TESTCASE( _PDCLIB_filemode( "a" ) == _PDCLIB_FAPPEND );
+ TESTCASE( _PDCLIB_filemode( "a" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE ) );
TESTCASE( _PDCLIB_filemode( "r+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW ) );
TESTCASE( _PDCLIB_filemode( "w+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW ) );
- TESTCASE( _PDCLIB_filemode( "a+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FRW ) );
+ TESTCASE( _PDCLIB_filemode( "a+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW ) );
TESTCASE( _PDCLIB_filemode( "rb" ) == ( _PDCLIB_FREAD | _PDCLIB_FBIN ) );
TESTCASE( _PDCLIB_filemode( "wb" ) == ( _PDCLIB_FWRITE | _PDCLIB_FBIN ) );
- TESTCASE( _PDCLIB_filemode( "ab" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "ab" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FBIN ) );
TESTCASE( _PDCLIB_filemode( "r+b" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) );
TESTCASE( _PDCLIB_filemode( "w+b" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) );
- TESTCASE( _PDCLIB_filemode( "a+b" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FRW | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "a+b" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) );
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 ) );
+ TESTCASE( _PDCLIB_filemode( "ab+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) );
TESTCASE( _PDCLIB_filemode( "x" ) == 0 );
TESTCASE( _PDCLIB_filemode( "r++" ) == 0 );
TESTCASE( _PDCLIB_filemode( "wbb" ) == 0 );
--- /dev/null
+/* $Id$ */
+
+/* _PDCLIB_prepread( struct _PDCLIB_file_t * )
+
+ 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>
+
+#define _PDCLIB_GLUE_H _PDCLIB_GLUE_H
+#include <_PDCLIB_glue.h>
+
+int _PDCLIB_prepread( struct _PDCLIB_file_t * stream )
+{
+ if ( ( stream->bufidx > stream->bufend ) ||
+ ( stream->status & ( _PDCLIB_FWRITE | _PDCLIB_FAPPEND | _PDCLIB_ERRORFLAG | _PDCLIB_WIDESTREAM | _PDCLIB_EOFFLAG ) ) ||
+ ! ( stream->status & ( _PDCLIB_FREAD | _PDCLIB_FRW ) ) )
+ {
+ _PDCLIB_errno = _PDCLIB_EIO;
+ stream->status |= _PDCLIB_ERRORFLAG;
+ return EOF;
+ }
+ stream->status |= _PDCLIB_FREAD | _PDCLIB_BYTESTREAM;
+ if ( ( stream->bufidx == stream->bufend ) && ( stream->ungetidx == 0 ) )
+ {
+ return _PDCLIB_fillbuffer( stream );
+ }
+ else
+ {
+ return 0;
+ }
+}
+
--- /dev/null
+/* $Id$ */
+
+/* _PDCLIB_prepwrite( struct _PDCLIB_file_t * )
+
+ 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>
+
+int _PDCLIB_prepwrite( struct _PDCLIB_file_t * stream )
+{
+ if ( ( stream->bufidx < stream->bufend ) || ( stream->ungetidx > 0 ) ||
+ ( stream->status & ( _PDCLIB_FREAD | _PDCLIB_ERRORFLAG | _PDCLIB_WIDESTREAM | _PDCLIB_EOFFLAG ) ) ||
+ ! ( stream->status & ( _PDCLIB_FWRITE | _PDCLIB_FAPPEND | _PDCLIB_FRW ) ) )
+ {
+ _PDCLIB_errno = _PDCLIB_EIO;
+ stream->status |= _PDCLIB_ERRORFLAG;
+ return EOF;
+ }
+ stream->status |= _PDCLIB_FWRITE | _PDCLIB_BYTESTREAM;
+ return 0;
+}
+
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
*/
#define DELIVER( x ) \
do { \
if ( status->i < status->n ) { \
- if ( status->stream != NULL ) { \
- status->stream->buffer[status->stream->bufidx++] = x; \
- if ( ( status->stream->bufidx == status->stream->bufsize ) \
- || ( ( status->stream->status & _IOLBF ) && ( x == '\n' ) ) \
- || ( status->stream->status & _IONBF ) ) \
- fflush( status->stream ); \
- } else \
+ if ( status->stream != NULL ) \
+ putc( x, status->stream ); \
+ else \
status->s[status->i] = x; \
} \
++(status->i); \
static int testprintf( char * buffer, size_t n, const char * format, ... )
{
/* Members: base, flags, n, i, this, s, width, prec, stream, arg */
- struct _PDCLIB_status_t status = { 0, 0, n, 0, 0, buffer, 0, 0, NULL, NULL };
- memset( buffer, '\0', 100 );
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = n;
+ status.i = 0;
+ status.this = 0;
+ status.s = buffer;
+ status.width = 0;
+ status.prec = 0;
+ status.stream = NULL;
va_start( status.arg, format );
+ memset( buffer, '\0', 100 );
if ( *(_PDCLIB_print( format, &status )) != '\0' )
{
printf( "_PDCLIB_print() did not return end-of-specifier on '%s'.\n", format );
digit = x - _PDCLIB_digits;
if ( ( rc < limval ) || ( ( rc == limval ) && ( digit <= limdigit ) ) )
{
- rc = rc * base + digit;
+ rc = rc * base + (unsigned)digit;
++(*p);
}
else
int main( void )
{
-#ifndef REGTEST
- FILE file = { 0, { 0, 0 }, NULL, 0, 0, 0, _IONBF, NULL, NULL };
- FILE * fh = &file;
+ FILE * fh;
+ remove( "testfile" );
+ TESTCASE( ( fh = fopen( "testfile", "w+" ) ) != NULL );
+ /* Flags should be clear */
TESTCASE( ! ferror( fh ) );
TESTCASE( ! feof( fh ) );
- fh->status |= _PDCLIB_ERRORFLAG;
+ /* Reading from input stream - should provoke error */
+ TESTCASE( fgetc( fh ) == EOF );
TESTCASE( ferror( fh ) );
TESTCASE( ! feof( fh ) );
+ /* clearerr() should clear flags */
clearerr( fh );
TESTCASE( ! ferror( fh ) );
TESTCASE( ! feof( fh ) );
- fh->status |= _PDCLIB_EOFFLAG;
- TESTCASE( ! ferror( fh ) );
- TESTCASE( feof( fh ) );
- clearerr( fh );
+ /* Reading from empty stream - should provoke EOF */
+ rewind( fh );
+ TESTCASE( fgetc( fh ) == EOF );
TESTCASE( ! ferror( fh ) );
- TESTCASE( ! feof( fh ) );
- fh->status |= _PDCLIB_EOFFLAG | _PDCLIB_ERRORFLAG;
- TESTCASE( ferror( fh ) );
TESTCASE( feof( fh ) );
+ /* clearerr() should clear flags */
clearerr( fh );
TESTCASE( ! ferror( fh ) );
TESTCASE( ! feof( fh ) );
-#else
- /* TODO: The above is ad-hoc and PDCLib specific. A better test driver
- should be internals-agnostic (provoking the error / eof flag by
- "regular" operations).
- */
- TESTCASE( NO_TESTDRIVER );
-#endif
+ TESTCASE( fclose( fh ) == 0 );
+ remove( "testfile" );
return TEST_RESULTS;
}
#endif
+
{
if ( stream == current )
{
- if ( stream->status & _PDCLIB_WROTELAST ) fflush( stream );
- if ( stream->status & _PDCLIB_LIBBUFFER ) free( stream->buffer );
+ /* Flush buffer */
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ /* Flush failed, errno already set */
+ return EOF;
+ }
+ }
+ /* Free buffer */
+ if ( stream->status & _PDCLIB_LIBBUFFER )
+ {
+ free( stream->buffer );
+ }
+ /* Close handle */
_PDCLIB_close( stream->handle );
+ /* Remove stream from list */
if ( previous != NULL )
{
previous->next = stream->next;
{
_PDCLIB_filelist = stream->next;
}
+ /* Free stream */
free( stream );
return 0;
}
previous = current;
current = current->next;
}
+ _PDCLIB_errno = _PDCLIB_EIO;
return -1;
}
#ifndef REGTEST
struct _PDCLIB_file_t * file1;
struct _PDCLIB_file_t * file2;
- TESTCASE( _PDCLIB_filelist == NULL );
+ remove( "testfile1" );
+ remove( "testfile2" );
+ TESTCASE( _PDCLIB_filelist == stdin );
TESTCASE( ( file1 = fopen( "testfile1", "w" ) ) != NULL );
TESTCASE( _PDCLIB_filelist == file1 );
TESTCASE( ( file2 = fopen( "testfile2", "w" ) ) != NULL );
TESTCASE( fclose( file1 ) == 0 );
TESTCASE( _PDCLIB_filelist == file2 );
TESTCASE( fclose( file2 ) == 0 );
- TESTCASE( _PDCLIB_filelist == NULL );
- system( "rm testfile1 testfile2" );
+ TESTCASE( _PDCLIB_filelist == stdin );
+ remove( "testfile1" );
+ remove( "testfile2" );
#else
puts( " NOTEST fclose() test driver is PDCLib-specific." );
#endif
}
#endif
+
int rc = 0;
while ( stream != NULL )
{
- if ( stream->bufidx > stream->bufend )
+ if ( stream->status & _PDCLIB_FWRITE )
{
- rc |= _PDCLIB_fflush( stream );
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ rc = EOF;
+ }
}
stream = stream->next;
}
}
else
{
- return _PDCLIB_fflush( stream );
+ return _PDCLIB_flushbuffer( stream );
}
}
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ /* Testing covered by ftell.c */
return TEST_RESULTS;
}
#include <stdio.h>
+#include <_PDCLIB_glue.h>
+
#ifndef REGTEST
int fgetc( struct _PDCLIB_file_t * stream )
{
- /* TODO: Implement. */
- return 0;
+ if ( _PDCLIB_prepread( stream ) == EOF )
+ {
+ return EOF;
+ }
+ if ( stream->ungetidx > 0 )
+ {
+ return stream->ungetbuf[ stream->ungetidx-- ];
+ }
+ return stream->buffer[stream->bufidx++];
}
#endif
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ /* Testing covered by ftell.c */
return TEST_RESULTS;
}
#ifndef REGTEST
-int fgetpos( struct _PDCLIB_file_t * _PDCLIB_restrict stream, _PDCLIB_fpos_t * _PDCLIB_restrict pos )
+int fgetpos( struct _PDCLIB_file_t * _PDCLIB_restrict stream, struct _PDCLIB_fpos_t * _PDCLIB_restrict pos )
{
- /* TODO: Implement. */
+ pos->offset = stream->pos.offset + stream->bufidx - stream->ungetidx;
+ pos->status = stream->pos.status;
return 0;
}
/* $Id$ */
-/* fgets( char *, int, FILE * );
+/* fgets( char *, int, FILE * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
#ifndef REGTEST
-char * fgets( char * _PDCLIB_restrict s, int n, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+#define _PDCLIB_GLUE_H _PDCLIB_GLUE_H
+#include <_PDCLIB_glue.h>
+
+char * fgets( char * s, int size, struct _PDCLIB_file_t * stream )
{
- /* TODO: Implement. */
- return NULL;
+ if ( size <= 1 )
+ {
+ /* TODO: This is the letter of the standard, but is it the right thing to do? */
+ *s = '\0';
+ return s;
+ }
+ if ( _PDCLIB_prepread( stdin ) == EOF )
+ {
+ return NULL;
+ }
+ char * dest = s;
+ while ( ( ( *dest = stdin->buffer[stdin->bufidx++] ) != '\n' ) && --size > 0 )
+ {
+ if ( stdin->bufidx == stdin->bufend )
+ {
+ if ( _PDCLIB_fillbuffer( stdin ) == EOF )
+ {
+ /* EOF adds \0, error leaves target indeterminate, so we can
+ just add the \0 anyway.
+ */
+ *dest = '\0';
+ return NULL;
+ }
+ }
+ ++dest;
+ }
+ *dest = '\0';
+ return s;
}
#endif
}
#endif
+
#ifndef REGTEST
#include <_PDCLIB_glue.h>
-/* FIXME: This approach is a possible attack vector. */
-struct _PDCLIB_file_t * _PDCLIB_filelist = NULL;
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
struct _PDCLIB_file_t * fopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode )
{
/* no memory for another FILE */
return NULL;
}
- if ( ( rc->status = _PDCLIB_filemode( mode ) ) == 0 ) goto fail; /* invalid mode */
+ if ( ( rc->status = _PDCLIB_filemode( mode ) ) == 0 )
+ {
+ /* invalid mode */
+ free( rc );
+ return NULL;
+ }
rc->handle = _PDCLIB_open( filename, rc->status );
- if ( rc->handle == _PDCLIB_NOHANDLE ) goto fail; /* OS open() failed */
+ if ( rc->handle == _PDCLIB_NOHANDLE )
+ {
+ /* OS open() failed */
+ free( rc );
+ return NULL;
+ }
/* Adding to list of open files */
rc->next = _PDCLIB_filelist;
_PDCLIB_filelist = rc;
/* Setting buffer, and mark as internal. TODO: Check for unbuffered */
- if ( ( rc->buffer = malloc( BUFSIZ ) ) == NULL ) goto fail;
+ if ( ( rc->buffer = malloc( BUFSIZ ) ) == NULL )
+ {
+ free( rc );
+ return NULL;
+ }
+ if ( ( rc->ungetbuf = malloc( _PDCLIB_UNGETCBUFSIZE ) ) == NULL )
+ {
+ free( rc->buffer );
+ free( rc );
+ return NULL;
+ }
rc->bufsize = BUFSIZ;
rc->bufidx = 0;
+ rc->ungetidx = 0;
/* Setting buffer to _IOLBF because "when opened, a stream is fully
buffered if and only if it can be determined not to refer to an
interactive device."
*/
- rc->status |= ( _PDCLIB_LIBBUFFER | _PDCLIB_VIRGINSTR /* | _IOLBF */ ); /* FIXME: Uncommenting the _IOLBF here breaks output. */
+ rc->status |= _PDCLIB_LIBBUFFER | _IOLBF;
/* TODO: Setting mbstate */
return rc;
-fail:
- free( rc );
- return NULL;
}
#endif
my system is at once less forgiving (segfaults on mode NULL) and more
forgiving (accepts undefined modes).
*/
-#ifndef REGTEST
- TESTCASE( fopen( NULL, NULL ) == NULL );
-#endif
+ remove( "testfile" );
+ TESTCASE_NOREG( fopen( NULL, NULL ) == NULL );
TESTCASE( fopen( NULL, "w" ) == NULL );
-#ifndef REGTEST
- TESTCASE( fopen( "", NULL ) == NULL );
-#endif
+ TESTCASE_NOREG( fopen( "", NULL ) == NULL );
TESTCASE( fopen( "", "w" ) == NULL );
TESTCASE( fopen( "foo", "" ) == NULL );
-#ifndef REGTEST
- TESTCASE( fopen( "testfile", "wq" ) == NULL ); /* Undefined mode */
- TESTCASE( fopen( "testfile", "wr" ) == NULL ); /* Undefined mode */
-#endif
+ TESTCASE_NOREG( fopen( "testfile", "wq" ) == NULL ); /* Undefined mode */
+ TESTCASE_NOREG( fopen( "testfile", "wr" ) == NULL ); /* Undefined mode */
TESTCASE( fopen( "testfile", "w" ) != NULL );
- system( "rm testfile" );
+ remove( "testfile" );
return TEST_RESULTS;
}
#include <stdio.h>
+#include <_PDCLIB_glue.h>
+
#ifndef REGTEST
/* Write the value c (cast to unsigned char) to the given stream.
Returns c if successful, EOF otherwise.
- If a write error occurs, sets the error indicator of the stream is set.
+ If a write error occurs, the error indicator of the stream is set.
*/
int fputc( int c, struct _PDCLIB_file_t * stream )
{
- /* FIXME: This is devoid of any error checking (file writeable? r/w
- constraints honored?) (Text format translations?)
- */
+ if ( _PDCLIB_prepwrite( stream ) == EOF )
+ {
+ return EOF;
+ }
stream->buffer[stream->bufidx++] = (char)c;
if ( ( stream->bufidx == stream->bufsize ) /* _IOFBF */
|| ( ( stream->status & _IOLBF ) && ( (char)c == '\n' ) ) /* _IOLBF */
)
{
/* buffer filled, unbuffered stream, or end-of-line. */
- fflush( stream );
- }
- else
- {
- stream->status |= _PDCLIB_WROTELAST;
+ return ( _PDCLIB_flushbuffer( stream ) == 0 ) ? c : EOF;
}
return c;
}
int main( void )
{
- FILE * fh;
- char buffer[100];
- TESTCASE( ( fh = fopen( "testfile", "w" ) ) != NULL );
- TESTCASE( fputc( '!', fh ) == '!' );
- TESTCASE( fclose( fh ) == 0 );
- TESTCASE( ( fh = fopen( "testfile", "r" ) ) != NULL );
- TESTCASE( fread( buffer, 1, 1, fh ) == 1 );
- TESTCASE( buffer[0] == '!' );
- TESTCASE( fclose( fh ) == 0 );
+ /* Testing covered by ftell.c */
return TEST_RESULTS;
}
#include <stdio.h>
#ifndef REGTEST
+#include <_PDCLIB_glue.h>
-int fputs( const char * _PDCLIB_restrict s, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+int fputs( const char * s, struct _PDCLIB_file_t * stream )
{
- /* FIXME: This is devoid of any error checking (file writeable? r/w
- constraints honored?)
- */
- /* FIXME: Proper buffering handling. */
- char written;
- while ( stream->bufidx < stream->bufsize )
+ if ( _PDCLIB_prepwrite( stream ) == EOF )
{
- written = ( stream->buffer[stream->bufidx++] = *(s++) );
- if ( ( written == '\0' ) ||
- ( ( stream->status & _IOLBF ) && ( written == '\n' ) ) ||
- ( stream->status & _IONBF ) )
- {
- break;
- }
+ return EOF;
}
- fflush( stream );
- if ( written != '\0' )
+ while ( *s != '\0' )
{
- /* FIXME: For _IONBF, this recurses once per character - unacceptable. */
- return fputs( s, stream );
+ /* Unbuffered and line buffered streams get flushed when fputs() does
+ write the terminating end-of-line. All streams get flushed if the
+ buffer runs full.
+ */
+ stream->buffer[ stream->bufidx++ ] = *s;
+ /* TODO: Should IOLBF flush on \n, or the correct EOL sequence of the system? */
+ if ( ( stream->bufidx == stream->bufsize )
+ || ( ( stream->status & _IOLBF ) && *s == '\n' ) )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ ++s;
}
- else
+ if ( stream->status & _IONBF )
{
- return 1;
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
}
+ return 0;
}
#endif
-
#ifdef TEST
#include <_PDCLIB_test.h>
-#include <string.h>
-
int main( void )
{
+ char const * const testfile = "testfile";
+ char const * const message = "SUCCESS testing fputs()";
FILE * fh;
- char buffer[100];
- char text[] = "SUCCESS testing fputs().";
- TESTCASE( ( fh = fopen( "testfile", "w" ) ) != NULL );
- TESTCASE( fputs( text, fh ) != EOF );
- TESTCASE( fclose( fh ) == 0 );
- TESTCASE( ( fh = fopen( "testfile", "r" ) ) != NULL );
- TESTCASE( fread( buffer, 1, strlen( text ), fh ) == strlen( text ) );
- TESTCASE( memcmp( buffer, text, strlen( text ) ) == 0 );
+ remove( testfile );
+ TESTCASE( ( fh = fopen( testfile, "w+" ) ) != NULL );
+ TESTCASE( fputs( message, fh ) >= 0 );
+ rewind( fh );
+ for ( size_t i = 0; i < 23; ++i )
+ {
+ TESTCASE( fgetc( fh ) == message[i] );
+ }
TESTCASE( fclose( fh ) == 0 );
- TESTCASE( remove( "testfile" ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
return TEST_RESULTS;
}
#endif
+
/* $Id$ */
-/* fread( void *, size_t, size_t, FILE * )
+/* fwrite( void *, size_t, size_t, FILE * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
#ifndef REGTEST
+#include <stdbool.h>
+#include <string.h>
+
size_t fread( void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
{
- return _PDCLIB_read( stream->handle, ptr, size * nmemb );
+ if ( _PDCLIB_prepread( stream ) == EOF )
+ {
+ return 0;
+ }
+ char * dest = (char *)ptr;
+ size_t nmemb_i;
+ for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i )
+ {
+ for ( size_t size_i = 0; size_i < size; ++size_i )
+ {
+ if ( stream->bufidx == stream->bufend )
+ {
+ if ( _PDCLIB_fillbuffer( stream ) == EOF )
+ {
+ /* Could not read requested data */
+ return nmemb_i;
+ }
+ }
+ dest[ nmemb_i * size + size_i ] = stream->buffer[ stream->bufidx++ ];
+ }
+ }
+ return nmemb_i;
}
#endif
int main( void )
{
- /* Testing handled by fwrite(). */
+ FILE * fh;
+ remove( "testfile" );
+ TESTCASE( ( fh = fopen( "testfile", "w" ) ) != NULL );
+ TESTCASE( fwrite( "SUCCESS testing fwrite()\n", 1, 25, fh ) == 25 );
+ TESTCASE( fclose( fh ) == 0 );
+ /* TODO: Add readback test. */
+ TESTCASE( remove( "testfile" ) == 0 );
return TEST_RESULTS;
}
#endif
+
/* FIXME: If filename is NULL, change mode. */
/* TODO: This function can change wide orientation of a stream */
if ( filename == NULL ) return NULL;
- if ( stream->status & _PDCLIB_WROTELAST ) fflush( stream );
+ if ( stream->status & _PDCLIB_FWRITE ) fflush( stream );
if ( stream->status & _PDCLIB_LIBBUFFER ) free( stream->buffer );
_PDCLIB_close( stream->handle );
clearerr( stream );
if ( ( stream->buffer = malloc( BUFSIZ ) ) == NULL ) return NULL;
stream->bufsize = BUFSIZ;
stream->bufidx = 0;
- stream->status |= ( _PDCLIB_LIBBUFFER | _PDCLIB_VIRGINSTR );
+ stream->status |= _PDCLIB_LIBBUFFER;
/* TODO: Setting mbstate */
return stream;
}
/* $Id$ */
-/* fseek( FILE *, long int, int )
+/* fseek( FILE *, long offset, int )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
#ifndef REGTEST
-int fseek( struct _PDCLIB_file_t * stream, long int offset, int whence )
+#include <_PDCLIB_glue.h>
+
+int fseek( struct _PDCLIB_file_t * _PDCLIB_restrict stream, long offset, int whence )
{
- if ( stream->status & _PDCLIB_WROTELAST )
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ stream->status &= ~ _PDCLIB_EOFFLAG;
+ if ( stream->status & _PDCLIB_FRW )
{
- fflush( stream );
+ stream->status &= ~ ( _PDCLIB_FREAD | _PDCLIB_FWRITE );
}
- /* TODO: Implement. */
- return 0;
+ return _PDCLIB_seek( stream, offset, whence );
}
#endif
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ /* Testing covered by ftell.c */
return TEST_RESULTS;
}
#endif
+
#include <stdio.h>
#ifndef REGTEST
+#include <_PDCLIB_glue.h>
-int fsetpos( struct _PDCLIB_file_t * stream, const _PDCLIB_fpos_t * pos )
+int fsetpos( struct _PDCLIB_file_t * stream, const struct _PDCLIB_fpos_t * pos )
{
- if ( stream->status & _PDCLIB_WROTELAST )
+ if ( stream->status & _PDCLIB_FWRITE )
{
- fflush( stream );
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
}
- /* TODO: Implement. */
+ if ( _PDCLIB_seek( stream, pos->offset, SEEK_SET ) == EOF )
+ {
+ return EOF;
+ }
+ stream->pos.status = pos->status;
return 0;
}
*/
#include <stdio.h>
+#include <limits.h>
#ifndef REGTEST
long int ftell( struct _PDCLIB_file_t * stream )
{
- /* TODO: Implement. */
- return 0;
+ /* TODO: A bit too fuzzy in the head now. stream->ungetidx should be in here
+ somewhere.
+ */
+ if ( stream->pos.offset > ( LONG_MAX - stream->bufidx ) )
+ {
+ /* integer overflow */
+ _PDCLIB_errno = _PDCLIB_EINVAL;
+ return -1;
+ }
+ /* Position of start-of-buffer, plus:
+ - buffered, unwritten content (for output streams), or
+ - already-parsed content from buffer (for input streams)
+ */
+ return (long int)( stream->pos.offset + stream->bufidx - stream->ungetidx );
}
#endif
#ifdef TEST
#include <_PDCLIB_test.h>
+#include <stdlib.h>
+
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ /* Testing all the basic I/O functions individually would result in lots
+ of duplicated code, so I took the liberty of lumping it all together
+ here.
+ */
+ /* The following functions delegate their tests to here:
+ fgetc fflush rewind fputc ungetc fseek
+ flushbuffer seek fillbuffer
+ */
+ char * buffer = (char*)malloc( 4 );
+ FILE * fh;
+ remove( "testfile" );
+ TESTCASE( ( fh = fopen( "testfile", "w+" ) ) != NULL );
+ TESTCASE( setvbuf( fh, buffer, _IOLBF, 4 ) == 0 );
+ TESTCASE( fputc( '1', fh ) == '1' );
+ TESTCASE( fputc( '2', fh ) == '2' );
+ TESTCASE( fputc( '3', fh ) == '3' );
+ /* Positions incrementing as expected? */
+ TESTCASE( ftell( fh ) == 3l );
+ TESTCASE_NOREG( fh->pos.offset == 0l );
+ TESTCASE_NOREG( fh->bufidx == 3l );
+ /* Buffer properly flushed when full? */
+ TESTCASE( fputc( '4', fh ) == '4' );
+ TESTCASE_NOREG( fh->pos.offset == 4l );
+ TESTCASE_NOREG( fh->bufidx == 0 );
+ /* fflush() resetting positions as expected? */
+ TESTCASE( fputc( '5', fh ) == '5' );
+ TESTCASE( fflush( fh ) == 0 );
+ TESTCASE( ftell( fh ) == 5l );
+ TESTCASE_NOREG( fh->pos.offset == 5l );
+ TESTCASE_NOREG( fh->bufidx == 0l );
+ /* rewind() resetting positions as expected? */
+ rewind( fh );
+ TESTCASE( ftell( fh ) == 0l );
+ TESTCASE_NOREG( fh->pos.offset == 0 );
+ TESTCASE_NOREG( fh->bufidx == 0 );
+ /* Reading back first character after rewind for basic read check */
+ TESTCASE( fgetc( fh ) == '1' );
+ TESTCASE( fclose( fh ) == 0 );
+ /* TODO: t.b.c. */
+ remove( "testfile" );
return TEST_RESULTS;
}
#endif
+
#ifndef REGTEST
+#include <stdbool.h>
+#include <string.h>
+
size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
{
- return _PDCLIB_write( stream->handle, ptr, size * nmemb );
+ if ( _PDCLIB_prepwrite( stream ) == EOF )
+ {
+ return 0;
+ }
+ _PDCLIB_size_t offset = 0;
+ bool lineend = false;
+ size_t nmemb_i;
+ for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i )
+ {
+ for ( size_t size_i = 0; size_i < size; ++size_i )
+ {
+ /* TODO: Should line-buffered streams be flushed on '\n' or system EOL? */
+ if ( ( stream->buffer[ stream->bufidx++ ] == ((char*)ptr)[ nmemb_i * size + size_i ] ) == '\n' )
+ {
+ /* Remember last newline, in case we have to do a partial line-buffered flush */
+ offset = stream->bufidx;
+ lineend = true;
+ }
+ if ( stream->bufidx == stream->bufsize )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ /* Returning number of objects completely buffered */
+ return nmemb_i;
+ }
+ lineend = false;
+ }
+ }
+ }
+ /* Fully-buffered streams are OK. Non-buffered streams must be flushed,
+ line-buffered streams only if there's a newline in the buffer.
+ */
+ switch ( stream->status & ( _IONBF | _IOLBF ) )
+ {
+ case _IONBF:
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ /* We are in a pinch here. We have an error, which requires a
+ return value < nmemb. On the other hand, all objects have
+ been written to buffer, which means all the caller had to
+ do was removing the error cause, and re-flush the stream...
+ Catch 22. We'll return a value one short, to indicate the
+ error, and can't really do anything about the inconsistency.
+ */
+ return nmemb_i - 1;
+ }
+ break;
+ case _IOLBF:
+ {
+ size_t bufidx = stream->bufidx;
+ stream->bufidx = offset;
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ /* See comment above. */
+ stream->bufidx = bufidx;
+ return nmemb_i - 1;
+ }
+ stream->bufidx = bufidx - offset;
+ memmove( stream->buffer, stream->buffer + offset, stream->bufidx );
+ }
+ }
+ return nmemb_i;
}
#endif
int main( void )
{
FILE * fh;
+ remove( "testfile" );
TESTCASE( ( fh = fopen( "testfile", "w" ) ) != NULL );
TESTCASE( fwrite( "SUCCESS testing fwrite()\n", 1, 25, fh ) == 25 );
TESTCASE( fclose( fh ) == 0 );
}
#endif
+
*/
#include <stdio.h>
-#include <limits.h>
#ifndef REGTEST
+#define _PDCLIB_GLUE_H _PDCLIB_GLUE_H
+#include <_PDCLIB_glue.h>
+
char * gets( char * s )
{
- return fgets( s, INT_MAX, stdin ); /* TODO: Replace with an unchecking call. */
+ if ( _PDCLIB_prepread( stdin ) == EOF )
+ {
+ return NULL;
+ }
+ char * dest = s;
+ while ( ( *dest = stdin->buffer[stdin->bufidx++] ) != '\n' )
+ {
+ if ( stdin->bufidx == stdin->bufend )
+ {
+ if ( _PDCLIB_fillbuffer( stdin ) == EOF )
+ {
+ return NULL;
+ }
+ }
+ ++dest;
+ }
+ *dest = '\n';
+ return s;
}
#endif
}
#endif
+
#include <stdio.h>
#ifndef REGTEST
+#include <_PDCLIB_glue.h>
+
+extern char * _PDCLIB_eol;
int puts( const char * s )
{
- /* TODO: Implement. */
+ if ( _PDCLIB_prepwrite( stdout ) == EOF )
+ {
+ return EOF;
+ }
+ while ( *s != '\0' )
+ {
+ stdout->buffer[ stdout->bufidx++ ] = *s++;
+ if ( stdout->bufidx == stdout->bufsize )
+ {
+ if ( _PDCLIB_flushbuffer( stdout ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ }
+ s = _PDCLIB_eol;
+ while ( *s != '\0' )
+ {
+ stdout->buffer[ stdout->bufidx++ ] = *s++;
+ if ( stdout->bufidx == stdout->bufsize )
+ {
+ if ( _PDCLIB_flushbuffer( stdout ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ }
+ if ( stdout->status & ( _IOLBF | _IONBF ) )
+ {
+ return _PDCLIB_flushbuffer( stdout );
+ }
return 0;
}
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ TESTCASE( puts( "SUCCESS testing puts()" ) >= 0 );
return TEST_RESULTS;
}
#endif
+
+++ /dev/null
-/* $Id$ */
-
-/* remove( const char * )
-
- 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>
-
-#ifndef REGTEST
-#include <_PDCLIB_glue.h>
-
-int remove( const char * filename )
-{
- /* TODO: Check open file list, flush and close file if open */
- return _PDCLIB_remove( filename );
-}
-
-#endif
-
-#ifdef TEST
-/* TODO: Work around the following undef */
-#undef SEEK_SET
-#include <_PDCLIB_test.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-int main( void )
-{
- /* TODO: Extend to internal testing (buffer etc.) */
- char filename[] = "touch testfile";
- system( filename );
- /* file is actually readable */
- TESTCASE( fopen( filename + 6, "r" ) != NULL );
- /* remove function does not return error */
- TESTCASE( remove( filename + 6 ) == 0 );
- /* file is no longer readable */
- TESTCASE( fopen( filename + 6, "r" ) == NULL );
- /* remove function does return error */
- TESTCASE( remove( filename + 6 ) != 0 );
- memcpy( filename, "mkdir", 5 );
- /* create directory */
- system( filename );
- /* remove function does not return error */
- TESTCASE( remove( filename + 6 ) == 0 );
- /* remove function does return error */
- TESTCASE( remove( filename + 6 ) != 0 );
- return TEST_RESULTS;
-}
-
-#endif
#endif
#ifdef TEST
-/* TODO: Work around the following undef */
-#undef SEEK_SET
#include <_PDCLIB_test.h>
#include <stdlib.h>
/* TODO: Extend to internal testing (buffer etc.) */
char filename1[] = "touch testfile1";
char filename2[] = "testfile2";
- /* check that neither file exists */
+ remove( filename1 + 6 );
+ remove( filename2 );
+ /* make sure that neither file exists */
TESTCASE( fopen( filename1 + 6, "r" ) == NULL );
TESTCASE( fopen( filename2, "r" ) == NULL );
/* rename file 1 to file 2 - expected to fail */
}
#endif
+
/* $Id$ */
-/* frewind( FILE * )
+/* rewind( FILE * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
void rewind( struct _PDCLIB_file_t * stream )
{
- if ( stream->status & _PDCLIB_WROTELAST )
- {
- fflush( stream );
- }
- /* TODO: Implement. */
- return;
+ stream->status &= ~ _PDCLIB_ERRORFLAG;
+ fseek( stream, 0L, SEEK_SET );
}
#endif
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ /* Testing covered by ftell.c */
return TEST_RESULTS;
}
void setbuf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, char * _PDCLIB_restrict buf )
{
- /* TODO: Only allowed on a "virgin" stream; add check. */
if ( buf == NULL )
{
setvbuf( stream, buf, _IONBF, BUFSIZ );
#ifdef TEST
#include <_PDCLIB_test.h>
+#include <stdlib.h>
int main( void )
{
/* TODO: Extend testing once setvbuf() is finished. */
#ifndef REGTEST
char const * const filename = "testfile";
- char buffer[ 100 ];
- struct _PDCLIB_file_t * fh;
+ char buffer[ BUFSIZ + 1 ];
+ FILE * fh;
+ remove( filename );
/* full buffered */
TESTCASE( ( fh = fopen( filename, "w" ) ) != NULL );
- TESTCASE( fh->status & _PDCLIB_LIBBUFFER );
- TESTCASE( fh->bufsize == BUFSIZ );
setbuf( fh, buffer );
-#if 0
TESTCASE( fh->buffer == buffer );
- TESTCASE( fh->bufsize == BUFFERSIZE );
-#endif
+ TESTCASE( fh->bufsize == BUFSIZ );
TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOFBF );
TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( filename ) == 0 );
/* not buffered */
TESTCASE( ( fh = fopen( filename, "w" ) ) != NULL );
setbuf( fh, NULL );
-#if 0
- TESTCASE( fh->buffer == NULL );
- TESTCASE( fh->bufsize == 0 );
-#endif
TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IONBF );
TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( filename ) == 0 );
#else
puts( " NOTEST setbuf() test driver is PDCLib-specific." );
#endif
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#ifndef REGTEST
int setvbuf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, char * _PDCLIB_restrict buf, int mode, size_t size )
{
- /* TODO: Honor user-provided buffer / buffer size. (Not actually required
- by the standard...) */
- stream->status &= ~( _IOFBF | _IOLBF | _IONBF );
- stream->status |= mode; /* TODO: Unchecked use of mode -> vulnerable. */
- return 0;
-
-#if 0
- /* Only allowed on "virgin" streams (i.e., before first I/O occurs), a
- valid value for mode, and only once per stream (i.e., the buffer
- attached to the stream should always be the one allocated by fopen().
- */
- if ( ( ! stream->status & _PDCLIB_VIRGINSTR ) ||
- ( ( mode != _IOFBF ) && ( mode != _IOLBF ) && ( mode != _IONBF ) ) ||
- ! ( stream->status & _PDCLIB_LIBBUFFER ) )
- {
- return -1;
- }
- if ( mode == _IONBF )
- {
- /* When unbuffered I/O is requested, we don't need a buffer. */
- buf = NULL;
- size = 0;
- }
- else
- {
- /* The standard does not really require this - only BUFSIZ is required
- to be no smaller than 256 - but it makes sense not to make buffers
- too small anyway.
- */
- if ( size < 256 )
- {
- buf = NULL; /* do not use too-small user buffer */
- size = 256;
- }
- }
- /* If a suitable buffer is provided by user... */
- if ( buf != NULL )
+ switch ( mode )
{
- /* ...do not free it in library functions like fclose(), freopen(). */
- stream->status &= ~_PDCLIB_LIBBUFFER;
+ case _IONBF:
+ /* When unbuffered I/O is requested, we keep the buffer anyway, as
+ we don't want to e.g. flush the stream for every character of a
+ stream being printed.
+ */
+ break;
+ case _IOFBF:
+ case _IOLBF:
+ if ( size > INT_MAX || size == NULL )
+ {
+ /* PDCLib only supports buffers up to INT_MAX in size. A size
+ of zero doesn't make sense.
+ */
+ return -1;
+ }
+ if ( buf == NULL )
+ {
+ /* User requested buffer size, but leaves it to library to
+ allocate the buffer.
+ */
+ if ( ( stream->bufsize < size ) || ( stream->bufsize > ( size << 1 ) ) )
+ {
+ /* If current buffer is big enough for requested size, but
+ not over twice as big (and wasting memory space), we use
+ the current buffer (i.e., do nothing), to save the
+ malloc() / free() overhead.
+ */
+ /* Free the buffer allocated by fopen(), and allocate a new
+ one.
+ */
+ if ( ( buf = (char *) malloc( size ) ) == NULL )
+ {
+ /* Out of memory error. */
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ /* User provided buffer -> set flag to not free() the buffer
+ on fclose().
+ */
+ stream->status &= ~ _PDCLIB_LIBBUFFER;
+ }
+ free( stream->buffer );
+ stream->buffer = buf;
+ stream->bufsize = size;
+ break;
+ default:
+ /* If mode is something else than _IOFBF, _IOLBF or _IONBF -> exit */
+ return -1;
}
- /* If we cannot allocate enough memory, that is not a reason for failure -
- the standard does not actually *require* that setvbuf() honors user-
- supplied buffer and buffer size, so we can quietly ignore this.
- */
- /* FIXME: Logic stops here. Handle _IONBF, new buf value etc. correctly. */
- puts("foo");
- if ( ( ( buf = malloc( size ) ) != NULL ) || ( mode == _IONBF ) )
- {
- free( stream->buffer );
- }
- puts("bar");
- /* Applying new settings to stream. */
+ /* Deleting current buffer mode */
stream->status &= ~( _IOFBF | _IOLBF | _IONBF );
+ /* Set user-defined mode */
stream->status |= mode;
- stream->bufsize = size;
- stream->status &= ~_PDCLIB_VIRGINSTR;
return 0;
-#endif
}
#endif
#ifdef TEST
#include <_PDCLIB_test.h>
+#include <errno.h>
+
#define BUFFERSIZE 500
int main( void )
#ifndef REGTEST
char const * const filename = "testfile";
char buffer[ BUFFERSIZE ];
- struct _PDCLIB_file_t * fh;
+ FILE * fh;
+ remove( filename );
/* full buffered, user-supplied buffer */
TESTCASE( ( fh = fopen( filename, "w" ) ) != NULL );
- TESTCASE( fh->status & _PDCLIB_LIBBUFFER );
- TESTCASE( fh->bufsize == BUFSIZ );
TESTCASE( setvbuf( fh, buffer, _IOFBF, BUFFERSIZE ) == 0 );
-#if 0
TESTCASE( fh->buffer == buffer );
TESTCASE( fh->bufsize == BUFFERSIZE );
-#endif
TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOFBF );
TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( filename ) == 0 );
/* line buffered, lib-supplied buffer */
TESTCASE( ( fh = fopen( filename, "w" ) ) != NULL );
TESTCASE( setvbuf( fh, NULL, _IOLBF, BUFFERSIZE ) == 0 );
-#if 0
- TESTCASE( fh->buffer != buffer );
TESTCASE( fh->buffer != NULL );
TESTCASE( fh->bufsize == BUFFERSIZE );
-#endif
TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOLBF );
TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( filename ) == 0 );
/* not buffered, user-supplied buffer */
TESTCASE( ( fh = fopen( filename, "w" ) ) != NULL );
TESTCASE( setvbuf( fh, buffer, _IONBF, BUFFERSIZE ) == 0 );
-#if 0
- TESTCASE( fh->buffer == NULL );
- TESTCASE( fh->bufsize == 0 );
-#endif
TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IONBF );
TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( filename ) == 0 );
#else
puts( " NOTEST setvbuf() test driver is PDCLib-specific." );
#endif
}
#endif
+
#ifndef REGTEST
-int ungetc( int c, struct _PDCLIB_file_t * stream )
+int ungetc( int c, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
{
- /* TODO: Implement. */
- return 0;
+ if ( c == EOF || stream->ungetidx == _PDCLIB_UNGETCBUFSIZE )
+ {
+ return -1;
+ }
+ return stream->ungetbuf[stream->ungetidx++] = (unsigned char) c;
}
#endif
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ /* Testing covered by ftell.c */
return TEST_RESULTS;
}
{
/* TODO: This function should interpret format as multibyte characters. */
/* Members: base, flags, n, i, this, s, width, prec, stream, arg */
- struct _PDCLIB_status_t status = { 0, 0, SIZE_MAX, 0, 0, NULL, 0, 0, stream, arg };
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = SIZE_MAX;
+ status.i = 0;
+ status.this = 0;
+ status.s = NULL;
+ status.width = 0;
+ status.prec = 0;
+ status.stream = stream;
+ va_copy( status.arg, arg );
while ( *format != '\0' )
{
const char * rc;
format = rc;
}
}
+ va_end( status.arg );
return status.i;
}
{
/* TODO: This function should interpret format as multibyte characters. */
/* Members: base, flags, n, i, this, s, width, prec, stream, arg */
- struct _PDCLIB_status_t status = { 0, 0, n, 0, 0, s, 0, 0, NULL, arg };
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = n;
+ status.i = 0;
+ status.this = 0;
+ status.s = s;
+ status.width = 0;
+ status.prec = 0;
+ status.stream = NULL;
+ va_copy( status.arg, arg );
+ // = { 0, 0, n, 0, 0, s, 0, 0, NULL };
while ( *format != '\0' )
{
const char * rc;
}
}
s[ status.i ] = '\0';
+ va_end( status.arg );
return status.i;
}
}
#endif
+
#ifndef REGTEST
-int foo = SIZE_MAX;
-
int vsprintf( char * str, const char * format, va_list arg )
{
return vsnprintf( str, SIZE_MAX, format, arg ); /* TODO: Replace with a non-checking call */
#include <stdlib.h>
#include <stdio.h>
-#include <_PDCLIB_glue.h>
#ifndef REGTEST
+#include <_PDCLIB_glue.h>
void _Exit( int status )
{
else
{
_PDCLIB_regstack[ --_PDCLIB_regptr ] = func;
- return 0;
+ return 0;
}
}
{
const void * pivot;
int rc;
- int corr;
+ size_t corr;
while ( nmemb )
{
/* algorithm needs -1 correction if remaining elements are an even number. */
- corr = ( nmemb % 2 ) - 1;
+ corr = nmemb % 2;
nmemb /= 2;
pivot = (const char *)base + (nmemb * size);
rc = compar( key, pivot );
if ( rc > 0 )
{
base = (const char *)pivot + size;
- nmemb += corr;
+ /* applying correction */
+ nmemb -= ( 1 - corr );
}
else if ( rc == 0 )
{
#include <stdlib.h>
#include <stdint.h>
+#include <stdbool.h>
#ifndef REGTEST
/* No exact fit; go for first fit */
if ( firstfit != NULL )
{
- if ( ( firstfit->size - size ) > _PDCLIB_MINALLOC )
+ bool node_split = false;
+ if ( ( firstfit->size - size ) > ( _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ) ) )
{
/* Oversized - split into two nodes */
struct _PDCLIB_memnode_t * newnode = (struct _PDCLIB_memnode_t *)( (char *)firstfit + sizeof( struct _PDCLIB_memnode_t ) + size );
newnode->next = firstfit->next;
firstfit->next = newnode;
firstfit->size = firstfit->size - newnode->size - sizeof( struct _PDCLIB_memnode_t );
+ node_split = true;
}
if ( firstfit_previous != NULL )
{
if ( _PDCLIB_memlist.last == firstfit )
{
/* Node is last in list */
- _PDCLIB_memlist.last = firstfit_previous;
+ if ( node_split )
+ {
+ _PDCLIB_memlist.last = firstfit->next;
+ }
+ else
+ {
+ _PDCLIB_memlist.last = firstfit_previous;
+ }
}
return (char *)firstfit + sizeof( struct _PDCLIB_memnode_t );
}
}
{
/* No fit possible; how many additional pages do we need? */
- int pages = ( ( size + sizeof( struct _PDCLIB_memnode_t ) - 1 ) / _PDCLIB_PAGESIZE ) + 1;
+ size_t pages = ( ( size + sizeof( struct _PDCLIB_memnode_t ) - 1 ) / _PDCLIB_PAGESIZE ) + 1;
/* Allocate more pages */
- struct _PDCLIB_memnode_t * newnode = (struct _PDCLIB_memnode_t *)_PDCLIB_allocpages( pages );
+ struct _PDCLIB_memnode_t * newnode = (struct _PDCLIB_memnode_t *)_PDCLIB_allocpages( (int)pages );
if ( newnode != NULL )
{
newnode->next = NULL;
#endif
+
#ifdef TEST
#include <_PDCLIB_test.h>
#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
-#define MEMTEST( ptr, size ) ( ( ptr = malloc( size ) ) != NULL ) && ( memset( ptr, 0, size ) == ptr )
-#define PAGETEST( x ) ( pages_start + x * _PDCLIB_PAGESIZE ) == sbrk( 0 )
+
+#ifndef REGTEST
+
+/* Effective page size, i.e. how many bytes can be allocated and still be on
+ one page of memory.
+*/
#define EFFECTIVE _PDCLIB_PAGESIZE - sizeof( struct _PDCLIB_memnode_t )
+#define MEMTEST( ptr, size ) ( ( ptr = malloc( size ) ) != NULL ) && ( memset( ptr, 0, size ) == ptr )
+
+char * pages_start = 0;
+int test_nodes( char const * const, int, ... );
+void PRINT( char const * const, ... );
-/* This can be enabled to give a dump of available nodes */
+/* This can be enabled to give a dump of node information */
#if 0
-#define NODETRACE( x ) do { struct _PDCLIB_memnode_t * tracer = _PDCLIB_memlist.first; printf( "Node trace #%d, %d allocated pages\n", x, ( (intptr_t)sbrk( 0 ) - (intptr_t)pages_start ) / _PDCLIB_PAGESIZE ); while ( tracer != NULL ) { printf( "- node %p, size %#x\n", (void *)tracer, tracer->size ); tracer = tracer->next; } } while ( 0 )
+void PRINT( char const * const format, ... )
+{
+ va_list( ap );
+ va_start( ap, format );
+ vprintf( format, ap );
+}
#else
-#define NODETRACE( x ) ( (void) 0 )
+void PRINT( char const * const format, ... )
+{
+ /* EMPTY */
+}
#endif
+/* Helper function checking number of allocated memory pages and the nodes
+ in the free memory list against expectations.
+*/
+int test_nodes( char const * const action, int expected_pages, ... )
+{
+ static int count = 1;
+ int result = 1;
+ PRINT( action );
+ /* Determining the amount of allocated pages */
+ int allocated_pages = ( (intptr_t)_PDCLIB_allocpages( 0 ) - (intptr_t)pages_start ) / _PDCLIB_PAGESIZE;
+ PRINT( "Test #%2d, %d allocated pages", count++, allocated_pages );
+ if ( allocated_pages != expected_pages )
+ {
+ PRINT( " - MISMATCH, expected\n %d pages\n", expected_pages );
+ result = 0;
+ }
+ else
+ {
+ PRINT( "\n" );
+ }
+ /* Now moving through the free nodes list */
+ va_list( ap );
+ va_start( ap, expected_pages );
+ struct _PDCLIB_memnode_t * tracer = _PDCLIB_memlist.first;
+ int firstnode = 0;
+ int lastnode = 0;
+ while ( tracer != NULL )
+ {
+ /* Data from node */
+ size_t node_location = (char *)tracer - (char *)pages_start;
+ PRINT( " - node %.4p, size %#.4x", node_location, tracer->size );
+ /* Expected data */
+ size_t expected_location = va_arg( ap, size_t );
+ if ( expected_location == 0 )
+ {
+ PRINT( " - UNEXPECTED NODE\n" );
+ result = 0;
+ continue;
+ }
+ /* Memorizing first and last expected node for later comparison. */
+ if ( firstnode == 0 )
+ {
+ firstnode = expected_location;
+ }
+ lastnode = expected_location;
+ /* Comparing expected node against current node */
+ size_t expected_size = va_arg( ap, size_t );
+ if ( ( node_location != expected_location ) || ( tracer->size != expected_size ) )
+ {
+ PRINT( " - MISMATCH, expected values\n %.4p %#.4p\n", expected_location, expected_size );
+ result = 0;
+ }
+ else
+ {
+ PRINT( "\n" );
+ }
+ tracer = tracer->next;
+ }
+ /* Comparing first and last node in memlist against expectations. */
+ PRINT( " - memlist first: %#.4x - last: %#.4x",
+ ( _PDCLIB_memlist.first == NULL ) ? NULL : (char *)_PDCLIB_memlist.first - (char *)pages_start,
+ ( _PDCLIB_memlist.last == NULL ) ? NULL : (char *)_PDCLIB_memlist.last - (char *)pages_start );
+ if ( ( firstnode != 0 ) &&
+ ( ( ( (char *)_PDCLIB_memlist.first - (char *)pages_start ) != firstnode )
+ || ( ( (char *)_PDCLIB_memlist.last - (char *)pages_start ) != lastnode ) ) )
+ {
+ PRINT( " - MISMATCH, expected values\n %#.4x - last: %#.4x\n", firstnode, lastnode );
+ result = 0;
+ }
+ else
+ {
+ PRINT( "\n" );
+ }
+ PRINT( "\n" );
+ return result;
+}
+
+#endif
+
/* Note that this test driver heavily tests *internals* of the implementation
above (and of free() and realloc(), too). That means that changes in the
implementation must be accompanied with appropriate changes of the test
I am afraid, and thus there is no REGTEST equivalent.
*/
-void * sbrk( intptr_t );
-
int main( void )
{
#ifndef REGTEST
- void * ptr1, * ptr2, * ptr3, * ptr4, * ptr5, * ptr6, * ptr7, * ptr8, * ptr9;
- char * pages_start = _PDCLIB_allocpages( 0 );
- /* allocating 10 byte; expected: 1 page allocation, node split */
+ void * ptr1, * ptr2, * ptr3, * ptr4, * ptr5, * ptr6, * ptr7, * ptr8, * ptr9, * ptrA, * ptrB, * ptrC;
+
+ pages_start = _PDCLIB_allocpages( 0 );
+ PRINT( "\nEffective is: %#.4x\nsizeof( memnode ) is: %#.2x\n\n", EFFECTIVE, sizeof( struct _PDCLIB_memnode_t ) );
+
+ /* Allocating 10 bytes; expecting one page allocation and a node split */
TESTCASE( MEMTEST( ptr1, 10 ) );
- TESTCASE( PAGETEST( 1 ) );
- NODETRACE( 1 );
- /* allocating EFFECTIVE - 10 byte; expected: no page allocation, receiving split node */
+ TESTCASE( test_nodes( "Allocating 10 bytes.", 1,
+ sizeof( struct _PDCLIB_memnode_t ) + 10, EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - 10,
+ 0 ) );
+
+ /* Allocating the rest of the page; expecting no page allocation and assignment of the remaining node */
TESTCASE( MEMTEST( ptr2, EFFECTIVE - 10 - sizeof( struct _PDCLIB_memnode_t ) ) );
- TESTCASE( PAGETEST( 1 ) );
- NODETRACE( 2 );
- /* allocating EFFECTIVE; expected: 1 page allocation, no node split */
+ TESTCASE( test_nodes( "Allocating the rest of the page.", 1,
+ 0 ) );
+
+ /* Allocating a full page; expecting one page allocation, no node split */
TESTCASE( MEMTEST( ptr3, EFFECTIVE ) );
- TESTCASE( PAGETEST( 2 ) );
- NODETRACE( 3 );
- /* allocating EFFECTIVE - 4; expected: 1 page allocation, no node split */
+ TESTCASE( test_nodes( "Allocating a full page.", 2,
+ 0 ) );
+
+ /* Allocating *almost* a full page; expecting one page allocation, no node split */
TESTCASE( MEMTEST( ptr4, EFFECTIVE - 4 ) );
- TESTCASE( PAGETEST( 3 ) );
- NODETRACE( 4 );
- /* freeing and re-allocating EFFECTIVE - 4; expected: no page allocation, no node split */
+ TESTCASE( test_nodes( "Allocating *almost* a full page.", 3,
+ 0 ) );
+
+ /* Freeing and re-allocating the "almost" full page; expecting no page allocation, no node split */
free( ptr4 );
TESTCASE( MEMTEST( ptr5, EFFECTIVE - 4 ) );
TESTCASE( ptr4 == ptr5 );
- TESTCASE( PAGETEST( 3 ) );
- NODETRACE( 5 );
- /* releasing EFFECTIVE; expected: no page release */
+ TESTCASE( test_nodes( "Freeing and re-allocating the \"almost\" full page.", 3 ) );
+
+ /* Freeing the full page from test #3; expecting a full-sized free node. */
free( ptr3 );
- TESTCASE( PAGETEST( 3 ) );
- NODETRACE( 6 );
- /* allocating EFFECTIVE + _PDCLIB_PAGESIZE; expected: 2 page allocation, no node split */
+ TESTCASE( test_nodes( "Freeing the full page from test #3.", 3,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Allocating two full pages; expecting two page allocations, no node split */
TESTCASE( MEMTEST( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE ) );
- TESTCASE( PAGETEST( 5 ) );
- NODETRACE( 7 );
- /* reallocating to 10 byte; expected: no page allocation, no node split */
+ TESTCASE( test_nodes( "Allocating two full pages.", 5,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Re-allocating to size of 10 bytes; expecting no page allocation, no node split */
+ /* TODO: Shouldn't realloc() split the now much-too-large node? */
TESTCASE( realloc( ptr3, 10 ) == ptr3 );
- TESTCASE( PAGETEST( 5 ) );
- NODETRACE( 8 );
- /* reallocating to EFFECTIVE + _PDCLIB_PAGESIZE; expected: no page allocation, no node split */
+ TESTCASE( test_nodes( "Re-allocating to size of 10 bytes.", 5,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Re-allocating to size of two full pages; expecting no page allocation, no node split */
TESTCASE( realloc( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE ) == ptr3 );
- TESTCASE( PAGETEST( 5 ) );
- NODETRACE( 9 );
- /* reallocating to EFFECTIVE + _PDCLIB_PAGESIZE * 2; expected: 3 page allocations, no node split */
+ TESTCASE( test_nodes( "Re-allocating to size of two full pages.", 5,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Re-allocating to size of three full pages; expecting three page allocation, freeing of two-page node */
TESTCASE( realloc( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE * 2 ) != ptr3 );
- TESTCASE( PAGETEST( 8 ) );
- NODETRACE( 10 );
- /* allocating EFFECTIVE + _PDCLIB_PAGESIZE; expected: no page allocation, no node split */
+ TESTCASE( test_nodes( "Re-allocating to size of three full pages.", 8,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ _PDCLIB_PAGESIZE * 3, EFFECTIVE + _PDCLIB_PAGESIZE,
+ 0 ) );
+
+ /* Allocating two full pages; expecting allocation of the available two-page node */
TESTCASE( MEMTEST( ptr4, EFFECTIVE + _PDCLIB_PAGESIZE ) );
- TESTCASE( PAGETEST( 8 ) );
- NODETRACE( 11 );
- /* allocating zero size; expected: no page allocation, no node split */
+ TESTCASE( test_nodes( "Allocating two full pages.", 8,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Allocating zero bytes; expecting no change */
TESTCASE( ! MEMTEST( ptr6, 0 ) );
- TESTCASE( PAGETEST( 8 ) );
- NODETRACE( 12 );
- /* allocating 4 byte; expected: no page allocation, upsizing of size, node split */
+ TESTCASE( test_nodes( "Allocating zero bytes.", 8,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Allocating 4 bytes; expecting upsizing of requestupsizing of size, node split */
TESTCASE( MEMTEST( ptr7, 4 ) );
- TESTCASE( PAGETEST( 8 ) );
- NODETRACE( 13 );
- /* allocating rest of page; expected: no page allocation, no node split */
+ TESTCASE( test_nodes( "Allocating 4 bytes.", 8,
+ _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ),
+ EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ),
+ 0 ) );
+
+ /* Allocating the rest of the page; expecting no page allocation and assignment of the remaining node */
TESTCASE( MEMTEST( ptr8, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) );
- TESTCASE( PAGETEST( 8 ) );
- NODETRACE( 14 );
- /* freeing, and allocating one byte more; expected: 1 page allocation, no node split */
+ TESTCASE( test_nodes( "Allocating the rest of the page.", 8, 0 ) );
+
+ /* Freeing the node from the previous test; expecting node to re-appear in free list */
free( ptr8 );
- NODETRACE( 15 );
+ TESTCASE( test_nodes( "Freeing the node from the previous test.", 8,
+ _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ),
+ EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ),
+ 0 ) );
+
+ /* Allocating one byte more than available in free node; expecting page allocation */
TESTCASE( MEMTEST( ptr8, EFFECTIVE + 1 - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) );
- TESTCASE( PAGETEST( 9 ) );
- NODETRACE( 16 );
- /* realloc with NULL pointer; expected: no page allocation, no node split */
- ptr9 = realloc( NULL, 4072 );
+ TESTCASE( test_nodes( "Allocating one byte more than available in free node.", 9,
+ _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ),
+ EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ),
+ 0 ) );
+
+ /* Re-allocating with NULL pointer; expecting no page allocation, no node split */
+ ptr9 = realloc( NULL, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) );
TESTCASE( ptr9 != NULL );
- TESTCASE( memset( ptr9, 0, 4072 ) == ptr9 );
- TESTCASE( PAGETEST( 9 ) );
- NODETRACE( 17 );
+ TESTCASE( memset( ptr9, 0, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) == ptr9 );
+ TESTCASE( test_nodes( "Re-allocating with NULL pointer.", 9, 0 ) );
+
+ /* Allocating a bit more than half a page; expecting page allocation, node split */
+#define TESTSIZE 3000
+ TESTCASE( MEMTEST( ptrA, TESTSIZE ) );
+ TESTCASE( test_nodes( "Allocating a bit more than half a page.", 10,
+ _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ 0 ) );
+
+ /* Allocating a bit more than half a page; expecting page allocation, node split */
+ TESTCASE( MEMTEST( ptrB, TESTSIZE ) );
+ TESTCASE( test_nodes( "Allocating a bit more than half a page.", 11,
+ _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ 0 ) );
+
+ /* Allocating a bit more than half a page; expecting page allocation, node split */
+ TESTCASE( MEMTEST( ptrC, TESTSIZE ) );
+ TESTCASE( test_nodes( "Allocating a bit more than half a page.", 12,
+ _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 11 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ 0 ) );
+
+ /* Freeing the middle node */
+ free( ptrB );
+ TESTCASE( test_nodes( "Freeing the middle node.", 12,
+ _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 11 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 10,
+ TESTSIZE,
+ 0 ) );
+
#else
puts( " NOTEST malloc() test driver is PDCLib-specific." );
#endif
{
char * i;
char * j;
- _PDCLIB_ptrdiff_t thresh = T * size;
- char * base_ = (char *)base;
- char * limit = base_ + nmemb * size;
+ _PDCLIB_size_t thresh = T * size;
+ char * base_ = (char *)base;
+ char * limit = base_ + nmemb * size;
PREPARE_STACK;
for ( ;; )
{
- if ( limit - base_ > thresh ) /* QSort for more than T elements. */
+ if ( (size_t)( limit - base_ ) > thresh ) /* QSort for more than T elements. */
{
/* We work from second to last - first will be pivot element. */
i = base_ + size;
int rand( void )
{
_PDCLIB_seed = _PDCLIB_seed * 1103515245 + 12345;
- return (unsigned int) ( _PDCLIB_seed / 65536 ) % 32768;
+ return (int)( _PDCLIB_seed / 65536 ) % 32768;
}
#endif
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 ), (int)( LONG_MAX % base ), &sign );
+ rc = (long int)_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 ), (int)( -( LONG_MIN % base ) ), &sign );
+ rc = (long int)_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( "0x8000000000000000", NULL, 0 ) == LONG_MAX );
TESTCASE( errno == ERANGE );
errno = 0;
- TESTCASE( strtol( "-0x7FFFFFFFFFFFFFFF", NULL, 0 ) == -0x8000000000000001 );
+ TESTCASE( strtol( "-0x7FFFFFFFFFFFFFFF", NULL, 0 ) == (long)0x8000000000000001 );
TESTCASE( errno == 0 );
TESTCASE( strtol( "-0x8000000000000000", 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 ), (int)( LLONG_MAX % base ), &sign );
+ rc = (long long int)_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 ), (int)( -( LLONG_MIN % base ) ), &sign );
+ rc = (long long int)_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;
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 ), (int)( ULONG_MAX % base ), &sign );
+ rc = (unsigned long int)_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;
}
++s1;
++s2;
}
- return ( *s1 - *s2 );
+ return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
}
#endif
int main( void )
{
char cmpabcde[] = "abcde";
+ char cmpabcd_[] = "abcd\xfc";
char empty[] = "";
TESTCASE( strcmp( abcde, cmpabcde ) == 0 );
TESTCASE( strcmp( abcde, abcdx ) < 0 );
TESTCASE( strcmp( abcdx, abcde ) > 0 );
TESTCASE( strcmp( empty, abcde ) < 0 );
TESTCASE( strcmp( abcde, empty ) > 0 );
+ TESTCASE( strcmp( abcde, cmpabcd_ ) < 0 );
return TEST_RESULTS;
}
#endif
}
else
{
- return ( *s1 - *s2 );
+ return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
}
}
int main( void )
{
char cmpabcde[] = "abcde\0f";
+ char cmpabcd_[] = "abcde\xfc";
char empty[] = "";
char x[] = "x";
TESTCASE( strncmp( abcde, cmpabcde, 5 ) == 0 );
TESTCASE( strncmp( abcde, abcdx, 4 ) == 0 );
TESTCASE( strncmp( abcde, x, 0 ) == 0 );
TESTCASE( strncmp( abcde, x, 1 ) < 0 );
+ TESTCASE( strncmp( abcde, cmpabcd_, 10 ) < 0 );
return TEST_RESULTS;
}
#endif
#define assert( expression ) ( ( expression ) ? (void) 0 \
: _PDCLIB_assert( "Assertion failed: " #expression \
", function ", __func__, \
- ", file " __FILE__ \
- ", line " _PDCLIB_symbol2string( __LINE__ ) \
- "." _PDCLIB_endl ) )
+ ", 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_assert( "Assertion failed: " #expression \
+ ", file " __FILE__ \
+ ", line " _PDCLIB_symbol2string( __LINE__ ) \
+ "." _PDCLIB_endl ) )
#endif
#endif
/* $Id$ */
-/* _PDCLIB_Xdigits
+/* Errors <errno.h>
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
+#ifndef _PDCLIB_ERRNO_H
+#define _PDCLIB_ERRNO_H _PDCLIB_ERRNO_H
+
#ifndef _PDCLIB_INT_H
#define _PDCLIB_INT_H _PDCLIB_INT_H
#include <_PDCLIB_int.h>
#endif
-char _PDCLIB_Xdigits[] = "0123456789ABCDEF";
-
-#ifdef TEST
-#include <_PDCLIB_test.h>
+#define errno (*_PDCLIB_errno_func())
-#include <string.h>
-
-int main( void )
-{
- TESTCASE( strcmp( _PDCLIB_Xdigits, "0123456789ABCDEF" ) == 0 );
- return TEST_RESULTS;
-}
+#define ERANGE _PDCLIB_ERANGE
+#define EDOM _PDCLIB_EDOM
#endif
+
#define _IONBF 4
/* The following are platform-dependant, and defined in _PDCLIB_config.h. */
-typedef _PDCLIB_fpos_t fpos_t;
+typedef struct _PDCLIB_fpos_t fpos_t;
typedef struct _PDCLIB_file_t FILE;
#define EOF -1
#define BUFSIZ _PDCLIB_BUFSIZ
#define TMP_MAX _PDCLIB_TMP_MAX
/* See fseek(), third argument */
-#define SEEK_CUR 1
-#define SEEK_END 2
-#define SEEK_SET 4
+#define SEEK_CUR _PDCLIB_SEEK_CUR
+#define SEEK_END _PDCLIB_SEEK_END
+#define SEEK_SET _PDCLIB_SEEK_SET
extern struct _PDCLIB_file_t * stdin;
extern struct _PDCLIB_file_t * stdout;
-/* $Id$ */\r
-\r
-/* String handling <string.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
-#ifndef _PDCLIB_STRING_H\r
-#define _PDCLIB_STRING_H _PDCLIB_STRING_H\r
-\r
-#ifndef _PDCLIB_INT_H\r
-#define _PDCLIB_INT_H _PDCLIB_INT_H\r
-#include <_PDCLIB_int.h>\r
-#endif\r
-\r
-#ifndef _PDCLIB_SIZE_T_DEFINED\r
-#define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED\r
-typedef _PDCLIB_size_t size_t;\r
-#endif\r
-\r
-#ifndef _PDCLIB_NULL_DEFINED\r
-#define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED\r
-#define NULL _PDCLIB_NULL\r
-#endif\r
-\r
-/* String function conventions */\r
-\r
-/*\r
- In any of the following functions taking a size_t n to specify the length of\r
- an array or size of a memory region, n may be 0, but the pointer arguments to\r
- the call shall still be valid unless otherwise stated.\r
-*/\r
-\r
-/* Copying functions */\r
-\r
-/* Copy a number of n characters from the memory area pointed to by s2 to the\r
- area pointed to by s1. If the two areas overlap, behaviour is undefined.\r
- Returns the value of s1.\r
-*/\r
-void * memcpy( void * _PDCLIB_restrict s1, const void * _PDCLIB_restrict s2, size_t n );\r
-\r
-/* Copy a number of n characters from the memory area pointed to by s2 to the\r
- area pointed to by s1. The two areas may overlap.\r
- Returns the value of s1.\r
-*/\r
-void * memmove( void * _PDCLIB_restrict s1, const void * _PDCLIB_restrict s2, size_t n );\r
-\r
-/* Copy the character array s2 (including terminating '\0' byte) into the\r
- character array s1.\r
- Returns the value of s1.\r
-*/\r
-char * strcpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 );\r
-\r
-/* Copy a maximum of n characters from the character array s2 into the character\r
- array s1. If s2 is shorter than n characters, '\0' bytes will be appended to\r
- the copy in s1 until n characters have been written. If s2 is longer than n\r
- characters, NO terminating '\0' will be written to s1. If the arrays overlap,\r
- behaviour is undefined.\r
- Returns the value of s1.\r
-*/\r
-char * strncpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n );\r
-\r
-/* Concatenation functions */\r
-\r
-/* Append the contents of the character array s2 (including terminating '\0') to\r
- the character array s1 (first character of s2 overwriting the '\0' of s1). If\r
- the arrays overlap, behaviour is undefined.\r
- Returns the value of s1.\r
-*/\r
-char * strcat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 );\r
-\r
-/* Append a maximum of n characters from the character array s1 to the character\r
- array s1 (first character of s2 overwriting the '\0' of s1). A terminating\r
- '\0' is ALWAYS appended, even if the full n characters have already been\r
- written. If the arrays overlap, behaviour is undefined.\r
- Returns the value of s1.\r
-*/\r
-char * strncat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n );\r
-\r
-/* Comparison functions */\r
-\r
-/* Compare the first n characters of the memory areas pointed to by s1 and s2.\r
- Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if\r
- s1 > s2.\r
-*/\r
-int memcmp( const void * s1, const void * s2, size_t n );\r
-\r
-/* Compare the character arrays s1 and s2.\r
- Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if\r
- s1 > s2.\r
-*/\r
-int strcmp( const char * s1, const char * s2 );\r
-\r
-/* Compare the character arrays s1 and s2, interpreted as specified by the\r
- LC_COLLATE category of the current locale.\r
- Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if\r
- s1 > s2.\r
- TODO: Currently a dummy wrapper for strcmp() as PDCLib does not yet support\r
- locales.\r
-*/\r
-int strcoll( const char * s1, const char * s2 );\r
-\r
-/* Compare no more than the first n characters of the character arrays s1 and\r
- s2.\r
- Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if\r
- s1 > s2.\r
-*/\r
-int strncmp( const char * s1, const char * s2, size_t n );\r
-\r
-/* Transform the character array s2 as appropriate for the LC_COLLATE setting of\r
- the current locale. If length of resulting string is less than n, store it in\r
- the character array pointed to by s1. Return the length of the resulting\r
- string.\r
-*/\r
-size_t strxfrm( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n );\r
-\r
-/* Search functions */\r
-\r
-/* Search the first n characters in the memory area pointed to by s for the\r
- character c (interpreted as unsigned char).\r
- Returns a pointer to the first instance found, or NULL.\r
-*/\r
-void * memchr( const void * s, int c, size_t n );\r
-\r
-/* Search the character array s (including terminating '\0') for the character c\r
- (interpreted as char).\r
- Returns a pointer to the first instance found, or NULL.\r
-*/\r
-char * strchr( const char * s, int c );\r
-\r
-/* Determine the length of the initial substring of character array s1 which\r
- consists only of characters not from the character array s2.\r
- Returns the length of that substring.\r
-*/\r
-size_t strcspn( const char * s1, const char * s2 );\r
-\r
-/* Search the character array s1 for any character from the character array s2.\r
- Returns a pointer to the first occurrence, or NULL.\r
-*/\r
-char * strpbrk( const char * s1, const char * s2 );\r
-\r
-/* Search the character array s (including terminating '\0') for the character c\r
- (interpreted as char).\r
- Returns a pointer to the last instance found, or NULL.\r
-*/\r
-char * strrchr( const char * s, int c );\r
-\r
-/* Determine the length of the initial substring of character array s1 which\r
- consists only of characters from the character array s2.\r
- Returns the length of that substring.\r
-*/\r
-size_t strspn( const char * s1, const char * s2 );\r
-\r
-/* Search the character array s1 for the substring in character array s2.\r
- Returns a pointer to that sbstring, or NULL. If s2 is of length zero,\r
- returns s1.\r
-*/\r
-char * strstr( const char * s1, const char * s2 );\r
-\r
-/* In a series of subsequent calls, parse a C string into tokens.\r
- On the first call to strtok(), the first argument is a pointer to the to-be-\r
- parsed C string. On subsequent calls, the first argument is NULL unless you\r
- want to start parsing a new string. s2 holds an array of seperator characters\r
- which can differ from call to call. Leading seperators are skipped, the first\r
- trailing seperator overwritten with '\0'.\r
- Returns a pointer to the next token.\r
- WARNING: This function uses static storage, and as such is not reentrant.\r
-*/\r
-char * strtok( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 );\r
-\r
-/* Miscellaneous functions */\r
-\r
-/* Write the character c (interpreted as unsigned char) to the first n\r
- characters of the memory area pointed to by s.\r
- Returns s.\r
-*/\r
-void * memset( void * s, int c, size_t n );\r
-\r
-/* Map an error number to a (locale-specific) error message string. Error\r
- numbers are typically errno values, but any number is mapped to a message.\r
- TODO: PDCLib does not yet support locales.\r
- TODO: strerror() not yet implemented.\r
-char * strerror( int errnum );\r
-*/\r
-\r
-/* Returns the length of the string s (excluding terminating '\0').\r
-*/\r
-size_t strlen( const char * s );\r
-\r
-#endif\r
+/* $Id$ */
+
+/* String handling <string.h>
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef _PDCLIB_STRING_H
+#define _PDCLIB_STRING_H _PDCLIB_STRING_H
+
+#ifndef _PDCLIB_INT_H
+#define _PDCLIB_INT_H _PDCLIB_INT_H
+#include <_PDCLIB_int.h>
+#endif
+
+#ifndef _PDCLIB_SIZE_T_DEFINED
+#define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED
+typedef _PDCLIB_size_t size_t;
+#endif
+
+#ifndef _PDCLIB_NULL_DEFINED
+#define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED
+#define NULL _PDCLIB_NULL
+#endif
+
+/* String function conventions */
+
+/*
+ In any of the following functions taking a size_t n to specify the length of
+ an array or size of a memory region, n may be 0, but the pointer arguments to
+ the call shall still be valid unless otherwise stated.
+*/
+
+/* Copying functions */
+
+/* Copy a number of n characters from the memory area pointed to by s2 to the
+ area pointed to by s1. If the two areas overlap, behaviour is undefined.
+ Returns the value of s1.
+*/
+void * memcpy( void * _PDCLIB_restrict s1, const void * _PDCLIB_restrict s2, size_t n );
+
+/* Copy a number of n characters from the memory area pointed to by s2 to the
+ area pointed to by s1. The two areas may overlap.
+ Returns the value of s1.
+*/
+void * memmove( void * _PDCLIB_restrict s1, const void * _PDCLIB_restrict s2, size_t n );
+
+/* Copy the character array s2 (including terminating '\0' byte) into the
+ character array s1.
+ Returns the value of s1.
+*/
+char * strcpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 );
+
+/* Copy a maximum of n characters from the character array s2 into the character
+ array s1. If s2 is shorter than n characters, '\0' bytes will be appended to
+ the copy in s1 until n characters have been written. If s2 is longer than n
+ characters, NO terminating '\0' will be written to s1. If the arrays overlap,
+ behaviour is undefined.
+ Returns the value of s1.
+*/
+char * strncpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n );
+
+/* Concatenation functions */
+
+/* Append the contents of the character array s2 (including terminating '\0') to
+ the character array s1 (first character of s2 overwriting the '\0' of s1). If
+ the arrays overlap, behaviour is undefined.
+ Returns the value of s1.
+*/
+char * strcat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 );
+
+/* Append a maximum of n characters from the character array s1 to the character
+ array s1 (first character of s2 overwriting the '\0' of s1). A terminating
+ '\0' is ALWAYS appended, even if the full n characters have already been
+ written. If the arrays overlap, behaviour is undefined.
+ Returns the value of s1.
+*/
+char * strncat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n );
+
+/* Comparison functions */
+
+/* Compare the first n characters of the memory areas pointed to by s1 and s2.
+ Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if
+ s1 > s2.
+*/
+int memcmp( const void * s1, const void * s2, size_t n );
+
+/* Compare the character arrays s1 and s2.
+ Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if
+ s1 > s2.
+*/
+int strcmp( const char * s1, const char * s2 );
+
+/* Compare the character arrays s1 and s2, interpreted as specified by the
+ LC_COLLATE category of the current locale.
+ Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if
+ s1 > s2.
+ TODO: Currently a dummy wrapper for strcmp() as PDCLib does not yet support
+ locales.
+*/
+int strcoll( const char * s1, const char * s2 );
+
+/* Compare no more than the first n characters of the character arrays s1 and
+ s2.
+ Returns 0 if s1 == s2, a negative number if s1 < s2, and a positive number if
+ s1 > s2.
+*/
+int strncmp( const char * s1, const char * s2, size_t n );
+
+/* Transform the character array s2 as appropriate for the LC_COLLATE setting of
+ the current locale. If length of resulting string is less than n, store it in
+ the character array pointed to by s1. Return the length of the resulting
+ string.
+*/
+size_t strxfrm( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n );
+
+/* Search functions */
+
+/* Search the first n characters in the memory area pointed to by s for the
+ character c (interpreted as unsigned char).
+ Returns a pointer to the first instance found, or NULL.
+*/
+void * memchr( const void * s, int c, size_t n );
+
+/* Search the character array s (including terminating '\0') for the character c
+ (interpreted as char).
+ Returns a pointer to the first instance found, or NULL.
+*/
+char * strchr( const char * s, int c );
+
+/* Determine the length of the initial substring of character array s1 which
+ consists only of characters not from the character array s2.
+ Returns the length of that substring.
+*/
+size_t strcspn( const char * s1, const char * s2 );
+
+/* Search the character array s1 for any character from the character array s2.
+ Returns a pointer to the first occurrence, or NULL.
+*/
+char * strpbrk( const char * s1, const char * s2 );
+
+/* Search the character array s (including terminating '\0') for the character c
+ (interpreted as char).
+ Returns a pointer to the last instance found, or NULL.
+*/
+char * strrchr( const char * s, int c );
+
+/* Determine the length of the initial substring of character array s1 which
+ consists only of characters from the character array s2.
+ Returns the length of that substring.
+*/
+size_t strspn( const char * s1, const char * s2 );
+
+/* Search the character array s1 for the substring in character array s2.
+ Returns a pointer to that sbstring, or NULL. If s2 is of length zero,
+ returns s1.
+*/
+char * strstr( const char * s1, const char * s2 );
+
+/* In a series of subsequent calls, parse a C string into tokens.
+ On the first call to strtok(), the first argument is a pointer to the to-be-
+ parsed C string. On subsequent calls, the first argument is NULL unless you
+ want to start parsing a new string. s2 holds an array of seperator characters
+ which can differ from call to call. Leading seperators are skipped, the first
+ trailing seperator overwritten with '\0'.
+ Returns a pointer to the next token.
+ WARNING: This function uses static storage, and as such is not reentrant.
+*/
+char * strtok( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 );
+
+/* Miscellaneous functions */
+
+/* Write the character c (interpreted as unsigned char) to the first n
+ characters of the memory area pointed to by s.
+ Returns s.
+*/
+void * memset( void * s, int c, size_t n );
+
+/* Map an error number to a (locale-specific) error message string. Error
+ numbers are typically errno values, but any number is mapped to a message.
+ TODO: PDCLib does not yet support locales.
+ TODO: strerror() not yet implemented.
+char * strerror( int errnum );
+*/
+
+/* Returns the length of the string s (excluding terminating '\0').
+*/
+size_t strlen( const char * s );
+
+#endif
/* OS "glue", part 2 */
/* These are the functions you will have to touch, as they are where PDCLib */
/* interfaces with the operating system. */
-/* Some operate on data types defined by _PDCLIB_config.h. */
+/* They operate on data types partially defined by _PDCLIB_config.h. */
/* -------------------------------------------------------------------------- */
+/* stdlib.h */
+
/* A system call that terminates the calling process, returning a given status
to the environment.
*/
*/
void * _PDCLIB_allocpages( int n );
+
+/* stdio.h */
+
/* 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 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.
+/* A system call that writes a stream's buffer.
+ Returns 0 on success, EOF on write error.
+ Sets stream error flags and errno appropriately on error.
*/
-int _PDCLIB_write( struct _PDCLIB_file_t * stream, char const * buffer, int n );
+int _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream );
-/* 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 fills a stream's buffer.
+ Returns 0 on success, EOF on read error / EOF.
+ Sets stream EOF / error flags and errno appropriately on error.
*/
-_PDCLIB_size_t _PDCLIB_read( _PDCLIB_fd_t fd, char * buffer, _PDCLIB_size_t n );
+int _PDCLIB_fillbuffer( struct _PDCLIB_file_t * stream );
+
+/* A system call that repositions within a file. Returns new offset on success,
+ -1 / errno on error.
+*/
+_PDCLIB_int64_t _PDCLIB_seek( struct _PDCLIB_file_t * stream, _PDCLIB_int64_t offset, int whence );
/* A system call that closes a file identified by given file descriptor. Return
zero on success, non-zero otherwise.
/* A system call that renames a file from given old name to given new name.
Return zero on success, non-zero otherwise. In case of failure, the file
- must still be accessible by old name.
+ must still be accessible by old name. Any handling of open files etc. is
+ done by standard rename() already.
*/
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 );
-
/* Internal flags, made to fit the same status field as the flags above. */
#define _PDCLIB_LIBBUFFER 512u
-#define _PDCLIB_VIRGINSTR 1024u
-#define _PDCLIB_ERRORFLAG 2048u
-#define _PDCLIB_EOFFLAG 4096u
-#define _PDCLIB_WIDESTREAM 8192u
-#define _PDCLIB_BYTESTREAM 16384u
+#define _PDCLIB_ERRORFLAG 1024u
+#define _PDCLIB_EOFFLAG 2048u
+#define _PDCLIB_WIDESTREAM 4096u
+#define _PDCLIB_BYTESTREAM 8192u
+/* Position / status structure for getpos() / fsetpos(). */
+struct _PDCLIB_fpos_t
+{
+ _PDCLIB_uint64_t offset; /* File position offset */
+ int status; /* Multibyte parsing state (unused, reserved) */
+};
+
+/* FILE structure */
struct _PDCLIB_file_t
{
- _PDCLIB_fd_t handle; /* OS-specific file descriptor */
- _PDCLIB_fpos_t position; /* file position indicator */
- char * buffer; /* file buffer */
- _PDCLIB_size_t bufsize; /* size of buffer */
- _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 */
+ _PDCLIB_fd_t handle; /* OS file handle */
+ char * buffer; /* Pointer to buffer memory */
+ _PDCLIB_size_t bufsize; /* Size of buffer */
+ _PDCLIB_size_t bufidx; /* Index of current position in buffer */
+ _PDCLIB_size_t bufend; /* Index of last pre-read character in buffer */
+ struct _PDCLIB_fpos_t pos; /* Offset and multibyte parsing state */
+ _PDCLIB_size_t ungetidx; /* Number of ungetc()'ed characters */
+ unsigned char * ungetbuf; /* ungetc() buffer */
+ unsigned int status; /* Status flags; see above */
+ /* multibyte parsing status to be added later */
+ char * filename; /* Name the current stream has been opened with */
+ struct _PDCLIB_file_t * next; /* Pointer to next struct (internal) */
};
/* -------------------------------------------------------------------------- */
*/
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 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.
+/* Sanity checking and preparing of read buffer, should be called first thing
+ by any stdio read-data function.
+ Returns 0 on success, EOF on error.
+ On error, EOF / error flags and errno are set appropriately.
+*/
+int _PDCLIB_prepread( struct _PDCLIB_file_t * stream );
+
+/* Sanity checking, should be called first thing by any stdio write-data
+ function.
+ Returns 0 on success, EOF on error.
+ On error, error flags and errno are set appropriately.
*/
-_PDCLIB_size_t _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream, _PDCLIB_size_t written, int retries );
+int _PDCLIB_prepwrite( struct _PDCLIB_file_t * stream );
+
+/* -------------------------------------------------------------------------- */
+/* errno */
+/* -------------------------------------------------------------------------- */
+
+extern int _PDCLIB_errno;
+int * _PDCLIB_errno_func( void );
+
+/* ERANGE and EDOM are specified by the standard. */
+#define _PDCLIB_ERANGE 1
+#define _PDCLIB_EDOM 2
+/* Used in the example implementation for any kind of I/O error. */
+#define _PDCLIB_EIO 3
+/* Used in the example implementation for "unknown error". */
+#define _PDCLIB_EUNKNOWN 4
+/* Used in the example implementation for "invalid parameter value". */
+#define _PDCLIB_EINVAL 5
+/* Used in the example implementation for "I/O retries exceeded". */
+#define _PDCLIB_ERETRY 6
char const abcde[] = "abcde";
char const abcdx[] = "abcdx";
+char const * teststring = "1234567890\nABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n";
int NO_TESTDRIVER = 0;
-//#define BEGIN_TESTS unsigned int rc = 0
-static unsigned int rc = 0;
+static int rc = 0;
+
#define TESTCASE( x ) if ( x ) {} \
else { rc += 1; printf( "FAILED: " __FILE__ ", line %d - " #x "\n", __LINE__ ); }
+
+#ifndef REGTEST
+#define TESTCASE_NOREG( x ) TESTCASE( x )
+#else
+#define TESTCASE_NOREG( x )
+#endif
+
#define TEST_RESULTS rc
+
#ifndef REGTEST
#include <_PDCLIB_glue.h>
-#include <unistd.h>
+
+extern void _exit( int status ) _PDCLIB_NORETURN;
void _PDCLIB_Exit( int status )
{
#endif
#ifdef TEST
-/* TODO: Work around the following undef */
-#undef SEEK_SET
#include <_PDCLIB_test.h>
int main( void )
#ifndef REGTEST
#include <_PDCLIB_glue.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
+extern int close( int fd );
int _PDCLIB_close( int fd )
{
--- /dev/null
+/* $Id$ */
+
+/* _PDCLIB_fillbuffer( struct _PDCLIB_file_t * stream )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+/* This is an example implementation of _PDCLIB_fillbuffer() fit for
+ use with POSIX kernels.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+#include <_PDCLIB_glue.h>
+
+#include </usr/include/errno.h>
+
+typedef long ssize_t;
+extern ssize_t read( int fd, void * buf, size_t count );
+
+int _PDCLIB_fillbuffer( struct _PDCLIB_file_t * stream )
+{
+ /* No need to handle buffers > INT_MAX, as PDCLib doesn't allow them */
+ ssize_t rc = read( stream->handle, stream->buffer, stream->bufsize );
+ if ( rc > 0 )
+ {
+ /* Reading successful. */
+ if ( ! ( stream->status & _PDCLIB_FBIN ) )
+ {
+ /* TODO: Text stream conversion here */
+ }
+ stream->bufend = rc;
+ stream->bufidx = 0;
+ return 0;
+ }
+ if ( rc < 0 )
+ {
+ /* Reading error */
+ switch ( errno )
+ {
+ case EBADF:
+ case EFAULT:
+ case EINTR:
+ case EINVAL:
+ case EIO:
+ _PDCLIB_errno = _PDCLIB_EIO;
+ break;
+ default:
+ _PDCLIB_errno = _PDCLIB_EUNKNOWN;
+ break;
+ }
+ stream->status |= _PDCLIB_ERRORFLAG;
+ return EOF;
+ }
+ /* End-of-File */
+ stream->status |= _PDCLIB_EOFFLAG;
+ return EOF;
+}
+
+#endif
+
+#ifdef TEST
+#include <_PDCLIB_test.h>
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
+
--- /dev/null
+/* $Id$ */
+
+/* _PDCLIB_flushbuffer( struct _PDCLIB_file_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+/* This is an example implementation of _PDCLIB_flushbuffer() fit for
+ use with POSIX kernels.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef REGTEST
+#include <_PDCLIB_glue.h>
+
+#include </usr/include/errno.h>
+
+typedef long ssize_t;
+extern ssize_t write( int fd, const void * buf, size_t count );
+
+/* The number of attempts to complete an output buffer flushing before giving
+ * up.
+ * */
+#define _PDCLIB_IO_RETRIES 1
+
+/* What the system should do after an I/O operation did not succeed, before */
+/* trying again. (Empty by default.) */
+#define _PDCLIB_IO_RETRY_OP( stream )
+
+int _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream )
+{
+ if ( ! ( stream->status & _PDCLIB_FBIN ) )
+ {
+ /* TODO: Text stream conversion here */
+ }
+ /* No need to handle buffers > INT_MAX, as PDCLib doesn't allow them */
+ _PDCLIB_size_t written = 0;
+ int rc;
+ /* Keep trying to write data until everything is written, an error
+ occurs, or the configured number of retries is exceeded.
+ */
+ for ( unsigned int retries = _PDCLIB_IO_RETRIES; retries > 0; --retries )
+ {
+ rc = (int)write( stream->handle, stream->buffer + written, stream->bufidx - written );
+ if ( rc < 0 )
+ {
+ /* Write error */
+ switch ( errno )
+ {
+ case EBADF:
+ case EFAULT:
+ case EFBIG:
+ case EINTR:
+ case EINVAL:
+ case EIO:
+ case ENOSPC:
+ case EPIPE:
+ _PDCLIB_errno = _PDCLIB_EIO;
+ break;
+ default:
+ _PDCLIB_errno = _PDCLIB_EUNKNOWN;
+ break;
+ }
+ stream->status |= _PDCLIB_ERRORFLAG;
+ /* Move unwritten remains to begin of buffer. */
+ stream->bufidx -= written;
+ memmove( stream->buffer, stream->buffer + written, stream->bufidx );
+ return EOF;
+ }
+ written += (_PDCLIB_size_t)rc;
+ stream->pos.offset += rc;
+ if ( written == stream->bufidx )
+ {
+ /* Buffer written completely. */
+ stream->bufidx = 0;
+ return 0;
+ }
+ }
+ _PDCLIB_errno = _PDCLIB_ERETRY;
+ stream->status |= _PDCLIB_ERRORFLAG;
+ /* Move unwritten remains to begin of buffer. */
+ stream->bufidx -= written;
+ memmove( stream->buffer, stream->buffer + written, stream->bufidx );
+ return EOF;
+}
+
+#endif
+
+
+#ifdef TEST
+#include <_PDCLIB_test.h>
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
+
+++ /dev/null
-/* $Id$ */
-
-/* _PDCLIB_isinteractive( _PDCLIB_fd_t fd )
-
- This file is part of the Public Domain C Library (PDCLib).
- Permission is granted to use, modify, and / or redistribute at will.
-*/
-
-/* This is an example implementation of _PDCLIB_isinteractive() (declared in
- _PDCLIB_glue.h), fit for use in POSIX kernels.
- If you do not have an equivalent function, replace this with a return (1)
- and you will have all streams line-buffered by default.
-*/
-
-#ifndef REGTEST
-#include <_PDCLIB_glue.h>
-
-int isatty( int );
-
-int _PDCLIB_isinteractive( int fd )
-{
- return isatty( fd );
-}
-
-#endif
-
-#ifdef TEST
-/* TODO: Work around the following undef */
-#undef SEEK_SET
-#include <_PDCLIB_test.h>
-
-int main( void )
-{
- TESTCASE( NO_TESTDRIVER );
- return TEST_RESULTS;
-}
-
-#endif
#include <fcntl.h>
#include <unistd.h>
+#include "/usr/include/errno.h"
+
int _PDCLIB_open( char const * const filename, unsigned int mode )
{
/* This is an example implementation of _PDCLIB_open() fit for use with
default: /* Invalid mode */
return -1;
}
+ int rc;
if ( osmode & O_CREAT )
{
- return open( filename, osmode, S_IRUSR | S_IWUSR );
+ rc = open( filename, osmode, S_IRUSR | S_IWUSR );
}
else
{
- return open( filename, osmode );
+ rc = open( filename, osmode );
+ }
+ if ( rc == -1 )
+ {
+ switch ( errno )
+ {
+ case EACCES:
+ case EFAULT:
+ case EINTR:
+ case EISDIR:
+ case ELOOP:
+ case EMFILE:
+ case ENAMETOOLONG:
+ case ENFILE:
+ case ENODEV:
+ case ENOENT:
+ case ENOMEM:
+ case ENOSPC:
+ case ENOTDIR:
+ case EOVERFLOW:
+ case EROFS:
+ case ETXTBSY:
+ _PDCLIB_errno = _PDCLIB_EIO;
+ default:
+ _PDCLIB_errno = _PDCLIB_EUNKNOWN;
+ }
}
+ return rc;
}
#endif
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
-
int main( void )
{
/* This testdriver assumes POSIX, i.e. _PDCLIB_fd_t being int and being
*/
int fh;
char buffer[ 10 ];
+ remove( "testfile" );
/* Trying to read non-existent file. */
TESTCASE( _PDCLIB_open( "testfile", _PDCLIB_FREAD ) == _PDCLIB_NOHANDLE );
/* Writing to file, trying to read from it. */
TESTCASE( memcmp( buffer, "tessiebaby", 10 ) == 0 );
TESTCASE( _PDCLIB_close( fh ) == 0 );
/* Cleaning up. */
- system( "rm testfile" );
+ TESTCASE( remove( "testfile" ) == 0 );
return TEST_RESULTS;
}
+++ /dev/null
-/* $Id$ */
-
-/* _PDCLIB_read( _PDCLIB_fd_t, char *, _PDCLIB_size_t )
-
- This file is part of the Public Domain C Library (PDCLib).
- Permission is granted to use, modify, and / or redistribute at will.
-*/
-
-#include <_PDCLIB_glue.h>
-
-#ifndef REGTEST
-
-int read(int, void *, unsigned int);
-
-_PDCLIB_size_t _PDCLIB_read( int fd, char * buffer, _PDCLIB_size_t n )
-{
- /* FIXME: Might return value < n, might return -1 on error */
- return read( fd, buffer, n );
-}
-
-#endif
-
-#ifdef TEST
-#include <_PDCLIB_test.h>
-
-int main( void )
-{
- TESTCASE( NO_TESTDRIVER );
- return TEST_RESULTS;
-}
-
-#endif
+++ /dev/null
-/* $Id$ */
-
-/* _PDCLIB_remove( const char * )
-
- This file is part of the Public Domain C Library (PDCLib).
- Permission is granted to use, modify, and / or redistribute at will.
-*/
-
-/* This is an example implementation of _PDCLIB_remove() (declared in
- _PDCLIB_glue.h), fit for use in POSIX kernels.
- NOTE: Linux is *not* POSIX-compliant in this, as it sets EISDIR instead of
- EPERM if you try to unlink a directory. Check the manpage for unlink(2).
-*/
-
-#ifndef REGTEST
-#include <_PDCLIB_glue.h>
-#include <errno.h>
-#include <unistd.h>
-
-int _PDCLIB_remove( const char * filename )
-{
- int prev_errno = errno;
- int rc;
- errno = 0;
- if ( ( ( rc = unlink( filename ) ) != 0 ) && ( errno == EISDIR ) )
- {
- rc = rmdir( filename );
- }
- errno = prev_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>
-
-int main( void )
-{
- char filename[] = "touch testfile";
- system( filename );
- /* file is actually readable */
- TESTCASE( fopen( filename + 6, "r" ) != NULL );
- /* remove function does not return error */
- TESTCASE( _PDCLIB_remove( filename + 6 ) == 0 );
- /* file is no longer readable */
- TESTCASE( fopen( filename + 6, "r" ) == NULL );
- /* remove function does return error */
- TESTCASE( _PDCLIB_remove( filename + 6 ) != 0 );
- memcpy( filename, "mkdir", 5 );
- /* create directory */
- system( filename );
- /* remove function does not return error */
- TESTCASE( _PDCLIB_remove( filename + 6 ) == 0 );
- /* remove function does return error */
- TESTCASE( _PDCLIB_remove( filename + 6 ) != 0 );
- return TEST_RESULTS;
-}
-
-#endif
Permission is granted to use, modify, and / or redistribute at will.
*/
+#include <stdio.h>
+
#ifndef REGTEST
-#include <unistd.h>
#include <_PDCLIB_glue.h>
+#include </usr/include/errno.h>
+
+extern int unlink( const char * pathname );
+extern int link( const char * old, const char * new );
+
int _PDCLIB_rename( const char * old, const char * new )
{
/* Note that the behaviour if new file exists is implementation-defined.
*/
if ( link( old, new ) == 0 )
{
- return unlink( old );
+ if ( unlink( old ) == EOF )
+ {
+ switch ( errno )
+ {
+ case EACCES:
+ case EFAULT:
+ case EIO:
+ case EISDIR:
+ case ELOOP:
+ case ENAMETOOLONG:
+ case ENOENT:
+ case ENOMEM:
+ case ENOTDIR:
+ case EPERM:
+ case EROFS:
+ _PDCLIB_errno = _PDCLIB_EIO;
+ break;
+ default:
+ _PDCLIB_errno = _PDCLIB_EUNKNOWN;
+ break;
+ }
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
}
else
{
- return -1;
+ switch ( errno )
+ {
+ case EACCES:
+ case EEXIST:
+ case EFAULT:
+ case EIO:
+ case ELOOP:
+ case EMLINK:
+ case ENAMETOOLONG:
+ case ENOENT:
+ case ENOMEM:
+ case ENOSPC:
+ case ENOTDIR:
+ case EPERM:
+ case EROFS:
+ case EXDEV:
+ _PDCLIB_errno = _PDCLIB_EIO;
+ break;
+ default:
+ _PDCLIB_errno = _PDCLIB_EUNKNOWN;
+ break;
+ }
+ return EOF;
}
}
#endif
#ifdef TEST
-/* TODO: Work around the following undef */
-#undef SEEK_SET
#include <_PDCLIB_test.h>
#include <stdlib.h>
{
char filename1[] = "touch testfile1";
char filename2[] = "testfile2";
+ remove( filename1 + 6 );
+ remove( filename2 );
/* check that neither file exists */
TESTCASE( fopen( filename1 + 6, "r" ) == NULL );
TESTCASE( fopen( filename2, "r" ) == NULL );
--- /dev/null
+/* $Id$ */
+
+/* int64_t _PDCLIB_seek( FILE *, int64_t, int )
+
+ 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>
+
+#ifndef _PDCLIB_GLUE_H
+#define _PDCLIB_GLUE_H
+#include <_PDCLIB_glue.h>
+#endif
+
+#include "/usr/include/errno.h"
+
+extern _PDCLIB_int64_t lseek64( int fd, _PDCLIB_int64_t offset, int whence );
+
+_PDCLIB_int64_t _PDCLIB_seek( struct _PDCLIB_file_t * stream, _PDCLIB_int64_t offset, int whence )
+{
+ switch ( whence )
+ {
+ case SEEK_SET:
+ case SEEK_CUR:
+ case SEEK_END:
+ /* EMPTY - OK */
+ break;
+ default:
+ _PDCLIB_errno = _PDCLIB_EINVAL;
+ return EOF;
+ break;
+ }
+ _PDCLIB_int64_t rc = lseek64( stream->handle, offset, whence );
+ if ( rc != EOF )
+ {
+ stream->ungetidx = 0;
+ stream->bufidx = 0;
+ stream->bufend = 0;
+ stream->pos.offset = rc;
+ return rc;
+ }
+ switch ( errno )
+ {
+ case EBADF:
+ case EFAULT:
+ _PDCLIB_errno = _PDCLIB_EIO;
+ break;
+ default:
+ _PDCLIB_errno = _PDCLIB_EUNKNOWN;
+ break;
+ }
+ return EOF;
+}
+
+#ifdef TEST
+#include <_PDCLIB_test.h>
+
+int main()
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
+
static char _PDCLIB_sout_buffer[BUFSIZ];
static char _PDCLIB_serr_buffer[BUFSIZ];
+static unsigned char _PDCLIB_sin_ungetbuf[_PDCLIB_UNGETCBUFSIZE];
+static unsigned char _PDCLIB_sout_ungetbuf[_PDCLIB_UNGETCBUFSIZE];
+static unsigned char _PDCLIB_serr_ungetbuf[_PDCLIB_UNGETCBUFSIZE];
+
/* FIXME: serr should handle one character. Buffering on out / in? */
-static struct _PDCLIB_file_t _PDCLIB_serr = { 2, { 0, 0 }, _PDCLIB_serr_buffer, BUFSIZ, 0, 0, _IONBF, NULL, NULL };
-static struct _PDCLIB_file_t _PDCLIB_sout = { 1, { 0, 0 }, _PDCLIB_sout_buffer, BUFSIZ, 0, 0, _IOLBF, NULL, &_PDCLIB_serr };
-static struct _PDCLIB_file_t _PDCLIB_sin = { 0, { 0, 0 }, _PDCLIB_sin_buffer, BUFSIZ, 0, 0, _IOLBF, NULL, &_PDCLIB_sout };
+static struct _PDCLIB_file_t _PDCLIB_serr = { 2, _PDCLIB_serr_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_serr_ungetbuf, _IONBF | _PDCLIB_FWRITE, NULL, NULL };
+static struct _PDCLIB_file_t _PDCLIB_sout = { 1, _PDCLIB_sout_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sout_ungetbuf, _IOLBF | _PDCLIB_FWRITE, NULL, &_PDCLIB_serr };
+static struct _PDCLIB_file_t _PDCLIB_sin = { 0, _PDCLIB_sin_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sin_ungetbuf, _IOLBF | _PDCLIB_FREAD, NULL, &_PDCLIB_sout };
struct _PDCLIB_file_t * stdin = &_PDCLIB_sin;
struct _PDCLIB_file_t * stdout = &_PDCLIB_sout;
struct _PDCLIB_file_t * stderr = &_PDCLIB_serr;
+/* FIXME: This approach is a possible attack vector. */
+struct _PDCLIB_file_t * _PDCLIB_filelist = &_PDCLIB_sin;
+
#endif
#ifdef TEST
-/* TODO: Necessity of this undef should probably be circumvented. */
-#undef SEEK_SET
#include <_PDCLIB_test.h>
int main( void )
{
- TESTCASE( NO_TESTDRIVER );
+ /* Testing covered by several other testdrivers using stdin / stdout /
+ stderr.
+ */
return TEST_RESULTS;
}
+++ /dev/null
-/* $Id$ */
-
-/* _PDCLIB_write( _PDCLIB_fd_t, char const *, _PDCLIB_size_t )
-
- This file is part of the Public Domain C Library (PDCLib).
- Permission is granted to use, modify, and / or redistribute at will.
-*/
-
-#include <_PDCLIB_glue.h>
-#include <unistd.h>
-
-#ifndef REGTEST
-
-int _PDCLIB_write( struct _PDCLIB_file_t * stream, char const * buffer, int 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 )
-{
- /* 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, 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
-
--- /dev/null
+/* $Id$ */
+
+/* remove( const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+/* This is an example implementation of remove() fit for use with POSIX kernels.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "/usr/include/errno.h"
+
+extern int unlink( const char * pathname );
+
+int remove( const char * pathname )
+{
+ int rc;
+ if ( ( rc = unlink( pathname ) ) == -1 )
+ {
+ switch ( errno )
+ {
+ /* These are the values possible on a Linux machine. Adapt the
+ values and their mapping to PDCLib errno values at will. (This
+ is an example implementation, so we keep it very simple.)
+ */
+ case EACCES:
+ case EFAULT:
+ case EIO:
+ case EISDIR:
+ case ELOOP:
+ case ENAMETOOLONG:
+ case ENOENT:
+ case ENOMEM:
+ case ENOTDIR:
+ case EPERM:
+ case EROFS:
+ _PDCLIB_errno = _PDCLIB_EIO;
+ break;
+ default:
+ _PDCLIB_errno = _PDCLIB_EUNKNOWN;
+ break;
+ }
+ }
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#include <_PDCLIB_test.h>
+
+int main( void )
+{
+ /* Testing covered by ftell.c (and several others) */
+ return TEST_RESULTS;
+}
+
+#endif
+
Permission is granted to use, modify, and / or redistribute at will.
*/
+#include <stdio.h>
+
#ifndef REGTEST
-#include <_PDCLIB_int.h>
struct _PDCLIB_file_t * tmpfile( void )
{
return NULL;
}
-#endif REGTEST
+#endif
#ifdef TEST
#include <_PDCLIB_test.h>
/* This is an example implementation of system() fit for use with POSIX kernels.
*/
-#include <unistd.h>
-#include <sys/wait.h>
+extern int fork( void );
+extern int execve( const char * filename, char * const argv[], char * const envp[] );
+extern int wait( int * status );
int system( const char * string )
{
}
#ifdef TEST
-/* TODO: Work around the following undef */
-#undef SEEK_SET
#include <_PDCLIB_test.h>
#define SHELLCOMMAND "echo 'SUCCESS testing system()'"
/* 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"
*/
#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
- stdinit.c, too. */
-typedef struct
-{
- int position;
- int mbstate;
-} _PDCLIB_fpos_t;
-
/* The default size for file buffers. Must be at least 256. */
#define _PDCLIB_BUFSIZ 1024
/* The minimum number of files the implementation can open simultaneously. Must
be at least 8. Depends largely on how the bookkeeping is done by fopen() /
- freopen() / fclose().
+ freopen() / fclose(). The example implementation limits the number of open
+ files only by available memory.
*/
#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.
+/* The values of SEEK_SET, SEEK_CUR and SEEK_END, used by fseek().
+ Since at least one platform (POSIX) uses the same symbols for its own "seek"
+ function, we use whatever the host defines (if it does define them).
*/
-#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_SEEK_SET 0
+#define _PDCLIB_SEEK_CUR 1
+#define _PDCLIB_SEEK_END 2
+
+/* The number of characters that can be buffered with ungetc(). The standard
+ guarantees only one (1); anything larger would make applications relying on
+ this capability dependent on implementation-defined behaviour (not good).
*/
-#define _PDCLIB_FLUSH_RETRY_PREP
+#define _PDCLIB_UNGETCBUFSIZE 1
--- /dev/null
+/* $Id$ */
+
+/* Internal PDCLib configuration <_PDCLIB_config.h>
+ (Generic Template)
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+/* -------------------------------------------------------------------------- */
+/* Misc */
+/* -------------------------------------------------------------------------- */
+
+/* The character (sequence) your platform uses as newline. */
+#define _PDCLIB_endl "\n"
+
+/* The number of attempts to complete an I/O operation before giving up. */
+/* (Example: How often a buffer flushing is attempted before reporting fail.) */
+#define _PDCLIB_IO_RETRIES 1
+
+/* What the system should do after an I/O operation did not succeed, before */
+/* trying again. (Empty by default.) */
+#define _PDCLIB_IO_RETRY_OP( stream )
+
+/* exit() can signal success to the host environment by the value of zero or */
+/* the constant EXIT_SUCCESS. Failure is signaled by EXIT_FAILURE. Note that */
+/* any other return value is "implementation-defined", i.e. your environment */
+/* is not required to handle it gracefully. Set your definitions here. */
+#define _PDCLIB_SUCCESS 0
+#define _PDCLIB_FAILURE -1
+
+/* qsort() in <stdlib.h> requires a function that swaps two memory areas. */
+/* Below is a naive implementation that can be improved significantly for */
+/* specific platforms, e.g. by swapping int instead of char. */
+#define _PDCLIB_memswp( i, j, size ) char tmp; do { tmp = *i; *i++ = *j; *j++ = tmp; } while ( --size );
+
+/* Define this to some compiler directive that can be written after the */
+/* parameter list of a function declaration to indicate the function does */
+/* never return. If your compiler does not support such a directive, define */
+/* to nothing. (This is to avoid warnings with the exit functions under GCC.) */
+#define _PDCLIB_NORETURN __attribute__(( noreturn ))
+
+/* -------------------------------------------------------------------------- */
+/* Integers */
+/* -------------------------------------------------------------------------- */
+/* Assuming 8-bit char, two's-complement architecture here. 'short' being */
+/* 16 bit, 'int' being either 16, 32 or 64 bit, 'long' being either 32 or 64 */
+/* bit (but 64 bit only if 'int' is 32 bit), and 'long long' being 64 bit if */
+/* 'long' is not, 64 or 128 bit otherwise. */
+/* Author is quite willing to support other systems but would like to hear of */
+/* interest in such support and details on the to-be-supported architecture */
+/* first, before going to lengths about it. */
+/* -------------------------------------------------------------------------- */
+
+/* Comment out (or delete) the line below if your 'char' type is unsigned. */
+#define _PDCLIB_CHAR_SIGNED 1
+
+/* Width of the integer types short, int, long, and long long, in bytes. */
+/* SHRT == 2, INT >= SHRT, LONG >= INT >= 4, LLONG >= LONG - check your */
+/* compiler manuals. */
+#define _PDCLIB_SHRT_BYTES 2
+#define _PDCLIB_INT_BYTES 4
+#define _PDCLIB_LONG_BYTES 8
+#define _PDCLIB_LLONG_BYTES 8
+
+/* <stdlib.h> defines the div() function family that allows taking quotient */
+/* and remainder of an integer division in one operation. Many platforms */
+/* support this in hardware / opcode, and the standard permits ordering of */
+/* the return structure in any way to fit the hardware. That is why those */
+/* structs can be configured here. */
+
+struct _PDCLIB_div_t
+{
+ int quot;
+ int rem;
+};
+
+struct _PDCLIB_ldiv_t
+{
+ long int quot;
+ long int rem;
+};
+
+struct _PDCLIB_lldiv_t
+{
+ long long int quot;
+ long long int rem;
+};
+
+/* -------------------------------------------------------------------------- */
+/* <stdint.h> defines a set of integer types that are of a minimum width, and */
+/* "usually fastest" on the system. (If, for example, accessing a single char */
+/* requires the CPU to access a complete int and then mask out the char, the */
+/* "usually fastest" type of at least 8 bits would be int, not char.) */
+/* If you do not have information on the relative performance of the types, */
+/* the standard allows you to define any type that meets minimum width and */
+/* signedness requirements. */
+/* The defines below are just configuration for the real typedefs and limit */
+/* definitions done in <_PDCLIB_int.h>. The uppercase define shall be either */
+/* SHRT, INT, LONG, or LLONG (telling which values to use for the *_MIN and */
+/* *_MAX limits); the lowercase define either short, int, long, or long long */
+/* (telling the actual type to use). */
+/* If you require a non-standard datatype to define the "usually fastest" */
+/* types, PDCLib as-is doesn't support that. Please contact the author with */
+/* details on your platform in that case, so support can be added. */
+/* -------------------------------------------------------------------------- */
+
+#define _PDCLIB_FAST8 INT
+#define _PDCLIB_fast8 int
+
+#define _PDCLIB_FAST16 INT
+#define _PDCLIB_fast16 int
+
+#define _PDCLIB_FAST32 INT
+#define _PDCLIB_fast32 int
+
+#define _PDCLIB_FAST64 LONG
+#define _PDCLIB_fast64 long
+
+/* -------------------------------------------------------------------------- */
+/* What follows are a couple of "special" typedefs and their limits. Again, */
+/* the actual definition of the limits is done in <_PDCLIB_int.h>, and the */
+/* defines here are merely "configuration". See above for details. */
+/* -------------------------------------------------------------------------- */
+
+/* The result type of substracting two pointers */
+#define _PDCLIB_ptrdiff long
+#define _PDCLIB_PTRDIFF LONG
+
+/* An integer type that can be accessed as atomic entity (think asynchronous
+ 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) */
+#define _PDCLIB_size unsigned long
+#define _PDCLIB_SIZE ULONG
+
+/* Large enough an integer to hold all character codes of the largest supported
+ locale.
+*/
+#define _PDCLIB_wchar unsigned short
+#define _PDCLIB_WCHAR USHRT
+
+#define _PDCLIB_intptr long
+#define _PDCLIB_INTPTR LONG
+
+/* Largest supported integer type. Implementation note: see _PDCLIB_atomax(). */
+#define _PDCLIB_intmax long long int
+#define _PDCLIB_INTMAX LLINT
+/* You are also required to state the literal suffix for the intmax type */
+#define _PDCLIB_INTMAX_LITERAL ll
+
+/* -------------------------------------------------------------------------- */
+/* Floating Point */
+/* -------------------------------------------------------------------------- */
+
+/* Whether the implementation rounds toward zero (0), to nearest (1), toward
+ positive infinity (2), or toward negative infinity (3). (-1) signifies
+ indeterminable rounding, any other value implementation-specific rounding.
+*/
+#define _PDCLIB_FLT_ROUNDS -1
+
+/* Whether the implementation uses exact-width precision (0), promotes float
+ to double (1), or promotes float and double to long double (2). (-1)
+ signifies indeterminable behaviour, any other value implementation-specific
+ behaviour.
+*/
+#define _PDCLIB_FLT_EVAL_METHOD -1
+
+/* "Number of the decimal digits (n), such that any floating-point number in the
+ widest supported floating type with p(max) radix (b) digits can be rounded to
+ a floating-point number with (n) decimal digits and back again without change
+ to the value p(max) log(10)b if (b) is a power of 10, [1 + p(max) log(10)b]
+ otherwise."
+ 64bit IEC 60559 double format (53bit mantissa) is DECIMAL_DIG 17.
+ 80bit IEC 60559 double-extended format (64bit mantissa) is DECIMAL_DIG 21.
+*/
+#define _PDCLIB_DECIMAL_DIG 17
+
+/* -------------------------------------------------------------------------- */
+/* Platform-dependent macros defined by the standard headers. */
+/* -------------------------------------------------------------------------- */
+
+/* The offsetof macro
+ Contract: Expand to an integer constant expression of type size_t, which
+ represents the offset in bytes to the structure member from the beginning
+ of the structure. If the specified member is a bitfield, behaviour is
+ undefined.
+ There is no standard-compliant way to do this.
+ This implementation casts an integer zero to 'pointer to type', and then
+ takes the address of member. This is undefined behaviour but should work on
+ most compilers.
+*/
+#define _PDCLIB_offsetof( type, member ) ( (size_t) &( ( (type *) 0 )->member ) )
+
+/* Variable Length Parameter List Handling (<stdarg.h>)
+ No way to cover x86_64 with a generic implementation, as it uses register-
+ based parameter passing. Using the GCC builtins here.
+*/
+typedef __builtin_va_list _PDCLIB_va_list;
+#define _PDCLIB_va_arg( ap, type ) ( __builtin_va_arg( ap, type ) )
+#define _PDCLIB_va_copy( dest, src ) ( __builtin_va_copy( dest, src ) )
+#define _PDCLIB_va_end( ap ) ( __builtin_va_end( ap ) )
+#define _PDCLIB_va_start( ap, parmN ) ( __builtin_va_start( ap, parmN ) )
+
+/* -------------------------------------------------------------------------- */
+/* OS "glue", part 1 */
+/* These are values and data type definitions that you would have to adapt to */
+/* the capabilities and requirements of your OS. */
+/* The actual *functions* of the OS interface are declared in _PDCLIB_glue.h. */
+/* -------------------------------------------------------------------------- */
+
+/* Memory management -------------------------------------------------------- */
+
+/* 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.)
+*/
+#define _PDCLIB_PAGESIZE 4096
+
+/* 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 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 ( (_PDCLIB_fd_t) -1 )
+
+/* The values of SEEK_SET, SEEK_CUR and SEEK_END, used by fseek().
+ Since at least one platform (POSIX) uses the same symbols for its own "seek"
+ function, we use whatever the host defines (if it does define them).
+*/
+#define _PDCLIB_SEEK_SET 0
+#define _PDCLIB_SEEK_CUR 1
+#define _PDCLIB_SEEK_END 2
+
+/* The number of characters that can be buffered with ungetc(). The standard
+ guarantees only one (1); anything larger would make applications relying on
+ this capability dependent on implementation-defined behaviour (not good).
+*/
+#define _PDCLIB_UNGETCBUFSIZE 1
+