Blame libio/tst-fgetc-after-eof.c

Packit 6c4009
/* Bug 1190: EOF conditions are supposed to be sticky.
Packit 6c4009
   Copyright (C) 2018 Free Software Foundation.
Packit 6c4009
   Copying and distribution of this file, with or without modification,
Packit 6c4009
   are permitted in any medium without royalty provided the copyright
Packit 6c4009
   notice and this notice are preserved. This file is offered as-is,
Packit 6c4009
   without any warranty.  */
Packit 6c4009
Packit 6c4009
/* ISO C1999 specification of fgetc:
Packit 6c4009
Packit 6c4009
       #include <stdio.h>
Packit 6c4009
       int fgetc (FILE *stream);
Packit 6c4009
Packit 6c4009
   Description
Packit 6c4009
Packit 6c4009
     If the end-of-file indicator for the input stream pointed to by
Packit 6c4009
     stream is not set and a next character is present, the fgetc
Packit 6c4009
     function obtains that character as an unsigned char converted to
Packit 6c4009
     an int and advances the associated file position indicator for
Packit 6c4009
     the stream (if defined).
Packit 6c4009
Packit 6c4009
   Returns
Packit 6c4009
Packit 6c4009
     If the end-of-file indicator for the stream is set, or if the
Packit 6c4009
     stream is at end-of-file, the end-of-file indicator for the
Packit 6c4009
     stream is set and the fgetc function returns EOF. Otherwise, the
Packit 6c4009
     fgetc function returns the next character from the input stream
Packit 6c4009
     pointed to by stream. If a read error occurs, the error indicator
Packit 6c4009
     for the stream is set and the fgetc function returns EOF.
Packit 6c4009
Packit 6c4009
   The requirement to return EOF "if the end-of-file indicator for the
Packit 6c4009
   stream is set" was new in C99; the language in the 1989 edition of
Packit 6c4009
   the standard was ambiguous.  Historically, BSD-derived Unix always
Packit 6c4009
   had the C99 behavior, whereas in System V fgetc would attempt to
Packit 6c4009
   call read() again before returning EOF again.  Prior to version 2.28,
Packit 6c4009
   glibc followed the System V behavior even though this does not
Packit 6c4009
   comply with C99.
Packit 6c4009
Packit 6c4009
   See
Packit 6c4009
   <https://sourceware.org/bugzilla/show_bug.cgi?id=1190>,
Packit 6c4009
   <https://sourceware.org/bugzilla/show_bug.cgi?id=19476>,
Packit 6c4009
   and the thread at
Packit 6c4009
   <https://sourceware.org/ml/libc-alpha/2012-09/msg00343.html>
Packit 6c4009
   for more detail.  */
Packit 6c4009
Packit 6c4009
#include <support/tty.h>
Packit 6c4009
#include <support/check.h>
Packit 6c4009
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
Packit 6c4009
#define XWRITE(fd, s, msg) do {                         \
Packit 6c4009
    if (write (fd, s, sizeof s - 1) != sizeof s - 1)    \
Packit 6c4009
      {                                                 \
Packit 6c4009
        perror ("write " msg);                          \
Packit 6c4009
        return 1;                                       \
Packit 6c4009
      }                                                 \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  /* The easiest way to set up the conditions under which you can
Packit 6c4009
     notice whether the end-of-file indicator is sticky, is with a
Packit 6c4009
     pseudo-tty.  This is also the case which applications are most
Packit 6c4009
     likely to care about.  And it avoids any question of whether and
Packit 6c4009
     how it is legitimate to access the same physical file with two
Packit 6c4009
     independent FILE objects.  */
Packit 6c4009
  int outer_fd, inner_fd;
Packit 6c4009
  FILE *fp;
Packit 6c4009
Packit 6c4009
  support_openpty (&outer_fd, &inner_fd, 0, 0, 0);
Packit 6c4009
  fp = fdopen (inner_fd, "r+");
Packit 6c4009
  if (!fp)
Packit 6c4009
    {
Packit 6c4009
      perror ("fdopen");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  XWRITE (outer_fd, "abc\n\004", "first line + EOF");
Packit 6c4009
  TEST_COMPARE (fgetc (fp), 'a');
Packit 6c4009
  TEST_COMPARE (fgetc (fp), 'b');
Packit 6c4009
  TEST_COMPARE (fgetc (fp), 'c');
Packit 6c4009
  TEST_COMPARE (fgetc (fp), '\n');
Packit 6c4009
  TEST_COMPARE (fgetc (fp), EOF);
Packit 6c4009
Packit 6c4009
  TEST_VERIFY_EXIT (feof (fp));
Packit 6c4009
  TEST_VERIFY_EXIT (!ferror (fp));
Packit 6c4009
Packit 6c4009
  XWRITE (outer_fd, "d\n", "second line");
Packit 6c4009
Packit 6c4009
  /* At this point, there is a new full line of input waiting in the
Packit 6c4009
     kernelside input buffer, but we should still observe EOF from
Packit 6c4009
     stdio, because the end-of-file indicator has not been cleared.  */
Packit 6c4009
  TEST_COMPARE (fgetc (fp), EOF);
Packit 6c4009
Packit 6c4009
  /* Clearing EOF should reveal the next line of input.  */
Packit 6c4009
  clearerr (fp);
Packit 6c4009
  TEST_COMPARE (fgetc (fp), 'd');
Packit 6c4009
  TEST_COMPARE (fgetc (fp), '\n');
Packit 6c4009
Packit 6c4009
  fclose (fp);
Packit 6c4009
  close (outer_fd);
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#include <support/test-driver.c>