From 48e0ba6d23bdc0fcad1b620cb410bb0a57684edc Mon Sep 17 00:00:00 2001
From: Eric Blake <ebb9@byu.net>
Date: Thu, 29 Oct 2009 10:43:31 -0600
Subject: [PATCH] dirname: split into dirname-lgpl

dirname.h is proving quite useful from multiple LGPL modules,
given the number of trailing slash bugs fixed in syscalls;
only the calls to xalloc_die need to remain GPL.

* modules/dirname-lgpl: New module.
* modules/dirname (Files): Move library-safe files into
dirname-lgpl.
(Depends-on): Add dirname-lgpl.
(configure.ac): Declare witness.
* modules/double-slash-root (License): Relax license.
* lib/dirname.h (base_name, dir_name): Only declare when using GPL
module.
* lib/dirname.c (dir_len, mdir_name): Move...
* lib/dirname-lgpl.c: ...into new file.
* lib/basename.c (last_component, base_len): Move...
* lib/basename-lgpl.c: ...into new file.
* m4/dirname.m4 (gl_DIRNAME_LGPL): New macro.
(gl_DIRNAME): Use it.
* MODULES.html.sh (Enhancements for POSIX:2008 functions):
Mention new module.
* modules/dirname-tests (Depends-on): Add progname.
* tests/test-dirname.c (program_name): Delete.

Signed-off-by: Eric Blake <ebb9@byu.net>
---
 ChangeLog                 | 20 +++++++++
 MODULES.html.sh           |  1 +
 lib/basename-lgpl.c       | 75 ++++++++++++++++++++++++++++++++++
 lib/basename.c            | 74 +--------------------------------
 lib/dirname-lgpl.c        | 86 +++++++++++++++++++++++++++++++++++++++
 lib/dirname.c             | 64 +----------------------------
 lib/dirname.h             |  5 ++-
 m4/dirname.m4             | 14 +++++--
 modules/dirname           |  9 ++--
 modules/dirname-lgpl      | 29 +++++++++++++
 modules/dirname-tests     |  1 +
 modules/double-slash-root |  2 +-
 tests/test-dirname.c      |  2 -
 13 files changed, 234 insertions(+), 148 deletions(-)
 create mode 100644 lib/basename-lgpl.c
 create mode 100644 lib/dirname-lgpl.c
 create mode 100644 modules/dirname-lgpl

diff --git a/ChangeLog b/ChangeLog
index 27528cb958..26a0abf57f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
 2009-10-29  Eric Blake  <ebb9@byu.net>
 
+	dirname: split into dirname-lgpl
+	* modules/dirname-lgpl: New module.
+	* modules/dirname (Files): Move library-safe files into
+	dirname-lgpl.
+	(Depends-on): Add dirname-lgpl.
+	(configure.ac): Declare witness.
+	* modules/double-slash-root (License): Relax license.
+	* lib/dirname.h (base_name, dir_name): Only declare when using GPL
+	module.
+	* lib/dirname.c (dir_len, mdir_name): Move...
+	* lib/dirname-lgpl.c: ...into new file.
+	* lib/basename.c (last_component, base_len): Move...
+	* lib/basename-lgpl.c: ...into new file.
+	* m4/dirname.m4 (gl_DIRNAME_LGPL): New macro.
+	(gl_DIRNAME): Use it.
+	* MODULES.html.sh (Enhancements for POSIX:2008 functions):
+	Mention new module.
+	* modules/dirname-tests (Depends-on): Add progname.
+	* tests/test-dirname.c (program_name): Delete.
+
 	mkdir: make safe for libraries
 	* modules/mkdir (Depends-on): Drop xalloc.
 	* lib/mkdir.c (rpl_mkdir): Fail with ENOMEM rather than calling
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 62abf0f6e4..d8677e0ef9 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -2404,6 +2404,7 @@ func_all_modules ()
   func_module chdir-long
   func_module dirent-safer
   func_module dirname
+  func_module dirname-lgpl
   func_module getopt
   func_module iconv_open-utf
   func_module unistd-safer
