Annotation of libwww/Library/src/HTBufWrt.c, revision 2.3
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.3 ! frystyk 6: ** @(#) $Id: HTBufWrt.c,v 2.2 1996/05/09 00:59:17 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 _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: {
69: int status;
2.3 ! frystyk 70: if (me->bb > 0) {
2.1 frystyk 71: len -= (me->block - buf);
2.3 ! frystyk 72: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
! 73: me->block += me->bb;
! 74: len -= me->bb;
! 75: me->bb = 0;
! 76: } else {
! 77: int available = me->data + me->size - me->read;
! 78:
! 79: /* Still room in buffer */
! 80: if (len <= available) {
! 81: memcpy(me->read, buf, len);
! 82: me->read += len;
! 83: return HT_OK;
! 84: }
! 85:
! 86: /* If already data in buffer then fill it and flush */
! 87: if (me->read > me->data) {
! 88: memcpy(me->read, buf, available);
! 89: me->block = (char *) buf+available;
! 90: }
! 91: if ((status = PUTBLOCK(me->data, me->size)) != HT_OK) return status;
! 92:
! 93: /* If more data then write n times buffer size */
! 94: if (!me->block)
! 95: me->block = (char *) buf;
! 96: else {
! 97: len -= (me->block - buf);
! 98: }
! 99: me->bb = len - len%me->size;
! 100: if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
! 101: me->block += me->bb;
! 102: len -= me->bb;
! 103: me->bb = 0;
2.1 frystyk 104: }
105:
106: /* If data is not aligned then save the rest in our buffer */
107: if (len > 0) {
108: memcpy(me->data, me->block, len);
109: me->read = me->data + len;
110: } else
111: me->read = me->data;
112: me->block = NULL;
113: return HT_OK;
114: }
115:
116: /* Character handling
117: ** ------------------
118: */
119: PRIVATE int HTBufferWriter_put_character (HTOutputStream * me, char c)
120: {
121: return HTBufferWriter_write(me, &c, 1);
122: }
123:
124: /* String handling
125: ** ---------------
126: **
127: ** Strings must be smaller than this buffer size.
128: */
129: PRIVATE int HTBufferWriter_put_string (HTOutputStream * me, const char * s)
130: {
131: return HTBufferWriter_write(me, s, (int) strlen(s));
132: }
133: /*
134: ** The difference between the close and the free method is that we don't
135: ** close the connection in the free method - we only call the free method
136: ** of the target stream. That way, we can keep the output stream as long
137: ** as the channel itself.
138: */
139: PRIVATE int HTBufferWriter_close (HTOutputStream * me)
140: {
141: if (me) {
142: HTBufferWriter_flush(me);
143: if (me->target) (*me->target->isa->close)(me->target);
144: HT_FREE(me->data);
145: HT_FREE(me);
146: }
147: return HT_OK;
148: }
149:
150: PRIVATE const HTOutputStreamClass HTBufferWriter =
151: {
152: "SocketWriter",
153: HTBufferWriter_flush,
154: HTBufferWriter_free,
155: HTBufferWriter_abort,
156: HTBufferWriter_put_character,
157: HTBufferWriter_put_string,
158: HTBufferWriter_write,
159: HTBufferWriter_close
160: };
161:
162: PUBLIC HTOutputStream * HTBufferWriter_new (HTNet * net, HTChannel * ch,
163: void * param, int bufsize)
164: {
165: if (net && ch) {
166: HTOutputStream * me = HTChannel_output(ch);
167: if (me == NULL) {
168: if (bufsize <= 0) bufsize = OUTPUT_BUFFER_SIZE;
169: if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream))) == NULL ||
170: (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
171: HT_OUTOFMEM("HTBufferWriter_new");
172: me->isa = &HTBufferWriter;
173: me->read = me->data;
174: me->size = bufsize;
175: me->target = HTWriter_new(net, ch, param, 0);
176: me->ch = ch;
2.2 eric 177: } else
178: HTWriter_set(me->target, net, ch, param, 0);
2.1 frystyk 179: me->net = net;
180: return me;
181: }
182: return NULL;
183: }
Webmaster