monotone

monotone Mtn Source Tree

Root/src/lua.cc

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