SWI-Prolog provides two different packages for input and output. The native I/O system is based on the ISO standard predicates open/3, close/1 and friends.98Actually based on Quintus Prolog, providing this interface before the ISO standard existed. Being more widely portable and equipped with a clearer and more robust specification, new code is encouraged to use these predicates for manipulation of I/O streams.
Section 4.17.3 describes tell/1, see/1 and friends, providing I/O in the spirit of the traditional Edinburgh standard. These predicates are layered on top of the ISO predicates. Both packages are fully integrated; the user may switch freely between them.
Each thread has five stream aliases: user_input
,
user_output
, user_error
, current_input
,
and
current_output
. Newly created threads inherit these stream
aliases from their parent. The user_input
, user_output
and user_error
aliases of the main
thread are
initially bound to the standard operating system I/O streams (stdin,
stdout and stderr, normally bound to the POSIX file
handles 0, 1 and 2). These aliases may be re-bound, for
example if standard I/O refers to a window such as in the swipl-win.exe
GUI executable for Windows. They can be re-bound by the user using
set_prolog_IO/3
and set_stream/2
by setting the alias of a stream (e.g,
set_stream(S, alias(user_output))
). An example of rebinding
can be found in library library(prolog_server)
, providing a telnet
service. The aliases current_input
and current_output
define the source and destination for predicates that do not take a
stream argument (e.g., read/1, write/1, get_code/1,
... ). Initially, these are bound to the same stream as user_input
and
user_error
. They are re-bound by see/1, tell/1, set_input/1
and
set_output/1.
The current_output
stream is also temporary re-bound by with_output_to/2
or format/3
using e.g.,
format(atom(A), ...
. Note that code which explicitly writes
to the streams user_output
and user_error
will
not be redirected by with_output_to/2.
Compatibility
Note that the ISO standard only defines the user_*
streams. The‘current’streams can be accessed using current_input/1
and
current_output/1.
For example, an ISO compatible implementation of
write/1
is
write(Term) :- current_output(Out), write_term(Out, Term).
while SWI-Prolog additionally allows for
write(Term) :- write(current_output, Term).
The predicates described in this section provide ISO compliant I/O, where streams are explicitly created using the predicate open/3. The resulting stream identifier is then passed as a parameter to the reading and writing predicates to specify the source or destination of the data.
This schema is not vulnerable to filename and stream ambiguities as well as changes to the working directory. On the other hand, using the notion of current-I/O simplifies reusability of code without the need to pass arguments around. E.g., see with_output_to/2.
SWI-Prolog streams are, compatible with the ISO standard, either input or output streams. To accommodate portability to other systems, a pair of streams can be packed into a stream-pair. See stream_pair/3 for details.
SWI-Prolog stream handles are unique symbols that have no syntactical
representation. They are written as <stream>(hex-number)
,
which is not valid input for read/1.
They are realised using a blob of type stream
(see blob/2
and section
12.4.10).
read
, write
, append
or update
.
Mode
append
opens the file for writing, positioning the file
pointer at the end. Mode update
opens the file for writing,
positioning the file pointer at the beginning of the file without
truncating the file. Stream is either a variable, in which
case it is bound to an integer identifying the stream, or an atom, in
which case this atom will be the stream identifier.99New
code should use the alias(Alias)
option for compatibility
with the ISO standard.
SWI-Prolog also allows SrcDest to be a term pipe(Command)
.
In this form, Command is started as a child process and if
Mode is write
, output written to Stream
is sent to the standard input of Command. Vice versa, if Mode
is
read
, data written by Command to the standard
output can be read from Stream. On Unix systems, Command
is handed to
popen() which hands it to the Unix shell. On Windows, Command
is executed directly and therefore shell syntax such as redirecting
(using e.g., >
file) does not work. Use of
the
pipe(Command)
feature is deprecated. The predicate
process_create/3
from library(process)
provides a richer and more portable
alternative for interacting with processes including handling all three
standard streams.
If SrcDest is an IRI, i.e., starts with
<scheme>://
, where <scheme>
is a non-empty sequence of lowercase ASCII letters open/3,4
calls hooks registered by register_iri_scheme/3.
Currently the only predefined IRI scheme is res
, providing
access to the resource database. See
section 14.4.
The following Options are recognised by open/4:
?- open(data, read, Fd, [alias(input)]). ..., read(input, Term), ...
true
for mode read
and
false
for mode write
. See also stream_property/2
and especially section
2.18.1.1 for a discussion of this feature.full
(default) defines
full buffering, line
buffering by line, and false
implies the stream is fully unbuffered. Smaller buffering is useful if
another process or the user is waiting for the output as it is being
produced. See also flush_output/[0,1].
This option is not an ISO option.true
(default), the stream is closed on an abort (see
abort/0).
If false
, the stream is not closed. If it is an output
stream, however, it will be flushed. Useful for logfiles and if the
stream is associated to a process (using the pipe/1
construct).write
,
append
or update
mode. Currently, List
is a list of atoms that describe the permissions of the created file.100Added
after feedback from Joachim Shimpf and Per Mildner. Defined
values are below. Not recognised values are silently ignored, allowing
for adding platform specific extensions to this set.
Note that if List is empty, the created file has no
associated access permissions. The create options map to the POSIX mode
option of open(), where read
map to 0444, write
to 0222 and execute
to 0111. On POSIX systems, the final
permission is defined as (mode &
umask).~
text
is derived from the
Prolog flag encoding.
For binary
streams the default encoding is octet
.
For details on encoding issues, see section
2.18.1.eof_code
, which makes get0/1
and friends return -1, and read/1
and friends return the atom
end_of_file
. Repetitive reading keeps yielding the same
result. Action error
is like eof_code
, but
repetitive reading will raise an error. With action reset
,
Prolog will examine the file again and return more data if the file has
grown.none
,
which does not lock the file. The value read
or shared
means other processes may read the file, but not write it. The value
write
or exclusive
means no other process may
read or write the file.
Locks are acquired through the POSIX function fcntl() using
the command
F_SETLKW
, which makes a blocked call wait for the lock to
be released. Please note that fcntl() locks are advisory
and therefore only other applications using the same advisory locks
honour your lock. As there are many issues around locking in Unix,
especially related to NFS (network file system), please study the
fcntl() manual page before trusting your locks!
The lock
option is a SWI-Prolog extension.
posix
, dos
or detect
. This option
is ignored for binary streams. Using detect
on an output
stream raises an exception. See also set_stream/2.false
(default true
), drop the position
tracking logic from the stream. This disables the use of stream_position/3
on this stream.text
(default), Prolog will write a text file in
an operating system compatible way. Using type binary
the
bytes will be read or written without any translation. See also the
option encoding
.lock
option. If
false
(default true
), the open call returns
immediately with an exception if the file is locked. The exception has
the format
permission_error(lock, source_sink, SrcDest)
./dev/null
) or exploit the counting properties. The
initial encoding of Stream is utf8
, enabling
arbitrary Unicode output. The encoding can be changed to determine byte
counts of the output in a particular encoding or validate if output is
possible in a particular encoding. For example, the code below
determines the number of characters emitted when writing Term.
write_length(Term, Len) :- open_null_stream(Out), write(Out, Term), character_count(Out, Len0), close(Out), Len = Len0.
If the closed stream is the current input, output or error stream, the stream alias is bound to the initial standard I/O streams of the process. Calling close/1 on the initial standard I/O streams of the process is a no-op for an input stream and flushes an output stream without closing it.101This behaviour was defined with purely interactive usage of Prolog in mind. Applications should not count on this behaviour. Future versions may allow for closing the initial standard I/O streams.
close(Stream, [force(true)])
as the only option.
Called this way, any resource errors (such as write errors while
flushing the output buffer) are ignored.full
, line
or false
.
See also open/4.true
, a BOM (Byte Order Mark) was
detected while opening the file for reading, or a BOM was written while
opening the stream. See section
2.18.1.1 for details.F_SETFD
using the flag
FD_CLOEXEC
on Unix and (negated) HANDLE_FLAG_INHERIT
on Windows.not
, at
or past
. See
also
at_end_of_stream/[0,1].eof_code
, reset
or
error
. See open/4
for details.true
, the stream is in an error state. Applies to both
input and output streams.SWI-Stream.h
.read
.read
, write
, append
and the SWI-Prolog extension update
.posix
or dos
. If dos
, text
streams will emit \r\n
for \n
and discard \r
from input streams. Default depends on the operating system.st_nlink
.write
, append
or
update
.error
(throw
an I/O error exception), prolog
(write \x<hex>\
),
unicode
(write \uXXXX
or \UXXXXXXXX
escape sequences) or xml
(write &#...;
XML
character entity). The initial mode is unicode
for the user
streams and
error
for all other streams. See also section
2.18.1 and
set_stream/2.infinite
.text
or binary
.true
if the stream is associated with a terminal. See also set_stream/2.error
(default) or ignore
.
The latter is intended to deal with service processes for which the
standard output handles are not connected to valid streams. In these
cases write errors may be ignored on user_error
.[]
if the stream refers to some other object.
Mode is one of read
or write
.
This predicate is deprecated. New code should use the ISO predicate stream_property/2.
Stream-pairs can be used by all I/O operations on streams, where the operation selects the appropriate member of the pair. The predicate close/1 closes the still open streams of the pair.102As of version 7.1.19, it is allowed to close one of the members of the stream directly and close the pair later. The output stream is closed before the input stream. If closing the output stream results in an error, the input stream is still closed. Success is only returned if both streams were closed successfully.
position(Pos)
property. See also seek/4.position(Pos)
property.
Field is one of line_count
, line_position
,
char_count
or byte_count
. See also line_count/2,
line_position/2, character_count/2
and byte_count/2.103Introduced
in version 5.6.4 after extending the position term with a byte count.
Compatible with SICStus Prolog.bof
, current
or eof
,
indicating positioning relative to the start, current point or end of
the underlying object. NewLocation is unified with the new
offset, relative to the start of the stream.
Positions are counted in‘units’. A unit is 1 byte, except for text files using 2-byte Unicode encoding (2 bytes) or wchar encoding (sizeof(wchar_t)). The latter guarantees comfortable interaction with wide-character text objects. Otherwise, the use of seek/4 on non-binary files (see open/4) is of limited use, especially when using multi-byte text encodings (e.g. UTF-8) or multi-byte newline files (e.g. DOS/Windows). On text files, SWI-Prolog offers reliable backup to an old position using stream_property/2 and set_stream_position/2. Skipping N character codes is achieved calling get_code/2 N times or using copy_stream_data/3, directing the output to a null stream (see open_null_stream/1). If the seek modifies the current location, the line number and character position in the line are set to 0.
If the stream cannot be repositioned, a permission_error
is raised. If applying the offset would result in a file position less
than zero, a domain_error
is raised. Behaviour when seeking
to positions beyond the size of the underlying object depend on the
object and possibly the operating system. The predicate seek/4
is compatible with Quintus Prolog, though the error conditions and
signalling is ISO compliant. See also stream_property/2
and set_stream_position/2.
eof_action
only applies to the read stream,
representation_errors
only applies to the write
stream and trying to set alias
or line_position
on a pair results in a permission_error
exception. See also
stream_property/2
and open/4.
set_stream(S,
current_input)
is the same as set_input/1,
and by setting the alias of a stream to user_input
, etc.,
all user terminal input is read from this stream. See also interactor/0.full
, line
or false
.close_on_exec
property. See stream_property/2.bom
causes the stream to check whether the current
character is a Unicode BOM marker. If a BOM marker is found, the
encoding is set accordingly and the call succeeds. Otherwise the call
fails.eof_code
, reset
or
error
.position
).detect
. It will be set to dos
if a \r
character was removed.
error(timeout_error(read, Stream)
, _)
text
or binary
.
See also open/4
and the encoding
property of streams. Switching to binary
sets the encoding to octet
. Switching to
text
sets the encoding to the default text encoding.set_stream(S, record_position(true))
resets the
position the start of line 1.user_input
and
current_input
of the calling thread. Out becomes
user_output
and current_output
. If Error
equals
Out an unbuffered stream is associated to the same
destination and linked to user_error
. Otherwise Error
is used for
user_error
. Output buffering for Out is set to
line
and buffering on Error is disabled. See
also prolog/0
and set_stream/2.
The clib package provides the library library(prolog_server)
,
creating a TCP/IP server for creating an interactive session to Prolog.stdin
. Out
becomes
stdout
. If Error equals Out an
unbuffered stream is associated to the same destination and linked to stderr
.
Otherwise Error is used for stderr
. Output
buffering for
Out is set to line and buffering on Error is
disabled. The operating system I/O streams are shared across all
threads. The three streams must be related to a file descriptor
or a
domain_error
file_stream
is raised. See also
stream_property/2,
property file_no(Fd)
.
Where set_prolog_IO/3
rebinds the Prolog streams user_input
,
user_output
and user_error
for a specific
thread providing a private interactive session, set_system_IO/3
rebinds the shared console I/O and also captures Prolog kernel events
(e.g., low-level debug messages, unexpected events) as well as messages
from foreign libraries that are directly written to stdout
or
stderr
.
This predicate is intended to capture all output in situations where standard I/O is normally lost, such as when Prolog is running as a service on Windows.
The package for implicit input and output destinations is (almost) compatible with Edinburgh DEC-10 and C-Prolog. The reading and writing predicates refer to, resp., the current input and output streams. Initially these streams are connected to the terminal. The current output stream is changed using tell/1 or append/1. The current input stream is changed using see/1. The stream's current value can be obtained using telling/1 for output and seeing/1 for input.
Source and destination are either a file, user
, or a
term‘pipe(Command)’. The reserved stream name user
refers to the terminal.104The ISO
I/O layer uses user_input
, user_output
and user_error
.
In the predicate descriptions below we will call the source/destination
argument‘SrcDest’. Below are some examples of
source/destination specifications.
?- see(data). | % Start reading from file‘data’. |
?- tell(user). | % Start writing to the terminal. |
?- tell(pipe(lpr)). | % Start writing to the printer. |
Another example of using the pipe/1
construct is shown
below.105As of version 5.3.15, the
pipe construct is supported in the MS-Windows version, both for swipl.exe
and swipl-win.exe. The implementation uses code from the LUA
programming language (http://www.lua.org).
Note that the pipe/1
construct is not part of Prolog's
standard I/O repertoire.
getwd(Wd) :- seeing(Old), see(pipe(pwd)), collect_wd(String), seen, see(Old), atom_codes(Wd, String). collect_wd([C|R]) :- get0(C), C \== -1, !, collect_wd(R). collect_wd([]).
The effect of tell/1 is not undone on backtracking, and since the stream handle is not specified explicitly in further I/O operations when using Edinburgh-style I/O, you may write to unintended streams more easily than when using ISO compliant I/O. For example, the following query writes both "a" and "b" into the file‘out’:
?- (tell(out), write(a), false ; write(b)), told.
Unlike Edinburgh Prolog systems, telling/1 and seeing/1 do not return the filename of the current input/output but rather the stream identifier, to ensure the design pattern below works under all circumstances:106Filenames can be ambiguous and SWI-Prolog streams can refer to much more than just files.
..., telling(Old), tell(x), ..., told, tell(Old), ...,
The predicates tell/1
and see/1
first check for user
, the
pipe(command)
and a stream handle. Otherwise, if the
argument is an atom it is first compared to open streams associated to a
file with exactly the same name. If such a stream exists,
created using
tell/1
or see/1,
output (input) is switched to the open stream. Otherwise a file with the
specified name is opened.
The behaviour is compatible with Edinburgh Prolog. This is not without problems. Changing directory, non-file streams, and multiple names referring to the same file easily lead to unexpected behaviour. New code, especially when managing multiple I/O channels, should consider using the ISO I/O predicates defined in section 4.17.2.
user
is returned if the current input is the
stream user_input
to improve compatibility with traditional
Edinburgh I/O. See the introduction of
section 4.17.3 for details.user
is returned if the current output is the
stream user_output
to improve compatibility with
traditional Edinburgh I/O. See the introduction of
section 4.17.3 for details.user_input
.user_output
.
The predicates below can be used for switching between the implicit and the explicit stream-based I/O predicates.
open(file,
read, Stream), set_input(Stream)
is equivalent to see(file)
.
The file handling predicates may be hooked to deal with
IRIs. An IRI starts with <scheme>://
,
where <scheme> is a non-empty sequence of lowercase
ASCII letters. After detecting the scheme the file manipulation
predicates call a hook that is registered using register_iri_scheme/3.
Hooking the file operations using extensible IRI schemas allows us to place any resource that is accessed through Prolog I/O predicates on arbitrary devices such as web servers or the ZIP archive used to store program resources (see section 14.2). This is typically combined with file_search_path/2 declarations to switch between accessing a set of resources from local files, from the program resource database, from a web-server, etc.
file
) and
exists_directory/1
(Mode is directory
). The result argument must be
unified with a boolean.
For capturing other streams, see with_output_to/3.
Applications should generally avoid creating atoms by breaking and concatenating other atoms, as the creation of large numbers of intermediate atoms generally leads to poor performance, even more so in multithreaded applications. This predicate supports creating difference lists from character data efficiently. The example below defines the DCG rule term//1 to insert a term in the output:
term(Term, In, Tail) :- with_output_to(codes(In, Tail), write(Term)). ?- phrase(term(hello), X). X = [104, 101, 108, 108, 111]
Output takes one of the shapes below. Except for the
first, the system creates a temporary stream using the wchar_t
internal encoding that points at a memory buffer. The encoding cannot be
changed and an attempt to call set_stream/2
using encoding(Encoding)
results in a permission_error
exception.
The predicates in this section provide fast binary I/O of arbitrary
Prolog terms, including cyclic terms and terms holding attributed
variables. Library library(fastrw)
is a SICSTus/Ciao
compatible library that extends the core primitives described below.
The binary representation the same as used by PL_record_external(). The use of these primitives instead of using write_canonical/2 has advantages and disadvantages. Below are the main considerations: