addToLibrary({
#if MODULARIZE == 'instance' && !INCLUDE_FULL_LIBRARY
$getCFunc__deps: [() => error('ccall is not yet compatible with MODULARIZE=instance')],
#endif
$getCFunc__internal: true,
$getCFunc: (ident) => {
var func = Module['_' + ident];
#if ASSERTIONS
assert(func, 'Cannot call unknown function ' + ident + ', make sure it is exported');
#endif
return func;
},
$ccall__deps: ['$getCFunc', '$writeArrayToMemory', '$stringToUTF8OnStack', '$stackSave', '$stackRestore', '$stackAlloc'],
$ccall__docs: `
/**
* @param {string|null=} returnType
* @param {Array=} argTypes
* @param {Array=} args
* @param {Object=} opts
*/`,
$ccall: (ident, returnType, argTypes, args, opts) => {
var toC = {
#if MEMORY64
'pointer': (p) => {{{ to64('p') }}},
#endif
'string': (str) => {
var ret = 0;
if (str !== null && str !== undefined && str !== 0) {
ret = stringToUTF8OnStack(str);
}
return {{{ to64('ret') }}};
},
'array': (arr) => {
var ret = stackAlloc(arr.length);
writeArrayToMemory(arr, ret);
return {{{ to64('ret') }}};
}
};
function convertReturnValue(ret) {
if (returnType === 'string') {
return UTF8ToString({{{ from64Expr('ret') }}});
}
#if MEMORY64
if (returnType === 'pointer') return Number(ret);
#endif
if (returnType === 'boolean') return Boolean(ret);
return ret;
}
var func = getCFunc(ident);
var cArgs = [];
var stack = 0;
#if ASSERTIONS
assert(returnType !== 'array', 'Return type should not be "array".');
#endif
if (args) {
for (var i = 0; i < args.length; i++) {
var converter = toC[argTypes[i]];
if (converter) {
if (stack === 0) stack = stackSave();
cArgs[i] = converter(args[i]);
} else {
cArgs[i] = args[i];
}
}
}
#if ASYNCIFY == 1
var previousAsync = Asyncify.currData;
#endif
var ret = func(...cArgs);
function onDone(ret) {
#if ASYNCIFY == 1
runtimeKeepalivePop();
#endif
if (stack !== 0) stackRestore(stack);
return convertReturnValue(ret);
}
#if ASYNCIFY
var asyncMode = opts?.async;
#endif
#if ASYNCIFY == 1
runtimeKeepalivePush();
if (Asyncify.currData != previousAsync) {
#if ASSERTIONS
assert(!(previousAsync && Asyncify.currData), 'We cannot start an async operation when one is already flight');
assert(!(previousAsync && !Asyncify.currData), 'We cannot stop an async operation in flight');
#endif
#if ASSERTIONS
assert(asyncMode, 'The call to ' + ident + ' is running asynchronously. If this was intended, add the async option to the ccall/cwrap call.');
#endif
return Asyncify.whenDone().then(onDone);
}
#endif
#if ASYNCIFY == 2
if (asyncMode) return ret.then(onDone);
#endif
ret = onDone(ret);
#if ASYNCIFY == 1
if (asyncMode) return Promise.resolve(ret);
#endif
return ret;
},
$cwrap__docs: `
/**
* @param {string=} returnType
* @param {Array=} argTypes
* @param {Object=} opts
*/`,
$cwrap__deps: [ '$ccall',
#if !ASSERTIONS
'$getCFunc',
#endif
],
$cwrap: (ident, returnType, argTypes, opts) => {
#if !ASSERTIONS
var numericArgs = !argTypes || argTypes.every((type) => type === 'number' || type === 'boolean');
var numericRet = returnType !== 'string';
if (numericRet && numericArgs && !opts) {
return getCFunc(ident);
}
#endif
return (...args) => ccall(ident, returnType, argTypes, args, opts);
},
});