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 32char * 33last_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 74char * 75base_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 111size_t 112base_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} 130