1*86d7f5d3SJohn Marino /* dirname.c -- return all but the last element in a file name
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino Copyright (C) 1990, 1998, 2000, 2001, 2003, 2004, 2005 Free Software
4*86d7f5d3SJohn Marino Foundation, Inc.
5*86d7f5d3SJohn Marino
6*86d7f5d3SJohn Marino This program is free software; you can redistribute it and/or modify
7*86d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
8*86d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
9*86d7f5d3SJohn Marino any later version.
10*86d7f5d3SJohn Marino
11*86d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
12*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
13*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*86d7f5d3SJohn Marino GNU General Public License for more details.
15*86d7f5d3SJohn Marino
16*86d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
17*86d7f5d3SJohn Marino along with this program; if not, write to the Free Software Foundation,
18*86d7f5d3SJohn Marino Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19*86d7f5d3SJohn Marino
20*86d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
21*86d7f5d3SJohn Marino # include <config.h>
22*86d7f5d3SJohn Marino #endif
23*86d7f5d3SJohn Marino
24*86d7f5d3SJohn Marino #include "dirname.h"
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino #include <string.h>
27*86d7f5d3SJohn Marino #include "xalloc.h"
28*86d7f5d3SJohn Marino
29*86d7f5d3SJohn Marino /* Return the length of `dirname (FILE)', or zero if FILE is
30*86d7f5d3SJohn Marino in the working directory. Works properly even if
31*86d7f5d3SJohn Marino there are trailing slashes (by effectively ignoring them). */
32*86d7f5d3SJohn Marino size_t
dir_len(char const * file)33*86d7f5d3SJohn Marino dir_len (char const *file)
34*86d7f5d3SJohn Marino {
35*86d7f5d3SJohn Marino size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file);
36*86d7f5d3SJohn Marino size_t length;
37*86d7f5d3SJohn Marino
38*86d7f5d3SJohn Marino /* Strip the basename and any redundant slashes before it. */
39*86d7f5d3SJohn Marino for (length = base_name (file) - file; prefix_length < length; length--)
40*86d7f5d3SJohn Marino if (! ISSLASH (file[length - 1]))
41*86d7f5d3SJohn Marino return length;
42*86d7f5d3SJohn Marino
43*86d7f5d3SJohn Marino /* But don't strip the only slash from "/". */
44*86d7f5d3SJohn Marino return prefix_length + ISSLASH (file[prefix_length]);
45*86d7f5d3SJohn Marino }
46*86d7f5d3SJohn Marino
47*86d7f5d3SJohn Marino /* Return the leading directories part of FILE,
48*86d7f5d3SJohn Marino allocated with xmalloc.
49*86d7f5d3SJohn Marino Works properly even if there are trailing slashes
50*86d7f5d3SJohn Marino (by effectively ignoring them). */
51*86d7f5d3SJohn Marino
52*86d7f5d3SJohn Marino char *
dir_name(char const * file)53*86d7f5d3SJohn Marino dir_name (char const *file)
54*86d7f5d3SJohn Marino {
55*86d7f5d3SJohn Marino size_t length = dir_len (file);
56*86d7f5d3SJohn Marino bool append_dot = (length == FILE_SYSTEM_PREFIX_LEN (file));
57*86d7f5d3SJohn Marino char *dir = xmalloc (length + append_dot + 1);
58*86d7f5d3SJohn Marino memcpy (dir, file, length);
59*86d7f5d3SJohn Marino if (append_dot)
60*86d7f5d3SJohn Marino dir[length++] = '.';
61*86d7f5d3SJohn Marino dir[length] = 0;
62*86d7f5d3SJohn Marino return dir;
63*86d7f5d3SJohn Marino }
64*86d7f5d3SJohn Marino
65*86d7f5d3SJohn Marino #ifdef TEST_DIRNAME
66*86d7f5d3SJohn Marino /*
67*86d7f5d3SJohn Marino
68*86d7f5d3SJohn Marino Run the test like this (expect no output):
69*86d7f5d3SJohn Marino gcc -DHAVE_CONFIG_H -DTEST_DIRNAME -I.. -O -Wall \
70*86d7f5d3SJohn Marino basename.c dirname.c xmalloc.c error.c
71*86d7f5d3SJohn Marino sed -n '/^BEGIN-DATA$/,/^END-DATA$/p' dirname.c|grep -v DATA|./a.out
72*86d7f5d3SJohn Marino
73*86d7f5d3SJohn Marino If it's been built on a DOS or Windows platforms, run another test like
74*86d7f5d3SJohn Marino this (again, expect no output):
75*86d7f5d3SJohn Marino sed -n '/^BEGIN-DOS-DATA$/,/^END-DOS-DATA$/p' dirname.c|grep -v DATA|./a.out
76*86d7f5d3SJohn Marino
77*86d7f5d3SJohn Marino BEGIN-DATA
78*86d7f5d3SJohn Marino foo//// .
79*86d7f5d3SJohn Marino bar/foo//// bar
80*86d7f5d3SJohn Marino foo/ .
81*86d7f5d3SJohn Marino / /
82*86d7f5d3SJohn Marino . .
83*86d7f5d3SJohn Marino a .
84*86d7f5d3SJohn Marino END-DATA
85*86d7f5d3SJohn Marino
86*86d7f5d3SJohn Marino BEGIN-DOS-DATA
87*86d7f5d3SJohn Marino c:///// c:/
88*86d7f5d3SJohn Marino c:/ c:/
89*86d7f5d3SJohn Marino c:/. c:/
90*86d7f5d3SJohn Marino c:foo c:.
91*86d7f5d3SJohn Marino c:foo/bar c:foo
92*86d7f5d3SJohn Marino END-DOS-DATA
93*86d7f5d3SJohn Marino
94*86d7f5d3SJohn Marino */
95*86d7f5d3SJohn Marino
96*86d7f5d3SJohn Marino # define MAX_BUFF_LEN 1024
97*86d7f5d3SJohn Marino # include <stdio.h>
98*86d7f5d3SJohn Marino
99*86d7f5d3SJohn Marino char *program_name;
100*86d7f5d3SJohn Marino
101*86d7f5d3SJohn Marino int
main(int argc,char * argv[])102*86d7f5d3SJohn Marino main (int argc, char *argv[])
103*86d7f5d3SJohn Marino {
104*86d7f5d3SJohn Marino char buff[MAX_BUFF_LEN + 1];
105*86d7f5d3SJohn Marino
106*86d7f5d3SJohn Marino program_name = argv[0];
107*86d7f5d3SJohn Marino
108*86d7f5d3SJohn Marino buff[MAX_BUFF_LEN] = 0;
109*86d7f5d3SJohn Marino while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
110*86d7f5d3SJohn Marino {
111*86d7f5d3SJohn Marino char file[MAX_BUFF_LEN];
112*86d7f5d3SJohn Marino char expected_result[MAX_BUFF_LEN];
113*86d7f5d3SJohn Marino char const *result;
114*86d7f5d3SJohn Marino sscanf (buff, "%s %s", file, expected_result);
115*86d7f5d3SJohn Marino result = dir_name (file);
116*86d7f5d3SJohn Marino if (strcmp (result, expected_result))
117*86d7f5d3SJohn Marino printf ("%s: got %s, expected %s\n", file, result, expected_result);
118*86d7f5d3SJohn Marino }
119*86d7f5d3SJohn Marino return 0;
120*86d7f5d3SJohn Marino }
121*86d7f5d3SJohn Marino #endif
122