]> pd.if.org Git - pdclib.old/commitdiff
Merged branch stdio_rewrite back into trunk.
authorsolar <>
Sun, 13 Sep 2009 15:14:02 +0000 (15:14 +0000)
committersolar <>
Sun, 13 Sep 2009 15:14:02 +0000 (15:14 +0000)
74 files changed:
Makefile
Notes.txt
functions/_PDCLIB/digits.c
functions/_PDCLIB/eol.c [new file with mode: 0644]
functions/_PDCLIB/errno.c [new file with mode: 0644]
functions/_PDCLIB/fflush.c [deleted file]
functions/_PDCLIB/filemode.c
functions/_PDCLIB/prepread.c [new file with mode: 0644]
functions/_PDCLIB/prepwrite.c [new file with mode: 0644]
functions/_PDCLIB/print.c
functions/_PDCLIB/strtox_main.c
functions/stdio/clearerr.c
functions/stdio/fclose.c
functions/stdio/feof.c
functions/stdio/ferror.c
functions/stdio/fflush.c
functions/stdio/fgetc.c
functions/stdio/fgetpos.c
functions/stdio/fgets.c
functions/stdio/fopen.c
functions/stdio/fputc.c
functions/stdio/fputs.c
functions/stdio/fread.c
functions/stdio/freopen.c
functions/stdio/fseek.c
functions/stdio/fsetpos.c
functions/stdio/ftell.c
functions/stdio/fwrite.c
functions/stdio/gets.c
functions/stdio/puts.c
functions/stdio/remove.c [deleted file]
functions/stdio/rename.c
functions/stdio/rewind.c
functions/stdio/setbuf.c
functions/stdio/setvbuf.c
functions/stdio/ungetc.c
functions/stdio/vfprintf.c
functions/stdio/vsnprintf.c
functions/stdio/vsprintf.c
functions/stdlib/_Exit.c
functions/stdlib/atexit.c
functions/stdlib/bsearch.c
functions/stdlib/malloc.c
functions/stdlib/qsort.c
functions/stdlib/rand.c
functions/stdlib/strtol.c
functions/stdlib/strtoll.c
functions/stdlib/strtoul.c
functions/string/strcmp.c
functions/string/strncmp.c
includes/assert.h
includes/errno.h [moved from functions/_PDCLIB/Xdigits.c with 51% similarity]
includes/stdio.h
includes/string.h
internals/_PDCLIB_glue.h
internals/_PDCLIB_int.h
internals/_PDCLIB_test.h
platform/example/functions/_PDCLIB/_Exit.c
platform/example/functions/_PDCLIB/close.c
platform/example/functions/_PDCLIB/fillbuffer.c [new file with mode: 0644]
platform/example/functions/_PDCLIB/flushbuffer.c [new file with mode: 0644]
platform/example/functions/_PDCLIB/isinteractive.c [deleted file]
platform/example/functions/_PDCLIB/open.c
platform/example/functions/_PDCLIB/read.c [deleted file]
platform/example/functions/_PDCLIB/remove.c [deleted file]
platform/example/functions/_PDCLIB/rename.c
platform/example/functions/_PDCLIB/seek.c [new file with mode: 0644]
platform/example/functions/_PDCLIB/stdinit.c
platform/example/functions/_PDCLIB/write.c [deleted file]
platform/example/functions/stdio/remove.c [new file with mode: 0644]
platform/example/functions/stdio/tmpfile.c
platform/example/functions/stdlib/system.c
platform/example/internals/_PDCLIB_config.h
platform/example_64/internals/_PDCLIB_config.h [new file with mode: 0644]

index 772c1e27fb2fc755f4f30aa868d04db7939c66ff..7750bf2cba8c498257455fa6ff1eaac70d4142d6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ SRCFILES := $(shell find $(PROJDIRS) -mindepth 1 -maxdepth 3 -name "*.c")
 # All header files of the project
 HDRFILES := $(shell find $(PROJDIRS) -mindepth 1 -maxdepth 3 -name "*.h")
 # All .c files in functions/_PDCLIB that do not have a regression test driver
-INTFILES := _Exit atomax digits open print 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)
@@ -29,13 +29,27 @@ ALLFILES := $(SRCFILES) $(HDRFILES) $(AUXFILES)
 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      $@"
