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