f539110f19a8793a11c3c9d8618d5b4d54d74d44
[haskell-directory.git] / cbits / inputReady.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-2002
3  *
4  * hWaitForInput Runtime Support
5  */
6
7 /* select and supporting types is not Posix */
8 /* #include "PosixSource.h" */
9 #include "HsBase.h"
10
11 /*
12  * inputReady(fd) checks to see whether input is available on the file
13  * descriptor 'fd'.  Input meaning 'can I safely read at least a
14  * *character* from this file object without blocking?'
15  */
16 int
17 fdReady(int fd, int write, int msecs, int isSock)
18 {
19     if 
20 #if defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32)
21     ( isSock ) {
22 #else
23     ( 1 ) {
24 #endif
25         int maxfd, ready;
26         fd_set rfd, wfd;
27         struct timeval tv;
28         
29         FD_ZERO(&rfd);
30         FD_ZERO(&wfd);
31         if (write) {
32             FD_SET(fd, &wfd);
33         } else {
34             FD_SET(fd, &rfd);
35         }
36         
37         /* select() will consider the descriptor set in the range of 0 to
38          * (maxfd-1) 
39          */
40         maxfd = fd + 1;
41         tv.tv_sec  = msecs / 1000;
42         tv.tv_usec = (msecs % 1000) * 1000;
43         
44         while ((ready = select(maxfd, &rfd, &wfd, NULL, &tv)) < 0 ) {
45             if (errno != EINTR ) {
46                 return -1;
47             }
48         }
49         
50         /* 1 => Input ready, 0 => not ready, -1 => error */
51         return (ready);
52     }
53 #if defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32)
54     else {
55         DWORD rc;
56         HANDLE hFile = (HANDLE)_get_osfhandle(fd);
57         DWORD avail;
58
59         // WaitForMultipleObjects() works for Console input, but it
60         // doesn't work for pipes (it always returns WAIT_OBJECT_0
61         // even when no data is available).  There doesn't seem to be
62         // an easy way to distinguish the two kinds of HANDLE, so we
63         // try to detect pipe input first, and if that fails we try
64         // WaitForMultipleObjects().
65         //
66         rc = PeekNamedPipe( hFile, NULL, 0, NULL, &avail, NULL );
67         if (rc != 0) {
68             if (avail != 0) {
69                 return 1;
70             } else {
71                 return 0;
72             }
73         } else {
74             rc = GetLastError();
75             if (rc == ERROR_BROKEN_PIPE) {
76                 return 1; // this is probably what we want
77             }
78             if (rc != ERROR_INVALID_HANDLE) {
79                 return -1;
80             }
81         }
82
83         rc = WaitForMultipleObjects( 1,
84                                      &hFile,
85                                      TRUE,   /* wait all */
86                                      msecs); /*millisecs*/
87         
88         /* 1 => Input ready, 0 => not ready, -1 => error */
89         switch (rc) {
90         case WAIT_TIMEOUT: return 0;
91         case WAIT_OBJECT_0: return 1;
92         default: return -1;
93         }
94     }
95 #endif
96 }