summaryrefslogtreecommitdiff
path: root/util/concat.c
diff options
context:
space:
mode:
authorRuss Allbery <rra@stanford.edu>2007-10-04 22:21:19 +0000
committerRuss Allbery <rra@stanford.edu>2007-10-04 22:21:19 +0000
commit9ff667addf39128f43d08d4ec56a6a94ec3bb062 (patch)
tree41cd39045fb2d37d343608af57aebf844ecd5690 /util/concat.c
parent2f9387bdf0e047bbd193532c4fed209acabd0e7a (diff)
Initial import of a C portability framework and utility functions from
remctl so that the wallet client error handling can rest on a firmer foundation.
Diffstat (limited to 'util/concat.c')
-rw-r--r--util/concat.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/util/concat.c b/util/concat.c
new file mode 100644
index 0000000..65ca04c
--- /dev/null
+++ b/util/concat.c
@@ -0,0 +1,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);
+}