tal/str: accept take() for arguments.
[ccan] / ccan / tal / str / str.c
1 /* Licensed under BSD-MIT - see LICENSE file for details */
2 #include <unistd.h>
3 #include <stdint.h>
4 #include <string.h>
5 #include <limits.h>
6 #include <stdlib.h>
7 #include "str.h"
8 #include <sys/types.h>
9 #include <regex.h>
10 #include <stdarg.h>
11 #include <unistd.h>
12 #include <ccan/str/str.h>
13 #include <ccan/tal/tal.h>
14 #include <ccan/take/take.h>
15
16 char **strsplit(const tal_t *ctx,
17                 const char *string, const char *delims, enum strsplit flags)
18 {
19         char **parts, *str;
20         size_t max = 64, num = 0;
21
22         parts = tal_arr(ctx, char *, max + 1);
23         if (unlikely(!parts)) {
24                 if (taken(string))
25                         tal_free(string);
26                 if (taken(delims))
27                         tal_free(delims);
28                 return NULL;
29         }
30         str = tal_strdup(parts, string);
31         if (unlikely(!str))
32                 goto fail;
33         if (unlikely(!delims) && is_taken(delims))
34                 goto fail;
35
36         if (flags == STR_NO_EMPTY)
37                 str += strspn(str, delims);
38
39         while (*str != '\0') {
40                 size_t len = strcspn(str, delims), dlen;
41
42                 parts[num] = str;
43                 dlen = strspn(str + len, delims);
44                 parts[num][len] = '\0';
45                 if (flags == STR_EMPTY_OK && dlen)
46                         dlen = 1;
47                 str += len + dlen;
48                 if (++num == max && !tal_resize(&parts, max*=2 + 1))
49                         goto fail;
50         }
51         parts[num] = NULL;
52         if (taken(delims))
53                 tal_free(delims);
54         return parts;
55
56 fail:
57         tal_free(parts);
58         if (taken(delims))
59                 tal_free(delims);
60         return NULL;
61 }
62
63 char *strjoin(const tal_t *ctx,
64               char *strings[], const char *delim, enum strjoin flags)
65 {
66         unsigned int i;
67         char *ret = NULL;
68         size_t totlen = 0, dlen;
69
70         if (unlikely(!strings) && is_taken(strings))
71                 goto fail;
72
73         if (unlikely(!delim) && is_taken(delim))
74                 goto fail;
75
76         dlen = strlen(delim);
77         ret = tal_arr(ctx, char, dlen*2+1);
78         if (!ret)
79                 goto fail;
80
81         ret[0] = '\0';
82         for (i = 0; strings[i]; i++) {
83                 size_t len = strlen(strings[i]);
84
85                 if (flags == STR_NO_TRAIL && !strings[i+1])
86                         dlen = 0;
87                 if (!tal_resize(&ret, totlen + len + dlen + 1))
88                         goto fail;
89                 memcpy(ret + totlen, strings[i], len);
90                 totlen += len;
91                 memcpy(ret + totlen, delim, dlen);
92                 totlen += dlen;
93         }
94         ret[totlen] = '\0';
95 out:
96         if (taken(strings))
97                 tal_free(strings);
98         if (taken(delim))
99                 tal_free(delim);
100         return ret;
101 fail:
102         ret = tal_free(ret);
103         goto out;
104 }
105
106 bool strreg(const tal_t *ctx, const char *string, const char *regex, ...)
107 {
108         size_t nmatch = 1 + strcount(regex, "(");
109         regmatch_t matches[nmatch];
110         regex_t r;
111         bool ret = false;
112         unsigned int i;
113         va_list ap;
114
115         if (unlikely(!regex) && is_taken(regex))
116                 goto fail_no_re;
117
118         if (regcomp(&r, regex, REG_EXTENDED) != 0)
119                 goto fail_no_re;
120
121         if (unlikely(!string) && is_taken(string))
122                 goto fail;
123
124         if (regexec(&r, string, nmatch, matches, 0) != 0)
125                 goto fail;
126
127         ret = true;
128         va_start(ap, regex);
129         for (i = 1; i < nmatch; i++) {
130                 char **arg = va_arg(ap, char **);
131                 if (arg) {
132                         /* eg. ([a-z])? can give "no match". */
133                         if (matches[i].rm_so == -1)
134                                 *arg = NULL;
135                         else {
136                                 *arg = tal_strndup(ctx,
137                                                    string + matches[i].rm_so,
138                                                    matches[i].rm_eo
139                                                    - matches[i].rm_so);
140                                 /* FIXME: If we fail, we set some and leak! */
141                                 if (!*arg) {
142                                         ret = false;
143                                         break;
144                                 }
145                         }
146                 }
147         }
148         va_end(ap);
149 fail:
150         regfree(&r);
151 fail_no_re:
152         if (taken(regex))
153                 tal_free(regex);
154         if (taken(string))
155                 tal_free(string);
156         return ret;
157 }