[alt.sources] fast which v3.0

maart@cs.vu.nl (Maarten Litmaath) (01/06/90)

: 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 'Makefile'
sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile'
X# Makefile for /usr/local/bin/which
X
Xwhich:		which.c
X		cc -O which.c -o which
X
Xinstall:	which
X		/bin/mv -f which /usr/local/bin
X
Xdoc:
X		nroff -man which.1 > which.man
+ END-OF-FILE Makefile
chmod 'u=rw,g=r,o=r' 'Makefile'
set `wc -c 'Makefile'`
count=$1
case $count in
167)	:;;
*)	echo 'Bad character count in ''Makefile' >&2
		echo 'Count should be 167' >&2
esac
echo Extracting 'which.1'
sed 's/^X//' > 'which.1' << '+ END-OF-FILE ''which.1'
X.TH WHICH 1 Sep\ 21\ 1989
X.SH NAME
Xwhich \- give alias, function or path expansion of command
X.SH SYNOPSIS
X.B which
X[
X.B \-i
X] [
X.B \-a
X] [
X.B \-\-
X] [
X.I command
X]
X.SH DESCRIPTION
X.I Which
Xprovides the user with the full expansion of the
X.I command
Xargument, be it either an \fIalias\fR, a \fIshell function\fR
Xor an executable file (default). To enable search for
X.I aliases
Xand \fIshell functions\fR
Xthe user should supply the `\fI\-i\fR'
X(= interactive) flag. In that case
X.I which
Xexpects as standard input the expansion of the \fIalias\fR
Xor \fIshell function\fR.
XIf the standard input is empty or the `\fI\-i\fR' flag has not been
Xgiven, \fIwhich\fR will try to locate \fIcommand\fR
Xin the user's \fIPATH\fR.
XThe interactive mode is easily used by setting an
X.I alias
Xlike the following:
X.ft B
X.nf
X
X	alias	which	alias !\\$ \\| /usr/local/bin/which \-i !\\*
X
X.fi
X.ft R
Xin \fIcsh\fR, or
X.ft B
X.nf
X
X	alias	which	eval alias '\\"\\$$#\\" |' \\
X			/usr/local/bin/which \-i '${1+"$@"}'
X
X.fi
X.ft R
Xin shells which are supersets of
X.I sh
Xand which know \fIaliases\fR. If your shell has \fIshell functions\fR, you
Xcan use the following function:
X.ft B
X.nf
X
X	which()
X	{
X		eval last=\\"\\$$#\\"
X		set | sed \-n "/^$last(){$/,/^}$/p" |
X			/usr/local/bin/which \-i ${1+"$@"}
X	}
X
X.fi
X.ft R
XIf the `\fI\-a\fR' (= all) flag is given,
X.I which
Xwill not stop after the first `match', but search for all occurrences of
X.I command
Xin the user's
X.I PATH.
XThe `\fI\-\-\fR'
Xflag can be used to end the list of options: the next argument (if present)
Xwill be taken as \fIcommand\fR, even if it starts with a `\-'.
X\fIWhich [\-i] [\-a] [\-\-]\fR
Xwithout further arguments 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.
X.SH EXAMPLE
X.ft B
X.nf
X% alias
Xwhich	alias !$ | /usr/local/bin/which \-i !*
X% which which
Xwhich	alias !$ | /usr/local/bin/which \-i !*
X% which \-a which
Xwhich	alias !$ | /usr/local/bin/which \-i !*
X/usr/local/bin/which
X/usr/ucb/which
X%
X.fi
X.ft R
X.SH AUTHOR
XMaarten Litmaath @ VU Informatika 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
2205)	:;;
*)	echo 'Bad character count in ''which.1' >&2
		echo 'Count should be 2205' >&2
esac
echo Extracting 'which.c'
sed 's/^X//' > 'which.c' << '+ END-OF-FILE ''which.c'
X/*
X * which [-i] [-a] [--] [<command>]
X * alias which alias !\$ \| /usr/local/bin/which -i !\*
X * alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}'
X * which()
X * {
X *	eval last=\"\$$#\"
X *	set | sed -n "/^$last(){$/,/^}$/p" |
X *		/usr/local/bin/which -i ${1+"$@"}
X * }
X *
X * author: Maarten Litmaath @ VU University 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 * second change:
X *	added support for shell functions and multiline aliases, added the
X *	`--' option, changed the source style
X */
X
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<stdio.h>
X
X#define		BUF_SIZE	512
X
Xchar	Version[] =
X	"@(#)which 3.0 89/09/21 Maarten Litmaath @ VU Informatika Amsterdam";
Xchar	*Prog;
X
X
Xvoid	usage()
X{
X	fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog);
X	exit(1);
X}
X
X
Xmain(argc, argv) 
Xint	argc;
Xregister char	**argv;
X{
X	register char	*path, *s;
X	char	*save, *strcpy(), *getenv(), *fgets(), buf[BUF_SIZE];
X	int	all = 0, inter = 0, stop = 0, found = 0, uid;
X	struct	stat	st;
X	void	usage(), convert();
X
X
X	Prog = *argv++;
X	--argc;
X
X	while (!stop && (s = *argv) && (*s == '-')) {
X		++argv;
X		--argc;
X		++s;
X		while (*s)
X			switch (*s++) {
X			case 'a':
X				all = 1;
X				break;
X			case 'i':
X				inter = 1;
X				break;
X			case '-':
X				stop = 1;
X				break;
X			default:
X				usage();
X			}
X	}
X
X	if (argc > 1)
X		usage();
X
X	if (inter && *argv) {
X		while (fgets(buf, sizeof buf, stdin)) {
X			if (!found) {
X				printf("%s", *argv);
X				found = 1;
X			}
X			printf("\t%s", buf);
X		}
X		if (found && !all)
X			exit(0);
X	}
X
X	if (!(save = path = getenv("PATH"))) {
X		fprintf(stderr, "%s: no PATH in environment!\n", Prog);
X		exit(1);
X	}
X
X	if (!*path)
X		save = path = ".";
X
X	if (!*argv) {
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,
X				"%s: %s found in unreadable directory %s!\n",
X				Prog, *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, "%s not found in\n%s\n", *argv, buf);
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
3392)	:;;
*)	echo 'Bad character count in ''which.c' >&2
		echo 'Count should be 3392' >&2
esac
exit 0
-- 
1755 EST, Dec 14, 1992: Henry Spencer is put on a one-way mission to the moon.|
  Maarten Litmaath @ VU Amsterdam:  maart@cs.vu.nl,  uunet!mcsun!botter!maart