/* Written by Jim Meyering. */ /* Specification. */ #include "filenamecat.h" #include #include #include "xalloc.h" #include "dirname.h" #if !HAVE_MEMPCPY && !defined mempcpy # define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) #endif /* 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 += 0; ((*f) == '/'); f++) continue; return f; } /* Concatenate two file name 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 |abase| in the returned concatenation. However, if |abase| begins with more than one slash, set |*base_in_result| to point to the sole corresponding slash that is copied into the result buffer. Return |NULL| if |malloc| fails. */ char * mfile_name_concat(char const *dir, char const *abase, char **base_in_result) { char const *dirbase = last_component(dir); size_t dirbaselen = base_len(dirbase); size_t dirlen = dirbase - dir + dirbaselen; size_t needs_separator = (dirbaselen && !((dirbase[dirbaselen - 1]) == '/')); char const *base = longest_relative_suffix(abase); size_t baselen = strlen(base); char *p_concat = malloc(dirlen + needs_separator + baselen + 1); char *p; if (p_concat == NULL) return NULL; p = mempcpy (p_concat, dir, dirlen); *p = '/'; p += needs_separator; if (base_in_result) *base_in_result = p - (abase[0] == '/'); p = mempcpy (p, base, baselen); *p = '\0'; return p_concat; } /* Written by Jim Meyering. */ /* Just like |mfile_name_concat| (|filenamecat-lgpl.c|), except, rather than returning |NULL| upon |malloc| failure, here, we report the "memory exhausted" condition and exit. */ char * file_name_concat(char const *dir, char const *abase, char **base_in_result) { char *p = mfile_name_concat(dir, abase, base_in_result); if (p == NULL) xalloc_die(); return p; }