Use another language to call a function: Difference between revisions

m
(→‎{{header|TXR}}: Remove first solution, improve carray solution, put callback discussion at end.)
m (→‎{{header|Wren}}: Minor tidy)
 
(23 intermediate revisions by 15 users not shown)
Line 2:
{{clarified-review}}
This task is inverse to the task [[Call foreign language function]]. Consider the following [[C]] program:
<langsyntaxhighlight lang="c">#include <stdio.h>
 
extern int Query (char * Data, size_t * Length);
Line 21:
putchar ('\n');
}
}</langsyntaxhighlight>
 
Implement the missing <code>Query</code> function in your language, and let this C program call it. The function should place the string ''<tt style="margin:0 0.5em">Here am I</tt>'' into the buffer which is passed to it as the parameter <code>Data</code>. The buffer size in bytes is passed as the parameter <code>Length</code>. When there is no room in the buffer, <code>Query</code> shall return 0. Otherwise it overwrites the beginning of <code>Buffer</code>, sets the number of overwritten bytes into <code>Length</code> and returns 1.
Line 27:
=={{header|Ada}}==
The interface package Exported specification:
<langsyntaxhighlight Adalang="ada">with Interfaces.C; use Interfaces.C;
with Interfaces.C.Strings; use Interfaces.C.Strings;
 
Line 34:
return int;
pragma Export (C, Query, "Query");
end Exported;</langsyntaxhighlight>
The package implementation:
<langsyntaxhighlight Adalang="ada">package body Exported is
function Query (Data : chars_ptr; Size : access size_t)
return int is
Line 49:
end if;
end Query;
end Exported;</langsyntaxhighlight>
With [[GNAT]] it can be built as follows:
<langsyntaxhighlight lang="ada">gcc -c main.c
gnatmake -c exported.adb
gnatbind -n exported.ali
gnatlink exported.ali main.o -o main</langsyntaxhighlight>
Sample output:
<pre>
Line 63:
It is possible to register an autohotkey function as a callback and get a pointer to it using the builtin registercallback function. Care should be taken that the external language code is running in the same thread as autohotkey. This is not a problem when using dllcall to use the external language. To run an autohotkey function from an external program running in a different thread, you can use [http://www.autohotkey.net/~HotKeyIt/AutoHotkey/ahkFunction.htm ahkFunction] in [http://www.autohotkey.net/~tinku99/ahkdll/ AutoHotkey.dll]
From the documentation on registercallback:
<langsyntaxhighlight AutoHotkeylang="autohotkey">; Example: The following is a working script that displays a summary of all top-level windows.
 
; For performance and memory conservation, call RegisterCallback() only once for a given callback:
Line 83:
Output .= "HWND: " . hwnd . "`tTitle: " . title . "`tClass: " . class . "`n"
return true ; Tell EnumWindows() to continue until all windows have been enumerated.
}</langsyntaxhighlight>
 
=={{header|C}}==
I rewrote the driver as
<langsyntaxhighlight lang="c">#if 0
I rewrote the driver according to good sense, my style,
and discussion.
Line 119:
return EXIT_SUCCESS;
}
</syntaxhighlight>
</lang>
With solution
<syntaxhighlight lang="c">
<lang c>
#if 0
This is file query.c
Line 143:
return 0;
}
</syntaxhighlight>
</lang>
And finally, excitement!
<langsyntaxhighlight lang="bash">$ gcc main.c query.o -o main && ./main
Here am I
$
</syntaxhighlight>
</lang>
 
=={{header|C++}}==
<syntaxhighlight lang="cpp">#include <string>
using std::string;
 
// C++ functions with extern "C" can get called from C.
extern "C" int
Query (char *Data, size_t *Length)
{
const string Message = "Here am I";
 
// Check that Message fits in Data.
if (*Length < Message.length())
return false; // C++ converts bool to int.
 
*Length = Message.length();
Message.copy(Data, *Length);
return true;
}</syntaxhighlight>
 
We must compile main() with a C compiler and Query() with a C++ compiler. One can use gcc and g++ (or clang and clang++).
 
<syntaxhighlight lang="bash">$ gcc -c main.c
$ g++ -c query.cpp
$ g++ -o main main.o query.o
$ ./main
Here am I</syntaxhighlight>
 
=={{header|COBOL}}==
{{works with|GnuCOBOL|2.0+}}
 
GnuCOBOL uses C intermediates and blends well with C programming. GnuCOBOL is also a fixed length data item language, so this Query routine has to set some limits on passed in external value lengths. 8K in this example, defined using OCCURS DEPENDING ON the input Length.
 
Instead of C being the master builder, cobc is used to combine the .c source and .cob source into the executable simplifying the tectonic for this example (cobc can generate and use .o object code, but that is all hidden here). GnuCOBOL also requires a COBOL runtime system, implicitly initialized with the -fimplicit-init compiler switch here. This emits code to ensure libcob is properly setup for calling from foreign languages (that would otherwise have to call cob_init() before invoking COBOL modules). The source code in the task description was saved to disk as <code>call-query.c</code>, and the listing below was saved as <code>query.cob</code> (with the internal subprogram named <code>Query</code>). A special <code>call-convention</code> is also used so the GnuCOBOL module does not make any assumptions about how the Query module is invoked (normal COBOL programs set some control fields in the libcob runtime space when calling modules, which won't be set when called from a foreign C ABI program). GnuCOBOL also sets <code>RETURN-CODE</code> to zero unless told otherwise (or some error occurs).
 
<syntaxhighlight lang="cobol"> identification division.
program-id. Query.
 
environment division.
configuration section.
special-names.
call-convention 0 is extern.
 
repository.
function all intrinsic.
 
data division.
working-storage section.
01 query-result.
05 filler value "Here I am".
 
linkage section.
01 data-reference.
05 data-buffer pic x occurs 0 to 8192 times
depending on length-reference.
01 length-reference usage binary-long.
 
procedure division extern using data-reference length-reference.
 
if length(query-result) less than or equal to length-reference
and length-reference less than 8193 then
move query-result to data-reference
move length(query-result) to length-reference
move 1 to return-code
end-if
 
goback.
end program Query.</syntaxhighlight>
 
{{out}}
<pre>
prompt$ cobc -x -fimplicit-init call-query.c query.cob
prompt$ ./call-query
Here I am</pre>
 
=={{header|D}}==
Line 155 ⟶ 229:
First write a D module like this, named "query_func.d":
 
<langsyntaxhighlight lang="d">import core.stdc.string;
 
extern(C) bool query(char *data, size_t *length) pure nothrow {
Line 168 ⟶ 242:
return true;
}
}</langsyntaxhighlight>
 
