From c8e1e71eb526475dd431443345262c2e5a627831 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Sat, 23 Oct 2021 11:17:25 -0700 Subject: chore(rename): libn -> base --- sys/base/bufio.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 sys/base/bufio.c (limited to 'sys/base/bufio.c') diff --git a/sys/base/bufio.c b/sys/base/bufio.c new file mode 100644 index 0000000..7ebee68 --- /dev/null +++ b/sys/base/bufio.c @@ -0,0 +1,190 @@ +#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; + + 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; + + // TEST: put a physical EOF byte at the end + // this would allow for an unget operation + if (n < buf->size) + *buf->end++ = EOF; + + 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) +{ + 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·bytetorune(&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) +{ + 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 -- cgit v1.2.1