Here's what I normally use. If I were doing it again today, I'd probably do it a bit differently, but it works well enough that I haven't really had any reason to look at it for years (in fact, I'm pretty sure the last time I did anything to it was adding "cmd" to the list of extensions when I ported it from DOS to Win32...
// Which.c:
#include <io.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *extensions[] = { "com", "exe", "bat", "cmd", NULL };
int is_exe(char *ext) {
int i;
for ( i = 0; extensions[i]; i++)
if ( 0 == stricmp(ext, extensions[i] ) )
return 1;
return 0;
}
int main(int argc, char **argv) {
char path[FILENAME_MAX];
char buffer[FILENAME_MAX];
char *path_var;
char *ext;
char *dir;
int i;
if (argc != 2) {
fprintf(stderr, "Usage: which <filename>\n");
return 1;
}
/* First try to find file name as-is.
*/
if ( 0 == access(argv[1], 0)) {
printf("\n%s", argv[1]);
return 0;
}
/* Okay, it wasn't found. See if it had an extension, and if not, try
* adding the usual ones...
*/
ext = strrchr(argv[1], '.' );
if ( 0 == ext++ || !is_exe(ext) ) {
for ( i = 0; extensions[i]; i++) {
sprintf(buffer, "%s.%s", argv[1], extensions[i]);
if ( 0 == access(buffer, 0)) {
printf("\n%s", buffer);
return 0;
}
}
if ( NULL == (path_var=getenv("PATH")))
return 1;
dir = strtok(path_var, ";");
do {
for ( i = 0; extensions[i]; i++) {
sprintf(buffer, "%s\\%s.%s", dir, argv[1], extensions[i]);
if ( 0 == access( buffer, 0)) {
printf("\n%s", buffer);
return 0;
}
}
} while ( NULL != ( dir = strtok(NULL, ";")));
}
else {
if ( NULL == (path_var=getenv("PATH")))
return 1;
dir = strtok(path_var, ";");
do {
sprintf(buffer, "%s\\%s", dir, argv[1]);
if ( 0 == access( buffer, 0)) {
printf("\n%s", buffer);
return 0;
}
} while ( NULL != ( dir = strtok(NULL, ";")));
}
return 1;
}