-
+ 06209A17B6C66FDBBF324A004AC8853D54FD3C2A69F985A27DBD8DC65E5310C4228C1F9B41D7C639D24B47515641413AA57E35460B6246F41C8C961C0A5889FA
vtools/lib/filenamecat.c
(0 . 0)(1 . 83)
767
768 /* Written by Jim Meyering. */
769
770 /* Specification. */
771 #include "filenamecat.h"
772
773 #include <stdlib.h>
774 #include <string.h>
775 #include "xalloc.h"
776
777 #include "dirname.h"
778
779 #if !HAVE_MEMPCPY && !defined mempcpy
780 # define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
781 #endif
782
783 /* Return the longest suffix of |f| that is a relative file name. If
784 it has no such suffix, return the empty string. */
785
786 static char const *
787 longest_relative_suffix(char const *f) {
788 for (f += 0; ((*f) == '/'); f++)
789 continue;
790 return f;
791 }
792
793 /* Concatenate two file name components, |dir| and |abase|, in
794 newly-allocated storage and return the result. The resulting file
795 name |f| is such that the commands |ls F| and |(cd DIR; ls BASE)|
796 refer to the same file, where |base| is |abase| with any file
797 system prefixes and leading separators removed. Arrange for a
798 directory separator if necessary between |dir| and |base| in the
799 result, removing any redundant separators. In any case, if
800 |base_in_result| is non-|NULL|, set |*base_in_result| to point to
801 the copy of |abase| in the returned concatenation. However, if
802 |abase| begins with more than one slash, set |*base_in_result| to
803 point to the sole corresponding slash that is copied into the
804 result buffer.
805
806 Return |NULL| if |malloc| fails. */
807
808 char *
809 mfile_name_concat(char const *dir, char const *abase, char **base_in_result) {
810 char const *dirbase = last_component(dir);
811 size_t dirbaselen = base_len(dirbase);
812 size_t dirlen = dirbase - dir + dirbaselen;
813 size_t needs_separator = (dirbaselen && !((dirbase[dirbaselen - 1]) == '/'));
814
815 char const *base = longest_relative_suffix(abase);
816 size_t baselen = strlen(base);
817
818 char *p_concat = malloc(dirlen + needs_separator + baselen + 1);
819 char *p;
820
821 if (p_concat == NULL)
822 return NULL;
823
824 p = mempcpy (p_concat, dir, dirlen);
825 *p = '/';
826 p += needs_separator;
827
828 if (base_in_result)
829 *base_in_result = p - (abase[0] == '/');
830
831 p = mempcpy (p, base, baselen);
832 *p = '\0';
833
834 return p_concat;
835 }
836
837 /* Written by Jim Meyering. */
838
839 /* Just like |mfile_name_concat| (|filenamecat-lgpl.c|), except,
840 rather than returning |NULL| upon |malloc| failure, here, we report
841 the "memory exhausted" condition and exit. */
842
843 char *
844 file_name_concat(char const *dir, char const *abase, char **base_in_result) {
845 char *p = mfile_name_concat(dir, abase, base_in_result);
846 if (p == NULL)
847 xalloc_die();
848 return p;
849 }