xref: /inferno-os/appl/lib/bufio.b (revision eddf3bddae4e8afadafd4472f20a5fe829e15ef8)
137da2899SCharles.Forsythimplement Bufio;
237da2899SCharles.Forsyth
337da2899SCharles.Forsythinclude "sys.m";
437da2899SCharles.Forsyth	sys: Sys;
537da2899SCharles.Forsyth
637da2899SCharles.Forsythinclude "bufio.m";
737da2899SCharles.Forsyth
837da2899SCharles.ForsythUTFself:	con 16r80;	# ascii and UTF sequences are the same (<)
937da2899SCharles.ForsythMaxrune:	con 8;	# could probably be Sys->UTFmax
1037da2899SCharles.ForsythBufsize:	con Sys->ATOMICIO;
1137da2899SCharles.Forsyth
1237da2899SCharles.ForsythFiller: adt
1337da2899SCharles.Forsyth{
1437da2899SCharles.Forsyth	iobuf:	ref Iobuf;
1537da2899SCharles.Forsyth	fill:	BufioFill;
1637da2899SCharles.Forsyth	next:	cyclic ref Filler;
1737da2899SCharles.Forsyth};
1837da2899SCharles.Forsyth
1937da2899SCharles.Forsythfillers:	ref Filler;
2037da2899SCharles.Forsyth
2137da2899SCharles.Forsythcreate(filename: string, mode, perm: int): ref Iobuf
2237da2899SCharles.Forsyth{
2337da2899SCharles.Forsyth	if (sys == nil)
2437da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
2537da2899SCharles.Forsyth	if ((fd := sys->create(filename, mode, perm)) == nil)
2637da2899SCharles.Forsyth		return nil;
2737da2899SCharles.Forsyth	return ref Iobuf(fd, array[Bufsize+Maxrune] of byte, 0, 0, 0, big 0, big 0, mode, mode);
2837da2899SCharles.Forsyth}
2937da2899SCharles.Forsyth
3037da2899SCharles.Forsythopen(filename: string, mode: int): ref Iobuf
3137da2899SCharles.Forsyth{
3237da2899SCharles.Forsyth	if (sys == nil)
3337da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
3437da2899SCharles.Forsyth	if ((fd := sys->open(filename, mode)) == nil)
3537da2899SCharles.Forsyth		return nil;
3637da2899SCharles.Forsyth	return ref Iobuf(fd, array[Bufsize+Maxrune] of byte, 0, 0, 0, big 0, big 0, mode, mode);
3737da2899SCharles.Forsyth}
3837da2899SCharles.Forsyth
3937da2899SCharles.Forsythfopen(fd: ref Sys->FD, mode: int): ref Iobuf
4037da2899SCharles.Forsyth{
4137da2899SCharles.Forsyth	if (sys == nil)
4237da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
4337da2899SCharles.Forsyth	if ((filpos := sys->seek(fd, big 0, 1)) < big 0)
4437da2899SCharles.Forsyth		filpos = big 0;
4537da2899SCharles.Forsyth	return ref Iobuf(fd, array[Bufsize+Maxrune] of byte, 0, 0, 0, filpos, filpos, mode, mode);
4637da2899SCharles.Forsyth}
4737da2899SCharles.Forsyth
4837da2899SCharles.Forsythsopen(input: string): ref Iobuf
4937da2899SCharles.Forsyth{
5037da2899SCharles.Forsyth	return aopen(array of byte input);
5137da2899SCharles.Forsyth}
5237da2899SCharles.Forsyth
5337da2899SCharles.Forsythaopen(b: array of byte): ref Iobuf
5437da2899SCharles.Forsyth{
5537da2899SCharles.Forsyth	if (sys == nil)
5637da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
5737da2899SCharles.Forsyth	return ref Iobuf(nil, b, 0, len b, 0, big 0, big 0, OREAD, OREAD);
5837da2899SCharles.Forsyth}
5937da2899SCharles.Forsyth
6037da2899SCharles.Forsythreadchunk(b: ref Iobuf): int
6137da2899SCharles.Forsyth{
6237da2899SCharles.Forsyth	if (b.fd == nil){
6337da2899SCharles.Forsyth		if ((f := filler(b)) != nil){
6437da2899SCharles.Forsyth			if ((n := f.fill->fill(b)) == EOF)
6537da2899SCharles.Forsyth				nofill(b);
6637da2899SCharles.Forsyth			return n;
6737da2899SCharles.Forsyth		}
6837da2899SCharles.Forsyth		return EOF;
6937da2899SCharles.Forsyth	}
7037da2899SCharles.Forsyth	if (b.filpos != b.bufpos + big b.size) {
7137da2899SCharles.Forsyth		s := b.bufpos + big b.size;
7237da2899SCharles.Forsyth		if (sys->seek(b.fd, s, 0) != s)
7337da2899SCharles.Forsyth			return ERROR;
7437da2899SCharles.Forsyth		b.filpos = s;
7537da2899SCharles.Forsyth	}
7637da2899SCharles.Forsyth	i := len b.buffer - b.size - 1;
7737da2899SCharles.Forsyth	if(i > Bufsize)
7837da2899SCharles.Forsyth		i = Bufsize;
7937da2899SCharles.Forsyth	if ((i = sys->read(b.fd, b.buffer[b.size:], i)) <= 0) {
8037da2899SCharles.Forsyth		if(i < 0)
8137da2899SCharles.Forsyth			return ERROR;
8237da2899SCharles.Forsyth		return EOF;
8337da2899SCharles.Forsyth	}
8437da2899SCharles.Forsyth	b.size += i;
8537da2899SCharles.Forsyth	b.filpos += big i;
8637da2899SCharles.Forsyth	return i;
8737da2899SCharles.Forsyth}
8837da2899SCharles.Forsyth
8937da2899SCharles.Forsythwritechunk(b: ref Iobuf): int
9037da2899SCharles.Forsyth{
918efcc025SCharles.Forsyth	err := (b.fd == nil);
9237da2899SCharles.Forsyth	if (b.filpos != b.bufpos) {
9337da2899SCharles.Forsyth		if (sys->seek(b.fd, b.bufpos, 0) != b.bufpos)
948efcc025SCharles.Forsyth			err = 1;
9537da2899SCharles.Forsyth		b.filpos = b.bufpos;
9637da2899SCharles.Forsyth	}
9737da2899SCharles.Forsyth	if ((size := b.size) > Bufsize)
9837da2899SCharles.Forsyth		size = Bufsize;
9937da2899SCharles.Forsyth	if (sys->write(b.fd, b.buffer, size) != size)
1008efcc025SCharles.Forsyth		err = 1;
10137da2899SCharles.Forsyth	b.filpos += big size;
10237da2899SCharles.Forsyth	b.size -= size;
10337da2899SCharles.Forsyth	if (b.size) {
10437da2899SCharles.Forsyth		b.dirty = 1;
10537da2899SCharles.Forsyth		b.buffer[0:] = b.buffer[Bufsize:Bufsize+b.size];
10637da2899SCharles.Forsyth	} else
10737da2899SCharles.Forsyth		b.dirty = 0;
10837da2899SCharles.Forsyth	b.bufpos += big size;
10937da2899SCharles.Forsyth	b.index -= size;
1108efcc025SCharles.Forsyth	if(err)
1118efcc025SCharles.Forsyth		return ERROR;
11237da2899SCharles.Forsyth	return size;
11337da2899SCharles.Forsyth}
11437da2899SCharles.Forsyth
11537da2899SCharles.ForsythIobuf.close(b: self ref Iobuf)
11637da2899SCharles.Forsyth{
11737da2899SCharles.Forsyth	if (b.fd == nil) {
11837da2899SCharles.Forsyth		nofill(b);
11937da2899SCharles.Forsyth		return;
12037da2899SCharles.Forsyth	}
12137da2899SCharles.Forsyth	if (b.dirty)
12237da2899SCharles.Forsyth		b.flush();
12337da2899SCharles.Forsyth	b.fd = nil;
12437da2899SCharles.Forsyth	b.buffer = nil;
12537da2899SCharles.Forsyth}
12637da2899SCharles.Forsyth
12737da2899SCharles.ForsythIobuf.flush(b: self ref Iobuf): int
12837da2899SCharles.Forsyth{
12937da2899SCharles.Forsyth	if (b.fd == nil)
13037da2899SCharles.Forsyth		return ERROR;
13137da2899SCharles.Forsyth	if (b.lastop == OREAD){
13237da2899SCharles.Forsyth		b.bufpos = b.filpos;
13337da2899SCharles.Forsyth		b.size = 0;
13437da2899SCharles.Forsyth		return 0;
13537da2899SCharles.Forsyth	}
13637da2899SCharles.Forsyth	while (b.dirty) {
13737da2899SCharles.Forsyth		if (writechunk(b) < 0)
13837da2899SCharles.Forsyth			return ERROR;
13937da2899SCharles.Forsyth		if (b.index < 0) {
14037da2899SCharles.Forsyth			b.bufpos += big b.index;
14137da2899SCharles.Forsyth			b.index = 0;
14237da2899SCharles.Forsyth		}
14337da2899SCharles.Forsyth	}
14437da2899SCharles.Forsyth	return 0;
14537da2899SCharles.Forsyth}
14637da2899SCharles.Forsyth
14737da2899SCharles.ForsythIobuf.seek(b: self ref Iobuf, off: big, start: int): big
14837da2899SCharles.Forsyth{
14937da2899SCharles.Forsyth	npos: big;
15037da2899SCharles.Forsyth
15137da2899SCharles.Forsyth	if (b.fd == nil){
15237da2899SCharles.Forsyth		if(filler(b) != nil)
15337da2899SCharles.Forsyth			return big ERROR;
15437da2899SCharles.Forsyth	}
15537da2899SCharles.Forsyth	case (start) {
15637da2899SCharles.Forsyth	0 =>	# absolute address
15737da2899SCharles.Forsyth		npos = off;
15837da2899SCharles.Forsyth	1 =>	# offset from current location
15937da2899SCharles.Forsyth		npos = b.bufpos + big b.index + off;
16037da2899SCharles.Forsyth		off = npos;
16137da2899SCharles.Forsyth		start = Sys->SEEKSTART;
16237da2899SCharles.Forsyth	2 =>	# offset from EOF
16337da2899SCharles.Forsyth		npos = big -1;
16437da2899SCharles.Forsyth	* =>	return big ERROR;
16537da2899SCharles.Forsyth	}
16637da2899SCharles.Forsyth	if (b.bufpos <= npos && npos < b.bufpos + big b.size) {
16737da2899SCharles.Forsyth		b.index = int(npos - b.bufpos);
16837da2899SCharles.Forsyth		return npos;
16937da2899SCharles.Forsyth	}
17037da2899SCharles.Forsyth	if (b.fd == nil || b.dirty && b.flush() < 0)
17137da2899SCharles.Forsyth		return big ERROR;
17237da2899SCharles.Forsyth	b.size = 0;
17337da2899SCharles.Forsyth	b.index = 0;
174*eddf3bddSforsyth	if ((s := sys->seek(b.fd, off, start)) < big 0) {
175*eddf3bddSforsyth		b.bufpos = b.filpos;
17637da2899SCharles.Forsyth		return big ERROR;
177*eddf3bddSforsyth	}
17837da2899SCharles.Forsyth	b.bufpos = b.filpos = s;
179c25d3f6dSforsyth	return s;
18037da2899SCharles.Forsyth}
18137da2899SCharles.Forsyth
18237da2899SCharles.ForsythIobuf.offset(b: self ref Iobuf): big
18337da2899SCharles.Forsyth{
18437da2899SCharles.Forsyth	return b.bufpos + big b.index;
18537da2899SCharles.Forsyth}
18637da2899SCharles.Forsyth
18737da2899SCharles.Forsythwrite2read(b: ref Iobuf): int
18837da2899SCharles.Forsyth{
18937da2899SCharles.Forsyth	while (b.dirty)
19037da2899SCharles.Forsyth		if (b.flush() < 0)
19137da2899SCharles.Forsyth			return ERROR;
19237da2899SCharles.Forsyth	b.bufpos = b.filpos;
19337da2899SCharles.Forsyth	b.size = 0;
19437da2899SCharles.Forsyth	b.lastop = OREAD;
19537da2899SCharles.Forsyth	if ((r := readchunk(b)) < 0)
19637da2899SCharles.Forsyth		return r;
19737da2899SCharles.Forsyth	if (b.index > b.size)
19837da2899SCharles.Forsyth		return EOF;
19937da2899SCharles.Forsyth	return 0;
20037da2899SCharles.Forsyth}
20137da2899SCharles.Forsyth
20237da2899SCharles.ForsythIobuf.read(b: self ref Iobuf, buf: array of byte, n: int): int
20337da2899SCharles.Forsyth{
20437da2899SCharles.Forsyth	if (b.mode == OWRITE)
20537da2899SCharles.Forsyth		return ERROR;
20637da2899SCharles.Forsyth	if (b.lastop != OREAD){
20737da2899SCharles.Forsyth		if ((r := write2read(b)) < 0)
20837da2899SCharles.Forsyth			return r;
20937da2899SCharles.Forsyth	}
21037da2899SCharles.Forsyth	k := n;
21137da2899SCharles.Forsyth	while (b.size - b.index < k) {
21237da2899SCharles.Forsyth		buf[0:] = b.buffer[b.index:b.size];
21337da2899SCharles.Forsyth		buf = buf[b.size - b.index:];
21437da2899SCharles.Forsyth		k -= b.size - b.index;
21537da2899SCharles.Forsyth
21637da2899SCharles.Forsyth		b.bufpos += big b.size;
21737da2899SCharles.Forsyth		b.index = 0;
21837da2899SCharles.Forsyth		b.size = 0;
21937da2899SCharles.Forsyth		if ((r := readchunk(b)) < 0) {
22037da2899SCharles.Forsyth			if(r == EOF || n != k)
22137da2899SCharles.Forsyth				return n-k;
22237da2899SCharles.Forsyth			return ERROR;
22337da2899SCharles.Forsyth		}
22437da2899SCharles.Forsyth	}
22537da2899SCharles.Forsyth	buf[0:] = b.buffer[b.index:b.index+k];
22637da2899SCharles.Forsyth	b.index += k;
22737da2899SCharles.Forsyth	return n;
22837da2899SCharles.Forsyth}
22937da2899SCharles.Forsyth
23037da2899SCharles.ForsythIobuf.getb(b: self ref Iobuf): int
23137da2899SCharles.Forsyth{
23237da2899SCharles.Forsyth	if(b.lastop != OREAD){
23337da2899SCharles.Forsyth		if(b.mode == OWRITE)
23437da2899SCharles.Forsyth			return ERROR;
23537da2899SCharles.Forsyth		if((r := write2read(b)) < 0)
23637da2899SCharles.Forsyth			return r;
23737da2899SCharles.Forsyth	}
23837da2899SCharles.Forsyth	if (b.index == b.size) {
23937da2899SCharles.Forsyth		b.bufpos += big b.index;
24037da2899SCharles.Forsyth		b.index = 0;
24137da2899SCharles.Forsyth		b.size = 0;
24237da2899SCharles.Forsyth		if ((r := readchunk(b)) < 0)
24337da2899SCharles.Forsyth			return r;
24437da2899SCharles.Forsyth	}
24537da2899SCharles.Forsyth	return int b.buffer[b.index++];
24637da2899SCharles.Forsyth}
24737da2899SCharles.Forsyth
24837da2899SCharles.ForsythIobuf.ungetb(b: self ref Iobuf): int
24937da2899SCharles.Forsyth{
25037da2899SCharles.Forsyth	if(b.mode == OWRITE || b.lastop != OREAD)
25137da2899SCharles.Forsyth		return ERROR;
25237da2899SCharles.Forsyth	b.index--;
25337da2899SCharles.Forsyth	return 1;
25437da2899SCharles.Forsyth}
25537da2899SCharles.Forsyth
25637da2899SCharles.ForsythIobuf.getc(b: self ref Iobuf): int
25737da2899SCharles.Forsyth{
25837da2899SCharles.Forsyth	r, i, s:	int;
25937da2899SCharles.Forsyth
26037da2899SCharles.Forsyth	if(b.lastop != OREAD){
26137da2899SCharles.Forsyth		if(b.mode == OWRITE)
26237da2899SCharles.Forsyth			return ERROR;
26337da2899SCharles.Forsyth		if((r = write2read(b)) < 0)
26437da2899SCharles.Forsyth			return r;
26537da2899SCharles.Forsyth	}
26637da2899SCharles.Forsyth	for(;;) {
26737da2899SCharles.Forsyth		if(b.index < b.size) {
26837da2899SCharles.Forsyth			r = int b.buffer[b.index];
26937da2899SCharles.Forsyth			if(r < UTFself){
27037da2899SCharles.Forsyth				b.index++;
27137da2899SCharles.Forsyth				return r;
27237da2899SCharles.Forsyth			}
27337da2899SCharles.Forsyth			(r, i, s) = sys->byte2char(b.buffer[0:b.size], b.index);
27437da2899SCharles.Forsyth			if (i != 0) {
27537da2899SCharles.Forsyth				b.index += i;
27637da2899SCharles.Forsyth				return r;
27737da2899SCharles.Forsyth			}
27837da2899SCharles.Forsyth			b.buffer[0:] = b.buffer[b.index:b.size];
27937da2899SCharles.Forsyth		}
28037da2899SCharles.Forsyth		b.bufpos += big b.index;
28137da2899SCharles.Forsyth		b.size -= b.index;
28237da2899SCharles.Forsyth		b.index = 0;
28337da2899SCharles.Forsyth		if ((r = readchunk(b)) < 0)
28437da2899SCharles.Forsyth			return r;
28537da2899SCharles.Forsyth	}
28637da2899SCharles.Forsyth	# Not reached:
28737da2899SCharles.Forsyth	return -1;
28837da2899SCharles.Forsyth}
28937da2899SCharles.Forsyth
29037da2899SCharles.ForsythIobuf.ungetc(b: self ref Iobuf): int
29137da2899SCharles.Forsyth{
29237da2899SCharles.Forsyth	if(b.index == 0 || b.mode == OWRITE || b.lastop != OREAD)
29337da2899SCharles.Forsyth		return ERROR;
29437da2899SCharles.Forsyth	stop := b.index - Sys->UTFmax;
29537da2899SCharles.Forsyth	if(stop < 0)
29637da2899SCharles.Forsyth		stop = 0;
29737da2899SCharles.Forsyth	buf := b.buffer[0:b.size];
29837da2899SCharles.Forsyth	for(i := b.index-1; i >= stop; i--){
2998efcc025SCharles.Forsyth		(nil, n, s) := sys->byte2char(buf, i);
30037da2899SCharles.Forsyth		if(s && i + n == b.index){
30137da2899SCharles.Forsyth			b.index = i;
30237da2899SCharles.Forsyth			return 1;
30337da2899SCharles.Forsyth		}
30437da2899SCharles.Forsyth	}
30537da2899SCharles.Forsyth	b.index--;
30637da2899SCharles.Forsyth
30737da2899SCharles.Forsyth	return 1;
30837da2899SCharles.Forsyth}
30937da2899SCharles.Forsyth
31037da2899SCharles.Forsyth# optimised when term < UTFself (common case)
31137da2899SCharles.Forsythtgets(b: ref Iobuf, t: int): string
31237da2899SCharles.Forsyth{
31337da2899SCharles.Forsyth	str: string;
31437da2899SCharles.Forsyth	term := byte t;
31537da2899SCharles.Forsyth	for(;;){
31637da2899SCharles.Forsyth		start := b.index;
31737da2899SCharles.Forsyth		end := start + sys->utfbytes(b.buffer[start:], b.size-start);
31837da2899SCharles.Forsyth		buf := b.buffer;
31937da2899SCharles.Forsyth		# XXX could speed up by adding extra byte to end of buffer and
32037da2899SCharles.Forsyth		# placing a sentinel there (eliminate one test, perhaps 35% speedup).
32137da2899SCharles.Forsyth		# (but not when we've been given the buffer externally)
32237da2899SCharles.Forsyth		for(i := start; i < end; i++){
32337da2899SCharles.Forsyth			if(buf[i] == term){
32437da2899SCharles.Forsyth				i++;
32537da2899SCharles.Forsyth				str += string buf[start:i];
32637da2899SCharles.Forsyth				b.index = i;
32737da2899SCharles.Forsyth				return str;
32837da2899SCharles.Forsyth			}
32937da2899SCharles.Forsyth		}
33037da2899SCharles.Forsyth		str += string buf[start:i];
33137da2899SCharles.Forsyth		if(i < b.size)
33237da2899SCharles.Forsyth			b.buffer[0:] = buf[i:b.size];
33337da2899SCharles.Forsyth		b.size -= i;
33437da2899SCharles.Forsyth		b.bufpos += big i;
33537da2899SCharles.Forsyth		b.index = 0;
33637da2899SCharles.Forsyth		if(readchunk(b) < 0)
33737da2899SCharles.Forsyth			break;
33837da2899SCharles.Forsyth	}
33937da2899SCharles.Forsyth	return str;
34037da2899SCharles.Forsyth}
34137da2899SCharles.Forsyth
34237da2899SCharles.ForsythIobuf.gets(b: self ref Iobuf, term: int): string
34337da2899SCharles.Forsyth{
34437da2899SCharles.Forsyth	i: int;
34537da2899SCharles.Forsyth
34637da2899SCharles.Forsyth	if(b.mode == OWRITE)
34737da2899SCharles.Forsyth		return nil;
34837da2899SCharles.Forsyth	if(b.lastop != OREAD && write2read(b) < 0)
34937da2899SCharles.Forsyth		return nil;
35037da2899SCharles.Forsyth#	if(term < UTFself)
35137da2899SCharles.Forsyth#		return tgets(b, term);
35237da2899SCharles.Forsyth	str: string;
35337da2899SCharles.Forsyth	ch := -1;
35437da2899SCharles.Forsyth	for (;;) {
35537da2899SCharles.Forsyth		start := b.index;
35637da2899SCharles.Forsyth		n := 0;
35737da2899SCharles.Forsyth		while(b.index < b.size){
35837da2899SCharles.Forsyth			(ch, i, nil) = sys->byte2char(b.buffer[0:b.size], b.index);
35937da2899SCharles.Forsyth			if(i == 0)	# too few bytes for full Rune
36037da2899SCharles.Forsyth				break;
36137da2899SCharles.Forsyth			n += i;
36237da2899SCharles.Forsyth			b.index += i;
36337da2899SCharles.Forsyth			if(ch == term)
36437da2899SCharles.Forsyth				break;
36537da2899SCharles.Forsyth		}
36637da2899SCharles.Forsyth		if(n > 0)
36737da2899SCharles.Forsyth			str += string b.buffer[start:start+n];
36837da2899SCharles.Forsyth		if(ch == term)
36937da2899SCharles.Forsyth			return str;
37037da2899SCharles.Forsyth		b.buffer[0:] = b.buffer[b.index:b.size];
37137da2899SCharles.Forsyth		b.bufpos += big b.index;
37237da2899SCharles.Forsyth		b.size -= b.index;
37337da2899SCharles.Forsyth		b.index = 0;
37437da2899SCharles.Forsyth		if (readchunk(b) < 0)
37537da2899SCharles.Forsyth			break;
37637da2899SCharles.Forsyth	}
37737da2899SCharles.Forsyth	return str;	# nil at EOF
37837da2899SCharles.Forsyth}
37937da2899SCharles.Forsyth
38037da2899SCharles.ForsythIobuf.gett(b: self ref Iobuf, s: string): string
38137da2899SCharles.Forsyth{
38237da2899SCharles.Forsyth	r := "";
38337da2899SCharles.Forsyth	if (b.mode == OWRITE || (ch := b.getc()) < 0)
38437da2899SCharles.Forsyth		return nil;
38537da2899SCharles.Forsyth	do {
38637da2899SCharles.Forsyth		r[len r] = ch;
38737da2899SCharles.Forsyth		for (i:=0; i<len(s); i++)
38837da2899SCharles.Forsyth			if (ch == s[i])
38937da2899SCharles.Forsyth				return r;
39037da2899SCharles.Forsyth	} while ((ch = b.getc()) >= 0);
39137da2899SCharles.Forsyth	return r;
39237da2899SCharles.Forsyth}
39337da2899SCharles.Forsyth
39437da2899SCharles.Forsythread2write(b: ref Iobuf)
39537da2899SCharles.Forsyth{
39637da2899SCharles.Forsyth	# last operation was a read
39737da2899SCharles.Forsyth	b.bufpos += big b.index;
39837da2899SCharles.Forsyth	b.size = 0;
39937da2899SCharles.Forsyth	b.index = 0;
40037da2899SCharles.Forsyth	b.lastop = OWRITE;
40137da2899SCharles.Forsyth}
40237da2899SCharles.Forsyth
40337da2899SCharles.ForsythIobuf.write(b: self ref Iobuf, buf: array of byte, n: int): int
40437da2899SCharles.Forsyth{
40537da2899SCharles.Forsyth	if(b.lastop != OWRITE) {
40637da2899SCharles.Forsyth		if(b.mode == OREAD)
40737da2899SCharles.Forsyth			return ERROR;
40837da2899SCharles.Forsyth		read2write(b);
40937da2899SCharles.Forsyth	}
41037da2899SCharles.Forsyth	start := 0;
41137da2899SCharles.Forsyth	k := n;
41237da2899SCharles.Forsyth	while(k > 0){
41337da2899SCharles.Forsyth		nw := Bufsize - b.index;
41437da2899SCharles.Forsyth		if(nw > k)
41537da2899SCharles.Forsyth			nw = k;
41637da2899SCharles.Forsyth		end := start + nw;
41737da2899SCharles.Forsyth		b.buffer[b.index:] = buf[start:end];
41837da2899SCharles.Forsyth		start = end;
41937da2899SCharles.Forsyth		b.index += nw;
42037da2899SCharles.Forsyth		k -= nw;
42137da2899SCharles.Forsyth		if(b.index > b.size)
42237da2899SCharles.Forsyth			b.size = b.index;
42337da2899SCharles.Forsyth		b.dirty = 1;
42437da2899SCharles.Forsyth		if(b.size == Bufsize && writechunk(b) < 0)
42537da2899SCharles.Forsyth			return ERROR;
42637da2899SCharles.Forsyth	}
42737da2899SCharles.Forsyth	return n;
42837da2899SCharles.Forsyth}
42937da2899SCharles.Forsyth
43037da2899SCharles.ForsythIobuf.putb(b: self ref Iobuf, c: byte): int
43137da2899SCharles.Forsyth{
43237da2899SCharles.Forsyth	if(b.lastop != OWRITE) {
43337da2899SCharles.Forsyth		if(b.mode == OREAD)
43437da2899SCharles.Forsyth			return ERROR;
43537da2899SCharles.Forsyth		read2write(b);
43637da2899SCharles.Forsyth	}
43737da2899SCharles.Forsyth	b.buffer[b.index++] = c;
43837da2899SCharles.Forsyth	if(b.index > b.size)
43937da2899SCharles.Forsyth		b.size = b.index;
44037da2899SCharles.Forsyth	b.dirty = 1;
44137da2899SCharles.Forsyth	if(b.size >= Bufsize) {
44237da2899SCharles.Forsyth		if (b.fd == nil)
44337da2899SCharles.Forsyth			return ERROR;
44437da2899SCharles.Forsyth		if (writechunk(b) < 0)
44537da2899SCharles.Forsyth			return ERROR;
44637da2899SCharles.Forsyth	}
44737da2899SCharles.Forsyth	return 0;
44837da2899SCharles.Forsyth}
44937da2899SCharles.Forsyth
45037da2899SCharles.ForsythIobuf.putc(b: self ref Iobuf, c: int): int
45137da2899SCharles.Forsyth{
45237da2899SCharles.Forsyth	if(b.lastop != OWRITE) {
45337da2899SCharles.Forsyth		if (b.mode == OREAD)
45437da2899SCharles.Forsyth			return ERROR;
45537da2899SCharles.Forsyth		read2write(b);
45637da2899SCharles.Forsyth	}
45737da2899SCharles.Forsyth	if(c < UTFself)
45837da2899SCharles.Forsyth		b.buffer[b.index++] = byte c;
45937da2899SCharles.Forsyth	else
46037da2899SCharles.Forsyth		b.index += sys->char2byte(c, b.buffer, b.index);
46137da2899SCharles.Forsyth	if (b.index > b.size)
46237da2899SCharles.Forsyth		b.size = b.index;
46337da2899SCharles.Forsyth	b.dirty = 1;
46437da2899SCharles.Forsyth	if (b.size >= Bufsize) {
46537da2899SCharles.Forsyth		if (writechunk(b) < 0)
46637da2899SCharles.Forsyth			return ERROR;
46737da2899SCharles.Forsyth	}
46837da2899SCharles.Forsyth	return 0;
46937da2899SCharles.Forsyth}
47037da2899SCharles.Forsyth
47137da2899SCharles.ForsythIobuf.puts(b: self ref Iobuf, s: string): int
47237da2899SCharles.Forsyth{
47337da2899SCharles.Forsyth	if(b.lastop != OWRITE) {
47437da2899SCharles.Forsyth		if (b.mode == OREAD)
47537da2899SCharles.Forsyth			return ERROR;
47637da2899SCharles.Forsyth		read2write(b);
47737da2899SCharles.Forsyth	}
47837da2899SCharles.Forsyth	n := len s;
47937da2899SCharles.Forsyth	if (n == 0)
48037da2899SCharles.Forsyth		return 0;
48137da2899SCharles.Forsyth	ind := b.index;
48237da2899SCharles.Forsyth	buf := b.buffer;
48337da2899SCharles.Forsyth	for(i := 0; i < n; i++){
48437da2899SCharles.Forsyth		c := s[i];
48537da2899SCharles.Forsyth		if(c < UTFself)
48637da2899SCharles.Forsyth			buf[ind++] = byte c;
48737da2899SCharles.Forsyth		else
48837da2899SCharles.Forsyth			ind += sys->char2byte(c, buf, ind);
48937da2899SCharles.Forsyth		if(ind >= Bufsize){
49037da2899SCharles.Forsyth			b.index = ind;
49137da2899SCharles.Forsyth			if(ind > b.size)
49237da2899SCharles.Forsyth				b.size = ind;
49337da2899SCharles.Forsyth			b.dirty = 1;
49437da2899SCharles.Forsyth			if(writechunk(b) < 0)
49537da2899SCharles.Forsyth				return ERROR;
49637da2899SCharles.Forsyth			ind = b.index;
49737da2899SCharles.Forsyth		}
49837da2899SCharles.Forsyth	}
49937da2899SCharles.Forsyth	b.dirty = b.index != ind;
50037da2899SCharles.Forsyth	b.index = ind;
50137da2899SCharles.Forsyth	if (ind > b.size)
50237da2899SCharles.Forsyth		b.size = ind;
50337da2899SCharles.Forsyth	return n;
50437da2899SCharles.Forsyth}
50537da2899SCharles.Forsyth
50637da2899SCharles.Forsythfiller(b: ref Iobuf): ref Filler
50737da2899SCharles.Forsyth{
50837da2899SCharles.Forsyth	for (f := fillers; f != nil; f = f.next)
50937da2899SCharles.Forsyth		if(f.iobuf == b)
51037da2899SCharles.Forsyth			return f;
51137da2899SCharles.Forsyth	return nil;
51237da2899SCharles.Forsyth}
51337da2899SCharles.Forsyth
51437da2899SCharles.ForsythIobuf.setfill(b: self ref Iobuf, fill: BufioFill)
51537da2899SCharles.Forsyth{
51637da2899SCharles.Forsyth	if ((f := filler(b)) != nil)
51737da2899SCharles.Forsyth		f.fill = fill;
51837da2899SCharles.Forsyth	else
51937da2899SCharles.Forsyth		fillers = ref Filler(b, fill, fillers);
52037da2899SCharles.Forsyth}
52137da2899SCharles.Forsyth
52237da2899SCharles.Forsythnofill(b: ref Iobuf)
52337da2899SCharles.Forsyth{
52437da2899SCharles.Forsyth	prev: ref Filler;
52537da2899SCharles.Forsyth	for(f := fillers; f != nil; f = f.next) {
52637da2899SCharles.Forsyth		if(f.iobuf == b) {
52737da2899SCharles.Forsyth			if (prev == nil)
52837da2899SCharles.Forsyth				fillers = f.next;
52937da2899SCharles.Forsyth			else
53037da2899SCharles.Forsyth				prev.next = f.next;
53137da2899SCharles.Forsyth		}
53237da2899SCharles.Forsyth		prev = f;
53337da2899SCharles.Forsyth	}
53437da2899SCharles.Forsyth}
535