summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--builtin.c3
-rw-r--r--jv.c48
-rw-r--r--jv.h1
3 files changed, 52 insertions, 0 deletions
diff --git a/builtin.c b/builtin.c
index 1e38482d..07682266 100644
--- a/builtin.c
+++ b/builtin.c
@@ -160,6 +160,8 @@ static jv f_divide(jv input, jv a, jv b) {
jv_free(input);
if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
return jv_number(jv_number_value(a) / jv_number_value(b));
+ } else if (jv_get_kind(a) == JV_KIND_STRING && jv_get_kind(b) == JV_KIND_STRING) {
+ return jv_string_split(a, b);
} else {
return type_error2(a, b, "cannot be divided");
}
@@ -539,6 +541,7 @@ static const struct cfunction function_list[] = {
{(cfunction_ptr)f_keys, "keys", 1},
{(cfunction_ptr)f_startswith, "startswith", 2},
{(cfunction_ptr)f_endswith, "endswith", 2},
+ {(cfunction_ptr)jv_string_split, "split", 2},
{(cfunction_ptr)jv_string_explode, "explode", 1},
{(cfunction_ptr)jv_string_implode, "implode", 1},
{(cfunction_ptr)jv_setpath, "setpath", 3}, // FIXME typechecking
diff --git a/jv.c b/jv.c
index d9a908ce..671f8d2f 100644
--- a/jv.c
+++ b/jv.c
@@ -596,6 +596,54 @@ int jv_string_length_codepoints(jv j) {
return len;
}
+#ifndef HAVE_MEMMEM
+static const void *memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+ const char *h = haystack;
+ const char *n = needle;
+ size_t hi, hi2, ni;
+
+ if (haystacklen < needlelen || haystacklen == 0)
+ return NULL;
+ for (hi = 0; hi < (haystacklen - needlelen + 1); hi++) {
+ for (ni = 0, hi2 = hi; ni < needlelen; ni++, hi2++) {
+ if (h[hi2] != n[ni])
+ goto not_this;
+ }
+
+ return &h[hi];
+
+not_this:
+ continue;
+ }
+ return NULL;
+}
+#endif /* HAVE_MEMMEM */
+
+jv jv_string_split(jv j, jv sep) {
+ assert(jv_get_kind(j) == JV_KIND_STRING);
+ assert(jv_get_kind(sep) == JV_KIND_STRING);
+ const char *jstr = jv_string_value(j);
+ const char *sepstr = jv_string_value(sep);
+ const char *p, *s;
+ int jlen = jv_string_length_bytes(jv_copy(j));
+ int seplen = jv_string_length_bytes(jv_copy(sep));
+ jv a = jv_array();
+
+ assert(jv_get_refcnt(a) == 1);
+
+ for (p = jstr; p < jstr + jlen; p = s + seplen) {
+ s = memmem(p, (jstr + jlen) - p, sepstr, seplen);
+ if (s == NULL)
+ s = jstr + jlen;
+ a = jv_array_append(a, jv_string_sized(p, s - p));
+ }
+ jv_free(j);
+ jv_free(sep);
+ return a;
+}
+
jv jv_string_explode(jv j) {
assert(jv_get_kind(j) == JV_KIND_STRING);
const char* i = jv_string_value(j);
diff --git a/jv.h b/jv.h
index a0bc3d4b..921345c4 100644
--- a/jv.h
+++ b/jv.h
@@ -87,6 +87,7 @@ jv jv_string_fmt(const char*, ...);
jv jv_string_append_codepoint(jv a, uint32_t c);
jv jv_string_append_buf(jv a, const char* buf, int len);
jv jv_string_append_str(jv a, const char* str);
+jv jv_string_split(jv j, jv sep);
jv jv_string_explode(jv j);
jv jv_string_implode(jv j);