@@ -380,8 +380,8 @@ void StreamCursor::backup(T_sp strm, claspCharacter c) {
380380const FileOps &duplicate_dispatch_table (const FileOps &ops);
381381const FileOps &stream_dispatch_table (T_sp strm);
382382
383- static int flisten (T_sp, FILE *);
384- static int file_listen (T_sp, int );
383+ static int file_listen (T_sp, FILE *);
384+ static int fd_listen (T_sp, int );
385385
386386// static T_sp alloc_stream();
387387
@@ -2782,7 +2782,7 @@ static int io_file_listen(T_sp strm) {
27822782 }
27832783 }
27842784 }
2785- return file_listen (strm, IOFileStreamDescriptor (strm));
2785+ return fd_listen (strm, IOFileStreamDescriptor (strm));
27862786}
27872787
27882788#if defined(CLASP_MS_WINDOWS_HOST)
@@ -2804,7 +2804,7 @@ static void io_file_clear_input(T_sp strm) {
28042804 /* Do not stop here: the FILE structure needs also to be flushed */
28052805 }
28062806#endif
2807- while (file_listen (strm, f) == CLASP_LISTEN_AVAILABLE) {
2807+ while (fd_listen (strm, f) == CLASP_LISTEN_AVAILABLE) {
28082808 claspCharacter c = eformat_read_char (strm);
28092809 if (c == EOF)
28102810 return ;
@@ -3612,7 +3612,7 @@ static cl_index io_stream_read_byte8(T_sp strm, unsigned char *c, cl_index n) {
36123612static int io_stream_listen (T_sp strm) {
36133613 if (StreamByteStack (strm).notnilp ()) // != nil<T_O>())
36143614 return CLASP_LISTEN_AVAILABLE;
3615- return flisten (strm, IOStreamStreamFile (strm));
3615+ return file_listen (strm, IOStreamStreamFile (strm));
36163616}
36173617
36183618static void io_stream_clear_input (T_sp strm) {
@@ -3625,7 +3625,7 @@ static void io_stream_clear_input(T_sp strm) {
36253625 /* Do not stop here: the FILE structure needs also to be flushed */
36263626 }
36273627#endif
3628- while (flisten (strm, fp) == CLASP_LISTEN_AVAILABLE) {
3628+ while (file_listen (strm, fp) == CLASP_LISTEN_AVAILABLE) {
36293629 clasp_disable_interrupts ();
36303630 getc (fp);
36313631 clasp_enable_interrupts ();
@@ -5054,60 +5054,8 @@ CL_DEFUN T_sp cl__close(T_sp strm, T_sp abort) { return core__closeSTAR(strm, ab
50545054 * BACKEND
50555055 */
50565056
5057- static int file_listen (T_sp stream, int fileno) {
5058- #if !defined(CLASP_MS_WINDOWS_HOST)
5059- #if defined(HAVE_POLL)
5060- struct pollfd fds[1 ];
5061- int retv;
5062- fds[0 ].fd = fileno;
5063- fds[0 ].events = POLLIN;
5064- fds[0 ].revents = 0 ;
5065- retv = poll (fds, 1 , 0 );
5066- if (UNLIKELY (retv < 0 ))
5067- file_libc_error (core::_sym_simpleStreamError, stream, " Error while listening to stream." , 0 );
5068- else if (retv > 0 )
5069- // POLLIN just means there's data, so that's fine.
5070- if (fds[0 ].revents & POLLIN) {
5071- return CLASP_LISTEN_AVAILABLE;
5072- } else if (fds[0 ].revents & ~POLLHUP) { // error or something.
5073- SIMPLE_ERROR ((" Illegal revents value from poll -> %d%s%s%s%s%s%s" ), fds[0 ].revents ,
5074- (fds[0 ].revents & POLLPRI) ? " POLLPRI" : " " , (fds[0 ].revents & POLLOUT) ? " POLLOUT" : " " ,
5075- (fds[0 ].revents & POLLOUT) ? " POLLRDHUP" : " " , (fds[0 ].revents & POLLERR) ? " POLLERR" : " " ,
5076- (fds[0 ].revents & POLLHUP) ? " POLLHUP" : " " , (fds[0 ].revents & POLLNVAL) ? " POLLNVAL" : " " );
5077- } else {
5078- // POLLHUP just means the other end hung up, which is kind of interesting
5079- // but is not an error. Useful when the stream is a process output or something.
5080- return CLASP_LISTEN_NO_CHAR;
5081- }
5082- else
5083- return CLASP_LISTEN_NO_CHAR;
5084- #elif defined(HAVE_SELECT)
5085- fd_set fds;
5086- int retv;
5087- struct timeval tv = {0 , 0 };
5088- /*
5089- * Note that the following code is fragile. If the file is closed (/dev/null)
5090- * then select() may return 1 (at least on OS X), so that we return a flag
5091- * saying characters are available but will find none to read. See also the
5092- * code in cl_clear_input().
5093- */
5094- FD_ZERO (&fds);
5095- FD_SET (fileno, &fds);
5096- retv = select (fileno + 1 , &fds, NULL , NULL , &tv);
5097- if (UNLIKELY (retv < 0 ))
5098- file_libc_error (core::_sym_simpleStreamError, stream, " Error while listening to stream." , 0 );
5099- else if (retv > 0 )
5100- return CLASP_LISTEN_AVAILABLE;
5101- else
5102- return CLASP_LISTEN_NO_CHAR;
5103- #elif defined(FIONREAD)
5104- {
5105- long c = 0 ;
5106- ioctl (fileno, FIONREAD, &c);
5107- return (c > 0 ) ? CLASP_LISTEN_AVAILABLE : CLASP_LISTEN_NO_CHAR;
5108- }
5109- #endif /* FIONREAD */
5110- #else
5057+ static int fd_listen (T_sp stream, int fileno) {
5058+ #ifdef CLASP_MS_WINDOWS_HOST
51115059 HANDLE hnd = (HANDLE)_get_osfhandle (fileno);
51125060 switch (GetFileType (hnd)) {
51135061 case FILE_TYPE_CHAR: {
@@ -5152,11 +5100,88 @@ static int file_listen(T_sp stream, int fileno) {
51525100 FEerror (" Unsupported Windows file type: ~A" , 1 , make_fixnum (GetFileType (hnd)).raw_ ());
51535101 break ;
51545102 }
5103+ #else
5104+ /* Method 1: poll, see POLL(2)
5105+ Method 2: select, see SELECT(2)
5106+ Method 3: ioctl FIONREAD, see FILIO(4)
5107+ Method 4: read a byte. Use non-blocking I/O if poll or select were not
5108+ available. */
5109+ int result;
5110+ #if defined(HAVE_POLL)
5111+ struct pollfd fd = {fileno, POLLIN, 0 };
5112+ restart_poll:
5113+ result = poll (&fd, 1 , 0 );
5114+ if (UNLIKELY (result < 0 )) {
5115+ if (errno == EINTR)
5116+ goto restart_poll;
5117+ goto listen_error;
5118+ }
5119+ if (fd.revents == 0 ) {
5120+ return CLASP_LISTEN_NO_CHAR;
5121+ }
5122+ /* When read() returns a result without blocking, this can also be
5123+ EOF! (Example: Linux and pipes.) We therefore refrain from simply
5124+ doing { return CLASP_LISTEN_AVAILABLE; } and instead try methods
5125+ 3 and 4. */
5126+ #elif defined(HAVE_SELECT)
5127+ fd_set fds;
5128+ struct timeval tv = {0 , 0 };
5129+ FD_ZERO (&fds);
5130+ FD_SET (fileno, &fds);
5131+ restart_select:
5132+ result = select (fileno + 1 , &fds, NULL , NULL , &tv);
5133+ if (UNLIKELY (result < 0 )) {
5134+ if (errno == EINTR)
5135+ goto restart_select;
5136+ if (errno != EBADF) /* UNIX_LINUX returns EBADF for files! */
5137+ goto listen_error;
5138+ } else if (result == 0 ) {
5139+ return CLASP_LISTEN_NO_CHAR;
5140+ }
5141+ #endif
5142+ #ifdef FIONREAD
5143+ long c = 0 ;
5144+ if (ioctl (fileno, FIONREAD, &c) < 0 ) {
5145+ if (!((errno == ENOTTY) || IS_EINVAL))
5146+ goto listen_error;
5147+ return (c > 0 ) ? CLASP_LISTEN_AVAILABLE : CLASP_LISTEN_EOF;
5148+ }
5149+ #endif
5150+ #if !defined(HAVE_POLL) && !defined(HAVE_SELECT)
5151+ int flags = fcntl (fd, F_GETFL, 0 );
5152+ #endif
5153+ int read_errno;
5154+ cl_index b;
5155+ restart_read:
5156+ #if !defined(HAVE_POLL) && !defined(HAVE_SELECT)
5157+ fcntl (fd, F_SETFL, flags | O_NONBLOCK);
5158+ #endif
5159+ result = read (fileno, &b, 1 );
5160+ read_errno = errno;
5161+ #if !defined(HAVE_POLL) && !defined(HAVE_SELECT)
5162+ fcntl (fd, F_SETFL, flags);
5163+ #endif
5164+ if (result < 0 ) {
5165+ if (read_errno == EINTR)
5166+ goto restart_read;
5167+ if (read_errno == EAGAIN || read_errno == EWOULDBLOCK)
5168+ return CLASP_LISTEN_NO_CHAR;
5169+ goto listen_error;
5170+ }
5171+
5172+ if (result == 0 ) {
5173+ return CLASP_LISTEN_EOF;
5174+ }
5175+
5176+ StreamByteStack (stream) = Cons_O::createList (make_fixnum (b));
5177+ return CLASP_LISTEN_AVAILABLE;
5178+ listen_error:
5179+ file_libc_error (core::_sym_simpleStreamError, stream, " Error while listening to stream." , 0 );
51555180#endif
5156- return - 3 ;
5181+ return CLASP_LISTEN_UNKNOWN ;
51575182}
51585183
5159- static int flisten (T_sp stream, FILE *fp) {
5184+ static int file_listen (T_sp stream, FILE *fp) {
51605185 ASSERT (stream.notnilp ());
51615186 int aux;
51625187 if (feof (fp))
@@ -5165,8 +5190,8 @@ static int flisten(T_sp stream, FILE *fp) {
51655190 if (FILE_CNT (fp) > 0 )
51665191 return CLASP_LISTEN_AVAILABLE;
51675192#endif
5168- aux = file_listen (stream, fileno (fp));
5169- if (aux != - 3 )
5193+ aux = fd_listen (stream, fileno (fp));
5194+ if (aux != CLASP_LISTEN_UNKNOWN )
51705195 return aux;
51715196 /* This code is portable, and implements the expected behavior for regular files.
51725197 It will fail on noninteractive streams. */
0 commit comments