bug-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: File path bug on windows platform


From: Eli Zaretskii
Subject: Re: File path bug on windows platform
Date: Sat, 25 Nov 2006 12:46:55 +0200

> Date: Fri, 24 Nov 2006 00:44:42 +0800
> From: goodmen <address@hidden>
> 
> I'm using gnu make version 3.81. I compile the soucre using msvc7.
> Please run this script on ms windows of any version.
> ===============================================================================
> __this_file := $(lastword $(MAKEFILE_LIST))
> __this_file := $(abspath $(__this_file))
> __sub_dir_path := $(realpath $(dir $(__this_file))/sub_dir)
> 
> $(warning $(__this_file))
> $(warning $(__sub_dir_path))
> 
> all :
> @ echo Please run this gnumake script on M$-windows
> ===============================================================================
> 
> the realpath do not work as the doc described.
> I'm tried to fix this bug, but I trust the skills of the authors than mine.
> Here is some info:
> in the file function.c , abspath() ,line 1892 says : "if (name[0] != '/')"
> but on windows system, this condition is not an indicator of whether a
> string is absolute path.

Thank you for your report.

As of Make 3.81, the functions abspath and realpath are not yet
supported on MS-Windows.  They currently only work on Posix platforms.

I hope to have that fixed in the next release.

In fact, I have a preliminary patch to fix that, so if you need this
ASAP, and can rebuild Make from sources on your machine, please try
the patch below and tell me if it works for you.


2006-05-27  Eli Zaretskii  <address@hidden>

        * function.c (IS_ABSOLUTE, ROOT_LEN): New macros.
        (abspath): Support systems that define HAVE_DOS_PATHS (have
        drive letters in their file names).  Use IS_PATHSEP instead of a
        literal '/' comparison.  Use IS_ABSOLUTE and ROOT_LEN.


--- function.c~1        2006-05-27 15:58:26.984375000 +0300
+++ function.c  2006-05-27 17:37:47.453125000 +0300
@@ -1890,6 +1890,14 @@ func_not (char *o, char **argv, char *fu
 #endif
 
 
+#ifdef HAVE_DOS_PATHS
+#define IS_ABSOLUTE(n) (n[0] && n[1] == ':')
+#define ROOT_LEN 3
+#else
+#define IS_ABSOLUTE(n) (n[0] == '/')
+#define ROOT_LEN 1
+#endif
+
 /* Return the absolute name of file NAME which does not contain any `.',
    `..' components nor any repeated path separators ('/').   */
 
@@ -1898,13 +1906,14 @@ abspath (const char *name, char *apath)
 {
   char *dest;
   const char *start, *end, *apath_limit;
+  unsigned long root_len = ROOT_LEN;
 
   if (name[0] == '\0' || apath == NULL)
     return NULL;
 
   apath_limit = apath + GET_PATH_MAX;
 
-  if (name[0] != '/')
+  if (!IS_ABSOLUTE(name))
     {
       /* It is unlikely we would make it until here but just to make sure. */
       if (!starting_directory)
@@ -1912,12 +1921,40 @@ abspath (const char *name, char *apath)
 
       strcpy (apath, starting_directory);
 
+#ifdef HAVE_DOS_PATHS
+      if (IS_PATHSEP(name[0]))
+       {
+         /* We have /foo, an absolute file name except for the drive
+            letter.  Assume the missing drive letter is the current
+            drive, which we can get if we remove from starting_directory
+            everything past the root directory.  */
+         apath[root_len] = '\0';
+       }
+#endif
+
       dest = strchr (apath, '\0');
     }
   else
     {
-      apath[0] = '/';
-      dest = apath + 1;
+      strncpy (apath, name, root_len);
+      apath[root_len] = '\0';
+      dest = apath + root_len;
+      /* Get past the root, since we already copied it.  */
+      name += root_len;
+#ifdef HAVE_DOS_PATHS
+      if (!IS_PATHSEP(apath[2]))
+       {
+         /* Convert d:foo into d:./foo and increase root_len.  */
+         apath[2] = '.';
+         apath[3] = '/';
+         dest++;
+         root_len++;
+         /* strncpy above copied one character too many.  */
+         name--;
+       }
+      else
+       apath[2] = '/'; /* make sure it's a forward slash */
+#endif
     }
 
   for (start = end = name; *start != '\0'; start = end)
@@ -1925,11 +1962,11 @@ abspath (const char *name, char *apath)
       unsigned long len;
 
       /* Skip sequence of multiple path-separators.  */
-      while (*start == '/')
+      while (IS_PATHSEP(*start))
        ++start;
 
       /* Find end of path component.  */
-      for (end = start; *end != '\0' && *end != '/'; ++end)
+      for (end = start; *end != '\0' && !IS_PATHSEP(*end); ++end)
         ;
 
       len = end - start;
@@ -1941,12 +1978,12 @@ abspath (const char *name, char *apath)
       else if (len == 2 && start[0] == '.' && start[1] == '.')
        {
          /* Back up to previous component, ignore if at root already.  */
-         if (dest > apath + 1)
-           while ((--dest)[-1] != '/');
+         if (dest > apath + root_len)
+           for (--dest; !IS_PATHSEP(dest[-1]); --dest);
        }
       else
        {
-         if (dest[-1] != '/')
+         if (!IS_PATHSEP(dest[-1]))
             *dest++ = '/';
 
          if (dest + len >= apath_limit)
@@ -1959,7 +1996,7 @@ abspath (const char *name, char *apath)
     }
 
   /* Unless it is root strip trailing separator.  */
-  if (dest > apath + 1 && dest[-1] == '/')
+  if (dest > apath + root_len && IS_PATHSEP(dest[-1]))
     --dest;
 
   *dest = '\0';




reply via email to

[Prev in Thread] Current Thread [Next in Thread]