00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifdef RUBY_EXPORT
00013 #include "ruby/ruby.h"
00014 #define dln_warning rb_warning
00015 #define dln_warning_arg
00016 #else
00017 #define dln_warning fprintf
00018 #define dln_warning_arg stderr,
00019 #endif
00020 #include "dln.h"
00021
00022 #ifdef HAVE_STDLIB_H
00023 # include <stdlib.h>
00024 #endif
00025
00026 #ifdef USE_DLN_A_OUT
00027 char *dln_argv0;
00028 #endif
00029
00030 #if defined(HAVE_ALLOCA_H)
00031 #include <alloca.h>
00032 #endif
00033
00034 #ifdef HAVE_STRING_H
00035 # include <string.h>
00036 #else
00037 # include <strings.h>
00038 #endif
00039
00040 #include <stdio.h>
00041 #if defined(_WIN32)
00042 #include "missing/file.h"
00043 #endif
00044 #include <sys/types.h>
00045 #include <sys/stat.h>
00046
00047 #ifndef S_ISDIR
00048 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
00049 #endif
00050
00051 #ifdef HAVE_SYS_PARAM_H
00052 # include <sys/param.h>
00053 #endif
00054 #ifndef MAXPATHLEN
00055 # define MAXPATHLEN 1024
00056 #endif
00057
00058 #ifdef HAVE_UNISTD_H
00059 # include <unistd.h>
00060 #endif
00061
00062 #if !defined(_WIN32) && !HAVE_DECL_GETENV
00063 char *getenv();
00064 #endif
00065
00066 static char *dln_find_1(const char *fname, const char *path, char *buf, size_t size, int exe_flag
00067 DLN_FIND_EXTRA_ARG_DECL);
00068
00069 char *
00070 dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size
00071 DLN_FIND_EXTRA_ARG_DECL)
00072 {
00073 char *envpath = 0;
00074
00075 if (!path) {
00076 path = getenv(PATH_ENV);
00077 if (path) path = envpath = strdup(path);
00078 }
00079
00080 if (!path) {
00081 #if defined(_WIN32)
00082 path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;.";
00083 #else
00084 path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
00085 #endif
00086 }
00087 buf = dln_find_1(fname, path, buf, size, 1 DLN_FIND_EXTRA_ARG);
00088 if (envpath) free(envpath);
00089 return buf;
00090 }
00091
00092 char *
00093 dln_find_file_r(const char *fname, const char *path, char *buf, size_t size
00094 DLN_FIND_EXTRA_ARG_DECL)
00095 {
00096 if (!path) path = ".";
00097 return dln_find_1(fname, path, buf, size, 0 DLN_FIND_EXTRA_ARG);
00098 }
00099
00100 static char *
00101 dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
00102 int exe_flag
00103 DLN_FIND_EXTRA_ARG_DECL)
00104 {
00105 register const char *dp;
00106 register const char *ep;
00107 register char *bp;
00108 struct stat st;
00109 size_t i, fnlen, fspace;
00110 #ifdef DOSISH
00111 static const char extension[][5] = {
00112 EXECUTABLE_EXTS,
00113 };
00114 size_t j;
00115 int is_abs = 0, has_path = 0;
00116 const char *ext = 0;
00117 #endif
00118 const char *p = fname;
00119
00120 static const char pathname_too_long[] = "openpath: pathname too long (ignored)\n\
00121 \tDirectory \"%.*s\"%s\n\tFile \"%.*s\"%s\n";
00122 #define PATHNAME_TOO_LONG() dln_warning(dln_warning_arg pathname_too_long, \
00123 ((bp - fbuf) > 100 ? 100 : (int)(bp - fbuf)), fbuf, \
00124 ((bp - fbuf) > 100 ? "..." : ""), \
00125 (fnlen > 100 ? 100 : (int)fnlen), fname, \
00126 (fnlen > 100 ? "..." : ""))
00127
00128 #define RETURN_IF(expr) if (expr) return (char *)fname;
00129
00130 RETURN_IF(!fname);
00131 fnlen = strlen(fname);
00132 if (fnlen >= size) {
00133 dln_warning(dln_warning_arg
00134 "openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n",
00135 (fnlen > 100 ? 100 : (int)fnlen), fname,
00136 (fnlen > 100 ? "..." : ""));
00137 return NULL;
00138 }
00139 #ifdef DOSISH
00140 # ifndef CharNext
00141 # define CharNext(p) ((p)+1)
00142 # endif
00143 # ifdef DOSISH_DRIVE_LETTER
00144 if (((p[0] | 0x20) - 'a') < 26 && p[1] == ':') {
00145 p += 2;
00146 is_abs = 1;
00147 }
00148 # endif
00149 switch (*p) {
00150 case '/': case '\\':
00151 is_abs = 1;
00152 p++;
00153 }
00154 has_path = is_abs;
00155 while (*p) {
00156 switch (*p) {
00157 case '/': case '\\':
00158 has_path = 1;
00159 ext = 0;
00160 p++;
00161 break;
00162 case '.':
00163 ext = p;
00164 p++;
00165 break;
00166 default:
00167 p = CharNext(p);
00168 }
00169 }
00170 if (ext) {
00171 for (j = 0; STRCASECMP(ext, extension[j]); ) {
00172 if (++j == sizeof(extension) / sizeof(extension[0])) {
00173 ext = 0;
00174 break;
00175 }
00176 }
00177 }
00178 ep = bp = 0;
00179 if (!exe_flag) {
00180 RETURN_IF(is_abs);
00181 }
00182 else if (has_path) {
00183 RETURN_IF(ext);
00184 i = p - fname;
00185 if (i + 1 > size) goto toolong;
00186 fspace = size - i - 1;
00187 bp = fbuf;
00188 ep = p;
00189 memcpy(fbuf, fname, i + 1);
00190 goto needs_extension;
00191 }
00192 p = fname;
00193 #endif
00194
00195 if (*p == '.' && *++p == '.') ++p;
00196 RETURN_IF(*p == '/');
00197 RETURN_IF(exe_flag && strchr(fname, '/'));
00198
00199 #undef RETURN_IF
00200
00201 for (dp = path;; dp = ++ep) {
00202 register size_t l;
00203
00204
00205 ep = strchr(dp, PATH_SEP[0]);
00206 if (ep == NULL)
00207 ep = dp+strlen(dp);
00208
00209
00210 l = ep - dp;
00211 bp = fbuf;
00212 fspace = size - 2;
00213 if (l > 0) {
00214
00215
00216
00217
00218
00219
00220
00221
00222 if (*dp == '~' && (l == 1 ||
00223 #if defined(DOSISH)
00224 dp[1] == '\\' ||
00225 #endif
00226 dp[1] == '/')) {
00227 char *home;
00228
00229 home = getenv("HOME");
00230 if (home != NULL) {
00231 i = strlen(home);
00232 if (fspace < i)
00233 goto toolong;
00234 fspace -= i;
00235 memcpy(bp, home, i);
00236 bp += i;
00237 }
00238 dp++;
00239 l--;
00240 }
00241 if (l > 0) {
00242 if (fspace < l)
00243 goto toolong;
00244 fspace -= l;
00245 memcpy(bp, dp, l);
00246 bp += l;
00247 }
00248
00249
00250 if (ep[-1] != '/')
00251 *bp++ = '/';
00252 }
00253
00254
00255 i = fnlen;
00256 if (fspace < i) {
00257 toolong:
00258 PATHNAME_TOO_LONG();
00259 goto next;
00260 }
00261 fspace -= i;
00262 memcpy(bp, fname, i + 1);
00263
00264 #if defined(DOSISH)
00265 if (exe_flag && !ext) {
00266 needs_extension:
00267 for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
00268 if (fspace < strlen(extension[j])) {
00269 PATHNAME_TOO_LONG();
00270 continue;
00271 }
00272 strlcpy(bp + i, extension[j], fspace);
00273 if (stat(fbuf, &st) == 0)
00274 return fbuf;
00275 }
00276 goto next;
00277 }
00278 #endif
00279
00280 if (stat(fbuf, &st) == 0) {
00281 if (exe_flag == 0) return fbuf;
00282
00283 if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
00284 return fbuf;
00285 }
00286 next:
00287
00288 if (*ep == '\0') {
00289 return NULL;
00290 }
00291
00292
00293 }
00294 }
00295