#include #include "stringgetter.h" typedef enum { SGT_PULL = 1, SGT_PUSH, } SGT; struct stringgetter { SGT type; union { struct { unsigned char *b; int a; int (*get)(void *); int (*term)(unsigned char, void *); void *arg; } pull; struct { unsigned char *b; int a; int n; void (*done)(STRINGGOT, void *); int (*term)(unsigned char, void *); void *arg; } push; } ; } ; STRINGGETTER *sg_init_pull(int (*get)(void *), int (*term)(unsigned char, void *), void *arg) { STRINGGETTER *g; g = malloc(sizeof(STRINGGETTER)); g->type = SGT_PULL; g->pull.b = 0; g->pull.a = 0; g->pull.get = get; g->pull.term = term; g->pull.arg = arg; return(g); } STRINGGETTER *sg_init_push(void (*done)(STRINGGOT, void *), int (*term)(unsigned char, void *), void *arg) { STRINGGETTER *g; g = malloc(sizeof(STRINGGETTER)); g->type = SGT_PUSH; g->push.b = 0; g->push.a = 0; g->push.n = 0; g->push.done = done; g->push.term = term; g->push.arg = arg; return(g); } void sg_done(STRINGGETTER *g) { switch (g->type) { case SGT_PULL: free(g->pull.b); break; case SGT_PUSH: free(g->push.b); break; default: abort(); break; } free(g); } STRINGGOT sg_get(STRINGGETTER *g) { int l; int c; STRINGGOT rv; void save(unsigned char ch) { if (l >= g->pull.a) g->pull.b = realloc(g->pull.b,g->pull.a=l+8); g->pull.b[l++] = ch; } if (g->type != SGT_PULL) abort(); l = 0; while (1) { c = (*g->pull.get)(g->pull.arg); if (c == EOF) { rv.len = -1; rv.str = 0; return(rv); } if ((*g->pull.term)(c,g->pull.arg)) { rv.len = l; save('\0'); rv.str = g->pull.b; return(rv); } save(c); } } void sg_put(STRINGGETTER *g, int ch) { void save(unsigned char ch) { if (g->push.n >= g->push.a) g->push.b = realloc(g->push.b,g->push.a=g->push.n+8); g->push.b[g->push.n++] = ch; } if (g->type != SGT_PUSH) abort(); if (ch == EOF) { (*g->push.done)((STRINGGOT){.len=-1,.str=0},g->push.arg); return; } if ((*g->push.term)(ch,g->push.arg)) { save('\0'); (*g->push.done)((STRINGGOT){.len=g->push.n-1,.str=g->push.b},g->push.arg); g->push.n = 0; } else { save(ch); } } /* XXX shouldn't have to cast arg to getc, but it's a macro. :-þ */ int sg_get_stdio(void *arg) { return(getc((FILE *)arg)); } int sg_term_nul(unsigned char ch, void *arg __attribute__((__unused__))) { return(!ch); } int sg_term_nl(unsigned char ch, void *arg __attribute__((__unused__))) { return(ch=='\n'); }