
1: /* basename.c -- return the last element in a file name 2: 3: Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 Free 4: Software Foundation, Inc. 5: 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 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: This program is distributed in the hope that it will be useful, 12: but WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14: GNU General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with this program; if not, write to the Free Software Foundation, 18: Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 19: 20: #include <config.h> 21: 22: #include "dirname.h" 23: 24: #include <string.h> 25: #include "xalloc.h" 26: #include "xstrndup.h" 27: 28: /* Return the address of the last file name component of NAME. If 29: NAME has no relative file name components because it is a file 30: system root, return the empty string. */ 31: 32: char * 33: last_component (char const *name) 34: { 35: char const *base = name + FILE_SYSTEM_PREFIX_LEN (name); 36: char const *p; 37: bool saw_slash = false; 38: 39: while (ISSLASH (*base)) 40: base++; 41: 42: for (p = base; *p; p++) 43: { 44: if (ISSLASH (*p)) 45: saw_slash = true; 46: else if (saw_slash) 47: { 48: base = p; 49: saw_slash = false; 50: } 51: } 52: 53: return (char *) base; 54: } 55: 56: 57: /* In general, we can't use the builtin `basename' function if available, 58: since it has different meanings in different environments. 59: In some environments the builtin `basename' modifies its argument. 60: 61: Return the last file name component of NAME, allocated with 62: xmalloc. On systems with drive letters, a leading "./" 63: distinguishes relative names that would otherwise look like a drive 64: letter. Unlike POSIX basename(), NAME cannot be NULL, 65: base_name("") returns "", and the first trailing slash is not 66: stripped. 67: 68: If lstat (NAME) would succeed, then { chdir (dir_name (NAME)); 69: lstat (base_name (NAME)); } will access the same file. Likewise, 70: if the sequence { chdir (dir_name (NAME)); 71: rename (base_name (NAME), "foo"); } succeeds, you have renamed NAME 72: to "foo" in the same directory NAME was in. */ 73: 74: char * 75: base_name (char const *name) 76: { 77: char const *base = last_component (name); 78: size_t length; 79: 80: /* If there is no last component, then name is a file system root or the 81: empty string. */ 82: if (! *base) 83: return xstrndup (name, base_len (name)); 84: 85: /* Collapse a sequence of trailing slashes into one. */ 86: length = base_len (base); 87: if (ISSLASH (base[length])) 88: length++; 89: 90: /* On systems with drive letters, `a/b:c' must return `./b:c' rather 91: than `b:c' to avoid confusion with a drive letter. On systems 92: with pure POSIX semantics, this is not an issue. */ 93: if (FILE_SYSTEM_PREFIX_LEN (base)) 94: { 95: char *p = xmalloc (length + 3); 96: p[0] = '.'; 97: p[1] = '/'; 98: memcpy (p + 2, base, length); 99: p[length + 2] = '\0'; 100: return p; 101: } 102: 103: /* Finally, copy the basename. */ 104: return xstrndup (base, length); 105: } 106: 107: /* Return the length of the basename NAME. Typically NAME is the 108: value returned by base_name or last_component. Act like strlen 109: (NAME), except omit all trailing slashes. */ 110: 111: size_t 112: base_len (char const *name) 113: { 114: size_t len; 115: size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name); 116: 117: for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--) 118: continue; 119: 120: if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1 121: && ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2]) 122: return 2; 123: 124: if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len 125: && len == prefix_len && ISSLASH (name[prefix_len])) 126: return prefix_len + 1; 127: 128: return len; 129: }