monotone

monotone Mtn Source Tree

Root/lua.cc

1
2#include "config.h"
3
4#include "lua.hh"
5
6#include "globish.hh"
7#include "sanity.hh"
8
9#include <string>
10#include <set>
11#include <vector>
12#include <utility>
13
14#include <boost/filesystem/path.hpp>
15#include <boost/filesystem/operations.hpp>
16#include <boost/regex.hpp>
17
18using std::pair;
19using std::set;
20using std::sort;
21using std::string;
22using std::vector;
23using std::strerror;
24using std::malloc;
25using std::free;
26namespace fs = boost::filesystem;
27
28// adapted from "programming in lua", section 24.2.3
29// http://www.lua.org/pil/24.2.3.html
30// output is from bottom (least accessible) to top (most accessible, where
31// push and pop happen).
32static string
33dump_stack(lua_State * st)
34{
35 string out;
36 int i;
37 int top = lua_gettop(st);
38 for (i = 1; i <= top; i++) { /* repeat for each level */
39 int t = lua_type(st, i);
40 switch (t) {
41 case LUA_TSTRING: /* strings */
42 out += '`';
43 out += string(lua_tostring(st, i), lua_strlen(st, i));
44 out += '\'';
45 break;
46
47 case LUA_TBOOLEAN: /* booleans */
48 out += (lua_toboolean(st, i) ? "true" : "false");
49 break;
50
51 case LUA_TNUMBER: /* numbers */
52 out += (FL("%g") % lua_tonumber(st, i)).str();
53 break;
54
55 default: /* other values */
56 out += std::string(lua_typename(st, t));
57 break;
58
59 }
60 out += " "; /* put a separator */
61 }
62 return out;
63}
64
65
66Lua::Lua(lua_State * s) :
67 st(s), failed(false)
68{}
69
70Lua::~Lua()
71{
72 lua_settop(st, 0);
73}
74
75void
76Lua::fail(string const & reason)
77{
78 L(FL("lua failure: %s; stack = %s") % reason % dump_stack(st));
79 failed = true;
80}
81
82bool
83Lua::ok()
84{
85 if (failed)
86 L(FL("Lua::ok(): failed"));
87 return !failed;
88}
89
90void
91Lua::report_error()
92{
93// I(lua_isstring(st, -1));
94 string err = string(lua_tostring(st, -1), lua_strlen(st, -1));
95 W(i18n_format("%s") % err);
96 L(FL("lua stack: %s") % dump_stack(st));
97 lua_pop(st, 1);
98 failed = true;
99}
100
101// getters
102
103Lua &
104Lua::get(int idx)
105{
106 if (failed) return *this;
107 if (!lua_istable (st, idx))
108 {
109 fail("istable() in get");
110 return *this;
111 }
112 if (lua_gettop (st) < 1)
113 {
114 fail("stack top > 0 in get");
115 return *this;
116 }
117 lua_gettable(st, idx);
118 return *this;
119}
120
121Lua &
122Lua::get_fn(int idx)
123{
124 if (failed) return *this;
125 get(idx);
126 if (!lua_isfunction (st, -1))
127 fail("isfunction() in get_fn");
128 return *this;
129}
130
131Lua &
132Lua::get_tab(int idx)
133{
134 if (failed) return *this;
135 get(idx);
136 if (!lua_istable (st, -1))
137 fail("istable() in get_tab");
138 return *this;
139}
140
141Lua &
142Lua::get_str(int idx)
143{
144 if (failed) return *this;
145 get(idx);
146 if (!lua_isstring (st, -1))
147 fail("isstring() in get_str");
148 return *this;
149}
150
151Lua &
152Lua::get_num(int idx)
153{
154 if (failed) return *this;
155 get(idx);
156 if (!lua_isnumber (st, -1))
157 fail("isnumber() in get_num");
158 return *this;
159}
160
161Lua &
162Lua::get_bool(int idx)
163{
164 if (failed) return *this;
165 get(idx);
166 if (!lua_isboolean (st, -1))
167 fail("isboolean() in get_bool");
168 return *this;
169}
170
171// extractors
172
173Lua &
174Lua::extract_str_nolog(string & str)
175{
176 if (failed) return *this;
177 if (!lua_isstring (st, -1))
178 {
179 fail("isstring() in extract_str");
180 return *this;
181 }
182 str = string(lua_tostring(st, -1), lua_strlen(st, -1));
183 return *this;
184}
185
186Lua &
187Lua::extract_str(string & str)
188{
189 extract_str_nolog(str);
190 L(FL("lua: extracted string = %s") % str);
191 return *this;
192}
193
194Lua &
195Lua::extract_classified_str(string & str)
196{
197 extract_str_nolog(str);
198 L(FL("lua: extracted string [CLASSIFIED]"));
199 return *this;
200}
201
202Lua &
203Lua::extract_int(int & i)
204{
205 if (failed) return *this;
206 if (!lua_isnumber (st, -1))
207 {
208 fail("isnumber() in extract_int");
209 return *this;
210 }
211 i = lua_tointeger(st, -1);
212 L(FL("lua: extracted int = %i") % i);
213 return *this;
214}
215
216Lua &
217Lua::extract_double(double & i)
218{
219 if (failed) return *this;
220 if (!lua_isnumber (st, -1))
221 {
222 fail("isnumber() in extract_double");
223 return *this;
224 }
225 i = lua_tonumber(st, -1);
226 L(FL("lua: extracted double = %i") % i);
227 return *this;
228}
229
230
231Lua &
232Lua::extract_bool(bool & i)
233{
234 if (failed) return *this;
235 if (!lua_isboolean (st, -1))
236 {
237 fail("isboolean() in extract_bool");
238 return *this;
239 }
240 i = (lua_toboolean(st, -1) == 1);
241 L(FL("lua: extracted bool = %i") % i);
242 return *this;
243}
244
245
246// table iteration
247
248Lua &
249Lua::begin()
250{
251 if (failed) return *this;
252 if (!lua_istable(st, -1))
253 {
254 fail("istable() in begin");
255 return *this;
256 }
257 I(lua_checkstack (st, 1));
258 lua_pushnil(st);
259 return *this;
260}
261
262bool
263Lua::next()
264{
265 if (failed) return false;
266 if (!lua_istable(st, -2))
267 {
268 fail("istable() in next");
269 return false;
270 }
271 I(lua_checkstack (st, 1));
272 if (lua_next(st, -2) != 0)
273 {
274 return true;
275 }
276 pop();
277 return false;
278}
279
280// pushers
281
282Lua &
283Lua::push_str(string const & str)
284{
285 if (failed) return *this;
286 I(lua_checkstack (st, 1));
287 lua_pushlstring(st, str.c_str(), str.size());
288 return *this;
289}
290
291Lua &
292Lua::push_int(int num)
293{
294 if (failed) return *this;
295 I(lua_checkstack (st, 1));
296 lua_pushnumber(st, num);
297 return *this;
298}
299
300Lua &
301Lua::push_double(double num)
302{
303 if (failed) return *this;
304 I(lua_checkstack (st, 1));
305 lua_pushnumber(st, num);
306 return *this;
307}
308
309Lua &
310Lua::push_bool(bool b)
311{
312 if (failed) return *this;
313 I(lua_checkstack (st, 1));
314 lua_pushboolean(st, b);
315 return *this;
316}
317
318Lua &
319Lua::push_nil()
320{
321 if (failed) return *this;
322 I(lua_checkstack (st, 1));
323 lua_pushnil(st);
324 return *this;
325}
326
327Lua &
328Lua::push_table()
329{
330 if (failed) return *this;
331 I(lua_checkstack (st, 1));
332 lua_newtable(st);
333 return *this;
334}
335
336Lua &
337Lua::set_table(int idx)
338{
339 if (failed) return *this;
340 I(lua_checkstack (st, 1));
341 lua_settable(st, idx);
342 return *this;
343}
344
345Lua &
346Lua::set_field(const string& key, int idx)
347{
348 if (failed) return *this;
349 lua_setfield(st, idx, key.c_str());
350 return *this;
351}
352
353Lua &
354Lua::call(int in, int out)
355{
356 if (failed) return *this;
357 I(lua_checkstack (st, out));
358 if (lua_pcall(st, in, out, 0) != 0)
359 {
360 report_error();
361 }
362 return *this;
363}
364
365Lua &
366Lua::pop(int count)
367{
368 if (failed) return *this;
369 if (lua_gettop (st) < count)
370 {
371 fail("stack top is not >= count in pop");
372 return *this;
373 }
374 lua_pop(st, count);
375 return *this;
376}
377
378Lua &
379Lua::func(string const & fname)
380{
381 L(FL("loading lua hook %s") % fname);
382 if (!failed)
383 {
384 if (missing_functions.find(fname) != missing_functions.end())
385 failed = true;
386 else
387 {
388 push_str(fname);
389 get_fn();
390 if (failed)
391 missing_functions.insert(fname);
392 }
393 }
394 return *this;
395}
396
397Lua &
398Lua::loadstring(string const & str, string const & identity)
399{
400 if (!failed)
401 {
402 if (luaL_loadbuffer(st, str.c_str(), str.size(), identity.c_str()))
403 {
404 report_error();
405 }
406 }
407 return *this;
408}
409
410Lua &
411Lua::loadfile(string const & filename)
412{
413 if (!failed)
414 {
415 if (luaL_loadfile(st, filename.c_str()))
416 {
417 report_error();
418 }
419 }
420 return *this;
421}
422
423set<string> Lua::missing_functions;
424
425luaext::ftmap * luaext::fns;
426
427luaext::extfn::extfn(std::string const & name, std::string const & table, int (*func) (lua_State *))
428{
429 static bool first(true);
430 if (first)
431 {
432 first = false;
433 fns = new ftmap;
434 }
435 (*fns)[table].insert(make_pair(name, func));
436}
437
438void add_functions(lua_State * st)
439{
440 for (luaext::ftmap::const_iterator i = luaext::fns->begin();
441 i != luaext::fns->end(); ++i)
442 {
443 std::string const & table(i->first);
444 if (table != "")
445 {
446 lua_newtable(st);
447 lua_pushvalue(st, -1);
448 lua_setfield(st, LUA_GLOBALSINDEX, table.c_str());
449 }
450 for (luaext::fmap::const_iterator j = i->second.begin();
451 j != i->second.end(); ++j)
452 {
453 if (table == "")
454 lua_register(st, j->first.c_str(), j->second);
455 else
456 {
457 lua_pushcfunction(st, j->second);
458 lua_setfield(st, -2, j->first.c_str());
459 }
460 }
461 if (table != "")
462 lua_pop(st, 1);
463 }
464}
465
466LUAEXT(include, )
467{
468 const char *path = luaL_checkstring(L, -1);
469 N(path, F("%s called with an invalid parameter") % "Include");
470
471 bool res =Lua(L)
472 .loadfile(string(path, lua_strlen(L, -1)))
473 .call(0,1)
474 .ok();
475
476 lua_pushboolean(L, res);
477 return 1;
478}
479
480LUAEXT(includedir, )
481{
482 const char *pathstr = luaL_checkstring(L, -1);
483 N(pathstr, F("%s called with an invalid parameter") % "IncludeDir");
484
485 fs::path locpath(pathstr, fs::native);
486 N(fs::exists(locpath), F("Directory '%s' does not exist") % pathstr);
487 N(fs::is_directory(locpath), F("'%s' is not a directory") % pathstr);
488
489 // directory, iterate over it, skipping subdirs, taking every filename,
490 // sorting them and loading in sorted order
491 fs::directory_iterator it(locpath);
492 vector<fs::path> arr;
493 while (it != fs::directory_iterator())
494 {
495 if (!fs::is_directory(*it))
496 arr.push_back(*it);
497 ++it;
498 }
499 sort(arr.begin(), arr.end());
500 for (vector<fs::path>::iterator i= arr.begin(); i != arr.end(); ++i)
501 {
502 bool res =Lua(L)
503 .loadfile(i->string())
504 .call(0,1)
505 .ok();
506 N(res, F("lua error while loading rcfile '%s'") % i->string());
507 }
508
509 lua_pushboolean(L, true);
510 return 1;
511}
512
513LUAEXT(includedirpattern, )
514{
515 const char *pathstr = luaL_checkstring(L, -2);
516 const char *pattern = luaL_checkstring(L, -1);
517 N(pathstr && pattern,
518 F("%s called with an invalid parameter") % "IncludeDirPattern");
519
520 fs::path locpath(pathstr, fs::native);
521 N(fs::exists(locpath), F("Directory '%s' does not exist") % pathstr);
522 N(fs::is_directory(locpath), F("'%s' is not a directory") % pathstr);
523
524 // directory, iterate over it, skipping subdirs, taking every filename
525 // matching the pattern, sorting them and loading in sorted order
526 fs::directory_iterator it(locpath);
527 globish r = globish(pattern);
528 globish_matcher glob(r, globish());
529 vector<fs::path> arr;
530 while (it != fs::directory_iterator())
531 {
532 if (!fs::is_directory(*it) && glob(it->string()))
533 arr.push_back(*it);
534 ++it;
535 }
536 sort(arr.begin(), arr.end());
537 for (vector<fs::path>::iterator i= arr.begin(); i != arr.end(); ++i)
538 {
539 bool res =Lua(L)
540 .loadfile(i->string())
541 .call(0,1)
542 .ok();
543 N(res, F("lua error while loading rcfile '%s'") % i->string());
544 }
545
546 lua_pushboolean(L, true);
547 return 1;
548}
549
550LUAEXT(search, regex)
551{
552 const char *re = luaL_checkstring(L, -2);
553 const char *str = luaL_checkstring(L, -1);
554 boost::cmatch what;
555
556 bool result = false;
557 try {
558 result = boost::regex_search(str, what, boost::regex(re));
559 } catch (boost::bad_pattern e) {
560 lua_pushstring(L, e.what());
561 lua_error(L);
562 return 0;
563 }
564 lua_pushboolean(L, result);
565 return 1;
566}
567
568LUAEXT(gettext, )
569{
570 const char *msgid = luaL_checkstring(L, -1);
571 lua_pushstring(L, gettext(msgid));
572 return 1;
573}
574
575bool
576run_string(lua_State * st, string const &str, string const & identity)
577{
578 I(st);
579 return
580 Lua(st)
581 .loadstring(str, identity)
582 .call(0,1)
583 .ok();
584}
585
586bool
587run_file(lua_State * st, string const &filename)
588{
589 I(st);
590 return
591 Lua(st)
592 .loadfile(filename)
593 .call(0,1)
594 .ok();
595}
596
597// Local Variables:
598// mode: C++
599// fill-column: 76
600// c-file-style: "gnu"
601// indent-tabs-mode: nil
602// End:
603// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status