[comp.sources.misc] v03i024: fast 'which

mjr@welchsun2.UUCP (Marcus J. Ranum) (05/25/88)

comp.sources.misc: Volume 3, Issue 24
Submitted-By: "Marcus J. Ranum" <mjr@welchsun2.UUCP>
Archive-Name: which

	A really quickie version of the 'which(ucb)' command. No excuses
for the looks, but it runs and is (as far as I can tell) "compatible"
and a lot faster than having to invoke the C-shell. For SYSV compile it
with -DSYSV - I think it should work.

uunet!mimsy!aplcen!osiris!welchvax!mjr
mjr@jhuigf.BITNET

-------cut------cut--------cut--------cut--------cut--------cut-------
#ifndef lint
static char *RCSid="$Header: which.c,v 1.2 88/05/24 19:29:53 mjr Exp $";
#endif

 /*
 *	Marcus Ranum, December 10, 1987 - a really fast and dirty hack-
 *	VERY tired of waiting for that idiot C shell script.
 *	actually this code is hacked from several of my other programs,
 *	hence the incoherence.
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>

char	*path = 0;

static void
prpath(str)
char	*str;
{
	char	*cp	= str;
	while(cp && *cp) {
		if(*cp == ':')
			putchar(' ');
		else
			putchar(*cp);
		cp++;
	}
	putchar('\n');
}

main(ac,av)
int	ac;
char	*av[];
{
	int	ret;
	extern	char	*getenv();

	if((path = getenv("PATH")) == NULL) {
		(void)fprintf(stderr,"no PATH in environment\n");
		exit(1);
	}


	for(ret =1; ret < ac; ret++){
		char	*todo, *xpath();

		if(!(todo = xpath(av[ret]))) {
			(void)printf("no \"%s\" in ",av[ret]);
			prpath(path);
		} else {
			puts(todo);
		}
	}
	exit(0);
}

static char	*
xpath(exe)
char	*exe;
{
	char	*ptr, *doxpath();
#ifndef SYSV
	extern	char	*index();
#else
	extern	char	*strchr();
#endif

	/* read the path and search for the first thing that matches */
	/* the name of the program */

	/* first check if absolute or relative path */
#ifndef SYSV
	if(exe[0] == '/' || index(exe, '/'))
#else
	if(exe[0] == '/' || strchr(exe, '/'))
#endif
		return(doxpath(exe));


	ptr = path;

	/* somewhat gnarly */
	while(*ptr) {
		char	pbuf[MAXPATHLEN];	/* thing to build path in */
		char	*p = pbuf, *p2 = exe;

		while(*ptr && *ptr != ':')
			*p++ = *ptr++;
		*p++ = '/';
		while(*p2)
			*p++ = *p2++;
		*p++ = '\0';
		if (p2 = doxpath(pbuf))
			return(p2);
		if(*ptr == ':')
			ptr++;
	} 
	return((char *)NULL);
}

static char	*
doxpath(path)
char	*path;
{
	struct stat	sbuf;

	if (!stat(path, &sbuf))
		if ((sbuf.st_mode & S_IFMT) == S_IFREG && (sbuf.st_mode & ~S_IFMT & S_IEXEC))
			return(path);
	return((char *) 0);
}