Annotation of libwww/Library/src/HTBufWrt.c, revision 2.5.2.6
2.1 frystyk 1: /*
2: ** BUFFERED TRANSPORT WRITER STREAM
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.5.2.6 ! eric 6: ** @(#) $Id: HTBufWrt.c,v 2.5.2.5 1996/11/21 19:42:14 eric Exp $
2.1 frystyk 7: **
8: ** A buffered output stream. This stream lets you write characters to a
9: ** stream without causing a write every time. The data is first written
10: ** into a buffer. Data is written to the actual stream only when the
11: ** buffer is full, or when the stream is flushed.
12: */
13:
14: /* Library include files */
15: #include "sysdep.h"
16: #include "WWWUtil.h"
17: #include "WWWCore.h"
18: #include "HTNetMan.h"
19: #include "HTWriter.h"
2.5.2.4 eric 20: #include "HTTimer.h"
2.5.2.6 ! eric 21: #include "HTWatch.h"
2.1 frystyk 22: #include "HTBufWrt.h" /* Implemented here */
23:
24: struct _HTOutputStream {
25: const HTOutputStreamClass * isa;
26: HTOutputStream * target; /* Target for outgoing data */
2.5.2.2 frystyk 27: HTHost * host;
2.1 frystyk 28: int size; /* Buffer size */
2.3 frystyk 29: int bb;
2.1 frystyk 30: char * block;
31: char * read; /* Position in 'data' */
32: char * data; /* buffer */
2.5.2.3 frystyk 33:
34: BOOL delaying;
2.5.2.4 eric 35: int lastFlushTime; /* polar coordinates of the moon */
36: HTTimer * timer;
2.1 frystyk 37: };
38:
39: #define PUTBLOCK(b,l) (*me->target->isa->put_block)(me->target,(b),(l))
40:
41: /* ------------------------------------------------------------------------- */
42:
2.5.2.4 eric 43: PRIVATE int HTBufferWriter_flush (HTOutputStream * me)
44: {
45: int status = HT_OK;
46: if (me == NULL) return HT_ERROR;
47: if (me->read > me->data) {
48: if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK)
49: return HT_WOULD_BLOCK;
50: me->lastFlushTime = HTGetTimeInMillis();
51: me->read = me->data;
52: me->block = NULL;
53: }
54: if (me->timer) {
55: HTTimer_delete(me->timer);
56: me->timer = NULL;
57: }
58: return status;
59: }
60:
61: PRIVATE int FlushEvent (HTTimer * timer, void * param)
2.5.2.3 frystyk 62: {
2.5.2.4 eric 63: HTOutputStream * me = (HTOutputStream *) param;
64: if (timer != me->timer) HTDebugBreak();
2.5.2.3 frystyk 65: HTBufferWriter_flush(me);
66: return HT_OK;
67: }
68:
2.5.2.4 eric 69: PRIVATE int HTBufferWriter_lazyFlush (HTOutputStream * me)
2.1 frystyk 70: {
2.5.2.4 eric 71: HTNet * net;
72: int delay;
2.5.2.3 frystyk 73:
2.5.2.4 eric 74: if (me->read <= me->data)
75: return HT_OK; /* nothing to flush */
2.5.2.3 frystyk 76: /*
2.5.2.4 eric 77: ** If we are allowed to delay the flush then set a timer with the
2.5.2.3 frystyk 78: ** delay descibed by our delay variable. If we can't delay then flush
79: ** right away.
80: */
2.5.2.4 eric 81: delay = HTHost_writeDelay(me->host, me->lastFlushTime, me->read - me->data);
82:
83: /*
84: ** Flush immediately
85: */
86: if (!delay)
87: return HTBufferWriter_flush(me);
88:
89: /*
90: ** Delayed flush
91: */
92: if (me->timer) /* already queued to flush */
93: return HT_OK;
94:
95: /*
96: ** Set a timer and tell the host we've done the write
97: */
98: net = HTHost_getWriteNet(me->host);
99: me->timer = HTTimer_new(NULL, FlushEvent, me, delay, YES);
100: HTHost_unregister(me->host, net, HTEvent_WRITE);
101: if (PROT_TRACE) HTTrace("Buffer...... Waiting...\n");
102: return HT_OK;
2.1 frystyk 103: }
104:
105: PRIVATE int HTBufferWriter_free (HTOutputStream * me)
106: {
2.5.2.5 eric 107: return HTBufferWriter_flush(me);
2.1 frystyk 108: }
109:
110: PRIVATE int HTBufferWriter_abort (HTOutputStream * me, HTList * e)
111: {
112: if (me->target) (*me->target->isa->abort)(me->target, e);
113: if (PROT_TRACE) HTTrace("Buffer...... ABORTING...\n");
114: return HT_ERROR;
115: }
116:
2.5.2.2 frystyk 117: PRIVATE int HTBufferWriter_write (HTOutputStream * me, const char * buf, int len)
2.1 frystyk 118: {
2.5.2.4 eric 119: HTNet * net = HTHost_getWriteNet(me->host);
2.4 frystyk 120: long total = len;
2.1 frystyk 121: int status;
2.4 frystyk 122:
2.3 frystyk 123: if (me->bb > 0) {
2.1 frystyk 124: len -= (me->block - buf);
2.3 frystyk 125: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
2.5.2.4 eric 126: me->lastFlushTime = HTGetTimeInMillis();
2.3 frystyk 127: me->block += me->bb;
128: len -= me->bb;
129: me->bb = 0;
130: } else {
131: int available = me->data + me->size - me->read;
132:
133: /* Still room in buffer */
134: if (len <= available) {
135: memcpy(me->read, buf, len);
136: me->read += len;
137: return HT_OK;
138: }
139:
140: /* If already data in buffer then fill it and flush */
141: if (me->read > me->data) {
142: memcpy(me->read, buf, available);
143: me->block = (char *) buf+available;
2.5.2.4 eric 144: if (me->timer && me->delaying) {
145: HTTimer_delete(me->timer);
146: me->timer=NULL;
2.5.2.3 frystyk 147: me->delaying = NO;
148: }
2.4 frystyk 149: if ((status = PUTBLOCK(me->data, me->size))!=HT_OK) return status;
2.5.2.4 eric 150: me->lastFlushTime = HTGetTimeInMillis();
2.3 frystyk 151: }
152:
153: /* If more data then write n times buffer size */
154: if (!me->block)
155: me->block = (char *) buf;
156: else {
157: len -= (me->block - buf);
158: }
159: me->bb = len - len%me->size;
2.5.2.4 eric 160: if (me->bb) {
161: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
162: me->lastFlushTime = HTGetTimeInMillis();
163: }
2.3 frystyk 164: me->block += me->bb;
165: len -= me->bb;
166: me->bb = 0;
2.1 frystyk 167: }
168:
169: /* If data is not aligned then save the rest in our buffer */
170: if (len > 0) {
171: memcpy(me->data, me->block, len);
172: me->read = me->data + len;
173: } else
174: me->read = me->data;
175: me->block = NULL;
2.5.2.4 eric 176: HTNet_addBytesWritten(net, total);
2.1 frystyk 177: return HT_OK;
178: }
179:
180: /* Character handling
181: ** ------------------
182: */
183: PRIVATE int HTBufferWriter_put_character (HTOutputStream * me, char c)
184: {
185: return HTBufferWriter_write(me, &c, 1);
186: }
187:
188: /* String handling
189: ** ---------------
190: **
191: ** Strings must be smaller than this buffer size.
192: */
193: PRIVATE int HTBufferWriter_put_string (HTOutputStream * me, const char * s)
194: {
195: return HTBufferWriter_write(me, s, (int) strlen(s));
196: }
197: /*
198: ** The difference between the close and the free method is that we don't
199: ** close the connection in the free method - we only call the free method
200: ** of the target stream. That way, we can keep the output stream as long
201: ** as the channel itself.
202: */
203: PRIVATE int HTBufferWriter_close (HTOutputStream * me)
204: {
205: if (me) {
206: HTBufferWriter_flush(me);
207: if (me->target) (*me->target->isa->close)(me->target);
208: HT_FREE(me->data);
209: HT_FREE(me);
210: }
211: return HT_OK;
212: }
213:
214: PRIVATE const HTOutputStreamClass HTBufferWriter =
215: {
2.5.2.5 eric 216: "BufferedSocketWriter",
2.5.2.4 eric 217: HTBufferWriter_lazyFlush,
2.1 frystyk 218: HTBufferWriter_free,
219: HTBufferWriter_abort,
220: HTBufferWriter_put_character,
221: HTBufferWriter_put_string,
222: HTBufferWriter_write,
223: HTBufferWriter_close
224: };
225:
2.5.2.2 frystyk 226: PUBLIC HTOutputStream * HTBufferWriter_new (HTHost * host, HTChannel * ch,
2.1 frystyk 227: void * param, int bufsize)
228: {
2.5.2.2 frystyk 229: if (host && ch) {
2.1 frystyk 230: HTOutputStream * me = HTChannel_output(ch);
2.5.2.2 frystyk 231: if (!me) {
232: HTOutputStream * me;
2.1 frystyk 233: if (bufsize <= 0) bufsize = OUTPUT_BUFFER_SIZE;
2.5.2.2 frystyk 234: if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL ||
2.1 frystyk 235: (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
236: HT_OUTOFMEM("HTBufferWriter_new");
237: me->isa = &HTBufferWriter;
238: me->read = me->data;
239: me->size = bufsize;
2.5.2.2 frystyk 240: me->target = HTWriter_new(host, ch, param, 0);
241: me->host = host;
242: return me;
243: }
2.1 frystyk 244: }
245: return NULL;
246: }
Webmaster