monotone

monotone Mtn Source Tree

Root/lua.cc

1
2
3#include "config.h"
4
5extern "C" {
6#include <lua.h>
7#include <lualib.h>
8#include <lauxlib.h>
9}
10#include <errno.h>
11#include <signal.h>
12//#include <stdlib.h>
13//#include <string.h>
14//#include <stdarg.h>
15
16#include "lua.hh"
17
18#include "sanity.hh"
19#include "platform.hh"
20#include "mkstemp.hh"
21#include "globish.hh"
22#include "basic_io.hh"
23#include "file_io.hh"
24
25#include <string>
26#include <fstream>
27#include <set>
28#include <vector>
29#include <utility>
30
31#include <boost/filesystem/path.hpp>
32#include <boost/filesystem/operations.hpp>
33#include <boost/regex.hpp>
34
35using std::ifstream;
36using std::ios_base;
37using std::pair;
38using std::set;
39using std::sort;
40using std::string;
41using std::vector;
42using std::strerror;
43using std::malloc;
44using std::free;
45
46// adapted from "programming in lua", section 24.2.3
47// http://www.lua.org/pil/24.2.3.html
48// output is from bottom (least accessible) to top (most accessible, where
49// push and pop happen).
50static string
51dump_stack(lua_State * st)
52{
53 string out;
54 int i;
55 int top = lua_gettop(st);
56 for (i = 1; i <= top; i++) { /* repeat for each level */
57 int t = lua_type(st, i);
58 switch (t) {
59 case LUA_TSTRING: /* strings */
60 out += '`';
61 out += string(lua_tostring(st, i), lua_strlen(st, i));
62 out += '\'';
63 break;
64
65 case LUA_TBOOLEAN: /* booleans */
66 out += (lua_toboolean(st, i) ? "true" : "false");
67 break;
68
69 case LUA_TNUMBER: /* numbers */
70 out += (FL("%g") % lua_tonumber(st, i)).str();
71 break;
72
73 default: /* other values */
74 out += std::string(lua_typename(st, t));
75 break;
76
77 }
78 out += " "; /* put a separator */
79 }
80 return out;
81}
82
83
84Lua::Lua(lua_State * s) :
85 st(s), failed(false)
86{}
87
88Lua::~Lua()
89{
90 lua_settop(st, 0);
91}
92
93void
94Lua::fail(string const & reason)
95{
96 L(FL("lua failure: %s; stack = %s") % reason % dump_stack(st));
97 failed = true;
98}
99
100bool
101Lua::ok()
102{
103 if (failed)
104 L(FL("Lua::ok(): failed"));
105 return !failed;
106}
107
108void
109Lua::report_error()
110{
111// I(lua_isstring(st, -1));
112 string err = string(lua_tostring(st, -1), lua_strlen(st, -1));
113 W(i18n_format("%s") % err);
114 L(FL("lua stack: %s") % dump_stack(st));
115 lua_pop(st, 1);
116 failed = true;
117}
118
119// getters
120
121Lua &
122Lua::get(int idx)
123{
124 if (failed) return *this;
125 if (!lua_istable (st, idx))
126 {
127 fail("istable() in get");
128 return *this;
129 }
130 if (lua_gettop (st) < 1)
131 {
132 fail("stack top > 0 in get");
133 return *this;
134 }
135 lua_gettable(st, idx);
136 return *this;
137}
138
139Lua &
140Lua::get_fn(int idx)
141{
142 if (failed) return *this;
143 get(idx);
144 if (!lua_isfunction (st, -1))
145 fail("isfunction() in get_fn");
146 return *this;
147}
148
149Lua &
150Lua::get_tab(int idx)
151{
152 if (failed) return *this;
153 get(idx);
154 if (!lua_istable (st, -1))
155 fail("istable() in get_tab");
156 return *this;
157}
158
159Lua &
160Lua::get_str(int idx)
161{
162 if (failed) return *this;
163 get(idx);
164 if (!lua_isstring (st, -1))
165 fail("isstring() in get_str");
166 return *this;
167}
168
169Lua &
170Lua::get_num(int idx)
171{
172 if (failed) return *this;
173 get(idx);
174 if (!lua_isnumber (st, -1))
175 fail("isnumber() in get_num");
176 return *this;
177}
178
179Lua &
180Lua::get_bool(int idx)
181{
182 if (failed) return *this;
183 get(idx);
184 if (!lua_isboolean (st, -1))
185 fail("isboolean() in get_bool");
186 return *this;
187}
188
189// extractors
190
191Lua &
192Lua::extract_str_nolog(string & str)
193{
194 if (failed) return *this;
195 if (!lua_isstring (st, -1))
196 {
197 fail("isstring() in extract_str");
198 return *this;
199 }
200 str = string(lua_tostring(st, -1), lua_strlen(st, -1));
201 return *this;
202}
203
204Lua &
205Lua::extract_str(string & str)
206{
207 extract_str_nolog(str);
208 L(FL("lua: extracted string = %s") % str);
209 return *this;
210}
211
212Lua &
213Lua::extract_classified_str(string & str)
214{
215 extract_str_nolog(str);
216 L(FL("lua: extracted string [CLASSIFIED]"));
217 return *this;
218}
219
220Lua &
221Lua::extract_int(int & i)
222{
223 if (failed) return *this;
224 if (!lua_isnumber (st, -1))
225 {
226 fail("isnumber() in extract_int");
227 return *this;
228 }
229 i = static_cast<int>(lua_tonumber(st, -1));
230 L(FL("lua: extracted int = %i") % i);
231 return *this;
232}
233
234Lua &
235Lua::extract_double(double & i)
236{
237 if (failed) return *this;
238 if (!lua_isnumber (st, -1))
239 {
240 fail("isnumber() in extract_double");
241 return *this;
242 }
243 i = lua_tonumber(st, -1);
244 L(FL("lua: extracted double = %i") % i);
245 return *this;
246}
247
248
249Lua &
250Lua::extract_bool(bool & i)
251{
252 if (failed) return *this;
253 if (!lua_isboolean (st, -1))
254 {
255 fail("isboolean() in extract_bool");
256 return *this;
257 }
258 i = (lua_toboolean(st, -1) == 1);
259 L(FL("lua: extracted bool = %i") % i);
260 return *this;
261}
262
263
264// table iteration
265
266Lua &
267Lua::begin()
268{
269 if (failed) return *this;
270 if (!lua_istable(st, -1))
271 {
272 fail("istable() in begin");
273 return *this;
274 }
275 I(lua_checkstack (st, 1));
276 lua_pushnil(st);
277 return *this;
278}
279
280bool
281Lua::next()
282{
283 if (failed) return false;
284 if (!lua_istable(st, -2))
285 {
286 fail("istable() in next");
287 return false;
288 }
289 I(lua_checkstack (st, 1));
290 if (lua_next(st, -2) != 0)
291 {
292 return true;
293 }
294 pop();
295 return false;
296}
297
298// pushers
299
300Lua &
301Lua::push_str(string const & str)
302{
303 if (failed) return *this;
304 I(lua_checkstack (st, 1));
305 lua_pushlstring(st, str.c_str(), str.size());
306 return *this;
307}
308
309Lua &
310Lua::push_int(int num)
311{
312 if (failed) return *this;
313 I(lua_checkstack (st, 1));
314 lua_pushnumber(st, num);
315 return *this;
316}
317
318Lua &
319Lua::push_int(double num)
320{
321 if (failed) return *this;
322 I(lua_checkstack (st, 1));
323 lua_pushnumber(st, num);
324 return *this;
325}
326
327Lua &
328Lua::push_bool(bool b)
329{
330 if (failed) return *this;
331 I(lua_checkstack (st, 1));
332 lua_pushboolean(st, b);
333 return *this;
334}
335
336Lua &
337Lua::push_nil()
338{
339 if (failed) return *this;
340 I(lua_checkstack (st, 1));
341 lua_pushnil(st);
342 return *this;
343}
344
345Lua &
346Lua::push_table()
347{
348 if (failed) return *this;
349 I(lua_checkstack (st, 1));
350 lua_newtable(st);
351 return *this;
352}
353
354Lua &
355Lua::set_table(int idx)
356{
357 if (failed) return *this;
358 I(lua_checkstack (st, 1));
359 lua_settable(st, idx);
360 return *this;
361}
362
363Lua &
364Lua::call(int in, int out)
365{
366 if (failed) return *this;
367 I(lua_checkstack (st, out));
368 if (lua_pcall(st, in, out, 0) != 0)
369 {
370 report_error();
371 }
372 return *this;
373}
374
375Lua &
376Lua::pop(int count)
377{
378 if (failed) return *this;
379 if (lua_gettop (st) < count)
380 {
381 fail("stack top is not >= count in pop");
382 return *this;
383 }
384 lua_pop(st, count);
385 return *this;
386}
387
388Lua &
389Lua::func(string const & fname)
390{
391 L(FL("loading lua hook %s") % fname);
392 if (!failed)
393 {
394 if (missing_functions.find(fname) != missing_functions.end())
395 failed = true;
396 else
397 {
398 push_str(fname);
399 get_fn();
400 if (failed)
401 missing_functions.insert(fname);
402 }
403 }
404 return *this;
405}
406
407Lua &
408Lua::loadstring(string const & str, string const & identity)
409{
410 if (!failed)
411 {
412 if (luaL_loadbuffer(st, str.c_str(), str.size(), identity.c_str()))
413 {
414 report_error();
415 }
416 }
417 return *this;
418}
419
420Lua &
421Lua::loadfile(string const & filename)
422{
423 if (!failed)
424 {
425 if (luaL_loadfile(st, filename.c_str()))
426 {
427 report_error();
428 }
429 }
430 return *this;
431}
432
433set<string> Lua::missing_functions;
434
435
436
437
438extern "C"
439{
440 static int
441 monotone_mkstemp_for_lua(lua_State *L)
442 {
443 int fd = -1;
444 FILE **pf = NULL;
445 char const *filename = luaL_checkstring (L, -1);
446 string dup(filename);
447
448 fd = monotone_mkstemp(dup);
449
450 if (fd == -1)
451 return 0;
452
453 // this magic constructs a lua object which the lua io library
454 // will enjoy working with
455 pf = static_cast<FILE **>(lua_newuserdata(L, sizeof(FILE *)));
456 *pf = fdopen(fd, "r+");
457 lua_pushstring(L, "FILE*");
458 lua_rawget(L, LUA_REGISTRYINDEX);
459 lua_setmetatable(L, -2);
460
461 lua_pushstring(L, dup.c_str());
462
463 if (*pf == NULL)
464 {
465 lua_pushnil(L);
466 lua_pushfstring(L, "%s", strerror(errno));
467 lua_pushnumber(L, errno);
468 return 3;
469 }
470 else
471 return 2;
472 }
473
474 static int
475 monotone_existsonpath_for_lua(lua_State *L)
476 {
477 const char *exe = luaL_checkstring(L, -1);
478 lua_pushnumber(L, existsonpath(exe));
479 return 1;
480 }
481
482 static int
483 monotone_is_executable_for_lua(lua_State *L)
484 {
485 const char *path = luaL_checkstring(L, -1);
486 lua_pushboolean(L, is_executable(path));
487 return 1;
488 }
489
490 static int
491 monotone_make_executable_for_lua(lua_State *L)
492 {
493 const char *path = luaL_checkstring(L, -1);
494 lua_pushnumber(L, make_executable(path));
495 return 1;
496 }
497
498 static int
499 monotone_spawn_for_lua(lua_State *L)
500 {
501 int n = lua_gettop(L);
502 const char *path = luaL_checkstring(L, -n);
503 char **argv = (char**)malloc((n+1)*sizeof(char*));
504 int i;
505 pid_t ret;
506 if (argv==NULL)
507 return 0;
508 argv[0] = (char*)path;
509 for (i=1; i<n; i++) argv[i] = (char*)luaL_checkstring(L, -(n - i));
510 argv[i] = NULL;
511 ret = process_spawn(argv);
512 free(argv);
513 lua_pushnumber(L, ret);
514 return 1;
515 }
516
517 static int
518 monotone_wait_for_lua(lua_State *L)
519 {
520 pid_t pid = static_cast<pid_t>(luaL_checknumber(L, -1));
521 int res;
522 int ret;
523 ret = process_wait(pid, &res);
524 lua_pushnumber(L, res);
525 lua_pushnumber(L, ret);
526 return 2;
527 }
528
529 static int
530 monotone_kill_for_lua(lua_State *L)
531 {
532 int n = lua_gettop(L);
533 pid_t pid = static_cast<pid_t>(luaL_checknumber(L, -2));
534 int sig;
535 if (n>1)
536 sig = static_cast<int>(luaL_checknumber(L, -1));
537 else
538 sig = SIGTERM;
539 lua_pushnumber(L, process_kill(pid, sig));
540 return 1;
541 }
542
543 static int
544 monotone_sleep_for_lua(lua_State *L)
545 {
546 int seconds = static_cast<int>(luaL_checknumber(L, -1));
547 lua_pushnumber(L, process_sleep(seconds));
548 return 1;
549 }
550
551 static int
552 monotone_guess_binary_file_contents_for_lua(lua_State *L)
553 {
554 const char *path = luaL_checkstring(L, -1);
555 N(path, F("%s called with an invalid parameter") % "guess_binary");
556
557 ifstream file(path, ios_base::binary);
558 if (!file)
559 {
560 lua_pushnil(L);
561 return 1;
562 }
563 const int bufsize = 8192;
564 char tmpbuf[bufsize];
565 string buf;
566 while (file.read(tmpbuf, sizeof tmpbuf))
567 {
568 I(file.gcount() <= static_cast<int>(sizeof tmpbuf));
569 buf.assign(tmpbuf, file.gcount());
570 if (guess_binary(buf))
571 {
572 lua_pushboolean(L, true);
573 return 1;
574 }
575 }
576 lua_pushboolean(L, false);
577 return 1;
578 }
579
580 static int
581 monotone_include_for_lua(lua_State *L)
582 {
583 const char *path = luaL_checkstring(L, -1);
584 N(path, F("%s called with an invalid parameter") % "Include");
585
586 bool res =Lua(L)
587 .loadfile(string(path, lua_strlen(L, -1)))
588 .call(0,1)
589 .ok();
590
591 lua_pushboolean(L, res);
592 return 1;
593 }
594
595 static int
596 monotone_includedir_for_lua(lua_State *L)
597 {
598 const char *pathstr = luaL_checkstring(L, -1);
599 N(pathstr, F("%s called with an invalid parameter") % "IncludeDir");
600
601 fs::path locpath(pathstr, fs::native);
602 N(fs::exists(locpath), F("Directory '%s' does not exist") % pathstr);
603 N(fs::is_directory(locpath), F("'%s' is not a directory") % pathstr);
604
605 // directory, iterate over it, skipping subdirs, taking every filename,
606 // sorting them and loading in sorted order
607 fs::directory_iterator it(locpath);
608 vector<fs::path> arr;
609 while (it != fs::directory_iterator())
610 {
611 if (!fs::is_directory(*it))
612 arr.push_back(*it);
613 ++it;
614 }
615 sort(arr.begin(), arr.end());
616 for (vector<fs::path>::iterator i= arr.begin(); i != arr.end(); ++i)
617 {
618 bool res =Lua(L)
619 .loadfile(i->string())
620 .call(0,1)
621 .ok();
622 N(res, F("lua error while loading rcfile '%s'") % i->string());
623 }
624
625 lua_pushboolean(L, true);
626 return 1;
627 }
628
629 static int
630 monotone_regex_search_for_lua(lua_State *L)
631 {
632 const char *re = luaL_checkstring(L, -2);
633 const char *str = luaL_checkstring(L, -1);
634 boost::cmatch what;
635
636 bool result = false;
637 try {
638 result = boost::regex_search(str, what, boost::regex(re));
639 } catch (boost::bad_pattern e) {
640 lua_pushstring(L, e.what());
641 lua_error(L);
642 return 0;
643 }
644 lua_pushboolean(L, result);
645 return 1;
646 }
647
648 static int
649 monotone_globish_match_for_lua(lua_State *L)
650 {
651 const char *re = luaL_checkstring(L, -2);
652 const char *str = luaL_checkstring(L, -1);
653
654 bool result = false;
655 try {
656 string r(re);
657 string n;
658 string s(str);
659 result = globish_matcher(r, n)(s);
660 } catch (informative_failure & e) {
661 lua_pushstring(L, e.what.c_str());
662 lua_error(L);
663 return 0;
664 } catch (boost::bad_pattern & e) {
665 lua_pushstring(L, e.what());
666 lua_error(L);
667 return 0;
668 } catch (...) {
669 lua_pushstring(L, "Unknown error.");
670 lua_error(L);
671 return 0;
672 }
673 lua_pushboolean(L, result);
674 return 1;
675 }
676
677 static int
678 monotone_gettext_for_lua(lua_State *L)
679 {
680 const char *msgid = luaL_checkstring(L, -1);
681 lua_pushstring(L, gettext(msgid));
682 return 1;
683 }
684
685 static int
686 monotone_parse_basic_io_for_lua(lua_State *L)
687 {
688 vector<pair<string, vector<string> > > res;
689 const string str(luaL_checkstring(L, -1), lua_strlen(L, -1));
690 basic_io::input_source in(str, "monotone_parse_basic_io_for_lua");
691 basic_io::tokenizer tok(in);
692 try
693 {
694 string got;
695 basic_io::token_type tt;
696 do
697 {
698 tt = tok.get_token(got);
699 switch (tt)
700 {
701 case basic_io::TOK_SYMBOL:
702 res.push_back(make_pair(got, vector<string>()));
703 break;
704 case basic_io::TOK_STRING:
705 case basic_io::TOK_HEX:
706 E(!res.empty(), F("bad input to parse_basic_io"));
707 res.back().second.push_back(got);
708 break;
709 default:
710 break;
711 }
712 }
713 while (tt != basic_io::TOK_NONE);
714 }
715 catch (informative_failure & e)
716 {// there was a syntax error in our string
717 lua_pushnil(L);
718 return 1;
719 }
720 lua_newtable(L);
721 int n = 1;
722 for (vector<pair<string, vector<string> > >::const_iterator i = res.begin();
723 i != res.end(); ++i)
724 {
725 lua_pushnumber(L, n++);
726 lua_newtable(L);
727 lua_pushstring(L, "name");
728 lua_pushstring(L, i->first.c_str());
729 lua_settable(L, -3);
730 lua_pushstring(L, "values");
731 lua_newtable(L);
732 int m = 1;
733 for (vector<string>::const_iterator j = i->second.begin();
734 j != i->second.end(); ++j)
735 {
736 lua_pushnumber(L, m++);
737 lua_pushstring(L, j->c_str());
738 lua_settable(L, -3);
739 }
740 lua_settable(L, -3);
741 lua_settable(L, -3);
742 }
743 return 1;
744 }
745}
746
747bool
748run_string(lua_State * st, string const &str, string const & identity)
749{
750 I(st);
751 return
752 Lua(st)
753 .loadstring(str, identity)
754 .call(0,1)
755 .ok();
756}
757
758bool
759run_file(lua_State * st, string const &filename)
760{
761 I(st);
762 return
763 Lua(st)
764 .loadfile(filename)
765 .call(0,1)
766 .ok();
767}
768
769void
770add_functions(lua_State * st)
771{
772 // add monotone-specific functions
773 lua_register(st, "mkstemp", monotone_mkstemp_for_lua);
774 lua_register(st, "existsonpath", monotone_existsonpath_for_lua);
775 lua_register(st, "is_executable", monotone_is_executable_for_lua);
776 lua_register(st, "make_executable", monotone_make_executable_for_lua);
777 lua_register(st, "spawn", monotone_spawn_for_lua);
778 lua_register(st, "wait", monotone_wait_for_lua);
779 lua_register(st, "kill", monotone_kill_for_lua);
780 lua_register(st, "sleep", monotone_sleep_for_lua);
781 lua_register(st, "guess_binary_file_contents", monotone_guess_binary_file_contents_for_lua);
782 lua_register(st, "include", monotone_include_for_lua);
783 lua_register(st, "includedir", monotone_includedir_for_lua);
784 lua_register(st, "gettext", monotone_gettext_for_lua);
785 lua_register(st, "parse_basic_io", monotone_parse_basic_io_for_lua);
786
787 // add regex functions:
788 lua_newtable(st);
789 lua_pushstring(st, "regex");
790 lua_pushvalue(st, -2);
791 lua_settable(st, LUA_GLOBALSINDEX);
792
793 lua_pushstring(st, "search");
794 lua_pushcfunction(st, monotone_regex_search_for_lua);
795 lua_settable(st, -3);
796
797 // add globish functions:
798 lua_newtable(st);
799 lua_pushstring(st, "globish");
800 lua_pushvalue(st, -2);
801 lua_settable(st, LUA_GLOBALSINDEX);
802
803 lua_pushstring(st, "match");
804 lua_pushcfunction(st, monotone_globish_match_for_lua);
805 lua_settable(st, -3);
806
807 lua_pop(st, 1);
808}
809
810// Local Variables:
811// mode: C++
812// fill-column: 76
813// c-file-style: "gnu"
814// indent-tabs-mode: nil
815// End:
816// 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