Generate a library file with:
Line 178 ⟶ 252:
Then create a C file named "mainc.c", given in the task description and here improved a little:
 
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdbool.h>
 
Line 193 ⟶ 267:
 
return 0;
}</langsyntaxhighlight>
 
Then you can compile and link all with the [http://www.digitalmars.com/download/freecompiler.html DMC C compiler](on Linux you can use GCC):
Line 204 ⟶ 278:
 
=={{header|Delphi}}==
<langsyntaxhighlight lang="delphi">
function Query(Buffer: PChar; var Size: Int64): LongBool;
const
Line 226 ⟶ 300:
Result := True;
end;
</syntaxhighlight>
</lang>
 
To use this function from C you have to export this as a DLL and bind your C program to this function.
 
== {{header|Fortran}} ==
Simple task because interoperability with C is in Fortran language since F2003 standard.
<syntaxhighlight lang="fortran">
<lang Fortran>
!-----------------------------------------------------------------------
!Function
Line 248 ⟶ 322:
answer = 1
end function fortran_query
</syntaxhighlight>
</lang>
compile it: gfortran main.c query.f90 -o main.x
 
Line 257 ⟶ 331:
 
Thus, I changed the specified C code to begin as follows,
<langsyntaxhighlight lang="c">#include <stdio.h>
#include "_cgo_export.h"
 
Line 266 ⟶ 340:
 
if (0 == Query (Buffer, &Size))
...</langsyntaxhighlight>
The biggest change is that I renamed main, since it is no longer a C main function. Another small change is that the extern declaration is replaced by an include. The included file is generated by cgo and contains an equivalent extern declaration.
 
In the Go code, below, you see that all main does is call C.Run. The C code is then in the driver's seat.
<langsyntaxhighlight lang="go">package main
 
// #include <stdlib.h>
Line 296 ⟶ 370:
*csiz = C.size_t(len(msg) + 1)
return 1
}</langsyntaxhighlight>
Output:
<pre>
Line 306 ⟶ 380:
 
The Go code for this task is as follows:
<syntaxhighlight lang="go">
<lang go>
// This buildmode requires the package to be main
package main
Line 352 ⟶ 426:
return 1
}
</syntaxhighlight>
</lang>
 
Assuming this is saved to query.go (and that the C code is saved as main.c) it can be compiled with:
Line 370 ⟶ 444:
=={{header|Haskell}}==
I modified the C source to include Haskell-specific headers and to init the Haskell environment. I also changed "Query" to "query_hs" due to capitalization issues:
<langsyntaxhighlight lang="c">#ifdef __GLASGOW_HASKELL__
#include "Called_stub.h"
extern void __stginit_Called(void);
Line 400 ⟶ 474:
hs_exit();
return 0;
}</langsyntaxhighlight>
 
The Haskell code then is:
 
<langsyntaxhighlight lang="haskell">{-# LANGUAGE ForeignFunctionInterface #-}
 
module Called where
Line 429 ⟶ 503:
return 1)
 
foreign export ccall query_hs :: CString -> Ptr CSize -> IO CInt</langsyntaxhighlight>
 
Compile the Haskell code with:
<langsyntaxhighlight lang="bash">ghc -c -O Called.hs</langsyntaxhighlight>
 
Then compile the C code together with the generated Haskell files (using GHC):
<langsyntaxhighlight lang="bash">ghc -optc-O calling.c Called.o Called_stub.o -o calling</langsyntaxhighlight>
 
Output:
Line 444 ⟶ 518:
=={{header|Haxe}}==
=== PHP ===
<langsyntaxhighlight lang="haxe">untyped __call__("functionName", args);</langsyntaxhighlight>
 
=={{header|J}}==
Line 452 ⟶ 526:
The J verb evaluates to the string unless there is no space.
File <tt>rc_embed.ijs</tt>
<syntaxhighlight lang="j">
<lang J>
query=:3 :'0&#^:(y < #)''Here am I'''
</syntaxhighlight>
</lang>
 
main.c
<syntaxhighlight lang="c">
<lang c>
#include<stdio.h>
#include<stdlib.h>
Line 475 ⟶ 549:
return EXIT_SUCCESS;
}
</syntaxhighlight>
</lang>
 
Query.c
<syntaxhighlight lang="c">
<lang c>
 
// J Front End Example
Line 597 ⟶ 671:
return 1;
}
</syntaxhighlight>
</lang>
 
makefile, adjust for your j installation.
<langsyntaxhighlight lang="make">
# jfe makefile info
# customize to create makefile suitable for your platform
Line 611 ⟶ 685:
 
main: main.o Query.o
</syntaxhighlight>
</lang>
 
Finally, build and execution. Again, adjust LD_LIBRARY_PATH to the directory of libj.so .
<langsyntaxhighlight lang="bash">
$ make main && LD_LIBRARY_PATH=~/Downloads/jgplsrc/j/bin ./main
Here am I
$
</syntaxhighlight>
</lang>
 
=={{header|Java}}==
We write a Java method, then write a C function <code>Query()</code> to use the Java Native Interface (JNI) to call our Java method. The C compiler must find ''jni.h'' and ''jni_md.h'' and link with ''libjvm''.
 
<syntaxhighlight lang="java">/* Query.java */
public class Query {
public static boolean call(byte[] data, int[] length)
throws java.io.UnsupportedEncodingException
{
String message = "Here am I";
byte[] mb = message.getBytes("utf-8");
if (length[0] < mb.length)
return false;
length[0] = mb.length;
System.arraycopy(mb, 0, data, 0, mb.length);
return true;
}
}</syntaxhighlight>
 
<syntaxhighlight lang="c">/* query-jni.c */
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
 
static JavaVM *jvm = NULL;
static JNIEnv *jenv = NULL;
 
