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