tonyb@tektools.UUCP (Tony Birnseth) (12/12/86)
Index: /bin/csh 4.3BSD Description: /usr/ucb/which does not handle builtin csh commands and is slower than a slug! The following is an internal which command for csh. We had a long argument about the functionality of this command. Should it be useful and fast? Or should it be compatible with /usr/ucb/which? Unfortunately, the compatibility argument won out. However it should be easy enough for a site to remove the -u option stuff and get a reasonably fast useful, which command. Fix: Apply the following diffs to sh.func.c and sh.init.c. *** /tmp/,RCSt1027852 Thu Dec 11 17:03:03 1986 --- sh.func.c Thu Dec 11 16:58:59 1986 *************** *** 1149,1151 if (reenter >= 2) error(NOSTR); } --- 1170,1325 ----- if (reenter >= 2) error(NOSTR); } + + + #ifdef TEK_MODS + + /* + * After much disucussion, it was decided to have this fast clean internal + * version of 'which' produce the same ugly output as it slower counterpart + * /usr/ucb/which. A -u (useful) flag was added to allow a user to alias + * which to which -u for a cleaner more useful form of the command. + * tonyb@tek + */ + dowhich(vec) + char **vec; + { + register struct biltins *bp; + register char *word, **pp, *func; + struct varent *vp, *pth; + char dir[MAXPATHLEN+1]; + int cmp, hit, outty, uflag; + + + /* + * Glob it up + */ + uflag = gflag = 0; + tglob(++vec); + if(gflag) { /* has globbing chars */ + vec = glob(vec); /* glob it */ + if(vec == 0) + bferr("No match"); + } else + trim( vec ); + + pth = adrof("path"); + + /* + * Find out if we're writting to a tty. If not, use "command type" + * output, else use "user" type output. + * command type output is used to do things like 'echo `which foobar`' + */ + outty = isatty(1); + + /* + * If no -u, go into useless mode, else provide useable, + * coherent output. + */ + if(eq(*vec,"-u")) { + uflag++; + vec++; + } + + while(word = *vec++) { + + /* + * check aliases first. + */ + vp = adrof1(word, &aliases); + if(vp) { + if(!uflag) { + printf("%s: \t aliased to '", word); + blkpr(vp->vec);printf("'\n"); + } else if(outty) { + printf("alias/%s '", word); + blkpr(vp->vec); printf("'\n"); + } else + printf("%s\n",word); + continue; + } + + /* + * If a hard path, just return it if it is executable, else + * return nothing. + */ + if(index(word, '/') ) { + if(executable(word)) { + printf("%s\n",word); + continue; + } + else if( !uflag ) { + printf("%s not found\n", word); + continue; + } + } + + /* + * Check builtins + * "standard" /usr/ucb/which does not support the concept + * of builtin commands. YUK!!! + */ + if(uflag) { + hit = 0; + for(bp=bfunc; func = bp->bname; bp++) { + cmp = strcmp(func, word); + if(cmp == 0) { + if(outty) + printf("builtin/%s\n",word); + else + printf("%s\n",word); + hit++; + } + else if(cmp > 0) + break; + } + if(hit) + continue; + } + + + /* + * Check the paths + * No need to read 'em, just check if it is executable. + */ + if(pth) { + register char *ep; + + hit = 0; + for(pp = pth->vec; pp && *pp && **pp; pp++) { + ep = strcpy(dir,*pp); + while(*ep) + ep++; + *ep++ = '/'; + strcpy(ep,word); + if(executable(dir)) { + printf("%s\n",dir); + hit++; + break; + } + } + } + + /* + * If not found and in useless mode + */ + if(!hit && !uflag) { + printf("no %s in ", word); + blkpr(pth->vec); + printf("\n"); + } + } /* end while */ + } + + + executable(path) + register char *path; + { + struct stat st; + + if(access(path,1) || stat(path, &st) ) + st.st_mode = 0; + return( (st.st_mode & S_IFMT) == S_IFREG); + } + #endif /* TEK_MODS */ + *** /tmp/,RCSt1027862 Thu Dec 11 17:03:14 1986 --- sh.init.c Thu Dec 11 12:47:00 1986 *************** *** 77,82 extern int dounhash(); extern int unset(); extern int dounsetenv(); #define INF 1000 --- 77,85 ----- extern int dounhash(); extern int unset(); extern int dounsetenv(); + #ifdef TEK_MODS + extern int dowhich(); + #endif /* TEK_MODS */ #define INF 1000 *************** *** 153,158 "unlimit", dounlimit, 0, INF, "unset", unset, 1, INF, "unsetenv", dounsetenv, 1, INF, "wait", dowait, 0, 0, "while", dowhile, 1, INF, }; --- 160,168 ----- "unlimit", dounlimit, 0, INF, "unset", unset, 1, INF, "unsetenv", dounsetenv, 1, INF, + #ifdef TEK_MODS + "which", dowhich, 1, INF, + #endif /* TEK_MODS */ "wait", dowait, 0, 0, "while", dowhile, 1, INF, };
dgc@ulysses.cs.ucla.edu (David G Cantor) (12/13/86)
Summary:
Expires:
Sender:
Followup-To:
Distribution:
In article <1991@tektools.UUCP> tonyb@tektools.UUCP (Tony Birnseth)
gives a mod to the csh which supports builtin commands and aliases.
Here is a simplified which which does support aliases for the csh
(correctly) and is compatible with the Bourne shell. It requires a one
line alias in the .cshrc file to handle aliases. If not present it
functions as the Berkeley which. It can be put in a users bin or in a
local bin (i.e. no mods to the "system" are required).
dgc
David G. Cantor
Internet: dgc@cs.ucla.edu
UUCP: ...!{ihnp4, randvax, sdcrdcf, ucbvax}!ucla-cs!dgc
/*
* Does a quick "which".
*
* To get aliases when using the cshell, put the following
* in your ".cshrc":
*
* alias which "this-function" whichalias \!^ \`alias \!^\`
*
* where "this-function" is replaced by the (completely-qualified)
* name of this function.
*
*/
#include <stdio.h>
main(argc, argv) int argc; char **argv; {
register char *path, *tp;
char *getenv(), tmp[4096], file[4096];
int end = 0;
if (argc < 2) exit(0);
path = getenv("PATH");
if (argc > 3) {
if (strcmp(*++argv, "whichalias") || *argv[2] <= 32) exit(0);
sprintf(file, "%s is an alias: ", *++argv);
while (*++argv) {strcat(file, " "); strcat(file, *argv);}
strcat(file, "\n");
printf(file);
exit(0);}
if (argc == 3 && strcmp(*++argv, "whichalias")) exit(0);
argv++;
while(1) {
tp = tmp;
while(1) {
*tp++ = *path++;
if (*(path-1) == ':') {*--tp = '\0'; break;}
else if (*(path-1) == '\0') {end++; break;} }
if (!access(tmp, 4)) {
sprintf(file, "%s/%s", tmp, *argv);
if (!access(file, 1)) printf("%s\n", file), exit(0);}
if (end) break;}
printf("%s not found\n", *argv);
exit(0);}