From: Markus Triska Date: Thu, 4 Nov 2021 17:28:05 +0000 (+0100) Subject: ENHANCED: open/4 to allow opening a stream by specifying stream(S). X-Git-Tag: v0.9.0~35^2 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=afcd44deaad49a8e77094d7dac6b377e3f263f73;p=scryer-prolog.git ENHANCED: open/4 to allow opening a stream by specifying stream(S). This allows switching standard output to binary, using for example: ?- current_output(S0), open(stream(S0), write, S, [type(binary)]). format/3 can then be used to write binary data to S. This is needed for example when piping binary data to other programs. This addresses #614, please read the discussion for more information. The current implementation is very preliminary: Specifically, it works by destructively modifiying the parameters of the underlying stream, making it no longer usable in its original mode. Currently, if the type of standard output is set to binary, then the toplevel no longer works. Therefore, after writing binary output to standard output, the program should either halt, or set the stream type back to text. --- diff --git a/src/clause_types.rs b/src/clause_types.rs index a22b542e..87dbbe27 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -221,6 +221,7 @@ pub(crate) enum SystemClauseType { NumberToCodes, OpDeclaration, Open, + SetStreamOptions, NextStream, PartialStringTail, PeekByte, @@ -478,6 +479,7 @@ impl SystemClauseType { &SystemClauseType::Halt => clause_name!("$halt"), &SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"), &SystemClauseType::Open => clause_name!("$open"), + &SystemClauseType::SetStreamOptions => clause_name!("$set_stream_options"), &SystemClauseType::OpDeclaration => clause_name!("$op"), &SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"), &SystemClauseType::InstallInferenceCounter => { @@ -701,6 +703,7 @@ impl SystemClauseType { ("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes), ("$op", 3) => Some(SystemClauseType::OpDeclaration), ("$open", 7) => Some(SystemClauseType::Open), + ("$set_stream_options", 5) => Some(SystemClauseType::SetStreamOptions), ("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding), ("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck), ("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter), diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 616a2b0d..3c9c27a1 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1466,7 +1466,11 @@ open(SourceSink, Mode, Stream, StreamOptions) :- throw(error(uninstantiation_error(Stream), open/4)) % 8.11.5.3f) ; parse_stream_options(StreamOptions, [Alias, EOFAction, Reposition, Type], open/4), - '$open'(SourceSink, Mode, Stream, Alias, EOFAction, Reposition, Type) + ( SourceSink = stream(S0) -> + '$set_stream_options'(S0, Alias, EOFAction, Reposition, Type), + Stream = S0 + ; '$open'(SourceSink, Mode, Stream, Alias, EOFAction, Reposition, Type) + ) ). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 8b4d7b27..3fbab138 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3220,6 +3220,22 @@ impl MachineState { self.bind(stream_var.as_var().unwrap(), stream); } + &SystemClauseType::SetStreamOptions => { + let mut stream = self.get_stream_or_alias( + self[temp_v!(1)], + &indices.stream_aliases, + "open", + 4, + )?; + + let alias = self[temp_v!(2)]; + let eof_action = self[temp_v!(3)]; + let reposition = self[temp_v!(4)]; + let stream_type = self[temp_v!(5)]; + + let options = self.to_stream_options(alias, eof_action, reposition, stream_type); + *stream.options_mut() = options; + } &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => { self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h)) }