[njs] String.startsWith() and String.endsWith() methods.

Valentin Bartenev vbart at nginx.com
Wed Nov 9 09:36:29 UTC 2016


details:   http://hg.nginx.org/njs/rev/cfd1e7ae9a07
branches:  
changeset: 242:cfd1e7ae9a07
user:      Valentin Bartenev <vbart at nginx.com>
date:      Wed Nov 09 12:37:59 2016 +0300
description:
String.startsWith() and String.endsWith() methods.

diffstat:

 njs/njs_string.c         |  107 +++++++++++++++++++++++++++++++++++++++++++++++
 njs/test/njs_unit_test.c |   45 +++++++++++++++++++
 2 files changed, 152 insertions(+), 0 deletions(-)

diffs (186 lines):

diff -r ad4b6e0b5014 -r cfd1e7ae9a07 njs/njs_string.c
--- a/njs/njs_string.c	Sun Nov 06 16:03:29 2016 +0300
+++ b/njs/njs_string.c	Wed Nov 09 12:37:59 2016 +0300
@@ -83,6 +83,8 @@ static nxt_noinline void njs_string_slic
     njs_value_t *args, nxt_uint_t nargs);
 static njs_ret_t njs_string_from_char_code(njs_vm_t *vm,
     njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_string_starts_or_ends_with(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, nxt_bool_t starts);
 static njs_ret_t njs_string_match_multiple(njs_vm_t *vm, njs_value_t *args,
     njs_regexp_pattern_t *pattern);
 static njs_ret_t njs_string_split_part_add(njs_vm_t *vm, njs_array_t *array,
@@ -1441,6 +1443,95 @@ done:
 }
 
 
+static njs_ret_t
+njs_string_prototype_starts_with(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused)
+{
+    return njs_string_starts_or_ends_with(vm, args, nargs, 1);
+}
+
+
+static njs_ret_t
+njs_string_prototype_ends_with(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused)
+{
+    return njs_string_starts_or_ends_with(vm, args, nargs, 0);
+}
+
+
+static njs_ret_t
+njs_string_starts_or_ends_with(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, nxt_bool_t starts)
+{
+    ssize_t            index, length, search_length;
+    const u_char       *p, *end;
+    const njs_value_t  *retval;
+    njs_string_prop_t  string, search;
+
+    retval = &njs_value_true;
+
+    if (nargs > 1) {
+        search_length = njs_string_prop(&search, &args[1]);
+
+        if (search_length == 0) {
+            goto done;
+        }
+
+        length = njs_string_prop(&string, &args[0]);
+
+        index = (nargs > 2) ? args[2].data.u.number : -1;
+
+        if (starts) {
+            if (index < 0) {
+                index = 0;
+            }
+
+            if (length - index < search_length) {
+                goto small;
+            }
+
+        } else {
+            if (index < 0 || index > length) {
+                index = length;
+            }
+
+            index -= search_length;
+
+            if (index < 0) {
+                goto small;
+            }
+        }
+
+        end = string.start + string.size;
+
+        if (string.size == (size_t) length) {
+            /* Byte or ASCII string. */
+            p = string.start + index;
+
+        } else {
+            /* UTF-8 string. */
+            p = njs_string_offset(string.start, end, index);
+        }
+
+        if ((size_t) (end - p) >= search.size
+            && memcmp(p, search.start, search.size) == 0)
+        {
+            goto done;
+        }
+    }
+
+small:
+
+    retval = &njs_value_false;
+
+done:
+
+    vm->retval = *retval;
+
+    return NXT_OK;
+}
+
+
 /*
  * njs_string_offset() assumes that index is correct
  * and the optional offset map has been initialized.
@@ -3075,6 +3166,22 @@ static const njs_object_prop_t  njs_stri
                      NJS_STRING_OBJECT_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG),
     },
 
+    /* ES6. */
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("startsWith"),
+        .value = njs_native_function(njs_string_prototype_starts_with, 0,
+                     NJS_STRING_OBJECT_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG),
+    },
+
+    /* ES6. */
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("endsWith"),
+        .value = njs_native_function(njs_string_prototype_ends_with, 0,
+                     NJS_STRING_OBJECT_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG),
+    },
+
     {
         .type = NJS_METHOD,
         .name = njs_string("toLowerCase"),
diff -r ad4b6e0b5014 -r cfd1e7ae9a07 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Sun Nov 06 16:03:29 2016 +0300
+++ b/njs/test/njs_unit_test.c	Wed Nov 09 12:37:59 2016 +0300
@@ -3291,6 +3291,51 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("'абв абв абвгдежз'.includes('абвгд', 9)"),
       nxt_string("false") },
 
+    { nxt_string("''.startsWith('')"),
+      nxt_string("true") },
+
+    { nxt_string("'12345'.startsWith()"),
+      nxt_string("false") },
+
+    { nxt_string("'abc'.startsWith('abc')"),
+      nxt_string("true") },
+
+    { nxt_string("'abc'.startsWith('abc', 1)"),
+      nxt_string("false") },
+
+    { nxt_string("'abc'.startsWith('abc', -1)"),
+      nxt_string("true") },
+
+    { nxt_string("'абв абв абвгдежз'.startsWith('абвгд', 8)"),
+      nxt_string("true") },
+
+    { nxt_string("'абв абв абвгдежз'.startsWith('абвгд', 9)"),
+      nxt_string("false") },
+
+    { nxt_string("''.endsWith('')"),
+      nxt_string("true") },
+
+    { nxt_string("'12345'.endsWith()"),
+      nxt_string("false") },
+
+    { nxt_string("'abc'.endsWith('abc')"),
+      nxt_string("true") },
+
+    { nxt_string("'abc'.endsWith('abc', 4)"),
+      nxt_string("true") },
+
+    { nxt_string("'abc'.endsWith('abc', 1)"),
+      nxt_string("false") },
+
+    { nxt_string("'abc'.endsWith('abc', -1)"),
+      nxt_string("true") },
+
+    { nxt_string("'абв абв абвгдежз'.endsWith('абвгд', 13)"),
+      nxt_string("true") },
+
+    { nxt_string("'абв абв абвгдежз'.endsWith('абвгд', 14)"),
+      nxt_string("false") },
+
     { nxt_string("'ABC'.toLowerCase()"),
       nxt_string("abc") },
 


More information about the nginx-devel mailing list