bug-gnulib
[Top][All Lists]
Advanced

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

findprog: don't exit => exit-free base_name, dir_name, etc


From: Jim Meyering
Subject: findprog: don't exit => exit-free base_name, dir_name, etc
Date: Thu, 28 Aug 2008 19:12:21 +0200

I wanted a version of findprog that I could use from a library
(libvirt), but the existing one can call exit in several ways.

My first cut at this changes findprog itself not to call exit anymore.
Obviously, this is an API change, and may well be undesirable, in which
case I can easily create a new module, say mfindprog, and make findprog
a trivial wrapper around that new function.  Bruno, let me know which
you'd prefer.

Since the modified findprog module uses file-name manipulation functions,
I wanted ones that meet my no-exit/LGPLv2+ requirement, so ended up with
a new module, mfilenamecat (wrapper around filenamecat), and mfilename
(contents of basename.c and dirname.c, adjusted not to exit).  Now,
the dirname module depends on mfilename.

This has led to the following seemingly large change, but the only API
impact is on findprog users, and I can remove that, if required.

I've tested this by running this

  for i in dirname findprog mfilename mfilenamecat; do echo $i;
    ./gnulib-tool --create-testdir --with-tests --test $i; done

and by using the updated files in both libvirt and coreutils, although
libvirt doesn't call findprog yet and coreutils call it, either.

Comments welcome.

Jim

>From 4287e5220121f7eddc360fcb07be1b39c101b3a3 Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Thu, 21 Aug 2008 17:01:18 +0200
Subject: [PATCH] mfilenamecat, mfilename: new modules;  findprog: do not exit

* modules/mfilename:New file.
* modules/mfilenamecat: New file.
* modules/findprog (License): Relicense to LGPLv2+.
(Depends-on): Add mfilename; remove xalloc and filename.
* m4/dirname.m4: Remove file.  No longer needed.
* modules/dirname (Files): Remove it here, too.
Remove dos.m4, too.  It's pulled in via dependency on mfilename.
(Depends-on): Add mfilename.
(configure.ac): Remove gl_DIRNAME.
(lib_SOURCES): Add dirname.c basename.c stripslash.c.
* modules/double-slash-root (License): Relicense to LGPLv2+.
* modules/filenamecat (Files): Remove dos.m4 and filenamecat.c.
Both are now pulled in via dependency on mfilenamecat.
(Depends-on): Add mfilenamecat.
(configure.ac): Remove gl_FILE_NAME_CONCAT.
* m4/filenamecat.m4: Remove file
* m4/mfilenamecat.m4 (gl_MFILE_NAME_CONCAT, gl_FILE_NAME_CONCAT):
New file, macros.  Adapted from filenamecat.m4.
* lib/filenamecat.c: Move mfile_name_concat to mfilenamecat.c.
* lib/filenamecat.h: Move decl of mfile_name_concat to mfilenamecat.h.
* lib/mfilenamecat.c: New file (contents from filenamecat.c)
* lib/mfilenamecat.h: New file
* lib/mfilename.c: New file.
* lib/mfilename.h: New file
* lib/basename.c: Include "mfilename.h".
(last_component, base_len): Move functions to mfilename.c.
(base_name): Replace contents with a use of new mbase_name.
* lib/dirname.h: Include "mfilename.h".
Move contents except for decls of base_name, dir_name,
and strip_trailing_slashes to mfilename.h.
* lib/dirname.c: Include "mfilename.h".
(dir_len): Move function to mfilename.c.
(dir_name): Replace contents with a use of new mdir_name
* lib/findprog.c: Include <errno.h> and "mfilenamecat.h", but
not "xalloc.h" or "filename.h".
(find_in_path): Use strdup, not xstrdup.
Use mfile_name_concat, not concatenated_filename.
Handle failures.
---
 lib/basename.c                         |   87 +--------------
 lib/dirname.c                          |   50 +--------
 lib/dirname.h                          |   45 +--------
 lib/filenamecat.c                      |   71 +------------
 lib/filenamecat.h                      |    5 +-
 lib/findprog.c                         |   30 ++++-
 lib/mfilename.c                        |  182 ++++++++++++++++++++++++++++++++
 lib/mfilename.h                        |   67 ++++++++++++
 lib/mfilenamecat.c                     |   88 +++++++++++++++
 lib/mfilenamecat.h                     |   21 ++++
 m4/dirname.m4                          |   18 ---
 m4/{filenamecat.m4 => mfilenamecat.m4} |    8 +-
 modules/dirname                        |    5 +-
 modules/double-slash-root              |    2 +-
 modules/filenamecat                    |    5 +-
 modules/findprog                       |    6 +-
 modules/mfilename                      |   25 +++++
 modules/mfilenamecat                   |   25 +++++
 18 files changed, 460 insertions(+), 280 deletions(-)
 create mode 100644 lib/mfilename.c
 create mode 100644 lib/mfilename.h
 create mode 100644 lib/mfilenamecat.c
 create mode 100644 lib/mfilenamecat.h
 delete mode 100644 m4/dirname.m4
 rename m4/{filenamecat.m4 => mfilenamecat.m4} (62%)
 create mode 100644 modules/mfilename
 create mode 100644 modules/mfilenamecat

