Adds a few useful string and array manipulation functions to utils.[ch]

Signed-off-by: Christian Seiler <christ...@iwakd.de>
---
 src/lxc/utils.c |  284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/utils.h |   32 +++++++
 2 files changed, 316 insertions(+)

diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index b188c47..dc98443 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -37,6 +37,7 @@
 #include <libgen.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <assert.h>
 
 #include "utils.h"
 #include "log.h"
@@ -523,3 +524,286 @@ FILE *fopen_cloexec(const char *path, const char *mode)
        errno = saved_errno;
        return ret;
 }
+
+char *lxc_string_replace(const char *needle, const char *replacement, const 
char *haystack)
+{
+       ssize_t len = -1, saved_len = -1;
+       char *result = NULL;
+       size_t replacement_len = strlen(replacement);
+       size_t needle_len = strlen(needle);
+
+       /* should be executed exactly twice */
+       while (len == -1 || result == NULL) {
+               char *p;
+               char *last_p;
+               ssize_t part_len;
+
+               if (len != -1) {
+                       result = calloc(1, len + 1);
+                       if (!result)
+                               return NULL;
+                       saved_len = len;
+               }
+
+               len = 0;
+
+               for (last_p = (char *)haystack, p = strstr(last_p, needle); p; 
last_p = p, p = strstr(last_p, needle)) {
+                       part_len = (ssize_t)(p - last_p);
+                       if (result && part_len > 0)
+                               memcpy(&result[len], last_p, part_len);
+                       len += part_len;
+                       if (result && replacement_len > 0)
+                               memcpy(&result[len], replacement, 
replacement_len);
+                       len += replacement_len;
+                       p += needle_len;
+               }
+               part_len = strlen(last_p);
+               if (result && part_len > 0)
+                       memcpy(&result[len], last_p, part_len);
+               len += part_len;
+       }
+
+       /* make sure we did the same thing twice,
+        * once for calculating length, the other
+        * time for copying data */
+       assert(saved_len == len);
+       /* make sure we didn't overwrite any buffer,
+        * due to calloc the string should be 0-terminated */
+       assert(result[len] == '\0');
+
+       return result;
+}
+
+bool lxc_string_in_array(const char *needle, const char **haystack)
+{
+       for (; haystack && *haystack; haystack++)
+               if (!strcmp(needle, *haystack))
+                       return true;
+       return false;
+}
+
+char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
+{
+       char *result;
+       char **p;
+       size_t sep_len = strlen(sep);
+       size_t result_len = use_as_prefix * sep_len;
+
+       /* calculate new string length */
+       for (p = (char **)parts; *p; p++)
+               result_len += (p > (char **)parts) * sep_len + strlen(*p);
+
+       result = calloc(result_len + 1, 1);
+       if (!result)
+               return NULL;
+
+       if (use_as_prefix)
+               strcpy(result, sep);
+       for (p = (char **)parts; *p; p++) {
+               if (p > (char **)parts)
+                       strcat(result, sep);
+               strcat(result, *p);
+       }
+
+       return result;
+}
+
+char **lxc_normalize_path(const char *path)
+{
+       char **components;
+       char **p;
+       size_t components_len = 0;
+       size_t pos = 0;
+
+       components = lxc_string_split(path, '/');
+       if (!components)
+               return NULL;
+       for (p = components; *p; p++)
+               components_len++;
+
+       /* resolve '.' and '..' */
+       for (pos = 0; pos < components_len; ) {
+               if (!strcmp(components[pos], ".") || (!strcmp(components[pos], 
"..") && pos == 0)) {
+                       /* eat this element */
+                       free(components[pos]);
+                       memmove(&components[pos], &components[pos+1], 
sizeof(char *) * (components_len - pos));
+                       components_len--;
+               } else if (!strcmp(components[pos], "..")) {
+                       /* eat this and the previous element */
+                       free(components[pos - 1]);
+                       free(components[pos]);
+                       memmove(&components[pos-1], &components[pos+1], 
sizeof(char *) * (components_len - pos));
+                       components_len -= 2;
+                       pos--;
+               } else {
+                       pos++;
+               }
+       }
+
+       return components;
+}
+
+bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
+{
+       char *token, *str, *saveptr = NULL;
+       char sep[2] = { _sep, '\0' };
+
+       if (!haystack || !needle)
+               return 0;
+
+       str = alloca(strlen(haystack)+1);
+       strcpy(str, haystack);
+       for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
+               if (strcmp(needle, token) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+char **lxc_string_split(const char *string, char _sep)
+{
+       char *token, *str, *saveptr = NULL;
+       char sep[2] = { _sep, '\0' };
+       char **result = NULL;
+       size_t result_capacity = 0;
+       size_t result_count = 0;
+       int r, saved_errno;
+
+       if (!string)
+               return calloc(1, sizeof(char *));
+
+       str = alloca(strlen(string)+1);
+       strcpy(str, string);
+       for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
+               r = lxc_grow_array((void ***)&result, &result_capacity, 
result_count + 1, 16);
+               if (r < 0)
+                       goto error_out;
+               result[result_count] = strdup(token);
+               if (!result[result_count])
+                       goto error_out;
+               result_count++;
+       }
+
+       /* if we allocated too much, reduce it */
+       return realloc(result, (result_count + 1) * sizeof(char *));
+error_out:
+       saved_errno = errno;
+       lxc_free_array((void **)result, free);
+       errno = saved_errno;
+       return NULL;
+}
+
+char **lxc_string_split_and_trim(const char *string, char _sep)
+{
+       char *token, *str, *saveptr = NULL;
+       char sep[2] = { _sep, '\0' };
+       char **result = NULL;
+       size_t result_capacity = 0;
+       size_t result_count = 0;
+       int r, saved_errno;
+       size_t i = 0;
+
+       if (!string)
+               return calloc(1, sizeof(char *));
+
+       str = alloca(strlen(string)+1);
+       strcpy(str, string);
+       for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
+               while (token[0] == ' ' || token[0] == '\t')
+                       token++;
+               i = strlen(token);
+               while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
+                       token[i - 1] = '\0';
+                       i--;
+               }
+               r = lxc_grow_array((void ***)&result, &result_capacity, 
result_count + 1, 16);
+               if (r < 0)
+                       goto error_out;
+               result[result_count] = strdup(token);
+               if (!result[result_count])
+                       goto error_out;
+               result_count++;
+       }
+
+       /* if we allocated too much, reduce it */
+       return realloc(result, (result_count + 1) * sizeof(char *));
+error_out:
+       saved_errno = errno;
+       lxc_free_array((void **)result, free);
+       errno = saved_errno;
+       return NULL;
+}
+
+void lxc_free_array(void **array, lxc_free_fn element_free_fn)
+{
+       void **p;
+       for (p = array; p && *p; p++)
+               element_free_fn(*p);
+       free((void*)array);
+}
+
+int lxc_grow_array(void ***array, size_t* capacity, size_t new_size, size_t 
capacity_increment)
+{
+       size_t new_capacity;
+       void **new_array;
+
+       /* first time around, catch some trivial mistakes of the user
+        * only initializing one of these */
+       if (!*array || !*capacity) {
+               *array = NULL;
+               *capacity = 0;
+       }
+
+       new_capacity = *capacity;
+       while (new_size + 1 > new_capacity)
+               new_capacity += capacity_increment;
+       if (new_capacity != *capacity) {
+               /* we have to reallocate */
+               new_array = realloc(*array, new_capacity * sizeof(void *));
+               if (!new_array)
+                       return -1;
+               memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * 
sizeof(void *));
+               *array = new_array;
+               *capacity = new_capacity;
+       }
+
+       /* array has sufficient elements */
+       return 0;
+}
+
+size_t lxc_array_len(void **array)
+{
+       void **p;
+       size_t result = 0;
+
+       for (p = array; p && *p; p++)
+               result++;
+
+       return result;
+}
+
+void **lxc_dup_array(void **array, lxc_dup_fn element_dup_fn, lxc_free_fn 
element_free_fn)
+{
+       size_t l = lxc_array_len(array);
+       void **result = calloc(l + 1, sizeof(void *));
+       void **pp;
+       void *p;
+       int saved_errno = 0;
+
+       if (!result)
+               return NULL;
+
+       for (l = 0, pp = array; pp && *pp; pp++, l++) {
+               p = element_dup_fn(*pp);
+               if (!p) {
+                       saved_errno = errno;
+                       lxc_free_array(result, element_free_fn);
+                       errno = saved_errno;
+                       return NULL;
+               }
+               result[l] = p;
+       }
+
+       return result;
+}
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index b79be44..7261846 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -197,4 +198,35 @@ extern int sha1sum_file(char *fnam, unsigned char 
*md_value);
 extern char** lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup);
 extern const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip);
 