static void die(const char *message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
 
static void oom(void) {
die("Query: out of memory");
}
 
static void except(void) {
if ((*jenv)->ExceptionCheck(jenv))
die("Query: unexpected Java exception");
}
 
static void do_at_exit(void) {
(*jvm)->DestroyJavaVM(jvm);
}
 
static void require_jvm(void) {
JavaVMInitArgs args;
 
if (jvm)
return;
 
args.version = JNI_VERSION_1_4;
args.nOptions = 0;
args.options = NULL;
args.ignoreUnrecognized = JNI_FALSE;
if (JNI_CreateJavaVM(&jvm, (void **)&jenv, &args) != JNI_OK)
die("Query: can't create Java VM");
atexit(do_at_exit);
}
 
int Query(char *data, size_t *length) {
jclass cQuery;
jmethodID mcall;
jintArray jlength;
jint jlength0;
jbyteArray jdata;
jboolean result;
 
jlength0 = (jint)length[0];
if ((size_t)jlength0 != length[0])
die("Query: length is too large for Java array");
 
require_jvm();
 
/* Create a local frame for references to Java objects. */
if ((*jenv)->PushLocalFrame(jenv, 16))
oom();
 
/* Look for class Query, static boolean call(byte[], int[]) */
cQuery = (*jenv)->FindClass(jenv, "Query");
if (cQuery == NULL)
die("Query: can't find Query.class");
mcall = (*jenv)->GetStaticMethodID(jenv, cQuery, "call", "([B[I)Z");
if (mcall == NULL)
die("Query: missing call() method");
 
/*
* Make arguments to Query.call(). We can't pass data[] and
* length[] to Java, so we make new Java arrays jdata[] and
* jlength[].
*/
jdata = (*jenv)->NewByteArray(jenv, (jsize)jlength0);
if (jdata == NULL)
oom();
jlength = (*jenv)->NewIntArray(jenv, 1);
if (jlength == NULL)
oom();
 
/* Set jlength[0] = length[0]. */
(*jenv)->SetIntArrayRegion(jenv, jlength, 0, 1, &jlength0);
except();
 
/*
* Call our Java method.
*/
result = (*jenv)->CallStaticBooleanMethod
(jenv, cQuery, mcall, jdata, jlength);
except();
 
/*
* Set length[0] = jlength[0].
* Copy length[0] bytes from jdata[] to data[].
*/
(*jenv)->GetIntArrayRegion(jenv, jlength, 0, 1, &jlength0);
except();
length[0] = (size_t)jlength0;
(*jenv)->GetByteArrayRegion
(jenv, jdata, 0, (jsize)jlength0, (jbyte *)data);
 
/* Drop our local frame and its references. */
(*jenv)->PopLocalFrame(jenv, NULL);
 
return (int)result;
}</syntaxhighlight>
 
<syntaxhighlight lang="make"># Makefile
 
# Edit these lines to match your JDK.
JAVA_HOME = /Library/Java/Home
CPPFLAGS = -I$(JAVA_HOME)/include
LIBS = -framework JavaVM
JAVAC = $(JAVA_HOME)/bin/javac
CC = cc
 
all: calljava Query.class
 
calljava: main.o query-jni.o
$(CC) -o calljava main.o query-jni.o $(LIBS)
 
.SUFFIXES: .c .class .java .o
.c.o:
$(CC) $(CPPFLAGS) -c $<
.java.class:
$(JAVAC) $<
 
clean:
rm -f calljava main.o query-jni.o Query.class</syntaxhighlight>
 
=={{header|Kotlin}}==
Reverse interop (calling Kotlin from C) was added to Kotlin Native in version 0.5 and the following shows how to perform this task on Ubuntu Linux.
 
First we compile the following Kotlin source file (Query.kt) using the '-platform dynamic' flag:
<syntaxhighlight lang="scala">// Kotlin Native v0.6
 
import kotlinx.cinterop.*
import platform.posix.*
 
fun query(data: CPointer<ByteVar>, length: CPointer<size_tVar>): Int {
val s = "Here am I"
val strLen = s.length
val bufferSize = length.pointed.value
if (strLen > bufferSize) return 0 // buffer not large enough
for (i in 0 until strLen) data[i] = s[i].toByte()
length.pointed.value = strLen.signExtend<size_t>()
return 1
}</syntaxhighlight>
 
This produces the dynamic library, libQuery.so, and the C header file libQuery_api.h:
<syntaxhighlight lang="c">#ifndef KONAN_LIBQUERY_H
#define KONAN_LIBQUERY_H
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned char libQuery_KBoolean;
typedef char libQuery_KByte;
typedef unsigned short libQuery_KChar;
typedef short libQuery_KShort;
typedef int libQuery_KInt;
typedef long long libQuery_KLong;
typedef float libQuery_KFloat;
typedef double libQuery_KDouble;
typedef void* libQuery_KNativePtr;
struct libQuery_KType;
typedef struct libQuery_KType libQuery_KType;
 
typedef struct {
/* Service functions. */
void (*DisposeStablePointer)(libQuery_KNativePtr ptr);
void (*DisposeString)(const char* string);
libQuery_KBoolean (*IsInstance)(libQuery_KNativePtr ref, const libQuery_KType* type);
 
/* User functions. */
struct {
struct {
libQuery_KInt (*query)(void* data, void* length);
} root;
} kotlin;
} libQuery_ExportedSymbols;
extern libQuery_ExportedSymbols* libQuery_symbols(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* KONAN_LIBQUERY_H */</syntaxhighlight>
 
We now compile a slightly modified version of the C program required for this task, linking to the above library, and 'including' the header file:
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include "libQuery_api.h"
 
static int Query (char * Data, size_t * Length)
{
return libQuery_symbols() -> kotlin.root.query(Data, Length);
}
 
int main (int argc, char * argv [])
{
char Buffer [1024];
size_t Size = sizeof (Buffer);
if (0 == Query (Buffer, &Size))
{
printf ("failed to call Query\n");
}
else
{
char * Ptr = Buffer;
while (Size-- > 0) putchar (*Ptr++);
putchar ('\n');
}
}</syntaxhighlight>
 
which when executed produces the expected output:
<pre>
Here am I
</pre>
 
=={{header|Lisaac}}==
query.li
<langsyntaxhighlight Lisaaclang="lisaac">Section Header
 
+ name := QUERY;
Line 653 ⟶ 962:
+ size : NATIVE_ARRAY[INTEGER];
query(buffer, size); // need this to pull the query() method
);</langsyntaxhighlight>
Makefile
<langsyntaxhighlight lang="lisaac">TARGET=test_query
 
all: $(TARGET)
Line 669 ⟶ 978:
 
clean:
rm -f $(TARGET) *.o query.c</langsyntaxhighlight>
 
=={{header|Mercury}}==
 
The code as written is horrible for Mercury, so some additional C is added as a shim that actually calls the Mercury predicate. Although no changes are required to the C code in this simple example, in a larger project, with modules that need initialization, there are [https://mercurylang.org/information/doc-latest/mercury_user_guide/Using-mmc.html some additional compilation steps] needed to get that initialization code in.
 
<syntaxhighlight lang="mercury">:- module query.
:- interface.
 
:- pred query(string::in, string::out) is det.
 
:- implementation.
 
query(_, "Hello, world!").
 
:- pragma foreign_export("C", query(in, out), "query").
 
:- pragma foreign_decl("C",
"
#include <string.h>
int Query (char * Data, size_t * Length);
").
:- pragma foreign_code("C",
"
int Query (char *Data, size_t *Length) {
MR_String input, result;
MR_allocate_aligned_string_msg(input, *Length, MR_ALLOC_ID);
memmove(input, Data, *Length);
query(input, &result);
*Length = strlen(result);
memmove(Data, result, *Length);
return 1;
}
").</syntaxhighlight>
 
Building with the unchanged C in useanother.c:
 
<pre>$ mmc -c query
$ gcc -Wall -c useanother.c
$ ml -o useanother useanother.o query.o</pre>
 
{{out}}
<pre>Hello, world!</pre>
 
=={{header|Nim}}==
<langsyntaxhighlight lang="nim">proc Query*(data: var array[1024, char], length: var cint): cint {.exportc.} =
const text = "Here am I"
if length < text.len:
return 0
 
for i in 0 .. <text.lenhigh:
data[i] = text[i]
length = text.len
return 1</langsyntaxhighlight>
Compile the above with <code>nim c --app:staticlib --no_main query.nim</code>.
<langsyntaxhighlight lang="c">#include <stdio.h>
 
extern int Query (char * Data, size_t * Length);
Line 701 ⟶ 1,052:
putchar ('\n');
}
}</langsyntaxhighlight>
Compile the above with <code>gcc -ldl -o main main.c libquery.nim.a</code>, then execute the resulting <code>main</code> binary:
<pre>./main
Here am I
Line 708 ⟶ 1,059:
 
=={{header|OCaml}}==
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <string.h>
#include <caml/mlvalues.h>
Line 743 ⟶ 1,094:
putchar ('\n');
}
}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="ocaml">let caml_query () =
let s = "Here am I" in
(s, String.length s)
Line 752 ⟶ 1,103:
let () =
Callback.register "Query function cb" caml_query;
;;</langsyntaxhighlight>
 
