X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftal%2Fstr%2Fstr.c;h=b7df54c42af704eee6e1fbd9d941205ec54a2235;hp=0c07002b157404d4bf87e517a2de166802fb0216;hb=5582b011948769779b0d839d35873c2bc557f9cb;hpb=d873aaec1339baf45c37db7cbaa2d687656343ba diff --git a/ccan/tal/str/str.c b/ccan/tal/str/str.c index 0c07002b..b7df54c4 100644 --- a/ccan/tal/str/str.c +++ b/ccan/tal/str/str.c @@ -9,98 +9,222 @@ #include #include #include -#include +#include #include +#include +#include + +char *tal_strdup(const tal_t *ctx, const char *p) +{ + /* We have to let through NULL for take(). */ + return tal_dup_(ctx, p, 1, p ? strlen(p) + 1: 1, 0, false, + TAL_LABEL(char, "[]")); +} + +char *tal_strndup(const tal_t *ctx, const char *p, size_t n) +{ + size_t len; + char *ret; + + /* We have to let through NULL for take(). */ + if (likely(p)) { + len = strlen(p); + if (len > n) + len = n; + } else + len = n; + + ret = tal_dup_(ctx, p, 1, len, 1, false, TAL_LABEL(char, "[]")); + if (ret) + ret[len] = '\0'; + return ret; +} + +char *tal_asprintf(const tal_t *ctx, const char *fmt, ...) +{ + va_list ap; + char *ret; + + va_start(ap, fmt); + ret = tal_vasprintf(ctx, fmt, ap); + va_end(ap); + + return ret; +} + +char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap) +{ + size_t max; + char *buf; + int ret; + + if (!fmt && taken(fmt)) + return NULL; -char **strsplit(const void *ctx, const char *string, const char *delims, - enum strsplit flags) + /* A decent guess to start. */ + max = strlen(fmt) * 2; + buf = tal_arr(ctx, char, max); + while (buf) { + va_list ap2; + + va_copy(ap2, ap); + ret = vsnprintf(buf, max, fmt, ap2); + va_end(ap2); + + if (ret < max) + break; + if (!tal_resize(&buf, max *= 2)) + buf = tal_free(buf); + } + if (taken(fmt)) + tal_free(fmt); + return buf; +} + +char **tal_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; - 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) - 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) 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; + + /* Ensure that tal_count() is correct. */ + if (unlikely(!tal_resize(&parts, num+1))) + goto fail; + + 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 *tal_strjoin(const tal_t *ctx, + char *strings[], const char *delim, enum strjoin flags) { 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++) { size_t len = strlen(strings[i]); + if (flags == STR_NO_TRAIL && !strings[i+1]) 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); totlen += len; memcpy(ret + totlen, delim, dlen); totlen += dlen; } ret[totlen] = '\0'; +out: + if (taken(strings)) + tal_free(strings); + if (taken(delim)) + tal_free(delim); return ret; +fail: + ret = tal_free(ret); + goto out; } -bool strreg(const void *ctx, const char *string, const char *regex, ...) +bool tal_strreg(const tal_t *ctx, const char *string, const char *regex, ...) { size_t nmatch = 1 + strcount(regex, "("); - regmatch_t *matches = tal_arr(ctx, regmatch_t, nmatch); + regmatch_t matches[nmatch]; 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); +fail_no_re: + if (taken(regex)) + tal_free(regex); + if (taken(string)) + tal_free(string); return ret; }