]> git.ozlabs.org Git - ccan/blob - ccan/str_talloc/str_talloc.c
str_talloc: make strjoin much more efficient.
[ccan] / ccan / str_talloc / str_talloc.c
1 #include <unistd.h>
2 #include <stdint.h>
3 #include <string.h>
4 #include <limits.h>
5 #include <stdlib.h>
6 #include "str_talloc.h"
7 #include <sys/types.h>
8 #include <regex.h>
9 #include <stdarg.h>
10 #include <unistd.h>
11 #include <ccan/talloc/talloc.h>
12 #include <ccan/str/str.h>
13
14 char **strsplit(const void *ctx, const char *string, const char *delims)
15 {
16         char **lines = NULL;
17         unsigned int max = 64, num = 0;
18
19         lines = talloc_array(ctx, char *, max+1);
20
21         while (*string != '\0') {
22                 unsigned int len = strcspn(string, delims);
23                 lines[num] = talloc_array(lines, char, len + 1);
24                 memcpy(lines[num], string, len);
25                 lines[num][len] = '\0';
26                 string += len;
27                 string += strspn(string, delims) ? 1 : 0;
28                 if (++num == max)
29                         lines = talloc_realloc(ctx, lines, char *, max*=2 + 1);
30         }
31         lines[num] = NULL;
32
33         /* Shrink, so talloc_get_size works */
34         return talloc_realloc(ctx, lines, char *, num+1);
35 }
36
37 char *strjoin(const void *ctx, char *strings[], const char *delim)
38 {
39         unsigned int i;
40         char *ret = talloc_strdup(ctx, "");
41         size_t totlen = 0, dlen = strlen(delim);
42
43         for (i = 0; strings[i]; i++) {
44                 size_t len = strlen(strings[i]);
45                 ret = talloc_realloc(ctx, ret, char, totlen + len + dlen + 1);
46                 memcpy(ret + totlen, strings[i], len);
47                 totlen += len;
48                 memcpy(ret + totlen, delim, dlen);
49                 totlen += dlen;
50         }
51         ret[totlen] = '\0';
52         return ret;
53 }
54
55 bool strreg(const void *ctx, const char *string, const char *regex, ...)
56 {
57         size_t nmatch = 1 + strcount(regex, "(");
58         regmatch_t *matches = talloc_array(ctx, regmatch_t, nmatch);
59         regex_t r;
60         bool ret;
61
62         if (!matches || regcomp(&r, regex, REG_EXTENDED) != 0)
63                 return false;
64
65         if (regexec(&r, string, nmatch, matches, 0) == 0) {
66                 unsigned int i;
67                 va_list ap;
68
69                 ret = true;
70                 va_start(ap, regex);
71                 for (i = 1; i < nmatch; i++) {
72                         char **arg;
73                         arg = va_arg(ap, char **);
74                         if (arg) {
75                                 /* eg. ([a-z])? can give "no match". */
76                                 if (matches[i].rm_so == -1)
77                                         *arg = NULL;
78                                 else {
79                                         *arg = talloc_strndup(ctx,
80                                                       string + matches[i].rm_so,
81                                                       matches[i].rm_eo
82                                                       - matches[i].rm_so);
83                                         if (!*arg) {
84                                                 ret = false;
85                                                 break;
86                                         }
87                                 }
88                         }
89                 }
90                 va_end(ap);
91         } else
92                 ret = false;
93         talloc_free(matches);
94         regfree(&r);
95         return ret;
96 }