compile with:
Line 761 ⟶ 1,112:
-L"`ocamlc -where`" \
-lm -ldl -lasmrun
 
=={{header|Ol}}==
Simpler solution: just return from otus-lisp a string.
<syntaxhighlight lang="c">
#include <extensions/embed.h>
 
#define min(x,y) (x < y ? x : y)
 
extern unsigned char repl[];
int Query(char *Data, size_t *Length) {
ol_t ol;
embed_new(&ol, repl, 0);
 
word s = embed_eval(&ol, new_string(&ol,
"(define sample \"Here am I\")"
"sample"
), 0);
if (!is_string(s))
goto fail;
 
int i = *Length = min(string_length(s), *Length);
 
memcpy(Data, string_value(s), i);
*Length = i;
 
OL_free(ol.vm);
return 1;
fail:
OL_free(ol.vm);
return 0;
}
</syntaxhighlight>
 
Better solution: do a copy of string directly in otus-lisp.
<syntaxhighlight lang="c">
#include <extensions/embed.h>
 
extern unsigned char repl[];
int Query(char *Data, size_t *Length) {
ol_t ol;
embed_new(&ol, repl, 0);
 
embed_eval(&ol, new_string(&ol,
"(import (otus ffi))"
"(define lib (load-dynamic-library #f))"
"(define memcpy (lib fft-void* \"memcpy\" fft-void* type-string fft-int))"
"(define (Query Data Length)"
" (define sample (c-string \"Here am I\"))"
" (when (memcpy Data sample (min (string-length sample) Length))"
" (min (string-length sample) Length)))"
), 0);
word r =
embed_eval(&ol, new_string(&ol, "Query"), new_vptr(&ol, Data), make_integer(*Length), 0);
if (!is_number(r))
goto fail;
*Length = ol2int(r);
OL_free(ol.vm);
return 1;
 
fail:
OL_free(ol.vm);
return 0;
}
</syntaxhighlight>
 
=={{header|PARI/GP}}==
Line 766 ⟶ 1,182:
This is a Linux solution. Message "Here I am" is encrypted with ROT13: "Urer V nz".
 
ROT13() is implemented as a PARI one-liner:<langsyntaxhighlight lang="parigp">Strchr(Vecsmall(apply(k->if(k>96&&k<123,(k-84)%26+97,if(k>64&&k<91,(k-52)%26+65,k)),Vec(Vecsmall(s)))))</langsyntaxhighlight>
PARI's interface for Query()... query.c:
<langsyntaxhighlight Clang="c">#include <pari/pari.h>
 
#define PARI_SECRET "s=\"Urer V nz\";Strchr(Vecsmall(apply(k->if(k>96&&k<123,(k-84)%26+97,if(k>64&&k<91,(k-52)%26+65,k)),Vec(Vecsmall(s)))))"
Line 790 ⟶ 1,206:
 
return rc;
}</langsyntaxhighlight>
 
Compile interface to a library: ''gcc -O2 -Wall -fPIC -shared query.c -o libquery.so -lpari''
Line 812 ⟶ 1,228:
The following code declares a callback for the C code (which I'd expect to be in a .dll or .so) to invoke.<br>
A 32-bit-only or a 64-bit-only version would of course be slightly shorter.
<!--<syntaxhighlight lang="phix">(notonline)-->
<lang Phix>constant Here_am_I = "Here am I"
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (peek/poke, call_back)</span>
function Query(atom pData, atom pLength)
<span style="color: #008080;">constant</span> <span style="color: #000000;">Here_am_I</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Here am I"</span>
integer len = peekNS(pLength,machine_word(),0)
<span style="color: #008080;">function</span> <span style="color: #000000;">Query</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">pData</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pLength</span><span style="color: #0000FF;">)</span>
if poke_string(pData,len,Here_am_I) then
<span style="color: #004080;">integer</span> <span style="color: #000000;">len</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">peekNS</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pLength</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">machine_word</span><span style="color: #0000FF;">(),</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
return 0
<span style="color: #008080;">if</span> <span style="color: #7060A8;">poke_string</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pData</span><span style="color: #0000FF;">,</span><span style="color: #000000;">len</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Here_am_I</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
end if
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span>
pokeN(pLength,length(Here_am_I)+1,machine_word())
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
return 1
<span style="color: #7060A8;">pokeN</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pLength</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">Here_am_I</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">machine_word</span><span style="color: #0000FF;">())</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">1</span>
constant Query_cb = call_back(routine_id("Query"))</lang>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">Query_cb</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">call_back</span><span style="color: #0000FF;">(</span><span style="color: #000000;">Query</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
 
=={{header|PicoLisp}}==
Line 830 ⟶ 1,249:
 
If there is a file "query.l"
<langsyntaxhighlight PicoLisplang="picolisp">(let (Str "Here am I" Len (format (opt))) # Get length from command line
(unless (>= (size Str) Len) # Check buffer size
(prinl Str) ) ) # Return string if OK</langsyntaxhighlight>
then the C function 'Query' could be
<langsyntaxhighlight Clang="c">int Query(char *Data, size_t *Length) {
FILE *fp;
char buf[64];
Line 844 ⟶ 1,263:
*Length = strlen(Data);
return pclose(fp) >= 0 && *Length != 0;
}</langsyntaxhighlight>
 
=={{header|Python}}==
 
Our embedded python function a) uses information from the main routine in c, and b) determines the information to populate the result returned to the main routine. This, I believe, fulfills the task requirement. The modifications and compilation are shown for Ubuntu linux Autumn 2011 version, with python3. It's easier to call a dynamic library from python using the ctypes module. Consider using <tt>PyRun_SimpleString</tt> to have main.c call python calling back to c.
<langsyntaxhighlight lang="python">
# store this in file rc_embed.py
# store this in file rc_embed.py
Line 856 ⟶ 1,275:
L = len(message)
return message[0:L*(L <= buffer_length)]
</syntaxhighlight>
</lang>
 
