Use another language to call a function: Difference between revisions

m
(Added COBOL (GnuCOBOL in particular))
m (→‎{{header|Wren}}: Minor tidy)
 
(15 intermediate revisions by 11 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++}}==
<langsyntaxhighlight lang="cpp">#include <string>
using std::string;
 
Line 167:
Message.copy(Data, *Length);
return true;
}</langsyntaxhighlight>
 
We must compile main() with a C compiler and Query() with a C++ compiler. One can use gcc and g++ (or clang and clang++).
 
<langsyntaxhighlight lang="bash">$ gcc -c main.c
$ g++ -c query.cpp
$ g++ -o main main.o query.o
$ ./main
Here am I</langsyntaxhighlight>
 
=={{header|COBOL}}==
Line 184:
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).
 
<langsyntaxhighlight lang="cobol"> identification division.
program-id. Query.
 
Line 216:
 
goback.
end program Query.</langsyntaxhighlight>
 
{{out}}
Line 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 242:
return true;
}
}</langsyntaxhighlight>
 
Generate a library file with:
Line 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 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 278:
 
=={{header|Delphi}}==
<langsyntaxhighlight lang="delphi">
function Query(Buffer: PChar; var Size: Int64): LongBool;
const
Line 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 322:
answer = 1
end function fortran_query
</syntaxhighlight>
</lang>
compile it: gfortran main.c query.f90 -o main.x
 
Line 331:
 
Thus, I changed the specified C code to begin as follows,
<langsyntaxhighlight lang="c">#include <stdio.h>
#include "_cgo_export.h"
 
Line 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 370:
*csiz = C.size_t(len(msg) + 1)
return 1
}</langsyntaxhighlight>
Output:
<pre>
Line 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 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 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 474:
hs_exit();
return 0;
}</langsyntaxhighlight>
 
The Haskell code then is:
 
<langsyntaxhighlight lang="haskell">{-# LANGUAGE ForeignFunctionInterface #-}
 
module Called where
Line 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 518:
=={{header|Haxe}}==
=== PHP ===
<langsyntaxhighlight lang="haxe">untyped __call__("functionName", args);</langsyntaxhighlight>
 
=={{header|J}}==
Line 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 549:
return EXIT_SUCCESS;
}
</syntaxhighlight>
</lang>
 
Query.c
<syntaxhighlight lang="c">
<lang c>
 
// J Front End Example
Line 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 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''.
 
<langsyntaxhighlight lang="java">/* Query.java */
public class Query {
public static boolean call(byte[] data, int[] length)
Line 710:
return true;
}
}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="c">/* query-jni.c */
#include <stdio.h>
#include <stdlib.h>
Line 816:
 
return (int)result;
}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="make"># Makefile
 
# Edit these lines to match your JDK.
Line 839:
 
clean:
rm -f calljava main.o query-jni.o Query.class</langsyntaxhighlight>
 
=={{header|Kotlin}}==
Line 845:
 
First we compile the following Kotlin source file (Query.kt) using the '-platform dynamic' flag:
<langsyntaxhighlight lang="scala">// Kotlin Native v0.6
 
import kotlinx.cinterop.*
Line 858:
length.pointed.value = strLen.signExtend<size_t>()
return 1
}</langsyntaxhighlight>
 
This produces the dynamic library, libQuery.so, and the C header file libQuery_api.h:
<langsyntaxhighlight lang="c">#ifndef KONAN_LIBQUERY_H
#define KONAN_LIBQUERY_H
#ifdef __cplusplus
Line 895:
} /* extern "C" */
#endif
#endif /* KONAN_LIBQUERY_H */</langsyntaxhighlight>
 
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:
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include "libQuery_api.h"
Line 922:
putchar ('\n');
}
}</langsyntaxhighlight>
 
which when executed produces the expected output:
Line 931:
=={{header|Lisaac}}==
query.li
<langsyntaxhighlight Lisaaclang="lisaac">Section Header
 
