diff --git a/CHANGES.current b/CHANGES.current
index e5697ca7b..a5f75897a 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -1,6 +1,11 @@
Version 1.3.35 (in progress)
============================
+03/17/2008: mgossage
+ [Lua] Added %luacode feature to add source code into wrappers.
+ Updated documentation to document this.
+ Added Examples/lua/arrays to show its use (and typemaps)
+
03/17/2008: olly
Fix nonportable sed usage which failed on Mac OS X (and probably
other platforms). Fixes SF#1903612.
diff --git a/Doc/Manual/Lua.html b/Doc/Manual/Lua.html
index 91a44d657..35a4d9b12 100644
--- a/Doc/Manual/Lua.html
+++ b/Doc/Manual/Lua.html
@@ -35,12 +35,13 @@
Details on the Lua binding
@@ -1089,7 +1090,43 @@ int native_function(lua_State*L) // my native code
The %native directive in the above example, tells SWIG that there is a function int native_function(lua_State*L); which is to be added into the module under the name 'my_func'. SWIG will not add any wrappering for this function, beyond adding it into the function table. How you write your code is entirely up to you.
-22.4 Details on the Lua binding
+22.3.17 Adding additional Lua code
+
+As well as adding additional C/C++ code, its also possible to add your own Lua code to the module as well.
+This code is executed once all other initialisation, including the %init code has been called.
+
+
+The directive %luacode adds code into the module which is executed upon loading. Normally you would
+use this to add your own functions to the module. Though you could easily perform other tasks.
+
+%module example;
+
+%luacode {
+ function example.greet()
+ print "hello world"
+ end
+
+ print "Module loaded ok"
+}
+...
+%}
+
+
+Notice that the code is not part of the module table. Therefore any references to the module must have the
+module name added.
+
+
+Should there be an error in the Lua code, this will not stop loading of the module.
+The default behaviour of SWIG is to print a error message to stderr and then continue.
+It is possible to change this behaviour by using a #define SWIG_DOSTRING_FAIL(STR) to
+define a different behaviour should the code fail.
+
+
+Good uses for this feature is adding of new code, or writing helper functions to simplify some of the code.
+See Examples/lua/arrays, for an example of this code.
+
+
+22.4 Details on the Lua binding
@@ -1100,7 +1137,7 @@ The %native directive in the above example, tells SWIG that there is a
-22.4.1 Binding global data into the module.
+22.4.1 Binding global data into the module.
@@ -1160,7 +1197,7 @@ end
That way when you call 'a=example.Foo', the interpreter looks at the table 'example' sees that there is no field 'Foo' and calls __index. This will in turn check in '.get' table and find the existence of 'Foo' and then return the value of the C function call 'Foo_get()'. Similarly for the code 'example.Foo=10', the interpreter will check the table, then call the __newindex which will then check the '.set' table and call the C function 'Foo_set(10)'.
-22.4.2 Userdata and Metatables
+22.4.2 Userdata and Metatables
@@ -1240,7 +1277,7 @@ Note: Both the opaque structures (like the FILE*) and normal wrappered classes/s
Note: Operator overloads are basically done in the same way, by adding functions such as '__add' & '__call' to the classes metatable. The current implementation is a bit rough as it will add any member function beginning with '__' into the metatable too, assuming its an operator overload.
-22.4.3 Memory management
+22.4.3 Memory management
diff --git a/Examples/lua/arrays/Makefile b/Examples/lua/arrays/Makefile
new file mode 100644
index 000000000..bb9cf0b3b
--- /dev/null
+++ b/Examples/lua/arrays/Makefile
@@ -0,0 +1,18 @@
+TOP = ../..
+SWIG = $(TOP)/../preinst-swig
+SRCS = example.c
+TARGET = example
+INTERFACE = example.i
+
+all::
+ $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \
+ TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' lua
+
+static::
+ $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \
+ TARGET='mylua' INTERFACE='$(INTERFACE)' lua_static
+
+clean::
+ $(MAKE) -f $(TOP)/Makefile lua_clean
+
+check: all
diff --git a/Examples/lua/arrays/example.c b/Examples/lua/arrays/example.c
new file mode 100644
index 000000000..40ed12c79
--- /dev/null
+++ b/Examples/lua/arrays/example.c
@@ -0,0 +1,25 @@
+/* File : example.c */
+
+#include
+
+/* we are using the qsort function, which needs a helper function to sort */
+int compare_int(const void * a, const void * b)
+{
+ return ( *(int*)a - *(int*)b );
+}
+
+void sort_int(int* arr, int len)
+{
+ qsort(arr, len, sizeof(int), compare_int);
+}
+
+// ditto doubles
+int compare_double(const void * a, const void * b)
+{
+ return ( *(double*)a - *(double*)b );
+}
+
+void sort_double(double* arr, int len)
+{
+ qsort(arr, len, sizeof(double), compare_double);
+}
diff --git a/Examples/lua/arrays/example.i b/Examples/lua/arrays/example.i
new file mode 100644
index 000000000..197a5a21b
--- /dev/null
+++ b/Examples/lua/arrays/example.i
@@ -0,0 +1,42 @@
+/* File : example.i */
+%module example
+
+/* in this file there are two sorting functions
+and three different ways to wrap them.
+
+See the lua code for how they are called
+*/
+
+%include // array helpers
+
+// this declares a batch of function for manipulating C integer arrays
+%array_functions(int,int)
+
+// this adds some lua code directly into the module
+// warning: you need the example. prefix if you want it added into the module
+// addmittedly this code is a bit tedious, but its a one off effort
+%luacode {
+function example.sort_int2(t)
+ local len=table.maxn(t) -- the len
+ local arr=example.new_int(len)
+ for i=1,len do
+ example.int_setitem(arr,i-1,t[i]) -- note: C index is one less then lua indea
+ end
+ example.sort_int(arr,len) -- call the fn
+ -- copy back
+ for i=1,len do
+ t[i]=example.int_getitem(arr,i-1) -- note: C index is one less then lua indea
+ end
+ example.delete_int(arr) -- must delete it
+end
+}
+
+// this way uses the SWIG-Lua typemaps to do the conversion for us
+// the %apply command states to apply this wherever the argument signature matches
+%include
+%apply (double *INOUT,int) {(double* arr,int len)};
+
+%inline %{
+extern void sort_int(int* arr, int len);
+extern void sort_double(double* arr, int len);
+%}
\ No newline at end of file
diff --git a/Examples/lua/arrays/runme.lua b/Examples/lua/arrays/runme.lua
new file mode 100644
index 000000000..b0f5cfc96
--- /dev/null
+++ b/Examples/lua/arrays/runme.lua
@@ -0,0 +1,74 @@
+---- importing ----
+if string.sub(_VERSION,1,7)=='Lua 5.0' then
+ -- lua5.0 doesnt have a nice way to do this
+ lib=loadlib('example.dll','luaopen_example') or loadlib('example.so','luaopen_example')
+ assert(lib)()
+else
+ -- lua 5.1 does
+ require('example')
+end
+
+-- a helper to print a Lua table
+function print_table(t)
+ print(table.concat(t,","))
+end
+
+-- a helper to print a C array
+function print_array(arr,len)
+ for i=0,len-1 do
+ io.write(example.int_getitem(arr,i),",")
+ end
+ io.write("\n")
+end
+
+math.randomseed(0) -- init random
+
+
+--[[ version 1: passing a C array to the code
+lets test call sort_int()
+this requires a C array, so is the hardest to use]]
+ARRAY_SIZE=10
+arr=example.new_int(ARRAY_SIZE)
+for i=0,ARRAY_SIZE-1 do
+ example.int_setitem(arr,i,math.random(1000))
+end
+print "unsorted"
+print_array(arr,ARRAY_SIZE)
+example.sort_int(arr,ARRAY_SIZE)
+print "sorted"
+print_array(arr,ARRAY_SIZE)
+example.delete_int(arr) -- must delete it
+print ""
+
+--[[ version 2: using %luacode to write a helper
+a simpler way is to use a %luacode
+which is a lua function added into the module
+this can do the conversion for us
+so we can just add a lua table directly
+(what we do is move the lua code into the module instead)
+]]
+t={}
+for i=1,ARRAY_SIZE do
+ t[i]=math.random(1000)
+end
+print "unsorted"
+print_table(t)
+example.sort_int2(t) -- calls lua helper which then calls C
+print "sorted"
+print_table(t)
+print ""
+
+--[[ version 3: use a typemap
+this is the best way
+it uses the SWIG-Lua typemaps to do the work
+one item of note: the typemap creates a copy, rather than edit-in-place]]
+t={}
+for i=1,ARRAY_SIZE do
+ t[i]=math.random(1000)/10
+end
+print "unsorted"
+print_table(t)
+t=example.sort_double(t) -- replace t with the result
+print "sorted"
+print_table(t)
+
diff --git a/Examples/lua/check.list b/Examples/lua/check.list
index d28b1342a..c8e09c493 100644
--- a/Examples/lua/check.list
+++ b/Examples/lua/check.list
@@ -1,4 +1,5 @@
# see top-level Makefile.in
+arrays
class
constants
dual
diff --git a/Lib/lua/lua.swg b/Lib/lua/lua.swg
index 65e95503e..b6d888670 100644
--- a/Lib/lua/lua.swg
+++ b/Lib/lua/lua.swg
@@ -228,5 +228,8 @@ SWIG_fail;%}
/* -----------------------------------------------------------------------------
* extras
* ----------------------------------------------------------------------------- */
+// this %define is to allow insertion of lua source code into the wrapper file
+#define %luacode %insert("luacode")
+
/* ------------------------------ end lua.swg ------------------------------ */
diff --git a/Lib/lua/luarun.swg b/Lib/lua/luarun.swg
index 751e062f0..f042bc6b0 100644
--- a/Lib/lua/luarun.swg
+++ b/Lib/lua/luarun.swg
@@ -671,12 +671,6 @@ SWIGRUNTIME const char *SWIG_Lua_typename(lua_State *L, int tp)
/* lua callable function to get the userdata's type */
SWIGRUNTIME int SWIG_Lua_type(lua_State* L)
{
-/* swig_lua_userdata* usr;
- if (!lua_isuserdata(L,1)) /* just in case */
- /* return 0; /* nil reply */
- /*usr=(swig_lua_userdata*)lua_touserdata(L,1); /* get data */
- /*lua_pushstring(L,usr->type->name);
- return 1;*/
lua_pushstring(L,SWIG_Lua_typename(L,1));
return 1;
}
@@ -698,9 +692,6 @@ SWIGRUNTIME int SWIG_Lua_equal(lua_State* L)
return 1;
}
-
-
-
/* -----------------------------------------------------------------------------
* global variable support code: class/struct typemap functions
* ----------------------------------------------------------------------------- */
@@ -747,6 +738,35 @@ SWIG_Lua_InstallConstants(lua_State* L, swig_lua_const_info constants[]) {
}
}
+/* -----------------------------------------------------------------------------
+ * executing lua code from within the wrapper
+ * ----------------------------------------------------------------------------- */
+
+#ifndef SWIG_DOSTRING_FAIL /* Allows redefining of error function */
+#define SWIG_DOSTRING_FAIL(S) fprintf(stderr,"%s\n",S)
+#endif
+/* Executes a C string in Lua a really simple way of calling lua from C
+Unfortunately lua keeps changing its API's, so we need a conditional compile
+In lua 5.0.X its lua_dostring()
+In lua 5.1.X its luaL_dostring()
+*/
+SWIGINTERN int
+SWIG_Lua_dostring(lua_State *L, const char* str) {
+ int ok,top;
+ if (str==0 || str[0]==0) return 0; /* nothing to do */
+ top=lua_gettop(L); /* save stack */
+#if (defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM>=501))
+ ok=luaL_dostring(L,str); /* looks like this is lua 5.1.X or later, good */
+#else
+ ok=lua_dostring(L,str); /* might be lua 5.0.x, using lua_dostring */
+#endif
+ if (ok!=0) {
+ SWIG_DOSTRING_FAIL(lua_tostring(L,-1));
+ }
+ lua_settop(L,top); /* restore the stack */
+ return ok;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/Lib/lua/luaruntime.swg b/Lib/lua/luaruntime.swg
index 04f1adf89..b82cd56d7 100644
--- a/Lib/lua/luaruntime.swg
+++ b/Lib/lua/luaruntime.swg
@@ -16,7 +16,7 @@
/* Forward declaration of where the user's %init{} gets inserted */
void SWIG_init_user(lua_State* L );
-
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/Lib/lua/typemaps.i b/Lib/lua/typemaps.i
index 284078081..bccfbe120 100644
--- a/Lib/lua/typemaps.i
+++ b/Lib/lua/typemaps.i
@@ -94,7 +94,7 @@ and quite a few functions defined
assuming we have functions
void process_array(int arr[3]); // nice fixed size array
void process_var_array(float arr[],int len); // variable sized array
-void process_var_array_inout(double arr*,int len); // variable sized array
+void process_var_array_inout(double* arr,int len); // variable sized array
// data passed in & out
void process_enum_inout_array_var(enum Days *arrinout, int len); // using enums
void return_array_5(int arrout[5]); // out array only
diff --git a/Source/Modules/lua.cxx b/Source/Modules/lua.cxx
index 4e529bcd7..bb141f926 100644
--- a/Source/Modules/lua.cxx
+++ b/Source/Modules/lua.cxx
@@ -102,6 +102,7 @@ private:
String *s_const_tab; // table of global constants
String *s_methods_tab; // table of class methods
String *s_attr_tab; // table of class atributes
+ String *s_luacode; // luacode to be called during init
int have_constructor;
int have_destructor;
@@ -137,7 +138,7 @@ public:
f_initbeforefunc = 0;
PrefixPlusUnderscore = 0;
- s_cmd_tab = s_var_tab = s_const_tab = 0;
+ s_cmd_tab = s_var_tab = s_const_tab = s_luacode = 0;
current=NO_CPP;
}
@@ -240,6 +241,10 @@ public:
s_var_tab = NewString("");
// s_methods_tab = NewString("");
s_const_tab = NewString("");
+
+ s_luacode = NewString("");
+ Swig_register_filebyname("luacode", s_luacode);
+
current=NO_CPP;
/* Standard stuff for the SWIG runtime section */
@@ -256,6 +261,7 @@ public:
Printf(f_header, "#define SWIG_name \"%s\"\n", module);
Printf(f_header, "#define SWIG_init luaopen_%s\n", module);
Printf(f_header, "#define SWIG_init_user luaopen_%s_user\n\n", module);
+ Printf(f_header, "#define SWIG_LUACODE luaopen_%s_luacode\n\n", module);
Printf(s_cmd_tab, "\nstatic const struct luaL_reg swig_commands[] = {\n");
Printf(s_var_tab, "\nstatic swig_lua_var_info swig_variables[] = {\n");
@@ -265,6 +271,7 @@ public:
/* %init code inclusion, effectively in the SWIG_init function */
Printf(f_init, "void SWIG_init_user(lua_State* L)\n{\n");
Language::top(n);
+ Printf(f_init,"/* exec Lua code if applicable */\nSWIG_Lua_dostring(L,SWIG_LUACODE);\n");
Printf(f_init, "}\n");
Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n");
@@ -280,14 +287,18 @@ public:
this basically combines several of the strings together
and then writes it all to a file
NEW LANGUAGE NOTE:END ************************************************/
- /* Close all of the files */
- Delete(s_cmd_tab);
- Delete(s_var_tab);
- Delete(s_const_tab);
Dump(f_header, f_runtime);
Dump(f_wrappers, f_runtime);
Dump(f_initbeforefunc, f_runtime);
+ /* for the Lua code it needs to be properly excaped to be added into the C/C++ code */
+ EscapeCode(s_luacode);
+ Printf(f_runtime, "const char* SWIG_LUACODE=\n \"%s\";\n\n",s_luacode);
Wrapper_pretty_print(f_init, f_runtime);
+ /* Close all of the files */
+ Delete(s_luacode);
+ Delete(s_cmd_tab);
+ Delete(s_var_tab);
+ Delete(s_const_tab);
Delete(f_header);
Delete(f_wrappers);
Delete(f_init);
@@ -1123,6 +1134,24 @@ public:
String *defaultExternalRuntimeFilename() {
return NewString("swigluarun.h");
}
+
+ /* ---------------------------------------------------------------------
+ * helpers
+ * --------------------------------------------------------------------- */
+
+ /* This is to convert the string of Lua code into a proper string, which can then be
+ emitted into the C/C++ code.
+ Basically is is a lot of search & replacing of odd sequences
+ */
+ void EscapeCode(String* str)
+ {
+ Printf(f_runtime,"/* original luacode:[[[\n%s\n]]]\n*/\n",str);
+ Chop(str); // trim
+ Replace(str,"\\","\\\\",DOH_REPLACE_ANY); // \ to \\ (this must be done first)
+ Replace(str,"\"","\\\"",DOH_REPLACE_ANY); // " to \"
+ Replace(str,"\n","\\n\"\n \"",DOH_REPLACE_ANY); // \n to \n"\n" (ie quoting every line)
+ Printf(f_runtime,"/* hacked luacode:[[[\n%s\n]]]\n*/\n",str);
+ }
};
/* NEW LANGUAGE NOTE:***********************************************
@@ -1146,7 +1175,7 @@ swig_module modules[] = {
{"-guile", swig_guile, "Guile"},
{"-java", swig_java, "Java"},
//etc,etc,etc...
- {"-Lua", swig_lua, "Lua"}, // this is my code
+ {"-lua", swig_lua, "Lua"}, // this is my code
{NULL, NULL, NULL} // this must come at the end of the list
};
======= end change ==========