[net.sources] Execute embedded text strings - a tool

pc@ukc.UUCP (R.P.A.Collinson) (10/22/85)

Here is a little program with a lot of power. It allows you to place
shell commands as comments in files and then execute the commands by
pointing the xtx command at the file. It solves many troff/nroff problems
and can be used in various other situations.

See the manual page for various `this was someone else's idea' caveats.

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	xtx.c
#	xtx.1
# This archive created: Mon Oct 21 22:17:15 1985
cat << \SHAR_EOF > xtx.c
#ifndef lint
static char sccsid[] = "@(#)xtx.c	1.1 (UKC) 13/10/85";
#endif  lint
/***

* program name:
	xtx.c
* function:
	Looks in a file for a string of the form
		<-xtx[letter]->
	If the string is followed by a line ending with a \n
	Then takes the line and executes it using /bin/sh
	The letter is used to select one of a number of commands
	which may be embedded in the file. The character '*' is
	used to mean the default.
* switches:
	-c [letter]	select a particular line in the file
	-e		echo the matched command from the file
	-a		print all matched commands from the file and their
			key letter
	+[letter]	same as -c [letter]
	files
	-		Take data from standard input for scanning
* libraries used:
	standard
* compile time parameters:
<-xtx-*>	cc -o xtx -O xtx.c
<-xtx-l>	lint -h xtx.c
* history:
	Written October 1985 Peter Collinson UKC
***/
#include <stdio.h>
#include <ctype.h>

char	cmdbuf[BUFSIZ];	/* Where to store the command */

char	selchar='*';	/* selection character */
int	echosw;		/* set if echo only */
int	allsw;		/* print all matched commands from the file */

#define WILD	1	/* Wild character in the string below */
char	matchs[] =	/* Used to find a match with a command */
{	'<','-','x','t','x','-',WILD,'>'	};
#define STORESTATE	(sizeof matchs)

char Usage[] = "Usage:txt [-e][-c letter|+letter] files..\n";

main(argc, argv)
char **argv;
{	register char *p;
	FILE *fd;

	while (--argc)
	{	p = *++argv;
		switch (*p)
		{
		case '-':
			p++;
			switch (*p)
			{
			case 'a':
				allsw++;
				echosw++;
				break;
			case 'c':
				if (--argc)
				{	argv++;
					selchar = **argv;
				}
				else
				fatal("No argument to -c given\n");
				break;
			case 'e':
				echosw++;
				break;
			case '\0':
				scanfile(stdin);
				if (cmdbuf[0])
					execute(cmdbuf);
				break;
			default:
				fatal(Usage);
			}
			break;
		case '+':
			selchar = p[1];
			break;
		default:
			if ((fd = fopen(argv[0], "r")) == NULL)
			{	perror(argv[0]);
				break;
			}
			scanfile(fd);
			(void) fclose(fd);
			if (cmdbuf[0])
				execute(cmdbuf);
			break;
		}
				
	}
	exit(1);	/* Command has failed */
}

/*
 *	Scan a file looking for an appropriate line
 */
scanfile(fd)
FILE *fd;
{	register c;
	register state = 0;
	register char *cmdp;

	while ((c = getc(fd)) != EOF)
	{	if (state == STORESTATE)
		{	if (isprint(c) || isspace(c))
			{	if (c == '\n')
				{	*cmdp = '\0';
					if (allsw)
					{	execute(cmdbuf);
						state = 0;
						continue;
					}
					return;
				}
				else
				if (cmdp < &cmdbuf[BUFSIZ])
					*cmdp++ = c;
				continue;
			}
			state = 0;
		}
		else
		if (matchs[state] == WILD)
		{	if (allsw)
				selchar = c;
			if (c == selchar)
				state++;
			else	state = 0;
		}
		else
		if (c == matchs[state])
		{	if (state++ == 0)
			{	cmdp = cmdbuf; *cmdp = '\0';	}
		}
		else	state = 0;
	}
}

/*
 *	Call the shell
 */
execute(cmdp)
register char *cmdp;
{
	for (; isspace(*cmdp); cmdp++);
	if (allsw)
		fprintf(stderr, "%c\t%s\n", selchar, cmdp);
	else
		fprintf(stderr, "%s\n", cmdp);
	if (allsw)
		return;
	if (echosw)
		exit(0);
	execl("/bin/sh", "sh", "-c", cmdp, 0);
	perror("Exec");
	exit(1);
}

fatal(str)
char *str;
{	fprintf(stderr, str);
	exit(1);
}
SHAR_EOF
cat << \SHAR_EOF > xtx.1
.TH XTX 1 "UKC local 19/10/85"
.UC
.SH NAME
xtx \- execute embedded text commands
.SH SYNOPSIS
.B xtx
[
.B \-a
] [
.B \-c
letter
|
.B \+ "letter"
] [
.B -e
] files ....
.SH DESCRIPTION
.I Xtx
looks for a magic string in a file and then takes the characters which follow
up to the next newline character as a command to be executed by 
.I sh (1).
The default magic string is
.TP
<\-xtx\-*>.
.PP
Any tabs and spaces which immediately follow the magic string are removed
before the remainder of the line is sent to
.I sh
for execution.
.PP
Several commands can be embedded in the file and selected independently by
the use of selector characters.
If the character * in the xtx command string
is replaced by another (printing) character; then
the line is only executed if the character is specified to 
.I xtx 
using the 
.B -c
letter
or 
.B + letter
switches.
For instance, a string of the form <\-xtx\-l> will only be recognised and
executed if
.I xtx
is called with the argument of `+l'; for Unix purists the form `-c l' may
also be specified with the same effect.
.PP
The arguments to the program are:-
.TP
.B -a
Print all the xtx lines which can be found in the file with their selector
letter.
.TP
.B -e
Echo the command which would be executed by this call to
.I xtx.
.TP
.B -c
is followed by a letter, use this letter as the selector character for the
.I xtx
run.
.B + <letter>
same as -c but allows the selector letter to be specified in the same argument.
.PP
All other arguments are files which are searched for matching command lines;
a `-' on the input causes data to be taken from the standard input for
searching.
.SH "SEE ALSO"
sh(1)
.SH AUTHOR
Peter Collinson UKC.
.PP
The basic idea is not new and exists in several editors (David Tilbrook's)
.I qed
and the infamous
.I vi .
However, the idea of making a tool for it seemed like the right thing to
do.
.PP
By the way,
xtx is pronounced `extex' and is a verb.
It is possible therefore to `extex' a file in order to execute something
on it in whatever way seems reasonable.
SHAR_EOF
#	End of shell archive
exit 0