+ name := QUERY;
Line 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 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 1,010 ⟶ 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 1,017 ⟶ 1,059:
 
=={{header|OCaml}}==
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <string.h>
#include <caml/mlvalues.h>
Line 1,052 ⟶ 1,094:
putchar ('\n');
}
}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="ocaml">let caml_query () =
let s = "Here am I" in
(s, String.length s)
Line 1,061 ⟶ 1,103:
let () =
Callback.register "Query function cb" caml_query;
;;</langsyntaxhighlight>
 
compile with:
Line 1,070 ⟶ 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 1,075 ⟶ 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 1,099 ⟶ 1,206:
 
return rc;
}</langsyntaxhighlight>
 
Compile interface to a library: ''gcc -O2 -Wall -fPIC -shared query.c -o libquery.so -lpari''
Line 1,121 ⟶ 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 1,139 ⟶ 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 1,153 ⟶ 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 1,165 ⟶ 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 1,191 ⟶ 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 1,255 ⟶ 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 1,271 ⟶ 1,381:
Here am I
$
</syntaxhighlight>
</lang>
 
=={{header|Racket}}==
Line 1,279 ⟶ 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 1,304 ⟶ 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}}==
Line 1,315 ⟶ 1,459:
{{works with|MRI|2.3+}}
 
<langsyntaxhighlight lang="ruby"># query.rb
require 'fiddle'
 
Line 1,351 ⟶ 1,495:
 
# Set the C variable to our Query.
Fiddle::Pointer.new(c_var)[0, sz_voidp] = [Query.to_i].pack('J')</langsyntaxhighlight>
 
<langsyntaxhighlight lang="c">/* query-rb.c */
#include <stdlib.h>
#include <ruby.h>
Line 1,433 ⟶ 1,577:
bad_exit(state);
return a.result;
}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="ruby"># Rakefile
 
# To build and run:
Line 1,461 ⟶ 1,605:
task 'clean' do
rm_f %w[callruby main.o query-rb.o]
end</langsyntaxhighlight>
 
=={{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}}==
Line 1,467 ⟶ 1,660:
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''.
 
<langsyntaxhighlight lang="scala">/* Query.scala */
object Query {
def call(data: Array[Byte], length: Array[Int]): Boolean = {
Line 1,478 ⟶ 1,671:
} else false
}
}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="c">/* query-jni.c */
#include <stdio.h>
#include <stdlib.h>
Line 1,584 ⟶ 1,777:
 
return (int)result;
}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="make"># Makefile
 
# Edit these lines to match your JDK.
Line 1,607 ⟶ 1,800:
 
clean:
rm -f calljava main.o query-jni.o Query.class</langsyntaxhighlight>
 
=={{header|Tcl}}==
The way you would tackle this problem depends on whether you are working with ‘In’ or ‘Out’ parameters. (It is normal model ‘inout’ parameters as Tcl variables; omitted for brevity.)
===‘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,633 ⟶ 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,655 ⟶ 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,671 ⟶ 1,865:
 
/* Rest of contents of main() from task header... */
}</langsyntaxhighlight>
 
=={{header|TXR}}==
Line 1,679 ⟶ 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,695 ⟶ 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,710 ⟶ 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.
 
<langsyntaxhighlight lang="txrlisp">(with-dyn-lib "./query.so"
(deffi query "query" void (closure)))
 
Line 1,723 ⟶ 1,917:
(t (carray-set-length buf size)
(carray-put buf s)
(set size l))))))))</langsyntaxhighlight>
 
{{out}}
Line 1,735 ⟶ 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:
 
<langsyntaxhighlight lang="txrlisp">(with-dyn-lib "./query.so"
(deffi query "query" void (closure)))
Line 1,750 ⟶ 1,944:
((> 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,780 ⟶ 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,788 ⟶ 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,834 ⟶ 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