[comp.sources.misc] v05i016: which2 version 2

maart@cs.vu.nl.UUCP (Maarten Litmaath) (10/28/88)

Posting-number: Volume 5, Issue 16
Submitted-by: "Maarten Litmaath" <maart@cs.vu.nl.UUCP>
Archive-name: which2-v2

Dear moderator, included below is the new and enhanced version of `which2'.
I think the comments in the source header and the manual describe the
changes clearly. This version is to supersede the previous one.
Special thanks to Emile LeBlanc for catching the bug and testing the fix.
Thanks for your attention.
Regards & enjoy!
				Maarten Litmaath @ VU Amsterdam:
				maart@cs.vu.nl, mcvax!botter!maart

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'which.c'
sed 's/^X//' > 'which.c' << '+ END-OF-FILE ''which.c'
X/*
X * [alias <command> |] which [-i] [-a] [<command>]
X * alias which alias !\$ \| /usr/local/bin/which -i !\*
X * alias which eval alias '\$$# |' /usr/local/bin/which -i $\*
X *
X * author: Maarten Litmaath @ Free U Amsterdam (maart@cs.vu.nl)
X * first change:
X *	Emile LeBlanc (leblanc%math.Berkeley.EDU@ucbvax.berkeley.edu) notes
X *	the access() system call considering everything executable for
X *	root (!), so we give root a special treatment
X *	'which', 'which -i' and 'which -a' with no further arguments now
X *	return the PATH environment variable, split up into its components
X *	the aliases defined above are slightly different from the previous
X *	version - now it's the shell who's doing the alias checking
X */
X
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<stdio.h>
X
X#define		BUF_SIZE	512
X
Xchar	E_usage[] = "Usage: [alias <command> |] %s [-i] [-a] [<command>]\n",
X	E_read[] = "%s - read error in ",
X	E_path[] = "no PATH in environment!\n",
X	E_dir[] = "%s found in unreadable directory %s!\n",
X	E_notfound[] = "%s not found in\n%s\n",
X	*prog;
Xint	uid;
X
X
Xmain(argc, argv) 
Xint	argc;
Xregister char	**argv;
X{
X	register char	*path, *s;
X	char	*save, *strcpy(), *getenv(), *gets(), buf[BUF_SIZE];
X	int	all = 0, inter = 0, found = 0;
X	struct	stat	st;
X	void	usage(), convert();
X
X
X	prog = *argv++;
X
X	if (argc > 4)
X		usage();
X
X	while (--argc > 1) {
X		s = *argv++;
X		if (*s++ != '-')
X			usage();
X		while (*s)
X			switch (*s++) {
X				case 'a':
X					all = 1;
X					break;
X				case 'i':
X					inter = 1;
X					break;
X				default:
X					usage();
X			}
X	}
X
X	if (inter) {
X		if (gets(buf) && *buf != '\n') {
X			printf("%s\t%s\n", *argv, buf);
X			if (!all)
X				exit(0);
X			found = 1;
X		}
X		if (ferror(stdin)) {
X			fprintf(stderr, E_read, prog);
X			perror("stdin");
X			exit(1);
X		}
X	}
X
X	if (!(save = path = getenv("PATH"))) {
X		fprintf(stderr, E_path);
X		exit(1);
X	}
X
X	if (!*path)
X		save = path = ".";
X
X	if (argc == 0) {
X		convert(path, buf);
X		puts(buf);
X		exit(0);
X	}
X
X	if (**argv == '-' && (*argv)[1] && !(*argv)[2])
X		switch ((*argv)[1]) {
X			case 'i':
X			case 'a':
X				convert(path, buf);
X				puts(buf);
X				exit(0);
X		}
X
X	uid = getuid();
X
X	while (*path) {
X		s = buf;
X		while ((*s++ = *path) && *path++ != ':')
X			;
X		if (*buf == ':') {
X			/*
X			 * to deal with the dubious convention that a spurious
X			 * colon is equivalent to a dot...
X			 */
X			*buf = '.';
X			++s;
X		}
X		(void) strcpy(s, *argv);
X		*--s = '/';
X		if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
X			continue;
X
X		/* file exists and is regular */
X
X		if (uid == 0 ? !(st.st_mode & 0111) : access(buf, 1) != 0)
X			continue;
X
X		/* file is executable */
X
X		*s = 0;
X		if (uid == 0 && stat(buf, &st) != 0) {
X			perror(buf);
X			continue;
X		}
X
X		if (uid == 0 ? !(st.st_mode & 0444) : access(buf, 4) != 0) {
X			fprintf(stderr, E_dir, *argv, buf);
X			continue;
X		}
X
X		/* directory is readable */
X
X		*s = '/';
X		puts(buf);
X		if (!all)
X			exit(0);
X		found = 1;
X	}
X
X	if (found)
X		exit(0);
X
X	convert(save, buf);
X	fprintf(stderr, E_notfound, *argv, buf);
X	exit(1);
X}
X
X
Xvoid	usage()
X{
X	fprintf(stderr, E_usage, prog);
X	exit(1);
X}
X
X
Xvoid	convert(path, buf)
Xregister char	*path, *buf;
X{
X	for (;;) {
X		while ((*buf++ = *path) && *path++ != ':')
X			;
X		if (!*path)
X			break;
X		*buf++ = '\n';
X	}
X	*buf = '\0';		/* to cope with a PATH ending in ':' */
X}
+ END-OF-FILE which.c
chmod 'u=rw,g=r,o=r' 'which.c'
set `wc -c 'which.c'`
count=$1
case $count in
3306)	:;;
*)	echo 'Bad character count in ''which.c' >&2
		echo 'Count should be 3306' >&2
esac
echo Extracting 'which.1'
sed 's/^X//' > 'which.1' << '+ END-OF-FILE ''which.1'
X.TH WHICH 1 Oct\ 3\ 1988
X.SH NAME
Xwhich \- give alias or path expansion of command
X.SH SYNOPSIS
X.B which
X[
X.B \-i
X] [
X.B \-a
X] [
X.I command
X]
X.SH DESCRIPTION
X.B Which
Xprovides the user with the full expansion of the
X.I command
Xargument, be it either an
X.I alias
Xor an executable file (default). To enable search for
X.I aliases
Xthe user should supply the
X.B \-i
X(= interactive) flag. In that case
X.B which
Xexpects as standard input the output of an
X.I alias
Xcommand. This demand is easily met by setting an
X.I alias
Xlike the following:
X.br
X
X.br
X.RS
X.B alias \t which \t \\\\
X.RS
X.B
Xalias !\\$ \\| /usr/local/bin/which \-i !\\*
X.RE
X.RE
X.br
X
X.br
Xin
X.I csh,
Xor
X.br
X
X.br
X.RS
X.B alias \t which \t \\\\
X.RS
X.B
Xeval alias '\\$$# |' /usr/local/bin/which \-i $\\*
X.RE
X.RE
X.br
X
X.br
Xin shells which are supersets of
X.I sh.
X.sp
XIf the
X.B \-i
Xflag is not supplied, only the user's
X.I PATH
Xis searched for the
X.I command.
XIf the
X.B \-a
X(= all) flag is given,
X.B which
Xwill not stop after the first 'match', but search for all occurrences of
X.I command
Xin the user's
X.I PATH.
X.B Which [-i | -a]
Xwithout further argument prints the user's
X.I PATH
Xbroken up into its components,
Xone per line.
X.PP
XThis new version of the
X.I which
Xcommand is not a
X.I csh
Xscript.
XBeing an executable it is much faster, and not sourcing 
X.I .cshrc
Xit gives a true picture of one's
X.I aliases
Xand can be used safely between backquotes, like:
X.sp
X.RS
X.B
X$ file `which which`
X.br
X.B /usr/local/bin/which: pure executable
X.br
X.B $
X.RE
X.SH EXAMPLE
X.B % alias
X.br
X.B which \t alias !$ | /usr/local/bin/which
X.B \-i !*
X.br
X.B % which which
X.br
X.B which \t alias !$ | /usr/local/bin/which
X.B \-i !*
X.br
X.B % which \-a which
X.br
X.B which \t alias !$ | /usr/local/bin/which
X.B \-i !*
X.br
X.B /usr/local/bin/which
X.br
X.B /usr/ucb/which
X.br
X.B %
X.SH AUTHOR
XMaarten Litmaath @ Free University Amsterdam
+ END-OF-FILE which.1
chmod 'u=rw,g=r,o=r' 'which.1'
set `wc -c 'which.1'`
count=$1
case $count in
1852)	:;;
*)	echo 'Bad character count in ''which.1' >&2
		echo 'Count should be 1852' >&2
esac
exit 0