aboutsummaryrefslogtreecommitdiff
path: root/sys/libn/bufio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/libn/bufio.c')
-rw-r--r--sys/libn/bufio.c206
1 files changed, 185 insertions, 21 deletions
diff --git a/sys/libn/bufio.c b/sys/libn/bufio.c
index 6b15760..38714a5 100644
--- a/sys/libn/bufio.c
+++ b/sys/libn/bufio.c
@@ -1,33 +1,197 @@
#include <u.h>
#include <libn.h>
-enum
+// -----------------------------------------------------------------------
+// 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 = buf->end - buf->beg;
+
+ 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;
+ }
+
+ n = buf->rdr.read(buf->h, 1, buf->size, buf->buf);
+ if (n < 0)
+ return bufio·err;
+ if (n == 0) {
+ buf->state |= bufio·end;
+ return 0;
+ }
+
+ if (n < buf->size) {
+ d = buf->size - n;
+
+ buf->state |= bufio·end;
+
+ memmove(buf->pos + d, buf->pos, n);
+ memmove(buf->pos + d - bufio·ungets, buf->buf, bufio·ungets);
+ }
+
+ 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·size = 8 * 2048,
- BUF·ungets = 8,
+ buf->state ^= bufio·end;
+ if (buf->state & bufio·rdr) {
+ errorf("attempted to unget on non-active reader");
+ return bufio·err;
+ }
- BUF·bad = -2,
- BUF·eof = -1,
+ if (buf->pos == buf->buf) {
+ errorf("attempted to unget past end of buffer");
+ return bufio·err;
+ }
- BUF·inactive = 0,
- BUF·rdractive,
- BUF·wtractive,
+ if (c != *buf->pos) {
+ errorf("unget char does not match");
+ return bufio·err;
+ }
- BUF·END,
-} bmode;
+ buf->pos--;
+ return 0;
+}
-typedef struct Buffer
+rune
+bufio·getrune(io·Buffer *buf)
{
- uint8 state;
- vlong off;
- vlong size;
+ 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;
- byte *bbuf, *ebuf;
- byte b[BUF·size + BUF·ungets];
-} Buffer;
+ 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");
-struct bufio·Stream
+ 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)
{
- Stream *s;
- Buffer buf;
-};
+ 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