Annotation of libwww/Library/src/HTBufWrt.c, revision 2.5
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 ! frystyk 6: ** @(#) $Id: HTBufWrt.c,v 2.4 1996/08/05 17:22:13 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;
2.1 frystyk 116: return HT_OK;
117: }
118:
119: /* Character handling
120: ** ------------------
121: */
122: PRIVATE int HTBufferWriter_put_character (HTOutputStream * me, char c)
123: {
124: return HTBufferWriter_write(me, &c, 1);
125: }
126:
127: /* String handling
128: ** ---------------
129: **
130: ** Strings must be smaller than this buffer size.
131: */
132: PRIVATE int HTBufferWriter_put_string (HTOutputStream * me, const char * s)
133: {
134: return HTBufferWriter_write(me, s, (int) strlen(s));
135: }
136: /*
137: ** The difference between the close and the free method is that we don't
138: ** close the connection in the free method - we only call the free method
139: ** of the target stream. That way, we can keep the output stream as long
140: ** as the channel itself.
141: */
142: PRIVATE int HTBufferWriter_close (HTOutputStream * me)
143: {
144: if (me) {
145: HTBufferWriter_flush(me);
146: if (me->target) (*me->target->isa->close)(me->target);
147: HT_FREE(me->data);
148: HT_FREE(me);
149: }
150: return HT_OK;
151: }
152:
153: PRIVATE const HTOutputStreamClass HTBufferWriter =
154: {
155: "SocketWriter",
156: HTBufferWriter_flush,
157: HTBufferWriter_free,
158: HTBufferWriter_abort,
159: HTBufferWriter_put_character,
160: HTBufferWriter_put_string,
161: HTBufferWriter_write,
162: HTBufferWriter_close
163: };
164:
165: PUBLIC HTOutputStream * HTBufferWriter_new (HTNet * net, HTChannel * ch,
166: void * param, int bufsize)
167: {
168: if (net && ch) {
169: HTOutputStream * me = HTChannel_output(ch);
170: if (me == NULL) {
171: if (bufsize <= 0) bufsize = OUTPUT_BUFFER_SIZE;
172: if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream))) == NULL ||
173: (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
174: HT_OUTOFMEM("HTBufferWriter_new");
175: me->isa = &HTBufferWriter;
176: me->read = me->data;
177: me->size = bufsize;
178: me->target = HTWriter_new(net, ch, param, 0);
179: me->ch = ch;
2.2 eric 180: } else
181: HTWriter_set(me->target, net, ch, param, 0);
2.1 frystyk 182: me->net = net;
183: return me;
184: }
185: return NULL;
186: }
Webmaster