X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fpath-concat.c;h=02e92af0172cd5ebed892aaac1115176a6835a97;hb=ec354b13bec21d8510dd60e1e129cc194809248b;hp=dfc54023817ae6f705bdb488a3c62ea909a072a6;hpb=45e296a3828e8c912d496030c251092c700bbbcb;p=gnulib.git diff --git a/lib/path-concat.c b/lib/path-concat.c index dfc540238..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 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,100 +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 -# include -#endif -#include +#include -#ifndef HAVE_DECL_MALLOC -"this configure-time declaration test was not run" -#endif -#if !HAVE_DECL_MALLOC -char *malloc (); -#endif - -#ifndef strdup -char *strdup (); -#endif +#include "dirname.h" +#include "xalloc.h" -#ifndef DIRECTORY_SEPARATOR -# define DIRECTORY_SEPARATOR '/' +#if ! HAVE_MEMPCPY && ! defined mempcpy +# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) #endif -#ifndef ISSLASH -# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) -#endif +/* Return the longest suffix of F that is a relative file name. + If it has no such suffix, return the empty string. */ -#include "xalloc.h" -#include "path-concat.h" +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 base_len; - size_t dir_len; - - if (!dir) - { - p_concat = strdup (base); - if (base_in_result) - *base_in_result = p_concat; - return p_concat; - } - - /* DIR is not empty. */ - base_len = strlen (base); - dir_len = strlen (dir); - - p_concat = malloc (dir_len + base_len + 2); - if (!p_concat) - return 0; - - p = mempcpy (p_concat, dir, dir_len); - - if (dir_len > 0) - { - if (ISSLASH (*(p - 1)) && ISSLASH(*base)) - --p; - else if (!ISSLASH (*(p - 1)) && !ISSLASH(*base)) - *p++ = DIRECTORY_SEPARATOR; - } + + p = mempcpy (p_concat, dir, dirlen); + *p = DIRECTORY_SEPARATOR; + p += needs_separator; if (base_in_result) *base_in_result = p; - memcpy (p, base, base_len + 1); + 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 (); -}