+/* Some simple string functions; if they return pointers, they are allocated 
buffers. */
+extern char *lxc_string_replace(const char *needle, const char *replacement, 
const char *haystack);
+extern bool lxc_string_in_array(const char *needle, const char **haystack);
+extern char *lxc_string_join(const char *sep, const char **parts, bool 
use_as_prefix);
+/* Normalize and split path: Leading and trailing / are removed, multiple
+ * / are compactified, .. and . are resolved (.. on the top level is considered
+ * identical to .).
+ * Examples:
+ *     /            ->   { NULL }
+ *     foo/../bar   ->   { bar, NULL }
+ *     ../../       ->   { NULL }
+ *     ./bar/baz/.. ->   { bar, NULL }
+ *     foo//bar     ->   { foo, bar, NULL }
+ */
+extern char **lxc_normalize_path(const char *path);
+/* Note: the following two functions use strtok(), so they will never
+ *       consider an empty element, even if two delimiters are next to
+ *       each other.
+ */
+extern bool lxc_string_in_list(const char *needle, const char *haystack, char 
sep);
+extern char **lxc_string_split(const char *string, char sep);
+extern char **lxc_string_split_and_trim(const char *string, char sep);
+
+/* some simple array manipulation utilities */
+typedef void (*lxc_free_fn)(void *);
+typedef void *(*lxc_dup_fn)(void *);
+extern int lxc_grow_array(void ***array, size_t* capacity, size_t new_size, 
size_t capacity_increment);
+extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
+extern size_t lxc_array_len(void **array);
+extern void **lxc_dup_array(void **array, lxc_dup_fn element_dup_fn, 
lxc_free_fn element_free_fn);
+
 #endif
-- 
1.7.10.4


------------------------------------------------------------------------------
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
_______________________________________________
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to