@@ -46,14 +60,16 @@ test: functions/$(FILE)
        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)
 
@@ -70,7 +86,7 @@ fixmes:
        -@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)..."
@@ -78,6 +94,7 @@ links:
        @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..."
@@ -85,6 +102,7 @@ unlink:
        @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:"
index a5ec9d29ac9ebd4bac975745960ec9a09235155d..aa065037216f789fb6910075096a262d20084200 100644 (file)
--- a/Notes.txt
+++ b/Notes.txt
@@ -34,11 +34,11 @@ giving other valuable hints, thanks.
 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.
 
@@ -53,13 +53,14 @@ I followed a set of guidelines in creating PDCLib. If you find some piece that
 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
@@ -67,24 +68,25 @@ obsessive when it comes to coding style. ;-)
   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
@@ -92,7 +94,7 @@ obsessive when it comes to coding style. ;-)
   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
index 751ac0852edbf71ee64a3abeebdcafa18d979940..940e962bd943f55e2d9469339621af72bbeba0e3 100644 (file)
@@ -13,6 +13,9 @@
 
 char _PDCLIB_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 
+/* For _PDCLIB/print.c only; obsolete with ctype.h */
+char _PDCLIB_Xdigits[] = "0123456789ABCDEF";
+
 #ifdef TEST
 #include <_PDCLIB_test.h>
 
@@ -21,6 +24,7 @@ char _PDCLIB_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 int main( void )
 {
     TESTCASE( strcmp( _PDCLIB_digits, "0123456789abcdefghijklmnopqrstuvwxyz" ) == 0 );
+    TESTCASE( strcmp( _PDCLIB_Xdigits, "0123456789ABCDEF" ) == 0 );
     return TEST_RESULTS;
 }
 
diff --git a/functions/_PDCLIB/eol.c b/functions/_PDCLIB/eol.c
new file mode 100644 (file)
index 0000000..d6edacf
--- /dev/null
@@ -0,0 +1,15 @@
+/* $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;
+
diff --git a/functions/_PDCLIB/errno.c b/functions/_PDCLIB/errno.c
new file mode 100644 (file)
index 0000000..ba01c35
--- /dev/null
@@ -0,0 +1,40 @@
+/* $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
+
diff --git a/functions/_PDCLIB/fflush.c b/functions/_PDCLIB/fflush.c
deleted file mode 100644 (file)
index e8c99db..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* $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
-
index fd734fcf632325ce025bcbec8aaba0a988b6e905..0e293aba2cfc55a6a4f1487b569b20efb8cd70c7 100644 (file)
@@ -14,7 +14,7 @@
 */
 unsigned int _PDCLIB_filemode( char const * const mode )
 {
-    int rc = 0;
+    unsigned rc = 0;
     switch ( mode[0] )
     {
         case 'r':
@@ -24,7 +24,7 @@ unsigned int _PDCLIB_filemode( char const * const mode )
             rc |= _PDCLIB_FWRITE;
             break;
         case 'a':
-            rc |= _PDCLIB_FAPPEND;
+            rc |= _PDCLIB_FAPPEND | _PDCLIB_FWRITE;
             break;
         default:
             /* Other than read, write, or append - invalid */
@@ -61,19 +61,19 @@ int main( void )
 {
     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 );
diff --git a/functions/_PDCLIB/prepread.c b/functions/_PDCLIB/prepread.c
new file mode 100644 (file)
index 0000000..53a2976
--- /dev/null
@@ -0,0 +1,34 @@
+/* $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;
+    }
+}
+
diff --git a/functions/_PDCLIB/prepwrite.c b/functions/_PDCLIB/prepwrite.c
new file mode 100644 (file)
index 0000000..774aeb2
--- /dev/null
@@ -0,0 +1,24 @@
+/* $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;
+}
+
index 0ac327220234d628f76893252f703b673bbea137..c36b00978ec7d7fd627087f117538472aaa4571c 100644 (file)
    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); \
@@ -532,9 +529,18 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status
 static int testprintf( char * buffer, size_t n, const char * format, ... )
 {
     /* Members: base, flags, n, i, this, s, width, prec, stream, arg         */
-    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 );
index fbdf8bbfad27a3fab8124eafa84937602c906ff9..b19a1e7d15d4f2b3cfba54bc3f07b6bac6353120 100644 (file)
@@ -23,7 +23,7 @@ _PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, uintm
         digit = x - _PDCLIB_digits;
         if ( ( rc < limval ) || ( ( rc == limval ) && ( digit <= limdigit ) ) )
         {
-            rc = rc * base + digit;
+            rc = rc * base + (unsigned)digit;
             ++(*p);
         }
         else
index 2bfe7c508448eb92830605de1f78031825ef16d2..922f6ab9d239e18cbf5eea9d959d0102c10d9f54 100644 (file)
@@ -22,37 +22,33 @@ void clearerr( struct _PDCLIB_file_t * stream )
 
 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
+
index 0b4233034afe5b79b7fe0bccfa8b2c477e8b2654..3f7ce19dec0407dac54652eecce496207adbf1ee 100644 (file)
@@ -24,9 +24,23 @@ int fclose( struct _PDCLIB_file_t * stream )
     {
         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;
@@ -35,12 +49,14 @@ int fclose( struct _PDCLIB_file_t * stream )
             {
                 _PDCLIB_filelist = stream->next;
             }
+            /* Free stream */
             free( stream );
             return 0;
         }
         previous = current;
         current = current->next;
     }
