xref: /netbsd-src/external/gpl3/gdb/dist/gnulib/import/dirname-lgpl.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
18dffb485Schristos /* dirname.c -- return all but the last element in a file name
28dffb485Schristos 
3*4b169a6bSchristos    Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2022 Free Software
48dffb485Schristos    Foundation, Inc.
58dffb485Schristos 
6*4b169a6bSchristos    This file is free software: you can redistribute it and/or modify
7*4b169a6bSchristos    it under the terms of the GNU Lesser General Public License as
8*4b169a6bSchristos    published by the Free Software Foundation; either version 2.1 of the
9*4b169a6bSchristos    License, or (at your option) any later version.
108dffb485Schristos 
11*4b169a6bSchristos    This file is distributed in the hope that it will be useful,
128dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
138dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*4b169a6bSchristos    GNU Lesser General Public License for more details.
158dffb485Schristos 
16*4b169a6bSchristos    You should have received a copy of the GNU Lesser General Public License
178dffb485Schristos    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
188dffb485Schristos 
198dffb485Schristos #include <config.h>
208dffb485Schristos 
218dffb485Schristos #include "dirname.h"
228dffb485Schristos 
238dffb485Schristos #include <stdlib.h>
248dffb485Schristos #include <string.h>
258dffb485Schristos 
268dffb485Schristos /* Return the length of the prefix of FILE that will be used by
278dffb485Schristos    dir_name.  If FILE is in the working directory, this returns zero
288dffb485Schristos    even though 'dir_name (FILE)' will return ".".  Works properly even
298dffb485Schristos    if there are trailing slashes (by effectively ignoring them).  */
308dffb485Schristos 
318dffb485Schristos size_t
dir_len(char const * file)328dffb485Schristos dir_len (char const *file)
338dffb485Schristos {
348dffb485Schristos   size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file);
358dffb485Schristos   size_t length;
368dffb485Schristos 
378dffb485Schristos   /* Advance prefix_length beyond important leading slashes.  */
388dffb485Schristos   prefix_length += (prefix_length != 0
398dffb485Schristos                     ? (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
408dffb485Schristos                        && ISSLASH (file[prefix_length]))
418dffb485Schristos                     : (ISSLASH (file[0])
428dffb485Schristos                        ? ((DOUBLE_SLASH_IS_DISTINCT_ROOT
438dffb485Schristos                            && ISSLASH (file[1]) && ! ISSLASH (file[2])
448dffb485Schristos                            ? 2 : 1))
458dffb485Schristos                        : 0));
468dffb485Schristos 
478dffb485Schristos   /* Strip the basename and any redundant slashes before it.  */
488dffb485Schristos   for (length = last_component (file) - file;
498dffb485Schristos        prefix_length < length; length--)
508dffb485Schristos     if (! ISSLASH (file[length - 1]))
518dffb485Schristos       break;
528dffb485Schristos   return length;
538dffb485Schristos }
548dffb485Schristos 
558dffb485Schristos 
568dffb485Schristos /* In general, we can't use the builtin 'dirname' function if available,
578dffb485Schristos    since it has different meanings in different environments.
588dffb485Schristos    In some environments the builtin 'dirname' modifies its argument.
598dffb485Schristos 
608dffb485Schristos    Return the leading directories part of FILE, allocated with malloc.
618dffb485Schristos    Works properly even if there are trailing slashes (by effectively
628dffb485Schristos    ignoring them).  Return NULL on failure.
638dffb485Schristos 
648dffb485Schristos    If lstat (FILE) would succeed, then { chdir (dir_name (FILE));
658dffb485Schristos    lstat (base_name (FILE)); } will access the same file.  Likewise,
668dffb485Schristos    if the sequence { chdir (dir_name (FILE));
678dffb485Schristos    rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE
688dffb485Schristos    to "foo" in the same directory FILE was in.  */
698dffb485Schristos 
708dffb485Schristos char *
mdir_name(char const * file)718dffb485Schristos mdir_name (char const *file)
728dffb485Schristos {
738dffb485Schristos   size_t length = dir_len (file);
748dffb485Schristos   bool append_dot = (length == 0
758dffb485Schristos                      || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
768dffb485Schristos                          && length == FILE_SYSTEM_PREFIX_LEN (file)
778dffb485Schristos                          && file[2] != '\0' && ! ISSLASH (file[2])));
788dffb485Schristos   char *dir = malloc (length + append_dot + 1);
798dffb485Schristos   if (!dir)
808dffb485Schristos     return NULL;
818dffb485Schristos   memcpy (dir, file, length);
828dffb485Schristos   if (append_dot)
838dffb485Schristos     dir[length++] = '.';
848dffb485Schristos   dir[length] = '\0';
858dffb485Schristos   return dir;
868dffb485Schristos }
87