[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / lib / std / cbits / writeFile.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: writeFile.c,v 1.3 1998/12/02 13:28:07 simonm Exp $
5  *
6  * hPutStr Runtime Support
7  */
8
9 #include "Rts.h"
10 #include "stgio.h"
11
12 StgInt
13 writeFileObject(ptr, bytes)
14 StgForeignPtr ptr;
15 StgInt bytes;
16 {
17     int rc=0;
18     IOFileObject* fo = (IOFileObject*)ptr;
19
20     char *p = (char *) fo->buf;
21
22     /* If we've got a r/w file object in our hand, flush the
23        (input) buffer contents first.
24     */
25     if ( FILEOBJ_READABLE(fo) && FILEOBJ_JUST_READ(fo) ) {
26        fo->flags = (fo->flags & ~FILEOBJ_RW_READ) | FILEOBJ_RW_WRITE;
27        rc = flushReadBuffer(ptr);
28        if (rc < 0) return rc;
29     }
30
31     return (writeBuffer(ptr, bytes));
32 }
33
34 StgInt
35 writeBuffer(ptr, bytes)
36 StgForeignPtr ptr;
37 StgInt bytes;
38 {
39     int count, rc=0;
40     IOFileObject* fo = (IOFileObject*)ptr;
41
42     char *p = (char *) fo->buf;
43
44     /* Disallow short writes */
45     if (bytes == 0  || fo->buf == NULL)
46         return 0;
47
48     if ( fo->flags & FILEOBJ_NONBLOCKING_IO && inputReady(ptr,0) != 1 )
49        return FILEOBJ_BLOCKED_WRITE;
50
51     while ((count = write(fo->fd, fo->buf, bytes)) < bytes) {
52         if (errno != EINTR) {
53             cvtErrno();
54             stdErrno();
55             return -1;
56         }
57         bytes -= count;
58         p += count;
59     }
60     /* Signal that we've emptied the buffer */
61     fo->bufWPtr=0;
62     return 0;
63 }
64
65
66 StgInt
67 writeBuf(ptr, buf, len)
68 StgForeignPtr ptr;
69 StgAddr buf;
70 StgInt  len;
71 {
72     IOFileObject* fo = (IOFileObject*)ptr;
73     int count;
74     int rc = 0;
75     char *p = (char *) buf;
76
77     if (len == 0 )
78         return 0;
79
80     /* First of all, check if we do need to flush the buffer .. */
81     /* Note - in the case of line buffering, we do not currently check
82        whether we need to flush buffer due to line terminators in the
83        buffer we're outputting */
84     if ( fo->buf != NULL                     &&   /* buffered and */
85          (fo->bufWPtr + len < (fo->bufSize))      /* there's room */
86        ) {
87        /* Block copying is likely to be cheaper than, flush, followed by write */
88        memcpy(((char*)fo->buf + fo->bufWPtr), buf, len);
89        fo->bufWPtr += len;
90        return 0;
91     }
92     /* If we do overflow, flush current contents of the buffer and
93        directly output the chunk.
94        (no attempt at splitting up the chunk is currently made)
95     */       
96     if ( fo->buf != NULL                     &&    /* buffered and */
97          (fo->bufWPtr + len >= (fo->bufSize))       /* there's not room */
98        ) {
99        /* Flush buffer */
100        rc = writeFileObject(ptr, fo->bufWPtr);
101        /* ToDo: undo buffer fill if we're blocking.. */
102     }
103
104     if (rc != 0) { 
105        return rc;
106     }
107
108     if ( fo->flags & FILEOBJ_NONBLOCKING_IO && inputReady(ptr,0) != 1 )
109        return FILEOBJ_BLOCKED_WRITE;
110
111     /* Disallow short writes */
112     while ((count = write(fo->fd, (char *)buf, (int)len)) < len) {
113         if (errno != EINTR) {
114             cvtErrno();
115             stdErrno();
116             return -1;
117         }
118         len -= count;
119         p += count;
120     }
121
122     return 0;
123 }
124
125 StgInt
126 writeBufBA(ptr, buf, len)
127      StgForeignPtr ptr;
128 StgByteArray buf;
129 StgInt  len;
130 { return (writeBuf(ptr,(StgAddr)buf, len)); }