summaryrefslogtreecommitdiff
path: root/lib/dirname.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2000-12-07 14:10:21 +0000
committerJim Meyering <jim@meyering.net>2000-12-07 14:10:21 +0000
commit4504b81f3b9a1071834012262bd4eac17f9290ff (patch)
tree5a0a24e2ec6dcc8d8db1e8b0650ff8414cfd8e2a /lib/dirname.c
parent222412dbf14be2eeeab5ab0139e3a7b11169942c (diff)
downloadcoreutils-4504b81f3b9a1071834012262bd4eac17f9290ff.tar.xz
(FILESYSTEM_PREFIX_LEN): Define.
(dir_name_r): Declare this function as static. [BACKSLASH_IS_PATH_SEPARATOR]: Fix a bug that'd manifest itself on a name containing a mix of slashes and backslashes. Make this function work with names starting with a DOS-style drive letter and colon prefix. (dir_name): Append `.' if necessary. Based mostly on patches from Prashant TR and Eli Zaretskii.
Diffstat (limited to 'lib/dirname.c')
-rw-r--r--lib/dirname.c57
1 files changed, 32 insertions, 25 deletions
diff --git a/lib/dirname.c b/lib/dirname.c
index 2225800ab..7826d8edb 100644
--- a/lib/dirname.c
+++ b/lib/dirname.c
@@ -43,17 +43,23 @@ void *memrchr ();
#include "dirname.h"
+#ifndef FILESYSTEM_PREFIX_LEN
+# define FILESYSTEM_PREFIX_LEN(Filename) 0
+#endif
+
#ifndef ISSLASH
# define ISSLASH(C) ((C) == '/')
#endif
#define BACKSLASH_IS_PATH_SEPARATOR ISSLASH ('\\')
-/* Return the length of `dirname (PATH)' and set *RESULT
- to point to PATH or to `"."', as appropriate.
- Works properly even if there are trailing slashes
- (by effectively ignoring them). */
-size_t
+/* Return the length of `dirname (PATH)' and set *RESULT to point
+ to PATH or to `"."', as appropriate. Works properly even if
+ there are trailing slashes (by effectively ignoring them).
+ WARNING: This function doesn't work for cwd-relative names like
+ `a:foo' that are specified with a drive-letter prefix. That case
+ is handled in the caller. */
+static size_t
dir_name_r (char const *path, char const **result)
{
char const *slash;
@@ -78,10 +84,11 @@ dir_name_r (char const *path, char const **result)
if (path < slash)
{
- slash = memrchr (path, '/', slash - path);
+ size_t len = slash - path;
+ slash = memrchr (path, '/', len);
if (BACKSLASH_IS_PATH_SEPARATOR)
{
- char const *b = memrchr (path, '\\', slash - path);
+ char const *b = memrchr (path, '\\', len);
if (b && slash < b)
slash = b;
}
@@ -91,27 +98,23 @@ dir_name_r (char const *path, char const **result)
if (slash == 0)
{
/* File is in the current directory. */
- path = ".";
- length = 1;
+
+ length = FILESYSTEM_PREFIX_LEN (path);
+
+ if (length == 0)
+ {
+ path = ".";
+ length = 1;
+ }
}
else
{
- /* Remove any trailing slashes from the result. */
- if (BACKSLASH_IS_PATH_SEPARATOR)
- {
- char const *lim = ((path[0] >= 'A' && path[0] <= 'z'
- && path[1] == ':')
- ? path + 2 : path);
+ /* Remove any trailing slashes from the result. If we have a
+ canonicalized "d:/path", leave alone the root case "d:/". */
+ char const *lim = path + FILESYSTEM_PREFIX_LEN (path);
- /* If canonicalized "d:/path", leave alone the root case "d:/". */
- while (slash > lim && ISSLASH (*slash))
- --slash;
- }
- else
- {
- while (slash > path && ISSLASH (*slash))
- --slash;
- }
+ while (slash > lim && ISSLASH (*slash))
+ --slash;
length = slash - path + 1;
}
@@ -130,10 +133,14 @@ dir_name (char const *path)
{
char const *result;
size_t length = dir_name_r (path, &result);
- char *newpath = (char *) malloc (length + 1);
+ int append_dot = (length && length == FILESYSTEM_PREFIX_LEN (newpath));
+ char *newpath = (char *) malloc (length + append_dot + 1);
if (newpath == 0)
return 0;
strncpy (newpath, result, length);
+ /* If PATH is "d:foo", return "d:.", the CWD on drive d: */
+ if (append_dot)
+ newpath[length++] = '.';
newpath[length] = 0;
return newpath;
}