Annotation of libwww/Library/src/HTTee.c, revision 2.20
2.5 frystyk 1: /* HTee.c
2: ** TEE CLASS STREAM DEFINITION
3: **
2.9 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.5 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.20 ! frystyk 6: ** @(#) $Id: HTTee.c,v 2.19 1998/05/04 19:37:33 frystyk Exp $
2.1 timbl 7: **
8: ** The Tee class just writes to two streams. Easy.
9: ** See also the Black Hole stream which is even easier.
2.3 duns 10: **
11: ** HISTORY:
12: ** 8 Jul 94 FM Insulate free() from _free structure element.
13: **
2.1 timbl 14: */
15:
2.7 frystyk 16: /* Library include files */
2.19 frystyk 17: #include "wwwsys.h"
2.18 frystyk 18: #include "WWWUtil.h"
2.1 timbl 19: #include "HTTee.h"
20:
21: /* Stream Object
22: ** ------------
23: */
24:
25: struct _HTStream {
2.15 frystyk 26: const HTStreamClass * isa;
2.13 frystyk 27: HTStream * s1;
28: HTStream * s2;
29: HTComparer * resolver;
2.1 timbl 30: };
31:
2.13 frystyk 32: /*
33: ** Algorithm produced by H&kon
34: */
2.15 frystyk 35: PRIVATE int default_resolver (const void *a, const void *b)
2.13 frystyk 36: {
37: if (*(int *) a < 0)
38: return *(int *) a;
39: if (*(int *) b < 0)
40: return *(int *) b;
41: if (*(int *) a == 0)
42: return *(int *) b;
43: return *(int *) a;
44: }
2.1 timbl 45:
2.11 frystyk 46: PRIVATE int HTTee_put_character (HTStream * me, char c)
2.1 timbl 47: {
2.8 frystyk 48: int ret1 = (*me->s1->isa->put_character)(me->s1, c);
49: int ret2 = (*me->s2->isa->put_character)(me->s2, c);
2.13 frystyk 50: return me->resolver(&ret1, &ret2);
2.1 timbl 51: }
2.8 frystyk 52:
2.15 frystyk 53: PRIVATE int HTTee_put_string (HTStream * me, const char* s)
2.1 timbl 54: {
2.8 frystyk 55: int ret1 = (*me->s1->isa->put_string)(me->s1, s);
56: int ret2 = (*me->s2->isa->put_string)(me->s2, s);
2.13 frystyk 57: return me->resolver(&ret1, &ret2);
2.1 timbl 58: }
2.8 frystyk 59:
2.15 frystyk 60: PRIVATE int HTTee_write (HTStream * me, const char* s, int l)
2.1 timbl 61: {
2.8 frystyk 62: int ret1 = (*me->s1->isa->put_block)(me->s1, s, l);
63: int ret2 = (*me->s2->isa->put_block)(me->s2, s, l);
2.13 frystyk 64: return me->resolver(&ret1, &ret2);
2.1 timbl 65: }
2.8 frystyk 66:
2.11 frystyk 67: PRIVATE int HTTee_flush (HTStream * me)
2.8 frystyk 68: {
69: int ret1 = (*me->s1->isa->flush)(me->s1);
70: int ret2 = (*me->s2->isa->flush)(me->s2);
2.13 frystyk 71: return me->resolver(&ret1, &ret2);
2.8 frystyk 72: }
73:
2.17 frystyk 74: /*
75: ** BUGS: We do not handle WOULD_BLOCK here. This is tricky as we don't
76: ** know which one actually blocked.
77: */
2.11 frystyk 78: PRIVATE int HTTee_free (HTStream * me)
2.1 timbl 79: {
2.18 frystyk 80: if (me) {
81: int ret1 = me->s1 ? (*me->s1->isa->_free)(me->s1) : HT_OK;
82: int ret2 = me->s2 ? (*me->s2->isa->_free)(me->s2) : HT_OK;
83: int ret = me->resolver(&ret1, &ret2);
84: me->s1 = me->s2 = NULL;
85: HT_FREE(me);
86: return ret;
87: }
88: return HT_OK;
2.1 timbl 89: }
2.8 frystyk 90:
2.11 frystyk 91: PRIVATE int HTTee_abort (HTStream * me, HTList * e)
2.1 timbl 92: {
2.18 frystyk 93: if (me) {
94: if (me->s1) (*me->s1->isa->abort)(me->s1, e);
95: if (me->s2) (*me->s2->isa->abort)(me->s2, e);
96: me->s1 = me->s2 = NULL;
97: HT_FREE(me);
98: }
2.8 frystyk 99: return HT_ERROR;
2.1 timbl 100: }
101:
102:
103: /* Tee stream
104: ** ----------
105: */
2.15 frystyk 106: PRIVATE const HTStreamClass HTTeeClass =
2.1 timbl 107: {
108: "Tee",
2.8 frystyk 109: HTTee_flush,
2.1 timbl 110: HTTee_free,
111: HTTee_abort,
112: HTTee_put_character, HTTee_put_string,
113: HTTee_write
114: };
115:
116:
2.13 frystyk 117: /* Tee Stream creation
118: ** -------------------
119: ** You can create a T stream using this method. Each stream returns a
120: ** return value and in order to resolve conflicts in the return code
121: ** you can specify a resolver callback function. Each time any of the
122: ** data methods are called the resolver function is then called with
123: ** the return codes from the two streams. The return code of the T stream
124: ** itself will be the result of the resolver function. If you pass NULL
125: ** as the resolver routine then a default resolver is used.
2.1 timbl 126: */
2.13 frystyk 127: PUBLIC HTStream * HTTee(HTStream * s1, HTStream * s2, HTComparer * resolver)
2.1 timbl 128: {
2.14 frystyk 129: HTStream * me;
130: if ((me = (HTStream *) HT_CALLOC(1, sizeof(*me))) == NULL)
131: HT_OUTOFMEM("HTTee");
2.1 timbl 132: me->isa = &HTTeeClass;
2.18 frystyk 133: me->s1 = s1 ? s1 : HTBlackHole();
134: me->s2 = s2 ? s2 : HTBlackHole();
2.13 frystyk 135: me->resolver = resolver ? resolver : default_resolver;
2.20 ! frystyk 136: HTTRACE(STREAM_TRACE, "Tee......... Created stream %p with resolver %p\n" _
! 137: me _ me->resolver);
2.1 timbl 138: return me;
139: }
140:
141:
Webmaster