comparison lib/dirname.c @ 3038:e42896c5352d

(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.
author Jim Meyering <jim@meyering.net>
date Thu, 07 Dec 2000 14:10:21 +0000
parents 0fdc03087206
children c98368348dc3
comparison
equal deleted inserted replaced
3037:e6757ccfb526 3038:e42896c5352d
41 void *memrchr (); 41 void *memrchr ();
42 #endif 42 #endif
43 43
44 #include "dirname.h" 44 #include "dirname.h"
45 45
46 #ifndef FILESYSTEM_PREFIX_LEN
47 # define FILESYSTEM_PREFIX_LEN(Filename) 0
48 #endif
49
46 #ifndef ISSLASH 50 #ifndef ISSLASH
47 # define ISSLASH(C) ((C) == '/') 51 # define ISSLASH(C) ((C) == '/')
48 #endif 52 #endif
49 53
50 #define BACKSLASH_IS_PATH_SEPARATOR ISSLASH ('\\') 54 #define BACKSLASH_IS_PATH_SEPARATOR ISSLASH ('\\')
51 55
52 /* Return the length of `dirname (PATH)' and set *RESULT 56 /* Return the length of `dirname (PATH)' and set *RESULT to point
53 to point to PATH or to `"."', as appropriate. 57 to PATH or to `"."', as appropriate. Works properly even if
54 Works properly even if there are trailing slashes 58 there are trailing slashes (by effectively ignoring them).
55 (by effectively ignoring them). */ 59 WARNING: This function doesn't work for cwd-relative names like
56 size_t 60 `a:foo' that are specified with a drive-letter prefix. That case
61 is handled in the caller. */
62 static size_t
57 dir_name_r (char const *path, char const **result) 63 dir_name_r (char const *path, char const **result)
58 { 64 {
59 char const *slash; 65 char const *slash;
60 size_t length; /* Length of result, not including NUL. */ 66 size_t length; /* Length of result, not including NUL. */
61 67
76 --slash; 82 --slash;
77 } 83 }
78 84
79 if (path < slash) 85 if (path < slash)
80 { 86 {
81 slash = memrchr (path, '/', slash - path); 87 size_t len = slash - path;
88 slash = memrchr (path, '/', len);
82 if (BACKSLASH_IS_PATH_SEPARATOR) 89 if (BACKSLASH_IS_PATH_SEPARATOR)
83 { 90 {
84 char const *b = memrchr (path, '\\', slash - path); 91 char const *b = memrchr (path, '\\', len);
85 if (b && slash < b) 92 if (b && slash < b)
86 slash = b; 93 slash = b;
87 } 94 }
88 } 95 }
89 } 96 }
90 97
91 if (slash == 0) 98 if (slash == 0)
92 { 99 {
93 /* File is in the current directory. */ 100 /* File is in the current directory. */
94 path = "."; 101
95 length = 1; 102 length = FILESYSTEM_PREFIX_LEN (path);
103
104 if (length == 0)
105 {
106 path = ".";
107 length = 1;
108 }
96 } 109 }
97 else 110 else
98 { 111 {
99 /* Remove any trailing slashes from the result. */ 112 /* Remove any trailing slashes from the result. If we have a
100 if (BACKSLASH_IS_PATH_SEPARATOR) 113 canonicalized "d:/path", leave alone the root case "d:/". */
101 { 114 char const *lim = path + FILESYSTEM_PREFIX_LEN (path);
102 char const *lim = ((path[0] >= 'A' && path[0] <= 'z'
103 && path[1] == ':')
104 ? path + 2 : path);
105 115
106 /* If canonicalized "d:/path", leave alone the root case "d:/". */ 116 while (slash > lim && ISSLASH (*slash))
107 while (slash > lim && ISSLASH (*slash)) 117 --slash;
108 --slash;
109 }
110 else
111 {
112 while (slash > path && ISSLASH (*slash))
113 --slash;
114 }
115 118
116 length = slash - path + 1; 119 length = slash - path + 1;
117 } 120 }
118 121
119 *result = path; 122 *result = path;
128 char * 131 char *
129 dir_name (char const *path) 132 dir_name (char const *path)
130 { 133 {
131 char const *result; 134 char const *result;
132 size_t length = dir_name_r (path, &result); 135 size_t length = dir_name_r (path, &result);
133 char *newpath = (char *) malloc (length + 1); 136 int append_dot = (length && length == FILESYSTEM_PREFIX_LEN (newpath));
137 char *newpath = (char *) malloc (length + append_dot + 1);
134 if (newpath == 0) 138 if (newpath == 0)
135 return 0; 139 return 0;
136 strncpy (newpath, result, length); 140 strncpy (newpath, result, length);
141 /* If PATH is "d:foo", return "d:.", the CWD on drive d: */
142 if (append_dot)
143 newpath[length++] = '.';
137 newpath[length] = 0; 144 newpath[length] = 0;
138 return newpath; 145 return newpath;
139 } 146 }
140 147
141 #ifdef TEST_DIRNAME 148 #ifdef TEST_DIRNAME