]> git.ozlabs.org Git - ccan/blob - ccan/tal/str/str.c
4606b47e3356955f7989389b9729db33c5b3b71f
[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 <stdio.h>
13 #include <ccan/str/str.h>
14 #include <ccan/tal/tal.h>
15 #include <ccan/take/take.h>
16
17 char *tal_strdup(const tal_t *ctx, const char *p)
18 {
19         /* We have to let through NULL for take(). */
20         return tal_dup_(ctx, p, 1, p ? strlen(p) + 1: 1, 0, false,
21                         TAL_LABEL(char, "[]"));
22 }
23
24 char *tal_strndup(const tal_t *ctx, const char *p, size_t n)
25 {
26         size_t len;
27         char *ret;
28
29         /* We have to let through NULL for take(). */
30         if (likely(p)) {
31                 len = strlen(p);
32                 if (len > n)
33                         len = n;
34         } else
35                 len = n;
36
37         ret = tal_dup_(ctx, p, 1, len, 1, false, TAL_LABEL(char, "[]"));
38         if (ret)
39                 ret[len] = '\0';
40         return ret;
41 }
42
43 char *tal_asprintf(const tal_t *ctx, const char *fmt, ...)
44 {
45         va_list ap;
46         char *ret;
47
48         va_start(ap, fmt);
49         ret = tal_vasprintf(ctx, fmt, ap);
50         va_end(ap);
51
52         return ret;
53 }
54
55 char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap)
56 {
57         size_t max;
58         char *buf;
59         int ret;
60
61         if (!fmt && taken(fmt))
62                 return NULL;
63
64         /* A decent guess to start. */
65         max = strlen(fmt) * 2;
66         buf = tal_arr(ctx, char, max);
67         while (buf) {
68                 va_list ap2;
69
70                 va_copy(ap2, ap);
71                 ret = vsnprintf(buf, max, fmt, ap2);
72                 va_end(ap2);
73
74                 if (ret < max)
75                         break;
76                 if (!tal_resize(&buf, max *= 2))
77                         buf = tal_free(buf);
78         }
79         if (taken(fmt))
80                 tal_free(fmt);
81         return buf;
82 }
83
84 char *tal_strcat(const tal_t *ctx, const char *s1, const char *s2)
85 {
86         size_t len1, len2;
87         char *ret;
88
89         if (unlikely(!s2) && taken(s2)) {
90                 if (taken(s1))
91                         tal_free(s1);
92                 return NULL;
93         }
94         /* We have to let through NULL for take(). */
95         len1 = s1 ? strlen(s1) : 0;
96         len2 = strlen(s2);
97
98         /* We use tal_dup_ here to avoid attaching a length property. */
99         ret = tal_dup_(ctx, s1, 1, len1, len2 + 1, false,
100                        TAL_LABEL(char, "[]"));
101         if (likely(ret))
102                 memcpy(ret + len1, s2, len2 + 1);
103
104         if (taken(s2))
105                 tal_free(s2);
106         return ret;
107 }
108
109 char **tal_strsplit(const tal_t *ctx,
110                     const char *string, const char *delims, enum strsplit flags)
111 {
112         char **parts, *str;
113         size_t max = 64, num = 0;
114
115         parts = tal_arr(ctx, char *, max + 1);
116         if (unlikely(!parts)) {
117                 if (taken(string))
118                         tal_free(string);
119                 if (taken(delims))
120                         tal_free(delims);
121                 return NULL;
122         }
123         str = tal_strdup(parts, string);
124         if (unlikely(!str))
125                 goto fail;
126         if (unlikely(!delims) && is_taken(delims))
127                 goto fail;
128
129         if (flags == STR_NO_EMPTY)
130                 str += strspn(str, delims);
131
132         while (*str != '\0') {
133                 size_t len = strcspn(str, delims), dlen;
134
135                 parts[num] = str;
136                 dlen = strspn(str + len, delims);
137                 parts[num][len] = '\0';
138                 if (flags == STR_EMPTY_OK && dlen)
139                         dlen = 1;
140                 str += len + dlen;
141                 if (++num == max && !tal_resize(&parts, max*=2 + 1))
142                         goto fail;
143         }
144         parts[num] = NULL;
145
146         /* Ensure that tal_count() is correct. */
147         if (unlikely(!tal_resize(&parts, num+1)))
148                 goto fail;
149
150         if (taken(delims))
151                 tal_free(delims);
152         return parts;
153
154 fail:
155         tal_free(parts);
156         if (taken(delims))
157                 tal_free(delims);
158         return NULL;
159 }
160
161 char *tal_strjoin(const tal_t *ctx,
162                   char *strings[], const char *delim, enum strjoin flags)
163 {
164         unsigned int i;
165         char *ret = NULL;
166         size_t totlen = 0, dlen;
167
168         if (unlikely(!strings) && is_taken(strings))
169                 goto fail;
170
171         if (unlikely(!delim) && is_taken(delim))
172                 goto fail;
173
174         dlen = strlen(delim);
175         ret = tal_arr(ctx, char, dlen*2+1);
176         if (!ret)
177                 goto fail;
178
179         ret[0] = '\0';
180         for (i = 0; strings[i]; i++) {
181                 size_t len = strlen(strings[i]);
182
183                 if (flags == STR_NO_TRAIL && !strings[i+1])
184                         dlen = 0;
185                 if (!tal_resize(&ret, totlen + len + dlen + 1))
186                         goto fail;
187                 memcpy(ret + totlen, strings[i], len);
188                 totlen += len;
189                 memcpy(ret + totlen, delim, dlen);
190                 totlen += dlen;
191         }
192         ret[totlen] = '\0';
193 out:
194         if (taken(strings))
195                 tal_free(strings);
196         if (taken(delim))
197                 tal_free(delim);
198         return ret;
199 fail:
200         ret = tal_free(ret);
201         goto out;
202 }
203
204 bool tal_strreg(const tal_t *ctx, const char *string, const char *regex, ...)
205 {
206         size_t nmatch = 1 + strcount(regex, "(");
207         regmatch_t matches[nmatch];
208         regex_t r;
209         bool ret = false;
210         unsigned int i;
211         va_list ap;
212
213         if (unlikely(!regex) && is_taken(regex))
214                 goto fail_no_re;
215
216         if (regcomp(&r, regex, REG_EXTENDED) != 0)
217                 goto fail_no_re;
218
219         if (unlikely(!string) && is_taken(string))
220                 goto fail;
221
222         if (regexec(&r, string, nmatch, matches, 0) != 0)
223                 goto fail;
224
225         ret = true;
226         va_start(ap, regex);
227         for (i = 1; i < nmatch; i++) {
228                 char **arg = va_arg(ap, char **);
229                 if (arg) {
230                         /* eg. ([a-z])? can give "no match". */
231                         if (matches[i].rm_so == -1)
232                                 *arg = NULL;
233                         else {
234                                 *arg = tal_strndup(ctx,
235                                                    string + matches[i].rm_so,
236                                                    matches[i].rm_eo
237                                                    - matches[i].rm_so);
238                                 /* FIXME: If we fail, we set some and leak! */
239                                 if (!*arg) {
240                                         ret = false;
241                                         break;
242                                 }
243                         }
244                 }
245         }
246         va_end(ap);
247 fail:
248         regfree(&r);
249 fail_no_re:
250         if (taken(regex))
251                 tal_free(regex);
252         if (taken(string))
253                 tal_free(string);
254         return ret;
255 }