1 /* dirname.c -- return all but the last element in a path
2 Copyright (C) 1990, 1998, 2000 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
27 #if defined STDC_HEADERS || defined HAVE_STRING_H
32 # define strrchr rindex
37 #ifndef HAVE_DECL_MEMRCHR
38 "this configure-time declaration test was not run"
40 #if !HAVE_DECL_MEMRCHR
46 #ifndef FILESYSTEM_PREFIX_LEN
47 # define FILESYSTEM_PREFIX_LEN(Filename) 0
51 # define ISSLASH(C) ((C) == '/')
54 #define BACKSLASH_IS_PATH_SEPARATOR ISSLASH ('\\')
56 /* Return the length of `dirname (PATH)' and set *RESULT to point
57 to PATH or to `"."', as appropriate. Works properly even if
58 there are trailing slashes (by effectively ignoring them).
59 WARNING: This function doesn't work for cwd-relative names like
60 `a:foo' that are specified with a drive-letter prefix. That case
61 is handled in the caller. */
63 dir_name_r (char const *path
, char const **result
)
66 size_t length
; /* Length of result, not including NUL. */
68 slash
= strrchr (path
, '/');
69 if (BACKSLASH_IS_PATH_SEPARATOR
)
71 char const *b
= strrchr (path
, '\\');
76 /* If the last byte of PATH is a slash, decrement SLASH until it's
77 pointing at the leftmost in a sequence of trailing slashes. */
78 if (slash
&& slash
[1] == 0)
80 while (path
< slash
&& ISSLASH (slash
[-1]))
87 size_t len
= slash
- path
;
88 slash
= memrchr (path
, '/', len
);
89 if (BACKSLASH_IS_PATH_SEPARATOR
)
91 char const *b
= memrchr (path
, '\\', len
);
100 /* File is in the current directory. */
102 length
= FILESYSTEM_PREFIX_LEN (path
);
112 /* Remove any trailing slashes from the result. If we have a
113 canonicalized "d:/path", leave alone the root case "d:/". */
114 char const *lim
= path
+ FILESYSTEM_PREFIX_LEN (path
);
116 while (lim
< slash
&& ISSLASH (*slash
))
119 length
= slash
- path
+ 1;
126 /* Return the leading directories part of PATH,
127 allocated with malloc. If out of memory, return 0.
128 Works properly even if there are trailing slashes
129 (by effectively ignoring them). */
132 dir_name (char const *path
)
135 size_t length
= dir_name_r (path
, &result
);
136 int append_dot
= (length
&& length
== FILESYSTEM_PREFIX_LEN (newpath
));
137 char *newpath
= (char *) malloc (length
+ append_dot
+ 1);
140 strncpy (newpath
, result
, length
);
141 /* If PATH is "d:foo", return "d:.", the CWD on drive d: */
143 newpath
[length
++] = '.';
151 Run the test like this (expect no output):
152 gcc -DHAVE_CONFIG_H -DTEST_DIRNAME -I.. -O -Wall memrchr.c dirname.c
153 sed -n '/^BEGIN-DATA$/,/^END-DATA$/p' dirname.c|grep -v DATA|./a.out
166 # define MAX_BUFF_LEN 1024
173 char buff
[MAX_BUFF_LEN
+ 1];
175 buff
[MAX_BUFF_LEN
] = 0;
176 while (fgets (buff
, MAX_BUFF_LEN
, stdin
) && buff
[0])
178 char path
[MAX_BUFF_LEN
];
179 char expected_result
[MAX_BUFF_LEN
];
181 sscanf (buff
, "%s %s", path
, expected_result
);
182 result
= dir_name (path
);
183 if (strcmp (result
, expected_result
))
184 printf ("%s: got %s, expected %s\n", path
, result
, expected_result
);