diff --git a/lib/basename.c b/lib/basename.c
index 426ed40..aa0ecaf 100644
--- a/lib/basename.c
+++ b/lib/basename.c
@@ -21,37 +21,8 @@
 #include "dirname.h"

 #include <string.h>
+#include "mfilename.h"
 #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.
@@ -73,56 +44,8 @@ last_component (char const *name)
 char *
 base_name (char const *name)
 {
-  char const *base = last_component (name);
-  size_t length;
-
-  /* If there is no last component, then name is a file system root or the
-     empty string.  */
-  if (! *base)
-    return xstrndup (name, base_len (name));
-
-  /* Collapse a sequence of trailing slashes into one.  */
-  length = base_len (base);
-  if (ISSLASH (base[length]))
-    length++;
-
-  /* On systems with drive letters, `a/b:c' must return `./b:c' rather
-     than `b:c' to avoid confusion with a drive letter.  On systems
-     with pure POSIX semantics, this is not an issue.  */
-  if (FILE_SYSTEM_PREFIX_LEN (base))
-    {
-      char *p = xmalloc (length + 3);
-      p[0] = '.';
-      p[1] = '/';
-      memcpy (p + 2, base, length);
-      p[length + 2] = '\0';
-      return p;
-    }
-
-  /* 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;
+  char *p = mbase_name (name);
+  if (!p)
+    xalloc_die ();
+  return p;
 }
diff --git a/lib/dirname.c b/lib/dirname.c
index c27e5b5..2ef4c29 100644
--- a/lib/dirname.c
+++ b/lib/dirname.c
@@ -1,6 +1,6 @@
 /* dirname.c -- return all but the last element in a file name

-   Copyright (C) 1990, 1998, 2000, 2001, 2003, 2004, 2005, 2006 Free Software
+   Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2008 Free Software
    Foundation, Inc.

    This program is free software: you can redistribute it and/or modify
@@ -19,40 +19,9 @@
 #include <config.h>

 #include "dirname.h"
-
-#include <string.h>
+#include "mfilename.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.
@@ -70,15 +39,8 @@ dir_len (char const *file)
 char *
 dir_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 = xmalloc (length + append_dot + 1);
-  memcpy (dir, file, length);
-  if (append_dot)
-    dir[length++] = '.';
-  dir[length] = '\0';
-  return dir;
+  char *p = mdir_name (file);
+  if (!p)
+    xalloc_die ();
+  return p;
 }
diff --git a/lib/dirname.h b/lib/dirname.h
index f592350..8cd094f 100644
--- a/lib/dirname.h
+++ b/lib/dirname.h
@@ -1,6 +1,6 @@
 /*  Take file names apart into directory and base names.

-    Copyright (C) 1998, 2001, 2003-2006 Free Software Foundation, Inc.
+    Copyright (C) 1998, 2001, 2003-2006, 2008 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
@@ -18,51 +18,10 @@
 #ifndef DIRNAME_H_
 # define DIRNAME_H_ 1

-# include <stdbool.h>
-# include <stddef.h>
-
-# ifndef DIRECTORY_SEPARATOR
-#  define DIRECTORY_SEPARATOR '/'
-# endif
-
-# ifndef ISSLASH
-#  define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
-# endif
-
-# ifndef FILE_SYSTEM_PREFIX_LEN
-#  if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
-    /* This internal macro assumes ASCII, but all hosts that support drive
-       letters use ASCII.  */
-#   define _IS_DRIVE_LETTER(c) (((unsigned int) (c) | ('a' - 'A')) - 'a' \
-                               <= 'z' - 'a')
-#   define FILE_SYSTEM_PREFIX_LEN(Filename) \
-          (_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':' ? 2 : 0)
-#  else
-#   define FILE_SYSTEM_PREFIX_LEN(Filename) 0
-#  endif
-# endif
-
-# ifndef FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
-#  define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0
-# endif
-
-# ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
-#  define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
-# endif
-
-# if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
-#  define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)])
-# else
-#  define IS_ABSOLUTE_FILE_NAME(F) \
-         (ISSLASH ((F)[0]) || 0 < FILE_SYSTEM_PREFIX_LEN (F))
-# endif
-# define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F))
+# include "mfilename.h"

 char *base_name (char const *file);
 char *dir_name (char const *file);
