]> Repositorios git - scryer-prolog.git/commitdiff
add set_stream_position/2
authorMark Thom <[email protected]>
Sat, 9 May 2020 20:20:32 +0000 (14:20 -0600)
committerMark Thom <[email protected]>
Sat, 9 May 2020 20:20:32 +0000 (14:20 -0600)
src/prolog/clause_types.rs
src/prolog/lib/builtins.pl
src/prolog/machine/machine_errors.rs
src/prolog/machine/streams.rs
src/prolog/machine/system_calls.rs

index b4f1ee8517c4cd849f1048c7107ea382e00b2f67..36f278df55293561d8c3b6d5caee680274b973a9 100644 (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),
index ba1f41fb3a4ae5e1d8844a2a049ac42a6d957f9f..798e201a8b1a61f82429f68d493455599184926d 100644 (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).
index d384185b6aac0ef793cfa84cf861ef9275025083..93c36a73833c224d62d94f46f4d5c3007551b076 100644 (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",
         }
     }
 }
index 66ad2b3259d202a728fbf5c9b7dced64196d8884..68b2ec3bf0b12b628f4483aeb6b5000afc8f0383 100644 (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 {
index 43bfba86c8eb1e99483795694964a514030a975b..e01008e03e94bff57032b1aac474669d4cf70bac 100644 (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,
                                             )
                                         }