#!/usr/bin/perl # usage: cmd | $0 [-silent] | cmd # implant an editor session into a pipe, allowing a # fallback to also forwarding the unmodified contents # even if the user already saved a modified buffer to disk. # # if used with file arguments (xargs), help and (empty) # contents of stdin can be found in the last buffer. my $version="0.1.2"; # created PJ 20090803 jakobi@acm.org # last change PJ 20091011 (fixed <> issue) # copyright: (c) 2009 jakobi@acm.org, GPL v3 or later # archive: http://jakobi.github.com/script-archive-doc/ # editor requirements: # # ability to read and write from tty redirection. Test with # 'echo | ($EDITORPIPED /etc/hosts /dev/tty;echo dummy) | wc -l'. # This must both allow an editor session and have wc -l see exactly 1 line. # Use shell variable $EDITORPIPED to avoid editor guessing. # vim tips: # # to just edit a bunch of files with a bufferlist in buffer 1, # using gf to switch to the file under the cursor: # find | sort | vim - # this '-' is half-magic, just like '.' # # even if - is missing, vim still can edit if stdin is guaranteed # to be empty. However, that requires a stty sane (possibly # to /dev/null allow doing this # without a temp file when used with :w >>/dev/stdout | :q # to exit [the >> is required, as vim assumes plain files # and throws errors otherwise. Likewise, a mere :wq fails # and might think it fun to create a spurious '-' file # somewhere hidden in the fs] $Me=$0; $Me=~s@.*/([^/]+)$@$1@; while(@ARGV) { $_=$ARGV[0]; /^--?silent$/ and do {$silent=1; shift; next}; /^--?head(er)?$/ and do {shift;$header=shift;next;}; last; } @vimargs=@ARGV; @ARGV=(); if ($ENV{EDITORPIPED}) { $EDITOR=$ENV{EDITORPIPED}; } else { # prefer vim, otherwise try guessing $EDITOR=$tmp if chomp($tmp=`which vim`) and not $?; $EDITOR=$ENV{EDITOR} if not -x $EDITOR; $EDITOR=$ENV{VISUAL} if not $EDITOR; $EDITOR="vi" if not $EDITOR; } chomp($tmpname =`mktemp -q /tmp/bufpipe.$$.XXXXXX`); ($? or $tmpname eq "") and die "# $Me: cannot create tmpfile\n"; # read all the input from STDIN and invoke the editor $msg=< INSECURE MESS undef $/; $_=<>; # SECURE:OK open(FH,">",$tmpname) and print FH $msg, $_ and close FH or do{unlink $tmpname; die "# ERR $Me: cannot write tmpfile\n" }; # sleep 2 if time-$time<3 and not $silent; # with useless cat to also protect against <() system "bash", "-c", $EDITOR.' "$@" /dev/tty | cat', "$Me:$EDITOR", @vimargs, $tmpname; $rc=$?>>8; if (not $rc) { $tmp=`cat $tmpname`; $tmp=~s/\A(#\Q $Me:\E.*\n)+\n?//; # remove remants of $msg if ($tmp=~/\A#[\t ]*(?:FAIL|EXIT)(?:[\t ](\d+))?([\t ].*|)\Z/) { $rc=20; $rc=$1 if $1; warn "# ERR $Me: setting rc to $rc as requestion - suppressing output\n"; } elsif ($tmp=~/\A#[\t ]*(ORG|ORIGINAL|PASS)([\t ].*|)\Z/) { warn "# $Me: passing on pre-editor pipe contents as requested\n"; print $_; } else { $tmp=~/\A\s*\z/ and $tmp=""; # spurious empty line due to broken editor? print $tmp; } } else { warn "# ERR $Me: editor returned $rc - suppressing output\n"; } unlink($tmpname); exit($rc);