1 /**********************************************************************
6 created at: Tue Jan 18 17:05:06 JST 1994
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
10 **********************************************************************/
13 #include "ruby/ruby.h"
14 #define dln_warning rb_warning
15 #define dln_warning_arg
17 #define dln_warning fprintf
18 #define dln_warning_arg stderr,
26 #if defined(HAVE_ALLOCA_H)
38 #include "missing/file.h"
40 #include <sys/types.h>
44 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
51 #if !defined(_WIN32) && !HAVE_DECL_GETENV
55 static char *dln_find_1(const char *fname
, const char *path
, char *buf
, size_t size
, int exe_flag
56 DLN_FIND_EXTRA_ARG_DECL
);
59 dln_find_exe_r(const char *fname
, const char *path
, char *buf
, size_t size
60 DLN_FIND_EXTRA_ARG_DECL
)
65 path
= getenv(PATH_ENV
);
66 if (path
) path
= envpath
= strdup(path
);
71 "/usr/local/bin" PATH_SEP
77 buf
= dln_find_1(fname
, path
, buf
, size
, 1 DLN_FIND_EXTRA_ARG
);
78 if (envpath
) free(envpath
);
83 dln_find_file_r(const char *fname
, const char *path
, char *buf
, size_t size
84 DLN_FIND_EXTRA_ARG_DECL
)
86 if (!path
) path
= ".";
87 return dln_find_1(fname
, path
, buf
, size
, 0 DLN_FIND_EXTRA_ARG
);
91 dln_find_1(const char *fname
, const char *path
, char *fbuf
, size_t size
,
92 int exe_flag
/* non 0 if looking for executable. */
93 DLN_FIND_EXTRA_ARG_DECL
)
95 register const char *dp
;
96 register const char *ep
;
99 size_t i
, fnlen
, fspace
;
101 static const char extension
[][5] = {
105 int is_abs
= 0, has_path
= 0;
108 const char *p
= fname
;
110 static const char pathname_too_long
[] = "openpath: pathname too long (ignored)\n\
111 \tDirectory \"%.*s\"%s\n\tFile \"%.*s\"%s\n";
112 #define PATHNAME_TOO_LONG() dln_warning(dln_warning_arg pathname_too_long, \
113 ((bp - fbuf) > 100 ? 100 : (int)(bp - fbuf)), fbuf, \
114 ((bp - fbuf) > 100 ? "..." : ""), \
115 (fnlen > 100 ? 100 : (int)fnlen), fname, \
116 (fnlen > 100 ? "..." : ""))
118 #define RETURN_IF(expr) if (expr) return (char *)fname;
121 fnlen
= strlen(fname
);
123 dln_warning(dln_warning_arg
124 "openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n",
125 (fnlen
> 100 ? 100 : (int)fnlen
), fname
,
126 (fnlen
> 100 ? "..." : ""));
131 # define CharNext(p) ((p)+1)
133 # ifdef DOSISH_DRIVE_LETTER
134 if (((p
[0] | 0x20) - 'a') < 26 && p
[1] == ':') {
161 for (j
= 0; STRCASECMP(ext
, extension
[j
]); ) {
162 if (++j
== sizeof(extension
) / sizeof(extension
[0])) {
175 if (i
+ 1 > size
) goto toolong
;
176 fspace
= size
- i
- 1;
179 memcpy(fbuf
, fname
, i
+ 1);
180 goto needs_extension
;
185 if (*p
== '.' && *++p
== '.') ++p
;
186 RETURN_IF(*p
== '/');
187 RETURN_IF(exe_flag
&& strchr(fname
, '/'));
191 for (dp
= path
;; dp
= ++ep
) {
194 /* extract a component */
195 ep
= strchr(dp
, PATH_SEP
[0]);
199 /* find the length of that component */
205 ** If the length of the component is zero length,
206 ** start from the current directory. If the
207 ** component begins with "~", start from the
208 ** user's $HOME environment variable. Otherwise
209 ** take the path literally.
212 if (*dp
== '~' && (l
== 1 ||
219 home
= getenv("HOME");
239 /* add a "/" between directory and filename */
244 /* now append the file name */
250 memcpy(bp
, fname
, i
+ 1);
253 if (exe_flag
&& !ext
) {
254 goto needs_extension
;
259 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
261 if (stat(fbuf
, &st
) == 0 && S_ISREG(st
.st_mode
)) {
262 if (exe_flag
== 0) return fbuf
;
263 /* looking for executable */
264 if (eaccess(fbuf
, X_OK
) == 0) return fbuf
;
267 /* if not, and no other alternatives, life is bleak */
279 for (j
= 0; j
< sizeof(extension
) / sizeof(extension
[0]); j
++) {
280 if (fspace
< strlen(extension
[j
])) {
284 strlcpy(bp
+ i
, extension
[j
], fspace
);
285 if (stat(fbuf
, &st
) == 0)
290 /* otherwise try the next component in the search path */