Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5205 | clevermous | 1 | /* |
2 | ** $Id: ldblib.c,v 1.131 2011/10/24 14:54:05 roberto Exp $ |
||
3 | ** Interface from Lua to its debug API |
||
4 | ** See Copyright Notice in lua.h |
||
5 | */ |
||
6 | |||
7 | |||
8 | #include |
||
9 | #include |
||
10 | #include |
||
11 | |||
12 | #define ldblib_c |
||
13 | #define LUA_LIB |
||
14 | |||
15 | #include "lua.h" |
||
16 | |||
17 | #include "lauxlib.h" |
||
18 | #include "lualib.h" |
||
19 | |||
20 | |||
21 | #define HOOKKEY "_HKEY" |
||
22 | |||
23 | |||
24 | |||
25 | static int db_getregistry (lua_State *L) { |
||
26 | lua_pushvalue(L, LUA_REGISTRYINDEX); |
||
27 | return 1; |
||
28 | } |
||
29 | |||
30 | |||
31 | static int db_getmetatable (lua_State *L) { |
||
32 | luaL_checkany(L, 1); |
||
33 | if (!lua_getmetatable(L, 1)) { |
||
34 | lua_pushnil(L); /* no metatable */ |
||
35 | } |
||
36 | return 1; |
||
37 | } |
||
38 | |||
39 | |||
40 | static int db_setmetatable (lua_State *L) { |
||
41 | int t = lua_type(L, 2); |
||
42 | luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, |
||
43 | "nil or table expected"); |
||
44 | lua_settop(L, 2); |
||
45 | lua_setmetatable(L, 1); |
||
46 | return 1; /* return 1st argument */ |
||
47 | } |
||
48 | |||
49 | |||
50 | static int db_getuservalue (lua_State *L) { |
||
51 | if (lua_type(L, 1) != LUA_TUSERDATA) |
||
52 | lua_pushnil(L); |
||
53 | else |
||
54 | lua_getuservalue(L, 1); |
||
55 | return 1; |
||
56 | } |
||
57 | |||
58 | |||
59 | static int db_setuservalue (lua_State *L) { |
||
60 | if (lua_type(L, 1) == LUA_TLIGHTUSERDATA) |
||
61 | luaL_argerror(L, 1, "full userdata expected, got light userdata"); |
||
62 | luaL_checktype(L, 1, LUA_TUSERDATA); |
||
63 | if (!lua_isnoneornil(L, 2)) |
||
64 | luaL_checktype(L, 2, LUA_TTABLE); |
||
65 | lua_settop(L, 2); |
||
66 | lua_setuservalue(L, 1); |
||
67 | return 1; |
||
68 | } |
||
69 | |||
70 | |||
71 | static void settabss (lua_State *L, const char *i, const char *v) { |
||
72 | lua_pushstring(L, v); |
||
73 | lua_setfield(L, -2, i); |
||
74 | } |
||
75 | |||
76 | |||
77 | static void settabsi (lua_State *L, const char *i, int v) { |
||
78 | lua_pushinteger(L, v); |
||
79 | lua_setfield(L, -2, i); |
||
80 | } |
||
81 | |||
82 | |||
83 | static void settabsb (lua_State *L, const char *i, int v) { |
||
84 | lua_pushboolean(L, v); |
||
85 | lua_setfield(L, -2, i); |
||
86 | } |
||
87 | |||
88 | |||
89 | static lua_State *getthread (lua_State *L, int *arg) { |
||
90 | if (lua_isthread(L, 1)) { |
||
91 | *arg = 1; |
||
92 | return lua_tothread(L, 1); |
||
93 | } |
||
94 | else { |
||
95 | *arg = 0; |
||
96 | return L; |
||
97 | } |
||
98 | } |
||
99 | |||
100 | |||
101 | static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { |
||
102 | if (L == L1) { |
||
103 | lua_pushvalue(L, -2); |
||
104 | lua_remove(L, -3); |
||
105 | } |
||
106 | else |
||
107 | lua_xmove(L1, L, 1); |
||
108 | lua_setfield(L, -2, fname); |
||
109 | } |
||
110 | |||
111 | |||
112 | static int db_getinfo (lua_State *L) { |
||
113 | lua_Debug ar; |
||
114 | int arg; |
||
115 | lua_State *L1 = getthread(L, &arg); |
||
116 | const char *options = luaL_optstring(L, arg+2, "flnStu"); |
||
117 | if (lua_isnumber(L, arg+1)) { |
||
118 | if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { |
||
119 | lua_pushnil(L); /* level out of range */ |
||
120 | return 1; |
||
121 | } |
||
122 | } |
||
123 | else if (lua_isfunction(L, arg+1)) { |
||
124 | lua_pushfstring(L, ">%s", options); |
||
125 | options = lua_tostring(L, -1); |
||
126 | lua_pushvalue(L, arg+1); |
||
127 | lua_xmove(L, L1, 1); |
||
128 | } |
||
129 | else |
||
130 | return luaL_argerror(L, arg+1, "function or level expected"); |
||
131 | if (!lua_getinfo(L1, options, &ar)) |
||
132 | return luaL_argerror(L, arg+2, "invalid option"); |
||
133 | lua_createtable(L, 0, 2); |
||
134 | if (strchr(options, 'S')) { |
||
135 | settabss(L, "source", ar.source); |
||
136 | settabss(L, "short_src", ar.short_src); |
||
137 | settabsi(L, "linedefined", ar.linedefined); |
||
138 | settabsi(L, "lastlinedefined", ar.lastlinedefined); |
||
139 | settabss(L, "what", ar.what); |
||
140 | } |
||
141 | if (strchr(options, 'l')) |
||
142 | settabsi(L, "currentline", ar.currentline); |
||
143 | if (strchr(options, 'u')) { |
||
144 | settabsi(L, "nups", ar.nups); |
||
145 | settabsi(L, "nparams", ar.nparams); |
||
146 | settabsb(L, "isvararg", ar.isvararg); |
||
147 | } |
||
148 | if (strchr(options, 'n')) { |
||
149 | settabss(L, "name", ar.name); |
||
150 | settabss(L, "namewhat", ar.namewhat); |
||
151 | } |
||
152 | if (strchr(options, 't')) |
||
153 | settabsb(L, "istailcall", ar.istailcall); |
||
154 | if (strchr(options, 'L')) |
||
155 | treatstackoption(L, L1, "activelines"); |
||
156 | if (strchr(options, 'f')) |
||
157 | treatstackoption(L, L1, "func"); |
||
158 | return 1; /* return table */ |
||
159 | } |
||
160 | |||
161 | |||
162 | static int db_getlocal (lua_State *L) { |
||
163 | int arg; |
||
164 | lua_State *L1 = getthread(L, &arg); |
||
165 | lua_Debug ar; |
||
166 | const char *name; |
||
167 | int nvar = luaL_checkint(L, arg+2); /* local-variable index */ |
||
168 | if (lua_isfunction(L, arg + 1)) { /* function argument? */ |
||
169 | lua_pushvalue(L, arg + 1); /* push function */ |
||
170 | lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ |
||
171 | return 1; |
||
172 | } |
||
173 | else { /* stack-level argument */ |
||
174 | if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ |
||
175 | return luaL_argerror(L, arg+1, "level out of range"); |
||
176 | name = lua_getlocal(L1, &ar, nvar); |
||
177 | if (name) { |
||
178 | lua_xmove(L1, L, 1); /* push local value */ |
||
179 | lua_pushstring(L, name); /* push name */ |
||
180 | lua_pushvalue(L, -2); /* re-order */ |
||
181 | return 2; |
||
182 | } |
||
183 | else { |
||
184 | lua_pushnil(L); /* no name (nor value) */ |
||
185 | return 1; |
||
186 | } |
||
187 | } |
||
188 | } |
||
189 | |||
190 | |||
191 | static int db_setlocal (lua_State *L) { |
||
192 | int arg; |
||
193 | lua_State *L1 = getthread(L, &arg); |
||
194 | lua_Debug ar; |
||
195 | if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ |
||
196 | return luaL_argerror(L, arg+1, "level out of range"); |
||
197 | luaL_checkany(L, arg+3); |
||
198 | lua_settop(L, arg+3); |
||
199 | lua_xmove(L, L1, 1); |
||
200 | lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); |
||
201 | return 1; |
||
202 | } |
||
203 | |||
204 | |||
205 | static int auxupvalue (lua_State *L, int get) { |
||
206 | const char *name; |
||
207 | int n = luaL_checkint(L, 2); |
||
208 | luaL_checktype(L, 1, LUA_TFUNCTION); |
||
209 | name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); |
||
210 | if (name == NULL) return 0; |
||
211 | lua_pushstring(L, name); |
||
212 | lua_insert(L, -(get+1)); |
||
213 | return get + 1; |
||
214 | } |
||
215 | |||
216 | |||
217 | static int db_getupvalue (lua_State *L) { |
||
218 | return auxupvalue(L, 1); |
||
219 | } |
||
220 | |||
221 | |||
222 | static int db_setupvalue (lua_State *L) { |
||
223 | luaL_checkany(L, 3); |
||
224 | return auxupvalue(L, 0); |
||
225 | } |
||
226 | |||
227 | |||
228 | static int checkupval (lua_State *L, int argf, int argnup) { |
||
229 | lua_Debug ar; |
||
230 | int nup = luaL_checkint(L, argnup); |
||
231 | luaL_checktype(L, argf, LUA_TFUNCTION); |
||
232 | lua_pushvalue(L, argf); |
||
233 | lua_getinfo(L, ">u", &ar); |
||
234 | luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index"); |
||
235 | return nup; |
||
236 | } |
||
237 | |||
238 | |||
239 | static int db_upvalueid (lua_State *L) { |
||
240 | int n = checkupval(L, 1, 2); |
||
241 | lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); |
||
242 | return 1; |
||
243 | } |
||
244 | |||
245 | |||
246 | static int db_upvaluejoin (lua_State *L) { |
||
247 | int n1 = checkupval(L, 1, 2); |
||
248 | int n2 = checkupval(L, 3, 4); |
||
249 | luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); |
||
250 | luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); |
||
251 | lua_upvaluejoin(L, 1, n1, 3, n2); |
||
252 | return 0; |
||
253 | } |
||
254 | |||
255 | |||
256 | #define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY); |
||
257 | |||
258 | |||
259 | static void hookf (lua_State *L, lua_Debug *ar) { |
||
260 | static const char *const hooknames[] = |
||
261 | {"call", "return", "line", "count", "tail call"}; |
||
262 | gethooktable(L); |
||
263 | lua_rawgetp(L, -1, L); |
||
264 | if (lua_isfunction(L, -1)) { |
||
265 | lua_pushstring(L, hooknames[(int)ar->event]); |
||
266 | if (ar->currentline >= 0) |
||
267 | lua_pushinteger(L, ar->currentline); |
||
268 | else lua_pushnil(L); |
||
269 | lua_assert(lua_getinfo(L, "lS", ar)); |
||
270 | lua_call(L, 2, 0); |
||
271 | } |
||
272 | } |
||
273 | |||
274 | |||
275 | static int makemask (const char *smask, int count) { |
||
276 | int mask = 0; |
||
277 | if (strchr(smask, 'c')) mask |= LUA_MASKCALL; |
||
278 | if (strchr(smask, 'r')) mask |= LUA_MASKRET; |
||
279 | if (strchr(smask, 'l')) mask |= LUA_MASKLINE; |