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