diff options
author | tcsullivan <tullivan99@gmail.com> | 2018-11-17 13:02:57 -0500 |
---|---|---|
committer | tcsullivan <tullivan99@gmail.com> | 2018-11-17 13:02:57 -0500 |
commit | c6ef89664b8c0d7aa85bddd5c7014aa6df82cbe7 (patch) | |
tree | d1f9d09412a46bdf4344fe30392455070a72993d /src/pdclib/functions/stdio | |
parent | db38c4b9dac461de0ed75bf6d079dacba1b31bc9 (diff) |
added pdclib, removed sash
Diffstat (limited to 'src/pdclib/functions/stdio')
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 Binary files differnew file mode 100644 index 0000000..f08c4d3 --- /dev/null +++ b/src/pdclib/functions/stdio/testfile.txt 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 |