-size_t base_len (char const *file);
-size_t dir_len (char const *file);
-char *last_component (char const *file);

 bool strip_trailing_slashes (char *file);

diff --git a/lib/filenamecat.c b/lib/filenamecat.c
index ef46de2..704e89b 100644
--- a/lib/filenamecat.c
+++ b/lib/filenamecat.c
@@ -1,6 +1,6 @@
 /* Concatenate two arbitrary file names.

-   Copyright (C) 1996-2007 Free Software Foundation, Inc.
+   Copyright (C) 1996-2008 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
@@ -22,73 +22,10 @@
 /* Specification.  */
 #include "filenamecat.h"

-#include <stdlib.h>
-#include <string.h>
-
-#include "dirname.h"
+#include "mfilenamecat.h"
 #include "xalloc.h"

-#if ! HAVE_MEMPCPY && ! defined mempcpy
-# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
-#endif
-
-/* Return the longest suffix of F that is a relative file name.
-   If it has no such suffix, return the empty string.  */
-
-static char const *
-longest_relative_suffix (char const *f)
-{
-  for (f += FILE_SYSTEM_PREFIX_LEN (f); ISSLASH (*f); f++)
-    continue;
-  return f;
-}
-
-/* Concatenate two file name components, DIR and ABASE, in
-   newly-allocated storage and return the result.
-   The resulting file name F is such that the commands "ls F" and "(cd
-   DIR; ls BASE)" refer to the same file, where BASE is ABASE with any
-   file system prefixes and leading separators removed.
-   Arrange for a directory separator if necessary between DIR and BASE
-   in the result, removing any redundant separators.
-   In any case, if BASE_IN_RESULT is non-NULL, set
-   *BASE_IN_RESULT to point to the copy of ABASE in the returned
-   concatenation.  However, if ABASE begins with more than one slash,
-   set *BASE_IN_RESULT to point to the sole corresponding slash that
-   is copied into the result buffer.
-
-   Return NULL if malloc fails.  */
-
-char *
-mfile_name_concat (char const *dir, char const *abase, char **base_in_result)
-{
-  char const *dirbase = last_component (dir);
-  size_t dirbaselen = base_len (dirbase);
-  size_t dirlen = dirbase - dir + dirbaselen;
-  size_t needs_separator = (dirbaselen && ! ISSLASH (dirbase[dirbaselen - 1]));
-
-  char const *base = longest_relative_suffix (abase);
-  size_t baselen = strlen (base);
-
-  char *p_concat = malloc (dirlen + needs_separator + baselen + 1);
-  char *p;
-
-  if (p_concat == NULL)
-    return NULL;
-
-  p = mempcpy (p_concat, dir, dirlen);
-  *p = DIRECTORY_SEPARATOR;
-  p += needs_separator;
-
-  if (base_in_result)
-    *base_in_result = p - IS_ABSOLUTE_FILE_NAME (abase);
-
-  p = mempcpy (p, base, baselen);
-  *p = '\0';
-
-  return p_concat;
-}
-
-/* Just like mfile_name_concat, above, except, rather than
+/* Just like mfile_name_concat, except, rather than
    returning NULL upon malloc failure, here, we report the
    "memory exhausted" condition and exit.  */

