aboutsummaryrefslogtreecommitdiffstats
path: root/src/pdclib/functions/stdio
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdclib/functions/stdio')
-rw-r--r--src/pdclib/functions/stdio/clearerr.c52
-rw-r--r--src/pdclib/functions/stdio/fclose.c106
-rw-r--r--src/pdclib/functions/stdio/feof.c28
-rw-r--r--src/pdclib/functions/stdio/ferror.c28
-rw-r--r--src/pdclib/functions/stdio/fflush.c53
-rw-r--r--src/pdclib/functions/stdio/fgetc.c38
-rw-r--r--src/pdclib/functions/stdio/fgetpos.c43
-rw-r--r--src/pdclib/functions/stdio/fgets.c88
-rw-r--r--src/pdclib/functions/stdio/fopen.c102
-rw-r--r--src/pdclib/functions/stdio/fprintf.c43
-rw-r--r--src/pdclib/functions/stdio/fputc.c47
-rw-r--r--src/pdclib/functions/stdio/fputs.c69
-rw-r--r--src/pdclib/functions/stdio/fread.c81
-rw-r--r--src/pdclib/functions/stdio/freopen.c104
-rw-r--r--src/pdclib/functions/stdio/fscanf.c41
-rw-r--r--src/pdclib/functions/stdio/fseek.c85
-rw-r--r--src/pdclib/functions/stdio/fsetpos.c43
-rw-r--r--src/pdclib/functions/stdio/ftell.c100
-rw-r--r--src/pdclib/functions/stdio/fwrite.c93
-rw-r--r--src/pdclib/functions/stdio/getc.c28
-rw-r--r--src/pdclib/functions/stdio/getchar.c28
-rw-r--r--src/pdclib/functions/stdio/perror.c58
-rw-r--r--src/pdclib/functions/stdio/printf.c44
-rw-r--r--src/pdclib/functions/stdio/putc.c28
-rw-r--r--src/pdclib/functions/stdio/putchar.c28
-rw-r--r--src/pdclib/functions/stdio/puts.c67
-rw-r--r--src/pdclib/functions/stdio/rename.c84
-rw-r--r--src/pdclib/functions/stdio/rewind.c29
-rw-r--r--src/pdclib/functions/stdio/scanf.c39
-rw-r--r--src/pdclib/functions/stdio/setbuf.c55
-rw-r--r--src/pdclib/functions/stdio/setvbuf.c108
-rw-r--r--src/pdclib/functions/stdio/snprintf.c43
-rw-r--r--src/pdclib/functions/stdio/sprintf.c41
-rw-r--r--src/pdclib/functions/stdio/sscanf.c39
-rw-r--r--src/pdclib/functions/stdio/testfile.txtbin0 -> 532 bytes
-rw-r--r--src/pdclib/functions/stdio/tmpnam.c42
-rw-r--r--src/pdclib/functions/stdio/ungetc.c32
-rw-r--r--src/pdclib/functions/stdio/vfprintf.c74
-rw-r--r--src/pdclib/functions/stdio/vfscanf.c113
-rw-r--r--src/pdclib/functions/stdio/vprintf.c46
-rw-r--r--src/pdclib/functions/stdio/vscanf.c45
-rw-r--r--src/pdclib/functions/stdio/vsnprintf.c80
-rw-r--r--src/pdclib/functions/stdio/vsprintf.c44
-rw-r--r--src/pdclib/functions/stdio/vsscanf.c109
44 files changed, 2548 insertions, 0 deletions
diff --git a/src/pdclib/functions/stdio/clearerr.c b/src/pdclib/functions/stdio/clearerr.c
new file mode 100644
index 0000000..91cd00a
--- /dev/null
+++ b/src/pdclib/functions/stdio/clearerr.c
@@ -0,0 +1,52 @@
+/* clearerr( 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>
+
+#ifndef REGTEST
+
+void clearerr( struct _PDCLIB_file_t * stream )
+{
+ stream->status &= ~( _PDCLIB_ERRORFLAG | _PDCLIB_EOFFLAG );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ FILE * fh;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ /* Flags should be clear */
+ TESTCASE( ! ferror( fh ) );
+ TESTCASE( ! feof( fh ) );
+ /* Reading from empty stream - should provoke EOF */
+ rewind( fh );
+ TESTCASE( fgetc( fh ) == EOF );
+ TESTCASE( ! ferror( fh ) );
+ TESTCASE( feof( fh ) );
+ /* clearerr() should clear flags */
+ clearerr( fh );
+ TESTCASE( ! ferror( fh ) );
+ TESTCASE( ! feof( fh ) );
+ /* reopen() the file write-only */
+ TESTCASE( ( fh = freopen( NULL, "w", fh ) ) != NULL );
+ /* Reading from write-only 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 ) );
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fclose.c b/src/pdclib/functions/stdio/fclose.c
new file mode 100644
index 0000000..9a1388d
--- /dev/null
+++ b/src/pdclib/functions/stdio/fclose.c
@@ -0,0 +1,106 @@
+/* fclose( 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 <stdlib.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+int fclose( struct _PDCLIB_file_t * stream )
+{
+ struct _PDCLIB_file_t * current = _PDCLIB_filelist;
+ struct _PDCLIB_file_t * previous = NULL;
+ /* Checking that the FILE handle is actually one we had opened before. */
+ while ( current != NULL )
+ {
+ if ( stream == current )
+ {
+ /* Flush buffer */
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ /* Flush failed, errno already set */
+ return EOF;
+ }
+ }
+ /* Close handle */
+ _PDCLIB_close( stream->handle );
+ /* Remove stream from list */
+ if ( previous != NULL )
+ {
+ previous->next = stream->next;
+ }
+ else
+ {
+ _PDCLIB_filelist = stream->next;
+ }
+ /* Delete tmpfile() */
+ if ( stream->status & _PDCLIB_DELONCLOSE )
+ {
+ remove( stream->filename );
+ }
+ /* Free user buffer (SetVBuf allocated) */
+ if ( stream->status & _PDCLIB_FREEBUFFER )
+ {
+ free( stream->buffer );
+ }
+ /* Free stream */
+ if ( ! ( stream->status & _PDCLIB_STATIC ) )
+ {
+ free( stream );
+ }
+ return 0;
+ }
+ previous = current;
+ current = current->next;
+ }
+ /* See the comments on implementation-defined errno values in
+ <_PDCLIB_config.h>.
+ */
+ _PDCLIB_errno = _PDCLIB_ERROR;
+ return -1;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ struct _PDCLIB_file_t * file1;
+ struct _PDCLIB_file_t * file2;
+ remove( testfile1 );
+ remove( testfile2 );
+ TESTCASE( _PDCLIB_filelist == stdin );
+ TESTCASE( ( file1 = fopen( testfile1, "w" ) ) != NULL );
+ TESTCASE( _PDCLIB_filelist == file1 );
+ TESTCASE( ( file2 = fopen( testfile2, "w" ) ) != NULL );
+ TESTCASE( _PDCLIB_filelist == file2 );
+ TESTCASE( fclose( file2 ) == 0 );
+ TESTCASE( _PDCLIB_filelist == file1 );
+ TESTCASE( ( file2 = fopen( testfile2, "w" ) ) != NULL );
+ TESTCASE( _PDCLIB_filelist == file2 );
+ TESTCASE( fclose( file1 ) == 0 );
+ TESTCASE( _PDCLIB_filelist == file2 );
+ TESTCASE( fclose( file2 ) == 0 );
+ TESTCASE( _PDCLIB_filelist == stdin );
+ TESTCASE( remove( testfile1 ) == 0 );
+ TESTCASE( remove( testfile2 ) == 0 );
+#else
+ puts( " NOTEST fclose() test driver is PDCLib-specific." );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/feof.c b/src/pdclib/functions/stdio/feof.c
new file mode 100644
index 0000000..a57071f
--- /dev/null
+++ b/src/pdclib/functions/stdio/feof.c
@@ -0,0 +1,28 @@
+/* feof( 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>
+
+#ifndef REGTEST
+
+int feof( struct _PDCLIB_file_t * stream )
+{
+ return stream->status & _PDCLIB_EOFFLAG;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by clearerr(). */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/ferror.c b/src/pdclib/functions/stdio/ferror.c
new file mode 100644
index 0000000..54f43f0
--- /dev/null
+++ b/src/pdclib/functions/stdio/ferror.c
@@ -0,0 +1,28 @@
+/* ferror( 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>
+
+#ifndef REGTEST
+
+int ferror( struct _PDCLIB_file_t * stream )
+{
+ return stream->status & _PDCLIB_ERRORFLAG;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by clearerr(). */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fflush.c b/src/pdclib/functions/stdio/fflush.c
new file mode 100644
index 0000000..3d0b297
--- /dev/null
+++ b/src/pdclib/functions/stdio/fflush.c
@@ -0,0 +1,53 @@
+/* fflush( 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>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+int fflush( struct _PDCLIB_file_t * stream )
+{
+ if ( stream == NULL )
+ {
+ int rc = 0;
+ stream = _PDCLIB_filelist;
+ /* TODO: Check what happens when fflush( NULL ) encounters write errors, in other libs */
+ while ( stream != NULL )
+ {
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ rc = EOF;
+ }
+ }
+ stream = stream->next;
+ }
+ return rc;
+ }
+ else
+ {
+ return _PDCLIB_flushbuffer( stream );
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fgetc.c b/src/pdclib/functions/stdio/fgetc.c
new file mode 100644
index 0000000..bdb233e
--- /dev/null
+++ b/src/pdclib/functions/stdio/fgetc.c
@@ -0,0 +1,38 @@
+/* fgetc( 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>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+int fgetc( struct _PDCLIB_file_t * stream )
+{
+ if ( _PDCLIB_prepread( stream ) == EOF )
+ {
+ return EOF;
+ }
+ if ( stream->ungetidx > 0 )
+ {
+ return (unsigned char)stream->ungetbuf[ --(stream->ungetidx) ];
+ }
+ return (unsigned char)stream->buffer[stream->bufidx++];
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fgetpos.c b/src/pdclib/functions/stdio/fgetpos.c
new file mode 100644
index 0000000..db9be06
--- /dev/null
+++ b/src/pdclib/functions/stdio/fgetpos.c
@@ -0,0 +1,43 @@
+/* fgetpos( FILE * , fpos_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>
+
+#ifndef REGTEST
+
+int fgetpos( struct _PDCLIB_file_t * _PDCLIB_restrict stream, struct _PDCLIB_fpos_t * _PDCLIB_restrict pos )
+{
+ pos->offset = stream->pos.offset + stream->bufidx - stream->ungetidx;
+ pos->status = stream->pos.status;
+ /* TODO: Add mbstate. */
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+
+int main( void )
+{
+ FILE * fh;
+ fpos_t pos1, pos2;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( fgetpos( fh, &pos1 ) == 0 );
+ TESTCASE( fwrite( teststring, 1, strlen( teststring ), fh ) == strlen( teststring ) );
+ TESTCASE( fgetpos( fh, &pos2 ) == 0 );
+ TESTCASE( fsetpos( fh, &pos1 ) == 0 );
+ TESTCASE( ftell( fh ) == 0 );
+ TESTCASE( fsetpos( fh, &pos2 ) == 0 );
+ TESTCASE( (size_t)ftell( fh ) == strlen( teststring ) );
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fgets.c b/src/pdclib/functions/stdio/fgets.c
new file mode 100644
index 0000000..0499afd
--- /dev/null
+++ b/src/pdclib/functions/stdio/fgets.c
@@ -0,0 +1,88 @@
+/* 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.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+char * fgets( char * _PDCLIB_restrict s, int size, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ char * dest = s;
+ if ( size == 0 )
+ {
+ return NULL;
+ }
+ if ( size == 1 )
+ {
+ *s = '\0';
+ return s;
+ }
+ if ( _PDCLIB_prepread( stream ) == EOF )
+ {
+ return NULL;
+ }
+ while ( ( ( *dest++ = stream->buffer[stream->bufidx++] ) != '\n' ) && --size > 0 )
+ {
+ if ( stream->bufidx == stream->bufend )
+ {
+ if ( _PDCLIB_fillbuffer( stream ) == EOF )
+ {
+ /* In case of error / EOF before a character is read, this
+ will lead to a \0 be written anyway. Since the results
+ are "indeterminate" by definition, this does not hurt.
+ */
+ break;
+ }
+ }
+ }
+ *dest = '\0';
+ return ( dest == s ) ? NULL : s;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+
+int main( void )
+{
+ FILE * fh;
+ char buffer[10];
+ const char * fgets_test = "foo\nbar\0baz\nweenie";
+ TESTCASE( ( fh = fopen( testfile, "wb+" ) ) != NULL );
+ TESTCASE( fwrite( fgets_test, 1, 18, fh ) == 18 );
+ rewind( fh );
+ TESTCASE( fgets( buffer, 10, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "foo\n" ) == 0 );
+ TESTCASE( fgets( buffer, 10, fh ) == buffer );
+ TESTCASE( memcmp( buffer, "bar\0baz\n", 8 ) == 0 );
+ TESTCASE( fgets( buffer, 10, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "weenie" ) == 0 );
+ TESTCASE( feof( fh ) );
+ TESTCASE( fseek( fh, -1, SEEK_END ) == 0 );
+ TESTCASE( fgets( buffer, 1, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "" ) == 0 );
+ TESTCASE( fgets( buffer, 0, fh ) == NULL );
+ TESTCASE( ! feof( fh ) );
+ TESTCASE( fgets( buffer, 1, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "" ) == 0 );
+ TESTCASE( ! feof( fh ) );
+ TESTCASE( fgets( buffer, 2, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "e" ) == 0 );
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( fgets( buffer, 2, fh ) == NULL );
+ TESTCASE( feof( fh ) );
+ TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fopen.c b/src/pdclib/functions/stdio/fopen.c
new file mode 100644
index 0000000..d5241a7
--- /dev/null
+++ b/src/pdclib/functions/stdio/fopen.c
@@ -0,0 +1,102 @@
+/* fopen( const char *, 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>
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+#include <string.h>
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+struct _PDCLIB_file_t * fopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode )
+{
+ struct _PDCLIB_file_t * rc;
+ size_t filename_len;
+ if ( mode == NULL || filename == NULL || filename[0] == '\0' )
+ {
+ /* Mode or filename invalid */
+ return NULL;
+ }
+ /* To reduce the number of malloc calls, all data fields are concatenated:
+ * the FILE structure itself,
+ * ungetc buffer,
+ * filename buffer,
+ * data buffer.
+ Data buffer comes last because it might change in size ( setvbuf() ).
+ */
+ filename_len = strlen( filename ) + 1;
+ if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + filename_len + BUFSIZ ) ) == NULL )
+ {
+ /* no memory */
+ return NULL;
+ }
+ 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 )
+ {
+ /* OS open() failed */
+ free( rc );
+ return NULL;
+ }
+ /* Setting pointers into the memory block allocated above */
+ rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t );
+ rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE;
+ rc->buffer = rc->filename + filename_len;
+ /* Copying filename to FILE structure */
+ strcpy( rc->filename, filename );
+ /* Initializing the rest of the structure */
+ 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 |= _IOLBF;
+ /* TODO: Setting mbstate */
+ /* Adding to list of open files */
+ rc->next = _PDCLIB_filelist;
+ _PDCLIB_filelist = rc;
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Some of the tests are not executed for regression tests, as the libc on
+ my system is at once less forgiving (segfaults on mode NULL) and more
+ forgiving (accepts undefined modes).
+ */
+ FILE * fh;
+ remove( testfile );
+ TESTCASE_NOREG( fopen( NULL, NULL ) == NULL );
+ TESTCASE( fopen( NULL, "w" ) == NULL );
+ TESTCASE_NOREG( fopen( "", NULL ) == NULL );
+ TESTCASE( fopen( "", "w" ) == NULL );
+ TESTCASE( fopen( "foo", "" ) == NULL );
+ TESTCASE_NOREG( fopen( testfile, "wq" ) == NULL ); /* Undefined mode */
+ TESTCASE_NOREG( fopen( testfile, "wr" ) == NULL ); /* Undefined mode */
+ TESTCASE( ( fh = fopen( testfile, "w" ) ) != NULL );
+ TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fprintf.c b/src/pdclib/functions/stdio/fprintf.c
new file mode 100644
index 0000000..e16adf8
--- /dev/null
+++ b/src/pdclib/functions/stdio/fprintf.c
@@ -0,0 +1,43 @@
+/* fprintf( FILE *, 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>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int fprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... )
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vfprintf( stream, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#include <stdint.h>
+#include <stddef.h>
+#define _PDCLIB_FILEID "stdio/fprintf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+#define testprintf( stream, ... ) fprintf( stream, __VA_ARGS__ )
+
+int main( void )
+{
+ FILE * target;
+ TESTCASE( ( target = tmpfile() ) != NULL );
+#include "printf_testcases.h"
+ TESTCASE( fclose( target ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fputc.c b/src/pdclib/functions/stdio/fputc.c
new file mode 100644
index 0000000..05ac792
--- /dev/null
+++ b/src/pdclib/functions/stdio/fputc.c
@@ -0,0 +1,47 @@
+/* fputc( int, 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>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+/* Write the value c (cast to unsigned char) to the given stream.
+ Returns c if successful, EOF otherwise.
+ If a write error occurs, the error indicator of the stream is set.
+*/
+int fputc( int c, struct _PDCLIB_file_t * stream )
+{
+ 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 */
+ || ( stream->status & _IONBF ) /* _IONBF */
+ )
+ {
+ /* buffer filled, unbuffered stream, or end-of-line. */
+ return ( _PDCLIB_flushbuffer( stream ) == 0 ) ? c : EOF;
+ }
+ return c;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fputs.c b/src/pdclib/functions/stdio/fputs.c
new file mode 100644
index 0000000..a5d7e56
--- /dev/null
+++ b/src/pdclib/functions/stdio/fputs.c
@@ -0,0 +1,69 @@
+/* fputs( const char *, 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>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+int fputs( const char * _PDCLIB_restrict s, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ if ( _PDCLIB_prepwrite( stream ) == EOF )
+ {
+ return EOF;
+ }
+ while ( *s != '\0' )
+ {
+ /* 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;
+ if ( ( stream->bufidx == stream->bufsize ) ||
+ ( ( stream->status & _IOLBF ) && *s == '\n' )
+ )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ ++s;
+ }
+ if ( stream->status & _IONBF )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ const char * const message = "SUCCESS testing fputs()";
+ FILE * fh;
+ size_t i;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( fputs( message, fh ) >= 0 );
+ rewind( fh );
+ for ( i = 0; i < 23; ++i )
+ {
+ TESTCASE( fgetc( fh ) == message[i] );
+ }
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fread.c b/src/pdclib/functions/stdio/fread.c
new file mode 100644
index 0000000..319e9ba
--- /dev/null
+++ b/src/pdclib/functions/stdio/fread.c
@@ -0,0 +1,81 @@
+/* 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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+size_t fread( void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ char * dest = (char *)ptr;
+ size_t nmemb_i;
+ if ( _PDCLIB_prepread( stream ) == EOF )
+ {
+ return 0;
+ }
+ for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i )
+ {
+ size_t size_i;
+ for ( 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
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ FILE * fh;
+ const char * message = "Testing fwrite()...\n";
+ char buffer[21];
+ buffer[20] = 'x';
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ /* fwrite() / readback */
+ TESTCASE( fwrite( message, 1, 20, fh ) == 20 );
+ rewind( fh );
+ TESTCASE( fread( buffer, 1, 20, fh ) == 20 );
+ TESTCASE( memcmp( buffer, message, 20 ) == 0 );
+ TESTCASE( buffer[20] == 'x' );
+ /* same, different nmemb / size settings */
+ rewind( fh );
+ TESTCASE( memset( buffer, '\0', 20 ) == buffer );
+ TESTCASE( fwrite( message, 5, 4, fh ) == 4 );
+ rewind( fh );
+ TESTCASE( fread( buffer, 5, 4, fh ) == 4 );
+ TESTCASE( memcmp( buffer, message, 20 ) == 0 );
+ TESTCASE( buffer[20] == 'x' );
+ /* same... */
+ rewind( fh );
+ TESTCASE( memset( buffer, '\0', 20 ) == buffer );
+ TESTCASE( fwrite( message, 20, 1, fh ) == 1 );
+ rewind( fh );
+ TESTCASE( fread( buffer, 20, 1, fh ) == 1 );
+ TESTCASE( memcmp( buffer, message, 20 ) == 0 );
+ TESTCASE( buffer[20] == 'x' );
+ /* Done. */
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/freopen.c b/src/pdclib/functions/stdio/freopen.c
new file mode 100644
index 0000000..2cb774c
--- /dev/null
+++ b/src/pdclib/functions/stdio/freopen.c
@@ -0,0 +1,104 @@
+/* freopen( const char *, const char *, 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 <stdlib.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ unsigned int status = stream->status & ( _IONBF | _IOLBF | _IOFBF | _PDCLIB_FREEBUFFER | _PDCLIB_DELONCLOSE );
+ /* TODO: This function can change wide orientation of a stream */
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ _PDCLIB_flushbuffer( stream );
+ }
+ if ( ( filename == NULL ) && ( stream->filename == NULL ) )
+ {
+ /* TODO: Special handling for mode changes on std-streams */
+ return NULL;
+ }
+ _PDCLIB_close( stream->handle );
+ /* TODO: It is not nice to do this on a stream we just closed.
+ It does not matter with the current implementation of clearerr(),
+ but it might start to matter if someone replaced that implementation.
+ */
+ clearerr( stream );
+ /* The new filename might not fit the old buffer */
+ if ( filename == NULL )
+ {
+ /* Use previous filename */
+ filename = stream->filename;
+ }
+ else if ( ( stream->filename != NULL ) && ( strlen( stream->filename ) >= strlen( filename ) ) )
+ {
+ /* Copy new filename into existing buffer */
+ strcpy( stream->filename, filename );
+ }
+ else
+ {
+ /* Allocate new buffer */
+ if ( ( stream->filename = (char *)malloc( strlen( filename ) ) ) == NULL )
+ {
+ return NULL;
+ }
+ strcpy( stream->filename, filename );
+ }
+ if ( ( mode == NULL ) || ( filename[0] == '\0' ) )
+ {
+ return NULL;
+ }
+ if ( ( stream->status = _PDCLIB_filemode( mode ) ) == 0 )
+ {
+ return NULL;
+ }
+ /* Re-add the flags we saved above */
+ stream->status |= status;
+ stream->bufidx = 0;
+ stream->bufend = 0;
+ stream->ungetidx = 0;
+ /* TODO: Setting mbstate */
+ if ( ( stream->handle = _PDCLIB_open( filename, stream->status ) ) == _PDCLIB_NOHANDLE )
+ {
+ return NULL;
+ }
+ return stream;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ FILE * fin;
+ FILE * fout;
+ TESTCASE( ( fin = fopen( testfile1, "wb+" ) ) != NULL );
+ TESTCASE( fputc( 'x', fin ) == 'x' );
+ TESTCASE( fclose( fin ) == 0 );
+ TESTCASE( ( fin = freopen( testfile1, "rb", stdin ) ) != NULL );
+ TESTCASE( getchar() == 'x' );
+
+ TESTCASE( ( fout = freopen( testfile2, "wb+", stdout ) ) != NULL );
+ TESTCASE( putchar( 'x' ) == 'x' );
+ rewind( fout );
+ TESTCASE( fgetc( fout ) == 'x' );
+
+ TESTCASE( fclose( fin ) == 0 );
+ TESTCASE( fclose( fout ) == 0 );
+ TESTCASE( remove( testfile1 ) == 0 );
+ TESTCASE( remove( testfile2 ) == 0 );
+
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fscanf.c b/src/pdclib/functions/stdio/fscanf.c
new file mode 100644
index 0000000..cc8c031
--- /dev/null
+++ b/src/pdclib/functions/stdio/fscanf.c
@@ -0,0 +1,41 @@
+/* fscanf( FILE *, 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>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int fscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... )
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vfscanf( stream, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/fscanf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+#define testscanf( stream, format, ... ) fscanf( stream, format, __VA_ARGS__ )
+
+int main( void )
+{
+ FILE * source;
+ TESTCASE( ( source = tmpfile() ) != NULL );
+#include "scanf_testcases.h"
+ TESTCASE( fclose( source ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fseek.c b/src/pdclib/functions/stdio/fseek.c
new file mode 100644
index 0000000..54f4c4b
--- /dev/null
+++ b/src/pdclib/functions/stdio/fseek.c
@@ -0,0 +1,85 @@
+/* fseek( FILE *, long, 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 REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+int fseek( struct _PDCLIB_file_t * stream, long offset, int whence )
+{
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ stream->status &= ~ _PDCLIB_EOFFLAG;
+ if ( stream->status & _PDCLIB_FRW )
+ {
+ stream->status &= ~ ( _PDCLIB_FREAD | _PDCLIB_FWRITE );
+ }
+ return ( _PDCLIB_seek( stream, offset, whence ) != EOF ) ? 0 : EOF;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+
+int main( void )
+{
+ FILE * fh;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( fwrite( teststring, 1, strlen( teststring ), fh ) == strlen( teststring ) );
+ /* General functionality */
+ TESTCASE( fseek( fh, -1, SEEK_END ) == 0 );
+ TESTCASE( (size_t)ftell( fh ) == strlen( teststring ) - 1 );
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( (size_t)ftell( fh ) == strlen( teststring ) );
+ TESTCASE( fseek( fh, 0, SEEK_SET ) == 0 );
+ TESTCASE( ftell( fh ) == 0 );
+ TESTCASE( fseek( fh, 5, SEEK_CUR ) == 0 );
+ TESTCASE( ftell( fh ) == 5 );
+ TESTCASE( fseek( fh, -3, SEEK_CUR ) == 0 );
+ TESTCASE( ftell( fh ) == 2 );
+ /* Checking behaviour around EOF */
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( ! feof( fh ) );
+ TESTCASE( fgetc( fh ) == EOF );
+ TESTCASE( feof( fh ) );
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( ! feof( fh ) );
+ /* Checking undo of ungetc() */
+ TESTCASE( fseek( fh, 0, SEEK_SET ) == 0 );
+ TESTCASE( fgetc( fh ) == teststring[0] );
+ TESTCASE( fgetc( fh ) == teststring[1] );
+ TESTCASE( fgetc( fh ) == teststring[2] );
+ TESTCASE( ftell( fh ) == 3 );
+ TESTCASE( ungetc( teststring[2], fh ) == teststring[2] );
+ TESTCASE( ftell( fh ) == 2 );
+ TESTCASE( fgetc( fh ) == teststring[2] );
+ TESTCASE( ftell( fh ) == 3 );
+ TESTCASE( ungetc( 'x', fh ) == 'x' );
+ TESTCASE( ftell( fh ) == 2 );
+ TESTCASE( fgetc( fh ) == 'x' );
+ TESTCASE( ungetc( 'x', fh ) == 'x' );
+ TESTCASE( ftell( fh ) == 2 );
+ TESTCASE( fseek( fh, 2, SEEK_SET ) == 0 );
+ TESTCASE( fgetc( fh ) == teststring[2] );
+ /* Checking error handling */
+ TESTCASE( fseek( fh, -5, SEEK_SET ) == -1 );
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fsetpos.c b/src/pdclib/functions/stdio/fsetpos.c
new file mode 100644
index 0000000..323aaae
--- /dev/null
+++ b/src/pdclib/functions/stdio/fsetpos.c
@@ -0,0 +1,43 @@
+/* fsetpos( FILE *, const fpos_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>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+int fsetpos( struct _PDCLIB_file_t * stream, const struct _PDCLIB_fpos_t * pos )
+{
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ if ( _PDCLIB_seek( stream, pos->offset, SEEK_SET ) == EOF )
+ {
+ return EOF;
+ }
+ stream->pos.status = pos->status;
+ /* TODO: Add mbstate. */
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* fsetpos() tested together with fsetpos(). */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/ftell.c b/src/pdclib/functions/stdio/ftell.c
new file mode 100644
index 0000000..f4bd300
--- /dev/null
+++ b/src/pdclib/functions/stdio/ftell.c
@@ -0,0 +1,100 @@
+/* ftell( 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>
+
+#ifndef REGTEST
+
+long int ftell( struct _PDCLIB_file_t * stream )
+{
+ /* ftell() must take into account:
+ - the actual *physical* offset of the file, i.e. the offset as recognized
+ by the operating system (and stored in stream->pos.offset); and
+ - any buffers held by PDCLib, which
+ - in case of unwritten buffers, count in *addition* to the offset; or
+ - in case of unprocessed pre-read buffers, count in *substraction* to
+ the offset. (Remember to count ungetidx into this number.)
+ Conveniently, the calculation ( ( bufend - bufidx ) + ungetidx ) results
+ in just the right number in both cases:
+ - in case of unwritten buffers, ( ( 0 - unwritten ) + 0 )
+ i.e. unwritten bytes as negative number
+ - in case of unprocessed pre-read, ( ( preread - processed ) + unget )
+ i.e. unprocessed bytes as positive number.
+ That is how the somewhat obscure return-value calculation works.
+ */
+ /* If offset is too large for return type, report error instead of wrong
+ offset value.
+ */
+ /* TODO: Check what happens when ungetc() is called on a stream at offset 0 */
+ if ( ( stream->pos.offset - stream->bufend ) > ( LONG_MAX - ( stream->bufidx - stream->ungetidx ) ) )
+ {
+ /* integer overflow */
+ _PDCLIB_errno = _PDCLIB_ERANGE;
+ return -1;
+ }
+ return (long int)( stream->pos.offset - ( ( (int)stream->bufend - (int)stream->bufidx ) + stream->ungetidx ) );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdlib.h>
+
+int main( void )
+{
+ /* 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 prepread prepwrite
+ */
+ char * buffer = (char*)malloc( 4 );
+ FILE * fh;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( setvbuf( fh, buffer, _IOLBF, 4 ) == 0 );
+ /* Testing ungetc() at offset 0 */
+ rewind( fh );
+ TESTCASE( ungetc( 'x', fh ) == 'x' );
+ TESTCASE( ftell( fh ) == -1l );
+ rewind( fh );
+ TESTCASE( ftell( fh ) == 0l );
+ /* Commence "normal" tests */
+ 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' );
+ /* TODO: t.b.c. */
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fwrite.c b/src/pdclib/functions/stdio/fwrite.c
new file mode 100644
index 0000000..7958a50
--- /dev/null
+++ b/src/pdclib/functions/stdio/fwrite.c
@@ -0,0 +1,93 @@
+/* fwrite( const 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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ _PDCLIB_size_t offset = 0;
+ /* TODO: lineend */
+ /* int lineend = 0; */
+ size_t nmemb_i;
+ if ( _PDCLIB_prepwrite( stream ) == EOF )
+ {
+ return 0;
+ }
+ for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i )
+ {
+ size_t size_i;
+ for ( size_i = 0; size_i < size; ++size_i )
+ {
+ 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
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by fread(). */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/getc.c b/src/pdclib/functions/stdio/getc.c
new file mode 100644
index 0000000..3d082b3
--- /dev/null
+++ b/src/pdclib/functions/stdio/getc.c
@@ -0,0 +1,28 @@
+/* getc( 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>
+
+#ifndef REGTEST
+
+int getc( struct _PDCLIB_file_t * stream )
+{
+ return fgetc( stream );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/getchar.c b/src/pdclib/functions/stdio/getchar.c
new file mode 100644
index 0000000..34ee545
--- /dev/null
+++ b/src/pdclib/functions/stdio/getchar.c
@@ -0,0 +1,28 @@
+/* getchar( void )
+
+ 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
+
+int getchar( void )
+{
+ return fgetc( stdin );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/perror.c b/src/pdclib/functions/stdio/perror.c
new file mode 100644
index 0000000..dd6633c
--- /dev/null
+++ b/src/pdclib/functions/stdio/perror.c
@@ -0,0 +1,58 @@
+/* perror( 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>
+#include <errno.h>
+#include <locale.h>
+
+#ifndef REGTEST
+
+/* TODO: Doing this via a static array is not the way to do it. */
+void perror( const char * s )
+{
+ if ( ( s != NULL ) && ( s[0] != '\n' ) )
+ {
+ fprintf( stderr, "%s: ", s );
+ }
+ if ( errno >= _PDCLIB_ERRNO_MAX )
+ {
+ fprintf( stderr, "Unknown error\n" );
+ }
+ else
+ {
+ fprintf( stderr, "%s\n", _PDCLIB_lc_messages.errno_texts[errno] );
+ }
+ return;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+int main( void )
+{
+ FILE * fh;
+ unsigned long long max = ULLONG_MAX;
+ char buffer[100];
+ sprintf( buffer, "%llu", max );
+ TESTCASE( ( fh = freopen( testfile, "wb+", stderr ) ) != NULL );
+ TESTCASE( strtol( buffer, NULL, 10 ) == LONG_MAX );
+ perror( "Test" );
+ rewind( fh );
+ TESTCASE( fread( buffer, 1, 7, fh ) == 7 );
+ TESTCASE( memcmp( buffer, "Test: ", 6 ) == 0 );
+ TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/printf.c b/src/pdclib/functions/stdio/printf.c
new file mode 100644
index 0000000..6d10113
--- /dev/null
+++ b/src/pdclib/functions/stdio/printf.c
@@ -0,0 +1,44 @@
+/* printf( 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>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int printf( const char * _PDCLIB_restrict format, ... )
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vfprintf( stdout, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/printf.c"
+#define _PDCLIB_FILEIO
+#include <stdint.h>
+#include <stddef.h>
+
+#include "_PDCLIB_test.h"
+
+#define testprintf( stream, ... ) printf( __VA_ARGS__ )
+
+int main( void )
+{
+ FILE * target;
+ TESTCASE( ( target = freopen( testfile, "wb+", stdout ) ) != NULL );
+#include "printf_testcases.h"
+ TESTCASE( fclose( target ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/putc.c b/src/pdclib/functions/stdio/putc.c
new file mode 100644
index 0000000..c1eb2b0
--- /dev/null
+++ b/src/pdclib/functions/stdio/putc.c
@@ -0,0 +1,28 @@
+/* putc( int, 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>
+
+#ifndef REGTEST
+
+int putc( int c, struct _PDCLIB_file_t * stream )
+{
+ return fputc( c, stream );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/putchar.c b/src/pdclib/functions/stdio/putchar.c
new file mode 100644
index 0000000..15bf299
--- /dev/null
+++ b/src/pdclib/functions/stdio/putchar.c
@@ -0,0 +1,28 @@
+/* putchar( 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 REGTEST
+
+int putchar( int c )
+{
+ return fputc( c, stdout );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/puts.c b/src/pdclib/functions/stdio/puts.c
new file mode 100644
index 0000000..89240cb
--- /dev/null
+++ b/src/pdclib/functions/stdio/puts.c
@@ -0,0 +1,67 @@
+/* puts( 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/_PDCLIB_glue.h"
+
+extern char * _PDCLIB_eol;
+
+int puts( const char * s )
+{
+ 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;
+ }
+ }
+ }
+ stdout->buffer[ stdout->bufidx++ ] = '\n';
+ if ( ( stdout->bufidx == stdout->bufsize ) ||
+ ( stdout->status & ( _IOLBF | _IONBF ) ) )
+ {
+ return _PDCLIB_flushbuffer( stdout );
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ FILE * fh;
+ const char * message = "SUCCESS testing puts()";
+ char buffer[23];
+ buffer[22] = 'x';
+ TESTCASE( ( fh = freopen( testfile, "wb+", stdout ) ) != NULL );
+ TESTCASE( puts( message ) >= 0 );
+ rewind( fh );
+ TESTCASE( fread( buffer, 1, 22, fh ) == 22 );
+ TESTCASE( memcmp( buffer, message, 22 ) == 0 );
+ TESTCASE( buffer[22] == 'x' );
+ TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/rename.c b/src/pdclib/functions/stdio/rename.c
new file mode 100644
index 0000000..5d45f1f
--- /dev/null
+++ b/src/pdclib/functions/stdio/rename.c
@@ -0,0 +1,84 @@
+/* rename( const char *, 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/_PDCLIB_glue.h"
+
+#include <string.h>
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+int rename( const char * old, const char * new )
+{
+ struct _PDCLIB_file_t * current = _PDCLIB_filelist;
+ while ( current != NULL )
+ {
+ if ( ( current->filename != NULL ) && ( strcmp( current->filename, old ) == 0 ) )
+ {
+ /* File of that name currently open. Do not rename. */
+ return EOF;
+ }
+ current = current->next;
+ }
+ return _PDCLIB_rename( old, new );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdlib.h>
+
+int main( void )
+{
+ FILE * file;
+ remove( testfile1 );
+ remove( testfile2 );
+ /* make sure that neither file exists */
+ TESTCASE( fopen( testfile1, "r" ) == NULL );
+ TESTCASE( fopen( testfile2, "r" ) == NULL );
+ /* rename file 1 to file 2 - expected to fail */
+ TESTCASE( rename( testfile1, testfile2 ) == -1 );
+ /* create file 1 */
+ TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL );
+ TESTCASE( fputs( "x", file ) != EOF );
+ TESTCASE( fclose( file ) == 0 );
+ /* check that file 1 exists */
+ TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL );
+ TESTCASE( fclose( file ) == 0 );
+ /* rename file 1 to file 2 */
+ TESTCASE( rename( testfile1, testfile2 ) == 0 );
+ /* check that file 2 exists, file 1 does not */
+ TESTCASE( fopen( testfile1, "r" ) == NULL );
+ TESTCASE( ( file = fopen( testfile2, "r" ) ) != NULL );
+ TESTCASE( fclose( file ) == 0 );
+ /* create another file 1 */
+ TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL );
+ TESTCASE( fputs( "x", file ) != EOF );
+ TESTCASE( fclose( file ) == 0 );
+ /* check that file 1 exists */
+ TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL );
+ TESTCASE( fclose( file ) == 0 );
+ /* rename file 1 to file 2 - expected to fail, see comment in
+ _PDCLIB_rename() itself.
+ */
+ /* NOREG as glibc overwrites existing destination file. */
+ TESTCASE_NOREG( rename( testfile1, testfile2 ) == -1 );
+ /* remove both files */
+ TESTCASE( remove( testfile1 ) == 0 );
+ TESTCASE( remove( testfile2 ) == 0 );
+ /* check that they're gone */
+ TESTCASE( fopen( testfile1, "r" ) == NULL );
+ TESTCASE( fopen( testfile2, "r" ) == NULL );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/rewind.c b/src/pdclib/functions/stdio/rewind.c
new file mode 100644
index 0000000..a449b7d
--- /dev/null
+++ b/src/pdclib/functions/stdio/rewind.c
@@ -0,0 +1,29 @@
+/* rewind( 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>
+
+#ifndef REGTEST
+
+void rewind( struct _PDCLIB_file_t * stream )
+{
+ stream->status &= ~ _PDCLIB_ERRORFLAG;
+ fseek( stream, 0L, SEEK_SET );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/scanf.c b/src/pdclib/functions/stdio/scanf.c
new file mode 100644
index 0000000..b29b1d5
--- /dev/null
+++ b/src/pdclib/functions/stdio/scanf.c
@@ -0,0 +1,39 @@
+/* scanf( 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>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int scanf( const char * _PDCLIB_restrict format, ... )
+{
+ va_list ap;
+ va_start( ap, format );
+ return vfscanf( stdin, format, ap );
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/scanf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+#define testscanf( stream, format, ... ) scanf( format, __VA_ARGS__ )
+
+int main( void )
+{
+ FILE * source;
+ TESTCASE( ( source = freopen( testfile, "wb+", stdin ) ) != NULL );
+#include "scanf_testcases.h"
+ TESTCASE( fclose( source ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/setbuf.c b/src/pdclib/functions/stdio/setbuf.c
new file mode 100644
index 0000000..6c32072
--- /dev/null
+++ b/src/pdclib/functions/stdio/setbuf.c
@@ -0,0 +1,55 @@
+/* setbuf( FILE *, 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
+
+void setbuf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, char * _PDCLIB_restrict buf )
+{
+ if ( buf == NULL )
+ {
+ setvbuf( stream, buf, _IONBF, BUFSIZ );
+ }
+ else
+ {
+ setvbuf( stream, buf, _IOFBF, BUFSIZ );
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdlib.h>
+
+int main( void )
+{
+ /* TODO: Extend testing once setvbuf() is finished. */
+#ifndef REGTEST
+ char buffer[ BUFSIZ + 1 ];
+ FILE * fh;
+ /* full buffered */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ setbuf( fh, buffer );
+ TESTCASE( fh->buffer == buffer );
+ TESTCASE( fh->bufsize == BUFSIZ );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOFBF );
+ TESTCASE( fclose( fh ) == 0 );
+ /* not buffered */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ setbuf( fh, NULL );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IONBF );
+ TESTCASE( fclose( fh ) == 0 );
+#else
+ puts( " NOTEST setbuf() test driver is PDCLib-specific." );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/setvbuf.c b/src/pdclib/functions/stdio/setvbuf.c
new file mode 100644
index 0000000..00592ff
--- /dev/null
+++ b/src/pdclib/functions/stdio/setvbuf.c
@@ -0,0 +1,108 @@
+/* setvbuf( FILE *, char *, int, 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 <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 )
+{
+ switch ( mode )
+ {
+ 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 == 0 )
+ {
+ /* 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 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.
+ */
+ if ( ( stream->bufsize < size ) || ( stream->bufsize > ( size << 1 ) ) )
+ {
+ /* Buffer too small, or much too large - allocate. */
+ if ( ( buf = (char *) malloc( size ) ) == NULL )
+ {
+ /* Out of memory error. */
+ return -1;
+ }
+ /* This buffer must be free()d on fclose() */
+ stream->status |= _PDCLIB_FREEBUFFER;
+ }
+ }
+ stream->buffer = buf;
+ stream->bufsize = size;
+ break;
+ default:
+ /* If mode is something else than _IOFBF, _IOLBF or _IONBF -> exit */
+ return -1;
+ }
+ /* Deleting current buffer mode */
+ stream->status &= ~( _IOFBF | _IOLBF | _IONBF );
+ /* Set user-defined mode */
+ stream->status |= mode;
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <errno.h>
+
+#define BUFFERSIZE 500
+
+int main( void )
+{
+#ifndef REGTEST
+ char buffer[ BUFFERSIZE ];
+ FILE * fh;
+ /* full buffered, user-supplied buffer */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( setvbuf( fh, buffer, _IOFBF, BUFFERSIZE ) == 0 );
+ TESTCASE( fh->buffer == buffer );
+ TESTCASE( fh->bufsize == BUFFERSIZE );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOFBF );
+ TESTCASE( fclose( fh ) == 0 );
+ /* line buffered, lib-supplied buffer */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( setvbuf( fh, NULL, _IOLBF, BUFFERSIZE ) == 0 );
+ TESTCASE( fh->buffer != NULL );
+ TESTCASE( fh->bufsize == BUFFERSIZE );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOLBF );
+ TESTCASE( fclose( fh ) == 0 );
+ /* not buffered, user-supplied buffer */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( setvbuf( fh, buffer, _IONBF, BUFFERSIZE ) == 0 );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IONBF );
+ TESTCASE( fclose( fh ) == 0 );
+#else
+ puts( " NOTEST setvbuf() test driver is PDCLib-specific." );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/snprintf.c b/src/pdclib/functions/stdio/snprintf.c
new file mode 100644
index 0000000..f095b8c
--- /dev/null
+++ b/src/pdclib/functions/stdio/snprintf.c
@@ -0,0 +1,43 @@
+/* snprintf( char *, size_t, 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>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int snprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, ...)
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vsnprintf( s, n, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/snprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stdint.h>
+#include <stddef.h>
+
+#include "_PDCLIB_test.h"
+
+#define testprintf( s, ... ) snprintf( s, 100, __VA_ARGS__ )
+
+int main( void )
+{
+ char target[100];
+#include "printf_testcases.h"
+ TESTCASE( snprintf( NULL, 0, "foo" ) == 3 );
+ TESTCASE( snprintf( NULL, 0, "%d", 100 ) == 3 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/sprintf.c b/src/pdclib/functions/stdio/sprintf.c
new file mode 100644
index 0000000..ce3a7ff
--- /dev/null
+++ b/src/pdclib/functions/stdio/sprintf.c
@@ -0,0 +1,41 @@
+/* sprintf( char *, 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>
+#include <stdint.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int sprintf( char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, ...)
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vsnprintf( s, SIZE_MAX, format, ap ); /* TODO: replace with non-checking call */
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/sprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stddef.h>
+
+#include "_PDCLIB_test.h"
+
+#define testprintf( s, ... ) sprintf( s, __VA_ARGS__ )
+
+int main( void )
+{
+ char target[100];
+#include "printf_testcases.h"
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/sscanf.c b/src/pdclib/functions/stdio/sscanf.c
new file mode 100644
index 0000000..9ba830d
--- /dev/null
+++ b/src/pdclib/functions/stdio/sscanf.c
@@ -0,0 +1,39 @@
+/* sscanf( const char *, 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>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int sscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, ... )
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vsscanf( s, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/sscanf.c"
+#define _PDCLIB_STRINGIO
+
+#include "_PDCLIB_test.h"
+
+#define testscanf( s, format, ... ) sscanf( s, format, __VA_ARGS__ )
+
+int main( void )
+{
+ char source[100];
+#include "scanf_testcases.h"
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/testfile.txt b/src/pdclib/functions/stdio/testfile.txt
new file mode 100644
index 0000000..f08c4d3
--- /dev/null
+++ b/src/pdclib/functions/stdio/testfile.txt
Binary files differ
diff --git a/src/pdclib/functions/stdio/tmpnam.c b/src/pdclib/functions/stdio/tmpnam.c
new file mode 100644
index 0000000..5909aff
--- /dev/null
+++ b/src/pdclib/functions/stdio/tmpnam.c
@@ -0,0 +1,42 @@
+/* tmpnam( 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/_PDCLIB_glue.h"
+
+#include <string.h>
+
+char * tmpnam( char * s )
+{
+ static char filename[ L_tmpnam ];
+ FILE * file = tmpfile();
+ if ( s == NULL )
+ {
+ s = filename;
+ }
+ strcpy( s, file->filename );
+ fclose( file );
+ return s;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+
+int main( void )
+{
+ TESTCASE( strlen( tmpnam( NULL ) ) < L_tmpnam );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/ungetc.c b/src/pdclib/functions/stdio/ungetc.c
new file mode 100644
index 0000000..dc5260b
--- /dev/null
+++ b/src/pdclib/functions/stdio/ungetc.c
@@ -0,0 +1,32 @@
+/* ungetc( int, 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>
+
+#ifndef REGTEST
+
+int ungetc( int c, struct _PDCLIB_file_t * stream )
+{
+ if ( c == EOF || stream->ungetidx == _PDCLIB_UNGETCBUFSIZE )
+ {
+ return -1;
+ }
+ return stream->ungetbuf[stream->ungetidx++] = (unsigned char) c;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vfprintf.c b/src/pdclib/functions/stdio/vfprintf.c
new file mode 100644
index 0000000..6f31bbd
--- /dev/null
+++ b/src/pdclib/functions/stdio/vfprintf.c
@@ -0,0 +1,74 @@
+/* vfprintf( FILE *, const char *, va_list )
+
+ 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 <stdarg.h>
+#include <stdint.h>
+
+#ifndef REGTEST
+
+int vfprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg )
+{
+ /* TODO: This function should interpret format as multibyte characters. */
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = SIZE_MAX;
+ status.i = 0;
+ status.current = 0;
+ status.s = NULL;
+ status.width = 0;
+ status.prec = EOF;
+ status.stream = stream;
+ va_copy( status.arg, arg );
+
+ while ( *format != '\0' )
+ {
+ const char * rc;
+ if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) )
+ {
+ /* No conversion specifier, print verbatim */
+ putc( *(format++), stream );
+ status.i++;
+ }
+ else
+ {
+ /* Continue parsing after conversion specifier */
+ format = rc;
+ }
+ }
+ va_end( status.arg );
+ return status.i;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vfprintf.c"
+#define _PDCLIB_FILEIO
+#include <stddef.h>
+#include "_PDCLIB_test.h"
+
+static int testprintf( FILE * stream, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vfprintf( stream, format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ FILE * target;
+ TESTCASE( ( target = tmpfile() ) != NULL );
+#include "printf_testcases.h"
+ TESTCASE( fclose( target ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vfscanf.c b/src/pdclib/functions/stdio/vfscanf.c
new file mode 100644
index 0000000..bb24456
--- /dev/null
+++ b/src/pdclib/functions/stdio/vfscanf.c
@@ -0,0 +1,113 @@
+/* vfscanf( FILE *, const char *, va_list )
+
+ 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 <stdarg.h>
+#include <ctype.h>
+
+#ifndef REGTEST
+
+int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg )
+{
+ /* TODO: This function should interpret format as multibyte characters. */
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = 0;
+ status.i = 0;
+ status.current = 0;
+ status.s = NULL;
+ status.width = 0;
+ status.prec = EOF;
+ status.stream = stream;
+ va_copy( status.arg, arg );
+
+ while ( *format != '\0' )
+ {
+ const char * rc;
+ if ( ( *format != '%' ) || ( ( rc = _PDCLIB_scan( format, &status ) ) == format ) )
+ {
+ int c;
+ /* No conversion specifier, match verbatim */
+ if ( isspace( *format ) )
+ {
+ /* Whitespace char in format string: Skip all whitespaces */
+ /* No whitespaces in input does not result in matching error */
+ while ( isspace( c = getc( stream ) ) )
+ {
+ ++status.i;
+ }
+ if ( ! feof( stream ) )
+ {
+ ungetc( c, stream );
+ }
+ }
+ else
+ {
+ /* Non-whitespace char in format string: Match verbatim */
+ if ( ( ( c = getc( stream ) ) != *format ) || feof( stream ) )
+ {
+ /* Matching error */
+ if ( ! feof( stream ) && ! ferror( stream ) )
+ {
+ ungetc( c, stream );
+ }
+ else if ( status.n == 0 )
+ {
+ return EOF;
+ }
+ return status.n;
+ }
+ else
+ {
+ ++status.i;
+ }
+ }
+ ++format;
+ }
+ else
+ {
+ /* NULL return code indicates matching error */
+ if ( rc == NULL )
+ {
+ break;
+ }
+ /* Continue parsing after conversion specifier */
+ format = rc;
+ }
+ }
+ va_end( status.arg );
+ return status.n;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vfscanf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+static int testscanf( FILE * stream, const char * format, ... )
+{
+ va_list ap;
+ int result;
+ va_start( ap, format );
+ result = vfscanf( stream, format, ap );
+ va_end( ap );
+ return result;
+}
+
+int main( void )
+{
+ FILE * source;
+ TESTCASE( ( source = tmpfile() ) != NULL );
+#include "scanf_testcases.h"
+ TESTCASE( fclose( source ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vprintf.c b/src/pdclib/functions/stdio/vprintf.c
new file mode 100644
index 0000000..fe80152
--- /dev/null
+++ b/src/pdclib/functions/stdio/vprintf.c
@@ -0,0 +1,46 @@
+/* vprintf( const char *, va_list )
+
+ 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 <stdarg.h>
+
+#ifndef REGTEST
+
+int vprintf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
+{
+ return vfprintf( stdout, format, arg );
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vprintf.c"
+#define _PDCLIB_FILEIO
+#include <stdint.h>
+#include <stddef.h>
+#include "_PDCLIB_test.h"
+
+static int testprintf( FILE * stream, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vprintf( format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ FILE * target;
+ TESTCASE( ( target = freopen( testfile, "wb+", stdout ) ) != NULL );
+#include "printf_testcases.h"
+ TESTCASE( fclose( target ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vscanf.c b/src/pdclib/functions/stdio/vscanf.c
new file mode 100644
index 0000000..d5ae5b3
--- /dev/null
+++ b/src/pdclib/functions/stdio/vscanf.c
@@ -0,0 +1,45 @@
+/* vscanf( const char *, va_list )
+
+ 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 <stdarg.h>
+
+#ifndef REGTEST
+
+int vscanf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
+{
+ return vfscanf( stdin, format, arg );
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vscanf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+static int testscanf( FILE * stream, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vscanf( format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ FILE * source;
+ TESTCASE( ( source = freopen( testfile, "wb+", stdin ) ) != NULL );
+#include "scanf_testcases.h"
+ TESTCASE( fclose( source ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vsnprintf.c b/src/pdclib/functions/stdio/vsnprintf.c
new file mode 100644
index 0000000..e57e682
--- /dev/null
+++ b/src/pdclib/functions/stdio/vsnprintf.c
@@ -0,0 +1,80 @@
+/* vsnprintf( char *, size_t, const char *, va_list )
+
+ 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 <stdarg.h>
+
+#ifndef REGTEST
+
+int vsnprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
+{
+ /* TODO: This function should interpret format as multibyte characters. */
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = n;
+ status.i = 0;
+ status.current = 0;
+ status.s = s;
+ status.width = 0;
+ status.prec = EOF;
+ status.stream = NULL;
+ va_copy( status.arg, arg );
+
+ while ( *format != '\0' )
+ {
+ const char * rc;
+ if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) )
+ {
+ /* No conversion specifier, print verbatim */
+ if ( status.i < n )
+ {
+ s[ status.i ] = *format;
+ }
+ status.i++;
+ format++;
+ }
+ else
+ {
+ /* Continue parsing after conversion specifier */
+ format = rc;
+ }
+ }
+ if ( status.i < n )
+ {
+ s[ status.i ] = '\0';
+ }
+ va_end( status.arg );
+ return status.i;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vsnprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stdint.h>
+#include <stddef.h>
+#include "_PDCLIB_test.h"
+
+static int testprintf( char * s, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vsnprintf( s, 100, format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ char target[100];
+#include "printf_testcases.h"
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vsprintf.c b/src/pdclib/functions/stdio/vsprintf.c
new file mode 100644
index 0000000..4ab2742
--- /dev/null
+++ b/src/pdclib/functions/stdio/vsprintf.c
@@ -0,0 +1,44 @@
+/* vsprintf( char *, const char *, va_list )
+
+ 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 <stdint.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int vsprintf( char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg )
+{
+ return vsnprintf( s, SIZE_MAX, format, arg ); /* TODO: Replace with a non-checking call */
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vsprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stdint.h>
+#include <stddef.h>
+#include "_PDCLIB_test.h"
+
+static int testprintf( char * s, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vsprintf( s, format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ char target[100];
+#include "printf_testcases.h"
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vsscanf.c b/src/pdclib/functions/stdio/vsscanf.c
new file mode 100644
index 0000000..e76e70e
--- /dev/null
+++ b/src/pdclib/functions/stdio/vsscanf.c
@@ -0,0 +1,109 @@
+/* vsscanf( const char *, const char *, va_list )
+
+ 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 <stdarg.h>
+#include <ctype.h>
+
+#ifndef REGTEST
+
+int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg )
+{
+ /* TODO: This function should interpret format as multibyte characters. */
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = 0;
+ status.i = 0;
+ status.current = 0;
+ status.s = (char *) s;
+ status.width = 0;
+ status.prec = EOF;
+ status.stream = NULL;
+ va_copy( status.arg, arg );
+
+ while ( *format != '\0' )
+ {
+ const char * rc;
+ if ( ( *format != '%' ) || ( ( rc = _PDCLIB_scan( format, &status ) ) == format ) )
+ {
+ /* No conversion specifier, match verbatim */
+ if ( isspace( *format ) )
+ {
+ /* Whitespace char in format string: Skip all whitespaces */
+ /* No whitespaces in input do not result in matching error */
+ while ( isspace( *status.s ) )
+ {
+ ++status.s;
+ ++status.i;
+ }
+ }
+ else
+ {
+ /* Non-whitespace char in format string: Match verbatim */
+ if ( *status.s != *format )
+ {
+ if ( *status.s == '\0' && status.n == 0 )
+ {
+ /* Early input error */
+ return EOF;
+ }
+ /* Matching error */
+ return status.n;
+ }
+ else
+ {
+ ++status.s;
+ ++status.i;
+ }
+ }
+ ++format;
+ }
+ else
+ {
+ /* NULL return code indicates error */
+ if ( rc == NULL )
+ {
+ if ( ( *status.s == '\n' ) && ( status.n == 0 ) )
+ {
+ status.n = EOF;
+ }
+ break;
+ }
+ /* Continue parsing after conversion specifier */
+ format = rc;
+ }
+ }
+ va_end( status.arg );
+ return status.n;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vsscanf.c"
+#define _PDCLIB_STRINGIO
+
+#include "_PDCLIB_test.h"
+
+static int testscanf( const char * stream, const char * format, ... )
+{
+ va_list ap;
+ int result;
+ va_start( ap, format );
+ result = vsscanf( stream, format, ap );
+ va_end( ap );
+ return result;
+}
+
+int main( void )
+{
+ char source[100];
+#include "scanf_testcases.h"
+ return TEST_RESULTS;
+}
+
+#endif