Blame src/gl/dirname-lgpl.c

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