[comp.sources.misc] v04i120: make any command screen oriented

george@rebel.UUCP (George M. Sipe) (10/11/88)

Posting-number: Volume 4, Issue 120
Submitted-by: "George M. Sipe" <george@rebel.UUCP>
Archive-name: vis

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	Makefile
#	vis.man
#	vis.c
# This archive created: Fri Jul 22 14:37:25 1988
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XVis repeatedly executes a specified command and refreshes the display
Xof its output on the screen.  This has the effect of making any
Xnormally non-screen oriented command into a screen oriented one.
X
XThe first line on the output screen is reserved for vis status and will
Xcontain the command on the left side with the current execution count
Xon the right side.  If command is too long to fit, vis will truncate it
Xin the status line and append an ellipsis ("...").
X
XThe output of the command normally begins on the third line and
Xcontinues to the end of the screen.  Lines which can not fit will be
Xdiscarded.  When this occurs, vis will automatically place the output
Xof following passes starting on line two in order to maximize the
Xamount of displayed information.
X
XSee the manual page for a complete information.
X
X
X     Copyright (c) 1988 by George M. Sipe.  All rights reserved.
X
XThis software may only be redistributed without fee and without any
Xother form of monetary gain (including sold, rented, leased, or
Xtraded), unless the express written permission of the copyright holder
Xis obtained in advance.
X
XThis copyright notice must be reproduced in its entirety on all copies
Xof this software.  Further, acknowledgment of the authorship of this
Xsoftware must not be removed from its current or derived
Xdocumentation.
X
XNo expressed or implied warranty is made for this software.  No party
Xconnected with this software assumes any liability or responsibility
Xfor its use, the correctness of its operation, or its fitness for any
Xpurpose.
X
XAny distributor of copies of this software shall grant the recipient
Xpermission for further redistribution as permitted by this notice.
X
XPermission is hereby granted to copy, reproduce, redistribute and
Xotherwise use this software as long as the conditions above are
Xstrictly adhered to.
X
XNOTE:	This software was originally written by Dan Heller
X	(argv@sri-spam.arpa) and enhanced / generalized by
X	George M.  Sipe (rebel!george) to the point where Dan
X	would no longer recoginze it.  No copyright notices
X	were embodied in the original net distribution.
SHAR_EOF
fi
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X# Makefile for:  vis - repeatedly run command, refreshing screen
X
XDEFINES		= -DBSD
XCFLAGS		= -O $(DEFINES)
XLIBS		= -lcurses -ltermcap
XROFF		= nroff
XRFLAGS		= -man
XLDFLAGS		= -s
XDESTBIN		= ${HOME}
XDESTMAN		= ${HOME}
XDESTCAT		= ${HOME}
XDESTOWN		= root
XDESTGRP		= staff
XSHELL		= /bin/sh
XMAKEFILE	= Makefile
XPROGRAM		= vis
XMANPAGES	= vis.man
XCATPAGES	= vis.cat
XSRCS		= vis.c
XOBJS		= vis.o
X
X.man.cat:
X		$(ROFF) $(RFLAGS) $< > $@
X
X.SUFFIXES:	.man .cat
X
X# Compile and load the program and format its manual pages.
Xall:		$(PROGRAM) $(CATPAGES)
X
X$(PROGRAM):	$(OBJS)
X		$(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
X
X# Run lint on source files, put results on standard output.
Xlint:
X		lint -u $(DEFINES) $(SRCS)
X
X# Create a tags file for use by a source code editor.
Xtags:		$(SRCS)
X		ctags $(SRCS)
X
X# Edit the makefile and regenerate the dependency information.
Xdepend:
X		mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DESTBIN=$(DESTBIN)
X
X# Print an index of functions on standard output.
Xindex:
X		ctags -wx $(SRCS)
X
X# Print source code files on standard output.
Xprint:
X		lpr -p $(SRCS) $(MANPAGES)
X
X# Compile and load the program, format manual pages, and move them
X# to their destination directories.
Xinstall:	$(PROGRAM) $(CATPAGES)
X		cp $(PROGRAM) $(DESTBIN)
X		chmod 755 $(DESTBIN)/$(PROGRAM)
X		chown $(DESTOWN) $(DESTBIN)/$(PROGRAM)
X		chgrp $(DESTGRP) $(DESTBIN)/$(PROGRAM)
X		-for manpage in $(MANPAGES); do \
X			basepage=`basename $$manpage .man`; \
X			cp $$basepage.man $(DESTMAN)/$$basepage.l; \
X			chmod 644 $(DESTMAN)/$$basepage.l; \
X			chown $(DESTOWN) $(DESTMAN)/$$basepage.l; \
X			chgrp $(DESTGRP) $(DESTMAN)/$$basepage.l; \
X			cp $$basepage.cat $(DESTCAT)/$$basepage.l; \
X			chmod 644 $(DESTCAT)/$$basepage.l; \
X			chown $(DESTOWN) $(DESTCAT)/$$basepage.l; \
X			chgrp $(DESTGRP) $(DESTCAT)/$$basepage.l; \
X		done
X
X# Remove the program and its formatted manual pages from their
X# destination directories.
Xuninstall:
X		rm -f $(DESTBIN)/$(PROGRAM)
X		-for manpage in $(MANPAGES); do \
X			basepage=`basename $$manpage .man`; \
X			rm -f $(DESTMAN)/$$basepage.l; \
X			rm -f $(DESTCAT)/$$basepage.l; \
X		done
X
X# Remove all target and intermediate files.
Xclean:
X		-rm -f $(PROGRAM) $(CATPAGES) $(OBJS)
X		-rm -f core a.out made *.o
SHAR_EOF
fi
if test -f 'vis.man'
then
	echo shar: "will not over-write existing file 'vis.man'"
else
sed 's/^X//' << \SHAR_EOF > 'vis.man'
X.TH VIS l "21 July 1988"
X.SH NAME
Xvis \- repeatedly run command, refreshing screen
X.SH SYNTAX
X.B vis "[-d delay] [-f] command [args]"
X.SH DESCRIPTION
X.I Vis
Xrepeatedly executes a specified
X.B command
Xand refreshes the display of its output on the screen.  This has the
Xeffect of making any normally non-screen oriented command into a screen
Xoriented one.
X.PP
X.B Command
Xmay represent multiple commands by enclosing them in quotes and
Xseparating them by ``;''.  Similarly, commands may be piped together by
Xenclosing them in quotes and separating them by ``|''.  The single or
Xdouble quotes around such a compound command are necessary to escape
Xprocessing from the shell.
X.PP
XThe first line on the output screen is reserved for
X.I vis
Xstatus and will contain the
X.B command
Xon the left side with the current execution count on the right side.  If
X.B command
Xis too long to fit,
X.I vis
Xwill truncate it in the status line and append an ellipsis ("...").
X.PP
XThe output of the command normally begins on the third line and
Xcontinues to the end of the screen.  Lines which can not fit will be
Xdiscarded.  When this occurs,
X.I vis
Xwill automatically place the output of following passes starting on line
Xtwo in order to maximize the amount of displayed information.
X.PP
XThe following switches may be specified if desired:
X.TP 10
X.B "-d delay"
Xspecifies a non-default delay of
X.B delay
Xseconds.  Normally
X.I vis
Xwill delay for 15 seconds between command re-executions.  If a
Xnon-default delay is specified, the
X.I vis
Xstatus line will also include the delay interval centered within it
X(unless that would cause it to overwrite a long command, in which case
Xit will be centered between the end of the command and the execution
Xcount).
X.TP
X.B -f
X.I Vis
Xwill automatically terminate if
X.B command
Xreturns a non-zero status.  The
X.B -f
Xflag forces
X.I vis
Xto continue.  When
X.B -f
Xis specified,
X.I vis
Xwill not terminate and will instead precede the execution count in the
X.I vis
Xstatus line by a ``!'' flag whenever a non-zero status has been returned
Xby
X.B command .
X.SH EXAMPLES
Xvis ps
X.IP "" 5
XContinually display the status of processes on the system (up to 23
Xlines).
X.PP
Xvis -d 60 'who ; echo ""; df'
X.IP "" 5
XDisplay the system users and disk usage statistics every 60 seconds.
XSeparate the two with a blank line.
X.SH "SEE ALSO"
XUser Commands (1):  sh, csh
X.SH DIAGNOSTICS
XIf
X.B command
Xreturns a non-zero status and
X.B -f
Xhas not been specified to
X.I vis ,
X.I vis
Xwill terminate and return that status.
X.SH AUTHOR
XOriginally written by Dan Heller (argv@sri-spam.arpa).
X.PP
XIt has been substantially enhanced and generalized by George M. Sipe
X(currently - 7/88, at rebel!george) to the point where Dan would no
Xlonger recognize it.
SHAR_EOF
fi
if test -f 'vis.c'
then
	echo shar: "will not over-write existing file 'vis.c'"
else
sed 's/^X//' << \SHAR_EOF > 'vis.c'
X/*   Copyright (c) 1988 by George M. Sipe.  All rights reserved.
X
XThis software may only be redistributed without fee and without any
Xother form of monetary gain (including sold, rented, leased, or
Xtraded), unless the express written permission of the copyright holder
Xis obtained in advance.
X
XThis copyright notice must be reproduced in its entirety on all copies
Xof this software.  Further, acknowledgment of the authorship of this
Xsoftware must not be removed from its current or derived
Xdocumentation.
X
XNo expressed or implied warranty is made for this software.  No party
Xconnected with this software assumes any liability or responsibility
Xfor its use, the correctness of its operation, or its fitness for any
Xpurpose.
X
XAny distributor of copies of this software shall grant the recipient
Xpermission for further redistribution as permitted by this notice.
X
XPermission is hereby granted to copy, reproduce, redistribute and
Xotherwise use this software as long as the conditions above are
Xstrictly adhered to.
X
X	NOTE:  This software was originally written by Dan Heller
X	(argv@sri-spam.arpa) and enhanced / generalized by George M.
X	Sipe (rebel!george) to the point where Dan would no longer
X	recoginze it.  No copyright notices were embodied in the
X	original net distribution.
X*/
X
X#include <stdio.h>
X#include <curses.h>
X#include <signal.h>
X#include <sys/types.h>
X
X#ifndef	DELAY
X#define	DELAY	15		/* default delay, if not otherwise set */
X#endif	DELAY
X#ifndef	BASELINE
X#define	BASELINE 2		/* default line number for output */
X#endif	BASELINE
X
X#define max(a,b) 		(a < b ? b : a)
X#define equal(str1,str2)	!strcmp(str1, str2)
X
X#define pinput 			fildes[0]
X#define poutput			fildes[1]
X
X#ifdef	BSD
X#include <sys/wait.h>
Xextern char *index();
Xextern time_t time();
Xextern int exit();
Xextern int _exit();
Xextern int perror();
Xextern int sleep();
X#else
Xunion wait {
X	int w_status;
X};
X#define	vfork()		fork()				/* fork on non-BSD */
X#define	dup2(from,to)	close(to); (void) dup(from)	/* good enough here */
X#define	index(str,chr)	strchr(str,chr)			/* strchr on non-BSD */
Xextern char *strchr();
Xextern long time();
Xextern void exit();
Xextern void _exit();
Xextern void perror();
Xextern unsigned int sleep();
X#endif	BSD
X
Xextern int optind;
Xextern char *optarg;
X
Xlong wait_delay = DELAY;	/* delay interval */
Xint force = 0;			/* true to force continued execution */
Xint needshell = 0;		/* non-zero if subshell needed */
X
X/* create command line string for display */
Xstatic char *command(argc, argv)
Xint argc;
Xchar **argv;
X{
X	static char string[255];
X	int count = 0;
X	char *cp = string;
X
X	do {
X		(void) sprintf(cp, "%s ", argv[count]);
X		cp += strlen(cp);
X		needshell |= (int) index(argv[count], '|');
X		needshell |= (int) index(argv[count], ';');
X	} while (++count < argc);
X	*--cp = '\000';
X	return (string);
X}
X
X/* all done, cleanup and exit */
Xstatic int terminate(cause)
X{
X#ifdef	BSD
X	(void) sigsetmask(-1);
X#endif
X	move(LINES - 1, 0);
X	clrtoeol();
X	echo();
X	refresh();
X	endwin();
X	exit(cause);
X}
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X	register int curline;
X	register int iteration = 0;
X	register int c;
X	int sw;
X	int badsw = 0;
X	int baseline = BASELINE;
X	long nextcycle;
X	long curtime;
X	long delta;
X	int fildes[2];
X	int pid;
X	union wait status;
X	char *cmd = argv[0];
X	char *shcmd[4];
X	FILE *fp;
X
X	(void) signal(SIGQUIT, terminate);	/* exit when requested */
X	(void) signal(SIGINT, terminate);	/* exit when requested */
X	(void) signal(SIGPIPE, SIG_IGN);	/* when output > screen size */
X
X	while ((sw = getopt (argc, argv, "d:f")) != EOF)
X		switch (sw) {
X			case 'f':
X				force = !force;
X				break;
X			case 'd':
X				wait_delay = atoi(optarg);
X				if (wait_delay < 1) wait_delay = 1;
X				break;
X			case '?':
X			default:
X				badsw = 1;
X				break;
X		}
X	argv = &argv[optind];
X	argc -= optind;
X	if (badsw || argc < 1) {
X		(void) fprintf(stderr,
X			"Usage: %s [-d delay] [-f] command [args]\n", cmd);
X		exit (-1);
X	}
X	initscr();
X	cmd = command(argc, argv);
X	if (needshell != 0) {
X		shcmd[0] = "sh";
X		shcmd[1] = "-c";
X		shcmd[2] = cmd;
X		shcmd[3] = (char *) 0;
X	}
X	if (wait_delay != DELAY) {
X		if (strlen(cmd) > COLS-39)
X			(void) sprintf(cmd, "%.*s...", COLS-42, cmd);
X		mvprintw(0, max((COLS-11)/2, strlen(cmd)+15), "Delay:  %d",
X			wait_delay);
X	} else if (strlen(cmd) > COLS-21)
X		(void) sprintf(cmd, "%.*s...", COLS-24, cmd);
X	mvprintw(0, 0, "Command:  %s", cmd);
X	noecho();			/* don't let typing ruin our painting */
X	nextcycle = time(0) + wait_delay;
X	while (1) {
X		mvprintw(0, COLS - 10, "Exec:  %d", ++iteration);
X		if (iteration == 1) refresh();
X		(void) pipe(fildes);
X		/* fork and exec redirecting stdout thru pipe to curses */
X		if (!(pid = vfork())) {
X			(void) dup2(poutput, 1);
X			(void) dup2(poutput, 2);
X			(void) close(pinput);
X			if (needshell == 0) (void) execvp(*argv, argv);
X			else (void) execv("/bin/sh", shcmd);
X			perror(*argv);
X			_exit(-1);
X		}
X		if (pid == -1) terminate(-2);
X		if (!(fp = fdopen(pinput, "r"))) terminate(-3);
X		(void) close(poutput);
X		curline = baseline;
X		move(curline, 0);
X		/* read the command's output */
X		while ((c = getc(fp)) != EOF && !ferror(fp) && curline < LINES)
X				if (c == '\n') {
X					clrtoeol();
X					move(++curline, 0);
X				}
X				else addch(c);
X		if (ferror(fp)) terminate(-4);
X		if (baseline > 1 && curline == LINES && c != EOF)
X			--baseline;
X		/* we've found the end of file, thus, the end of exec */
X		(void) fclose(fp);
X		clrtobot();
X		move(LINES - 1, 0);
X		refresh();
X		(void) wait(&status);	/* wait for child to terminate */
X		/* if child didn't terminate properly, w_status will != 0 */
X		if (status.w_status) {
X			mvprintw(0, COLS - 12, "!");
X			if (!force) terminate(status.w_status);
X		}
X		curtime = time(0);
X		delta = nextcycle - curtime;
X		if (delta > 0) {
X			nextcycle = curtime + delta + wait_delay;
X			(void) sleep((unsigned) delta);
X		} else nextcycle = curtime + wait_delay;
X	}
X}
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
George M. Sipe,		Phone: (404) 662-1533
Tolerant Systems, 6961 Peachtree Industrial, Norcross, GA  30071
UUCP: ...!{decvax,hplabs,linus,rutgers,seismo}!gatech!rebel!george