YJIT: implement cache for recently encoded/decoded contexts (#10938)
[ruby.git] / dln_find.c
blobae37b9dde424266855732c22cd04883268ab3a5f
1 /**********************************************************************
3 dln_find.c -
5 $Author$
6 created at: Tue Jan 18 17:05:06 JST 1994
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
10 **********************************************************************/
12 #ifdef RUBY_EXPORT
13 #include "ruby/ruby.h"
14 #define dln_warning(...) rb_warning(__VA_ARGS__)
15 #else
16 #define dln_warning(...) fprintf(stderr, __VA_ARGS__)
17 #endif
18 #include "dln.h"
20 #ifdef HAVE_STDLIB_H
21 # include <stdlib.h>
22 #endif
24 #if defined(HAVE_ALLOCA_H)
25 #include <alloca.h>
26 #endif
28 #ifdef HAVE_STRING_H
29 # include <string.h>
30 #else
31 # include <strings.h>
32 #endif
34 #include <stdio.h>
35 #if defined(_WIN32)
36 #include "missing/file.h"
37 #endif
38 #include <sys/types.h>
39 #include <sys/stat.h>
41 #ifndef S_ISDIR
42 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
43 #endif
45 #ifdef HAVE_UNISTD_H
46 # include <unistd.h>
47 #endif
49 #if !defined(_WIN32) && !HAVE_DECL_GETENV
50 char *getenv();
51 #endif
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);
56 char *
57 dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size
58 DLN_FIND_EXTRA_ARG_DECL)
60 char *envpath = 0;
62 if (!path) {
63 path = getenv(PATH_ENV);
64 if (path) path = envpath = strdup(path);
67 if (!path) {
68 path =
69 "/usr/local/bin" PATH_SEP
70 "/usr/ucb" PATH_SEP
71 "/usr/bin" PATH_SEP
72 "/bin" PATH_SEP
73 ".";
75 buf = dln_find_1(fname, path, buf, size, 1 DLN_FIND_EXTRA_ARG);
76 free(envpath);
77 return buf;
80 char *
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);
88 static char *
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;
95 register char *bp;
96 struct stat st;
97 size_t i, fnlen, fspace;
98 #ifdef DOSISH
99 static const char extension[][5] = {
100 EXECUTABLE_EXTS,
102 size_t j;
103 int is_abs = 0, has_path = 0;
104 const char *ext = 0;
105 #endif
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;
118 RETURN_IF(!fname);
119 fnlen = strlen(fname);
120 if (fnlen >= size) {
121 dln_warning("openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n",
122 (fnlen > 100 ? 100 : (int)fnlen), fname,
123 (fnlen > 100 ? "..." : ""));
124 return NULL;
126 #ifdef DOSISH
127 # ifndef CharNext
128 # define CharNext(p) ((p)+1)
129 # endif
130 # ifdef DOSISH_DRIVE_LETTER
131 if (((p[0] | 0x20) - 'a') < 26 && p[1] == ':') {
132 p += 2;
133 is_abs = 1;
135 # endif
136 switch (*p) {
137 case '/': case '\\':
138 is_abs = 1;
139 p++;
141 has_path = is_abs;
142 while (*p) {
143 switch (*p) {
144 case '/': case '\\':
145 has_path = 1;
146 ext = 0;
147 p++;
148 break;
149 case '.':
150 ext = p;
151 p++;
152 break;
153 default:
154 p = CharNext(p);
157 if (ext) {
158 for (j = 0; STRCASECMP(ext, extension[j]); ) {
159 if (++j == sizeof(extension) / sizeof(extension[0])) {
160 ext = 0;
161 break;
165 ep = bp = 0;
166 if (!exe_flag) {
167 RETURN_IF(is_abs);
169 else if (has_path) {
170 RETURN_IF(ext);
171 i = p - fname;
172 if (i + 1 > size) goto toolong;
173 fspace = size - i - 1;
174 bp = fbuf;
175 ep = p;
176 memcpy(fbuf, fname, i + 1);
177 goto needs_extension;
179 p = fname;
180 #endif
182 if (*p == '.' && *++p == '.') ++p;
183 RETURN_IF(*p == '/');
184 RETURN_IF(exe_flag && strchr(fname, '/'));
186 #undef RETURN_IF
188 for (dp = path;; dp = ++ep) {
189 register size_t l;
191 /* extract a component */
192 ep = strchr(dp, PATH_SEP[0]);
193 if (ep == NULL)
194 ep = dp+strlen(dp);
196 /* find the length of that component */
197 l = ep - dp;
198 bp = fbuf;
199 fspace = size - 2;
200 if (l > 0) {
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 ||
210 #if defined(DOSISH)
211 dp[1] == '\\' ||
212 #endif
213 dp[1] == '/')) {
214 const char *home;
216 home = getenv("HOME");
217 if (home != NULL) {
218 i = strlen(home);
219 if (fspace < i)
220 goto toolong;
221 fspace -= i;
222 memcpy(bp, home, i);
223 bp += i;
225 dp++;
226 l--;
228 if (l > 0) {
229 if (fspace < l)
230 goto toolong;
231 fspace -= l;
232 memcpy(bp, dp, l);
233 bp += l;
236 /* add a "/" between directory and filename */
237 if (ep[-1] != '/')
238 *bp++ = '/';
241 /* now append the file name */
242 i = fnlen;
243 if (fspace < i) {
244 goto toolong;
246 fspace -= i;
247 memcpy(bp, fname, i + 1);
249 #if defined(DOSISH)
250 if (exe_flag && !ext) {
251 goto needs_extension;
253 #endif
255 #ifndef S_ISREG
256 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
257 #endif
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;
263 next:
264 /* if not, and no other alternatives, life is bleak */
265 if (*ep == '\0') {
266 return NULL;
268 continue;
270 toolong:
271 PATHNAME_TOO_LONG();
272 goto next;
274 #if defined(DOSISH)
275 needs_extension:
276 for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
277 if (fspace < strlen(extension[j])) {
278 PATHNAME_TOO_LONG();
279 continue;
281 strlcpy(bp + i, extension[j], fspace);
282 if (stat(fbuf, &st) == 0)
283 return fbuf;
285 goto next;
286 #endif
287 /* otherwise try the next component in the search path */