diff --git a/RELEASES.rst b/RELEASES.rst index c012a337a0..7033a5892b 100644 --- a/RELEASES.rst +++ b/RELEASES.rst @@ -2557,6 +2557,12 @@ Planned * Add shebang support to module-node (GH-1452) +* Add duk_opt_xxx() API calls which behave like duk_require_xxx() but allow a + default value to be used when the index doesn't exist or the value is + undefined (null is rejected with TypeError to mimic ES2015 optional + arguments); for example: "int port = duk_opt_int(ctx, -3, 80);" + (GH-1458) + * Spawn the ArrayBuffer object backing a typed array lazily when its .buffer property is first read, reducing memory usage in common cases where the view is constructed directly without needing the ArrayBuffer object (GH-1225) diff --git a/src-input/duk_api_codec.c b/src-input/duk_api_codec.c index 96d6c1d84d..38beaaa795 100644 --- a/src-input/duk_api_codec.c +++ b/src-input/duk_api_codec.c @@ -18,7 +18,10 @@ DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t idx DUK_ASSERT(duk_is_valid_index(ctx, idx)); /* checked by caller */ - ptr = duk_get_buffer_data_raw(ctx, idx, out_len, 0 /*throw_flag*/, &isbuffer); + /* XXX: with def_ptr set to a stack related pointer, isbuffer could + * be removed from the helper? + */ + ptr = duk_get_buffer_data_raw(ctx, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer); if (isbuffer) { DUK_ASSERT(*out_len == 0 || ptr != NULL); return (const duk_uint8_t *) ptr; diff --git a/src-input/duk_api_internal.h b/src-input/duk_api_internal.h index 25960b28db..eb757e9e47 100644 --- a/src-input/duk_api_internal.h +++ b/src-input/duk_api_internal.h @@ -101,7 +101,7 @@ DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx); DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx); DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx); -DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_found); +DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len, duk_bool_t throw_flag, duk_bool_t *out_isbuffer); DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum); diff --git a/src-input/duk_api_public.h.in b/src-input/duk_api_public.h.in index 76d164d2a8..22ed1b4695 100644 --- a/src-input/duk_api_public.h.in +++ b/src-input/duk_api_public.h.in @@ -648,8 +648,25 @@ DUK_EXTERNAL_DECL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); -DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); + +/* + * Opt operations: like require operations but with an explicit default value + * when value is undefined or index is invalid (null and non-matching types + * cause a TypeError). + */ + +DUK_EXTERNAL_DECL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); +DUK_EXTERNAL_DECL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); +DUK_EXTERNAL_DECL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); +DUK_EXTERNAL_DECL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); +DUK_EXTERNAL_DECL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr); +DUK_EXTERNAL_DECL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); +DUK_EXTERNAL_DECL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size); +DUK_EXTERNAL_DECL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value); +DUK_EXTERNAL_DECL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); +DUK_EXTERNAL_DECL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value); +DUK_EXTERNAL_DECL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value); /* * Require operations: no coercion, throw error if index or type @@ -727,6 +744,17 @@ DUK_EXTERNAL_DECL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t id #define duk_safe_to_string(ctx,idx) \ duk_safe_to_lstring((ctx), (idx), NULL) +/* + * Value length + */ + +DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx); +DUK_EXTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len); +#if 0 +/* duk_require_length()? */ +/* duk_opt_length()? */ +#endif + /* * Misc conversion */ diff --git a/src-input/duk_api_stack.c b/src-input/duk_api_stack.c index 478f03c2c5..988a1e5bff 100644 --- a/src-input/duk_api_stack.c +++ b/src-input/duk_api_stack.c @@ -76,7 +76,7 @@ DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = { DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag); -DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -136,10 +136,11 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_boo DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } -DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_bool_t require) { +DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; duk_small_int_t c; @@ -189,7 +190,8 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_b DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } - return 0; + + return def_value; } /* @@ -1182,7 +1184,7 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, } /* - * Get/require + * Get/opt/require */ DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t idx) { @@ -1211,8 +1213,8 @@ DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t idx) { } } -DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { - duk_bool_t ret = 0; /* default: false */ +DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + duk_bool_t ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -1221,12 +1223,21 @@ DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_BOOLEAN(tv)) { ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + } else { + ret = def_value; + /* Not guaranteed to be 0 or 1. */ } - DUK_ASSERT(ret == 0 || ret == 1); return ret; } +DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) { + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_boolean_raw(ctx, idx, 0); /* default: false */ +} + DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1236,35 +1247,57 @@ DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) { tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_BOOLEAN(tv))) { + if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) { + ret = DUK_TVAL_GET_BOOLEAN(tv); + DUK_ASSERT(ret == 0 || ret == 1); + return ret; + } else { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN); } - ret = DUK_TVAL_GET_BOOLEAN(tv); - DUK_ASSERT(ret == 0 || ret == 1); - return ret; } -DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { +DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_boolean(ctx, idx); +} + +DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { duk_double_union ret; duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); - ret.d = DUK_DOUBLE_NAN; /* default: NaN */ tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_NUMBER(tv)) { - ret.d = DUK_TVAL_GET_NUMBER(tv); +#if defined(DUK_USE_FASTINT) + if (DUK_TVAL_IS_FASTINT(tv)) { + ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */ + } + else +#endif + if (DUK_TVAL_IS_DOUBLE(tv)) { + /* When using packed duk_tval, number must be in NaN-normalized form + * for it to be a duk_tval, so no need to normalize. NOP for unpacked + * duk_tval. + */ + ret.d = DUK_TVAL_GET_DOUBLE(tv); + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); + } else { + ret.d = def_value; + /* Default value (including NaN) may not be normalized. */ } - /* When using packed duk_tval, number must be in NaN-normalized form - * for it to be a duk_tval, so no need to normalize. NOP for unpacked - * duk_tval. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); return ret.d; } +DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) { + return duk__get_number_raw(ctx, idx, DUK_DOUBLE_NAN); /* default: NaN */ +} + DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1288,56 +1321,77 @@ DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) { return ret.d; } +DUK_EXTERNAL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + /* User provided default is not NaN normalized. */ + return def_value; + } + return duk_require_number(ctx, idx); +} + DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 1 /*require*/); + + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 1 /*require*/); } DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx) { - /* Custom coercion for API */ DUK_ASSERT_CTX_VALID(ctx); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 1 /*require*/); + + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 1 /*require*/); } -DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { - const char *ret; - duk_tval *tv; +DUK_EXTERNAL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_int(ctx, idx); +} +DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) { DUK_ASSERT_CTX_VALID(ctx); - /* default: NULL, length 0 */ - ret = NULL; - if (out_len) { - *out_len = 0; + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; } + return duk_require_uint(ctx, idx); +} - tv = duk_get_tval_or_unused(ctx, idx); - DUK_ASSERT(tv != NULL); - if (DUK_TVAL_IS_STRING(tv)) { - /* Here we rely on duk_hstring instances always being zero - * terminated even if the actual string is not. - */ - duk_hstring *h = DUK_TVAL_GET_STRING(tv); - DUK_ASSERT(h != NULL); +DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) { + duk_hstring *h; + const char *ret; + duk_size_t len; + + DUK_ASSERT_CTX_VALID(ctx); + + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + len = DUK_HSTRING_GET_BYTELEN(h); ret = (const char *) DUK_HSTRING_GET_DATA(h); - if (out_len) { - *out_len = DUK_HSTRING_GET_BYTELEN(h); - } + } else { + len = 0; + ret = NULL; } + if (out_len != NULL) { + *out_len = len; + } return ret; } @@ -1368,9 +1422,37 @@ DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_context *ctx, duk_idx } DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t idx) { + duk_hstring *h; + DUK_ASSERT_CTX_VALID(ctx); - return duk_get_lstring(ctx, idx, NULL); + h = duk_get_hstring(ctx, idx); + if (h != NULL) { + return (const char *) DUK_HSTRING_GET_DATA(h); + } else { + return NULL; + } +} + +DUK_EXTERNAL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_len != NULL) { + *out_len = def_len; + } + return def_ptr; + } + return duk_require_lstring(ctx, idx, out_len); +} + +DUK_EXTERNAL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_ptr; + } + return duk_require_string(ctx, idx); } DUK_INTERNAL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx) { @@ -1402,7 +1484,7 @@ DUK_INTERNAL const char *duk_require_string_notsymbol(duk_context *ctx, duk_idx_ return (const char *) DUK_HSTRING_GET_DATA(h); } -DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { +DUK_LOCAL void *duk__get_pointer_raw(duk_context *ctx, duk_idx_t idx, void *def_value) { duk_tval *tv; void *p; @@ -1411,13 +1493,26 @@ DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); if (!DUK_TVAL_IS_POINTER(tv)) { - return NULL; + return def_value; } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ return p; } +DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) { + return duk__get_pointer_raw(ctx, idx, NULL /*def_value*/); +} + +DUK_EXTERNAL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_pointer(ctx, idx); +} + DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1456,10 +1551,12 @@ DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t idx) { } #endif -DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag) { +DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) { duk_hthread *thr = (duk_hthread *) ctx; - duk_tval *tv; duk_hbuffer *h; + void *ret; + duk_size_t len; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); DUK_UNREF(thr); @@ -1470,27 +1567,48 @@ DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size tv = duk_get_tval_or_unused(ctx, idx); DUK_ASSERT(tv != NULL); - if (DUK_UNLIKELY(!DUK_TVAL_IS_BUFFER(tv))) { + if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) { + h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + + len = DUK_HBUFFER_GET_SIZE(h); + ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); + } else { if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + len = def_size; + ret = def_ptr; } - h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - if (out_size) { - *out_size = DUK_HBUFFER_GET_SIZE(h); + if (out_size != NULL) { + *out_size = len; } - return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ + return ret; } DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 0 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/); +} + +DUK_EXTERNAL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer(ctx, idx, out_size); } DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk__get_buffer_helper(ctx, idx, out_size, 1 /*throw_flag*/); + DUK_ASSERT_CTX_VALID(ctx); + + return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/); } /* Get the active buffer data area for a plain buffer or a buffer object. @@ -1498,7 +1616,7 @@ DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_ * have a NULL data pointer when its size is zero, the optional 'out_isbuffer' * argument allows caller to detect this reliably. */ -DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { +DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -1509,7 +1627,7 @@ DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_ *out_isbuffer = 0; } if (out_size != NULL) { - *out_size = 0; + *out_size = def_size; } tv = duk_get_tval_or_unused(ctx, idx); @@ -1558,15 +1676,27 @@ DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_ if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); } - return NULL; + return def_ptr; } DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 0 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL); +} + +DUK_EXTERNAL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + if (out_size != NULL) { + *out_size = def_size; + } + return def_ptr; + } + return duk_require_buffer_data(ctx, idx, out_size); } DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) { - return duk_get_buffer_data_raw(ctx, idx, out_size, 1 /*throw_flag*/, NULL); + return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL); } /* Raw helper for getting a value from the stack, checking its tag. @@ -1723,6 +1853,15 @@ DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx) return f->func; } +DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_c_function(ctx, idx); +} + DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_c_function ret; @@ -1764,6 +1903,15 @@ DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t idx) { return (duk_context *) duk_require_hthread(ctx, idx); } +DUK_EXTERNAL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_context(ctx, idx); +} + DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) { duk_tval *tv; void *ret; @@ -1781,6 +1929,15 @@ DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) { return ret; } +DUK_EXTERNAL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value) { + DUK_ASSERT_CTX_VALID(ctx); + + if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { + return def_value; + } + return duk_require_heapptr(ctx, idx); +} + DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; @@ -2248,7 +2405,7 @@ DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx) { */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/); + return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx) { @@ -2257,7 +2414,7 @@ DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx) { */ DUK_ASSERT_CTX_VALID(ctx); (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger); - return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/); + return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/); } DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx) { @@ -5266,7 +5423,7 @@ DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, duk_ return duk_js_strict_equals(tv1, tv2); } -DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { +DUK_EXTERNAL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) { duk_tval *tv1, *tv2; DUK_ASSERT_CTX_VALID(ctx); diff --git a/tests/api/test-all-public-symbols.c b/tests/api/test-all-public-symbols.c index 4d6e816e16..7b264411b0 100644 --- a/tests/api/test-all-public-symbols.c +++ b/tests/api/test-all-public-symbols.c @@ -168,6 +168,18 @@ static duk_ret_t test_func(duk_context *ctx, void *udata) { (void) duk_new(ctx, 0); (void) duk_next(ctx, 0, 0); (void) duk_normalize_index(ctx, 0); + (void) duk_opt_boolean(ctx, 0, 0); + (void) duk_opt_number(ctx, 0, 0.0); + (void) duk_opt_int(ctx, 0, 0); + (void) duk_opt_uint(ctx, 0, 0); + (void) duk_opt_string(ctx, 0, NULL); + (void) duk_opt_lstring(ctx, 0, NULL, NULL, 0); + (void) duk_opt_buffer(ctx, 0, NULL, NULL, 0); + (void) duk_opt_buffer_data(ctx, 0, NULL, NULL, 0); + (void) duk_opt_pointer(ctx, 0, NULL); + (void) duk_opt_c_function(ctx, 0, NULL); + (void) duk_opt_context(ctx, 0, NULL); + (void) duk_opt_heapptr(ctx, 0, NULL); (void) duk_pcall_method(ctx, 0); (void) duk_pcall_prop(ctx, 0, 0); (void) duk_pcall(ctx, 0); diff --git a/tests/api/test-check-type-mask.c b/tests/api/test-check-type-mask.c index 2812097bd9..253851d3cf 100644 --- a/tests/api/test-check-type-mask.c +++ b/tests/api/test-check-type-mask.c @@ -35,7 +35,7 @@ void test(duk_context *ctx) { duk_push_c_function(ctx, my_c_func, DUK_VARARGS); duk_push_fixed_buffer(ctx, 1024); duk_push_dynamic_buffer(ctx, 1024); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); for (i = 0; i < n + 1; i++) { /* end on invalid index on purpose */ diff --git a/tests/api/test-check-type.c b/tests/api/test-check-type.c index c994bac4af..4a8f1b84c9 100644 --- a/tests/api/test-check-type.c +++ b/tests/api/test-check-type.c @@ -32,7 +32,7 @@ void test(duk_context *ctx) { duk_push_c_function(ctx, my_c_func, DUK_VARARGS); duk_push_fixed_buffer(ctx, 1024); duk_push_dynamic_buffer(ctx, 1024); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); for (i = 0; i < n + 1; i++) { /* end on invalid index on purpose */ diff --git a/tests/api/test-dev-api-verbose-error-messages-gh441.c b/tests/api/test-dev-api-verbose-error-messages-gh441.c index d6e458a04d..7f601afa97 100644 --- a/tests/api/test-dev-api-verbose-error-messages-gh441.c +++ b/tests/api/test-dev-api-verbose-error-messages-gh441.c @@ -276,7 +276,7 @@ static duk_ret_t test_2a(duk_context *ctx, void *udata) { duk_set_top(ctx, 0); duk_push_string(ctx, "foo\x00" "bar"); test__require_calls(ctx); duk_set_top(ctx, 0); duk_push_fixed_buffer(ctx, 16); test__require_calls(ctx); duk_set_top(ctx, 0); duk_push_pointer(ctx, NULL); test__require_calls(ctx); - duk_set_top(ctx, 0); duk_push_pointer(ctx, (void *) 0xdeadbeef); test__require_calls(ctx); + duk_set_top(ctx, 0); duk_push_pointer(ctx, (void *) 0xdeadbeefUL); test__require_calls(ctx); duk_set_top(ctx, 0); duk_push_object(ctx); test__require_calls(ctx); duk_set_top(ctx, 0); duk_push_array(ctx); test__require_calls(ctx); duk_set_top(ctx, 0); duk_push_c_function(ctx, dummy_func, 0); test__require_calls(ctx); diff --git a/tests/api/test-equals-strict-equals.c b/tests/api/test-equals-strict-equals.c index d9f9eae99a..3e5247c2a4 100644 --- a/tests/api/test-equals-strict-equals.c +++ b/tests/api/test-equals-strict-equals.c @@ -96,7 +96,7 @@ void test(duk_context *ctx) { buf3[0] = 'b'; buf3[1] = 'a'; buf3[2] = 'r'; duk_push_pointer(ctx, NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); for (i = 0; i < n; i++) { diff --git a/tests/api/test-get-boolean.c b/tests/api/test-get-boolean.c index be522b3812..0a633e108d 100644 --- a/tests/api/test-get-boolean.c +++ b/tests/api/test-get-boolean.c @@ -11,6 +11,7 @@ index 7: boolean 0 index 8: boolean 0 index 9: boolean 0 index 10: boolean 0 +index 11: boolean 0 ===*/ void test(duk_context *ctx) { @@ -30,7 +31,7 @@ void test(duk_context *ctx) { n = duk_get_top(ctx); printf("top: %ld\n", (long) n); - for (i = 0; i < n; i++) { + for (i = 0; i <= n; i++) { /* End out-of-bounds on purpose. */ printf("index %ld: boolean %d\n", (long) i, (int) duk_get_boolean(ctx, i)); } } diff --git a/tests/api/test-get-buffer.c b/tests/api/test-get-buffer.c index 7462c2b7d7..f27dd2a7cb 100644 --- a/tests/api/test-get-buffer.c +++ b/tests/api/test-get-buffer.c @@ -130,7 +130,7 @@ static duk_ret_t test_buffer_object(duk_context *ctx, void *udata) { (void) udata; - /* duk_get_buffer_data() doesn't accept a buffer object */ + /* duk_get_buffer() doesn't accept a buffer object */ duk_set_top(ctx, 0); duk_eval_string(ctx, "new ArrayBuffer(16)"); diff --git a/tests/api/test-get-error-code-is-error.c b/tests/api/test-get-error-code-is-error.c index ce88d251b6..c0e3ffe608 100644 --- a/tests/api/test-get-error-code-is-error.c +++ b/tests/api/test-get-error-code-is-error.c @@ -75,7 +75,7 @@ static duk_ret_t test_basic(duk_context *ctx, void *udata) { duk_push_dynamic_buffer(ctx, 0); duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); /* Some errors */ duk_eval_string(ctx, "new Error('error')"); diff --git a/tests/api/test-get-int.c b/tests/api/test-get-int.c index 669e11343c..c3150c53de 100644 --- a/tests/api/test-get-int.c +++ b/tests/api/test-get-int.c @@ -11,6 +11,8 @@ NaN coerces to zero number: 0 non-number coerces to zero number: 0 +invalid index returns zero +number: 0 ===*/ void test(duk_context *ctx) { @@ -66,4 +68,7 @@ void test(duk_context *ctx) { duk_push_string(ctx, "123"); printf("number: %ld\n", (long) duk_get_int(ctx, -1)); duk_pop(ctx); + + printf("invalid index returns zero\n"); + printf("number: %ld\n", (long) duk_get_int(ctx, 100)); } diff --git a/tests/api/test-get-number.c b/tests/api/test-get-number.c index 2b999cfbb4..674d33441e 100644 --- a/tests/api/test-get-number.c +++ b/tests/api/test-get-number.c @@ -14,6 +14,7 @@ index 10: number 123456789.000000, FP_NAN=0, FP_INFINITE=0, FP_ZERO=0, FP_SUBNOR index 11: number inf, FP_NAN=0, FP_INFINITE=1, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=0, signbit=0 index 12: number nan, FP_NAN=1, FP_INFINITE=0, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=0, signbit=0 index 13: number nan, FP_NAN=1, FP_INFINITE=0, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=0, signbit=0 +index 14: number nan, FP_NAN=1, FP_INFINITE=0, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=0, signbit=0 ===*/ void test(duk_context *ctx) { @@ -36,7 +37,7 @@ void test(duk_context *ctx) { n = duk_get_top(ctx); printf("top: %ld\n", (long) n); - for (i = 0; i < n; i++) { + for (i = 0; i <= n; i++) { double d = duk_get_number(ctx, i); int c = fpclassify(d); printf("index %ld: number %lf, FP_NAN=%d, FP_INFINITE=%d, FP_ZERO=%d, FP_SUBNORMAL=%d, FP_NORMAL=%d, signbit=%d\n", diff --git a/tests/api/test-get-pointer.c b/tests/api/test-get-pointer.c index e8afdaff40..8a64214082 100644 --- a/tests/api/test-get-pointer.c +++ b/tests/api/test-get-pointer.c @@ -9,6 +9,7 @@ index 5, pointer (nil) index 6, pointer (nil) index 7, pointer (nil) index 8, pointer 0xdeadbeef +index 9, pointer (nil) ===*/ void test(duk_context *ctx) { @@ -22,11 +23,11 @@ void test(duk_context *ctx) { duk_push_int(ctx, 123); duk_push_object(ctx); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); - for (i = 0; i < n; i++) { + for (i = 0; i <= n; i++) { void *ptr = duk_get_pointer(ctx, i); printf("index %ld, pointer %p\n", (long) i, ptr); } diff --git a/tests/api/test-get-set-magic.c b/tests/api/test-get-set-magic.c index 4bc07325b2..4194e7600d 100644 --- a/tests/api/test-get-set-magic.c +++ b/tests/api/test-get-set-magic.c @@ -63,7 +63,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_pop(ctx); /* 0xdeadbeef gets truncated to 0xffffbeef == -16657 */ - duk_set_magic(ctx, -2, 0xdeadbeef); + duk_set_magic(ctx, -2, 0xdeadbeefUL); printf("magic: %ld\n", (long) duk_get_magic(ctx, -2)); duk_dup(ctx, -2); duk_call(ctx, 0); diff --git a/tests/api/test-get-string.c b/tests/api/test-get-string.c index 087c4bf7ae..8ea7f025c0 100644 --- a/tests/api/test-get-string.c +++ b/tests/api/test-get-string.c @@ -33,6 +33,7 @@ index 6: [66 6f 6f] index 7: [e1 88 b4 78 79 7a] index 8: null index 9: null +index 10: null ==> rc=0, result='undefined' ===*/ @@ -54,7 +55,7 @@ static duk_ret_t test_get_string(duk_context *ctx, void *udata) { n = duk_get_top(ctx); printf("top: %ld\n", (long) n); - for (i = 0; i < n; i++) { + for (i = 0; i <= n; i++) { printf("index %ld: ", (long) i); dump((const unsigned char *) duk_get_string(ctx, i)); } @@ -85,6 +86,8 @@ index 8: length 0: null index 8: null index 9: length 0: null index 9: null +index 10: length 0: null +index 10: null ==> rc=0, result='undefined' ===*/ @@ -106,11 +109,11 @@ static duk_ret_t test_get_lstring(duk_context *ctx, void *udata) { n = duk_get_top(ctx); printf("top: %ld\n", (long) n); - for (i = 0; i < n; i++) { + for (i = 0; i <= n; i++) { const char *buf; size_t len; - len = (size_t) 0xdeadbeef; + len = (size_t) 0xdeadbeefUL; buf = duk_get_lstring(ctx, i, &len); printf("index %ld: length %lu: ", (long) i, (unsigned long) len); diff --git a/tests/api/test-get-uint.c b/tests/api/test-get-uint.c new file mode 100644 index 0000000000..91ab1a96d7 --- /dev/null +++ b/tests/api/test-get-uint.c @@ -0,0 +1,49 @@ +/*=== +positive numbers truncate towards zero +number: 3 +negative numbers are clipped to zero +number: 0 +above DUK_UINT_MAX +number is DUK_UINT_MAX: 1 +NaN coerces to zero +number: 0 +non-number coerces to zero +number: 0 +invalid index returns zero +number: 0 +===*/ + +void test(duk_context *ctx) { + double d; + + printf("positive numbers truncate towards zero\n"); + d = 3.9; + duk_push_number(ctx, d); + printf("number: %lu\n", (unsigned long) duk_get_uint(ctx, -1)); + duk_pop(ctx); + + printf("negative numbers are clipped to zero\n"); + d = -3.9; + duk_push_number(ctx, d); + printf("number: %lu\n", (unsigned long) duk_get_uint(ctx, -1)); + duk_pop(ctx); + + printf("above DUK_UINT_MAX\n"); + d = ((double) DUK_UINT_MAX) * 2.0; + duk_push_number(ctx, d); + printf("number is DUK_UINT_MAX: %d\n", (duk_get_uint(ctx, -1) == DUK_UINT_MAX)); + duk_pop(ctx); + + printf("NaN coerces to zero\n"); + duk_push_nan(ctx); + printf("number: %lu\n", (unsigned long) duk_get_uint(ctx, -1)); + duk_pop(ctx); + + printf("non-number coerces to zero\n"); + duk_push_string(ctx, "123"); + printf("number: %lu\n", (unsigned long) duk_get_uint(ctx, -1)); + duk_pop(ctx); + + printf("invalid index returns zero\n"); + printf("number: %lu\n", (unsigned long) duk_get_uint(ctx, 100)); +} diff --git a/tests/api/test-opt-boolean.c b/tests/api/test-opt-boolean.c new file mode 100644 index 0000000000..95f5d05169 --- /dev/null +++ b/tests/api/test-opt-boolean.c @@ -0,0 +1,59 @@ +/*=== +*** test_basic (duk_safe_call) +top: 11 +index 0: boolean 123 +index 1: TypeError: boolean required, found null (stack index 1) +index 2: boolean 1 +index 3: boolean 0 +index 4: TypeError: boolean required, found '' (stack index 4) +index 5: TypeError: boolean required, found 'foo' (stack index 5) +index 6: TypeError: boolean required, found 'true' (stack index 6) +index 7: TypeError: boolean required, found 'false' (stack index 7) +index 8: TypeError: boolean required, found 0 (stack index 8) +index 9: TypeError: boolean required, found 123 (stack index 9) +index 10: TypeError: boolean required, found [object Object] (stack index 10) +index 11: boolean 123 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t safe_helper(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + + printf("index %ld: boolean %d\n", (long) idx, (int) duk_opt_boolean(ctx, idx, 123)); + return 0; +} + +static duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, ""); + duk_push_string(ctx, "foo"); + duk_push_string(ctx, "true"); + duk_push_string(ctx, "false"); + duk_push_int(ctx, 0); + duk_push_int(ctx, 123); + duk_push_object(ctx); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { /* End out-of-bounds on purpose. */ + rc = duk_safe_call(ctx, safe_helper, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); +} diff --git a/tests/api/test-opt-buffer-data.c b/tests/api/test-opt-buffer-data.c new file mode 100644 index 0000000000..7aaaf93671 --- /dev/null +++ b/tests/api/test-opt-buffer-data.c @@ -0,0 +1,144 @@ +static duk_ret_t safe_helper1(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + void *buf; + duk_size_t len; + + len = (duk_size_t) 0xdeadbeefUL; + buf = duk_opt_buffer_data(ctx, idx, &len, (void *) 0x1357acefUL, (duk_size_t) 0x87654321UL); + + printf("index %ld: length %lu, ptr-is-NULL %d, ptr-is-0x1357acef %d\n", + (long) idx, (unsigned long) len, (buf == NULL ? 1 : 0), (buf == 0x1357acefUL)); + return 0; +} + +static duk_ret_t safe_helper2(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + void *buf; + + buf = duk_opt_buffer_data(ctx, idx, NULL, (void *) 0x1357acefUL, (duk_size_t) 0x87654321UL); + + printf("index %ld: ptr-is-NULL %d, ptr-is-0x1357acef %d\n", + (long) idx, (buf == NULL ? 1 : 0), (buf == 0x1357acefUL)); + return 0; +} + +/*=== +*** test_basic (duk_safe_call) +top: 18 +index 0: length 2271560481, ptr-is-NULL 0, ptr-is-0x1357acef 1 +index 0: ptr-is-NULL 0, ptr-is-0x1357acef 1 +index 1: TypeError: buffer required, found null (stack index 1) +index 1: TypeError: buffer required, found null (stack index 1) +index 2: TypeError: buffer required, found true (stack index 2) +index 2: TypeError: buffer required, found true (stack index 2) +index 3: TypeError: buffer required, found false (stack index 3) +index 3: TypeError: buffer required, found false (stack index 3) +index 4: TypeError: buffer required, found '' (stack index 4) +index 4: TypeError: buffer required, found '' (stack index 4) +index 5: TypeError: buffer required, found 'foo' (stack index 5) +index 5: TypeError: buffer required, found 'foo' (stack index 5) +index 6: TypeError: buffer required, found 123 (stack index 6) +index 6: TypeError: buffer required, found 123 (stack index 6) +index 7: TypeError: buffer required, found [object Object] (stack index 7) +index 7: TypeError: buffer required, found [object Object] (stack index 7) +index 8: length 0, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 8: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 9: length 1024, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 9: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 10: length 0, ptr-is-NULL 1, ptr-is-0x1357acef 0 +index 10: ptr-is-NULL 1, ptr-is-0x1357acef 0 +index 11: length 2048, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 11: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 12: length 16, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 12: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 13: length 64, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 13: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 14: length 16, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 14: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 15: length 12, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 15: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 16: length 8, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 16: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 17: length 3, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 17: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 18: length 2271560481, ptr-is-NULL 0, ptr-is-0x1357acef 1 +index 18: ptr-is-NULL 0, ptr-is-0x1357acef 1 +final top: 18 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, ""); + duk_push_string(ctx, "foo"); + duk_push_int(ctx, 123); + duk_push_object(ctx); + duk_push_fixed_buffer(ctx, 0); + duk_push_fixed_buffer(ctx, 1024); + duk_push_dynamic_buffer(ctx, 0); + duk_push_dynamic_buffer(ctx, 2048); + duk_eval_string(ctx, "(function () { return new ArrayBuffer(16); })()"); + duk_eval_string(ctx, "(function () { return new Uint32Array(16); })()"); + duk_eval_string(ctx, "(function () { return new DataView(new ArrayBuffer(16)); })()"); + duk_eval_string(ctx, "(function () { return new Uint32Array(16).subarray(3, 6); })()"); + duk_eval_string(ctx, "(function () { return new Buffer('ABCDEFGH'); })()"); + duk_eval_string(ctx, "(function () { return new Buffer('ABCDEFGH').slice(3, 6); })()"); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { + rc = duk_safe_call(ctx, safe_helper1, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + + rc = duk_safe_call(ctx, safe_helper2, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + printf("final top: %ld\n", (long) duk_get_top(ctx)); + return 0; +} + +/*=== +*** test_uncovered (duk_safe_call) +==> rc=1, result='TypeError: buffer required, found [object ArrayBuffer] (stack index -1)' +===*/ + +static duk_ret_t test_uncovered(duk_context *ctx, void *udata) { + void *ptr; + duk_size_t sz; + + (void) udata; + + ptr = duk_push_dynamic_buffer(ctx, 1024); + memset(ptr, 0, 1024); + duk_push_buffer_object(ctx, -1, 0, 1024, DUK_BUFOBJ_ARRAYBUFFER); + duk_resize_buffer(ctx, -2, 1); /* 1024 -> 1 byte(s) */ + + ptr = (void *) 0xdeadbeefUL; + sz = (void *) 0x12345678UL; + ptr = duk_opt_buffer_data(ctx, -1, &sz, 0x87654321UL, 0xabcdef99UL); + printf("ptr: NULL=%d, 0xdeadbeef=%d 0x87654321=%d\n", ptr == NULL, ptr == (void *) 0xdeadbeefUL, ptr == (void *) 0x87654321UL); + printf("sz: 0=%d, 0x12345678=%d 0xabcdef99=%d\n", sz == 0, sz == 0x12345678UL, sz == 0xabcdef99); + + printf("final top: %ld\n", (long) duk_get_top(ctx)); + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); + TEST_SAFE_CALL(test_uncovered); +} diff --git a/tests/api/test-opt-buffer.c b/tests/api/test-opt-buffer.c new file mode 100644 index 0000000000..cd6f674755 --- /dev/null +++ b/tests/api/test-opt-buffer.c @@ -0,0 +1,117 @@ +static duk_ret_t safe_helper1(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + void *buf; + duk_size_t len; + + len = (duk_size_t) 0xdeadbeefUL; + buf = duk_opt_buffer(ctx, idx, &len, (void *) 0x1357acefUL, (duk_size_t) 0x87654321UL); + + printf("index %ld: length %lu, ptr-is-NULL %d, ptr-is-0x1357acef %d\n", + (long) idx, (unsigned long) len, (buf == NULL ? 1 : 0), (buf == 0x1357acefUL)); + return 0; +} + +static duk_ret_t safe_helper2(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + void *buf; + + buf = duk_opt_buffer(ctx, idx, NULL, (void *) 0x1357acefUL, (duk_size_t) 0x87654321UL); + + printf("index %ld: ptr-is-NULL %d, ptr-is-0x1357acef %d\n", + (long) idx, (buf == NULL ? 1 : 0), (buf == 0x1357acefUL)); + return 0; +} + +/*=== +*** test_basic (duk_safe_call) +top: 18 +index 0: length 2271560481, ptr-is-NULL 0, ptr-is-0x1357acef 1 +index 0: ptr-is-NULL 0, ptr-is-0x1357acef 1 +index 1: TypeError: buffer required, found null (stack index 1) +index 1: TypeError: buffer required, found null (stack index 1) +index 2: TypeError: buffer required, found true (stack index 2) +index 2: TypeError: buffer required, found true (stack index 2) +index 3: TypeError: buffer required, found false (stack index 3) +index 3: TypeError: buffer required, found false (stack index 3) +index 4: TypeError: buffer required, found '' (stack index 4) +index 4: TypeError: buffer required, found '' (stack index 4) +index 5: TypeError: buffer required, found 'foo' (stack index 5) +index 5: TypeError: buffer required, found 'foo' (stack index 5) +index 6: TypeError: buffer required, found 123 (stack index 6) +index 6: TypeError: buffer required, found 123 (stack index 6) +index 7: TypeError: buffer required, found [object Object] (stack index 7) +index 7: TypeError: buffer required, found [object Object] (stack index 7) +index 8: length 0, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 8: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 9: length 1024, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 9: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 10: length 0, ptr-is-NULL 1, ptr-is-0x1357acef 0 +index 10: ptr-is-NULL 1, ptr-is-0x1357acef 0 +index 11: length 2048, ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 11: ptr-is-NULL 0, ptr-is-0x1357acef 0 +index 12: TypeError: buffer required, found [object ArrayBuffer] (stack index 12) +index 12: TypeError: buffer required, found [object ArrayBuffer] (stack index 12) +index 13: TypeError: buffer required, found [object Uint32Array] (stack index 13) +index 13: TypeError: buffer required, found [object Uint32Array] (stack index 13) +index 14: TypeError: buffer required, found [object DataView] (stack index 14) +index 14: TypeError: buffer required, found [object DataView] (stack index 14) +index 15: TypeError: buffer required, found [object Uint32Array] (stack index 15) +index 15: TypeError: buffer required, found [object Uint32Array] (stack index 15) +index 16: TypeError: buffer required, found [object Uint8Array] (stack index 16) +index 16: TypeError: buffer required, found [object Uint8Array] (stack index 16) +index 17: TypeError: buffer required, found [object Uint8Array] (stack index 17) +index 17: TypeError: buffer required, found [object Uint8Array] (stack index 17) +index 18: length 2271560481, ptr-is-NULL 0, ptr-is-0x1357acef 1 +index 18: ptr-is-NULL 0, ptr-is-0x1357acef 1 +final top: 18 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, ""); + duk_push_string(ctx, "foo"); + duk_push_int(ctx, 123); + duk_push_object(ctx); + duk_push_fixed_buffer(ctx, 0); + duk_push_fixed_buffer(ctx, 1024); + duk_push_dynamic_buffer(ctx, 0); + duk_push_dynamic_buffer(ctx, 2048); + duk_eval_string(ctx, "(function () { return new ArrayBuffer(16); })()"); + duk_eval_string(ctx, "(function () { return new Uint32Array(16); })()"); + duk_eval_string(ctx, "(function () { return new DataView(new ArrayBuffer(16)); })()"); + duk_eval_string(ctx, "(function () { return new Uint32Array(16).subarray(3, 6); })()"); + duk_eval_string(ctx, "(function () { return new Buffer('ABCDEFGH'); })()"); + duk_eval_string(ctx, "(function () { return new Buffer('ABCDEFGH').slice(3, 6); })()"); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { + rc = duk_safe_call(ctx, safe_helper1, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + + rc = duk_safe_call(ctx, safe_helper2, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + printf("final top: %ld\n", (long) duk_get_top(ctx)); + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); +} diff --git a/tests/api/test-opt-c-function.c b/tests/api/test-opt-c-function.c new file mode 100644 index 0000000000..823b486c7b --- /dev/null +++ b/tests/api/test-opt-c-function.c @@ -0,0 +1,70 @@ +/*=== +*** test_basic (duk_safe_call) +top: 9 +index 0, my_func 0, dummy_func: 1 +index 1: TypeError: nativefunction required, found null (stack index 1) +index 2: TypeError: nativefunction required, found true (stack index 2) +index 3: TypeError: nativefunction required, found false (stack index 3) +index 4: TypeError: nativefunction required, found 'foo' (stack index 4) +index 5: TypeError: nativefunction required, found 123 (stack index 5) +index 6: TypeError: nativefunction required, found [object Object] (stack index 6) +index 7: TypeError: nativefunction required, found (0xdeadbeef) (stack index 7) +index 8, my_func 1, dummy_func: 0 +index 9, my_func 0, dummy_func: 1 +final top: 9 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t my_func(duk_context *ctx) { + (void) ctx; + return 0; +} + +static duk_ret_t dummy_func(duk_context *ctx) { + (void) ctx; + return 1; +} + +static duk_ret_t safe_helper(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + duk_c_function funcptr; + + funcptr = duk_opt_c_function(ctx, idx, dummy_func); + printf("index %ld, my_func %d, dummy_func: %d\n", + (long) idx, (funcptr == my_func), (funcptr == dummy_func)); + return 0; +} + +duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, "foo"); + duk_push_int(ctx, 123); + duk_push_object(ctx); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); + duk_push_c_function(ctx, my_func, 1 /*nargs*/); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { + rc = duk_safe_call(ctx, safe_helper, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + printf("final top: %ld\n", (long) duk_get_top(ctx)); + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); +} diff --git a/tests/api/test-opt-context.c b/tests/api/test-opt-context.c new file mode 100644 index 0000000000..b306cac059 --- /dev/null +++ b/tests/api/test-opt-context.c @@ -0,0 +1,65 @@ +/*=== +*** test_basic (duk_safe_call) +top: 12 +index 0: dummy 1 +index 1: TypeError: thread required, found null (stack index 1) +index 2: TypeError: thread required, found true (stack index 2) +index 3: TypeError: thread required, found false (stack index 3) +index 4: TypeError: thread required, found '' (stack index 4) +index 5: TypeError: thread required, found 'foo' (stack index 5) +index 6: TypeError: thread required, found 'true' (stack index 6) +index 7: TypeError: thread required, found 'false' (stack index 7) +index 8: TypeError: thread required, found 0 (stack index 8) +index 9: TypeError: thread required, found 123 (stack index 9) +index 10: TypeError: thread required, found [object Object] (stack index 10) +index 11: dummy 0 +index 12: dummy 1 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t safe_helper(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + duk_context *v; + char dummy; + + v = duk_opt_context(ctx, idx, (duk_context *) &dummy); + printf("index %ld: dummy %d\n", + (long) idx, (v == (duk_context *) &dummy)); + return 0; +} + +static duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, ""); + duk_push_string(ctx, "foo"); + duk_push_string(ctx, "true"); + duk_push_string(ctx, "false"); + duk_push_int(ctx, 0); + duk_push_int(ctx, 123); + duk_push_object(ctx); + (void) duk_push_thread(ctx); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { /* End out-of-bounds on purpose. */ + rc = duk_safe_call(ctx, safe_helper, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); +} diff --git a/tests/api/test-opt-heapptr.c b/tests/api/test-opt-heapptr.c new file mode 100644 index 0000000000..801db9fb5c --- /dev/null +++ b/tests/api/test-opt-heapptr.c @@ -0,0 +1,65 @@ +/*=== +*** test_basic (duk_safe_call) +top: 12 +index 0: NULL 0 0x1357acef 1 +index 1: TypeError: heapobject required, found null (stack index 1) +index 2: TypeError: heapobject required, found true (stack index 2) +index 3: TypeError: heapobject required, found false (stack index 3) +index 4: NULL 0 0x1357acef 0 +index 5: NULL 0 0x1357acef 0 +index 6: NULL 0 0x1357acef 0 +index 7: NULL 0 0x1357acef 0 +index 8: TypeError: heapobject required, found 0 (stack index 8) +index 9: TypeError: heapobject required, found 123 (stack index 9) +index 10: NULL 0 0x1357acef 0 +index 11: NULL 0 0x1357acef 0 +index 12: NULL 0 0x1357acef 1 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t safe_helper(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + void *ptr; + + ptr = duk_opt_heapptr(ctx, idx, (void *) 0x1357acef); + + printf("index %ld: NULL %d 0x1357acef %d\n", + (long) idx, (ptr == NULL), (ptr == (void *) 0x1357acef)); + return 0; +} + +static duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, ""); + duk_push_string(ctx, "foo"); + duk_push_string(ctx, "true"); + duk_push_string(ctx, "false"); + duk_push_int(ctx, 0); + duk_push_int(ctx, 123); + duk_push_object(ctx); + duk_eval_string(ctx, "(function () {})"); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { /* End out-of-bounds on purpose. */ + rc = duk_safe_call(ctx, safe_helper, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); +} diff --git a/tests/api/test-opt-int.c b/tests/api/test-opt-int.c new file mode 100644 index 0000000000..99304fe924 --- /dev/null +++ b/tests/api/test-opt-int.c @@ -0,0 +1,78 @@ +/*=== +*** test_basic (duk_safe_call) +top: 18 +index 0: value 123, DUK_INT_MIN=0, DUK_INT_MAX=0 +index 1: TypeError: number required, found null (stack index 1) +index 2: TypeError: number required, found true (stack index 2) +index 3: TypeError: number required, found false (stack index 3) +index 4: TypeError: number required, found 'foo' (stack index 4) +index 5: TypeError: number required, found '123' (stack index 5) +index 6: value -2147483648, DUK_INT_MIN=1, DUK_INT_MAX=0 +index 7: value -2147483648, DUK_INT_MIN=1, DUK_INT_MAX=0 +index 8: value -3, DUK_INT_MIN=0, DUK_INT_MAX=0 +index 9: value 0, DUK_INT_MIN=0, DUK_INT_MAX=0 +index 10: value 0, DUK_INT_MIN=0, DUK_INT_MAX=0 +index 11: value 3, DUK_INT_MIN=0, DUK_INT_MAX=0 +index 12: value 123456789, DUK_INT_MIN=0, DUK_INT_MAX=0 +index 13: value 2147483647, DUK_INT_MIN=0, DUK_INT_MAX=1 +index 14: value 2147483647, DUK_INT_MIN=0, DUK_INT_MAX=1 +index 15: value 2147483647, DUK_INT_MIN=0, DUK_INT_MAX=1 +index 16: value 0, DUK_INT_MIN=0, DUK_INT_MAX=0 +index 17: TypeError: number required, found [object Object] (stack index 17) +index 18: value 123, DUK_INT_MIN=0, DUK_INT_MAX=0 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t safe_helper(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + duk_int_t v = duk_opt_int(ctx, idx, 123); + (void) udata; + + printf("index %ld: value %ld, DUK_INT_MIN=%d, DUK_INT_MAX=%d\n", + (long) idx, (long) v, + (v == DUK_INT_MIN), + (v == DUK_INT_MAX)); + return 0; +} + +static duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, "foo"); + duk_push_string(ctx, "123"); + duk_push_number(ctx, -INFINITY); + duk_push_number(ctx, ((duk_double_t) DUK_INT_MIN) * 2.0); + duk_push_number(ctx, -3.9); + duk_push_number(ctx, -0.0); + duk_push_number(ctx, +0.0); + duk_push_number(ctx, +3.9); + duk_push_number(ctx, +123456789.0); + duk_push_number(ctx, ((duk_double_t) DUK_INT_MAX) * 2.0); + duk_push_number(ctx, ((duk_double_t) DUK_UINT_MAX) * 2.0); + duk_push_number(ctx, +INFINITY); + duk_push_nan(ctx); + duk_push_object(ctx); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { + rc = duk_safe_call(ctx, safe_helper, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); +} diff --git a/tests/api/test-opt-number.c b/tests/api/test-opt-number.c new file mode 100644 index 0000000000..4ad48a209f --- /dev/null +++ b/tests/api/test-opt-number.c @@ -0,0 +1,70 @@ +/*=== +*** test_basic (duk_safe_call) +top: 14 +index 0: number 123.000000, FP_NAN=0, FP_INFINITE=0, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=1, signbit=0 +index 1: TypeError: number required, found null (stack index 1) +index 2: TypeError: number required, found true (stack index 2) +index 3: TypeError: number required, found false (stack index 3) +index 4: TypeError: number required, found 'foo' (stack index 4) +index 5: TypeError: number required, found '123' (stack index 5) +index 6: number -inf, FP_NAN=0, FP_INFINITE=1, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=0, signbit=1 +index 7: number -123456789.000000, FP_NAN=0, FP_INFINITE=0, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=1, signbit=1 +index 8: number -0.000000, FP_NAN=0, FP_INFINITE=0, FP_ZERO=1, FP_SUBNORMAL=0, FP_NORMAL=0, signbit=1 +index 9: number 0.000000, FP_NAN=0, FP_INFINITE=0, FP_ZERO=1, FP_SUBNORMAL=0, FP_NORMAL=0, signbit=0 +index 10: number 123456789.000000, FP_NAN=0, FP_INFINITE=0, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=1, signbit=0 +index 11: number inf, FP_NAN=0, FP_INFINITE=1, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=0, signbit=0 +index 12: number nan, FP_NAN=1, FP_INFINITE=0, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=0, signbit=0 +index 13: TypeError: number required, found [object Object] (stack index 13) +index 14: number 123.000000, FP_NAN=0, FP_INFINITE=0, FP_ZERO=0, FP_SUBNORMAL=0, FP_NORMAL=1, signbit=0 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t safe_helper(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + double d = duk_opt_number(ctx, idx, 123.0); + int c = fpclassify(d); + (void) udata; + + printf("index %ld: number %lf, FP_NAN=%d, FP_INFINITE=%d, FP_ZERO=%d, FP_SUBNORMAL=%d, FP_NORMAL=%d, signbit=%d\n", + (long) idx, d, (c == FP_NAN ? 1 : 0), (c == FP_INFINITE ? 1 : 0), (c == FP_ZERO ? 1 : 0), + (c == FP_SUBNORMAL ? 1 : 0), (c == FP_NORMAL ? 1 : 0), (signbit(d) ? 1 : 0)); + return 0; +} + +static duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, "foo"); + duk_push_string(ctx, "123"); + duk_push_number(ctx, -INFINITY); + duk_push_number(ctx, -123456789.0); + duk_push_number(ctx, -0.0); + duk_push_number(ctx, +0.0); + duk_push_number(ctx, +123456789.0); + duk_push_number(ctx, +INFINITY); + duk_push_nan(ctx); + duk_push_object(ctx); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { + rc = duk_safe_call(ctx, safe_helper, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); +} diff --git a/tests/api/test-opt-pointer.c b/tests/api/test-opt-pointer.c new file mode 100644 index 0000000000..ac1d6e560e --- /dev/null +++ b/tests/api/test-opt-pointer.c @@ -0,0 +1,59 @@ +static duk_ret_t safe_helper(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + void *ptr; + + ptr = duk_opt_pointer(ctx, idx, (void *) 0x87654321UL); + printf("index %ld, pointer %p\n", (long) idx, ptr); + return 0; +} + +/*=== +*** test_basic (duk_safe_call) +top: 9 +index 0, pointer 0x87654321 +index 1: TypeError: pointer required, found null (stack index 1) +index 2: TypeError: pointer required, found true (stack index 2) +index 3: TypeError: pointer required, found false (stack index 3) +index 4: TypeError: pointer required, found 'foo' (stack index 4) +index 5: TypeError: pointer required, found 123 (stack index 5) +index 6: TypeError: pointer required, found [object Object] (stack index 6) +index 7, pointer (nil) +index 8, pointer 0xdeadbeef +index 9, pointer 0x87654321 +final top: 9 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, "foo"); + duk_push_int(ctx, 123); + duk_push_object(ctx); + duk_push_pointer(ctx, (void *) NULL); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { + rc = duk_safe_call(ctx, safe_helper, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + printf("final top: %ld\n", (long) duk_get_top(ctx)); + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); +} diff --git a/tests/api/test-opt-string.c b/tests/api/test-opt-string.c new file mode 100644 index 0000000000..ab87b9289d --- /dev/null +++ b/tests/api/test-opt-string.c @@ -0,0 +1,168 @@ +static void dump(const unsigned char *buf) { + const unsigned char *p = buf; + int first = 1; + + if (!buf) { + printf("null\n"); + return; + } + + printf("["); + while (*p) { + if (first) { + first = 0; + } else { + printf(" "); + } + printf("%02x", (int) (*p)); + p++; + } + printf("]\n"); +} + +static duk_ret_t safe_helper_string(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + + dump((const unsigned char *) duk_opt_string(ctx, idx, "default")); + return 0; +} + +static duk_ret_t safe_helper_lstring1(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + const char *buf; + size_t len; + + len = (size_t) 0xdeadbeefUL; + buf = duk_opt_lstring(ctx, idx, &len, "default!", 7); + printf("length %lu: ", (unsigned long) len); + dump((const unsigned char *) buf); + return 0; +} + +static duk_ret_t safe_helper_lstring2(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + const char *buf; + + buf = duk_opt_lstring(ctx, idx, NULL, "default!", 7); + dump((const unsigned char *) buf); + return 0; +} + +/*=== +*** test_opt_string (duk_safe_call) +top: 10 +index 0: [64 65 66 61 75 6c 74] +index 1: TypeError: string required, found null (stack index 1) +index 2: TypeError: string required, found true (stack index 2) +index 3: TypeError: string required, found false (stack index 3) +index 4: [] +index 5: [66 6f 6f] +index 6: [66 6f 6f] +index 7: [e1 88 b4 78 79 7a] +index 8: TypeError: string required, found NaN (stack index 8) +index 9: TypeError: string required, found [object Object] (stack index 9) +index 10: [64 65 66 61 75 6c 74] +==> rc=0, result='undefined' +===*/ + +static duk_ret_t test_opt_string(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, ""); + duk_push_string(ctx, "foo"); + duk_push_lstring(ctx, "foo\0bar", 7); + duk_push_string(ctx, "\xe1\x88\xb4xyz"); /* 4 chars, first char utf-8 encoded U+1234 */ + duk_push_nan(ctx); + duk_push_object(ctx); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { + printf("index %ld: ", (long) i); + rc = duk_safe_call(ctx, safe_helper_string, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("%s\n", duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + return 0; +} + +/*=== +*** test_opt_lstring (duk_safe_call) +top: 10 +index 0: length 7: [64 65 66 61 75 6c 74 21] +index 0: [64 65 66 61 75 6c 74 21] +index 1: TypeError: string required, found null (stack index 1) +index 1: TypeError: string required, found null (stack index 1) +index 2: TypeError: string required, found true (stack index 2) +index 2: TypeError: string required, found true (stack index 2) +index 3: TypeError: string required, found false (stack index 3) +index 3: TypeError: string required, found false (stack index 3) +index 4: length 0: [] +index 4: [] +index 5: length 3: [66 6f 6f] +index 5: [66 6f 6f] +index 6: length 7: [66 6f 6f] +index 6: [66 6f 6f] +index 7: length 6: [e1 88 b4 78 79 7a] +index 7: [e1 88 b4 78 79 7a] +index 8: TypeError: string required, found NaN (stack index 8) +index 8: TypeError: string required, found NaN (stack index 8) +index 9: TypeError: string required, found [object Object] (stack index 9) +index 9: TypeError: string required, found [object Object] (stack index 9) +index 10: length 7: [64 65 66 61 75 6c 74 21] +index 10: [64 65 66 61 75 6c 74 21] +==> rc=0, result='undefined' +===*/ + +static duk_ret_t test_opt_lstring(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, ""); + duk_push_string(ctx, "foo"); + duk_push_lstring(ctx, "foo\0bar", 7); + duk_push_string(ctx, "\xe1\x88\xb4xyz"); /* 4 chars, first char utf-8 encoded U+1234 */ + duk_push_nan(ctx); + duk_push_object(ctx); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { + printf("index %ld: ", (long) i); + rc = duk_safe_call(ctx, safe_helper_lstring1, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("%s\n", duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + + printf("index %ld: ", (long) i); + rc = duk_safe_call(ctx, safe_helper_lstring2, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("%s\n", duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_opt_string); + TEST_SAFE_CALL(test_opt_lstring); +} diff --git a/tests/api/test-opt-uint.c b/tests/api/test-opt-uint.c new file mode 100644 index 0000000000..42ce1c2d31 --- /dev/null +++ b/tests/api/test-opt-uint.c @@ -0,0 +1,77 @@ +/*=== +*** test_basic (duk_safe_call) +top: 18 +index 0: value 123, DUK_UINT_MAX=0 +index 1: TypeError: number required, found null (stack index 1) +index 2: TypeError: number required, found true (stack index 2) +index 3: TypeError: number required, found false (stack index 3) +index 4: TypeError: number required, found 'foo' (stack index 4) +index 5: TypeError: number required, found '123' (stack index 5) +index 6: value 0, DUK_UINT_MAX=0 +index 7: value 0, DUK_UINT_MAX=0 +index 8: value 0, DUK_UINT_MAX=0 +index 9: value 0, DUK_UINT_MAX=0 +index 10: value 0, DUK_UINT_MAX=0 +index 11: value 3, DUK_UINT_MAX=0 +index 12: value 123456789, DUK_UINT_MAX=0 +index 13: value 4294967294, DUK_UINT_MAX=0 +index 14: value 4294967295, DUK_UINT_MAX=1 +index 15: value 4294967295, DUK_UINT_MAX=1 +index 16: value 0, DUK_UINT_MAX=0 +index 17: TypeError: number required, found [object Object] (stack index 17) +index 18: value 123, DUK_UINT_MAX=0 +==> rc=0, result='undefined' +===*/ + +static duk_ret_t safe_helper(duk_context *ctx, void *udata) { + duk_idx_t idx = (duk_idx_t) udata & 0xffffffffUL; + duk_uint_t v = duk_opt_uint(ctx, idx, 123); + (void) udata; + + printf("index %ld: value %lu, DUK_UINT_MAX=%d\n", + (long) idx, (unsigned long) v, + (v == DUK_UINT_MAX)); + return 0; +} + +static duk_ret_t test_basic(duk_context *ctx, void *udata) { + duk_idx_t i, n; + duk_int_t rc; + + (void) udata; + + duk_push_undefined(ctx); + duk_push_null(ctx); + duk_push_true(ctx); + duk_push_false(ctx); + duk_push_string(ctx, "foo"); + duk_push_string(ctx, "123"); + duk_push_number(ctx, -INFINITY); + duk_push_number(ctx, ((duk_double_t) DUK_INT_MIN) * 2.0); + duk_push_number(ctx, -3.9); + duk_push_number(ctx, -0.0); + duk_push_number(ctx, +0.0); + duk_push_number(ctx, +3.9); + duk_push_number(ctx, +123456789.0); + duk_push_number(ctx, ((duk_double_t) DUK_INT_MAX) * 2.0); + duk_push_number(ctx, ((duk_double_t) DUK_UINT_MAX) * 2.0); + duk_push_number(ctx, +INFINITY); + duk_push_nan(ctx); + duk_push_object(ctx); + + n = duk_get_top(ctx); + printf("top: %ld\n", (long) n); + for (i = 0; i <= n; i++) { + rc = duk_safe_call(ctx, safe_helper, (void *) i, 0, 1); + if (rc != DUK_EXEC_SUCCESS) { + printf("index %ld: %s\n", (long) i, duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); + } + + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic); +} diff --git a/tests/api/test-push-buffer-object.c b/tests/api/test-push-buffer-object.c index e174663e51..bb9e5a0bf1 100644 --- a/tests/api/test-push-buffer-object.c +++ b/tests/api/test-push-buffer-object.c @@ -405,7 +405,7 @@ static duk_ret_t test_invalid_flags2(duk_context *ctx, void *udata) { (void) udata; duk_push_fixed_buffer(ctx, 256); - duk_push_buffer_object(ctx, -1, 7, 512, (duk_uint_t) 0xdeadbeef /* ERROR: bogus type */); + duk_push_buffer_object(ctx, -1, 7, 512, (duk_uint_t) 0xdeadbeefUL /* ERROR: bogus type */); printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; } diff --git a/tests/api/test-push-this.c b/tests/api/test-push-this.c index 8f58ac0534..04e1411ba4 100644 --- a/tests/api/test-push-this.c +++ b/tests/api/test-push-this.c @@ -39,7 +39,7 @@ void test(duk_context *ctx) { duk_push_object(ctx); duk_push_array(ctx); duk_push_fixed_buffer(ctx, 16); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); diff --git a/tests/api/test-pushers.c b/tests/api/test-pushers.c index 802f9e97a3..61cfa85cb5 100644 --- a/tests/api/test-pushers.c +++ b/tests/api/test-pushers.c @@ -135,5 +135,5 @@ void test(duk_context *ctx) { res = test_vsprintf_null(ctx, 2, 3, 5); PRINTRESTOP(); duk_push_pointer(ctx, (void *) 0); PRINTTOP(); - duk_push_pointer(ctx, (void *) 0xdeadbeef); PRINTTOP(); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); PRINTTOP(); } diff --git a/tests/api/test-require-lstring.c b/tests/api/test-require-lstring.c index e807083c8e..68276f159d 100644 --- a/tests/api/test-require-lstring.c +++ b/tests/api/test-require-lstring.c @@ -31,19 +31,19 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_push_lstring(ctx, "foo\0bar", 7); duk_push_string(ctx, ""); - sz = (duk_size_t) 0xdeadbeef; + sz = (duk_size_t) 0xdeadbeefUL; p = duk_require_lstring(ctx, 0, &sz); dump_string_size(p, sz); - sz = (duk_size_t) 0xdeadbeef; + sz = (duk_size_t) 0xdeadbeefUL; p = duk_require_lstring(ctx, 0, NULL); dump_string(p); - sz = (duk_size_t) 0xdeadbeef; + sz = (duk_size_t) 0xdeadbeefUL; p = duk_require_lstring(ctx, 1, &sz); dump_string_size(p, sz); - sz = (duk_size_t) 0xdeadbeef; + sz = (duk_size_t) 0xdeadbeefUL; p = duk_require_lstring(ctx, 1, NULL); dump_string(p); return 0; diff --git a/tests/api/test-require-pointer.c b/tests/api/test-require-pointer.c index 28a298f1e1..eba3a09999 100644 --- a/tests/api/test-require-pointer.c +++ b/tests/api/test-require-pointer.c @@ -15,7 +15,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { (void) udata; duk_set_top(ctx, 0); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); duk_push_pointer(ctx, (void *) NULL); printf("pointer: %p\n", duk_require_pointer(ctx, 0)); printf("pointer: %p\n", duk_require_pointer(ctx, 1)); diff --git a/tests/api/test-to-boolean.c b/tests/api/test-to-boolean.c index 50327a80a1..9c1c95a91b 100644 --- a/tests/api/test-to-boolean.c +++ b/tests/api/test-to-boolean.c @@ -49,7 +49,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_push_dynamic_buffer(ctx, 0); duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); diff --git a/tests/api/test-to-buffer.c b/tests/api/test-to-buffer.c index 400403aa58..cb556b4fb1 100644 --- a/tests/api/test-to-buffer.c +++ b/tests/api/test-to-buffer.c @@ -99,7 +99,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { buf[i] = i; } duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); @@ -110,7 +110,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_dup(ctx, i); t1 = duk_get_type(ctx, -1); - sz = (duk_size_t) 0xdeadbeef; + sz = (duk_size_t) 0xdeadbeefUL; ptr = duk_to_buffer(ctx, -1, &sz); t2 = duk_get_type(ctx, -1); printf("index %ld, type %ld -> %ld, ptr-is-NULL %d, size %lu\n", diff --git a/tests/api/test-to-int-uint.c b/tests/api/test-to-int-uint.c index 457e203fde..3b1843b7d2 100644 --- a/tests/api/test-to-int-uint.c +++ b/tests/api/test-to-int-uint.c @@ -120,7 +120,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); #if 0 printf("%lld %lld %llu %llu\n", diff --git a/tests/api/test-to-int32-uint32-uint16.c b/tests/api/test-to-int32-uint32-uint16.c index 54cca406cd..ab676a7003 100644 --- a/tests/api/test-to-int32-uint32-uint16.c +++ b/tests/api/test-to-int32-uint32-uint16.c @@ -198,7 +198,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); diff --git a/tests/api/test-to-lstring.c b/tests/api/test-to-lstring.c index 144149f59b..9b37558690 100644 --- a/tests/api/test-to-lstring.c +++ b/tests/api/test-to-lstring.c @@ -80,7 +80,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { ptr[i] = (char) ('a' + i); } duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); @@ -89,7 +89,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_size_t sz; duk_dup(ctx, i); - sz = (duk_size_t) 0xdeadbeef; + sz = (duk_size_t) 0xdeadbeefUL; p = (const unsigned char *) duk_to_lstring(ctx, -1, &sz); printf("index %ld, string: '", (long) i); for (j = 0; j < sz; j++) { @@ -103,7 +103,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_pop(ctx); duk_dup(ctx, i); - sz = (duk_size_t) 0xdeadbeef; + sz = (duk_size_t) 0xdeadbeefUL; p = (const unsigned char *) duk_to_lstring(ctx, -1, NULL); printf("index %ld, string: '%s'\n", (long) i, (const char *) p); duk_pop(ctx); diff --git a/tests/api/test-to-null.c b/tests/api/test-to-null.c index 7db6cc21da..03fee1b67e 100644 --- a/tests/api/test-to-null.c +++ b/tests/api/test-to-null.c @@ -49,7 +49,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_push_dynamic_buffer(ctx, 0); duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); diff --git a/tests/api/test-to-number.c b/tests/api/test-to-number.c index cb66448228..d21feca012 100644 --- a/tests/api/test-to-number.c +++ b/tests/api/test-to-number.c @@ -74,7 +74,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_push_dynamic_buffer(ctx, 0); duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); diff --git a/tests/api/test-to-object.c b/tests/api/test-to-object.c index 8e50ddfd04..0e3f57dd6f 100644 --- a/tests/api/test-to-object.c +++ b/tests/api/test-to-object.c @@ -142,7 +142,7 @@ static duk_ret_t test_2g(duk_context *ctx, void *udata) { static duk_ret_t test_2h(duk_context *ctx, void *udata) { (void) udata; duk_set_top(ctx, 0); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); duk_to_object(ctx, 0); printf("index 0 OK\n"); return 0; diff --git a/tests/api/test-to-pointer.c b/tests/api/test-to-pointer.c index 96f26b0b4c..07455268df 100644 --- a/tests/api/test-to-pointer.c +++ b/tests/api/test-to-pointer.c @@ -51,7 +51,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_push_dynamic_buffer(ctx, 0); duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); diff --git a/tests/api/test-to-primitive.c b/tests/api/test-to-primitive.c index 0166c7375c..19cb96162d 100644 --- a/tests/api/test-to-primitive.c +++ b/tests/api/test-to-primitive.c @@ -56,7 +56,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_push_dynamic_buffer(ctx, 0); duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); diff --git a/tests/api/test-to-string.c b/tests/api/test-to-string.c index 4127882a9b..0af1753faa 100644 --- a/tests/api/test-to-string.c +++ b/tests/api/test-to-string.c @@ -60,7 +60,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { ptr[i] = (char) ('a' + i); } duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); diff --git a/tests/api/test-to-undefined.c b/tests/api/test-to-undefined.c index 70d4eaf6d1..f3bc337e5b 100644 --- a/tests/api/test-to-undefined.c +++ b/tests/api/test-to-undefined.c @@ -49,7 +49,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_push_dynamic_buffer(ctx, 0); duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); diff --git a/tests/api/test-types.c b/tests/api/test-types.c index ca492c1500..d2f355492e 100644 --- a/tests/api/test-types.c +++ b/tests/api/test-types.c @@ -36,7 +36,7 @@ void test(duk_context *ctx) { duk_push_c_function(ctx, my_c_func, DUK_VARARGS); duk_push_fixed_buffer(ctx, 1024); duk_push_dynamic_buffer(ctx, 1024); - duk_push_pointer(ctx, (void *) 0xdeadbeef); + duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); for (i = 0; i < n + 1; i++) { /* end on invalid index on purpose */ diff --git a/website/api/buffer-null-pointer-ambiguity.html b/website/api/buffer-null-pointer-ambiguity.html index 18aba8aefe..206879e113 100644 --- a/website/api/buffer-null-pointer-ambiguity.html +++ b/website/api/buffer-null-pointer-ambiguity.html @@ -3,6 +3,7 @@ based on the return values alone: a NULL with zero size is returned for a non-buffer. The same values may be returned for a zero-size buffer (although it is also possible that a non-NULL pointer is returned). Use -duk_is_buffer_data() when type -checking a buffer or a buffer object. +duk_is_buffer() or +duk_is_buffer_data() or +when type checking a buffer or a buffer object. diff --git a/website/api/default-pointer-validity.html b/website/api/default-pointer-validity.html new file mode 100644 index 0000000000..3ae33d366e --- /dev/null +++ b/website/api/default-pointer-validity.html @@ -0,0 +1,10 @@ +
+Default pointer values given to duk_opt_xxx() are not tracked by Duktape, +e.g. duk_opt_string() does not make a copy of the default string argument. +The caller is responsible for ensuring that the default pointer remains +valid for its intended use. For example, duk_opt_string(ctx, 3, "localhost") +works fine because a string constant is always valid, but if the argument is +a libc allocated string, caller must ensure the pointer returned from +duk_opt_string() is not used beyond the lifetime of the libc allocated +string (in case the return value was the default). +
diff --git a/website/api/duk_get_lstring.yaml b/website/api/duk_get_lstring.yaml index 824b63ad7f..6c2aa7b66c 100644 --- a/website/api/duk_get_lstring.yaml +++ b/website/api/duk_get_lstring.yaml @@ -18,21 +18,22 @@ summary: |

To get the string character length (instead of byte length), use duk_get_length().

-
- A non-NULL return value is guaranteed even for zero length strings; - this differs from how buffer data pointers are handled (for technical reasons). -
+
example: | - const char *buf; + const char *str; duk_size_t len; - buf = duk_get_lstring(ctx, -3, &len); - if (buf) { + str = duk_get_lstring(ctx, -3, &len); + if (str) { printf("value is a string, %lu bytes\n", (unsigned long) len); } +seealso: + - duk_get_string + tags: - stack + - string introduced: 1.0.0 diff --git a/website/api/duk_get_number.yaml b/website/api/duk_get_number.yaml index 612e6623fc..fca194f31b 100644 --- a/website/api/duk_get_number.yaml +++ b/website/api/duk_get_number.yaml @@ -14,4 +14,7 @@ summary: | example: | printf("value: %lf\n", (double) duk_get_number(ctx, -3)); +tags: + - stack + introduced: 1.0.0 diff --git a/website/api/duk_get_string.yaml b/website/api/duk_get_string.yaml index 499e6b4851..6be9ffad3f 100644 --- a/website/api/duk_get_string.yaml +++ b/website/api/duk_get_string.yaml @@ -16,21 +16,21 @@ summary: | contains embedded NUL characters), use duk_get_lstring().

-
- A non-NULL return value is guaranteed even for zero length strings; - this differs from how buffer data pointers are handled (for technical reasons). -
+
example: | - const char *buf; + const char *str; - buf = duk_get_string(ctx, -3); - if (buf) { - printf("value is a string: %s\n", buf); + str = duk_get_string(ctx, -3); + if (str) { + printf("value is a string: %s\n", str); } +seealso: + - duk_get_lstring + tags: - stack - string diff --git a/website/api/duk_is_buffer_data.yaml b/website/api/duk_is_buffer_data.yaml index e74d2ececb..4a747bc60b 100644 --- a/website/api/duk_is_buffer_data.yaml +++ b/website/api/duk_is_buffer_data.yaml @@ -19,6 +19,7 @@ example: | tags: - stack - buffer + - bufferobject seealso: - duk_is_buffer diff --git a/website/api/duk_opt_boolean.yaml b/website/api/duk_opt_boolean.yaml new file mode 100644 index 0000000000..75257358e9 --- /dev/null +++ b/website/api/duk_opt_boolean.yaml @@ -0,0 +1,22 @@ +name: duk_opt_boolean + +proto: | + duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value); + +stack: | + [ ... val! ... ] + +summary: | +

Get the boolean value at idx without modifying or coercing + the value. Returns 1 if the value is true, 0 if the value is + false. If the value is undefined or the index is + invalid, def_value default value is returned. In other cases + (null or non-matching type) throws an error.

+ +example: | + duk_bool_t flag_xyz = duk_opt_boolean(ctx, 2, 1); /* default: true */ + +tags: + - stack + +introduced: 2.1.0 diff --git a/website/api/duk_opt_buffer.yaml b/website/api/duk_opt_buffer.yaml new file mode 100644 index 0000000000..3ffb74b1bf --- /dev/null +++ b/website/api/duk_opt_buffer.yaml @@ -0,0 +1,40 @@ +name: duk_opt_buffer + +proto: | + void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); + +stack: | + [ ... val! ... ] + +summary: | +

Get the data pointer for a (plain) buffer value at idx without + modifying or coercing the value. Returns a non-NULL pointer if the value + is a valid buffer with a non-zero size. For a zero-size buffer, may return a + NULL or a non-NULL pointer. If out_size is + non-NULL, the size of the buffer is written to *out_size. + If the value is undefined or the index is invalid, def_ptr + default value is returned and the def_len default length is written + to *out_size (if out_size is non-NULL). + In other cases (null and non-matching type) throws an error.

+ +
+ +
+ +example: | + void *ptr; + duk_size_t sz; + char buf[256]; + + /* Use a buffer given at index 2, or default to 'buf'. */ + ptr = duk_opt_buffer(ctx, 2, &sz, (void *) buf, sizeof(buf)); + printf("buf=%p, size=%lu\n", ptr, (unsigned long) sz); + +tags: + - stack + - buffer + +seealso: + - duk_opt_buffer_data + +introduced: 2.1.0 diff --git a/website/api/duk_opt_buffer_data.yaml b/website/api/duk_opt_buffer_data.yaml new file mode 100644 index 0000000000..5b8b3ed495 --- /dev/null +++ b/website/api/duk_opt_buffer_data.yaml @@ -0,0 +1,47 @@ +name: duk_opt_buffer_data + +proto: | + void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len); + +stack: | + [ ... val! ... ] + +summary: | +

Get the data pointer for a plain buffer or a buffer object (ArrayBuffer, + Node.js Buffer, DataView, or TypedArray view) value at idx without + modifying or coercing the value. Return a non-NULL pointer if the + value is a valid buffer with a non-zero size. For a zero-size buffer, may return + a NULL or a non-NULL pointer. If out_size + is non-NULL, the size of the buffer is written to *out_size. + If the value is undefined or the index is invalid, def_ptr + default value is returned and the def_len default length is written + to *out_size (if out_size is non-NULL). + In other cases (null and non-matching type) throws an error. + Also throws if the value is a buffer object whose "backing buffer" doesn't + fully cover the buffer object's apparent size.

+ +

The data area indicated by the return pointer and length is the full + buffer for a plain buffer value, and the active "slice" for a buffer object. + The length returned is expressed in bytes (instead of elements), so that you + can always access ptr[0] to ptr[len - 1]. + See duk_get_buffer_data() for examples.

+ +
+ +example: | + void *ptr; + duk_size_t sz; + char buf[256]; + + /* Use a buffer given at index 2, or default to 'buf'. */ + ptr = duk_opt_buffer_data(ctx, 2, &sz, (void *) buf, sizeof(buf)); + +tags: + - stack + - buffer + - bufferobject + +seealso: + - duk_opt_buffer + +introduced: 2.1.0 diff --git a/website/api/duk_opt_c_function.yaml b/website/api/duk_opt_c_function.yaml new file mode 100644 index 0000000000..667b177a83 --- /dev/null +++ b/website/api/duk_opt_c_function.yaml @@ -0,0 +1,26 @@ +name: duk_opt_c_function + +proto: | + duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value); + +stack: | + [ ... val! ... ] + +summary: | +

Get the Duktape/C function pointer (a duk_c_function) from an + Ecmascript function object associated with a Duktape/C function. If the + value is undefined or the index is invalid, def_value + default value is returned. In other cases (null or non-matching + type) throws an error.

+ +example: | + duk_c_function funcptr; + + /* Native callback, default to nop_callback. */ + funcptr = duk_opt_c_function(ctx, -3, nop_callback); + +tags: + - stack + - function + +introduced: 2.1.0 diff --git a/website/api/duk_opt_context.yaml b/website/api/duk_opt_context.yaml new file mode 100644 index 0000000000..58d3473b08 --- /dev/null +++ b/website/api/duk_opt_context.yaml @@ -0,0 +1,26 @@ +name: duk_opt_context + +proto: | + duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value); + +stack: | + [ ... val! ... ] + +summary: | +

Get a context pointer for a Duktape thread at idx. If the + value is undefined or the index is invalid, def_value + default value is returned. In other cases (null or non-matching + type) throws an error.

+ +
+ +example: | + duk_context *target_ctx; + + target_ctx = duk_get_context(ctx, 2, default_ctx); + +tags: + - stack + - borrowed + +introduced: 2.1.0 diff --git a/website/api/duk_opt_heapptr.yaml b/website/api/duk_opt_heapptr.yaml new file mode 100644 index 0000000000..1e3e176ce6 --- /dev/null +++ b/website/api/duk_opt_heapptr.yaml @@ -0,0 +1,27 @@ +name: duk_opt_heapptr + +proto: | + void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx); + +stack: | + [ ... val! ... ] + +summary: | +

Get a borrowed void * reference to a Duktape heap allocated + value (object, buffer, string) at idx. If the value is + undefined or the index is invalid, def_value + default value is returned. In other cases (null or + non-matching type) throws an error.

+ +
+ +example: | + void *ptr; + + ptr = duk_opt_heapptr(ctx, 2, default_ptr); + +tags: + - stack + - borrowed + +introduced: 2.1.0 diff --git a/website/api/duk_opt_int.yaml b/website/api/duk_opt_int.yaml new file mode 100644 index 0000000000..adb7581048 --- /dev/null +++ b/website/api/duk_opt_int.yaml @@ -0,0 +1,23 @@ +name: duk_opt_int + +proto: | + duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value); + +stack: | + [ ... val! ... ] + +summary: | +

Get the number at idx and convert it to a C duk_int_t + by first clamping the value between [DUK_INT_MIN, DUK_INT_MAX] and then + truncating towards zero. The value on the stack is not modified. + If the value is undefined or the index is invalid, + def_value default value is returned. In other cases + (null or non-matching type) throws an error.

+ +example: | + int port = (int) duk_opt_int(ctx, 1, 80); /* default: 80 */ + +tags: + - stack + +introduced: 2.1.0 diff --git a/website/api/duk_opt_lstring.yaml b/website/api/duk_opt_lstring.yaml new file mode 100644 index 0000000000..bcd8d52fdf --- /dev/null +++ b/website/api/duk_opt_lstring.yaml @@ -0,0 +1,37 @@ +name: duk_opt_lstring + +proto: | + const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len); + +stack: | + [ ... val! ... ] + +summary: | +

Get character data pointer and length for a string at idx + without modifying or coercing the value. Returns a non-NULL + pointer to the read-only, NUL-terminated string data, and writes the + string byte length to *out_len (if out_len is + non-NULL). If the value is undefined or the index + is invalid, def_ptr default value is returned and the + def_len default length is written to *out_len + (if out_len is non-NULL). In other cases + (null or non-matching type) throws an error.

+ +
+ +
+ +example: | + const char *str; + duk_size_t len; + + str = duk_opt_lstring(ctx, -3, &len, "foo" "\x00" "bar", 7); + +seealso: + - duk_opt_string + +tags: + - stack + - string + +introduced: 2.1.0 diff --git a/website/api/duk_opt_number.yaml b/website/api/duk_opt_number.yaml new file mode 100644 index 0000000000..0573797023 --- /dev/null +++ b/website/api/duk_opt_number.yaml @@ -0,0 +1,21 @@ +name: duk_opt_number + +proto: | + duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value); + +stack: | + [ ... val! ... ] + +summary: | +

Get the number value at idx without modifying or coercing + the value. If the value is undefined or the index is invalid, + def_value default value is returned. In other cases + (null or non-matching type) throws an error.

+ +example: | + double backoff_multiplier = (double) duk_opt_number(ctx, 2, 1.5); /* default: 1.5 */ + +tags: + - stack + +introduced: 2.1.0 diff --git a/website/api/duk_opt_pointer.yaml b/website/api/duk_opt_pointer.yaml new file mode 100644 index 0000000000..d394c8c124 --- /dev/null +++ b/website/api/duk_opt_pointer.yaml @@ -0,0 +1,24 @@ +name: duk_opt_pointer + +proto: | + void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value); + +stack: | + [ ... val! ... ] + +summary: | +

Get the pointer value at idx as void * without + modifying or coercing the value. If the value is undefined or + the index is invalid, def_value default value is returned. + In other cases (null or non-matching type) throws an error.

+ +example: | + void *ptr; + + ptr = duk_opt_pointer(ctx, -3, (void *) 0x12345678); + printf("my pointer is: %p\n", ptr); + +tags: + - stack + +introduced: 2.1.0 diff --git a/website/api/duk_opt_string.yaml b/website/api/duk_opt_string.yaml new file mode 100644 index 0000000000..f4d205a7e2 --- /dev/null +++ b/website/api/duk_opt_string.yaml @@ -0,0 +1,37 @@ +name: duk_opt_string + +proto: | + const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr); + +stack: | + [ ... val! ... ] + +summary: | +

