1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
/*
* Concatenate strings with dynamic memory allocation.
*
* Usage:
*
* string = concat(string1, string2, ..., (char *) 0);
* path = concatpath(base, name);
*
* Dynamically allocates (using xmalloc) sufficient memory to hold all of the
* strings given and then concatenates them together into that allocated
* memory, returning a pointer to it. Caller is responsible for freeing.
* Assumes xmalloc is available. The last argument must be a null pointer (to
* a char *, if you actually find a platform where it matters).
*
* concatpath is similar, except that it only takes two arguments. If the
* second argument begins with / or ./, a copy of it is returned; otherwise,
* the first argument, a slash, and the second argument are concatenated
* together and returned. This is useful for building file names where names
* that aren't fully qualified are qualified with some particular directory.
*
* Written by Russ Allbery <rra@stanford.edu>
* This work is hereby placed in the public domain by its author.
*/
#include <config.h>
#include <portable/system.h>
#include <util/concat.h>
#include <util/xmalloc.h>
/* Abbreviation for cleaner code. */
#define VA_NEXT(var, type) ((var) = (type) va_arg(args, type))
/*
* Concatenate all of the arguments into a newly allocated string. ANSI C
* requires at least one named parameter, but it's not treated any different
* than the rest.
*/
char *
concat(const char *first, ...)
{
va_list args;
char *result, *p;
const char *string;
size_t length = 0;
/* Find the total memory required. */
va_start(args, first);
for (string = first; string != NULL; VA_NEXT(string, const char *))
length += strlen(string);
va_end(args);
length++;
/*
* Create the string. Doing the copy ourselves avoids useless string
* traversals of result, if using strcat, or string, if using strlen to
* increment a pointer into result, at the cost of losing the native
* optimization of strcat if any.
*/
result = xmalloc(length);
p = result;
va_start(args, first);
for (string = first; string != NULL; VA_NEXT(string, const char *))
while (*string != '\0')
*p++ = *string++;
va_end(args);
*p = '\0';
return result;
}
/*
* Concatenate name with base, unless name begins with / or ./. Return the
* new string in newly allocated memory.
*/
char *
concatpath(const char *base, const char *name)
{
if (name[0] == '/' || (name[0] == '.' && name[1] == '/'))
return xstrdup(name);
else
return concat(base != NULL ? base : ".", "/", name, (char *) 0);
}
|