#!/bin/sh
#
# @(#)  /u/des/src/duf/vip  1.10  97/11/13  13:45:25
#
# vip: 'vi' a pipe
#
# Description:
#	'vip' lets you use 'vi' (or the editor of your choice)
#	within a pileline.
#
# Usage:
#	vip [-no] [command]
#
#	-n  close stdin;
#	-o  do not send output;
#	If command is not specified, stdin is used.
#
# Copyright (c) 1997 by Daniel E. Singer.  All rights reserved.
# Permission is granted to reproduce and distribute this program
# with the following conditions:
#   1) This copyright notice and the author identification below
#      must be left intact in the program and in any copies.
#   2) Any modifications to the program must be clearly identified
#      in the source file.
#
# Written by Daniel E. Singer, Duke Univ. Dept of Computer Science, 5/30/95
#
# Modifications:
#
# 12/06/96, D.Singer
#	added -o;
#	added use of VISUAL and EDITOR environment variables;
#
# 7/14/97, D.Singer
#	added -n;
#	reversed meaning of -o;
#	other cosmetic changes;
#
# 8/1/97, D.Singer
#	changed name from pvi to vip;
#
# 8/13/97, D.Singer
#	changed option processing to 'getopts';
#	added use of TMPDIR environment variable;
#
# 8/21/97, D.Singer
#	oops!, 'getopts' doesn't seem to be universally available,
#	so some home-grown code has been added;
#
# 11/13/97, D.Singer
#	added some additional signal processing so can kill the pipeline
#	during the edit;

#PATH='/bin:/usr/bin:/usr/ucb'
#export PATH

PROG=`basename $0`
USAGE="
Usage:  $PROG [ -no ] [ command ]

	  Edit interactively in a pipeline.

	  -n		close stdin, if from the keyboard;
	  -o		do not send edited text to stdout;
	  command	command to run to produce initial text for editing,
			otherwise stdin is used;
"

: ${TMPDIR:="/var/tmp"}		# where temp. files go
TEMP_FILE="$TMPDIR/$PROG.$$"	# temp. file to hold data to edit
COMMAND="cat"			# default command to produce input
DFLT_ED="vi"			# default editor
ED="$DFLT_ED"			# editor
AWK=nawk

# system annoyances
SYS=`uname -sr`
case "$SYS" in
  "Linux "*)
	AWK=awk
	;;
  "HP-UX "*)
	AWK=awk
	;;
  "NetBSD "*)
	AWK=awk
  esac

#
# get editor from the environment, if possible
#
if [ -n "$VISUAL" ]; then
	ED="$VISUAL"
  elif [ -n "$EDITOR" ]; then
	ED="$EDITOR"
  fi

#
# access to user only for temp. files
#
umask 077

#
# clean up if certain signals caught;
# see below for additional signal handling;
#
# the symbolic signals do not work on SunOS 4
#trap 'rm -f "$TEMP_FILE"; exit' HUP INT QUIT TERM
#trap 'rm -f "$TEMP_FILE"; exit' 1 2 3 15
trap 'rm -f "$TEMP_FILE"; exit' 0 1 2 3 15

IN_OPT=0		# close input option
OUT_OPT=0		# no output option
COMMAND_OPT=0		# if command args given
SYNTAX="$PROG: option syntax error."

#
# process command line options
#
while [ "$#" -gt 0 ]; do
	OPT="$1"
	case "$OPT" in
	  -n)
		IN_OPT=1
		;;
	  -o)
		OUT_OPT=1
		;;
	  --)
		shift
		break
		;;
	  # unknown option
	  -?)
		echo "$SYNTAX" >&2
		echo "$USAGE" >&2
		exit 1
		;;
	  # compound option, break it up
	  -??*)
		NEW_OPTS=`$AWK 'BEGIN {
			OPT_STR = "'"$OPT"'";
			LEN = length(OPT_STR);
			NEW_OPTS = "";
			STATUS = 0;
			for (POS=2; POS+0 <= LEN; ++POS) {
				OPT = substr(OPT_STR,POS,1);
				if (OPT !~ /[a-zA-Z0-9]/)
					STATUS = 1;
				NEW_OPTS = NEW_OPTS " -" OPT;
			}
			print NEW_OPTS;
			exit STATUS;
		  }' <&-` || {
			echo "$SYNTAX" >&2
			echo "$USAGE" >&2
			exit 1
		  }
		shift
		if [ "$#" -gt 0 ]; then
			set -- $NEW_OPTS "$@"
		  else
			set -- $NEW_OPTS
		  fi
		continue
		;;
	  # end of options, just command arguments left
	  *)
		break
	  esac
	shift
  done

#
# if there are still arguments on the command line,
# use them as a command to produce input;
#
if [ "$#" != '0' ]; then
	COMMAND="$*"
	COMMAND_OPT=1
  fi


#
# dump input to a temp file, which will be edited and later deleted
#
if [ "$IN_OPT" = 1 -a -t 0 ]; then
	#
	# close stdin
	#
	exec <&-

	#
	# still try to run any specified command, hopefully
	# it doesn't need stdin
	#
	if [ "$COMMAND_OPT" = 1 ]; then
		eval "$COMMAND" > "$TEMP_FILE"
	  else
		> "$TEMP_FILE"
	  fi
  else
	eval "$COMMAND" > "$TEMP_FILE"
  fi

#
# change input to the keyboard for the edit
#
exec </dev/tty

#
# hold a copy of stdout for later listing;
# output should go specifically to the screen,
# to stay out of any pipelines during the edit;
#
exec 3>&1
exec >/dev/tty

#
# need a way to kill the edit session without having the pipeline continue;
# if one of these signals is caught, send TERM to the process group;
#
trap 'clear; kill -15 0' 1 2 3

#
# edit the temp file, might want to save it elsewhere...
#
$ED "$TEMP_FILE"
STATUS="$?"

#
# deal appropriately with stdout,
# then get rid of the temp file
#
if [ "$OUT_OPT" = 0 -a -f "$TEMP_FILE" ]; then
	cat "$TEMP_FILE" >&3
  fi
exec 3>&-
exec >&-
# this should happen on exit via the trap
#rm -f "$TEMP_FILE"

exit $STATUS