@@ -96,7 +33,7 @@ char *
 file_name_concat (char const *dir, char const *abase, char **base_in_result)
 {
   char *p = mfile_name_concat (dir, abase, base_in_result);
-  if (p == NULL)
+  if (!p)
     xalloc_die ();
   return p;
 }
diff --git a/lib/filenamecat.h b/lib/filenamecat.h
index 334c887..88d4380 100644
--- a/lib/filenamecat.h
+++ b/lib/filenamecat.h
@@ -1,6 +1,6 @@
 /* Concatenate two arbitrary file names.

-   Copyright (C) 1996, 1997, 2003, 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1996-1997, 2003, 2005, 2007-2008 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
@@ -19,6 +19,3 @@

 char *file_name_concat (char const *dir, char const *base,
                        char **base_in_result);
-
-char *mfile_name_concat (char const *dir, char const *base,
-                        char **base_in_result);
diff --git a/lib/findprog.c b/lib/findprog.c
index 3b8cd39..bdf1ba2 100644
--- a/lib/findprog.c
+++ b/lib/findprog.c
@@ -1,5 +1,5 @@
 /* Locating a program in PATH.
-   Copyright (C) 2001-2004, 2006-2007 Free Software Foundation, Inc.
+   Copyright (C) 2001-2004, 2006-2008 Free Software Foundation, Inc.
    Written by Bruno Haible <address@hidden>, 2001.

    This program is free software: you can redistribute it and/or modify
@@ -25,9 +25,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>

-#include "xalloc.h"
-#include "filename.h"
+#include "mfilenamecat.h"


 const char *
@@ -56,7 +56,10 @@ find_in_path (const char *progname)
     return progname;

   /* Make a copy, to prepare for destructive modifications.  */
