From 8275244150b81ff747f907383b3565c38e2e51e8 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 30 Mar 2008 12:25:40 +0200 Subject: [PATCH] Improve freadseek's efficiency after ungetc. --- ChangeLog | 10 ++++++ lib/freadseek.c | 96 ++++++++++++++++++++++++++++++++++++------------------- modules/freadseek | 2 ++ 3 files changed, 75 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index e021282ef..0e88c4b51 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2008-03-30 Bruno Haible + Improve freadseek's efficiency after ungetc. + * lib/freadseek.c: Include freadahead.h. + (freadptrinc): New function, extracted from freadseek. + (freadseek): Use it in a loop. Use freadahead to determine the number + of loop iterations. + * modules/freadseek (Depends-on): Add freadahead. + (configure.ac): Require AC_C_INLINE. + +2008-03-30 Bruno Haible + * lib/freadseek.c (freadseek): Don't ignore the return value of freadptr. diff --git a/lib/freadseek.c b/lib/freadseek.c index 9e56ccc57..c4078d4f5 100644 --- a/lib/freadseek.c +++ b/lib/freadseek.c @@ -22,28 +22,21 @@ #include #include +#include "freadahead.h" #include "freadptr.h" -int -freadseek (FILE *fp, size_t offset) +/* Increment the in-memory pointer. INCREMENT must be at most the buffer size + returned by freadptr(). + This is very cheap (no system calls). */ +static inline void +freadptrinc (FILE *fp, size_t increment) { - size_t buffered; - int fd; - - if (offset == 0) - return 0; - - /* Increment the in-memory pointer. This is very cheap (no system calls). */ - if (freadptr (fp, &buffered) != NULL && buffered > 0) - { - size_t increment = (buffered < offset ? buffered : offset); - - /* Keep this code in sync with freadptr! */ + /* Keep this code in sync with freadptr! */ #if defined _IO_ferror_unlocked /* GNU libc, BeOS */ - fp->_IO_read_ptr += increment; + fp->_IO_read_ptr += increment; #elif defined __sferror /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */ - fp->_p += increment; - fp->_r -= increment; + fp->_p += increment; + fp->_r -= increment; #elif defined _IOERR /* AIX, HP-UX, IRIX, OSF/1, Solaris, mingw */ # if defined __sun && defined _LP64 /* Solaris/{SPARC,AMD64} 64-bit */ # define fp_ ((struct { unsigned char *_ptr; \ @@ -53,27 +46,63 @@ freadseek (FILE *fp, size_t offset) int _file; \ unsigned int _flag; \ } *) fp) - fp_->_ptr += increment; - fp_->_cnt -= increment; + fp_->_ptr += increment; + fp_->_cnt -= increment; # else - fp->_ptr += increment; - fp->_cnt -= increment; + fp->_ptr += increment; + fp->_cnt -= increment; # endif #elif defined __UCLIBC__ /* uClibc */ # ifdef __STDIO_BUFFERS - fp->__bufpos += increment; + fp->__bufpos += increment; # else - abort (); + abort (); # endif #elif defined __QNX__ /* QNX */ - fp->_Next += increment; + fp->_Next += increment; #else #error "Please port gnulib freadseek.c to your platform! Look at the definition of getc, getc_unlocked on your system, then report this to bug-gnulib." #endif +} + +int +freadseek (FILE *fp, size_t offset) +{ + size_t total_buffered; + int fd; + + if (offset == 0) + return 0; + + /* Seek over the already read and buffered input as quickly as possible, + without doing any system calls. */ + total_buffered = freadahead (fp); + /* This loop is usually executed at most twice: once for ungetc buffer (if + present) and once for the main buffer. */ + while (total_buffered > 0) + { + size_t buffered; - offset -= increment; + if (freadptr (fp, &buffered) != NULL && buffered > 0) + { + size_t increment = (buffered < offset ? buffered : offset); + + freadptrinc (fp, increment); + offset -= increment; + if (offset == 0) + return 0; + total_buffered -= increment; + if (total_buffered == 0) + break; + } + /* Read one byte. If we were reading from the ungetc buffer, this + switches the stream back to the main buffer. */ + if (fgetc (fp) == EOF) + goto eof; + offset--; if (offset == 0) return 0; + total_buffered--; } /* Test whether the stream is seekable or not. */ @@ -93,18 +122,19 @@ freadseek (FILE *fp, size_t offset) { size_t count = (sizeof (buf) < offset ? sizeof (buf) : offset); if (fread (buf, 1, count, fp) < count) - { - if (ferror (fp)) - /* EOF, or error before or while reading. */ - return EOF; - else - /* Encountered EOF. */ - return 0; - } + goto eof; offset -= count; } while (offset > 0); return 0; } + + eof: + /* EOF, or error before or while reading. */ + if (ferror (fp)) + return EOF; + else + /* Encountered EOF. */ + return 0; } diff --git a/modules/freadseek b/modules/freadseek index c9a8555ea..899842199 100644 --- a/modules/freadseek +++ b/modules/freadseek @@ -6,10 +6,12 @@ lib/freadseek.h lib/freadseek.c Depends-on: +freadahead freadptr lseek configure.ac: +AC_REQUIRE([AC_C_INLINE]) Makefile.am: lib_SOURCES += freadseek.c -- 2.11.0