damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

talstr.c (7232B)


      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 "talstr.h"
      8 #include <sys/types.h>
      9 #include <regex.h>
     10 #include <stdarg.h>
     11 #include <unistd.h>
     12 #include <stdio.h>
     13 #include "str.h"
     14 
     15 char *tal_strdup_(const tal_t *ctx, const char *p, const char *label)
     16 {
     17     /* We have to let through NULL for take(). */
     18     return tal_dup_arr_label(ctx, char, p, p ? strlen(p) + 1: 1, 0, label);
     19 }
     20 
     21 char *tal_strndup_(const tal_t *ctx, const char *p, size_t n, const char *label)
     22 {
     23     size_t len;
     24     char *ret;
     25 
     26     /* We have to let through NULL for take(). */
     27     if (likely(p))
     28         len = strnlen(p, n);
     29     else
     30         len = n;
     31 
     32     ret = tal_dup_arr_label(ctx, char, p, len, 1, label);
     33     if (ret)
     34         ret[len] = '\0';
     35     return ret;
     36 }
     37 
     38 char *tal_fmt_(const tal_t *ctx, const char *label, const char *fmt, ...)
     39 {
     40     va_list ap;
     41     char *ret;
     42 
     43     va_start(ap, fmt);
     44     ret = tal_vfmt_(ctx, fmt, ap, label);
     45     va_end(ap);
     46 
     47     return ret;
     48 }
     49 
     50 static bool do_vfmt(char **buf, size_t off, const char *fmt, va_list ap)
     51 {
     52     /* A decent guess to start. */
     53     size_t max = strlen(fmt) * 2 + 1;
     54     bool ok;
     55 
     56     for (;;) {
     57         va_list ap2;
     58         int ret;
     59 
     60         if (!tal_resize(buf, off + max)) {
     61             ok = false;
     62             break;
     63         }
     64 
     65         va_copy(ap2, ap);
     66         ret = vsnprintf(*buf + off, max, fmt, ap2);
     67         va_end(ap2);
     68 
     69         if (ret < max) {
     70             ok = true;
     71             /* Make sure tal_count() is correct! */
     72             tal_resize(buf, off + ret + 1);
     73             break;
     74         }
     75         max *= 2;
     76     }
     77 
     78     if (taken(fmt))
     79         tal_free(fmt);
     80     return ok;
     81 }
     82 
     83 char *tal_vfmt_(const tal_t *ctx, const char *fmt, va_list ap, const char *label)
     84 {
     85     char *buf;
     86 
     87     if (!fmt && taken(fmt))
     88         return NULL;
     89 
     90     /* A decent guess to start. */
     91     buf = tal_arr_label(ctx, char, strlen(fmt) * 2, label);
     92     if (!do_vfmt(&buf, 0, fmt, ap))
     93         buf = tal_free(buf);
     94     return buf;
     95 }
     96 
     97 bool tal_append_vfmt(char **baseptr, const char *fmt, va_list ap)
     98 {
     99     if (!fmt && taken(fmt))
    100         return false;
    101 
    102     return do_vfmt(baseptr, strlen(*baseptr), fmt, ap);
    103 }
    104 
    105 bool tal_append_fmt(char **baseptr, const char *fmt, ...)
    106 {
    107     va_list ap;
    108     bool ret;
    109 
    110     va_start(ap, fmt);
    111     ret = tal_append_vfmt(baseptr, fmt, ap);
    112     va_end(ap);
    113 
    114     return ret;
    115 }
    116 
    117 char *tal_strcat_(const tal_t *ctx, const char *s1, const char *s2,
    118           const char *label)
    119 {
    120     size_t len1, len2;
    121     char *ret;
    122 
    123     if (unlikely(!s2) && taken(s2)) {
    124         if (taken(s1))
    125             tal_free(s1);
    126         return NULL;
    127     }
    128     /* We have to let through NULL for take(). */
    129     len1 = s1 ? strlen(s1) : 0;
    130     len2 = strlen(s2);
    131 
    132     ret = tal_dup_arr_label(ctx, char, s1, len1, len2 + 1, label);
    133     if (likely(ret))
    134         memcpy(ret + len1, s2, len2 + 1);
    135 
    136     if (taken(s2))
    137         tal_free(s2);
    138     return ret;
    139 }
    140 
    141 char **tal_strsplit_(const tal_t *ctx,
    142              const char *string, const char *delims, enum strsplit flags,
    143              const char *label)
    144 {
    145     char **parts, *str;
    146     size_t max = 64, num = 0;
    147 
    148     parts = tal_arr(ctx, char *, max + 1);
    149     if (unlikely(!parts)) {
    150         if (taken(string))
    151             tal_free(string);
    152         if (taken(delims))
    153             tal_free(delims);
    154         return NULL;
    155     }
    156     str = tal_strdup(parts, string);
    157     if (unlikely(!str))
    158         goto fail;
    159     if (unlikely(!delims) && is_taken(delims))
    160         goto fail;
    161 
    162     if (flags == STR_NO_EMPTY)
    163         str += strspn(str, delims);
    164 
    165     while (*str != '\0') {
    166         size_t len = strcspn(str, delims), dlen;
    167 
    168         parts[num] = str;
    169         dlen = strspn(str + len, delims);
    170         parts[num][len] = '\0';
    171         if (flags == STR_EMPTY_OK && dlen)
    172             dlen = 1;
    173         str += len + dlen;
    174         if (++num == max && !tal_resize(&parts, max*=2 + 1))
    175             goto fail;
    176     }
    177     parts[num] = NULL;
    178 
    179     /* Ensure that tal_count() is correct. */
    180     if (unlikely(!tal_resize(&parts, num+1)))
    181         goto fail;
    182 
    183     if (taken(delims))
    184         tal_free(delims);
    185     return parts;
    186 
    187 fail:
    188     tal_free(parts);
    189     if (taken(delims))
    190         tal_free(delims);
    191     return NULL;
    192 }
    193 
    194 char *tal_strjoin_(const tal_t *ctx,
    195            char *strings[], const char *delim, enum strjoin flags,
    196            const char *label)
    197 {
    198     unsigned int i;
    199     char *ret = NULL;
    200     size_t totlen = 0, dlen;
    201 
    202     if (unlikely(!strings) && is_taken(strings))
    203         goto fail;
    204 
    205     if (unlikely(!delim) && is_taken(delim))
    206         goto fail;
    207 
    208     dlen = strlen(delim);
    209     ret = tal_arr_label(ctx, char, dlen*2+1, label);
    210     if (!ret)
    211         goto fail;
    212 
    213     ret[0] = '\0';
    214     for (i = 0; strings[i]; i++) {
    215         size_t len = strlen(strings[i]);
    216 
    217         if (flags == STR_NO_TRAIL && !strings[i+1])
    218             dlen = 0;
    219         if (!tal_resize(&ret, totlen + len + dlen + 1))
    220             goto fail;
    221         memcpy(ret + totlen, strings[i], len);
    222         totlen += len;
    223         memcpy(ret + totlen, delim, dlen);
    224         totlen += dlen;
    225     }
    226     ret[totlen] = '\0';
    227     /* Make sure tal_count() is correct! */
    228     tal_resize(&ret, totlen+1);
    229 out:
    230     if (taken(strings))
    231         tal_free(strings);
    232     if (taken(delim))
    233         tal_free(delim);
    234     return ret;
    235 fail:
    236     ret = tal_free(ret);
    237     goto out;
    238 }
    239 
    240 static size_t count_open_braces(const char *string)
    241 {
    242 #if 1
    243     size_t num = 0, esc = 0;
    244 
    245     while (*string) {
    246         if (*string == '\\')
    247             esc++;
    248         else {
    249             /* An odd number of \ means it's escaped. */
    250             if (*string == '(' && (esc & 1) == 0)
    251                 num++;
    252             esc = 0;
    253         }
    254         string++;
    255     }
    256     return num;
    257 #else
    258     return strcount(string, "(");
    259 #endif
    260 }
    261 
    262 bool tal_strreg_(const tal_t *ctx, const char *string, const char *label,
    263          const char *regex, ...)
    264 {
    265     size_t nmatch = 1 + count_open_braces(regex);
    266     regmatch_t matches[nmatch];
    267     regex_t r;
    268     bool ret = false;
    269     unsigned int i;
    270     va_list ap;
    271 
    272     if (unlikely(!regex) && is_taken(regex))
    273         goto fail_no_re;
    274 
    275     if (regcomp(&r, regex, REG_EXTENDED) != 0)
    276         goto fail_no_re;
    277 
    278     if (unlikely(!string) && is_taken(string))
    279         goto fail;
    280 
    281     if (regexec(&r, string, nmatch, matches, 0) != 0)
    282         goto fail;
    283 
    284     ret = true;
    285     va_start(ap, regex);
    286     for (i = 1; i < nmatch; i++) {
    287         char **arg = va_arg(ap, char **);
    288         if (arg) {
    289             /* eg. ([a-z])? can give "no match". */
    290             if (matches[i].rm_so == -1)
    291                 *arg = NULL;
    292             else {
    293                 *arg = tal_strndup_(ctx,
    294                             string + matches[i].rm_so,
    295                             matches[i].rm_eo
    296                             - matches[i].rm_so,
    297                             label);
    298                 /* FIXME: If we fail, we set some and leak! */
    299                 if (!*arg) {
    300                     ret = false;
    301                     break;
    302                 }
    303             }
    304         }
    305     }
    306     va_end(ap);
    307 fail:
    308     regfree(&r);
    309 fail_no_re:
    310     if (taken(regex))
    311         tal_free(regex);
    312     if (taken(string))
    313         tal_free(string);
    314     return ret;
    315 }