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