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