#include #include #include #include #include #define tmalloc(type) malloc(sizeof(type)) #define tnmalloc(type, n) malloc(sizeof(type) * n) struct block { char *start; int size; }; struct block *block_new(this, size) struct block *this; int size; { this->start = malloc(size); this->size = size; return this; } struct block *block_delete(this) struct block *this; { free(this->start); return this; } int block_find_char(this, start, to_find) struct block *this; int start; char to_find; { char *p, *end; p = this->start + start; end = this->start + this->size; for (; p != end; ++p) if (*p == to_find) return p - this->start; return -1; } ssize_t block_write(this, fd) struct block *this; int fd; { return write(fd, this->start, this->size); } struct vblock { char *start; int size; int alloc; }; struct vblock *vblock_new(this, size) struct vblock *this; int size; { this->start = malloc(size); this->size = this->alloc = size; return this; } int min(a, b) int a, b; { return a < b ? a : b; } int max(a, b) int a, b; { return a > b ? a : b; } void vblock_resize(this, new_size) struct vblock *this; int new_size; { if (this->alloc < new_size) { this->alloc = max(new_size, 2 * (this->alloc)); this->start = realloc(this->start, this->alloc); } this->size = new_size; } struct vblock *vblock_delete(this) struct vblock *this; { free(this->start); return this; } void vblock_append_block(this, to_append) struct vblock *this; struct block *to_append; { int old_size = this->size; vblock_resize(this, old_size + to_append->size); memcpy(this->start + old_size, to_append->start, to_append->size); } struct stream_splitter { enum stream_splitter_state { accumulating, line_ready } state; struct vblock buf; struct block *output; }; struct stream_splitter *stream_splitter_new(this) struct stream_splitter *this; { this->state = accumulating; vblock_new(&this->buf, 0); return this; } void _stream_splitter_check_for_delimiter(this, start) struct stream_splitter *this; int start; { int line_size; if ((line_size = block_find_char((struct block *)&this->buf, start, '\n')) >= 0) { this->output = tmalloc(struct block); block_new(this->output, line_size); memcpy(this->output->start, this->buf.start, line_size); line_size++; this->buf.size -= line_size; memmove(this->buf.start, this->buf.start + line_size, this->buf.size); this->state = line_ready; } else { this->state = accumulating; } } void stream_splitter_push_input(this, input) struct stream_splitter *this; struct block *input; { int old_size; assert(this->state == accumulating); old_size = this->buf.size; vblock_append_block(&this->buf, input); _stream_splitter_check_for_delimiter(this, old_size); } struct block *stream_splitter_pop_output(this) struct stream_splitter *this; { struct block *output; assert(this->state == line_ready); output = this->output; _stream_splitter_check_for_delimiter(this, 0); return output; } int main(argc, argv) int argc; char **argv; { struct stream_splitter *ss; struct vblock *in; struct block *out; char *text = "Hello World!\nI wonder if this will work?\nI'd like to say "; stream_splitter_new(ss = tmalloc(struct stream_splitter)); in = vblock_new(tmalloc(struct vblock), strlen(text)); memcpy(in->start, text, strlen(text)); stream_splitter_push_input(ss, in); while (ss->state == line_ready) { out = stream_splitter_pop_output(ss); block_write(out, STDOUT_FILENO); write(STDOUT_FILENO, "\n", 1); } assert(ss->buf.size != 0); stream_splitter_push_input(ss, in); while (ss->state == line_ready) { out = stream_splitter_pop_output(ss); block_write(out, STDOUT_FILENO); write(STDOUT_FILENO, "\n", 1); } assert(ss->state == accumulating); assert(ss->buf.size == 16); return 0; }