-  path = xstrdup (path);
+  path = strdup (path);
+  if (path == NULL)
+    return NULL;
+
   for (path_rest = path; ; path_rest = cp + 1)
     {
       const char *dir;
@@ -75,7 +78,14 @@ find_in_path (const char *progname)
        dir = ".";

       /* Concatenate dir and progname.  */
-      progpathname = concatenated_filename (dir, progname, NULL);
+      progpathname = mfile_name_concat (dir, progname, NULL);
+      if (progpathname == NULL)
+       {
+         int saved_errno = errno;
+         free (path);
+         errno = saved_errno;
+         return NULL;
+       }

       /* On systems which have the eaccess() system call, let's use it.
         On other systems, let's hope that this program is not installed
@@ -91,7 +101,15 @@ find_in_path (const char *progname)
              /* Add the "./" prefix for real, that concatenated_filename()
                 optimized away.  This avoids a second PATH search when the
                 caller uses execlp/execvp.  */
-             progpathname = XNMALLOC (2 + strlen (progname) + 1, char);
+             progpathname = malloc (2 + strlen (progname) + 1);
+             if (progpathname == NULL)
+               {
+                 int saved_errno = errno;
+                 free (path);
+                 errno = saved_errno;
+                 return NULL;
+               }
+
              progpathname[0] = '.';
              progpathname[1] = '/';
              memcpy (progpathname + 2, progname, strlen (progname) + 1);
diff --git a/lib/mfilename.c b/lib/mfilename.c
new file mode 100644
index 0000000..10bdfbd
--- /dev/null
+++ b/lib/mfilename.c
@@ -0,0 +1,182 @@
+/* simple file-name-manipulation functions that never exit
+
+   Copyright (C) 1996-2008 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 "mfilename.h"
+#include <string.h>
+
+/* 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;
+}
+
+/* Return the length of the prefix of FILE that will be used by
+   mdir_name.  If FILE is in the working directory, this returns zero
+   even though `mdir_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;
+}
+
+/* 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 malloc.
+   If memory allocation fails, return NULL.  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, mbase_name("") returns "", and the first trailing
+   slash is not stripped.
+
+   If lstat (NAME) would succeed, then { chdir (mdir_name (NAME));
+   lstat (mbase_name (NAME)); } will access the same file.  Likewise,
+   if the sequence { chdir (mdir_name (NAME));
+   rename (mbase_name (NAME), "foo"); } succeeds, you have renamed NAME
+   to "foo" in the same directory NAME was in.  */
+char *
+mbase_name (char const *name)
+{
+  char const *base = last_component (name);
+  size_t length;
+
+  /* If there is no last component, then name is a file system root or the
+     empty string.  */
+  if (! *base)
+    return strndup (name, base_len (name));
+
+  /* Collapse a sequence of trailing slashes into one.  */
+  length = base_len (base);
+  if (ISSLASH (base[length]))
+    length++;
+
+  /* On systems with drive letters, `a/b:c' must return `./b:c' rather
+     than `b:c' to avoid confusion with a drive letter.  On systems
+     with pure POSIX semantics, this is not an issue.  */
+  if (FILE_SYSTEM_PREFIX_LEN (base))
+    {
+      char *p = malloc (length + 3);
+      if (!p)
+       return p;
+      p[0] = '.';
+      p[1] = '/';
+      memcpy (p + 2, base, length);
+      p[length + 2] = '\0';
+      return p;
+    }
+
+  /* Finally, copy the basename.  */
+  return strndup (base, 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.
+   If memory allocation fails, return NULL.
+   Works properly even if there are trailing slashes (by effectively
+   ignoring them).  Unlike POSIX dirname(), FILE cannot be NULL.
+
+   If lstat (FILE) would succeed, then { chdir (mdir_name (FILE));
+   lstat (base_name (FILE)); } will access the same file.  Likewise,
+   if the sequence { chdir (mdir_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 dir;
+  memcpy (dir, file, length);
+  if (append_dot)
+    dir[length++] = '.';
+  dir[length] = '\0';
+  return dir;
+}
diff --git a/lib/mfilename.h b/lib/mfilename.h
new file mode 100644
index 0000000..8416f54
--- /dev/null
+++ b/lib/mfilename.h
@@ -0,0 +1,67 @@
+/*  Take file names apart into directory and base names.
+
+    Copyright (C) 2008 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/>.  */
+
+#ifndef MFILENAME_H_
+# define MFILENAME_H_ 1
+
+# include <stdbool.h>
+# include <stddef.h>
+
+# ifndef DIRECTORY_SEPARATOR
+#  define DIRECTORY_SEPARATOR '/'
+# endif
+
+# ifndef ISSLASH
+#  define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
+# endif
+
+# ifndef FILE_SYSTEM_PREFIX_LEN
+#  if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
+    /* This internal macro assumes ASCII, but all hosts that support drive
+       letters use ASCII.  */
+#   define _IS_DRIVE_LETTER(c) (((unsigned int) (c) | ('a' - 'A')) - 'a' \
+                               <= 'z' - 'a')
+#   define FILE_SYSTEM_PREFIX_LEN(Filename) \
+          (_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':' ? 2 : 0)
+#  else
+#   define FILE_SYSTEM_PREFIX_LEN(Filename) 0
+#  endif
+# endif
+
+# ifndef FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
+#  define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0
+# endif
+
+# ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
+#  define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
+# endif
+
+# if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
+#  define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)])
+# else
+#  define IS_ABSOLUTE_FILE_NAME(F) \
+         (ISSLASH ((F)[0]) || 0 < FILE_SYSTEM_PREFIX_LEN (F))
+# endif
+# define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F))
+
+size_t base_len (char const *file);
+char *last_component (char const *file);
+size_t dir_len (char const *file);
+char *mbase_name (char const *name);
+char *mdir_name (char const *file);
+
+#endif /* not MFILENAME_H_ */
diff --git a/lib/mfilenamecat.c b/lib/mfilenamecat.c
new file mode 100644
index 0000000..a4fe070
--- /dev/null
+++ b/lib/mfilenamecat.c
@@ -0,0 +1,88 @@
+/* Concatenate two arbitrary file names.
+
+   Copyright (C) 1996-2008 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 Jim Meyering.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "mfilenamecat.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mfilename.h"
+
+#if ! HAVE_MEMPCPY && ! defined mempcpy
+# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
+#endif
+
+/* Return the longest suffix of F that is a relative file name.
+   If it has no such suffix, return the empty string.  */
+
+static char const *
+longest_relative_suffix (char const *f)
+{
+  for (f += FILE_SYSTEM_PREFIX_LEN (f); ISSLASH (*f); f++)
+    continue;
+  return f;
+}
+
+/* Concatenate two file name components, DIR and ABASE, in
+   newly-allocated storage and return the result.
+   The resulting file name F is such that the commands "ls F" and "(cd
+   DIR; ls BASE)" refer to the same file, where BASE is ABASE with any
+   file system prefixes and leading separators removed.
+   Arrange for a directory separator if necessary between DIR and BASE
+   in the result, removing any redundant separators.
+   In any case, if BASE_IN_RESULT is non-NULL, set
+   *BASE_IN_RESULT to point to the copy of ABASE in the returned
+   concatenation.  However, if ABASE begins with more than one slash,
+   set *BASE_IN_RESULT to point to the sole corresponding slash that
+   is copied into the result buffer.
+
+   Return NULL if malloc fails.  */
+
+char *
+mfile_name_concat (char const *dir, char const *abase, char **base_in_result)
+{
+  char const *dirbase = last_component (dir);
+  size_t dirbaselen = base_len (dirbase);
+  size_t dirlen = dirbase - dir + dirbaselen;
+  size_t needs_separator = (dirbaselen && ! ISSLASH (dirbase[dirbaselen - 1]));
+
+  char const *base = longest_relative_suffix (abase);
+  size_t baselen = strlen (base);
+
+  char *p_concat = malloc (dirlen + needs_separator + baselen + 1);
+  char *p;
+
+  if (p_concat == NULL)
+    return NULL;
+
+  p = mempcpy (p_concat, dir, dirlen);
+  *p = DIRECTORY_SEPARATOR;
+  p += needs_separator;
+
+  if (base_in_result)
+    *base_in_result = p - IS_ABSOLUTE_FILE_NAME (abase);
+
+  p = mempcpy (p, base, baselen);
+  *p = '\0';
+
+  return p_concat;
+}
diff --git a/lib/mfilenamecat.h b/lib/mfilenamecat.h
new file mode 100644
index 0000000..27e00a6
--- /dev/null
+++ b/lib/mfilenamecat.h
@@ -0,0 +1,21 @@
+/* Concatenate two arbitrary file names.
+
+   Copyright (C) 1996-1997, 2003, 2005, 2007-2008 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 Jim Meyering.  */
+
+char *mfile_name_concat (char const *dir, char const *base,
+                        char **base_in_result);
diff --git a/m4/dirname.m4 b/m4/dirname.m4
deleted file mode 100644
index e35da96..0000000
--- a/m4/dirname.m4
+++ /dev/null
@@ -1,18 +0,0 @@
-#serial 7   -*- autoconf -*-
-dnl Copyright (C) 2002-2006 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_LIBOBJ([basename])
-  AC_LIBOBJ([dirname])
-  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.
-])
diff --git a/m4/filenamecat.m4 b/m4/mfilenamecat.m4
similarity index 62%
rename from m4/filenamecat.m4
rename to m4/mfilenamecat.m4
index bb46dba..59467a4 100644
--- a/m4/filenamecat.m4
+++ b/m4/mfilenamecat.m4
@@ -1,13 +1,11 @@
-# filenamecat.m4 serial 8
-dnl Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# mfilenamecat.m4 serial 1
+dnl Copyright (C) 2002-2006, 2008 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_FILE_NAME_CONCAT],
+AC_DEFUN([gl_MFILE_NAME_CONCAT],
 [
-  AC_LIBOBJ([filenamecat])
-
   dnl Prerequisites of lib/filenamecat.c.
   AC_CHECK_FUNCS_ONCE(mempcpy)
 ])
