Ruby  2.1.10p492(2016-04-01revision54464)
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
68 
69 char *
70 dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size
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
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. */
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) {
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:
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])) {
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 }
#define PATHNAME_TOO_LONG()
#define X_OK
Definition: file.h:18
size_t strlen(const char *)
#define CharNext(p)
Definition: eval_intern.h:254
#define RETURN_IF(expr)
gz path
Definition: zlib.c:2279
#define dln_find_file_r
Definition: win32.c:76
#define PATH_SEP
int size
Definition: encoding.c:49
i
Definition: enum.c:446
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
#define dln_warning
Definition: dln_find.c:17
#define STRCASECMP(s1, s2)
#define DLN_FIND_EXTRA_ARG
Definition: dln.h:34
#define dp(v)
Definition: vm_debug.h:21
#define S_ISDIR(m)
Definition: dln_find.c:48
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
#define DLN_FIND_EXTRA_ARG_DECL
Definition: dln.h:37
memcpy(buf+1, str, len)
RUBY_EXTERN int eaccess(const char *, int)
Definition: file.c:1147
#define strdup(s)
Definition: util.h:67
#define dln_warning_arg
Definition: dln_find.c:18
char * strchr(char *, char)
#define free(x)
Definition: dln.c:50
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
#define getenv(name)
Definition: win32.c:66
#define PATH_ENV
register C_block * p
Definition: crypt.c:309
#define stat(path, st)
Definition: win32.h:213
VALUE j
Definition: enum.c:1347
#define NULL
Definition: _sdbm.c:102
#define bp()
Definition: vm_debug.h:25
#define dln_find_exe_r
Definition: win32.c:75