Eric Blake wrote: > | - freadptr is changed to also return the size of the buffer. > | extern const char * freadptr (FILE *stream, size_t *sizep); > | When the return value is non-NULL, *sizep is set to the size of the > | buffer whose address is the return value. > > Sounds fine to me.
Here is the first part, the extended freadptr API. 2008-03-09 Bruno Haible <[EMAIL PROTECTED]> Extend freadptr to return also the buffer size. * lib/freadptr.h (freadptr): Add sizep argument. * lib/freadptr.c: Include freadptr.h, not freadahead.h. (freadptr): Add sizep argument. Determine buffer size like freadahead does. * tests/test-freadptr.c: Don't include freadahead.h. (main): Adapt for new calling convention of freadptr. * tests/test-freadptr2.c: New file, based on tests/test-freadahead.c. * tests/test-freadptr2.sh: New file, based on tests/test-freadahead.sh. * modules/freadptr-tests (Files): Add tests/test-freadptr2.c, tests/test-freadptr2.sh. (Depends): Remove freadahead. (TESTS): Add test-freadptr2.sh. (check_PROGRAMS): Add test-freadptr2. *** lib/freadptr.h.orig 2008-03-10 00:14:43.000000000 +0100 --- lib/freadptr.h 2008-03-09 23:10:57.000000000 +0100 *************** *** 22,40 **** #endif /* Assuming the stream STREAM is open for reading: ! Return a pointer to the input buffer of STREAM. ! If freadahead (STREAM) > 0, the result is either a pointer to ! freadahead (STREAM) bytes, or NULL. The latter case can happen after ! use of 'ungetc (..., STREAM)'. ! If freadahead (STREAM) == 0, the result is not usable; it may be NULL. ! In this case, you should use getc (STREAM), fgetc (STREAM), or ! fread (..., STREAM) to access the input from STREAM. The resulting pointer becomes invalid upon any operation on STREAM. STREAM must not be wide-character oriented. */ ! extern const char * freadptr (FILE *stream); #ifdef __cplusplus } --- 22,38 ---- #endif /* Assuming the stream STREAM is open for reading: ! Return a pointer to the input buffer of STREAM, or NULL. ! If the returned pointer is non-NULL, *SIZEP is set to the (positive) size ! of the input buffer. ! If the returned pointer is NULL, you should use getc (STREAM), ! fgetc (STREAM), or fread (..., STREAM) to access the input from STREAM. The resulting pointer becomes invalid upon any operation on STREAM. STREAM must not be wide-character oriented. */ ! extern const char * freadptr (FILE *stream, size_t *sizep); #ifdef __cplusplus } *** lib/freadptr.c.orig 2008-03-10 00:14:43.000000000 +0100 --- lib/freadptr.c 2008-03-10 00:11:51.000000000 +0100 *************** *** 17,31 **** #include <config.h> /* Specification. */ ! #include "freadahead.h" const char * ! freadptr (FILE *fp) { /* Keep this code in sync with freadahead! */ #if defined _IO_ferror_unlocked /* GNU libc, BeOS */ return (const char *) fp->_IO_read_ptr; #elif defined __sferror /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */ return (const char *) fp->_p; #elif defined _IOERR /* AIX, HP-UX, IRIX, OSF/1, Solaris, mingw */ # if defined __sun && defined _LP64 /* Solaris/{SPARC,AMD64} 64-bit */ --- 17,45 ---- #include <config.h> /* Specification. */ ! #include "freadptr.h" const char * ! freadptr (FILE *fp, size_t *sizep) { + size_t size; + /* Keep this code in sync with freadahead! */ #if defined _IO_ferror_unlocked /* GNU libc, BeOS */ + if (fp->_IO_write_ptr > fp->_IO_write_base) + return NULL; + size = fp->_IO_read_end - fp->_IO_read_ptr; + if (size == 0) + return NULL; + *sizep = size; return (const char *) fp->_IO_read_ptr; #elif defined __sferror /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */ + if ((fp->_flags & __SWR) != 0 || fp->_r < 0) + return NULL; + size = fp->_r; + if (size == 0) + return NULL; + *sizep = size; return (const char *) fp->_p; #elif defined _IOERR /* AIX, HP-UX, IRIX, OSF/1, Solaris, mingw */ # if defined __sun && defined _LP64 /* Solaris/{SPARC,AMD64} 64-bit */ *************** *** 36,54 **** int _file; \ unsigned int _flag; \ } *) fp) return (const char *) fp_->_ptr; # else return (const char *) fp->_ptr; # endif #elif defined __UCLIBC__ /* uClibc */ # ifdef __STDIO_BUFFERS return (const char *) fp->__bufpos; # else return NULL; # endif #elif defined __QNX__ /* QNX */ return (const char *) fp->_Next; #else ! #error "Please port gnulib freadptr.c to your platform! Look at the definition of getc, getc_unlocked on your system, then report this to bug-gnulib." #endif } --- 50,93 ---- int _file; \ unsigned int _flag; \ } *) fp) + if ((fp_->_flag & _IOWRT) != 0) + return NULL; + size = fp_->_cnt; + if (size == 0) + return NULL; + *sizep = size; return (const char *) fp_->_ptr; # else + if ((fp->_flag & _IOWRT) != 0) + return NULL; + size = fp->_cnt; + if (size == 0) + return NULL; + *sizep = size; return (const char *) fp->_ptr; # endif #elif defined __UCLIBC__ /* uClibc */ # ifdef __STDIO_BUFFERS + if (fp->__modeflags & __FLAG_WRITING) + return NULL; + size = fp->__bufread - fp->__bufpos; + if (size == 0) + return NULL; + *sizep = size; return (const char *) fp->__bufpos; # else return NULL; # endif #elif defined __QNX__ /* QNX */ + if ((fp->_Mode & 0x2000 /* _MWRITE */) != 0) + return NULL; + /* fp->_Buf <= fp->_Next <= fp->_Rend */ + size = fp->_Rend - fp->_Next; + if (size == 0) + return NULL; + *sizep = size; return (const char *) fp->_Next; #else ! #error "Please port gnulib freadptr.c to your platform! Look at the definition of fflush, fread, getc, getc_unlocked on your system, then report this to bug-gnulib." #endif } *** tests/test-freadptr.c.orig 2008-03-10 00:14:43.000000000 +0100 --- tests/test-freadptr.c 2008-03-09 23:26:37.000000000 +0100 *************** *** 25,32 **** #include <string.h> #include <unistd.h> - #include "freadahead.h" - #define ASSERT(expr) \ do \ { \ --- 25,30 ---- *************** *** 46,125 **** ASSERT (fread (buf, 1, nbytes, stdin) == nbytes); if (lseek (0, 0, SEEK_CUR) == nbytes) ! /* An unbuffered stdio, such as BeOS or on uClibc compiled without ! __STDIO_BUFFERS. Or stdin is a pipe. */ ! ASSERT (freadahead (stdin) == 0); else { /* Normal buffered stdio. */ const char stdin_contents[] = "#!/bin/sh\n\n./test-freadptr${EXEEXT} 5 < \"$srcdir/test-freadptr.sh\" || exit 1\ncat \"$srcdir/test-freadptr.sh\" | ./test-freadptr${EXEEXT} 5 || exit 1\nexit 0\n"; const char *expected = stdin_contents + nbytes; ! size_t available; size_t available2; size_t available3; /* Test normal behaviour. */ - available = freadahead (stdin); - ASSERT (available != 0); - ASSERT (available <= strlen (expected)); { ! const char *ptr = freadptr (stdin); ASSERT (ptr != NULL); ! ASSERT (memcmp (ptr, expected, available) == 0); } /* Test behaviour after normal ungetc. */ ungetc (fgetc (stdin), stdin); ! available2 = freadahead (stdin); ! ASSERT (/* available2 == available - 1 || */ available2 == available); ! #if 0 ! if (available2 == available - 1) ! { ! ASSERT (freadptr (stdin) == NULL); ! } ! else ! #endif ! { ! const char *ptr = freadptr (stdin); ! ! ASSERT (ptr != NULL); ! ASSERT (memcmp (ptr, expected, available) == 0); ! } /* Test behaviour after arbitrary ungetc. */ fgetc (stdin); ungetc ('@', stdin); ! available3 = freadahead (stdin); ! ASSERT (available3 == 0 || available3 == 1 || /* available3 == available - 1 || */ available3 == available); ! if (available3 == 0) ! ; ! else if (available3 == 1) ! { ! const char *ptr = freadptr (stdin); ! ! if (ptr != NULL) ! { ! ASSERT (ptr[0] == '@'); ! } ! } ! #if 0 ! else if (available3 == available - 1) ! { ! ASSERT (freadptr (stdin) == NULL); ! } ! #endif ! else ! { ! const char *ptr = freadptr (stdin); ! ! if (ptr != NULL) ! { ! ASSERT (ptr[0] == '@'); ! ASSERT (memcmp (ptr + 1, expected + 1, available - 1) == 0); ! } ! } } return 0; --- 44,103 ---- ASSERT (fread (buf, 1, nbytes, stdin) == nbytes); if (lseek (0, 0, SEEK_CUR) == nbytes) ! { ! /* An unbuffered stdio, such as BeOS or on uClibc compiled without ! __STDIO_BUFFERS. Or stdin is a pipe. */ ! size_t size; ! ASSERT (freadptr (stdin, &size) == NULL); ! } else { /* Normal buffered stdio. */ const char stdin_contents[] = "#!/bin/sh\n\n./test-freadptr${EXEEXT} 5 < \"$srcdir/test-freadptr.sh\" || exit 1\ncat \"$srcdir/test-freadptr.sh\" | ./test-freadptr${EXEEXT} 5 || exit 1\nexit 0\n"; const char *expected = stdin_contents + nbytes; ! size_t available1; size_t available2; size_t available3; /* Test normal behaviour. */ { ! const char *ptr = freadptr (stdin, &available1); ASSERT (ptr != NULL); ! ASSERT (available1 != 0); ! ASSERT (available1 <= strlen (expected)); ! ASSERT (memcmp (ptr, expected, available1) == 0); } /* Test behaviour after normal ungetc. */ ungetc (fgetc (stdin), stdin); ! { ! const char *ptr = freadptr (stdin, &available2); ! ! if (ptr != NULL) ! { ! ASSERT (available2 == available1); ! ASSERT (memcmp (ptr, expected, available2) == 0); ! } ! } /* Test behaviour after arbitrary ungetc. */ fgetc (stdin); ungetc ('@', stdin); ! { ! const char *ptr = freadptr (stdin, &available3); ! ! if (ptr != NULL) ! { ! ASSERT (available3 == 1 || available3 == available1); ! ASSERT (ptr[0] == '@'); ! if (available3 > 1) ! { ! ASSERT (memcmp (ptr + 1, expected + 1, available3 - 1) == 0); ! } ! } ! } } return 0; *** modules/freadptr-tests.orig 2008-03-10 00:14:43.000000000 +0100 --- modules/freadptr-tests 2008-03-09 23:17:39.000000000 +0100 *************** *** 1,15 **** Files: tests/test-freadptr.c tests/test-freadptr.sh Depends-on: lseek - freadahead unistd configure.ac: Makefile.am: ! TESTS += test-freadptr.sh TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' srcdir='$(srcdir)' ! check_PROGRAMS += test-freadptr --- 1,16 ---- Files: tests/test-freadptr.c tests/test-freadptr.sh + tests/test-freadptr2.c + tests/test-freadptr2.sh Depends-on: lseek unistd configure.ac: Makefile.am: ! TESTS += test-freadptr.sh test-freadptr2.sh TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' srcdir='$(srcdir)' ! check_PROGRAMS += test-freadptr test-freadptr2 ======================== tests/test-freadptr2.c ============================== /* Test of freadptr() function. Copyright (C) 2007-2008 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* Written by Bruno Haible <[EMAIL PROTECTED]>, 2007. */ #include <config.h> #include "freadptr.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define ASSERT(expr) \ do \ { \ if (!(expr)) \ { \ fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ abort (); \ } \ } \ while (0) static int freadptrbufsize (FILE *fp) { size_t size = 0; freadptr (fp, &size); return size; } int main (int argc, char **argv) { int nbytes = atoi (argv[1]); if (nbytes > 0) { void *buf = malloc (nbytes); ASSERT (fread (buf, 1, nbytes, stdin) == nbytes); } if (nbytes == 0) ASSERT (freadptrbufsize (stdin) == 0); else { if (lseek (0, 0, SEEK_CUR) == nbytes) /* An unbuffered stdio, such as BeOS or on uClibc compiled without __STDIO_BUFFERS. */ ASSERT (freadptrbufsize (stdin) == 0); else /* Normal buffered stdio. */ ASSERT (freadptrbufsize (stdin) != 0); } return 0; } ======================== tests/test-freadptr2.sh ============================= #!/bin/sh ./test-freadptr2${EXEEXT} 0 < "$srcdir/test-freadptr2.sh" || exit 1 ./test-freadptr2${EXEEXT} 5 < "$srcdir/test-freadptr2.sh" || exit 1 exit 0