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