diff --git a/modules/dirname b/modules/dirname
index 7c405c2..f1dd4be 100644
--- a/modules/dirname
+++ b/modules/dirname
@@ -6,19 +6,18 @@ lib/dirname.h
 lib/dirname.c
 lib/basename.c
 lib/stripslash.c
-m4/dirname.m4
-m4/dos.m4

 Depends-on:
 double-slash-root
+mfilename
 stdbool
 xalloc
 xstrndup

 configure.ac:
-gl_DIRNAME

 Makefile.am:
+lib_SOURCES += dirname.c basename.c stripslash.c

 Include:
 "dirname.h"
diff --git a/modules/double-slash-root b/modules/double-slash-root
index 6b809d0..af78f26 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/modules/filenamecat b/modules/filenamecat
index fb1786b..0aabbbe 100644
--- a/modules/filenamecat
+++ b/modules/filenamecat
@@ -4,17 +4,16 @@ Concatenate two arbitrary file names.
 Files:
 lib/filenamecat.h
 lib/filenamecat.c
-m4/dos.m4
-m4/filenamecat.m4

 Depends-on:
 xalloc
 dirname
+mfilenamecat

 configure.ac:
-gl_FILE_NAME_CONCAT

 Makefile.am:
+lib_SOURCES += filenamecat.c filenamecat.h

 Include:
 "filenamecat.h"
