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