]> granicus.if.org Git - jq/commitdiff
Add string division by string (split on separator)
authorNicolas Williams <nico@cryptonector.com>
Fri, 29 Nov 2013 04:27:23 +0000 (22:27 -0600)
committerNicolas Williams <nico@cryptonector.com>
Thu, 5 Dec 2013 00:21:39 +0000 (18:21 -0600)
builtin.c
jv.c
jv.h

index 1e38482d36f2f87080ad26d24960e192f336f516..07682266dc7c20ecb36788998b620ed0bd495379 100644 (file)
--- 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 d9a908ce9028a2ea164f06d2a231f09da1ea638e..671f8d2f8cda20d7148f6c041c19566f3e48ec65 100644 (file)
--- 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 a0bc3d4bffa0e7d619874c8010affca0e8f2c972..921345c4cfa40fb2fa9d2e4b6b19a7aa9404ebba 100644 (file)
--- 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);