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