add close/{1,2}, better EOF action handling in read_term
This commit is contained in:
@@ -165,6 +165,7 @@ pub enum SystemClauseType {
|
|||||||
CodesToNumber,
|
CodesToNumber,
|
||||||
CopyTermWithoutAttrVars,
|
CopyTermWithoutAttrVars,
|
||||||
CheckCutPoint,
|
CheckCutPoint,
|
||||||
|
Close,
|
||||||
CopyToLiftedHeap,
|
CopyToLiftedHeap,
|
||||||
CreatePartialString,
|
CreatePartialString,
|
||||||
CurrentHostname,
|
CurrentHostname,
|
||||||
@@ -310,6 +311,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
|
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
|
||||||
clause_name!("$use_qualified_module_from_file")
|
clause_name!("$use_qualified_module_from_file")
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::Close => clause_name!("$close"),
|
||||||
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
|
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
|
||||||
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
|
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
|
||||||
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
|
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
|
||||||
@@ -462,6 +464,7 @@ impl SystemClauseType {
|
|||||||
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
||||||
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
||||||
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
||||||
|
("$close", 2) => Some(SystemClauseType::Close),
|
||||||
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
|
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
|
||||||
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
|
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
|
||||||
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
|
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
|
||||||
|
|||||||
@@ -43,18 +43,18 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
|||||||
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
|
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
|
||||||
abolish/1, asserta/1, assertz/1, atom_chars/2,
|
abolish/1, asserta/1, assertz/1, atom_chars/2,
|
||||||
atom_codes/2, atom_concat/3, atom_length/2,
|
atom_codes/2, atom_concat/3, atom_length/2,
|
||||||
bagof/3, catch/3, char_code/2, clause/2,
|
bagof/3, catch/3, char_code/2, clause/2, close/1,
|
||||||
current_input/1, current_output/1, current_op/3,
|
close/2, current_input/1, current_output/1,
|
||||||
current_predicate/1, current_prolog_flag/2,
|
current_op/3, current_predicate/1,
|
||||||
expand_goal/2, expand_term/2, fail/0, false/0,
|
current_prolog_flag/2, expand_goal/2,
|
||||||
findall/3, findall/4, get_char/1, halt/0,
|
expand_term/2, fail/0, false/0, findall/3,
|
||||||
max_arity/1, number_chars/2, number_codes/2,
|
findall/4, get_char/1, halt/0, max_arity/1,
|
||||||
once/1, op/3, open/3, open/4, read_term/2,
|
number_chars/2, number_codes/2, once/1, op/3,
|
||||||
read_term/3, repeat/0, retract/1,
|
open/3, open/4, read_term/2, read_term/3,
|
||||||
set_prolog_flag/2, set_input/1, set_output/1,
|
repeat/0, retract/1, set_prolog_flag/2,
|
||||||
setof/3, sub_atom/5, subsumes_term/2,
|
set_input/1, set_output/1, setof/3, sub_atom/5,
|
||||||
term_variables/2, throw/1, true/0,
|
subsumes_term/2, term_variables/2, throw/1,
|
||||||
unify_with_occurs_check/2, write/1,
|
true/0, unify_with_occurs_check/2, write/1,
|
||||||
write_canonical/1, write_term/2, write_term/3,
|
write_canonical/1, write_term/2, write_term/3,
|
||||||
writeq/1]).
|
writeq/1]).
|
||||||
|
|
||||||
@@ -1161,3 +1161,23 @@ open(SourceSink, Mode, Stream, StreamOptions) :-
|
|||||||
'$open'(SourceSink, Mode, Stream, Alias, EOFAction, Reposition, Type)
|
'$open'(SourceSink, Mode, Stream, Alias, EOFAction, Reposition, Type)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
|
parse_close_options(Options, OptionValues, Stub) :-
|
||||||
|
DefaultOptions = [force-false],
|
||||||
|
parse_options_list(Options, parse_close_options_, DefaultOptions, OptionValues, Stub).
|
||||||
|
|
||||||
|
parse_close_options_(force(Force), force-Force) :-
|
||||||
|
( nonvar(Force), lists:member(Force, [true, false]), !
|
||||||
|
;
|
||||||
|
throw(error(domain_error(close_option, force(Force)), _))
|
||||||
|
).
|
||||||
|
parse_close_options_(E, _) :-
|
||||||
|
throw(error(domain_error(close_option, E), _)).
|
||||||
|
|
||||||
|
|
||||||
|
close(Stream, CloseOptions) :-
|
||||||
|
parse_close_options(CloseOptions, [Force], close/2),
|
||||||
|
'$close'(Stream, CloseOptions).
|
||||||
|
|
||||||
|
close(Stream) :-
|
||||||
|
close(Stream, []).
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use std::fmt;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::net::TcpStream;
|
use std::net::{Shutdown, TcpStream};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
@@ -42,6 +42,18 @@ pub enum StreamInstance {
|
|||||||
TcpStream(TcpStream),
|
TcpStream(TcpStream),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for StreamInstance {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
match self {
|
||||||
|
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
||||||
|
tcp_stream.shutdown(Shutdown::Both).unwrap();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for StreamInstance {
|
impl fmt::Debug for StreamInstance {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -140,12 +152,21 @@ impl Default for StreamOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct Stream {
|
pub struct Stream {
|
||||||
pub options: StreamOptions,
|
pub options: StreamOptions,
|
||||||
stream_inst: WrappedStreamInstance,
|
stream_inst: WrappedStreamInstance,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Stream {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.stream_inst == other.stream_inst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Stream {}
|
||||||
|
|
||||||
impl From<TcpStream> for Stream {
|
impl From<TcpStream> for Stream {
|
||||||
fn from(tcp_stream: TcpStream) -> Self {
|
fn from(tcp_stream: TcpStream) -> Self {
|
||||||
tcp_stream.set_read_timeout(None).unwrap();
|
tcp_stream.set_read_timeout(None).unwrap();
|
||||||
@@ -292,6 +313,12 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn close(&mut self) {
|
||||||
|
*self.stream_inst.0.borrow_mut() = StreamInstance::Null;
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn is_input_stream(&self) -> bool {
|
fn is_input_stream(&self) -> bool {
|
||||||
|
|||||||
@@ -1743,6 +1743,26 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::Close => {
|
||||||
|
let mut stream =
|
||||||
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "close", 2)?;
|
||||||
|
|
||||||
|
if stream.is_output_stream() {
|
||||||
|
stream.flush().unwrap(); // 8.11.6.1b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stream == *current_input_stream {
|
||||||
|
*current_input_stream = readline::input_stream();
|
||||||
|
} else if stream == *current_output_stream {
|
||||||
|
*current_output_stream = Stream::stdout();
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.close();
|
||||||
|
|
||||||
|
if let Some(alias) = stream.options.alias {
|
||||||
|
indices.stream_aliases.remove(&alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
&SystemClauseType::CopyToLiftedHeap => {
|
&SystemClauseType::CopyToLiftedHeap => {
|
||||||
match self.store(self.deref(self[temp_v!(1)])) {
|
match self.store(self.deref(self[temp_v!(1)])) {
|
||||||
Addr::Usize(lh_offset) => {
|
Addr::Usize(lh_offset) => {
|
||||||
@@ -2298,6 +2318,10 @@ impl MachineState {
|
|||||||
|
|
||||||
stream.options = options;
|
stream.options = options;
|
||||||
|
|
||||||
|
if let Some(ref alias) = &stream.options.alias {
|
||||||
|
indices.stream_aliases.insert(alias.clone(), stream.clone());
|
||||||
|
}
|
||||||
|
|
||||||
let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream));
|
let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream));
|
||||||
let stream_var = self.store(self.deref(self[temp_v!(3)]));
|
let stream_var = self.store(self.deref(self[temp_v!(3)]));
|
||||||
|
|
||||||
@@ -3464,12 +3488,12 @@ impl MachineState {
|
|||||||
match TcpStream::connect(socket_addr).map_err(|e| e.kind()) {
|
match TcpStream::connect(socket_addr).map_err(|e| e.kind()) {
|
||||||
Ok(tcp_stream) => {
|
Ok(tcp_stream) => {
|
||||||
let mut stream = Stream::from(tcp_stream);
|
let mut stream = Stream::from(tcp_stream);
|
||||||
|
stream.options = options;
|
||||||
|
|
||||||
if let Some(ref alias) = &options.alias {
|
if let Some(ref alias) = &stream.options.alias {
|
||||||
indices.stream_aliases.insert(alias.clone(), stream.clone());
|
indices.stream_aliases.insert(alias.clone(), stream.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.options = options;
|
|
||||||
self.heap.to_unifiable(HeapCellValue::Stream(stream))
|
self.heap.to_unifiable(HeapCellValue::Stream(stream))
|
||||||
}
|
}
|
||||||
Err(ErrorKind::PermissionDenied) => {
|
Err(ErrorKind::PermissionDenied) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user