Get character data pointer for a string at idx without + modifying or coercing the value. Returns a non-NULL pointer to + the read-only, NUL-terminated string data. If the value is + undefined or the index is invalid, def_ptr + default value is returned. In other cases (null or non-matching + type) throws an error.

+ +

To get the string byte length explicitly (which is useful if the string + contains embedded NUL characters), use + duk_opt_lstring().

+ +
+ +
+ +
+ +example: | + const char *host = duk_opt_string(ctx, 3, "localhost"); + +seealso: + - duk_opt_lstring + +tags: + - stack + - string + +introduced: 2.1.0 diff --git a/website/api/duk_opt_uint.yaml b/website/api/duk_opt_uint.yaml new file mode 100644 index 0000000000..612e9cc10a --- /dev/null +++ b/website/api/duk_opt_uint.yaml @@ -0,0 +1,23 @@ +name: duk_opt_uint + +proto: | + duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value); + +stack: | + [ ... val! ... ] + +summary: | +

Get the number at idx and convert it to a C duk_uint_t + by first clamping the value between [0, DUK_UINT_MAX] and then + truncating towards zero. The value on the stack is not modified. + If the value is undefined or the index is invalid, + def_value default value is returned. In other cases + (null or non-matching type) throws an error.

+ +example: | + unsigned int count = (unsigned int) duk_opt_uint(ctx, 1, 3); /* default: 3 */ + +tags: + - stack + +introduced: 2.1.0 diff --git a/website/api/duk_require_buffer_data.yaml b/website/api/duk_require_buffer_data.yaml index b422133a22..7e9bdcba79 100644 --- a/website/api/duk_require_buffer_data.yaml +++ b/website/api/duk_require_buffer_data.yaml @@ -9,7 +9,8 @@ stack: | summary: |

