tal/str: move tal string functions here from tal.
[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_strsplit(const tal_t *ctx,
85                     const char *string, const char *delims, enum strsplit flags)
86 {
87         char **parts, *str;
88         size_t max = 64, num = 0;
89
90         parts = tal_arr(ctx, char *, max + 1);
91         if (unlikely(!parts)) {
92                 if (taken(string))
93                         tal_free(string);
94                 if (taken(delims))
95                         tal_free(delims);
96                 return NULL;
97         }
98         str = tal_strdup(parts, string);
99         if (unlikely(!str))
100                 goto fail;
101         if (unlikely(!delims) && is_taken(delims))
102                 goto fail;
103
104         if (flags == STR_NO_EMPTY)
105                 str += strspn(str, delims);
106
107         while (*str != '\0') {
108                 size_t len = strcspn(str, delims), dlen;
109
110                 parts[num] = str;
111                 dlen = strspn(str + len, delims);
112                 parts[num][len] = '\0';
113                 if (flags == STR_EMPTY_OK && dlen)
114                         dlen = 1;
115                 str += len + dlen;
116                 if (++num == max && !tal_resize(&parts, max*=2 + 1))
117                         goto fail;
118         }
119         parts[num] = NULL;
120
121         /* Ensure that tal_count() is correct. */
122         if (unlikely(!tal_resize(&parts, num+1)))
123                 goto fail;
124
125         if (taken(delims))
126                 tal_free(delims);
127         return parts;
128
129 fail:
130         tal_free(parts);
131         if (taken(delims))
132                 tal_free(delims);
133         return NULL;
134 }
135
136 char *tal_strjoin(const tal_t *ctx,
137                   char *strings[], const char *delim, enum strjoin flags)
138 {
139         unsigned int i;
140         char *ret = NULL;
141         size_t totlen = 0, dlen;
142
143         if (unlikely(!strings) && is_taken(strings))
144                 goto fail;
145
146         if (unlikely(!delim) && is_taken(delim))
147                 goto fail;
148
149         dlen = strlen(delim);
150         ret = tal_arr(ctx, char, dlen*2+1);
151         if (!ret)
152                 goto fail;
153
154         ret[0] = '\0';
155         for (i = 0; strings[i]; i++) {
156                 size_t len = strlen(strings[i]);
157
158                 if (flags == STR_NO_TRAIL && !strings[i+1])
159                         dlen = 0;
160                 if (!tal_resize(&ret, totlen + len + dlen + 1))
161                         goto fail;
162                 memcpy(ret + totlen, strings[i], len);
163                 totlen += len;
164                 memcpy(ret + totlen, delim, dlen);
165                 totlen += dlen;
166         }
167         ret[totlen] = '\0';
168 out:
169         if (taken(strings))
170                 tal_free(strings);
171         if (taken(delim))
172                 tal_free(delim);
173         return ret;
174 fail:
175         ret = tal_free(ret);
176         goto out;
177 }
178
179 bool tal_strreg(const tal_t *ctx, const char *string, const char *regex, ...)
180 {
181         size_t nmatch = 1 + strcount(regex, "(");
182         regmatch_t matches[nmatch];
183         regex_t r;
184         bool ret = false;
185         unsigned int i;
186         va_list ap;
187
188         if (unlikely(!regex) && is_taken(regex))
189                 goto fail_no_re;
190
191         if (regcomp(&r, regex, REG_EXTENDED) != 0)
192                 goto fail_no_re;
193
194         if (unlikely(!string) && is_taken(string))
195                 goto fail;
196
197         if (regexec(&r, string, nmatch, matches, 0) != 0)
198                 goto fail;
199
200         ret = true;
201         va_start(ap, regex);
202         for (i = 1; i < nmatch; i++) {
203                 char **arg = va_arg(ap, char **);
204                 if (arg) {
205                         /* eg. ([a-z])? can give "no match". */
206                         if (matches[i].rm_so == -1)
207                                 *arg = NULL;
208                         else {
209                                 *arg = tal_strndup(ctx,
210                                                    string + matches[i].rm_so,
211                                                    matches[i].rm_eo
212                                                    - matches[i].rm_so);
213                                 /* FIXME: If we fail, we set some and leak! */
214                                 if (!*arg) {
215                                         ret = false;
216                                         break;
217                                 }
218                         }
219                 }
220         }
221         va_end(ap);
222 fail:
223         regfree(&r);
224 fail_no_re:
225         if (taken(regex))
226                 tal_free(regex);
227         if (taken(string))
228                 tal_free(string);
229         return ret;
230 }