summaryrefslogtreecommitdiffstats
path: root/lib/basename.c
blob: c5a6bdc9d5d1274664f0a90d8043b063a7d216d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/* basename.c -- return the last element in a file name

   Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2024 Free Software
   Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */

#include <config.h>

#include "dirname.h"

#include <string.h>
#include "xalloc.h"

char *
base_name (char const *name)
{
  char const *base = last_component (name);
  idx_t length;
  int dotslash_len;
  if (*base)
    {
      length = base_len (base);

      /* Collapse a sequence of trailing slashes into one.  */
      length += ISSLASH (base[length]);

      /* On systems with drive letters, "a/b:c" must return "./b:c" rather
         than "b:c" to avoid confusion with a drive letter.  On systems
         with pure POSIX semantics, this is not an issue.  */
      dotslash_len = FILE_SYSTEM_PREFIX_LEN (base) != 0 ? 2 : 0;
    }
  else
    {
      /* There is no last component, so NAME is a file system root or
         the empty string.  */
      base = name;
      length = base_len (base);
      dotslash_len = 0;
    }

  char *p = ximalloc (dotslash_len + length + 1);
  if (dotslash_len)
    {
      p[0] = '.';
      p[1] = '/';
    }

  /* Finally, copy the basename.  */
  memcpy (p + dotslash_len, base, length);
  p[dotslash_len + length] = '\0';
  return p;
}