add set_stream_position/2

This commit is contained in:
Mark Thom
2020-05-09 14:20:32 -06:00
parent 034f5b16bd
commit 6f927b9941
5 changed files with 88 additions and 5 deletions

View File

@@ -248,6 +248,7 @@ pub enum SystemClauseType {
StoreGlobalVar,
StoreGlobalVarWithOffset,
StreamProperty,
SetStreamPosition,
InferenceLevel,
CleanUpBlock,
EraseBall,
@@ -422,6 +423,7 @@ impl SystemClauseType {
&SystemClauseType::SetOutput => clause_name!("$set_output"),
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
&SystemClauseType::StreamProperty => clause_name!("$stream_property"),
&SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"),
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
&SystemClauseType::StoreGlobalVarWithOffset => {
clause_name!("$store_global_var_with_offset")
@@ -575,6 +577,7 @@ impl SystemClauseType {
("$set_input", 1) => Some(SystemClauseType::SetInput),
("$set_output", 1) => Some(SystemClauseType::SetOutput),
("$stream_property", 3) => Some(SystemClauseType::StreamProperty),
("$set_stream_position", 2) => Some(SystemClauseType::SetStreamPosition),
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),

View File

@@ -59,10 +59,10 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
put_byte/1, put_byte/2, put_code/1, put_code/2,
put_char/1, put_char/2, read_term/2, read_term/3,
repeat/0, retract/1, set_prolog_flag/2,
set_input/1, set_output/1, setof/3,
stream_property/2, sub_atom/5, subsumes_term/2,
term_variables/2, throw/1, true/0,
unify_with_occurs_check/2, write/1,
set_input/1, set_stream_position/2, set_output/1,
setof/3, stream_property/2, sub_atom/5,
subsumes_term/2, term_variables/2, throw/1,
true/0, unify_with_occurs_check/2, write/1,
write_canonical/1, write_term/2, write_term/3,
writeq/1]).
@@ -1320,3 +1320,12 @@ at_end_of_stream :-
!,
( E = at ; E = past ).
set_stream_position(S_or_a, Position) :-
( var(Position) ->
throw(error(instantiation_error, set_stream_position/2))
; integer(Position), Position >= 0 ->
true
; throw(error(domain_error(stream_position, Position)))
),
'$set_stream_position'(S_or_a, Position).

View File

@@ -468,9 +468,11 @@ pub enum Permission {
Modify,
Open,
OutputStream,
Reposition,
}
impl Permission {
#[inline]
pub fn as_str(self) -> &'static str {
match self {
Permission::Access => "access",
@@ -479,6 +481,7 @@ impl Permission {
Permission::Modify => "modify",
Permission::Open => "open",
Permission::OutputStream => "output",
Permission::Reposition => "reposition",
}
}
}

View File

@@ -27,6 +27,15 @@ impl StreamType {
#[inline]
pub(crate)
fn as_str(&self) -> &'static str {
match self {
StreamType::Binary => "binary_stream",
StreamType::Text => "text_stream",
}
}
#[inline]
pub(crate)
fn as_property_str(&self) -> &'static str {
match self {
StreamType::Binary => "binary",
StreamType::Text => "text",
@@ -296,6 +305,22 @@ impl Stream {
}
}
#[inline]
pub(crate)
fn set_position(&mut self, position: u64) {
match self.stream_inst.0.borrow_mut().deref_mut() {
(past_end_of_stream, StreamInstance::InputFile(_, ref mut file)) => {
file.seek(SeekFrom::Start(position)).unwrap();
if let Ok(metadata) = file.metadata() {
*past_end_of_stream = position > metadata.len();
}
}
_ => {
}
}
}
#[inline]
pub(crate)
fn past_end_of_stream(&self) -> bool {

View File

@@ -4556,6 +4556,49 @@ impl MachineState {
}
}
}
&SystemClauseType::SetStreamPosition => {
let mut stream = self.get_stream_or_alias(
self[temp_v!(1)],
indices,
"set_stream_position",
2,
)?;
if !stream.options.reposition {
let stub = MachineError::functor_stub(clause_name!("set_stream_position"), 2);
let err = MachineError::permission_error(
self.heap.h(),
Permission::Reposition,
"stream",
vec![HeapCellValue::Stream(stream)],
);
return Err(self.error_form(err, stub));
}
let position = self.store(self.deref(self[temp_v!(2)]));
let position =
match Number::try_from((position, &self.heap)) {
Ok(Number::Fixnum(n)) => {
n as u64
}
Ok(Number::Integer(n)) => {
if let Some(n) = n.to_u64() {
n
} else {
self.fail = true;
return Ok(());
}
}
_ => {
unreachable!()
}
};
stream.set_position(position);
}
&SystemClauseType::StreamProperty => {
let mut stream = self.get_stream_or_alias(
self[temp_v!(1)],
@@ -4648,7 +4691,7 @@ impl MachineState {
}
"type" => {
HeapCellValue::Atom(
clause_name!(stream.options.stream_type.as_str()),
clause_name!(stream.options.stream_type.as_property_str()),
None,
)
}