comparison lib/basename.c @ 6912:314715e0260d

Merge from coreutils.
author Paul Eggert <eggert@cs.ucla.edu>
date Mon, 03 Jul 2006 08:32:46 +0000
parents 96c32553b4c6
children 8a1a9361108c
comparison
equal deleted inserted replaced
6911:8e002ebcf4b6 6912:314715e0260d
1 /* basename.c -- return the last element in a file name 1 /* basename.c -- return the last element in a file name
2 2
3 Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free 3 Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 Free
4 Software Foundation, Inc. 4 Software Foundation, Inc.
5 5
6 This program is free software; you can redistribute it and/or modify 6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by 7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option) 8 the Free Software Foundation; either version 2, or (at your option)
20 #ifdef HAVE_CONFIG_H 20 #ifdef HAVE_CONFIG_H
21 # include <config.h> 21 # include <config.h>
22 #endif 22 #endif
23 23
24 #include "dirname.h" 24 #include "dirname.h"
25
25 #include <string.h> 26 #include <string.h>
27 #include "xalloc.h"
28 #include "xstrndup.h"
26 29
27 /* In general, we can't use the builtin `basename' function if available, 30 /* Return the address of the last file name component of NAME. If
28 since it has different meanings in different environments. 31 NAME has no relative file name components because it is a file
29 In some environments the builtin `basename' modifies its argument. 32 system root, return the empty string. */
30
31 Return the address of the last file name component of NAME. If
32 NAME has no file name components because it is all slashes, return
33 NAME if it is empty, the address of its last slash otherwise. */
34 33
35 char * 34 char *
36 base_name (char const *name) 35 last_component (char const *name)
37 { 36 {
38 char const *base = name + FILE_SYSTEM_PREFIX_LEN (name); 37 char const *base = name + FILE_SYSTEM_PREFIX_LEN (name);
39 char const *p; 38 char const *p;
39 bool saw_slash = false;
40
41 while (ISSLASH (*base))
42 base++;
40 43
41 for (p = base; *p; p++) 44 for (p = base; *p; p++)
42 { 45 {
43 if (ISSLASH (*p)) 46 if (ISSLASH (*p))
47 saw_slash = true;
48 else if (saw_slash)
44 { 49 {
45 /* Treat multiple adjacent slashes like a single slash. */
46 do p++;
47 while (ISSLASH (*p));
48
49 /* If the file name ends in slash, use the trailing slash as
50 the basename if no non-slashes have been found. */
51 if (! *p)
52 {
53 if (ISSLASH (*base))
54 base = p - 1;
55 break;
56 }
57
58 /* *P is a non-slash preceded by a slash. */
59 base = p; 50 base = p;
51 saw_slash = false;
60 } 52 }
61 } 53 }
62 54
63 return (char *) base; 55 return (char *) base;
64 } 56 }
65 57
66 /* Return the length of of the basename NAME. Typically NAME is the 58
67 value returned by base_name. Act like strlen (NAME), except omit 59 /* In general, we can't use the builtin `basename' function if available,
68 redundant trailing slashes. */ 60 since it has different meanings in different environments.
61 In some environments the builtin `basename' modifies its argument.
62
63 Return the last file name component of NAME, allocated with
64 xmalloc. On systems with drive letters, a leading "./"
65 distinguishes relative names that would otherwise look like a drive
66 letter. Unlike POSIX basename(), NAME cannot be NULL,
67 base_name("") returns "", and the first trailing slash is not
68 stripped.
69
70 If lstat (NAME) would succeed, then { chdir (dir_name (NAME));
71 lstat (base_name (NAME)); } will access the same file. Likewise,
72 if the sequence { chdir (dir_name (NAME));
73 rename (base_name (NAME), "foo"); } succeeds, you have renamed NAME
74 to "foo" in the same directory NAME was in. */
75
76 char *
77 base_name (char const *name)
78 {
79 char const *base = last_component (name);
80 size_t length;
81
82 /* If there is no last component, then name is a file system root or the
83 empty string. */
84 if (! *base)
85 return xstrndup (name, base_len (name));
86
87 /* Collapse a sequence of trailing slashes into one. */
88 length = base_len (base);
89 if (ISSLASH (base[length]))
90 length++;
91
92 /* On systems with drive letters, `a/b:c' must return `./b:c' rather
93 than `b:c' to avoid confusion with a drive letter. On systems
94 with pure POSIX semantics, this is not an issue. */
95 if (FILE_SYSTEM_PREFIX_LEN (base))
96 {
97 char *p = xmalloc (length + 3);
98 p[0] = '.';
99 p[1] = '/';
100 memcpy (p + 2, base, length);
101 p[length + 2] = '\0';
102 return p;
103 }
104
105 /* Finally, copy the basename. */
106 return xstrndup (base, length);
107 }
108
109 /* Return the length of the basename NAME. Typically NAME is the
110 value returned by base_name or last_component. Act like strlen
111 (NAME), except omit all trailing slashes. */
69 112
70 size_t 113 size_t
71 base_len (char const *name) 114 base_len (char const *name)
72 { 115 {
73 size_t len; 116 size_t len;
117 size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
74 118
75 for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--) 119 for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--)
76 continue; 120 continue;
77 121
122 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1
123 && ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2])
124 return 2;
125
126 if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len
127 && len == prefix_len && ISSLASH (name[prefix_len]))
128 return prefix_len + 1;
129
78 return len; 130 return len;
79 } 131 }