8c3be1437d7484df95445bd32db68e0de63545e1
[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.9 1999/12/08 15:47:08 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     int rc=0, count;
215
216     /* Check if someone hasn't zapped us */
217     if ( fo == NULL || fo->fd == -1 )
218        return -2;
219
220     if ( FILEOBJ_IS_EOF(fo) ) {
221         ghc_errtype = ERR_EOF;
222         ghc_errstr = "";
223         return -1;
224     }
225
226     /* Weird case: buffering has been turned off.
227        Return non-std value and deal with this case on the Haskell side.
228     */
229     if ( FILEOBJ_UNBUFFERED(fo) ) {
230         return -3;
231     }
232
233     /* if input stream is connect to an output stream, flush it first */
234     if ( fo->connectedTo != NULL   &&
235          fo->connectedTo->fd != -1 &&
236          (fo->connectedTo->flags & FILEOBJ_WRITE)
237        ) {
238        rc = flushFile((StgForeignPtr)fo->connectedTo);
239     }
240     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
241
242     /* RW object: flush the (output) buffer first. */
243     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) ) {
244         rc = flushBuffer(ptr);
245         if (rc < 0) return rc;
246     }
247     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
248
249     if ( fo->bufRPtr < 0 || fo->bufRPtr >= fo->bufWPtr ) { /* Buffer is empty */
250        fo->bufRPtr=0; fo->bufWPtr=0;
251        rc = fill_up_line_buffer(fo);
252        if (rc < 0) return rc;
253     }
254
255     while (1) {
256        unsigned char* s1 = memchr((unsigned char *)fo->buf+fo->bufRPtr, '\n', fo->bufWPtr - fo->bufRPtr);
257        if (s1 != NULL ) {  /* Found one */
258           /* Note: we *don't* zero terminate the line */
259           count = s1 - ((unsigned char*)fo->buf + fo->bufRPtr) + 1;
260           fo->bufRPtr += count;
261           return count;
262        } else {
263           /* Just return partial line */
264           count = fo->bufWPtr - fo->bufRPtr;
265           fo->bufRPtr += count;
266           return count;
267        }
268     }
269
270 }
271
272 StgInt
273 readChar(ptr)
274 StgForeignPtr ptr;
275 {
276     IOFileObject* fo= (IOFileObject*)ptr;
277     int count,rc=0;
278     unsigned char c;
279
280     /* Check if someone hasn't zapped us */
281     if ( fo == NULL || fo->fd == -1)
282        return -2;
283
284     if ( FILEOBJ_IS_EOF(fo) ) {
285         ghc_errtype = ERR_EOF;
286         ghc_errstr = "";
287         return -1;
288     }
289
290     /* Buffering has been changed, report back */
291     if ( FILEOBJ_LINEBUFFERED(fo) ) {
292        return -3;
293     } else if ( FILEOBJ_BLOCKBUFFERED(fo) ) {
294        return -4;
295     }
296
297     /* if input stream is connect to an output stream, flush it first */
298     if ( fo->connectedTo != NULL   &&
299          fo->connectedTo->fd != -1 &&
300          (fo->connectedTo->flags & FILEOBJ_WRITE)
301        ) {
302        rc = flushFile((StgForeignPtr)fo->connectedTo);
303     }
304     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
305
306     /* RW object: flush the (output) buffer first. */
307     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) && FILEOBJ_NEEDS_FLUSHING(fo) ) {
308         rc = flushBuffer(ptr);
309         if (rc < 0) return rc;
310     }
311     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
312
313     while ( (count = 
314                (
315 #ifdef USE_WINSOCK
316                  fo->flags & FILEOBJ_WINSOCK ?
317                  recv(fo->fd, &c, 1, 0) :
318                  read(fo->fd, &c, 1))) <= 0 ) {
319 #else
320                  read(fo->fd, &c, 1))) <= 0 ) {
321 #endif
322         if ( count == 0 ) {
323             ghc_errtype = ERR_EOF;
324             ghc_errstr = "";
325             return -1;
326         } else if ( count == -1 && errno == EAGAIN) {
327             errno = 0;
328             return FILEOBJ_BLOCKED_READ;
329         } else if ( count == -1 && errno != EINTR) {
330             cvtErrno();
331             stdErrno();
332             return -1;
333         }
334     }
335
336     if ( isatty(fo->fd) && c == EOT ) {
337         return EOF;
338     } else {
339         return (int)c;
340     }
341 }