#line 643 "/home/ubuntu/felix/src/packages/io.fdoc"
class IOStream {
requires package "demux";
requires package "faio";
open Faio;
if PLAT_POSIX do
open Faio_posix;
typedef fd_t = FileSystem::posix_file;
else
open Faio_win32;
typedef fd_t = Faio_win32::fd_t;
done
publish "The interface for a readable stream of bytes."
class IByteStream[T] {
publish "Read N bytes from the stream into the address."
virtual proc read: T * &int * address * &bool;
}
publish "The interface for a writable stream of bytes."
class OByteStream[T] {
publish "Write N bytes from the address into the stream."
virtual proc write: T * &int * address * &bool;
}
publish "The interface for a readable and writable stream of bytes."
class IOByteStream[T] {
inherit IByteStream[T];
inherit OByteStream[T];
}
publish "A readable stream that can have it's read channel closed."
class TerminalIByteStream[T] {
inherit IByteStream[T];
publish "Close the input stream."
virtual proc iclose: T;
}
publish "A writable stream that can have it's write channel closed."
class TerminalOByteStream[T] {
inherit OByteStream[T];
publish "Close the output stream."
virtual proc oclose: T;
}
publish "A writable stream that can have it's channels closed."
class TerminalIOByteStream[T] {
inherit TerminalIByteStream[T];
inherit TerminalOByteStream[T];
publish "Close the stream."
virtual proc ioclose: T;
}
variant devnull_t = DEVNULL;
publish "devnull_t"
instance IByteStream[devnull_t]
{
proc read(strm: devnull_t, len: &int, buf: address, eof: &bool) {
len <- 0;
eof <- true;
}
}
instance OByteStream[devnull_t]
{
proc write(strm: devnull_t, len: &int, buf: address, eof: &bool) {
eof <- false;
}
}
instance IOByteStream[devnull_t] {}
instance TerminalIByteStream[devnull_t] { proc iclose (x:devnull_t) {} }
instance TerminalOByteStream[devnull_t] { proc oclose (x:devnull_t) {} }
instance TerminalIOByteStream[devnull_t] { proc ioclose (x:devnull_t) {} }
publish "fd_t -- native file handle (disk file)"
instance IByteStream[fd_t]
{
if PLAT_POSIX do
gen cread: fd_t * int * address -> int = "read($1,$2,$3)";
proc read(fd: fd_t, len: &int, buf: address, eof: &bool) {
var oldlen = *len;
len <- cread(fd, *len, buf);
eof <- oldlen < *len;
}
else
gen ReadFile: fd_t * address * int32 * &int32 -> bool =
"ReadFile($1,$2,$3,$4,NULL)"
;
proc read(fd: fd_t, len: &int, buf: address, eof: &bool) {
var oldlen = *len;
var readin: int32;
var res = ReadFile(fd, buf, len*.int32, &readin);
len <- readin.int;
eof <- res or (oldlen < *len);
}
done
}
instance OByteStream[fd_t]
{
if PLAT_POSIX do
gen cwrite: fd_t * int * address -> int = "write($1,$2,$3)";
proc write(fd: fd_t, len: &int, buf: address, eof: &bool) {
var oldlen = *len;
len <- cwrite(fd, *len, buf);
eof <- oldlen < *len;
}
else
gen WriteFile: fd_t * address * int32 * &int32 -> bool =
"WriteFile($1,$2,$3,$4,NULL)"
;
proc write(fd: fd_t, len: &int, buf: address, eof: &bool) {
var oldlen = *len;
var written: int32;
var res = WriteFile(fd, buf, len*.int32, &written);
len <- written.int;
eof <- res or (oldlen < *len);
}
done
}
instance IOByteStream[fd_t] {}
instance TerminalIByteStream[fd_t]
{
proc iclose (fd: fd_t) {
if PLAT_POSIX do
C_hack::ignore(FileSystem::close fd);
else
CloseFile fd;
done
}
}
instance TerminalOByteStream[fd_t]
{
proc oclose (fd: fd_t) {
if PLAT_POSIX do
C_hack::ignore(FileSystem::close fd);
else
CloseFile fd;
done
}
}
instance TerminalIOByteStream[fd_t]
{
proc ioclose (fd: fd_t) {
if PLAT_POSIX do
C_hack::ignore(FileSystem::close fd);
else
CloseFile fd;
done
}
}
publish "Read the input stream to the output stream."
proc cat[istr,ostr with IByteStream[istr], OByteStream[ostr]] (
istream: istr,
ostream: ostr,
buf: address,
bufsize: int)
{
var reof = false;
var weof = false;
var len: int;
while not reof and not weof do
len = bufsize;
read (istream, &len, buf, &reof);
write(ostream, &len, buf, &weof);
done
}
publish "Read the input stream to the output stream."
proc cat[istr,ostr with IByteStream[istr], OByteStream[ostr]] (
istream: istr,
ostream: ostr)
{
val BUFSIZE = 100000;
var buf = Memory::malloc(BUFSIZE);
cat (istream, ostream, buf, BUFSIZE);
Memory::free (buf);
}
publish "Read all the input streams to the output stream."
proc cat[istr,ostr with IByteStream[istr], OByteStream[ostr]] (
istreams: list[istr],
ostream: ostr,
buf: address,
bufsize: int)
{
List::iter (proc (istream:istr) {
cat (istream, ostream, buf, bufsize);
}) istreams;
}
publish "Compare the results of two streams."
proc stream_cmp[istr1,istr2 with IByteStream[istr1], IByteStream[istr2]] (
stream1: istr1,
stream2: istr2,
buf1: address,
buf2: address,
bufsize: int,
sign: &int)
{
var eof1 = false;
var eof2 = false;
var len1: int;
var len2: int;
var terminated = false;
var cmp = 0;
while cmp == 0 and not terminated do
len1 = bufsize; read(stream1, &len1, buf1, &eof1);
len2 = bufsize; read(stream2, &len2, buf2, &eof2);
len := min(len1, len2);
cmp = Memory::memcmp(buf1, buf2, size len);
if cmp == 0 do
cmp = len1 - len2;
if cmp == 0 do
terminated = eof1 and eof2;
cmp =
match eof1, eof2 with
| case 1, case 1 => 0
| case 0, case 0 => 0
| case 0, case 1 => 1
| case 1, case 0 => -1
endmatch
;
done
done
done
sign <- cmp;
}
publish "Compare the results of two streams."
proc cmp[istr1, istr2 with IByteStream[istr1], IByteStream[istr2]] (
istream1: istr1,
istream2: istr2,
res: &int)
{
val BUFSIZE = 100000;
var buf1 = Memory::malloc(BUFSIZE);
var buf2 = Memory::malloc(BUFSIZE);
stream_cmp(istream1, istream2, buf1, buf2, BUFSIZE, res);
Memory::free(buf1);
Memory::free(buf2);
}
publish "Read the results of a stream back into it's stream."
proc echo[iostr with IOByteStream[iostr]] (
iostream: iostr,
buf: address,
bufsize: int)
{
cat(iostream, iostream, buf, bufsize);
}
publish "Read in from a stream and write to two streams."
proc tee[istr,ostr with IByteStream[istr], OByteStream[ostr]] (
istream: istr,
ostream1: ostr,
ostream2: ostr)
{
var reof = false;
var weof1 = false;
var weof2 = false;
var len: int;
val BUFSIZE = 10*1024;
var buf = Memory::malloc(BUFSIZE);
while not reof and not weof1 and not weof2 do
len = BUFSIZE;
read (istream, &len, buf, &reof);
write (ostream1, &len, buf, &weof1);
write (ostream2, &len, buf, &weof2);
done
Memory::free buf;
}
noinline proc get_line[istr with IByteStream[istr]] (
istream: istr,
s: &string)
{
var c: char;
val ac = address (&c);
var st: string="";
var finished = false;
while not finished do
var len = 1;
var eof: bool;
read(istream, &len, ac, &eof);
if eof or c == char '\n' do
finished = true;
else
st += c;
done
done
s <- st;
}
proc write_string[ostr with OByteStream[ostr]] (
ostream: ostr,
var s: string,
eof: &bool)
{
var slen = s.len.int;
var a = C_hack::cast[address]$ cstr s;
write(ostream, &slen, a, eof);
}
}