+    _PDCLIB_errno = _PDCLIB_EIO;
     return -1;
 }
 
@@ -54,7 +70,9 @@ int main( void )
 #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 );
@@ -66,8 +84,9 @@ int main( void )
     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
@@ -75,3 +94,4 @@ int main( void )
 }
 
 #endif
+
index 784ea4ed517e3a4dd3458de89f79ff7c56b16e72..d5cf188d23811f105c4a7eb965078dfd19912086 100644 (file)
@@ -27,3 +27,4 @@ int main( void )
 }
 
 #endif
+
index 6f24080697ba63e435fe41c1b6583857ef64603e..7ca531ed441bb00eec8b35e59370b6928f7aa798 100644 (file)
@@ -27,3 +27,4 @@ int main( void )
 }
 
 #endif
+
index 5118503c530e413232e79dc8ece526356597ccf0..b8d32ec307d45b389d3a0fa37fb79263998e9f16 100644 (file)
@@ -22,9 +22,12 @@ int fflush( struct _PDCLIB_file_t * stream )
         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;
         }
@@ -32,7 +35,7 @@ int fflush( struct _PDCLIB_file_t * stream )
     }
     else
     {
-        return _PDCLIB_fflush( stream );
+        return _PDCLIB_flushbuffer( stream );
     }
 }
                 
@@ -43,7 +46,7 @@ int fflush( struct _PDCLIB_file_t * stream )
 
 int main( void )
 {
-    TESTCASE( NO_TESTDRIVER );
+    /* Testing covered by ftell.c */
     return TEST_RESULTS;
 }
 
index 900cd0a12181a2f7f3e53df03d3538a53952a0b3..1a90eb95dadea9780b28a024c6fb94c9bad99570 100644 (file)
@@ -8,12 +8,21 @@
 
 #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
@@ -23,7 +32,7 @@ int fgetc( struct _PDCLIB_file_t * stream )
 
 int main( void )
 {
-    TESTCASE( NO_TESTDRIVER );
+    /* Testing covered by ftell.c */
     return TEST_RESULTS;
 }
 
index b023bfe4cebbaad90cf6416035d8eb86f734ed1b..5d90382c25d8d71bf491bbf933d4422bd717c0b2 100644 (file)
 
 #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;
 }
 
index 203d3ff0306643de6527de273556f155266a36a1..a82818ad23542f9eaef5a14abc1883913b1024a5 100644 (file)
@@ -1,6 +1,6 @@
 /* $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
@@ -28,3 +57,4 @@ int main( void )
 }
 
 #endif
+
index d181cc1f876ded1362cc297e8c2fad923e67ae64..48c07d2b3ff41d6c2244461bc417832546063161 100644 (file)
@@ -12,8 +12,7 @@
 #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 )
 {
@@ -28,26 +27,44 @@ struct _PDCLIB_file_t * fopen( const char * _PDCLIB_restrict filename, const cha
         /* 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
@@ -61,21 +78,16 @@ int main( void )
        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;
 }
 
index e9036112297875ab33a8d4ef6dd26503cea30fc1..beff43a5aa4b34a3ab77532b3b11c8106b1d0f14 100644 (file)
@@ -8,17 +8,20 @@
 
 #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 */
