vtools_genesis 1
vtools_genesis 2
vtools_genesis 3
vtools_genesis 4
vtools_genesis 5 #include "filenamecat.h"
vtools_genesis 6
vtools_genesis 7 #include <stdlib.h>
vtools_genesis 8 #include <string.h>
vtools_genesis 9 #include "xalloc.h"
vtools_genesis 10
vtools_genesis 11 #include "dirname.h"
vtools_genesis 12
vtools_genesis 13 #if !HAVE_MEMPCPY && !defined mempcpy
vtools_genesis 14 # define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
vtools_genesis 15 #endif
vtools_genesis 16
vtools_genesis 17
vtools_genesis 18 it has no such suffix, return the empty string. */
vtools_genesis 19
vtools_genesis 20 static char const *
vtools_genesis 21 longest_relative_suffix(char const *f) {
vtools_genesis 22 for (f += 0; ((*f) == '/'); f++)
vtools_genesis 23 continue;
vtools_genesis 24 return f;
vtools_genesis 25 }
vtools_genesis 26
vtools_genesis 27
vtools_genesis 28 newly-allocated storage and return the result. The resulting file
vtools_genesis 29 name |f| is such that the commands |ls F| and |(cd DIR; ls BASE)|
vtools_genesis 30 refer to the same file, where |base| is |abase| with any file
vtools_genesis 31 system prefixes and leading separators removed. Arrange for a
vtools_genesis 32 directory separator if necessary between |dir| and |base| in the
vtools_genesis 33 result, removing any redundant separators. In any case, if
vtools_genesis 34 |base_in_result| is non-|NULL|, set |*base_in_result| to point to
vtools_genesis 35 the copy of |abase| in the returned concatenation. However, if
vtools_genesis 36 |abase| begins with more than one slash, set |*base_in_result| to
vtools_genesis 37 point to the sole corresponding slash that is copied into the
vtools_genesis 38 result buffer.
vtools_genesis 39
vtools_genesis 40 Return |NULL| if |malloc| fails. */
vtools_genesis 41
vtools_genesis 42 char *
vtools_genesis 43 mfile_name_concat(char const *dir, char const *abase, char **base_in_result) {
vtools_genesis 44 char const *dirbase = last_component(dir);
vtools_genesis 45 size_t dirbaselen = base_len(dirbase);
vtools_genesis 46 size_t dirlen = dirbase - dir + dirbaselen;
vtools_genesis 47 size_t needs_separator = (dirbaselen && !((dirbase[dirbaselen - 1]) == '/'));
vtools_genesis 48
vtools_genesis 49 char const *base = longest_relative_suffix(abase);
vtools_genesis 50 size_t baselen = strlen(base);
vtools_genesis 51
vtools_genesis 52 char *p_concat = malloc(dirlen + needs_separator + baselen + 1);
vtools_genesis 53 char *p;
vtools_genesis 54
vtools_genesis 55 if (p_concat == NULL)
vtools_genesis 56 return NULL;
vtools_genesis 57
vtools_genesis 58 p = mempcpy (p_concat, dir, dirlen);
vtools_genesis 59 *p = '/';
vtools_genesis 60 p += needs_separator;
vtools_genesis 61
vtools_genesis 62 if (base_in_result)
vtools_genesis 63 *base_in_result = p - (abase[0] == '/');
vtools_genesis 64
vtools_genesis 65 p = mempcpy (p, base, baselen);
vtools_genesis 66 *p = '\0';
vtools_genesis 67
vtools_genesis 68 return p_concat;
vtools_genesis 69 }
vtools_genesis 70
vtools_genesis 71
vtools_genesis 72
vtools_genesis 73
vtools_genesis 74 rather than returning |NULL| upon |malloc| failure, here, we report
vtools_genesis 75 the "memory exhausted" condition and exit. */
vtools_genesis 76
vtools_genesis 77 char *
vtools_genesis 78 file_name_concat(char const *dir, char const *abase, char **base_in_result) {
vtools_genesis 79 char *p = mfile_name_concat(dir, abase, base_in_result);
vtools_genesis 80 if (p == NULL)
vtools_genesis 81 xalloc_die();
vtools_genesis 82 return p;
vtools_genesis 83 }