## winix-data-file-for-os-g--premicrothread.pkg
#
# Here we combine the platform-specific code in our wxd
# argument with the platfrom-agnostic code in our
# body to generate a complete binary-file I/O package
# for a particular platform.
# This is the binary-file counterpart to
#
#
src/lib/std/src/io/winix-text-file-for-os-g--premicrothread.pkg#
# This is intended for monothreaded code, so threadkit defines an alternative:
#
#
src/lib/std/src/io/winix-data-file-for-os-g.pkg# Compiled by:
#
src/lib/std/src/standard-core.sublib# QUESTION: What operations should raise exceptions
# when the stream is closed?
stipulate
package eow = io_startup_and_shutdown__premicrothread; # "eow" == "end of world" # io_startup_and_shutdown__premicrothread is from
src/lib/std/src/io/io-startup-and-shutdown--premicrothread.pkg package int = int_guts; # int_guts is from
src/lib/std/src/int-guts.pkg package iox = io_exceptions; # io_exceptions is from
src/lib/std/src/io/io-exceptions.pkg package pos = file_position_guts; # file_position_guts is from
src/lib/std/src/bind-position-31.pkg package a = rw_vector_of_one_byte_unts; # rw_vector_of_one_byte_unts is from
src/lib/std/src/rw-vector-of-one-byte-unts.pkg package rs = rw_vector_slice_of_one_byte_unts; # rw_vector_slice_of_one_byte_unts is from
src/lib/std/src/rw-vector-slice-of-one-byte-unts.pkg package v = vector_of_one_byte_unts; # vector_of_one_byte_unts is from
src/lib/std/src/vector-of-one-byte-unts.pkg package vs = vector_slice_of_one_byte_unts; # vector_slice_of_one_byte_unts is from
src/lib/std/src/vector-slice-of-one-byte-unts.pkgherein
# This generic gets invoked from:
#
#
src/lib/std/src/posix/winix-data-file-for-posix--premicrothread.pkg #
src/lib/std/src/win32/winix-data-file-for-win32.pkg #
generic package winix_data_file_for_os_g__premicrothread (
# ========================================
#
# "wxd" == "WiniX file io Driver".
# It will will be one of:
#
# winix_data_file_io_driver_for_posix__premicrothread is from
src/lib/std/src/posix/winix-data-file-io-driver-for-posix--premicrothread.pkg # winix_data_file_io_driver_for_win32__premicrothread is from
src/lib/std/src/win32/winix-data-file-io-driver-for-win32--premicrothread.pkg package wxd
: Winix_Extended_File_Io_Driver_For_Os__Premicrothread # Winix_Extended_File_Io_Driver_For_Os__Premicrothread is from
src/lib/std/src/io/winix-extended-file-io-driver-for-os--premicrothread.api where
drv == winix_base_data_file_io_driver_for_posix__premicrothread;
)
: (weak) Winix_Data_File_For_Os__Premicrothread # Winix_Data_File_For_Os__Premicrothread is from
src/lib/std/src/io/winix-data-file-for-os--premicrothread.api {
package drv = wxd::drv;
# An element for initializing buffers:
#
some_element = (0u0: one_byte_unt::Unt);
# # Fast, but unsafe version (from vector_of_one_byte_unts)
# vecSub = inline_t::vector_of_one_byte_unts::get
# arrUpdate = inline_t::rw_vector_of_one_byte_unts::update
# /* fast vector extract operation. This should never be called with
# * a length of 0.
# */
# fun vecExtract (v, base, optLen) = let
# len = v::length v
# fun newVec n = let
# newV = assembly::a::make_string n
# fun fill i = if (i < n)
# then (
# inline_t::vector_of_one_byte_unts::update (newV, i, vecSub (v, base+i));
# fill (i+1))
# else ()
# in
# fill 0; newV
# end
# in
# case (base, optLen)
# of (0, NULL) => v
#
| (_, NULL) => newVec (len - base)
#
| (_, THE n) => newVec n
# # end case
# end
#
vec_extract = vs::to_vector o vs::make_slice;
vec_get = v::get;
rw_vec_set = a::set;
empty = v::from_list [];
package pur { # "pur" is short for "pure" (I/O).
#
Vector = v::Vector;
Element = v::Element;
Filereader = drv::Filereader;
Filewriter = drv::Filewriter;
File_Position = drv::File_Position;
# *** Functional input streams ***
# We represent an Input_Stream by a pointer to a buffer and an offset
# into the buffer. The buffers are chained by the "next" field from
# the beginning of the stream towards the end. If the "next" field
# is LAST, then it refers to an empty buffer (consuming the EOF marker
# involves moving the stream from immediately in front of the LAST to
# to the empty buffer). A "next" field of TERMINATED marks a
# terminated stream. We also have the invariant that the "last_nextref"
# field of the "global_file_stuff" package points to a next REF that is either
# NO_NEXT or TERMINATED.
Input_Stream = INPUT_STREAM (Input_Buffer, Int)
also
Input_Buffer
=
INPUT_BUFFER
{
data: Vector,
file_position: Null_Or( File_Position ),
#
next: Ref( Next ),
global_file_stuff: Global_File_Stuff
}
also
Next
= NEXT Input_Buffer # forward link to additional data
| LAST Input_Buffer
# End of stream marker
| NO_NEXT
# placeholder for forward link
| TERMINATED
# termination of the stream
also
Global_File_Stuff
=
GLOBAL_FILE_STUFF
{ filereader: Filereader,
read_vector: Int -> Vector,
is_closed: Ref( Bool ),
get_file_position: Void -> Null_Or( File_Position ),
last_nextref: Ref( Ref( Next ) ), # Points to the 'next' cell of the last buffer.
clean_tag: eow::Tag
};
fun global_file_stuff_of_ibuf (INPUT_BUFFER { global_file_stuff, ... } )
=
global_file_stuff;
fun best_io_quantum_of_ibuf buf
=
{ (global_file_stuff_of_ibuf buf)
->
GLOBAL_FILE_STUFF { filereader => drv::FILEREADER { best_io_quantum, ... }, ... };
best_io_quantum;
};
fun read_vector (INPUT_BUFFER { global_file_stuff=>GLOBAL_FILE_STUFF { read_vector=>f, ... }, ... } )
=
f;
fun raise_io_exception (GLOBAL_FILE_STUFF { filereader => drv::FILEREADER { filename, ... }, ... }, ml_op, exn)
=
raise exception iox::IO { op=>ml_op, name => filename, cause=>exn };
fun extend_stream (read_fn, ml_op, buf as INPUT_BUFFER { next, global_file_stuff, ... } )
=
{ global_file_stuff -> GLOBAL_FILE_STUFF { get_file_position, last_nextref, ... };
file_position = get_file_position();
chunk = read_fn (best_io_quantum_of_ibuf buf);
new_next = REF NO_NEXT;
buf' = INPUT_BUFFER {
file_position,
global_file_stuff,
data => chunk,
next => new_next
};
result = v::length chunk == 0 ?? LAST buf'
:: NEXT buf';
next := result;
last_nextref := new_next;
result;
}
except
ex = raise_io_exception (global_file_stuff, ml_op, ex);
fun get_next_buffer (read_fn, ml_op) (buf as INPUT_BUFFER { next, global_file_stuff, ... } )
=
case *next
#
TERMINATED => (LAST buf);
NO_NEXT => extend_stream (read_fn, ml_op, buf);
next => next;
esac;
# Read a chunk that is at least the specified size:
#
fun read_chunk buf
=
{ (global_file_stuff_of_ibuf buf)
->
GLOBAL_FILE_STUFF { read_vector, filereader => drv::FILEREADER { best_io_quantum, ... }, ... };
case (best_io_quantum - 1)
#
0 => (\\ n = read_vector n);
k => (\\ n # round up to next multiple of best_io_quantum
=
read_vector (int::quot((n+k), best_io_quantum) * best_io_quantum)
);
esac;
};
fun generalized_input get_buf
=
{ fun get (INPUT_STREAM (buf as INPUT_BUFFER { data, ... }, pos))
=
{ len = v::length data;
if (pos < len)
#
( vec_extract (data, pos, NULL),
INPUT_STREAM (buf, len)
);
else
case (get_buf buf)
#
LAST buf => (empty, INPUT_STREAM (buf, 0));
NEXT rest => get (INPUT_STREAM (rest, 0));
_ => raise exception DIE "bogus get_buf";
esac;
fi;
};
get;
};
# Terminate an input stream:
#
fun terminate (GLOBAL_FILE_STUFF { last_nextref, clean_tag, ... } )
=
case *last_nextref
#
m as REF NO_NEXT
=>
{ eow::drop_stream_startup_and_shutdown_actions clean_tag;
#
m := TERMINATED;
};
m as REF TERMINATED
=>
();
_ => raise exception MATCH; # To quiet the compiler.
esac;
fun read (stream as INPUT_STREAM (buf, _))
=
generalized_input
(get_next_buffer (read_vector buf, "read"))
stream;
fun read_one (INPUT_STREAM (buf, pos))
=
{ buf -> INPUT_BUFFER { data, next, ... };
if (pos < v::length data)
#
THE (vec_get (data, pos), INPUT_STREAM (buf, pos+1));
else
case *next
#
NEXT buf => read_one (INPUT_STREAM (buf, 0));
LAST _ => NULL;
TERMINATED => NULL;
NO_NEXT =>
case (extend_stream (read_vector buf, "read_one", buf))
#
NEXT rest => read_one (INPUT_STREAM (rest, 0));
_ => NULL;
esac;
esac;
fi;
};
fun read_n (INPUT_STREAM (buf, pos), bytes_to_read)
=
{ (read_as_list_of_vectors (buf, pos, bytes_to_read))
->
(list_of_vectors, remaining_stream);
(v::cat list_of_vectors, remaining_stream);
}
where
fun join (item, (list, stream))
=
(item ! list, stream);
fun read_as_list_of_vectors (buf as INPUT_BUFFER { data, ... }, i, n)
=
{ len = v::length data;
#
remain = len-i;
if (remain >= n)
#
([vec_extract (data, i, THE n)], INPUT_STREAM (buf, i+n));
else
join (
vec_extract (data, i, NULL),
next_buf (buf, n-remain)
);
fi;
}
also
fun next_buf (buf as INPUT_BUFFER { next, data, ... }, n)
=
case *next
#
NEXT buf => read_as_list_of_vectors (buf, 0, n);
LAST buf => ([], INPUT_STREAM (buf, 0));
TERMINATED => ([], INPUT_STREAM (buf, v::length data));
NO_NEXT => case (extend_stream (read_vector buf, "read_n", buf))
#
NEXT rest => read_as_list_of_vectors (rest, 0, n);
_ => ([], INPUT_STREAM (buf, v::length data));
esac;
esac;
end;
fun read_all (stream as INPUT_STREAM (buf, _))
=
{ (global_file_stuff_of_ibuf buf)
->
GLOBAL_FILE_STUFF { filereader => drv::FILEREADER { avail, ... }, ... };
# Read a chunk that is as large
# as the available input:
#
fun big_chunk _
=
read_chunk buf delta
where
delta = case (avail ())
#
NULL => best_io_quantum_of_ibuf buf;
THE n => n;
esac;
end;
big_input
=
generalized_input (get_next_buffer (big_chunk, "read_all"));
fun loop (v, stream)
=
if (v::length v == 0)
#
([], stream);
else
(loop (big_input stream))
->
(l, stream');
(v ! l, stream');
fi;
(loop (big_input stream))
->
(data, stream');
(v::cat data, stream');
};
fun close_input (INPUT_STREAM (buf, _))
=
case (global_file_stuff_of_ibuf buf)
#
GLOBAL_FILE_STUFF { is_closed => REF TRUE, ... }
=>
();
global_file_stuff as GLOBAL_FILE_STUFF { is_closed, filereader => drv::FILEREADER { close, ... }, ... }
=>
{ terminate global_file_stuff;
#
is_closed := TRUE;
close ()
except
ex = raise_io_exception (global_file_stuff, "close_input", ex);
};
esac;
fun end_of_stream (INPUT_STREAM (buf, pos))
=
case buf
#
INPUT_BUFFER { next=>REF (NEXT _), ... } => FALSE;
INPUT_BUFFER { next=>REF (LAST _), ... } => TRUE;
INPUT_BUFFER { next, data, global_file_stuff=>GLOBAL_FILE_STUFF { is_closed, ... }, ... }
=>
if (pos == v::length data)
#
case (*next, *is_closed)
#
(NO_NEXT, FALSE)
=>
case (extend_stream (read_vector buf, "end_of_stream", buf))
#
(LAST _) => TRUE;
_ => FALSE;
esac;
_ => TRUE;
esac;
else
FALSE;
fi;
esac;
fun make_instream (filereader, data)
=
{ filereader -> drv::FILEREADER { read_vector, get_file_position, set_file_position, ... };
#
get_file_position
=
case (get_file_position, set_file_position)
#
(THE f, THE _ ) => (\\ () = THE (f()));
_ => (\\ () = NULL);
esac;
next = REF NO_NEXT;
closed_flag = REF FALSE;
tag = eow::note_stream_startup_and_shutdown_actions
{
init => \\ () = closed_flag := TRUE,
flush => \\ () = (),
close => \\ () = closed_flag := TRUE
};
global_file_stuff
=
GLOBAL_FILE_STUFF
{
get_file_position,
filereader,
read_vector,
#
is_closed => closed_flag,
last_nextref => REF next,
clean_tag => tag
};
# What should we do about the position when there is initial data?? *
# Suggestion: When building a stream with supplied initial data,
# nothing can be said about the positions inside that initial
# data (who knows where that data even came from!).
file_position
=
if (v::length data == 0) get_file_position ();
else NULL;
fi;
INPUT_STREAM ( INPUT_BUFFER { file_position, data, global_file_stuff, next },
0
);
};
fun get_reader (INPUT_STREAM (buf, pos))
=
{
buf -> INPUT_BUFFER
{ data,
next,
global_file_stuff as GLOBAL_FILE_STUFF { filereader, ... },
...
};
fun get_data (NEXT (INPUT_BUFFER { data, next, ... } ))
=>
data ! get_data *next;
get_data _
=>
[];
end;
terminate global_file_stuff;
if (pos < v::length data)
#
( filereader,
v::cat (vec_extract (data, pos, NULL) ! get_data *next)
);
else
( filereader,
v::cat (get_data *next)
);
fi;
};
# Get the underlying file position of a stream:
#
fun file_position_in (INPUT_STREAM (buf, pos))
=
case buf
#
INPUT_BUFFER { file_position => NULL, global_file_stuff, ... }
=>
raise_io_exception (global_file_stuff, "filePosIn", iox::RANDOM_ACCESS_IO_NOT_SUPPORTED);
INPUT_BUFFER { file_position => THE b, global_file_stuff, ... }
=>
pos::(+) (b, pos::from_int pos);
esac;
Output_Stream
=
OUTPUT_STREAM
{
buffer: a::Rw_Vector,
first_free_byte_in_buffer: Ref( Int ),
#
is_closed: Ref( Bool ),
buffering_mode: Ref( iox::Buffering_Mode ),
filewriter: Filewriter,
#
write_rw_vector: rs::Slice -> Void,
write_vector: vs::Slice -> Void,
#
clean_tag: eow::Tag
};
fun raise_io_exception (OUTPUT_STREAM { filewriter => drv::FILEWRITER { filename, ... }, ... }, ml_op, cause)
=
raise exception iox::IO { op => ml_op, name => filename, cause };
fun is_closed_out (stream as OUTPUT_STREAM { is_closed=>REF TRUE, ... }, ml_op)
=>
raise_io_exception (stream, ml_op, iox::CLOSED_IO_STREAM);
is_closed_out _
=>
();
end;
fun flush_buffer (stream as OUTPUT_STREAM { buffer, first_free_byte_in_buffer, write_rw_vector, ... }, ml_op)
=
case *first_free_byte_in_buffer
#
0 => ();
#
n => { write_rw_vector (rs::make_slice (buffer, 0, THE n));
first_free_byte_in_buffer := 0;
}
except
any_exception = raise_io_exception (stream, ml_op, any_exception);
esac;
fun write (stream as OUTPUT_STREAM os, v)
=
{
is_closed_out (stream, "write");
os -> { buffer, first_free_byte_in_buffer, buffering_mode, ... };
fun flush ()
=
flush_buffer (stream, "write");
fun flush_all ()
=
os.write_rw_vector (rs::make_full_slice buffer)
except
any_exception
=
raise_io_exception
(stream, "write", any_exception);
fun write_direct ()
=
{ case *first_free_byte_in_buffer
#
0 => ();
n => { os.write_rw_vector (rs::make_slice (buffer, 0, THE n));
#
first_free_byte_in_buffer := 0;
};
esac;
os.write_vector (vs::make_full_slice v);
}
except
any_exception
=
raise_io_exception
(stream, "write", any_exception);
fun insert copy_vec
=
{ buf_len = a::length buffer;
data_len = v::length v;
if (data_len >= buf_len)
#
write_direct ();
else
i = *first_free_byte_in_buffer;
avail = buf_len - i;
if (avail < data_len)
#
copy_vec (v, 0, avail, buffer, i);
flush_all ();
copy_vec (v, avail, data_len-avail, buffer, 0);
first_free_byte_in_buffer := data_len-avail;
else
copy_vec (v, 0, data_len, buffer, i);
first_free_byte_in_buffer := i + data_len;
if (avail == data_len) flush (); fi;
fi;
fi;
};
case *buffering_mode
#
iox::NO_BUFFERING
=>
write_direct ();
_ =>
insert copy_vector
where
fun copy_vector (from, from_i, from_len, into, at)
=
rs::copy_vector
{ from => vs::make_slice (from, from_i, THE from_len),
into,
at
};
end;
esac;
};
fun write_one (stream as OUTPUT_STREAM { buffer, first_free_byte_in_buffer, buffering_mode, write_rw_vector, ... }, element)
=
{ is_closed_out (stream, "write_one");
#
case *buffering_mode
#
iox::NO_BUFFERING
=>
{ rw_vec_set (buffer, 0, element);
#
write_rw_vector (rs::make_slice (buffer, 0, THE 1))
except
ex = raise_io_exception (stream, "write_one", ex);
};
_ =>
{ i = *first_free_byte_in_buffer;
i' = i+1;
rw_vec_set (buffer, i, element);
first_free_byte_in_buffer := i';
if (i' == a::length buffer)
#
flush_buffer (stream, "write_one");
fi;
};
esac;
};
fun flush stream
=
flush_buffer (stream, "flush");
fun close_output (stream as OUTPUT_STREAM { filewriter => drv::FILEWRITER { filename, close, ... }, is_closed, clean_tag, ... } )
=
if (not *is_closed)
#
flush_buffer (stream, "close");
is_closed := TRUE;
eow::drop_stream_startup_and_shutdown_actions clean_tag;
# print ("close-output -- is_closed is FALSE so calling close() of '" + filename + "'. -- winix-data-file-for-os-g--premicrothread.pkg\n");
close();
# else
# print ("close-output -- is_closed is TRUE, nothing to do for '" + filename + "'. -- winix-data-file-for-os-g--premicrothread.pkg\n");
fi;
fun make_outstream (wr as drv::FILEWRITER { best_io_quantum, write_rw_vector, write_vector, ... }, mode)
=
{ fun iterate (f, size, subslice)
=
lp
where
fun lp sl
=
if (size sl != 0)
n = f sl;
lp (subslice (sl, n, NULL));
fi;
end;
write_rw_vector'
=
case write_rw_vector
#
NULL => (\\ _ = raise exception iox::BLOCKING_IO_NOT_SUPPORTED);
THE f => iterate (f, rs::length, rs::make_subslice);
esac;
write_vector'
=
case write_vector
#
NULL => (\\ _ = raise exception iox::BLOCKING_IO_NOT_SUPPORTED);
THE f => iterate (f, vs::length, vs::make_subslice);
esac;
# Install a dummy cleaner:
#
tag = eow::note_stream_startup_and_shutdown_actions {
init => \\ () = (),
flush => \\ () = (),
close => \\ () = ()
};
stream = OUTPUT_STREAM
{
buffer => a::make_rw_vector (best_io_quantum, some_element),
first_free_byte_in_buffer => REF 0,
#
is_closed => REF FALSE,
buffering_mode => REF mode,
#
filewriter => wr,
write_rw_vector => write_rw_vector',
#
write_vector => write_vector',
clean_tag => tag
};
eow::change_stream_startup_and_shutdown_actions (tag, {
init => \\ () = close_output stream,
flush => \\ () = flush stream,
close => \\ () = close_output stream
} );
stream;
};
fun get_writer (stream as OUTPUT_STREAM { filewriter, buffering_mode, ... } )
=
{ flush_buffer (stream, "getWriter");
#
(filewriter, *buffering_mode);
};
# Position operations on outstreams
Out_Position
=
OUT_POSITION {
pos: drv::File_Position,
stream: Output_Stream
};
fun get_output_position (stream as OUTPUT_STREAM { filewriter, ... } )
=
{ flush_buffer (stream, "get_output_position");
#
case filewriter
#
drv::FILEWRITER { get_file_position=>THE f, ... }
=>
OUT_POSITION { pos => f(), stream }
except
ex = raise_io_exception (stream, "get_output_position", ex);
_ => raise_io_exception (stream, "get_output_position", iox::RANDOM_ACCESS_IO_NOT_SUPPORTED);
esac;
};
fun file_pos_out (OUT_POSITION { pos, stream } )
=
{ is_closed_out (stream, "filePosOut");
#
pos;
};
fun set_output_position (OUT_POSITION { pos, stream as OUTPUT_STREAM { filewriter, ... } } )
=
{ is_closed_out (stream, "set_output_position");
case filewriter
#
drv::FILEWRITER { set_file_position=>THE f, ... }
=>
(f pos)
except
ex = raise_io_exception (stream, "set_output_position", ex);
_ => raise_io_exception (stream, "get_output_position", iox::RANDOM_ACCESS_IO_NOT_SUPPORTED);
esac;
};
fun set_buffering_mode (stream as OUTPUT_STREAM { buffering_mode, ... }, iox::NO_BUFFERING)
=>
{ flush_buffer (stream, "setBufferMode");
#
buffering_mode := iox::NO_BUFFERING;
};
set_buffering_mode (stream as OUTPUT_STREAM { buffering_mode, ... }, mode)
=>
{ is_closed_out (stream, "setBufferMode");
#
buffering_mode := mode;
};
end;
fun get_buffering_mode (stream as OUTPUT_STREAM { buffering_mode, ... } )
=
{ is_closed_out (stream, "get_buffering_mode");
#
*buffering_mode;
};
}; # package pure_io
Vector = v::Vector;
Element = v::Element;
Input_Stream = Ref( pur::Input_Stream );
Output_Stream = Ref( pur::Output_Stream );
# * Input operations *
#
fun read stream
=
{ (pur::read *stream)
->
(v, stream');
stream := stream';
v;
};
fun read_one stream
=
case (pur::read_one *stream)
#
THE (element, stream') => { stream := stream';
THE element;
};
NULL => NULL;
esac;
fun read_n (stream, n)
=
{ (pur::read_n (*stream, n))
->
(v, stream');
stream := stream';
v;
};
fun read_all (stream: Input_Stream)
=
{ (pur::read_all *stream)
->
(v, s);
stream := s;
v;
};
fun peek (stream: Input_Stream)
=
case (pur::read_one *stream)
#
THE (element, _) => THE element;
NULL => NULL;
esac;
fun close_input stream
=
{ (*stream) -> (s as pur::INPUT_STREAM (buf as pur::INPUT_BUFFER { data, ... }, _));
# Find the end of the stream:
#
fun find_eos (pur::INPUT_BUFFER { next=>REF (pur::NEXT buf), ... } )
=>
find_eos buf;
find_eos (pur::INPUT_BUFFER { next=>REF (pur::LAST buf), ... } )
=>
find_eos buf;
find_eos (buf as pur::INPUT_BUFFER { data, ... } )
=>
pur::INPUT_STREAM (buf, v::length data);
end;
pur::close_input s;
stream := find_eos buf;
};
fun end_of_stream stream
=
pur::end_of_stream *stream;
# Output operations:
#
fun write (stream, v) = pur::write(*stream, v);
fun write_one (stream, c) = pur::write_one(*stream, c);
fun flush stream = pur::flush *stream;
fun close_output stream = pur::close_output *stream;
fun get_output_position stream = pur::get_output_position *stream;
fun set_output_position (stream, p as pur::OUT_POSITION { stream=>stream', ... } )
=
{ stream := stream';
#
pur::set_output_position p;
};
fun make_instream (stream: pur::Input_Stream) = REF stream;
fun get_instream (stream: Input_Stream) = *stream;
fun set_instream (stream: Input_Stream, stream') = stream := stream';
fun make_outstream (stream: pur::Output_Stream) = REF stream;
fun get_outstream (stream: Output_Stream) = *stream;
fun set_outstream (stream: Output_Stream, stream') = stream := stream';
# * Open files *
#
fun open_for_read filename
=
make_instream (pur::make_instream (wxd::open_for_read filename, empty))
except
ex = {
# print ("winix-data-file-for-os-g--premicrothread.pkg: open_for_read: failed to open for input: '" + filename + "\n");
raise exception iox::IO { op=>"open_for_read", name=>filename, cause=>ex };
};
fun open_for_write filename
=
make_outstream (pur::make_outstream (wxd::open_for_write filename, iox::BLOCK_BUFFERING))
except
ex = {
raise exception iox::IO { op=>"open", name=>filename, cause=>ex };
};
fun open_for_append filename
=
make_outstream (pur::make_outstream (wxd::open_for_append filename, iox::NO_BUFFERING))
except
ex = {
raise exception iox::IO { op => "open_for_append", name => filename, cause=>ex };
};
}; # winix_data_file_for_os_g__premicrothread
end;
## COPYRIGHT (c) 1995 AT&T Bell Laboratories.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.