]> git.ozlabs.org Git - ccan/blob - ccan/tal/str/str.c
tal/str: use tal_ prefix.
[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 **tal_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
53         /* Ensure that tal_count() is correct. */
54         if (unlikely(!tal_resize(&parts, num+1)))
55                 goto fail;
56
57         if (taken(delims))
58                 tal_free(delims);
59         return parts;
60
61 fail:
62         tal_free(parts);
63         if (taken(delims))
64                 tal_free(delims);
65         return NULL;
66 }
67
68 char *tal_strjoin(const tal_t *ctx,
69                   char *strings[], const char *delim, enum strjoin flags)
70 {
71         unsigned int i;
72         char *ret = NULL;
73         size_t totlen = 0, dlen;
74
75         if (unlikely(!strings) && is_taken(strings))
76                 goto fail;
77
78         if (unlikely(!delim) && is_taken(delim))
79                 goto fail;
80
81         dlen = strlen(delim);
82         ret = tal_arr(ctx, char, dlen*2+1);
83         if (!ret)
84                 goto fail;
85
86         ret[0] = '\0';
87         for (i = 0; strings[i]; i++) {
88                 size_t len = strlen(strings[i]);
89
90                 if (flags == STR_NO_TRAIL && !strings[i+1])
91                         dlen = 0;
92                 if (!tal_resize(&ret, totlen + len + dlen + 1))
93                         goto fail;
94                 memcpy(ret + totlen, strings[i], len);
95                 totlen += len;
96                 memcpy(ret + totlen, delim, dlen);
97                 totlen += dlen;
98         }
99         ret[totlen] = '\0';
100 out:
101         if (taken(strings))
102                 tal_free(strings);
103         if (taken(delim))
104                 tal_free(delim);
105         return ret;
106 fail:
107         ret = tal_free(ret);
108         goto out;
109 }
110
111 bool tal_strreg(const tal_t *ctx, const char *string, const char *regex, ...)
112 {
113         size_t nmatch = 1 + strcount(regex, "(");
114         regmatch_t matches[nmatch];
115         regex_t r;
116         bool ret = false;
117         unsigned int i;
118         va_list ap;
119
120         if (unlikely(!regex) && is_taken(regex))
121                 goto fail_no_re;
122
123         if (regcomp(&r, regex, REG_EXTENDED) != 0)
124                 goto fail_no_re;
125
126         if (unlikely(!string) && is_taken(string))
127                 goto fail;
128
129         if (regexec(&r, string, nmatch, matches, 0) != 0)
130                 goto fail;
131
132         ret = true;
133         va_start(ap, regex);
134         for (i = 1; i < nmatch; i++) {
135                 char **arg = va_arg(ap, char **);
136                 if (arg) {
137                         /* eg. ([a-z])? can give "no match". */
138                         if (matches[i].rm_so == -1)
139                                 *arg = NULL;
140                         else {
141                                 *arg = tal_strndup(ctx,
142                                                    string + matches[i].rm_so,
143                                                    matches[i].rm_eo
144                                                    - matches[i].rm_so);
145                                 /* FIXME: If we fail, we set some and leak! */
146                                 if (!*arg) {
147                                         ret = false;
148                                         break;
149                                 }
150                         }
151                 }
152         }
153         va_end(ap);
154 fail:
155         regfree(&r);
156 fail_no_re:
157         if (taken(regex))
158                 tal_free(regex);
159         if (taken(string))
160                 tal_free(string);
161         return ret;
162 }