bug-coreutils
[Top][All Lists]
Advanced

[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

reply via email to

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