[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: bugs in dirname module - coreutils portion
From: |
Eric Blake |
Subject: |
Re: bugs in dirname module - coreutils portion |
Date: |
Sat, 26 Nov 2005 07:15:40 -0700 |
User-agent: |
Mozilla Thunderbird 1.0.2 (Windows/20050317) |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
According to Eric Blake on 11/23/2005 2:04 PM:
> I normally run emacs with
> (add-hook 'before-save-hook 'whitespace-cleanup)
> That was the culprit. I guess I should file a bug with emacs that
> whitespace.el should not normalize spaces inside string literals.
>
> Meanwhile, is there an easier way to run emacs whitespace-cleanup
> to catch trailing whitespace and space-before-tab issues without
> also being forced to turn on the 8-spaces-vs-tab cleanup? What
> settings do you use for whitespace happiness during editing?
I added the following to my .emacs to ignore 8-spaces-vs-tab, and
regenerated the patch without corrupting existing lines with leading spaces:
(setq whitespace-check-indent-whitespace nil)
It looks like the whitespace.el version 3.4 that comes with emacs 21.3.50
(the cygwin distro's bundled CVS snapshot) is a bit more configurable than
what you experienced when you first switched to the
nuke-trailing-whitespace package; but I will consider switching to
nuke-trailing-whitespace.
Meanwhile, it looks like the only lines where we must absolutely use
leading spaces instead of switching to tabs are lines that are embedded in
multi-line string literals, therefore those lines end in \n\. My lisp-foo
wasn't good enough to modify whitespace-indent-regexp or
whitespace-indent-cleanup to ignore lines that match "\\n\\$", but to do
the 8-spaces-vs-tab cleanups on other lines. But as you said,
8-spaces-vs-tabs cleanup tends to be noisy, so skipping it altogether is
probably okay.
>
>>It might be better, for a larger change like this, to do the
>>tab-normalization changes separately anyway, so that we can see the
>>more-important stuff easily.
OK, I will do better at not combining whitespace cleanup with real
patches. And I agree with your comment that using diff -b as a crutch is
not wise, so here is the updated patch with no whitespace filtering.
ChangeLog:
2005-11-26 Eric Blake <address@hidden>
* tests/misc/dirname: New file.
* tests/basename/Makefile.am: Delete.
* tests/basename/basic: Move to...
* tests/misc/basename: ... this new file. Add some tests,
including fixed behavior for //.
* tests/misc/Makefile.am (TESTS): Sort. Add basename, dirname.
* tests/Makefile.am (SUBDIRS): Remove basename.
* configure.ac (AC_CONFIG_FILES): Remove tests/basename.
Improvements to dirname/basename handling on platforms like
cygwin with distinct // and with drive letters.
* src/basename.c (main): Don't strip suffix from file system
roots.
* src/cp.c (target_directory_operand): Use new last_component.
(ASSIGN_BASENAME_STRDUPA): Likewise. Reduce time spent
traversing the string.
* src/dircolors.c (guess_shell_syntax): Use new last_component.
* src/install.c (target_directory_operand, install_file_in_dir):
Likewise.
* src/ln.c (target_directory_operand, main): Likewise.
* src/ls.c (basename_is_dot_or_dotdot): Likewise.
* src/mv.c (target_directory_operand, movefile): Likewise.
* src/remove.c (rm_1): Likewise.
* src/rm.c (usage): Clean up after base_name.
* src/shred.c (wipename): Use new last_component.
* src/split.c (next_file_name): Likewise.
* src/su.c (log_su, run_shell): Likewise.
doc/ChangeLog:
2005-11-23 Eric Blake <address@hidden>
* coreutils.texi (basename invocation, dirname invocation):
Improve documentation to match recent patches.
(paste invocation): Fix whitespace.
m4/ChangeLog: (merge from gnulib patch)
2005-11-22 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_CAN_BE_RELATIVE): New define.
lib/ChangeLog: (merge from gnulib patch)
2005-11-24 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.
2005-11-24 Eric Blake <address@hidden>,
Paul Eggert <address@hidden>
* 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
iD8DBQFDiG4L84KuGfSFAYARArnJAJ4kgOYAKJI/ZNpk2DQAGPeBxtpY7ACfZ2tc
BS3BfbLIEa02QOhPSN2QLic=
=dzIb
-----END PGP SIGNATURE-----
Index: configure.ac
===================================================================
RCS file: /cvsroot/coreutils/coreutils/configure.ac,v
retrieving revision 1.74
diff -u -p -r1.74 configure.ac
--- configure.ac 22 Nov 2005 15:32:20 -0000 1.74
+++ configure.ac 25 Nov 2005 15:00:12 -0000
@@ -259,7 +259,6 @@ AC_CONFIG_FILES(
po/Makefile.in
src/Makefile
tests/Makefile
- tests/basename/Makefile
tests/chgrp/Makefile
tests/chmod/Makefile
tests/chown/Makefile
Index: doc/coreutils.texi
===================================================================
RCS file: /cvsroot/coreutils/coreutils/doc/coreutils.texi,v
retrieving revision 1.296
diff -u -p -r1.296 coreutils.texi
--- doc/coreutils.texi 16 Nov 2005 22:45:12 -0000 1.296
+++ doc/coreutils.texi 25 Nov 2005 15:00:15 -0000
@@ -4636,7 +4636,7 @@ c
$ paste num2 let3
1 a
2 b
- c
+ @ c
@end example
Synopsis:
@@ -10394,8 +10394,21 @@ basename @var{name} address@hidden
@end example
If @var{suffix} is specified and is identical to the end of @var{name},
-it is removed from @var{name} as well. @command{basename} prints the
-result on standard output.
+it is removed from @var{name} as well. Note that since trailing slashes
+are removed prior to suffix matching, @var{suffix} will do nothing if it
+contains slashes. @command{basename} prints the result on standard
+output.
+
+Together, @command{basename} and @command{dirname} are designed such
+that if @samp{ls "$name"} succeeds, then the command sequence @samp{cd
+"$(dirname "$name")"; ls "$(basename "$name")"} will too. This works
+for everything except filenames containing a trailing newline.
+
address@hidden allows the implementation to define the results if
address@hidden is empty or @samp{//}. In the former case, @acronym{GNU}
address@hidden returns the empty string. In the latter case, the
+result is @samp{//} on platforms where @var{//} is distinct from
address@hidden/}, and @samp{/} on platforms where there is no difference.
The only options are @option{--help} and @option{--version}. @xref{Common
options}. Options must precede operands.
@@ -10430,6 +10443,16 @@ dirname @var{name}
If @var{name} is a single component, @command{dirname} prints @samp{.}
(meaning the current directory).
+
+Together, @command{basename} and @command{dirname} are designed such
+that if @samp{ls "$name"} succeeds, then the command sequence @samp{cd
+"$(dirname "$name")"; ls "$(basename "$name")"} will too. This works
+for everything except filenames containing a trailing newline.
+
address@hidden allows the implementation to define the results if
address@hidden is @samp{//}. With @acronym{GNU} @command{dirname}, the
+result is @samp{//} on platforms where @var{//} is distinct from
address@hidden/}, and @samp{/} on platforms where there is no difference.
The only options are @option{--help} and @option{--version}. @xref{Common
options}.
Index: lib/backupfile.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/lib/backupfile.c,v
retrieving revision 1.49
diff -u -p -r1.49 backupfile.c
--- lib/backupfile.c 22 Sep 2005 06:05:39 -0000 1.49
+++ lib/backupfile.c 25 Nov 2005 15:00: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/coreutils/coreutils/lib/basename.c,v
retrieving revision 1.26
diff -u -p -r1.26 basename.c
--- lib/basename.c 22 Sep 2005 06:05:39 -0000 1.26
+++ lib/basename.c 25 Nov 2005 15:00:17 -0000
@@ -22,58 +22,110 @@
#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;
+ bool saw_slash = false;
+
+ while (ISSLASH (*base))
+ base++;
for (p = base; *p; p++)
{
if (ISSLASH (*p))
+ saw_slash = true;
+ else if (saw_slash)
{
- /* Treat multiple adjacent slashes like a single slash. */
- 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 (! *p)
- {
- if (ISSLASH (*base))
- base = p - 1;
- break;
- }
-
- /* *P is a non-slash preceded by a slash. */
base = p;
+ saw_slash = false;
}
}
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);
+ 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;
}
Index: lib/dirname.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/lib/dirname.c,v
retrieving revision 1.36
diff -u -p -r1.36 dirname.c
--- lib/dirname.c 22 Sep 2005 06:05:39 -0000 1.36
+++ lib/dirname.c 25 Nov 2005 15:00:17 -0000
@@ -26,96 +26,62 @@
#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)
{
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 = 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]);
+ break;
+ return length;
}
-/* 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_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;
+ 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/coreutils/coreutils/lib/dirname.h,v
retrieving revision 1.15
diff -u -p -r1.15 dirname.h
--- lib/dirname.h 2 Jun 2005 05:05:29 -0000 1.15
+++ lib/dirname.h 25 Nov 2005 15:00:17 -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_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 1
+# 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))
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/coreutils/coreutils/lib/filenamecat.c,v
retrieving revision 1.2
diff -u -p -r1.2 filenamecat.c
--- lib/filenamecat.c 22 Sep 2005 06:05:39 -0000 1.2
+++ lib/filenamecat.c 25 Nov 2005 15:00:17 -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/coreutils/coreutils/lib/same.c,v
retrieving revision 1.18
diff -u -p -r1.18 same.c
--- lib/same.c 22 Sep 2005 06:05:39 -0000 1.18
+++ lib/same.c 25 Nov 2005 15:00:17 -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/coreutils/coreutils/lib/stripslash.c,v
retrieving revision 1.15
diff -u -p -r1.15 stripslash.c
--- lib/stripslash.c 22 Sep 2005 06:05:39 -0000 1.15
+++ lib/stripslash.c 25 Nov 2005 15:00:17 -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/dirname.m4
===================================================================
RCS file: /cvsroot/coreutils/coreutils/m4/dirname.m4,v
retrieving revision 1.7
diff -u -p -r1.7 dirname.m4
--- m4/dirname.m4 29 Jan 2005 00:16:39 -0000 1.7
+++ m4/dirname.m4 25 Nov 2005 15:00:18 -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/coreutils/coreutils/m4/dos.m4,v
retrieving revision 1.13
diff -u -p -r1.13 dos.m4
--- m4/dos.m4 23 Jan 2005 09:07:57 -0000 1.13
+++ m4/dos.m4 25 Nov 2005 15:00:18 -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_can_be_relative=1
+ else
+ ac_fs_drive_letter_can_be_relative=0
+ fi
else
ac_fs_accepts_drive_letter_prefix=0
ac_fs_backslash_is_file_name_separator=0
+ ac_fs_drive_letter_can_be_relative=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_CAN_BE_RELATIVE],
+ $ac_fs_drive_letter_can_be_relative,
+ [Define if a drive letter prefix denotes a relative path if it is
+ not followed by a file name component separator.])
])
Index: src/basename.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/basename.c,v
retrieving revision 1.63
diff -u -p -r1.63 basename.c
--- src/basename.c 2 Jun 2005 05:17:24 -0000 1.63
+++ src/basename.c 25 Nov 2005 15:00:19 -0000
@@ -126,12 +126,20 @@ main (int argc, char **argv)
}
name = base_name (argv[optind]);
- name[base_len (name)] = '\0';
+ strip_trailing_slashes (name);
- if (argc == optind + 2)
+ /* Per POSIX, `basename // /' must return `//' on platforms with
+ distinct //. On platforms with drive letters, this generalizes
+ to making `basename c: :' return `c:'. This rule is captured by
+ skipping suffix stripping if base_name returned an absolute path
+ or a drive letter (only possible if name is a file-system
+ root). */
+ if (argc == optind + 2 && IS_RELATIVE_FILE_NAME (name)
+ && ! FILE_SYSTEM_PREFIX_LEN (name))
remove_suffix (name, argv[optind + 1]);
puts (name);
+ free (name);
exit (EXIT_SUCCESS);
}
Index: src/cp.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/cp.c,v
retrieving revision 1.215
diff -u -p -r1.215 cp.c
--- src/cp.c 16 Sep 2005 07:50:33 -0000 1.215
+++ src/cp.c 25 Nov 2005 15:00:19 -0000
@@ -1,5 +1,5 @@
/* cp.c -- file copying (main routines)
- Copyright (C) 89, 90, 91, 1995-2005 Free Software Foundation.
+ Copyright (C) 1989, 1990, 1991, 1995-2005 Free Software Foundation.
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
@@ -41,8 +41,8 @@
{ \
char *tmp_abns_; \
ASSIGN_STRDUPA (tmp_abns_, (File_name)); \
+ Dest = last_component (tmp_abns_); \
strip_trailing_slashes (tmp_abns_); \
- Dest = base_name (tmp_abns_); \
} \
while (0)
@@ -471,7 +471,7 @@ make_dir_parents_private (char const *co
static bool
target_directory_operand (char const *file, struct stat *st, bool *new_dst)
{
- char const *b = base_name (file);
+ char const *b = last_component (file);
size_t blen = strlen (b);
bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
int err = (stat (file, st) == 0 ? 0 : errno);
Index: src/dircolors.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/dircolors.c,v
retrieving revision 1.97
diff -u -p -r1.97 dircolors.c
--- src/dircolors.c 24 Oct 2005 10:39:46 -0000 1.97
+++ src/dircolors.c 25 Nov 2005 15:00:19 -0000
@@ -137,7 +137,7 @@ guess_shell_syntax (void)
if (shell == NULL || *shell == '\0')
return SHELL_SYNTAX_UNKNOWN;
- shell = base_name (shell);
+ shell = last_component (shell);
if (STREQ (shell, "csh") || STREQ (shell, "tcsh"))
return SHELL_SYNTAX_C;
Index: src/install.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/install.c,v
retrieving revision 1.189
diff -u -p -r1.189 install.c
--- src/install.c 23 Sep 2005 20:50:49 -0000 1.189
+++ src/install.c 25 Nov 2005 15:00:19 -0000
@@ -168,7 +168,7 @@ cp_option_init (struct cp_options *x)
static bool
target_directory_operand (char const *file)
{
- char const *b = base_name (file);
+ char const *b = last_component (file);
size_t blen = strlen (b);
bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
struct stat st;
@@ -464,7 +464,7 @@ static bool
install_file_in_dir (const char *from, const char *to_dir,
const struct cp_options *x)
{
- const char *from_base = base_name (from);
+ const char *from_base = last_component (from);
char *to = file_name_concat (to_dir, from_base, NULL);
bool ret = install_file_in_file (from, to, x);
free (to);
Index: src/ln.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/ln.c,v
retrieving revision 1.155
diff -u -p -r1.155 ln.c
--- src/ln.c 16 Nov 2005 22:32:45 -0000 1.155
+++ src/ln.c 25 Nov 2005 15:00:19 -0000
@@ -1,5 +1,5 @@
/* `ln' program to create links between files.
- Copyright (C) 86, 89, 90, 91, 1995-2005 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1989-1991, 1995-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
@@ -113,7 +113,7 @@ static struct option const long_options[
static bool
target_directory_operand (char const *file)
{
- char const *b = base_name (file);
+ char const *b = last_component (file);
size_t blen = strlen (b);
bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
struct stat st;
@@ -525,7 +525,8 @@ main (int argc, char **argv)
for (i = 0; i < n_files; ++i)
{
char *dest_base;
- char *dest = file_name_concat (target_directory, base_name (file[i]),
+ char *dest = file_name_concat (target_directory,
+ last_component (file[i]),
&dest_base);
strip_trailing_slashes (dest_base);
ok &= do_link (file[i], dest);
Index: src/ls.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/ls.c,v
retrieving revision 1.403
diff -u -p -r1.403 ls.c
--- src/ls.c 17 Nov 2005 12:28:34 -0000 1.403
+++ src/ls.c 25 Nov 2005 15:00:20 -0000
@@ -2779,7 +2779,7 @@ make_link_name (char const *name, char c
static bool
basename_is_dot_or_dotdot (const char *name)
{
- char const *base = base_name (name);
+ char const *base = last_component (name);
return DOT_OR_DOTDOT (base);
}
Index: src/mv.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/mv.c,v
retrieving revision 1.171
diff -u -p -r1.171 mv.c
--- src/mv.c 2 Nov 2005 21:52:33 -0000 1.171
+++ src/mv.c 25 Nov 2005 15:00:20 -0000
@@ -1,5 +1,5 @@
/* mv -- move or rename files
- Copyright (C) 86, 89, 90, 91, 1995-2005 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1989-1991, 1995-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
@@ -154,7 +154,7 @@ cp_option_init (struct cp_options *x)
static bool
target_directory_operand (char const *file)
{
- char const *b = base_name (file);
+ char const *b = last_component (file);
size_t blen = strlen (b);
bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
struct stat st;
@@ -272,7 +272,7 @@ movefile (char *source, char *dest, bool
if (dest_is_dir)
{
/* Treat DEST as a directory; build the full filename. */
- char const *src_basename = base_name (source);
+ char const *src_basename = last_component (source);
char *new_dest = file_name_concat (dest, src_basename, NULL);
strip_trailing_slashes (new_dest);
ok = do_move (source, new_dest, x);
Index: src/remove.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/remove.c,v
retrieving revision 1.139
diff -u -p -r1.139 remove.c
--- src/remove.c 23 Nov 2005 04:52:48 -0000 1.139
+++ src/remove.c 25 Nov 2005 15:00:21 -0000
@@ -1322,7 +1322,7 @@ static enum RM_status
rm_1 (Dirstack_state *ds, char const *filename,
struct rm_options const *x, bool *cwd_restore_failed)
{
- char const *base = base_name (filename);
+ char const *base = last_component (filename);
if (DOT_OR_DOTDOT (base))
{
error (0, 0, _("cannot remove `.' or `..'"));
Index: src/rm.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/rm.c,v
retrieving revision 1.136
diff -u -p -r1.136 rm.c
--- src/rm.c 2 Nov 2005 21:53:20 -0000 1.136
+++ src/rm.c 25 Nov 2005 15:00:21 -0000
@@ -169,6 +169,7 @@ the contents of that file. If you want
truly unrecoverable, consider using shred.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
+ free (base);
}
exit (status);
}
Index: src/shred.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/shred.c,v
retrieving revision 1.117
diff -u -p -r1.117 shred.c
--- src/shred.c 24 Sep 2005 13:40:37 -0000 1.117
+++ src/shred.c 25 Nov 2005 15:00:21 -0000
@@ -1344,7 +1344,7 @@ static bool
wipename (char *oldname, char const *qoldname, struct Options const *flags)
{
char *newname = xstrdup (oldname);
- char *base = base_name (newname);
+ char *base = last_component (newname);
size_t len = base_len (base);
char *dir = dir_name (newname);
char *qdir = xstrdup (quotearg_colon (dir));
Index: src/split.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/split.c,v
retrieving revision 1.112
diff -u -p -r1.112 split.c
--- src/split.c 11 Jul 2005 18:24:42 -0000 1.112
+++ src/split.c 25 Nov 2005 15:00:21 -0000
@@ -1,5 +1,5 @@
/* split.c -- split a file into pieces.
- Copyright (C) 88, 91, 1995-2005 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1991, 1995-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
@@ -171,7 +171,7 @@ next_file_name (void)
{
char *dir = dir_name (outfile);
long name_max = pathconf (dir, _PC_NAME_MAX);
- if (0 <= name_max && name_max < base_len (base_name (outfile)))
+ if (0 <= name_max && name_max < base_len (last_component (outfile)))
error (EXIT_FAILURE, ENAMETOOLONG, "%s", outfile);
free (dir);
}
Index: src/su.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/su.c,v
retrieving revision 1.89
diff -u -p -r1.89 su.c
--- src/su.c 23 Aug 2005 15:09:13 -0000 1.89
+++ src/su.c 25 Nov 2005 15:00:21 -0000
@@ -219,7 +219,7 @@ log_su (struct passwd const *pw, bool su
if (!tty)
tty = "none";
/* 4.2BSD openlog doesn't have the third parameter. */
- openlog (base_name (program_name), 0
+ openlog (last_component (program_name), 0
# ifdef LOG_AUTH
, LOG_AUTH
# endif
@@ -350,14 +350,14 @@ run_shell (char const *shell, char const
char *arg0;
char *shell_basename;
- shell_basename = base_name (shell);
+ shell_basename = last_component (shell);
arg0 = xmalloc (strlen (shell_basename) + 2);
arg0[0] = '-';
strcpy (arg0 + 1, shell_basename);
args[0] = arg0;
}
else
- args[0] = base_name (shell);
+ args[0] = last_component (shell);
if (fast_startup)
args[argno++] = "-f";
if (command)
Index: tests/Makefile.am
===================================================================
RCS file: /cvsroot/coreutils/coreutils/tests/Makefile.am,v
retrieving revision 1.25
diff -u -p -r1.25 Makefile.am
--- tests/Makefile.am 24 Nov 2005 17:25:08 -0000 1.25
+++ tests/Makefile.am 25 Nov 2005 15:00:21 -0000
@@ -19,10 +19,10 @@ EXTRA_DIST = \
rwx-to-mode sample-test setgid-check umask-check very-expensive
SUBDIRS = \
- basename chgrp chmod chown cp cut dd dircolors du expr factor \
- fmt head install join ln ls ls-2 md5sum misc mkdir mv od pr readlink \
- rm rmdir seq sha1sum shred sort stty sum tac tail tail-2 tee test \
- touch tr tsort unexpand uniq wc
+ chgrp chmod chown cp cut dd dircolors du expr factor fmt head \
+ install join ln ls ls-2 md5sum misc mkdir mv od pr readlink rm rmdir \
+ seq sha1sum shred sort stty sum tac tail tail-2 tee test touch tr \
+ tsort unexpand uniq wc
.PHONY: check-root
check-root:
Index: tests/basename/Makefile.am
===================================================================
RCS file: tests/basename/Makefile.am
diff -N tests/basename/Makefile.am
--- tests/basename/Makefile.am 5 Apr 2003 18:03:47 -0000 1.4
+++ tests/basename/Makefile.am 1 Jan 1970 00:00:00 -0000
@@ -1,11 +0,0 @@
-## Process this file with automake to produce Makefile.in -*-Makefile-*-.
-AUTOMAKE_OPTIONS = 1.4 gnits
-
-TESTS = basic
-EXTRA_DIST = $(TESTS)
-TESTS_ENVIRONMENT = \
- top_srcdir=$(top_srcdir) \
- srcdir=$(srcdir) \
- PERL="$(PERL)" \
- PATH="`pwd`/../../src$(PATH_SEPARATOR)$$PATH" \
- PROG=basename
Index: tests/basename/basic
===================================================================
RCS file: tests/basename/basic
diff -N tests/basename/basic
--- tests/basename/basic 20 Apr 2005 07:54:54 -0000 1.6
+++ tests/basename/basic 1 Jan 1970 00:00:00 -0000
@@ -1,66 +0,0 @@
-#!/bin/sh
-# -*-perl-*-
-
-: ${PERL=perl}
-: ${srcdir=.}
-
-$PERL -e 1 > /dev/null 2>&1 || {
- echo 1>&2 "$0: configure didn't find a usable version of Perl," \
- "so can't run this test"
- exit 77
-}
-
-d=$srcdir/..
-exec $PERL -w -I$d -MCoreutils -- - << \EOF
-require 5.003;
-use strict;
-
-(my $program_name = $0) =~ s|.*/||;
-
-# Turn off localisation of executable's ouput.
address@hidden(LANGUAGE LANG LC_ALL)} = ('C') x 3;
-
-my $prog = $ENV{PROG} || die "$0: \$PROG not specified in environment\n";
-
-my @Tests =
- (
- ['fail-1', {ERR => "$prog: missing operand\n"
- . "Try `$prog --help' for more information.\n"}, {EXIT => '1'}],
- ['fail-2', qw(a b c), {ERR => "$prog: extra operand `c'\n"
- . "Try `$prog --help' for more information.\n"}, {EXIT => '1'}],
-
- ['a', qw(d/f), {OUT => 'f'}],
- ['b', qw(/d/f), {OUT => 'f'}],
- ['c', qw(d/f/), {OUT => 'f'}],
- ['d', qw(d/f//), {OUT => 'f'}],
- ['e', qw(f), {OUT => 'f'}],
- ['f', qw(/), {OUT => '/'}],
- ['g', qw(//), {OUT => '/'}],
- ['h', qw(///), {OUT => '/'}],
- ['i', qw(///a///), {OUT => 'a'}],
- ['1', qw(f.s .s), {OUT => 'f'}],
- ['2', qw(fs s), {OUT => 'f'}],
- ['3', qw(fs fs), {OUT => 'fs'}],
- ['4', qw(fs fs), {OUT => 'fs'}],
- ['5', qw(dir/file.suf .suf), {OUT => 'file'}],
- );
-
-# Append a newline to end of each expected `OUT' string.
-my $t;
-foreach $t (@Tests)
- {
- my $arg1 = $t->[1];
- my $e;
- foreach $e (@$t)
- {
- $e->{OUT} = "$e->{OUT}\n"
- if ref $e eq 'HASH' and exists $e->{OUT};
- }
- }
-
-my $save_temps = $ENV{SAVE_TEMPS};
-my $verbose = $ENV{VERBOSE};
-
-my $fail = run_tests ($program_name, $prog, address@hidden, $save_temps,
$verbose);
-exit $fail;
-EOF
Index: tests/misc/Makefile.am
===================================================================
RCS file: /cvsroot/coreutils/coreutils/tests/misc/Makefile.am,v
retrieving revision 1.31
diff -u -p -r1.31 Makefile.am
--- tests/misc/Makefile.am 23 Oct 2005 15:46:14 -0000 1.31
+++ tests/misc/Makefile.am 25 Nov 2005 15:00:22 -0000
@@ -12,23 +12,34 @@ TESTS_ENVIRONMENT = \
PROG=$$tst
TESTS = \
- sha224sum \
- sha256sum \
- sha384sum \
- sha512sum \
- date \
- tac-continue \
+ basename \
close-stdout \
- pwd \
+ csplit \
+ date \
date-sec \
- paste-no-nl \
- stat-fmt \
+ dirname \
expand \
+ false \
fold \
- nohup \
+ head-c \
head-elide-tail \
- split-fail \
- false \
- tty-eof \
+ head-pos \
+ nice \
+ nl \
+ nohup \
+ paste-no-nl \
+ pathchk1 \
+ printf \
printf-hex \
- nl split-l printf split-a head-pos sort head-c csplit nice pathchk1
+ pwd \
+ sha224sum \
+ sha256sum \
+ sha384sum \
+ sha512sum \
+ sort \
+ split-a \
+ split-fail \
+ split-l \
+ stat-fmt \
+ tac-continue \
+ tty-eof
Index: tests/misc/basename
===================================================================
RCS file: tests/misc/basename
diff -N tests/misc/basename
--- tests/misc/basename 1 Jan 1970 00:00:00 -0000
+++ tests/misc/basename 25 Nov 2005 15:00:22 -0000
@@ -0,0 +1,78 @@
+#!/bin/sh
+# -*-perl-*-
+
+: ${PERL=perl}
+: ${srcdir=.}
+
+$PERL -e 1 > /dev/null 2>&1 || {
+ echo 1>&2 "$0: configure didn't find a usable version of Perl," \
+ "so can't run this test"
+ exit 77
+}
+
+d=$srcdir/..
+exec $PERL -w -I$d -MCoreutils -- - << \EOF
+require 5.003;
+use strict;
+use File::stat;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localisation of executable's ouput.
address@hidden(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $stat_single = stat('/');
+my $stat_double = stat('//');
+my $double_slash = ($stat_single->dev == $stat_double->dev
+ && $stat_single->ino == $stat_double->ino) ? '/' : '//';
+
+my $prog = $ENV{PROG} || die "$0: \$PROG not specified in environment\n";
+
+my @Tests =
+ (
+ ['fail-1', {ERR => "$prog: missing operand\n"
+ . "Try `$prog --help' for more information.\n"}, {EXIT => '1'}],
+ ['fail-2', qw(a b c), {ERR => "$prog: extra operand `c'\n"
+ . "Try `$prog --help' for more information.\n"}, {EXIT => '1'}],
+
+ ['a', qw(d/f), {OUT => 'f'}],
+ ['b', qw(/d/f), {OUT => 'f'}],
+ ['c', qw(d/f/), {OUT => 'f'}],
+ ['d', qw(d/f//), {OUT => 'f'}],
+ ['e', qw(f), {OUT => 'f'}],
+ ['f', qw(/), {OUT => '/'}],
+ ['g', qw(//), {OUT => "$double_slash"}],
+ ['h', qw(///), {OUT => '/'}],
+ ['i', qw(///a///), {OUT => 'a'}],
+ ['j', qw(''), {OUT => ''}],
+ ['1', qw(f.s .s), {OUT => 'f'}],
+ ['2', qw(fs s), {OUT => 'f'}],
+ ['3', qw(fs fs), {OUT => 'fs'}],
+ ['4', qw(fs/ s), {OUT => 'f'}],
+ ['5', qw(dir/file.suf .suf), {OUT => 'file'}],
+ ['6', qw(// /), {OUT => "$double_slash"}],
+ ['7', qw(// //), {OUT => "$double_slash"}],
+ ['8', qw(fs x), {OUT => 'fs'}],
+ ['9', qw(fs ''), {OUT => 'fs'}],
+ ['10', qw(fs/ s/), {OUT => 'fs'}],
+ );
+
+# Append a newline to end of each expected `OUT' string.
+my $t;
+foreach $t (@Tests)
+ {
+ my $arg1 = $t->[1];
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} = "$e->{OUT}\n"
+ if ref $e eq 'HASH' and exists $e->{OUT};
+ }
+ }
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, address@hidden, $save_temps,
$verbose);
+exit $fail;
+EOF
Index: tests/misc/dirname
===================================================================
RCS file: tests/misc/dirname
diff -N tests/misc/dirname
--- tests/misc/dirname 1 Jan 1970 00:00:00 -0000
+++ tests/misc/dirname 25 Nov 2005 15:00:22 -0000
@@ -0,0 +1,71 @@
+#!/bin/sh
+# -*-perl-*-
+
+: ${PERL=perl}
+: ${srcdir=.}
+
+$PERL -e 1 > /dev/null 2>&1 || {
+ echo 1>&2 "$0: configure didn't find a usable version of Perl," \
+ "so can't run this test"
+ exit 77
+}
+
+d=$srcdir/..
+exec $PERL -w -I$d -MCoreutils -- - << \EOF
+require 5.003;
+use strict;
+use File::stat;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localisation of executable's ouput.
address@hidden(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $stat_single = stat('/');
+my $stat_double = stat('//');
+my $double_slash = ($stat_single->dev == $stat_double->dev
+ && $stat_single->ino == $stat_double->ino) ? '/' : '//';
+
+my $prog = $ENV{PROG} || die "$0: \$PROG not specified in environment\n";
+
+my @Tests =
+ (
+ ['fail-1', {ERR => "$prog: missing operand\n"
+ . "Try `$prog --help' for more information.\n"}, {EXIT => '1'}],
+ ['fail-2', qw(a b), {ERR => "$prog: extra operand `b'\n"
+ . "Try `$prog --help' for more information.\n"}, {EXIT => '1'}],
+
+ ['a', qw(d/f), {OUT => 'd'}],
+ ['b', qw(/d/f), {OUT => '/d'}],
+ ['c', qw(d/f/), {OUT => 'd'}],
+ ['d', qw(d/f//), {OUT => 'd'}],
+ ['e', qw(f), {OUT => '.'}],
+ ['f', qw(/), {OUT => '/'}],
+ ['g', qw(//), {OUT => "$double_slash"}],
+ ['h', qw(///), {OUT => '/'}],
+ ['i', qw(//a//), {OUT => "$double_slash"}],
+ ['j', qw(///a///), {OUT => '/'}],
+ ['k', qw(///a///b), {OUT => '///a'}],
+ ['l', qw(///a//b/), {OUT => '///a'}],
+ ['m', qw(''), {OUT => '.'}],
+ );
+
+# Append a newline to end of each expected `OUT' string.
+my $t;
+foreach $t (@Tests)
+ {
+ my $arg1 = $t->[1];
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} = "$e->{OUT}\n"
+ if ref $e eq 'HASH' and exists $e->{OUT};
+ }
+ }
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, address@hidden, $save_temps,
$verbose);
+exit $fail;
+EOF