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