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