#include #include // ----------------------------------------------------------------------- // reader error bufio·initreader(io·Buffer *buf, io·Reader rdr, void *h) { if (buf->state) { errorf("attemped to initialize an active buffer, state is '%d'", buf->state); return bufio·err; } buf->state = bufio·rdr; buf->runesize = 0; buf->h = h; buf->rdr = rdr; buf->beg = buf->buf + bufio·ungets; buf->pos = buf->beg; buf->end = buf->pos; buf->size = bufio·size - bufio·ungets; return 0; } void bufio·finireader(io·Buffer *buf) { buf->state = bufio·nil; buf->runesize = 0; buf->rdr = (io·Reader){ .read = nil }; } static int refill(io·Buffer *buf) { int n, d; if (buf->state & bufio·end) { return bufio·err; } memcpy(buf->buf, buf->pos - bufio·ungets, bufio·ungets); n = buf->rdr.read(buf->h, 1, buf->size, buf->beg); if (n < 0) return bufio·err; if (n == 0) { buf->state |= bufio·end; return 0; } buf->pos = buf->beg; buf->end = buf->pos + n; return n; } int bufio·getbyte(io·Buffer *buf) { getbyte: if (buf->pos < buf->end) { return *buf->pos++; } memmove(buf->buf, buf->end - bufio·ungets, bufio·ungets); if (refill(buf) <= 0) return bufio·eof; goto getbyte; } error bufio·ungetbyte(io·Buffer *buf, byte c) { buf->state ^= bufio·end; if (buf->state & bufio·rdr) { errorf("attempted to unget on non-active reader"); return bufio·err; } if (buf->pos == buf->buf) { errorf("attempted to unget past end of buffer"); return bufio·err; } buf->pos--; return 0; } rune bufio·getrune(io·Buffer *buf) { ubyte b; int i; byte str[UTFmax+1]; rune r; // NOTE: I'm worried about the sign here... b = bufio·getbyte(buf); if (b < RuneSelf) { buf->runesize = 1; return b; } i = 0; str[i++] = b; nextbyte: b = bufio·getbyte(buf); if (b < 0) return b; if (i >= arrlen(str)) return RuneErr; str[i++] = b; if (!utf8·fullrune(str, i)) goto nextbyte; buf->runesize = utf8·chartorune(&r, str); if (r == RuneErr && b == 1) { errorf("illegal UTF-8 sequence"); for (; i >= 0; i--) errorf("%s%.2x", i > 0 ? " " : "", *(ubyte*)(str+i)); errorf("\n"); buf->runesize = 0; } else for (; i > buf->runesize; i--) bufio·ungetbyte(buf, str[i]); return r; } // TODO: Check that we are given the correct rune! error bufio·ungetrune(io·Buffer *buf, rune r) { buf->state ^= bufio·end; if (buf->state & bufio·rdr) { errorf("attempted to unget on non-active reader"); return bufio·err; } if (buf->pos == buf->buf) { errorf("attempted to unget past end of buffer"); return bufio·err; } buf->pos -= buf->runesize; return 0; } int bufio·read(io·Buffer *buf, int sz, int n, void *out) { byte *wtr; int nr, rem, diff; if (n == 0 || buf->state & bufio·end) return bufio·err; assert(buf->state & bufio·rdr); wtr = out; rem = n*sz; while (rem > 0) { diff = buf->end - buf->pos; nr = MIN(diff, rem); if (!nr) { if (buf->state & bufio·end) break; if (refill(buf) <= 0) break; continue; } memmove(wtr, buf->pos, nr); wtr += nr; buf->pos += nr; rem -= nr; } return n - rem/sz; } // ----------------------------------------------------------------------- // writer