@@ -26,11 +29,7 @@ int fputc( int c, struct _PDCLIB_file_t * stream )
     )
     {
         /* buffer filled, unbuffered stream, or end-of-line. */
-        fflush( stream );
-    }
-    else
-    {
-        stream->status |= _PDCLIB_WROTELAST;
+        return ( _PDCLIB_flushbuffer( stream ) == 0 ) ? c : EOF;
     }
     return c;
 }
@@ -42,15 +41,7 @@ int fputc( int c, struct _PDCLIB_file_t * stream )
 
 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;
 }
 
index 94af1ad6a9154dd88b36a4bbbdf7bb75f90c8975..7a62d03de2ff5178b624c68b5fc0c381c407309a 100644 (file)
@@ -9,57 +9,63 @@
 #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
+
index 83bc3b7e6d0eb2f5dd5e571e393bcdfb46f5a69d..b77b5dd4724d700dafdc2a242793bb8f047a705e 100644 (file)
@@ -1,6 +1,6 @@
 /* $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
@@ -23,8 +47,15 @@ size_t fread( void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PD
 
 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
+
index 13992deb8214f5fe9f7e7d76584da4a5b1247dc3..e8cc72a1f2924cba8e56c8acc5947ff2525ed7bf 100644 (file)
@@ -27,7 +27,7 @@ struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const c
     /* 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 );
@@ -37,7 +37,7 @@ struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const c
     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;
 }
index ca0017cacfc02f1fbaaf259be15fd0ca90f1c4a1..e3d3e7791836e7e92e25b293a6fe7ec853099fbe 100644 (file)
@@ -1,6 +1,6 @@
 /* $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
@@ -27,8 +36,9 @@ int fseek( struct _PDCLIB_file_t * stream, long int offset, int whence )
 
 int main( void )
 {
-    TESTCASE( NO_TESTDRIVER );
+    /* Testing covered by ftell.c */
     return TEST_RESULTS;
 }
 
 #endif
+
index 76c5ede87ec7dea39ef49b194581bfd7a130c878..4820f73b3ddf89b0d2014bd3a25cc9fccdabde20 100644 (file)
@@ -9,14 +9,22 @@
 #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;
 }
 
index 9838156a3901f1f7f729f02d0e64b716bf5d2295..9ca449fe54a155d14bb747f0dca137aac8ede6c5 100644 (file)
@@ -7,13 +7,26 @@
 */
 
 #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
@@ -21,10 +34,52 @@ long int ftell( struct _PDCLIB_file_t * stream )
 #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
+
index 8765d0be7e23c70507c1779e359674fc948624b3..d3e58592f1c7eab5c1d0ac0bc0ec5f36b08d7a72 100644 (file)
 
 #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
@@ -24,6 +88,7 @@ size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, str
 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 );
@@ -33,3 +98,4 @@ int main( void )
 }
 
 #endif
+
index 3529b0be466074c2550a3d68f3179c9156949d48..9dbc515f88cc8ae213c0be6c333160ba674d33b7 100644 (file)
@@ -7,13 +7,32 @@
 */
 
 #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
@@ -28,3 +47,4 @@ int main( void )
 }
 
 #endif
+
index 40c9727643fa3ad424cd33032b59e75f9950e2f3..a90e07863fbdb26185b9ae2827da22eed895b054 100644 (file)
@@ -9,10 +9,43 @@
 #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;
 }
 
@@ -23,8 +56,9 @@ int puts( const char * s )
 
 int main( void )
 {
-    TESTCASE( NO_TESTDRIVER );
+    TESTCASE( puts( "SUCCESS testing puts()" ) >= 0 );
     return TEST_RESULTS;
 }
 
 #endif
+
diff --git a/functions/stdio/remove.c b/functions/stdio/remove.c
deleted file mode 100644 (file)
index a563e4c..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* $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
index f3ff01ee604a44ba46fc65c4802d8c17ef22ba9a..3f9152dca7a5d2fb07f1eaa0b558910f040ceb2e 100644 (file)
@@ -20,8 +20,6 @@ int rename( const char * old, const char * new )
 #endif
 
 #ifdef TEST
-/* TODO: Work around the following undef */
-#undef SEEK_SET
 #include <_PDCLIB_test.h>
 
 #include <stdlib.h>
