summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/bio.h30
-rw-r--r--libbio/bgetc.c1
-rw-r--r--libbio/bgetrune.c16
-rw-r--r--libbio/binit.c20
-rw-r--r--libbio/boffset.c4
-rw-r--r--libbio/bprint.c23
-rw-r--r--libbio/bputc.c29
-rw-r--r--libbio/bputrune.c2
-rw-r--r--libbio/brdstr.c111
-rw-r--r--libbio/bseek.c21
-rw-r--r--libbio/bvprint.c36
-rw-r--r--libbio/bwrite.c6
-rw-r--r--libbio/mkfile2
13 files changed, 217 insertions, 84 deletions
diff --git a/include/bio.h b/include/bio.h
index b4e552d8..67ec18ed 100644
--- a/include/bio.h
+++ b/include/bio.h
@@ -5,7 +5,7 @@ typedef struct Biobuf Biobuf;
enum
{
Bsize = 8*1024,
- Bungetsize = 4, /* space for ungetc */
+ Bungetsize = UTFmax+1, /* space for ungetc */
Bmagic = 0x314159,
Beof = -1,
Bbad = -2,
@@ -27,7 +27,7 @@ struct Biobuf
int state; /* r/w/inactive */
int fid; /* open file */
int flag; /* magic if malloc'ed */
- long offset; /* offset of buffer in file */
+ vlong offset; /* offset of buffer in file */
int bsize; /* size of buffer */
uchar* bbuf; /* pointer to beginning of buffer */
uchar* ebuf; /* pointer to end of buffer */
@@ -35,20 +35,12 @@ struct Biobuf
uchar b[Bungetsize+Bsize];
};
-#define BGETC(bp)\
- ((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
-#define BPUTC(bp,c)\
- ((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
-#define BOFFSET(bp)\
- (((bp)->state==Bractive)?\
- (bp)->offset + (bp)->icount:\
- (((bp)->state==Bwactive)?\
- (bp)->offset + ((bp)->bsize + (bp)->ocount):\
- -1))
-#define BLINELEN(bp)\
- (bp)->rdline
-#define BFILDES(bp)\
- (bp)->fid
+/* Dregs, redefined as functions for backwards compatibility */
+#define BGETC(bp) Bgetc(bp)
+#define BPUTC(bp,c) Bputc(bp,c)
+#define BOFFSET(bp) Boffset(bp)
+#define BLINELEN(bp) Blinelen(bp)
+#define BFILDES(bp) Bfildes(bp)
int Bbuffered(Biobuf*);
int Bfildes(Biobuf*);
@@ -59,14 +51,16 @@ long Bgetrune(Biobuf*);
int Binit(Biobuf*, int, int);
int Binits(Biobuf*, int, int, uchar*, int);
int Blinelen(Biobuf*);
-long Boffset(Biobuf*);
+vlong Boffset(Biobuf*);
Biobuf* Bopen(char*, int);
int Bprint(Biobuf*, char*, ...);
+int Bvprint(Biobuf*, char*, va_list);
int Bputc(Biobuf*, int);
int Bputrune(Biobuf*, long);
void* Brdline(Biobuf*, int);
+char* Brdstr(Biobuf*, int, int);
long Bread(Biobuf*, void*, long);
-long Bseek(Biobuf*, long, int);
+vlong Bseek(Biobuf*, vlong, int);
int Bterm(Biobuf*);
int Bungetc(Biobuf*);
int Bungetrune(Biobuf*);
diff --git a/libbio/bgetc.c b/libbio/bgetc.c
index 4c8ae90c..741b692f 100644
--- a/libbio/bgetc.c
+++ b/libbio/bgetc.c
@@ -26,6 +26,7 @@ loop:
i = read(bp->fid, bp->bbuf, bp->bsize);
bp->gbuf = bp->bbuf;
if(i <= 0) {
+ bp->state = Bracteof;
if(i < 0)
bp->state = Binactive;
return Beof;
diff --git a/libbio/bgetrune.c b/libbio/bgetrune.c
index ed216379..13b02bec 100644
--- a/libbio/bgetrune.c
+++ b/libbio/bgetrune.c
@@ -6,7 +6,7 @@ Bgetrune(Biobuf *bp)
{
int c, i;
Rune rune;
- char str[4];
+ char str[UTFmax];
c = Bgetc(bp);
if(c < Runeself) { /* one char */
@@ -14,19 +14,25 @@ Bgetrune(Biobuf *bp)
return c;
}
str[0] = c;
+ bp->runesize = 0;
for(i=1;;) {
c = Bgetc(bp);
if(c < 0)
return c;
+ if (i >= sizeof str)
+ return Runeerror;
str[i++] = c;
if(fullrune(str, i)) {
+ /* utf is long enough to be a rune, but could be bad. */
bp->runesize = chartorune(&rune, str);
- while(i > bp->runesize) {
- Bungetc(bp);
- i--;
- }
+ if (rune == Runeerror)
+ bp->runesize = 0; /* push back nothing */
+ else
+ /* push back bytes unconsumed by chartorune */
+ for(; i > bp->runesize; i--)
+ Bungetc(bp);
return rune;
}
}
diff --git a/libbio/binit.c b/libbio/binit.c
index ecbad119..4d9bc785 100644
--- a/libbio/binit.c
+++ b/libbio/binit.c
@@ -61,7 +61,7 @@ Binits(Biobuf *bp, int f, int mode, uchar *p, int size)
p += Bungetsize; /* make room for Bungets */
size -= Bungetsize;
- switch(mode) {
+ switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
default:
fprint(2, "Bopen: unknown mode %d\n", mode);
return Beof;
@@ -103,22 +103,21 @@ Bopen(char *name, int mode)
Biobuf *bp;
int f;
- switch(mode) {
+ switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
default:
fprint(2, "Bopen: unknown mode %d\n", mode);
return 0;
case OREAD:
f = open(name, OREAD);
- if(f < 0)
- return 0;
break;
case OWRITE:
- f = create(name, OWRITE, 0666);
- if(f < 0)
- return 0;
+ f = create(name, mode, 0666);
+ break;
}
+ if(f < 0)
+ return 0;
bp = malloc(sizeof(Biobuf));
if(bp == nil)
return 0;
@@ -130,13 +129,16 @@ Bopen(char *name, int mode)
int
Bterm(Biobuf *bp)
{
+ int r;
deinstall(bp);
- Bflush(bp);
+ r = Bflush(bp);
if(bp->flag == Bmagic) {
bp->flag = 0;
close(bp->fid);
+ bp->fid = -1; /* prevent accidents */
free(bp);
}
- return 0;
+ /* otherwise opened with Binit(s) */
+ return r;
}
diff --git a/libbio/boffset.c b/libbio/boffset.c
index 72ce34cf..88c4c358 100644
--- a/libbio/boffset.c
+++ b/libbio/boffset.c
@@ -1,10 +1,10 @@
#include "lib9.h"
#include <bio.h>
-long
+vlong
Boffset(Biobuf *bp)
{
- long n;
+ vlong n;
switch(bp->state) {
default:
diff --git a/libbio/bprint.c b/libbio/bprint.c
index 26870024..36890e6d 100644
--- a/libbio/bprint.c
+++ b/libbio/bprint.c
@@ -4,26 +4,11 @@
int
Bprint(Biobuf *bp, char *fmt, ...)
{
- va_list ap;
- char *ip, *ep, *out;
+ va_list arg;
int n;
- ep = (char*)bp->ebuf;
- ip = ep + bp->ocount;
- va_start(ap, fmt);
- out = vseprint(ip, ep, fmt, ap);
- va_end(ap);
- if(out == nil || out >= ep-5) {
- if(Bflush(bp) < 0)
- return Beof;
- ip = ep + bp->ocount;
- va_start(ap, fmt);
- out = vseprint(ip, ep, fmt, ap);
- va_end(ap);
- if(out == nil || out >= ep-5)
- return Beof;
- }
- n = out-ip;
- bp->ocount += n;
+ va_start(arg, fmt);
+ n = Bvprint(bp, fmt, arg);
+ va_end(arg);
return n;
}
diff --git a/libbio/bputc.c b/libbio/bputc.c
index 5f0fba59..d05badaa 100644
--- a/libbio/bputc.c
+++ b/libbio/bputc.c
@@ -4,26 +4,17 @@
int
Bputc(Biobuf *bp, int c)
{
- int i, j;
+ int i;
-loop:
- i = bp->ocount;
- j = i+1;
- if(i != 0) {
- bp->ocount = j;
- bp->ebuf[i] = c;
- return 0;
+ for(;;) {
+ i = bp->ocount;
+ if(i) {
+ bp->ebuf[i++] = c;
+ bp->ocount = i;
+ return 0;
+ }
+ if(Bflush(bp) == Beof)
+ break;
}
- if(bp->state != Bwactive)
- return Beof;
- j = write(bp->fid, bp->bbuf, bp->bsize);
- if(j == bp->bsize) {
- bp->ocount = -bp->bsize;
- bp->offset += j;
- goto loop;
- }
- fprint(2, "Bputc: write error\n");
- bp->state = Binactive;
- bp->ocount = 0;
return Beof;
}
diff --git a/libbio/bputrune.c b/libbio/bputrune.c
index a864541d..4b4a7a9a 100644
--- a/libbio/bputrune.c
+++ b/libbio/bputrune.c
@@ -5,7 +5,7 @@ int
Bputrune(Biobuf *bp, long c)
{
Rune rune;
- char str[4];
+ char str[UTFmax];
int n;
rune = c;
diff --git a/libbio/brdstr.c b/libbio/brdstr.c
new file mode 100644
index 00000000..227bdd62
--- /dev/null
+++ b/libbio/brdstr.c
@@ -0,0 +1,111 @@
+#include "lib9.h"
+#include <bio.h>
+
+static char*
+badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
+{
+ int n;
+
+ n = *np;
+ p = realloc(p, n+ndata+1);
+ if(p){
+ memmove(p+n, data, ndata);
+ n += ndata;
+ if(n>0 && nulldelim && p[n-1]==delim)
+ p[--n] = '\0';
+ else
+ p[n] = '\0';
+ *np = n;
+ }
+ return p;
+}
+
+char*
+Brdstr(Biobuf *bp, int delim, int nulldelim)
+{
+ char *ip, *ep, *p;
+ int i, j;
+
+ i = -bp->icount;
+ bp->rdline = 0;
+ if(i == 0) {
+ /*
+ * eof or other error
+ */
+ if(bp->state != Bractive) {
+ if(bp->state == Bracteof)
+ bp->state = Bractive;
+ bp->gbuf = bp->ebuf;
+ return nil;
+ }
+ }
+
+ /*
+ * first try in remainder of buffer (gbuf doesn't change)
+ */
+ ip = (char*)bp->ebuf - i;
+ ep = memchr(ip, delim, i);
+ if(ep) {
+ j = (ep - ip) + 1;
+ bp->icount += j;
+ return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
+ }
+
+ /*
+ * copy data to beginning of buffer
+ */
+ if(i < bp->bsize)
+ memmove(bp->bbuf, ip, i);
+ bp->gbuf = bp->bbuf;
+
+ /*
+ * append to buffer looking for the delim
+ */
+ p = nil;
+ for(;;){
+ ip = (char*)bp->bbuf + i;
+ while(i < bp->bsize) {
+ j = read(bp->fid, ip, bp->bsize-i);
+ if(j <= 0 && i == 0)
+ return p;
+ if(j <= 0 && i > 0){
+ /*
+ * end of file but no delim. pretend we got a delim
+ * by making the delim \0 and smashing it with nulldelim.
+ */
+ j = 1;
+ ep = ip;
+ delim = '\0';
+ nulldelim = 1;
+ *ep = delim; /* there will be room for this */
+ }else{
+ bp->offset += j;
+ ep = memchr(ip, delim, j);
+ }
+ i += j;
+ if(ep) {
+ /*
+ * found in new piece
+ * copy back up and reset everything
+ */
+ ip = (char*)bp->ebuf - i;
+ if(i < bp->bsize){
+ memmove(ip, bp->bbuf, i);
+ bp->gbuf = (uchar*)ip;
+ }
+ j = (ep - (char*)bp->bbuf) + 1;
+ bp->icount = j - i;
+ return badd(p, &bp->rdline, ip, j, delim, nulldelim);
+ }
+ ip += j;
+ }
+
+ /*
+ * full buffer without finding; add to user string and continue
+ */
+ p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
+ i = 0;
+ bp->icount = 0;
+ bp->gbuf = bp->ebuf;
+ }
+}
diff --git a/libbio/bseek.c b/libbio/bseek.c
index 9e68f5ea..32e8dda4 100644
--- a/libbio/bseek.c
+++ b/libbio/bseek.c
@@ -1,10 +1,10 @@
#include "lib9.h"
#include <bio.h>
-long
-Bseek(Biobuf *bp, long offset, int base)
+vlong
+Bseek(Biobuf *bp, vlong offset, int base)
{
- long n, d;
+ vlong n, d;
switch(bp->state) {
default:
@@ -27,15 +27,16 @@ Bseek(Biobuf *bp, long offset, int base)
* try to seek within buffer
*/
if(base == 0) {
+ /*
+ * if d is too large for an int, icount may wrap,
+ * so we need to ensure that icount hasn't wrapped
+ * and points within the buffer's valid data.
+ */
d = n - Boffset(bp);
bp->icount += d;
- if(d >= 0) {
- if(bp->icount <= 0)
- return n;
- } else {
- if(bp->ebuf - bp->gbuf >= -bp->icount)
- return n;
- }
+ if(d <= bp->bsize && bp->icount <= 0 &&
+ bp->ebuf - bp->gbuf >= -bp->icount)
+ return n;
}
/*
diff --git a/libbio/bvprint.c b/libbio/bvprint.c
new file mode 100644
index 00000000..c11b1dc3
--- /dev/null
+++ b/libbio/bvprint.c
@@ -0,0 +1,36 @@
+#include "lib9.h"
+#include <bio.h>
+
+static int
+fmtBflush(Fmt *f)
+{
+ Biobuf *bp;
+
+ bp = f->farg;
+ bp->ocount = (char*)f->to - (char*)f->stop;
+ if(Bflush(bp) < 0)
+ return 0;
+ f->stop = bp->ebuf;
+ f->to = (char*)f->stop + bp->ocount;
+ f->start = f->to;
+ return 1;
+}
+
+int
+Bvprint(Biobuf *bp, char *fmt, va_list arg)
+{
+ int n;
+ Fmt f;
+
+ f.runes = 0;
+ f.stop = bp->ebuf;
+ f.start = (char*)f.stop + bp->ocount;
+ f.to = f.start;
+ f.flush = fmtBflush;
+ f.farg = bp;
+ f.nfmt = 0;
+ f.args = arg;
+ n = dofmt(&f, fmt);
+ bp->ocount = (char*)f.to - (char*)f.stop;
+ return n;
+}
diff --git a/libbio/bwrite.c b/libbio/bwrite.c
index 87256fd0..7661b745 100644
--- a/libbio/bwrite.c
+++ b/libbio/bwrite.c
@@ -7,6 +7,7 @@ Bwrite(Biobuf *bp, void *ap, long count)
long c;
uchar *p;
int i, n, oc;
+ char errbuf[ERRMAX];
p = ap;
c = count;
@@ -21,7 +22,10 @@ Bwrite(Biobuf *bp, void *ap, long count)
return Beof;
i = write(bp->fid, bp->bbuf, bp->bsize);
if(i != bp->bsize) {
- bp->state = Binactive;
+ errstr(errbuf, sizeof errbuf);
+ if(strstr(errbuf, "interrupt") == nil)
+ bp->state = Binactive;
+ errstr(errbuf, sizeof errbuf);
return Beof;
}
bp->offset += i;
diff --git a/libbio/mkfile b/libbio/mkfile
index e9afe025..d3f60869 100644
--- a/libbio/mkfile
+++ b/libbio/mkfile
@@ -14,8 +14,10 @@ OFILES=\
bputrune.$O\
bputc.$O\
brdline.$O\
+ brdstr.$O\
bread.$O\
bseek.$O\
+ bvprint.$O\
bwrite.$O\
HFILES= $ROOT/include/bio.h