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(__VA_ARGS__)
16 #define dln_warning(...) fprintf(stderr, __VA_ARGS__)
24 #if defined(HAVE_ALLOCA_H)
36 #include "missing/file.h"
38 #include <sys/types.h>
42 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
49 #if !defined(_WIN32) && !HAVE_DECL_GETENV
53 static char *dln_find_1(const char *fname
, const char *path
, char *buf
, size_t size
, int exe_flag
54 DLN_FIND_EXTRA_ARG_DECL
);
57 dln_find_exe_r(const char *fname
, const char *path
, char *buf
, size_t size
58 DLN_FIND_EXTRA_ARG_DECL
)
63 path
= getenv(PATH_ENV
);
64 if (path
) path
= envpath
= strdup(path
);
69 "/usr/local/bin" PATH_SEP
75 buf
= dln_find_1(fname
, path
, buf
, size
, 1 DLN_FIND_EXTRA_ARG
);
81 dln_find_file_r(const char *fname
, const char *path
, char *buf
, size_t size
82 DLN_FIND_EXTRA_ARG_DECL
)
84 if (!path
) path
= ".";
85 return dln_find_1(fname
, path
, buf
, size
, 0 DLN_FIND_EXTRA_ARG
);
89 dln_find_1(const char *fname
, const char *path
, char *fbuf
, size_t size
,
90 int exe_flag
/* non 0 if looking for executable. */
91 DLN_FIND_EXTRA_ARG_DECL
)
93 register const char *dp
;
94 register const char *ep
;
97 size_t i
, fnlen
, fspace
;
99 static const char extension
[][5] = {
103 int is_abs
= 0, has_path
= 0;
106 const char *p
= fname
;
108 static const char pathname_too_long
[] = "openpath: pathname too long (ignored)\n\
109 \tDirectory \"%.*s\"%s\n\tFile \"%.*s\"%s\n";
110 #define PATHNAME_TOO_LONG() dln_warning(pathname_too_long, \
111 ((bp - fbuf) > 100 ? 100 : (int)(bp - fbuf)), fbuf, \
112 ((bp - fbuf) > 100 ? "..." : ""), \
113 (fnlen > 100 ? 100 : (int)fnlen), fname, \
114 (fnlen > 100 ? "..." : ""))
116 #define RETURN_IF(expr) if (expr) return (char *)fname;
119 fnlen
= strlen(fname
);
121 dln_warning("openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n",
122 (fnlen
> 100 ? 100 : (int)fnlen
), fname
,
123 (fnlen
> 100 ? "..." : ""));
128 # define CharNext(p) ((p)+1)
130 # ifdef DOSISH_DRIVE_LETTER
131 if (((p
[0] | 0x20) - 'a') < 26 && p
[1] == ':') {
158 for (j
= 0; STRCASECMP(ext
, extension
[j
]); ) {
159 if (++j
== sizeof(extension
) / sizeof(extension
[0])) {
172 if (i
+ 1 > size
) goto toolong
;
173 fspace
= size
- i
- 1;
176 memcpy(fbuf
, fname
, i
+ 1);
177 goto needs_extension
;
182 if (*p
== '.' && *++p
== '.') ++p
;
183 RETURN_IF(*p
== '/');
184 RETURN_IF(exe_flag
&& strchr(fname
, '/'));
188 for (dp
= path
;; dp
= ++ep
) {
191 /* extract a component */
192 ep
= strchr(dp
, PATH_SEP
[0]);
196 /* find the length of that component */
202 ** If the length of the component is zero length,
203 ** start from the current directory. If the
204 ** component begins with "~", start from the
205 ** user's $HOME environment variable. Otherwise
206 ** take the path literally.
209 if (*dp
== '~' && (l
== 1 ||
216 home
= getenv("HOME");
236 /* add a "/" between directory and filename */
241 /* now append the file name */
247 memcpy(bp
, fname
, i
+ 1);
250 if (exe_flag
&& !ext
) {
251 goto needs_extension
;
256 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
258 if (stat(fbuf
, &st
) == 0 && S_ISREG(st
.st_mode
)) {
259 if (exe_flag
== 0) return fbuf
;
260 /* looking for executable */
261 if (eaccess(fbuf
, X_OK
) == 0) return fbuf
;
264 /* if not, and no other alternatives, life is bleak */
276 for (j
= 0; j
< sizeof(extension
) / sizeof(extension
[0]); j
++) {
277 if (fspace
< strlen(extension
[j
])) {
281 strlcpy(bp
+ i
, extension
[j
], fspace
);
282 if (stat(fbuf
, &st
) == 0)
287 /* otherwise try the next component in the search path */