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