/* $Id$ */
-/* freopen( const char *, const char * )
+/* 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 <_PDCLIB_glue.h>
#include <stdlib.h>
+#include <string.h>
-/* 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 the following mode changes: TODO
- (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 * stream )
+struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
{
- /* FIXME: This is ad-hoc (to make the vprintf() testdriver work), and must be checked. */
- /* FIXME: If filename is NULL, change mode. */
+ unsigned int status = stream->status & ( _IONBF | _IOLBF | _IOFBF | _PDCLIB_FREEBUFFER | _PDCLIB_DELONCLOSE );
/* TODO: This function can change wide orientation of a stream */
- if ( filename == NULL ) return NULL;
- if ( stream->status & _PDCLIB_FWRITE ) fflush( stream );
- if ( stream->status & _PDCLIB_LIBBUFFER ) free( stream->buffer );
+ 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 );
- if ( ( mode == NULL ) || ( filename[0] == '\0' ) ) return NULL;
- if ( ( stream->status = _PDCLIB_filemode( mode ) ) == 0 ) return NULL;
- stream->handle = _PDCLIB_open( filename, stream->status );
- if ( ( stream->buffer = malloc( BUFSIZ ) ) == NULL ) return NULL;
- stream->bufsize = BUFSIZ;
+ /* 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->status |= _PDCLIB_LIBBUFFER;
+ stream->bufend = 0;
+ stream->ungetidx = 0;
/* TODO: Setting mbstate */
+ if ( ( stream->handle = _PDCLIB_open( filename, stream->status ) ) == _PDCLIB_NOHANDLE )
+ {
+ return NULL;
+ }
return stream;
}