mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
6194 lines
208 KiB
Mathematica
6194 lines
208 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1993-2012 The University of Melbourne.
|
|
% Copyright (C) 2013-2026 The Mercury team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: io.m.
|
|
% Main author: fjh.
|
|
% Stability: high.
|
|
%
|
|
% This file encapsulates all the file I/O.
|
|
%
|
|
% We implement a purely logical I/O system using non-logical I/O primitives of
|
|
% the underlying system. We ensure referential transparency by passing around
|
|
% a ``state-of-the-world'' argument using unique modes. The compiler will check
|
|
% that the state of the world argument is properly single-threaded, and will
|
|
% also ensure that the program doesn't attempt to backtrack over any I/O.
|
|
%
|
|
% Attempting any operation on a stream which has already been closed results
|
|
% in undefined behaviour.
|
|
%
|
|
% In multithreaded programs, each thread in the program has its own set of
|
|
% "current" input and output streams. At the time it is created, a child
|
|
% thread inherits the current streams from its parent. Predicates that
|
|
% change which stream is current affect only the calling thread.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module io.
|
|
:- interface.
|
|
|
|
:- include_module call_system.
|
|
:- include_module environment.
|
|
:- include_module file.
|
|
|
|
:- import_module array.
|
|
:- import_module bitmap.
|
|
:- import_module bool.
|
|
:- import_module char.
|
|
:- import_module deconstruct.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module stream.
|
|
:- import_module string.
|
|
:- import_module time.
|
|
:- import_module univ.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Exported types.
|
|
%
|
|
|
|
% The state of the universe.
|
|
%
|
|
:- type io.state.
|
|
|
|
% An alternative, more concise name for `io.state'.
|
|
%
|
|
:- type io == io.state.
|
|
|
|
% Opaque handles for text I/O streams.
|
|
%
|
|
:- type text_input_stream.
|
|
:- type text_output_stream.
|
|
|
|
% Alternative names for the above.
|
|
%
|
|
:- type input_stream == text_input_stream.
|
|
:- type output_stream == text_output_stream.
|
|
|
|
% Opaque handles for binary I/O streams.
|
|
%
|
|
:- type binary_input_stream.
|
|
:- type binary_output_stream.
|
|
|
|
% Various types used for the result from the access predicates.
|
|
%
|
|
:- type res
|
|
---> ok
|
|
; error(io.error).
|
|
|
|
:- type res(T)
|
|
---> ok(T)
|
|
; error(io.error).
|
|
|
|
% maybe_partial_res is used where it is possible to return a partial result
|
|
% when an error occurs.
|
|
%
|
|
:- type maybe_partial_res(T)
|
|
---> ok(T)
|
|
; error(T, io.error).
|
|
|
|
:- type maybe_partial_res_2(T1, T2)
|
|
---> ok2(T1, T2)
|
|
; error2(T1, T2, io.error).
|
|
|
|
:- inst maybe_partial_res(T) for maybe_partial_res/1
|
|
---> ok(T)
|
|
; error(T, ground).
|
|
|
|
:- type result
|
|
---> ok
|
|
; eof
|
|
; error(io.error).
|
|
|
|
:- type result(T)
|
|
---> ok(T)
|
|
; eof
|
|
; error(io.error).
|
|
|
|
% maybe_incomplete_result is returned when reading multibyte values from a
|
|
% binary stream. `incomplete(Bytes)' is returned when at least one byte of
|
|
% a value has already been read but there are insufficient bytes
|
|
% remaining in the stream to complete the value. In that case, Bytes will
|
|
% contain the bytes that have already been read from the stream, in the
|
|
% order in which they were read.
|
|
%
|
|
:- type maybe_incomplete_result(T)
|
|
---> ok(T)
|
|
; eof
|
|
; incomplete(list(uint8))
|
|
; error(io.error).
|
|
|
|
:- type read_result(T)
|
|
---> ok(T)
|
|
; eof
|
|
; error(string, int). % error message, line number
|
|
|
|
% A value indicating an error.
|
|
% This may or may not have an associated io.system_error value.
|
|
%
|
|
:- type io.error.
|
|
|
|
% A system-dependent error value.
|
|
%
|
|
% For C backends, this is either an errno value (e.g. ENOENT)
|
|
% or a Windows system error code (e.g. ERROR_FILE_NOT_FOUND).
|
|
% A value of 0 represents success in both cases.
|
|
%
|
|
% For the Java and C# backends, this is an exception object or null,
|
|
% where null represents no error.
|
|
%
|
|
:- type system_error.
|
|
:- pragma foreign_type(c, system_error, "MR_Integer",
|
|
[can_pass_as_mercury_type]).
|
|
:- pragma foreign_type("C#", system_error, "System.Exception").
|
|
:- pragma foreign_type(java, system_error, "java.lang.Exception").
|
|
|
|
% whence denotes the base for a seek operation.
|
|
% set - seek relative to the start of the file
|
|
% cur - seek relative to the current position in the file
|
|
% end - seek relative to the end of the file.
|
|
%
|
|
:- type whence
|
|
---> set
|
|
; cur
|
|
; end.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Opening and closing streams, both text and binary.
|
|
%
|
|
|
|
% Attempts to open a text file for input.
|
|
% Result is either 'ok(Stream)' or 'error(ErrorCode)'.
|
|
%
|
|
:- pred open_input(string::in, io.res(io.text_input_stream)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Attempts to open a binary file for input.
|
|
% Result is either 'ok(Stream)' or 'error(ErrorCode)'.
|
|
%
|
|
:- pred open_binary_input(string::in,
|
|
io.res(io.binary_input_stream)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Attempts to open a text file for output.
|
|
% Result is either 'ok(Stream)' or 'error(ErrorCode)'.
|
|
%
|
|
:- pred open_output(string::in, io.res(io.text_output_stream)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Attempts to open a file for binary output.
|
|
% Result is either 'ok(Stream)' or 'error(ErrorCode)'.
|
|
%
|
|
:- pred open_binary_output(string::in,
|
|
io.res(io.binary_output_stream)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Attempts to open a text file for appending.
|
|
% Result is either 'ok(Stream)' or 'error(ErrorCode)'.
|
|
%
|
|
:- pred open_append(string::in, io.res(io.text_output_stream)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Attempts to open a file for binary appending.
|
|
% Result is either 'ok(Stream)' or 'error(ErrorCode)'.
|
|
%
|
|
:- pred open_binary_append(string::in,
|
|
io.res(io.binary_output_stream)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Closes an open text input stream.
|
|
% This will throw an io.error exception if an I/O error occurs.
|
|
%
|
|
:- pred close_input(io.text_input_stream::in, io::di, io::uo) is det.
|
|
|
|
% Closes an open binary input stream.
|
|
% This will throw an io.error exception if an I/O error occurs.
|
|
%
|
|
:- pred close_binary_input(io.binary_input_stream::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Closes an open text output stream.
|
|
% This will throw an io.error exception if an I/O error occurs.
|
|
%
|
|
:- pred close_output(io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
% Closes an open binary output stream.
|
|
% This will throw an io.error exception if an I/O error occurs.
|
|
%
|
|
:- pred close_binary_output(io.binary_output_stream::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Switching streams.
|
|
%
|
|
|
|
% set_input_stream(NewStream, OldStream, !IO):
|
|
% Changes the current input stream to NewStream.
|
|
% Returns the previous input stream as OldStream.
|
|
%
|
|
:- pred set_input_stream(io.text_input_stream::in,
|
|
io.text_input_stream::out, io::di, io::uo) is det.
|
|
|
|
% Changes the current input stream to the stream specified.
|
|
% Returns the previous stream.
|
|
%
|
|
:- pred set_binary_input_stream(io.binary_input_stream::in,
|
|
io.binary_input_stream::out, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% set_output_stream(NewStream, OldStream, !IO):
|
|
% Changes the current output stream to NewStream.
|
|
% Returns the previous output stream as OldStream.
|
|
%
|
|
:- pred set_output_stream(io.text_output_stream::in,
|
|
io.text_output_stream::out, io::di, io::uo) is det.
|
|
|
|
% Changes the current binary output stream to the stream specified.
|
|
% Returns the previous stream.
|
|
%
|
|
:- pred set_binary_output_stream(io.binary_output_stream::in,
|
|
io.binary_output_stream::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Seeking on binary streams.
|
|
%
|
|
|
|
% Seek to an offset relative to Whence (documented above)
|
|
% on a specified binary input stream. Attempting to seek on a pipe
|
|
% or tty results in implementation dependent behaviour.
|
|
%
|
|
% A successful seek undoes any effects of putback_byte on the stream.
|
|
%
|
|
:- pred seek_binary_input(io.binary_input_stream::in, io.whence::in,
|
|
int::in, io::di, io::uo) is det.
|
|
|
|
% As above, but the offset is always a 64-bit value.
|
|
%
|
|
:- pred seek_binary_input64(io.binary_input_stream::in, io.whence::in,
|
|
int64::in, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Seek to an offset relative to Whence (documented above)
|
|
% on a specified binary output stream. Attempting to seek on a pipe
|
|
% or tty results in implementation dependent behaviour.
|
|
%
|
|
:- pred seek_binary_output(io.binary_output_stream::in, io.whence::in,
|
|
int::in, io::di, io::uo) is det.
|
|
|
|
% As above, but the offset is always a 64-bit value.
|
|
%
|
|
:- pred seek_binary_output64(io.binary_output_stream::in, io.whence::in,
|
|
int64::in, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Returns the offset (in bytes) into the specified binary input stream.
|
|
% Throws an exception if the offset is outside the range that can be
|
|
% represented by the int type. To avoid this possibility, you can use the
|
|
% 64-bit offset version of this predicate below.
|
|
%
|
|
:- pred binary_input_stream_offset(io.binary_input_stream::in, int::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% As above, but the offset is always a 64-bit value.
|
|
%
|
|
:- pred binary_input_stream_offset64(io.binary_input_stream::in, int64::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Returns the offset (in bytes) into the specified binary output stream.
|
|
% Throws an exception if the offset is outside the range that can be
|
|
% represented by the int type. To avoid this possibility, you can use the
|
|
% 64-bit offset version of this predicate below.
|
|
%
|
|
:- pred binary_output_stream_offset(io.binary_output_stream::in, int::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% As above, but the offset is always a 64-bit value.
|
|
%
|
|
:- pred binary_output_stream_offset64(io.binary_output_stream::in, int64::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Standard stream id predicates.
|
|
%
|
|
|
|
% Retrieves the standard input stream.
|
|
%
|
|
:- func stdin_stream = io.text_input_stream.
|
|
|
|
% Retrieves the standard input stream.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred stdin_stream(io.text_input_stream::out, io::di, io::uo) is det.
|
|
|
|
% Retrieves the standard binary input stream.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred stdin_binary_stream(io.binary_input_stream::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Retrieves the standard output stream.
|
|
%
|
|
:- func stdout_stream = io.text_output_stream.
|
|
|
|
% Retrieves the standard output stream.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred stdout_stream(io.text_output_stream::out, io::di, io::uo) is det.
|
|
|
|
% Retrieves the standard binary output stream.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred stdout_binary_stream(io.binary_output_stream::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Retrieves the standard error stream.
|
|
%
|
|
:- func stderr_stream = io.text_output_stream.
|
|
|
|
% Retrieves the standard error stream.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred stderr_stream(io.text_output_stream::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Current stream id predicates.
|
|
%
|
|
|
|
% Retrieves the current input stream.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred input_stream(io.text_input_stream::out, io::di, io::uo) is det.
|
|
|
|
% Retrieves the current binary input stream.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred binary_input_stream(io.binary_input_stream::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Retrieves the current output stream.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred output_stream(io.text_output_stream::out, io::di, io::uo) is det.
|
|
|
|
% Retrieves the current binary output stream.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred binary_output_stream(io.binary_output_stream::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Getting and setting stream properties.
|
|
%
|
|
|
|
% Retrieves the human-readable name associated with the current input
|
|
% stream or the specified input stream. For file streams, this is
|
|
% the filename. For stdin, this is the string "<standard input>".
|
|
%
|
|
:- pred input_stream_name(string::out, io::di, io::uo) is det.
|
|
:- pred input_stream_name(io.text_input_stream::in, string::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Retrieves the human-readable name associated with the current binary
|
|
% input stream or the specified binary input stream. For file streams,
|
|
% this is the filename.
|
|
%
|
|
:- pred binary_input_stream_name(string::out, io::di, io::uo) is det.
|
|
:- pred binary_input_stream_name(io.binary_input_stream::in, string::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Retrieves the human-readable name associated with the current
|
|
% output stream or the specified output stream.
|
|
% For file streams, this is the filename.
|
|
% For stdout, this is the string "<standard output>".
|
|
% For stderr, this is the string "<standard error>".
|
|
%
|
|
:- pred output_stream_name(string::out, io::di, io::uo) is det.
|
|
:- pred output_stream_name(io.text_output_stream::in, string::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Retrieves the human-readable name associated with the current
|
|
% binary output stream or the specified binary output stream.
|
|
% For file streams, this is the filename.
|
|
%
|
|
:- pred binary_output_stream_name(string::out, io::di, io::uo) is det.
|
|
:- pred binary_output_stream_name(io.binary_output_stream::in,
|
|
string::out, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Return the line number of the current input stream or the specified
|
|
% input stream. Lines are normally numbered starting at 1, but this
|
|
% can be overridden by calling set_line_number.
|
|
%
|
|
:- pred get_line_number(int::out, io::di, io::uo) is det.
|
|
:- pred get_line_number(io.text_input_stream::in, int::out, io::di, io::uo)
|
|
is det.
|
|
|
|
% Set the line number of the current input stream or the specified
|
|
% input stream.
|
|
%
|
|
:- pred set_line_number(int::in, io::di, io::uo) is det.
|
|
:- pred set_line_number(io.text_input_stream::in, int::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Return the line number of the current output stream or the
|
|
% specified output stream. Lines are normally numbered starting at 1,
|
|
% but this can be overridden by calling set_output_line_number.
|
|
%
|
|
:- pred get_output_line_number(int::out, io::di, io::uo) is det.
|
|
:- pred get_output_line_number(io.text_output_stream::in, int::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Set the line number of the current output stream or the specified
|
|
% output stream.
|
|
%
|
|
:- pred set_output_line_number(int::in, io::di, io::uo) is det.
|
|
:- pred set_output_line_number(io.text_output_stream::in, int::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Reading values of primitive types.
|
|
%
|
|
|
|
% Read a character (code point) from the current input stream
|
|
% or from the specified stream.
|
|
%
|
|
:- pred read_char(io.result(char)::out, io::di, io::uo) is det.
|
|
:- pred read_char(io.text_input_stream::in, io.result(char)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Reads a character (code point) from the specified stream.
|
|
% This interface avoids memory allocation when there is no error.
|
|
%
|
|
:- pred read_char_unboxed(io.text_input_stream::in, io.result::out, char::out,
|
|
io::di, io::uo) is det.
|
|
% NOTE_TO_IMPLEMENTORS There is no version without an explicit stream argument.
|
|
|
|
% Un-read a character (code point) from the current input stream
|
|
% or from the specified stream.
|
|
% You can put back as many characters as you like.
|
|
% You can even put back something that you didn't actually read.
|
|
%
|
|
% On some systems and backends, only one byte of pushback is guaranteed.
|
|
% putback_char will throw an io.error exception if the pushback buffer
|
|
% is full.
|
|
%
|
|
:- pred putback_char(char::in, io::di, io::uo) is det.
|
|
:- pred putback_char(io.text_input_stream::in, char::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Note that there are no read equivalents of write_int, write_intN,
|
|
% write_uint, write_uintN, or write_float. Mercury programs that want to read
|
|
% numbers must first read in strings, and try to convert the appropriate
|
|
% parts of those strings to numbers. This allows them to handle any errors
|
|
% in that conversion process in whatever way they like. Since there are many
|
|
% possible ways to handle conversion failures, it is not very likely that
|
|
% a programmer's chosen method would agree with the one used by a
|
|
% system-supplied predicate for reading in e.g. floats, if this module had one.
|
|
|
|
%---------------------%
|
|
|
|
% Reads a single 8-bit byte from the current binary input stream
|
|
% or from the specified binary input stream.
|
|
%
|
|
:- pred read_byte(io.result(int)::out, io::di, io::uo) is det.
|
|
:- pred read_byte(io.binary_input_stream::in, io.result(int)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Reads a single signed 8-bit integer from the current binary input
|
|
% stream or from the specified binary input stream.
|
|
%
|
|
:- pred read_binary_int8(io.result(int8)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_int8(io.binary_input_stream::in, io.result(int8)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Reads a single signed 8-bit integer from the specified binary input
|
|
% stream. This interface avoids memory allocation when there is no error.
|
|
%
|
|
:- pred read_binary_int8_unboxed(io.binary_input_stream::in, io.result::out,
|
|
int8::out, io::di, io::uo) is det.
|
|
% NOTE_TO_IMPLEMENTORS There is no version without an explicit stream argument.
|
|
|
|
% Reads a single unsigned 8-bit integer from the current binary input
|
|
% stream or from the specified binary input stream.
|
|
%
|
|
:- pred read_binary_uint8(io.result(uint8)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint8(io.binary_input_stream::in, io.result(uint8)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Reads a single unsigned 8-bit integer from the specified binary input
|
|
% stream. This interface avoids memory allocation when there is no error.
|
|
%
|
|
:- pred read_binary_uint8_unboxed(io.binary_input_stream::in, io.result::out,
|
|
uint8::out, io::di, io::uo) is det.
|
|
% NOTE_TO_IMPLEMENTORS There is no version without an explicit stream argument.
|
|
|
|
%---------------------%
|
|
|
|
% Un-reads a byte from the current binary input stream or from the
|
|
% specified stream. The byte is taken from the bottom 8 bits of the
|
|
% specified int.
|
|
%
|
|
% You can put back as many bytes as you like.
|
|
% You can even put back something that you did not actually read.
|
|
%
|
|
% On some systems and backends, only one byte of pushback is guaranteed.
|
|
% putback_byte will throw an io.error exception if the pushback buffer
|
|
% is full.
|
|
%
|
|
% Pushing back a byte decrements the file position by one, except when
|
|
% the file position is already zero, in which case the new file position
|
|
% is unspecified.
|
|
%
|
|
:- pred putback_byte(int::in, io::di, io::uo) is det.
|
|
:- pred putback_byte(io.binary_input_stream::in, int::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Like putback_byte, but where the byte value un-read is the 8 bits of the
|
|
% int8 reinterpreted as a uint8.
|
|
%
|
|
:- pred putback_int8(int8::in, io::di, io::uo) is det.
|
|
:- pred putback_int8(io.binary_input_stream::in, int8::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Like putback_byte, but where the byte value un-read is the 8 bits of the
|
|
% uint8.
|
|
%
|
|
:- pred putback_uint8(uint8::in, io::di, io::uo) is det.
|
|
:- pred putback_uint8(io.binary_input_stream::in, uint8::in, io::di, io::uo)
|
|
is det.
|
|
|
|
%---------------------%
|
|
|
|
% The following predicates read multibyte integer values, either from
|
|
% the current binary input stream, or from the specified binary
|
|
% input stream.
|
|
%
|
|
% The names of these predicates have the form:
|
|
%
|
|
% read_binary_<TYPE><SUFFIX>
|
|
%
|
|
% where <TYPE> is the name of one of the Mercury multibyte fixed size
|
|
% integer types. The optional <SUFFIX> specifies the order in which
|
|
% the bytes that make up the multibyte integer occur in the input stream.
|
|
% The suffix may be one of:
|
|
%
|
|
% "_le": the bytes are in little endian byte order.
|
|
% "_be": the bytes are in big endian byte order.
|
|
% none: the bytes are in the byte order of the underlying platform.
|
|
|
|
:- pred read_binary_int16(maybe_incomplete_result(int16)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_int16(io.binary_input_stream::in,
|
|
maybe_incomplete_result(int16)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_int16_le(maybe_incomplete_result(int16)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_int16_le(io.binary_input_stream::in,
|
|
maybe_incomplete_result(int16)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_int16_be(maybe_incomplete_result(int16)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_int16_be(io.binary_input_stream::in,
|
|
maybe_incomplete_result(int16)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint16(maybe_incomplete_result(uint16)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_uint16(io.binary_input_stream::in,
|
|
maybe_incomplete_result(uint16)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint16_le(maybe_incomplete_result(uint16)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_uint16_le(io.binary_input_stream::in,
|
|
maybe_incomplete_result(uint16)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint16_be(maybe_incomplete_result(uint16)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_uint16_be(io.binary_input_stream::in,
|
|
maybe_incomplete_result(uint16)::out, io::di, io::uo) is det.
|
|
|
|
:- pred read_binary_int32(maybe_incomplete_result(int32)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_int32(io.binary_input_stream::in,
|
|
maybe_incomplete_result(int32)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_int32_le(maybe_incomplete_result(int32)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_int32_le(io.binary_input_stream::in,
|
|
maybe_incomplete_result(int32)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_int32_be(maybe_incomplete_result(int32)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_int32_be(io.binary_input_stream::in,
|
|
maybe_incomplete_result(int32)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint32(maybe_incomplete_result(uint32)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_uint32(io.binary_input_stream::in,
|
|
maybe_incomplete_result(uint32)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint32_le(maybe_incomplete_result(uint32)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_uint32_le(io.binary_input_stream::in,
|
|
maybe_incomplete_result(uint32)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint32_be(maybe_incomplete_result(uint32)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_uint32_be(io.binary_input_stream::in,
|
|
maybe_incomplete_result(uint32)::out, io::di, io::uo) is det.
|
|
|
|
:- pred read_binary_int64(maybe_incomplete_result(int64)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_int64(io.binary_input_stream::in,
|
|
maybe_incomplete_result(int64)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_int64_le(maybe_incomplete_result(int64)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_int64_le(io.binary_input_stream::in,
|
|
maybe_incomplete_result(int64)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_int64_be(maybe_incomplete_result(int64)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_int64_be(io.binary_input_stream::in,
|
|
maybe_incomplete_result(int64)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint64(maybe_incomplete_result(uint64)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_uint64(io.binary_input_stream::in,
|
|
maybe_incomplete_result(uint64)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint64_le(maybe_incomplete_result(uint64)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_uint64_le(io.binary_input_stream::in,
|
|
maybe_incomplete_result(uint64)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_uint64_be(maybe_incomplete_result(uint64)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_binary_uint64_be(io.binary_input_stream::in,
|
|
maybe_incomplete_result(uint64)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Writing values of primitive types.
|
|
%
|
|
|
|
% Writes a character to the current output stream
|
|
% or to the specified output stream.
|
|
%
|
|
:- pred write_char(char::in, io::di, io::uo) is det.
|
|
:- pred write_char(io.text_output_stream::in, char::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Writes a signed or unsigned integer to the current output stream
|
|
% or to the specified output stream.
|
|
%
|
|
:- pred write_int(int::in, io::di, io::uo) is det.
|
|
:- pred write_int(io.text_output_stream::in, int::in, io::di, io::uo) is det.
|
|
:- pred write_uint(uint::in, io::di, io::uo) is det.
|
|
:- pred write_uint(io.text_output_stream::in, uint::in, io::di, io::uo) is det.
|
|
|
|
% Write a signed or unsigned 8-bit integer to the current output stream
|
|
% or to the specified output stream.
|
|
%
|
|
:- pred write_int8(int8::in, io::di, io::uo) is det.
|
|
:- pred write_int8(io.text_output_stream::in, int8::in, io::di, io::uo) is det.
|
|
:- pred write_uint8(uint8::in, io::di, io::uo) is det.
|
|
:- pred write_uint8(io.text_output_stream::in, uint8::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Write a signed or unsigned 16-bit integer to the current output stream
|
|
% or to the specified output stream.
|
|
%
|
|
:- pred write_int16(int16::in, io::di, io::uo) is det.
|
|
:- pred write_int16(io.text_output_stream::in, int16::in, io::di, io::uo)
|
|
is det.
|
|
:- pred write_uint16(uint16::in, io::di, io::uo) is det.
|
|
:- pred write_uint16(io.text_output_stream::in, uint16::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Write a signed or unsigned 32-bit integer to the current output stream
|
|
% or to the specified output stream.
|
|
%
|
|
:- pred write_int32(int32::in, io::di, io::uo) is det.
|
|
:- pred write_int32(io.text_output_stream::in, int32::in, io::di, io::uo)
|
|
is det.
|
|
:- pred write_uint32(uint32::in, io::di, io::uo) is det.
|
|
:- pred write_uint32(io.text_output_stream::in, uint32::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Write a signed or unsigned 64-bit integer to the current output stream
|
|
% or to the specified output stream.
|
|
%
|
|
:- pred write_int64(int64::in, io::di, io::uo) is det.
|
|
:- pred write_int64(io.text_output_stream::in, int64::in, io::di, io::uo)
|
|
is det.
|
|
:- pred write_uint64(uint64::in, io::di, io::uo) is det.
|
|
:- pred write_uint64(io.text_output_stream::in, uint64::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Writes a floating point number to the current output stream
|
|
% or to the specified output stream.
|
|
%
|
|
:- pred write_float(float::in, io::di, io::uo) is det.
|
|
:- pred write_float(io.text_output_stream::in, float::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Writes a string to the current output stream or to the
|
|
% specified output stream.
|
|
%
|
|
:- pred write_string(string::in, io::di, io::uo) is det.
|
|
:- pred write_string(io.text_output_stream::in, string::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Writes a newline character to the current output stream
|
|
% or to the specified stream.
|
|
%
|
|
:- pred nl(io::di, io::uo) is det.
|
|
:- pred nl(io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Writes a single byte to the current binary output stream
|
|
% or to the specified binary output stream. The byte is taken from
|
|
% the bottom 8 bits of the specified int.
|
|
%
|
|
:- pred write_byte(int::in, io::di, io::uo) is det.
|
|
:- pred write_byte(io.binary_output_stream::in, int::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Writes a signed or unsigned 8-bit integer to the current binary
|
|
% output stream or to the specified binary output stream.
|
|
%
|
|
:- pred write_binary_int8(int8::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int8(io.binary_output_stream::in, int8::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint8(uint8::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint8(io.binary_output_stream::in, uint8::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% The following predicates write multibyte integer values, either to the
|
|
% current binary output stream, or to the specified binary output stream.
|
|
%
|
|
% The names of these predicates have the form:
|
|
%
|
|
% write_binary_<TYPE><SUFFIX>
|
|
%
|
|
% where <TYPE> is the name of one of the Mercury multibyte fixed size
|
|
% integer types. The optional <SUFFIX> specifies the order in which
|
|
% the bytes that make up the multibyte integer are written to the stream.
|
|
% The suffix may be one of:
|
|
%
|
|
% "_le": the bytes are in little endian byte order.
|
|
% "_be": the bytes are in big endian byte order.
|
|
% none: the bytes are in the byte order of the underlying platform.
|
|
|
|
:- pred write_binary_int16(int16::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int16(io.binary_output_stream::in, int16::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint16(uint16::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint16(io.binary_output_stream::in, uint16::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_int16_le(int16::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int16_le(io.binary_output_stream::in, int16::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint16_le(uint16::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint16_le(io.binary_output_stream::in, uint16::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_int16_be(int16::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int16_be(io.binary_output_stream::in, int16::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint16_be(uint16::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint16_be(io.binary_output_stream::in, uint16::in,
|
|
io::di, io::uo) is det.
|
|
|
|
:- pred write_binary_int32(int32::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int32(io.binary_output_stream::in, int32::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint32(uint32::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint32(io.binary_output_stream::in, uint32::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_int32_le(int32::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int32_le(io.binary_output_stream::in, int32::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint32_le(uint32::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint32_le(io.binary_output_stream::in, uint32::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_int32_be(int32::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int32_be(io.binary_output_stream::in, int32::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint32_be(uint32::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint32_be(io.binary_output_stream::in, uint32::in,
|
|
io::di, io::uo) is det.
|
|
|
|
:- pred write_binary_int64(int64::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int64(io.binary_output_stream::in, int64::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint64(uint64::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint64(io.binary_output_stream::in, uint64::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_int64_le(int64::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int64_le(io.binary_output_stream::in, int64::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint64_le(uint64::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint64_le(io.binary_output_stream::in, uint64::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_int64_be(int64::in, io::di, io::uo) is det.
|
|
:- pred write_binary_int64_be(io.binary_output_stream::in, int64::in,
|
|
io::di, io::uo) is det.
|
|
:- pred write_binary_uint64_be(uint64::in, io::di, io::uo) is det.
|
|
:- pred write_binary_uint64_be(io.binary_output_stream::in, uint64::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Write the UTF-8 encoding of a string to the current binary output stream
|
|
% or the specified binary output stream. If the given string is not
|
|
% well-formed, then the behaviour is implementation dependent.
|
|
%
|
|
:- pred write_binary_string_utf8(string::in, io::di, io::uo) is det.
|
|
:- pred write_binary_string_utf8(io.binary_output_stream::in, string::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Text input predicates.
|
|
%
|
|
|
|
% Read a whitespace delimited word from the current input stream
|
|
% or from the specified stream.
|
|
%
|
|
% See char.is_whitespace for the definition of whitespace characters
|
|
% used by this predicate.
|
|
%
|
|
:- pred read_word(io.result(list(char))::out, io::di, io::uo) is det.
|
|
:- pred read_word(io.text_input_stream::in, io.result(list(char))::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Read a line from the current input stream or from the specified
|
|
% stream, returning the result as a list of characters (code points).
|
|
%
|
|
% See the documentation for string.line for the definition of a line.
|
|
%
|
|
:- pred read_line(io.result(list(char))::out, io::di, io::uo) is det.
|
|
:- pred read_line(io.text_input_stream::in, io.result(list(char))::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Read a line from the current input stream or from the specified
|
|
% stream, returning the result as a string.
|
|
%
|
|
% See the documentation for string.line for the definition of a line.
|
|
%
|
|
% WARNING: the returned string is NOT guaranteed to be valid UTF-8
|
|
% or UTF-16.
|
|
%
|
|
:- pred read_line_as_string(io.result(string)::out, io::di, io::uo) is det.
|
|
:- pred read_line_as_string(io.text_input_stream::in, io.result(string)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Discards all the whitespace characters satisfying char.is_whitespace
|
|
% from the current stream or from the specified stream.
|
|
%
|
|
:- pred ignore_whitespace(io.result::out, io::di, io::uo) is det.
|
|
:- pred ignore_whitespace(io.text_input_stream::in, io.result::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Bitmap input and output predicates.
|
|
%
|
|
|
|
% Fill a bitmap from the current binary input stream
|
|
% or from the specified binary input stream.
|
|
% Return the number of bytes read. On end-of-file, the number of
|
|
% bytes read will be less than the size of the bitmap, and
|
|
% the result will be `ok'.
|
|
% Throws an exception if the bitmap has a partial final byte.
|
|
%
|
|
:- pred read_bitmap(bitmap::bitmap_di, bitmap::bitmap_uo,
|
|
int::out, io.res::out, io::di, io::uo) is det.
|
|
:- pred read_bitmap(io.binary_input_stream::in,
|
|
bitmap::bitmap_di, bitmap::bitmap_uo,
|
|
int::out, io.res::out, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(read_bitmap/6), [bitmap.read_bitmap/6]).
|
|
:- pragma obsolete(pred(read_bitmap/7), [bitmap.read_bitmap/7]).
|
|
|
|
% read_bitmap(StartByte, NumBytes, !Bitmap, BytesRead, Result, !IO)
|
|
%
|
|
% Read NumBytes bytes into a bitmap starting at StartByte from the
|
|
% current binary input stream, or from the specified binary input stream.
|
|
% Return the number of bytes read. On end-of-file, the number of
|
|
% bytes read will be less than NumBytes, and the result will be `ok'.
|
|
%
|
|
:- pred read_bitmap(byte_index::in, num_bytes::in,
|
|
bitmap::bitmap_di, bitmap::bitmap_uo, num_bytes::out, io.res::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_bitmap(io.binary_input_stream::in, byte_index::in, num_bytes::in,
|
|
bitmap::bitmap_di, bitmap::bitmap_uo, num_bytes::out, io.res::out,
|
|
io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(read_bitmap/8), [bitmap.read_bitmap_range/8]).
|
|
:- pragma obsolete(pred(read_bitmap/9), [bitmap.read_bitmap_range/9]).
|
|
|
|
%---------------------%
|
|
|
|
% Write a bitmap to the current binary output stream
|
|
% or to the specified binary output stream. The bitmap must not contain
|
|
% a partial final byte.
|
|
%
|
|
:- pred write_bitmap(bitmap, io, io).
|
|
%:- mode write_bitmap(bitmap_ui, di, uo) is det.
|
|
:- mode write_bitmap(in, di, uo) is det.
|
|
:- pred write_bitmap(io.binary_output_stream, bitmap, io, io).
|
|
%:- mode write_bitmap(in, bitmap_ui, di, uo) is det.
|
|
:- mode write_bitmap(in, in, di, uo) is det.
|
|
:- pragma obsolete(pred(write_bitmap/3), [bitmap.write_bitmap/3]).
|
|
:- pragma obsolete(pred(write_bitmap/4), [bitmap.write_bitmap/4]).
|
|
|
|
% write_bitmap(BM, StartByte, NumBytes, !IO):
|
|
% write_bitmap(Stream, BM, StartByte, NumBytes, !IO):
|
|
%
|
|
% Write part of a bitmap to the current binary output stream
|
|
% or to the specified binary output stream.
|
|
%
|
|
:- pred write_bitmap(bitmap, int, int, io, io).
|
|
%:- mode write_bitmap(bitmap_ui, in, in, di, uo) is det.
|
|
:- mode write_bitmap(in, in, in, di, uo) is det.
|
|
:- pred write_bitmap(io.binary_output_stream, bitmap, int, int, io, io).
|
|
%:- mode write_bitmap(in, bitmap_ui, in, in, di, uo) is det.
|
|
:- mode write_bitmap(in, in, in, in, di, uo) is det.
|
|
:- pragma obsolete(pred(write_bitmap/5), [bitmap.write_bitmap_range/5]).
|
|
:- pragma obsolete(pred(write_bitmap/6), [bitmap.write_bitmap_range/6]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Reading values of arbitrary types.
|
|
%
|
|
|
|
% Read a ground term of any type, written using standard Mercury syntax,
|
|
% from the current stream or from the specified input stream.
|
|
% The type of the term read is determined by the context from which
|
|
% io.read is called.
|
|
%
|
|
% This predicate reads the input stream until reaching one of
|
|
% an end-of-term token, end-of-file, or I/O error.
|
|
%
|
|
% - If it finds no non-whitespace characters before the end-of-file,
|
|
% then it returns `eof'.
|
|
%
|
|
% - If it finds a sequence of tokens ending with an end-of-term token,
|
|
% which is a `.' followed by whitespace, then it leaves the trailing
|
|
% whitespace in the input stream, and decides what to do based on
|
|
% the contents of the token sequence before the end-of-term token.
|
|
%
|
|
% - If the tokens form a syntactically correct ground term of the
|
|
% expected type, then it returns `ok(Term)'.
|
|
%
|
|
% - If the tokens do not form a syntactically correct term, or if the
|
|
% term they form is not ground, or if the term is not a valid term
|
|
% of the expected type, then it returns `error(Message, LineNumber)'.
|
|
%
|
|
% - If it encounters an I/O error, then it also returns
|
|
% `error(Message, LineNumber)'.
|
|
%
|
|
% See char.is_whitespace for the definition of whitespace characters
|
|
% used by this predicate.
|
|
%
|
|
:- pred read(io.read_result(T)::out, io::di, io::uo) is det.
|
|
:- pred read(io.text_input_stream::in, io.read_result(T)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% The type `posn' represents a position within a string.
|
|
%
|
|
:- type posn
|
|
---> posn(
|
|
% The first two fields are used only for computing
|
|
% term contexts, for use e.g. in error messages.
|
|
%
|
|
% Line numbers start at 1; offsets start at zero.
|
|
% So the usual posn at the start of a file is posn(1, 0, 0).
|
|
% You can write it yourself, or get it by calling init_posn.
|
|
posn_current_line_number :: int,
|
|
posn_offset_of_start_of_line :: int,
|
|
posn_current_offset :: int
|
|
).
|
|
|
|
:- func init_posn = posn.
|
|
|
|
% read_from_string(FileName, String, MaxPos, Result, Posn0, Posn):
|
|
%
|
|
% Does the same job as read/4, but reads from a string, not from a stream.
|
|
%
|
|
% FileName is the name of the source (for use in error messages).
|
|
% String is the string to be parsed.
|
|
% Posn0 is the position to start parsing from.
|
|
% Posn is the position one past where the term read in ends.
|
|
% MaxPos is the offset in the string which should be considered the
|
|
% end-of-stream -- this is the upper bound for Posn.
|
|
% (In the usual case, MaxPos is just the length of the String.)
|
|
% WARNING: if MaxPos > length of String, then the behaviour is UNDEFINED.
|
|
%
|
|
:- pred read_from_string(string::in, string::in, int::in, read_result(T)::out,
|
|
posn::in, posn::out) is det.
|
|
|
|
% Reads a binary representation of a term of type T from the current
|
|
% binary input stream or from the specified binary input stream.
|
|
%
|
|
% Note: if you attempt to read a binary representation written by
|
|
% a different program, or a different version of the same program,
|
|
% then the results are not guaranteed to be meaningful. Another caveat
|
|
% is that higher-order types cannot be read. (If you try, you will get
|
|
% a runtime error.)
|
|
%
|
|
% XXX Note also that in the current implementation, read_binary
|
|
% will not work on the Java back-end.
|
|
%
|
|
:- pred read_binary(io.result(T)::out, io::di, io::uo) is det.
|
|
:- pred read_binary(io.binary_input_stream::in, io.result(T)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Writing values of arbitrary types.
|
|
%
|
|
|
|
% These will all throw an io.error exception if an I/O error occurs.
|
|
|
|
% print/3 writes its argument to the standard output stream.
|
|
% print/4 writes its second argument to the output stream specified in
|
|
% its first argument. In all cases, the argument to output can be of any
|
|
% type. It is output in a format that is intended to be human readable.
|
|
%
|
|
% - If the argument is just a single string or character,
|
|
% then it will be printed out exactly as is (unquoted).
|
|
%
|
|
% - If the argument is of type integer (i.e. it is an arbitrary precision
|
|
% integer), then its decimal representation will be printed.
|
|
%
|
|
% - If the argument is of type univ, then the value stored in the univ
|
|
% will be printed out, but not the type.
|
|
%
|
|
% - If the argument is of type date_time, then it will be printed out
|
|
% in the same form as the string returned by the date_to_string/1
|
|
% function.
|
|
%
|
|
% - If the argument is of type duration, then it will be printed out
|
|
% in the same form as the string returned by the duration_to_string/1
|
|
% function.
|
|
%
|
|
% print/5 is the same as print/4 except that it allows the caller to
|
|
% specify how non-canonical types should be handled. print/3 and print/4
|
|
% implicitly specify `canonicalize' as the method for handling
|
|
% non-canonical types. This means that for higher-order types, or types
|
|
% with user-defined equality axioms, or types defined using the foreign
|
|
% language interface (i.e. pragma foreign_type), the text output
|
|
% will describe only the type that is being printed, not the value.
|
|
%
|
|
% print_cc/3 is the same as print/3 except that it specifies
|
|
% `include_details_cc' rather than `canonicalize'. This means that it will
|
|
% print the details of non-canonical types. However, it has determinism
|
|
% `cc_multi'.
|
|
%
|
|
% Note that even if `include_details_cc' is specified, some implementations
|
|
% may not be able to print all the details for higher-order types or types
|
|
% defined using the foreign language interface.
|
|
%
|
|
:- pred print(T::in, io::di, io::uo) is det.
|
|
:- pred print(io.text_output_stream::in, T::in, io::di, io::uo) is det.
|
|
|
|
:- pred print(io.text_output_stream, deconstruct.noncanon_handling, T, io, io).
|
|
:- mode print(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode print(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode print(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode print(in, in, in, di, uo) is cc_multi.
|
|
|
|
:- pred print_cc(T::in, io::di, io::uo) is cc_multi.
|
|
|
|
% print_line calls print and then writes a newline character.
|
|
%
|
|
:- pred print_line(T::in, io::di, io::uo) is det.
|
|
:- pred print_line(io.text_output_stream::in, T::in, io::di, io::uo) is det.
|
|
|
|
:- pred print_line(io.text_output_stream, deconstruct.noncanon_handling,
|
|
T, io, io).
|
|
:- mode print_line(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode print_line(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode print_line(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode print_line(in, in, in, di, uo) is cc_multi.
|
|
|
|
:- pred print_line_cc(T::in, io::di, io::uo) is cc_multi.
|
|
|
|
% write/3 writes its argument to the current output stream.
|
|
% write/4 writes its second argument to the output stream specified
|
|
% in its first argument. In all cases, the argument to output may be
|
|
% of any type. The argument is written in a format that is intended to
|
|
% be valid Mercury syntax whenever possible.
|
|
%
|
|
% Strings and characters are always printed out in quotes, using backslash
|
|
% escapes if necessary and backslash or octal escapes for all characters
|
|
% for which char.is_control/1 is true. For higher-order types, or for types
|
|
% defined using the foreign language interface (pragma foreign_type), the
|
|
% text output will only describe the type that is being printed, not the
|
|
% value, and the result may not be parsable by `read'. For the types
|
|
% containing existential quantifiers, the type `type_desc' and closure
|
|
% types, the result may not be parsable by `read', either. But in all other
|
|
% cases the format used is standard Mercury syntax, and if you append a
|
|
% period and newline (".\n"), then the results can be read in again using
|
|
% `read'.
|
|
%
|
|
% write/5 is the same as write/4 except that it allows the caller
|
|
% to specify how non-canonical types should be handled. write_cc/3
|
|
% is the same as write/3 except that it specifies `include_details_cc'
|
|
% rather than `canonicalize'.
|
|
%
|
|
:- pred write(T::in, io::di, io::uo) is det.
|
|
:- pred write(io.text_output_stream::in, T::in, io::di, io::uo) is det.
|
|
|
|
:- pred write(io.text_output_stream, deconstruct.noncanon_handling, T, io, io).
|
|
:- mode write(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode write(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode write(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode write(in, in, in, di, uo) is cc_multi.
|
|
|
|
:- pred write_cc(T::in, io::di, io::uo) is cc_multi.
|
|
:- pred write_cc(io.text_output_stream::in, T::in, io::di, io::uo) is cc_multi.
|
|
|
|
% write_line calls write and then writes a newline character.
|
|
%
|
|
:- pred write_line(T::in, io::di, io::uo) is det.
|
|
:- pred write_line(io.text_output_stream::in, T::in, io::di, io::uo) is det.
|
|
|
|
:- pred write_line(io.text_output_stream, deconstruct.noncanon_handling, T,
|
|
io, io).
|
|
:- mode write_line(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode write_line(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode write_line(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode write_line(in, in, in, di, uo) is cc_multi.
|
|
|
|
:- pred write_line_cc(T::in, io::di, io::uo) is cc_multi.
|
|
:- pred write_line_cc(io.text_output_stream::in, T::in, io::di, io::uo)
|
|
is cc_multi.
|
|
|
|
% Writes a binary representation of a term to the current binary output
|
|
% stream or to the specified stream, in a format suitable for reading in
|
|
% again with read_binary.
|
|
%
|
|
:- pred write_binary(T::in, io::di, io::uo) is det.
|
|
:- pred write_binary(io.binary_output_stream::in, T::in, io::di, io::uo)
|
|
is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Formatted output.
|
|
%
|
|
|
|
% Formats the specified arguments according to the format string,
|
|
% using string.format, and then writes the result to the current
|
|
% output stream or to the specified output stream.
|
|
% (See the documentation of string.format for details.)
|
|
%
|
|
:- pred format(string::in, list(poly_type)::in, io::di, io::uo) is det.
|
|
:- pred format(io.text_output_stream::in, string::in, list(poly_type)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Writing out several values.
|
|
%
|
|
|
|
% Writes a list of strings to the current output stream
|
|
% or to the specified output stream.
|
|
%
|
|
:- pred write_strings(list(string)::in, io::di, io::uo) is det.
|
|
:- pred write_strings(io.text_output_stream::in, list(string)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% write_prefixed_lines(Prefix, Lines, !IO):
|
|
% write_prefixed_lines(Stream, Prefix, Lines, !IO):
|
|
%
|
|
% Write each line in Lines to the current output stream or to the
|
|
% specified output stream. Write Prefix before each line and write
|
|
% a newline after each line.
|
|
%
|
|
:- pred write_prefixed_lines(string::in, list(string)::in, io::di, io::uo)
|
|
is det.
|
|
:- pred write_prefixed_lines(io.text_output_stream::in, string::in,
|
|
list(string)::in, io::di, io::uo) is det.
|
|
|
|
% Writes the specified arguments to the current output stream
|
|
% or to the specified output stream.
|
|
%
|
|
:- pred write_many(list(poly_type)::in, io::di, io::uo) is det.
|
|
:- pred write_many(io.text_output_stream::in, list(poly_type)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% write_list(List, Separator, OutputPred, !IO):
|
|
% write_list(Stream, List, Separator, OutputPred, !IO):
|
|
%
|
|
% Applies OutputPred to each element of List, printing Separator
|
|
% (to the current output stream or to Stream) between each element.
|
|
%
|
|
:- pred write_list(list(T), string, pred(T, io, io), io, io).
|
|
:- mode write_list(in, in, in(pred(in, di, uo) is det), di, uo) is det.
|
|
:- mode write_list(in, in, in(pred(in, di, uo) is cc_multi), di, uo)
|
|
is cc_multi.
|
|
|
|
% write_list(Stream, List, Separator, OutputPred, !IO):
|
|
% Sets the current output stream to Stream, then applies OutputPred to
|
|
% each element of List, printing Separator between each element.
|
|
% The original output stream is restored whether returning normally
|
|
% or if an exception is thrown.
|
|
%
|
|
:- pred write_list(io.text_output_stream, list(T), string,
|
|
pred(T, io, io), io, io).
|
|
:- mode write_list(in, in, in, in(pred(in, di, uo) is det), di, uo) is det.
|
|
:- mode write_list(in, in, in, in(pred(in, di, uo) is cc_multi), di, uo)
|
|
is cc_multi.
|
|
|
|
% write_array(Array, Separator, OutputPred, !IO):
|
|
% Applies OutputPred to each element of Array, printing Separator
|
|
% to the current output stream between each element.
|
|
%
|
|
:- pred write_array(array(T), string, pred(T, io, io), io, io).
|
|
:- mode write_array(in, in, in(pred(in, di, uo) is det), di, uo) is det.
|
|
%:- mode write_array(array_ui, in, in(pred(in, di, uo) is det), di uo) is det.
|
|
:- mode write_array(in, in, in(pred(in, di, uo) is cc_multi), di, uo)
|
|
is cc_multi.
|
|
%:- mode write_array(array_ui, in, in(pred(in, di, uo) is cc_multi), di uo)
|
|
% is cc_multi.
|
|
|
|
% write_array(Stream, Array, Separator, OutputPred, !IO):
|
|
% Sets the current output stream to Stream, then applies OutputPred to
|
|
% each element of Array, printing Separator between each element.
|
|
% The original output stream is restored whether returning normally
|
|
% or if an exception is thrown.
|
|
%
|
|
:- pred write_array(io.text_output_stream, array(T), string, pred(T, io, io),
|
|
io, io).
|
|
:- mode write_array(in, in, in, in(pred(in, di, uo) is det), di, uo) is det.
|
|
%:- mode write_array(in, array_ui, in, in(pred(in, di, uo) is det), di uo)
|
|
% is det.
|
|
:- mode write_array(in, in, in, in(pred(in, di, uo) is cc_multi), di, uo)
|
|
is cc_multi.
|
|
%:- mode write_array(in, array_ui, in, in(pred(in, di, uo) is cc_multi), di uo)
|
|
% is cc_multi.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Flushing output to the operating system.
|
|
%
|
|
|
|
% Flush the output buffer of the current output stream
|
|
% or of the specified output stream.
|
|
%
|
|
:- pred flush_output(io::di, io::uo) is det.
|
|
:- pred flush_output(io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
% Flush the output buffer of the current binary output stream.
|
|
% or of the specified binary output stream.
|
|
%
|
|
:- pred flush_binary_output(io::di, io::uo) is det.
|
|
:- pred flush_binary_output(io.binary_output_stream::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Whole file input predicates.
|
|
%
|
|
|
|
% Open and read the named file, and if successful, return its contents
|
|
% as a string. If either the opening or the reading fails, return
|
|
% an error message describing the failure.
|
|
%
|
|
% With the first version, the returned string is NOT guaranteed to be valid
|
|
% UTF-8 (when targeting C) or UTF-16 (when targeting Java or C#).
|
|
% The version that has the _wf suffix DOES guarantee that the
|
|
% returned string is valid UTF-8 or UTF-16; if the contents of the file
|
|
% is not a well formed string, it will report an error.
|
|
%
|
|
:- pred read_named_file_as_string(string::in, io.res(string)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_named_file_as_string_wf(string::in, io.res(string)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Open and read the named file, and if successful, return its contents
|
|
% as a list of lines. If either the opening or the reading fails, return
|
|
% an error message describing the failure.
|
|
%
|
|
% This predicate views files as consisting of a sequence of lines,
|
|
% with each line consisting of a possibly empty sequence of non-newline
|
|
% characters, followed either by a newline character, or by the
|
|
% end of the file. The string returned for each line will not contain
|
|
% the newline character.
|
|
%
|
|
% With the first version, the returned string is NOT guaranteed to be valid
|
|
% UTF-8 (when targeting C) or UTF-16 (when targeting Java or C#).
|
|
% The version that has the _wf suffix DOES guarantee that the
|
|
% returned string is valid UTF-8 or UTF-16; if the contents of the file
|
|
% is not a well formed string, it will report an error.
|
|
%
|
|
:- pred read_named_file_as_lines(string::in, io.res(list(string))::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_named_file_as_lines_wf(string::in, io.res(list(string))::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% Read all the characters (code points) from the current input stream
|
|
% or from the specified stream, until eof or error.
|
|
%
|
|
:- pred read_file(io.maybe_partial_res(list(char))::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_file(io.text_input_stream::in,
|
|
io.maybe_partial_res(list(char))::out, io::di, io::uo) is det.
|
|
|
|
% Read all the characters (code points) from the current input stream
|
|
% or from the specified stream, until eof or error. Returns the result
|
|
% as a string rather than as a list of char.
|
|
%
|
|
% Returns an error if the file contains a null character, because
|
|
% null characters are not allowed in Mercury strings.
|
|
%
|
|
% With the first two versions, the returned string is NOT guaranteed to be
|
|
% valid UTF-8 (when targeting C) or UTF-16 (when targeting Java or C#).
|
|
% The two versions that have the _wf suffix DO guarantee that the
|
|
% returned string is valid UTF-8 or UTF-16; if the contents of the file
|
|
% is not a well formed string, they will report an error.
|
|
%
|
|
:- pred read_file_as_string(io.maybe_partial_res(string)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_file_as_string(io.text_input_stream::in,
|
|
io.maybe_partial_res(string)::out, io::di, io::uo) is det.
|
|
:- pred read_file_as_string_wf(io.maybe_partial_res(string)::out,
|
|
io::di, io::uo) is det.
|
|
:- pred read_file_as_string_wf(io.text_input_stream::in,
|
|
io.maybe_partial_res(string)::out, io::di, io::uo) is det.
|
|
|
|
% The same as read_file_as_string, but returns not only a string,
|
|
% but also the number of code units in that string.
|
|
%
|
|
% With the first two versions, the returned string is NOT guaranteed to be
|
|
% valid UTF-8 (when targeting C) or UTF-16 (when targeting Java or C#).
|
|
% The two versions that have the _wf suffix DO guarantee that the
|
|
% returned string is valid UTF-8 or UTF-16; if the contents of the file
|
|
% is not a well formed string, they will report an error.
|
|
%
|
|
:- pred read_file_as_string_and_num_code_units(
|
|
io.maybe_partial_res_2(string, int)::out, io::di, io::uo) is det.
|
|
:- pred read_file_as_string_and_num_code_units(io.text_input_stream::in,
|
|
io.maybe_partial_res_2(string, int)::out, io::di, io::uo) is det.
|
|
:- pred read_file_as_string_and_num_code_units_wf(
|
|
io.maybe_partial_res_2(string, int)::out, io::di, io::uo) is det.
|
|
:- pred read_file_as_string_and_num_code_units_wf(io.text_input_stream::in,
|
|
io.maybe_partial_res_2(string, int)::out, io::di, io::uo) is det.
|
|
|
|
% Reads all the bytes until eof or error from the current binary input
|
|
% stream or from the specified binary input stream.
|
|
%
|
|
:- pred read_binary_file(
|
|
io.result(list(int))::out, io::di, io::uo) is det.
|
|
:- pred read_binary_file(io.binary_input_stream::in,
|
|
io.result(list(int))::out, io::di, io::uo) is det.
|
|
|
|
% Reads all the bytes until eof or error from the current binary input
|
|
% stream or from the specified binary input stream into a bitmap.
|
|
%
|
|
:- pred read_binary_file_as_bitmap(
|
|
io.res(bitmap)::out, io::di, io::uo) is det.
|
|
:- pred read_binary_file_as_bitmap(io.binary_input_stream::in,
|
|
io.res(bitmap)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Processing the contents of a whole file.
|
|
%
|
|
|
|
% Applies the given closure to each character (code point) read from
|
|
% the input stream in turn, until eof or error.
|
|
%
|
|
:- pred input_stream_foldl(pred(char, T, T), T, io.maybe_partial_res(T),
|
|
io, io).
|
|
:- mode input_stream_foldl(in(pred(in, in, out) is det), in, out,
|
|
di, uo) is det.
|
|
:- mode input_stream_foldl(in(pred(in, in, out) is cc_multi), in, out,
|
|
di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(input_stream_foldl/5), [stream.input_stream_fold/6]).
|
|
|
|
% Applies the given closure to each character (code point) read from the
|
|
% input stream in turn, until eof or error.
|
|
%
|
|
:- pred input_stream_foldl(io.text_input_stream, pred(char, T, T),
|
|
T, io.maybe_partial_res(T), io, io).
|
|
:- mode input_stream_foldl(in, in(pred(in, in, out) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode input_stream_foldl(in, in(pred(in, in, out) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(input_stream_foldl/6), [stream.input_stream_fold/6]).
|
|
|
|
% Applies the given closure to each character (code point) read from
|
|
% the input stream in turn, until eof or error.
|
|
%
|
|
:- pred input_stream_foldl_io(pred(char, io, io), io.res, io, io).
|
|
:- mode input_stream_foldl_io(in(pred(in, di, uo) is det), out, di, uo)
|
|
is det.
|
|
:- mode input_stream_foldl_io(in(pred(in, di, uo) is cc_multi), out, di, uo)
|
|
is cc_multi.
|
|
:- pragma obsolete(pred(input_stream_foldl_io/4),
|
|
[stream.input_stream_fold_state/5]).
|
|
|
|
% Applies the given closure to each character (code point) read from the
|
|
% input stream in turn, until eof or error.
|
|
%
|
|
:- pred input_stream_foldl_io(io.text_input_stream, pred(char, io, io),
|
|
io.res, io, io).
|
|
:- mode input_stream_foldl_io(in, in(pred(in, di, uo) is det),
|
|
out, di, uo) is det.
|
|
:- mode input_stream_foldl_io(in, in(pred(in, di, uo) is cc_multi),
|
|
out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(input_stream_foldl_io/5),
|
|
[stream.input_stream_fold_state/5]).
|
|
|
|
% Applies the given closure to each character (code point) read from
|
|
% the input stream in turn, until eof or error.
|
|
%
|
|
:- pred input_stream_foldl2_io(pred(char, T, T, io, io),
|
|
T, io.maybe_partial_res(T), io, io).
|
|
:- mode input_stream_foldl2_io(in(pred(in, in, out, di, uo) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode input_stream_foldl2_io(in(pred(in, in, out, di, uo) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(input_stream_foldl2_io/5),
|
|
[stream.input_stream_fold_state/6]).
|
|
|
|
% Applies the given closure to each character (code point) read from the
|
|
% input stream in turn, until eof or error.
|
|
%
|
|
:- pred input_stream_foldl2_io(io.text_input_stream,
|
|
pred(char, T, T, io, io),
|
|
T, maybe_partial_res(T), io, io).
|
|
:- mode input_stream_foldl2_io(in,
|
|
in(pred(in, in, out, di, uo) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode input_stream_foldl2_io(in,
|
|
in(pred(in, in, out, di, uo) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(input_stream_foldl2_io/6),
|
|
[stream.input_stream_fold_state/6]).
|
|
|
|
% Applies the given closure to each character (code point) read from the
|
|
% input stream in turn, until eof or error, or the closure returns `no' as
|
|
% its second argument.
|
|
%
|
|
:- pred input_stream_foldl2_io_maybe_stop(
|
|
pred(char, bool, T, T, io, io),
|
|
T, io.maybe_partial_res(T), io, io).
|
|
:- mode input_stream_foldl2_io_maybe_stop(
|
|
in(pred(in, out, in, out, di, uo) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode input_stream_foldl2_io_maybe_stop(
|
|
in(pred(in, out, in, out, di, uo) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(input_stream_foldl2_io_maybe_stop/5),
|
|
[stream.input_stream_fold2_state_maybe_stop/6]).
|
|
|
|
% Applies the given closure to each character (code point) read from the
|
|
% input stream in turn, until eof or error, or the closure returns `no' as
|
|
% its second argument.
|
|
%
|
|
:- pred input_stream_foldl2_io_maybe_stop(io.text_input_stream,
|
|
pred(char, bool, T, T, io, io),
|
|
T, maybe_partial_res(T), io, io).
|
|
:- mode input_stream_foldl2_io_maybe_stop(in,
|
|
in(pred(in, out, in, out, di, uo) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode input_stream_foldl2_io_maybe_stop(in,
|
|
in(pred(in, out, in, out, di, uo) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(input_stream_foldl2_io_maybe_stop/6),
|
|
[stream.input_stream_fold2_state_maybe_stop/6]).
|
|
|
|
%---------------------%
|
|
|
|
% Applies the given closure to each byte read from the current binary
|
|
% input stream in turn, until eof or error.
|
|
%
|
|
:- pred binary_input_stream_foldl(pred(int, T, T),
|
|
T, maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl(in(pred(in, in, out) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl(in(pred(in, in, out) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(binary_input_stream_foldl/5),
|
|
[stream.input_stream_fold/6]).
|
|
|
|
% Applies the given closure to each byte read from the given binary
|
|
% input stream in turn, until eof or error.
|
|
%
|
|
:- pred binary_input_stream_foldl(io.binary_input_stream,
|
|
pred(int, T, T), T, maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl(in, in(pred(in, in, out) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl(in, in(pred(in, in, out) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(binary_input_stream_foldl/6),
|
|
[stream.input_stream_fold/6]).
|
|
|
|
% Applies the given closure to each byte read from the current binary
|
|
% input stream in turn, until eof or error.
|
|
%
|
|
:- pred binary_input_stream_foldl_io(pred(int, io, io),
|
|
io.res, io, io).
|
|
:- mode binary_input_stream_foldl_io(in(pred(in, di, uo) is det),
|
|
out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl_io(in(pred(in, di, uo) is cc_multi),
|
|
out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(binary_input_stream_foldl_io/4),
|
|
[stream.input_stream_fold_state/6]).
|
|
|
|
% Applies the given closure to each byte read from the given binary
|
|
% input stream in turn, until eof or error.
|
|
%
|
|
:- pred binary_input_stream_foldl_io(io.binary_input_stream,
|
|
pred(int, io, io), io.res, io, io).
|
|
:- mode binary_input_stream_foldl_io(in, in(pred(in, di, uo) is det),
|
|
out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl_io(in, in(pred(in, di, uo) is cc_multi),
|
|
out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(binary_input_stream_foldl_io/5),
|
|
[stream.input_stream_fold_state/6]).
|
|
|
|
% Applies the given closure to each byte read from the current binary
|
|
% input stream in turn, until eof or error.
|
|
%
|
|
:- pred binary_input_stream_foldl2_io(
|
|
pred(int, T, T, io, io), T, maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io(
|
|
in(pred(in, in, out, di, uo) is det), in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io(
|
|
in(pred(in, in, out, di, uo) is cc_multi), in, out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(binary_input_stream_foldl2_io/5),
|
|
[stream.input_stream_fold2_state/6]).
|
|
|
|
% Applies the given closure to each byte read from the given binary
|
|
% input stream in turn, until eof or error.
|
|
%
|
|
:- pred binary_input_stream_foldl2_io(io.binary_input_stream,
|
|
pred(int, T, T, io, io), T, maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io(in,
|
|
in(pred(in, in, out, di, uo) is det), in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io(in,
|
|
in(pred(in, in, out, di, uo) is cc_multi), in, out, di, uo) is cc_multi.
|
|
:- pragma obsolete(pred(binary_input_stream_foldl2_io/6),
|
|
[stream.input_stream_fold2_state/6]).
|
|
|
|
% Applies the given closure to each byte read from the current binary
|
|
% input stream in turn, until eof or error, or the closure returns `no'
|
|
% as its second argument.
|
|
%
|
|
:- pred binary_input_stream_foldl2_io_maybe_stop(
|
|
pred(int, bool, T, T, io, io), T, maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop(
|
|
in(pred(in, out, in, out, di, uo) is det), in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop(
|
|
in(pred(in, out, in, out, di, uo) is cc_multi), in, out, di, uo)
|
|
is cc_multi.
|
|
:- pragma obsolete(pred(binary_input_stream_foldl2_io_maybe_stop/5),
|
|
[stream.input_stream_fold2_state_maybe_stop/6]).
|
|
|
|
% Applies the given closure to each byte read from the given binary input
|
|
% stream in turn, until eof or error, or the closure returns `no' as its
|
|
% second argument.
|
|
%
|
|
:- pred binary_input_stream_foldl2_io_maybe_stop(io.binary_input_stream,
|
|
pred(int, bool, T, T, io, io), T, maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop(in,
|
|
in(pred(in, out, in, out, di, uo) is det), in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop(in,
|
|
in(pred(in, out, in, out, di, uo) is cc_multi), in, out, di, uo)
|
|
is cc_multi.
|
|
:- pragma obsolete(pred(binary_input_stream_foldl2_io_maybe_stop/6),
|
|
[stream.input_stream_fold2_state_maybe_stop/6]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File handling predicates.
|
|
%
|
|
|
|
% NOTE_TO_IMPLEMENTORS The definitions of access_type and file_type logically
|
|
% NOTE_TO_IMPLEMENTORS belong in io.file.m, and they should be moved there
|
|
% NOTE_TO_IMPLEMENTORS when the forwarding predicates below to io.file.m
|
|
% NOTE_TO_IMPLEMENTORS are removed. However, while the forwarding predicates
|
|
% NOTE_TO_IMPLEMENTORS are here, the types that some of them depend on
|
|
% NOTE_TO_IMPLEMENTORS should be here as well.
|
|
% NOTE_TO_IMPLEMENTORS
|
|
% NOTE_TO_IMPLEMENTORS Keeping the definitions of these types here suits both
|
|
% NOTE_TO_IMPLEMENTORS old code and new code.
|
|
% NOTE_TO_IMPLEMENTORS
|
|
% NOTE_TO_IMPLEMENTORS - Old code can call all the forwarding predicates,
|
|
% NOTE_TO_IMPLEMENTORS and pass them values of these types, while importing
|
|
% NOTE_TO_IMPLEMENTORS only io.m.
|
|
% NOTE_TO_IMPLEMENTORS
|
|
% NOTE_TO_IMPLEMENTORS - New code using io.file.m must also import io.m anyway,
|
|
% NOTE_TO_IMPLEMENTORS not just because io.m is io.file.m's parent
|
|
% NOTE_TO_IMPLEMENTORS (a requirement that we may eliminate in the future),
|
|
% NOTE_TO_IMPLEMENTORS but because all the operations in io.file.m take
|
|
% NOTE_TO_IMPLEMENTORS a pair of I/O state arguments, and the I/O state type
|
|
% NOTE_TO_IMPLEMENTORS is defined here.
|
|
% NOTE_TO_IMPLEMENTORS
|
|
% NOTE_TO_IMPLEMENTORS On the other hand, if we moved the definitions of
|
|
% NOTE_TO_IMPLEMENTORS these types to io.file.m, new code would still work,
|
|
% NOTE_TO_IMPLEMENTORS but old code would break immediately, in a way that
|
|
% NOTE_TO_IMPLEMENTORS shutting up warnings about obsolete predicates
|
|
% NOTE_TO_IMPLEMENTORS would not override.
|
|
:- type access_type
|
|
---> read
|
|
; write
|
|
; execute.
|
|
|
|
:- type file_type
|
|
---> regular_file
|
|
; directory
|
|
; symbolic_link
|
|
; named_pipe
|
|
; socket
|
|
; character_device
|
|
; block_device
|
|
; message_queue
|
|
; semaphore
|
|
; shared_memory
|
|
; unknown.
|
|
|
|
% remove_file(FileName, Result, !IO) attempts to remove the file
|
|
% FileName, binding Result to ok/0 if it succeeds, or error/1 if it
|
|
% fails. If FileName names a file that is currently open, the behaviour
|
|
% is implementation-dependent.
|
|
%
|
|
% If FileName names a directory, the behavior is currently
|
|
% implementation-dependent. On most platforms, an empty directory will be
|
|
% deleted.
|
|
%
|
|
:- pred remove_file(string::in, io.res::out, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(remove_file/4), [io.file.remove_file/4]).
|
|
|
|
% remove_file_recursively(FileName, Result, !IO) attempts to remove
|
|
% the file FileName, binding Result to ok/0 if it succeeds, or error/1
|
|
% if it fails. If FileName names a file that is currently open, the
|
|
% behaviour is implementation-dependent.
|
|
%
|
|
% Unlike remove_file, this predicate will attempt to remove non-empty
|
|
% directories (recursively). If it fails, some of the directory elements
|
|
% may already have been removed.
|
|
%
|
|
:- pred remove_file_recursively(string::in, io.res::out, io::di, io::uo)
|
|
is det.
|
|
:- pragma obsolete(pred(remove_file_recursively/4),
|
|
[io.file.remove_file_recursively/4]).
|
|
|
|
% rename_file(OldFileName, NewFileName, Result, !IO).
|
|
%
|
|
% Attempts to rename the file or directory OldFileName as NewFileName,
|
|
% binding Result to ok/0 if it succeeds, or error/1 if it fails.
|
|
% If OldFileName names a file that is currently open, the behaviour is
|
|
% implementation-dependent. If NewFileName names a file that already
|
|
% exists, the behaviour is also implementation-dependent; on some systems,
|
|
% the file previously named NewFileName will be deleted and replaced
|
|
% with the file previously named OldFileName.
|
|
%
|
|
:- pred rename_file(string::in, string::in, io.res::out, io::di, io::uo)
|
|
is det.
|
|
:- pragma obsolete(pred(rename_file/5), [io.file.rename_file/5]).
|
|
|
|
%---------------------%
|
|
|
|
% Succeeds if this platform can read and create symbolic links.
|
|
%
|
|
:- pred have_symlinks is semidet.
|
|
:- pragma obsolete(pred(have_symlinks/0), [io.file.have_symlinks/0]).
|
|
|
|
% make_symlink(FileName, LinkFileName, Result, !IO).
|
|
%
|
|
% Attempts to make LinkFileName be a symbolic link to FileName.
|
|
% If FileName is a relative path, it is interpreted relative
|
|
% to the directory containing LinkFileName.
|
|
%
|
|
:- pred make_symlink(string::in, string::in, io.res::out, io::di, io::uo)
|
|
is det.
|
|
:- pragma obsolete(pred(make_symlink/5), [io.file.make_symlink/5]).
|
|
|
|
% read_symlink(FileName, Result, !IO) returns `ok(LinkTarget)'
|
|
% if FileName is a symbolic link pointing to LinkTarget, and
|
|
% `error(Error)' otherwise. If LinkTarget is a relative path,
|
|
% it should be interpreted relative to the directory containing FileName,
|
|
% not the current directory.
|
|
%
|
|
:- pred read_symlink(string::in, io.res(string)::out, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(read_symlink/4), [io.file.read_symlink/4]).
|
|
|
|
%---------------------%
|
|
|
|
% check_file_accessibility(FileName, AccessTypes, Result):
|
|
%
|
|
% Check whether the current process can perform the operations given
|
|
% in AccessTypes on FileName.
|
|
% XXX When using the .NET CLI, this predicate will sometimes report
|
|
% that a directory is writable when in fact it is not.
|
|
%
|
|
:- pred check_file_accessibility(string::in, list(access_type)::in,
|
|
io.res::out, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(check_file_accessibility/5),
|
|
[io.file.check_file_accessibility/5]).
|
|
|
|
% file_type(FollowSymLinks, FileName, TypeResult)
|
|
% finds the type of the given file.
|
|
%
|
|
:- pred file_type(bool::in, string::in, io.res(file_type)::out,
|
|
io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(file_type/5), [io.file.file_type/5]).
|
|
|
|
% file_modification_time(FileName, TimeResult)
|
|
% finds the last modification time of the given file.
|
|
%
|
|
:- pred file_modification_time(string::in, io.res(time_t)::out,
|
|
io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(file_modification_time/4),
|
|
[io.file.file_modification_time/4]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Predicates for handling temporary files.
|
|
%
|
|
|
|
% make_temp_file(Result, !IO) creates an empty file whose name is different
|
|
% to the name of any existing file. If successful Result returns the name
|
|
% of the file. It is the responsibility of the caller to delete the file
|
|
% when it is no longer required.
|
|
%
|
|
% The file is placed in the directory returned by get_temp_directory/3.
|
|
%
|
|
% On the Java backend, this does not attempt to create the file
|
|
% with restrictive permissions (600 on Unix-like systems) and therefore
|
|
% should not be used when security is required.
|
|
%
|
|
:- pred make_temp_file(io.res(string)::out, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(make_temp_file/3), [io.file.make_temp_file/3]).
|
|
|
|
% make_temp_file(Dir, Prefix, Suffix, Result, !IO) creates an empty file
|
|
% whose name is different to the name of any existing file. The file will
|
|
% reside in the directory specified by Dir and will have a prefix using up
|
|
% to the first 5 code units of Prefix. If successful, Result returns the
|
|
% name of the file. It is the responsibility of the caller to delete the
|
|
% file when it is no longer required.
|
|
%
|
|
% The reason for truncating Prefix is historical; in future the behaviour
|
|
% may be changed. Note that the truncation is performed without regard for
|
|
% code point boundaries. It is recommended to use only (printable) ASCII
|
|
% characters in the prefix string.
|
|
%
|
|
% The C backend has the following limitations:
|
|
% - Suffix may be ignored.
|
|
%
|
|
% The C# backend has the following limitations:
|
|
% - Dir is ignored.
|
|
% - Prefix is ignored.
|
|
% - Suffix is ignored.
|
|
%
|
|
% On the Java backend, this does not attempt to create the file
|
|
% with restrictive permissions (600 on Unix-like systems) and therefore
|
|
% should not be used when security is required.
|
|
%
|
|
:- pred make_temp_file(string::in, string::in, string::in, io.res(string)::out,
|
|
io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(make_temp_file/6), [io.file.make_temp_file/6]).
|
|
|
|
% make_temp_directory(Result, !IO) creates an empty directory whose name
|
|
% is different from the name of any existing directory.
|
|
%
|
|
% On the Java backend this is insecure as the file permissions are not set.
|
|
%
|
|
:- pred make_temp_directory(io.res(string)::out, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(make_temp_directory/3),
|
|
[io.file.make_temp_directory/3]).
|
|
|
|
% make_temp_directory(Dir, Prefix, Suffix, Result, !IO) creates an empty
|
|
% directory whose name is different from the name of any existing
|
|
% directory. The new directory will reside in the existing directory
|
|
% specified by Dir and will have a prefix using up to the first 5
|
|
% characters of Prefix and a Suffix. Result returns the name of the
|
|
% new directory. It is the responsibility of the program to delete the
|
|
% directory when it is no longer needed.
|
|
%
|
|
% The C backend has the following limitations:
|
|
% - Suffix is ignored.
|
|
%
|
|
% The C# backend has the following limitations:
|
|
% - Prefix is ignored.
|
|
% - Suffix is ignored.
|
|
%
|
|
% On the Java backend this is insecure as the file permissions are not set.
|
|
%
|
|
:- pred make_temp_directory(string::in, string::in, string::in,
|
|
io.res(string)::out, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(make_temp_directory/6),
|
|
[io.file.make_temp_directory/6]).
|
|
|
|
% Test if the make_temp_directory predicates are available.
|
|
% This is false for C backends without support for mkdtemp(3).
|
|
%
|
|
:- pred have_make_temp_directory is semidet.
|
|
:- pragma obsolete(pred(have_make_temp_directory/0),
|
|
[io.file.have_make_temp_directory/0]).
|
|
|
|
% get_temp_directory(DirName, !IO)
|
|
%
|
|
% DirName is the name of a directory where applications should put
|
|
% temporary files.
|
|
%
|
|
% This is implementation-dependent. For current Mercury implementations,
|
|
% it is determined as follows:
|
|
% 1. For the non-Java back-ends:
|
|
% - On Microsoft Windows systems, the file will reside in
|
|
% the current directory if the TMP environment variable
|
|
% is not set, or in the directory specified by TMP if it is set.
|
|
% - On Unix systems, the file will reside in /tmp if the TMPDIR
|
|
% environment variable is not set, or in the directory specified
|
|
% by TMPDIR if it is set.
|
|
% 2. For the Java back-end, the system-dependent default
|
|
% temporary-file directory will be used, specified by the Java
|
|
% system property java.io.tmpdir. On UNIX systems the default
|
|
% value of this property is typically "/tmp" or "/var/tmp";
|
|
% on Microsoft Windows systems it is typically "c:\\temp".
|
|
%
|
|
:- pred get_temp_directory(string::out, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(get_temp_directory/3), [io.file.get_temp_directory/3]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Global state predicates.
|
|
%
|
|
|
|
% progname(DefaultProgname, Progname).
|
|
%
|
|
% Returns the name that the program was invoked with, if available,
|
|
% or DefaultProgname if the name is not available.
|
|
% Does not modify the I/O state.
|
|
%
|
|
:- pred progname(string::in, string::out, io::di, io::uo) is det.
|
|
|
|
% progname_base(DefaultProgname, Progname).
|
|
%
|
|
% Like `progname', except that it strips off any path name
|
|
% preceding the program name. Useful for error messages.
|
|
%
|
|
:- pred progname_base(string::in, string::out, io::di, io::uo) is det.
|
|
|
|
% Returns the arguments that the program was invoked with,
|
|
% if available, otherwise an empty list. Does not modify the I/O state.
|
|
%
|
|
:- pred command_line_arguments(list(string)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% The I/O state contains an integer used to record the program's exit
|
|
% status. When the program finishes, it will return this exit status
|
|
% to the operating system. The following predicates can be used to get
|
|
% and set the exit status.
|
|
%
|
|
:- pred get_exit_status(int::out, io::di, io::uo) is det.
|
|
:- pred set_exit_status(int::in, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
|
|
% NOTE_TO_IMPLEMENTORS This type is here for the same reason that
|
|
% NOTE_TO_IMPLEMENTORS the access_type type is here. See the comment there.
|
|
% Values of this type map the names of environment variables
|
|
% to their values.
|
|
%
|
|
:- type environment_var_map == map(string, string).
|
|
|
|
% The following predicates provide an interface to the environment list.
|
|
% Do not attempt to put spaces or '=' signs in the names of environment
|
|
% variables, or bad things may result!
|
|
%
|
|
% First argument is the name of the environment variable. Returns
|
|
% yes(Value) if the variable was set (Value will be set to the value
|
|
% of the variable) and no if the variable was not set.
|
|
%
|
|
:- pred get_environment_var(string::in, maybe(string)::out,
|
|
io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(get_environment_var/4),
|
|
[io.environment.get_environment_var/4]).
|
|
|
|
% First argument is the name of the environment variable, second argument
|
|
% is the value to be assigned to that variable. Res is 'ok' on success or
|
|
% 'error(ErrorCode)' if the system runs out of environment space or if
|
|
% the environment cannot be modified.
|
|
%
|
|
% Note that the environment cannot be modified on Java.
|
|
%
|
|
:- pred set_environment_var(string::in, string::in, io.res::out,
|
|
io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(set_environment_var/5),
|
|
[io.environment.set_environment_var/5]).
|
|
|
|
% Same as set_environment_var/5, but throws an exception if an error
|
|
% occurs.
|
|
%
|
|
:- pred set_environment_var(string::in, string::in, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(set_environment_var/4),
|
|
[io.environment.set_environment_var/4]).
|
|
|
|
% Test if the set_environment_var/{4,5} predicates are available.
|
|
% This is false for Java backends.
|
|
%
|
|
:- pred have_set_environment_var is semidet.
|
|
:- pragma obsolete(pred(have_set_environment_var/0),
|
|
[io.environment.have_set_environment_var/0]).
|
|
|
|
% Return a map containing all the environment variables in the current
|
|
% environment, together with their values.
|
|
%
|
|
:- pred get_environment_var_map(environment_var_map::out,
|
|
io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(get_environment_var_map/3),
|
|
[io.environment.get_environment_var_map/3]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% System access predicates.
|
|
%
|
|
|
|
% NOTE_TO_IMPLEMENTORS This type is here for the same reason that
|
|
% NOTE_TO_IMPLEMENTORS the access_type type is here. See the comment there.
|
|
:- type system_result
|
|
---> exited(int)
|
|
; signalled(int).
|
|
|
|
% Invokes the operating system shell with the specified Command.
|
|
% Result is either `ok(ExitStatus)', if it was possible to invoke
|
|
% the command, or `error(ErrorCode)' if not. The ExitStatus will be 0
|
|
% if the command completed successfully or the return value of the system
|
|
% call. If a signal kills the system call, then Result will be an error
|
|
% indicating which signal occurred.
|
|
%
|
|
:- pred call_system(string::in, io.res(int)::out, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(call_system/4), [io.call_system.call_system/4]).
|
|
|
|
% call_system_return_signal(Command, Result, !IO):
|
|
%
|
|
% Invokes the operating system shell with the specified Command.
|
|
% Result is either `ok(ExitStatus)' if it was possible to invoke
|
|
% the command or `error(Error)' if the command could not be executed.
|
|
% If the command could be executed then ExitStatus is either
|
|
% `exited(ExitCode)' if the command ran to completion or
|
|
% `signalled(SignalNum)' if the command was killed by a signal.
|
|
% If the command ran to completion then ExitCode will be 0 if the command
|
|
% ran successfully and the return value of the command otherwise.
|
|
%
|
|
:- pred call_system_return_signal(string::in, io.res(system_result)::out,
|
|
io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(call_system_return_signal/4),
|
|
[io.call_system.call_system_return_signal/4]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Managing the globals structure that Mercury attaches to the I/O state.
|
|
%
|
|
|
|
% The I/O state includes a `globals' field which is not used by the
|
|
% standard library, but can be used by the application. The globals field
|
|
% is of type univ so that the application can store any data it wants
|
|
% there. The following predicates can be used to access this global state.
|
|
%
|
|
% Does not modify the I/O state.
|
|
%
|
|
% The globals field is obsolete. A mutable declaration will provide
|
|
% the same functionality with better type safety.
|
|
%
|
|
:- pred get_globals(univ::out, io::di, io::uo) is det.
|
|
:- pred set_globals(univ::in, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(get_globals/3)).
|
|
:- pragma obsolete(pred(set_globals/3)).
|
|
|
|
% update_globals(UpdatePred, !IO).
|
|
% Update the globals field in the I/O state based upon its current value.
|
|
% This is equivalent to the following:
|
|
%
|
|
% get_globals(Globals0, !IO),
|
|
% UpdatePred(Globals0, Globals),
|
|
% set_globals(Globals, !IO)
|
|
%
|
|
% In parallel grades calls to update_globals/3 are atomic.
|
|
% If UpdatePred throws an exception then the globals field is
|
|
% left unchanged.
|
|
%
|
|
% The globals field is obsolete. A mutable declaration will provide
|
|
% the same functionality with better type safety.
|
|
%
|
|
:- pred update_globals(pred(univ, univ)::in(pred(in, out) is det),
|
|
io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(update_globals/3)).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Predicates that report statistics about the execution of the current process
|
|
% so far.
|
|
%
|
|
|
|
% report_stats(Stream, Selector, !IO):
|
|
% report_stats(Selector, !IO):
|
|
%
|
|
% Write selected statistics to the specified stream, or (if none)
|
|
% to stderr. What statistics will be written is controlled by the
|
|
% Selector argument. What selector values cause what statistics
|
|
% to be printed is implementation defined.
|
|
%
|
|
% The Melbourne implementation supports the following selectors:
|
|
%
|
|
% "standard"
|
|
% Writes memory/time usage statistics.
|
|
%
|
|
% "full_memory_stats"
|
|
% Writes complete memory usage statistics, including information
|
|
% about all procedures and types. Requires compilation with memory
|
|
% profiling enabled.
|
|
%
|
|
% "tabling"
|
|
% Writes statistics about the internals of the tabling system.
|
|
% Requires the runtime to have been compiled with the macro
|
|
% MR_TABLE_STATISTICS defined.
|
|
%
|
|
:- pred report_stats(io.text_output_stream::in, string::in,
|
|
io::di, io::uo) is det.
|
|
:- pred report_stats(string::in, io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(report_stats/4), [benchmarking.report_stats/4]).
|
|
:- pragma obsolete(pred(report_stats/3), [benchmarking.report_stats/3]).
|
|
|
|
% Write standard memory/time usage statistics to the specified stream,
|
|
% or (if none) to stderr.
|
|
%
|
|
:- pred report_standard_stats(io.text_output_stream::in,
|
|
io::di, io::uo) is det.
|
|
:- pred report_standard_stats(io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(report_standard_stats/3),
|
|
[benchmarking.report_standard_stats/3]).
|
|
:- pragma obsolete(pred(report_standard_stats/2),
|
|
[benchmarking.report_standard_stats/2]).
|
|
|
|
% report_full_memory_stats/3 reports a full memory profile
|
|
% to the specified output stream, or (if none) to stderr.
|
|
%
|
|
:- pred report_full_memory_stats(io.text_output_stream::in,
|
|
io::di, io::uo) is det.
|
|
:- pred report_full_memory_stats(io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(report_full_memory_stats/3),
|
|
[benchmarking.report_full_memory_stats/3]).
|
|
:- pragma obsolete(pred(report_full_memory_stats/2),
|
|
[benchmarking.report_full_memory_stats/2]).
|
|
|
|
% report_tabling_statistics/3, as its name says, reports statistics
|
|
% about tabling to the specified output stream, or (if none) to stderr.
|
|
%
|
|
% XXX For now, these predicates work only with the C backend.
|
|
%
|
|
:- pred report_tabling_statistics(io.text_output_stream::in,
|
|
io::di, io::uo) is det.
|
|
:- pred report_tabling_statistics(io::di, io::uo) is det.
|
|
:- pragma obsolete(pred(report_tabling_statistics/3),
|
|
[benchmarking.report_tabling_statistics/3]).
|
|
:- pragma obsolete(pred(report_tabling_statistics/2),
|
|
[benchmarking.report_tabling_statistics/2]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Interpreting I/O error messages.
|
|
%
|
|
|
|
% Construct an error value with the specified error message.
|
|
% The error value will not have an associated system error.
|
|
%
|
|
:- func make_io_error(string) = io.error.
|
|
|
|
% make_io_error_from_system_error(SystemError, Prefix, Error, !IO):
|
|
%
|
|
% Construct an io.error value given a system error and an error message
|
|
% prefix, which may be the empty string. The error message will be
|
|
% constructed by appending Prefix and the error message retrieved from the
|
|
% system for SystemError.
|
|
%
|
|
% On C backends, the io.system_error must be an errno value,
|
|
% not a Windows error code.
|
|
%
|
|
:- pred make_io_error_from_system_error(io.system_error::in, string::in,
|
|
io.error::out, io::di, io::uo) is det.
|
|
|
|
% make_io_error_from_windows_error(SystemError, Prefix, Error, !IO):
|
|
%
|
|
% Construct an io.error value from the given Windows system error and error
|
|
% message prefix. This predicate may only be called when using a C backend
|
|
% running on Windows. On other platforms, it throws an exception.
|
|
%
|
|
:- pred make_io_error_from_windows_error(io.system_error::in, string::in,
|
|
io.error::out, io::di, io::uo) is det.
|
|
|
|
% Return an error message for the error value.
|
|
%
|
|
:- func error_message(io.error) = string.
|
|
:- pred error_message(io.error::in, string::out) is det.
|
|
|
|
% get_system_error(Error, SystemError):
|
|
%
|
|
% Succeeds if-and-only-if SystemError is a system error
|
|
% associated with Error.
|
|
%
|
|
:- pred get_system_error(io.error::in, io.system_error::out) is semidet.
|
|
|
|
% As above, but only succeeds if the system error is an errno value.
|
|
%
|
|
:- pred get_errno_error(io.error::in, io.system_error::out) is semidet.
|
|
|
|
% As above, but only succeeds if the system error is a Windows error code.
|
|
%
|
|
:- pred get_windows_error(io.error::in, io.system_error::out) is semidet.
|
|
|
|
% As above, but only if the system error is a C# or Java exception object,
|
|
% or null.
|
|
%
|
|
:- pred get_exception_object_error(io.error::in, io.system_error::out)
|
|
is semidet.
|
|
|
|
% get_system_error_name(Error, ErrorName):
|
|
%
|
|
% Succeeds if Error has an associated system error, otherwise fails.
|
|
% On success, ErrorName is a name for that system error as follows.
|
|
%
|
|
% For C backends, a system error is usually an errno value. If the errno
|
|
% value is recognised by the Mercury system, then ErrorName will be the
|
|
% name for that errno value as defined in <errno.h>, e.g. "ENOENT".
|
|
% Otherwise, ErrorName will be "errno N" where N is a decimal number.
|
|
%
|
|
% For C backends on Windows, a system error may instead be a Windows system
|
|
% error code. If the error code is recognised by the Mercury system, then
|
|
% ErrorName will be the name for that error code in the Windows API,
|
|
% e.g. "ERROR_FILE_NOT_FOUND". Otherwise, ErrorName will be
|
|
% "System error 0xN" where 0xN is a hexadecimal number.
|
|
%
|
|
% For the C# backend, ErrorName will be the fully qualified class name
|
|
% of an exception object, e.g. "System.IO.FileNotFoundException",
|
|
% or "null".
|
|
%
|
|
% For the Java backend, ErrorName will be the fully qualified class name
|
|
% of an exception object, e.g. "java.io.FileNotFoundException",
|
|
% or "null".
|
|
%
|
|
:- pred get_system_error_name(io.error::in, string::out) is semidet.
|
|
|
|
% Succeeds if the given system error value corresponds to the lack of an
|
|
% error.
|
|
%
|
|
:- pred system_error_is_success(io.system_error::in) is semidet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Instances of the stream typeclasses.
|
|
%
|
|
|
|
:- instance stream.error(io.error).
|
|
|
|
% Text input stream instances.
|
|
:- instance stream.stream(text_input_stream, io).
|
|
:- instance stream.input(text_input_stream, io).
|
|
:- instance stream.line_oriented(text_input_stream, io).
|
|
|
|
:- instance stream.reader(text_input_stream, char, io, io.error).
|
|
:- instance stream.reader(text_input_stream, line, io, io.error).
|
|
:- instance stream.reader(text_input_stream, text_file, io, io.error).
|
|
|
|
:- instance stream.unboxed_reader(text_input_stream, char, io, io.error).
|
|
|
|
:- instance stream.putback(text_input_stream, char, io, io.error).
|
|
|
|
% Binary input stream instances.
|
|
:- instance stream.stream(binary_input_stream, io).
|
|
:- instance stream.input(binary_input_stream, io).
|
|
:- instance stream.seekable(binary_input_stream, io).
|
|
|
|
:- instance stream.reader(binary_input_stream, int, io, io.error).
|
|
:- instance stream.reader(binary_input_stream, int8, io, io.error).
|
|
:- instance stream.reader(binary_input_stream, uint8, io, io.error).
|
|
% The instance for int, which predates the addition of sized integers
|
|
% to Mercury, reads a byte, which it stores in the least significant
|
|
% eight bits. The plan is to eventually delete the instance for int.
|
|
|
|
:- instance stream.unboxed_reader(binary_input_stream, int8, io, io.error).
|
|
:- instance stream.unboxed_reader(binary_input_stream, uint8, io, io.error).
|
|
% This typeclass was defined after the addition of sized integers
|
|
% to Mercury, which is why there is no instance for int.
|
|
|
|
:- instance stream.putback(binary_input_stream, int, io, io.error).
|
|
:- instance stream.putback(binary_input_stream, int8, io, io.error).
|
|
:- instance stream.putback(binary_input_stream, uint8, io, io.error).
|
|
% The instance for int, which predates the addition of sized integers
|
|
% to Mercury, puts back a byte, which it stores in the least significant
|
|
% eight bits. The plan is to eventually delete the instance for int.
|
|
|
|
% Text output stream instances.
|
|
:- instance stream.stream(text_output_stream, io).
|
|
:- instance stream.output(text_output_stream, io).
|
|
:- instance stream.line_oriented(text_output_stream, io).
|
|
|
|
:- instance stream.writer(text_output_stream, char, io).
|
|
:- instance stream.writer(text_output_stream, float, io).
|
|
:- instance stream.writer(text_output_stream, int, io).
|
|
:- instance stream.writer(text_output_stream, int8, io).
|
|
:- instance stream.writer(text_output_stream, int16, io).
|
|
:- instance stream.writer(text_output_stream, int32, io).
|
|
:- instance stream.writer(text_output_stream, int64, io).
|
|
:- instance stream.writer(text_output_stream, uint, io).
|
|
:- instance stream.writer(text_output_stream, uint8, io).
|
|
:- instance stream.writer(text_output_stream, uint16, io).
|
|
:- instance stream.writer(text_output_stream, uint32, io).
|
|
:- instance stream.writer(text_output_stream, uint64, io).
|
|
:- instance stream.writer(text_output_stream, string, io).
|
|
:- instance stream.writer(text_output_stream, univ, io).
|
|
|
|
% Binary output stream instances.
|
|
:- instance stream.stream(binary_output_stream, io).
|
|
:- instance stream.output(binary_output_stream, io).
|
|
:- instance stream.seekable(binary_output_stream, io).
|
|
|
|
:- instance stream.writer(binary_output_stream, byte, io).
|
|
:- instance stream.writer(binary_output_stream, int8, io).
|
|
:- instance stream.writer(binary_output_stream, uint8, io).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
% Everything below here is not intended to be part of the public interface,
|
|
% and will not be included in the Mercury library reference manual.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- interface.
|
|
|
|
:- include_module error_util.
|
|
:- include_module primitives_read. % Include exported for symmetry.
|
|
:- include_module primitives_write. % Include exported for benchmarking.m.
|
|
:- include_module stream_db. % Include exported for browser/browse.m.
|
|
:- include_module stream_ops. % Include exported for benchmarking.m.
|
|
:- include_module text_read. % Include exported for symmetry.
|
|
|
|
%---------------------%
|
|
%
|
|
% For use by library.m.
|
|
%
|
|
|
|
:- pred init_state(io::di, io::uo) is det.
|
|
:- pred finalize_state(io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
%
|
|
% For use by dir.m.
|
|
%
|
|
|
|
% Succeeds if-and-only-if the Win32 API is available.
|
|
%
|
|
:- pred have_win32 is semidet.
|
|
|
|
% Succeeds if-and-only-if the current process was compiled
|
|
% against the Cygwin library.
|
|
%
|
|
:- pred have_cygwin is semidet.
|
|
|
|
% Succeeds if-and-only-if the .NET class library is available.
|
|
%
|
|
:- pred have_dotnet is semidet.
|
|
|
|
% Return a unique identifier for the given file (after following
|
|
% symlinks in FileName).
|
|
% XXX On Cygwin sometimes two files will have the same file_id.
|
|
% This is because MS-Windows does not use inodes, so Cygwin hashes
|
|
% the absolute file name. On Windows without Cygwin this will always
|
|
% return error(_). That does not matter, because this function is
|
|
% only used for checking for symlink loops in dir.foldl2, but
|
|
% plain Windows doesn't support symlinks.
|
|
%
|
|
:- type file_id.
|
|
:- pred file_id(string::in, io.res(file_id)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------%
|
|
%
|
|
% For use by bitmap.m.
|
|
%
|
|
|
|
:- type stream.
|
|
:- func input_stream_get_stream(text_input_stream) = stream.
|
|
:- func output_stream_get_stream(text_output_stream) = stream.
|
|
:- func binary_input_stream_get_stream(binary_input_stream) = stream.
|
|
:- func binary_output_stream_get_stream(binary_output_stream) = stream.
|
|
|
|
%---------------------%
|
|
%
|
|
% For use by the compiler transformation that implements trace [io(!IO)].
|
|
% Both of these are builtins.
|
|
%
|
|
|
|
:- semipure pred unsafe_get_io_state(io::uo) is det.
|
|
:- impure pred unsafe_set_io_state(io::di) is det.
|
|
|
|
%---------------------%
|
|
%
|
|
% Workaround for problem in commit 318e708.
|
|
% XXX Not exporting a declaration for this type causes a compiler abort
|
|
% when installing the java grade.
|
|
|
|
:- type stream_id.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module benchmarking.
|
|
:- import_module dir.
|
|
:- import_module exception.
|
|
:- import_module int.
|
|
:- import_module int8.
|
|
:- import_module int16.
|
|
:- import_module int32.
|
|
:- import_module int64.
|
|
:- import_module io.call_system.
|
|
:- import_module io.environment.
|
|
:- import_module io.error_util.
|
|
:- import_module io.file.
|
|
:- import_module io.primitives_read.
|
|
:- import_module io.primitives_write.
|
|
:- import_module io.stream_db.
|
|
:- import_module io.stream_ops.
|
|
:- import_module io.text_read.
|
|
:- import_module mercury_term_parser.
|
|
:- import_module require.
|
|
:- import_module stream.string_writer.
|
|
:- import_module term.
|
|
:- import_module term_conversion.
|
|
:- import_module term_subst.
|
|
:- import_module type_desc.
|
|
:- import_module uint8.
|
|
:- import_module uint16.
|
|
:- import_module uint32.
|
|
:- import_module uint64.
|
|
|
|
:- use_module rtti_implementation.
|
|
:- use_module table_builtin.
|
|
|
|
:- pragma foreign_import_module("C", time). % For ML_construct_time_t.
|
|
:- pragma foreign_import_module("C", string).
|
|
% mercury_std{in,out,err} are defined in io.stream_ops.
|
|
% This foreign_import_module is needed with LIBRARY_INTERMODULE = no.
|
|
:- pragma foreign_import_module("C", io.stream_ops).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Private type definitions.
|
|
%
|
|
|
|
% Values of type io.state are never really used:
|
|
% instead we store data in global variables.
|
|
% The reason this is defined as a foreign type is to prevent attempts
|
|
% to deconstruct values of the type.
|
|
:- pragma foreign_type("C", io.state, "MR_Word",
|
|
[can_pass_as_mercury_type])
|
|
where equality is io_state_equal, comparison is io_state_compare.
|
|
:- pragma foreign_type("C#", io.state, "int",
|
|
[can_pass_as_mercury_type])
|
|
where equality is io_state_equal, comparison is io_state_compare.
|
|
:- pragma foreign_type("Java", io.state, "java.lang.Object",
|
|
[can_pass_as_mercury_type])
|
|
where equality is io_state_equal, comparison is io_state_compare.
|
|
|
|
:- pred io_state_equal(io.state::in, io.state::in) is semidet.
|
|
|
|
:- pragma no_determinism_warning(pred(io_state_equal/2)).
|
|
io_state_equal(_, _) :-
|
|
error("attempt to unify two I/O states").
|
|
|
|
:- pred io_state_compare(comparison_result::uo, io.state::in, io.state::in)
|
|
is det.
|
|
|
|
:- pragma no_determinism_warning(pred(io_state_compare/3)).
|
|
io_state_compare(_, _, _) :-
|
|
error("attempt to compare two I/O states").
|
|
|
|
:- type text_input_stream
|
|
---> text_input_stream(stream).
|
|
:- type text_output_stream
|
|
---> text_output_stream(stream).
|
|
% While these definitions of the text_input_stream and text_output_stream types
|
|
% are visible only in io.m for Mercury code, you can access the underlying
|
|
% stdio streams using MR_file(*MR_unwrap_{input,output}_stream(Stream))
|
|
% in C code.
|
|
%
|
|
% XXX Document any equivalent mechanisms for Java and C#.
|
|
|
|
:- type binary_input_stream
|
|
---> binary_input_stream(stream).
|
|
:- type binary_output_stream
|
|
---> binary_output_stream(stream).
|
|
|
|
:- type stream
|
|
---> stream(c_pointer).
|
|
:- pragma foreign_type("C", stream,
|
|
"MercuryFilePtr", [can_pass_as_mercury_type]).
|
|
:- pragma foreign_type("C#", stream,
|
|
"mercury.io__stream_ops.MR_MercuryFileStruct").
|
|
:- pragma foreign_type("Java", stream,
|
|
"jmercury.io__stream_ops.MR_MercuryFileStruct").
|
|
|
|
% A unique identifier for an I/O stream.
|
|
%
|
|
:- type stream_id == int.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Opening and closing streams, both text and binary.
|
|
%
|
|
|
|
open_input(FileName, Result, !IO) :-
|
|
do_open_text(FileName, "r", OpenCount, NewStream, Error, !IO),
|
|
is_error(Error, "can't open input file: ", MaybeIOError, !IO),
|
|
(
|
|
MaybeIOError = yes(IOError),
|
|
Result = error(IOError)
|
|
;
|
|
MaybeIOError = no,
|
|
Result = ok(text_input_stream(NewStream)),
|
|
StreamInfo = stream(OpenCount, input, text, file(FileName)),
|
|
insert_stream_info(NewStream, StreamInfo, !IO)
|
|
).
|
|
|
|
open_binary_input(FileName, Result, !IO) :-
|
|
do_open_binary(FileName, "rb", OpenCount, NewStream, Error, !IO),
|
|
is_error(Error, "can't open input file: ", MaybeIOError, !IO),
|
|
(
|
|
MaybeIOError = yes(IOError),
|
|
Result = error(IOError)
|
|
;
|
|
MaybeIOError = no,
|
|
Result = ok(binary_input_stream(NewStream)),
|
|
StreamInfo = stream(OpenCount, input, binary, file(FileName)),
|
|
insert_stream_info(NewStream, StreamInfo, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
open_output(FileName, Result, !IO) :-
|
|
do_open_text(FileName, "w", OpenCount, NewStream, Error, !IO),
|
|
is_error(Error, "can't open output file: ", MaybeIOError, !IO),
|
|
(
|
|
MaybeIOError = yes(IOError),
|
|
Result = error(IOError)
|
|
;
|
|
MaybeIOError = no,
|
|
Result = ok(text_output_stream(NewStream)),
|
|
StreamInfo = stream(OpenCount, output, text, file(FileName)),
|
|
insert_stream_info(NewStream, StreamInfo, !IO)
|
|
).
|
|
|
|
open_binary_output(FileName, Result, !IO) :-
|
|
do_open_binary(FileName, "wb", OpenCount, NewStream, Error, !IO),
|
|
is_error(Error, "can't open output file: ", MaybeIOError, !IO),
|
|
(
|
|
MaybeIOError = yes(IOError),
|
|
Result = error(IOError)
|
|
;
|
|
MaybeIOError = no,
|
|
Result = ok(binary_output_stream(NewStream)),
|
|
StreamInfo = stream(OpenCount, output, binary, file(FileName)),
|
|
insert_stream_info(NewStream, StreamInfo, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
open_append(FileName, Result, !IO) :-
|
|
do_open_text(FileName, "a", OpenCount, NewStream, Error, !IO),
|
|
is_error(Error, "can't append to file: ", MaybeIOError, !IO),
|
|
(
|
|
MaybeIOError = yes(IOError),
|
|
Result = error(IOError)
|
|
;
|
|
MaybeIOError = no,
|
|
Result = ok(text_output_stream(NewStream)),
|
|
StreamInfo = stream(OpenCount, append, text, file(FileName)),
|
|
insert_stream_info(NewStream, StreamInfo, !IO)
|
|
).
|
|
|
|
open_binary_append(FileName, Result, !IO) :-
|
|
do_open_binary(FileName, "ab", OpenCount, NewStream, Error, !IO),
|
|
is_error(Error, "can't append to file: ", MaybeIOError, !IO),
|
|
(
|
|
MaybeIOError = yes(IOError),
|
|
Result = error(IOError)
|
|
;
|
|
MaybeIOError = no,
|
|
Result = ok(binary_output_stream(NewStream)),
|
|
StreamInfo = stream(OpenCount, append, binary, file(FileName)),
|
|
insert_stream_info(NewStream, StreamInfo, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
close_input(text_input_stream(Stream), !IO) :-
|
|
maybe_delete_stream_info(Stream, !IO),
|
|
close_stream(Stream, Error, !IO),
|
|
throw_on_close_error(Error, !IO).
|
|
|
|
close_binary_input(binary_input_stream(Stream), !IO) :-
|
|
maybe_delete_stream_info(Stream, !IO),
|
|
close_stream(Stream, Error, !IO),
|
|
throw_on_close_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
close_output(text_output_stream(Stream), !IO) :-
|
|
maybe_delete_stream_info(Stream, !IO),
|
|
close_stream(Stream, Error, !IO),
|
|
throw_on_close_error(Error, !IO).
|
|
|
|
close_binary_output(binary_output_stream(Stream), !IO) :-
|
|
maybe_delete_stream_info(Stream, !IO),
|
|
close_stream(Stream, Error, !IO),
|
|
throw_on_close_error(Error, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Switching streams.
|
|
%
|
|
|
|
set_input_stream(text_input_stream(NewStream),
|
|
text_input_stream(OutStream), !IO) :-
|
|
set_input_stream_2(NewStream, OutStream, !IO).
|
|
|
|
set_binary_input_stream(binary_input_stream(NewStream),
|
|
binary_input_stream(OutStream), !IO) :-
|
|
set_binary_input_stream_2(NewStream, OutStream, !IO).
|
|
|
|
%---------------------%
|
|
|
|
set_output_stream(text_output_stream(NewStream),
|
|
text_output_stream(OutStream), !IO) :-
|
|
set_output_stream_2(NewStream, OutStream, !IO).
|
|
|
|
set_binary_output_stream(binary_output_stream(NewStream),
|
|
binary_output_stream(OutStream), !IO) :-
|
|
set_binary_output_stream_2(NewStream, OutStream, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Seeking on binary streams.
|
|
%
|
|
|
|
seek_binary_input(binary_input_stream(Stream), Whence, Offset, !IO) :-
|
|
whence_to_int(Whence, Flag),
|
|
seek_binary_2(Stream, Flag, int64.from_int(Offset), Error, !IO),
|
|
throw_on_error(Error, "error seeking in file: ", !IO).
|
|
|
|
:- pred stream_seek_binary_input(binary_input_stream::in, stream.whence::in,
|
|
int::in, io::di, io::uo) is det.
|
|
|
|
stream_seek_binary_input(Stream, Whence0, OffSet, !IO) :-
|
|
Whence = stream_whence_to_io_whence(Whence0),
|
|
seek_binary_input(Stream, Whence, OffSet, !IO).
|
|
|
|
seek_binary_input64(binary_input_stream(Stream), Whence, Offset, !IO) :-
|
|
whence_to_int(Whence, Flag),
|
|
seek_binary_2(Stream, Flag, Offset, Error, !IO),
|
|
throw_on_error(Error, "error seeking in file: ", !IO).
|
|
|
|
:- pred stream_seek_binary_input64(binary_input_stream::in, stream.whence::in,
|
|
int64::in, io::di, io::uo) is det.
|
|
|
|
stream_seek_binary_input64(Stream, Whence0, OffSet, !IO) :-
|
|
Whence = stream_whence_to_io_whence(Whence0),
|
|
seek_binary_input64(Stream, Whence, OffSet, !IO).
|
|
|
|
%---------------------%
|
|
|
|
seek_binary_output(binary_output_stream(Stream), Whence, Offset, !IO) :-
|
|
whence_to_int(Whence, Flag),
|
|
seek_binary_2(Stream, Flag, int64.from_int(Offset), Error, !IO),
|
|
throw_on_error(Error, "error seeking in file: ", !IO).
|
|
|
|
:- pred stream_seek_binary_output(binary_output_stream::in, stream.whence::in,
|
|
int::in, io::di, io::uo) is det.
|
|
|
|
stream_seek_binary_output(Stream, Whence0, OffSet, !IO) :-
|
|
Whence = stream_whence_to_io_whence(Whence0),
|
|
seek_binary_output(Stream, Whence, OffSet, !IO).
|
|
|
|
seek_binary_output64(binary_output_stream(Stream), Whence, Offset, !IO) :-
|
|
whence_to_int(Whence, Flag),
|
|
seek_binary_2(Stream, Flag, Offset, Error, !IO),
|
|
throw_on_error(Error, "error seeking in file: ", !IO).
|
|
|
|
:- pred stream_seek_binary_output64(binary_output_stream::in,
|
|
stream.whence::in, int64::in, io::di, io::uo) is det.
|
|
|
|
stream_seek_binary_output64(Stream, Whence0, Offset, !IO) :-
|
|
Whence = stream_whence_to_io_whence(Whence0),
|
|
seek_binary_output64(Stream, Whence, Offset, !IO).
|
|
|
|
%---------------------%
|
|
|
|
binary_input_stream_offset(binary_input_stream(Stream), Offset, !IO) :-
|
|
binary_stream_offset_2(Stream, Offset64, Error, !IO),
|
|
throw_on_error(Error, "error getting file offset: ", !IO),
|
|
( if int64.to_int(Offset64, OffsetPrime) then
|
|
Offset = OffsetPrime
|
|
else
|
|
error("io.binary_input_stream_offset: offset exceeds range of an int")
|
|
).
|
|
|
|
binary_input_stream_offset64(binary_input_stream(Stream), Offset, !IO) :-
|
|
binary_stream_offset_2(Stream, Offset, Error, !IO),
|
|
throw_on_error(Error, "error getting file offset: ", !IO).
|
|
|
|
%---------------------%
|
|
|
|
binary_output_stream_offset(binary_output_stream(Stream), Offset, !IO) :-
|
|
binary_stream_offset_2(Stream, Offset64, Error, !IO),
|
|
throw_on_error(Error, "error getting file offset: ", !IO),
|
|
( if int64.to_int(Offset64, OffsetPrime) then
|
|
Offset = OffsetPrime
|
|
else
|
|
error("io.binary_output_stream_offset: offset exceeds range of an int")
|
|
).
|
|
|
|
binary_output_stream_offset64(binary_output_stream(Stream), Offset, !IO) :-
|
|
binary_stream_offset_2(Stream, Offset, Error, !IO),
|
|
throw_on_error(Error, "error getting file offset: ", !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Standard stream id predicates.
|
|
%
|
|
|
|
stdin_stream = text_input_stream(stdin_stream_2).
|
|
|
|
stdin_stream(text_input_stream(Stream), !IO) :-
|
|
stdin_stream_2(Stream, !IO).
|
|
|
|
stdin_binary_stream(binary_input_stream(Stream), !IO) :-
|
|
stdin_binary_stream_2(Stream, !IO).
|
|
|
|
%---------------------%
|
|
|
|
stdout_stream = text_output_stream(stdout_stream_2).
|
|
|
|
stdout_stream(text_output_stream(Stream), !IO) :-
|
|
stdout_stream_2(Stream, !IO).
|
|
|
|
stdout_binary_stream(binary_output_stream(Stream), !IO) :-
|
|
stdout_binary_stream_2(Stream, !IO).
|
|
|
|
%---------------------%
|
|
|
|
stderr_stream = text_output_stream(stderr_stream_2).
|
|
|
|
stderr_stream(text_output_stream(Stream), !IO) :-
|
|
stderr_stream_2(Stream, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Current stream id predicates.
|
|
%
|
|
|
|
input_stream(text_input_stream(Stream), !IO) :-
|
|
input_stream_2(Stream, !IO).
|
|
|
|
binary_input_stream(binary_input_stream(Stream), !IO) :-
|
|
binary_input_stream_2(Stream, !IO).
|
|
|
|
%---------------------%
|
|
|
|
output_stream(text_output_stream(Stream), !IO) :-
|
|
output_stream_2(Stream, !IO).
|
|
|
|
binary_output_stream(binary_output_stream(Stream), !IO) :-
|
|
binary_output_stream_2(Stream, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Getting and setting stream properties.
|
|
%
|
|
|
|
input_stream_name(Name, !IO) :-
|
|
io.input_stream(text_input_stream(Stream), !IO),
|
|
stream_name(Stream, Name, !IO).
|
|
|
|
input_stream_name(text_input_stream(Stream), Name, !IO) :-
|
|
stream_name(Stream, Name, !IO).
|
|
|
|
binary_input_stream_name(Name, !IO) :-
|
|
binary_input_stream(binary_input_stream(Stream), !IO),
|
|
stream_name(Stream, Name, !IO).
|
|
|
|
binary_input_stream_name(binary_input_stream(Stream), Name, !IO) :-
|
|
stream_name(Stream, Name, !IO).
|
|
|
|
%---------------------%
|
|
|
|
output_stream_name(Name, !IO) :-
|
|
io.output_stream(text_output_stream(Stream), !IO),
|
|
stream_name(Stream, Name, !IO).
|
|
|
|
output_stream_name(text_output_stream(Stream), Name, !IO) :-
|
|
stream_name(Stream, Name, !IO).
|
|
|
|
binary_output_stream_name(Name, !IO) :-
|
|
binary_output_stream(binary_output_stream(Stream), !IO),
|
|
stream_name(Stream, Name, !IO).
|
|
|
|
binary_output_stream_name(binary_output_stream(Stream), Name, !IO) :-
|
|
stream_name(Stream, Name, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
get_line_number(LineNum, !IO) :-
|
|
input_stream_2(Stream, !IO),
|
|
get_input_line_number_2(Stream, LineNum, !IO).
|
|
|
|
get_line_number(text_input_stream(Stream), LineNum, !IO) :-
|
|
get_input_line_number_2(Stream, LineNum, !IO).
|
|
|
|
%---------------------%
|
|
|
|
set_line_number(LineNum, !IO) :-
|
|
input_stream_2(Stream, !IO),
|
|
set_input_line_number_2(Stream, LineNum, !IO).
|
|
|
|
set_line_number(text_input_stream(Stream), LineNum, !IO) :-
|
|
set_input_line_number_2(Stream, LineNum,!IO).
|
|
|
|
%---------------------%
|
|
|
|
get_output_line_number(LineNum, !IO) :-
|
|
output_stream_2(Stream, !IO),
|
|
get_output_line_number_2(Stream, LineNum, !IO).
|
|
|
|
get_output_line_number(text_output_stream(Stream), LineNum, !IO) :-
|
|
get_output_line_number_2(Stream, LineNum, !IO).
|
|
|
|
%---------------------%
|
|
|
|
set_output_line_number(LineNum, !IO) :-
|
|
output_stream_2(Stream, !IO),
|
|
set_output_line_number_2(Stream, LineNum, !IO).
|
|
|
|
set_output_line_number(text_output_stream(Stream), LineNum, !IO) :-
|
|
set_output_line_number_2(Stream, LineNum, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Reading values of primitive types.
|
|
%
|
|
|
|
:- pragma inline(pred(read_char/3)). % Inline to allow deforestation.
|
|
read_char(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
read_char(Stream, Result, !IO).
|
|
|
|
:- pred stream_read_char(text_input_stream::in,
|
|
stream.result(char, io.error)::out, io::di, io::uo) is det.
|
|
|
|
stream_read_char(Stream, Result, !IO) :-
|
|
read_char(Stream, Result0, !IO),
|
|
Result = io.result1_to_stream_result1(Result0).
|
|
|
|
:- pragma inline(pred(read_char/4)). % Inline to allow deforestation.
|
|
read_char(Stream, Result, !IO) :-
|
|
read_char_code(Stream, ResultCode, Error, Char, !IO),
|
|
interpret_result_code1(ResultCode, Error, Char, Result, !IO).
|
|
|
|
:- pragma inline(pred(read_char_unboxed/5)). % Inline to allow deforestation.
|
|
read_char_unboxed(Stream, Result, Char, !IO) :-
|
|
read_char_code(Stream, ResultCode, Error, Char, !IO),
|
|
interpret_result_code0(ResultCode, Error, Result, !IO).
|
|
|
|
:- pred stream_read_char_unboxed(text_input_stream::in,
|
|
stream.result(io.error)::out, char::out, io::di, io::uo) is det.
|
|
|
|
stream_read_char_unboxed(Stream, Result, Char, !IO) :-
|
|
read_char_unboxed(Stream, Result0, Char, !IO),
|
|
Result = io.result0_to_stream_result0(Result0).
|
|
|
|
%---------------------%
|
|
|
|
putback_char(Char, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
putback_char(Stream, Char, !IO).
|
|
|
|
putback_char(text_input_stream(Stream), Character, !IO) :-
|
|
putback_char_2(Stream, Character, Ok, !IO),
|
|
(
|
|
Ok = yes
|
|
;
|
|
Ok = no,
|
|
throw(io_error_string("failed to put back character"))
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pragma inline(pred(read_byte/3)). % Inline to allow deforestation.
|
|
read_byte(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_byte(Stream, Result, !IO).
|
|
|
|
:- pragma inline(pred(read_byte/4)). % Inline to allow deforestation.
|
|
read_byte(binary_input_stream(Stream), Result, !IO) :-
|
|
read_byte_val(text_input_stream(Stream), ResultCode, Error, Byte, !IO),
|
|
interpret_result_code1(ResultCode, Error, Byte, Result, !IO).
|
|
|
|
:- pred stream_read_byte(io.binary_input_stream::in,
|
|
stream.result(int, io.error)::out, io::di, io::uo) is det.
|
|
|
|
stream_read_byte(Stream, Result, !IO) :-
|
|
read_byte(Stream, Result0, !IO),
|
|
Result = result1_to_stream_result1(Result0).
|
|
|
|
read_binary_int8(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int8(Stream, Result, !IO).
|
|
|
|
read_binary_int8(binary_input_stream(Stream), Result, !IO) :-
|
|
read_byte_val(text_input_stream(Stream), ResultCode, Error, Int, !IO),
|
|
Int8 = cast_from_int(Int), % This call cannot throw an exception.
|
|
interpret_result_code1(ResultCode, Error, Int8, Result, !IO).
|
|
|
|
:- pred stream_read_binary_int8(binary_input_stream::in,
|
|
stream.result(int8, io.error)::out, io::di, io::uo) is det.
|
|
|
|
stream_read_binary_int8(Stream, Result, !IO) :-
|
|
read_binary_int8(Stream, Result0, !IO),
|
|
Result = result1_to_stream_result1(Result0).
|
|
|
|
read_binary_int8_unboxed(binary_input_stream(Stream), Result, Int8, !IO) :-
|
|
read_byte_val(text_input_stream(Stream), ResultCode, Error, Int, !IO),
|
|
Int8 = cast_from_int(Int),
|
|
interpret_result_code0(ResultCode, Error, Result, !IO).
|
|
|
|
:- pred stream_read_binary_int8_unboxed(binary_input_stream::in,
|
|
stream.result(io.error)::out, int8::out, io::di, io::uo) is det.
|
|
|
|
stream_read_binary_int8_unboxed(Stream, Result, Int8, !IO) :-
|
|
read_binary_int8_unboxed(Stream, Result0, Int8, !IO),
|
|
Result = io.result0_to_stream_result0(Result0).
|
|
|
|
read_binary_uint8(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint8(Stream, Result, !IO).
|
|
|
|
read_binary_uint8(binary_input_stream(Stream), Result, !IO) :-
|
|
read_byte_val(text_input_stream(Stream), ResultCode, Error, Int, !IO),
|
|
UInt8 = cast_from_int(Int), % This call cannot throw an exception.
|
|
interpret_result_code1(ResultCode, Error, UInt8, Result, !IO).
|
|
|
|
:- pred stream_read_binary_uint8(binary_input_stream::in,
|
|
stream.result(uint8, io.error)::out, io::di, io::uo) is det.
|
|
|
|
stream_read_binary_uint8(Stream, Result, !IO) :-
|
|
read_binary_uint8(Stream, Result0, !IO),
|
|
Result = result1_to_stream_result1(Result0).
|
|
|
|
read_binary_uint8_unboxed(binary_input_stream(Stream), Result, UInt8, !IO) :-
|
|
read_byte_val(text_input_stream(Stream), ResultCode, Error, Int, !IO),
|
|
UInt8 = cast_from_int(Int),
|
|
interpret_result_code0(ResultCode, Error, Result, !IO).
|
|
|
|
:- pred stream_read_binary_uint8_unboxed(binary_input_stream::in,
|
|
stream.result(io.error)::out, uint8::out, io::di, io::uo) is det.
|
|
|
|
stream_read_binary_uint8_unboxed(Stream, Result, UInt8, !IO) :-
|
|
read_binary_uint8_unboxed(Stream, Result0, UInt8, !IO),
|
|
Result = io.result0_to_stream_result0(Result0).
|
|
|
|
%---------------------%
|
|
|
|
putback_byte(Int, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
putback_byte(Stream, Int, !IO).
|
|
|
|
putback_byte(Stream, Int, !IO) :-
|
|
UInt8 = uint8.cast_from_int(Int /\ 0xff),
|
|
putback_uint8(Stream, UInt8, !IO).
|
|
|
|
%---------------------%
|
|
|
|
putback_int8(Int8, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
putback_int8(Stream, Int8, !IO).
|
|
|
|
putback_int8(binary_input_stream(Stream), Int8, !IO) :-
|
|
UInt8 = uint8.cast_from_int8(Int8),
|
|
putback_uint8_2(Stream, UInt8, Ok, !IO),
|
|
(
|
|
Ok = yes
|
|
;
|
|
Ok = no,
|
|
throw(io_error_string("failed to put back int8"))
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
putback_uint8(UInt8, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
putback_uint8(Stream, UInt8, !IO).
|
|
|
|
putback_uint8(binary_input_stream(Stream), UInt8, !IO) :-
|
|
putback_uint8_2(Stream, UInt8, Ok, !IO),
|
|
(
|
|
Ok = yes
|
|
;
|
|
Ok = no,
|
|
throw(io_error_string("failed to put back uint8"))
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_int16(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int16(Stream, Result, !IO).
|
|
|
|
read_binary_int16(Stream, Result, !IO) :-
|
|
( if native_byte_order_is_big_endian then
|
|
read_binary_int16_be(Stream, Result, !IO)
|
|
else
|
|
read_binary_int16_le(Stream, Result, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_int16_le(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int16_le(Stream, Result, !IO).
|
|
|
|
read_binary_int16_le(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint16(Stream, little_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt16, !IO),
|
|
Int16 = cast_from_uint16(UInt16), % This call cannot throw an exception.
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
Int16, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_int16_be(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int16_be(Stream, Result, !IO).
|
|
|
|
read_binary_int16_be(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint16(Stream, big_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt16, !IO),
|
|
Int16 = cast_from_uint16(UInt16), % This call cannot throw an exception.
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
Int16, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_uint16(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint16(Stream, Result, !IO).
|
|
|
|
read_binary_uint16(Stream, Result, !IO) :-
|
|
( if native_byte_order_is_big_endian then
|
|
read_binary_uint16_be(Stream, Result, !IO)
|
|
else
|
|
read_binary_uint16_le(Stream, Result, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_uint16_le(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint16_le(Stream, Result, !IO).
|
|
|
|
read_binary_uint16_le(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint16(Stream, little_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt16, !IO),
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
UInt16, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_uint16_be(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint16_be(Stream, Result, !IO).
|
|
|
|
read_binary_uint16_be(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint16(Stream, big_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt16, !IO),
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
UInt16, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_int32(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int32(Stream, Result, !IO).
|
|
|
|
read_binary_int32(Stream, Result, !IO) :-
|
|
( if native_byte_order_is_big_endian then
|
|
read_binary_int32_be(Stream, Result, !IO)
|
|
else
|
|
read_binary_int32_le(Stream, Result, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_int32_le(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int32_le(Stream, Result, !IO).
|
|
|
|
read_binary_int32_le(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint32(Stream, little_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt32, !IO),
|
|
Int32 = cast_from_uint32(UInt32), % This call cannot throw an exception.
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
Int32, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_int32_be(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int32_be(Stream, Result, !IO).
|
|
|
|
read_binary_int32_be(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint32(Stream, big_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt32, !IO),
|
|
Int32 = cast_from_uint32(UInt32), % This call cannot throw an exception.
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
Int32, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_uint32(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint32(Stream, Result, !IO).
|
|
|
|
read_binary_uint32(Stream, Result, !IO) :-
|
|
( if native_byte_order_is_big_endian then
|
|
read_binary_uint32_be(Stream, Result, !IO)
|
|
else
|
|
read_binary_uint32_le(Stream, Result, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_uint32_le(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint32_le(Stream, Result, !IO).
|
|
|
|
read_binary_uint32_le(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint32(Stream, little_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt32, !IO),
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
UInt32, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_uint32_be(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint32_be(Stream, Result, !IO).
|
|
|
|
read_binary_uint32_be(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint32(Stream, big_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt32, !IO),
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
UInt32, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_int64(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int64(Stream, Result, !IO).
|
|
|
|
read_binary_int64(Stream, Result, !IO) :-
|
|
( if native_byte_order_is_big_endian then
|
|
read_binary_int64_be(Stream, Result, !IO)
|
|
else
|
|
read_binary_int64_le(Stream, Result, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_int64_le(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int64_le(Stream, Result, !IO).
|
|
|
|
read_binary_int64_le(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint64(Stream, little_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt64, !IO),
|
|
Int64 = cast_from_uint64(UInt64), % This call cannot throw an exception.
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
Int64, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_int64_be(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_int64_be(Stream, Result, !IO).
|
|
|
|
read_binary_int64_be(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint64(Stream, big_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt64, !IO),
|
|
Int64 = cast_from_uint64(UInt64), % This call cannot throw an exception.
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
Int64, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_uint64(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint64(Stream, Result, !IO).
|
|
|
|
read_binary_uint64(Stream, Result, !IO) :-
|
|
( if native_byte_order_is_big_endian then
|
|
read_binary_uint64_be(Stream, Result, !IO)
|
|
else
|
|
read_binary_uint64_le(Stream, Result, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_uint64_le(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint64_le(Stream, Result, !IO).
|
|
|
|
read_binary_uint64_le(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint64(Stream, little_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt64, !IO),
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
UInt64, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_uint64_be(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_uint64_be(Stream, Result, !IO).
|
|
|
|
read_binary_uint64_be(binary_input_stream(Stream), Result, !IO) :-
|
|
do_read_binary_uint64(Stream, big_endian, ResultCode, Error,
|
|
IncompleteBytes, UInt64, !IO),
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
UInt64, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
:- type byte_order
|
|
---> big_endian
|
|
; little_endian.
|
|
|
|
:- pragma foreign_export_enum("C", byte_order/0,
|
|
[prefix("ML_"), uppercase]).
|
|
:- pragma foreign_export_enum("Java", byte_order/0,
|
|
[prefix("ML_"), uppercase]).
|
|
:- pragma foreign_export_enum("C#", byte_order/0,
|
|
[prefix("ML_"), uppercase]).
|
|
|
|
:- pred native_byte_order_is_big_endian is semidet.
|
|
|
|
:- pragma foreign_proc("C",
|
|
native_byte_order_is_big_endian,
|
|
[promise_pure, will_not_call_mercury, thread_safe],
|
|
"
|
|
#if defined(MR_BIG_ENDIAN)
|
|
SUCCESS_INDICATOR = MR_TRUE;
|
|
#else
|
|
SUCCESS_INDICATOR = MR_FALSE;
|
|
#endif
|
|
").
|
|
|
|
:- pragma foreign_proc("C#",
|
|
native_byte_order_is_big_endian,
|
|
[promise_pure, will_not_call_mercury, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR = !(System.BitConverter.IsLittleEndian);
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
native_byte_order_is_big_endian,
|
|
[promise_pure, will_not_call_mercury, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR =
|
|
(java.nio.ByteOrder.nativeOrder() == java.nio.ByteOrder.BIG_ENDIAN);
|
|
").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Writing values of primitive types.
|
|
%
|
|
|
|
write_char(Character, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_char(Stream, Character, !IO).
|
|
|
|
write_char(text_output_stream(Stream), Character, !IO) :-
|
|
do_write_char(Stream, Character, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_int(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_int(Stream, Val, !IO).
|
|
|
|
write_int(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_int(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_uint(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_uint(Stream, Val, !IO).
|
|
|
|
write_uint(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_uint(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_int8(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_int8(Stream, Val, !IO).
|
|
|
|
write_int8(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_int8(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_uint8(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_uint8(Stream, Val, !IO).
|
|
|
|
write_uint8(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_uint8(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_int16(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_int16(Stream, Val, !IO).
|
|
|
|
write_int16(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_int16(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_uint16(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_uint16(Stream, Val, !IO).
|
|
|
|
write_uint16(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_uint16(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_int32(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_int32(Stream, Val, !IO).
|
|
|
|
write_int32(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_int32(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_uint32(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_uint32(Stream, Val, !IO).
|
|
|
|
write_uint32(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_uint32(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_int64(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_int64(Stream, Val, !IO).
|
|
|
|
write_int64(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_int64(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_uint64(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_uint64(Stream, Val, !IO).
|
|
|
|
write_uint64(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_uint64(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_float(Val, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_float(Stream, Val, !IO).
|
|
|
|
write_float(text_output_stream(Stream), Val, !IO) :-
|
|
do_write_float(Stream, Val, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_string(Message, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_string(Stream, Message, !IO).
|
|
|
|
write_string(text_output_stream(Stream), Message, !IO) :-
|
|
do_write_string(Stream, Message, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
nl(!IO) :-
|
|
write_char('\n', !IO).
|
|
|
|
nl(Stream, !IO) :-
|
|
write_char(Stream, '\n', !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
write_byte(Byte, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_byte(Stream, Byte, !IO).
|
|
|
|
write_byte(binary_output_stream(Stream), Byte, !IO) :-
|
|
do_write_byte(Stream, Byte, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
write_binary_int8(Int8, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_int8(Stream, Int8, !IO).
|
|
|
|
write_binary_int8(binary_output_stream(Stream), Int8, !IO) :-
|
|
UInt8 = uint8.cast_from_int8(Int8),
|
|
Int = uint8.to_int(UInt8),
|
|
do_write_byte(Stream, Int, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
write_binary_uint8(UInt8, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint8(Stream, UInt8, !IO).
|
|
|
|
write_binary_uint8(binary_output_stream(Stream), UInt8, !IO) :-
|
|
Int = uint8.to_int(UInt8),
|
|
do_write_byte(Stream, Int, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_int16(Int16, !IO) :-
|
|
UInt16 = uint16.cast_from_int16(Int16),
|
|
write_binary_uint16(UInt16, !IO).
|
|
|
|
write_binary_int16(Stream, Int16, !IO) :-
|
|
UInt16 = uint16.cast_from_int16(Int16),
|
|
write_binary_uint16(Stream, UInt16, !IO).
|
|
|
|
write_binary_uint16(UInt16, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint16(Stream, UInt16, !IO).
|
|
|
|
write_binary_uint16(binary_output_stream(Stream), UInt16, !IO) :-
|
|
do_write_binary_uint16(Stream, UInt16, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_int16_le(Int16, !IO) :-
|
|
UInt16 = uint16.cast_from_int16(Int16),
|
|
write_binary_uint16_le(UInt16, !IO).
|
|
|
|
write_binary_int16_le(Stream, Int16, !IO) :-
|
|
UInt16 = uint16.cast_from_int16(Int16),
|
|
write_binary_uint16_le(Stream, UInt16, !IO).
|
|
|
|
write_binary_uint16_le(UInt16, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint16_le(Stream, UInt16, !IO).
|
|
|
|
write_binary_uint16_le(binary_output_stream(Stream), UInt16, !IO) :-
|
|
do_write_binary_uint16_le(Stream, UInt16, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_int16_be(Int16, !IO) :-
|
|
UInt16 = uint16.cast_from_int16(Int16),
|
|
write_binary_uint16_be(UInt16, !IO).
|
|
|
|
write_binary_int16_be(Stream, Int16, !IO) :-
|
|
UInt16 = uint16.cast_from_int16(Int16),
|
|
write_binary_uint16_be(Stream, UInt16, !IO).
|
|
|
|
write_binary_uint16_be(UInt16, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint16_be(Stream, UInt16, !IO).
|
|
|
|
write_binary_uint16_be(binary_output_stream(Stream), UInt16, !IO) :-
|
|
do_write_binary_uint16_be(Stream, UInt16, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_int32(Int32, !IO) :-
|
|
UInt32 = uint32.cast_from_int32(Int32),
|
|
write_binary_uint32(UInt32, !IO).
|
|
|
|
write_binary_int32(Stream, Int32, !IO) :-
|
|
UInt32 = uint32.cast_from_int32(Int32),
|
|
write_binary_uint32(Stream, UInt32, !IO).
|
|
|
|
write_binary_uint32(UInt32, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint32(Stream, UInt32, !IO).
|
|
|
|
write_binary_uint32(binary_output_stream(Stream), UInt32, !IO) :-
|
|
do_write_binary_uint32(Stream, UInt32, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_int32_le(Int32, !IO) :-
|
|
UInt32 = uint32.cast_from_int32(Int32),
|
|
write_binary_uint32_le(UInt32, !IO).
|
|
|
|
write_binary_int32_le(Stream, Int32, !IO) :-
|
|
UInt32 = uint32.cast_from_int32(Int32),
|
|
write_binary_uint32_le(Stream, UInt32, !IO).
|
|
|
|
write_binary_uint32_le(UInt32, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint32_le(Stream, UInt32, !IO).
|
|
|
|
write_binary_uint32_le(binary_output_stream(Stream), UInt32, !IO) :-
|
|
do_write_binary_uint32_le(Stream, UInt32, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_int32_be(Int32, !IO) :-
|
|
UInt32 = uint32.cast_from_int32(Int32),
|
|
write_binary_uint32_be(UInt32, !IO).
|
|
|
|
write_binary_int32_be(Stream, Int32, !IO) :-
|
|
UInt32 = uint32.cast_from_int32(Int32),
|
|
write_binary_uint32_be(Stream, UInt32, !IO).
|
|
|
|
write_binary_uint32_be(UInt32, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint32_be(Stream, UInt32, !IO).
|
|
|
|
write_binary_uint32_be(binary_output_stream(Stream), UInt32, !IO) :-
|
|
do_write_binary_uint32_be(Stream, UInt32, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_int64(Int64, !IO) :-
|
|
UInt64 = uint64.cast_from_int64(Int64),
|
|
write_binary_uint64(UInt64, !IO).
|
|
|
|
write_binary_int64(Stream, Int64, !IO) :-
|
|
UInt64 = uint64.cast_from_int64(Int64),
|
|
write_binary_uint64(Stream, UInt64, !IO).
|
|
|
|
write_binary_uint64(UInt64, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint64(Stream, UInt64, !IO).
|
|
|
|
write_binary_uint64(binary_output_stream(Stream), UInt64, !IO) :-
|
|
do_write_binary_uint64(Stream, UInt64, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_int64_le(Int64, !IO) :-
|
|
UInt64 = uint64.cast_from_int64(Int64),
|
|
write_binary_uint64_le(UInt64, !IO).
|
|
|
|
write_binary_int64_le(Stream, Int64, !IO) :-
|
|
UInt64 = uint64.cast_from_int64(Int64),
|
|
write_binary_uint64_le(Stream, UInt64, !IO).
|
|
|
|
write_binary_uint64_le(UInt64, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint64_le(Stream, UInt64, !IO).
|
|
|
|
write_binary_uint64_le(binary_output_stream(Stream), UInt64, !IO) :-
|
|
do_write_binary_uint64_le(Stream, UInt64, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_int64_be(Int64, !IO) :-
|
|
UInt64 = uint64.cast_from_int64(Int64),
|
|
write_binary_uint64_be(UInt64, !IO).
|
|
|
|
write_binary_int64_be(Stream, Int64, !IO) :-
|
|
UInt64 = uint64.cast_from_int64(Int64),
|
|
write_binary_uint64_be(Stream, UInt64, !IO).
|
|
|
|
write_binary_uint64_be(UInt64, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_uint64_be(Stream, UInt64, !IO).
|
|
|
|
write_binary_uint64_be(binary_output_stream(Stream), UInt64, !IO) :-
|
|
do_write_binary_uint64_be(Stream, UInt64, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary_string_utf8(String, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary_string_utf8(Stream, String, !IO).
|
|
|
|
write_binary_string_utf8(binary_output_stream(Stream), String, !IO) :-
|
|
do_write_binary_string_utf8(Stream, String, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Text input predicates.
|
|
%
|
|
|
|
read_word(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
read_word(Stream, Result, !IO).
|
|
|
|
read_word(Stream, Result, !IO) :-
|
|
io.ignore_whitespace(Stream, WSResult, !IO),
|
|
(
|
|
WSResult = error(Error),
|
|
Result = error(Error)
|
|
;
|
|
WSResult = eof,
|
|
Result = eof
|
|
;
|
|
WSResult = ok,
|
|
read_word_2(Stream, Result, !IO)
|
|
).
|
|
|
|
read_line(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
read_line(Stream, Result, !IO).
|
|
|
|
read_line(Stream, Result, !IO) :-
|
|
read_line_2(Stream, ResultCode, Error, Chars, !IO),
|
|
(
|
|
ResultCode = result_code_ok,
|
|
Result = ok(Chars)
|
|
;
|
|
ResultCode = result_code_eof,
|
|
Result = eof
|
|
;
|
|
ResultCode = result_code_error,
|
|
make_io_error_from_system_error(Error, "read failed: ", IOError, !IO),
|
|
Result = error(IOError)
|
|
).
|
|
|
|
read_line_as_string(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
read_line_as_string(Stream, Result, !IO).
|
|
|
|
read_line_as_string(text_input_stream(Stream), Result, !IO) :-
|
|
read_line_as_string_2(Stream, yes, Res, Error, String, !IO),
|
|
(
|
|
Res = rlas_ok,
|
|
Result = ok(String)
|
|
;
|
|
Res = rlas_eof,
|
|
Result = eof
|
|
;
|
|
Res = rlas_null_char,
|
|
Result = error(io_error_string("null character in input"))
|
|
;
|
|
Res = rlas_error,
|
|
make_io_error_from_system_error(Error, "read failed: ", IOError, !IO),
|
|
Result = error(IOError)
|
|
).
|
|
|
|
:- pred stream_read_line_as_string(text_input_stream::in,
|
|
stream.result(line, io.error)::out, io::di, io::uo) is det.
|
|
|
|
stream_read_line_as_string(Stream, Result, !IO) :-
|
|
read_line_as_string(Stream, Result0, !IO),
|
|
(
|
|
Result0 = ok(String),
|
|
Result = ok(line(String))
|
|
;
|
|
Result0 = eof,
|
|
Result = eof
|
|
;
|
|
Result0 = error(Error),
|
|
Result = error(Error)
|
|
).
|
|
|
|
ignore_whitespace(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
ignore_whitespace(Stream, Result, !IO).
|
|
|
|
ignore_whitespace(Stream, Result, !IO) :-
|
|
read_char(Stream, CharResult, !IO),
|
|
(
|
|
CharResult = error(Error),
|
|
Result = error(Error)
|
|
;
|
|
CharResult = eof,
|
|
Result = eof
|
|
;
|
|
CharResult = ok(Char),
|
|
( if char.is_whitespace(Char) then
|
|
ignore_whitespace(Stream, Result, !IO)
|
|
else
|
|
putback_char(Stream, Char, !IO),
|
|
Result = ok
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Bitmap input and output predicates.
|
|
%
|
|
|
|
read_bitmap(!Bitmap, BytesRead, Result, !IO) :-
|
|
bitmap.read_bitmap(!Bitmap, BytesRead, Result, !IO).
|
|
|
|
read_bitmap(Stream, !Bitmap, BytesRead, Result, !IO) :-
|
|
bitmap.read_bitmap(Stream, !Bitmap, BytesRead, Result, !IO).
|
|
|
|
read_bitmap(StartByte, NumBytes, !Bitmap, BytesRead, Result, !IO) :-
|
|
bitmap.read_bitmap_range(StartByte, NumBytes, !Bitmap,
|
|
BytesRead, Result, !IO).
|
|
|
|
read_bitmap(Stream, Start, NumBytes, !Bitmap, BytesRead, Result, !IO) :-
|
|
bitmap.read_bitmap_range(Stream, Start, NumBytes, !Bitmap,
|
|
BytesRead, Result, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_bitmap(Bitmap, !IO) :-
|
|
bitmap.write_bitmap(Bitmap, !IO).
|
|
|
|
write_bitmap(Stream, Bitmap, !IO) :-
|
|
bitmap.write_bitmap(Stream, Bitmap, !IO).
|
|
|
|
write_bitmap(Bitmap, Start, NumBytes, !IO) :-
|
|
bitmap.write_bitmap_range(Bitmap, Start, NumBytes, !IO).
|
|
|
|
write_bitmap(Stream, Bitmap, Start, NumBytes, !IO) :-
|
|
bitmap.write_bitmap_range(Stream, Bitmap, Start, NumBytes, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Reading values of arbitrary types.
|
|
%
|
|
|
|
read(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
mercury_term_parser.read_term(Stream, ReadResult, !IO),
|
|
get_line_number(Stream, LineNumber, !IO),
|
|
process_read_term($pred, ReadResult, LineNumber, Result).
|
|
|
|
read(Stream, Result, !IO) :-
|
|
mercury_term_parser.read_term(Stream, ReadResult, !IO),
|
|
get_line_number(Stream, LineNumber, !IO),
|
|
process_read_term($pred, ReadResult, LineNumber, Result).
|
|
|
|
init_posn = posn(1, 0, 0).
|
|
|
|
read_from_string(FileName, String, Len, Result, !Posn) :-
|
|
mercury_term_parser.read_term_from_substring(FileName, String, Len,
|
|
!Posn, ReadResult),
|
|
!.Posn = posn(LineNumber, _, _),
|
|
process_read_term($pred, ReadResult, LineNumber, Result).
|
|
|
|
:- pred process_read_term(string::in, read_term::in, int::in,
|
|
io.read_result(T)::out) is det.
|
|
|
|
process_read_term(PredId, ReadResult, LineNumber, Result) :-
|
|
(
|
|
ReadResult = term(_VarSet, Term),
|
|
( if term_to_type(Term, Type) then
|
|
Result = ok(Type)
|
|
else
|
|
( if term_subst.term_is_ground(Term) then
|
|
Msg = "the term read did not have the right type"
|
|
else
|
|
Msg = "the term read was not a ground term"
|
|
),
|
|
Result = error(PredId ++ ": " ++ Msg, LineNumber)
|
|
)
|
|
;
|
|
ReadResult = eof,
|
|
Result = eof
|
|
;
|
|
ReadResult = error(Msg, LN),
|
|
Result = error(Msg, LN)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary(Result, !IO) :-
|
|
binary_input_stream(BinaryInputStream, !IO),
|
|
read_binary(BinaryInputStream, Result, !IO).
|
|
|
|
read_binary(BinaryInputStream, Result, !IO) :-
|
|
% XXX This "cast" will not work for the Java back-end.
|
|
% See the comment at the top of the MR_MercuryFileStruct class definition
|
|
% in io.stream_ops.m.
|
|
BinaryInputStream = binary_input_stream(Stream),
|
|
TextInputStream = text_input_stream(Stream),
|
|
read_binary_from_text_input_stream(TextInputStream, Result, !IO).
|
|
|
|
:- pred read_binary_from_text_input_stream(io.text_input_stream::in,
|
|
io.result(T)::out, io::di, io::uo) is det.
|
|
|
|
read_binary_from_text_input_stream(Stream, Result, !IO) :-
|
|
read(Stream, ReadResult, !IO),
|
|
(
|
|
ReadResult = ok(T),
|
|
% We have read the newline and the trailing full stop.
|
|
% Now skip the newline after the full stop.
|
|
read_char(Stream, NewLineRes, !IO),
|
|
(
|
|
NewLineRes = error(Error),
|
|
Result = error(Error)
|
|
;
|
|
NewLineRes = ok(NewLineChar),
|
|
( if NewLineChar = '\n' then
|
|
Result = ok(T)
|
|
else
|
|
Result = error(
|
|
io_error_string("io.read_binary: missing newline"))
|
|
)
|
|
;
|
|
NewLineRes = eof,
|
|
Result = error(io_error_string("io.read_binary: missing newline"))
|
|
)
|
|
;
|
|
ReadResult = eof,
|
|
Result = eof
|
|
;
|
|
% XXX ERROR: would need to change read_result(T) to return io.error
|
|
ReadResult = error(ErrorMsg, _Line),
|
|
Result = error(io_error_string(ErrorMsg))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Writing values of arbitrary types.
|
|
%
|
|
|
|
print(Term, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
stream.string_writer.print(Stream, canonicalize, Term, !IO).
|
|
|
|
print(Stream, Term, !IO) :-
|
|
stream.string_writer.print(Stream, canonicalize, Term, !IO).
|
|
|
|
print(Stream, MaybeCanon, Term, !IO) :-
|
|
stream.string_writer.print(Stream, MaybeCanon, Term, !IO).
|
|
|
|
print_cc(Term, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
stream.string_writer.print_cc(Stream, Term, !IO).
|
|
|
|
print_line(Term, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
print_line(Stream, Term, !IO).
|
|
|
|
print_line(Stream, Term, !IO) :-
|
|
io.print(Stream, Term, !IO),
|
|
io.nl(Stream, !IO).
|
|
|
|
print_line(Stream, MaybeCanon, Term, !IO) :-
|
|
io.print(Stream, MaybeCanon, Term, !IO),
|
|
io.nl(Stream, !IO).
|
|
|
|
print_line_cc(Term, !IO) :-
|
|
io.print_cc(Term, !IO),
|
|
io.nl(!IO).
|
|
|
|
%---------------------%
|
|
|
|
% XXX Only use this for debugging. Strictly speaking, io.print may throw an
|
|
% exception which is not allowed across the C interface.
|
|
%
|
|
:- pred print_to_stream(io.stream::in, T::in, io::di, io::uo) is det.
|
|
:- pragma foreign_export("C", io.print_to_stream(in, in, di, uo),
|
|
"ML_io_print_to_stream").
|
|
|
|
print_to_stream(Stream, Term, !IO) :-
|
|
io.print(text_output_stream(Stream), canonicalize, Term, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write(X, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
stream.string_writer.write(Stream, canonicalize, X, !IO).
|
|
|
|
write(Stream, X, !IO) :-
|
|
stream.string_writer.write(Stream, canonicalize, X, !IO).
|
|
|
|
write(Stream, MaybeCanon, X, !IO) :-
|
|
stream.string_writer.write(Stream, MaybeCanon, X, !IO).
|
|
|
|
write_cc(X, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
io.write_cc(Stream, X, !IO).
|
|
|
|
write_cc(Stream, X, !IO) :-
|
|
stream.string_writer.write(Stream, include_details_cc, X, !IO).
|
|
|
|
write_line(X, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_line(Stream, X, !IO).
|
|
|
|
write_line(Stream, X, !IO) :-
|
|
io.write(Stream, X, !IO),
|
|
io.nl(Stream, !IO).
|
|
|
|
write_line(Stream, MaybeCanon, X, !IO) :-
|
|
io.write(Stream, MaybeCanon, X, !IO),
|
|
io.nl(Stream, !IO).
|
|
|
|
write_line_cc(X, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_line_cc(Stream, X, !IO).
|
|
|
|
write_line_cc(Stream, X, !IO) :-
|
|
io.write_cc(Stream, X, !IO),
|
|
io.nl(Stream, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_binary(Term, !IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
write_binary(Stream, Term, !IO).
|
|
|
|
write_binary(binary_output_stream(Stream), Term, !IO) :-
|
|
% A quick-and-dirty implementation... not very space-efficient
|
|
% (not really binary!)
|
|
% XXX This will not work for the Java back-end. See the comment at the
|
|
% top of the MR_MercuryFileStruct class definition.
|
|
io.write(text_output_stream(Stream), Term, !IO),
|
|
io.write_string(text_output_stream(Stream), ".\n", !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Formatted output.
|
|
%
|
|
|
|
format(FormatString, Arguments, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
disable_warning [unknown_format_calls] (
|
|
io.format(Stream, FormatString, Arguments, !IO)
|
|
).
|
|
|
|
format(Stream, FormatString, Arguments, !IO) :-
|
|
disable_warning [unknown_format_calls] (
|
|
string.format(FormatString, Arguments, String)
|
|
),
|
|
write_string(Stream, String, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Writing out several values.
|
|
%
|
|
|
|
write_strings(Strings, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_strings(Stream, Strings, !IO).
|
|
|
|
write_strings(_Stream, [], !IO).
|
|
write_strings(Stream, [S | Ss], !IO) :-
|
|
write_string(Stream, S, !IO),
|
|
write_strings(Stream, Ss, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_prefixed_lines(Prefix, Lines, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_prefixed_lines(Stream, Prefix, Lines, !IO).
|
|
|
|
write_prefixed_lines(_, _, [], !IO).
|
|
write_prefixed_lines(Stream, Prefix, [Str | Strs], !IO) :-
|
|
io.format(Stream, "%s%s\n", [s(Prefix), s(Str)], !IO),
|
|
write_prefixed_lines(Stream, Prefix, Strs, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_many(Vals, !IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
write_many(Stream, Vals, !IO).
|
|
|
|
write_many(_Stream, [], !IO).
|
|
write_many(Stream, [Val | Vals], !IO) :-
|
|
(
|
|
Val = c(C),
|
|
write_char(Stream, C, !IO)
|
|
;
|
|
Val = i(I),
|
|
write_int(Stream, I, !IO)
|
|
;
|
|
Val = i8(I),
|
|
write_int8(Stream, I, !IO)
|
|
;
|
|
Val = i16(I),
|
|
write_int16(Stream, I, !IO)
|
|
;
|
|
Val = i32(I),
|
|
write_int32(Stream, I, !IO)
|
|
;
|
|
Val = i64(I),
|
|
write_int64(Stream, I, !IO)
|
|
;
|
|
Val = u(U),
|
|
write_uint(Stream, U, !IO)
|
|
;
|
|
Val = u8(U),
|
|
write_uint8(Stream, U, !IO)
|
|
;
|
|
Val = u16(U),
|
|
write_uint16(Stream, U, !IO)
|
|
;
|
|
Val = u32(U),
|
|
write_uint32(Stream, U, !IO)
|
|
;
|
|
Val = u64(U),
|
|
write_uint64(Stream, U, !IO)
|
|
;
|
|
Val = s(S),
|
|
write_string(Stream, S, !IO)
|
|
;
|
|
Val = f(F),
|
|
write_float(Stream, F, !IO)
|
|
),
|
|
write_many(Stream, Vals, !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_list([], _Separator, _OutputPred, !IO).
|
|
write_list([Head | Tail], Separator, OutputPred, !IO) :-
|
|
OutputPred(Head, !IO),
|
|
(
|
|
Tail = []
|
|
;
|
|
Tail = [TailHead | TailTail],
|
|
write_list_lag(TailHead, TailTail, Separator, OutputPred, !IO)
|
|
).
|
|
|
|
:- pred write_list_lag(T, list(T), string, pred(T, io, io), io, io).
|
|
:- mode write_list_lag(in, in, in, in(pred(in, di, uo) is det),
|
|
di, uo) is det.
|
|
:- mode write_list_lag(in, in, in, in(pred(in, di, uo) is cc_multi),
|
|
di, uo) is cc_multi.
|
|
|
|
write_list_lag(Head, Tail, Separator, OutputPred, !IO) :-
|
|
write_string(Separator, !IO),
|
|
OutputPred(Head, !IO),
|
|
(
|
|
Tail = []
|
|
;
|
|
Tail = [TailHead | TailTail],
|
|
write_list_lag(TailHead, TailTail, Separator, OutputPred, !IO)
|
|
).
|
|
|
|
write_list(Stream, List, Separator, OutputPred, !IO) :-
|
|
% OutputPred expects the current output stream to be Stream.
|
|
with_output_stream(Stream,
|
|
write_list(List, Separator, OutputPred), !IO).
|
|
|
|
%---------------------%
|
|
|
|
write_array(Array, Separator, OutputPred, !IO) :-
|
|
array.bounds(Array, Lo, Hi),
|
|
( if Lo =< Hi then
|
|
array.unsafe_lookup(Array, Lo, E),
|
|
OutputPred(E, !IO),
|
|
do_write_array(Array, Separator, OutputPred, Lo + 1, Hi, !IO)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred do_write_array(array(T), string, pred(T, io, io), int, int, io, io).
|
|
:- mode do_write_array(in, in, in(pred(in, di, uo) is det),
|
|
in, in, di, uo) is det.
|
|
:- mode do_write_array(in, in, in(pred(in, di, uo) is cc_multi),
|
|
in, in, di, uo) is cc_multi.
|
|
|
|
do_write_array(Array, Separator, OutputPred, I, Hi, !IO) :-
|
|
( if I =< Hi then
|
|
write_string(Separator, !IO),
|
|
array.unsafe_lookup(Array, I, E),
|
|
OutputPred(E, !IO),
|
|
do_write_array(Array, Separator, OutputPred, I + 1, Hi, !IO)
|
|
else
|
|
true
|
|
).
|
|
|
|
write_array(Stream, Array, Separator, OutputPred, !IO) :-
|
|
% OutputPred expects the current output stream to be Stream.
|
|
with_output_stream(Stream,
|
|
write_array(Array, Separator, OutputPred), !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Flushing output to the operating system.
|
|
%
|
|
|
|
flush_output(!IO) :-
|
|
io.output_stream(Stream, !IO),
|
|
flush_output(Stream, !IO).
|
|
|
|
flush_output(text_output_stream(Stream), !IO) :-
|
|
flush_text_output_2(Stream, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------%
|
|
|
|
flush_binary_output(!IO) :-
|
|
binary_output_stream(Stream, !IO),
|
|
flush_binary_output(Stream, !IO).
|
|
|
|
flush_binary_output(binary_output_stream(Stream), !IO) :-
|
|
flush_binary_output_2(Stream, Error, !IO),
|
|
throw_on_output_error(Error, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Whole file input predicates.
|
|
%
|
|
|
|
read_named_file_as_string(FileName, Result, !IO) :-
|
|
io.open_input(FileName, OpenResult, !IO),
|
|
(
|
|
OpenResult = ok(FileStream),
|
|
io.read_file_as_string(FileStream, ReadResult, !IO),
|
|
(
|
|
ReadResult = ok(String),
|
|
Result = ok(String)
|
|
;
|
|
ReadResult = error(_PartialString, Error),
|
|
Result = error(Error)
|
|
),
|
|
io.close_input(FileStream, !IO)
|
|
;
|
|
OpenResult = error(Error),
|
|
Result = error(Error)
|
|
).
|
|
|
|
read_named_file_as_string_wf(FileName, Result, !IO) :-
|
|
read_named_file_as_string(FileName, Result0, !IO),
|
|
(
|
|
Result0 = error(_),
|
|
Result = Result0
|
|
;
|
|
Result0 = ok(String),
|
|
check_well_formedness(String, MaybeWellFormed),
|
|
(
|
|
MaybeWellFormed = ill_formed(FirstIllFormedPos),
|
|
Msg = "ill formed character at offset " ++
|
|
string.int_to_string(FirstIllFormedPos),
|
|
Result = error(io_error_string(Msg))
|
|
;
|
|
MaybeWellFormed = well_formed,
|
|
Result = Result0
|
|
)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_named_file_as_lines(FileName, Result, !IO) :-
|
|
io.open_input(FileName, OpenResult, !IO),
|
|
(
|
|
OpenResult = ok(FileStream),
|
|
io.read_file_as_string(FileStream, ReadResult, !IO),
|
|
(
|
|
ReadResult = ok(String),
|
|
Lines = split_into_lines(String),
|
|
Result = ok(Lines)
|
|
;
|
|
ReadResult = error(_PartialString, Error),
|
|
Result = error(Error)
|
|
),
|
|
io.close_input(FileStream, !IO)
|
|
;
|
|
OpenResult = error(Error),
|
|
Result = error(Error)
|
|
).
|
|
|
|
read_named_file_as_lines_wf(FileName, Result, !IO) :-
|
|
% We duplicate the logic of read_named_file_as_lines here because
|
|
% it is simpler and faster to check the well-formedness of String
|
|
% than it is to check the well-formedness of all the Lines.
|
|
io.open_input(FileName, OpenResult, !IO),
|
|
(
|
|
OpenResult = ok(FileStream),
|
|
io.read_file_as_string(FileStream, ReadResult, !IO),
|
|
(
|
|
ReadResult = ok(String),
|
|
check_well_formedness(String, MaybeWellFormed),
|
|
(
|
|
MaybeWellFormed = ill_formed(FirstIllFormedPos),
|
|
Msg = "ill formed character at offset " ++
|
|
string.int_to_string(FirstIllFormedPos),
|
|
Result = error(io_error_string(Msg))
|
|
;
|
|
MaybeWellFormed = well_formed,
|
|
Lines = split_into_lines(String),
|
|
Result = ok(Lines)
|
|
)
|
|
;
|
|
ReadResult = error(_PartialString, Error),
|
|
Result = error(Error)
|
|
),
|
|
io.close_input(FileStream, !IO)
|
|
;
|
|
OpenResult = error(Error),
|
|
Result = error(Error)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_file(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
read_file(Stream, Result, !IO).
|
|
|
|
read_file(Stream, Result, !IO) :-
|
|
read_file_chars_acc(Stream, [], Result, !IO).
|
|
|
|
:- pred read_file_chars_acc(text_input_stream::in, list(char)::in,
|
|
maybe_partial_res(list(char))::out, io::di, io::uo) is det.
|
|
|
|
read_file_chars_acc(Stream, RevChars0, Result, !IO) :-
|
|
read_char(Stream, Result0, !IO),
|
|
(
|
|
Result0 = eof,
|
|
Result = ok(list.reverse(RevChars0))
|
|
;
|
|
Result0 = error(Error),
|
|
Result = error(list.reverse(RevChars0), Error)
|
|
;
|
|
Result0 = ok(Char),
|
|
RevChars = [Char | RevChars0],
|
|
read_file_chars_acc(Stream, RevChars, Result, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_file_as_string(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
read_file_as_string(Stream, Result, !IO).
|
|
|
|
read_file_as_string(text_input_stream(Stream), Result, !IO) :-
|
|
read_file_as_string_2(Stream, String, _NumCUs, Error, NullCharError, !IO),
|
|
is_error(Error, "read failed: ", MaybeIOError, !IO),
|
|
(
|
|
MaybeIOError = yes(IOError),
|
|
Result = error(String, IOError)
|
|
;
|
|
MaybeIOError = no,
|
|
(
|
|
NullCharError = yes,
|
|
Result = error("", io_error_string("null character in input"))
|
|
;
|
|
NullCharError = no,
|
|
Result = ok(String)
|
|
)
|
|
).
|
|
|
|
:- pred stream_read_file_as_string(text_input_stream::in,
|
|
stream.result(text_file, io.error)::out, io::di, io::uo) is det.
|
|
|
|
stream_read_file_as_string(Stream, Result, !IO) :-
|
|
read_file_as_string(Stream, Result0, !IO),
|
|
(
|
|
Result0 = ok(String),
|
|
Result = ok(text_file(String))
|
|
;
|
|
Result0 = error(_PartialString, Error),
|
|
Result = error(Error)
|
|
).
|
|
|
|
read_file_as_string_wf(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
read_file_as_string_wf(Stream, Result, !IO).
|
|
|
|
read_file_as_string_wf(Stream, Result, !IO) :-
|
|
read_file_as_string(Stream, Result0, !IO),
|
|
(
|
|
Result0 = error(_, _),
|
|
Result = Result0
|
|
;
|
|
Result0 = ok(String),
|
|
check_well_formedness(String, MaybeWellFormed),
|
|
(
|
|
MaybeWellFormed = ill_formed(FirstIllFormedPos),
|
|
Msg = "ill formed character at offset " ++
|
|
string.int_to_string(FirstIllFormedPos),
|
|
Result = error("", io_error_string(Msg))
|
|
;
|
|
MaybeWellFormed = well_formed,
|
|
Result = Result0
|
|
)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_file_as_string_and_num_code_units(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
read_file_as_string_and_num_code_units(Stream, Result, !IO).
|
|
|
|
read_file_as_string_and_num_code_units(text_input_stream(Stream),
|
|
Result, !IO) :-
|
|
read_file_as_string_2(Stream, String, NumCUs, Error, NullCharError, !IO),
|
|
is_error(Error, "read failed: ", MaybeIOError, !IO),
|
|
(
|
|
MaybeIOError = yes(IOError),
|
|
Result = error2(String, NumCUs, IOError)
|
|
;
|
|
MaybeIOError = no,
|
|
(
|
|
NullCharError = yes,
|
|
Result = error2("", 0, io_error_string("null character in input"))
|
|
;
|
|
NullCharError = no,
|
|
Result = ok2(String, NumCUs)
|
|
)
|
|
).
|
|
|
|
read_file_as_string_and_num_code_units_wf(Result, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
read_file_as_string_and_num_code_units_wf(Stream, Result, !IO).
|
|
|
|
read_file_as_string_and_num_code_units_wf(Stream, Result, !IO) :-
|
|
read_file_as_string_and_num_code_units(Stream, Result0, !IO),
|
|
(
|
|
Result0 = error2(_, _, _),
|
|
Result = Result0
|
|
;
|
|
Result0 = ok2(String, _NumCUs),
|
|
check_well_formedness(String, MaybeWellFormed),
|
|
(
|
|
MaybeWellFormed = ill_formed(FirstIllFormedPos),
|
|
Msg = "ill formed character at offset " ++
|
|
string.int_to_string(FirstIllFormedPos),
|
|
Result = error2("", 0, io_error_string(Msg))
|
|
;
|
|
MaybeWellFormed = well_formed,
|
|
Result = Result0
|
|
)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_file(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_file(Stream, Result, !IO).
|
|
|
|
read_binary_file(Stream, Result, !IO) :-
|
|
read_binary_file_2(Stream, [], Result, !IO).
|
|
|
|
:- pred read_binary_file_2(binary_input_stream::in, list(int)::in,
|
|
io.result(list(int))::out, io::di, io::uo) is det.
|
|
|
|
read_binary_file_2(Stream, Bytes0, Result, !IO) :-
|
|
read_byte(Stream, Result0, !IO),
|
|
(
|
|
Result0 = eof,
|
|
list.reverse(Bytes0, Bytes),
|
|
Result = ok(Bytes)
|
|
;
|
|
Result0 = error(Err),
|
|
Result = error(Err)
|
|
;
|
|
Result0 = ok(Byte),
|
|
read_binary_file_2(Stream, [Byte | Bytes0], Result, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
read_binary_file_as_bitmap(Result, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
read_binary_file_as_bitmap(Stream, Result, !IO).
|
|
|
|
read_binary_file_as_bitmap(Stream, Result, !IO) :-
|
|
read_binary_file_as_bitmap_2(Stream, Result, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Processing the contents of a whole file.
|
|
%
|
|
|
|
input_stream_foldl(Pred, T0, Res, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
input_stream_foldl(Stream, Pred, T0, Res, !IO).
|
|
|
|
input_stream_foldl(Stream, Pred, T0, Res, !IO) :-
|
|
read_char(Stream, CharResult, !IO),
|
|
(
|
|
CharResult = ok(Char),
|
|
Pred(Char, T0, T1),
|
|
input_stream_foldl(Stream, Pred, T1, Res, !IO)
|
|
;
|
|
CharResult = eof,
|
|
Res = ok(T0)
|
|
;
|
|
CharResult = error(Error),
|
|
Res = error(T0, Error)
|
|
).
|
|
|
|
input_stream_foldl_io(Pred, Res, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
input_stream_foldl_io(Stream, Pred, Res, !IO).
|
|
|
|
input_stream_foldl_io(Stream, Pred, Res, !IO) :-
|
|
read_char(Stream, CharResult, !IO),
|
|
(
|
|
CharResult = ok(Char),
|
|
Pred(Char, !IO),
|
|
input_stream_foldl_io(Stream, Pred, Res, !IO)
|
|
;
|
|
CharResult = eof,
|
|
Res = ok
|
|
;
|
|
CharResult = error(Error),
|
|
Res = error(Error)
|
|
).
|
|
|
|
input_stream_foldl2_io(Pred, T0, Res, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
input_stream_foldl2_io(Stream, Pred, T0, Res, !IO).
|
|
|
|
input_stream_foldl2_io(Stream, Pred, T0, Res, !IO) :-
|
|
read_char(Stream, CharResult, !IO),
|
|
(
|
|
CharResult = ok(Char),
|
|
Pred(Char, T0, T1, !IO),
|
|
input_stream_foldl2_io(Stream, Pred, T1, Res, !IO)
|
|
;
|
|
CharResult = eof,
|
|
Res = ok(T0)
|
|
;
|
|
CharResult = error(Error),
|
|
Res = error(T0, Error)
|
|
).
|
|
|
|
input_stream_foldl2_io_maybe_stop(Pred, T0, Res, !IO) :-
|
|
io.input_stream(Stream, !IO),
|
|
input_stream_foldl2_io_maybe_stop(Stream, Pred, T0, Res, !IO).
|
|
|
|
input_stream_foldl2_io_maybe_stop(Stream, Pred, T0, Res, !IO) :-
|
|
read_char(Stream, CharResult, !IO),
|
|
(
|
|
CharResult = ok(Char),
|
|
Pred(Char, Continue, T0, T1, !IO),
|
|
(
|
|
Continue = no,
|
|
Res = ok(T1)
|
|
;
|
|
Continue = yes,
|
|
input_stream_foldl2_io_maybe_stop(Stream, Pred, T1, Res, !IO)
|
|
)
|
|
;
|
|
CharResult = eof,
|
|
Res = ok(T0)
|
|
;
|
|
CharResult = error(Error),
|
|
Res = error(T0, Error)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
binary_input_stream_foldl(Pred, T0, Res, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
binary_input_stream_foldl(Stream, Pred, T0, Res, !IO).
|
|
|
|
binary_input_stream_foldl(Stream, Pred, T0, Res, !IO) :-
|
|
read_byte(Stream, ByteResult, !IO),
|
|
(
|
|
ByteResult = ok(Byte),
|
|
Pred(Byte, T0, T1),
|
|
binary_input_stream_foldl(Stream, Pred, T1, Res, !IO)
|
|
;
|
|
ByteResult = eof,
|
|
Res = ok(T0)
|
|
;
|
|
ByteResult = error(Error),
|
|
Res = error(T0, Error)
|
|
).
|
|
|
|
binary_input_stream_foldl_io(Pred, Res, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
binary_input_stream_foldl_io(Stream, Pred, Res, !IO).
|
|
|
|
binary_input_stream_foldl_io(Stream, Pred, Res, !IO) :-
|
|
should_reduce_stack_usage(ShouldReduce),
|
|
(
|
|
ShouldReduce = no,
|
|
binary_input_stream_foldl_io_plain(Stream, Pred, Res, !IO)
|
|
;
|
|
ShouldReduce = yes,
|
|
io.binary_input_stream_foldl_io_chunk(Stream, Pred, Res, !IO)
|
|
).
|
|
|
|
:- pred binary_input_stream_foldl_io_plain(binary_input_stream,
|
|
pred(int, io, io), io.res, io, io).
|
|
:- mode binary_input_stream_foldl_io_plain(in,
|
|
in(pred(in, di, uo) is det), out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl_io_plain(in,
|
|
in(pred(in, di, uo) is cc_multi), out, di, uo) is cc_multi.
|
|
|
|
binary_input_stream_foldl_io_plain(Stream, Pred, Res, !IO) :-
|
|
read_byte(Stream, ByteResult, !IO),
|
|
(
|
|
ByteResult = ok(Byte),
|
|
Pred(Byte, !IO),
|
|
binary_input_stream_foldl_io_plain(Stream, Pred, Res, !IO)
|
|
;
|
|
ByteResult = eof,
|
|
Res = ok
|
|
;
|
|
ByteResult = error(Error),
|
|
Res = error(Error)
|
|
).
|
|
|
|
:- type chunk_inner_res0
|
|
---> cir0_ok
|
|
; cir0_error(io.error)
|
|
; cir0_more.
|
|
|
|
:- type chunk_inner_res(T)
|
|
---> cir_ok(T)
|
|
; cir_error(T, io.error)
|
|
; cir_more(T).
|
|
|
|
:- pred binary_input_stream_foldl_io_chunk(binary_input_stream,
|
|
pred(int, io, io), io.res, io, io).
|
|
:- mode binary_input_stream_foldl_io_chunk(in,
|
|
in(pred(in, di, uo) is det), out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl_io_chunk(in,
|
|
in(pred(in, di, uo) is cc_multi), out, di, uo) is cc_multi.
|
|
|
|
binary_input_stream_foldl_io_chunk(Stream, Pred, Res, !IO) :-
|
|
binary_input_stream_foldl_io_inner(chunk_size, Stream, Pred,
|
|
InnerRes, !IO),
|
|
(
|
|
InnerRes = cir0_ok,
|
|
Res = ok
|
|
;
|
|
InnerRes = cir0_error(Error),
|
|
Res = error(Error)
|
|
;
|
|
InnerRes = cir0_more,
|
|
binary_input_stream_foldl_io_chunk(Stream, Pred, Res, !IO)
|
|
).
|
|
|
|
:- pred binary_input_stream_foldl_io_inner(int, binary_input_stream,
|
|
pred(int, io, io), chunk_inner_res0, io, io).
|
|
:- mode binary_input_stream_foldl_io_inner(in, in,
|
|
in(pred(in, di, uo) is det), out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl_io_inner(in, in,
|
|
in(pred(in, di, uo) is cc_multi), out, di, uo) is cc_multi.
|
|
|
|
binary_input_stream_foldl_io_inner(Left, Stream, Pred, Res, !IO) :-
|
|
( if Left > 0 then
|
|
read_byte(Stream, ByteResult, !IO),
|
|
(
|
|
ByteResult = ok(Byte),
|
|
Pred(Byte, !IO),
|
|
binary_input_stream_foldl_io_inner(Left - 1,
|
|
Stream, Pred, Res, !IO)
|
|
;
|
|
ByteResult = eof,
|
|
Res = cir0_ok
|
|
;
|
|
ByteResult = error(Error),
|
|
Res = cir0_error(Error)
|
|
)
|
|
else
|
|
Res = cir0_more
|
|
).
|
|
|
|
binary_input_stream_foldl2_io(Pred, T0, Res, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
binary_input_stream_foldl2_io(Stream, Pred, T0, Res, !IO).
|
|
|
|
binary_input_stream_foldl2_io(Stream, Pred, T0, Res, !IO) :-
|
|
should_reduce_stack_usage(ShouldReduce),
|
|
(
|
|
ShouldReduce = no,
|
|
binary_input_stream_foldl2_io_plain(Stream, Pred, T0, Res, !IO)
|
|
;
|
|
ShouldReduce = yes,
|
|
binary_input_stream_foldl2_io_chunk(Stream, Pred, T0, Res, !IO)
|
|
).
|
|
|
|
:- pred binary_input_stream_foldl2_io_plain(binary_input_stream,
|
|
pred(int, T, T, io, io), T, io.maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io_plain(in,
|
|
in(pred(in, in, out, di, uo) is det), in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io_plain(in,
|
|
in(pred(in, in, out, di, uo) is cc_multi), in, out, di, uo) is cc_multi.
|
|
|
|
binary_input_stream_foldl2_io_plain(Stream, Pred, T0, Res, !IO) :-
|
|
read_byte(Stream, ByteResult, !IO),
|
|
(
|
|
ByteResult = ok(Byte),
|
|
Pred(Byte, T0, T1, !IO),
|
|
binary_input_stream_foldl2_io_plain(Stream, Pred, T1, Res, !IO)
|
|
;
|
|
ByteResult = eof,
|
|
Res = ok(T0)
|
|
;
|
|
ByteResult = error(Error),
|
|
Res = error(T0, Error)
|
|
).
|
|
|
|
:- pred binary_input_stream_foldl2_io_chunk(binary_input_stream,
|
|
pred(int, T, T, io, io), T, io.maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io_chunk(in,
|
|
in(pred(in, in, out, di, uo) is det), in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io_chunk(in,
|
|
in(pred(in, in, out, di, uo) is cc_multi), in, out, di, uo) is cc_multi.
|
|
|
|
binary_input_stream_foldl2_io_chunk(Stream, Pred, T0, Res, !IO) :-
|
|
binary_input_stream_foldl2_io_inner(chunk_size, Stream, Pred, T0,
|
|
InnerRes, !IO),
|
|
(
|
|
InnerRes = cir_ok(T),
|
|
Res = ok(T)
|
|
;
|
|
InnerRes = cir_error(T, Error),
|
|
Res = error(T, Error)
|
|
;
|
|
InnerRes = cir_more(T1),
|
|
binary_input_stream_foldl2_io_chunk(Stream, Pred, T1, Res, !IO)
|
|
).
|
|
|
|
:- pred binary_input_stream_foldl2_io_inner(int, binary_input_stream,
|
|
pred(int, T, T, io, io), T, chunk_inner_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io_inner(in, in,
|
|
in(pred(in, in, out, di, uo) is det), in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io_inner(in, in,
|
|
in(pred(in, in, out, di, uo) is cc_multi), in, out, di, uo) is cc_multi.
|
|
|
|
binary_input_stream_foldl2_io_inner(Left, Stream, Pred, T0, Res, !IO) :-
|
|
( if Left > 0 then
|
|
read_byte(Stream, ByteResult, !IO),
|
|
(
|
|
ByteResult = ok(Byte),
|
|
Pred(Byte, T0, T1, !IO),
|
|
binary_input_stream_foldl2_io_inner(Left - 1,
|
|
Stream, Pred, T1, Res, !IO)
|
|
;
|
|
ByteResult = eof,
|
|
Res = cir_ok(T0)
|
|
;
|
|
ByteResult = error(Error),
|
|
Res = cir_error(T0, Error)
|
|
)
|
|
else
|
|
Res = cir_more(T0)
|
|
).
|
|
|
|
binary_input_stream_foldl2_io_maybe_stop(Pred, T0, Res, !IO) :-
|
|
binary_input_stream(Stream, !IO),
|
|
binary_input_stream_foldl2_io_maybe_stop(Stream, Pred, T0, Res, !IO).
|
|
|
|
binary_input_stream_foldl2_io_maybe_stop(Stream, Pred, T0, Res, !IO) :-
|
|
should_reduce_stack_usage(ShouldReduce),
|
|
(
|
|
ShouldReduce = no,
|
|
binary_input_stream_foldl2_io_maybe_stop_plain(Stream,
|
|
Pred, T0, Res, !IO)
|
|
;
|
|
ShouldReduce = yes,
|
|
binary_input_stream_foldl2_io_maybe_stop_chunk(Stream,
|
|
Pred, T0, Res, !IO)
|
|
).
|
|
|
|
:- pred binary_input_stream_foldl2_io_maybe_stop_plain(
|
|
binary_input_stream, pred(int, bool, T, T, io, io),
|
|
T, io.maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop_plain(
|
|
in, in(pred(in, out, in, out, di, uo) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop_plain(
|
|
in, in(pred(in, out, in, out, di, uo) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
|
|
binary_input_stream_foldl2_io_maybe_stop_plain(Stream, Pred, T0, Res,
|
|
!IO) :-
|
|
read_byte(Stream, ByteResult, !IO),
|
|
(
|
|
ByteResult = ok(Byte),
|
|
Pred(Byte, Continue, T0, T1, !IO),
|
|
(
|
|
Continue = no,
|
|
Res = ok(T1)
|
|
;
|
|
Continue = yes,
|
|
binary_input_stream_foldl2_io_maybe_stop_plain(Stream, Pred, T1,
|
|
Res, !IO)
|
|
)
|
|
;
|
|
ByteResult = eof,
|
|
Res = ok(T0)
|
|
;
|
|
ByteResult = error(Error),
|
|
Res = error(T0, Error)
|
|
).
|
|
|
|
:- pred binary_input_stream_foldl2_io_maybe_stop_chunk(
|
|
binary_input_stream, pred(int, bool, T, T, io, io),
|
|
T, io.maybe_partial_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop_chunk(
|
|
in, in(pred(in, out, in, out, di, uo) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop_chunk(
|
|
in, in(pred(in, out, in, out, di, uo) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
|
|
binary_input_stream_foldl2_io_maybe_stop_chunk(Stream, Pred, T0, Res,
|
|
!IO) :-
|
|
binary_input_stream_foldl2_io_maybe_stop_inner(chunk_size,
|
|
Stream, Pred, T0, InnerRes, !IO),
|
|
(
|
|
InnerRes = cir_ok(T),
|
|
Res = ok(T)
|
|
;
|
|
InnerRes = cir_error(T, Error),
|
|
Res = error(T, Error)
|
|
;
|
|
InnerRes = cir_more(T1),
|
|
binary_input_stream_foldl2_io_maybe_stop_chunk(Stream, Pred, T1,
|
|
Res, !IO)
|
|
).
|
|
|
|
:- pred binary_input_stream_foldl2_io_maybe_stop_inner(int,
|
|
binary_input_stream, pred(int, bool, T, T, io, io),
|
|
T, chunk_inner_res(T), io, io).
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop_inner(in,
|
|
in, in(pred(in, out, in, out, di, uo) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode binary_input_stream_foldl2_io_maybe_stop_inner(in,
|
|
in, in(pred(in, out, in, out, di, uo) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
|
|
binary_input_stream_foldl2_io_maybe_stop_inner(Left, Stream, Pred, T0, Res,
|
|
!IO) :-
|
|
( if Left > 0 then
|
|
read_byte(Stream, ByteResult, !IO),
|
|
(
|
|
ByteResult = ok(Byte),
|
|
Pred(Byte, Continue, T0, T1, !IO),
|
|
(
|
|
Continue = no,
|
|
Res = cir_ok(T1)
|
|
;
|
|
Continue = yes,
|
|
binary_input_stream_foldl2_io_maybe_stop_inner(Left - 1,
|
|
Stream, Pred, T1, Res, !IO)
|
|
)
|
|
;
|
|
ByteResult = eof,
|
|
Res = cir_ok(T0)
|
|
;
|
|
ByteResult = error(Error),
|
|
Res = cir_error(T0, Error)
|
|
)
|
|
else
|
|
Res = cir_more(T0)
|
|
).
|
|
|
|
:- pred should_reduce_stack_usage(bool::out) is det.
|
|
|
|
% For non-C backends.
|
|
should_reduce_stack_usage(yes).
|
|
|
|
:- pragma foreign_proc("C",
|
|
should_reduce_stack_usage(ShouldReduce::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe,
|
|
does_not_affect_liveness],
|
|
"
|
|
#ifdef MR_EXEC_TRACE
|
|
ShouldReduce = MR_YES;
|
|
#else
|
|
ShouldReduce = MR_NO;
|
|
#endif
|
|
").
|
|
|
|
% Chunk_size gives the maximum number of recursive calls we want to allow
|
|
% in the binary_input_stream_foldl*_inner predicates. Without such a limit,
|
|
% the depth of recursion, which depends on the size of the file they read,
|
|
% will cause exhaustion of the det stack in debug grades, since there is
|
|
% no tail recursion in such grades.
|
|
%
|
|
% With this arrangement, the maximum number of stack frames needed
|
|
% to process a file of size N is N/1000 + 1000, the former being the
|
|
% number of frames of binary_input_stream_foldl*_chunk predicates,
|
|
% the latter being the max number of frames of the *_inner predicates.
|
|
%
|
|
:- func chunk_size = int.
|
|
|
|
chunk_size = 1000.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File handling predicates.
|
|
%
|
|
|
|
remove_file(FileName, Result, !IO) :-
|
|
io.file.remove_file(FileName, Result, !IO).
|
|
|
|
remove_file_recursively(FileName, Res, !IO) :-
|
|
io.file.remove_file_recursively(FileName, Res, !IO).
|
|
|
|
rename_file(OldFileName, NewFileName, Result, !IO) :-
|
|
io.file.rename_file(OldFileName, NewFileName, Result, !IO).
|
|
|
|
have_symlinks :-
|
|
io.file.have_symlinks.
|
|
|
|
make_symlink(FileName, LinkFileName, Result, !IO) :-
|
|
io.file.make_symlink(FileName, LinkFileName, Result, !IO).
|
|
|
|
read_symlink(FileName, Result, !IO) :-
|
|
io.file.read_symlink(FileName, Result, !IO).
|
|
|
|
check_file_accessibility(FileName, AccessTypes, Result, !IO) :-
|
|
io.file.check_file_accessibility(FileName, AccessTypes, Result, !IO).
|
|
|
|
file_type(FollowSymLinks, FileName, Result, !IO) :-
|
|
io.file.file_type(FollowSymLinks, FileName, Result, !IO).
|
|
|
|
file_modification_time(File, Result, !IO) :-
|
|
io.file.file_modification_time(File, Result, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Predicates for handling temporary files.
|
|
%
|
|
|
|
make_temp_file(Result, !IO) :-
|
|
io.file.make_temp_file(Result, !IO).
|
|
|
|
make_temp_file(Dir, Prefix, Suffix, Result, !IO) :-
|
|
io.file.make_temp_file(Dir, Prefix, Suffix, Result, !IO).
|
|
|
|
make_temp_directory(Result, !IO) :-
|
|
io.file.make_temp_directory(Result, !IO).
|
|
|
|
make_temp_directory(Dir, Prefix, Suffix, Result, !IO) :-
|
|
io.file.make_temp_directory(Dir, Prefix, Suffix, Result, !IO).
|
|
|
|
have_make_temp_directory :-
|
|
io.file.have_make_temp_directory.
|
|
|
|
get_temp_directory(Dir, !IO) :-
|
|
io.file.get_temp_directory(Dir, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Global state predicates.
|
|
%
|
|
|
|
:- pragma foreign_proc("C",
|
|
progname(DefaultProgname::in, PrognameOut::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
|
|
does_not_affect_liveness, may_not_duplicate],
|
|
"
|
|
if ((MR_progname != NULL) && MR_progname_is_known) {
|
|
MR_make_aligned_string(PrognameOut, MR_progname);
|
|
} else {
|
|
PrognameOut = DefaultProgname;
|
|
}
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
progname(Default::in, PrognameOut::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, thread_safe, may_not_duplicate],
|
|
"
|
|
PrognameOut = jmercury.runtime.JavaInternal.progname;
|
|
if (PrognameOut == null) {
|
|
PrognameOut = Default;
|
|
}
|
|
").
|
|
|
|
% Fallback implementation.
|
|
progname(DefaultProgName, ProgName, !IO) :-
|
|
ProgName = DefaultProgName.
|
|
|
|
progname_base(DefaultName, PrognameBase, !IO) :-
|
|
progname(DefaultName, Progname, !IO),
|
|
PrognameBase = dir.det_basename(Progname).
|
|
|
|
%---------------------%
|
|
|
|
:- pragma foreign_proc("C",
|
|
command_line_arguments(Args::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
|
|
does_not_affect_liveness, may_not_duplicate,
|
|
no_sharing],
|
|
% no_sharing is okay because the string elements can't be reused.
|
|
"{
|
|
int i;
|
|
|
|
// Convert mercury_argv from a vector to a list.
|
|
i = mercury_argc;
|
|
Args = MR_list_empty_msg(MR_ALLOC_ID);
|
|
while (--i >= 0) {
|
|
Args = MR_string_list_cons_msg((MR_Word) mercury_argv[i], Args,
|
|
MR_ALLOC_ID);
|
|
}
|
|
}").
|
|
|
|
:- pragma foreign_proc("C#",
|
|
command_line_arguments(Args::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
string[] arg_vector = System.Environment.GetCommandLineArgs();
|
|
int i = arg_vector.Length;
|
|
Args = list.empty_list();
|
|
// We don't get the 0th argument: it is the executable name.
|
|
while (--i > 0) {
|
|
Args = list.cons(arg_vector[i], Args);
|
|
}
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
command_line_arguments(Args::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, thread_safe, may_not_duplicate],
|
|
"
|
|
String[] arg_vector = jmercury.runtime.JavaInternal.args;
|
|
Args = list.empty_list();
|
|
// The argument vector may not be set if Mercury is being used
|
|
// as a library by a native Java application.
|
|
if (arg_vector != null) {
|
|
// arg_vector does not include the executable name.
|
|
for (int i = arg_vector.length - 1; i >= 0; --i) {
|
|
Args = list.cons(arg_vector[i], Args);
|
|
}
|
|
}
|
|
").
|
|
|
|
%---------------------%
|
|
|
|
:- pragma foreign_proc("C",
|
|
get_exit_status(ExitStatus::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
ExitStatus = mercury_exit_status;
|
|
").
|
|
|
|
:- pragma foreign_proc("C#",
|
|
get_exit_status(ExitStatus::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
ExitStatus = System.Environment.ExitCode;
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
get_exit_status(ExitStatus::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, may_not_duplicate],
|
|
"
|
|
ExitStatus = jmercury.runtime.JavaInternal.exit_status;
|
|
").
|
|
|
|
%---------------------%
|
|
|
|
:- pragma foreign_proc("C",
|
|
set_exit_status(ExitStatus::in, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
mercury_exit_status = (int) ExitStatus;
|
|
").
|
|
|
|
:- pragma foreign_proc("C#",
|
|
set_exit_status(ExitStatus::in, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
System.Environment.ExitCode = ExitStatus;
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
set_exit_status(ExitStatus::in, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, may_not_duplicate],
|
|
"
|
|
jmercury.runtime.JavaInternal.exit_status = ExitStatus;
|
|
").
|
|
|
|
%---------------------%
|
|
|
|
get_environment_var(Var, OptValue, !IO) :-
|
|
io.environment.get_environment_var(Var, OptValue, !IO).
|
|
|
|
set_environment_var(Var, Value, Res, !IO) :-
|
|
io.environment.set_environment_var(Var, Value, Res, !IO).
|
|
|
|
set_environment_var(Var, Value, !IO) :-
|
|
io.environment.set_environment_var(Var, Value, !IO).
|
|
|
|
have_set_environment_var :-
|
|
io.environment.have_set_environment_var.
|
|
|
|
get_environment_var_map(EnvVarMap, !IO) :-
|
|
io.environment.get_environment_var_map(EnvVarMap, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% System access predicates.
|
|
%
|
|
|
|
call_system(Command, Result, !IO) :-
|
|
io.call_system.call_system(Command, Result, !IO).
|
|
|
|
call_system_return_signal(Command, Result, !IO) :-
|
|
io.call_system.call_system_return_signal(Command, Result, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Managing the globals structure that Mercury attaches to the I/O state.
|
|
%
|
|
|
|
get_globals(Globals, !IO) :-
|
|
lock_globals(!IO),
|
|
unsafe_get_globals(Globals, !IO),
|
|
unlock_globals(!IO).
|
|
|
|
set_globals(Globals, !IO) :-
|
|
lock_globals(!IO),
|
|
unsafe_set_globals(Globals, !IO),
|
|
unlock_globals(!IO).
|
|
|
|
update_globals(UpdatePred, !IO) :-
|
|
promise_pure (
|
|
lock_globals(!IO),
|
|
unsafe_get_globals(Globals0, !IO),
|
|
promise_equivalent_solutions [!:IO] (
|
|
Update =
|
|
( pred(G::out) is det :-
|
|
UpdatePred(Globals0, G)
|
|
),
|
|
try(Update, UpdateResult),
|
|
(
|
|
UpdateResult = succeeded(Globals),
|
|
unsafe_set_globals(Globals, !IO),
|
|
unlock_globals(!IO)
|
|
;
|
|
% If the update operation threw an exception
|
|
% then release the lock and rethrow the exception.
|
|
UpdateResult = exception(_),
|
|
impure io.unlock_globals,
|
|
rethrow(UpdateResult)
|
|
)
|
|
)
|
|
).
|
|
|
|
:- pred lock_globals(io::di, io::uo) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
lock_globals(_IO0::di, _IO::uo),
|
|
[promise_pure, will_not_call_mercury, thread_safe, tabled_for_io,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
#ifdef MR_THREAD_SAFE
|
|
MR_LOCK(&ML_io_user_globals_lock, \"io.lock_globals/2\");
|
|
#endif
|
|
").
|
|
|
|
% For the non-C backends.
|
|
lock_globals(!IO).
|
|
|
|
:- pred unlock_globals(io::di, io::uo) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
unlock_globals(_IO0::di, _IO::uo),
|
|
[promise_pure, will_not_call_mercury, thread_safe, tabled_for_io,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
#ifdef MR_THREAD_SAFE
|
|
MR_UNLOCK(&ML_io_user_globals_lock, \"io.unlock_globals/2\");
|
|
#endif
|
|
").
|
|
|
|
% For the non-C backends.
|
|
unlock_globals(!IO).
|
|
|
|
:- impure pred unlock_globals is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
unlock_globals,
|
|
[will_not_call_mercury, thread_safe,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
#ifdef MR_THREAD_SAFE
|
|
MR_UNLOCK(&ML_io_user_globals_lock, \"io.unlock_globals/2\");
|
|
#endif
|
|
").
|
|
|
|
% For the non-C backends.
|
|
unlock_globals :-
|
|
impure impure_true.
|
|
|
|
%---------------------%
|
|
|
|
% NOTE: io.unsafe_{get, set}_globals/3 are marked as thread_safe so that
|
|
% calling them to does not acquire the global lock. Since calls to these
|
|
% predicates should be surrounded by calls to io.{lock, unlock}_globals/2,
|
|
% this is safe.
|
|
%
|
|
:- pred unsafe_get_globals(univ::out, io::di, io::uo) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
unsafe_get_globals(Globals::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
|
|
does_not_affect_liveness],
|
|
"
|
|
Globals = ML_io_user_globals;
|
|
").
|
|
|
|
:- pragma foreign_proc("C#",
|
|
unsafe_get_globals(Globals::out, _IOState0::di, _IOState::uo),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
Globals = io.ML_io_user_globals;
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
unsafe_get_globals(Globals::out, _IOState0::di, _IOState::uo),
|
|
[will_not_call_mercury, promise_pure, may_not_duplicate],
|
|
"
|
|
Globals = io.ML_io_user_globals;
|
|
").
|
|
|
|
%---------------------%
|
|
|
|
:- pred unsafe_set_globals(univ::in, io::di, io::uo) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
unsafe_set_globals(Globals::in, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
// XXX need to globalize the memory.
|
|
ML_io_user_globals = Globals;
|
|
").
|
|
|
|
:- pragma foreign_proc("C#",
|
|
unsafe_set_globals(Globals::in, _IOState0::di, _IOState::uo),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
io.ML_io_user_globals = Globals;
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
unsafe_set_globals(Globals::in, _IOState0::di, _IOState::uo),
|
|
[will_not_call_mercury, promise_pure, may_not_duplicate],
|
|
"
|
|
io.ML_io_user_globals = Globals;
|
|
").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Predicates that report statistics about the current program execution.
|
|
%
|
|
|
|
report_stats(Stream, Selector, !IO) :-
|
|
benchmarking.report_stats(Stream, Selector, !IO).
|
|
|
|
report_stats(Selector, !IO) :-
|
|
benchmarking.report_stats(Selector, !IO).
|
|
|
|
%---------------------%
|
|
|
|
report_standard_stats(Stream, !IO) :-
|
|
benchmarking.report_standard_stats(Stream, !IO).
|
|
|
|
report_standard_stats(!IO) :-
|
|
benchmarking.report_standard_stats(!IO).
|
|
|
|
%---------------------%
|
|
|
|
report_full_memory_stats(Stream, !IO) :-
|
|
benchmarking.report_full_memory_stats(Stream, !IO).
|
|
|
|
report_full_memory_stats(!IO) :-
|
|
benchmarking.report_full_memory_stats(!IO).
|
|
|
|
%---------------------%
|
|
|
|
report_tabling_statistics(Stream, !IO) :-
|
|
benchmarking.report_tabling_statistics(Stream, !IO).
|
|
|
|
report_tabling_statistics(!IO) :-
|
|
benchmarking.report_tabling_statistics(!IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Interpreting I/O error messages.
|
|
%
|
|
|
|
:- type io.error
|
|
---> io_error_string(string)
|
|
; io_error_errno(string, system_error)
|
|
; io_error_win32(string, system_error)
|
|
; io_error_exception_object(string, system_error).
|
|
|
|
make_io_error(Error) = io_error_string(Error).
|
|
|
|
make_io_error_from_system_error(Error, Prefix, IOError, !IO) :-
|
|
io.error_util.make_io_error_from_system_error_impl(Error, Prefix, IOError,
|
|
!IO).
|
|
|
|
make_io_error_from_windows_error(Error, Prefix, IOError, !IO) :-
|
|
io.error_util.make_io_error_from_windows_error_impl(Error, Prefix, IOError,
|
|
!IO).
|
|
|
|
%---------------------%
|
|
|
|
error_message(Error) = Msg :-
|
|
error_message(Error, Msg).
|
|
|
|
error_message(Error, Msg) :-
|
|
( Error = io_error_string(Msg)
|
|
; Error = io_error_errno(Msg, _)
|
|
; Error = io_error_win32(Msg, _)
|
|
; Error = io_error_exception_object(Msg, _)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
get_system_error(Error, SystemError) :-
|
|
require_complete_switch [Error]
|
|
( Error = io_error_string(_), fail
|
|
; Error = io_error_errno(_, SystemError)
|
|
; Error = io_error_win32(_, SystemError)
|
|
; Error = io_error_exception_object(_, SystemError)
|
|
).
|
|
|
|
get_errno_error(Error, Errno) :-
|
|
Error = io_error_errno(_, Errno).
|
|
|
|
get_windows_error(Error, ErrorCode) :-
|
|
Error = io_error_win32(_, ErrorCode).
|
|
|
|
get_exception_object_error(Error, Exception) :-
|
|
Error = io_error_exception_object(_, Exception).
|
|
|
|
%---------------------%
|
|
|
|
get_system_error_name(Error, Name) :-
|
|
require_complete_switch [Error]
|
|
(
|
|
Error = io_error_string(_),
|
|
fail
|
|
;
|
|
Error = io_error_errno(_, Errno),
|
|
system_error_errno_name(Errno, Name)
|
|
;
|
|
Error = io_error_win32(_, ErrorCode),
|
|
system_error_win32_error_name(ErrorCode, Name)
|
|
;
|
|
Error = io_error_exception_object(_, Exception),
|
|
system_error_exception_name(Exception, Name)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred system_error_errno_name(io.system_error::in, string::out) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
system_error_errno_name(Errno::in, Name::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe, may_not_export_body],
|
|
"
|
|
const char *str = MR_errno_name(Errno);
|
|
if (str != NULL) {
|
|
Name = (MR_String) str;
|
|
} else {
|
|
Name = MR_make_string(MR_ALLOC_ID, ""errno %d"", Errno);
|
|
}
|
|
").
|
|
|
|
system_error_errno_name(_, _) :-
|
|
error("io.system_error_errno_name: inapplicable back-end").
|
|
|
|
%---------------------%
|
|
|
|
:- pred system_error_win32_error_name(io.system_error::in, string::out) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
system_error_win32_error_name(ErrorCode::in, Name::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe, may_not_export_body],
|
|
"
|
|
#ifdef MR_WIN32
|
|
const char *suffix = MR_win32_error_name(ErrorCode);
|
|
if (suffix != NULL) {
|
|
const char prefix[6] = ""ERROR_"";
|
|
size_t prefix_len;
|
|
size_t suffix_len;
|
|
|
|
prefix_len = sizeof(prefix);
|
|
suffix_len = strlen(suffix);
|
|
MR_allocate_aligned_string_msg(Name, prefix_len + suffix_len,
|
|
MR_ALLOC_ID);
|
|
MR_memcpy(Name, prefix, prefix_len);
|
|
MR_memcpy(Name + prefix_len, suffix, suffix_len + 1); // include NUL
|
|
} else {
|
|
Name = MR_make_string(MR_ALLOC_ID, ""System error 0x%X"", ErrorCode);
|
|
}
|
|
#else
|
|
MR_fatal_error(""io.system_error_win32_error_name: not on Windows"");
|
|
#endif
|
|
").
|
|
|
|
system_error_win32_error_name(_, _) :-
|
|
error("io.system_error_win32_error_name: inapplicable back-end").
|
|
|
|
%---------------------%
|
|
|
|
:- pred system_error_exception_name(io.system_error::in, string::out) is det.
|
|
:- pragma no_determinism_warning(pred(system_error_exception_name/2)).
|
|
|
|
:- pragma foreign_proc("C#",
|
|
system_error_exception_name(Exception::in, Name::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe, may_not_export_body],
|
|
"
|
|
if (Exception == null) {
|
|
Name = ""null"";
|
|
} else {
|
|
Name = Exception.GetType().FullName;
|
|
}
|
|
").
|
|
:- pragma foreign_proc("Java",
|
|
system_error_exception_name(Exception::in, Name::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe, may_not_export_body],
|
|
"
|
|
if (Exception == null) {
|
|
Name = ""null"";
|
|
} else {
|
|
Name = Exception.getClass().getName();
|
|
}
|
|
").
|
|
|
|
system_error_exception_name(_, _) :-
|
|
error("io.system_error_exception_name: inapplicable back-end").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pragma inline(pred(system_error_is_success/1)).
|
|
:- pragma foreign_proc("C",
|
|
system_error_is_success(Error::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
// This works for errno and Win32 error values (ERROR_SUCCESS == 0).
|
|
SUCCESS_INDICATOR = (Error == 0) ? MR_TRUE : MR_FALSE;
|
|
").
|
|
|
|
:- pragma foreign_proc("C#",
|
|
system_error_is_success(Error::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR = (Error == null);
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
system_error_is_success(Error::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR = (Error == null);
|
|
").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% For use by library.m.
|
|
%
|
|
|
|
init_state(!IO) :-
|
|
init_std_streams(!IO),
|
|
init_current_streams(!IO),
|
|
io.gc_init(type_of(StreamDb), type_of(Globals), !IO),
|
|
map.init(StreamDb),
|
|
type_to_univ("<globals>", Globals),
|
|
io.stream_db.set_stream_db(StreamDb, !IO),
|
|
io.set_globals(Globals, !IO),
|
|
io.insert_std_stream_names(!IO).
|
|
|
|
:- pred init_std_streams(io::di, io::uo) is det.
|
|
|
|
init_std_streams(!IO).
|
|
|
|
:- pred init_current_streams(io::di, io::uo) is det.
|
|
|
|
init_current_streams(!IO) :-
|
|
% In C grades the "current" streams are thread-local values, so can only be
|
|
% set after the MR_Context has been initialised for the initial thread.
|
|
set_input_stream(stdin_stream, _, !IO),
|
|
set_output_stream(stdout_stream, _, !IO),
|
|
stdin_binary_stream(StdinBinary, !IO),
|
|
stdout_binary_stream(StdoutBinary, !IO),
|
|
set_binary_input_stream(StdinBinary, _, !IO),
|
|
set_binary_output_stream(StdoutBinary, _, !IO).
|
|
|
|
:- pragma foreign_proc("C#",
|
|
init_current_streams(_IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
// Do nothing in the C# grade -- setting the current streams is handled
|
|
// during class initialization.
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
init_current_streams(_IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
// Do nothing in the Java grade -- setting the current streams is handled
|
|
// during class initialization.
|
|
").
|
|
|
|
:- pred gc_init(type_desc::in, type_desc::in, io::di, io::uo) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
gc_init(StreamDbType::in, UserGlobalsType::in, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, not_thread_safe, tabled_for_io,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
// For Windows DLLs, we need to call GC_INIT() from each DLL.
|
|
#ifdef MR_BOEHM_GC
|
|
GC_INIT();
|
|
#endif
|
|
MR_add_root(&ML_io_stream_db, (MR_TypeInfo) StreamDbType);
|
|
MR_add_root(&ML_io_user_globals, (MR_TypeInfo) UserGlobalsType);
|
|
").
|
|
|
|
gc_init(_, _, !IO).
|
|
|
|
:- pred insert_std_stream_names(io::di, io::uo) is det.
|
|
|
|
insert_std_stream_names(!IO) :-
|
|
stdin_stream(text_input_stream(Stdin), !IO),
|
|
insert_stream_info(Stdin, stream(0, input, preopen, stdin), !IO),
|
|
stdout_stream(text_output_stream(Stdout), !IO),
|
|
insert_stream_info(Stdout, stream(1, output, preopen, stdout), !IO),
|
|
stderr_stream(text_output_stream(Stderr), !IO),
|
|
insert_stream_info(Stderr, stream(1, output, preopen, stderr), !IO).
|
|
|
|
% Currently no finalization needed...
|
|
% (Perhaps we should close all open Mercury files?
|
|
% That will happen on process exit anyway, so currently we don't bother.)
|
|
finalize_state(!IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% For use by dir.m.
|
|
%
|
|
|
|
:- pragma foreign_proc("C",
|
|
have_win32,
|
|
[will_not_call_mercury, promise_pure, thread_safe,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
#if defined(MR_WIN32)
|
|
SUCCESS_INDICATOR = MR_TRUE;
|
|
#else
|
|
SUCCESS_INDICATOR = MR_FALSE;
|
|
#endif
|
|
").
|
|
|
|
have_win32 :-
|
|
semidet_fail.
|
|
|
|
:- pragma foreign_proc("C",
|
|
have_cygwin,
|
|
[will_not_call_mercury, promise_pure, thread_safe,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
#if defined(MR_CYGWIN)
|
|
SUCCESS_INDICATOR = MR_TRUE;
|
|
#else
|
|
SUCCESS_INDICATOR = MR_FALSE;
|
|
#endif
|
|
").
|
|
|
|
have_cygwin :-
|
|
semidet_fail.
|
|
|
|
:- pragma foreign_proc("C#",
|
|
have_dotnet,
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR = true;
|
|
").
|
|
|
|
have_dotnet :-
|
|
semidet_fail.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type file_id
|
|
---> file_id.
|
|
|
|
:- pragma foreign_type("C", file_id, "ML_File_Id")
|
|
where comparison is compare_file_id.
|
|
|
|
:- pragma foreign_decl("C", "
|
|
#ifdef MR_WIN32
|
|
#include <wchar.h> // for dev_t, ino_t
|
|
#endif
|
|
|
|
#ifdef MR_HAVE_DEV_T
|
|
typedef dev_t ML_dev_t;
|
|
#else
|
|
typedef MR_Integer ML_dev_t;
|
|
#endif
|
|
|
|
#ifdef MR_HAVE_INO_T
|
|
typedef ino_t ML_ino_t;
|
|
#else
|
|
typedef MR_Integer ML_ino_t;
|
|
#endif
|
|
|
|
typedef struct {
|
|
ML_dev_t device;
|
|
ML_ino_t inode;
|
|
} ML_File_Id;
|
|
").
|
|
|
|
:- pred compare_file_id(comparison_result::uo, file_id::in, file_id::in)
|
|
is det.
|
|
:- pragma consider_used(pred(compare_file_id/3)).
|
|
|
|
compare_file_id(Result, FileId1, FileId2) :-
|
|
compare_file_id_2(Result0, FileId1, FileId2),
|
|
( if Result0 < 0 then
|
|
Result = (<)
|
|
else if Result0 = 0 then
|
|
Result = (=)
|
|
else
|
|
Result = (>)
|
|
).
|
|
|
|
:- pred compare_file_id_2(int::out, file_id::in, file_id::in) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
compare_file_id_2(Res::out, FileId1::in, FileId2::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
int device_cmp;
|
|
int inode_cmp;
|
|
|
|
// For compilers other than GCC, glibc defines dev_t as struct (dev_t
|
|
// is 64 bits, and other compilers may not have a 64-bit arithmetic type).
|
|
// XXX This code assumes that dev_t and ino_t do not include padding bits.
|
|
// In practice, that should be OK.
|
|
device_cmp = memcmp(&(FileId1.device), &(FileId2.device),
|
|
sizeof(ML_dev_t));
|
|
|
|
if (device_cmp < 0) {
|
|
Res = -1;
|
|
} else if (device_cmp > 0) {
|
|
Res = 1;
|
|
} else {
|
|
inode_cmp = memcmp(&(FileId1.inode), &(FileId2.inode),
|
|
sizeof(ML_ino_t));
|
|
if (inode_cmp < 0) {
|
|
Res = -1;
|
|
} else if (inode_cmp > 0) {
|
|
Res = 1;
|
|
} else {
|
|
Res = 0;
|
|
}
|
|
}
|
|
").
|
|
|
|
compare_file_id_2(_, _, _) :-
|
|
unexpected($pred, "File IDs are not supported by Java").
|
|
|
|
file_id(FileName, Result, !IO) :-
|
|
file_id_2(FileName, FileId, Error, !IO),
|
|
is_error(Error, "cannot get file id: ", MaybeIOError, !IO),
|
|
(
|
|
MaybeIOError = yes(IOError),
|
|
Result = error(IOError)
|
|
;
|
|
MaybeIOError = no,
|
|
Result = ok(FileId)
|
|
).
|
|
|
|
:- pred file_id_2(string::in, file_id::out, system_error::out, io::di, io::uo)
|
|
is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
file_id_2(FileName::in, FileId::out, Error::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
|
|
does_not_affect_liveness, no_sharing],
|
|
"
|
|
// Win32 returns junk in the st_ino field of `struct stat'.
|
|
#if defined(MR_HAVE_STAT) && !defined(MR_WIN32)
|
|
struct stat s;
|
|
int stat_result = stat(FileName, &s);
|
|
|
|
if (stat_result == 0) {
|
|
FileId.device = s.st_dev;
|
|
FileId.inode = s.st_ino;
|
|
Error = 0;
|
|
} else {
|
|
Error = errno;
|
|
}
|
|
#else
|
|
Error = ENOSYS;
|
|
#endif
|
|
").
|
|
|
|
:- pragma foreign_proc("C#",
|
|
file_id_2(_FileName::in, _FileId::out, Error::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Error = new System.NotSupportedException(
|
|
""io.file_id not supported on this platform"");
|
|
").
|
|
|
|
:- pragma foreign_proc("Java",
|
|
file_id_2(_FileName::in, _FileId::out, Error::out, _IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Error = new java.lang.UnsupportedOperationException(
|
|
""io.file_id not supported on this platform"");
|
|
").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% For use by bitmap.m.
|
|
%
|
|
|
|
input_stream_get_stream(text_input_stream(Stream)) = Stream.
|
|
output_stream_get_stream(text_output_stream(Stream)) = Stream.
|
|
binary_input_stream_get_stream(binary_input_stream(Stream)) = Stream.
|
|
binary_output_stream_get_stream(binary_output_stream(Stream)) = Stream.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Predicates to temporarily change the input/output stream.
|
|
% XXX We should not need these if we passed streams explicitly everywhere.
|
|
%
|
|
|
|
:- pred with_output_stream(text_output_stream, pred(io, io), io, io).
|
|
:- mode with_output_stream(in, in(pred(di, uo) is det),
|
|
di, uo) is det.
|
|
:- mode with_output_stream(in, in(pred(di, uo) is cc_multi),
|
|
di, uo) is cc_multi.
|
|
|
|
with_output_stream(Stream, Pred, !IO) :-
|
|
set_output_stream(Stream, OrigStream, !IO),
|
|
finally(call_pred_no_result(Pred), _Result,
|
|
restore_output_stream(Pred, OrigStream), _CleanupRes, !IO).
|
|
|
|
:- pred call_pred_no_result(pred(io, io), {}, io, io).
|
|
:- mode call_pred_no_result(in(pred(di, uo) is det),
|
|
out, di, uo) is det.
|
|
:- mode call_pred_no_result(in(pred(di, uo) is cc_multi),
|
|
out, di, uo) is cc_multi.
|
|
|
|
call_pred_no_result(Pred, {}, !IO) :-
|
|
Pred(!IO).
|
|
|
|
:- pred restore_output_stream(pred(io, io),
|
|
text_output_stream, io.res, io, io).
|
|
:- mode restore_output_stream(in(pred(di, uo) is det),
|
|
in, out, di, uo) is det.
|
|
:- mode restore_output_stream(in(pred(di, uo) is cc_multi),
|
|
in, out, di, uo) is cc_multi.
|
|
:- pragma no_determinism_warning(pred(restore_output_stream/5)).
|
|
|
|
restore_output_stream(_DummyPred, Stream, ok, !IO) :-
|
|
set_output_stream(Stream, _OldStream, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Instances of the stream typeclasses.
|
|
%
|
|
|
|
:- instance stream.error(error) where [
|
|
func(stream.error_message/1) is io.error_message
|
|
].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Text input streams.
|
|
%
|
|
|
|
:- instance stream.stream(text_input_stream, io) where [
|
|
pred(name/4) is input_stream_name
|
|
].
|
|
|
|
:- instance stream.input(text_input_stream, io) where [].
|
|
|
|
:- instance stream.line_oriented(text_input_stream, io) where
|
|
[
|
|
pred(get_line/4) is io.get_line_number,
|
|
pred(set_line/4) is io.set_line_number
|
|
].
|
|
|
|
%---------------------%
|
|
|
|
:- instance stream.reader(text_input_stream, char, io, io.error)
|
|
where
|
|
[
|
|
pred(get/4) is stream_read_char
|
|
].
|
|
|
|
:- instance stream.reader(text_input_stream, line, io, io.error)
|
|
where
|
|
[
|
|
pred(get/4) is stream_read_line_as_string
|
|
].
|
|
|
|
:- instance stream.reader(text_input_stream, text_file, io, io.error)
|
|
where
|
|
[
|
|
pred(get/4) is stream_read_file_as_string
|
|
].
|
|
|
|
%---------------------%
|
|
|
|
:- instance stream.unboxed_reader(text_input_stream, char, io, io.error)
|
|
where
|
|
[
|
|
pred(unboxed_get/5) is stream_read_char_unboxed
|
|
].
|
|
|
|
%---------------------%
|
|
|
|
:- instance stream.putback(text_input_stream, char, io, io.error) where
|
|
[
|
|
pred(unget/4) is putback_char
|
|
].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Binary input streams.
|
|
%
|
|
|
|
:- instance stream.stream(binary_input_stream, io)
|
|
where
|
|
[
|
|
pred(name/4) is binary_input_stream_name
|
|
].
|
|
|
|
:- instance stream.input(binary_input_stream, io)
|
|
where [].
|
|
|
|
:- instance stream.seekable(binary_input_stream, io)
|
|
where
|
|
[
|
|
pred(seek/5) is stream_seek_binary_input,
|
|
pred(seek64/5) is stream_seek_binary_input64
|
|
].
|
|
|
|
%---------------------%
|
|
|
|
:- instance stream.reader(binary_input_stream, int, io, io.error)
|
|
where
|
|
[
|
|
pred(get/4) is stream_read_byte
|
|
].
|
|
|
|
:- instance stream.reader(binary_input_stream, int8, io, io.error)
|
|
where
|
|
[
|
|
pred(get/4) is stream_read_binary_int8
|
|
].
|
|
|
|
:- instance stream.reader(binary_input_stream, uint8, io, io.error)
|
|
where
|
|
[
|
|
pred(get/4) is stream_read_binary_uint8
|
|
].
|
|
|
|
%---------------------%
|
|
|
|
:- instance stream.unboxed_reader(binary_input_stream, int8, io, io.error)
|
|
where
|
|
[
|
|
pred(unboxed_get/5) is stream_read_binary_int8_unboxed
|
|
].
|
|
|
|
:- instance stream.unboxed_reader(binary_input_stream, uint8, io, io.error)
|
|
where
|
|
[
|
|
pred(unboxed_get/5) is stream_read_binary_uint8_unboxed
|
|
].
|
|
|
|
%---------------------%
|
|
|
|
:- instance stream.putback(binary_input_stream, int, io, io.error)
|
|
where
|
|
[
|
|
pred(unget/4) is putback_byte
|
|
].
|
|
|
|
:- instance stream.putback(binary_input_stream, int8, io, io.error)
|
|
where
|
|
[
|
|
pred(unget/4) is putback_int8
|
|
].
|
|
|
|
:- instance stream.putback(binary_input_stream, uint8, io, io.error)
|
|
where
|
|
[
|
|
pred(unget/4) is putback_uint8
|
|
].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Text output streams.
|
|
%
|
|
|
|
:- instance stream.stream(text_output_stream, io) where [
|
|
pred(name/4) is output_stream_name
|
|
].
|
|
|
|
:- instance stream.output(text_output_stream, io) where [
|
|
pred(flush/3) is flush_output
|
|
].
|
|
|
|
:- instance stream.line_oriented(text_output_stream, io) where
|
|
[
|
|
pred(get_line/4) is get_output_line_number,
|
|
pred(set_line/4) is set_output_line_number
|
|
].
|
|
|
|
%---------------------%
|
|
|
|
:- instance stream.writer(text_output_stream, char, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_char
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, float, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_float
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, int, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_int
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, int8, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_int8
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, int16, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_int16
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, int32, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_int32
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, int64, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_int64
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, uint, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_uint
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, uint8, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_uint8
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, uint16, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_uint16
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, uint32, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_uint32
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, uint64, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_uint64
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, string, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_string
|
|
].
|
|
|
|
:- instance stream.writer(text_output_stream, univ, io)
|
|
where
|
|
[
|
|
pred(put/4) is stream.string_writer.write_univ
|
|
].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Binary output streams.
|
|
%
|
|
|
|
:- instance stream.stream(binary_output_stream, io)
|
|
where
|
|
[
|
|
pred(name/4) is binary_output_stream_name
|
|
].
|
|
|
|
:- instance stream.output(binary_output_stream, io)
|
|
where
|
|
[
|
|
pred(flush/3) is flush_binary_output
|
|
].
|
|
|
|
:- instance stream.seekable(binary_output_stream, io)
|
|
where
|
|
[
|
|
pred(seek/5) is stream_seek_binary_output,
|
|
pred(seek64/5) is stream_seek_binary_output64
|
|
].
|
|
|
|
%---------------------%
|
|
|
|
:- instance stream.writer(binary_output_stream, byte, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_byte
|
|
].
|
|
|
|
:- instance stream.writer(binary_output_stream, int8, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_binary_int8
|
|
].
|
|
|
|
:- instance stream.writer(binary_output_stream, uint8, io)
|
|
where
|
|
[
|
|
pred(put/4) is write_binary_uint8
|
|
].
|
|
|
|
%---------------------%
|
|
%
|
|
% Functions used only by concrete instance methods.
|
|
%
|
|
|
|
:- func result1_to_stream_result1(io.result(T)) = stream.result(T, io.error).
|
|
|
|
result1_to_stream_result1(ok(T)) = ok(T).
|
|
result1_to_stream_result1(eof) = eof.
|
|
result1_to_stream_result1(error(Error)) = error(Error).
|
|
|
|
:- func result0_to_stream_result0(io.result) = stream.result(io.error).
|
|
|
|
result0_to_stream_result0(ok) = ok.
|
|
result0_to_stream_result0(eof) = eof.
|
|
result0_to_stream_result0(error(Error)) = error(Error).
|
|
|
|
:- func stream_whence_to_io_whence(stream.whence) = io.whence.
|
|
|
|
stream_whence_to_io_whence(set) = set.
|
|
stream_whence_to_io_whence(cur) = cur.
|
|
stream_whence_to_io_whence(end) = end.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Error handling.
|
|
%
|
|
% The predicates interpreting result codes ought to stay in io.m,
|
|
% because moving them to e.g. io.error_util.m would prevent them
|
|
% from being inlined into their call sites above at low optimization levels,
|
|
% and some of those call sites (e.g. in read_char) can be expected to be
|
|
% heavily used in some programs.
|
|
%
|
|
|
|
:- type result_code
|
|
---> result_code_ok
|
|
; result_code_eof
|
|
; result_code_error.
|
|
|
|
:- pragma foreign_export_enum("C", result_code/0,
|
|
[prefix("ML_"), uppercase]).
|
|
:- pragma foreign_export_enum("C#", result_code/0,
|
|
[prefix("ML_"), uppercase]).
|
|
:- pragma foreign_export_enum("Java", result_code/0,
|
|
[prefix("ML_"), uppercase]).
|
|
|
|
:- pred interpret_result_code0(result_code::in, system_error::in,
|
|
io.result::out, io::di, io::uo) is det.
|
|
:- pragma inline(pred(interpret_result_code0/5)).
|
|
|
|
interpret_result_code0(ResultCode, Error, Result, !IO) :-
|
|
(
|
|
ResultCode = result_code_ok,
|
|
Result = ok
|
|
;
|
|
ResultCode = result_code_eof,
|
|
Result = eof
|
|
;
|
|
ResultCode = result_code_error,
|
|
make_io_error_from_system_error(Error, "read failed: ", IOError, !IO),
|
|
Result = error(IOError)
|
|
).
|
|
|
|
:- pred interpret_result_code1(result_code::in, system_error::in,
|
|
T::in, io.result(T)::out, io::di, io::uo) is det.
|
|
:- pragma inline(pred(interpret_result_code1/6)).
|
|
|
|
interpret_result_code1(ResultCode, Error, Value, Result, !IO) :-
|
|
(
|
|
ResultCode = result_code_ok,
|
|
Result = ok(Value)
|
|
;
|
|
ResultCode = result_code_eof,
|
|
Result = eof
|
|
;
|
|
ResultCode = result_code_error,
|
|
make_io_error_from_system_error(Error, "read failed: ", IOError, !IO),
|
|
Result = error(IOError)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- type maybe_incomplete_result_code
|
|
---> mirc_ok
|
|
; mirc_eof
|
|
; mirc_incomplete
|
|
; mirc_error.
|
|
|
|
:- pragma foreign_export_enum("C", maybe_incomplete_result_code/0,
|
|
[prefix("ML_"), uppercase]).
|
|
:- pragma foreign_export_enum("C#", maybe_incomplete_result_code/0,
|
|
[prefix("ML_"), uppercase]).
|
|
:- pragma foreign_export_enum("Java", maybe_incomplete_result_code/0,
|
|
[prefix("ML_"), uppercase]).
|
|
|
|
:- pred interpret_maybe_incomplete_result_code(
|
|
maybe_incomplete_result_code::in, system_error::in, list(uint8)::in,
|
|
T::in, maybe_incomplete_result(T)::out, io::di, io::uo) is det.
|
|
:- pragma inline(pred(interpret_maybe_incomplete_result_code/7)).
|
|
|
|
interpret_maybe_incomplete_result_code(ResultCode, Error, IncompleteBytes,
|
|
Value, Result, !IO) :-
|
|
(
|
|
ResultCode = mirc_ok,
|
|
Result = ok(Value)
|
|
;
|
|
ResultCode = mirc_eof,
|
|
Result = eof
|
|
;
|
|
ResultCode = mirc_incomplete,
|
|
Result = incomplete(IncompleteBytes)
|
|
;
|
|
ResultCode = mirc_error,
|
|
make_io_error_from_system_error(Error, "read failed: ", IOError, !IO),
|
|
Result = error(IOError)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pragma foreign_decl("C", "
|
|
#ifdef MR_HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef MR_HAVE_SYS_STAT_H
|
|
#include <sys/stat.h>
|
|
#endif
|
|
#include ""mercury_types.h"" // for MR_Integer
|
|
#include ""mercury_library_types.h"" // for MercuryFilePtr
|
|
#include ""mercury_int.h"" // for MR_*_reverse_bytes
|
|
|
|
#include ""mercury_init.h""
|
|
#include ""mercury_wrapper.h""
|
|
#include ""mercury_type_info.h""
|
|
#include ""mercury_errno_name.h""
|
|
#include ""mercury_file.h""
|
|
#include ""mercury_heap.h""
|
|
#include ""mercury_misc.h""
|
|
#include ""mercury_runtime_util.h""
|
|
#include ""mercury_report_stats.h""
|
|
#include ""mercury_windows_error_name.h""
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <limits.h>
|
|
|
|
#ifdef MR_HAVE_SYS_WAIT_H
|
|
#include <sys/wait.h> // for WIFEXITED, WEXITSTATUS, etc.
|
|
#endif
|
|
|
|
#ifdef MR_WIN32
|
|
#include ""mercury_windows.h""
|
|
#endif
|
|
|
|
extern MR_Word ML_io_user_globals;
|
|
#ifdef MR_THREAD_SAFE
|
|
extern MercuryLock ML_io_user_globals_lock;
|
|
#endif
|
|
|
|
#if 0
|
|
extern MR_Word ML_io_ops_table;
|
|
#endif
|
|
|
|
void mercury_init_io(void);
|
|
|
|
").
|
|
|
|
:- pragma foreign_code("C", "
|
|
MR_Word ML_io_user_globals;
|
|
#ifdef MR_THREAD_SAFE
|
|
MercuryLock ML_io_user_globals_lock;
|
|
#endif
|
|
|
|
#if 0
|
|
MR_Word ML_io_ops_table;
|
|
#endif
|
|
|
|
static void
|
|
mercury_set_binary_mode(FILE *f)
|
|
{
|
|
#if defined(MR_MSVC) || defined(MR_MINGW)
|
|
// Calling fdopen with 'b' in the mode string does not necessarily put the
|
|
// standard input or standard output file into binary translation mode on
|
|
// Windows. This is the case with MinGW and MSVC. The cause is likely the
|
|
// MSVC CRT. The solution is to change the mode on the file after opening.
|
|
_setmode(_fileno(f), _O_BINARY);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
mercury_init_io(void)
|
|
{
|
|
MR_mercuryfile_init(stdin, 1, &mercury_stdin);
|
|
MR_mercuryfile_init(stdout, 1, &mercury_stdout);
|
|
MR_mercuryfile_init(stderr, 1, &mercury_stderr);
|
|
|
|
MR_mercuryfile_init(NULL, 1, &mercury_stdin_binary);
|
|
MR_mercuryfile_init(NULL, 1, &mercury_stdout_binary);
|
|
|
|
mercury_current_text_input_index = MR_new_thread_local_mutable_index();
|
|
mercury_current_text_output_index = MR_new_thread_local_mutable_index();
|
|
mercury_current_binary_input_index = MR_new_thread_local_mutable_index();
|
|
mercury_current_binary_output_index = MR_new_thread_local_mutable_index();
|
|
|
|
#if defined(MR_HAVE_FDOPEN) && (defined(MR_HAVE_FILENO) || defined(fileno)) \
|
|
&& defined(MR_HAVE_DUP)
|
|
MR_file(mercury_stdin_binary) = fdopen(dup(fileno(stdin)), ""rb"");
|
|
if (MR_file(mercury_stdin_binary) != NULL) {
|
|
mercury_set_binary_mode(MR_file(mercury_stdin_binary));
|
|
} else {
|
|
// The call to fdopen() may fail if stdin is not available.
|
|
// We don't abort since we still want Mercury programs to be runnable
|
|
// in such a circumstance (aside from those that use stdin).
|
|
// For the same reason, we treat binary stdout identically below.
|
|
//
|
|
// NOTE: some versions of nohup may also cause the above call to
|
|
// fdopen() to fail, because they redirect stdin to /dev/null
|
|
// in *write* mode. Setting binary stdin to stdin in such a case
|
|
// also ensures that we work with those versions of nohup.
|
|
MR_file(mercury_stdin_binary) = stdin;
|
|
}
|
|
|
|
MR_file(mercury_stdout_binary) = fdopen(dup(fileno(stdout)), ""wb"");
|
|
if (MR_file(mercury_stdout_binary) != NULL) {
|
|
mercury_set_binary_mode(MR_file(mercury_stdout_binary));
|
|
} else {
|
|
MR_file(mercury_stdout_binary) = stdout;
|
|
}
|
|
#else
|
|
// XXX Standard ANSI/ISO C provides no way to set stdin/stdout
|
|
// to binary mode. I guess we just have to punt...
|
|
MR_file(mercury_stdin_binary) = stdin;
|
|
MR_file(mercury_stdout_binary) = stdout;
|
|
#endif
|
|
|
|
#ifdef MR_THREAD_SAFE
|
|
pthread_mutex_init(&ML_io_stream_db_lock, MR_MUTEX_ATTR);
|
|
pthread_mutex_init(&ML_io_user_globals_lock, MR_MUTEX_ATTR);
|
|
pthread_mutex_init(&ML_io_next_stream_id_lock, MR_MUTEX_ATTR);
|
|
#endif
|
|
}
|
|
").
|
|
|
|
%---------------------%
|
|
|
|
:- pragma foreign_code("Java", "
|
|
public static univ.Univ_0 ML_io_user_globals = null;
|
|
").
|
|
|
|
%---------------------%
|
|
|
|
:- pragma foreign_code("C#", "
|
|
// The ML_ prefixes here are not really needed,
|
|
// since the C# code all gets generated inside a class,
|
|
// but we keep them for consistency with the C code.
|
|
|
|
public static univ.Univ_0 ML_io_user_globals;
|
|
").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module io.
|
|
%---------------------------------------------------------------------------%
|