[project @ 1999-09-16 13:14:38 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.8 1999/09/16 13:14:43 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 (errno != EINTR) {
66             cvtErrno();
67             stdErrno();
68             return -1;
69         }
70         bytes -= count;
71         pBuf  += count;
72     }
73     /* Signal that we've emptied the buffer */
74     fo->bufWPtr=0;
75     return 0;
76 }
77
78
79 StgInt
80 writeBuf(ptr, buf, len)
81 StgForeignPtr ptr;
82 StgAddr buf;
83 StgInt  len;
84 {
85     IOFileObject* fo = (IOFileObject*)ptr;
86     int count;
87     int rc = 0;
88     char *pBuf = (char *) buf;
89
90     if (len == 0 )
91         return 0;
92
93     /* First of all, check if we do need to flush the buffer .. */
94     /* Note - in the case of line buffering, we do not currently check
95        whether we need to flush buffer due to line terminators in the
96        buffer we're outputting */
97     if ( fo->buf != NULL                     &&   /* buffered and */
98          (fo->bufWPtr + len < (fo->bufSize))      /* there's room */
99        ) {
100        /* Block copying is likely to be cheaper than, flush, followed by write */
101        memcpy(((char*)fo->buf + fo->bufWPtr), buf, len);
102        fo->bufWPtr += len;
103        return 0;
104     }
105     /* If we do overflow, flush current contents of the buffer and
106        directly output the chunk.
107        (no attempt at splitting up the chunk is currently made)
108     */       
109     if ( fo->buf != NULL                     &&    /* buffered and */
110          (fo->bufWPtr + len >= (fo->bufSize))       /* there's not room */
111        ) {
112        /* Flush buffer */
113        rc = writeFileObject(ptr, fo->bufWPtr);
114        /* ToDo: undo buffer fill if we're blocking.. */
115     }
116
117     if (rc != 0) { 
118        return rc;
119     }
120
121     while ((count = 
122                (
123 #ifdef USE_WINSOCK
124                  fo->flags & FILEOBJ_WINSOCK ?
125                  send(fo->fd,  pBuf, (int)len, 0) :
126                  write(fo->fd, pBuf, (int)len))) < len ) {
127 #else
128                  write(fo->fd, pBuf, (int)len))) < len ) {
129 #endif
130         if ( count >= 0 ) {
131             len -= count;
132             pBuf += count;
133             continue;
134         } else if ( errno == EAGAIN ) {
135             errno = 0;
136             return FILEOBJ_BLOCKED_WRITE;
137         } else if ( errno != EINTR ) {
138             cvtErrno();
139             stdErrno();
140             return -1;
141         }
142     }
143
144     return 0;
145 }
146
147 StgInt
148 writeBufBA(ptr, buf, len)
149      StgForeignPtr ptr;
150 StgByteArray buf;
151 StgInt  len;
152 { return (writeBuf(ptr,(StgAddr)buf, len)); }