@@ -31,7 +29,9 @@ int main( void )
     /* 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 */
@@ -68,3 +68,4 @@ int main( void )
 }
 
 #endif
+
index d97e4e21ac289db2e2ae8e3a60555350dedf29f7..4dab8e9e2cbe9943392011876bf9723a060005b9 100644 (file)
@@ -1,6 +1,6 @@
 /* $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
@@ -27,7 +23,7 @@ void rewind( struct _PDCLIB_file_t * stream )
 
 int main( void )
 {
-    TESTCASE( NO_TESTDRIVER );
+    /* Testing covered by ftell.c */
     return TEST_RESULTS;
 }
 
index e77d2d4807692e80373c08080d95e78bc1f1c041..a68ea27da8ac01aef06c3a9c4c25510f6f049ee8 100644 (file)
@@ -12,7 +12,6 @@
 
 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 );
@@ -27,34 +26,30 @@ void setbuf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, char * _PDCLIB_res
 
 #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
index 5ac14a9357345653e7e64d7b980999c7d4b806b3..125a73f8808a32d341cd67710c1f0c0d7b9694e2 100644 (file)
@@ -8,70 +8,71 @@
 
 #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
@@ -79,6 +80,8 @@ int setvbuf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, char * _PDCLIB_res
 #ifdef TEST
 #include <_PDCLIB_test.h>
 
+#include <errno.h>
+
 #define BUFFERSIZE 500
 
 int main( void )
@@ -86,37 +89,30 @@ 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
@@ -124,3 +120,4 @@ int main( void )
 }
 
 #endif
+
index fdafc9de1054f34ca1e5b09c42ea06507ecf59e2..f85ca9ce96344f423a096807ce6a42cbafc22acc 100644 (file)
 
 #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
@@ -23,7 +26,7 @@ int ungetc( int c, struct _PDCLIB_file_t * stream )
 
 int main( void )
 {
-    TESTCASE( NO_TESTDRIVER );
+    /* Testing covered by ftell.c */
     return TEST_RESULTS;
 }
 
index 8c8c0224974dd05555fb8255726279b8db37904f..82ba8719afd2507cd41779dfdb78e012e0129d6d 100644 (file)
@@ -16,7 +16,17 @@ int vfprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDC
 {
     /* 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;
@@ -32,6 +42,7 @@ int vfprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDC
             format = rc;
         }
     }
+    va_end( status.arg );
     return status.i;
 }
 
index 96a151bb2ae3a53e48f5bbc963a8308e635f05f7..9c9ab591f0993c2f5e78a2278fc8e283e56c9427 100644 (file)
@@ -15,7 +15,18 @@ int vsnprintf( char * s, size_t n, const char * format, _PDCLIB_va_list arg )
 {
     /* TODO: This function should interpret format as multibyte characters.  */
     /* Members: base, flags, n, i, this, s, width, prec, stream, arg         */
-    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;
@@ -31,6 +42,7 @@ int vsnprintf( char * s, size_t n, const char * format, _PDCLIB_va_list arg )
         }
     }
     s[ status.i ] = '\0';
+    va_end( status.arg );
     return status.i;
 }
 
@@ -313,3 +325,4 @@ int main( void )
 }
 
 #endif
+
index 6baa9120feb91aeae6ed1d0405f690c8c4649efa..308b71051456e751b2211cb05b614946932b8a70 100644 (file)
@@ -12,8 +12,6 @@
 
 #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 */
index 7871385d8a025775ad995e641b2fc0be882e27fa..3244f93e2978a0d7776e12f60a6c102e71a089be 100644 (file)
@@ -8,9 +8,9 @@
 
 #include <stdlib.h>
 #include <stdio.h>
-#include <_PDCLIB_glue.h>
 
 #ifndef REGTEST
+#include <_PDCLIB_glue.h>
 
 void _Exit( int status )
 {
index 558190f4b97dc89b49e019eb115fdbf06edf042d..a81a8cb6ec34f06e1e8174959430c8573afdbc84 100644 (file)
@@ -22,7 +22,7 @@ int atexit( void (*func)( void ) )
     else
     {
         _PDCLIB_regstack[ --_PDCLIB_regptr ] = func;
-       return 0;
+        return 0;
     }
 }
 
