1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
/* 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
#ifndef __STDC_NO_THREADS__
#include <threads.h>
#endif
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.
*/
_PDCLIB_LOCK( stream->mtx );
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 provided buffer. Deallocate existing buffer, and mark
the stream so that fclose() does not try to deallocate the
user's buffer.
*/
if ( stream->status & _PDCLIB_FREEBUFFER )
{
free( stream->buffer );
}
stream->status &= ~_PDCLIB_FREEBUFFER;
}
else
{
/* 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.
*/
_PDCLIB_LOCK( stream->mtx );
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. */
_PDCLIB_UNLOCK( stream->mtx );
return -1;
}
if ( stream->status & _PDCLIB_FREEBUFFER )
{
free( stream->buffer );
}
/* 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;
_PDCLIB_UNLOCK( stream->mtx );
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
|