main.c
<syntaxhighlight lang="c">
<lang c>
#if 0
//I rewrote the driver according to good sense, my style,
Line 882 ⟶ 1,301:
return EXIT_SUCCESS;
}
</syntaxhighlight>
</lang>
 
In Query.c I don't promise to have tested every case with missing module, missing function, or to have used <tt>Py_DECREF</tt> correctly.
<syntaxhighlight lang="c">
<lang c>
#include<stdio.h>
#include<stdlib.h>
Line 946 ⟶ 1,365:
return result;
}
</syntaxhighlight>
</lang>
 
Compilation, linkage, execution. Note the python tools used to extract the correct flags.
<langsyntaxhighlight lang="bash">
$ make main.o
cc -c -o main.o main.c
Line 962 ⟶ 1,381:
Here am I
$
</syntaxhighlight>
</lang>
 
=={{header|Racket}}==
Line 970 ⟶ 1,389:
Starting with the given C code, modify it so that <tt>Query</tt> is a variable instead of an external:
 
<syntaxhighlight lang="c">
<lang C>
typedef int strfun (char * Data, size_t * Length);
strfun *Query = NULL;
</syntaxhighlight>
</lang>
 
The rest of the C code is left as-is. Compile it into a dynamic library, then run the following Racket code:
 
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 995 ⟶ 1,414:
((get-ffi-obj "main" xlib (_fun _int (_list i _bytes) -> _void))
0 '())
</syntaxhighlight>
</lang>
 
Note that this code is intentionally in a simple low-level form, for example, it sets the pointer directly instead of using a C function.
 
The output is the expected “<tt>Here I am</tt>” line.
 
=={{header|Raku}}==
(formerly Perl 6)
This [https://stackoverflow.com/a/50771971/3386748 SO answer], by JJ Merelo, explained the difficulty on providing a simple solution.  So this attempt takes the same approach as PicoLisp by summoning the interpreter at run time.
{{trans|PicoLisp}}
query.raku
<syntaxhighlight lang="raku" line>#!/usr/bin/env raku
 
sub MAIN (Int :l(:len(:$length))) {
my Str $String = "Here am I";
$*OUT.print: $String if $String.codes ≤ $length
}</syntaxhighlight>
query.c
<syntaxhighlight lang="c">#include<stdio.h>
#include<stddef.h>
#include<string.h>
 
int Query(char *Data, size_t *Length) {
FILE *fp;
char buf[64];
 
sprintf(buf, "/home/user/query.raku --len=%zu", *Length);
if (!(fp = popen(buf, "r")))
return 0;
fgets(Data, *Length, fp);
*Length = strlen(Data);
return pclose(fp) >= 0 && *Length != 0;
}</syntaxhighlight>
{{out}}
<pre>
gcc -Wall -o main main.c query.c
./main
Here am I
</pre>
 
=={{header|Ruby}}==
We have four files. First, ''main.c'' has the <code>main()</code> from the top of this page. Second, ''query.rb'' uses Fiddle to create a C function at run time. It sets the C variable <code>QueryPointer</code> to this function. It needs at least Ruby 2.3 for <code>Array#unpack('J')</code>. Our <code>main()</code> can't call <code>QueryPointer()</code>, because it expects <code>Query()</code> to exist at link time, and it would crash if Ruby raised an error. The third file ''query-rb.c'' provides <code>Query()</code> as a wrapper around <code>QueryPointer()</code>. The wrapper embeds the Ruby interpreter and protects against Ruby errors. The fourth file ''Rakefile'' builds the program.
 
{{works with|MRI|2.3+}}
 
<syntaxhighlight lang="ruby"># query.rb
require 'fiddle'
 
# Look for a C variable named QueryPointer.
# Raise an error if it is missing.
c_var = Fiddle.dlopen(nil)['QueryPointer']
 
int = Fiddle::TYPE_INT
voidp = Fiddle::TYPE_VOIDP
sz_voidp = Fiddle::SIZEOF_VOIDP
 
# Implement the C function
# int Query(void *data, size_t *length)
# in Ruby code. Store it in a global constant in Ruby (named Query)
# to protect it from Ruby's garbage collector.
#
Query = Fiddle::Closure::BlockCaller
.new(int, [voidp, voidp]) do |datap, lengthp|
message = "Here am I"
 
# We got datap and lengthp as Fiddle::Pointer objects.
# Read length, assuming sizeof(size_t) == sizeof(void *).
length = lengthp[0, sz_voidp].unpack('J').first
 
# Does the message fit in length bytes?
if length < message.bytesize
0 # failure
else
length = message.bytesize
datap[0, length] = message # Copy the message.
lengthp[0, sz_voidp] = [length].pack('J') # Update the length.
1 # success
end
end
 
# Set the C variable to our Query.
Fiddle::Pointer.new(c_var)[0, sz_voidp] = [Query.to_i].pack('J')</syntaxhighlight>
 
<syntaxhighlight lang="c">/* query-rb.c */
#include <stdlib.h>
#include <ruby.h>
 
/*
* QueryPointer() uses Ruby and may raise a Ruby error. Query() is a
* C wrapper around QueryPointer() that loads Ruby, sets QueryPointer,
* and protects against Ruby errors.
*/
int (*QueryPointer)(char *, size_t *) = NULL;
 
static int in_bad_exit = 0;
 
static void
do_at_exit(void)
{
RUBY_INIT_STACK;
 
if (!in_bad_exit)
ruby_cleanup(0);
}
 
static void
bad_exit(int state)
{
in_bad_exit = 1;
ruby_stop(state); /* Clean up Ruby and exit the process. */
}
 
static void
require_query(void)
{
static int done = 0;
int state;
 
if (done)
return;
done = 1;
 
ruby_init();
atexit(do_at_exit);
ruby_init_loadpath(); /* needed to require 'fiddle' */
 
/* Require query.rb in current directory. */
rb_eval_string_protect("require_relative 'query'", &state);
if (!state && !QueryPointer)
rb_eval_string_protect("fail 'missing QueryPointer'", &state);
if (state)
bad_exit(state); /* Ruby will report the error. */
}
 
struct args {
char *data;
size_t *length;
int result;
};
 
static VALUE
Query1(VALUE v) {
struct args *a = (struct args *)v;
a->result = QueryPointer(a->data, a->length);
return Qnil;
}
 
int
Query(char *data, size_t *length)
{
struct args a;
int state;
RUBY_INIT_STACK;
 
require_query();
 
/* Call QueryPointer(), protect against errors. */
a.data = data;
a.length = length;
rb_protect(Query1, (VALUE)&a, &state);
if (state)
bad_exit(state);
return a.result;
}</syntaxhighlight>
 
<syntaxhighlight lang="ruby"># Rakefile
 
# To build and run:
# $ rake
# $ ./callruby
 
# Must link with cc -Wl,-E so query.c exports QueryPointer.
CC = ENV.fetch('CC', 'cc')
LDFLAGS = '-Wl,-E'
CPPFLAGS = RbConfig.expand('-I$(rubyarchhdrdir) -I$(rubyhdrdir)')
LIBS = RbConfig.expand('$(LIBRUBYARG) $(LIBS)')
 
task 'default' => 'callruby'
 
desc 'compiles callruby'
file 'callruby' => %w[main.o query-rb.o] do |t|
sh "#{CC} #{LDFLAGS} -o #{t.name} #{t.sources.join(' ')} #{LIBS}"
end
 
rule '.o' => %w[.c] do |t|
sh "#{CC} #{CPPFLAGS} -o #{t.name} -c #{t.source}"
end
 
desc 'removes callruby and .o files'
task 'clean' do
rm_f %w[callruby main.o query-rb.o]
end</syntaxhighlight>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">
//! In order to run this task, you will need to compile the C program locating in the task linked
//! above. The C program will need to be linked with the library produced by this file.
//!
//! 1. Compile this library:
//!
//! ```bash
//! $ cargo build --release
//! ```
//!
//! 2. Copy the C program into query.c.
//! 3. Compile and link the C program with the produced library:
//!
//! ```bash
//! $ LD_LIBRARY_PATH=/path/to/library gcc query.c -o query -Wall -Werror libquery
//! ```
//! 4. Run the resulting binary.
//!
//! ```bash
//! $ LD_LIBRARY_PATH=/path/to/library ./query
//! Here am I
//! ```
 
#![crate_type = "cdylib"]
 
extern crate libc;
 
use std::ffi::CString;
 
use libc::{c_char, c_int, size_t};
 
#[no_mangle]
#[allow(non_snake_case)]
#[allow(clippy::missing_safety_doc)]
pub unsafe extern "C" fn Query(data: *mut c_char, length: *mut size_t) -> c_int {
let string = "Here am I";
if *length + 1 < string.len() {
0
} else {
let c_string = CString::new(string).unwrap();
libc::strcpy(data, c_string.as_ptr());
*length = string.len();
1
}
}
 
</syntaxhighlight>
 
=={{header|Scala}}==
===Using the JVM===
We write a Scala function, then write a C function <code>Query()</code> to use the Java Native Interface (JNI) to call our Scala method. The C compiler must find ''jni.h'' and ''jni_md.h'' and link with ''libjvm''.
 
<syntaxhighlight lang="scala">/* Query.scala */
object Query {
def call(data: Array[Byte], length: Array[Int]): Boolean = {
val message = "Here am I"
val mb = message.getBytes("utf-8")
if (length(0) >= mb.length) {
length(0) = mb.length
System.arraycopy(mb, 0, data, 0, mb.length)
true
} else false
}
}</syntaxhighlight>
 
<syntaxhighlight lang="c">/* query-jni.c */
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
 
static JavaVM *jvm = NULL;
static JNIEnv *jenv = NULL;
 
static void die(const char *message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
 
static void oom(void) {
die("Query: out of memory");
}
 
static void except(void) {
if ((*jenv)->ExceptionCheck(jenv))
die("Query: unexpected Java exception");
}
 
static void do_at_exit(void) {
(*jvm)->DestroyJavaVM(jvm);
}
 
static void require_jvm(void) {
JavaVMInitArgs args;
 
if (jvm)
return;
 
args.version = JNI_VERSION_1_4;
args.nOptions = 0;
args.options = NULL;
args.ignoreUnrecognized = JNI_FALSE;
if (JNI_CreateJavaVM(&jvm, (void **)&jenv, &args) != JNI_OK)
die("Query: can't create Java VM");
atexit(do_at_exit);
}
 
int Query(char *data, size_t *length) {
jclass cQuery;
jmethodID mcall;
jintArray jlength;
jint jlength0;
jbyteArray jdata;
jboolean result;
 
jlength0 = (jint)length[0];
if ((size_t)jlength0 != length[0])
die("Query: length is too large for Scala array");
 
require_jvm();
 
/* Create a local frame for references to Scala objects. */
if ((*jenv)->PushLocalFrame(jenv, 16))
oom();
 
/* Look for class Query, static boolean call(byte[], int[]) */
cQuery = (*jenv)->FindClass(jenv, "Query");
if (cQuery == NULL)
die("Query: can't find Query.class");
mcall = (*jenv)->GetStaticMethodID(jenv, cQuery, "call", "([B[I)Z");
if (mcall == NULL)
die("Query: missing call() method");
 
/*
* Make arguments to Query.call(). We can't pass data[] and
* length[] to Scala, so we make new Scala arrays jdata[] and
* jlength[].
*/
jdata = (*jenv)->NewByteArray(jenv, (jsize)jlength0);
if (jdata == NULL)
oom();
jlength = (*jenv)->NewIntArray(jenv, 1);
if (jlength == NULL)
oom();
 
/* Set jlength[0] = length[0]. */
(*jenv)->SetIntArrayRegion(jenv, jlength, 0, 1, &jlength0);
except();
 
/*
* Call our Scala method.
*/
result = (*jenv)->CallStaticBooleanMethod
(jenv, cQuery, mcall, jdata, jlength);
except();
 
/*
* Set length[0] = jlength[0].
* Copy length[0] bytes from jdata[] to data[].
*/
(*jenv)->GetIntArrayRegion(jenv, jlength, 0, 1, &jlength0);
except();
length[0] = (size_t)jlength0;
(*jenv)->GetByteArrayRegion
(jenv, jdata, 0, (jsize)jlength0, (jbyte *)data);
 
/* Drop our local frame and its references. */
(*jenv)->PopLocalFrame(jenv, NULL);
 
return (int)result;
}</syntaxhighlight>
 
<syntaxhighlight lang="make"># Makefile
 
# Edit these lines to match your JDK.
JAVA_HOME = /Library/Java/Home
CPPFLAGS = -I$(JAVA_HOME)/include
LIBS = -framework JavaVM
JAVAC = $(JAVA_HOME)/bin/javac
CC = cc
 
all: calljava Query.class
 
calljava: main.o query-jni.o
$(CC) -o calljava main.o query-jni.o $(LIBS)
 
.SUFFIXES: .c .class .java .o
.c.o:
$(CC) $(CPPFLAGS) -c $<
.java.class:
$(JAVAC) $<
 
clean:
rm -f calljava main.o query-jni.o Query.class</syntaxhighlight>
 
=={{header|Tcl}}==
Line 1,005 ⟶ 1,806:
===‘In’ Parameters===
To connect a function to Tcl that passes an arbitrary C string as input, you'd use a short C thunk, like this:
<langsyntaxhighlight lang="c">int Query (char * Data, size_t * Length) {
Tcl_Obj *arguments[2];
int code;
Line 1,026 ⟶ 1,827:
}
return code;
}</langsyntaxhighlight>
Which would lead to a <code>Query</code> implementation like this:
<langsyntaxhighlight lang="tcl">proc Query data {
puts "Query was $data"
return 1;
}</langsyntaxhighlight>
 
===‘Out’ Parameters===
However, in the specific case of writing to a user-specified buffer (an “out” parameter) the thunk code would instead manage copying the result from the interpreter back to the buffer:
<langsyntaxhighlight lang="tcl">int Query (char * Data, size_t * Length) {
const char *str;
int len;
Line 1,048 ⟶ 1,849:
memcpy(Data, str, len+1);
return 1;
}</langsyntaxhighlight>
And the implementation of <code>Query</code> would be just:
<langsyntaxhighlight lang="tcl">proc Query {} {
return "Here am I"
}</langsyntaxhighlight>
(Since this is working with a literal, this would actually be efficient and just result in references being passed.)
===Connecting up the pieces===
You would also need a short piece of code in <code>main()</code> to initialize the Tcl library and create an interpreter instance, and you would need to build and link against [[libtcl]].
<langsyntaxhighlight lang="c">#include <tcl.h>
Tcl_Interp *interp;
 
Line 1,064 ⟶ 1,865:
 
/* Rest of contents of main() from task header... */
}</langsyntaxhighlight>
 
=={{header|TXR}}==
Line 1,072 ⟶ 1,873:
The TXR run-time is not available as a library that can be linked to a C program. Instead, we can put the C driver into a small library and call out to it from TXR, then accept its callback. Here is that library:
 
<langsyntaxhighlight lang="c">#include <stdio.h>
 
int query(int (*callback)(char *, size_t *))
Line 1,088 ⟶ 1,889:
putchar('\n');
}
}</langsyntaxhighlight>
 
