*BSD News Article 78821


Return to BSD News archive

Newsgroups: comp.bugs.2bsd
Path: euryale.cc.adfa.oz.au!newshost.carno.net.au!harbinger.cc.monash.edu.au!news.mira.net.au!news.mel.connect.com.au!munnari.OZ.AU!news.ecn.uoknor.edu!news.wildstar.net!cancer.vividnet.com!hunter.premier.net!news1.erols.com!howland.erols.net!newsfeed.internetmci.com!in2.uu.net!news.new-york.net!wlbr!moe.2bsd.com!sms
From: sms@moe.2bsd.com (Steven M. Schultz)
Subject: csh lacks 'which' builtin (#330)
Organization: 2BSD, Simi Valley CA USA
Message-ID: <Dy49xF.FAH@moe.2bsd.com>
Date: Sun, 22 Sep 1996 04:32:03 GMT
Lines: 728

Subject: csh lacks 'which' builtin (#330)
Index:	bin/csh/sh.exec.c,sh.exec2.c,sh.h 2.11BSD

Description:
	csh does not have the 'which' command as a builtin.  This causes
	the very slow script /usr/ucb/which to be used.

	tcsh has 'which' as a builtin as does 4.4BSD's csh.

Repeat-By:
	time which which
	/usr/ucb/which
	1.4u  1.5s  0:03  76%  44+5io 3ov 0sw

Fix:
	The 'which' code was borrowed from 4.4-Lite2's csh source. 

	To ease porting the /sys/h/stat.h file was augmented with the
	macros for testing the file type (S_IFDIR, etc).

	Adding 'which' caused the sh.exec.o module to become too large for
	the overlay it resided in.  To get around this a new source module
	(sh.exec2.c) was created.  This new module was then placed into
	the second overlay.

	sh.exec2.c referenced the hash macros and definitions so these
	were moved from sh.exec.c into an include file (sh.exec.h).

	After rebuilding and installing csh the 'which' command is almost
	instantaneous:

Script started on Sat Sep 21 21:05:21 1996
# time which which
which: shell built-in command.
0.0u 0.0s 0:00 83% 0+0io 2ov 0sw
# exit
# 
script done on Sat Sep 21 21:05:31 1996

	The update consists of two files:  a shar archive of new files to
	be added to the system and a patch file which updates existing files.

	To install this update cut where indicated, saving to a file (/tmp/330).

	Then:

		cd /tmp
		sh 330
		sh 330.shar
		patch -p0 < 330.patch
		cd /usr/src/bin/csh
		make csh tags
		make install
		make clean

	It will be necessary to log out and back in for the new shell to
	take effect.

	This and previous updates are available via anonymous FTP to either
	FTP.IIPO.GTEGSC.COM or MOE.2BSD.COM in the directory /pub/2.11BSD.

---------------------------cut here---------------------------
#! /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:
#	330.patch
#	330.shar
# This archive created: Sat Sep 21 21:15:39 1996
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f '330.patch'
then
	echo shar: "will not over-write existing file '330.patch'"
else
sed 's/^X//' << \SHAR_EOF > '330.patch'
X*** /usr/src/bin/csh/Makefile.old	Sat Apr  9 00:19:41 1994
X--- /usr/src/bin/csh/Makefile	Sat Sep 21 20:36:13 1996
X***************
X*** 3,9 ****
X  # All rights reserved.  The Berkeley Software License Agreement
X  # specifies the terms and conditions for redistribution.
X  #
X! #	@(#)Makefile	5.3.1 (2.11BSD GTE) 4/9/94
X  #
X  # C Shell with process control; VM/UNIX VAX Makefile
X  # Bill Joy UC Berkeley; Jim Kulp IIASA, Austria
X--- 3,9 ----
X  # All rights reserved.  The Berkeley Software License Agreement
X  # specifies the terms and conditions for redistribution.
X  #
X! #	@(#)Makefile	5.3.2 (2.11BSD GTE) 1996/9/20
X  #
X  # C Shell with process control; VM/UNIX VAX Makefile
X  # Bill Joy UC Berkeley; Jim Kulp IIASA, Austria
X***************
X*** 29,36 ****
X  	sh.init.o sh.lex.o sh.misc.o sh.parse.o sh.print.o sh.proc.o sh.sem.o \
X  	sh.set.o
X  OV1= 	sh.o sh.exec.o sh.time.o
X  
X! OBJS=	${BASE} ${OV1}
X  
X  LIBOBJS= ndbm.o getpwent.o
X  
X--- 29,37 ----
X  	sh.init.o sh.lex.o sh.misc.o sh.parse.o sh.print.o sh.proc.o sh.sem.o \
X  	sh.set.o
X  OV1= 	sh.o sh.exec.o sh.time.o
X+ OV2=	sh.exec2.o
X  
X! OBJS=	${BASE} ${OV1} ${OV2}
X  
X  LIBOBJS= ndbm.o getpwent.o
X  
X***************
X*** 47,53 ****
X  	rm -f csh
X  	/bin/ld ${SEPFLAG} /lib/crt0.o ${BASE} \
X  		-Z ${OV1} \
X! 		-Z ${LIBOBJS} \
X  		-Y strings.o -o csh ${LIBES};
X  
X  .DEFAULT:
X--- 48,54 ----
X  	rm -f csh
X  	/bin/ld ${SEPFLAG} /lib/crt0.o ${BASE} \
X  		-Z ${OV1} \
X! 		-Z ${OV2} ${LIBOBJS} \
X  		-Y strings.o -o csh ${LIBES};
X  
X  .DEFAULT:
X***************
X*** 91,97 ****
X  	${VGRIND} -t -x -h Index index >grind/index.t
X  
X  install: csh
X! 	install -s csh ${DESTDIR}/bin/csh
X  
X  clean:
X  	${RM} -f a.out strings x.c xs.c csh errs
X--- 92,98 ----
X  	${VGRIND} -t -x -h Index index >grind/index.t
X  
X  install: csh
X! 	install -m 755 -o bin -g bin -s csh ${DESTDIR}/bin/csh
X  
X  clean:
X  	${RM} -f a.out strings x.c xs.c csh errs
X***************
X*** 98,104 ****
X  	${RM} -f *.o
X  	${RM} -rf vgrind
X  
X! tags:
X  	${CTAGS} -t *.h sh*.c
X  
X  sh.o: sh.h sh.local.h sh.char.h
X--- 99,105 ----
X  	${RM} -f *.o
X  	${RM} -rf vgrind
X  
X! tags:	*.h sh*.c
X  	${CTAGS} -t *.h sh*.c
X  
X  sh.o: sh.h sh.local.h sh.char.h
X***************
X*** 107,112 ****
X--- 108,114 ----
X  sh.dol.o: sh.h sh.local.h sh.char.h
X  sh.err.o: sh.h sh.local.h sh.char.h
X  sh.exec.o: sh.h sh.local.h sh.char.h
X+ sh.exec2.o: sh.h sh.local.h sh.char.h
X  sh.exp.o: sh.h sh.local.h sh.char.h
X  sh.file.o: sh.h sh.local.h sh.char.h
X  sh.func.o: sh.h sh.local.h sh.char.h
X*** /usr/src/bin/csh/sh.exec.c.old	Sat Mar 30 23:09:13 1996
X--- /usr/src/bin/csh/sh.exec.c	Sat Sep 21 20:17:59 1996
X***************
X*** 5,11 ****
X   */
X  
X  #if	!defined(lint) && defined(DOSCCS)
X! static char *sccsid = "@(#)sh.exec.c	5.2.1 (2.11BSD) 1996/3/20";
X  #endif
X  
X  #include "sh.h"
X--- 5,11 ----
X   */
X  
X  #if	!defined(lint) && defined(DOSCCS)
X! static char *sccsid = "@(#)sh.exec.c	5.2.2 (2.11BSD) 1996/9/20";
X  #endif
X  
X  #include "sh.h"
X***************
X*** 33,61 ****
X  char	*exerr;			/* Execution error message */
X  char	*expath;		/* Path for exerr */
X  
X! /*
X!  * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
X!  * to hash execs.  If it is allocated (havhash true), then to tell
X!  * whether ``name'' is (possibly) present in the i'th component
X!  * of the variable path, you look at the bit in xhash indexed by
X!  * hash(hashname("name"), i).  This is setup automatically
X!  * after .login is executed, and recomputed whenever ``path'' is
X!  * changed.
X!  * The two part hash function is designed to let texec() call the
X!  * more expensive hashname() only once and the simple hash() several
X!  * times (once for each path component checked).
X!  * Byte size is assumed to be 8.
X!  */
X! #define	HSHSIZ		8192			/* 1k bytes */
X! #define HSHMASK		(HSHSIZ - 1)
X! #define HSHMUL		243
X! char	xhash[HSHSIZ / 8];
X! #define hash(a, b)	((a) * HSHMUL + (b) & HSHMASK)
X! #define bit(h, b)	((h)[(b) >> 3] & 1 << ((b) & 7))	/* bit test */
X! #define bis(h, b)	((h)[(b) >> 3] |= 1 << ((b) & 7))	/* bit set */
X! #ifdef VFORK
X! int	hits, misses;
X! #endif
X  
X  /* Dummy search path for just absolute search when no path */
X  char	*justabs[] =	{ "", 0 };
X--- 33,39 ----
X  char	*exerr;			/* Execution error message */
X  char	*expath;		/* Path for exerr */
X  
X! #include "sh.exec.h"
X  
X  /* Dummy search path for just absolute search when no path */
X  char	*justabs[] =	{ "", 0 };
X***************
X*** 297,303 ****
X  		dirp = opendir(*pv);
X  		if (dirp == NULL)
X  			continue;
X! 		if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
X  			closedir(dirp);
X  			continue;
X  		}
X--- 275,281 ----
X  		dirp = opendir(*pv);
X  		if (dirp == NULL)
X  			continue;
X! 		if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) {
X  			closedir(dirp);
X  			continue;
X  		}
X*** /usr/src/bin/csh/sh.glob.c.old	Sat Aug 31 00:08:21 1991
X--- /usr/src/bin/csh/sh.glob.c	Fri Sep 20 01:34:49 1996
X***************
X*** 5,11 ****
X   */
X  
X  #if	!defined(lint) && defined(DOSCCS)
X! static char *sccsid = "@(#)sh.glob.c	5.4 (Berkeley) 5/13/86";
X  #endif
X  
X  #include "sh.h"
X--- 5,11 ----
X   */
X  
X  #if	!defined(lint) && defined(DOSCCS)
X! static char *sccsid = "@(#)sh.glob.c	5.4.1 (2.11BSD) 1996/9/20";
X  #endif
X  
X  #include "sh.h"
X***************
X*** 189,195 ****
X  	}
X  	if (fstat(dirp->dd_fd, &stb) < 0)
X  		goto patherr1;
X! 	if (!isdir(stb)) {
X  		errno = ENOTDIR;
X  		goto patherr1;
X  	}
X--- 189,195 ----
X  	}
X  	if (fstat(dirp->dd_fd, &stb) < 0)
X  		goto patherr1;
X! 	if (!S_ISDIR(stb.st_mode)) {
X  		errno = ENOTDIR;
X  		goto patherr1;
X  	}
X***************
X*** 376,382 ****
X  			while (*s)
X  				addpath(*s++);
X  			addpath('/');
X! 			if (stat(gpath, &stb) == 0 && isdir(stb))
X  				if (*p == 0) {
X  					Gcat(gpath, "");
X  					globcnt++;
X--- 376,382 ----
X  			while (*s)
X  				addpath(*s++);
X  			addpath('/');
X! 			if (stat(gpath, &stb) == 0 && S_ISDIR(stb.st_mode))
X  				if (*p == 0) {
X  					Gcat(gpath, "");
X  					globcnt++;
X*** /usr/src/bin/csh/sh.h.old	Mon Jan 10 21:38:15 1994
X--- /usr/src/bin/csh/sh.h	Fri Sep 20 01:27:43 1996
X***************
X*** 3,9 ****
X   * All rights reserved.  The Berkeley Software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)sh.h	5.3.1 (2.11BSD GTE) 1/1/94
X   */
X  
X  #include <sys/time.h>
X--- 3,9 ----
X   * All rights reserved.  The Berkeley Software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)sh.h	5.3.2 (2.11BSD GTE) 1996/9/20
X   */
X  
X  #include <sys/time.h>
X***************
X*** 25,32 ****
X   * Jim Kulp, IIASA, Laxenburg Austria
X   * April, 1980
X   */
X- 
X- #define	isdir(d)	((d.st_mode & S_IFMT) == S_IFDIR)
X  
X  typedef	char	bool;
X  
X--- 25,30 ----
X*** /usr/src/bin/csh/sh.init.c.old	Sat Aug 31 00:09:14 1991
X--- /usr/src/bin/csh/sh.init.c	Fri Sep 20 00:19:18 1996
X***************
X*** 5,11 ****
X   */
X  
X  #if	!defined(lint) && defined(DOSCCS)
X! static char *sccsid = "@(#)sh.init.c	5.2 (Berkeley) 6/6/85";
X  #endif
X  
X  #include "sh.local.h"
X--- 5,11 ----
X   */
X  
X  #if	!defined(lint) && defined(DOSCCS)
X! static char *sccsid = "@(#)sh.init.c	5.2.1 (2.11BSD) 1996/9/20";
X  #endif
X  
X  #include "sh.local.h"
X***************
X*** 66,71 ****
X--- 66,72 ----
X  extern	int doumask();
X  extern	int dowait();
X  extern	int dowhile();
X+ extern	int dowhich();
X  extern	int dozip();
X  extern	int execash();
X  extern	int goodbye();
X***************
X*** 159,164 ****
X--- 160,166 ----
X  	"unset",	unset,		1,	INF,
X  	"unsetenv",	dounsetenv,	1,	INF,
X  	"wait",		dowait,		0,	0,
X+ 	"which",	dowhich,	1,	INF,
X  	"while",	dowhile,	1,	INF,
X  };
X  int nbfunc = sizeof bfunc / sizeof *bfunc;
X*** /usr/src/sys/h/stat.h.old	Mon Mar 13 21:06:42 1995
X--- /usr/src/sys/h/stat.h	Fri Sep 20 00:50:01 1996
X***************
X*** 3,9 ****
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)stat.h	7.1.4 (2.11BSD) 1995/03/13
X   */
X  
X  #ifndef	_STAT_H_
X--- 3,9 ----
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)stat.h	7.1.5 (2.11BSD) 1996/09/20
X   */
X  
X  #ifndef	_STAT_H_
X***************
X*** 65,70 ****
X--- 65,75 ----
X  #define S_IROTH 0000004		/* R for other */
X  #define S_IWOTH 0000002		/* W for other */
X  #define S_IXOTH 0000001		/* X for other */
X+ 
X+ #define	S_ISDIR(m)	((m & 0170000) == 0040000)	/* directory */
X+ #define	S_ISCHR(m)	((m & 0170000) == 0020000)	/* char special */
X+ #define	S_ISBLK(m)	((m & 0170000) == 0060000)	/* block special */
X+ #define	S_ISREG(m)	((m & 0170000) == 0100000)	/* regular file */
X  
X  /*
X   * Definitions of flags stored in file flags word.  Different from 4.4 because
X*** /VERSION.old	Sun Sep 15 22:15:36 1996
X--- /VERSION	Mon Sep 16 21:00:09 1996
X***************
X*** 1,4 ****
X! Current Patch Level: 329
X  
X  2.11 BSD
X  ============
X--- 1,4 ----
X! Current Patch Level: 330
X  
X  2.11 BSD
X  ============
SHAR_EOF
fi
if test -f '330.shar'
then
	echo shar: "will not over-write existing file '330.shar'"
else
sed 's/^X//' << \SHAR_EOF > '330.shar'
X#! /bin/sh
X# This is a shell archive, meaning:
X# 1. Remove everything above the #! /bin/sh line.
X# 2. Save the resulting text in a file.
X# 3. Execute the file with /bin/sh (not csh) to create:
X#	/usr/src/bin/csh/sh.exec2.c
X#	/usr/src/bin/csh/sh.exec.h
X# This archive created: Sat Sep 21 20:46:01 1996
Xexport PATH; PATH=/bin:/usr/bin:$PATH
Xif test -f '/usr/src/bin/csh/sh.exec2.c'
Xthen
X	echo shar: "will not over-write existing file '/usr/src/bin/csh/sh.exec2.c'"
Xelse
Xsed 's/^Z//' << \SHAR_EOF > '/usr/src/bin/csh/sh.exec2.c'
XZ/*
XZ * From the 4.4-Lite2 CD's csh sources and modified appropriately.
XZ*/
XZ
XZ#if	!defined(lint) && defined(DOSCCS)
XZstatic char *sccsid = "@(#)sh.exec2.c	1.0 (2.11BSD) 1996/9/20";
XZ#endif
XZ
XZ#include "sh.h"
XZ#include <string.h>
XZ#include <sys/file.h>
XZ#include <sys/stat.h>
XZ#include <sys/dir.h>
XZ#include "sh.exec.h"
XZ
XZextern	char	*justabs[];	/* in sh.exec.c */
XZ
XZstatic int
XZiscommand(name)
XZ    char   *name;
XZ{
XZ    register char **pv;
XZ    register char *sav;
XZ    register struct varent *v;
XZ    bool slash = any(name, '/');
XZ    int hashval = 0, hashval1, i;
XZ
XZ    v = adrof("path");
XZ    if (v == 0 || v->vec[0] == 0 || slash)
XZ	pv = justabs;
XZ    else
XZ	pv = v->vec;
XZ    sav = strspl("/", name);	/* / command name for postpending */
XZ    if (havhash)
XZ	hashval = hashname(name);
XZ    i = 0;
XZ    do {
XZ	if (!slash && pv[0][0] == '/' && havhash) {
XZ	    hashval1 = hash(hashval, i);
XZ	    if (!bit(xhash, hashval1))
XZ		goto cont;
XZ	}
XZ	if (pv[0][0] == 0 || eq(pv[0], ".")) {	/* don't make ./xxx */
XZ	    if (executable(NULL, name, 0)) {
XZ		xfree(sav);
XZ		return i + 1;
XZ	    }
XZ	}
XZ	else {
XZ	    if (executable(*pv, sav, 0)) {
XZ		xfree(sav);
XZ		return i + 1;
XZ	    }
XZ	}
XZcont:
XZ	pv++;
XZ	i++;
XZ    } while (*pv);
XZ    xfree(sav);
XZ    return 0;
XZ}
XZ
XZ/* Also by:
XZ *  Andreas Luik <luik@isaak.isa.de>
XZ *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
XZ *  Azenberstr. 35
XZ *  D-7000 Stuttgart 1
XZ *  West-Germany
XZ * is the executable() routine below and changes to iscommand().
XZ * Thanks again!!
XZ */
XZ
XZ/*
XZ * executable() examines the pathname obtained by concatenating dir and name
XZ * (dir may be NULL), and returns 1 either if it is executable by us, or
XZ * if dir_ok is set and the pathname refers to a directory.
XZ * This is a bit kludgy, but in the name of optimization...
XZ */
XZstatic int
XZexecutable(dir, name, dir_ok)
XZ    char   *dir, *name;
XZ    bool    dir_ok;
XZ{
XZ    struct stat stbuf;
XZ    char    path[MAXPATHLEN + 1];
XZ    register char *dp, *sp;
XZ    char   *strname;
XZ
XZ    if (dir && *dir) {
XZ	for (dp = path, sp = dir; *sp; *dp++ = *sp++)
XZ	    if (dp == &path[MAXPATHLEN + 1]) {
XZ		*--dp = '\0';
XZ		break;
XZ	    }
XZ	for (sp = name; *sp; *dp++ = *sp++)
XZ	    if (dp == &path[MAXPATHLEN + 1]) {
XZ		*--dp = '\0';
XZ		break;
XZ	    }
XZ	*dp = '\0';
XZ	strname = path;
XZ    }
XZ    else
XZ	strname = name;
XZ    return (stat(strname, &stbuf) != -1 &&
XZ	    ((S_ISREG(stbuf.st_mode) &&
XZ    /* save time by not calling access() in the hopeless case */
XZ	      (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
XZ	      access(strname, X_OK) == 0) ||
XZ	     (dir_ok && S_ISDIR(stbuf.st_mode))));
XZ}
XZ/* The dowhich() is by:
XZ *  Andreas Luik <luik@isaak.isa.de>
XZ *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
XZ *  Azenberstr. 35
XZ *  D-7000 Stuttgart 1
XZ *  West-Germany
XZ * Thanks!!
XZ */
XZ/*ARGSUSED*/
XZvoid
XZdowhich(v, c)
XZ    register char **v;
XZ    struct command *c;
XZ{
XZ    struct wordent lex[3];
XZ    struct varent *vp;
XZ
XZ    lex[0].next = &lex[1];
XZ    lex[1].next = &lex[2];
XZ    lex[2].next = &lex[0];
XZ
XZ    lex[0].prev = &lex[2];
XZ    lex[1].prev = &lex[0];
XZ    lex[2].prev = &lex[1];
XZ
XZ    lex[0].word = "";
XZ    lex[2].word = "\n";
XZ
XZ    while (*++v) {
XZ	if ((vp = adrof1(*v, &aliases)) != NULL) {
XZ	    (void) printf("%s: \t aliased to ", *v);
XZ	    blkpr(vp->vec);
XZ	    (void) putchar('\n');
XZ	}
XZ	else {
XZ	    lex[1].word = *v;
XZ	    tellmewhat(lex);
XZ	}
XZ    }
XZ}
XZ
XZstatic void
XZtellmewhat(lex)
XZ    struct wordent *lex;
XZ{
XZ    int i;
XZ    struct biltins *bptr;
XZ    register struct wordent *sp = lex->next;
XZ    bool    aliased = 0;
XZ    register char   *s2;
XZ    char *s0, *s1, *cmd;
XZ    char    qc;
XZ
XZ    if (adrof1(sp->word, &aliases)) {
XZ	alias(lex);
XZ	sp = lex->next;
XZ	aliased = 1;
XZ    }
XZ
XZ    s0 = sp->word;		/* to get the memory freeing right... */
XZ
XZ    /* handle quoted alias hack */
XZ    if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
XZ	(sp->word)++;
XZ
XZ    /* do quoting, if it hasn't been done */
XZ    s1 = s2 = sp->word;
XZ    while (*s2)
XZ	switch (*s2) {
XZ	case '\'':
XZ	case '"':
XZ	    qc = *s2++;
XZ	    while (*s2 && *s2 != qc)
XZ		*s1++ = *s2++ | QUOTE;
XZ	    if (*s2)
XZ		s2++;
XZ	    break;
XZ	case '\\':
XZ	    if (*++s2)
XZ		*s1++ = *s2++ | QUOTE;
XZ	    break;
XZ	default:
XZ	    *s1++ = *s2++;
XZ	}
XZ    *s1 = '\0';
XZ
XZ    for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
XZ	if (eq(sp->word, bptr->bname)) {
XZ	    if (aliased)
XZ		prlex(lex);
XZ	    (void) printf("%s: shell built-in command.\n", sp->word);
XZ	    sp->word = s0;	/* we save and then restore this */
XZ	    return;
XZ	}
XZ    }
XZ
XZ    sp->word = cmd = globone(sp->word);
XZ
XZ    if ((i = iscommand(strip(sp->word))) != 0) {
XZ	register char **pv;
XZ	register struct varent *v;
XZ	bool    slash = any(sp->word, '/');
XZ
XZ	v = adrof("path");
XZ	if (v == 0 || v->vec[0] == 0 || slash)
XZ	    pv = justabs;
XZ	else
XZ	    pv = v->vec;
XZ
XZ	while (--i)
XZ	    pv++;
XZ	if (pv[0][0] == 0 || eq(pv[0], ".")) {
XZ	    if (!slash) {
XZ		sp->word = strspl("./", sp->word);
XZ		prlex(lex);
XZ		xfree(sp->word);
XZ	    }
XZ	    else
XZ		prlex(lex);
XZ	    sp->word = s0;	/* we save and then restore this */
XZ	    xfree(cmd);
XZ	    return;
XZ	}
XZ	s1 = strspl(*pv, "/");
XZ	sp->word = strspl(s1, sp->word);
XZ	xfree(s1);
XZ	prlex(lex);
XZ	xfree(sp->word);
XZ    }
XZ    else {
XZ	if (aliased)
XZ	    prlex(lex);
XZ	(void) printf("%s: Command not found.\n", sp->word);
XZ    }
XZ    sp->word = s0;		/* we save and then restore this */
XZ    xfree(cmd);
XZ}
XSHAR_EOF
Xchmod 644 '/usr/src/bin/csh/sh.exec2.c'
Xfi
Xif test -f '/usr/src/bin/csh/sh.exec.h'
Xthen
X	echo shar: "will not over-write existing file '/usr/src/bin/csh/sh.exec.h'"
Xelse
Xsed 's/^Z//' << \SHAR_EOF > '/usr/src/bin/csh/sh.exec.h'
XZ/*
XZ * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
XZ * to hash execs.  If it is allocated (havhash true), then to tell
XZ * whether ``name'' is (possibly) present in the i'th component
XZ * of the variable path, you look at the bit in xhash indexed by
XZ * hash(hashname("name"), i).  This is setup automatically
XZ * after .login is executed, and recomputed whenever ``path'' is
XZ * changed.
XZ * The two part hash function is designed to let texec() call the
XZ * more expensive hashname() only once and the simple hash() several
XZ * times (once for each path component checked).
XZ * Byte size is assumed to be 8.
XZ */
XZ#define	HSHSIZ		8192			/* 1k bytes */
XZ#define HSHMASK		(HSHSIZ - 1)
XZ#define HSHMUL		243
XZchar	xhash[HSHSIZ / 8];
XZ#define hash(a, b)	((a) * HSHMUL + (b) & HSHMASK)
XZ#define bit(h, b)	((h)[(b) >> 3] & 1 << ((b) & 7))	/* bit test */
XZ#define bis(h, b)	((h)[(b) >> 3] |= 1 << ((b) & 7))	/* bit set */
XZ#ifdef VFORK
XZint	hits, misses;
XZ#endif
XSHAR_EOF
Xchmod 644 '/usr/src/bin/csh/sh.exec.h'
Xfi
Xexit 0
X#	End of shell archive
SHAR_EOF
fi
exit 0
#	End of shell archive