]> git.lizzy.rs Git - metalua.git/blob - src/binlibs/rings.c
94a8cb83b96f941417e59f4926df1e112e225d32
[metalua.git] / src / binlibs / rings.c
1 /*
2 ** Rings: Multiple Lua States
3 ** $Id: rings.c,v 1.7 2007/06/11 23:36:37 carregal Exp $
4 ** See Copyright Notice in license.html
5 */
6
7 #include "string.h"
8
9 #include "lua.h"
10 #include "lualib.h"
11 #include "lauxlib.h"
12
13
14 #define RINGS_TABLENAME "rings"
15 #define RINGS_CACHE     "rings cache"
16 #define STATE_METATABLE "state metatable"
17
18
19 typedef struct {
20         lua_State *L;
21 } state_data;
22
23
24 LUALIB_API int luaopen_rings (lua_State *L);
25
26
27 /*
28 ** Get a State object from the first call stack position.
29 */
30 static state_data *getstate (lua_State *L) {
31         state_data *s = (state_data *)luaL_checkudata (L, 1, STATE_METATABLE);
32         luaL_argcheck (L, s != NULL, 1, "not a Lua State");
33         luaL_argcheck (L, s->L, 1, "already closed state");
34         return s;
35 }
36
37
38 /*
39 **
40 */
41 static int state_tostring (lua_State *L) {
42         state_data *s = (state_data *)luaL_checkudata (L, 1, STATE_METATABLE);
43         lua_pushfstring (L, "Lua State (%p)", s);
44         return 1;
45 }
46
47
48 /*
49 ** Copies values from State src to State dst.
50 */
51 static void copy_values (lua_State *dst, lua_State *src, int i, int top) {
52         for (; i <= top; i++) {
53                 switch (lua_type (src, i)) {
54                         case LUA_TNUMBER:
55                                 lua_pushnumber (dst, lua_tonumber (src, i));
56                                 break;
57                         case LUA_TBOOLEAN:
58                                 lua_pushboolean (dst, lua_toboolean (src, i));
59                                 break;
60                         case LUA_TSTRING: {
61                                 const char *string = lua_tostring (src, i);
62                                 size_t length = lua_strlen (src, i);
63                                 lua_pushlstring (dst, string, length);
64                                 break;
65                         }
66                         case LUA_TUSERDATA:
67                         case LUA_TLIGHTUSERDATA: {
68                                 lua_pushlightuserdata (dst, lua_touserdata (src, i));
69                                 break;
70                         }
71                         case LUA_TNIL:
72                         default:
73                                 lua_pushnil (dst);
74                                 break;
75                 }
76         }
77 }
78
79
80 /*
81 ** Obtains a function which is the compiled string in the given state.
82 ** It also caches the resulting function to optimize future uses.
83 ** Leaves the compiled function on top of the stack or the error message
84 ** produced by luaL_loadbuffer.
85 */
86 static int compile_string (lua_State *L, const char *str) {
87         lua_pushliteral (L, RINGS_CACHE);
88         lua_gettable (L, LUA_REGISTRYINDEX); /* push cache table */
89         lua_pushstring (L, str);
90         lua_gettable (L, -2); /* cache[str] */
91         if (!lua_isfunction (L, -1)) {
92                 int status;
93                 lua_pop (L, 1); /* remove cache[str] (= nil) from top of the stack */
94                 status = luaL_loadbuffer (L, str, strlen(str), str); /* Compile */
95                 if (status != 0) { /* error? */
96                         lua_remove (L, -2); /* removes cache table; leaves the error message */
97                         return status;
98                 }
99                 /* Stores the produced function at cache[str] */
100                 lua_pushstring (L, str);
101                 lua_pushvalue (L, -2);
102                 lua_settable (L, -4); /* cache[str] = func */
103         }
104         lua_remove (L, -2); /* removes cache table; leaves the function */
105         return 0;
106 }
107
108
109 /*
110 ** Executes a string of code from State src into State dst.
111 ** idx is the index of the string of code.
112 */
113 static int dostring (lua_State *dst, lua_State *src, int idx) {
114         const char *str = luaL_checkstring (src, idx);
115         int base = lua_gettop (dst);
116         idx++; /* ignore first argument (string of code) */
117         if (compile_string (dst, str) == 0) { /* Compile OK? => push function */
118                 int arg_top = lua_gettop (src);
119                 copy_values (dst, src, idx, arg_top); /* Push arguments to dst stack */
120                 if (lua_pcall (dst, arg_top-idx+1, LUA_MULTRET, 0) == 0) { /* run OK? */
121                         int ret_top = lua_gettop (dst);
122                         lua_pushboolean (src, 1); /* Push status = OK */
123                         copy_values (src, dst, base+1, ret_top); /* Return values to src */
124                         lua_pop (dst, ret_top-base);
125                         return 1+(ret_top-base); /* Return true (success) plus return values */
126                 }
127         }
128         lua_pushboolean (src, 0); /* Push status = ERR */
129         lua_pushstring (src, lua_tostring (dst, -1));
130         lua_pop (dst, 1); /* pops result from dst state */
131         return 2;
132 }
133
134
135 /*
136 ** Executes a string of Lua code in the master state.
137 */
138 static int master_dostring (lua_State *S) {
139         lua_State *M = (lua_State *)lua_touserdata (S, lua_upvalueindex (1));
140         return dostring (M, S, 1);
141 }
142
143
144 /*
145 ** Executes a string of Lua code in a given slave state.
146 */
147 static int slave_dostring (lua_State *M) {
148         state_data *s = getstate (M); /* S == s->L */
149         return dostring (s->L, M, 2);
150 }
151
152
153 /*
154 ** Creates a weak table in the registry.
155 */
156 static void create_cache (lua_State *L) {
157         lua_pushliteral (L, RINGS_CACHE);
158         lua_newtable (L);
159         lua_newtable (L); /* cache metatable */
160         lua_pushliteral (L, "__mode");
161         lua_pushliteral (L, "kv");
162         lua_settable (L, -3); /* metatable.__mode = "kv" */
163         lua_setmetatable (L, -2);
164         lua_settable (L, LUA_REGISTRYINDEX);
165 }
166
167
168 /*
169 ** Creates a new Lua State and returns an userdata that represents it.
170 */
171 static int state_new (lua_State *L) {
172         state_data *s = (state_data *)lua_newuserdata (L, sizeof (state_data));
173         s->L = NULL;
174         luaL_getmetatable (L, STATE_METATABLE);
175         lua_setmetatable (L, -2);
176         s->L = lua_open ();
177
178         /* load base libraries */
179         luaL_openlibs(s->L);
180
181         /* define dostring function (which runs strings on the master state) */
182         lua_pushliteral (s->L, "remotedostring");
183         lua_pushlightuserdata (s->L, L);
184         lua_pushcclosure (s->L, master_dostring, 1);
185         lua_settable (s->L, LUA_GLOBALSINDEX);
186
187         create_cache (s->L);
188
189         return 1;
190 }
191
192
193 /*
194 ** Closes a Lua State.
195 ** Returns `true' in case of success; `nil' when the state was already closed.
196 */
197 static int slave_close (lua_State *L) {
198         state_data *s = (state_data *)luaL_checkudata (L, 1, STATE_METATABLE);
199         luaL_argcheck (L, s != NULL, 1, "not a Lua State");
200         if (s->L == NULL)
201                 return 0;
202         lua_close (s->L);
203         s->L = NULL;
204         lua_pushboolean (L, 1);
205         return 1;
206 }
207
208
209 /*
210 ** Creates the metatable for the state on top of the stack.
211 */
212 static int state_createmetatable (lua_State *L) {
213         /* State methods */
214         struct luaL_reg methods[] = {
215                 {"close", slave_close},
216                 {"dostring", slave_dostring},
217                 {NULL, NULL},
218         };
219         /* State metatable */
220         if (!luaL_newmetatable (L, STATE_METATABLE)) {
221                 return 0;
222         }
223         /* define methods */
224         luaL_openlib (L, NULL, methods, 0);
225         /* define metamethods */
226         lua_pushliteral (L, "__gc");
227         lua_pushcfunction (L, slave_close);
228         lua_settable (L, -3);
229
230         lua_pushliteral (L, "__index");
231         lua_pushvalue (L, -2);
232         lua_settable (L, -3);
233
234         lua_pushliteral (L, "__tostring");
235         lua_pushcfunction (L, state_tostring);
236         lua_settable (L, -3);
237
238         lua_pushliteral (L, "__metatable");
239         lua_pushliteral (L, "You're not allowed to get the metatable of a Lua State");
240         lua_settable (L, -3);
241         return 1;
242 }
243
244
245 /*
246 **
247 */
248 static void set_info (lua_State *L) {
249         lua_pushliteral (L, "_COPYRIGHT");
250         lua_pushliteral (L, "Copyright (C) 2006-2007 Kepler Project");
251         lua_settable (L, -3);
252         lua_pushliteral (L, "_DESCRIPTION");
253         lua_pushliteral (L, "Rings: Multiple Lua States");
254         lua_settable (L, -3);    lua_pushliteral (L, "_VERSION");
255         lua_pushliteral (L, "Rings 1.1.0");
256         lua_settable (L, -3);
257 }
258
259
260 /*
261 ** Opens library.
262 */
263 LUALIB_API int luaopen_rings (lua_State *L) {
264         /* Library functions */
265         struct luaL_reg rings[] = {
266                 {"new", state_new},
267                 {NULL, NULL},
268         };
269         if (!state_createmetatable (L))
270                 return 0;
271         lua_pop (L, 1);
272         /* define library functions */
273         luaL_openlib (L, RINGS_TABLENAME, rings, 0);
274         create_cache (L);
275         set_info (L);
276
277         return 1;
278 }