From: Valentin Bartenev Date: Sun, 28 Jul 2019 10:19:03 +0000 (+0300) Subject: Added String.prototype.trimStrart() and String.prototype.trimEnd(). X-Git-Url: http://git.kaiwu.me/sitemap.xml?a=commitdiff_plain;h=65c34a6a0ac2d37a3f4e9a91cc0ab22c3e5c2719;p=njs.git Added String.prototype.trimStrart() and String.prototype.trimEnd(). --- diff --git a/njs/njs_string.c b/njs/njs_string.c index 3018ba1d..218d39fa 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -10,6 +10,10 @@ #include +#define NJS_TRIM_START 1 +#define NJS_TRIM_END 2 + + typedef struct { u_char *start; size_t size; @@ -68,6 +72,8 @@ static njs_ret_t njs_string_bytes_from_string(njs_vm_t *vm, const njs_value_t *args, nxt_uint_t nargs); 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_trim(njs_vm_t *vm, njs_value_t *value, + nxt_uint_t mode); static njs_ret_t njs_string_prototype_pad(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, nxt_bool_t pad_start); static njs_ret_t njs_string_match_multiple(njs_vm_t *vm, njs_value_t *args, @@ -2355,6 +2361,29 @@ njs_string_prototype_to_upper_case(njs_vm_t *vm, njs_value_t *args, static njs_ret_t njs_string_prototype_trim(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) +{ + return njs_string_trim(vm, &args[0], NJS_TRIM_START|NJS_TRIM_END); +} + + +static njs_ret_t +njs_string_prototype_trim_start(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_string_trim(vm, &args[0], NJS_TRIM_START); +} + + +static njs_ret_t +njs_string_prototype_trim_end(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_string_trim(vm, &args[0], NJS_TRIM_END); +} + + +static njs_ret_t +njs_string_trim(njs_vm_t *vm, njs_value_t *value, nxt_uint_t mode) { uint32_t u, trim, length; const u_char *p, *prev, *start, *end; @@ -2362,152 +2391,109 @@ njs_string_prototype_trim(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, trim = 0; - njs_string_prop(&string, &args[0]); + njs_string_prop(&string, value); - p = string.start; + start = string.start; end = string.start + string.size; if (string.length == 0 || string.length == string.size) { /* Byte or ASCII string. */ - while (p < end) { + if (mode & NJS_TRIM_START) { + for ( ;; ) { + if (start == end) { + goto empty; + } - switch (*p) { - case 0x09: /* */ - case 0x0A: /* */ - case 0x0B: /* */ - case 0x0C: /* */ - case 0x0D: /* */ - case 0x20: /* */ - case 0xA0: /* */ - trim++; - p++; - continue; + if (nxt_is_whitespace(*start)) { + start++; + trim++; + continue; + } - default: - start = p; - p = end; + break; + } + } - for ( ;; ) { - p--; - - switch (*p) { - case 0x09: /* */ - case 0x0A: /* */ - case 0x0B: /* */ - case 0x0C: /* */ - case 0x0D: /* */ - case 0x20: /* */ - case 0xA0: /* */ - trim++; - continue; - - default: - p++; - goto done; - } + if (mode & NJS_TRIM_END) { + for ( ;; ) { + if (start == end) { + goto empty; } + + end--; + + if (nxt_is_whitespace(*end)) { + trim++; + continue; + } + + end++; + break; } } } else { /* UTF-8 string. */ - while (p < end) { - prev = p; - u = nxt_utf8_decode(&p, end); - - switch (u) { - case 0x0009: /* */ - case 0x000A: /* */ - case 0x000B: /* */ - case 0x000C: /* */ - case 0x000D: /* */ - case 0x0020: /* */ - case 0x00A0: /* */ - case 0x1680: - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - case 0x2004: - case 0x2005: - case 0x2006: - case 0x2007: - case 0x2008: - case 0x2009: - case 0x200A: - case 0x2028: /* */ - case 0x2029: /* */ - case 0x202F: - case 0x205F: - case 0x3000: - case 0xFEFF: /* */ - trim++; - continue; + if (mode & NJS_TRIM_START) { + for ( ;; ) { + if (start == end) { + goto empty; + } - default: - start = prev; - prev = end; - - for ( ;; ) { - prev = nxt_utf8_prev(prev); - p = prev; - u = nxt_utf8_decode(&p, end); - - switch (u) { - case 0x0009: /* */ - case 0x000A: /* */ - case 0x000B: /* */ - case 0x000C: /* */ - case 0x000D: /* */ - case 0x0020: /* */ - case 0x00A0: /* */ - case 0x1680: - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - case 0x2004: - case 0x2005: - case 0x2006: - case 0x2007: - case 0x2008: - case 0x2009: - case 0x200A: - case 0x2028: /* */ - case 0x2029: /* */ - case 0x202F: - case 0x205F: - case 0x3000: - case 0xFEFF: /* */ - trim++; - continue; - - default: - goto done; - } + p = start; + u = nxt_utf8_decode(&start, end); + + if (nxt_utf8_is_whitespace(u)) { + trim++; + continue; } + + start = p; + break; } } - } - vm->retval = njs_string_empty; + if (mode & NJS_TRIM_END) { + prev = end; - return NXT_OK; + for ( ;; ) { + if (start == prev) { + goto empty; + } -done: + prev = nxt_utf8_prev(prev); + p = prev; + u = nxt_utf8_decode(&p, end); + + if (nxt_utf8_is_whitespace(u)) { + trim++; + continue; + } + + end = p; + break; + } + } + } if (trim == 0) { /* GC: retain. */ - vm->retval = args[0]; + vm->retval = *value; return NXT_OK; } length = (string.length != 0) ? string.length - trim : 0; - return njs_string_new(vm, &vm->retval, start, p - start, length); + return njs_string_new(vm, &vm->retval, start, end - start, length); + +empty: + + vm->retval = njs_string_empty; + + return NXT_OK; } @@ -4250,6 +4236,26 @@ static const njs_object_prop_t njs_string_prototype_properties[] = .configurable = 1, }, + /* ES10. */ + { + .type = NJS_METHOD, + .name = njs_string("trimStart"), + .value = njs_native_function(njs_string_prototype_trim_start, + NJS_STRING_OBJECT_ARG), + .writable = 1, + .configurable = 1, + }, + + /* ES10. */ + { + .type = NJS_METHOD, + .name = njs_string("trimEnd"), + .value = njs_native_function(njs_string_prototype_trim_end, + NJS_STRING_OBJECT_ARG), + .writable = 1, + .configurable = 1, + }, + /* ES6. */ { .type = NJS_METHOD, diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 0c3f0ade..cb3cc185 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -5623,7 +5623,7 @@ static njs_unit_test_t njs_test[] = nxt_string("304,453,456,459,498,1012,7838,8486,8490,8491") }, #endif - { nxt_string("'abc'.trim()"), + { nxt_string("'abc'.trimStart().trim().trimEnd()"), nxt_string("abc") }, { nxt_string("''.trim()"), @@ -5632,22 +5632,22 @@ static njs_unit_test_t njs_test[] = { nxt_string("' '.trim()"), nxt_string("") }, - { nxt_string("'abc '.trim()"), + { nxt_string("'abc '.trimEnd()"), nxt_string("abc") }, - { nxt_string("' abc'.trim()"), + { nxt_string("' abc'.trimStart()"), nxt_string("abc") }, { nxt_string("' abc '.trim()"), nxt_string("abc") }, - { nxt_string("'абв '.trim()"), + { nxt_string("'абв '.trimEnd()"), nxt_string("абв") }, - { nxt_string("' абв'.trim()"), + { nxt_string("' абв'.trimStart()"), nxt_string("абв") }, - { nxt_string("' абв '.trim()"), + { nxt_string("' абв '.trimStart().trimEnd()"), nxt_string("абв") }, { nxt_string("'\\u2029abc\\uFEFF\\u2028'.trim()"), diff --git a/nxt/nxt_string.h b/nxt/nxt_string.h index 20c8b1bb..d7c92024 100644 --- a/nxt/nxt_string.h +++ b/nxt/nxt_string.h @@ -41,6 +41,25 @@ nxt_upper_case(u_char c) } +nxt_inline nxt_bool_t +nxt_is_whitespace(u_char c) +{ + switch (c) { + case 0x09: /* */ + case 0x0A: /* */ + case 0x0B: /* */ + case 0x0C: /* */ + case 0x0D: /* */ + case 0x20: /* */ + case 0xA0: /* */ + return 1; + + default: + return 0; + } +} + + nxt_inline u_char * nxt_strlchr(u_char *p, u_char *last, u_char c) { diff --git a/nxt/nxt_utf8.h b/nxt/nxt_utf8.h index e2d78aa9..db1a865e 100644 --- a/nxt/nxt_utf8.h +++ b/nxt/nxt_utf8.h @@ -122,4 +122,41 @@ nxt_utf8_copy(u_char *dst, const u_char **src, const u_char *end) ((u < 0x80) ? 1 : ((u < 0x0800) ? 2 : 3)) +nxt_inline nxt_bool_t +nxt_utf8_is_whitespace(uint32_t c) +{ + switch (c) { + case 0x0009: /* */ + case 0x000A: /* */ + case 0x000B: /* */ + case 0x000C: /* */ + case 0x000D: /* */ + case 0x0020: /* */ + case 0x00A0: /* */ + case 0x1680: + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + case 0x2004: + case 0x2005: + case 0x2006: + case 0x2007: + case 0x2008: + case 0x2009: + case 0x200A: + case 0x2028: /* */ + case 0x2029: /* */ + case 0x202F: + case 0x205F: + case 0x3000: + case 0xFEFF: /* */ + return 1; + + default: + return 0; + } +} + + #endif /* _NXT_UTF8_H_INCLUDED_ */