Blame gnulib/lib/dirname-lgpl.c

Packit Service a2ae7a
/* dirname.c -- return all but the last element in a file name
Packit Service a2ae7a
Packit Service a2ae7a
   Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2019 Free Software
Packit Service a2ae7a
   Foundation, Inc.
Packit Service a2ae7a
Packit Service a2ae7a
   This program is free software: you can redistribute it and/or modify
Packit Service a2ae7a
   it under the terms of the GNU Lesser General Public License as published by
Packit Service a2ae7a
   the Free Software Foundation; either version 2.1 of the License, or
Packit Service a2ae7a
   (at your option) any later version.
Packit Service a2ae7a
Packit Service a2ae7a
   This program is distributed in the hope that it will be useful,
Packit Service a2ae7a
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2ae7a
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2ae7a
   GNU Lesser General Public License for more details.
Packit Service a2ae7a
Packit Service a2ae7a
   You should have received a copy of the GNU Lesser General Public License
Packit Service a2ae7a
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2ae7a
Packit Service a2ae7a
#include <config.h>
Packit Service a2ae7a
Packit Service a2ae7a
#include "dirname.h"
Packit Service a2ae7a
Packit Service a2ae7a
#include <stdlib.h>
Packit Service a2ae7a
#include <string.h>
Packit Service a2ae7a
Packit Service a2ae7a
/* Return the length of the prefix of FILE that will be used by
Packit Service a2ae7a
   dir_name.  If FILE is in the working directory, this returns zero
Packit Service a2ae7a
   even though 'dir_name (FILE)' will return ".".  Works properly even
Packit Service a2ae7a
   if there are trailing slashes (by effectively ignoring them).  */
Packit Service a2ae7a
Packit Service a2ae7a
size_t
Packit Service a2ae7a
dir_len (char const *file)
Packit Service a2ae7a
{
Packit Service a2ae7a
  size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file);
Packit Service a2ae7a
  size_t length;
Packit Service a2ae7a
Packit Service a2ae7a
  /* Advance prefix_length beyond important leading slashes.  */
Packit Service a2ae7a
  prefix_length += (prefix_length != 0
Packit Service a2ae7a
                    ? (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
Packit Service a2ae7a
                       && ISSLASH (file[prefix_length]))
Packit Service a2ae7a
                    : (ISSLASH (file[0])
Packit Service a2ae7a
                       ? ((DOUBLE_SLASH_IS_DISTINCT_ROOT
Packit Service a2ae7a
                           && ISSLASH (file[1]) && ! ISSLASH (file[2])
Packit Service a2ae7a
                           ? 2 : 1))
Packit Service a2ae7a
                       : 0));
Packit Service a2ae7a
Packit Service a2ae7a
  /* Strip the basename and any redundant slashes before it.  */
Packit Service a2ae7a
  for (length = last_component (file) - file;
Packit Service a2ae7a
       prefix_length < length; length--)
Packit Service a2ae7a
    if (! ISSLASH (file[length - 1]))
Packit Service a2ae7a
      break;
Packit Service a2ae7a
  return length;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
Packit Service a2ae7a
/* In general, we can't use the builtin 'dirname' function if available,
Packit Service a2ae7a
   since it has different meanings in different environments.
Packit Service a2ae7a
   In some environments the builtin 'dirname' modifies its argument.
Packit Service a2ae7a
Packit Service a2ae7a
   Return the leading directories part of FILE, allocated with malloc.
Packit Service a2ae7a
   Works properly even if there are trailing slashes (by effectively
Packit Service a2ae7a
   ignoring them).  Return NULL on failure.
Packit Service a2ae7a
Packit Service a2ae7a
   If lstat (FILE) would succeed, then { chdir (dir_name (FILE));
Packit Service a2ae7a
   lstat (base_name (FILE)); } will access the same file.  Likewise,
Packit Service a2ae7a
   if the sequence { chdir (dir_name (FILE));
Packit Service a2ae7a
   rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE
Packit Service a2ae7a
   to "foo" in the same directory FILE was in.  */
Packit Service a2ae7a
Packit Service a2ae7a
char *
Packit Service a2ae7a
mdir_name (char const *file)
Packit Service a2ae7a
{
Packit Service a2ae7a
  size_t length = dir_len (file);
Packit Service a2ae7a
  bool append_dot = (length == 0
Packit Service a2ae7a
                     || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
Packit Service a2ae7a
                         && length == FILE_SYSTEM_PREFIX_LEN (file)
Packit Service a2ae7a
                         && file[2] != '\0' && ! ISSLASH (file[2])));
Packit Service a2ae7a
  char *dir = malloc (length + append_dot + 1);
Packit Service a2ae7a
  if (!dir)
Packit Service a2ae7a
    return NULL;
Packit Service a2ae7a
  memcpy (dir, file, length);
Packit Service a2ae7a
  if (append_dot)
Packit Service a2ae7a
    dir[length++] = '.';
Packit Service a2ae7a
  dir[length] = '\0';
Packit Service a2ae7a
  return dir;
Packit Service a2ae7a
}