1 /* $Id: concat.c 10100 2016-11-04 22:24:26Z iulius $
2  *
3  * Concatenate strings with dynamic memory allocation.
4  *
5  * Usage:
6  *
7  *      string = concat(string1, string2, ..., (char *) 0);
8  *      path = concatpath(base, name);
9  *
10  * Dynamically allocates (using xmalloc) sufficient memory to hold all of the
11  * strings given and then concatenates them together into that allocated
12  * memory, returning a pointer to it.  Caller is responsible for freeing.
13  * Assumes xmalloc is available.  The last argument must be a null pointer (to
14  * a char *, if you actually find a platform where it matters).
15  *
16  * concatpath is similar, except that it only takes two arguments.  If the
17  * second argument begins with / or ./, a copy of it is returned; otherwise,
18  * the first argument, a slash, and the second argument are concatenated
19  * together and returned.  This is useful for building file names where names
20  * that aren't fully qualified are qualified with some particular directory.
21  *
22  * The canonical version of this file *used to be* maintained in the
23  * rra-c-util package, which can be found at
24  * <http://www.eyrie.org/~eagle/software/rra-c-util/>.
25  *
26  * Written by Russ Allbery <eagle@eyrie.org>
27  *
28  * The authors hereby relinquish any claim to any copyright that they may have
29  * in this work, whether granted under contract or by operation of law or
30  * international treaty, and hereby commit to the public, at large, that they
31  * shall not, at any time in the future, seek to enforce any copyright in this
32  * work against any person or entity, or prevent any person or entity from
33  * copying, publishing, distributing or creating derivative works of this
34  * work.
35  */
36 
37 #include "config.h"
38 #include "clibrary.h"
39 
40 #include "inn/concat.h"
41 #include "inn/xmalloc.h"
42 
43 /* Abbreviation for cleaner code. */
44 #define VA_NEXT(var, type) ((var) = (type) va_arg(args, type))
45 
46 
47 /*
48  * Concatenate all of the arguments into a newly allocated string.  ANSI C
49  * requires at least one named parameter, but it's not treated any different
50  * than the rest.
51  */
52 char *
concat(const char * first,...)53 concat(const char *first, ...)
54 {
55     va_list args;
56     char *result, *p;
57     const char *string;
58     size_t length = 0;
59 
60     /* Find the total memory required. */
61     va_start(args, first);
62     for (string = first; string != NULL; VA_NEXT(string, const char *))
63         length += strlen(string);
64     va_end(args);
65     length++;
66 
67     /*
68      * Create the string.  Doing the copy ourselves avoids useless string
69      * traversals of result, if using strcat, or string, if using strlen to
70      * increment a pointer into result, at the cost of losing the native
71      * optimization of strcat if any.
72      */
73     result = xmalloc(length);
74     p = result;
75     va_start(args, first);
76     for (string = first; string != NULL; VA_NEXT(string, const char *))
77         while (*string != '\0')
78             *p++ = *string++;
79     va_end(args);
80     *p = '\0';
81 
82     return result;
83 }
84 
85 
86 /*
87  * Concatenate name with base, unless name begins with / or ./.  Return the
88  * new string in newly allocated memory.
89  */
90 char *
concatpath(const char * base,const char * name)91 concatpath(const char *base, const char *name)
92 {
93     if (name[0] == '/' || (name[0] == '.' && name[1] == '/'))
94         return xstrdup(name);
95     else
96         return concat(base != NULL ? base : ".", "/", name, (char *) 0);
97 }
98