Permalink
Cannot retrieve contributors at this time
/********************************************************************** | |
dln_find.c - | |
$Author$ | |
created at: Tue Jan 18 17:05:06 JST 1994 | |
Copyright (C) 1993-2007 Yukihiro Matsumoto | |
**********************************************************************/ | |
#ifdef RUBY_EXPORT | |
#include "ruby/ruby.h" | |
#define dln_warning rb_warning | |
#define dln_warning_arg | |
#else | |
#define dln_warning fprintf | |
#define dln_warning_arg stderr, | |
#endif | |
#include "dln.h" | |
#ifdef HAVE_STDLIB_H | |
# include <stdlib.h> | |
#endif | |
#ifdef USE_DLN_A_OUT | |
char *dln_argv0; | |
#endif | |
#if defined(HAVE_ALLOCA_H) | |
#include <alloca.h> | |
#endif | |
#ifdef HAVE_STRING_H | |
# include <string.h> | |
#else | |
# include <strings.h> | |
#endif | |
#include <stdio.h> | |
#if defined(_WIN32) | |
#include "missing/file.h" | |
#endif | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#ifndef S_ISDIR | |
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) | |
#endif | |
#ifdef HAVE_UNISTD_H | |
# include <unistd.h> | |
#endif | |
#if !defined(_WIN32) && !HAVE_DECL_GETENV | |
char *getenv(); | |
#endif | |
static char *dln_find_1(const char *fname, const char *path, char *buf, size_t size, int exe_flag | |
DLN_FIND_EXTRA_ARG_DECL); | |
char * | |
dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size | |
DLN_FIND_EXTRA_ARG_DECL) | |
{ | |
char *envpath = 0; | |
if (!path) { | |
path = getenv(PATH_ENV); | |
if (path) path = envpath = strdup(path); | |
} | |
if (!path) { | |
path = | |
"/usr/local/bin" PATH_SEP | |
"/usr/ucb" PATH_SEP | |
"/usr/bin" PATH_SEP | |
"/bin" PATH_SEP | |
"."; | |
} | |
buf = dln_find_1(fname, path, buf, size, 1 DLN_FIND_EXTRA_ARG); | |
if (envpath) free(envpath); | |
return buf; | |
} | |
char * | |
dln_find_file_r(const char *fname, const char *path, char *buf, size_t size | |
DLN_FIND_EXTRA_ARG_DECL) | |
{ | |
if (!path) path = "."; | |
return dln_find_1(fname, path, buf, size, 0 DLN_FIND_EXTRA_ARG); | |
} | |
static char * | |
dln_find_1(const char *fname, const char *path, char *fbuf, size_t size, | |
int exe_flag /* non 0 if looking for executable. */ | |
DLN_FIND_EXTRA_ARG_DECL) | |
{ | |
register const char *dp; | |
register const char *ep; | |
register char *bp; | |
struct stat st; | |
size_t i, fnlen, fspace; | |
#ifdef DOSISH | |
static const char extension[][5] = { | |
EXECUTABLE_EXTS, | |
}; | |
size_t j; | |
int is_abs = 0, has_path = 0; | |
const char *ext = 0; | |
#endif | |
const char *p = fname; | |
static const char pathname_too_long[] = "openpath: pathname too long (ignored)\n\ | |
\tDirectory \"%.*s\"%s\n\tFile \"%.*s\"%s\n"; | |
#define PATHNAME_TOO_LONG() dln_warning(dln_warning_arg pathname_too_long, \ | |
((bp - fbuf) > 100 ? 100 : (int)(bp - fbuf)), fbuf, \ | |
((bp - fbuf) > 100 ? "..." : ""), \ | |
(fnlen > 100 ? 100 : (int)fnlen), fname, \ | |
(fnlen > 100 ? "..." : "")) | |
#define RETURN_IF(expr) if (expr) return (char *)fname; | |
RETURN_IF(!fname); | |
fnlen = strlen(fname); | |
if (fnlen >= size) { | |
dln_warning(dln_warning_arg | |
"openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n", | |
(fnlen > 100 ? 100 : (int)fnlen), fname, | |
(fnlen > 100 ? "..." : "")); | |
return NULL; | |
} | |
#ifdef DOSISH | |
# ifndef CharNext | |
# define CharNext(p) ((p)+1) | |
# endif | |
# ifdef DOSISH_DRIVE_LETTER | |
if (((p[0] | 0x20) - 'a') < 26 && p[1] == ':') { | |
p += 2; | |
is_abs = 1; | |
} | |
# endif | |
switch (*p) { | |
case '/': case '\\': | |
is_abs = 1; | |
p++; | |
} | |
has_path = is_abs; | |
while (*p) { | |
switch (*p) { | |
case '/': case '\\': | |
has_path = 1; | |
ext = 0; | |
p++; | |
break; | |
case '.': | |
ext = p; | |
p++; | |
break; | |
default: | |
p = CharNext(p); | |
} | |
} | |
if (ext) { | |
for (j = 0; STRCASECMP(ext, extension[j]); ) { | |
if (++j == sizeof(extension) / sizeof(extension[0])) { | |
ext = 0; | |
break; | |
} | |
} | |
} | |
ep = bp = 0; | |
if (!exe_flag) { | |
RETURN_IF(is_abs); | |
} | |
else if (has_path) { | |
RETURN_IF(ext); | |
i = p - fname; | |
if (i + 1 > size) goto toolong; | |
fspace = size - i - 1; | |
bp = fbuf; | |
ep = p; | |
memcpy(fbuf, fname, i + 1); | |
goto needs_extension; | |
} | |
p = fname; | |
#endif | |
if (*p == '.' && *++p == '.') ++p; | |
RETURN_IF(*p == '/'); | |
RETURN_IF(exe_flag && strchr(fname, '/')); | |
#undef RETURN_IF | |
for (dp = path;; dp = ++ep) { | |
register size_t l; | |
/* extract a component */ | |
ep = strchr(dp, PATH_SEP[0]); | |
if (ep == NULL) | |
ep = dp+strlen(dp); | |
/* find the length of that component */ | |
l = ep - dp; | |
bp = fbuf; | |
fspace = size - 2; | |
if (l > 0) { | |
/* | |
** If the length of the component is zero length, | |
** start from the current directory. If the | |
** component begins with "~", start from the | |
** user's $HOME environment variable. Otherwise | |
** take the path literally. | |
*/ | |
if (*dp == '~' && (l == 1 || | |
#if defined(DOSISH) | |
dp[1] == '\\' || | |
#endif | |
dp[1] == '/')) { | |
char *home; | |
home = getenv("HOME"); | |
if (home != NULL) { | |
i = strlen(home); | |
if (fspace < i) | |
goto toolong; | |
fspace -= i; | |
memcpy(bp, home, i); | |
bp += i; | |
} | |
dp++; | |
l--; | |
} | |
if (l > 0) { | |
if (fspace < l) | |
goto toolong; | |
fspace -= l; | |
memcpy(bp, dp, l); | |
bp += l; | |
} | |
/* add a "/" between directory and filename */ | |
if (ep[-1] != '/') | |
*bp++ = '/'; | |
} | |
/* now append the file name */ | |
i = fnlen; | |
if (fspace < i) { | |
goto toolong; | |
} | |
fspace -= i; | |
memcpy(bp, fname, i + 1); | |
#if defined(DOSISH) | |
if (exe_flag && !ext) { | |
goto needs_extension; | |
} | |
#endif | |
#ifndef S_ISREG | |
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) | |
#endif | |
if (stat(fbuf, &st) == 0 && S_ISREG(st.st_mode)) { | |
if (exe_flag == 0) return fbuf; | |
/* looking for executable */ | |
if (eaccess(fbuf, X_OK) == 0) return fbuf; | |
} | |
next: | |
/* if not, and no other alternatives, life is bleak */ | |
if (*ep == '\0') { | |
return NULL; | |
} | |
continue; | |
toolong: | |
PATHNAME_TOO_LONG(); | |
goto next; | |
#if defined(DOSISH) | |
needs_extension: | |
for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) { | |
if (fspace < strlen(extension[j])) { | |
PATHNAME_TOO_LONG(); | |
continue; | |
} | |
strlcpy(bp + i, extension[j], fspace); | |
if (stat(fbuf, &st) == 0) | |
return fbuf; | |
} | |
goto next; | |
#endif | |
/* otherwise try the next component in the search path */ | |
} | |
} |