[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: closein, freadahead and ungetc
From: |
Bruno Haible |
Subject: |
Re: closein, freadahead and ungetc |
Date: |
Mon, 10 Mar 2008 00:22:49 +0100 |
User-agent: |
KMail/1.5.4 |
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 <address@hidden>
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 <address@hidden>, 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