Here are the build steps to produce a `query.so` object from it on GNU/Linux:
 
<langsyntaxhighlight lang="shell">gcc -g -fPIC query.c -c
gcc -g --shared query.c -o query.c</langsyntaxhighlight>
 
===Using <code>carray</code>===
Line 1,103 ⟶ 1,904:
Callbacks are modeled as "FFI closures". The macro <code>deffi-cb</code> defines a function which itself isn't a callback, but is rather a combinator which converts a Lisp function into a FFI callback.
 
<syntaxhighlight lang ="txrlisp">(with-dyn-lib "./query.so"
(deffi query "query" void (closure)))
 
(deffi-cb query-cb int ((carray char) (ptr (array 1 size-t))))
 
(query (query-cb (lambda (buf sizeptr)
(symacrolet ((size [sizeptr 0]))
(let* ((s "Here am I")
(l (length s)))
(cond
((> l size) 0)
(t (carray-set-length buf size)
(carray-put buf s)
(set size l))))))))</langsyntaxhighlight>
 
{{out}}
Line 1,123 ⟶ 1,924:
 
Note that the obvious way of passing a <code>size_t</code> value by pointer, namely <code>(ptr size-t)</code> doesn't work. While the callback will receive the size (FFI will decode the pointer type's semantics and get the size value), updating the size will not propagate back to the caller, because it becomes, effectively, a by-value parameter. A <code>(ptr size-t)</code> object has to be embedded in an aggregate that is passed by reference, in order to have two-way semantics. Here we use the trick of treating the <code>size_t *</code> as an array of 1, which it ''de facto'' is. In the callback, we establish local symbol macro which lets us just refer to <code>[sizeptr 0]</code> it as <code>size</code>.
 
 
=== Using <code>cptr</code> and <code>memcpy</code> ===
Line 1,129 ⟶ 1,929:
An alternative approach is possible if we avail ourselves of the <code>memcpy</code> function via FFI. We can receive the data as an opaque foreign pointer represented by the <code>cptr</code> type. We can set up <code>memcpy</code> so that its destination argument and return value is a <code>cptr</code>, but the source argument is a string:
 
