+/* Also by:
+ * Andreas Luik <luik@isaak.isa.de>
+ * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
+ * Azenberstr. 35
+ * D-7000 Stuttgart 1
+ * West-Germany
+ * is the executable() routine below and changes to iscommand().
+ * Thanks again!!
+ */
+
+/*
+ * executable() examines the pathname obtained by concatenating dir and name
+ * (dir may be NULL), and returns 1 either if it is executable by us, or
+ * if dir_ok is set and the pathname refers to a directory.
+ * This is a bit kludgy, but in the name of optimization...
+ */
+static int
+executable(dir, name, dir_ok)
+ Char *dir, *name;
+ bool dir_ok;
+{
+ struct stat stbuf;
+ Char path[MAXPATHLEN + 1], *dp, *sp;
+ char *strname;
+
+ if (dir && *dir) {
+ for (dp = path, sp = dir; *sp; *dp++ = *sp++)
+ if (dp == &path[MAXPATHLEN + 1]) {
+ *--dp = '\0';
+ break;
+ }
+ for (sp = name; *sp; *dp++ = *sp++)
+ if (dp == &path[MAXPATHLEN + 1]) {
+ *--dp = '\0';
+ break;
+ }
+ *dp = '\0';
+ strname = short2str(path);
+ }
+ else
+ strname = short2str(name);
+ return (stat(strname, &stbuf) != -1 &&
+ ((S_ISREG(stbuf.st_mode) &&
+ /* save time by not calling access() in the hopeless case */
+ (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
+ access(strname, X_OK) == 0) ||
+ (dir_ok && S_ISDIR(stbuf.st_mode))));
+}
+
+/* The dowhich() is by:
+ * Andreas Luik <luik@isaak.isa.de>
+ * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
+ * Azenberstr. 35
+ * D-7000 Stuttgart 1
+ * West-Germany
+ * Thanks!!
+ */
+/*ARGSUSED*/
+void
+dowhich(v, c)
+ register Char **v;
+ struct command *c;
+{
+ struct wordent lex[3];
+ struct varent *vp;
+
+ lex[0].next = &lex[1];
+ lex[1].next = &lex[2];
+ lex[2].next = &lex[0];
+
+ lex[0].prev = &lex[2];
+ lex[1].prev = &lex[0];
+ lex[2].prev = &lex[1];
+
+ lex[0].word = STRNULL;
+ lex[2].word = STRret;
+
+ while (*++v) {
+ if ((vp = adrof1(*v, &aliases)) != NULL) {
+ (void) fprintf(cshout, "%s: \t aliased to ", vis_str(*v));
+ blkpr(cshout, vp->vec);
+ (void) fputc('\n', cshout);
+ }
+ else {
+ lex[1].word = *v;
+ tellmewhat(lex);
+ }
+ }
+}
+
+static void
+tellmewhat(lex)
+ struct wordent *lex;
+{
+ register int i;
+ register struct biltins *bptr;
+ register struct wordent *sp = lex->next;
+ bool aliased = 0;
+ Char *s0, *s1, *s2, *cmd;
+ Char qc;
+
+ if (adrof1(sp->word, &aliases)) {
+ alias(lex);
+ sp = lex->next;
+ aliased = 1;
+ }
+
+ s0 = sp->word; /* to get the memory freeing right... */
+
+ /* handle quoted alias hack */
+ if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
+ (sp->word)++;
+
+ /* do quoting, if it hasn't been done */
+ s1 = s2 = sp->word;
+ while (*s2)
+ switch (*s2) {
+ case '\'':
+ case '"':
+ qc = *s2++;
+ while (*s2 && *s2 != qc)
+ *s1++ = *s2++ | QUOTE;
+ if (*s2)
+ s2++;
+ break;
+ case '\\':
+ if (*++s2)
+ *s1++ = *s2++ | QUOTE;
+ break;
+ default:
+ *s1++ = *s2++;
+ }
+ *s1 = '\0';
+
+ for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
+ if (eq(sp->word, str2short(bptr->bname))) {
+ if (aliased)
+ prlex(cshout, lex);
+ (void) fprintf(cshout, "%s: shell built-in command.\n",
+ vis_str(sp->word));
+ sp->word = s0; /* we save and then restore this */
+ return;
+ }
+ }
+
+ sp->word = cmd = globone(sp->word, G_IGNORE);
+
+ if ((i = iscommand(strip(sp->word))) != 0) {
+ register Char **pv;
+ register struct varent *v;
+ bool slash = any(short2str(sp->word), '/');
+
+ v = adrof(STRpath);
+ if (v == 0 || v->vec[0] == 0 || slash)
+ pv = justabs;
+ else
+ pv = v->vec;
+
+ while (--i)
+ pv++;
+ if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
+ if (!slash) {
+ sp->word = Strspl(STRdotsl, sp->word);
+ prlex(cshout, lex);
+ xfree((ptr_t) sp->word);
+ }
+ else
+ prlex(cshout, lex);
+ sp->word = s0; /* we save and then restore this */
+ xfree((ptr_t) cmd);
+ return;
+ }
+ s1 = Strspl(*pv, STRslash);
+ sp->word = Strspl(s1, sp->word);
+ xfree((ptr_t) s1);
+ prlex(cshout, lex);
+ xfree((ptr_t) sp->word);
+ }
+ else {
+ if (aliased)
+ prlex(cshout, lex);
+ (void) fprintf(csherr, "%s: Command not found.\n", vis_str(sp->word));
+ }
+ sp->word = s0; /* we save and then restore this */
+ xfree((ptr_t) cmd);