aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ClientHamr
diff options
context:
space:
mode:
authorDavid Walter Seikel2014-03-28 15:44:43 +1000
committerDavid Walter Seikel2014-03-28 15:44:43 +1000
commit5018f9e7673f533bbe3240c2ecce703b47d76a73 (patch)
treec9cfa3b06f3a830d2819ee42ccd50f7a6378f343 /ClientHamr
parentTODO++ (diff)
downloadSledjHamr-5018f9e7673f533bbe3240c2ecce703b47d76a73.zip
SledjHamr-5018f9e7673f533bbe3240c2ecce703b47d76a73.tar.gz
SledjHamr-5018f9e7673f533bbe3240c2ecce703b47d76a73.tar.bz2
SledjHamr-5018f9e7673f533bbe3240c2ecce703b47d76a73.tar.xz
Make test_c a real skang module, and tweaks to the rest of the system to support C skang modules.
Diffstat (limited to 'ClientHamr')
-rw-r--r--ClientHamr/GuiLua/skang.lua19
-rw-r--r--ClientHamr/GuiLua/test.lua5
-rw-r--r--ClientHamr/GuiLua/test_c.c177
3 files changed, 147 insertions, 54 deletions
diff --git a/ClientHamr/GuiLua/skang.lua b/ClientHamr/GuiLua/skang.lua
index c5c2096..6f06131 100644
--- a/ClientHamr/GuiLua/skang.lua
+++ b/ClientHamr/GuiLua/skang.lua
@@ -77,10 +77,12 @@ local versions = {
77 77
78-- Trying to capture best practices here for creating modules, especially since module() is broken and deprecated. 78-- Trying to capture best practices here for creating modules, especially since module() is broken and deprecated.
79-- TODO - Should parse in license type to. 79-- TODO - Should parse in license type to.
80moduleBegin = function (name, author, copyright, version, timestamp, skin) 80moduleBegin = function (name, author, copyright, version, timestamp, skin, isLua)
81 local _M = {} -- This is what we return to require(). 81 local _M = {} -- This is what we return to require().
82 local level = 2 82 local level = 2
83 83
84 if 'nil' == type(isLua) then isLua = true end
85
84 package.loaded[name] = _M -- Stuff the result into where require() can find it, instead of returning it at the end. 86 package.loaded[name] = _M -- Stuff the result into where require() can find it, instead of returning it at the end.
85 -- Returning it at the end does the same thing. 87 -- Returning it at the end does the same thing.
86 -- This is so that we can have all the module stuff at the top, in this function. 88 -- This is so that we can have all the module stuff at the top, in this function.
@@ -102,6 +104,7 @@ moduleBegin = function (name, author, copyright, version, timestamp, skin)
102 _M._M = _M -- So that references to _M below the setfenv() actually go to the real _M. 104 _M._M = _M -- So that references to _M below the setfenv() actually go to the real _M.
103 _M._NAME = name 105 _M._NAME = name
104 _M._PACKAGE = string.gsub(_M._NAME, "[^.]*$", "") -- Strip the name down to the package name. 106 _M._PACKAGE = string.gsub(_M._NAME, "[^.]*$", "") -- Strip the name down to the package name.
107 _M.isLua = isLua
105 108
106 -- Parse in an entire copyright message, and strip that down into bits, to put back together. 109 -- Parse in an entire copyright message, and strip that down into bits, to put back together.
107 local date, owner = string.match(copyright, '[Cc]opyright (%d%d%d%d) (.*)') 110 local date, owner = string.match(copyright, '[Cc]opyright (%d%d%d%d) (.*)')
@@ -129,12 +132,15 @@ moduleBegin = function (name, author, copyright, version, timestamp, skin)
129 132
130 setmetatable(_M, Thing) 133 setmetatable(_M, Thing)
131 _M.savedEnvironment = savedEnvironment 134 _M.savedEnvironment = savedEnvironment
132 -- setfenv() sets the environment for the FUNCTION, stack level deep. 135 -- NOTE - setfenv() wont work if the environment it refers to is a C function. Worse, getfenv() returns the global environment, so we can't tell.
133 -- The number is the stack level - 136 if isLua then
134 -- 0 running thread, 1 current function, 2 function that called this function, etc 137 -- setfenv() sets the environment for the FUNCTION, stack level deep.
135 setfenv(level, _M) -- Use the result for the modules internal global environment, so they don't need to qualify internal names. 138 -- The number is the stack level -
139 -- 0 running thread, 1 current function, 2 function that called this function, etc
140 setfenv(level, _M) -- Use the result for the modules internal global environment, so they don't need to qualify internal names.
136 -- Dunno if this causes problems with the do ... end style of joining modules. It does. So we need to restore in moduleEnd(). 141 -- Dunno if this causes problems with the do ... end style of joining modules. It does. So we need to restore in moduleEnd().
137 -- Next question, does this screw with the environment of the skang module? No it doesn't, coz that's set up at require 'skang' time. 142 -- Next question, does this screw with the environment of the skang module? No it doesn't, coz that's set up at require 'skang' time.
143 end
138 144
139 print('Loaded module ' .. _M._NAME .. ' version ' .. _M.VERSION .. ', ' .. _M.COPYRIGHT .. '.\n ' .. _M.VERSION_DESC) 145 print('Loaded module ' .. _M._NAME .. ' version ' .. _M.VERSION .. ', ' .. _M.COPYRIGHT .. '.\n ' .. _M.VERSION_DESC)
140 146
@@ -146,7 +152,7 @@ moduleEnd = function (module)
146 -- TODO - Look for _NAME.properties, and load it into the modules Things. 152 -- TODO - Look for _NAME.properties, and load it into the modules Things.
147 -- TODO - Parse command line parameters at some point. 153 -- TODO - Parse command line parameters at some point.
148 -- http://stackoverflow.com/questions/3745047/help-locate-c-sample-code-to-read-lua-command-line-arguments 154 -- http://stackoverflow.com/questions/3745047/help-locate-c-sample-code-to-read-lua-command-line-arguments
149 setfenv(2, module.savedEnvironment) 155 if module.isLua then setfenv(2, module.savedEnvironment) end
150end 156end
151 157
152-- Call this now so that from now on, this is like any other module. 158-- Call this now so that from now on, this is like any other module.
@@ -424,6 +430,7 @@ thing = function (names, ...)
424 thing.required = params[5] or thing.required 430 thing.required = params[5] or thing.required
425 thing.acl = params[6] or thing.acl 431 thing.acl = params[6] or thing.acl
426 thing.boss = params[7] or thing.boss 432 thing.boss = params[7] or thing.boss
433 thing.module = params[8] or thing.module -- Mostly for things like C functions, where get/setfenv() wont do what we need.
427 434
428 -- PUll out named arguments. 435 -- PUll out named arguments.
429 for k, v in pairs(params) do 436 for k, v in pairs(params) do
diff --git a/ClientHamr/GuiLua/test.lua b/ClientHamr/GuiLua/test.lua
index 3c2e9ab..d566354 100644
--- a/ClientHamr/GuiLua/test.lua
+++ b/ClientHamr/GuiLua/test.lua
@@ -49,10 +49,11 @@ local skang = require 'skang'
49local test = require 'test' 49local test = require 'test'
50local test_c = require 'test_c' 50local test_c = require 'test_c'
51 51
52print('foo = ' .. test.foo .. ' ->> ' .. skang.things.foo.help)
53print('End ' .. test.bar .. ' ' .. test.VERSION .. ' ' .. skang.things.ffunc.help .. ' ->> ' .. skang.things.f.action) 52print('End ' .. test.bar .. ' ' .. test.VERSION .. ' ' .. skang.things.ffunc.help .. ' ->> ' .. skang.things.f.action)
53print('foo = ' .. test.foo .. ' ->> ' .. skang.things.foo.help)
54print('cfunc ->> ' .. skang.things.cfunc.help)
54test.ffunc('one', 2) 55test.ffunc('one', 2)
55test_c.ffunc(0, 'zero') 56test_c.cfunc(0, 'zero')
56--skang.things.ffunc('seven', 'aight') 57--skang.things.ffunc('seven', 'aight')
57print('') 58print('')
58 59
diff --git a/ClientHamr/GuiLua/test_c.c b/ClientHamr/GuiLua/test_c.c
index 8d3ab81..e3fd801 100644
--- a/ClientHamr/GuiLua/test_c.c
+++ b/ClientHamr/GuiLua/test_c.c
@@ -8,9 +8,6 @@ http://lua.2524044.n2.nabble.com/C-Lua-modules-not-compatible-with-every-Lua-int
8http://lua-users.org/wiki/LuaProxyDllFour 8http://lua-users.org/wiki/LuaProxyDllFour
9http://stackoverflow.com/questions/11492194/how-do-you-create-a-lua-plugin-that-calls-the-c-lua-api?rq=1 9http://stackoverflow.com/questions/11492194/how-do-you-create-a-lua-plugin-that-calls-the-c-lua-api?rq=1
10http://lua-users.org/lists/lua-l/2008-01/msg00671.html 10http://lua-users.org/lists/lua-l/2008-01/msg00671.html
11
12
13
14*/ 11*/
15 12
16 13
@@ -19,72 +16,160 @@ http://lua-users.org/lists/lua-l/2008-01/msg00671.html
19//#include <lualib.h> 16//#include <lualib.h>
20 17
21 18
22static int ffunc (lua_State *L) 19static const char *ourName = "test_c";
20int skang, _M;
21
22static int cfunc (lua_State *L)
23{ 23{
24 double arg1 = luaL_checknumber(L, 1); 24 double arg1 = luaL_checknumber(L, 1);
25 const char *arg2 = luaL_checkstring(L, 2); 25 const char *arg2 = luaL_checkstring(L, 2);
26 26
27 printf("Inside test_c.ffunc(%f, %s)\n", arg1, arg2); 27 printf("Inside %s.cfunc(%f, %s)\n", ourName, arg1, arg2);
28 return 0; 28 return 0;
29} 29}
30 30
31 31
32static const struct luaL_reg test_c [] = 32static void dumpStack(lua_State *L, int i)
33{ 33{
34 {"ffunc", ffunc}, 34 int type = lua_type(L, i);
35 {NULL, NULL} 35
36}; 36 switch (type)
37 37 {
38 case LUA_TNONE : printf("Stack %d is empty\n", i); break;
39 case LUA_TNIL : printf("Stack %d is a nil\n", i); break;
40 case LUA_TBOOLEAN : printf("Stack %d is a boolean\n", i); break;
41 case LUA_TNUMBER : printf("Stack %d is a number\n", i); break;
42 case LUA_TSTRING : printf("Stack %d is a string - %s\n", i, lua_tostring(L, i)); break;
43 case LUA_TFUNCTION : printf("Stack %d is a function\n", i); break;
44 case LUA_TTHREAD : printf("Stack %d is a thread\n", i); break;
45 case LUA_TTABLE : printf("Stack %d is a table\n", i); break;
46 case LUA_TUSERDATA : printf("Stack %d is a userdata\n", i); break;
47 case LUA_TLIGHTUSERDATA : printf("Stack %d is a light userdata\n", i); break;
48 default : printf("Stack %d is unknown\n", i); break;
49 }
50}
38 51
39/* local test_c = require 'test_c' 52/* local test_c = require 'test_c'
40 53
41Lua's require() function will strip any stuff from the front of the name 54Lua's require() function will strip any stuff from the front of the name
42separated by a hypen, so 'GuiLua-test_c' -> 'test_c'. Then it will 55separated by a hyphen, so 'GuiLua-test_c' -> 'test_c'. Then it will
43search through a path, and eventually find this test_c.so (or test_c.dll 56search through a path, and eventually find this test_c.so (or test_c.dll
44or whatever), then call luaopen_test_c(), which should return a table. 57or whatever), then call luaopen_test_c(), which should return a table.
58The argument (only thing on the stack) for this function will be
59'test_c'.
45 60
46Normally luaL_register() creates a table of functions, that is the table 61Normally luaL_register() creates a table of functions, that is the table
47returned, but we want to do something different with skang. 62returned, but we want to do something different with skang.
48
49*/ 63*/
50int luaopen_test_c(lua_State *L) 64int luaopen_test_c(lua_State *L)
51{ 65{
52// This is a moving target, old ways get deperecated, new ways get added,
53// would have to check version before doing any of these.
54// luaL_openlib(L, "test_c", test_c, 0); // Lua 5.0 way.
55// luaL_register (L, "test_c", test_c); // Lua 5.1 way.
56// luaL_newlib() or luaL_setfuncs() // Lua 5.2 way.
57 // Creates a global table "test_c", does the package.loaded[test_c] thing.
58 lua_newtable(L);
59 luaL_register (L, NULL, test_c); // Lua 5.1 way.
60 // Puts the funcions in a table on top of the stack.
61
62/* BUT REALLY ...
63
64We are in fact NOT putting any functions into the returned table.
65
66skang.moduleBegin() returns the table we need to send back to Lua.
67 it saves getfenv(2) as the old environment, which should in theory be L
68 and setfenv(_M, 2) to set the tbale to be it's own environment
69 it does the package.loaded[test_c] thing for us
70 it returns the table it created, so we should just leave that on the stack as our result
71
72skang.thing() also uses getfenv(2) to grab the module's table
73 66
67 // In theory, the only thing on the stack now is 'test_c' from the require() call.
68
69// pseudo-indices, special tables that can be accessed like the stack -
70// LUA_GLOBALSINDEX - thread environment, where globals are
71// LUA_ENVIRONINDEX - C function environment, in this case luaopen_test_c() is the C function
72// LUA_REGISTRYINDEX - C registry, global, for unique keys use the module name as a string, or a lightuserdata address to a C object in our module.
73// lua_upvalueindex(n) - C function upvalues
74
75// The only locals we care about are skang and _M.
76// All modules go into package.loaded[name] as well.
77// skang is essentially a global anyway.
78// _M we pass back as the result, and our functions get added to it by skang.thing()
79// Not entirely true, skang.things is a proxy table, skang.things.ffunc.func would be our function.
80// skang.things.ffunc.module is our _M ('environment of our calling function', so that's the 'environment' right here, since we call skang.thing().
81// test_c.ffunc() -> test_c.__index(test_c, 'ffunc') -> skang.things[ffunc].value() -> test_c.c->ffunc()
82// this is a C function, not a Lua function
83
84// local skang = require 'skang'
85 lua_getglobal(L, "require");
86 lua_pushstring(L, "skang");
87 lua_call(L, 1, 1);
88 skang = lua_gettop(L);
89// dumpStack(L, skang);
90
91// local _M = skang.moduleBegin('test_c', nil, 'Copyright 2014 David Seikel', '0.1', '2014-03-27 03:57:00', nil, true)
92 lua_getfield(L, skang, "moduleBegin");
93 lua_pushstring(L, ourName);
94 lua_pushnil(L); // Author comes from copyright.
95 lua_pushstring(L, "Copyright 2014 David Seikel");
96 lua_pushstring(L, "0.1");
97 lua_pushstring(L, "2014-03-27 03:57:00");
98 lua_pushnil(L); // No skin.
99 lua_pushboolean(L, 0); // We are not a Lua module.
100 lua_call(L, 7, 1); // call 'skang.moduleBegin' with 7 arguments and 1 result.
101 _M = lua_gettop(L);
102// dumpStack(L, _M);
103
104 // At this point the stack should be - 'test_c', skang, _M. Let's test that.
105/*
106 int top = 0, i;
107
108 top = lua_gettop(L);
109 printf("MODULE test_c has %d stack items.\n", top);
110 for (i = 1; i <= top; i++)
111 dumpStack(L, i);
74*/ 112*/
75 113
76/* TODO - load skang, create things, etc. 114 // Save this module in the C registry.
77 115 lua_setfield(L, LUA_REGISTRYINDEX, ourName);
78local skang = require "skang" 116
79local _M = skang.moduleBegin("test_c", nil, "Copyright 2014 David Seikel", "0.1", "2014-03-27 03:57:00") 117// skang.thing('cfooble,c', 'Help text goes here', 1, 'number', \"'edit', 'The fooble:', 1, 1, 10, 50\", true)
118 lua_getfield(L, skang, "thing");
119 lua_pushstring(L, "cfooble,c");
120 lua_pushstring(L, "Help text");
121 lua_pushnumber(L, 1);
122 lua_pushstring(L, "number");
123 lua_pushstring(L, "'edit', 'The cfooble:', 1, 1, 10, 50");
124 lua_pushboolean(L, 1); // Is required.
125 lua_pushnil(L); // Default ACL.
126 lua_pushnil(L); // No boss.
127 lua_getfield(L, LUA_REGISTRYINDEX, ourName); // Coz getfenv() can't find C environment.
128 lua_call(L, 9, 0);
129
130// skang.thing('cbar', 'Help text', 'Default')
131 lua_getfield(L, skang, "thing");
132 lua_pushstring(L, "cbar");
133 lua_pushstring(L, "Help text");
134 lua_pushstring(L, "Default");
135 lua_pushnil(L); // No type.
136 lua_pushnil(L); // No widget.
137 lua_pushnil(L); // Not required.
138 lua_pushnil(L); // Default ACL.
139 lua_pushnil(L); // No boss.
140 lua_getfield(L, LUA_REGISTRYINDEX, ourName); // Coz getfenv() can't find C environment.
141 lua_call(L, 9, 0);
142
143// skang.thing('cfoo')
144 lua_getfield(L, skang, "thing");
145 lua_pushstring(L, "cfoo");
146 lua_pushnil(L); // No help.
147 lua_pushnil(L); // No default.
148 lua_pushnil(L); // No type.
149 lua_pushnil(L); // No widget.
150 lua_pushnil(L); // Not required.
151 lua_pushnil(L); // Default ACL.
152 lua_pushnil(L); // No boss.
153 lua_getfield(L, LUA_REGISTRYINDEX, ourName); // Coz getfenv() can't find C environment.
154 lua_call(L, 9, 0);
155
156// skang.thing('cfunc', 'Help Text', ffunc, 'number,string')
157 lua_getfield(L, skang, "thing");
158 lua_pushstring(L, "cfunc");
159 lua_pushstring(L, "cfunc does nothing really");
160 lua_pushcfunction(L, cfunc);
161 lua_pushstring(L, "number,string");
162 lua_pushnil(L); // No widget.
163 lua_pushnil(L); // Not required.
164 lua_pushnil(L); // Default ACL.
165 lua_pushnil(L); // No boss.
166 lua_getfield(L, LUA_REGISTRYINDEX, ourName); // Coz getfenv() can't find C environment.
167 lua_call(L, 9, 0);
168
169// skang.moduleEnd(_M)
170 lua_getfield(L, skang, "moduleEnd");
171 lua_getfield(L, LUA_REGISTRYINDEX, ourName);
172 lua_call(L, 1, 1);
80 173
81skang.thing("fooble,f", "Help text goes here", 1, "number", "'edit', 'The fooble:', 1, 1, 10, 50", true)
82skang.thing("bar", "Help text", "Default")
83skang.thing("foo")
84skang.thing("ffunc", "Help Text", ffunc, "number,string")
85
86skang.moduleEnd(_M)
87
88*/
89 return 1; 174 return 1;
90} 175}