tomwalters@0: /* tomwalters@0: fillable.c tomwalters@0: ========== tomwalters@0: tomwalters@0: Sources whose native mode of operation is the fill entry point. tomwalters@0: They may be pulled in which case a buffer is allocated. tomwalters@0: tomwalters@0: */ tomwalters@0: tomwalters@0: #include "stitch.h" tomwalters@0: #include "source.h" tomwalters@0: tomwalters@0: #ifndef lint tomwalters@0: static char *sccs_id = "@(#)fillable.c 1.2 John Holdsworth (MRC-APU) 11/8/90" ; tomwalters@0: #endif tomwalters@0: tomwalters@0: #if 0 tomwalters@0: #define DEBUG 1 tomwalters@0: #endif tomwalters@0: tomwalters@0: Source SharingSource( source1, source2 ) tomwalters@0: struct _fillable_source *source1, *source2 ; tomwalters@0: { tomwalters@0: DeleteBuffer( source1->buffer ) ; tomwalters@0: tomwalters@0: source1->buffer = SharedBuffer( source2->buffer ) ; tomwalters@0: tomwalters@0: return ( (Source) source1 ) ; tomwalters@0: } tomwalters@0: tomwalters@0: /* converter of pull command to fill commands */ tomwalters@0: tomwalters@0: static Pointer pullFromFillable( source, bytes ) tomwalters@0: struct _fillable_source *source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: { tomwalters@0: #if DEBUG tomwalters@0: printf( "buffering pulling from passive \"%s\", %d bytes\n", SourceName( source ), *bytes ) ; tomwalters@0: #endif tomwalters@0: #if 00 tomwalters@0: if( source->bsize < *bytes ) { tomwalters@0: tomwalters@0: if( source->bsize != 0 ) tomwalters@0: Delete( source->buffer ) ; tomwalters@0: tomwalters@0: source->buffer = Allocate( *bytes, "fillable.c for source buffer" ) ; tomwalters@0: tomwalters@0: source->bsize = *bytes ; tomwalters@0: } tomwalters@0: #endif tomwalters@0: return ( source->parent.fill( source, bytes, SizedBufferPointer( SourceBuffer( source ), *bytes ) ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: /* constructor for all pullable sources */ tomwalters@0: tomwalters@0: Source setFillableSource( source, filler, name ) tomwalters@0: struct _fillable_source *source ; tomwalters@0: Pointer (*filler)() ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: source->buffer = NewBuffer( "pulling" ) ; tomwalters@0: tomwalters@0: return ( SetSource( source, pullFromFillable, filler, nonRoller, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Pointer deleteFillableSource( source ) tomwalters@0: struct _fillable_source *source ; tomwalters@0: { tomwalters@0: DeleteBuffer( source->buffer ) ; tomwalters@0: tomwalters@0: return ( DeleteSource( source ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /* derived fillable source */ tomwalters@0: tomwalters@0: typedef struct { tomwalters@0: struct _fillable_source parent ; tomwalters@0: Pointer data, end, ptr ; tomwalters@0: } *RepeatingSource ; tomwalters@0: tomwalters@0: static Pointer repeating_callback( source, bytes, buffer ) tomwalters@0: RepeatingSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: register Pointer bptr = buffer ; tomwalters@0: register Pointer bend = buffer + *bytes ; tomwalters@0: register ByteCount segment ; tomwalters@0: tomwalters@0: if( !last ) { tomwalters@0: tomwalters@0: while( bptr < bend ) { tomwalters@0: tomwalters@0: segment = source->end - source->ptr ; tomwalters@0: if( segment > bend - bptr ) tomwalters@0: segment = bend - bptr ; tomwalters@0: tomwalters@0: CopyArray( (char *) source->ptr, (char *) bptr, segment ) ; tomwalters@0: tomwalters@0: source->ptr += segment ; tomwalters@0: bptr += segment ; tomwalters@0: tomwalters@0: if( source->ptr == source->end ) tomwalters@0: source->ptr = source->data ; tomwalters@0: } tomwalters@0: tomwalters@0: return ( buffer ) ; tomwalters@0: } tomwalters@0: else tomwalters@0: return ( DeleteFillableSource( source ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source newRepeatingSource( data, segment ) tomwalters@0: Pointer data ; tomwalters@0: ByteCount segment ; tomwalters@0: { tomwalters@0: DeclareNew( RepeatingSource, source ) ; tomwalters@0: tomwalters@0: source->data = data ; tomwalters@0: source->end = data + segment ; tomwalters@0: tomwalters@0: source->ptr = source->data ; tomwalters@0: tomwalters@0: return ( SetFillableSource( source, repeating_callback, "fillable.c repeating" ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: typedef struct { tomwalters@0: struct _fillable_source parent ; tomwalters@0: Source input ; ByteCount segment ; tomwalters@0: } *SegmentingSource ; tomwalters@0: tomwalters@0: static Pointer segmenting_callback( source, bytes, buffer ) tomwalters@0: SegmentingSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: Pointer bptr = buffer ; tomwalters@0: ByteCount segment ; tomwalters@0: tomwalters@0: do { tomwalters@0: tomwalters@0: segment = source->segment ; tomwalters@0: tomwalters@0: if( segment > buffer + *bytes - bptr ) tomwalters@0: segment = buffer + *bytes - bptr ; tomwalters@0: tomwalters@0: (void) FillSome( source->input, &segment, bptr ) ; tomwalters@0: tomwalters@0: bptr += segment ; tomwalters@0: tomwalters@0: } while ( bptr < buffer + *bytes ) ; tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( buffer ) ; tomwalters@0: else tomwalters@0: return ( DeleteFillableSource( source ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source newSegmentingSource( input, segment ) tomwalters@0: Source input ; tomwalters@0: ByteCount segment ; tomwalters@0: { tomwalters@0: DeclareNew( SegmentingSource, source ) ; tomwalters@0: tomwalters@0: source->input = input ; tomwalters@0: tomwalters@0: source->segment = segment ; tomwalters@0: tomwalters@0: return ( SetFillableSource( source, segmenting_callback, "segmenting" ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: tomwalters@0: /* higher level methods to sources */ tomwalters@0: tomwalters@0: tomwalters@0: typedef struct _callback_source { tomwalters@0: struct _fillable_source parent ; tomwalters@0: Pointer state ; tomwalters@0: void (*callback)(), (*close)() ; tomwalters@0: } *CallbackSource ; tomwalters@0: tomwalters@0: Source setCallbackSource( source, filler, state, callback, close, name ) tomwalters@0: CallbackSource source ; tomwalters@0: Pointer (*filler)() ; tomwalters@0: Pointer state ; tomwalters@0: void (*callback)(), (*close)() ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: source->state = state ; tomwalters@0: source->callback = callback ; tomwalters@0: source->close = close ; tomwalters@0: tomwalters@0: return ( SetFillableSource( source, filler, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source newCallbackSource( filler, state, callback, close, name ) tomwalters@0: Pointer (*filler)() ; tomwalters@0: Pointer state ; tomwalters@0: void (*callback)(), (*close)() ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: return ( setCallbackSource( New( CallbackSource ), filler, state, callback, close, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: static Pointer externalFiller( source, bytes, buffer ) tomwalters@0: CallbackSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: tomwalters@0: source->callback( source->state, bytes, buffer, buffer+*bytes ) ; tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( buffer ) ; tomwalters@0: else { tomwalters@0: if( source->close != (void ( * )()) 0 ) tomwalters@0: source->close( source->state ) ; tomwalters@0: tomwalters@0: return ( DeleteFillableSource( source ) ) ; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: Source newExternalSource( state, callback, close, name ) tomwalters@0: Pointer state ; tomwalters@0: void (*callback)(), (*close)() ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: return ( newCallbackSource( externalFiller, state, callback, close, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: typedef struct _through_source { tomwalters@0: struct _callback_source parent ; tomwalters@0: Source input ; tomwalters@0: } *ThroughSource ; tomwalters@0: tomwalters@0: static Source setThroughSource( source, filler, state, callback, close, input, name ) tomwalters@0: ThroughSource source ; tomwalters@0: Pointer (*filler)() ; tomwalters@0: Pointer state ; tomwalters@0: void (*callback)(), (*close)() ; tomwalters@0: Source input ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: source->input = input ; tomwalters@0: tomwalters@0: return ( setCallbackSource( (CallbackSource) source, filler, state, callback, close, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source newThroughSource( filler, state, callback, close, input, name ) tomwalters@0: Pointer (*filler)(), state ; tomwalters@0: void (*callback)(), (*close)() ; tomwalters@0: Source input ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: return ( setThroughSource( New( ThroughSource ), filler, state, callback, close, input, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: static Pointer processingFiller( source, bytes, buffer ) tomwalters@0: ThroughSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: tomwalters@0: source->parent.callback( source->parent.state, bytes, buffer, buffer+*bytes, PullSome( source->input, bytes ) ) ; tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( buffer ) ; tomwalters@0: else { tomwalters@0: if( source->parent.close != (void ( * )()) 0 ) tomwalters@0: source->parent.close( source->parent.state ) ; tomwalters@0: tomwalters@0: return ( DeleteFillableSource( &source->parent ) ) ; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: Source newProcessingSource( state, callback, close, input, name ) tomwalters@0: Pointer state ; tomwalters@0: void (*callback)(), (*close)() ; tomwalters@0: Source input ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: return ( newThroughSource( processingFiller, state, callback, close, input, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source newSimpleProcessingSource( callback, input, name ) tomwalters@0: void (*callback)() ; tomwalters@0: Source input ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: return ( NewProcessingSource( (Pointer) 0, callback, (void ( * )()) 0, input, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: typedef struct { tomwalters@0: struct _fillable_source parent ; tomwalters@0: Pointer *states ; tomwalters@0: int (*callback)() ; tomwalters@0: void (*close)() ; tomwalters@0: int channels ; tomwalters@0: Source input ; tomwalters@0: } *MultiplexedSource ; tomwalters@0: tomwalters@0: static Pointer multiplexed_callback( source, bytes, buffer ) tomwalters@0: MultiplexedSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: Pointer iptr = PullSome( source->input, bytes ) ; tomwalters@0: Pointer optr = buffer ; tomwalters@0: Pointer end = buffer + *bytes ; tomwalters@0: ByteCount data_size ; tomwalters@0: int channel ; tomwalters@0: tomwalters@0: for( channel=0 ; channelchannels ; channel++ ) { tomwalters@0: data_size = source->callback( source->states[channel], optr, end, iptr, source->channels ) ; tomwalters@0: iptr += data_size ; tomwalters@0: optr += data_size ; tomwalters@0: } tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( buffer ) ; tomwalters@0: else { tomwalters@0: if( source->close != (void ( * )()) 0 ) tomwalters@0: for( channel=0 ; channelchannels ; channel++ ) tomwalters@0: source->close( source->states[channel] ) ; tomwalters@0: tomwalters@0: Delete( source->states ) ; tomwalters@0: tomwalters@0: return ( DeleteFillableSource( source ) ) ; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: Source newMultiplexedSource( states, callback, close, channels, input, name ) tomwalters@0: Pointer *states ; tomwalters@0: int (*callback)() ; tomwalters@0: void (*close)() ; tomwalters@0: int channels ; tomwalters@0: Source input ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: DeclareNew( MultiplexedSource, source ) ; tomwalters@0: tomwalters@0: source->states = states ; tomwalters@0: source->callback = callback ; tomwalters@0: source->close = close ; tomwalters@0: source->channels = channels ; tomwalters@0: tomwalters@0: source->input = input ; tomwalters@0: tomwalters@0: return ( SetFillableSource( source, multiplexed_callback, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: typedef struct _merging_source { tomwalters@0: struct _callback_source parent ; Source *inputs ; tomwalters@0: } *MergingSource ; tomwalters@0: tomwalters@0: static Pointer mergingFiller( source, bytes, buffer ) tomwalters@0: MergingSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: Pointer input1, input2 ; tomwalters@0: int n ; tomwalters@0: tomwalters@0: input1 = PullSome( source->inputs[0], bytes ) ; tomwalters@0: tomwalters@0: for( n=1 ; _SPTR( source->inputs[n] ) != (struct _source *) 0 ; n++ ) { tomwalters@0: tomwalters@0: input2 = PullSome( source->inputs[n], bytes ) ; tomwalters@0: tomwalters@0: source->parent.callback( source->parent.state, bytes, buffer, buffer+*bytes, input1, input2 ) ; tomwalters@0: tomwalters@0: input1 = buffer ; tomwalters@0: } tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( buffer ) ; tomwalters@0: else { tomwalters@0: Delete( source->inputs ) ; tomwalters@0: tomwalters@0: return ( DeleteFillableSource( &source->parent ) ) ; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: Source newMergingSource( state, callback, close, inputs, name ) tomwalters@0: Pointer state ; tomwalters@0: void (*callback)(), (*close)() ; tomwalters@0: Source *inputs ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: DeclareNew( MergingSource, source ) ; tomwalters@0: tomwalters@0: source->inputs = inputs ; tomwalters@0: tomwalters@0: return ( setCallbackSource( (CallbackSource) source, mergingFiller, state, callback, close, name ) ) ; tomwalters@0: } tomwalters@0: