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
47 # define ISSLASH(C) ((C) == '/')
50 #define BACKSLASH_IS_PATH_SEPARATOR ISSLASH ('\\')
52 /* Return the length of `dirname (PATH)' and set *RESULT
53 to point to PATH or to `"."', as appropriate.
54 Works properly even if there are trailing slashes
55 (by effectively ignoring them). */
57 dir_name_r (char const *path, char const **result)
60 size_t length; /* Length of result, not including NUL. */
62 slash = strrchr (path, '/');
63 if (BACKSLASH_IS_PATH_SEPARATOR)
65 char const *b = strrchr (path, '\\');
70 /* If the last byte of PATH is a slash, decrement SLASH until it's
71 pointing at the leftmost in a sequence of trailing slashes. */
72 if (slash && slash[1] == 0)
74 while (path < slash && ISSLASH (slash[-1]))
81 slash = memrchr (path, '/', slash - path);
82 if (BACKSLASH_IS_PATH_SEPARATOR)
84 char const *b = memrchr (path, '\\', slash - path);
93 /* File is in the current directory. */
99 /* Remove any trailing slashes from the result. */
100 if (BACKSLASH_IS_PATH_SEPARATOR)
102 char const *lim = ((path[0] >= 'A' && path[0] <= 'z'
106 /* If canonicalized "d:/path", leave alone the root case "d:/". */
107 while (slash > lim && ISSLASH (*slash))
112 while (slash > path && ISSLASH (*slash))
116 length = slash - path + 1;
123 /* Return the leading directories part of PATH,
124 allocated with malloc. If out of memory, return 0.
125 Works properly even if there are trailing slashes
126 (by effectively ignoring them). */
129 dir_name (char const *path)
132 size_t length = dir_name_r (path, &result);
133 char *newpath = (char *) malloc (length + 1);
136 strncpy (newpath, result, length);
144 Run the test like this (expect no output):
145 gcc -DHAVE_CONFIG_H -DTEST_DIRNAME -I.. -O -Wall memrchr.c dirname.c
146 sed -n '/^BEGIN-DATA$/,/^END-DATA$/p' dirname.c|grep -v DATA|./a.out
159 # define MAX_BUFF_LEN 1024
166 char buff[MAX_BUFF_LEN + 1];
168 buff[MAX_BUFF_LEN] = 0;
169 while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
171 char path[MAX_BUFF_LEN];
172 char expected_result[MAX_BUFF_LEN];
174 sscanf (buff, "%s %s", path, expected_result);
175 result = dir_name (path);
176 if (strcmp (result, expected_result))
177 printf ("%s: got %s, expected %s\n", path, result, expected_result);