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