--- /dev/null
+#!/bin/bash
+# Matt's improved version of Fedora's lesspipe.sh
+#
+# To use this filter with less, define LESSOPEN:
+# export LESSOPEN="|lesspipe.sh %s"
+
+# Updated for "less" that checks our exit code ~ Matt 2010-12-28
+
+# This script is entirely driven by the file content, with type detected by
+# file(1). For reproducibility and to avoid problems with strange names and
+# even symlinks, we do not use the original name of the file for anything.
+
+set -e
+set -o pipefail
+#set -x
+
+# Attach the file to an FD. We will reopen /dev/fd/$f to get as many fresh FDs as
+# we need.
+exec {f}<"$1"
+shift
+
+function run_stream_stdin {
+ if [ "$decompressor" == cat ]; then
+ <&$f "$@"
+ else
+ <&$f "$decompressor" | "$@"
+ fi
+}
+
+function stage_to_file_stdin {
+ if [ "$decompressor" != cat ]; then
+ # There is an unavoidable race here, so I am not trying to avoid
+ # it. If we rewrite the script in Perl, we can use open(undef).
+ # Integration with in2tempfile looks too hard.
+ tmpfile="$(mktemp --tmpdir lesspipe.XXXXXXXXXX)"
+ exec {tf}>"$tmpfile"
+ rm -f "$tmpfile"
+ <&$f "$decompressor" >&$tf # Synchronous
+ # Get a new FD for reading on the tempfile. This might not be
+ # necessary if the command is just going to reopen it.
+ exec {f}>&- </dev/fd/$tf {tf}>&-
+ else
+ exec <&$f-
+ fi
+}
+
+# Note: the bash file tests (except -h) follow symlinks.
+if [ -f /dev/fd/$f ]; then
+ # Specify the input as -. This avoids irrelevant "set[ug]id" output for
+ # executables and also follows the symlink without us having to pass -L.
+ # We have to reopen stdin to not consume it.
+ content_type="$(</dev/fd/$f file -b -)"
+
+ case "$content_type" in
+ ('gzip compressed data'*)
+ decompressor=gunzip;;
+ ('bzip2 compressed data'*)
+ decompressor=bunzip2;;
+ ('XZ compressed data'*)
+ decompressor=unxz;;
+ (*)
+ decompressor=cat;;
+ esac
+
+ if [ "$decompressor" != cat ]; then
+ # Get the real content type. Whatever work the decompressor
+ # does before it is killed with SIGPIPE, we will duplicate later
+ # when we read the file, but there is no good alternative:
+ # - If we do a "tee" with one pipe held for later use, "tee"
+ # will block once it fills up that pipe. So if "file" needs
+ # more data than the pipe buffer to make its decision
+ # (probably unlikely), we could hang.
+ # - Going ahead and dumping the decompressed data to a temporary
+ # file is a waste of work if the content type turns out to be
+ # one for which we have a streaming viewer, but of course we
+ # don't know that yet.
+ content_type="$(</dev/fd/$f "$decompressor" | file -b -)" || [ $? == 141 ] # SIGPIPE
+ fi
+
+ case "$content_type" in
+ ('troff or preprocessor input'*)
+ ## Presuming our parent is "less", set COLUMNS based on the width
+ ## of the terminal.
+ #exec {pt}>/proc/$PPID/fd/1
+ #if [ -t $pt ]; then
+ # # XXX Does this really use stderr rather than the controlling terminal?
+ # export COLUMNS="$(bash -i -c 'echo $COLUMNS' 2>&$pt)"
+ #fi
+ #exec {pt}>&-
+ # viapty is a more comprehensive solution than the above. ~ 2011-09-05
+ # Hm, by the time we hack in PAGER=cat, maybe it's not any better... ~ 2011-09-06
+ run_stream_stdin viapty man -l -;;
+ (*'tar archive'*)
+ run_stream_stdin tar -tvv;;
+ (*'cpio archive'*)
+ run_stream_stdin cpio --quiet -itv;;
+ (RPM*)
+ run_stream_stdin rpm -qivl --changelog -p -;;
+ (*image*) # FIXME: will catch disk "images" as well as graphical images
+ if type identify &>/dev/null; then
+ identify_cmd=(identify)
+ elif type gm &>/dev/null; then
+ identify_cmd=(gm identify)
+ else
+ ### Give them the binary data.
+ #echo "No identify available"
+ #echo "Install ImageMagick or GraphicsMagick to browse images"
+ identify_cmd=(false)
+ fi
+ if [ "${identify_cmd[0]}" != false ]; then
+ # Make a file so identify won't stage it again with a
+ # nonreproducible name. (Note that "identify -" will
+ # stage again even if /dev/stdin is a file!)
+ stage_to_file_stdin
+ "${identify_cmd[@]}" /dev/stdin
+ fi;;
+ ('OpenDocument Text'|_,'OpenDocument Text Template')
+ stage_to_file_stdin
+ ### CUSTOM SCRIPT -- This part cannot be upstreamed unless odt2text is.
+ odt2text /dev/stdin # based on unzip, needs a file
+ ;;
+ # This has to come after the special case for odt2text.
+ ('Zip archive data'*|_,'OpenDocument'*|_,'OpenOffice 1.x'*)
+ stage_to_file_stdin
+ zipinfo /dev/stdin # needs a file
+ ;;
+ ('PDF document'*)
+ run_stream_stdin pdftotext - -;;
+ ('PostScript document'*)
+ # If you wanted to see the PostScript source code, sorry...
+ run_stream_stdin ps2ascii;;
+ (ELF*'dynamically linked'*)
+ stage_to_file_stdin # read twice
+ objdump -xRTdgl /dev/stdin
+ # The above does not seem to show data sections. Run a separate command
+ # to show them. (Of course I would prefer a single command.)
+ objdump -s -j .rodata -j .data /dev/stdin
+ ;;
+ (ELF*)
+ stage_to_file_stdin # read twice
+ objdump -xdgl /dev/stdin
+ objdump -s -j .rodata -j .data /dev/stdin
+ ;;
+ ('SQLite 3.x database'*)
+ # TODO: Reimplement copy to a temporary directory to
+ # handle databases that use write-ahead mode, etc. I had
+ # implemented this in main VM and I forgot to copy it to
+ # main-template before shutting down. :( ~ Noted 2015-12-28
+ stage_to_file_stdin
+ # I believe that this will honor a write lock held on an
+ # uncompressed database by another instance of SQLite. I
+ # further believe that is what we want.
+ sqlite3 /dev/stdin .dump # needs a file
+ ;;
+ ('compiled Java class data'*)
+ # Agghhh... why couldn't javap just take a filename? It's clear
+ # that all it is doing is translating our argument to a file and
+ # opening that, without checking the correctness of the package
+ # or class name.
+ # XXX: Proper cleanup on failure
+ dir="$(mktemp -d --tmpdir lesspipe-javap.XXXXXXXXXX)"
+ ln -s /dev/stdin "$dir/Stdin.class"
+ run_stream_stdin javap -classpath "$dir" -private -s -c -verbose Stdin
+ rm -rf "$dir"
+ ;;
+ # Disabled for now.
+ #(*.grl)
+ # stage_to_file_stdin
+ # head -n 1 /dev/stdin | fold -w 28
+ # tail -n +2;;
+ (*) # Unknown content type.
+ if [ "$decompressor" != cat ]; then
+ # Just decompress the file.
+ <&$f "$decompressor"
+ else
+ # We cannot add value in this case.
+ # Let "less" show the original file.
+ exit 77
+ fi;;
+ esac
+
+elif [ -d /dev/fd/$f ]; then
+ # nip blank line at the end
+ # XXX: how to make sure "less" has -R enabled?
+ #ls -H -al --color=always -- /dev/fd/$f/ | head --bytes=-3
+ ### Between coreutils-7.6-9.matt1.fc12 and coreutils-8.5-7.fc14, the
+ ### output has changed to put the \n at the end, so the special hack is
+ ### no longer necessary (less ignores a final \n) and in fact corrupts
+ ### the colors. ~ Matt 2011-06-19
+ ls -H -al --color=always -- /dev/fd/$f/
+else
+ # Device/special file. Don't print anything; let less complain about it.
+ # (For now, we are not interested in content sniffing on pipes. If less
+ # gained support for calling LESSOPEN for stdin, we might reconsider.)
+ exit 77
+fi