]> Repositorios git - scryer-prolog.git/commitdiff
fix read/1 on non-TTY stdin blocking until newline #3262
authorno382001 <[email protected]>
Tue, 31 Mar 2026 12:40:20 +0000 (14:40 +0200)
committerno382001 <[email protected]>
Tue, 31 Mar 2026 13:52:27 +0000 (15:52 +0200)
src/machine/streams.rs
tests-pl/issue3262.pl [new file with mode: 0644]
tests/scryer/issues.rs

index 58d685a0585d6d986dbf47b9f3cd2b2503ee06aa..a2ac58a4af8111c9ecaee0929e80222eb56c7a61 100644 (file)
@@ -23,7 +23,7 @@ use std::fmt::Debug;
 use std::fs::{File, OpenOptions};
 use std::hash::Hash;
 use std::io;
-use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
+use std::io::{Cursor, ErrorKind, IsTerminal, Read, Seek, SeekFrom, Write};
 use std::mem::ManuallyDrop;
 use std::net::{Shutdown, TcpStream};
 use std::ops::{Deref, DerefMut};
@@ -657,10 +657,27 @@ impl Stream {
 
     #[inline]
     pub fn stdin(arena: &mut Arena, add_history: bool) -> Stream {
-        Stream::Readline(arena_alloc!(
-            StreamLayout::new(ReadlineStream::new("", add_history)),
-            arena
-        ))
+        if std::io::stdin().is_terminal() {
+            Stream::Readline(arena_alloc!(
+                StreamLayout::new(ReadlineStream::new("", add_history)),
+                arena
+            ))
+        } else {
+            #[cfg(unix)]
+            {
+                use std::os::unix::io::{FromRawFd, RawFd};
+                // dup fd 0 so the File can be owned (and closed later) without
+                // closing the real stdin.
+                let fd = unsafe { libc::dup(0 as RawFd) };
+                let file = unsafe { File::from_raw_fd(fd) };
+                return Stream::from_file_as_input(atom!("user_input"), file, arena);
+            }
+            #[allow(unreachable_code)]
+            Stream::Readline(arena_alloc!(
+                StreamLayout::new(ReadlineStream::new("", add_history)),
+                arena
+            ))
+        }
     }
 
     pub fn from_tag(tag: ArenaHeaderTag, ptr: UntypedArenaPtr) -> Self {
diff --git a/tests-pl/issue3262.pl b/tests-pl/issue3262.pl
new file mode 100644 (file)
index 0000000..15e54ae
--- /dev/null
@@ -0,0 +1,4 @@
+:- initialization(main).
+main :-
+    read(Term),
+    write(Term).
index 10ca8e240f05c176d974195fd42a51c4e00af776..bdd50027ef0f3f1dbc12d7e0484754972d34de66 100644 (file)
@@ -1,4 +1,5 @@
 use crate::helper::load_module_test;
+use crate::helper::load_module_test_with_input;
 #[cfg(not(target_arch = "wasm32"))]
 use crate::helper::load_module_test_with_tokio_runtime;
 use serial_test::serial;
@@ -148,6 +149,13 @@ fn issue_rename_file() {
     load_module_test("tests-pl/issue_rename_file.pl", "file_renamed");
 }
 
+// issue #3262: read/1 on non-TTY stdin should resolve without requiring a newline
+#[test]
+#[cfg_attr(miri, ignore = "unsupported operation when isolation is enabled")]
+fn issue3262_read_from_stdin_no_newline() {
+    load_module_test_with_input("tests-pl/issue3262.pl", "hello.", "hello");
+}
+
 #[test]
 #[cfg(feature = "http")]
 #[cfg(not(target_arch = "wasm32"))]