index e8e4f3125f53ef61677defaf38787103269c50b4..ab93b94782284e7a1414aa9b5176a50203965a3c 100644 (file)
@@ -14,18 +14,19 @@ void * bsearch( const void * key, const void * base, size_t nmemb, size_t size,
 {
     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 )
         {
index ab0920b8bb7f959336f8f63aa6eb56ec3806d554..05fd82ed42acf670969a4ba4a14fcc89f8466177 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <stdlib.h>
 #include <stdint.h>
+#include <stdbool.h>
 
 #ifndef REGTEST
 
@@ -75,7 +76,8 @@ void * malloc( size_t size )
     /* 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 );
@@ -83,6 +85,7 @@ void * malloc( size_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 )
         {
@@ -97,16 +100,23 @@ void * malloc( size_t size )
         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;
@@ -138,21 +148,120 @@ void * malloc( size_t size )
 
 #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
@@ -160,83 +269,157 @@ void * malloc( size_t size )
    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
index 6bb636f5631d5c50a51f9052c9b947f61507fb49..c37760f546fa47a089b913cff22d47e084f7d13f 100644 (file)
@@ -41,14 +41,14 @@ void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *,
 {
     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;
index b4d01de8db5a056ed4157a7b03c7544d1b17cc4f..40d782448421c4e1201fe31b7dd97aff3c16d94c 100644 (file)
@@ -13,7 +13,7 @@
 int rand( void )
 {
     _PDCLIB_seed = _PDCLIB_seed * 1103515245 + 12345;
-    return (unsigned int) ( _PDCLIB_seed / 65536 ) % 32768;
+    return (int)( _PDCLIB_seed / 65536 ) % 32768;
 }
 
 #endif
index 04c8617541c0650b4bfb3a42b6b3b3ecb154a3c4..8fc95b0fce7c66d842bcb8d325e371f211f2cac9 100644 (file)
@@ -21,12 +21,12 @@ long int strtol( const char * s, char ** endptr, int base )
     if ( base < 2 || base > 36 ) return 0;
     if ( sign == '+' )
     {
-        rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MAX, (uintmax_t)( LONG_MAX / base ), (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;
@@ -106,7 +106,7 @@ int main( void )
     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 );
index 0eb8423f609c5246294f53e865a38df4e8f2af46..aa91163842a09bc4923a64c95a1e65333d9c49d2 100644 (file)
@@ -21,13 +21,13 @@ long long int strtoll( const char * s, char ** endptr, int base )
     if ( base < 2 || base > 36 ) return 0;
     if ( sign == '+' )
     {
-        rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MAX, (uintmax_t)( LLONG_MAX / base ), (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;
index 68f790af7a44fff289c9482d2ac6e31b1f997198..7bd8488feaae1cc80932d2b71ec98c232f27f205 100644 (file)
@@ -19,7 +19,7 @@ unsigned long int strtoul( const char * s, char ** endptr, int base )
     char sign = '+';
     const char * p = _PDCLIB_strtox_prelim( s, &sign, &base );
     if ( base < 2 || base > 36 ) return 0;
-    rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)ULONG_MAX, (uintmax_t)( ULONG_MAX / base ), (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;
 }
index 42ed51c01c86d5b96a9a62270d35015185694179..5202771a67d52f266000746cf63c7608cd9b7682 100644 (file)
@@ -17,7 +17,7 @@ int strcmp( const char * s1, const char * s2 )
         ++s1;
         ++s2;
     }
-    return ( *s1 - *s2 );
+    return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
 }
 
 #endif
@@ -28,12 +28,14 @@ int strcmp( const char * s1, const char * s2 )
 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
index ac9c10f38b51cf5397cd2caa98d5215ff5ec79c9..43321709ee515a0d4fcc1380b0bf2b8e0d250d26 100644 (file)
@@ -24,7 +24,7 @@ int strncmp( const char * s1, const char * s2, size_t n )
     }
     else
     {
-        return ( *s1 - *s2 );
+        return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
     }
 }
 
@@ -36,6 +36,7 @@ int strncmp( const char * s1, const char * s2, size_t n )
 int main( void )
 {
     char cmpabcde[] = "abcde\0f";
+    char cmpabcd_[] = "abcde\xfc";
     char empty[] = "";
     char x[] = "x";
     TESTCASE( strncmp( abcde, cmpabcde, 5 ) == 0 );
@@ -47,6 +48,7 @@ int main( void )
     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
index 35c2795352bba439b21e4e391c73864a090b5613..fb6dbf1b1b63a5118cf523c3f2c6567b953b580f 100644 (file)
@@ -35,15 +35,15 @@ void _PDCLIB_assert( char const * const );
 #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
 
similarity index 51%
rename from functions/_PDCLIB/Xdigits.c
rename to includes/errno.h
index 7568474248e90b78857d10ac88b9a961dfd41886..2795fdf6c727128b247a0c742471e23a0f228ff6 100644 (file)
@@ -1,27 +1,23 @@
 /* $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
+
index 68f1cb7de20fb0823d584d0dad068b6fbbcf69ac..643bcf88beb9f355da1ddbbe5a3328dff9973e49 100644 (file)
@@ -30,7 +30,7 @@ typedef _PDCLIB_size_t size_t;
 #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
@@ -40,9 +40,9 @@ typedef struct _PDCLIB_file_t FILE;
 #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;
index a9f935d9bba7a7d0fbc2ab8b55365a8a3669c6ac..2aa7aaedb41206750ca1beac9a1c252b1e9c3fe5 100644 (file)
-/* $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
index 96cedca1e66f0d4d6404eb20be7f61d506cc4011..3c5872bcbeab7744d215b9b765d78e9cc72ab684 100644 (file)
 /* 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.
 */
@@ -30,23 +32,31 @@ void _PDCLIB_Exit( int status ) _PDCLIB_NORETURN;
 */
 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.
@@ -60,12 +70,8 @@ int _PDCLIB_remove( const char * filename );
 
 /* 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 );
-
index d4d0d9a00eb99e0e3762c554b9f7810b51bbe02c..02e122eb3ada87dfa4f09e2a21712370a72bcadb 100644 (file)
@@ -259,23 +259,33 @@ typedef unsigned _PDCLIB_intmax _PDCLIB_uintmax_t;
 
 /* 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) */
 };
 
 /* -------------------------------------------------------------------------- */
@@ -341,16 +351,39 @@ extern char _PDCLIB_Xdigits[];
 */
 const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status );
 
