Home | History | Annotate | Download | only in lib
      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 3 of the License, or
      9    (at your option) 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, see <http://www.gnu.org/licenses/>.  */
     18 
     19 #include <config.h>
     20 
     21 #include "dirname.h"
     22 
     23 #include <string.h>
     24 #include "xalloc.h"
     25 #include "xstrndup.h"
     26 
     27 /* Return the address of the last file name component of NAME.  If
     28    NAME has no relative file name components because it is a file
     29    system root, return the empty string.  */
     30 
     31 char *
     32 last_component (char const *name)
     33 {
     34   char const *base = name + FILE_SYSTEM_PREFIX_LEN (name);
     35   char const *p;
     36   bool saw_slash = false;
     37 
     38   while (ISSLASH (*base))
     39     base++;
     40 
     41   for (p = base; *p; p++)
     42     {
     43       if (ISSLASH (*p))
     44 	saw_slash = true;
     45       else if (saw_slash)
     46 	{
     47 	  base = p;
     48 	  saw_slash = false;
     49 	}
     50     }
     51 
     52   return (char *) base;
     53 }
     54 
     55 
     56 /* In general, we can't use the builtin `basename' function if available,
     57    since it has different meanings in different environments.
     58    In some environments the builtin `basename' modifies its argument.
     59 
     60    Return the last file name component of NAME, allocated with
     61    xmalloc.  On systems with drive letters, a leading "./"
     62    distinguishes relative names that would otherwise look like a drive
     63    letter.  Unlike POSIX basename(), NAME cannot be NULL,
     64    base_name("") returns "", and the first trailing slash is not
     65    stripped.
     66 
     67    If lstat (NAME) would succeed, then { chdir (dir_name (NAME));
     68    lstat (base_name (NAME)); } will access the same file.  Likewise,
     69    if the sequence { chdir (dir_name (NAME));
     70    rename (base_name (NAME), "foo"); } succeeds, you have renamed NAME
     71    to "foo" in the same directory NAME was in.  */
     72 
     73 char *
     74 base_name (char const *name)
     75 {
     76   char const *base = last_component (name);
     77   size_t length;
     78 
     79   /* If there is no last component, then name is a file system root or the
     80      empty string.  */
     81   if (! *base)
     82     return xstrndup (name, base_len (name));
     83 
     84   /* Collapse a sequence of trailing slashes into one.  */
     85   length = base_len (base);
     86   if (ISSLASH (base[length]))
     87     length++;
     88 
     89   /* On systems with drive letters, `a/b:c' must return `./b:c' rather
     90      than `b:c' to avoid confusion with a drive letter.  On systems
     91      with pure POSIX semantics, this is not an issue.  */
     92   if (FILE_SYSTEM_PREFIX_LEN (base))
     93     {
     94       char *p = xmalloc (length + 3);
     95       p[0] = '.';
     96       p[1] = '/';
     97       memcpy (p + 2, base, length);
     98       p[length + 2] = '\0';
     99       return p;
    100     }
    101 
    102   /* Finally, copy the basename.  */
    103   return xstrndup (base, length);
    104 }
    105 
    106 /* Return the length of the basename NAME.  Typically NAME is the
    107    value returned by base_name or last_component.  Act like strlen
    108    (NAME), except omit all trailing slashes.  */
    109 
    110 size_t
    111 base_len (char const *name)
    112 {
    113   size_t len;
    114   size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
    115 
    116   for (len = strlen (name);  1 < len && ISSLASH (name[len - 1]);  len--)
    117     continue;
    118 
    119   if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1
    120       && ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2])
    121     return 2;
    122 
    123   if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len
    124       && len == prefix_len && ISSLASH (name[prefix_len]))
    125     return prefix_len + 1;
    126 
    127   return len;
    128 }
    129