@scriptc/runtime 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/package.json +16 -6
- package/src/scr_array.c +488 -0
- package/src/scr_assert.c +1393 -0
- package/src/scr_async.c +2593 -0
- package/src/scr_async_dyn.c +607 -0
- package/src/scr_bytes.c +1425 -0
- package/src/scr_bytes_io.c +161 -0
- package/src/scr_child.c +3587 -0
- package/src/scr_closure.c +214 -0
- package/src/scr_console.c +143 -0
- package/src/scr_cycle.c +218 -0
- package/src/scr_dc.c +805 -0
- package/src/scr_dgram.c +1007 -0
- package/src/scr_dyn_handle.c +154 -0
- package/src/scr_dyn_invoke.c +644 -0
- package/src/scr_error.c +332 -0
- package/src/scr_events.c +714 -0
- package/src/scr_events_emitter.c +699 -0
- package/src/scr_exception.c +242 -0
- package/src/scr_fetch.c +1130 -0
- package/src/scr_fetch_curl.c +654 -0
- package/src/scr_http.c +3482 -0
- package/src/scr_http2.c +3030 -0
- package/src/scr_inspect.c +803 -0
- package/src/scr_inspect_island.c +51 -0
- package/src/scr_island.c +9363 -0
- package/src/scr_json.c +2151 -0
- package/src/scr_lib.c +3612 -0
- package/src/scr_loop_epoll.c +241 -0
- package/src/scr_loop_kqueue.c +121 -0
- package/src/scr_loop_wsapoll.c +208 -0
- package/src/scr_map.c +591 -0
- package/src/scr_net.c +3017 -0
- package/src/scr_net_island.c +458 -0
- package/src/scr_number.c +115 -0
- package/src/scr_object.c +25 -0
- package/src/scr_path.c +1266 -0
- package/src/scr_platform.h +119 -0
- package/src/scr_readline.c +287 -0
- package/src/scr_regex.c +1080 -0
- package/src/scr_runtime.h +5036 -0
- package/src/scr_stream.c +2877 -0
- package/src/scr_string.c +1176 -0
- package/src/scr_symbol.c +132 -0
- package/src/scr_test.c +662 -0
- package/src/scr_tls.c +1520 -0
- package/src/scr_union.c +105 -0
- package/src/scr_url.c +911 -0
- package/src/scr_url_internal.h +29 -0
- package/src/scr_url_params.c +561 -0
- package/src/scr_watch.c +568 -0
- package/src/scr_web.c +1778 -0
- package/src/scr_win.c +76 -0
- package/src/scr_zlib.c +197 -0
- package/src/scr_zlib_island.c +15 -0
- package/vendor/README.md +52 -0
- package/vendor/curl/COPYRIGHT +534 -0
- package/vendor/curl/include/curl/curl.h +3214 -0
- package/vendor/curl/include/curl/curlver.h +79 -0
- package/vendor/curl/include/curl/easy.h +125 -0
- package/vendor/curl/include/curl/header.h +74 -0
- package/vendor/curl/include/curl/mprintf.h +52 -0
- package/vendor/curl/include/curl/multi.h +460 -0
- package/vendor/curl/include/curl/options.h +70 -0
- package/vendor/curl/include/curl/stdcheaders.h +35 -0
- package/vendor/curl/include/curl/system.h +508 -0
- package/vendor/curl/include/curl/typecheck-gcc.h +716 -0
- package/vendor/curl/include/curl/urlapi.h +149 -0
- package/vendor/curl/include/curl/websockets.h +84 -0
- package/vendor/mbedtls/LICENSE +553 -0
- package/vendor/mbedtls/include/CMakeLists.txt +22 -0
- package/vendor/mbedtls/include/mbedtls/aes.h +631 -0
- package/vendor/mbedtls/include/mbedtls/aria.h +343 -0
- package/vendor/mbedtls/include/mbedtls/asn1.h +642 -0
- package/vendor/mbedtls/include/mbedtls/asn1write.h +390 -0
- package/vendor/mbedtls/include/mbedtls/base64.h +82 -0
- package/vendor/mbedtls/include/mbedtls/bignum.h +1088 -0
- package/vendor/mbedtls/include/mbedtls/block_cipher.h +76 -0
- package/vendor/mbedtls/include/mbedtls/build_info.h +194 -0
- package/vendor/mbedtls/include/mbedtls/camellia.h +305 -0
- package/vendor/mbedtls/include/mbedtls/ccm.h +526 -0
- package/vendor/mbedtls/include/mbedtls/chacha20.h +209 -0
- package/vendor/mbedtls/include/mbedtls/chachapoly.h +351 -0
- package/vendor/mbedtls/include/mbedtls/check_config.h +1149 -0
- package/vendor/mbedtls/include/mbedtls/cipher.h +1250 -0
- package/vendor/mbedtls/include/mbedtls/cmac.h +246 -0
- package/vendor/mbedtls/include/mbedtls/compat-2.x.h +46 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_crypto.h +578 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_from_psa.h +873 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_psa_from_legacy.h +359 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_psa_superset_legacy.h +145 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_ssl.h +91 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_x509.h +35 -0
- package/vendor/mbedtls/include/mbedtls/config_psa.h +61 -0
- package/vendor/mbedtls/include/mbedtls/constant_time.h +36 -0
- package/vendor/mbedtls/include/mbedtls/ctr_drbg.h +596 -0
- package/vendor/mbedtls/include/mbedtls/debug.h +156 -0
- package/vendor/mbedtls/include/mbedtls/des.h +385 -0
- package/vendor/mbedtls/include/mbedtls/dhm.h +972 -0
- package/vendor/mbedtls/include/mbedtls/ecdh.h +455 -0
- package/vendor/mbedtls/include/mbedtls/ecdsa.h +674 -0
- package/vendor/mbedtls/include/mbedtls/ecjpake.h +298 -0
- package/vendor/mbedtls/include/mbedtls/ecp.h +1517 -0
- package/vendor/mbedtls/include/mbedtls/entropy.h +274 -0
- package/vendor/mbedtls/include/mbedtls/error.h +201 -0
- package/vendor/mbedtls/include/mbedtls/gcm.h +387 -0
- package/vendor/mbedtls/include/mbedtls/hkdf.h +124 -0
- package/vendor/mbedtls/include/mbedtls/hmac_drbg.h +434 -0
- package/vendor/mbedtls/include/mbedtls/lms.h +440 -0
- package/vendor/mbedtls/include/mbedtls/mbedtls_config.h +4446 -0
- package/vendor/mbedtls/include/mbedtls/md.h +526 -0
- package/vendor/mbedtls/include/mbedtls/md5.h +190 -0
- package/vendor/mbedtls/include/mbedtls/memory_buffer_alloc.h +142 -0
- package/vendor/mbedtls/include/mbedtls/net_sockets.h +299 -0
- package/vendor/mbedtls/include/mbedtls/nist_kw.h +166 -0
- package/vendor/mbedtls/include/mbedtls/oid.h +727 -0
- package/vendor/mbedtls/include/mbedtls/pem.h +160 -0
- package/vendor/mbedtls/include/mbedtls/pk.h +1303 -0
- package/vendor/mbedtls/include/mbedtls/pkcs12.h +186 -0
- package/vendor/mbedtls/include/mbedtls/pkcs5.h +198 -0
- package/vendor/mbedtls/include/mbedtls/pkcs7.h +252 -0
- package/vendor/mbedtls/include/mbedtls/platform.h +516 -0
- package/vendor/mbedtls/include/mbedtls/platform_time.h +79 -0
- package/vendor/mbedtls/include/mbedtls/platform_util.h +247 -0
- package/vendor/mbedtls/include/mbedtls/poly1305.h +168 -0
- package/vendor/mbedtls/include/mbedtls/private_access.h +20 -0
- package/vendor/mbedtls/include/mbedtls/psa_util.h +207 -0
- package/vendor/mbedtls/include/mbedtls/ripemd160.h +136 -0
- package/vendor/mbedtls/include/mbedtls/rsa.h +1170 -0
- package/vendor/mbedtls/include/mbedtls/sha1.h +219 -0
- package/vendor/mbedtls/include/mbedtls/sha256.h +200 -0
- package/vendor/mbedtls/include/mbedtls/sha3.h +172 -0
- package/vendor/mbedtls/include/mbedtls/sha512.h +208 -0
- package/vendor/mbedtls/include/mbedtls/ssl.h +5887 -0
- package/vendor/mbedtls/include/mbedtls/ssl_cache.h +187 -0
- package/vendor/mbedtls/include/mbedtls/ssl_ciphersuites.h +482 -0
- package/vendor/mbedtls/include/mbedtls/ssl_cookie.h +106 -0
- package/vendor/mbedtls/include/mbedtls/ssl_ticket.h +199 -0
- package/vendor/mbedtls/include/mbedtls/threading.h +167 -0
- package/vendor/mbedtls/include/mbedtls/timing.h +94 -0
- package/vendor/mbedtls/include/mbedtls/version.h +78 -0
- package/vendor/mbedtls/include/mbedtls/x509.h +500 -0
- package/vendor/mbedtls/include/mbedtls/x509_crl.h +184 -0
- package/vendor/mbedtls/include/mbedtls/x509_crt.h +1208 -0
- package/vendor/mbedtls/include/mbedtls/x509_csr.h +382 -0
- package/vendor/mbedtls/include/psa/build_info.h +20 -0
- package/vendor/mbedtls/include/psa/crypto.h +4998 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_auto_enabled.h +31 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_dependencies.h +51 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_key_pair_types.h +101 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_synonyms.h +49 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_composites.h +214 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_key_derivation.h +118 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_primitives.h +114 -0
- package/vendor/mbedtls/include/psa/crypto_compat.h +230 -0
- package/vendor/mbedtls/include/psa/crypto_config.h +145 -0
- package/vendor/mbedtls/include/psa/crypto_driver_common.h +44 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_composites.h +151 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_key_derivation.h +52 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_primitives.h +105 -0
- package/vendor/mbedtls/include/psa/crypto_extra.h +2145 -0
- package/vendor/mbedtls/include/psa/crypto_legacy.h +88 -0
- package/vendor/mbedtls/include/psa/crypto_platform.h +102 -0
- package/vendor/mbedtls/include/psa/crypto_se_driver.h +1383 -0
- package/vendor/mbedtls/include/psa/crypto_sizes.h +1319 -0
- package/vendor/mbedtls/include/psa/crypto_struct.h +527 -0
- package/vendor/mbedtls/include/psa/crypto_types.h +508 -0
- package/vendor/mbedtls/include/psa/crypto_values.h +2782 -0
- package/vendor/mbedtls/library/aes.c +2294 -0
- package/vendor/mbedtls/library/aesce.c +624 -0
- package/vendor/mbedtls/library/aesce.h +136 -0
- package/vendor/mbedtls/library/aesni.c +846 -0
- package/vendor/mbedtls/library/aesni.h +162 -0
- package/vendor/mbedtls/library/alignment.h +704 -0
- package/vendor/mbedtls/library/aria.c +969 -0
- package/vendor/mbedtls/library/asn1parse.c +468 -0
- package/vendor/mbedtls/library/asn1write.c +440 -0
- package/vendor/mbedtls/library/base64.c +322 -0
- package/vendor/mbedtls/library/base64_internal.h +45 -0
- package/vendor/mbedtls/library/bignum.c +2583 -0
- package/vendor/mbedtls/library/bignum_core.c +1240 -0
- package/vendor/mbedtls/library/bignum_core.h +872 -0
- package/vendor/mbedtls/library/bignum_core_invasive.h +38 -0
- package/vendor/mbedtls/library/bignum_internal.h +122 -0
- package/vendor/mbedtls/library/bignum_mod.c +394 -0
- package/vendor/mbedtls/library/bignum_mod.h +452 -0
- package/vendor/mbedtls/library/bignum_mod_raw.c +276 -0
- package/vendor/mbedtls/library/bignum_mod_raw.h +416 -0
- package/vendor/mbedtls/library/bignum_mod_raw_invasive.h +34 -0
- package/vendor/mbedtls/library/block_cipher.c +207 -0
- package/vendor/mbedtls/library/block_cipher_internal.h +99 -0
- package/vendor/mbedtls/library/bn_mul.h +1094 -0
- package/vendor/mbedtls/library/camellia.c +1058 -0
- package/vendor/mbedtls/library/ccm.c +777 -0
- package/vendor/mbedtls/library/chacha20.c +563 -0
- package/vendor/mbedtls/library/chacha20_internal.h +23 -0
- package/vendor/mbedtls/library/chachapoly.c +487 -0
- package/vendor/mbedtls/library/check_crypto_config.h +136 -0
- package/vendor/mbedtls/library/cipher.c +1712 -0
- package/vendor/mbedtls/library/cipher_invasive.h +28 -0
- package/vendor/mbedtls/library/cipher_wrap.c +2482 -0
- package/vendor/mbedtls/library/cipher_wrap.h +178 -0
- package/vendor/mbedtls/library/cmac.c +1067 -0
- package/vendor/mbedtls/library/common.h +487 -0
- package/vendor/mbedtls/library/constant_time.c +247 -0
- package/vendor/mbedtls/library/constant_time_impl.h +541 -0
- package/vendor/mbedtls/library/constant_time_internal.h +579 -0
- package/vendor/mbedtls/library/ctr.h +35 -0
- package/vendor/mbedtls/library/ctr_drbg.c +1016 -0
- package/vendor/mbedtls/library/debug.c +475 -0
- package/vendor/mbedtls/library/debug_internal.h +185 -0
- package/vendor/mbedtls/library/des.c +1042 -0
- package/vendor/mbedtls/library/dhm.c +700 -0
- package/vendor/mbedtls/library/ecdh.c +696 -0
- package/vendor/mbedtls/library/ecdsa.c +858 -0
- package/vendor/mbedtls/library/ecjpake.c +1216 -0
- package/vendor/mbedtls/library/ecp.c +3674 -0
- package/vendor/mbedtls/library/ecp_curves.c +6125 -0
- package/vendor/mbedtls/library/ecp_curves_new.c +9 -0
- package/vendor/mbedtls/library/ecp_internal_alt.h +287 -0
- package/vendor/mbedtls/library/ecp_invasive.h +305 -0
- package/vendor/mbedtls/library/entropy.c +680 -0
- package/vendor/mbedtls/library/entropy_poll.c +233 -0
- package/vendor/mbedtls/library/entropy_poll.h +64 -0
- package/vendor/mbedtls/library/error.c +878 -0
- package/vendor/mbedtls/library/gcm.c +1330 -0
- package/vendor/mbedtls/library/hkdf.c +161 -0
- package/vendor/mbedtls/library/hmac_drbg.c +633 -0
- package/vendor/mbedtls/library/lmots.c +789 -0
- package/vendor/mbedtls/library/lmots.h +288 -0
- package/vendor/mbedtls/library/lms.c +778 -0
- package/vendor/mbedtls/library/md.c +1108 -0
- package/vendor/mbedtls/library/md5.c +426 -0
- package/vendor/mbedtls/library/md_psa.h +26 -0
- package/vendor/mbedtls/library/md_wrap.h +46 -0
- package/vendor/mbedtls/library/memory_buffer_alloc.c +751 -0
- package/vendor/mbedtls/library/mps_common.h +181 -0
- package/vendor/mbedtls/library/mps_error.h +89 -0
- package/vendor/mbedtls/library/mps_reader.c +538 -0
- package/vendor/mbedtls/library/mps_reader.h +366 -0
- package/vendor/mbedtls/library/mps_trace.c +112 -0
- package/vendor/mbedtls/library/mps_trace.h +154 -0
- package/vendor/mbedtls/library/net_sockets.c +694 -0
- package/vendor/mbedtls/library/nist_kw.c +729 -0
- package/vendor/mbedtls/library/oid.c +1166 -0
- package/vendor/mbedtls/library/padlock.c +157 -0
- package/vendor/mbedtls/library/padlock.h +111 -0
- package/vendor/mbedtls/library/pem.c +554 -0
- package/vendor/mbedtls/library/pk.c +1602 -0
- package/vendor/mbedtls/library/pk_ecc.c +261 -0
- package/vendor/mbedtls/library/pk_internal.h +241 -0
- package/vendor/mbedtls/library/pk_wrap.c +1618 -0
- package/vendor/mbedtls/library/pk_wrap.h +138 -0
- package/vendor/mbedtls/library/pkcs12.c +437 -0
- package/vendor/mbedtls/library/pkcs5.c +500 -0
- package/vendor/mbedtls/library/pkcs7.c +787 -0
- package/vendor/mbedtls/library/pkparse.c +1392 -0
- package/vendor/mbedtls/library/pkwrite.c +631 -0
- package/vendor/mbedtls/library/pkwrite.h +121 -0
- package/vendor/mbedtls/library/platform.c +402 -0
- package/vendor/mbedtls/library/platform_util.c +258 -0
- package/vendor/mbedtls/library/poly1305.c +492 -0
- package/vendor/mbedtls/library/psa_crypto.c +9532 -0
- package/vendor/mbedtls/library/psa_crypto_aead.c +646 -0
- package/vendor/mbedtls/library/psa_crypto_aead.h +499 -0
- package/vendor/mbedtls/library/psa_crypto_cipher.c +747 -0
- package/vendor/mbedtls/library/psa_crypto_cipher.h +316 -0
- package/vendor/mbedtls/library/psa_crypto_client.c +22 -0
- package/vendor/mbedtls/library/psa_crypto_core.h +983 -0
- package/vendor/mbedtls/library/psa_crypto_core_common.h +52 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers.h +2896 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.c +256 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.h +31 -0
- package/vendor/mbedtls/library/psa_crypto_ecp.c +594 -0
- package/vendor/mbedtls/library/psa_crypto_ecp.h +267 -0
- package/vendor/mbedtls/library/psa_crypto_ffdh.c +361 -0
- package/vendor/mbedtls/library/psa_crypto_ffdh.h +131 -0
- package/vendor/mbedtls/library/psa_crypto_hash.c +470 -0
- package/vendor/mbedtls/library/psa_crypto_hash.h +211 -0
- package/vendor/mbedtls/library/psa_crypto_invasive.h +92 -0
- package/vendor/mbedtls/library/psa_crypto_its.h +131 -0
- package/vendor/mbedtls/library/psa_crypto_mac.c +505 -0
- package/vendor/mbedtls/library/psa_crypto_mac.h +264 -0
- package/vendor/mbedtls/library/psa_crypto_pake.c +571 -0
- package/vendor/mbedtls/library/psa_crypto_pake.h +159 -0
- package/vendor/mbedtls/library/psa_crypto_random.c +181 -0
- package/vendor/mbedtls/library/psa_crypto_random.h +72 -0
- package/vendor/mbedtls/library/psa_crypto_random_impl.h +200 -0
- package/vendor/mbedtls/library/psa_crypto_rsa.c +714 -0
- package/vendor/mbedtls/library/psa_crypto_rsa.h +321 -0
- package/vendor/mbedtls/library/psa_crypto_se.c +373 -0
- package/vendor/mbedtls/library/psa_crypto_se.h +192 -0
- package/vendor/mbedtls/library/psa_crypto_slot_management.c +1137 -0
- package/vendor/mbedtls/library/psa_crypto_slot_management.h +344 -0
- package/vendor/mbedtls/library/psa_crypto_storage.c +481 -0
- package/vendor/mbedtls/library/psa_crypto_storage.h +392 -0
- package/vendor/mbedtls/library/psa_its_file.c +254 -0
- package/vendor/mbedtls/library/psa_util.c +614 -0
- package/vendor/mbedtls/library/psa_util_internal.h +100 -0
- package/vendor/mbedtls/library/ripemd160.c +490 -0
- package/vendor/mbedtls/library/rsa.c +3121 -0
- package/vendor/mbedtls/library/rsa_alt_helpers.c +455 -0
- package/vendor/mbedtls/library/rsa_alt_helpers.h +209 -0
- package/vendor/mbedtls/library/rsa_internal.h +188 -0
- package/vendor/mbedtls/library/sha1.c +480 -0
- package/vendor/mbedtls/library/sha256.c +983 -0
- package/vendor/mbedtls/library/sha3.c +721 -0
- package/vendor/mbedtls/library/sha512.c +1115 -0
- package/vendor/mbedtls/library/ssl_cache.c +410 -0
- package/vendor/mbedtls/library/ssl_ciphersuites.c +2050 -0
- package/vendor/mbedtls/library/ssl_ciphersuites_internal.h +154 -0
- package/vendor/mbedtls/library/ssl_client.c +1023 -0
- package/vendor/mbedtls/library/ssl_client.h +22 -0
- package/vendor/mbedtls/library/ssl_cookie.c +384 -0
- package/vendor/mbedtls/library/ssl_debug_helpers.h +85 -0
- package/vendor/mbedtls/library/ssl_debug_helpers_generated.c +251 -0
- package/vendor/mbedtls/library/ssl_misc.h +3198 -0
- package/vendor/mbedtls/library/ssl_msg.c +6619 -0
- package/vendor/mbedtls/library/ssl_ticket.c +556 -0
- package/vendor/mbedtls/library/ssl_tls.c +10234 -0
- package/vendor/mbedtls/library/ssl_tls12_client.c +3688 -0
- package/vendor/mbedtls/library/ssl_tls12_server.c +4311 -0
- package/vendor/mbedtls/library/ssl_tls13_client.c +3208 -0
- package/vendor/mbedtls/library/ssl_tls13_generic.c +1793 -0
- package/vendor/mbedtls/library/ssl_tls13_invasive.h +23 -0
- package/vendor/mbedtls/library/ssl_tls13_keys.c +1918 -0
- package/vendor/mbedtls/library/ssl_tls13_keys.h +668 -0
- package/vendor/mbedtls/library/ssl_tls13_server.c +3624 -0
- package/vendor/mbedtls/library/threading.c +193 -0
- package/vendor/mbedtls/library/threading_internal.h +28 -0
- package/vendor/mbedtls/library/timing.c +152 -0
- package/vendor/mbedtls/library/version.c +32 -0
- package/vendor/mbedtls/library/version_features.c +856 -0
- package/vendor/mbedtls/library/x509.c +1776 -0
- package/vendor/mbedtls/library/x509_create.c +570 -0
- package/vendor/mbedtls/library/x509_crl.c +708 -0
- package/vendor/mbedtls/library/x509_crt.c +3311 -0
- package/vendor/mbedtls/library/x509_csr.c +648 -0
- package/vendor/mbedtls/library/x509_internal.h +101 -0
- package/vendor/mbedtls/library/x509write.c +174 -0
- package/vendor/mbedtls/library/x509write_crt.c +688 -0
- package/vendor/mbedtls/library/x509write_csr.c +336 -0
- package/vendor/quickjs-ng/CMakeLists.txt +566 -0
- package/vendor/quickjs-ng/LICENSE +24 -0
- package/vendor/quickjs-ng/README.md +24 -0
- package/vendor/quickjs-ng/api-test.c +1195 -0
- package/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
- package/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
- package/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
- package/vendor/quickjs-ng/cutils.h +1998 -0
- package/vendor/quickjs-ng/dtoa.c +1619 -0
- package/vendor/quickjs-ng/dtoa.h +87 -0
- package/vendor/quickjs-ng/gen/function_source.c +81 -0
- package/vendor/quickjs-ng/gen/hello.c +53 -0
- package/vendor/quickjs-ng/gen/hello_module.c +106 -0
- package/vendor/quickjs-ng/gen/repl.c +3036 -0
- package/vendor/quickjs-ng/gen/standalone.c +323 -0
- package/vendor/quickjs-ng/gen/test_fib.c +81 -0
- package/vendor/quickjs-ng/libregexp-opcode.h +73 -0
- package/vendor/quickjs-ng/libregexp.c +3474 -0
- package/vendor/quickjs-ng/libregexp.h +101 -0
- package/vendor/quickjs-ng/libunicode-table.h +5173 -0
- package/vendor/quickjs-ng/libunicode.c +2069 -0
- package/vendor/quickjs-ng/libunicode.h +172 -0
- package/vendor/quickjs-ng/list.h +107 -0
- package/vendor/quickjs-ng/lre-test.c +52 -0
- package/vendor/quickjs-ng/qjs.c +762 -0
- package/vendor/quickjs-ng/qjsc.c +673 -0
- package/vendor/quickjs-ng/quickjs-atom.h +280 -0
- package/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
- package/vendor/quickjs-ng/quickjs-libc.c +5037 -0
- package/vendor/quickjs-ng/quickjs-libc.h +87 -0
- package/vendor/quickjs-ng/quickjs-opcode.h +377 -0
- package/vendor/quickjs-ng/quickjs.c +64041 -0
- package/vendor/quickjs-ng/quickjs.h +1447 -0
- package/vendor/quickjs-ng/run-test262.c +2374 -0
- package/vendor/quickjs-ng/unicode_gen.c +3121 -0
- package/vendor/quickjs-ng/unicode_gen_def.h +310 -0
- package/vendor/ryu/LICENSE-Boost +23 -0
- package/vendor/ryu/common.h +114 -0
- package/vendor/ryu/d2s.c +509 -0
- package/vendor/ryu/d2s_full_table.h +367 -0
- package/vendor/ryu/d2s_intrinsics.h +357 -0
- package/vendor/ryu/d2s_small_table.h +186 -0
- package/vendor/ryu/digit_table.h +35 -0
- package/vendor/ryu/ryu.h +46 -0
- package/vendor/zlib/LICENSE +22 -0
- package/vendor/zlib/adler32.c +164 -0
- package/vendor/zlib/compress.c +75 -0
- package/vendor/zlib/crc32.c +1049 -0
- package/vendor/zlib/crc32.h +9446 -0
- package/vendor/zlib/deflate.c +2139 -0
- package/vendor/zlib/deflate.h +377 -0
- package/vendor/zlib/gzclose.c +23 -0
- package/vendor/zlib/gzguts.h +214 -0
- package/vendor/zlib/gzlib.c +582 -0
- package/vendor/zlib/gzread.c +602 -0
- package/vendor/zlib/gzwrite.c +631 -0
- package/vendor/zlib/infback.c +628 -0
- package/vendor/zlib/inffast.c +320 -0
- package/vendor/zlib/inffast.h +11 -0
- package/vendor/zlib/inffixed.h +94 -0
- package/vendor/zlib/inflate.c +1526 -0
- package/vendor/zlib/inflate.h +126 -0
- package/vendor/zlib/inftrees.c +299 -0
- package/vendor/zlib/inftrees.h +62 -0
- package/vendor/zlib/trees.c +1117 -0
- package/vendor/zlib/trees.h +128 -0
- package/vendor/zlib/uncompr.c +85 -0
- package/vendor/zlib/zconf.h +543 -0
- package/vendor/zlib/zlib.h +1938 -0
- package/vendor/zlib/zutil.c +299 -0
- package/vendor/zlib/zutil.h +254 -0
- package/README.md +0 -3
- package/index.js +0 -2
package/src/scr_string.c
ADDED
|
@@ -0,0 +1,1176 @@
|
|
|
1
|
+
#include "scr_runtime.h"
|
|
2
|
+
|
|
3
|
+
#include <math.h>
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
#include <string.h>
|
|
7
|
+
|
|
8
|
+
/* Live heap-string count for the RC audit lane (-DSCR_RC_AUDIT): the test
|
|
9
|
+
* harness builds with it to prove the emitted retain/release discipline
|
|
10
|
+
* leaks nothing and frees nothing twice (double-free shows up as ASan
|
|
11
|
+
* use-after-free on the rc field or a negative count here). */
|
|
12
|
+
#ifdef SCR_RC_AUDIT
|
|
13
|
+
static long scr_live_strings = 0;
|
|
14
|
+
long scr_str_live_count(void) { return scr_live_strings; }
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
static void scr_oom(void) {
|
|
18
|
+
fputs("scriptc: out of memory\n", stderr);
|
|
19
|
+
abort();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* ── UTF-16 index cache ───────────────────────────────────────────────
|
|
23
|
+
* JS string semantics are UTF-16 indices over our UTF-8 storage, so
|
|
24
|
+
* .length, charCodeAt, charAt, indexOf and slice all need unit↔byte
|
|
25
|
+
* conversions. Computed from scratch each is O(len), which turns the
|
|
26
|
+
* canonical `for (i = 0; i < s.length; i++) s.charCodeAt(i)` loop into
|
|
27
|
+
* O(len²). This small direct cache remembers, per recently-touched string,
|
|
28
|
+
* the UTF-16 length (computed once) and one unit↔byte cursor that walking
|
|
29
|
+
* code advances incrementally — sequential scans in either direction
|
|
30
|
+
* become O(1) amortized per access.
|
|
31
|
+
*
|
|
32
|
+
* Correctness: entries are keyed by pointer, so any path that frees a
|
|
33
|
+
* string MUST purge its entry (all frees go through scr_str_release) and
|
|
34
|
+
* the in-place concat below invalidates the cached length (the prefix —
|
|
35
|
+
* and therefore the cursor — stays valid). Strings are immutable in every
|
|
36
|
+
* other respect. The runtime is single-threaded by design.
|
|
37
|
+
*/
|
|
38
|
+
#define SCR_SIDX_N 4
|
|
39
|
+
#define SCR_U16_UNKNOWN SIZE_MAX
|
|
40
|
+
typedef struct {
|
|
41
|
+
const ScrStr *s; /* NULL = empty slot */
|
|
42
|
+
size_t u16len; /* SCR_U16_UNKNOWN until computed */
|
|
43
|
+
size_t cu, cb; /* cursor: byte offset cb starts the char at unit cu */
|
|
44
|
+
} ScrSidx;
|
|
45
|
+
static ScrSidx scr_sidx_tab[SCR_SIDX_N];
|
|
46
|
+
static unsigned scr_sidx_clock;
|
|
47
|
+
|
|
48
|
+
static void scr_sidx_purge(const ScrStr *s) {
|
|
49
|
+
for (int i = 0; i < SCR_SIDX_N; i++) {
|
|
50
|
+
if (scr_sidx_tab[i].s == s) scr_sidx_tab[i].s = NULL;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static ScrSidx *scr_sidx(const ScrStr *s) {
|
|
55
|
+
for (int i = 0; i < SCR_SIDX_N; i++) {
|
|
56
|
+
if (scr_sidx_tab[i].s == s) return &scr_sidx_tab[i];
|
|
57
|
+
}
|
|
58
|
+
ScrSidx *e = &scr_sidx_tab[scr_sidx_clock++ % SCR_SIDX_N];
|
|
59
|
+
e->s = s;
|
|
60
|
+
e->u16len = SCR_U16_UNKNOWN;
|
|
61
|
+
e->cu = 0;
|
|
62
|
+
e->cb = 0;
|
|
63
|
+
return e;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* ── allocation ─────────────────────────────────────────────────────── */
|
|
67
|
+
|
|
68
|
+
static ScrStr *scr_str_alloc(size_t len, size_t cap) {
|
|
69
|
+
ScrStr *s = malloc(sizeof(ScrStr) + cap + 1);
|
|
70
|
+
if (!s) scr_oom();
|
|
71
|
+
s->rc = 1;
|
|
72
|
+
s->len = len;
|
|
73
|
+
s->cap = cap;
|
|
74
|
+
#ifdef SCR_RC_AUDIT
|
|
75
|
+
scr_live_strings++;
|
|
76
|
+
#endif
|
|
77
|
+
return s;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
ScrStr *scr_str_new(const char *bytes, size_t len) {
|
|
81
|
+
ScrStr *s = scr_str_alloc(len, len);
|
|
82
|
+
memcpy(s->data, bytes, len);
|
|
83
|
+
s->data[len] = '\0';
|
|
84
|
+
return s;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* One-slot free-block cache for append loops: `s += x` compiles to
|
|
88
|
+
* concat + release-of-the-old-string every iteration, so the block freed
|
|
89
|
+
* on iteration n is (with the geometric slack below) big enough for the
|
|
90
|
+
* allocation on iteration n+1 — the loop ping-pongs between two warm
|
|
91
|
+
* blocks instead of paging in fresh zero-filled memory 40k times. Disabled
|
|
92
|
+
* in the audit lane so ASan sees every logical free as a real free. */
|
|
93
|
+
#ifndef SCR_RC_AUDIT
|
|
94
|
+
static ScrStr *scr_str_spare;
|
|
95
|
+
#endif
|
|
96
|
+
|
|
97
|
+
/* A spare-block reuse must not waste grossly (cap <= 4x the need) and only
|
|
98
|
+
* sizable blocks are worth stashing (>= 512). */
|
|
99
|
+
static ScrStr *scr_str_take_spare(size_t len) {
|
|
100
|
+
#ifndef SCR_RC_AUDIT
|
|
101
|
+
ScrStr *s = scr_str_spare;
|
|
102
|
+
if (s && s->cap >= len && s->cap / 4 <= len) {
|
|
103
|
+
scr_str_spare = NULL;
|
|
104
|
+
s->rc = 1;
|
|
105
|
+
s->len = len; /* keeps its larger cap */
|
|
106
|
+
return s;
|
|
107
|
+
}
|
|
108
|
+
#else
|
|
109
|
+
(void)len;
|
|
110
|
+
#endif
|
|
111
|
+
return NULL;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Builder entry points (scr_json.c): raw block with undefined bytes, and
|
|
115
|
+
* an rc==1-only grow. The spare block is worth trying first — a stringify
|
|
116
|
+
* loop's previous output is usually the right size for the next one. */
|
|
117
|
+
ScrStr *scr_str_alloc_raw(size_t len, size_t cap) {
|
|
118
|
+
ScrStr *s = scr_str_take_spare(cap);
|
|
119
|
+
if (!s) return scr_str_alloc(len, cap);
|
|
120
|
+
s->len = len; /* keeps its (possibly larger) cap */
|
|
121
|
+
return s;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
ScrStr *scr_str_regrow(ScrStr *s, size_t newcap) {
|
|
125
|
+
scr_sidx_purge(s); /* realloc may move; the old address may be recycled */
|
|
126
|
+
ScrStr *r = realloc(s, sizeof(ScrStr) + newcap + 1);
|
|
127
|
+
if (!r) scr_oom();
|
|
128
|
+
r->cap = newcap;
|
|
129
|
+
return r;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
void scr_str_release(ScrStr *s) {
|
|
133
|
+
if (!s || s->rc == SIZE_MAX) return; /* NULL: an uninitialized `let` local */
|
|
134
|
+
if (--s->rc == 0) {
|
|
135
|
+
scr_sidx_purge(s); /* the address may be recycled by the next malloc */
|
|
136
|
+
#ifdef SCR_RC_AUDIT
|
|
137
|
+
scr_live_strings--;
|
|
138
|
+
#endif
|
|
139
|
+
#ifndef SCR_RC_AUDIT
|
|
140
|
+
if (s->cap >= 512) {
|
|
141
|
+
ScrStr *old = scr_str_spare;
|
|
142
|
+
scr_str_spare = s;
|
|
143
|
+
if (!old) return;
|
|
144
|
+
s = old; /* evict the previous spare */
|
|
145
|
+
}
|
|
146
|
+
#endif
|
|
147
|
+
free(s);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
ScrStr *scr_str_concat(ScrStr *a, ScrStr *b) {
|
|
152
|
+
if (a->len > SIZE_MAX - b->len - sizeof(ScrStr) - 1) scr_oom();
|
|
153
|
+
size_t newlen = a->len + b->len;
|
|
154
|
+
/* In-place append: a is uniquely owned by the caller's borrow (rc == 1 —
|
|
155
|
+
* never an interned literal, those are SIZE_MAX) and has room. Fires on
|
|
156
|
+
* concat chains (`a + b + c`, template literals), where each intermediate
|
|
157
|
+
* result reaches the next concat as a sole-reference temp. Any string
|
|
158
|
+
* with rc > 1 might be aliased and is copied, never mutated. */
|
|
159
|
+
if (a->rc == 1 && a != b && a->cap >= newlen) {
|
|
160
|
+
memcpy(a->data + a->len, b->data, b->len);
|
|
161
|
+
a->len = newlen;
|
|
162
|
+
a->data[newlen] = '\0';
|
|
163
|
+
/* A cached UTF-16 length for a is stale now; its cursor still valid. */
|
|
164
|
+
for (int i = 0; i < SCR_SIDX_N; i++) {
|
|
165
|
+
if (scr_sidx_tab[i].s == a) scr_sidx_tab[i].u16len = SCR_U16_UNKNOWN;
|
|
166
|
+
}
|
|
167
|
+
a->rc = 2; /* +1 for the returned reference, beside the caller's borrow */
|
|
168
|
+
return a;
|
|
169
|
+
}
|
|
170
|
+
/* Copy path. Geometric slack keeps appenders amortized: a uniquely-owned
|
|
171
|
+
* left side that outgrew its capacity is a concat chain, and any sizable
|
|
172
|
+
* result is presumed an append loop's accumulator (`s += x` reaches here
|
|
173
|
+
* with rc == 2 — the variable plus the emitted temp — every iteration;
|
|
174
|
+
* the slack is what lets the free-block cache above satisfy the next
|
|
175
|
+
* iteration's slightly-larger allocation). */
|
|
176
|
+
size_t newcap = newlen;
|
|
177
|
+
if (a->rc == 1) {
|
|
178
|
+
size_t grown = a->cap + (a->cap >> 1) + 16;
|
|
179
|
+
if (grown > newcap) newcap = grown;
|
|
180
|
+
} else if (newlen >= 512 && newlen <= (SIZE_MAX - sizeof(ScrStr) - 1) / 2) {
|
|
181
|
+
newcap = newlen + (newlen >> 1);
|
|
182
|
+
}
|
|
183
|
+
ScrStr *s = scr_str_take_spare(newlen);
|
|
184
|
+
if (!s) s = scr_str_alloc(newlen, newcap);
|
|
185
|
+
memcpy(s->data, a->data, a->len);
|
|
186
|
+
memcpy(s->data + a->len, b->data, b->len);
|
|
187
|
+
s->data[newlen] = '\0';
|
|
188
|
+
return s;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
bool scr_str_eq(ScrStr *a, ScrStr *b) {
|
|
192
|
+
return a == b || (a->len == b->len && memcmp(a->data, b->data, a->len) == 0);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
int scr_str_cmp(ScrStr *a, ScrStr *b) {
|
|
196
|
+
size_t min = a->len < b->len ? a->len : b->len;
|
|
197
|
+
int c = memcmp(a->data, b->data, min);
|
|
198
|
+
if (c != 0) return c;
|
|
199
|
+
return a->len < b->len ? -1 : (a->len > b->len ? 1 : 0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* ── interned strings ─────────────────────────────────────────────────
|
|
203
|
+
* The empty string and every single-character ASCII string are immortal
|
|
204
|
+
* statics (same layout the emitter uses for literals): charAt/slice churn
|
|
205
|
+
* in tight loops returns these without allocating.
|
|
206
|
+
*/
|
|
207
|
+
typedef struct { size_t rc; size_t len; size_t cap; char data[2]; } ScrChar1;
|
|
208
|
+
#define SCR_A(c) {SIZE_MAX, 1, 1, {(char)(c), 0}}
|
|
209
|
+
#define SCR_A8(c) \
|
|
210
|
+
SCR_A(c), SCR_A(c + 1), SCR_A(c + 2), SCR_A(c + 3), \
|
|
211
|
+
SCR_A(c + 4), SCR_A(c + 5), SCR_A(c + 6), SCR_A(c + 7)
|
|
212
|
+
static const ScrChar1 scr_ascii1[128] = {
|
|
213
|
+
SCR_A8(0), SCR_A8(8), SCR_A8(16), SCR_A8(24),
|
|
214
|
+
SCR_A8(32), SCR_A8(40), SCR_A8(48), SCR_A8(56),
|
|
215
|
+
SCR_A8(64), SCR_A8(72), SCR_A8(80), SCR_A8(88),
|
|
216
|
+
SCR_A8(96), SCR_A8(104), SCR_A8(112), SCR_A8(120),
|
|
217
|
+
};
|
|
218
|
+
static const struct { size_t rc; size_t len; size_t cap; char data[1]; }
|
|
219
|
+
scr_lit_empty = {SIZE_MAX, 0, 0, ""};
|
|
220
|
+
|
|
221
|
+
static ScrStr *scr_str_empty(void) { return (ScrStr *)&scr_lit_empty; }
|
|
222
|
+
|
|
223
|
+
/* Interned when the content is empty or one ASCII byte; fresh otherwise. */
|
|
224
|
+
static ScrStr *scr_str_from_span(const char *bytes, size_t len) {
|
|
225
|
+
if (len == 0) return scr_str_empty();
|
|
226
|
+
if (len == 1 && (unsigned char)bytes[0] < 0x80) {
|
|
227
|
+
return (ScrStr *)&scr_ascii1[(unsigned char)bytes[0]];
|
|
228
|
+
}
|
|
229
|
+
return scr_str_new(bytes, len);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* ── string methods: UTF-16 semantics over UTF-8 storage ──────────
|
|
233
|
+
* All strings in the system are well-formed UTF-8 (the compiler replaces
|
|
234
|
+
* lone surrogates in literals with U+FFFD), so the decode helpers below
|
|
235
|
+
* may assume valid sequences and never validate.
|
|
236
|
+
*/
|
|
237
|
+
|
|
238
|
+
/* UTF-8 encoding of U+FFFD REPLACEMENT CHARACTER — stands in for the lone
|
|
239
|
+
* surrogate JS would produce when charAt/slice split an astral pair. */
|
|
240
|
+
#define SCR_REPLACEMENT "\xEF\xBF\xBD"
|
|
241
|
+
#define SCR_REPLACEMENT_LEN ((size_t)3)
|
|
242
|
+
|
|
243
|
+
/* Byte length of the well-formed UTF-8 sequence starting at lead byte c. */
|
|
244
|
+
static size_t scr_utf8_seq_len(unsigned char c) {
|
|
245
|
+
if (c < 0x80) return 1;
|
|
246
|
+
if (c < 0xE0) return 2;
|
|
247
|
+
if (c < 0xF0) return 3;
|
|
248
|
+
return 4;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* Decode the code point at p (well-formed UTF-8); *adv gets the byte
|
|
252
|
+
* length of the sequence. */
|
|
253
|
+
static uint32_t scr_utf8_decode(const char *p, size_t *adv) {
|
|
254
|
+
unsigned char c = (unsigned char)p[0];
|
|
255
|
+
if (c < 0x80) {
|
|
256
|
+
*adv = 1;
|
|
257
|
+
return c;
|
|
258
|
+
}
|
|
259
|
+
if (c < 0xE0) {
|
|
260
|
+
*adv = 2;
|
|
261
|
+
return ((uint32_t)(c & 0x1F) << 6) | ((unsigned char)p[1] & 0x3F);
|
|
262
|
+
}
|
|
263
|
+
if (c < 0xF0) {
|
|
264
|
+
*adv = 3;
|
|
265
|
+
return ((uint32_t)(c & 0x0F) << 12) |
|
|
266
|
+
((uint32_t)((unsigned char)p[1] & 0x3F) << 6) |
|
|
267
|
+
((unsigned char)p[2] & 0x3F);
|
|
268
|
+
}
|
|
269
|
+
*adv = 4;
|
|
270
|
+
return ((uint32_t)(c & 0x07) << 18) |
|
|
271
|
+
((uint32_t)((unsigned char)p[1] & 0x3F) << 12) |
|
|
272
|
+
((uint32_t)((unsigned char)p[2] & 0x3F) << 6) |
|
|
273
|
+
((unsigned char)p[3] & 0x3F);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* Number of UTF-16 code units in s (BMP char = 1, astral char = 2).
|
|
277
|
+
* Byte-classification is position-independent (well-formed UTF-8):
|
|
278
|
+
* units = #bytes - #continuation-bytes + #4-byte-leads, so the word-wise
|
|
279
|
+
* loop counts eight bytes at a time — bits 10xxxxxx mark a continuation,
|
|
280
|
+
* 11110xxx an astral lead — with an all-ASCII early out per word. */
|
|
281
|
+
static size_t scr_utf16_units(const ScrStr *s) {
|
|
282
|
+
const unsigned char *d = (const unsigned char *)s->data;
|
|
283
|
+
const uint64_t hibits = 0x8080808080808080ull;
|
|
284
|
+
size_t units = 0, i = 0;
|
|
285
|
+
while (i + 8 <= s->len) {
|
|
286
|
+
uint64_t w;
|
|
287
|
+
memcpy(&w, d + i, 8);
|
|
288
|
+
i += 8;
|
|
289
|
+
if ((w & hibits) == 0) { /* all ASCII */
|
|
290
|
+
units += 8;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
uint64_t cont = w & ~(w << 1) & hibits;
|
|
294
|
+
uint64_t lead4 = w & (w << 1) & (w << 2) & (w << 3) & hibits;
|
|
295
|
+
units += 8 - (size_t)__builtin_popcountll(cont) +
|
|
296
|
+
(size_t)__builtin_popcountll(lead4);
|
|
297
|
+
}
|
|
298
|
+
while (i < s->len) {
|
|
299
|
+
unsigned char c = d[i++];
|
|
300
|
+
if ((c & 0xC0) == 0x80) continue; /* continuation byte */
|
|
301
|
+
units += c >= 0xF0 ? 2 : 1;
|
|
302
|
+
}
|
|
303
|
+
return units;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* Cached UTF-16 length; computes and remembers on first use. Note that
|
|
307
|
+
* u16len == byte len is exactly "all ASCII" — the walkers below use that
|
|
308
|
+
* to answer conversions in O(1) without a cursor. */
|
|
309
|
+
static size_t scr_sidx_len(const ScrStr *s, ScrSidx *e) {
|
|
310
|
+
if (e->u16len == SCR_U16_UNKNOWN) e->u16len = scr_utf16_units(s);
|
|
311
|
+
return e->u16len;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* Step the cursor back one char (cb must be > 0 and on a boundary). */
|
|
315
|
+
static void scr_sidx_back(const ScrStr *s, size_t *cu, size_t *cb) {
|
|
316
|
+
size_t p = *cb - 1;
|
|
317
|
+
while (p > 0 && ((unsigned char)s->data[p] & 0xC0) == 0x80) p--;
|
|
318
|
+
*cu -= scr_utf8_seq_len((unsigned char)s->data[p]) == 4 ? 2 : 1;
|
|
319
|
+
*cb = p;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* Convert a UTF-16 index to a byte offset, walking from the cached cursor
|
|
323
|
+
* (either direction). If u16 addresses the second (low-surrogate) unit of
|
|
324
|
+
* an astral char, *mid is set and the returned offset is the START of that
|
|
325
|
+
* 4-byte sequence. u16 at or past the end returns s->len with *mid false.
|
|
326
|
+
* Same contract as a from-scratch scan; O(distance from cursor). */
|
|
327
|
+
static size_t scr_u16_to_byte_c(const ScrStr *s, ScrSidx *e, size_t u16,
|
|
328
|
+
bool *mid) {
|
|
329
|
+
if (e->u16len == s->len) { /* all ASCII: identity mapping */
|
|
330
|
+
*mid = false;
|
|
331
|
+
return u16 < s->len ? u16 : s->len;
|
|
332
|
+
}
|
|
333
|
+
size_t cu = e->cu, cb = e->cb;
|
|
334
|
+
/* Restart from whichever end is closer than the cursor. */
|
|
335
|
+
if (u16 < cu && cu - u16 > u16) {
|
|
336
|
+
cu = 0;
|
|
337
|
+
cb = 0;
|
|
338
|
+
}
|
|
339
|
+
while (cu > u16) scr_sidx_back(s, &cu, &cb);
|
|
340
|
+
bool m = false;
|
|
341
|
+
while (cu < u16 && cb < s->len) {
|
|
342
|
+
size_t seq = scr_utf8_seq_len((unsigned char)s->data[cb]);
|
|
343
|
+
size_t w = seq == 4 ? 2 : 1;
|
|
344
|
+
if (cu + w > u16) { /* u16 lands between the halves of an astral char */
|
|
345
|
+
m = true;
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
cu += w;
|
|
349
|
+
cb += seq;
|
|
350
|
+
}
|
|
351
|
+
e->cu = cu;
|
|
352
|
+
e->cb = cb;
|
|
353
|
+
*mid = m;
|
|
354
|
+
return cb;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* Convert a byte offset (must be a char boundary) to a UTF-16 index,
|
|
358
|
+
* walking from the cached cursor. */
|
|
359
|
+
static size_t scr_byte_to_u16_c(const ScrStr *s, ScrSidx *e,
|
|
360
|
+
size_t byte_off) {
|
|
361
|
+
if (e->u16len == s->len) return byte_off; /* all ASCII */
|
|
362
|
+
size_t cu = e->cu, cb = e->cb;
|
|
363
|
+
if (byte_off < cb && cb - byte_off > byte_off) {
|
|
364
|
+
cu = 0;
|
|
365
|
+
cb = 0;
|
|
366
|
+
}
|
|
367
|
+
while (cb > byte_off) scr_sidx_back(s, &cu, &cb);
|
|
368
|
+
while (cb < byte_off) {
|
|
369
|
+
size_t seq = scr_utf8_seq_len((unsigned char)s->data[cb]);
|
|
370
|
+
cu += seq == 4 ? 2 : 1;
|
|
371
|
+
cb += seq;
|
|
372
|
+
}
|
|
373
|
+
e->cu = cu;
|
|
374
|
+
e->cb = cb;
|
|
375
|
+
return cu;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* ECMA-262 ToIntegerOrInfinity for a double already known to be a Number:
|
|
379
|
+
* NaN → +0, otherwise truncate toward zero, ±Infinity preserved. */
|
|
380
|
+
static double scr_to_integer_or_infinity(double x) {
|
|
381
|
+
if (isnan(x)) return 0.0;
|
|
382
|
+
return trunc(x);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/* Naive byte substring search (needle and hay are both well-formed UTF-8,
|
|
386
|
+
* so any byte-level match starts on a char boundary — UTF-8 is
|
|
387
|
+
* self-synchronizing). Empty needle matches at hay. */
|
|
388
|
+
static const char *scr_byte_find(const char *hay, size_t hay_len,
|
|
389
|
+
const char *nee, size_t nee_len) {
|
|
390
|
+
if (nee_len == 0) return hay;
|
|
391
|
+
if (nee_len > hay_len) return NULL;
|
|
392
|
+
for (size_t i = 0; i + nee_len <= hay_len; i++) {
|
|
393
|
+
if (hay[i] == nee[0] && memcmp(hay + i, nee, nee_len) == 0)
|
|
394
|
+
return hay + i;
|
|
395
|
+
}
|
|
396
|
+
return NULL;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
double scr_str_utf16_len(ScrStr *s) {
|
|
400
|
+
return (double)scr_sidx_len(s, scr_sidx(s));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
double scr_str_char_code_at(ScrStr *s, double i) {
|
|
404
|
+
double idx = scr_to_integer_or_infinity(i);
|
|
405
|
+
if (!(idx >= 0)) return NAN; /* negative or -Infinity */
|
|
406
|
+
/* UTF-16 length <= byte length always, so this also fences the cast. */
|
|
407
|
+
if (idx >= (double)s->len) return NAN;
|
|
408
|
+
ScrSidx *e = scr_sidx(s);
|
|
409
|
+
if (e->u16len == s->len) return (double)(unsigned char)s->data[(size_t)idx];
|
|
410
|
+
bool mid;
|
|
411
|
+
size_t off = scr_u16_to_byte_c(s, e, (size_t)idx, &mid);
|
|
412
|
+
if (off >= s->len) return NAN; /* idx >= length */
|
|
413
|
+
size_t adv;
|
|
414
|
+
uint32_t cp = scr_utf8_decode(s->data + off, &adv);
|
|
415
|
+
if (cp < 0x10000) return (double)cp;
|
|
416
|
+
uint32_t v = cp - 0x10000;
|
|
417
|
+
return mid ? (double)(0xDC00 + (v & 0x3FF)) : (double)(0xD800 + (v >> 10));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
double scr_str_index_of(ScrStr *s, ScrStr *needle, double fromIndex) {
|
|
421
|
+
double pos = scr_to_integer_or_infinity(fromIndex);
|
|
422
|
+
ScrSidx *e = scr_sidx(s);
|
|
423
|
+
size_t len16 = scr_sidx_len(s, e);
|
|
424
|
+
size_t start16 = pos <= 0 ? 0
|
|
425
|
+
: pos >= (double)len16 ? len16
|
|
426
|
+
: (size_t)pos;
|
|
427
|
+
/* Per spec, the empty needle is found at the clamped fromIndex itself —
|
|
428
|
+
* even when that index is between the halves of an astral pair. */
|
|
429
|
+
if (needle->len == 0) return (double)start16;
|
|
430
|
+
bool mid;
|
|
431
|
+
size_t start_b = scr_u16_to_byte_c(s, e, start16, &mid);
|
|
432
|
+
/* A match can't begin on a low-surrogate half (needles are well-formed),
|
|
433
|
+
* so resume at the next char boundary. */
|
|
434
|
+
if (mid) start_b += 4;
|
|
435
|
+
const char *found =
|
|
436
|
+
scr_byte_find(s->data + start_b, s->len - start_b, needle->data,
|
|
437
|
+
needle->len);
|
|
438
|
+
if (!found) return -1.0;
|
|
439
|
+
return (double)scr_byte_to_u16_c(s, e, (size_t)(found - s->data));
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/* substring: slice's clamp-and-swap sibling — ToIntegerOrInfinity both
|
|
443
|
+
* boundaries (NaN → 0), clamp each to [0, len16] (negatives clamp to 0,
|
|
444
|
+
* NOT relative like slice's), swap when start > end, then extract exactly
|
|
445
|
+
* like slice (whose relative/negative handling is inert on the
|
|
446
|
+
* already-clamped values — delegation is exact). */
|
|
447
|
+
ScrStr *scr_str_substring(ScrStr *s, double start, double end) {
|
|
448
|
+
ScrSidx *e = scr_sidx(s);
|
|
449
|
+
double len16 = (double)scr_sidx_len(s, e);
|
|
450
|
+
double a = scr_to_integer_or_infinity(start);
|
|
451
|
+
double b = scr_to_integer_or_infinity(end);
|
|
452
|
+
double fa = a < 0 ? 0 : a > len16 ? len16 : a;
|
|
453
|
+
double fb = b < 0 ? 0 : b > len16 ? len16 : b;
|
|
454
|
+
return fa < fb ? scr_str_slice(s, fa, fb) : scr_str_slice(s, fb, fa);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
bool scr_str_includes(ScrStr *s, ScrStr *needle) {
|
|
458
|
+
return scr_byte_find(s->data, s->len, needle->data, needle->len) != NULL;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
bool scr_str_starts_with(ScrStr *s, ScrStr *needle) {
|
|
462
|
+
return needle->len <= s->len &&
|
|
463
|
+
memcmp(s->data, needle->data, needle->len) == 0;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
bool scr_str_ends_with(ScrStr *s, ScrStr *needle) {
|
|
467
|
+
return needle->len <= s->len &&
|
|
468
|
+
memcmp(s->data + (s->len - needle->len), needle->data,
|
|
469
|
+
needle->len) == 0;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/* Resolve one slice() boundary: negatives are relative to the end, then
|
|
473
|
+
* clamp to [0, len16]. Handles ±Infinity (already through
|
|
474
|
+
* ToIntegerOrInfinity). */
|
|
475
|
+
static size_t scr_slice_boundary(double v, size_t len16) {
|
|
476
|
+
if (v < 0) {
|
|
477
|
+
double t = v + (double)len16; /* -Infinity stays -Infinity */
|
|
478
|
+
return t <= 0 ? 0 : (size_t)t;
|
|
479
|
+
}
|
|
480
|
+
return v >= (double)len16 ? len16 : (size_t)v;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
ScrStr *scr_str_slice(ScrStr *s, double start, double end) {
|
|
484
|
+
ScrSidx *e = scr_sidx(s);
|
|
485
|
+
size_t len16 = scr_sidx_len(s, e);
|
|
486
|
+
size_t from = scr_slice_boundary(scr_to_integer_or_infinity(start), len16);
|
|
487
|
+
size_t to = scr_slice_boundary(scr_to_integer_or_infinity(end), len16);
|
|
488
|
+
if (from >= to) return scr_str_empty();
|
|
489
|
+
|
|
490
|
+
bool from_mid, to_mid;
|
|
491
|
+
size_t from_b = scr_u16_to_byte_c(s, e, from, &from_mid);
|
|
492
|
+
size_t to_b = scr_u16_to_byte_c(s, e, to, &to_mid);
|
|
493
|
+
/* Both *_mid offsets point at the start of the split astral char; the
|
|
494
|
+
* kept content is the whole chars strictly inside the boundaries. */
|
|
495
|
+
size_t content_b = from_mid ? from_b + 4 : from_b;
|
|
496
|
+
size_t content_len = to_b - content_b;
|
|
497
|
+
|
|
498
|
+
if (!from_mid && !to_mid)
|
|
499
|
+
return scr_str_from_span(s->data + from_b, content_len);
|
|
500
|
+
|
|
501
|
+
/* Divergence: JS would emit the lone surrogate half; we emit U+FFFD. */
|
|
502
|
+
size_t total = content_len + (from_mid ? SCR_REPLACEMENT_LEN : 0) +
|
|
503
|
+
(to_mid ? SCR_REPLACEMENT_LEN : 0);
|
|
504
|
+
char *tmp = malloc(total);
|
|
505
|
+
if (!tmp) scr_oom();
|
|
506
|
+
size_t o = 0;
|
|
507
|
+
if (from_mid) {
|
|
508
|
+
memcpy(tmp + o, SCR_REPLACEMENT, SCR_REPLACEMENT_LEN);
|
|
509
|
+
o += SCR_REPLACEMENT_LEN;
|
|
510
|
+
}
|
|
511
|
+
memcpy(tmp + o, s->data + content_b, content_len);
|
|
512
|
+
o += content_len;
|
|
513
|
+
if (to_mid) memcpy(tmp + o, SCR_REPLACEMENT, SCR_REPLACEMENT_LEN);
|
|
514
|
+
ScrStr *r = scr_str_new(tmp, total);
|
|
515
|
+
free(tmp);
|
|
516
|
+
return r;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
ScrStr *scr_str_repeat(ScrStr *s, double count) {
|
|
520
|
+
double n = scr_to_integer_or_infinity(count);
|
|
521
|
+
if (n < 0 || (isinf(n) && n > 0)) {
|
|
522
|
+
fputs("scriptc: RangeError: Invalid count value\n", stderr);
|
|
523
|
+
abort();
|
|
524
|
+
}
|
|
525
|
+
if (n == 0 || s->len == 0) return scr_str_empty();
|
|
526
|
+
/* n is a finite non-negative integer here. Reject sizes malloc could not
|
|
527
|
+
* satisfy anyway before the double→size_t conversion can overflow. */
|
|
528
|
+
if (n > (double)((SIZE_MAX - sizeof(ScrStr) - 1) / s->len)) scr_oom();
|
|
529
|
+
size_t total = (size_t)n * s->len;
|
|
530
|
+
ScrStr *r = scr_str_alloc(total, total);
|
|
531
|
+
memcpy(r->data, s->data, s->len);
|
|
532
|
+
size_t filled = s->len;
|
|
533
|
+
while (filled < total) { /* doubling fill */
|
|
534
|
+
size_t chunk = filled <= total - filled ? filled : total - filled;
|
|
535
|
+
memcpy(r->data + filled, r->data, chunk);
|
|
536
|
+
filled += chunk;
|
|
537
|
+
}
|
|
538
|
+
r->data[total] = '\0';
|
|
539
|
+
return r;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/* Exact ECMA-262 WhiteSpace ∪ LineTerminator membership. */
|
|
543
|
+
static bool scr_is_js_whitespace(uint32_t cp) {
|
|
544
|
+
switch (cp) {
|
|
545
|
+
case 0x0009: case 0x000A: case 0x000B: case 0x000C: case 0x000D:
|
|
546
|
+
case 0x0020: case 0x00A0: case 0x1680: case 0x2028: case 0x2029:
|
|
547
|
+
case 0x202F: case 0x205F: case 0x3000: case 0xFEFF:
|
|
548
|
+
return true;
|
|
549
|
+
default:
|
|
550
|
+
return cp >= 0x2000 && cp <= 0x200A;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
ScrStr *scr_str_trim(ScrStr *s) {
|
|
555
|
+
size_t b = 0, e = s->len;
|
|
556
|
+
while (b < e) {
|
|
557
|
+
size_t adv;
|
|
558
|
+
uint32_t cp = scr_utf8_decode(s->data + b, &adv);
|
|
559
|
+
if (!scr_is_js_whitespace(cp)) break;
|
|
560
|
+
b += adv;
|
|
561
|
+
}
|
|
562
|
+
while (e > b) {
|
|
563
|
+
size_t cs = e - 1; /* back up to the lead byte of the last char */
|
|
564
|
+
while (cs > b && ((unsigned char)s->data[cs] & 0xC0) == 0x80) cs--;
|
|
565
|
+
size_t adv;
|
|
566
|
+
uint32_t cp = scr_utf8_decode(s->data + cs, &adv);
|
|
567
|
+
if (!scr_is_js_whitespace(cp)) break;
|
|
568
|
+
e = cs;
|
|
569
|
+
}
|
|
570
|
+
return scr_str_from_span(s->data + b, e - b);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
ScrStr *scr_str_char_at(ScrStr *s, double i) {
|
|
574
|
+
double idx = scr_to_integer_or_infinity(i);
|
|
575
|
+
if (!(idx >= 0)) return scr_str_empty();
|
|
576
|
+
if (idx >= (double)s->len) return scr_str_empty(); /* len16 <= len */
|
|
577
|
+
ScrSidx *e = scr_sidx(s);
|
|
578
|
+
if (e->u16len == s->len) { /* all ASCII */
|
|
579
|
+
return (ScrStr *)&scr_ascii1[(unsigned char)s->data[(size_t)idx]];
|
|
580
|
+
}
|
|
581
|
+
bool mid;
|
|
582
|
+
size_t off = scr_u16_to_byte_c(s, e, (size_t)idx, &mid);
|
|
583
|
+
if (off >= s->len) return scr_str_empty(); /* out of range */
|
|
584
|
+
size_t adv;
|
|
585
|
+
uint32_t cp = scr_utf8_decode(s->data + off, &adv);
|
|
586
|
+
if (cp >= 0x10000) {
|
|
587
|
+
/* Divergence: JS returns the lone surrogate half; we return U+FFFD. */
|
|
588
|
+
return scr_str_new(SCR_REPLACEMENT, SCR_REPLACEMENT_LEN);
|
|
589
|
+
}
|
|
590
|
+
return scr_str_from_span(s->data + off, adv);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/* trimStart()/trimEnd(): the one-sided halves of trim — same exact JS
|
|
594
|
+
* WhiteSpace ∪ LineTerminator set, same scan loops. */
|
|
595
|
+
ScrStr *scr_str_trim_start(ScrStr *s) {
|
|
596
|
+
size_t b = 0;
|
|
597
|
+
while (b < s->len) {
|
|
598
|
+
size_t adv;
|
|
599
|
+
uint32_t cp = scr_utf8_decode(s->data + b, &adv);
|
|
600
|
+
if (!scr_is_js_whitespace(cp)) break;
|
|
601
|
+
b += adv;
|
|
602
|
+
}
|
|
603
|
+
return scr_str_from_span(s->data + b, s->len - b);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
ScrStr *scr_str_trim_end(ScrStr *s) {
|
|
607
|
+
size_t e = s->len;
|
|
608
|
+
while (e > 0) {
|
|
609
|
+
size_t cs = e - 1; /* back up to the lead byte of the last char */
|
|
610
|
+
while (cs > 0 && ((unsigned char)s->data[cs] & 0xC0) == 0x80) cs--;
|
|
611
|
+
size_t adv;
|
|
612
|
+
uint32_t cp = scr_utf8_decode(s->data + cs, &adv);
|
|
613
|
+
if (!scr_is_js_whitespace(cp)) break;
|
|
614
|
+
e = cs;
|
|
615
|
+
}
|
|
616
|
+
return scr_str_from_span(s->data, e);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/* Immortal U+FFFD — the divergence-2 stand-in wherever JS would produce a
|
|
620
|
+
* lone surrogate (empty-separator split of an astral char, a pad fill
|
|
621
|
+
* truncated mid-pair). */
|
|
622
|
+
static const struct { size_t rc; size_t len; size_t cap; char data[4]; }
|
|
623
|
+
scr_lit_fffd = {SIZE_MAX, 3, 3, "\xEF\xBF\xBD"};
|
|
624
|
+
|
|
625
|
+
/* split(separator) with a STRING separator, no limit (ECMA-262 22.1.3.23):
|
|
626
|
+
* an empty separator splits into single UTF-16 code units ("".split("") is
|
|
627
|
+
* [] — no probe matches nothing); a non-empty separator splits on every
|
|
628
|
+
* byte-level occurrence (well-formed UTF-8 is self-synchronizing, so byte
|
|
629
|
+
* matches are exactly code-point matches), keeping empty pieces at the
|
|
630
|
+
* ends and between adjacent separators; an empty subject with a non-empty
|
|
631
|
+
* separator is [""]. Where JS's per-unit split of an astral char would
|
|
632
|
+
* yield the two lone surrogate halves, each half is U+FFFD here
|
|
633
|
+
* (divergence 2 — the same substitution the island's boundary marshal
|
|
634
|
+
* applied). Borrows both; returns a +1 string[]. */
|
|
635
|
+
ScrArr *scr_str_split(ScrStr *s, ScrStr *sep) {
|
|
636
|
+
ScrArr *out = scr_arr_new(SCR_ELEM_STR, 0);
|
|
637
|
+
if (sep->len == 0) {
|
|
638
|
+
size_t i = 0;
|
|
639
|
+
while (i < s->len) {
|
|
640
|
+
size_t adv;
|
|
641
|
+
uint32_t cp = scr_utf8_decode(s->data + i, &adv);
|
|
642
|
+
if (cp >= 0x10000) { /* two units in JS: both halves become U+FFFD */
|
|
643
|
+
scr_arr_push_ref(out, scr_str_retain((ScrStr *)&scr_lit_fffd));
|
|
644
|
+
scr_arr_push_ref(out, scr_str_retain((ScrStr *)&scr_lit_fffd));
|
|
645
|
+
} else {
|
|
646
|
+
scr_arr_push_ref(out, scr_str_from_span(s->data + i, adv));
|
|
647
|
+
}
|
|
648
|
+
i += adv;
|
|
649
|
+
}
|
|
650
|
+
return out;
|
|
651
|
+
}
|
|
652
|
+
size_t start = 0;
|
|
653
|
+
for (;;) {
|
|
654
|
+
const char *found = scr_byte_find(s->data + start, s->len - start,
|
|
655
|
+
sep->data, sep->len);
|
|
656
|
+
if (!found) break;
|
|
657
|
+
size_t at = (size_t)(found - s->data);
|
|
658
|
+
scr_arr_push_ref(out, scr_str_from_span(s->data + start, at - start));
|
|
659
|
+
start = at + sep->len;
|
|
660
|
+
}
|
|
661
|
+
scr_arr_push_ref(out, scr_str_from_span(s->data + start, s->len - start));
|
|
662
|
+
return out;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/* StringPad (ECMA-262 22.1.3.16/17): target length in UTF-16 units, the
|
|
666
|
+
* filler built from whole repetitions of `fill` plus a truncated prefix.
|
|
667
|
+
* A target at or below the length (or an empty fill) returns the receiver
|
|
668
|
+
* unchanged. A truncation that would split an astral char in the fill
|
|
669
|
+
* emits U+FFFD for the kept half (one unit, like the lone surrogate JS
|
|
670
|
+
* keeps — divergence 2). Sizes beyond what malloc can satisfy abort (the
|
|
671
|
+
* repeat() policy; JS's RangeError fires around 2^29 units). Borrows both;
|
|
672
|
+
* returns +1. */
|
|
673
|
+
static ScrStr *scr_pad_impl(ScrStr *s, double maxLength, ScrStr *fill,
|
|
674
|
+
bool at_start) {
|
|
675
|
+
double target = scr_to_integer_or_infinity(maxLength);
|
|
676
|
+
ScrSidx *e = scr_sidx(s);
|
|
677
|
+
size_t len16 = scr_sidx_len(s, e);
|
|
678
|
+
if (!(target > (double)len16) || fill->len == 0) return scr_str_retain(s);
|
|
679
|
+
/* Reject pad sizes malloc could not satisfy before the double→size_t
|
|
680
|
+
* conversion can overflow (each unit is at most 3 bytes here: BMP chars
|
|
681
|
+
* and the U+FFFD stand-in; astral chars are 4 bytes for 2 units). */
|
|
682
|
+
if (target > (double)((SIZE_MAX - sizeof(ScrStr) - 1) / 4)) scr_oom();
|
|
683
|
+
size_t pad16 = (size_t)target - len16;
|
|
684
|
+
size_t fill16 = scr_sidx_len(fill, scr_sidx(fill));
|
|
685
|
+
size_t reps = pad16 / fill16, rem16 = pad16 % fill16;
|
|
686
|
+
/* The truncated prefix of fill: whole chars while they fit in rem16
|
|
687
|
+
* units; a final astral char that doesn't fit contributes U+FFFD. */
|
|
688
|
+
size_t prefix_b = 0, prefix_units = 0;
|
|
689
|
+
bool prefix_fffd = false;
|
|
690
|
+
while (prefix_units < rem16) {
|
|
691
|
+
size_t seq = scr_utf8_seq_len((unsigned char)fill->data[prefix_b]);
|
|
692
|
+
size_t w = seq == 4 ? 2 : 1;
|
|
693
|
+
if (prefix_units + w > rem16) { /* astral char split by the truncation */
|
|
694
|
+
prefix_fffd = true;
|
|
695
|
+
prefix_units += 1;
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
prefix_b += seq;
|
|
699
|
+
prefix_units += w;
|
|
700
|
+
}
|
|
701
|
+
size_t pad_b = reps * fill->len + prefix_b +
|
|
702
|
+
(prefix_fffd ? SCR_REPLACEMENT_LEN : 0);
|
|
703
|
+
if (pad_b > SIZE_MAX - sizeof(ScrStr) - 1 - s->len) scr_oom();
|
|
704
|
+
size_t total = s->len + pad_b;
|
|
705
|
+
ScrStr *r = scr_str_alloc(total, total);
|
|
706
|
+
char *w = r->data + (at_start ? 0 : s->len);
|
|
707
|
+
for (size_t i = 0; i < reps; i++) {
|
|
708
|
+
memcpy(w, fill->data, fill->len);
|
|
709
|
+
w += fill->len;
|
|
710
|
+
}
|
|
711
|
+
memcpy(w, fill->data, prefix_b);
|
|
712
|
+
w += prefix_b;
|
|
713
|
+
if (prefix_fffd) {
|
|
714
|
+
memcpy(w, SCR_REPLACEMENT, SCR_REPLACEMENT_LEN);
|
|
715
|
+
w += SCR_REPLACEMENT_LEN;
|
|
716
|
+
}
|
|
717
|
+
memcpy(at_start ? w : r->data, s->data, s->len);
|
|
718
|
+
r->data[total] = '\0';
|
|
719
|
+
return r;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
ScrStr *scr_str_pad_start(ScrStr *s, double maxLength, ScrStr *fill) {
|
|
723
|
+
return scr_pad_impl(s, maxLength, fill, true);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
ScrStr *scr_str_pad_end(ScrStr *s, double maxLength, ScrStr *fill) {
|
|
727
|
+
return scr_pad_impl(s, maxLength, fill, false);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/* ── parseInt: ECMA-262 19.2.5, exactly ───────────────────────────────
|
|
731
|
+
* Skip JS whitespace, take an optional sign, resolve the radix through
|
|
732
|
+
* ToInt32 (0 → 10 with a 0x/0X hex escape; 16 also strips the prefix;
|
|
733
|
+
* outside 2..36 → NaN), scan the longest digit prefix, and round the
|
|
734
|
+
* EXACT mathematical value to double. The fast path accumulates in u64
|
|
735
|
+
* (u64→double conversion is correctly rounded); digit strings that
|
|
736
|
+
* overflow 64 bits go through a small base-2^32 bignum and round-to-
|
|
737
|
+
* nearest-even on the top 53 bits, so thousand-digit inputs in any radix
|
|
738
|
+
* are Node-exact, Infinity overflow included. */
|
|
739
|
+
|
|
740
|
+
static double scr_to_int32_d(double d) {
|
|
741
|
+
if (!isfinite(d) || d == 0) return 0;
|
|
742
|
+
double m = fmod(trunc(d), 4294967296.0);
|
|
743
|
+
if (m < 0) m += 4294967296.0;
|
|
744
|
+
return m >= 2147483648.0 ? m - 4294967296.0 : m;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
static int scr_digit_value(char c) {
|
|
748
|
+
if (c >= '0' && c <= '9') return c - '0';
|
|
749
|
+
if (c >= 'a' && c <= 'z') return c - 'a' + 10;
|
|
750
|
+
if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
|
|
751
|
+
return 99;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/* Digit string → double (digits already validated against the radix,
|
|
755
|
+
* leading zeros stripped, count >= 1). Node (V8) is the oracle, and V8 is
|
|
756
|
+
* only EXACT where the spec requires it (radix 2, 4, 8, 10, 16, 32); for
|
|
757
|
+
* every other radix it runs a 32-bit-chunked double accumulation whose
|
|
758
|
+
* rounding error the spec explicitly permits ("mathInt may be an
|
|
759
|
+
* implementation-dependent approximation"). Reproduce both behaviors
|
|
760
|
+
* bit-exactly: the chunk loop for the approximate radixes, correct
|
|
761
|
+
* rounding (u64 fast path, bignum beyond) for the exact ones. */
|
|
762
|
+
static double scr_digits_to_double(const char *p, size_t n, int radix) {
|
|
763
|
+
if (radix != 10 && (radix & (radix - 1)) != 0) {
|
|
764
|
+
/* V8's generic-radix loop (numbers/conversions.cc): consume the
|
|
765
|
+
* longest digit run whose multiplier stays below 0xFFFFFFFF/36, then
|
|
766
|
+
* fold with one double multiply-add per chunk — the rounding of each
|
|
767
|
+
* fold IS the observable Node behavior. */
|
|
768
|
+
const uint32_t kMaximumMultiplier = 0xFFFFFFFFu / 36u;
|
|
769
|
+
double v = 0.0;
|
|
770
|
+
size_t i = 0;
|
|
771
|
+
bool done = false;
|
|
772
|
+
do {
|
|
773
|
+
uint32_t part = 0, multiplier = 1;
|
|
774
|
+
for (;;) {
|
|
775
|
+
if (i == n) {
|
|
776
|
+
done = true;
|
|
777
|
+
break;
|
|
778
|
+
}
|
|
779
|
+
uint32_t d = (uint32_t)scr_digit_value(p[i]);
|
|
780
|
+
uint32_t m = multiplier * (uint32_t)radix;
|
|
781
|
+
if (m > kMaximumMultiplier) break; /* digit starts the next chunk */
|
|
782
|
+
part = part * (uint32_t)radix + d;
|
|
783
|
+
multiplier = m;
|
|
784
|
+
i++;
|
|
785
|
+
}
|
|
786
|
+
v = v * (double)multiplier + (double)part;
|
|
787
|
+
} while (!done);
|
|
788
|
+
return v;
|
|
789
|
+
}
|
|
790
|
+
/* u64 fast path: exact while the accumulator fits. */
|
|
791
|
+
uint64_t acc = 0;
|
|
792
|
+
size_t i = 0;
|
|
793
|
+
for (; i < n; i++) {
|
|
794
|
+
int dv = scr_digit_value(p[i]);
|
|
795
|
+
if (acc > (UINT64_MAX - (uint64_t)dv) / (uint64_t)radix) break;
|
|
796
|
+
acc = acc * (uint64_t)radix + (uint64_t)dv;
|
|
797
|
+
}
|
|
798
|
+
if (i == n) return (double)acc;
|
|
799
|
+
/* Bignum path: base-2^32 limbs, little-endian, multiply-add per digit. */
|
|
800
|
+
size_t cap = 4 + (n * 6) / 32; /* log2(36) < 6 bits per digit */
|
|
801
|
+
uint32_t *limbs = malloc(cap * sizeof(uint32_t));
|
|
802
|
+
if (!limbs) scr_oom();
|
|
803
|
+
limbs[0] = (uint32_t)acc;
|
|
804
|
+
limbs[1] = (uint32_t)(acc >> 32);
|
|
805
|
+
size_t nl = limbs[1] ? 2 : 1;
|
|
806
|
+
for (; i < n; i++) {
|
|
807
|
+
uint64_t carry = (uint64_t)scr_digit_value(p[i]);
|
|
808
|
+
for (size_t j = 0; j < nl; j++) {
|
|
809
|
+
uint64_t t = (uint64_t)limbs[j] * (uint64_t)radix + carry;
|
|
810
|
+
limbs[j] = (uint32_t)t;
|
|
811
|
+
carry = t >> 32;
|
|
812
|
+
}
|
|
813
|
+
if (carry) {
|
|
814
|
+
if (nl == cap) { /* unreachable by the cap bound; belt and braces */
|
|
815
|
+
cap *= 2;
|
|
816
|
+
limbs = realloc(limbs, cap * sizeof(uint32_t));
|
|
817
|
+
if (!limbs) scr_oom();
|
|
818
|
+
}
|
|
819
|
+
limbs[nl++] = (uint32_t)carry;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
/* Round the bignum to double: top 53 bits, guard, sticky, half-even. */
|
|
823
|
+
size_t topbits = 32 - (size_t)__builtin_clz(limbs[nl - 1]);
|
|
824
|
+
size_t bitlen = 32 * (nl - 1) + topbits;
|
|
825
|
+
/* bitlen > 64 here (the fast path overflowed), so shift > 0. */
|
|
826
|
+
size_t shift = bitlen - 54; /* keep 53 mantissa bits + 1 guard bit */
|
|
827
|
+
uint64_t top = 0;
|
|
828
|
+
for (size_t k = 0; k < 54; k++) {
|
|
829
|
+
size_t bit = shift + k;
|
|
830
|
+
uint64_t b = (limbs[bit / 32] >> (bit % 32)) & 1u;
|
|
831
|
+
top |= b << k;
|
|
832
|
+
}
|
|
833
|
+
bool sticky = false;
|
|
834
|
+
for (size_t bit = 0; bit < shift && !sticky; bit++) {
|
|
835
|
+
sticky = ((limbs[bit / 32] >> (bit % 32)) & 1u) != 0;
|
|
836
|
+
}
|
|
837
|
+
free(limbs);
|
|
838
|
+
uint64_t mant = top >> 1;
|
|
839
|
+
bool guard = (top & 1u) != 0;
|
|
840
|
+
if (guard && (sticky || (mant & 1u))) mant++;
|
|
841
|
+
int exp2 = (int)shift + 1;
|
|
842
|
+
if (mant == (1ull << 53)) { /* rounding carried into a new bit */
|
|
843
|
+
mant >>= 1;
|
|
844
|
+
exp2++;
|
|
845
|
+
}
|
|
846
|
+
return ldexp((double)mant, exp2); /* overflow → HUGE_VAL, JS's Infinity */
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
double scr_parse_int(ScrStr *s, double radix) {
|
|
850
|
+
double r32 = scr_to_int32_d(radix);
|
|
851
|
+
const char *p = s->data;
|
|
852
|
+
size_t n = s->len, i = 0;
|
|
853
|
+
while (i < n) {
|
|
854
|
+
size_t adv;
|
|
855
|
+
uint32_t cp = scr_utf8_decode(p + i, &adv);
|
|
856
|
+
if (!scr_is_js_whitespace(cp)) break;
|
|
857
|
+
i += adv;
|
|
858
|
+
}
|
|
859
|
+
double sign = 1.0;
|
|
860
|
+
if (i < n && (p[i] == '+' || p[i] == '-')) {
|
|
861
|
+
if (p[i] == '-') sign = -1.0;
|
|
862
|
+
i++;
|
|
863
|
+
}
|
|
864
|
+
int radix_i;
|
|
865
|
+
bool strip_prefix = true;
|
|
866
|
+
if (r32 != 0) {
|
|
867
|
+
if (r32 < 2 || r32 > 36) return NAN;
|
|
868
|
+
radix_i = (int)r32;
|
|
869
|
+
if (radix_i != 16) strip_prefix = false;
|
|
870
|
+
} else {
|
|
871
|
+
radix_i = 10;
|
|
872
|
+
}
|
|
873
|
+
if (strip_prefix && i + 1 < n && p[i] == '0' &&
|
|
874
|
+
(p[i + 1] == 'x' || p[i + 1] == 'X')) {
|
|
875
|
+
i += 2;
|
|
876
|
+
radix_i = 16;
|
|
877
|
+
}
|
|
878
|
+
size_t dig_start = i;
|
|
879
|
+
while (i < n && scr_digit_value(p[i]) < radix_i) i++;
|
|
880
|
+
if (i == dig_start) return NAN;
|
|
881
|
+
while (dig_start < i && p[dig_start] == '0') dig_start++;
|
|
882
|
+
if (dig_start == i) return sign * 0.0; /* all zeros; "-0" is -0 */
|
|
883
|
+
return sign * scr_digits_to_double(p + dig_start, i - dig_start, radix_i);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/* ES parseFloat (ECMA-262 StrDecimalLiteral prefix over the trimmed
|
|
887
|
+
* input): skip JS whitespace, then take the LONGEST decimal-literal
|
|
888
|
+
* prefix — [+-]? (Infinity | digits [. digits*] | . digits) with an
|
|
889
|
+
* optional [eE][+-]?digits exponent — and answer NaN when none exists.
|
|
890
|
+
* Deliberately narrower than strtod's own grammar (no hex, no
|
|
891
|
+
* "inf"/"nan" spellings, "Infinity" exact-case only), so the validated
|
|
892
|
+
* span is COPIED before strtod sees it — handing strtod the raw tail
|
|
893
|
+
* would let it claim "0x10" as hex where JS answers 0. strtod on the
|
|
894
|
+
* validated span is correctly rounded (the JSON parser's precedent). */
|
|
895
|
+
double scr_parse_float(ScrStr *s) {
|
|
896
|
+
const char *p = s->data;
|
|
897
|
+
size_t n = s->len, i = 0;
|
|
898
|
+
while (i < n) {
|
|
899
|
+
size_t adv;
|
|
900
|
+
uint32_t cp = scr_utf8_decode(p + i, &adv);
|
|
901
|
+
if (!scr_is_js_whitespace(cp)) break;
|
|
902
|
+
i += adv;
|
|
903
|
+
}
|
|
904
|
+
size_t start = i;
|
|
905
|
+
double sign = 1.0;
|
|
906
|
+
if (i < n && (p[i] == '+' || p[i] == '-')) {
|
|
907
|
+
if (p[i] == '-') sign = -1.0;
|
|
908
|
+
i++;
|
|
909
|
+
}
|
|
910
|
+
if (i + 8 <= n && memcmp(p + i, "Infinity", 8) == 0) {
|
|
911
|
+
return sign * (double)INFINITY;
|
|
912
|
+
}
|
|
913
|
+
size_t int_digits = 0, frac_digits = 0;
|
|
914
|
+
while (i < n && p[i] >= '0' && p[i] <= '9') {
|
|
915
|
+
i++;
|
|
916
|
+
int_digits++;
|
|
917
|
+
}
|
|
918
|
+
if (i < n && p[i] == '.') {
|
|
919
|
+
size_t j = i + 1;
|
|
920
|
+
while (j < n && p[j] >= '0' && p[j] <= '9') {
|
|
921
|
+
j++;
|
|
922
|
+
frac_digits++;
|
|
923
|
+
}
|
|
924
|
+
/* "." alone is not a literal; "1." is (trailing dot, no fraction). */
|
|
925
|
+
if (int_digits > 0 || frac_digits > 0) i = j;
|
|
926
|
+
}
|
|
927
|
+
if (int_digits == 0 && frac_digits == 0) return NAN;
|
|
928
|
+
size_t end = i;
|
|
929
|
+
if (i < n && (p[i] == 'e' || p[i] == 'E')) {
|
|
930
|
+
size_t j = i + 1;
|
|
931
|
+
if (j < n && (p[j] == '+' || p[j] == '-')) j++;
|
|
932
|
+
size_t ed = j;
|
|
933
|
+
while (j < n && p[j] >= '0' && p[j] <= '9') j++;
|
|
934
|
+
if (j > ed) end = j; /* exponent joins only with digits ("1e" is 1) */
|
|
935
|
+
}
|
|
936
|
+
size_t span = end - start;
|
|
937
|
+
char buf[64];
|
|
938
|
+
char *tmp = span < sizeof(buf) ? buf : malloc(span + 1);
|
|
939
|
+
if (!tmp) scr_oom();
|
|
940
|
+
memcpy(tmp, p + start, span);
|
|
941
|
+
tmp[span] = '\0';
|
|
942
|
+
double r = strtod(tmp, NULL);
|
|
943
|
+
if (tmp != buf) free(tmp);
|
|
944
|
+
return r;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
ScrStr *scr_f64_to_scrstr(double x) {
|
|
948
|
+
char buf[32];
|
|
949
|
+
size_t len = scr_f64_to_str(x, buf);
|
|
950
|
+
return scr_str_new(buf, len);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/* ── encodeURIComponent / encodeURI ───────────────────────────────────
|
|
954
|
+
* ECMA-262 Encode() over the UTF-8 storage. The spec transcodes UTF-16
|
|
955
|
+
* to UTF-8 and percent-encodes every byte outside the unescaped set —
|
|
956
|
+
* storage here already IS well-formed UTF-8 (lone surrogates were
|
|
957
|
+
* substituted with U+FFFD at their producers, SEMANTICS.md 2), so the
|
|
958
|
+
* walk is byte-wise and the spec's URIError arm (unpaired surrogates)
|
|
959
|
+
* is unreachable: the encoders are total. Unescaped sets are the
|
|
960
|
+
* spec's: uriUnescaped = ALPHA / DIGIT / -_.!~*'() for
|
|
961
|
+
* encodeURIComponent; encodeURI keeps uriReserved ;/?:@&=+$, and #
|
|
962
|
+
* too. Hex digits are uppercase, per spec. Borrows s; result +1. */
|
|
963
|
+
static bool scr_uri_unescaped(unsigned char c, bool keep_reserved) {
|
|
964
|
+
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) return true;
|
|
965
|
+
switch (c) {
|
|
966
|
+
case '-': case '_': case '.': case '!': case '~': case '*': case '\'': case '(': case ')':
|
|
967
|
+
return true;
|
|
968
|
+
default:
|
|
969
|
+
break;
|
|
970
|
+
}
|
|
971
|
+
if (!keep_reserved) return false;
|
|
972
|
+
switch (c) {
|
|
973
|
+
case ';': case '/': case '?': case ':': case '@': case '&': case '=':
|
|
974
|
+
case '+': case '$': case ',': case '#':
|
|
975
|
+
return true;
|
|
976
|
+
default:
|
|
977
|
+
return false;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
static ScrStr *scr_encode_uri_impl(ScrStr *s, bool keep_reserved) {
|
|
982
|
+
const unsigned char *b = (const unsigned char *)s->data;
|
|
983
|
+
size_t n = s->len, out_len = 0;
|
|
984
|
+
for (size_t i = 0; i < n; i++) out_len += scr_uri_unescaped(b[i], keep_reserved) ? 1 : 3;
|
|
985
|
+
if (out_len == n) return scr_str_retain(s); /* nothing escapes — share */
|
|
986
|
+
ScrStr *out = scr_str_alloc_raw(out_len, out_len);
|
|
987
|
+
static const char hex[] = "0123456789ABCDEF";
|
|
988
|
+
char *w = out->data;
|
|
989
|
+
for (size_t i = 0; i < n; i++) {
|
|
990
|
+
if (scr_uri_unescaped(b[i], keep_reserved)) {
|
|
991
|
+
*w++ = (char)b[i];
|
|
992
|
+
} else {
|
|
993
|
+
*w++ = '%';
|
|
994
|
+
*w++ = hex[b[i] >> 4];
|
|
995
|
+
*w++ = hex[b[i] & 0xF];
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
out->len = out_len;
|
|
999
|
+
out->data[out_len] = '\0';
|
|
1000
|
+
return out;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
ScrStr *scr_encode_uri_component(ScrStr *s) { return scr_encode_uri_impl(s, false); }
|
|
1004
|
+
|
|
1005
|
+
ScrStr *scr_encode_uri(ScrStr *s) { return scr_encode_uri_impl(s, true); }
|
|
1006
|
+
|
|
1007
|
+
/* ── isWellFormed / toWellFormed ──────────────────────────────────────
|
|
1008
|
+
* Storage here IS well-formed by invariant: every producer substitutes
|
|
1009
|
+
* the lone surrogates JS strings could carry with U+FFFD at creation
|
|
1010
|
+
* (SEMANTICS.md 2), so no string this runtime can hold is ill-formed.
|
|
1011
|
+
* isWellFormed answers the constant the invariant guarantees and
|
|
1012
|
+
* toWellFormed is the identity (per spec both are no-ops on well-formed
|
|
1013
|
+
* input). A program whose Node run would see `false` already diverged
|
|
1014
|
+
* at the string's creation, not here. */
|
|
1015
|
+
bool scr_str_is_well_formed(ScrStr *s) {
|
|
1016
|
+
(void)s;
|
|
1017
|
+
return true;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
ScrStr *scr_str_to_well_formed(ScrStr *s) { return scr_str_retain(s); }
|
|
1021
|
+
|
|
1022
|
+
/* Immortal interned booleans (same layout trick the emitter uses for
|
|
1023
|
+
* string literals). */
|
|
1024
|
+
static const struct { size_t rc; size_t len; size_t cap; char data[5]; }
|
|
1025
|
+
scr_lit_true = {SIZE_MAX, 4, 4, "true"};
|
|
1026
|
+
static const struct { size_t rc; size_t len; size_t cap; char data[6]; }
|
|
1027
|
+
scr_lit_false = {SIZE_MAX, 5, 5, "false"};
|
|
1028
|
+
|
|
1029
|
+
ScrStr *scr_bool_to_scrstr(bool b) {
|
|
1030
|
+
return b ? (ScrStr *)&scr_lit_true : (ScrStr *)&scr_lit_false;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/* The string iterator's step (for-of over strings): the full CHARACTER at
|
|
1034
|
+
* UTF-16 index i — one code POINT, so an astral char comes back as its
|
|
1035
|
+
* whole two-unit string where charAt would truncate to U+FFFD. The
|
|
1036
|
+
* iterating loop advances by the result's UTF-16 length, exactly JS's
|
|
1037
|
+
* String[Symbol.iterator] contract. Storage is valid UTF-8 by invariant
|
|
1038
|
+
* (literals canonicalized lone surrogates to U+FFFD at creation), so every
|
|
1039
|
+
* decode is a whole char; an i addressing the LOW half of an astral pair
|
|
1040
|
+
* (unreachable from the iterator, which only lands on char starts) answers
|
|
1041
|
+
* the containing char. Out of range → empty string. Borrows s; +1. */
|
|
1042
|
+
ScrStr *scr_str_cp_at(ScrStr *s, double i) {
|
|
1043
|
+
double idx = scr_to_integer_or_infinity(i);
|
|
1044
|
+
if (!(idx >= 0)) return scr_str_empty();
|
|
1045
|
+
if (idx >= (double)s->len) return scr_str_empty(); /* len16 <= len */
|
|
1046
|
+
ScrSidx *e = scr_sidx(s);
|
|
1047
|
+
if (e->u16len == s->len) { /* all ASCII */
|
|
1048
|
+
return (ScrStr *)&scr_ascii1[(unsigned char)s->data[(size_t)idx]];
|
|
1049
|
+
}
|
|
1050
|
+
bool mid;
|
|
1051
|
+
size_t off = scr_u16_to_byte_c(s, e, (size_t)idx, &mid);
|
|
1052
|
+
if (off >= s->len) return scr_str_empty(); /* out of range */
|
|
1053
|
+
size_t adv;
|
|
1054
|
+
(void)scr_utf8_decode(s->data + off, &adv);
|
|
1055
|
+
return scr_str_from_span(s->data + off, adv);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
/* ── the URI component codecs (encodeURIComponent/decodeURIComponent) ──
|
|
1060
|
+
* ECMA-262 Encode/Decode with the component sets, byte-wise over the
|
|
1061
|
+
* runtime's UTF-8 storage: the spec percent-encodes each code point's
|
|
1062
|
+
* UTF-8 bytes, which over UTF-8 storage is exactly a byte scan, and
|
|
1063
|
+
* Decode's "octets must form a valid UTF-8 encoding" is a strict
|
|
1064
|
+
* validation of the assembled escape bytes (raw bytes copy through —
|
|
1065
|
+
* they are the already-valid encoding of code points the spec leaves
|
|
1066
|
+
* untouched). */
|
|
1067
|
+
|
|
1068
|
+
/* The component unreserved set: ALPHA / DIGIT / - _ . ! ~ * ' ( ). */
|
|
1069
|
+
static bool scr_uri_unreserved(unsigned char c) {
|
|
1070
|
+
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) return true;
|
|
1071
|
+
switch (c) {
|
|
1072
|
+
case '-': case '_': case '.': case '!': case '~':
|
|
1073
|
+
case '*': case '\'': case '(': case ')':
|
|
1074
|
+
return true;
|
|
1075
|
+
default:
|
|
1076
|
+
return false;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
ScrStr *scr_str_encode_uri_component(ScrStr *s) {
|
|
1081
|
+
size_t extra = 0;
|
|
1082
|
+
for (size_t i = 0; i < s->len; i++) {
|
|
1083
|
+
if (!scr_uri_unreserved((unsigned char)s->data[i])) extra += 2;
|
|
1084
|
+
}
|
|
1085
|
+
if (extra == 0) {
|
|
1086
|
+
scr_str_retain(s);
|
|
1087
|
+
return s;
|
|
1088
|
+
}
|
|
1089
|
+
static const char hex[] = "0123456789ABCDEF";
|
|
1090
|
+
ScrStr *out = scr_str_alloc_raw(s->len + extra, s->len + extra);
|
|
1091
|
+
char *w = out->data;
|
|
1092
|
+
for (size_t i = 0; i < s->len; i++) {
|
|
1093
|
+
unsigned char c = (unsigned char)s->data[i];
|
|
1094
|
+
if (scr_uri_unreserved(c)) {
|
|
1095
|
+
*w++ = (char)c;
|
|
1096
|
+
} else {
|
|
1097
|
+
*w++ = '%';
|
|
1098
|
+
*w++ = hex[c >> 4];
|
|
1099
|
+
*w++ = hex[c & 0xf];
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
out->data[out->len] = '\0';
|
|
1103
|
+
return out;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
static void scr_uri_malformed(void) {
|
|
1107
|
+
scr_throw_error_named(scr_str_new("URIError", 8),
|
|
1108
|
+
scr_str_new("URI malformed", 13));
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/* One %XX escape's byte, or -1 (bad hex / truncated). */
|
|
1112
|
+
static int scr_uri_hex_byte(const char *p, size_t rem) {
|
|
1113
|
+
if (rem < 3 || p[0] != '%') return -1;
|
|
1114
|
+
int hi, lo;
|
|
1115
|
+
char a = p[1], b = p[2];
|
|
1116
|
+
if (a >= '0' && a <= '9') hi = a - '0';
|
|
1117
|
+
else if (a >= 'A' && a <= 'F') hi = a - 'A' + 10;
|
|
1118
|
+
else if (a >= 'a' && a <= 'f') hi = a - 'a' + 10;
|
|
1119
|
+
else return -1;
|
|
1120
|
+
if (b >= '0' && b <= '9') lo = b - '0';
|
|
1121
|
+
else if (b >= 'A' && b <= 'F') lo = b - 'A' + 10;
|
|
1122
|
+
else if (b >= 'a' && b <= 'f') lo = b - 'a' + 10;
|
|
1123
|
+
else return -1;
|
|
1124
|
+
return (hi << 4) | lo;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
ScrStr *scr_str_decode_uri_component(ScrStr *s) {
|
|
1128
|
+
/* Decoding only ever shrinks (%XX → 1 byte), so len is a safe cap. */
|
|
1129
|
+
ScrStr *out = scr_str_alloc_raw(0, s->len);
|
|
1130
|
+
size_t w = 0;
|
|
1131
|
+
const char *p = s->data;
|
|
1132
|
+
size_t n = s->len, i = 0;
|
|
1133
|
+
while (i < n) {
|
|
1134
|
+
if (p[i] != '%') {
|
|
1135
|
+
out->data[w++] = p[i++];
|
|
1136
|
+
continue;
|
|
1137
|
+
}
|
|
1138
|
+
int b0 = scr_uri_hex_byte(p + i, n - i);
|
|
1139
|
+
if (b0 < 0) goto malformed;
|
|
1140
|
+
i += 3;
|
|
1141
|
+
if (b0 < 0x80) {
|
|
1142
|
+
/* The empty component reserved set: every ASCII escape decodes. */
|
|
1143
|
+
out->data[w++] = (char)b0;
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
/* Multibyte: the continuation bytes must ALSO be escapes (a raw byte
|
|
1147
|
+
* is its own code point in the spec's string, never a continuation),
|
|
1148
|
+
* and the whole sequence must be strictly valid UTF-8. */
|
|
1149
|
+
int need; /* continuation count */
|
|
1150
|
+
int lo = 0x80, hi = 0xBF; /* first continuation's tightened range */
|
|
1151
|
+
if (b0 >= 0xC2 && b0 <= 0xDF) need = 1;
|
|
1152
|
+
else if (b0 == 0xE0) { need = 2; lo = 0xA0; }
|
|
1153
|
+
else if (b0 == 0xED) { need = 2; hi = 0x9F; } /* no surrogates */
|
|
1154
|
+
else if (b0 >= 0xE1 && b0 <= 0xEF) need = 2;
|
|
1155
|
+
else if (b0 == 0xF0) { need = 3; lo = 0x90; }
|
|
1156
|
+
else if (b0 == 0xF4) { need = 3; hi = 0x8F; } /* <= U+10FFFF */
|
|
1157
|
+
else if (b0 >= 0xF1 && b0 <= 0xF3) need = 3;
|
|
1158
|
+
else goto malformed; /* 0x80..0xC1, 0xF5..0xFF: never a leading byte */
|
|
1159
|
+
out->data[w++] = (char)b0;
|
|
1160
|
+
for (int k = 0; k < need; k++) {
|
|
1161
|
+
int bc = scr_uri_hex_byte(p + i, n - i);
|
|
1162
|
+
if (bc < 0) goto malformed;
|
|
1163
|
+
if (k == 0 ? (bc < lo || bc > hi) : (bc < 0x80 || bc > 0xBF)) goto malformed;
|
|
1164
|
+
i += 3;
|
|
1165
|
+
out->data[w++] = (char)bc;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
out->len = w;
|
|
1169
|
+
out->data[w] = '\0';
|
|
1170
|
+
return out;
|
|
1171
|
+
malformed:
|
|
1172
|
+
scr_str_release(out);
|
|
1173
|
+
scr_uri_malformed();
|
|
1174
|
+
return NULL;
|
|
1175
|
+
}
|
|
1176
|
+
|