Annotation of libwww/Library/src/HTBufWrt.c, revision 2.5.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.5.2.3 ! frystyk     6: **     @(#) $Id: HTBufWrt.c,v 2.5.2.2 1996/10/30 23:21:52 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 _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 */
2.5.2.3 ! frystyk    31: 
        !            32:     BOOL                       delay_output;
        !            33:     BOOL                       delaying;
        !            34:     int                                delay_ms;                     /* Delay in ms */
        !            35:     HTEvent *                  delay_event;
2.1       frystyk    36: };
                     37: 
                     38: #define PUTBLOCK(b,l) (*me->target->isa->put_block)(me->target,(b),(l))
                     39: 
                     40: /* ------------------------------------------------------------------------- */
                     41: 
2.5.2.3 ! frystyk    42: PRIVATE int HTBufferWriter_flush (HTOutputStream * me);
        !            43: PRIVATE int FlushEvent (SOCKET soc, void * pVoid, HTEventType type)
        !            44: {
        !            45:     HTOutputStream * me = (HTOutputStream *) pVoid;
        !            46:     me->delay_output = NO;
        !            47:     HTBufferWriter_flush(me);
        !            48:     me->delay_output = YES;
        !            49:     return HT_OK;
        !            50: }
        !            51: 
2.1       frystyk    52: PRIVATE int HTBufferWriter_flush (HTOutputStream * me)
                     53: {
                     54:     int status = HT_OK;
2.5.2.3 ! frystyk    55: 
        !            56:     /*
        !            57:     **  If we are allowed to delay the flush then register an event with the
        !            58:     **  delay descibed by our delay variable. If we can't delay then flush 
        !            59:     **  right away.
        !            60:     */
        !            61:     if (me->delay_output) {
        !            62:        HTChannel * ch = HTHost_channel(me->host);
        !            63:        me->delay_event = HTEvent_new(FlushEvent, me, HT_PRIORITY_MAX, me->delay_ms);
        !            64:        HTEvent_register(HTChannel_socket(ch), HTEvent_TIMEOUT, me->delay_event);
        !            65:        me->delaying = YES;
        !            66:        if (PROT_TRACE) HTTrace("Buffer...... Waiting...\n");
        !            67:     } else if (me->read > me->data) {
2.1       frystyk    68:        if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK)
                     69:            return HT_WOULD_BLOCK;
                     70:        me->read = me->data;
                     71:        me->block = NULL;
                     72:     }
                     73:     return status;
                     74: }
                     75: 
                     76: PRIVATE int HTBufferWriter_free (HTOutputStream * me)
                     77: {
2.5.2.3 ! frystyk    78:     me->delay_output = NO;
2.1       frystyk    79:     return HTBufferWriter_flush(me);
                     80: }
                     81: 
                     82: PRIVATE int HTBufferWriter_abort (HTOutputStream * me, HTList * e)
                     83: {
                     84:     if (me->target) (*me->target->isa->abort)(me->target, e);
                     85:     if (PROT_TRACE) HTTrace("Buffer...... ABORTING...\n");
                     86:     return HT_ERROR;
                     87: }
                     88: 
