From 8a0a6e92d2fc01331b4a7c80f7d7569625af352a Mon Sep 17 00:00:00 2001 From: Fabrice Bellard Date: Wed, 10 Sep 2025 18:25:34 +0200 Subject: [PATCH] better pretty printing of strings - removed String.prototype.__quote() --- quickjs.c | 82 +++++++++++++++++++++++++++++++-------------- tests/test_bjson.js | 2 +- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/quickjs.c b/quickjs.c index b93e282..2ca46aa 100644 --- a/quickjs.c +++ b/quickjs.c @@ -13126,18 +13126,61 @@ static uint32_t js_string_get_length(JSValueConst val) } } -static void js_dump_char(JSPrintValueState *s, int c, int sep) +/* pretty print the first 'len' characters of 'p' */ +static void js_print_string1(JSPrintValueState *s, JSString *p, int len, int sep) { - if (c == sep || c == '\\') { - js_putc(s, '\\'); - js_putc(s, c); - } else if (c >= ' ' && c <= 126) { - js_putc(s, c); - } else if (c == '\n') { - js_putc(s, '\\'); - js_putc(s, 'n'); - } else { - js_printf(s, "\\u%04x", c); + uint8_t buf[UTF8_CHAR_LEN_MAX]; + int l, i, c, c1; + + for(i = 0; i < len; i++) { + c = string_get(p, i); + switch(c) { + case '\t': + c = 't'; + goto quote; + case '\r': + c = 'r'; + goto quote; + case '\n': + c = 'n'; + goto quote; + case '\b': + c = 'b'; + goto quote; + case '\f': + c = 'f'; + goto quote; + case '\\': + quote: + js_putc(s, '\\'); + js_putc(s, c); + break; + default: + if (c == sep) + goto quote; + if (c >= 32 && c <= 126) { + js_putc(s, c); + } else if (c < 32 || + (c >= 0x7f && c <= 0x9f)) { + escape: + js_printf(s, "\\u%04x", c); + } else { + if (is_hi_surrogate(c)) { + if ((i + 1) >= len) + goto escape; + c1 = string_get(p, i + 1); + if (!is_lo_surrogate(c1)) + goto escape; + i++; + c = from_surrogate(c, c1); + } else if (is_lo_surrogate(c)) { + goto escape; + } + l = unicode_to_utf8(buf, c); + s->write_func(s->write_opaque, (char *)buf, l); + } + break; + } } } @@ -13146,12 +13189,10 @@ static void js_print_string_rec(JSPrintValueState *s, JSValueConst val, { if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) { JSString *p = JS_VALUE_GET_STRING(val); - uint32_t i, len; + uint32_t len; if (pos < s->options.max_string_length) { len = min_uint32(p->len, s->options.max_string_length - pos); - for(i = 0; i < len; i++) { - js_dump_char(s, string_get(p, i), sep); - } + js_print_string1(s, p, len, sep); } } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) { JSStringRope *r = JS_VALUE_GET_PTR(val); @@ -13224,9 +13265,7 @@ static void js_print_atom(JSPrintValueState *s, JSAtom atom) } } else { js_putc(s, '"'); - for(i = 0; i < p->len; i++) { - js_dump_char(s, string_get(p, i), '\"'); - } + js_print_string1(s, p, p->len, '\"'); js_putc(s, '"'); } } @@ -43859,12 +43898,6 @@ static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val, return ret; } -static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToQuotedString(ctx, this_val); -} - /* return 0 if before the first char */ static int string_prevc(JSString *p, int *pidx) { @@ -44352,7 +44385,6 @@ static const JSCFunctionListEntry js_string_proto_funcs[] = { JS_ALIAS_DEF("trimLeft", "trimStart" ), JS_CFUNC_DEF("toString", 0, js_string_toString ), JS_CFUNC_DEF("valueOf", 0, js_string_toString ), - JS_CFUNC_DEF("__quote", 1, js_string___quote ), JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ), JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ), JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ), diff --git a/tests/test_bjson.js b/tests/test_bjson.js index a90bfe1..8794b22 100644 --- a/tests/test_bjson.js +++ b/tests/test_bjson.js @@ -86,7 +86,7 @@ function toStr(a) case "undefined": return "undefined"; case "string": - return a.__quote(); + return JSON.stringify(a); case "number": if (a == 0 && 1 / a < 0) return "-0";