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