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