X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fpath-concat.c;h=02e92af0172cd5ebed892aaac1115176a6835a97;hb=ec354b13bec21d8510dd60e1e129cc194809248b;hp=86579b7369fd7cce6b446e6920db45dabf10140a;hpb=cf42d3e5e80be6bf7093a3ca9be0d04033eaf527;p=gnulib.git diff --git a/lib/path-concat.c b/lib/path-concat.c index 86579b736..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 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,49 +23,65 @@ # include #endif -#ifndef HAVE_MEMPCPY +/* Specification. */ +#include "path-concat.h" + +#include + +#include "dirname.h" +#include "xalloc.h" + +#if ! HAVE_MEMPCPY && ! defined mempcpy # define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) #endif -#include -#if HAVE_STRING_H -# include -#endif -#include +/* Return the longest suffix of F that is a relative file name. + If it has no such suffix, return the empty string. */ -char *malloc (); +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 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. -/* 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 *BASE_IN_RESULT to point to the copy of - BASE in the returned concatenation. */ + 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 *p; - char *p_concat; - size_t base_len = strlen (base); - size_t dir_len = strlen (dir); + 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])); - p_concat = malloc (dir_len + base_len + 2); - if (!p_concat) - return 0; + char const *base = longest_relative_suffix (abase); + size_t baselen = strlen (base); - p = mempcpy (p_concat, dir, dir_len); + char *p_concat = xmalloc (dirlen + needs_separator + baselen + 1); + char *p; - if (*(p - 1) == '/' && *base == '/') - --p; - else if (*(p - 1) != '/' && *base != '/') - *p++ = '/'; + 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; }