[project @ 1999-11-23 14:36:31 by simonmar]
[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.9 1999/11/05 15:25:49 simonmar Exp $
5  *
6  * hPutStr 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 StgInt
21 writeFileObject(ptr, bytes)
22 StgForeignPtr ptr;
23 StgInt bytes;
24 {
25     int rc=0;
26     IOFileObject* fo = (IOFileObject*)ptr;
27
28     char *p = (char *) fo->buf;
29
30     /* If we've got a r/w file object in our hand, flush the
31        (input) buffer contents first.
32     */
33     if ( FILEOBJ_READABLE(fo) && FILEOBJ_JUST_READ(fo) ) {
34        fo->flags = (fo->flags & ~FILEOBJ_RW_READ) | FILEOBJ_RW_WRITE;
35        rc = flushReadBuffer(ptr);
36        if (rc < 0) return rc;
37     }
38
39     return (writeBuffer(ptr, bytes));
40 }
41
42 StgInt
43 writeBuffer(ptr, bytes)
44 StgForeignPtr ptr;
45 StgInt bytes;
46 {
47     int count, rc=0;
48     IOFileObject* fo = (IOFileObject*)ptr;
49
50     char *pBuf = (char *) fo->buf;
51
52     /* Disallow short writes */
53     if (bytes == 0  || fo->buf == NULL)
54         return 0;
55
56     while ((count = 
57                (
58 #ifdef USE_WINSOCK
59                  fo->flags & FILEOBJ_WINSOCK ?
60                  send(fo->fd,  pBuf, bytes, 0) :
61                  write(fo->fd, pBuf, bytes))) < bytes) {
62 #else
63                  write(fo->fd, pBuf, bytes))) < bytes) {
64 #endif
65         if ( count == -1 && errno == EAGAIN) {
66             errno = 0;
67             return FILEOBJ_BLOCKED_WRITE;
68         }
69         else if ( count == -1 && errno != EINTR ) {
70             cvtErrno();
71             stdErrno();
72             return -1;
73         }
74         else {
75             bytes -= count;
76             pBuf  += count;
77         }
78     }
79     /* Signal that we've emptied the buffer */
80     fo->bufWPtr=0;
81     return 0;
82 }
83
84
85 StgInt
86 writeBuf(ptr, buf, len)
87 StgForeignPtr ptr;
88 StgAddr buf;
89 StgInt  len;
90 {
91     IOFileObject* fo = (IOFileObject*)ptr;
92     int count;
93     int rc = 0;
94     char *pBuf = (char *) buf;
95
96     if (len == 0 )
97         return 0;
98
99     /* First of all, check if we do need to flush the buffer .. */
100     /* Note - in the case of line buffering, we do not currently check
101        whether we need to flush buffer due to line terminators in the
102        buffer we're outputting */
103     if ( fo->buf != NULL                     &&   /* buffered and */
104          (fo->bufWPtr + len < (fo->bufSize))      /* there's room */
105        ) {
106        /* Block copying is likely to be cheaper than, flush, followed by write */
107        memcpy(((char*)fo->buf + fo->bufWPtr), buf, len);
108        fo->bufWPtr += len;
109        return 0;
110     }
111     /* If we do overflow, flush current contents of the buffer and
112        directly output the chunk.
113        (no attempt at splitting up the chunk is currently made)
114     */       
115     if ( fo->buf != NULL                     &&    /* buffered and */
116          (fo->bufWPtr + len >= (fo->bufSize))       /* there's not room */
117        ) {
118        /* Flush buffer */
119        rc = writeFileObject(ptr, fo->bufWPtr);
120        /* ToDo: undo buffer fill if we're blocking.. */
121     }
122
123     if (rc != 0) { 
124        return rc;
125     }
126
127     while ((count = 
128                (
129 #ifdef USE_WINSOCK
130                  fo->flags & FILEOBJ_WINSOCK ?
131                  send(fo->fd,  pBuf, (int)len, 0) :
132                  write(fo->fd, pBuf, (int)len))) < len ) {
133 #else
134                  write(fo->fd, pBuf, (int)len))) < len ) {
135 #endif
136         if ( count >= 0 ) {
137             len -= count;
138             pBuf += count;
139             continue;
140         } else if ( errno == EAGAIN ) {
141             errno = 0;
142             return FILEOBJ_BLOCKED_WRITE;
143         } else if ( errno != EINTR ) {
144             cvtErrno();
145             stdErrno();
146             return -1;
147         }
148     }
149
150     return 0;
151 }
152
153 StgInt
154 writeBufBA(ptr, buf, len)
155      StgForeignPtr ptr;
156 StgByteArray buf;
157 StgInt  len;
158 { return (writeBuf(ptr,(StgAddr)buf, len)); }