aboutsummaryrefslogtreecommitdiff
path: root/src/base/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/io')
-rw-r--r--src/base/io/close.c7
-rw-r--r--src/base/io/fd.c7
-rw-r--r--src/base/io/flush.c33
-rw-r--r--src/base/io/get.c7
-rw-r--r--src/base/io/getc.c45
-rw-r--r--src/base/io/getr.c29
-rw-r--r--src/base/io/init.c102
-rw-r--r--src/base/io/interface.c70
-rw-r--r--src/base/io/internal.h4
-rw-r--r--src/base/io/offset.c24
-rw-r--r--src/base/io/open.c27
-rw-r--r--src/base/io/openfd.c12
-rw-r--r--src/base/io/print.c14
-rw-r--r--src/base/io/putbyte.c7
-rw-r--r--src/base/io/putc.c19
-rw-r--r--src/base/io/putstring.c7
-rw-r--r--src/base/io/read.c53
-rw-r--r--src/base/io/readline.c11
-rw-r--r--src/base/io/readln.c12
-rw-r--r--src/base/io/readuntil.c65
-rw-r--r--src/base/io/rules.mk21
-rw-r--r--src/base/io/seek.c54
-rw-r--r--src/base/io/stat.c7
-rw-r--r--src/base/io/tell.c7
-rw-r--r--src/base/io/unget.c7
-rw-r--r--src/base/io/ungetc.c13
-rw-r--r--src/base/io/ungetr.c13
-rw-r--r--src/base/io/vprint.c34
-rw-r--r--src/base/io/write.c39
29 files changed, 588 insertions, 162 deletions
diff --git a/src/base/io/close.c b/src/base/io/close.c
deleted file mode 100644
index 5a773cd..0000000
--- a/src/base/io/close.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "internal.h"
-
-int
-io·close(io·Stream *s)
-{
- return fclose(s);
-}
diff --git a/src/base/io/fd.c b/src/base/io/fd.c
deleted file mode 100644
index ded1b02..0000000
--- a/src/base/io/fd.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "internal.h"
-
-int
-io·fd(io·Stream *s)
-{
- return fileno(s);
-}
diff --git a/src/base/io/flush.c b/src/base/io/flush.c
index 0f1217a..ff970b4 100644
--- a/src/base/io/flush.c
+++ b/src/base/io/flush.c
@@ -1,7 +1,36 @@
#include "internal.h"
int
-io·flush(io·Stream *s)
+io·flush(io·Header *io)
{
- return fflush(s);
+ intptr ni, no;
+
+ switch(io->state){
+ case io·BufWtr:
+ if((ni = io->cap + io->olen))
+ return 0;
+
+ sys·write(io->fd, ni, io->b, &no);
+
+ if(no!=ni){
+ io->pos += ni;
+ io->olen = -io->cap;
+ return 0;
+ }
+
+ io->state = io·BufNil;
+ io->olen = 0;
+ break;
+
+ case io·BufEof:
+ io->state = io·BufRdr;
+ /* fallthrough */
+ case io·BufRdr:
+ io->ilen = 0;
+ io->g = io->e;
+ return 0;
+ default:
+ ;
+ }
+ return io·BufEof;
}
diff --git a/src/base/io/get.c b/src/base/io/get.c
deleted file mode 100644
index d4e52f8..0000000
--- a/src/base/io/get.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "internal.h"
-
-byte
-io·getbyte(io·Stream *s)
-{
- return fgetc(s);
-}
diff --git a/src/base/io/getc.c b/src/base/io/getc.c
new file mode 100644
index 0000000..68e1772
--- /dev/null
+++ b/src/base/io/getc.c
@@ -0,0 +1,45 @@
+#include "internal.h"
+
+int
+io·getc(io·Header *io)
+{
+ int i;
+ intptr nr;
+
+loop:
+ i = io->ilen;
+ if(i != 0){
+ io->ilen = i+1;
+ return io->e[i];
+ }
+
+ if(io->state != io·BufRdr){
+ if(io->state == io·BufEnd)
+ io->state = io·BufRdr;
+ return io·BufEof;
+ }
+
+ /*
+ * get next buffer, try to keep io·BufUngets bytes
+ * pre-catenated from the previous read to allow for ungets
+ */
+ mem·move(io->b-io·BufUngets, io->e-io·BufUngets, io·BufUngets);
+ if(sys·read(io->fd, io->cap, io->b, &nr)){
+ io->state = io·BufNil;
+ return io·BufEof;
+ }
+ if(nr == 0){
+ io->state = io·BufEnd;
+ return io·BufEof;
+ }
+
+ if(nr < io->cap){
+ mem·move(io->e-i-io·BufUngets, io->b-io·BufUngets, i+io·BufUngets);
+ io->g = io->e-i;
+ }
+
+ io->ilen = -i;
+ io->pos += +i;
+
+ goto loop;
+}
diff --git a/src/base/io/getr.c b/src/base/io/getr.c
new file mode 100644
index 0000000..01b0f45
--- /dev/null
+++ b/src/base/io/getr.c
@@ -0,0 +1,29 @@
+#include "internal.h"
+
+rune
+io·getr(io·Header *io)
+{
+ int c, i;
+ rune r;
+ char buf[UTFmax];
+
+ c = io·getc(io);
+ if(utf8·onebyte(c)){
+ io->runesz = 1;
+ return c;
+ }
+ buf[0] = c;
+
+ for(i=1;;){
+ if((c = io·getc(io))<0)
+ return c;
+
+ buf[i++] = c;
+ if(utf8·fullrune(buf, i)){
+ io->runesz = utf8·decode(buf, &r);
+ while(i-- > io->runesz)
+ io·ungetc(io);
+ return r;
+ }
+ }
+}
diff --git a/src/base/io/init.c b/src/base/io/init.c
new file mode 100644
index 0000000..81b26c2
--- /dev/null
+++ b/src/base/io/init.c
@@ -0,0 +1,102 @@
+#include "internal.h"
+
+#define MAXHEADERS 20
+static io·Header *tracked[MAXHEADERS];
+static int doexit;
+
+static void
+untrackall(void *arg)
+{
+ int i;
+ io·Header *it;
+
+ for(i=0; i < MAXHEADERS; i++){
+ it = tracked[i];
+ if(it){
+ tracked[i] = nil;
+ io·flush(it);
+ }
+ }
+}
+
+static void
+untrack(io·Header *io)
+{
+ int i;
+
+ for(i=0; i<arrlen(tracked); i++){
+ if(tracked[i] == io)
+ tracked[i] = nil;
+ }
+}
+
+static void
+track(io·Header *io)
+{
+ int i;
+
+ untrack(io);
+ for(i=0; i<arrlen(tracked); i++){
+ if(!tracked[i]){
+ tracked[i] = io;
+ break;
+ }
+ }
+
+ if(!doexit){
+ doexit = 1;
+ rt·atexit(untrackall, nil);
+ }
+}
+
+int
+io·initcap(io·Header *io, int fd, int mode, int cap, uchar *buf)
+{
+ buf += io·BufUngets;
+ cap += io·BufUngets;
+
+ switch(mode & ~(sys·OCloseExec|sys·OTrunc)){
+ default:
+ /* fmt·fprint(2, "initcap: unknown mode %d\n" , mode); */
+ return io·BufErr;
+ case sys·ORead:
+ io->state = io·BufRdr;
+ io->olen = 0;
+ break;
+ case sys·OWrite:
+ track(io);
+ io->state = io·BufWtr;
+ io->olen = -cap;
+ break;
+ }
+
+ io->b = buf;
+ io->e = buf+cap;
+ io->g = io->e;
+ io->fd = fd;
+ io->cap = cap;
+ io->pos = io->runesz = io->flag = io->ilen = io->nread = 0;
+ return 0;
+}
+
+int
+io·init(io·Buffer *io, int fd, int mode)
+{
+ return io·initcap(header(io), fd, mode, io·BufLen + io·BufUngets, io->bytes);
+}
+
+int
+io·close(io·Header *io)
+{
+ int err;
+
+ untrack(io);
+
+ err = io·flush(io);
+ if(io->flag == io·BufMagic){
+ io->flag = 0;
+ if((err=sys·close(io->fd)))
+ return err;
+ }
+ return 0;
+}
diff --git a/src/base/io/interface.c b/src/base/io/interface.c
deleted file mode 100644
index 80469bf..0000000
--- a/src/base/io/interface.c
+++ /dev/null
@@ -1,70 +0,0 @@
-#include "internal.h"
-
-static
-int
-·read(void *rdr, int size, int n, void *buf)
-{
- return io·read((io·Stream *)rdr, size, n, buf);
-}
-
-static
-byte
-·get(void *rdr)
-{
- return io·getbyte((io·Stream *)rdr);
-}
-
-static
-int
-·unget(void *rdr, byte c)
-{
- return io·ungetbyte((io·Stream *)rdr, c);
-}
-
-static
-int
-·write(void *wtr, int sz, int n, void *buf)
-{
- return io·write((io·Stream *)wtr, sz, n, buf);
-}
-
-static
-int
-·put(void *wtr, byte c)
-{
- return io·putbyte((io·Stream *)wtr, c);
-}
-
-static
-int
-·puts(void *wtr, string s)
-{
- return io·putstring((io·Stream *)wtr, s);
-}
-
-static
-int
-·seek(void *skr, long off, int whence)
-{
- return io·seek((io·Stream *)skr, off, whence);
-}
-
-static
-long
-·tell(void *skr)
-{
- return io·tell((io·Stream *)skr);
-}
-
-/* actual interfaces */
-io·Reader sys·Reader = (io·Reader){ ·read };
-io·Seeker sys·Seeker = (io·Seeker){ ·seek, ·tell };
-io·Peeker sys·Peeker = (io·Peeker){ ·get, ·unget };
-io·SeekReader sys·SeekReader = (io·SeekReader){ ·seek, ·tell, ·read };
-io·PeekReader sys·PeekReader = (io·PeekReader){ ·read, ·get, ·unget };
-
-io·Writer sys·Writer = (io·Writer){ ·write };
-io·Putter sys·Putter = (io·Putter){ ·put, ·puts };
-io·PutWriter sys·PutWriter = (io·PutWriter){ ·write, ·put, ·puts };
-
-io·ReadWriter sys·ReadWriter = (io·ReadWriter){ ·read, ·write };
diff --git a/src/base/io/internal.h b/src/base/io/internal.h
index 302c035..a59e787 100644
--- a/src/base/io/internal.h
+++ b/src/base/io/internal.h
@@ -1,4 +1,4 @@
-#pragma once
-
#include <u.h>
#include <base.h>
+
+#define header(io) ((io·Header*)(io))
diff --git a/src/base/io/offset.c b/src/base/io/offset.c
new file mode 100644
index 0000000..81ef994
--- /dev/null
+++ b/src/base/io/offset.c
@@ -0,0 +1,24 @@
+#include "internal.h"
+
+intptr
+io·offset(io·Header *io)
+{
+ intptr n;
+ switch(io->state){
+ default:
+ fmt·fprint(2, "offset: unknown state %d\n", io->state);
+ n = io·BufEof;
+ break;
+
+ case io·BufEnd:
+ case io·BufRdr:
+ n = io->pos + io->ilen;
+ break;
+
+ case io·BufWtr:
+ n = io->pos + (io->cap + io->olen);
+ break;
+ }
+
+ return n;
+}
diff --git a/src/base/io/open.c b/src/base/io/open.c
index fe78255..ed0be92 100644
--- a/src/base/io/open.c
+++ b/src/base/io/open.c
@@ -1,7 +1,28 @@
#include "internal.h"
-io·Stream*
-io·open(byte *name, byte *mode)
+int
+io·open(char *path, int flag, io·Buffer *io)
{
- return fopen(name, mode);
+ int err,fd;
+ switch(flag & ~(sys·OCloseExec|sys·OTrunc)){
+ default:
+ /* fmt·fprint(2, "open: unknown flag %d\n", flag); */
+ return 1;
+
+ case sys·ORead:
+ if((err=sys·open(path, flag, 0, &fd)))
+ return err;
+ break;
+
+ case sys·OWrite:
+ if((err=sys·open(path, flag, 0666, &fd)))
+ return err;
+ break;
+ }
+
+ if((err=io·openfd(fd, flag, io))){
+ sys·close(fd);
+ return err;
+ }
+ return 0;
}
diff --git a/src/base/io/openfd.c b/src/base/io/openfd.c
new file mode 100644
index 0000000..db13413
--- /dev/null
+++ b/src/base/io/openfd.c
@@ -0,0 +1,12 @@
+#include "internal.h"
+
+int
+io·openfd(int fd, int flag, io·Buffer *io)
+{
+ int err;
+ if((err=io·init(io, fd, flag)))
+ return err;
+
+ io->flag = io·BufMagic;
+ return 0;
+}
diff --git a/src/base/io/print.c b/src/base/io/print.c
new file mode 100644
index 0000000..00d39d9
--- /dev/null
+++ b/src/base/io/print.c
@@ -0,0 +1,14 @@
+#include "internal.h"
+
+int
+io·print(io·Header *io, char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = io·vprint(io, fmt, args);
+ va_end(args);
+
+ return n;
+}
diff --git a/src/base/io/putbyte.c b/src/base/io/putbyte.c
deleted file mode 100644
index 2350a8d..0000000
--- a/src/base/io/putbyte.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "internal.h"
-
-int
-io·putbyte(io·Stream *s, byte c)
-{
- return fputc(c, s);
-}
diff --git a/src/base/io/putc.c b/src/base/io/putc.c
new file mode 100644
index 0000000..167f10f
--- /dev/null
+++ b/src/base/io/putc.c
@@ -0,0 +1,19 @@
+#include "internal.h"
+
+int
+io·putc(io·Header *io, int c)
+{
+ intptr i;
+
+ for(;;){
+ i = io->olen;
+ if(i){
+ io->e[i++] = c;
+ io->olen = i;
+ return 0;
+ }
+ if(io·flush(io) == io·BufEof)
+ break;
+ }
+ return io·BufEof;
+}
diff --git a/src/base/io/putstring.c b/src/base/io/putstring.c
deleted file mode 100644
index 53fa993..0000000
--- a/src/base/io/putstring.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "internal.h"
-
-int
-io·putstring(io·Stream *s, string str)
-{
- return fputs(str, s);
-}
diff --git a/src/base/io/read.c b/src/base/io/read.c
index b0ed3d2..d4f7bd9 100644
--- a/src/base/io/read.c
+++ b/src/base/io/read.c
@@ -1,7 +1,54 @@
#include "internal.h"
-int
-io·read(io·Stream *s, int sz, int n, void *buf)
+intptr
+io·read(io·Header *io, intptr len, void *buf)
{
- return fread(buf, sz, n, s);
+ uchar *b;
+ intptr c0, c, nr, n, ic;
+
+ b = buf;
+ c = len;
+ ic = io->ilen; // how many bytes we've read and not flushed
+
+ while(c > 0){
+ n = -ic;
+ if(n > c)
+ n = c;
+ if(n == 0){
+ /* only continue if we are a file reader */
+ if(io->state != io·BufRdr)
+ break;
+
+ /* get more bytes */
+ if(sys·read(io->fd, io->cap, io->b, &nr)){
+ io->state = io·BufNil;
+ break;
+ }
+
+ if(nr == 0){
+ io->state = io·BufEnd;
+ break;
+ }
+
+ /* shift bytes within buffer so they end at terminal */
+ io->g = io->b;
+ io->pos += nr;
+ if(nr < io->cap){
+ io->g = io->e-nr;
+ mem·move(io->g, io->b, nr);
+ }
+ ic -= nr;
+ continue;
+ }
+ /* move our read bytes into the caller's buffer */
+ mem·move(b, io->e+ic, n);
+ c -= n;
+ ic += n;
+ b += n;
+ }
+ io->ilen = ic;
+ if(c == len && io->state == io·BufNil)
+ return -1;
+
+ return len-c;
}
diff --git a/src/base/io/readline.c b/src/base/io/readline.c
new file mode 100644
index 0000000..2be19db
--- /dev/null
+++ b/src/base/io/readline.c
@@ -0,0 +1,11 @@
+#include "internal.h"
+
+void *
+io·readline(io·Header *io, int null)
+{
+ char *start = io·readuntil(io, '\n');
+ if(null && start)
+ start[io->nread-1] = 0;
+
+ return start;
+}
diff --git a/src/base/io/readln.c b/src/base/io/readln.c
deleted file mode 100644
index 283472d..0000000
--- a/src/base/io/readln.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "internal.h"
-
-int
-io·readln(io·Stream *s, int n, byte* buf)
-{
- byte* b;
- b = fgets(buf, n+1, s);
- if(b == nil)
- return -1;
-
- return strlen(buf);
-}
diff --git a/src/base/io/readuntil.c b/src/base/io/readuntil.c
new file mode 100644
index 0000000..d5c2ed6
--- /dev/null
+++ b/src/base/io/readuntil.c
@@ -0,0 +1,65 @@
+#include "internal.h"
+
+void *
+io·readuntil(io·Header *io, int delim)
+{
+ char *b, *e;
+ intptr i, j;
+
+ i = -io->ilen;
+ if(i==0){
+ if(io->state != io·BufRdr){
+ if(io->state == io·BufEnd)
+ io->state = io·BufRdr;
+ io->nread = 0;
+ io->g = io->e;
+ return nil;
+ }
+ }
+
+ /* best case, we find it in the remaining bytes */
+ b = (char*)io->e - i;
+ if((e = mem·findc(b, i, delim)) != nil){
+ j = (e - b)+1;
+ io->nread = j;
+ io->ilen += j;
+ return b;
+ }
+ /* ok no luck, shift over the data and get more */
+ if(i < io->cap)
+ mem·move(io->b, b, i);
+ io->g = io->b;
+
+ /* write to the buffer while we search for delim */
+ b = (char *)io->b + i;
+ while(i < io->cap){
+ if(sys·read(io->fd, io->cap-i, b, &j) || j == 0){
+ mem·move(io->e-i, io->b, i);
+ io->nread = +i;
+ io->ilen = -i;
+ io->g = io->e - i;
+ return 0;
+ }
+ io->pos += j;
+ i += j;
+ e = mem·findc(b, j, delim);
+ if(e!=nil){
+ /* finally have a hit. reset the world */
+ b = (char*)io->e - i;
+ if(i < io->cap){
+ mem·move(b, io->b, i);
+ io->g = (uchar *)b;
+ }
+ j = (e - (char*)io->b) + 1;
+ io->nread = j;
+ io->ilen = j - i;
+ return b;
+ }
+ b += j;
+ }
+
+ io->nread = +io->cap;
+ io->ilen = -io->cap;
+ io->g = io->b;
+ return nil;
+}
diff --git a/src/base/io/rules.mk b/src/base/io/rules.mk
index 124cd09..3a091be 100644
--- a/src/base/io/rules.mk
+++ b/src/base/io/rules.mk
@@ -1,15 +1,18 @@
SRCS_$(d)+=\
- $(d)/io/fd.c\
$(d)/io/flush.c\
- $(d)/io/interface.c\
+ $(d)/io/getc.c\
+ $(d)/io/getr.c\
+ $(d)/io/init.c\
+ $(d)/io/offset.c\
$(d)/io/open.c\
- $(d)/io/close.c\
- $(d)/io/putbyte.c\
- $(d)/io/putstring.c\
+ $(d)/io/openfd.c\
+ $(d)/io/print.c\
+ $(d)/io/putc.c\
$(d)/io/read.c\
- $(d)/io/readln.c\
+ $(d)/io/readline.c\
+ $(d)/io/readuntil.c\
$(d)/io/seek.c\
- $(d)/io/stat.c\
- $(d)/io/tell.c\
- $(d)/io/unget.c\
+ $(d)/io/ungetc.c\
+ $(d)/io/ungetr.c\
+ $(d)/io/vprint.c\
$(d)/io/write.c
diff --git a/src/base/io/seek.c b/src/base/io/seek.c
index 1be4ee7..4fa1aff 100644
--- a/src/base/io/seek.c
+++ b/src/base/io/seek.c
@@ -1,7 +1,57 @@
#include "internal.h"
int
-io·seek(io·Stream *s, long off, int whence)
+io·seek(io·Header *io, intptr offset, int whence, intptr *pos)
{
- return fseek(s, off, whence);
+ intptr n,d,cap;
+
+ switch(io->state){
+ default:
+ fmt·fprint(2, "seek: unknown state %d\n", io->state);
+ return io·BufEof;
+ case io·BufEnd:
+ io->state = io·BufRdr;
+ io->ilen = 0;
+ io->g = io->e;
+ /* fallthrough */
+ case io·BufRdr:
+ n = offset;
+ if(whence == sys·SeekCur){
+ n += io·offset(io);
+ whence = sys·SeekSet;
+ }
+
+ /* can we seek inside our buffer */
+ if(whence == sys·SeekSet){
+ d = n - io·offset(io);
+ cap = io->e - io->g;
+ if(-cap <= d && d <= cap){
+ io->ilen += d;
+ if(d >= 0){
+ if(io->ilen <= 0){
+ *pos = n;
+ return 0;
+ }
+ }else{
+ if(io->e - io->g >= -io->ilen){
+ *pos = n;
+ return 0;
+ }
+ }
+ }
+ }
+
+ /* nope, call the kernel to do it for us */
+ sys·seek(io->fd, offset, whence, &n);
+ io->ilen = 0;
+ io->g = io->e;
+ break;
+
+ case io·BufWtr:
+ io·flush(io);
+ sys·seek(io->fd, offset, whence, &n);
+ break;
+ }
+ io->pos = *pos = n;
+ return 0;
}
diff --git a/src/base/io/stat.c b/src/base/io/stat.c
deleted file mode 100644
index 063ff8f..0000000
--- a/src/base/io/stat.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "internal.h"
-
-int
-io·stat(io·Stream *s, io·Stat *buf)
-{
- return fstat(fileno(s), buf);
-}
diff --git a/src/base/io/tell.c b/src/base/io/tell.c
deleted file mode 100644
index 1c50439..0000000
--- a/src/base/io/tell.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "internal.h"
-
-long
-io·tell(io·Stream *s)
-{
- return ftell(s);
-}
diff --git a/src/base/io/unget.c b/src/base/io/unget.c
deleted file mode 100644
index 5c37433..0000000
--- a/src/base/io/unget.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "internal.h"
-
-int
-io·ungetbyte(io·Stream *s, byte c)
-{
- return ungetc(c, s);
-}
diff --git a/src/base/io/ungetc.c b/src/base/io/ungetc.c
new file mode 100644
index 0000000..201ffd6
--- /dev/null
+++ b/src/base/io/ungetc.c
@@ -0,0 +1,13 @@
+#include "internal.h"
+
+int
+io·ungetc(io·Header *io)
+{
+ if(io->state == io·BufEnd)
+ io->state = io·BufRdr;
+ if(io->state != io·BufRdr)
+ return io·BufEof;
+
+ io->ilen--;
+ return 0;
+}
diff --git a/src/base/io/ungetr.c b/src/base/io/ungetr.c
new file mode 100644
index 0000000..c0b8e9d
--- /dev/null
+++ b/src/base/io/ungetr.c
@@ -0,0 +1,13 @@
+#include "internal.h"
+
+rune
+io·ungetr(io·Header *io)
+{
+ if(io->state == io·BufEnd)
+ io->state = io·BufRdr;
+ if(io->state != io·BufRdr)
+ return io·BufEof;
+ io->ilen -= io->runesz;
+ io->runesz = 0;
+ return 0;
+}
diff --git a/src/base/io/vprint.c b/src/base/io/vprint.c
new file mode 100644
index 0000000..6fa446e
--- /dev/null
+++ b/src/base/io/vprint.c
@@ -0,0 +1,34 @@
+#include "internal.h"
+
+static int
+flush(fmt·State *fmt)
+{
+ io·Header *io = fmt->file;
+ io->olen = fmt->buffer.cur - fmt->buffer.end;
+ if(io·flush(io))
+ return 0;
+
+ fmt->buffer.end = (char*)io->e;
+ fmt->buffer.cur = fmt->buffer.beg = fmt->buffer.end + io->olen;
+ return 1;
+}
+
+int
+io·vprint(io·Header *io, char *fmt, va_list args)
+{
+ int n;
+ fmt·State f;
+
+ f.buffer.end = (char*)io->e;
+ f.buffer.beg = f.buffer.cur = (char*)(io->e + io->olen);
+ f.n = 0;
+ f.file = io;
+ f.flush = flush;
+
+ va_copy(f.args,args);
+ n = fmt·do(&f, fmt);
+ va_end(f.args);
+
+ io->olen = f.buffer.cur - f.buffer.beg;
+ return n;
+}
diff --git a/src/base/io/write.c b/src/base/io/write.c
index 63df664..2f37200 100644
--- a/src/base/io/write.c
+++ b/src/base/io/write.c
@@ -1,7 +1,40 @@
#include "internal.h"
-int
-io·write(io·Stream *s, int sz, int n, void *buf)
+intptr
+io·write(io·Header *io, intptr len, void *buf)
{
- return fwrite(buf, sz, n, s);
+ char *b;
+ intptr c, o, nw, n;
+
+ b = buf;
+ c = len;
+ o = io->olen;
+
+ while(c > 0){
+ n = -o;
+ if(n > c)
+ n = c;
+ if(n == 0){
+ if(io->state != io·BufWtr)
+ return io·BufEof;
+ switch(sys·write(io->fd, io->cap, io->b, &nw)){
+ case 0:
+ if(nw != io->cap) goto error;
+ io->pos += nw;
+ o = -io->cap;
+ continue;
+ case sys·ErrorInterrupt:
+ io->state = io·BufNil;
+ /* fallthrough */
+ default: error:
+ return io·BufEof;
+ }
+ }
+ mem·move(io->e+o, b, n);
+ o += n;
+ c -= n;
+ b += n;
+ }
+ io->olen = o;
+ return len-c;
}