aboutsummaryrefslogtreecommitdiff
path: root/src/bufio/writer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bufio/writer.c')
-rw-r--r--src/bufio/writer.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/bufio/writer.c b/src/bufio/writer.c
new file mode 100644
index 0000000..07573d5
--- /dev/null
+++ b/src/bufio/writer.c
@@ -0,0 +1,95 @@
+#include "impl.h"
+
+struct bufio·Writer
+{
+ io·Writer w;
+ Buffer buf;
+};
+
+// Constructor/destructor.
+
+bufio·Writer*
+bufio·newwriter(io·Writer w)
+{
+ bufio·Writer* bw = newbuffer(offsetof(bufio·Writer, buf), 0);
+ bw->w = w;
+ bw->buf.pos = bw->buf.base;
+
+ return bw;
+}
+
+error
+bufio·freewriter(bufio·Writer* w)
+{
+ free(w);
+
+ return 0;
+}
+
+// Write will write n bytes from the input buffer into the storage buffer.
+// Returns the actual number of bytes written.
+int
+bufio·write(bufio·Writer* w, byte* buf, int count)
+{
+ int remain = count;
+ byte* wtr = buf;
+
+ int n, nw;
+ while (remain > 0) {
+ int bdiff = w->buf.end - w->buf.pos;
+ n = (bdiff > remain) ? remain : bdiff;
+ if (!n) {
+ if (w->buf.eof) break;
+ nw = w->w.write(w->w.impl, buf, count);
+ if (nw < w->buf.size) {
+ w->buf.eof = 1;
+ return BUF·err;
+ }
+ w->buf.off += nw;
+ w->buf.pos = w->buf.base;
+ }
+ memmove(w->buf.pos, wtr, n);
+ wtr += n;
+ w->buf.pos += n;
+ remain -= n;
+ }
+
+ return count - remain;
+}
+
+error
+bufio·put(bufio·Writer* w, byte c)
+{
+ int diff;
+putbyte:
+ diff = w->buf.end - w->buf.pos;
+ if (diff) {
+ *w->buf.pos++ = c;
+ return 0;
+ }
+ if (bufio·flush(w) != BUF·err) goto putbyte;
+
+ return BUF·err;
+}
+
+error
+bufio·flush(bufio·Writer* w)
+{
+ int active = (w->buf.eof == 0);
+
+ int n, nw;
+ if (active && w) {
+ n = w->buf.pos - w->buf.base;
+ if (!n) return 0;
+
+ nw = w->w.write(w->w.impl, w->buf.base, n);
+ if (nw == n) {
+ w->buf.off += n;
+ return 0;
+ }
+ w->buf.eof = 1;
+ w->buf.pos = w->buf.end;
+ }
+
+ return BUF·err;
+}