From 05556502a427911d4499c22b809ca7d366327d7c Mon Sep 17 00:00:00 2001 From: Owen Shepherd Date: Sun, 26 Aug 2012 16:33:48 +0100 Subject: [PATCH] PDCLIB-7: Add _PDCLIB_ftell64 to give us full precision file positioning information. Rewrite ftell to use it, and fseek to use it for the SEEK_CUR case. This should resolve PDCLIB-7 --- functions/stdio/_PDCLIB_ftell64.c | 55 +++++++++++++++++++++++++++++++ functions/stdio/fseek.c | 12 ++++++- functions/stdio/ftell.c | 30 ++++------------- includes/stdio.h | 1 + 4 files changed, 74 insertions(+), 24 deletions(-) create mode 100644 functions/stdio/_PDCLIB_ftell64.c diff --git a/functions/stdio/_PDCLIB_ftell64.c b/functions/stdio/_PDCLIB_ftell64.c new file mode 100644 index 0000000..650eda5 --- /dev/null +++ b/functions/stdio/_PDCLIB_ftell64.c @@ -0,0 +1,55 @@ +/* $Id$ */ + +/* _PDCLIB_ftell64( FILE * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include +#include + +#ifndef REGTEST + +uint_fast64_t _PDCLIB_ftell64( 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. + */ + + /* ungetc on a stream at offset==0 will cause an overflow to UINT64_MAX. + * C99/C11 says that the return value of ftell in this case is + * "indeterminate" + */ + + return ( stream->pos.offset - ( ( (int)stream->bufend - (int)stream->bufidx ) + (int)stream->ungetidx ) ); +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +#include + +int main( void ) +{ + /* Tested by ftell */ + return TEST_RESULTS; +} + +#endif + diff --git a/functions/stdio/fseek.c b/functions/stdio/fseek.c index 18c38c3..8e10c2b 100644 --- a/functions/stdio/fseek.c +++ b/functions/stdio/fseek.c @@ -31,7 +31,7 @@ int fseek( struct _PDCLIB_file_t * stream, long loffset, int whence ) if ( whence == SEEK_CUR ) { whence = SEEK_SET; - offset += stream->pos.offset; + offset += _PDCLIB_ftell64( stream ); } return ( _PDCLIB_seek( stream, offset, whence ) != EOF ) ? 0 : EOF; @@ -83,6 +83,16 @@ int main( void ) TESTCASE( ftell( fh ) == 2 ); TESTCASE( fseek( fh, 2, SEEK_SET ) == 0 ); TESTCASE( fgetc( fh ) == teststring[2] ); + /* PDCLIB-7: Check that we handle the underlying file descriptor correctly + * in the SEEK_CUR case */ + TESTCASE( fseek( fh, 10, SEEK_SET ) == 0 ); + TESTCASE( ftell( fh ) == 10l ); + TESTCASE( fseek( fh, 0, SEEK_CUR ) == 0 ); + TESTCASE( ftell( fh ) == 10l ); + TESTCASE( fseek( fh, 2, SEEK_CUR ) == 0 ); + TESTCASE( ftell( fh ) == 12l ); + TESTCASE( fseek( fh, -1, SEEK_CUR ) == 0 ); + TESTCASE( ftell( fh ) == 11l ); /* Checking error handling */ TESTCASE( fseek( fh, -5, SEEK_SET ) == -1 ); TESTCASE( fseek( fh, 0, SEEK_END ) == 0 ); diff --git a/functions/stdio/ftell.c b/functions/stdio/ftell.c index e82ca48..d39297f 100644 --- a/functions/stdio/ftell.c +++ b/functions/stdio/ftell.c @@ -7,39 +7,23 @@ */ #include +#include #include +#include #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 ) ) ) + uint_fast64_t off64 = _PDCLIB_ftell64( stream ); + + if ( off64 > LONG_MAX ) { /* integer overflow */ - _PDCLIB_errno = _PDCLIB_ERANGE; + errno = ERANGE; return -1; } - long int res = ( stream->pos.offset - ( ( (int)stream->bufend - (int)stream->bufidx ) + stream->ungetidx ) ); - return res; + return off64; } #endif diff --git a/includes/stdio.h b/includes/stdio.h index b5c8abe..7441333 100644 --- a/includes/stdio.h +++ b/includes/stdio.h @@ -788,6 +788,7 @@ int fsetpos( FILE * stream, const fpos_t * pos ) _PDCLIB_nothrow; TODO: Implementation-defined errno setting for ftell(). */ long int ftell( FILE * stream ) _PDCLIB_nothrow; +_PDCLIB_uint_fast64_t _PDCLIB_ftell64( FILE * stream ) _PDCLIB_nothrow; /* Equivalent to (void)fseek( stream, 0L, SEEK_SET ), except that the error indicator for the stream is also cleared. -- 2.40.0