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