X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=functions%2Fstdio%2Ffreopen.c;h=fb356a820a6e32721a78c4a722d9fc0ace69f300;hb=b5b6c4a890795ea76f9b92b817b0a83c6bb4862c;hp=a2c0adade6b91908d5644c7b3dbb1e7ad66fd6b7;hpb=11b081417bc53095a3ae58ae0265cc09ad982947;p=pdclib.old diff --git a/functions/stdio/freopen.c b/functions/stdio/freopen.c index a2c0ada..fb356a8 100644 --- a/functions/stdio/freopen.c +++ b/functions/stdio/freopen.c @@ -9,39 +9,70 @@ #include #ifndef REGTEST - +#include <_PDCLIB_io.h> #include <_PDCLIB_glue.h> #include +#include -/* Close any file currently associated with the given stream. Open the file - identified by the given filename with the given mode (equivalent to fopen()), - and associate it with the given stream. If filename is a NULL pointer, - attempt to change the mode of the given stream. - This implementation allows any mode changes. - (Primary use of this function is to redirect stdin, stdout, and stderr.) -*/ -struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode, struct _PDCLIB_file_t * _PDCLIB_restrict stream ) +FILE * freopen( + const char * _PDCLIB_restrict filename, + const char * _PDCLIB_restrict mode, + FILE * _PDCLIB_restrict stream +) { - unsigned int status = stream->status & ( _IONBF | _IOLBF | _IOFBF | _PDCLIB_FREEBUFFER | _PDCLIB_DELONCLOSE ); + _PDCLIB_flockfile( stream ); + + unsigned int status = stream->status & + ( _IONBF | _IOLBF | _IOFBF | _PDCLIB_FREEBUFFER + | _PDCLIB_DELONCLOSE | _PDCLIB_STATIC ); + /* TODO: This function can change wide orientation of a stream */ if ( stream->status & _PDCLIB_FWRITE ) { _PDCLIB_flushbuffer( stream ); } - _PDCLIB_close( stream->handle ); - clearerr( stream ); - /* FIXME: Copy filename into the FILE structure. */ - /* FIXME: filename cannot reside in "big block" memory */ + if ( ( filename == NULL ) && ( stream->filename == NULL ) ) + { + /* TODO: Special handling for mode changes on std-streams */ + _PDCLIB_funlockfile( stream ); + return NULL; + } + stream->ops->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. + */ + _PDCLIB_clearerr_unlocked( 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 ) + { + _PDCLIB_funlockfile( stream ); + return NULL; + } + strcpy( stream->filename, filename ); + } if ( ( mode == NULL ) || ( filename[0] == '\0' ) ) { + _PDCLIB_funlockfile( stream ); return NULL; } if ( ( stream->status = _PDCLIB_filemode( mode ) ) == 0 ) { + _PDCLIB_funlockfile( stream ); return NULL; } /* Re-add the flags we saved above */ @@ -50,10 +81,13 @@ struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const c stream->bufend = 0; stream->ungetidx = 0; /* TODO: Setting mbstate */ - if ( ( stream->handle = _PDCLIB_open( filename, stream->status ) ) == _PDCLIB_NOHANDLE ) + if ( ! _PDCLIB_open( &stream->handle, &stream->ops, filename, + stream->status ) ) { + _PDCLIB_funlockfile( stream ); return NULL; } + _PDCLIB_funlockfile( stream ); return stream; } @@ -64,7 +98,24 @@ struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const c int main( void ) { - TESTCASE( NO_TESTDRIVER ); + 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; }