Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

dln_find.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 dln_find.c -
4
5 $Author$
6 created at: Tue Jan 18 17:05:06 JST 1994
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10 **********************************************************************/
11
12 #ifdef RUBY_EXPORT
13 #include "ruby/ruby.h"
14 #define dln_warning rb_warning
15 #define dln_warning_arg
16 #else
17 #define dln_warning fprintf
18 #define dln_warning_arg stderr,
19 #endif
20 #include "dln.h"
21
22 #ifdef HAVE_STDLIB_H
23 # include <stdlib.h>
24 #endif
25
26 #ifdef USE_DLN_A_OUT
27 char *dln_argv0;
28 #endif
29
30 #if defined(HAVE_ALLOCA_H)
31 #include <alloca.h>
32 #endif
33
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #else
37 # include <strings.h>
38 #endif
39
40 #include <stdio.h>
41 #if defined(_WIN32)
42 #include "missing/file.h"
43 #endif
44 #include <sys/types.h>
45 #include <sys/stat.h>
46
47 #ifndef S_ISDIR
48 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
49 #endif
50
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54
55 #if !defined(_WIN32) && !HAVE_DECL_GETENV
56 char *getenv();
57 #endif
58
59 static char *dln_find_1(const char *fname, const char *path, char *buf, size_t size, int exe_flag
60 DLN_FIND_EXTRA_ARG_DECL);
61
62 char *
63 dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size
64 DLN_FIND_EXTRA_ARG_DECL)
65 {
66 char *envpath = 0;
67
68 if (!path) {
69 path = getenv(PATH_ENV);
70 if (path) path = envpath = strdup(path);
71 }
72
73 if (!path) {
74 path =
75 "/usr/local/bin" PATH_SEP
76 "/usr/ucb" PATH_SEP
77 "/usr/bin" PATH_SEP
78 "/bin" PATH_SEP
79 ".";
80 }
81 buf = dln_find_1(fname, path, buf, size, 1 DLN_FIND_EXTRA_ARG);
82 if (envpath) free(envpath);
83 return buf;
84 }
85
86 char *
87 dln_find_file_r(const char *fname, const char *path, char *buf, size_t size
88 DLN_FIND_EXTRA_ARG_DECL)
89 {
90 if (!path) path = ".";
91 return dln_find_1(fname, path, buf, size, 0 DLN_FIND_EXTRA_ARG);
92 }
93
94 static char *
95 dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
96 int exe_flag /* non 0 if looking for executable. */
97 DLN_FIND_EXTRA_ARG_DECL)
98 {
99 register const char *dp;
100 register const char *ep;
101 register char *bp;
102 struct stat st;
103 size_t i, fnlen, fspace;
104 #ifdef DOSISH
105 static const char extension[][5] = {
106 EXECUTABLE_EXTS,
107 };
108 size_t j;
109 int is_abs = 0, has_path = 0;
110 const char *ext = 0;
111 #endif
112 const char *p = fname;
113
114 static const char pathname_too_long[] = "openpath: pathname too long (ignored)\n\
115 \tDirectory \"%.*s\"%s\n\tFile \"%.*s\"%s\n";
116 #define PATHNAME_TOO_LONG() dln_warning(dln_warning_arg pathname_too_long, \
117 ((bp - fbuf) > 100 ? 100 : (int)(bp - fbuf)), fbuf, \
118 ((bp - fbuf) > 100 ? "..." : ""), \
119 (fnlen > 100 ? 100 : (int)fnlen), fname, \
120 (fnlen > 100 ? "..." : ""))
121
122 #define RETURN_IF(expr) if (expr) return (char *)fname;
123
124 RETURN_IF(!fname);
125 fnlen = strlen(fname);
126 if (fnlen >= size) {
127 dln_warning(dln_warning_arg
128 "openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n",
129 (fnlen > 100 ? 100 : (int)fnlen), fname,
130 (fnlen > 100 ? "..." : ""));
131 return NULL;
132 }
133 #ifdef DOSISH
134 # ifndef CharNext
135 # define CharNext(p) ((p)+1)
136 # endif
137 # ifdef DOSISH_DRIVE_LETTER
138 if (((p[0] | 0x20) - 'a') < 26 && p[1] == ':') {
139 p += 2;
140 is_abs = 1;
141 }
142 # endif
143 switch (*p) {
144 case '/': case '\\':
145 is_abs = 1;
146 p++;
147 }
148 has_path = is_abs;
149 while (*p) {
150 switch (*p) {
151 case '/': case '\\':
152 has_path = 1;
153 ext = 0;
154 p++;
155 break;
156 case '.':
157 ext = p;
158 p++;
159 break;
160 default:
161 p = CharNext(p);
162 }
163 }
164 if (ext) {
165 for (j = 0; STRCASECMP(ext, extension[j]); ) {
166 if (++j == sizeof(extension) / sizeof(extension[0])) {
167 ext = 0;
168 break;
169 }
170 }
171 }
172 ep = bp = 0;
173 if (!exe_flag) {
174 RETURN_IF(is_abs);
175 }
176 else if (has_path) {
177 RETURN_IF(ext);
178 i = p - fname;
179 if (i + 1 > size) goto toolong;
180 fspace = size - i - 1;
181 bp = fbuf;
182 ep = p;
183 memcpy(fbuf, fname, i + 1);
184 goto needs_extension;
185 }
186 p = fname;
187 #endif
188
189 if (*p == '.' && *++p == '.') ++p;
190 RETURN_IF(*p == '/');
191 RETURN_IF(exe_flag && strchr(fname, '/'));
192
193 #undef RETURN_IF
194
195 for (dp = path;; dp = ++ep) {
196 register size_t l;
197
198 /* extract a component */
199 ep = strchr(dp, PATH_SEP[0]);
200 if (ep == NULL)
201 ep = dp+strlen(dp);
202
203 /* find the length of that component */
204 l = ep - dp;
205 bp = fbuf;
206 fspace = size - 2;
207 if (l > 0) {
208 /*
209 ** If the length of the component is zero length,
210 ** start from the current directory. If the
211 ** component begins with "~", start from the
212 ** user's $HOME environment variable. Otherwise
213 ** take the path literally.
214 */
215
216 if (*dp == '~' && (l == 1 ||
217 #if defined(DOSISH)
218 dp[1] == '\\' ||
219 #endif
220 dp[1] == '/')) {
221 char *home;
222
223 home = getenv("HOME");
224 if (home != NULL) {
225 i = strlen(home);
226 if (fspace < i)
227 goto toolong;
228 fspace -= i;
229 memcpy(bp, home, i);
230 bp += i;
231 }
232 dp++;
233 l--;
234 }
235 if (l > 0) {
236 if (fspace < l)
237 goto toolong;
238 fspace -= l;
239 memcpy(bp, dp, l);
240 bp += l;
241 }
242
243 /* add a "/" between directory and filename */
244 if (ep[-1] != '/')
245 *bp++ = '/';
246 }
247
248 /* now append the file name */
249 i = fnlen;
250 if (fspace < i) {
251 toolong:
252 PATHNAME_TOO_LONG();
253 goto next;
254 }
255 fspace -= i;
256 memcpy(bp, fname, i + 1);
257
258 #if defined(DOSISH)
259 if (exe_flag && !ext) {
260 needs_extension:
261 for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
262 if (fspace < strlen(extension[j])) {
263 PATHNAME_TOO_LONG();
264 continue;
265 }
266 strlcpy(bp + i, extension[j], fspace);
267 if (stat(fbuf, &st) == 0)
268 return fbuf;
269 }
270 goto next;
271 }
272 #endif
273
274 #ifndef S_ISREG
275 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
276 #endif
277 if (stat(fbuf, &st) == 0 && S_ISREG(st.st_mode)) {
278 if (exe_flag == 0) return fbuf;
279 /* looking for executable */
280 if (eaccess(fbuf, X_OK) == 0) return fbuf;
281 }
282 next:
283 /* if not, and no other alternatives, life is bleak */
284 if (*ep == '\0') {
285 return NULL;
286 }
287
288 /* otherwise try the next component in the search path */
289 }
290 }
eaccess
int eaccess(const char *path, int mode)
Definition: file.c:1460
stat
Definition: rb_mjit_min_header-2.7.0.h:2384
file.h
path
VALUE path
Definition: rb_mjit_min_header-2.7.0.h:7351
strchr
char * strchr(char *, char)
bp
#define bp()
Definition: internal.h:1445
stat
int stat(const char *__restrict __path, struct stat *__restrict __sbuf)
dp
#define dp(v)
Definition: vm_debug.h:21
NULL
#define NULL
Definition: _sdbm.c:101
PATHNAME_TOO_LONG
#define PATHNAME_TOO_LONG()
ruby.h
strlen
size_t strlen(const char *)
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
RETURN_IF
#define RETURN_IF(expr)
i
uint32_t i
Definition: rb_mjit_min_header-2.7.0.h:5464
size
int size
Definition: encoding.c:58
strlcpy
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
Definition: strlcpy.c:29
DLN_FIND_EXTRA_ARG_DECL
#define DLN_FIND_EXTRA_ARG_DECL
Definition: dln.h:37
PATH_ENV
#define PATH_ENV
Definition: defines.h:441
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4322
dln_warning
#define dln_warning
Definition: dln_find.c:17
strdup
char * strdup(const char *) __attribute__((__malloc__)) __attribute__((__warn_unused_result__))
STRCASECMP
#define STRCASECMP(s1, s2)
Definition: ruby.h:2323
EXECUTABLE_EXTS
#define EXECUTABLE_EXTS
Definition: rb_mjit_min_header-2.7.0.h:437
dln_find_exe_r
char * dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size DLN_FIND_EXTRA_ARG_DECL)
Definition: dln_find.c:63
st
enum ruby_tag_type st
Definition: rb_mjit_min_header-2.7.0.h:11111
X_OK
#define X_OK
Definition: file.h:18
dln_warning_arg
#define dln_warning_arg
Definition: dln_find.c:18
free
#define free(x)
Definition: dln.c:52
CharNext
#define CharNext(p)
Definition: eval_intern.h:296
getenv
char * getenv()
PATH_SEP
#define PATH_SEP
Definition: defines.h:437
dln_find_file_r
char * dln_find_file_r(const char *fname, const char *path, char *buf, size_t size DLN_FIND_EXTRA_ARG_DECL)
Definition: dln_find.c:87
S_ISREG
#define S_ISREG(m)
dln.h
DLN_FIND_EXTRA_ARG
#define DLN_FIND_EXTRA_ARG
Definition: dln.h:34