Annotation of libwww/Library/src/HTBufWrt.c, revision 2.5.2.2
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.2 ! frystyk 6: ** @(#) $Id: HTBufWrt.c,v 2.5.2.1 1996/10/29 21:26:40 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"
20: #include "HTBufWrt.h" /* Implemented here */
21:
22: struct _HTOutputStream {
23: const HTOutputStreamClass * isa;
24: HTOutputStream * target; /* Target for outgoing data */
2.5.2.2 ! frystyk 25: HTHost * host;
2.1 frystyk 26: int size; /* Buffer size */
2.3 frystyk 27: int bb;
2.1 frystyk 28: char * block;
29: char * read; /* Position in 'data' */
30: char * data; /* buffer */
31: };
32:
33: #define PUTBLOCK(b,l) (*me->target->isa->put_block)(me->target,(b),(l))
34:
35: /* ------------------------------------------------------------------------- */
36:
37: PRIVATE int HTBufferWriter_flush (HTOutputStream * me)
38: {
39: int status = HT_OK;
40: if (me->read > me->data) {
41: if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK)
42: return HT_WOULD_BLOCK;
43: me->read = me->data;
44: me->block = NULL;
45: }
46: return status;
47: }
48:
49: PRIVATE int HTBufferWriter_free (HTOutputStream * me)
50: {
51: return HTBufferWriter_flush(me);
52: }
53:
54: PRIVATE int HTBufferWriter_abort (HTOutputStream * me, HTList * e)
55: {
56: if (me->target) (*me->target->isa->abort)(me->target, e);
57: if (PROT_TRACE) HTTrace("Buffer...... ABORTING...\n");
58: return HT_ERROR;
59: }
60:
2.5.2.2 ! frystyk 61: PRIVATE int HTBufferWriter_write (HTOutputStream * me, const char * buf, int len)
2.1 frystyk 62: {
2.5.2.2 ! frystyk 63: HTNet * net = HTHost_getReadNet(me->host);
2.4 frystyk 64: long total = len;
2.1 frystyk 65: int status;
2.4 frystyk 66:
2.3 frystyk 67: if (me->bb > 0) {
2.1 frystyk 68: len -= (me->block - buf);
2.3 frystyk 69: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
70: me->block += me->bb;
71: len -= me->bb;
72: me->bb = 0;
73: } else {
74: int available = me->data + me->size - me->read;
75:
76: /* Still room in buffer */
77: if (len <= available) {
78: memcpy(me->read, buf, len);
79: me->read += len;
80: return HT_OK;
81: }
82:
83: /* If already data in buffer then fill it and flush */
84: if (me->read > me->data) {
85: memcpy(me->read, buf, available);
86: me->block = (char *) buf+available;
2.4 frystyk 87: if ((status = PUTBLOCK(me->data, me->size))!=HT_OK) return status;
2.3 frystyk 88: }
89:
90: /* If more data then write n times buffer size */
91: if (!me->block)
92: me->block = (char *) buf;
93: else {
94: len -= (me->block - buf);
95: }
96: me->bb = len - len%me->size;
97: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
98: me->block += me->bb;
99: len -= me->bb;
100: me->bb = 0;
2.1 frystyk 101: }
102:
103: /* If data is not aligned then save the rest in our buffer */
104: if (len > 0) {
105: memcpy(me->data, me->block, len);
106: me->read = me->data + len;
107: } else
108: me->read = me->data;
109: me->block = NULL;
2.5.2.2 ! frystyk 110: net->bytesWritten += total;
2.1 frystyk 111: return HT_OK;
112: }
113:
114: /* Character handling
115: ** ------------------
116: */
117: PRIVATE int HTBufferWriter_put_character (HTOutputStream * me, char c)
118: {
119: return HTBufferWriter_write(me, &c, 1);
120: }
121:
122: /* String handling
123: ** ---------------
124: **
125: ** Strings must be smaller than this buffer size.
126: */
127: PRIVATE int HTBufferWriter_put_string (HTOutputStream * me, const char * s)
128: {
129: return HTBufferWriter_write(me, s, (int) strlen(s));
130: }
131: /*
132: ** The difference between the close and the free method is that we don't
133: ** close the connection in the free method - we only call the free method
134: ** of the target stream. That way, we can keep the output stream as long
135: ** as the channel itself.
136: */
137: PRIVATE int HTBufferWriter_close (HTOutputStream * me)
138: {
139: if (me) {
140: HTBufferWriter_flush(me);
141: if (me->target) (*me->target->isa->close)(me->target);
142: HT_FREE(me->data);
143: HT_FREE(me);
144: }
145: return HT_OK;
146: }
147:
148: PRIVATE const HTOutputStreamClass HTBufferWriter =
149: {
150: "SocketWriter",
151: HTBufferWriter_flush,
152: HTBufferWriter_free,
153: HTBufferWriter_abort,
154: HTBufferWriter_put_character,
155: HTBufferWriter_put_string,
156: HTBufferWriter_write,
157: HTBufferWriter_close
158: };
159:
2.5.2.2 ! frystyk 160: PUBLIC HTOutputStream * HTBufferWriter_new (HTHost * host, HTChannel * ch,
2.1 frystyk 161: void * param, int bufsize)
162: {
2.5.2.2 ! frystyk 163: if (host && ch) {
2.1 frystyk 164: HTOutputStream * me = HTChannel_output(ch);
2.5.2.2 ! frystyk 165: if (!me) {
! 166: HTOutputStream * me;
2.1 frystyk 167: if (bufsize <= 0) bufsize = OUTPUT_BUFFER_SIZE;
2.5.2.2 ! frystyk 168: if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL ||
2.1 frystyk 169: (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
170: HT_OUTOFMEM("HTBufferWriter_new");
171: me->isa = &HTBufferWriter;
172: me->read = me->data;
173: me->size = bufsize;
2.5.2.2 ! frystyk 174: me->target = HTWriter_new(host, ch, param, 0);
! 175: me->host = host;
! 176: return me;
! 177: }
2.1 frystyk 178: }
179: return NULL;
180: }
Webmaster