summaryrefslogtreecommitdiff
path: root/src/strutil.c
blob: 7d436ecb15219a698904a4b29a1648c6d9ba5562 (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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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;
}