diff --git a/lib/basename-lgpl.c b/lib/basename-lgpl.c
new file mode 100644
index 0000000000..444f042650
--- /dev/null
+++ b/lib/basename-lgpl.c
@@ -0,0 +1,75 @@
+/* basename.c -- return the last element in a file name
+
+   Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+   2009 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/>.  */
+
+#include <config.h>
+
+#include "dirname.h"
+
+#include <string.h>
+
+/* Return the address of the last file name component of NAME.  If
+   NAME has no relative file name components because it is a file
+   system root, return the empty string.  */
+
+char *
+last_component (char const *name)
+{
+  char const *base = name + FILE_SYSTEM_PREFIX_LEN (name);
+  char const *p;
+  bool saw_slash = false;
+
+  while (ISSLASH (*base))
+    base++;
+
+  for (p = base; *p; p++)
+    {
+      if (ISSLASH (*p))
+        saw_slash = true;
+      else if (saw_slash)
+        {
+          base = p;
+          saw_slash = false;
+        }
+    }
+
+  return (char *) base;
+}
+
+/* Return the length of the basename NAME.  Typically NAME is the
+   value returned by base_name or last_component.  Act like strlen
+   (NAME), except omit all trailing slashes.  */
+
+size_t
+base_len (char const *name)
+{
+  size_t len;
+  size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
+
+  for (len = strlen (name);  1 < len && ISSLASH (name[len - 1]);  len--)
+    continue;
+
+  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1
+      && ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2])
+    return 2;
+
+  if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len
+      && len == prefix_len && ISSLASH (name[prefix_len]))
+    return prefix_len + 1;
+
+  return len;
+}
diff --git a/lib/basename.c b/lib/basename.c
index 426ed40f1a..a6403f55f7 100644
--- a/lib/basename.c
+++ b/lib/basename.c
@@ -1,7 +1,7 @@
 /* basename.c -- return the last element in a file name
 
-   Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 Free
-   Software Foundation, Inc.
+   Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+   2009 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
@@ -24,52 +24,6 @@
 #include "xalloc.h"
 #include "xstrndup.h"
 
-/* Return the address of the last file name component of NAME.  If
-   NAME has no relative file name components because it is a file
-   system root, return the empty string.  */
-
-char *
-last_component (char const *name)
-{
-  char const *base = name + FILE_SYSTEM_PREFIX_LEN (name);
-  char const *p;
-  bool saw_slash = false;
-
-  while (ISSLASH (*base))
-    base++;
-
-  for (p = base; *p; p++)
-    {
-      if (ISSLASH (*p))
-	saw_slash = true;
-      else if (saw_slash)
-	{
-	  base = p;
-	  saw_slash = false;
-	}
-    }
-
-  return (char *) base;
-}
-
-
-/* In general, we can't use the builtin `basename' function if available,
-   since it has different meanings in different environments.
-   In some environments the builtin `basename' modifies its argument.
-
-   Return the last file name component of NAME, allocated with
-   xmalloc.  On systems with drive letters, a leading "./"
-   distinguishes relative names that would otherwise look like a drive
-   letter.  Unlike POSIX basename(), NAME cannot be NULL,
-   base_name("") returns "", and the first trailing slash is not
-   stripped.
-
-   If lstat (NAME) would succeed, then { chdir (dir_name (NAME));
-   lstat (base_name (NAME)); } will access the same file.  Likewise,
-   if the sequence { chdir (dir_name (NAME));
-   rename (base_name (NAME), "foo"); } succeeds, you have renamed NAME
-   to "foo" in the same directory NAME was in.  */
-
 char *
 base_name (char const *name)
 {
@@ -102,27 +56,3 @@ base_name (char const *name)
   /* Finally, copy the basename.  */
   return xstrndup (base, length);
 }