diff --git a/modules/findprog b/modules/findprog
index 0fffcf3..7be2d28 100644
--- a/modules/findprog
+++ b/modules/findprog
@@ -8,9 +8,8 @@ m4/findprog.m4
 m4/eaccess.m4

 Depends-on:
+mfilenamecat
 stdbool
-xalloc
-filename
 unistd

 configure.ac:
@@ -23,8 +22,7 @@ Include:
 "findprog.h"

 License:
-GPL
+LGPLv2+

 Maintainer:
 Bruno Haible
-
diff --git a/modules/mfilename b/modules/mfilename
new file mode 100644
index 0000000..9af2d2c
--- /dev/null
+++ b/modules/mfilename
@@ -0,0 +1,25 @@
+Description:
+simple file-name-manipulation functions that never exit
+
+Files:
+lib/mfilename.c
+lib/mfilename.h
+m4/dos.m4
+
+Depends-on:
+double-slash-root
+
+configure.ac:
+gl_AC_DOS
+
+Makefile.am:
+lib_SOURCES += mfilename.c mfilename.h
+
+Include:
+"mfilename.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+Jim Meyering
diff --git a/modules/mfilenamecat b/modules/mfilenamecat
new file mode 100644
index 0000000..50651e1
--- /dev/null
+++ b/modules/mfilenamecat
@@ -0,0 +1,25 @@
+Description:
+Concatenate two arbitrary file names.
+
+Files:
+lib/mfilenamecat.c
+lib/mfilenamecat.h
+m4/mfilenamecat.m4
+
+Depends-on:
+mfilename
+
+configure.ac:
+gl_MFILE_NAME_CONCAT
+
+Makefile.am:
+lib_SOURCES += mfilenamecat.c mfilenamecat.h
+
+Include:
+"mfilenamecat.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+Jim Meyering
--
1.6.0.1.126.ga118




reply via email to

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