[project @ 2000-01-18 12:42:12 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.10 2000/01/18 12:42:12 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(StgForeignPtr ptr)
26 {
27     IOFileObject* fo = (IOFileObject*)ptr;
28     int count,rc=0;
29     int fd;
30
31     /* Check if someone hasn't zapped us */
32     if ( fo == NULL || fo->fd == -1 )
33        return -2;
34
35     fd = fo->fd;
36
37     if ( FILEOBJ_IS_EOF(fo) ) {
38         ghc_errtype = ERR_EOF;
39         ghc_errstr = "";
40         return -1;
41     }
42
43     /* Weird case: buffering has suddenly been turned off.
44        Return non-std value and deal with this case on the Haskell side.
45     */
46     if ( FILEOBJ_UNBUFFERED(fo) ) {
47         return -3;
48     }
49
50     /* if input stream is connect to an output stream, flush this one first. */
51     if ( fo->connectedTo != NULL   &&
52          fo->connectedTo->fd != -1 &&
53          (fo->connectedTo->flags & FILEOBJ_WRITE)
54        ) {
55        rc = flushFile((StgForeignPtr)fo->connectedTo);
56     }
57     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
58
59     /* RW object: flush the (output) buffer first. */
60     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) && FILEOBJ_NEEDS_FLUSHING(fo) ) {
61         rc = flushBuffer(ptr);
62         if (rc < 0) return rc;
63     }
64     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
65
66     /* return the unread parts of the file buffer..*/
67     if ( fo->flags & FILEOBJ_READ && 
68          fo->bufRPtr > 0          &&
69          fo->bufWPtr > fo->bufRPtr ) {
70         count = fo->bufWPtr - fo->bufRPtr;
71         fo->bufRPtr=0;
72         return count;
73     }
74
75 #if 0
76     fprintf(stderr, "rb: %d %d %d\n", fo->bufRPtr, fo->bufWPtr, fo->bufSize);
77 #endif
78
79     while ((count =
80              (
81 #ifdef USE_WINSOCK
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(StgForeignPtr ptr, StgAddr buf, StgInt len)
110 {
111     IOFileObject* fo = (IOFileObject*)ptr;
112     int count=0,rc=0, total_count;
113     int fd;
114     char* p;
115
116     /* Check if someone hasn't zapped us */
117     if ( fo == NULL )
118        return -2;
119
120     fd = fo->fd;
121
122     if ( fd == -1 ) /* File has been closed for us */
123        return -2;
124
125     if ( FILEOBJ_IS_EOF(fo) ) {
126         ghc_errtype = ERR_EOF;
127         ghc_errstr = "";
128         return -1;
129     }
130
131     /* if input stream is connect to an output stream, flush it first */
132     if ( fo->connectedTo != NULL   &&
133          fo->connectedTo->fd != -1 &&
134          (fo->connectedTo->flags & FILEOBJ_WRITE)
135        ) {
136        rc = flushFile((StgForeignPtr)fo->connectedTo);
137     }
138     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
139
140     /* RW object: flush the (output) buffer first. */
141     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) && FILEOBJ_NEEDS_FLUSHING(fo) ) {
142         rc = flushBuffer(ptr);
143         if (rc < 0) return rc;
144     }
145     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
146
147     /* copy the unread parts of the file buffer..*/
148     if ( FILEOBJ_READABLE(fo) && 
149          fo->bufRPtr > 0      &&
150          fo->bufWPtr >= fo->bufRPtr ) {
151         count = ( len < (fo->bufWPtr - fo->bufRPtr)) ? len : (fo->bufWPtr - fo->bufRPtr);
152         memcpy(buf,fo->buf, count);
153         fo->bufWPtr=0;
154         fo->bufRPtr=0;
155         
156     }
157
158     if (len - count <= 0)
159        return count;
160
161     len -= count;
162     p = buf;
163     p += count;
164     total_count = count;
165
166     while ((count =
167              (
168 #ifdef USE_WINSOCK
169                fo->flags & FILEOBJ_WINSOCK ?
170                  recv(fd, p, len, 0) :
171                  read(fd, p, len))) <= 0 ) {
172 #else
173                  read(fd, p, len))) <= 0 ) {
174 #endif
175         if ( count == 0 ) { /* EOF */
176             break;
177         } else if ( count == -1 && errno == EAGAIN) {
178             /* ToDo: partial/blocked reads??????  Looks like we don't recover
179              * from this properly.
180              */
181             errno = 0;
182             return FILEOBJ_BLOCKED_READ;
183         } else if ( count == -1 && errno != EINTR) {
184             cvtErrno();
185             stdErrno();
186             return -1;
187         }
188         total_count += count;
189         len -= count;
190         p += count;
191     }
192
193     total_count += count;
194     /* ToDo: might point beyond the end of the buffer??? */
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(StgForeignPtr ptr)
211 {
212     IOFileObject* fo = (IOFileObject*)ptr;
213     int rc=0, count;
214
215     /* Check if someone hasn't zapped us */
216     if ( fo == NULL || fo->fd == -1 )
217        return -2;
218
219     if ( FILEOBJ_IS_EOF(fo) ) {
220         ghc_errtype = ERR_EOF;
221         ghc_errstr = "";
222         return -1;
223     }
224
225     /* Weird case: buffering has been turned off.
226        Return non-std value and deal with this case on the Haskell side.
227     */
228     if ( FILEOBJ_UNBUFFERED(fo) ) {
229         return -3;
230     }
231
232     /* if input stream is connect to an output stream, flush it first */
233     if ( fo->connectedTo != NULL   &&
234          fo->connectedTo->fd != -1 &&
235          (fo->connectedTo->flags & FILEOBJ_WRITE)
236        ) {
237        rc = flushFile((StgForeignPtr)fo->connectedTo);
238     }
239     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
240
241     /* RW object: flush the (output) buffer first. */
242     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) ) {
243         rc = flushBuffer(ptr);
244         if (rc < 0) return rc;
245     }
246     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
247
248     if ( fo->bufRPtr < 0 || fo->bufRPtr >= fo->bufWPtr ) { /* Buffer is empty */
249        fo->bufRPtr=0; fo->bufWPtr=0;
250        rc = fill_up_line_buffer(fo);
251        if (rc < 0) return rc;
252     }
253
254     while (1) {
255        unsigned char* s1 = memchr((unsigned char *)fo->buf+fo->bufRPtr, '\n', fo->bufWPtr - fo->bufRPtr);
256        if (s1 != NULL ) {  /* Found one */
257           /* Note: we *don't* zero terminate the line */
258           count = s1 - ((unsigned char*)fo->buf + fo->bufRPtr) + 1;
259           fo->bufRPtr += count;
260           return count;
261        } else {
262           /* Just return partial line */
263           count = fo->bufWPtr - fo->bufRPtr;
264           fo->bufRPtr += count;
265           return count;
266        }
267     }
268
269 }
270
271 StgInt
272 readChar(StgForeignPtr ptr)
273 {
274     IOFileObject* fo= (IOFileObject*)ptr;
275     int count,rc=0;
276     unsigned char c;
277
278     /* Check if someone hasn't zapped us */
279     if ( fo == NULL || fo->fd == -1)
280        return -2;
281
282     if ( FILEOBJ_IS_EOF(fo) ) {
283         ghc_errtype = ERR_EOF;
284         ghc_errstr = "";
285         return -1;
286     }
287
288     /* Buffering has been changed, report back */
289     if ( FILEOBJ_LINEBUFFERED(fo) ) {
290        return -3;
291     } else if ( FILEOBJ_BLOCKBUFFERED(fo) ) {
292        return -4;
293     }
294
295     /* if input stream is connect to an output stream, flush it first */
296     if ( fo->connectedTo != NULL   &&
297          fo->connectedTo->fd != -1 &&
298          (fo->connectedTo->flags & FILEOBJ_WRITE)
299        ) {
300        rc = flushFile((StgForeignPtr)fo->connectedTo);
301     }
302     if (rc < 0) return (rc == FILEOBJ_BLOCKED_WRITE ? FILEOBJ_BLOCKED_CONN_WRITE : rc);
303
304     /* RW object: flush the (output) buffer first. */
305     if ( FILEOBJ_WRITEABLE(fo) && FILEOBJ_JUST_WRITTEN(fo) && FILEOBJ_NEEDS_FLUSHING(fo) ) {
306         rc = flushBuffer(ptr);
307         if (rc < 0) return rc;
308     }
309     fo->flags = (fo->flags & ~FILEOBJ_RW_WRITE) | FILEOBJ_RW_READ;
310
311     while ( (count = 
312                (
313 #ifdef USE_WINSOCK
314                  fo->flags & FILEOBJ_WINSOCK ?
315                  recv(fo->fd, &c, 1, 0) :
316                  read(fo->fd, &c, 1))) <= 0 ) {
317 #else
318                  read(fo->fd, &c, 1))) <= 0 ) {
319 #endif
320         if ( count == 0 ) {
321             ghc_errtype = ERR_EOF;
322             ghc_errstr = "";
323             return -1;
324         } else if ( count == -1 && errno == EAGAIN) {
325             errno = 0;
326             return FILEOBJ_BLOCKED_READ;
327         } else if ( count == -1 && errno != EINTR) {
328             cvtErrno();
329             stdErrno();
330             return -1;
331         }
332     }
333
334     if ( isatty(fo->fd) && c == EOT ) {
335         return EOF;
336     } else {
337         return (int)c;
338     }
339 }