bug-gnulib
[Top][All Lists]
Advanced

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

new module: relpath


From: Akim Demaille
Subject: new module: relpath
Date: Thu, 14 Jun 2012 18:02:35 +0200

Hi all,

In Bison, I consider computing relative paths between files
(one concrete use is when the user creates the parser implementation
file in --output=sub1/sub2/parser.c and the header file in
--defines=sub3/sub4/parser.h, in which case parser.c should include
"../../sub3/sub4/parser.h").

At least to experiment on the concept, and on a suggestion from
Eric Blake weeks ago, I stole bits of the coreutils, and made them
a gnulib module.

I am far from being a genuine gnulib contributor, especially not
a module author, so I would appreciate comments, and even more,
patches :)  The following patch corresponds to what's currently
in akim/relpath on the main repository.  This is almost a straight
direct copy from the coreutils.  My contribution is merely adding
the dependencies, expanding #include "system.h", and adding the
convert_abs_rel function to relpath.[ch] (it lives in ln.c).

(I will write the ChangeLog when it's mature and ready to be
pushed).

Thanks!

From 2005fbf739536a0f60bf970c24c1ecf3c9cc8a43 Mon Sep 17 00:00:00 2001
From: Akim Demaille <address@hidden>
Date: Wed, 13 Jun 2012 22:21:57 +0200
Subject: [PATCH] relpath: new module

* lib/relpath.c: New.
* lib/relpath.h: New.
* modules/relpath: New.
---
 lib/relpath.c   |  176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/relpath.h   |   34 +++++++++++
 modules/relpath |   28 +++++++++
 3 files changed, 238 insertions(+)
 create mode 100644 lib/relpath.c
 create mode 100644 lib/relpath.h
 create mode 100644 modules/relpath

diff --git a/lib/relpath.c b/lib/relpath.c
new file mode 100644
index 0000000..1869178
--- /dev/null
+++ b/lib/relpath.c
@@ -0,0 +1,176 @@
+/* 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 <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+#include "canonicalize.h"
+#include "dirname.h"
+#include "error.h"
+#include "relpath.h"
+#include "xalloc.h"
+
+#include "pathmax.h"
+#ifndef PATH_MAX
+# define PATH_MAX 8192
+#endif
+
+
+/* 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;
+}
+
+/* Return FROM represented as relative to the dir of TARGET.
+   The result is malloced.  */
+
+char *
+convert_abs_rel (const char *from, const char *target)
+{
+  char *realtarget = canonicalize_filename_mode (target, CAN_MISSING);
+  char *realfrom = canonicalize_filename_mode (from, CAN_MISSING);
+
+  /* Write to a PATH_MAX buffer.  */
+  char *relative_from = xmalloc (PATH_MAX);
+
+  /* Get dirname to generate paths relative to.  */
+  realtarget[dir_len (realtarget)] = '\0';
+
+  if (!relpath (realfrom, realtarget, relative_from, PATH_MAX))
+    {
+      free (relative_from);
+      relative_from = NULL;
+    }
+
+  free (realtarget);
+  free (realfrom);
+
+  return relative_from ? relative_from : xstrdup (from);
+}
diff --git a/lib/relpath.h b/lib/relpath.h
new file mode 100644
index 0000000..ad49976
--- /dev/null
+++ b/lib/relpath.h
@@ -0,0 +1,34 @@
+/* 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
+
+/* 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);
+
+/* Return FROM represented as relative to the dir of TARGET.
+   The result is malloced.  */
+
+char *
+convert_abs_rel (const char *from, const char *target);
+
+#endif
diff --git a/modules/relpath b/modules/relpath
new file mode 100644
index 0000000..a250296
--- /dev/null
+++ b/modules/relpath
@@ -0,0 +1,28 @@
+Description:
+Convert absolute paths to relative.
+
+Files:
+lib/relpath.h
+lib/relpath.c
+
+Depends-on:
+canonicalize
+dirname
+error
+pathmax
+stdbool
+xalloc
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += relpath.c
+
+Include:
+"relpath.h"
+
+License:
+GPLv3+
+
+Maintainer:
+Pádraig Brady
-- 
1.7.10.4





reply via email to

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