]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
maint: refactor relpath() from `realpath` for use by `ln`
authorPádraig Brady <P@draigBrady.com>
Thu, 22 Mar 2012 20:34:57 +0000 (20:34 +0000)
committerPádraig Brady <P@draigBrady.com>
Thu, 22 Mar 2012 20:34:57 +0000 (20:34 +0000)
* src/relpath.c: Refactored from realpath.c and adjusted
to support returning the relative path rather than just
printing to stdout.
* src/relpath.h: Export the relpath function.
* src/Makefile.am: Reference the refactored relpath module.
* po/POTFILES.in: Likewise.
* src/realpath.c: Adjust to the refactored relpath module.

po/POTFILES.in
src/Makefile.am
src/realpath.c
src/relpath.c [new file with mode: 0644]
src/relpath.h [new file with mode: 0644]

index c92dd3c3e8db3521ebaf0800d4483c53d4bc95a4..7b3de0b01e6f80cbd3bec49bdc96185aa2289e63 100644 (file)
@@ -103,6 +103,7 @@ src/ptx.c
 src/pwd.c
 src/readlink.c
 src/realpath.c
+src/relpath.c
 src/remove.c
 src/rm.c
 src/rmdir.c
index b1240647719f19a8d65bcff1afc34ed882991d7f..85f12d65a5a34279cf5e709d6eda364e81bc8cf1 100644 (file)
@@ -477,6 +477,7 @@ ls_SOURCES = ls.c ls-ls.c
 chown_SOURCES = chown.c chown-core.c
 chgrp_SOURCES = chgrp.c chown-core.c
 kill_SOURCES = kill.c operand2sig.c
+realpath_SOURCES = realpath.c relpath.c relpath.h
 timeout_SOURCES = timeout.c operand2sig.c
 
 mv_SOURCES = mv.c remove.c $(copy_sources)
index 206f8006d0ee2c691344ed460ba40ef14c74992b..cd595b8c750cbaf4a8bade0857167d03081c2bcf 100644 (file)
@@ -25,6 +25,7 @@
 #include "canonicalize.h"
 #include "error.h"
 #include "quote.h"
+#include "relpath.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
 #define PROGRAM_NAME "realpath"
@@ -136,97 +137,6 @@ path_prefix (const char *prefix, const char *path)
   return (!*prefix && (*path == '/' || !*path));
 }
 
-/* Return the length of the longest common prefix
-   of canonical PATH1 and PATH2, ensuring only full path components
-   are matched.  Return 0 on no match.  */
-static int _GL_ATTRIBUTE_PURE
-path_common_prefix (const char *path1, const char *path2)
-{
-  int i = 0;
-  int ret = 0;
-
-  /* We already know path1[0] and path2[0] are '/'.  Special case
-     '//', which is only present in a canonical name on platforms
-     where it is distinct.  */
-  if ((path1[1] == '/') != (path2[1] == '/'))
-    return 0;
-
-  while (*path1 && *path2)
-    {
-      if (*path1 != *path2)
-        break;
-      if (*path1 == '/')
-        ret = i + 1;
-      path1++;
-      path2++;
-      i++;
-    }
-
-  if (!*path1 && !*path2)
-    ret = i;
-  if (!*path1 && *path2 == '/')
-    ret = i;
-  if (!*path2 && *path1 == '/')
-    ret = i;
-
-  return ret;
-}
-
-/* Output the relative representation if requested.  */
-static bool
-relpath (const char *can_fname)
-{
-  if (can_relative_to)
-    {
-      /* Enforce --relative-base.  */
-      if (can_relative_base && !path_prefix (can_relative_base, can_fname))
-        return false;
-
-      /* Skip the prefix common to --relative-to and path.  */
-      int common_index = path_common_prefix (can_relative_to, can_fname);
-      if (!common_index)
-        return false;
-
-      const char *relto_suffix = can_relative_to + common_index;
-      const char *fname_suffix = can_fname + common_index;
-
-      /* skip over extraneous '/'.  */
-      if (*relto_suffix == '/')
-        relto_suffix++;
-      if (*fname_suffix == '/')
-        fname_suffix++;
-
-      /* Replace remaining components of --relative-to with '..', to get
-         to a common directory.  Then output the remainder of fname.  */
-      if (*relto_suffix)
-        {
-          fputs ("..", stdout);
-          for (; *relto_suffix; ++relto_suffix)
-            {
-              if (*relto_suffix == '/')
-                fputs ("/..", stdout);
-            }
-
-          if (*fname_suffix)
-            {
-              putchar ('/');
-              fputs (fname_suffix, stdout);
-            }
-        }
-      else
-        {
-          if (*fname_suffix)
-            fputs (fname_suffix, stdout);
-          else
-            putchar ('.');
-        }
-
-      return true;
-    }
-
-  return false;
-}
-
 static bool
 isdir (const char *path)
 {
@@ -247,7 +157,9 @@ process_path (const char *fname, int can_mode)
       return false;
     }
 