-
-/* Return the length of the basename NAME.  Typically NAME is the
-   value returned by base_name or last_component.  Act like strlen
-   (NAME), except omit all trailing slashes.  */
-
-size_t
-base_len (char const *name)
-{
-  size_t len;
-  size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
-
-  for (len = strlen (name);  1 < len && ISSLASH (name[len - 1]);  len--)
-    continue;
-
-  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1
-      && ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2])
-    return 2;
-
-  if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len
-      && len == prefix_len && ISSLASH (name[prefix_len]))
-    return prefix_len + 1;
-
-  return len;
-}
diff --git a/lib/dirname-lgpl.c b/lib/dirname-lgpl.c
new file mode 100644
index 0000000000..79ee0b5fba
--- /dev/null
+++ b/lib/dirname-lgpl.c
@@ -0,0 +1,86 @@
+/* dirname.c -- return all but the last element in a file name
+
+   Copyright (C) 1990, 1998, 2000, 2001, 2003, 2004, 2005, 2006, 2009
+   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/>.  */
+
+#include <config.h>
+
+#include "dirname.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Return the length of the prefix of FILE that will be used by
+   dir_name.  If FILE is in the working directory, this returns zero
+   even though `dir_name (FILE)' will return ".".  Works properly even
+   if there are trailing slashes (by effectively ignoring them).  */
+
+size_t
+dir_len (char const *file)
+{
+  size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file);
+  size_t length;
+
+  /* Advance prefix_length beyond important leading slashes.  */
+  prefix_length += (prefix_length != 0
+                    ? (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
+                       && ISSLASH (file[prefix_length]))
+                    : (ISSLASH (file[0])
+                       ? ((DOUBLE_SLASH_IS_DISTINCT_ROOT
+                           && ISSLASH (file[1]) && ! ISSLASH (file[2])
+                           ? 2 : 1))
+                       : 0));
+
+  /* Strip the basename and any redundant slashes before it.  */
+  for (length = last_component (file) - file;
+       prefix_length < length; length--)
+    if (! ISSLASH (file[length - 1]))
+      break;
+  return length;
+}
+
+
+/* In general, we can't use the builtin `dirname' function if available,
+   since it has different meanings in different environments.
+   In some environments the builtin `dirname' modifies its argument.
+
+   Return the leading directories part of FILE, allocated with malloc.
+   Works properly even if there are trailing slashes (by effectively
+   ignoring them).  Return NULL on failure.
+
+   If lstat (FILE) would succeed, then { chdir (dir_name (FILE));
+   lstat (base_name (FILE)); } will access the same file.  Likewise,
+   if the sequence { chdir (dir_name (FILE));
+   rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE
+   to "foo" in the same directory FILE was in.  */
+
+char *
+mdir_name (char const *file)
+{
+  size_t length = dir_len (file);
+  bool append_dot = (length == 0
+                     || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
+                         && length == FILE_SYSTEM_PREFIX_LEN (file)
+                         && file[2] != '\0' && ! ISSLASH (file[2])));
+  char *dir = malloc (length + append_dot + 1);
+  if (!dir)
+    return NULL;
+  memcpy (dir, file, length);
+  if (append_dot)
+    dir[length++] = '.';
+  dir[length] = '\0';
+  return dir;
+}
diff --git a/lib/dirname.c b/lib/dirname.c
index 20dcaf5b87..d032270a87 100644
--- a/lib/dirname.c
+++ b/lib/dirname.c
@@ -24,69 +24,7 @@
 #include <string.h>
 #include "xalloc.h"
 
-/* Return the length of the prefix of FILE that will be used by
-   dir_name.  If FILE is in the working directory, this returns zero
-   even though `dir_name (FILE)' will return ".".  Works properly even
-   if there are trailing slashes (by effectively ignoring them).  */
-
-size_t
-dir_len (char const *file)
-{
-  size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file);
-  size_t length;
-
-  /* Advance prefix_length beyond important leading slashes.  */
-  prefix_length += (prefix_length != 0
-		    ? (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
-		       && ISSLASH (file[prefix_length]))
-		    : (ISSLASH (file[0])
-		       ? ((DOUBLE_SLASH_IS_DISTINCT_ROOT
-			   && ISSLASH (file[1]) && ! ISSLASH (file[2])
-			   ? 2 : 1))
-		       : 0));
-
-  /* Strip the basename and any redundant slashes before it.  */
-  for (length = last_component (file) - file;
-       prefix_length < length; length--)
-    if (! ISSLASH (file[length - 1]))
-      break;
-  return length;
-}
-
-
-/* In general, we can't use the builtin `dirname' function if available,
-   since it has different meanings in different environments.
-   In some environments the builtin `dirname' modifies its argument.
-
-   Return the leading directories part of FILE, allocated with malloc.
-   Works properly even if there are trailing slashes (by effectively
-   ignoring them).  Return NULL on failure.
-
-   If lstat (FILE) would succeed, then { chdir (dir_name (FILE));
-   lstat (base_name (FILE)); } will access the same file.  Likewise,
-   if the sequence { chdir (dir_name (FILE));
-   rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE
-   to "foo" in the same directory FILE was in.  */
-
-char *
-mdir_name (char const *file)
-{
-  size_t length = dir_len (file);
-  bool append_dot = (length == 0
-		     || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
-			 && length == FILE_SYSTEM_PREFIX_LEN (file)
-			 && file[2] != '\0' && ! ISSLASH (file[2])));
-  char *dir = malloc (length + append_dot + 1);
-  if (!dir)
-    return NULL;
-  memcpy (dir, file, length);
-  if (append_dot)
-    dir[length++] = '.';
-  dir[length] = '\0';
-  return dir;
-}
-
-/* Just like mdir_name, above, except, rather than
+/* Just like mdir_name (dirname-lgpl.c), except, rather than
    returning NULL upon malloc failure, here, we report the
    "memory exhausted" condition and exit.  */
 
