dln_find.c

Go to the documentation of this file.
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_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 /* non 0 if looking for executable. */
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         /* extract a component */
00205         ep = strchr(dp, PATH_SEP[0]);
00206         if (ep == NULL)
00207             ep = dp+strlen(dp);
00208 
00209         /* find the length of that component */
00210         l = ep - dp;
00211         bp = fbuf;
00212         fspace = size - 2;
00213         if (l > 0) {
00214             /*
00215             **  If the length of the component is zero length,
00216             **  start from the current directory.  If the
00217             **  component begins with "~", start from the
00218             **  user's $HOME environment variable.  Otherwise
00219             **  take the path literally.
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             /* add a "/" between directory and filename */
00250             if (ep[-1] != '/')
00251                 *bp++ = '/';
00252         }
00253 
00254         /* now append the file name */
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 /* _WIN32 or __EMX__ */
00279 
00280         if (stat(fbuf, &st) == 0) {
00281             if (exe_flag == 0) return fbuf;
00282             /* looking for executable */
00283             if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
00284                 return fbuf;
00285         }
00286       next:
00287         /* if not, and no other alternatives, life is bleak */
00288         if (*ep == '\0') {
00289             return NULL;
00290         }
00291 
00292         /* otherwise try the next component in the search path */
00293     }
00294 }
00295 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7