2.5.2.2   frystyk    89: PRIVATE int HTBufferWriter_write (HTOutputStream * me, const char * buf, int len)
2.1       frystyk    90: {
2.5.2.2   frystyk    91:     HTNet * net = HTHost_getReadNet(me->host);
2.4       frystyk    92:     long total = len;
2.1       frystyk    93:     int status;
2.4       frystyk    94: 
2.3       frystyk    95:     if (me->bb > 0) {
2.1       frystyk    96:        len -= (me->block - buf);
2.3       frystyk    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;
                    101:     } else {
                    102:        int available = me->data + me->size - me->read;
                    103: 
                    104:        /* Still room in buffer */
                    105:        if (len <= available) {
                    106:            memcpy(me->read, buf, len);
                    107:            me->read += len;
                    108:            return HT_OK;
                    109:        }
                    110: 
                    111:        /* If already data in buffer then fill it and flush */
                    112:        if (me->read > me->data) {
                    113:            memcpy(me->read, buf, available);
                    114:            me->block = (char *) buf+available;
2.5.2.3 ! frystyk   115:            if (me->delay_event && me->delaying) {
        !           116:                HTChannel * ch = HTHost_channel(me->host);
        !           117:                HTEvent_unregister(HTChannel_socket(ch), HTEvent_TIMEOUT);
        !           118:                me->delaying = NO;
        !           119:            }
2.4       frystyk   120:            if ((status = PUTBLOCK(me->data, me->size))!=HT_OK) return status;
2.3       frystyk   121:        }
                    122: 
                    123:        /* If more data then write n times buffer size */
                    124:        if (!me->block)
                    125:            me->block = (char *) buf;
                    126:        else {
                    127:            len -= (me->block - buf);
                    128:        }
                    129:        me->bb = len - len%me->size;
                    130:        if ((status = PUTBLOCK(me->block, me->bb)) != HT_OK) return status;
                    131:        me->block += me->bb;
                    132:        len -= me->bb;
                    133:        me->bb = 0;
2.1       frystyk   134:     }
                    135: 
                    136:     /* If data is not aligned then save the rest in our buffer */
                    137:     if (len > 0) {
                    138:        memcpy(me->data, me->block, len);
                    139:        me->read = me->data + len;
                    140:     } else
                    141:        me->read = me->data;
                    142:     me->block = NULL;
2.5.2.2   frystyk   143:     net->bytesWritten += total;
2.1       frystyk   144:     return HT_OK;
                    145: }
                    146: 
                    147: /*     Character handling
                    148: **     ------------------
                    149: */
                    150: PRIVATE int HTBufferWriter_put_character (HTOutputStream * me, char c)
                    151: {
                    152:     return HTBufferWriter_write(me, &c, 1);
                    153: }
                    154: 
                    155: /*     String handling
                    156: **     ---------------
                    157: **
                    158: **     Strings must be smaller than this buffer size.
                    159: */
                    160: PRIVATE int HTBufferWriter_put_string (HTOutputStream * me, const char * s)
                    161: {
                    162:     return HTBufferWriter_write(me, s, (int) strlen(s));
                    163: }
                    164: /*
                    165: **     The difference between the close and the free method is that we don't
                    166: **     close the connection in the free method - we only call the free method
                    167: **     of the target stream. That way, we can keep the output stream as long 
                    168: **     as the channel itself.
                    169: */
                    170: PRIVATE int HTBufferWriter_close (HTOutputStream * me)
                    171: {
                    172:     if (me) {
2.5.2.3 ! frystyk   173:        me->delay_output = NO;
2.1       frystyk   174:        HTBufferWriter_flush(me);
                    175:        if (me->target) (*me->target->isa->close)(me->target);
                    176:        HT_FREE(me->data);
                    177:        HT_FREE(me);
                    178:     }
                    179:     return HT_OK;
                    180: }
                    181: 
                    182: PRIVATE const HTOutputStreamClass HTBufferWriter =
                    183: {              
                    184:     "SocketWriter",
                    185:     HTBufferWriter_flush,
                    186:     HTBufferWriter_free,
                    187:     HTBufferWriter_abort,
                    188:     HTBufferWriter_put_character,
                    189:     HTBufferWriter_put_string,
                    190:     HTBufferWriter_write,
                    191:     HTBufferWriter_close
                    192: }; 
                    193: 
2.5.2.2   frystyk   194: PUBLIC HTOutputStream * HTBufferWriter_new (HTHost * host, HTChannel * ch,
2.1       frystyk   195:                                            void * param, int bufsize)
                    196: {
2.5.2.2   frystyk   197:     if (host && ch) {
2.1       frystyk   198:        HTOutputStream * me = HTChannel_output(ch);
2.5.2.2   frystyk   199:        if (!me) {
                    200:            HTOutputStream * me;
2.1       frystyk   201:            if (bufsize <= 0) bufsize = OUTPUT_BUFFER_SIZE;
2.5.2.2   frystyk   202:            if ((me = (HTOutputStream *) HT_CALLOC(1, sizeof(HTOutputStream)))==NULL ||
2.1       frystyk   203:                (me->data = (char *) HT_MALLOC(bufsize)) == NULL)
                    204:                HT_OUTOFMEM("HTBufferWriter_new");
                    205:            me->isa = &HTBufferWriter;
                    206:            me->read = me->data;
                    207:            me->size = bufsize;
2.5.2.2   frystyk   208:            me->target = HTWriter_new(host, ch, param, 0);
                    209:            me->host = host;
2.5.2.3 ! frystyk   210:            me->delay_output = YES;
        !           211:            me->delay_ms = 10000;
2.5.2.2   frystyk   212:            return me;
                    213:        }
2.1       frystyk   214:     }
                    215:     return NULL;
                    216: }

Webmaster