pcb 4.1.1
An interactive printed circuit board layout editor.

lrealpath.c

Go to the documentation of this file.
00001 
00029 /*
00030 
00031 @deftypefn Replacement {const char*} lrealpath (const char *@var{name})
00032 
00033 Given a pointer to a string containing a pathname, returns a canonical
00034 version of the filename.  Symlinks will be resolved, and ``.'' and ``..''
00035 components will be simplified.  The returned value will be allocated using
00036 @code{malloc}, or @code{NULL} will be returned on a memory allocation error.
00037 
00038 @end deftypefn
00039 
00040 */
00041 
00042 #include "config.h"
00043 #include "lrealpath.h"
00044 
00045 #ifdef HAVE_LIMITS_H
00046 #include <limits.h>
00047 #endif
00048 #ifdef HAVE_STDLIB_H
00049 #include <stdlib.h>
00050 #endif
00051 #ifdef HAVE_UNISTD_H
00052 #include <unistd.h>
00053 #endif
00054 #ifdef HAVE_STRING_H
00055 #include <string.h>
00056 #endif
00057 
00058 /* On GNU libc systems the declaration is only visible with _GNU_SOURCE.  */
00059 #if defined(HAVE_CANONICALIZE_FILE_NAME) \
00060     && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
00061 extern char *canonicalize_file_name (const char *);
00062 #endif
00063 
00064 #if defined(HAVE_REALPATH)
00065 # if defined (PATH_MAX)
00066 #  define REALPATH_LIMIT PATH_MAX
00067 # else
00068 #  if defined (MAXPATHLEN)
00069 #   define REALPATH_LIMIT MAXPATHLEN
00070 #  endif
00071 # endif
00072 #else
00073   /* cygwin has realpath, so it won't get here.  */ 
00074 # if defined (_WIN32)
00075 #  define WIN32_LEAN_AND_MEAN
00076 #  include <windows.h> /* for GetFullPathName */
00077 # endif
00078 #endif
00079 
00083 char *
00084 lrealpath (const char *filename)
00085 {
00086   /* Method 1: The system has a compile time upper bound on a filename
00087      path.  Use that and realpath() to canonicalize the name.  This is
00088      the most common case.  Note that, if there isn't a compile time
00089      upper bound, you want to avoid realpath() at all costs.  */
00090 #if defined(REALPATH_LIMIT)
00091   {
00092     char buf[REALPATH_LIMIT];
00093     const char *rp = realpath (filename, buf);
00094     if (rp == NULL)
00095       rp = filename;
00096     return strdup (rp);
00097   }
00098   /* REALPATH_LIMIT */
00099 
00100   /* Method 2: The host system (i.e., GNU) has the function
00101      canonicalize_file_name() which malloc's a chunk of memory and
00102      returns that, use that.  */
00103 #elif defined(HAVE_CANONICALIZE_FILE_NAME)
00104   {
00105     char *rp = canonicalize_file_name (filename);
00106     if (rp == NULL)
00107       return strdup (filename);
00108     else
00109       return rp;
00110   }
00111   /* HAVE_CANONICALIZE_FILE_NAME */
00112 
00113   /* Method 3: Now we're getting desperate!  The system doesn't have a
00114      compile time buffer size and no alternative function.  Query the
00115      OS, using pathconf(), for the buffer limit.  Care is needed
00116      though, some systems do not limit PATH_MAX (return -1 for
00117      pathconf()) making it impossible to pass a correctly sized buffer
00118      to realpath() (it could always overflow).  On those systems, we
00119      skip this.  */
00120 #elif defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H)
00121   {
00122     /* Find out the max path size.  */
00123     long path_max = pathconf ("/", _PC_PATH_MAX);
00124     if (path_max > 0)
00125       {
00126         /* PATH_MAX is bounded.  */
00127         char *buf, *rp, *ret;
00128         buf = (char *) malloc (path_max);
00129         if (buf == NULL)
00130           return NULL;
00131         rp = realpath (filename, buf);
00132         ret = strdup (rp ? rp : filename);
00133         free (buf);
00134         return ret;
00135       }
00136   }
00137   /* HAVE_REALPATH && HAVE_UNISTD_H */
00138 
00139   /* The MS Windows method.  If we don't have realpath, we assume we
00140      don't have symlinks and just canonicalize to a Windows absolute
00141      path.  GetFullPath converts ../ and ./ in relative paths to
00142      absolute paths, filling in current drive if one is not given
00143      or using the current directory of a specified drive (eg, "E:foo").
00144      It also converts all forward slashes to back slashes.  */
00145 #elif defined (_WIN32)
00146   {
00147     char buf[MAX_PATH];
00148     char* basename;
00149     DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename);
00150     if (len == 0 || len > MAX_PATH - 1)
00151       return strdup (filename);
00152     else
00153       {
00154         /* The file system is case-preserving but case-insensitive,
00155            Canonicalize to lowercase, using the codepage associated
00156            with the process locale.  */
00157         CharLowerBuff (buf, len);
00158         return strdup (buf);
00159       }
00160   }
00161 #else
00162 
00163   /* This system is a lost cause, just duplicate the filename.  */
00164   return strdup (filename);
00165 #endif
00166 }