summaryrefslogtreecommitdiff
path: root/util/concat.c
blob: 65ca04cad122df9486309e7fc49326386592ff62 (plain)
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
/*  $Id$
**
**  Concatenate strings with dynamic memory allocation.
**
**  Written by Russ Allbery <rra@stanford.edu>
**  This work is hereby placed in the public domain by its author.
**
**  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.
*/

#include <config.h>
#include <system.h>

#include <util/util.h>

/* Abbreviation for cleaner code. */
#define VA_NEXT(var, type)      ((var) = (type) va_arg(args, type))

/* ANSI C requires at least one named parameter. */
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;
}


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);
}