[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: bugs in dirname module - gnulib portion
From: |
Eric Blake |
Subject: |
Re: bugs in dirname module - gnulib portion |
Date: |
Mon, 21 Nov 2005 06:26:49 -0700 |
User-agent: |
Mozilla Thunderbird 1.0.2 (Windows/20050317) |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
According to Jim Meyering on 11/18/2005 6:28 AM:
>>so I am prepared to provide
>>this segregation into base_name() vs. last_component()
>>as part of my patch.
>
> I'd go along with that.
This is my patch to gnulib to change the semantics of base_name() to use
xmalloc(), similar to dir_name(); and which adds last_component() as a new
method similar to the old base_name semantics except that it returns a
pointer to the final '\0' on file system roots. I'm still in the middle
of preparing followup patches to coreutils, tar, findutils, and m4; those
patches will be sent to the respective lists; it will probably take me a
few more days to do all that. I wanted to post the gnulib side of the
patch now, for review. However, it is probably wise to wait to apply the
gnulib patch until my follow-on patches have also been posted and
reviewed, so that we minimize the breakage to CVS builds of projects that
use gnulib-tool to import the dirname module.
I'm using my audit list of all base_name occurances, in the message
http://lists.gnu.org/archive/html/bug-gnulib/2005-11/msg00013.html,
as my list of things to patch in the various projects. Most of the usages
still work with a simple change to last_component, but some do indeed need
to stick with base_name and add a free().
ChangeLog:
2005-11-21 Eric Blake <address@hidden>
* modules/dirname (Depends-on): Add xstrndup.
* modules/dirname-tests: New module.
* tests/test-dirname.c: New file, replacing dirname.c TEST_DIRNAME
section.
m4/ChangeLog:
2005-11-21 Eric Blake <address@hidden>
* dirname.m4 (DOUBLE_SLASH_IS_DISTINCT_ROOT): New define.
* dos.m4 (FILE_SYSTEM_PREFIX_LEN): Move from here to dirname.h.
(FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE): New define.
lib/ChangeLog:
2005-11-21 Eric Blake <address@hidden>
* backupfile.c (check_extension, numbered_backup): Adjust to
changed semantics in dirname module.
* filenamecat.c (file_name_concat): Ditto.
* same.c (same_name): Ditto.
* dirname.h (FILE_SYSTEM_PREFIX_LEN): Move here from dos.m4.
[FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX]: Don't treat 1: as a
drive prefix.
(IS_ABSOLUTE_FILE_NAME): Treat all drive letters as absolute on
platforms like cygwin with FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE.
(last_component): New method.
* dirname.c (dir_len): Determine when drive letters need a
subsequent slash. Preserve // when it is special.
(dir_name): Don't append dot when drive letter is absolute.
[TEST_DIRNAME]: Move into a full-blown gnulib test.
* basename.c (base_name): New semantics - malloc the result.
Preserve // when it is special. Preserve relative files that look
like drive letters.
(base_len): Preserve // when it is special.
(last_component): New method, similar to old base_name semantics.
* stripslash.c (strip_trailing_slashes): Use last_component, not
base_name. Strip redundant slashes from ///.
- --
Life is short - so eat dessert first!
Eric Blake address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFDgcsZ84KuGfSFAYARAvVtAJ4zLJyFz3u2NOWwNJnbGk+zXOdKEwCgpLL2
U06AxmEbmhLBBD3wGsbXHoQ=
=YTVY
-----END PGP SIGNATURE-----
Index: ChangeLog
===================================================================
RCS file: /cvsroot/gnulib/gnulib/ChangeLog,v
retrieving revision 1.445
diff -u -p -p -r1.445 ChangeLog
Index: lib/ChangeLog
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/ChangeLog,v
retrieving revision 1.1051
diff -u -p -p -r1.1051 ChangeLog
Index: lib/backupfile.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/backupfile.c,v
retrieving revision 1.47
diff -u -p -p -r1.47 backupfile.c
--- lib/backupfile.c 23 Sep 2005 04:15:13 -0000 1.47
+++ lib/backupfile.c 21 Nov 2005 12:58:17 -0000
@@ -115,7 +115,7 @@ char const *simple_backup_suffix = "~";
static void
check_extension (char *file, size_t filelen, char e)
{
- char *base = base_name (file);
+ char *base = last_component (file);
size_t baselen = base_len (base);
size_t baselen_max = HAVE_LONG_FILE_NAMES ? 255 : NAME_MAX_MINIMUM;
@@ -202,7 +202,7 @@ numbered_backup (char **buffer, size_t b
struct dirent *dp;
char *buf = *buffer;
size_t versionlenmax = 1;
- char *base = base_name (buf);
+ char *base = last_component (buf);
size_t base_offset = base - buf;
size_t baselen = base_len (base);
Index: lib/basename.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/basename.c,v
retrieving revision 1.26
diff -u -p -p -r1.26 basename.c
--- lib/basename.c 19 Sep 2005 17:28:14 -0000 1.26
+++ lib/basename.c 21 Nov 2005 12:58:17 -0000
@@ -22,18 +22,17 @@
#endif
#include "dirname.h"
-#include <string.h>
-/* 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.
+#include <string.h>
+#include "xalloc.h"
+#include "xstrndup.h"
- Return the address of the last file name component of NAME. If
- NAME has no file name components because it is all slashes, return
- NAME if it is empty, the address of its last slash otherwise. */
+/* 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 *
-base_name (char const *name)
+last_component (char const *name)
{
char const *base = name + FILE_SYSTEM_PREFIX_LEN (name);
char const *p;
@@ -46,12 +45,12 @@ base_name (char const *name)
do p++;
while (ISSLASH (*p));
- /* If the file name ends in slash, use the trailing slash as
- the basename if no non-slashes have been found. */
+ /* If the file name ends in slash, but no non-slashes have
+ been found, then return the empty string. */
if (! *p)
{
if (ISSLASH (*base))
- base = p - 1;
+ base = p;
break;
}
@@ -63,17 +62,76 @@ base_name (char const *name)
return (char *) base;
}
-/* Return the length of of the basename NAME. Typically NAME is the
- value returned by base_name. Act like strlen (NAME), except omit
- redundant trailing slashes. */
+
+/* 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)
+{
+ char const *base = last_component (name);
+
+ /* 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. */
+ size_t 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] = DIRECTORY_SEPARATOR;
+ 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 (prefix_len && ! FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE
+ && len == prefix_len && ISSLASH (name[prefix_len]))
+ return prefix_len + 1;
return len;
}
Index: lib/dirname.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/dirname.c,v
retrieving revision 1.35
diff -u -p -p -r1.35 dirname.c
--- lib/dirname.c 19 Sep 2005 17:28:14 -0000 1.35
+++ lib/dirname.c 21 Nov 2005 12:58:21 -0000
@@ -26,9 +26,11 @@
#include <string.h>
#include "xalloc.h"
-/* Return the length of `dirname (FILE)', or zero if FILE is
- in the working directory. Works properly even if
- there are trailing slashes (by effectively ignoring them). */
+/* 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)
{
@@ -36,86 +38,50 @@ dir_len (char const *file)
size_t length;
/* Strip the basename and any redundant slashes before it. */
- for (length = base_name (file) - file; prefix_length < length; length--)
+ for (length = last_component (file) - file;
+ prefix_length < length; length--)
if (! ISSLASH (file[length - 1]))
return length;
- /* But don't strip the only slash from "/". */
- return prefix_length + ISSLASH (file[prefix_length]);
+ /* Be careful of drive prefixes, where that matters. */
+ if (0 < prefix_length)
+ return (prefix_length
+ + (! FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE
+ && ISSLASH (file[prefix_length])));
+
+ /* Don't strip the only slash from "/", or from "//" where that matters. */
+ return (ISSLASH (file[0])
+ + (DOUBLE_SLASH_IS_DISTINCT_ROOT && ISSLASH (file[0])
+ && ISSLASH (file[1]) && ! ISSLASH (file[2])));
}
-/* Return the leading directories part of FILE,
- allocated with xmalloc.
- Works properly even if there are trailing slashes
- (by effectively ignoring them). */
+
+/* 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 xmalloc.
+ 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 (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 *
dir_name (char const *file)
{
size_t length = dir_len (file);
- bool append_dot = (length == FILE_SYSTEM_PREFIX_LEN (file));
+ bool append_dot = (length == 0
+ || (! FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE
+ && 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;
+ dir[length] = '\0';
return dir;
}
-
-#ifdef TEST_DIRNAME
-/*
-
-Run the test like this (expect no output):
- gcc -DHAVE_CONFIG_H -DTEST_DIRNAME -I.. -O -Wall \
- basename.c dirname.c xmalloc.c error.c
- sed -n '/^BEGIN-DATA$/,/^END-DATA$/p' dirname.c|grep -v DATA|./a.out
-
-If it's been built on a DOS or Windows platforms, run another test like
-this (again, expect no output):
- sed -n '/^BEGIN-DOS-DATA$/,/^END-DOS-DATA$/p' dirname.c|grep -v DATA|./a.out
-
-BEGIN-DATA
-foo//// .
-bar/foo//// bar
-foo/ .
-/ /
-. .
-a .
-END-DATA
-
-BEGIN-DOS-DATA
-c:///// c:/
-c:/ c:/
-c:/. c:/
-c:foo c:.
-c:foo/bar c:foo
-END-DOS-DATA
-
-*/
-
-# define MAX_BUFF_LEN 1024
-# include <stdio.h>
-
-char *program_name;
-
-int
-main (int argc, char *argv[])
-{
- char buff[MAX_BUFF_LEN + 1];
-
- program_name = argv[0];
-
- buff[MAX_BUFF_LEN] = 0;
- while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
- {
- char file[MAX_BUFF_LEN];
- char expected_result[MAX_BUFF_LEN];
- char const *result;
- sscanf (buff, "%s %s", file, expected_result);
- result = dir_name (file);
- if (strcmp (result, expected_result))
- printf ("%s: got %s, expected %s\n", file, result, expected_result);
- }
- return 0;
-}
-#endif
Index: lib/dirname.h
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/dirname.h,v
retrieving revision 1.11
diff -u -p -p -r1.11 dirname.h
--- lib/dirname.h 2 Jun 2005 20:41:05 -0000 1.11
+++ lib/dirname.h 21 Nov 2005 12:58:21 -0000
@@ -31,16 +31,39 @@
# endif
# ifndef FILE_SYSTEM_PREFIX_LEN
-# define FILE_SYSTEM_PREFIX_LEN(File_name) 0
+# 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
-# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)])
+# ifndef FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE
+# define FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE 0
+# endif
+
+# ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
+# define DOUBLE_SLASH_IS_DISTINCT_ROOT 1
+# endif
+
+# if FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE
+# define IS_ABSOLUTE_FILE_NAME(F) \
+ (0 < FILE_SYSTEM_PREFIX_LEN (F) || ISSLASH ((F)[0]))
+# else
+# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)])
+# endif
# define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F))
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);
Index: lib/filenamecat.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/filenamecat.c,v
retrieving revision 1.2
diff -u -p -p -r1.2 filenamecat.c
--- lib/filenamecat.c 19 Sep 2005 17:28:14 -0000 1.2
+++ lib/filenamecat.c 21 Nov 2005 12:58:21 -0000
@@ -64,7 +64,7 @@ longest_relative_suffix (char const *f)
char *
file_name_concat (char const *dir, char const *abase, char **base_in_result)
{
- char const *dirbase = base_name (dir);
+ 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]));
Index: lib/same.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/same.c,v
retrieving revision 1.19
diff -u -p -p -r1.19 same.c
--- lib/same.c 23 Sep 2005 04:15:13 -0000 1.19
+++ lib/same.c 21 Nov 2005 12:58:21 -0000
@@ -59,8 +59,8 @@ bool
same_name (const char *source, const char *dest)
{
/* Compare the basenames. */
- char const *source_basename = base_name (source);
- char const *dest_basename = base_name (dest);
+ char const *source_basename = last_component (source);
+ char const *dest_basename = last_component (dest);
size_t source_baselen = base_len (source_basename);
size_t dest_baselen = base_len (dest_basename);
bool identical_basenames =
Index: lib/stripslash.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/stripslash.c,v
retrieving revision 1.15
diff -u -p -p -r1.15 stripslash.c
--- lib/stripslash.c 19 Sep 2005 17:28:15 -0000 1.15
+++ lib/stripslash.c 21 Nov 2005 12:58:21 -0000
@@ -22,19 +22,26 @@
#include "dirname.h"
-/* Remove trailing slashes from FILE.
- Return true if a trailing slash was removed.
- This is useful when using file name completion from a shell that
- adds a "/" after directory names (such as tcsh and bash), because
- the Unix rename and rmdir system calls return an "Invalid argument" error
- when given a file that ends in "/" (except for the root directory). */
+/* Remove trailing slashes from FILE. Return true if a trailing slash
+ was removed. This is useful when using file name completion from a
+ shell that adds a "/" after directory names (such as tcsh and
+ bash), because on symlinks to directories, several system calls
+ have different semantics according to whether a trailing slash is
+ present. */
bool
strip_trailing_slashes (char *file)
{
- char *base = base_name (file);
- char *base_lim = base + base_len (base);
- bool had_slash = (*base_lim != '\0');
+ char *base = last_component (file);
+ char *base_lim;
+ bool had_slash;
+
+ /* last_component returns "" for file system roots, but we need to turn
+ `///' into `/'. */
+ if (! *base)
+ base = file;
+ base_lim = base + base_len (base);
+ had_slash = (*base_lim != '\0');
*base_lim = '\0';
return had_slash;
}
Index: m4/ChangeLog
===================================================================
RCS file: /cvsroot/gnulib/gnulib/m4/ChangeLog,v
retrieving revision 1.758
diff -u -p -p -r1.758 ChangeLog
Index: m4/dirname.m4
===================================================================
RCS file: /cvsroot/gnulib/gnulib/m4/dirname.m4,v
retrieving revision 1.8
diff -u -p -p -r1.8 dirname.m4
--- m4/dirname.m4 21 Mar 2005 22:06:27 -0000 1.8
+++ m4/dirname.m4 21 Nov 2005 12:58:26 -0000
@@ -1,4 +1,4 @@
-# dirname.m4 serial 5
+# dirname.m4 serial 6
dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -11,6 +11,28 @@ AC_DEFUN([gl_DIRNAME],
dnl Prerequisites of lib/dirname.h.
AC_REQUIRE([gl_AC_DOS])
+ AC_CACHE_CHECK([whether // is distinct from /], [ac_cv_double_slash_root],
+ [ if test x"$cross_compiling" = xyes ; then
+ # When cross-compiling, there is no way to tell whether // is special
+ # short of a list of hosts; so always treat it as special.
+ ac_cv_double_slash_root=unknown
+ else
+ set x `ls -di / //`
+ if test $[2] = $[4]; then
+ ac_cv_double_slash_root=no
+ else
+ ac_cv_double_slash_root=yes
+ fi
+ fi])
+ if test x"$ac_cv_double_slash_root" = xno; then
+ ac_double_slash_root=0
+ else
+ ac_double_slash_root=1
+ fi
+
+ AC_DEFINE_UNQUOTED([DOUBLE_SLASH_IS_DISTINCT_ROOT],
+ $ac_double_slash_root,
+ [Define to 1 if // is a file system root distinct from /.])
dnl No prerequisites of lib/basename.c, lib/dirname.c, lib/stripslash.c.
])
Index: m4/dos.m4
===================================================================
RCS file: /cvsroot/gnulib/gnulib/m4/dos.m4,v
retrieving revision 1.12
diff -u -p -p -r1.12 dos.m4
--- m4/dos.m4 23 Jan 2005 08:06:57 -0000 1.12
+++ m4/dos.m4 21 Nov 2005 12:58:26 -0000
@@ -1,9 +1,9 @@
-#serial 9
+#serial 10
# Define some macros required for proper operation of code in lib/*.c
# on MSDOS/Windows systems.
-# Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc.
+# Copyright (C) 2000, 2001, 2004, 2005 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -14,30 +14,38 @@ AC_DEFUN([gl_AC_DOS],
[
AC_CACHE_CHECK([whether system is Windows or MSDOS], [ac_cv_win_or_dos],
[
- AC_TRY_COMPILE([],
- [#if !defined _WIN32 && !defined __WIN32__ && !defined __MSDOS__ &&
!defined __CYGWIN__
+ AC_TRY_COMPILE([],
+ [#if !defined _WIN32 && !defined __WIN32__ && !defined __MSDOS__ &&
!defined __CYGWIN__
neither MSDOS nor Windows
#endif],
- [ac_cv_win_or_dos=yes],
- [ac_cv_win_or_dos=no])
+ [ac_cv_win_or_dos=yes],
+ [ac_cv_win_or_dos=no])
])
if test x"$ac_cv_win_or_dos" = xyes; then
ac_fs_accepts_drive_letter_prefix=1
ac_fs_backslash_is_file_name_separator=1
+ AC_CACHE_CHECK([whether drive letter can start relative path],
+ [ac_cv_drive_letter_can_be_relative],
+ [
+ AC_TRY_COMPILE([],
+ [#if defined __CYGWIN__
+drive letters are always absolute
+#endif],
+ [ac_cv_drive_letter_can_be_relative=yes],
+ [ac_cv_drive_letter_can_be_relative=no])
+ ])
+ if test x"$ac_cv_drive_letter_can_be_relative" = xyes; then
+ ac_fs_drive_letter_always_absolute=0
+ else
+ ac_fs_drive_letter_always_absolute=1
+ fi
else
ac_fs_accepts_drive_letter_prefix=0
ac_fs_backslash_is_file_name_separator=0
+ ac_fs_drive_letter_always_absolute=0
fi
- AH_VERBATIM(FILE_SYSTEM_PREFIX_LEN,
- [#if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
-# define FILE_SYSTEM_PREFIX_LEN(Filename) \
- ((Filename)[0] && (Filename)[1] == ':' ? 2 : 0)
-#else
-# define FILE_SYSTEM_PREFIX_LEN(Filename) 0
-#endif])
-
AC_DEFINE_UNQUOTED([FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX],
$ac_fs_accepts_drive_letter_prefix,
[Define on systems for which file names may have a so-called
@@ -55,4 +63,9 @@ neither MSDOS nor Windows
$ac_fs_backslash_is_file_name_separator,
[Define if the backslash character may also serve as a file name
component separator.])
+
+ AC_DEFINE_UNQUOTED([FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE],
+ $ac_fs_drive_letter_always_absolute,
+ [Define if a drive letter prefix always denotes an absolute path, even
+ when it is not followed by a file name component separator.])
])
Index: modules/dirname
===================================================================
RCS file: /cvsroot/gnulib/gnulib/modules/dirname,v
retrieving revision 1.6
diff -u -p -p -r1.6 dirname
--- modules/dirname 6 May 2005 17:22:45 -0000 1.6
+++ modules/dirname 21 Nov 2005 12:58:26 -0000
@@ -6,12 +6,13 @@ lib/dirname.h
lib/dirname.c
lib/basename.c
lib/stripslash.c
-m4/dos.m4
m4/dirname.m4
+m4/dos.m4
Depends-on:
-xalloc
stdbool
+xalloc
+xstrndup
configure.ac:
gl_DIRNAME
Index: modules/dirname-tests
===================================================================
RCS file: modules/dirname-tests
diff -N modules/dirname-tests
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/dirname-tests 21 Nov 2005 12:58:26 -0000
@@ -0,0 +1,12 @@
+Files:
+tests/test-dirname.c
+
+Depends-on:
+strdup
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-dirname
+noinst_PROGRAMS += test-dirname
+test_dirname_SOURCES = test-dirname.c
Index: tests/test-dirname.c
===================================================================
RCS file: tests/test-dirname.c
diff -N tests/test-dirname.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/test-dirname.c 21 Nov 2005 12:58:26 -0000
@@ -0,0 +1,193 @@
+/* Test the gnulib dirname module.
+ Copyright (C) 2005 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 2, 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, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "dirname.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "strdup.h"
+
+const char *program_name = "test-dirname";
+
+struct test {
+ const char *name; /* Name under test. */
+ const char *dir; /* dir_name (name). */
+ const char *last; /* last_component (name). */
+ const char *base; /* base_name (name). */
+ const char *stripped; /* name after strip_trailing_slashes (name). */
+ bool modified; /* result of strip_trailing_slashes (name). */
+ bool absolute; /* IS_ABSOLUTE_FILE_NAME (name). */
+};
+
+static struct test tests[] = {
+ {"d/f", "d", "f", "f", "d/f", false, false},
+ {"/d/f", "/d", "f", "f", "/d/f", false, true},
+ {"d/f/", "d", "f/", "f/", "d/f", true, false},
+ {"d/f//", "d", "f//", "f/", "d/f", true, false},
+ {"f", ".", "f", "f", "f", false, false},
+ {"/", "/", "", "/", "/", false, true},
+#if DOUBLE_SLASH_IS_DISTINCT_ROOT
+ {"//", "//", "", "//", "//", false, true},
+ {"//d", "//", "d", "d", "//d", false, true},
+#else
+ {"//", "/", "", "/", "/", true, true},
+ {"//d", "/", "d", "d", "//d", false, true},
+#endif
+ {"///", "/", "", "/", "/", true, true},
+ {"///a///", "/", "a///", "a/", "///a", true, true},
+ /* POSIX requires dirname("") and basename("") to both return ".",
+ but dir_name and base_name are defined differently. */
+ {"", ".", "", "", "", false, false},
+ {".", ".", ".", ".", ".", false, false},
+ {"..", ".", "..", "..", "..", false, false},
+#if FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR
+ {"a\\", ".", "a\\", "a\\", "a", true, false},
+ {"a\\b", "a", "b", "b", "a\\b", false, false},
+ {"\\", "\\", "", "\\", "\\", false, true},
+ {"\\/\\", "\\", "", "\\", "\\", true, true},
+ {"\\\\/", "\\", "", "\\", "\\", true, true},
+ {"\\//", "\\", "", "\\", "\\", true, true},
+ {"//\\", "/", "", "/", "/", true, true},
+#else
+ {"a\\", ".", "a\\", "a\\", "a\\", false, false},
+ {"a\\b", ".", "a\\b", "a\\b", "a\\b", false, false},
+ {"\\", ".", "\\", "\\", "\\", false, false},
+ {"\\/\\", "\\", "\\", "\\", "\\/\\",false, false},
+ {"\\\\/", ".", "\\\\/","\\\\/","\\\\", true, false},
+ {"\\//", ".", "\\//", "\\/", "\\", true, false},
+# if DOUBLE_SLASH_IS_DISTINCT_ROOT
+ {"//\\", "//", "\\", "\\", "//\\", false, true},
+# else
+ {"//\\", "/", "\\", "\\", "//\\", false, true},
+# endif
+#endif
+#if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX
+# if FILE_SYSTEM_DRIVE_PREFIX_IS_ABSOLUTE
+ {"c:", "c:", "", "c:", "c:", false, true},
+ {"c:/", "c:", "", "c:", "c:", true, true},
+ {"c://", "c:", "", "c:", "c:", true, true},
+ {"c:/d", "c:", "d", "d", "c:/d", false, true},
+ {"c://d", "c:", "d", "d", "c://d",false, true},
+ {"c:/d/", "c:", "d/", "d/", "c:/d", true, true},
+ {"c:/d/f", "c:/d", "f", "f", "c:/d/f",false, true},
+ {"c:d", "c:", "d", "d", "c:d", false, true},
+ {"c:d/", "c:", "d/", "d/", "c:d", true, true},
+ {"c:d/f", "c:d", "f", "f", "c:d/f",false, true},
+ {"a:b:c", "a:", "b:c", "./b:c","a:b:c",false, true},
+ {"a/b:c", "a", "b:c", "./b:c","a/b:c",false, false},
+# else
+ {"c:", "c:", "", "c:", "c:", false, false},
+ {"c:/", "c:/", "", "c:/", "c:/", false, true},
+ {"c://", "c:/", "", "c:/", "c:/", true, true},
+ {"c:/d", "c:/", "d", "d", "c:/d", false, true},
+ {"c://d", "c:/", "d", "d", "c://d",false, true},
+ {"c:/d/", "c:/", "d/", "d/", "c:/d", true, true},
+ {"c:/d/f", "c:/d", "f", "f", "c:/d/f",false, true},
+ {"c:d", "c:.", "d", "d", "c:d", false, false},
+ {"c:d/", "c:.", "d/", "d/", "c:d", true, false},
+ {"c:d/f", "c:d", "f", "f", "c:d/f",false, false},
+ {"a:b:c", "a:.", "b:c", "./b:c","a:b:c",false, false},
+ {"a/b:c", "a", "b:c", "./b:c","a/b:c",false, false},
+# endif
+#else /* !FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX */
+ {"c:", ".", "c:", "c:", "c:", false, false},
+ {"c:/", ".", "c:/", "c:/", "c:", true, false},
+ {"c://", ".", "c://", "c:/", "c:", true, false},
+ {"c:/d", "c:", "d", "d", "c:/d", false, false},
+ {"c://d", "c:", "d", "d", "c://d",false, false},
+ {"c:/d/", "c:", "d/", "d/", "c:/d", true, false},
+ {"c:/d/f", "c:/d", "f", "f", "c:/d/f",false, false},
+ {"c:d", ".", "c:d", "c:d", "c:d", false, false},
+ {"c:d/", ".", "c:d/", "c:d/", "c:d", true, false},
+ {"c:d/f", "c:d", "f", "f", "c:d/f",false, false},
+ {"a:b:c", ".", "a:b:c","a:b:c","a:b:c",false, false},
+ {"a/b:c", "a", "b:c", "b:c", "a/b:c",false, false},
+#endif
+ {"1:", ".", "1:", "1:", "1:", false, false},
+ {"1:/", ".", "1:/", "1:/", "1:", true, false},
+ {"/:", "/", ":", ":", "/:", false, true},
+ {"/:/", "/", ":/", ":/", "/:", true, true},
+ /* End sentinel. */
+ {NULL, NULL, NULL, NULL, NULL, false, false}
+};
+
+int
+main ()
+{
+ struct test *t;
+ bool ok = true;
+
+ for (t = tests; t->name; t++)
+ {
+ char *dir = dir_name (t->name);
+ int dirlen = dir_len (t->name);
+ char *last = last_component (t->name);
+ char *base = base_name (t->name);
+ int baselen = base_len (base);
+ char *stripped = strdup (t->name);
+ bool modified = strip_trailing_slashes (stripped);
+ bool absolute = IS_ABSOLUTE_FILE_NAME (t->name);
+ if (! (strcmp (dir, t->dir) == 0
+ && (dirlen == strlen (dir)
+ || (dirlen + 1 == strlen (dir) && dir[dirlen] == '.'))))
+ {
+ ok = false;
+ printf ("dir_name `%s': got `%s' len %d, expected `%s' len %d\n",
+ t->name, dir, dirlen, t->dir, strlen (t->dir));
+ }
+ if (strcmp (last, t->last))
+ {
+ ok = false;
+ printf ("last_component `%s': got `%s', expected `%s'\n",
+ t->name, last, t->last);
+ }
+ if (! (strcmp (base, t->base) == 0
+ && (baselen == strlen (base)
+ || (baselen + 1 == strlen (base)
+ && ISSLASH (base[baselen])))))
+ {
+ ok = false;
+ printf ("base_name `%s': got `%s' len %d, expected `%s' len %d\n",
+ t->name, base, baselen, t->base, strlen (t->base));
+ }
+ if (strcmp (stripped, t->stripped) || modified != t->modified)
+ {
+ ok = false;
+ printf ("strip_trailing_slashes `%s': got %s %s, expected %s %s\n",
+ t->name, stripped, modified ? "changed" : "unchanged",
+ t->stripped, t->modified ? "changed" : "unchanged");
+ }
+ if (t->absolute != absolute)
+ {
+ ok = false;
+ printf ("`%s': got %s, expected %s\n", t->name,
+ absolute ? "absolute" : "relative",
+ t->absolute ? "absolute" : "relative");
+ }
+ free (dir);
+ free (base);
+ free (stripped);
+ }
+ return ok ? 0 : 1;
+}
- Re: bugs in dirname module, (continued)
- Re: bugs in dirname module, Paul Eggert, 2005/11/10
- Re: bugs in dirname module, Eric Blake, 2005/11/10
- Re: bugs in dirname module, Paul Eggert, 2005/11/11
- Re: bugs in dirname module, Eric Blake, 2005/11/11
- Re: bugs in dirname module, Paul Eggert, 2005/11/16
- Re: bugs in dirname module, Eric Blake, 2005/11/17
- Re: bugs in dirname module, Paul Eggert, 2005/11/17
- Re: bugs in dirname module, Jim Meyering, 2005/11/17
Re: bugs in dirname module, Eric Blake, 2005/11/17
Re: bugs in dirname module, Eric Blake, 2005/11/17