Like duk_get_buffer_data(), but throws an error if the value at idx is not a plain buffer - or a buffer object or if the index is invalid.

+ or a buffer object, the value is a buffer object whose "backing buffer" doesn't + fully cover the buffer object's apparent size, or the index is invalid.

example: | void *ptr; diff --git a/website/api/duk_require_lstring.yaml b/website/api/duk_require_lstring.yaml index 96d0f1568b..bd015bd09c 100644 --- a/website/api/duk_require_lstring.yaml +++ b/website/api/duk_require_lstring.yaml @@ -11,6 +11,8 @@ summary: | but throws an error if the value at idx is not a string or if the index is invalid.

+
+ example: | const char *buf; duk_size_t len; @@ -18,6 +20,9 @@ example: | buf = duk_require_lstring(ctx, -3, &len); printf("value is a string, %lu bytes\n", (unsigned long) len); +seealso: + - duk_require_string + tags: - stack - string diff --git a/website/api/duk_require_string.yaml b/website/api/duk_require_string.yaml index eabcca44f1..8ea02b3ee5 100644 --- a/website/api/duk_require_string.yaml +++ b/website/api/duk_require_string.yaml @@ -11,6 +11,8 @@ summary: | but throws an error if the value at idx is not a string or if the index is invalid.

+
+
example: | @@ -19,6 +21,9 @@ example: | buf = duk_require_string(ctx, -3); printf("value is a string: %s\n", buf); +seealso: + - duk_require_lstring + tags: - stack - string diff --git a/website/api/string-non-null-zero-length.html b/website/api/string-non-null-zero-length.html new file mode 100644 index 0000000000..7e1be1806d --- /dev/null +++ b/website/api/string-non-null-zero-length.html @@ -0,0 +1,4 @@ +
+A non-NULL return value is guaranteed even for zero length strings; +this differs from how buffer data pointers are handled (for technical reasons). +