-/* Common denominator of puts() and fputs() */
-int _PDCLIB_puts( const char * s, const char * endl, struct _PDCLIB_file_t * stream );
-
 /* Parsing any fopen() style filemode string into a number of flags. */
 unsigned int _PDCLIB_filemode( const char * mode );
 
-/* Writing out unwritten buffers 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
 
index 302c27b8e24b1a4b9ab7e74b23a1d84115f678bf..eba739122878918b627ee7ce9463174ebcfeddf0 100644 (file)
 
 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
+
index c3ecfbc373b26718be4d43024f17aedb801d9c3e..5c95fca8c03379452931b1fda5beaa6b9e38afb3 100644 (file)
@@ -14,7 +14,8 @@
 
 #ifndef REGTEST
 #include <_PDCLIB_glue.h>
-#include <unistd.h>
+
+extern void _exit( int status ) _PDCLIB_NORETURN;
 
 void _PDCLIB_Exit( int status )
 {
@@ -24,8 +25,6 @@ void _PDCLIB_Exit( int status )
 #endif
 
 #ifdef TEST
-/* TODO: Work around the following undef */
-#undef SEEK_SET
 #include <_PDCLIB_test.h>
 
 int main( void )
index f3475974adb3048ce3021ae2bb9f512344e72dd1..c4b61738794444b55c1a5e387c6c7bf5315c68b0 100644 (file)
 #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 )
 {
diff --git a/platform/example/functions/_PDCLIB/fillbuffer.c b/platform/example/functions/_PDCLIB/fillbuffer.c
new file mode 100644 (file)
index 0000000..ecfb968
--- /dev/null
@@ -0,0 +1,74 @@
+/* $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
+
diff --git a/platform/example/functions/_PDCLIB/flushbuffer.c b/platform/example/functions/_PDCLIB/flushbuffer.c
new file mode 100644 (file)
index 0000000..c2ac98d
--- /dev/null
@@ -0,0 +1,103 @@
+/* $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
+
diff --git a/platform/example/functions/_PDCLIB/isinteractive.c b/platform/example/functions/_PDCLIB/isinteractive.c
deleted file mode 100644 (file)
index ec3e778..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* $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
index fc82485aec2d730b3505ee6e3e655e1c83faa11b..79497266350fb49992c533adb00bd546fe2b8e5e 100644 (file)
@@ -20,6 +20,8 @@
 #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
@@ -51,14 +53,41 @@ int _PDCLIB_open( char const * const filename, unsigned int mode )
         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
@@ -69,8 +98,6 @@ int _PDCLIB_open( char const * const filename, unsigned int mode )
 #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
@@ -78,6 +105,7 @@ int main( void )
     */
     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. */
@@ -126,7 +154,7 @@ int main( void )
     TESTCASE( memcmp( buffer, "tessiebaby", 10 ) == 0 );
     TESTCASE( _PDCLIB_close( fh ) == 0 );
     /* Cleaning up. */
-    system( "rm testfile" );
+    TESTCASE( remove( "testfile" ) == 0 );
     return TEST_RESULTS;
 }
 
