#include #include #include const char * CopyRightString = "Copyright 2001 David Lee Lambert"; /* *** which.c purpose: show where an executable program that will be executed actually is. I hacked this together on a rainy Saturday afternoon. Apologies for the coding-style; however, it compiles just fine (and is functional) under three different compilers: [DJGPP 2.x - gcc 2.7.2.1] gcc -o which.exe -DCASE which.c [i586-linux - gcc 2.7.2.1] gcc -g -o which -DCASE which.c -DVERBOSE -DUX [Borland C++ 5.0] bcc32 which.c -d The Borland executable seems a bit slower, but it's much smaller, so that's what I'll install. *** */ #ifdef CASE #define strcmpi strcasecmp #endif #include struct svec { char **mem; int size; int cap; }; int spush(struct svec * v, char * s) { char **temp; if (! (v->size < v->cap)) { /* double the size if full */ if (v->cap) v->cap *= 2; else v->cap = 1; temp = malloc(sizeof(char *) * v->cap); memcpy(temp, v->mem, v->size*sizeof(char *)); free(v->mem); v->mem = temp; } v->mem[v->size++] = s; return 0; } int sfree(struct svec * v) { int i; for (i = 0; i < v->size; i++) free(v->mem[i]); free(v->mem); return 0; } int sclear(struct svec * v) { v->size = v->cap = 0; return 0; } int main(int argc, char * argv[], char * envp[]) { char *envent = NULL; char *execname = NULL; int i, j; struct svec pathlist = { 0 , 0, 0}; struct svec fnlist = { 0 , 0, 0}; char * p; char * fn, *fnx; DIR * dpath; struct dirent * dirent; /* parse command-line */ if (argc == 2) execname = strdup(argv[1]); else { printf("%s: Wrong # of args (%d) -- syntax= which \n", argv[0], argc); puts(CopyRightString); putchar('\n'); return 1; } /* (always check the current directory...) */ spush(&pathlist, strdup(".")); #ifdef VERBOSE printf("OK, searching for %s...\n", execname); #endif /* find the PATH variable */ envent = strdup(getenv("PATH")); if (envent == NULL) { printf("%s: PATH not defined\n", argv[0]); return 1; } /* for each directory in the path... */ #ifdef UX p = strtok(envent, ":"); #else p = strtok(envent, ";"); #endif while (p != NULL) { spush(&pathlist, strdup(p)); #ifdef UX p = strtok(NULL, ":"); #else p = strtok(NULL, ";"); #endif } /* OK, now we have a list of directories... */ free(envent); for (i = 0; i < pathlist.size; i++) { p = pathlist.mem[i]; #ifdef VERBOSE printf("(checking %s/...)\n", p); fflush(stdout); #endif /* -- and for each file in that directory... */ sclear(&fnlist); dpath = opendir(p); while ( dpath != NULL && (dirent=readdir(dpath)) != NULL) { /* check whether it's the right one; if so, display it and exit */ fn = strdup(dirent->d_name); #ifdef VERBOSE printf("( file %s)\n", fn); fflush(stdout); #endif if ((strtok(fn, ".")) && strcmpi(fn, execname) == 0 && (fnx = strtok(NULL, ".")) && ( strcmpi(fnx, "exe") == 0 || strcmpi(fnx, "com") == 0 || strcmpi(fnx, "bat") == 0 ) ) { #ifdef UX printf("%s/%s\n", p, dirent->d_name); #else printf("%s\\%s\n", p, dirent->d_name); #endif sfree(&pathlist); sfree(&fnlist); free(fn); free(execname); return 0; } free(fn); } closedir(dpath); } /* (if not found) say so and exit */ printf("not found\n"); sfree(&pathlist); sfree(&fnlist); free(execname); return 1; }