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 @@
+
To get the string character length (instead of byte length), use
duk_get_length()
.
NULL
return value is guaranteed even for zero length strings;
- this differs from how buffer data pointers are handled (for technical reasons).
- duk_get_lstring()
.
- NULL
return value is guaranteed even for zero length strings;
- this differs from how buffer data pointers are handled (for technical reasons).
- 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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()
.
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.
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.
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 @@
+NULL
return value is guaranteed even for zero length strings;
+this differs from how buffer data pointers are handled (for technical reasons).
+