]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - lib/sh/input_avail.c
bash-5.1 distribution sources and documentation
[thirdparty/bash.git] / lib / sh / input_avail.c
index ac157a9f7412d1135a66604ace02551e9c95bb6f..695165fdcd0d99e2ad5dbe7ec40ee779ec5e985e 100644 (file)
@@ -1,7 +1,7 @@
 /* input_avail.c -- check whether or not data is available for reading on a
                    specified file descriptor. */
 
-/* Copyright (C) 2008,2009 Free Software Foundation, Inc.
+/* Copyright (C) 2008,2009-2019 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
 #  include <sys/file.h>
 #endif /* HAVE_SYS_FILE_H */
 
+#if defined (HAVE_PSELECT)
+#  include <signal.h>
+#endif
+
 #if defined (HAVE_UNISTD_H)
 #  include <unistd.h>
 #endif /* HAVE_UNISTD_H */
@@ -82,10 +86,8 @@ input_avail (fd)
   timeout.tv_usec = 0;
   result = select (fd + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout);
   return ((result <= 0) ? 0 : 1);
-
 #endif
 
-  result = -1;
 #if defined (FIONREAD)
   errno = 0;
   result = ioctl (fd, FIONREAD, &chars_avail);
@@ -96,3 +98,68 @@ input_avail (fd)
 
   return 0;
 }
+
+/* Wait until NCHARS are available for reading on file descriptor FD.
+   This can wait indefinitely. Return -1 on error. */
+int
+nchars_avail (fd, nchars)
+     int fd;
+     int nchars;
+{
+  int result, chars_avail;
+#if defined(HAVE_SELECT)
+  fd_set readfds, exceptfds;
+#endif
+#if defined (HAVE_PSELECT)
+  sigset_t set, oset;
+#endif
+
+  if (fd < 0 || nchars < 0)
+    return -1;
+  if (nchars == 0)
+    return (input_avail (fd));
+
+  chars_avail = 0;
+
+#if defined (HAVE_SELECT)
+  FD_ZERO (&readfds);
+  FD_ZERO (&exceptfds);
+  FD_SET (fd, &readfds);
+  FD_SET (fd, &exceptfds);
+#endif
+#if defined (HAVE_SELECT) || defined (HAVE_PSELECT)
+  sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set);
+#  ifdef SIGCHLD
+  sigaddset (&set, SIGCHLD);
+#  endif
+  sigemptyset (&oset);
+#endif
+
+  while (1)
+    {
+      result = 0;
+#if defined (HAVE_PSELECT)
+      /* XXX - use pselect(2) to block SIGCHLD atomically */
+      result = pselect (fd + 1, &readfds, (fd_set *)NULL, &exceptfds, (struct timespec *)NULL, &set);
+#elif defined (HAVE_SELECT)
+      sigprocmask (SIG_BLOCK, &set, &oset);
+      result = select (fd + 1, &readfds, (fd_set *)NULL, &exceptfds, (struct timeval *)NULL);
+      sigprocmask (SIG_BLOCK, &oset, (sigset_t *)NULL);
+#endif
+      if (result < 0)
+        return -1;
+
+#if defined (FIONREAD)
+      errno = 0;
+      result = ioctl (fd, FIONREAD, &chars_avail);
+      if (result == -1 && errno == EIO)
+        return -1;
+      if (chars_avail >= nchars)
+        break;
+#else
+      break;
+#endif
+    }
+
+  return 0;
+}