1 /* path-concat.c -- concatenate two arbitrary pathnames
3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
4 Software Foundation, Inc.
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 2, or (at your option)
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 /* Written by Jim Meyering. */
27 #include "path-concat.h"
34 #if ! HAVE_MEMPCPY && ! defined mempcpy
35 # define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
38 /* Return the longest suffix of F that is a relative file name.
39 If it has no such suffix, return the empty string. */
42 longest_relative_suffix (char const *f)
44 for (f += FILE_SYSTEM_PREFIX_LEN (f); ISSLASH (*f); f++)
49 /* Concatenate two pathname components, DIR and ABASE, in
50 newly-allocated storage and return the result.
51 The resulting file name F is such that the commands "ls F" and "(cd
52 DIR; ls BASE)" refer to the same file, where BASE is ABASE with any
53 file system prefixes and leading separators removed.
54 Arrange for a directory separator if necessary between DIR and BASE
55 in the result, removing any redundant separators.
56 In any case, if BASE_IN_RESULT is non-NULL, set
57 *BASE_IN_RESULT to point to the copy of BASE in the returned
60 Report an error if memory is exhausted. */
63 path_concat (char const *dir, char const *abase, char **base_in_result)
65 char const *dirbase = base_name (dir);
66 size_t dirbaselen = base_len (dirbase);
67 size_t dirlen = dirbase - dir + dirbaselen;
68 size_t needs_separator = (dirbaselen && ! ISSLASH (dirbase[dirbaselen - 1]));
70 char const *base = longest_relative_suffix (abase);
71 size_t baselen = strlen (base);
73 char *p_concat = xmalloc (dirlen + needs_separator + baselen + 1);
76 p = mempcpy (p_concat, dir, dirlen);
77 *p = DIRECTORY_SEPARATOR;
83 p = mempcpy (p, base, baselen);