<syntaxhighlight lang ="txrlisp">(with-dyn-lib "./query.so"
(deffi query "query" void (closure)))
(with-dyn-lib nil
(deffi memcpy "memcpy" cptr (cptr str size-t)))
(deffi-cb query-cb int (cptr (ptr (array 1 size-t))))
(query (query-cb (lambda (buf sizeptr) ; int lambda(void *buf, size_t *sizeptr)siz
(symacrolet ((size [sizeptr 0])) ; { #define size sizeptr[0]
(let* ((s "Here am I") ; char *s = "Here am I";
(l (length s))) ; size_t l = strlen(s);
(cond ; if (length > size)
((> l size) 0) ; { return 0; } else
(t (memcpy buf s l) ; { memcpy(buf, s, l);
(set size l)))))))) ; return size = l; } }</langsyntaxhighlight>
 
Here, the use of the <code>str</code> type in the <code>memcpy</code> interface means that FFI automatically produces a UTF-8 encoding of the string in a temporary buffer. The pointer to that temporary buffer is what is passed into <code>memcpy</code>. The temporary buffer is released after <code>memcpy</code> returns.
Line 1,174 ⟶ 1,974:
If a return value other than zero indicates that the callback failed, that can be arranged with an additional argument in <code>deffi-cb</code>:
 
