Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

dln_find.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 dln_find.c -
4
5 $Author: nobu $
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_SYS_PARAM_H
52 # include <sys/param.h>
53 #endif
54 #ifndef MAXPATHLEN
55 # define MAXPATHLEN 1024
56 #endif
57
58 #ifdef HAVE_UNISTD_H
59 # include <unistd.h>
60 #endif
61
62 #if !defined(_WIN32) && !HAVE_DECL_GETENV
63 char *getenv();
64 #endif
65
66 static char *dln_find_1(const char *fname, const char *path, char *buf, size_t size, int exe_flag
67 DLN_FIND_EXTRA_ARG_DECL);
68
69 char *
70 dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size
71 DLN_FIND_EXTRA_ARG_DECL)
72 {
73 char *envpath = 0;
74
75 if (!path) {
76 path = getenv(PATH_ENV);
77 if (path) path = envpath = strdup(path);
78 }
79
80 if (!path) {
81 #if defined(_WIN32)
82 path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;.";
83 #else
84 path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
85 #endif
86 }
87 buf = dln_find_1(fname, path, buf, size, 1 DLN_FIND_EXTRA_ARG);
88 if (envpath) free(envpath);
89 return buf;
90 }
91
92 char *
93 dln_find_file_r(const char *fname, const char *path, char *buf, size_t size
94 DLN_FIND_EXTRA_ARG_DECL)
95 {
96 if (!path) path = ".";
97 return dln_find_1(fname, path, buf, size, 0 DLN_FIND_EXTRA_ARG);
98 }
99
100 static char *
101 dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
102 int exe_flag /* non 0 if looking for executable. */
103 DLN_FIND_EXTRA_ARG_DECL)
104 {
105 register const char *dp;
106 register const char *ep;
107 register char *bp;
108 struct stat st;
109 size_t i, fnlen, fspace;
110 #ifdef DOSISH
111 static const char extension[][5] = {
112 EXECUTABLE_EXTS,
113 };
114 size_t j;
115 int is_abs = 0, has_path = 0;
116 const char *ext = 0;
117 #endif
118 const char *p = fname;
119
120 static const char pathname_too_long[] = "openpath: pathname too long (ignored)\n\
121 \tDirectory \"%.*s\"%s\n\tFile \"%.*s\"%s\n";
122 #define PATHNAME_TOO_LONG() dln_warning(dln_warning_arg pathname_too_long, \
123 ((bp - fbuf) > 100 ? 100 : (int)(bp - fbuf)), fbuf, \
124 ((bp - fbuf) > 100 ? "..." : ""), \
125 (fnlen > 100 ? 100 : (int)fnlen), fname, \
126 (fnlen > 100 ? "..." : ""))
127
128 #define RETURN_IF(expr) if (expr) return (char *)fname;
129
130 RETURN_IF(!fname);
131 fnlen = strlen(fname);
132 if (fnlen >= size) {
133 dln_warning(dln_warning_arg
134 "openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n",
135 (fnlen > 100 ? 100 : (int)fnlen), fname,
136 (fnlen > 100 ? "..." : ""));
137 return NULL;
138 }
139 #ifdef DOSISH
140 # ifndef CharNext
141 # define CharNext(p) ((p)+1)
142 # endif
143 # ifdef DOSISH_DRIVE_LETTER
144 if (((p[0] | 0x20) - 'a') < 26 && p[1] == ':') {
145 p += 2;
146 is_abs = 1;
147 }
148 # endif
149 switch (*p) {
150 case '/': case '\\':
151 is_abs = 1;
152 p++;
153 }
154 has_path = is_abs;
155 while (*p) {
156 switch (*p) {
157 case '/': case '\\':
158 has_path = 1;
159 ext = 0;
160 p++;
161 break;
162 case '.':
163 ext = p;
164 p++;
165 break;
166 default:
167 p = CharNext(p);
168 }
169 }
170 if (ext) {
171 for (j = 0; STRCASECMP(ext, extension[j]); ) {
172 if (++j == sizeof(extension) / sizeof(extension[0])) {
173 ext = 0;
174 break;
175 }
176 }
177 }
178 ep = bp = 0;
179 if (!exe_flag) {
180 RETURN_IF(is_abs);
181 }
182 else if (has_path) {
183 RETURN_IF(ext);
184 i = p - fname;
185 if (i + 1 > size) goto toolong;
186 fspace = size - i - 1;
187 bp = fbuf;
188 ep = p;
189 memcpy(fbuf, fname, i + 1);
190 goto needs_extension;
191 }
192 p = fname;
193 #endif
194
195 if (*p == '.' && *++p == '.') ++p;
196 RETURN_IF(*p == '/');
197 RETURN_IF(exe_flag && strchr(fname, '/'));
198
199 #undef RETURN_IF
200
201 for (dp = path;; dp = ++ep) {
202 register size_t l;
203
204 /* extract a component */
205 ep = strchr(dp, PATH_SEP[0]);
206 if (ep == NULL)
207 ep = dp+strlen(dp);
208
209 /* find the length of that component */
210 l = ep - dp;
211 bp = fbuf;
212 fspace = size - 2;
213 if (l > 0) {
214 /*
215 ** If the length of the component is zero length,
216 ** start from the current directory. If the
217 ** component begins with "~", start from the
218 ** user's $HOME environment variable. Otherwise
219 ** take the path literally.
220 */
221
222 if (*dp == '~' && (l == 1 ||
223 #if defined(DOSISH)
224 dp[1] == '\\' ||
225 #endif
226 dp[1] == '/')) {
227 char *home;
228
229 home = getenv("HOME");
230 if (home != NULL) {
231 i = strlen(home);
232 if (fspace < i)
233 goto toolong;
234 fspace -= i;
235 memcpy(bp, home, i);
236 bp += i;
237 }
238 dp++;
239 l--;
240 }
241 if (l > 0) {
242 if (fspace < l)
243 goto toolong;
244 fspace -= l;
245 memcpy(bp, dp, l);
246 bp += l;
247 }
248
249 /* add a "/" between directory and filename */
250 if (ep[-1] != '/')
251 *bp++ = '/';
252 }
253
254 /* now append the file name */
255 i = fnlen;
256 if (fspace < i) {
257 toolong:
258 PATHNAME_TOO_LONG();
259 goto next;
260 }
261 fspace -= i;
262 memcpy(bp, fname, i + 1);
263
264 #if defined(DOSISH)
265 if (exe_flag && !ext) {
266 needs_extension:
267 for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
268 if (fspace < strlen(extension[j])) {
269 PATHNAME_TOO_LONG();
270 continue;
271 }
272 strlcpy(bp + i, extension[j], fspace);
273 if (stat(fbuf, &st) == 0)
274 return fbuf;
275 }
276 goto next;
277 }
278 #endif /* _WIN32 or __EMX__ */
279
280 if (stat(fbuf, &st) == 0) {
281 if (exe_flag == 0) return fbuf;
282 /* looking for executable */
283 if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
284 return fbuf;
285 }
286 next:
287 /* if not, and no other alternatives, life is bleak */
288 if (*ep == '\0') {
289 return NULL;
290 }
291
292 /* otherwise try the next component in the search path */
293 }
294 }
PATHNAME_TOO_LONG
#define PATHNAME_TOO_LONG()
X_OK
#define X_OK
Definition: file.h:18
strlen
size_t strlen(const char *)
CharNext
#define CharNext(p)
Definition: eval_intern.h:254
dln.h
RETURN_IF
#define RETURN_IF(expr)
ruby.h
eaccess
int eaccess(const char *path, int mode)
Definition: file.c:1146
file.h
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:70
dln_warning
#define dln_warning
Definition: dln_find.c:17
DLN_FIND_EXTRA_ARG
#define DLN_FIND_EXTRA_ARG
Definition: dln.h:34
dp
#define dp(v)
Definition: vm_debug.h:21
unistd.h
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:93
S_ISDIR
#define S_ISDIR(m)
Definition: dln_find.c:48
DLN_FIND_EXTRA_ARG_DECL
#define DLN_FIND_EXTRA_ARG_DECL
Definition: dln.h:37
strdup
#define strdup(s)
Definition: util.h:67
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
PATH_ENV
#define PATH_ENV
Definition: defines.h:280
dln_warning_arg
#define dln_warning_arg
Definition: dln_find.c:18
strchr
char * strchr(char *, char)
strlcpy
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
Definition: strlcpy.c:44
dln_find_1
static char * dln_find_1(const char *fname, const char *path, char *buf, size_t size, int exe_flag DLN_FIND_EXTRA_ARG_DECL)
Definition: dln_find.c:101
size
int size
Definition: encoding.c:49
STRCASECMP
#define STRCASECMP(s1, s2)
Definition: ruby.h:1783
getenv
char * getenv()
PATH_SEP
#define PATH_SEP
Definition: defines.h:276
stat
#define stat(path, st)
Definition: win32.h:213
NULL
#define NULL
Definition: _sdbm.c:103
free
free(psz)
bp
#define bp()
Definition: vm_debug.h:25