blob: bb23081459b95a2aa68a96c098188f016c11a11a [file] [log] [blame] [raw]
/* which - toolbox
Copyright 2015 libdll.so
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#if defined _WIN32 && !defined _WIN32_WCE && !defined _WIN32_WNT_NATIVE
#define PATHS_SEPARATOR ';'
#else
#define PATHS_SEPARATOR ':'
#endif
static void print_usage(const char *name) {
fprintf(stderr, "Usage: %s [-a|-s] <name>\n", name);
}
int which(const char *path, const char *filename, char *rpath) {
//fprintf(stderr, "function: which(%p<%s>, %p<%s>, %p)\n", path, path, filename, filename, rpath);
char current_path[PATH_MAX + 1];
int i = 0;
if(!path || !filename) return -1;
do {
//char *p = current_path;
struct stat st;
int j = 0;
while(path[i] != PATHS_SEPARATOR) {
if(!path[i]) {
i = 0;
break;
}
if(j > PATH_MAX) {
j = 0;
while(path[++i] != PATHS_SEPARATOR) if(!path[i]) return -1;
i++;
}
//*p++ = path[i++];
current_path[j++] = path[i++];
}
if(i) i++;
//if(p == current_path) *p++ = '.';
//if(p[-1] != '/') *p++ = '/';
if(!j) current_path[j++] = '.';
if(current_path[j - 1] != '/') current_path[j++] = '/';
size_t filename_len = strlen(filename);
//size_t len = p - current_path + filename_len;
size_t len = j + filename_len;
if(len > PATH_MAX) continue;
//memcpy(p, filename, filename_len + 1);
memcpy(current_path + j, filename, filename_len + 1);
if(access(current_path, X_OK) < 0) {
#if defined _WIN32 && !defined _WIN32_WNT_NATIVE
if(len + 4 > PATH_MAX) continue;
strcpy(current_path + len, ".exe");
len += 4;
if(access(current_path, X_OK) < 0)
#endif
continue;
}
if(stat(current_path, &st) == 0 && S_ISREG(st.st_mode)) {
if(rpath) memcpy(rpath, current_path, len + 1);
return i;
}
} while(i);
return -1;
}
int which_main(int argc, char **argv) {
char candidate[PATH_MAX];
int print_all = 0;
int silent = 0;
int r = 0;
while(1) {
int c = getopt(argc, argv, "ash");
if(c == -1) break;
switch(c) {
case 'a':
print_all = 1;
break;
case 's':
silent = 1;
break;
case 'h':
print_usage(argv[0]);
return 0;
case '?':
return -1;
}
}
if(optind == argc) {
print_usage(argv[0]);
return -1;
}
argv += optind;
const char *path = getenv("PATH");
if(!path) return 1;
while(*argv) {
int i = 0;
do {
int j = which(path + i, *argv, silent ? NULL : candidate);
if(j < 0) {
r++;
break;
}
if(silent) break;
puts(candidate);
if(!j) break;
i += j;
} while(print_all);
argv++;
}
return r;
}