<langsyntaxhighlight lang="txrlisp">(deffi-cb query-cb int (cptr (ptr (array 1 size-t))) -1)</langsyntaxhighlight>
 
Now the <code>query-cb</code> function generates callbacks that return -1 to the caller, rather than zero, if aborted by a non-local control transfer such as an exception.
 
=={{header|Wren}}==
Currently, the only way to call a Wren function from another language is to embed it in a program written in that language. Therefore, we embed this Wren script:
<syntaxhighlight lang="wren">/* Use_another_language_to_call_a_function.wren */
 
class RCQuery {
// Both arguments are lists as we need pass by reference here
static query(Data, Length) {
var s = "Here am I"
var sc = s.count
if (sc > Length[0]) return 0 // buffer too small
for (i in 0...sc) Data[i] = s[i].bytes[0]
Length[0] = sc
return 1
}
}</syntaxhighlight>
<br>
in the following C program, compile and run:
<syntaxhighlight lang="c">/* gcc Use_another_language_to_call_a_function.c -o Use_another_language_to_call_a_function -lwren -lm */
 
#include <stdio.h>
#include "wren.h"
 
char *script;
WrenVM * vm;
 
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
return NULL; // nothing needed here
}
 
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
 
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
 
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
 
int configWrenVM() {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignMethodFn = &bindForeignMethod;
vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "Use_another_language_to_call_a_function.wren";
script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
return -1;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
return -1;
case WREN_RESULT_SUCCESS:
break;
}
return 0;
}
 
int Query(char *Data, size_t *Length) {
int i, r;
wrenEnsureSlots(vm, 4);
 
// create list for Data, fill with zeros and put in slot 1
wrenSetSlotNewList(vm, 1);
wrenSetSlotDouble(vm, 2, 0.0);
for (i = 0; i < *Length; ++i) wrenInsertInList(vm, 1, i, 2);
 
// create list for Length and put in slot 2
wrenSetSlotNewList(vm, 2);
wrenSetSlotDouble(vm, 3, (double)*Length);
wrenInsertInList(vm, 2, 0, 3);
 
// get handle to Wren's query method
WrenHandle* method = wrenMakeCallHandle(vm, "query(_,_)");
 
// get its class and put in slot 0
wrenGetVariable(vm, "main", "RCQuery", 0);
 
// call the Wren method
wrenCall(vm, method);
 
// get the result and check it's 1
r = (int)wrenGetSlotDouble(vm, 0);
if (r) {
// get the length of the string from slot 2
wrenGetListElement(vm, 2, 0, 3);
*Length = (int)wrenGetSlotDouble(vm, 3);
 
// copy the bytes from the list in slot 1 to the C buffer
for (i = 0; i < *Length; ++i) {
wrenGetListElement(vm, 1, i, 3);
Data[i] = (char)wrenGetSlotDouble(vm, 3);
}
}
return r;
}
 
int main() {
int e = configWrenVM();
if (!e) {
char Buffer [1024];
size_t Size = sizeof(Buffer);
if (0 == Query(Buffer, &Size)) {
printf ("failed to call Query\n");
e = 1;
} else {
char * Ptr = Buffer;
while (Size-- > 0) putchar (*Ptr++);
putchar ('\n');
}
}
wrenFreeVM(vm);
free(script);
return e;
}</syntaxhighlight>
 
{{out}}
<pre>
Here am I
</pre>
 
=={{header|X86-64 Assembly}}==
===UASM 2.52===
<syntaxhighlight lang="asm">
option casemap:none
 
 
strlen proto :qword
strncpy proto :qword, :qword, :dword
 
Query proto :qword, :qword
 
.data
szstr db "Here am I",0
 
.code
Query proc Data:qword, len:qword
local d:qword, l:qword, s:dword
 
mov d, Data
mov l, len
invoke strlen, addr szstr
.if rax <= l
mov s, eax
invoke strncpy, d, addr szstr, s
mov eax, s
mov rax, l
mov dword ptr [rax], ecx
mov rax, 1
ret
.endif
mov rax, 0
ret
Query endp
end
</syntaxhighlight>
 
===NASM===
<syntaxhighlight lang="asm">
section .data
szmsg db "Here I am",0
 
section .text
global Query
 
strlen:
push rbp
mov rbp, rsp
mov rsi, rdi
mov rcx, -1
_1:
inc rcx
cmp byte [rsi+rcx], 0
jne _1
mov rax, rcx
pop rbp
ret
 
Query:
push rbp
mov rbp, rsp
;;mov r9, rcx ;;Arg 1, windows
;;mov r8, rdx ;;Arg 2, windows
mov r9, rdi ;;Arg 1, Linux
mov r8, rsi ;;Arg 2, Linux
lea rdi, szmsg
call strlen
cmp rax, r8
jg _err
mov r10d, eax
mov rdi, r9
lea rsi, szmsg
rep movsb
mov rax, r8
mov dword [rax], r10d
jmp _exit
 
_err:
mov rax, 0
_exit:
pop rbp
ret
</syntaxhighlight>
 
=={{header|Zig}}==
<syntaxhighlight lang="zig">const std = @import("std");
 
export fn Query(Data: [*c]u8, Length: *usize) callconv(.C) c_int {
const value = "Here I am";
 
if (Length.* >= value.len) {
@memcpy(@ptrCast([*]u8, Data), value, value.len);
Length.* = value.len;
return 1;
}
 
return 0;
}</syntaxhighlight>
 
=={{header|zkl}}==
Line 1,182 ⟶ 2,232:
 
Modified main.c:
<langsyntaxhighlight lang="c">// query.c
// export zklRoot=/home/ZKL
// clang query.c -I $zklRoot/VM -L $zklRoot/Lib -lzkl -pthread -lncurses -o query
Line 1,228 ⟶ 2,278:
 
return 0;
}</langsyntaxhighlight>
Our query program:
<langsyntaxhighlight lang="zkl">// query.zkl
var query="Here am I";</langsyntaxhighlight>
On Linux:
{{out}}
9,476

edits