!	I/O-Stream routines for T3X.
!	Copyright (C) 1997,1998 Nils M Holm.

struct IOS =	IOS_FD,
		IOS_BUFFER,
		IOS_FLAGS,
		IOS_LEN,
		IOS_PTR,
		IOS_END;

const		IOF_READ	= 00001,
		IOF_WRITE	= 00002,
		IOF_EOF		= 00004,
		IOF_LASTW	= 00008;

const		SEEK_SET	= 0,
		SEEK_REL	= 1,
		SEEK_END	= 2;


ios_create(iostream, fd, buffer, len, mode) do
	iostream[IOS_FD] := fd;
	iostream[IOS_BUFFER] := buffer;
	iostream[IOS_FLAGS] := mode;
	iostream[IOS_LEN] := len;
	iostream[IOS_PTR] := 0;
	iostream[IOS_END] := 0;
	return iostream;
end


ios_open(iostream, name, buffer, len, flags) do
	var	fd, mode;

	mode := flags = IOF_READ-> 0:
		flags = IOF_WRITE-> 1:
		flags = IOF_READ|IOF_WRITE-> 2: %1;
	if (mode < 0) return %1;
	fd := open(name, mode);
	if (fd < 0) return %1;
	return ios_create(iostream, fd, buffer, len, flags);
end


ios_flush(iostream) do
	var	k;

	if (	iostream[IOS_FLAGS] & IOF_WRITE /\
		iostream[IOS_FLAGS] & IOF_LASTW /\
		iostream[IOS_PTR]
	) do
		k := writepacked(iostream[IOS_FD], iostream[IOS_BUFFER],
			iostream[IOS_PTR]);
		if (k \= iostream[IOS_PTR]) return %1;
	end
	iostream[IOS_PTR] := 0;
	iostream[IOS_END] := 0;
	return 0;
end


ios_close(iostream) do
	if (ios_flush(iostream) = %1) return %1;
	close(iostream[IOS_FD]);
	iostream[IOS_FLAGS] := 0;
	return 0;
end


ios_wrch(iostream, ch) do
	iostream[IOS_FLAGS] := iostream[IOS_FLAGS] | IOF_LASTW;
	if (	iostream[IOS_PTR] >= iostream[IOS_LEN] /\
		ios_flush(iostream) = %1
	)
		return %1;
	iostream[IOS_BUFFER]::iostream[IOS_PTR] := ch;
	iostream[IOS_PTR] := iostream[IOS_PTR]+1;
	return ch;
end


ios_write(iostream, buffer, len) do
	var	i, p, l, b;

	iostream[IOS_FLAGS] := iostream[IOS_FLAGS] | IOF_LASTW;
	i := 0;
	p := iostream[IOS_PTR];
	l := iostream[IOS_LEN];
	b := iostream[IOS_BUFFER];
	while (len) do
		if (p >= l) do
			iostream[IOS_PTR] := p;
			if (ios_flush(iostream) = %1) return %1;
			p := iostream[IOS_PTR];
			l := iostream[IOS_LEN];
		end
		b::p := buffer::i;
		p := p+1;
		i := i+1;
		len := len-1;
	end
	iostream[IOS_PTR] := p;
	return i;
end


ios_writes(iostream, str) do
	var	k;
	var	b[1024];

	k := 0;
	while (str[k]) k := k+1;
	if (k > 1024) return %1;
	pack(str, b);
	return ios_write(iostream, b, k);
end


ios__more(iostream) do
	var	k;

	if (iostream[IOS_FLAGS] & IOF_READ) do
		k := readpacked(iostream[IOS_FD], iostream[IOS_BUFFER],
			iostream[IOS_LEN]);
		if (k <= 0) do
			iostream[IOS_FLAGS] := iostream[IOS_FLAGS] | IOF_EOF;
			if (k < 0) return %1;
		end
		iostream[IOS_END] := k;
		iostream[IOS_PTR] := 0;
	end
	return k;
end


ios_rdch(iostream) do
	var	c;

	iostream[IOS_FLAGS] := iostream[IOS_FLAGS] & ~IOF_LASTW;
	if (iostream[IOS_FLAGS] & IOF_EOF) return %1;
	if (	iostream[IOS_PTR] >= iostream[IOS_END] /\
		ios__more(iostream) < 1
	)
		return %1;
	c := iostream[IOS_BUFFER]::iostream[IOS_PTR];
	iostream[IOS_PTR] := iostream[IOS_PTR]+1;
	return c;
end


ios__read(iostream, buffer, len, ckln) do
	var	i, p, e, b;

	iostream[IOS_FLAGS] := iostream[IOS_FLAGS] & ~IOF_LASTW;
	i := 0;
	p := iostream[IOS_PTR];
	e := iostream[IOS_END];
	b := iostream[IOS_BUFFER];
	while (len) do
		if (p >= e) do
			iostream[IOS_PTR] := p;
			if (ios__more(iostream) < 1) leave;
			p := iostream[IOS_PTR];
			e := iostream[IOS_END];
		end
		buffer::i := b::p;
		p := p+1;
		i := i+1;
		len := len-1;
		if (ckln /\ buffer::(i-1) = '\n') leave;
	end
	if (ckln) buffer::i := 0;
	iostream[IOS_PTR] := p;
	iostream[IOS_END] := e;
	return i;
end


ios_read(iostream, buffer, len) return ios__read(iostream, buffer, len, 0);


ios_reads(iostream, buffer, len) return ios__read(iostream, buffer, len, 1);


ios_position(iostream, offh, offl, how) do
	var	delta;

	ie (how = SEEK_REL /\ iostream[IOS_FLAGS] & IOF_LASTW) do
		if (ios_flush(iostream) = %1) return %1;
	end
	else ie (how = SEEK_REL) do
		delta := iostream[IOS_END] - iostream[IOS_PTR];
		if (ios_flush(iostream) = %1) return %1;
		if (offl < delta) offh := offh - 1;
		offl := offl - delta;
	end
	else do
		if (ios_flush(iostream) = %1) return %1;
	end
	return reposition(iostream[IOS_FD], offh, offl, how);
end


ios_rdwrd(s) return ios_rdch(s) | (ios_rdch(s) << 8);


ios_wrwrd(s, w) do
	ios_wrch(s, w & 255);
	ios_wrch(s, w >> 8);
end


ios_eof(iostream) return (iostream[IOS_FLAGS] & IOF_EOF) -> %1: 0;
