summaryrefslogtreecommitdiff
path: root/src/strutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/strutil.c')
-rw-r--r--src/strutil.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/strutil.c b/src/strutil.c
new file mode 100644
index 0000000..7d436ec
--- /dev/null
+++ b/src/strutil.c
@@ -0,0 +1,124 @@
+#include "common.h"
+
+#include "strutil.h"
+
+#include <string.h>
+
+char* strdup_len(const char* src, size_t len)
+{
+ char* ret = malloc(len + 1);
+ if (ret)
+ {
+ memcpy(ret, src, len);
+ ret[len] = '\0';
+ }
+ return ret;
+}
+
+static inline bool escaped(char* start, char* cur)
+{
+ return cur > start && cur[-1] == '\\' && !escaped(start, cur - 1);
+}
+
+void unescape(char* str)
+{
+ char* end = str + strlen(str);
+ char* s;
+ for (s = end - 1; s >= str; s--)
+ {
+ if (*s == '\\' && s < end - 1 && !escaped(str, s))
+ {
+ end--;
+ memmove(s, s + 1, end - s);
+ }
+ }
+ *end = '\0';
+}
+
+char* escape(const char* str, const char* chars)
+{
+ dynstr_t* d = dynstr_new_str(str);
+ if (d)
+ {
+ if (dynstr_escape(d, chars))
+ {
+ return dynstr_done(d);
+ }
+ dynstr_free(d);
+ }
+ return NULL;
+}
+
+bool dynstr_escape(dynstr_t* str, const char* chars)
+{
+ char* s;
+ for (s = str->data + str->len - 1; s >= str->data; s--)
+ {
+ if (*s == '\\' || strchr(chars, *s))
+ {
+ size_t pos = s - str->data;
+ if (!dynstr_appendc(str, '/'))
+ {
+ return false;
+ }
+ s = str->data + pos;
+ memmove(s + 1, s, str->len - (pos + 1));
+ *s = '\\';
+ }
+ }
+ return true;
+}
+
+static void free_list(char** list, size_t count)
+{
+ char** l;
+ for (l = list; count-- > 0; l++)
+ {
+ free(*l);
+ }
+ free(list);
+}
+
+char** split_len(const char* start, const char* end, char delim)
+{
+ char** ret;
+ size_t count = 0, size = 2;
+ assert(start && end);
+ assert(start <= end);
+ ret = malloc((size + 1) * sizeof(char*));
+ if (ret)
+ {
+ const char* last = start;
+ for (;;)
+ {
+ const char* p;
+ for (p = last; p < end && *p != delim; p++);
+ if (count == size)
+ {
+ size_t ns = size * 2;
+ char** tmp = realloc(ret, (ns + 1) * sizeof(char*));
+ if (!tmp)
+ {
+ free_list(ret, count);
+ return NULL;
+ }
+ size = ns;
+ ret = tmp;
+ }
+ ret[count] = strdup_len(last, p - last);
+ if (!ret[count])
+ {
+ free_list(ret, count);
+ return NULL;
+ }
+ count++;
+ if (p == end)
+ {
+ break;
+ }
+ last = p + 1;
+ }
+ ret[count] = NULL;
+ }
+ return ret;
+}