diff --git a/platform/example/functions/_PDCLIB/read.c b/platform/example/functions/_PDCLIB/read.c
deleted file mode 100644 (file)
index 2e35cea..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* $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
diff --git a/platform/example/functions/_PDCLIB/remove.c b/platform/example/functions/_PDCLIB/remove.c
deleted file mode 100644 (file)
index 184a1f2..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* $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
index 849f872946476beae89d24f890e20f34f1a4721f..3f770c9cc54cc32cc49ac3e47b6f5a586b4837e4 100644 (file)
@@ -6,10 +6,16 @@
    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.
@@ -19,19 +25,65 @@ int _PDCLIB_rename( const char * old, const char * new )
     */
     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>
@@ -40,6 +92,8 @@ int main( void )
 {
     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 );
diff --git a/platform/example/functions/_PDCLIB/seek.c b/platform/example/functions/_PDCLIB/seek.c
new file mode 100644 (file)
index 0000000..9e2d102
--- /dev/null
@@ -0,0 +1,66 @@
+/* $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
+
index a02c691c4af8772140a8c5c35e3c9314559550d8..af37f069c2e74cea62b79bec20e028a5e93a9e73 100644 (file)
@@ -23,25 +23,32 @@ static char _PDCLIB_sin_buffer[BUFSIZ];
 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;
 }
 
diff --git a/platform/example/functions/_PDCLIB/write.c b/platform/example/functions/_PDCLIB/write.c
deleted file mode 100644 (file)
index 2147908..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* $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
-
diff --git a/platform/example/functions/stdio/remove.c b/platform/example/functions/stdio/remove.c
new file mode 100644 (file)
index 0000000..0e66f4c
--- /dev/null
@@ -0,0 +1,64 @@
+/* $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
+
index 79c9569c50f912b7ae5a6c6530fc3c871c29cf12..255a35eb75721d58d352cd1279a1dd7f3fdda622 100644 (file)
@@ -6,8 +6,9 @@
    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 )
 {
@@ -15,7 +16,7 @@ struct _PDCLIB_file_t * tmpfile( void )
     return NULL;
 }
 
-#endif REGTEST
+#endif
 
 #ifdef TEST
 #include <_PDCLIB_test.h>
index fb3c40685da55e10c0d832efe6d1228f3f6c99ad..2e0079a449d942178badaedf8d98a285e842d95d 100644 (file)
@@ -11,8 +11,9 @@
 /* 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 )
 {
@@ -33,8 +34,6 @@ 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()'"
index 0df16791cd26f98afbd8f5c53343585d73a2295a..6864eb9a4b11f6b8e68566b5a1be13fe10305b39 100644 (file)
 /* 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"
 
@@ -244,21 +236,13 @@ typedef int _PDCLIB_fd_t;
 */
 #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
 
@@ -271,13 +255,17 @@ typedef struct
 /* Number of distinct file names that can be generated by tmpnam(). */
 #define _PDCLIB_TMP_MAX 50
 
-/* The number of times fflush() tries to write a file buffer before giving up
-   if no characters can be written.
+/* 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
 
diff --git a/platform/example_64/internals/_PDCLIB_config.h b/platform/example_64/internals/_PDCLIB_config.h
new file mode 100644 (file)
index 0000000..c8aa535
--- /dev/null
@@ -0,0 +1,253 @@
+/* $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
+