diff --git a/lib/dirname.h b/lib/dirname.h
index 90a1f0c2c1..df12ccaaa3 100644
--- a/lib/dirname.h
+++ b/lib/dirname.h
@@ -58,9 +58,12 @@
 # endif
 # define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F))
 
+# if GNULIB_DIRNAME
 char *base_name (char const *file);
-char *mdir_name (char const *file);
 char *dir_name (char const *file);
+# endif
+
+char *mdir_name (char const *file);
 size_t base_len (char const *file);
 size_t dir_len (char const *file);
 char *last_component (char const *file);
diff --git a/m4/dirname.m4 b/m4/dirname.m4
index e35da96582..4252b62e3a 100644
--- a/m4/dirname.m4
+++ b/m4/dirname.m4
@@ -1,18 +1,26 @@
-#serial 7   -*- autoconf -*-
-dnl Copyright (C) 2002-2006 Free Software Foundation, Inc.
+#serial 8   -*- autoconf -*-
+dnl Copyright (C) 2002-2006, 2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
 AC_DEFUN([gl_DIRNAME],
 [
+  AC_REQUIRE([gl_DIRNAME_LGPL])
   AC_LIBOBJ([basename])
   AC_LIBOBJ([dirname])
+])
+
+AC_DEFUN([gl_DIRNAME_LGPL],
+[
+  AC_LIBOBJ([basename-lgpl])
+  AC_LIBOBJ([dirname-lgpl])
   AC_LIBOBJ([stripslash])
 
   dnl Prerequisites of lib/dirname.h.
   AC_REQUIRE([gl_AC_DOS])
   AC_REQUIRE([gl_DOUBLE_SLASH_ROOT])
 
-  dnl No prerequisites of lib/basename.c, lib/dirname.c, lib/stripslash.c.
+  dnl No prerequisites of lib/basename-lgpl.c, lib/dirname-lgpl.c,
+  dnl lib/stripslash.c.
 ])
diff --git a/modules/dirname b/modules/dirname
index 7c405c2855..888c8bad48 100644
--- a/modules/dirname
+++ b/modules/dirname
@@ -2,21 +2,18 @@ Description:
 Extract specific portions of filenames.
 
 Files:
-lib/dirname.h
 lib/dirname.c
 lib/basename.c
 lib/stripslash.c
-m4/dirname.m4
-m4/dos.m4
 
 Depends-on:
-double-slash-root
-stdbool
+dirname-lgpl
 xalloc
 xstrndup
 
 configure.ac:
 gl_DIRNAME
+gl_MODULE_INDICATOR([dirname])
 
 Makefile.am:
 
@@ -27,4 +24,4 @@ License:
 GPL
 
 Maintainer:
-Jim Meyering
+Jim Meyering, Eric Blake
diff --git a/modules/dirname-lgpl b/modules/dirname-lgpl
new file mode 100644
index 0000000000..38f779abde
--- /dev/null
+++ b/modules/dirname-lgpl
@@ -0,0 +1,29 @@
+Description:
+Extract specific portions of filenames.
+
+Files:
+lib/dirname.h
+lib/dirname-lgpl.c
+lib/basename-lgpl.c
+lib/stripslash.c
+m4/dirname.m4
+m4/dos.m4
+
+Depends-on:
+double-slash-root
+malloc-posix
+stdbool
+
+configure.ac:
+gl_DIRNAME_LGPL
+
+Makefile.am:
+
+Include:
+"dirname.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+Jim Meyering, Eric Blake
diff --git a/modules/dirname-tests b/modules/dirname-tests
index e2e86e658f..49eeb596dd 100644
--- a/modules/dirname-tests
+++ b/modules/dirname-tests
@@ -2,6 +2,7 @@ Files:
 tests/test-dirname.c
 
 Depends-on:
+progname
 strdup
 
 configure.ac:
diff --git a/modules/double-slash-root b/modules/double-slash-root
index 6b809d067c..af78f2681c 100644
--- a/modules/double-slash-root
+++ b/modules/double-slash-root
@@ -14,7 +14,7 @@ Makefile.am:
 Include:
 
 License:
-LGPL
+LGPLv2+
 
 Maintainer:
 Eric Blake, Paul Eggert, Jim Meyering
diff --git a/tests/test-dirname.c b/tests/test-dirname.c
index bd75020151..debda3f1c9 100644
--- a/tests/test-dirname.c
+++ b/tests/test-dirname.c
@@ -23,8 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-const char *program_name = "test-dirname";
-
 struct test {
   const char *name;	/* Name under test.  */
   const char *dir;	/* dir_name (name).  */
-- 
2.39.5