8949ba28fbed55db6307140024cb70f0208ffdf5
[ghc-hetmet.git] / ghc / lib / std / cbits / readFile.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: readFile.c,v 1.4 1999/05/05 10:33:16 sof Exp $
5  *
6  * hGetContents Runtime Support
7  */
8
9 #include "Rts.h"
10 #include "stgio.h"
11
12 #ifdef HAVE_WINSOCK_H
13 #include <winsock.h>
14 #endif
15
16 #define EOT 4
17
18 /* Filling up a (block-buffered) buffer, that
19    is completely empty. */
20 StgInt
21 readBlock(ptr)
22 StgForeignPtr ptr;
23 {
24     IOFileObject* fo = (IOFileObject*)ptr;
25     int count,rc=0;
26     int fd;
27
28     /* Check if someone hasn't zapped us */
29     if ( fo == NULL || fo->fd == -1 )
30        return -2;
31
32     fd = fo->fd;
33
34     if ( FILEOBJ_IS_EOF(fo) ) {
35         ghc_errtype = ERR_EOF;
36         ghc_errstr = "";
37         return -1;
38     }
39
40     /* Weird case: buffering has suddenly been turned off.
41        Return non-std value and deal with this case on the Haskell side.
42     */
43     if ( FILEOBJ_UNBUFFERED(fo) ) {
44         return -3;
45     }
46
47     /* if input stream is connect to an output stream, flush this one first. */
48     if ( fo->connectedTo != NULL   &&
49          fo->connectedTo->fd != -1 &&
50          (fo->connectedTo->flags & FILEOBJ_WRITE)
51        ) {
52        rc = flushFile((StgForeignPtr)fo->connectedTo);
53     }
54     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
55
56     /* RW object: flush the (output) buffer first. */
57     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) && FILEOBJ_NEEDS_FLUSHING(fo) ) {
58         rc = flushBuffer(ptr);
59         if (rc < 0) return rc;
60     }
61     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
62
63     /* return the unread parts of the file buffer..*/
64     if ( fo->flags & FILEOBJ_READ && 
65          fo->bufRPtr > 0          &&
66          fo->bufWPtr > fo->bufRPtr ) {
67         count = fo->bufWPtr - fo->bufRPtr;
68         fo->bufRPtr=0;
69         return count;
70     }
71
72 #if 0
73     fprintf(stderr, "rb: %d %d %d\n", fo->bufRPtr, fo->bufWPtr, fo->bufSize);
74 #endif
75
76     if ( fo->flags & FILEOBJ_NONBLOCKING_IO && inputReady (ptr,0) != 1 )
77       return FILEOBJ_BLOCKED_READ;
78
79     while ((count =
80              (
81 #ifdef HAVE_WINSOCK_H
82                fo->flags & FILEOBJ_WINSOCK ?
83                  recv(fd, fo->buf, fo->bufSize, 0) :
84                  read(fd, fo->buf, fo->bufSize))) <= 0 ) {
85 #else
86                  read(fd, fo->buf, fo->bufSize))) <= 0 ) {
87 #endif
88         if ( count == 0 ) {
89             FILEOBJ_SET_EOF(fo);
90             ghc_errtype = ERR_EOF;
91             ghc_errstr = "";
92             return -1;
93         } else if ( count == -1 && errno == EAGAIN) {
94             errno = 0;
95             return FILEOBJ_BLOCKED_READ;
96         } else if ( count == -1 && errno != EINTR) {
97             cvtErrno();
98             stdErrno();
99             return -1;
100         }
101     }
102     fo->bufWPtr = count;
103     fo->bufRPtr = 0;
104     return count;
105 }
106
107 /* Filling up a (block-buffered) buffer of length len */
108 StgInt
109 readChunk(ptr,buf,len)
110 StgForeignPtr ptr;
111 StgAddr buf;
112 StgInt len;
113 {
114     IOFileObject* fo = (IOFileObject*)ptr;
115     int count=0,rc=0, total_count;
116     int fd;
117     char* p;
118
119     /* Check if someone hasn't zapped us */
120     if ( fo == NULL )
121        return -2;
122
123     fd = fo->fd;
124
125     if ( fd == -1 ) /* File has been closed for us */
126        return -2;
127
128     if ( FILEOBJ_IS_EOF(fo) ) {
129         ghc_errtype = ERR_EOF;
130         ghc_errstr = "";
131         return -1;
132     }
133
134     /* if input stream is connect to an output stream, flush it first */
135     if ( fo->connectedTo != NULL   &&
136          fo->connectedTo->fd != -1 &&
137          (fo->connectedTo->flags & FILEOBJ_WRITE)
138        ) {
139        rc = flushFile((StgForeignPtr)fo->connectedTo);
140     }
141     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
142
143     /* RW object: flush the (output) buffer first. */
144     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) && FILEOBJ_NEEDS_FLUSHING(fo) ) {
145         rc = flushBuffer(ptr);
146         if (rc < 0) return rc;
147     }
148     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
149
150     /* copy the unread parts of the file buffer..*/
151     if ( FILEOBJ_READABLE(fo) && 
152          fo->bufRPtr > 0      &&
153          fo->bufWPtr >= fo->bufRPtr ) {
154         count = ( len < (fo->bufWPtr - fo->bufRPtr)) ? len : (fo->bufWPtr - fo->bufRPtr);
155         memcpy(buf,fo->buf, count);
156         fo->bufWPtr=0;
157         fo->bufRPtr=0;
158         
159     }
160
161     if (len - count <= 0)
162        return count;
163
164     len -= count;
165     p = buf;
166     p += count;
167     total_count = count;
168
169     if ( fo->flags & FILEOBJ_NONBLOCKING_IO && inputReady (ptr,0) != 1 )
170       return FILEOBJ_BLOCKED_READ;
171
172     while ((count =
173              (
174 #ifdef HAVE_WINSOCK_H
175                fo->flags & FILEOBJ_WINSOCK ?
176                  recv(fd, p, len, 0) :
177                  read(fd, p, len))) <= 0 ) {
178 #else
179                  read(fd, p, len))) <= 0 ) {
180 #endif
181         if ( count == 0 ) { /* EOF */
182             break;
183         } else if ( count == -1 && errno == EAGAIN) {
184             errno = 0;
185             return FILEOBJ_BLOCKED_READ;
186         } else if ( count == -1 && errno != EINTR) {
187             cvtErrno();
188             stdErrno();
189             return -1;
190         }
191         total_count += count;
192         len -= count;
193         p += count;
194     }
195
196     total_count += count;
197     fo->bufWPtr = total_count;
198     fo->bufRPtr = 0;
199     return total_count;
200 }
201
202 /*
203   readLine() tries to fill the buffer up with a line of chars, returning
204   the length of the resulting line. 
205   
206   Users of readLine() should immediately afterwards copy out the line
207   from the buffer.
208
209 */
210
211 StgInt
212 readLine(ptr)
213 StgForeignPtr ptr;
214 {
215     IOFileObject* fo = (IOFileObject*)ptr;
216     char *s;
217     int rc=0, count;
218
219     /* Check if someone hasn't zapped us */
220     if ( fo == NULL || fo->fd == -1 )
221        return -2;
222
223     if ( FILEOBJ_IS_EOF(fo) ) {
224         ghc_errtype = ERR_EOF;
225         ghc_errstr = "";
226         return -1;
227     }
228
229     /* Weird case: buffering has been turned off.
230        Return non-std value and deal with this case on the Haskell side.
231     */
232     if ( FILEOBJ_UNBUFFERED(fo) ) {
233         return -3;
234     }
235
236     /* if input stream is connect to an output stream, flush it first */
237     if ( fo->connectedTo != NULL   &&
238          fo->connectedTo->fd != -1 &&
239          (fo->connectedTo->flags & FILEOBJ_WRITE)
240        ) {
241        rc = flushFile((StgForeignPtr)fo->connectedTo);
242     }
243     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
244
245     /* RW object: flush the (output) buffer first. */
246     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) ) {
247         rc = flushBuffer(ptr);
248         if (rc < 0) return rc;
249     }
250     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
251
252     if ( fo->bufRPtr < 0 || fo->bufRPtr >= fo->bufWPtr ) { /* Buffer is empty */
253        fo->bufRPtr=0; fo->bufWPtr=0;
254        rc = fill_up_line_buffer(fo);
255        if (rc < 0) return rc;
256     }
257
258     while (1) {
259        unsigned char* s1 = memchr((unsigned char *)fo->buf+fo->bufRPtr, '\n', fo->bufWPtr - fo->bufRPtr);
260        if (s1 != NULL ) {  /* Found one */
261           /* Note: we *don't* zero terminate the line */
262           count = s1 - ((unsigned char*)fo->buf + fo->bufRPtr) + 1;
263           fo->bufRPtr += count;
264           return count;
265        } else {
266           /* Just return partial line */
267           count = fo->bufWPtr - fo->bufRPtr;
268           fo->bufRPtr += count;
269           return count;
270        }
271     }
272
273 }
274
275 StgInt
276 readChar(ptr)
277 StgForeignPtr ptr;
278 {
279     IOFileObject* fo= (IOFileObject*)ptr;
280     int count,rc=0;
281     char c;
282
283     /* Check if someone hasn't zapped us */
284     if ( fo == NULL || fo->fd == -1)
285        return -2;
286
287     if ( FILEOBJ_IS_EOF(fo) ) {
288         ghc_errtype = ERR_EOF;
289         ghc_errstr = "";
290         return -1;
291     }
292
293     /* Buffering has been changed, report back */
294     if ( FILEOBJ_LINEBUFFERED(fo) ) {
295        return -3;
296     } else if ( FILEOBJ_BLOCKBUFFERED(fo) ) {
297        return -4;
298     }
299
300     /* if input stream is connect to an output stream, flush it first */
301     if ( fo->connectedTo != NULL   &&
302          fo->connectedTo->fd != -1 &&
303          (fo->connectedTo->flags & FILEOBJ_WRITE)
304        ) {
305        rc = flushFile((StgForeignPtr)fo->connectedTo);
306     }
307     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
308
309     /* RW object: flush the (output) buffer first. */
310     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) && FILEOBJ_NEEDS_FLUSHING(fo) ) {
311         rc = flushBuffer(ptr);
312         if (rc < 0) return rc;
313     }
314     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
315
316     if ( fo->flags & FILEOBJ_NONBLOCKING_IO && inputReady (ptr,0) != 1 )
317       return FILEOBJ_BLOCKED_READ;
318
319     while ( (count = 
320                (
321 #ifdef HAVE_WINSOCK_H
322                  fo->flags & FILEOBJ_WINSOCK ?
323                  recv(fo->fd, &c, 1, 0) :
324                  read(fo->fd, &c, 1))) <= 0 ) {
325 #else
326                  read(fo->fd, &c, 1))) <= 0 ) {
327 #endif
328         if ( count == 0 ) {
329             ghc_errtype = ERR_EOF;
330             ghc_errstr = "";
331             return -1;
332         } else if ( count == -1 && errno == EAGAIN) {
333             errno = 0;
334             return FILEOBJ_BLOCKED_READ;
335         } else if ( count == -1 && errno != EINTR) {
336             cvtErrno();
337             stdErrno();
338             return -1;
339         }
340     }
341
342     if ( isatty(fo->fd) && c == EOT ) {
343         return EOF;
344     } else {
345         return (int)c;
346     }
347 }