X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fpath-concat.c;h=02e92af0172cd5ebed892aaac1115176a6835a97;hb=3bd23802ad65a4379e0c97d736dc6c2ab2d37f1d;hp=622d5d73b6aca55086d665c076328e1e16035669;hpb=e6d6498c6caf7642510024fefbf64e9d477b19cf;p=gnulib.git diff --git a/lib/path-concat.c b/lib/path-concat.c index 622d5d73b..02e92af01 100644 --- a/lib/path-concat.c +++ b/lib/path-concat.c @@ -1,5 +1,7 @@ /* path-concat.c -- concatenate two arbitrary pathnames - Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 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 @@ -21,107 +23,65 @@ # include #endif -#ifndef HAVE_MEMPCPY -# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) -#endif +/* Specification. */ +#include "path-concat.h" -#include - -#if HAVE_STRING_H -# if !STDC_HEADERS && HAVE_MEMORY_H -# include -# endif -# include -#else -# if HAVE_STRINGS_H -# include -# endif -#endif -#if HAVE_STDLIB_H -# include -#endif -#if HAVE_UNISTD_H -# include -#endif +#include -#ifndef HAVE_DECL_MALLOC -"this configure-time declaration test was not run" -#endif -#if !HAVE_DECL_MALLOC -char *malloc (); -#endif +#include "dirname.h" +#include "xalloc.h" -#ifndef strdup -char *strdup (); +#if ! HAVE_MEMPCPY && ! defined mempcpy +# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) #endif -#include "dirname.h" -#include "xalloc.h" -#include "path-concat.h" +/* Return the longest suffix of F that is a relative file name. + If it has no such suffix, return the empty string. */ + +static char const * +longest_relative_suffix (char const *f) +{ + for (f += FILE_SYSTEM_PREFIX_LEN (f); ISSLASH (*f); f++) + continue; + return f; +} -/* Concatenate two pathname components, DIR and BASE, in - newly-allocated storage and return the result. Return 0 if out of - memory. Add a slash between DIR and BASE in the result if neither - would contribute one. If each would contribute at least one, elide - one from the end of DIR. Otherwise, simply concatenate DIR and - BASE. In any case, if BASE_IN_RESULT is non-NULL, set +/* Concatenate two pathname components, DIR and ABASE, in + newly-allocated storage and return the result. + The resulting file name F is such that the commands "ls F" and "(cd + DIR; ls BASE)" refer to the same file, where BASE is ABASE with any + file system prefixes and leading separators removed. + Arrange for a directory separator if necessary between DIR and BASE + in the result, removing any redundant separators. + In any case, if BASE_IN_RESULT is non-NULL, set *BASE_IN_RESULT to point to the copy of BASE in the returned concatenation. - DIR may be NULL, BASE must not be. - - Return NULL if memory is exhausted. */ + Report an error if memory is exhausted. */ char * -path_concat (const char *dir, const char *base, char **base_in_result) +path_concat (char const *dir, char const *abase, char **base_in_result) { + char const *dirbase = base_name (dir); + size_t dirbaselen = base_len (dirbase); + size_t dirlen = dirbase - dir + dirbaselen; + size_t needs_separator = (dirbaselen && ! ISSLASH (dirbase[dirbaselen - 1])); + + char const *base = longest_relative_suffix (abase); + size_t baselen = strlen (base); + + char *p_concat = xmalloc (dirlen + needs_separator + baselen + 1); char *p; - char *p_concat; - size_t baselen; - size_t dirlen; - - if (!dir) - { - p_concat = strdup (base); - if (base_in_result) - *base_in_result = p_concat; - return p_concat; - } - - /* DIR is not empty. */ - baselen = base_len (base); - dirlen = strlen (dir); - - p_concat = malloc (dirlen + baselen + 2); - if (!p_concat) - return 0; p = mempcpy (p_concat, dir, dirlen); - - if (FILESYSTEM_PREFIX_LEN (dir) < dirlen) - { - if (ISSLASH (*(p - 1)) && ISSLASH (*base)) - --p; - else if (!ISSLASH (*(p - 1)) && !ISSLASH (*base)) - *p++ = DIRECTORY_SEPARATOR; - } + *p = DIRECTORY_SEPARATOR; + p += needs_separator; if (base_in_result) *base_in_result = p; - memcpy (p, base, baselen); - p[baselen] = '\0'; + p = mempcpy (p, base, baselen); + *p = '\0'; return p_concat; } - -/* Same, but die when memory is exhausted. */ - -char * -xpath_concat (const char *dir, const char *base, char **base_in_result) -{ - char *res = path_concat (dir, base, base_in_result); - if (res) - return res; - xalloc_die (); -}