monotone

monotone Mtn Source Tree

Root/lua.cc

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