synchronous stream implementation in C
FILE *infile, *outfile; infile = fopen("src/stream.c", "r"); outfile = stdout; sst_file_t *infs = sst_file_new(infile, NULL); infs->end_cb = oninfile_end; sst_t *tx = sst_new(); tx->write = tx_write; tx->end_cb = ontx_end; sst_file_t *outfs = sst_file_new(outfile, NULL); outfs->end_cb = onoutfile_end; sst_pipe((sst_t*)infs, tx, (sst_t*)outfs); sst_file_write_init(outfs); sst_file_read_start(infs);
clib install thlorenz/sync-stream.c
enum sst_encoding { UTF8 = 0x0 , BASE64 = 0x2 , HEX = 0x4 , CUSTOM = 0x1000 }; /* * chunk */ typedef struct sst_chunk_s sst_chunk_t; typedef void (*sst_chunk_data_free_cb)(void*); /* * chunk struct * * @data the data transmitted with the chunk * @enc (default: UTF8) encoding of the data * @free_data (default: NULL) is invoked when the chunk is freed in order to ensure data is freed properly * @error (default: 0) set this to a non-zero value to signal an error * @ctx set this to anything you need to track */ struct sst_chunk_s { void *data; enum sst_encoding enc; void (*free_data)(void*); int error; void* ctx; }; /* * Initializes new chunk and returns the result. * * @see chunk struct for more initialization options * * @data data to transport with the chunk * @free_data (default: NULL) is invoked when the chunk is freed in order to ensure data is freed properly * since we know best how to free the data when we create the chunk, we provide it here * if the data doesn't need to be freed, i.e. because it isn't allocated pass NULL * @return chunk */ sst_chunk_t *sst_chunk_new(void* data, void (*free_data)(void*)); /** * frees the chunk * * @chunk the chunk to free */ void sst_chunk_free(sst_chunk_t* chunk); /* * stream */ typedef struct sst_s sst_t; /* callbacks */ typedef void ( *sst_write_cb) ( sst_t*, sst_chunk_t*); typedef void ( *sst_emit_cb) ( sst_t*, sst_chunk_t*); typedef void ( *sst_end_cb) ( sst_t*); #define SST_FIELDS \ sst_write_cb write; \ sst_emit_cb emit_cb; \ sst_end_cb end_cb; \ \ /* readonly */ \ sst_emit_cb emit; \ sst_end_cb end; \ \ /* private */ \ \ /* the stream upstream from this stream and thus the source of all data */ \ /* we track it here only to be able to free it later */ \ sst_t *_source; \ \ /* the stream downstream from this stream, if set all emitted chunk will be written it */ \ sst_t *_destination; /* * stream struct * * @write call this with a @see chunk in order to feed data into the stream * @emit_cb if provided, it is called with every chunk emitted by the stream * @end_cb if provided, it is called when the stream ends * @emit call this to emit a chunk * @end call this to signal that no more data will be written to the stream */ struct sst_s { SST_FIELDS }; /** * Initializes a stream and returns it * @see stream struct for more initializiation options * * @return stream */ sst_t* sst_new(); /** * Frees the given stream and walks up the `_source`s to free all streams that are upstream as well * * @self the stream to free */ void sst_free(sst_t* self); /** * Pipes the source stream into the destination stream(s). * All chunks emitted by the source are now written to the destination(s). * * When source ends, destinations are ended as well. * * When most downstream destination is freed, * all other destinations and the source are freed as well. * * @source upstream source * @... followed by the downstream destination(s) which get chained together to form one pipe */ void sst__pipe(sst_t** streams); #define sst_pipe(source, ...) { \ sst_t** streams = (sst_t*[]) { source, __VA_ARGS__, NULL }; \ sst__pipe(streams); \ } /* * file stream */ typedef struct sst_file_s sst_file_t; /* file stream struct * * extends stream struct * * @file the open file to read from or write to * @free_file (default: NULL) is invoked when the file stream is freed in order to free file if needed * if the data doesn't need to be freed, i.e. because it isn't allocated pass NULL * @bufsize (default: BUFSIZ) size of buffers to write */ struct sst_file_s { SST_FIELDS FILE *file; void (*free_file)(void*); size_t bufsize; short free_onend; }; /** * Initializes a file stream from the given file. * * @file the file to wrap in a stream * @free_file invoked when the file stream is freed in order to ensure file is freed properly * ensure that the file is closed however * if the file doesn't need to be freed, i.e. because it isn't allocated pass NULL * @return file stream wrapping the file */ sst_file_t *sst_file_new(FILE *file, void (*free_file)(void*)); /** * Frees the file stream including the FILE it is wrapping. * Note: the underlying file handle is assumed to be closed at this point. * * @self the file stream */ void sst_file_free(sst_file_t* self); /** * Starts reading from the wrapped file. * For each read buffer a chunk is `emit`ted. * Note: file is assumed to be open at this point. * * When all chunks were read the stream invokes `end`. * * @self file stream */ void sst_file_read_start(sst_file_t* self); /** * Initializes file stream for writing. * Note: file is assumed to be open at this point and needs to manually be closed before freeing the stream. * * All values written to the stream wrapper are `fputs`ed to the underlying file. * After chunks were written they are freed automatically. * @self the file stream */ void sst_file_write_init(sst_file_t* self); #endif
MIT
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4