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