about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBart Schaefer <schaefer@zsh.org>2024-02-03 20:10:52 -0800
committerBart Schaefer <schaefer@zsh.org>2024-02-03 20:10:52 -0800
commit2744208ab3eab1741157e01484d08095bd8ef528 (patch)
tree165e370de30f748bbb9b58afda8bd39ce2b9aaf3
parentc039a74e094bb6a4d965899f67fe34d2b84dda8d (diff)
downloadzsh-2744208ab3eab1741157e01484d08095bd8ef528.tar.gz
zsh-2744208ab3eab1741157e01484d08095bd8ef528.tar.xz
zsh-2744208ab3eab1741157e01484d08095bd8ef528.zip
unposted: elaboration on Roman's "slurp" implementation from zsh-users
-rw-r--r--ChangeLog3
-rw-r--r--Functions/Misc/zslurp31
2 files changed, 34 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 386ef3ab9..238c12c16 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2024-02-03  Bart Schaefer  <schaefer@zsh.org>
 
+ 	* unposted: cf. Roman in users/29472: Functions/Misc/zslurp:
+	Efficient lossless read of stdin into $REPLY
+
 	* unposted: Src/Zle/zle_tricky.c, Src/parse.c, Src/pattern.c:
 	Record as comments some notes about namespace usage exceptions.
 
diff --git a/Functions/Misc/zslurp b/Functions/Misc/zslurp
new file mode 100644
index 000000000..84df0c948
--- /dev/null
+++ b/Functions/Misc/zslurp
@@ -0,0 +1,31 @@
+#!/bin/zsh -f
+
+# Read stdin verbatim and as efficiently as possible into $REPLY,
+# stopping without any change to $REPLY in the event of any error.
+# Benchmarked by Roman Perepelitsa in zsh-users/29472
+
+# Although this function faithfully records the input stream, later
+# references to $REPLY with the multibyte option back in effect will
+# (re-)interpret the content as multibyte characters.  This may not be
+# what is desired.
+
+emulate -L zsh -o no_multibyte
+
+### Alternate formulation, faster on bigger files
+# # /dev/fd/0 is treated specially by -f so also check /dev/fd
+# if [[ -d /dev/fd && -f /dev/fd/0 ]] && zmodload zsh/mapfile
+# then
+#     local +h -Ar mapfile
+#     typeset -g REPLY="${mapfile[/dev/fd/0]}" && return
+# fi
+# # else fall through to read from pipe/socket
+
+zmodload zsh/system || return
+local -a content
+local -i i=0
+while true; do
+    sysread 'content[++i]' && continue
+    (( $? == 5 )) || return
+    break
+done
+typeset -g REPLY=${(j::)content}