-  if (!relpath (can_fname))
+  if (!can_relative_to
+      || (can_relative_base && !path_prefix (can_relative_base, can_fname))
+      || (can_relative_to && !relpath (can_fname, can_relative_to, NULL, 0)))
     fputs (can_fname, stdout);
 
   putchar (use_nuls ? '\0' : '\n');
diff --git a/src/relpath.c b/src/relpath.c
new file mode 100644 (file)
index 0000000..4405361
--- /dev/null
@@ -0,0 +1,133 @@
+/* relpath - print the relative path
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Pádraig Brady.  */
+
+#include <config.h>
+
+#include "error.h"
+#include "system.h"
+#include "relpath.h"
+
+
+/* Return the length of the longest common prefix
+   of canonical PATH1 and PATH2, ensuring only full path components
+   are matched.  Return 0 on no match.  */
+static int _GL_ATTRIBUTE_PURE
+path_common_prefix (const char *path1, const char *path2)
+{
+  int i = 0;
+  int ret = 0;
+
+  /* We already know path1[0] and path2[0] are '/'.  Special case
+     '//', which is only present in a canonical name on platforms
+     where it is distinct.  */
+  if ((path1[1] == '/') != (path2[1] == '/'))
+    return 0;
+
+  while (*path1 && *path2)
+    {
+      if (*path1 != *path2)
+        break;
+      if (*path1 == '/')
+        ret = i + 1;
+      path1++;
+      path2++;
+      i++;
+    }
+
+  if ((!*path1 && !*path2)
+      || (!*path1 && *path2 == '/')
+      || (!*path2 && *path1 == '/'))
+    ret = i;
+
+  return ret;
+}
+
+/* Either output STR to stdout or
+   if *PBUF is not NULL then append STR to *PBUF
+   and update *PBUF to point to the end of the buffer
+   and adjust *PLEN to reflect the remaining space.
+   Return TRUE on failure.  */
+static bool
+buffer_or_output (const char* str, char **pbuf, size_t *plen)
+{
+  if (*pbuf)
+    {
+      size_t slen = strlen (str);
+      if (slen >= *plen)
+        return true;
+      memcpy (*pbuf, str, slen + 1);
+      *pbuf += slen;
+      *plen -= slen;
+    }
+  else
+    {
+      fputs (str, stdout);
+    }
+
+  return false;
+}
+
+/* Output the relative representation if possible.
+   If BUF is non NULL, write to that buffer rather than to stdout.  */
+bool
+relpath (const char *can_fname, const char *can_reldir, char *buf, size_t len)
+{
+  bool buf_err = false;
+
+  /* Skip the prefix common to --relative-to and path.  */
+  int common_index = path_common_prefix (can_reldir, can_fname);
+  if (!common_index)
+    return false;
+
+  const char *relto_suffix = can_reldir + common_index;
+  const char *fname_suffix = can_fname + common_index;
+
+  /* Skip over extraneous '/'.  */
+  if (*relto_suffix == '/')
+    relto_suffix++;
+  if (*fname_suffix == '/')
+    fname_suffix++;
+
+  /* Replace remaining components of --relative-to with '..', to get
+     to a common directory.  Then output the remainder of fname.  */
+  if (*relto_suffix)
+    {
+      buf_err |= buffer_or_output ("..", &buf, &len);
+      for (; *relto_suffix; ++relto_suffix)
+        {
+          if (*relto_suffix == '/')
+            buf_err |= buffer_or_output ("/..", &buf, &len);
+        }
+
+      if (*fname_suffix)
+        {
+          buf_err |= buffer_or_output ("/", &buf, &len);
+          buf_err |= buffer_or_output (fname_suffix, &buf, &len);
+        }
+    }
+  else
+    {
+        buf_err |= buffer_or_output (*fname_suffix ? fname_suffix : ".",
+                                     &buf, &len);
+    }
+
+  if (buf_err)
+    error (0, ENAMETOOLONG, "%s", _("generating relative path"));
+
+  return !buf_err;
+}
diff --git a/src/relpath.h b/src/relpath.h
new file mode 100644 (file)
index 0000000..e25f82b
--- /dev/null
@@ -0,0 +1,25 @@
+/* relpath - print the relative path
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Pádraig Brady.  */
+
+#ifndef _RELPATH_H
+# define _RELPATH_H
+
+extern bool
+relpath (const char *can_fname, const char *can_reldir, char *buf, size_t len);
+
+#endif