You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

141 lines
5.7 KiB

name: duk_safe_call
proto: |
duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets);
stack: |
[ ... arg1! ...! argN! ] -> [ ... ret1! ...! retN! ]
summary: |
<p>Perform a protected pure C function call inside the current value stack
frame (the call is not visible on the call stack). <code>nargs</code>
topmost values in the current value stack frame are identified as call
arguments, and <code>nrets</code> return values are provided after the call
returns. Calling code must ensure value stack has reserve for <code>nrets</code>
using e.g. <code><a href="#duk_check_stack">duk_check_stack()</a></code>, and
handling reservation errors.</p>
<p>The <code>udata</code> (userdata) pointer is passed on to
<code>func</code> as is, and makes it easy to pass one or more C values to
the target function without using the value stack. Multiple values can be
passed by packing them into a stack-allocated C struct and passing a pointer
to the struct as userdata. The userdata argument is not interpreted by
Duktape; if it isn't needed simply pass a <code>NULL</code> and ignore the
udata argument in the safe call target.</p>
<p>The return value is:</p>
<ul>
<li><code>DUK_EXEC_SUCCESS</code> (0): call succeeded, <code>nargs</code> arguments are replaced
with <code>nrets</code> return values. (This return code constant is guaranteed to be
zero, so that one can check for success with a "zero or non-zero" check.)</li>
<li><code>DUK_EXEC_ERROR</code>: call failed, <code>nargs</code> arguments are replaced with
<code>nrets</code> values, first of which is an error value and the rest are <code>undefined</code>.
(In exceptional cases, e.g. when there are too few arguments on the value stack, the call
may throw.)</li>
</ul>
<div class="note">
Unlike most Duktape API calls, this call returns zero on success. This allows
multiple error codes to be defined later.
</div>
<p>Because this call operates on the current value stack frame, stack behavior
and return code handling differ a bit from other call types.</p>
<p>The top <code>nargs</code> elements of the stack top are identified as arguments to
<code>func</code> establishing a "base index" for the return stack as:</p>
<pre>
(duk_get_top() - nargs)
</pre>
<p>When <code>func</code> returns, it indicates with its return value the number of
return values it has pushed on top of the stack; multiple or zero return
values possible. The stack is then manipulated so that there are exactly
<code>nrets</code> values starting at the "base index" established before the call.</p>
<p>Note that since <code>func</code> has full access to the value stack, it may modify
the stack below the indended arguments and even pop elements below the "base index"
off the stack. Such elements are restored with <code>undefined</code> values before
returning, to ensure that the stack is always in a consistent state upon returning.</p>
<p>If an error occurs, the stack will still have <code>nrets</code> values at "base index";
the first of such values is the error, and the remaining values are <code>undefined</code>.
If <code>nrets</code> is zero, the error will not be present on the stack (the return stack
top will equal the "base index"), so calling this function with <code>nrets</code> as 0
is not very useful.</p>
<p>Example value stack behavior with <code>nargs = 3</code>, <code>nrets = 2</code>,
<code>func</code> returns 4. Pipe chars indicate logical value stack boundaries:</p>
<pre>
.--- frame bottom
|
| .--- "base index"
v v
[ ... | ... | a b c ] stack before calling 'func'
[ ... | ... | a b | x y z w ] stack after calling 'func', which has
popped one argument and written four
return values (and returned 4)
[ ... | ... | x y ] stack after duk_safe_call() returns,
2 (= nrets) first 'func' return values
are left at "base index"
</pre>
<div class="note">
Note that <code>func</code> uses the caller's stack frame, so bottom-based
references are dangerous within 'func' unless the calling context is known.
</div>
<div class="note">
The userdata argument was added in Duktape 2.x.
</div>
example: |
typedef struct {
int floor;
} my_safe_args;
duk_ret_t my_safe_func(duk_context *ctx, void *udata) {
my_safe_args *args = (my_safe_args *) udata;
double a, b, c, t;
a = duk_get_number(ctx, -3);
b = duk_get_number(ctx, -2);
c = duk_get_number(ctx, -1); /* ignored on purpose */
t = a + b;
if (args->floor) {
t = floor(t);
}
duk_push_number(ctx, t);
/* Indicates that there is only one return value. Because the caller
* requested two (nrets == 2), Duktape will automatically add an
* additional "undefined" result value.
*/
return 1;
}
my_safe_args args; /* C struct whose pointer is passed as userdata */
duk_int_t rc;
args.floor = 1;
duk_push_int(ctx, 10);
duk_push_int(ctx, 11);
duk_push_int(ctx, 12);
rc = duk_safe_call(ctx, my_func, (void *) &args, 3 /*nargs*/, 2 /*nrets*/);
if (rc == DUK_EXEC_SUCCESS) {
printf("1st return value: %s\n", duk_to_string(ctx, -2)); /* 21 */
printf("2nd return value: %s\n", duk_to_string(ctx, -1)); /* undefined */
} else {
printf("error value: %s\n", duk_to_string(ctx, -2));
}
duk_pop_2(ctx);
tags:
- call
- protected
# Introduced in 1.0.0 but incompatible change in 2.0.0.
introduced: 1.0.0