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