September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -0,0 +1,17 @@
|
|||
#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;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
$ gcc -c main.c
|
||||
$ g++ -c query.cpp
|
||||
$ g++ -o main main.o query.o
|
||||
$ ./main
|
||||
Here am I
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/* 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# 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
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# 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')
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# 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
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int query(int (*callback)(char *, size_t *))
|
||||
{
|
||||
char buffer[1024];
|
||||
size_t size = sizeof buffer;
|
||||
|
||||
if (callback(buffer, &size) == 0) {
|
||||
puts("query: callback failed");
|
||||
} else {
|
||||
char *ptr = buffer;
|
||||
|
||||
while (size-- > 0)
|
||||
putchar (*ptr++);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
gcc -g -fPIC query.c -c
|
||||
gcc -g --shared query.c -o query.c
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
(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))))))))
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
(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, 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; } }
|
||||
|
|
@ -0,0 +1 @@
|
|||
(deffi-cb query-cb int (cptr (ptr (array 1 size-t))) -1)
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// query.c
|
||||
// export zklRoot=/home/ZKL
|
||||
// clang query.c -I $zklRoot/VM -L $zklRoot/Lib -lzkl -pthread -lncurses -o query
|
||||
// LD_LIBRARY_PATH=$zklRoot/Lib ./query
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "zklObject.h"
|
||||
#include "zklImports.h"
|
||||
#include "zklClass.h"
|
||||
#include "zklFcn.h"
|
||||
#include "zklString.h"
|
||||
|
||||
int query(char *buf, size_t *sz)
|
||||
{
|
||||
Instance *r;
|
||||
pVM vm;
|
||||
MLIST(mlist,10);
|
||||
|
||||
// Bad practice: not protecting things from the garbage collector
|
||||
|
||||
// build the call parameters: ("query.zkl",False,False,True)
|
||||
mlistBuild(mlist,stringCreate("query.zkl",I_OWNED,NoVM),
|
||||
BoolFalse,BoolFalse,BoolTrue,ZNIL);
|
||||
// Import is in the Vault, a store of useful stuff
|
||||
// We want to call TheVault.Import.import("query.zkl",False,False,True)
|
||||
// which will load/compile/run query.zkl
|
||||
r = fcnRunith("Import","import",(Instance *)mlist,NoVM);
|
||||
// query.zkl is a class with a var that has the query result
|
||||
r = classFindVar(r,"query",0,NoVM); // -->the var contents
|
||||
strcpy(buf,stringText(r)); // decode the string into a char *
|
||||
*sz = strlen(buf); // screw overflow checking
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char buf[100];
|
||||
size_t sz = sizeof(buf);
|
||||
|
||||
zklConstruct(argc,argv); // initialize the zkl shared library
|
||||
query(buf,&sz);
|
||||
printf("Query() --> \"%s\"\n",buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
// query.zkl
|
||||
var query="Here am I";
|
||||
Loading…
Add table
Add a link
Reference in a new issue