|
@@ -9,98 +9,149 @@
|
|
|
#include <regex.h>
|
|
#include <regex.h>
|
|
|
#include <stdarg.h>
|
|
#include <stdarg.h>
|
|
|
#include <unistd.h>
|
|
#include <unistd.h>
|
|
|
-#include <ccan/tal/tal.h>
|
|
|
|
|
#include <ccan/str/str.h>
|
|
#include <ccan/str/str.h>
|
|
|
|
|
+#include <ccan/tal/tal.h>
|
|
|
|
|
+#include <ccan/take/take.h>
|
|
|
|
|
|
|
|
-char **strsplit(const void *ctx, const char *string, const char *delims,
|
|
|
|
|
- enum strsplit flags)
|
|
|
|
|
|
|
+char **strsplit(const tal_t *ctx,
|
|
|
|
|
+ const char *string, const char *delims, enum strsplit flags)
|
|
|
{
|
|
{
|
|
|
- char **lines = NULL;
|
|
|
|
|
|
|
+ char **parts, *str;
|
|
|
size_t max = 64, num = 0;
|
|
size_t max = 64, num = 0;
|
|
|
|
|
|
|
|
- lines = tal_arr(ctx, char *, max+1);
|
|
|
|
|
|
|
+ parts = tal_arr(ctx, char *, max + 1);
|
|
|
|
|
+ if (unlikely(!parts)) {
|
|
|
|
|
+ if (taken(string))
|
|
|
|
|
+ tal_free(string);
|
|
|
|
|
+ if (taken(delims))
|
|
|
|
|
+ tal_free(delims);
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ str = tal_strdup(parts, string);
|
|
|
|
|
+ if (unlikely(!str))
|
|
|
|
|
+ goto fail;
|
|
|
|
|
+ if (unlikely(!delims) && is_taken(delims))
|
|
|
|
|
+ goto fail;
|
|
|
|
|
|
|
|
if (flags == STR_NO_EMPTY)
|
|
if (flags == STR_NO_EMPTY)
|
|
|
- string += strspn(string, delims);
|
|
|
|
|
|
|
+ str += strspn(str, delims);
|
|
|
|
|
|
|
|
- while (*string != '\0') {
|
|
|
|
|
- size_t len = strcspn(string, delims), dlen;
|
|
|
|
|
|
|
+ while (*str != '\0') {
|
|
|
|
|
+ size_t len = strcspn(str, delims), dlen;
|
|
|
|
|
|
|
|
- lines[num] = tal_arr(lines, char, len + 1);
|
|
|
|
|
- memcpy(lines[num], string, len);
|
|
|
|
|
- lines[num][len] = '\0';
|
|
|
|
|
- string += len;
|
|
|
|
|
- dlen = strspn(string, delims);
|
|
|
|
|
|
|
+ parts[num] = str;
|
|
|
|
|
+ dlen = strspn(str + len, delims);
|
|
|
|
|
+ parts[num][len] = '\0';
|
|
|
if (flags == STR_EMPTY_OK && dlen)
|
|
if (flags == STR_EMPTY_OK && dlen)
|
|
|
dlen = 1;
|
|
dlen = 1;
|
|
|
- string += dlen;
|
|
|
|
|
- if (++num == max)
|
|
|
|
|
- tal_resize(&lines, max*=2 + 1);
|
|
|
|
|
|
|
+ str += len + dlen;
|
|
|
|
|
+ if (++num == max && !tal_resize(&parts, max*=2 + 1))
|
|
|
|
|
+ goto fail;
|
|
|
}
|
|
}
|
|
|
- lines[num] = NULL;
|
|
|
|
|
- return lines;
|
|
|
|
|
|
|
+ parts[num] = NULL;
|
|
|
|
|
+ if (taken(delims))
|
|
|
|
|
+ tal_free(delims);
|
|
|
|
|
+ return parts;
|
|
|
|
|
+
|
|
|
|
|
+fail:
|
|
|
|
|
+ tal_free(parts);
|
|
|
|
|
+ if (taken(delims))
|
|
|
|
|
+ tal_free(delims);
|
|
|
|
|
+ return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-char *strjoin(const void *ctx, char *strings[], const char *delim,
|
|
|
|
|
- enum strjoin flags)
|
|
|
|
|
|
|
+char *strjoin(const tal_t *ctx,
|
|
|
|
|
+ char *strings[], const char *delim, enum strjoin flags)
|
|
|
{
|
|
{
|
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
- char *ret = tal_strdup(ctx, "");
|
|
|
|
|
- size_t totlen = 0, dlen = strlen(delim);
|
|
|
|
|
|
|
+ char *ret = NULL;
|
|
|
|
|
+ size_t totlen = 0, dlen;
|
|
|
|
|
|
|
|
|
|
+ if (unlikely(!strings) && is_taken(strings))
|
|
|
|
|
+ goto fail;
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(!delim) && is_taken(delim))
|
|
|
|
|
+ goto fail;
|
|
|
|
|
+
|
|
|
|
|
+ dlen = strlen(delim);
|
|
|
|
|
+ ret = tal_arr(ctx, char, dlen*2+1);
|
|
|
|
|
+ if (!ret)
|
|
|
|
|
+ goto fail;
|
|
|
|
|
+
|
|
|
|
|
+ ret[0] = '\0';
|
|
|
for (i = 0; strings[i]; i++) {
|
|
for (i = 0; strings[i]; i++) {
|
|
|
size_t len = strlen(strings[i]);
|
|
size_t len = strlen(strings[i]);
|
|
|
|
|
+
|
|
|
if (flags == STR_NO_TRAIL && !strings[i+1])
|
|
if (flags == STR_NO_TRAIL && !strings[i+1])
|
|
|
dlen = 0;
|
|
dlen = 0;
|
|
|
- tal_resize(&ret, totlen + len + dlen + 1);
|
|
|
|
|
|
|
+ if (!tal_resize(&ret, totlen + len + dlen + 1))
|
|
|
|
|
+ goto fail;
|
|
|
memcpy(ret + totlen, strings[i], len);
|
|
memcpy(ret + totlen, strings[i], len);
|
|
|
totlen += len;
|
|
totlen += len;
|
|
|
memcpy(ret + totlen, delim, dlen);
|
|
memcpy(ret + totlen, delim, dlen);
|
|
|
totlen += dlen;
|
|
totlen += dlen;
|
|
|
}
|
|
}
|
|
|
ret[totlen] = '\0';
|
|
ret[totlen] = '\0';
|
|
|
|
|
+out:
|
|
|
|
|
+ if (taken(strings))
|
|
|
|
|
+ tal_free(strings);
|
|
|
|
|
+ if (taken(delim))
|
|
|
|
|
+ tal_free(delim);
|
|
|
return ret;
|
|
return ret;
|
|
|
|
|
+fail:
|
|
|
|
|
+ ret = tal_free(ret);
|
|
|
|
|
+ goto out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-bool strreg(const void *ctx, const char *string, const char *regex, ...)
|
|
|
|
|
|
|
+bool strreg(const tal_t *ctx, const char *string, const char *regex, ...)
|
|
|
{
|
|
{
|
|
|
size_t nmatch = 1 + strcount(regex, "(");
|
|
size_t nmatch = 1 + strcount(regex, "(");
|
|
|
- regmatch_t *matches = tal_arr(ctx, regmatch_t, nmatch);
|
|
|
|
|
|
|
+ regmatch_t matches[nmatch];
|
|
|
regex_t r;
|
|
regex_t r;
|
|
|
- bool ret;
|
|
|
|
|
-
|
|
|
|
|
- if (!matches || regcomp(&r, regex, REG_EXTENDED) != 0)
|
|
|
|
|
- return false;
|
|
|
|
|
-
|
|
|
|
|
- if (regexec(&r, string, nmatch, matches, 0) == 0) {
|
|
|
|
|
- unsigned int i;
|
|
|
|
|
- va_list ap;
|
|
|
|
|
-
|
|
|
|
|
- ret = true;
|
|
|
|
|
- va_start(ap, regex);
|
|
|
|
|
- for (i = 1; i < nmatch; i++) {
|
|
|
|
|
- char **arg;
|
|
|
|
|
- arg = va_arg(ap, char **);
|
|
|
|
|
- if (arg) {
|
|
|
|
|
- /* eg. ([a-z])? can give "no match". */
|
|
|
|
|
- if (matches[i].rm_so == -1)
|
|
|
|
|
- *arg = NULL;
|
|
|
|
|
- else {
|
|
|
|
|
- *arg = tal_strndup(ctx,
|
|
|
|
|
- string + matches[i].rm_so,
|
|
|
|
|
- matches[i].rm_eo
|
|
|
|
|
- - matches[i].rm_so);
|
|
|
|
|
- if (!*arg) {
|
|
|
|
|
- ret = false;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ bool ret = false;
|
|
|
|
|
+ unsigned int i;
|
|
|
|
|
+ va_list ap;
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(!regex) && is_taken(regex))
|
|
|
|
|
+ goto fail_no_re;
|
|
|
|
|
+
|
|
|
|
|
+ if (regcomp(&r, regex, REG_EXTENDED) != 0)
|
|
|
|
|
+ goto fail_no_re;
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(!string) && is_taken(string))
|
|
|
|
|
+ goto fail;
|
|
|
|
|
+
|
|
|
|
|
+ if (regexec(&r, string, nmatch, matches, 0) != 0)
|
|
|
|
|
+ goto fail;
|
|
|
|
|
+
|
|
|
|
|
+ ret = true;
|
|
|
|
|
+ va_start(ap, regex);
|
|
|
|
|
+ for (i = 1; i < nmatch; i++) {
|
|
|
|
|
+ char **arg = va_arg(ap, char **);
|
|
|
|
|
+ if (arg) {
|
|
|
|
|
+ /* eg. ([a-z])? can give "no match". */
|
|
|
|
|
+ if (matches[i].rm_so == -1)
|
|
|
|
|
+ *arg = NULL;
|
|
|
|
|
+ else {
|
|
|
|
|
+ *arg = tal_strndup(ctx,
|
|
|
|
|
+ string + matches[i].rm_so,
|
|
|
|
|
+ matches[i].rm_eo
|
|
|
|
|
+ - matches[i].rm_so);
|
|
|
|
|
+ /* FIXME: If we fail, we set some and leak! */
|
|
|
|
|
+ if (!*arg) {
|
|
|
|
|
+ ret = false;
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- va_end(ap);
|
|
|
|
|
- } else
|
|
|
|
|
- ret = false;
|
|
|
|
|
- tal_free(matches);
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ va_end(ap);
|
|
|
|
|
+fail:
|
|
|
regfree(&r);
|
|
regfree(&r);
|
|
|
|
|
+fail_no_re:
|
|
|
|
|
+ if (taken(regex))
|
|
|
|
|
+ tal_free(regex);
|
|
|
|
|
+ if (taken(string))
|
|
|
|
|
+ tal_free(string);
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|