rh.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. #include "eruta.h"
  2. #include "image.h"
  3. #include "rh.h"
  4. #include "fifi.h"
  5. #include "zori.h"
  6. #include "str.h"
  7. #include "mem.h"
  8. #include "state.h"
  9. #include "monolog.h"
  10. #include <string.h>
  11. #include <stdarg.h>
  12. #include <mruby.h>
  13. #include <mruby/error.h>
  14. /* Debugging level for console output. */
  15. #define LOG_CONSOLE(FORMAT, ...) LOG_LEVEL("CONSOLE", FORMAT, __VA_ARGS__)
  16. #define LOG_ENABLE_CONSOLE() LOG_ENABLE(CONSOLE)
  17. #define LOG_DISABLE_CONSOLE() LOG_DISABLE(CONSOLE)
  18. /* Amount of parameters a mruby function can be called with using _va functions */
  19. #define RH_ARGS_MAX 64
  20. /*
  21. * RH contains helper functions for the mruby ruby interpreter.
  22. */
  23. /*
  24. * Converts C like arguments to an array of mruby mrb_values.
  25. * Returns amount of arguments parsed, negative on failure.
  26. *
  27. * Format specifier characters for the format argument:
  28. *
  29. * z: String from null terminated C string [char*]
  30. * s: String [char*, int]
  31. * Y: sYmbol from null terminated C string [char*]
  32. * y: symbol [char*, int]
  33. *
  34. * f: Float [double]
  35. * i: Integer [int]
  36. * b: Boolean [int]
  37. * 0: nil
  38. * Other characters: Error. Will return -(index or erroneous character) .
  39. */
  40. int rh_args_va(Ruby * ruby, mrb_value * values, int size, char * format, va_list list) {
  41. int ch; int index;
  42. int i; double d; const char * str;
  43. index = 0;
  44. for (ch = (*format) ; (ch) && (index < size) ; format++ , ch = (*format)) {
  45. mrb_value val;
  46. int error = FALSE;
  47. switch(ch) {
  48. case 's':
  49. str = va_arg(list, const char*);
  50. i = va_arg(list, int);
  51. val = mrb_str_new(ruby, str, i);
  52. break;
  53. case 'z':
  54. str = va_arg(list, const char*);
  55. val = mrb_str_new_cstr(ruby, str);
  56. break;
  57. case 'y':
  58. str = va_arg(list, const char*);
  59. i = va_arg(list, int);
  60. val = mrb_symbol_value(mrb_intern(ruby, str, (size_t)i));
  61. break;
  62. case 'Y':
  63. str = va_arg(list, const char*);
  64. val = mrb_symbol_value(mrb_intern_cstr(ruby, str));
  65. break;
  66. case 'i':
  67. i = va_arg(list, int);
  68. val = mrb_fixnum_value(i);
  69. break;
  70. case 'f':
  71. d = va_arg(list, double);
  72. val = mrb_float_value(ruby, d);
  73. break;
  74. case 'b':
  75. i = va_arg(list, int);
  76. val = ( i ? mrb_true_value() : mrb_false_value());
  77. break;
  78. case '0':
  79. val = mrb_nil_value();
  80. break;
  81. default:
  82. error = TRUE;
  83. break;
  84. }
  85. if (error) {
  86. return -index;
  87. }
  88. values[index] = val;
  89. index ++;
  90. }
  91. return index;
  92. }
  93. /* strdup isn't ANSI C, just posix... :p so we need our own version.*/
  94. char *rh_strdup(const char *str) {
  95. char * res = malloc(strlen(str) + 1);
  96. if(res) { strcpy(res, str); }
  97. return res;
  98. }
  99. /* Helps convert C values to mruby values in an array. */
  100. int rh_args(Ruby * ruby, mrb_value * values, int size, char * format, ...) {
  101. int res;
  102. va_list list;
  103. va_start(list, format);
  104. res = rh_args_va(ruby, values, size, format, list);
  105. va_end(list);
  106. return res;
  107. }
  108. /** Calulates the execption string. Result only tempoarily available..
  109. XXX: check if this doesn't leak memory... you must free the results manually.
  110. */
  111. char * rh_exceptionstring(Ruby * self) {
  112. char * result;
  113. mrb_value value;
  114. mrb_value backtrace;
  115. mrb_value backtrace_str;
  116. if (!self->exc) return NULL;
  117. //
  118. /* XXX: Too bad, the backtrace doesn't seem to be filled in for some reason...
  119. * Should figure out how to fix this.
  120. */
  121. mrb_print_backtrace(self);
  122. backtrace = // mrb_get_backtrace(self);
  123. mrb_funcall(self, mrb_obj_value(self->exc), "backtrace", 0);
  124. backtrace_str = mrb_funcall(self, backtrace, "join", 1, mrb_str_new_lit(self, "\n"));
  125. LOG_ERROR("backtrace: %s\n", mrb_string_value_cstr(self, &backtrace_str));
  126. value = mrb_funcall(self, mrb_obj_value(self->exc), "inspect", 0);
  127. // reset exception since we have it's string value.
  128. // Does this leak memory or not???
  129. self->exc = NULL;
  130. return rh_strdup(mrb_string_value_cstr(self, &value));
  131. }
  132. /** Allocates and initialzes a new ruby state. */
  133. Ruby * rh_new() {
  134. Ruby * self = mrb_open();
  135. /*mrb_define_method(self, self->kernel_module,
  136. "path", tr_Path, ARGS_REQ(1));*/
  137. return self;
  138. }
  139. /** Frees a ruby state. */
  140. Ruby * rh_free(Ruby * self) {
  141. mrb_close(self);
  142. return NULL;
  143. }
  144. /** Returns an mrb_value that contains the value of object.inspect.
  145. */
  146. mrb_value rh_inspect(mrb_state *mrb, mrb_value obj) {
  147. return mrb_inspect(mrb, obj);
  148. }
  149. char * rh_inspect_cstr(mrb_state *mrb, mrb_value value) {
  150. mrb_value res = rh_inspect(mrb, value);
  151. /* XXX: check that it's not modified anywere or export the const? */
  152. return (char *) mrb_string_value_cstr(mrb, &res);
  153. }
  154. /* Does the actual reporting depending on the current state of
  155. ruby and the returned value. */
  156. int rh_make_report(Ruby * self, mrb_value v) {
  157. int res = 0;
  158. char * str;
  159. /* Report exceptions */
  160. str = rh_exceptionstring(self);
  161. if(str) {
  162. LOG_WARNING("mruby exception: %s", str);
  163. free(str);
  164. return 0;
  165. }
  166. /* Report result value if it's not nil on debug and console levels.
  167. */
  168. if (!mrb_nil_p(v)) {
  169. str = rh_inspect_cstr(self, v);
  170. LOG_DEBUG("mruby result: %s", str);
  171. LOG_CONSOLE("-> %s", str);
  172. return 0;
  173. }
  174. return 0;
  175. }
  176. /* Runs a file and reports any errors over the monolog logging system. */
  177. int rh_run_file(Ruby * self, const char * filename, FILE * file) {
  178. int res;
  179. char * str;
  180. mrbc_context * c ;
  181. mrb_value v;
  182. int ai;
  183. ai = mrb_gc_arena_save(self);
  184. c = mrbc_context_new(self);
  185. mrbc_filename(self, c, filename);
  186. v = mrb_load_file_cxt(self, file, c);
  187. mrbc_context_free(self, c);
  188. /* Report exceptions */
  189. res = rh_make_report(self, v);
  190. mrb_gc_arena_restore(self, ai);
  191. return res;
  192. }
  193. int rh_run_filename(Ruby * self, const char * filename) {
  194. FILE * file = fopen(filename, "rt");
  195. int res;
  196. if (!file) {
  197. LOG_ERROR("No such ruby file: %s\n", filename);
  198. return -1;
  199. }
  200. res = rh_run_file(self, filename, file);
  201. fclose(file);
  202. return 0;
  203. }
  204. /**
  205. * Executes a ruby file in Eruta's data/script directory with reporting.
  206. * Returns -2 if the file was not found.
  207. * Returns -3 if the path wasn't found.
  208. */
  209. int rh_run_script(Ruby * self, const char * filename) {
  210. char * buf;
  211. int runres;
  212. buf = malloc(strlen(filename) + 256);
  213. if(!buf) return -3;
  214. strcpy(buf, "script/");
  215. strncat(buf, filename, strlen(filename));
  216. ALLEGRO_PATH * path = fifi_data_vpath(buf);
  217. if(!path) {
  218. free(buf);
  219. return -3;
  220. }
  221. runres = rh_run_filename(self, PATH_CSTR(path));
  222. al_destroy_path(path);
  223. free(buf);
  224. return runres;
  225. }
  226. /* Executes a ruby command string.
  227. Errors are reported to the reporter callback if it isn't NULL. */
  228. int rh_dostring(Ruby * self, const char * command) {
  229. int res = 0;
  230. char * str;
  231. mrb_value v;
  232. int ai;
  233. ai = mrb_gc_arena_save(self);
  234. #ifdef RH_USE_CONTEXT
  235. mrbc_context * c = mrbc_context_new(self);
  236. mrbc_filename(self, c, "command");
  237. v = mrb_load_string_cxt(self, command, c);
  238. mrbc_context_free(self, c);
  239. #else
  240. v = mrb_load_string(self, command);
  241. #endif
  242. /* Report exceptions */
  243. res = rh_make_report(self, v);
  244. /* mrb GC area seems to be an area for 1024 "new" objects for the generational
  245. * GC. It can overflow if a lot of new objects are generated
  246. * (say exceptions, etc) on the C side. To prevent this the area must be saved
  247. * and restored anywhere many ruby objects may have been generated.
  248. * It seems that here too this is needed.
  249. */
  250. mrb_gc_arena_restore(self, ai);
  251. return res;
  252. }
  253. /* Executes a ruby function with parameters.
  254. Errors are reported to the reporter callback if it isn't NULL. */
  255. mrb_value rh_run_function_args(Ruby * self, mrb_value rubyself, char * funcname,
  256. int argc, mrb_value * argv) {
  257. int res = 0;
  258. char * str;
  259. mrb_value v;
  260. mrb_sym symname = mrb_intern_cstr(self, funcname);
  261. int ai;
  262. if(!mrb_respond_to(self, rubyself, symname)) {
  263. return mrb_nil_value();
  264. }
  265. ai = mrb_gc_arena_save(self);
  266. v = mrb_funcall_argv(self, rubyself, symname, argc, argv);
  267. res = rh_make_report(self, v);
  268. mrb_gc_arena_restore(self, ai);
  269. return v;
  270. }
  271. /** Runs a function in the ruby interpreter, with C arguments according to the
  272. * given format string, logging results and errors back to
  273. * the reporter. The limit is RH_ARGS_MAX arguments.
  274. */
  275. mrb_value
  276. rh_run_function_va(Ruby * self, mrb_value rubyself, char * funcname,
  277. char * format, va_list list) {
  278. mrb_value argv[RH_ARGS_MAX];
  279. int argc;
  280. argc = rh_args_va(self, argv, RH_ARGS_MAX, format, list);
  281. if (argc < 0) return mrb_nil_value();
  282. return rh_run_function_args(self, rubyself, funcname, argc, argv);
  283. }
  284. /** Runs a function in the ruby interpreter, under the toplevel self.
  285. * This logs results and errors using monolog.h interfaces.
  286. */
  287. mrb_value rh_run_toplevel_args(Ruby * ruby, char * name, int argc, mrb_value * argv) {
  288. return rh_run_function_args(ruby, mrb_top_self(ruby), name, argc, argv);
  289. }
  290. /** Runs a function in the ruby interpreter, under the toplevel self.
  291. * This logs results and errors using monolog.h interfaces.
  292. */
  293. mrb_value rh_run_toplevel_va(Ruby * ruby, char * name, char * format, va_list list) {
  294. return rh_run_function_va(ruby, mrb_top_self(ruby), name, format, list);
  295. }
  296. /** Runs a function in the ruby interpreter, logging results and errors
  297. * using monolog.h interfaces.
  298. */
  299. mrb_value rh_run_function(Ruby * ruby, mrb_value rubyself,
  300. char * name, char * format, ...) {
  301. mrb_value res;
  302. va_list list;
  303. va_start(list, format);
  304. res = rh_run_function_va(ruby, rubyself, name, format, list);
  305. va_end(list);
  306. return res;
  307. }
  308. /** Runs a function in the ruby interpreter, under the toplevel self.
  309. * This logs results and errors using monolog.h interfaces.
  310. */
  311. mrb_value rh_run_toplevel(Ruby * ruby, char * name, char * format, ...) {
  312. mrb_value res;
  313. va_list list;
  314. va_start(list, format);
  315. res = rh_run_function_va(ruby, mrb_top_self(ruby), name, format, list);
  316. va_end(list);
  317. return res;
  318. }
  319. /* Calls a function, doesn't log anything. */
  320. mrb_value rh_simple_funcall(Ruby * ruby, char * name) {
  321. int ai;
  322. Ruby * mrb = (Ruby *) ruby;
  323. mrb_value args[16];
  324. ai = mrb_gc_arena_save(mrb);
  325. LOG("GC Area: %d\n", ai);
  326. // if(ai> 99) exit(0);
  327. mrb_value v = mrb_funcall_argv(mrb, mrb_top_self(mrb), mrb_intern_cstr(mrb, name),
  328. 0, args);
  329. if (mrb->exc) {
  330. if (!mrb_undef_p(v)) {
  331. mrb_p(mrb, mrb_obj_value(mrb->exc));
  332. }
  333. return mrb_nil_value();
  334. }
  335. mrb_gc_arena_restore(mrb, 0);
  336. return v;
  337. }
  338. /* Maybe wrap this too?
  339. mrb_value mrb_funcall_argv(mrb_state*, mrb_value, mrb_sym, int, mrb_value*);
  340. */
  341. /* Converts and mrb_value to a C boolean as per the ruby interpretation. */
  342. int rh_tobool(mrb_value v) {
  343. if (mrb_nil_p(v)) return FALSE;
  344. return mrb_bool(v);
  345. }
  346. /* Documentation for mrb_get_args
  347. retrieve arguments from mrb_state.
  348. mrb_get_args(mrb, format, ...)
  349. returns number of arguments parsed.
  350. format specifiers:
  351. o: Object [mrb_value]
  352. S: String [mrb_value]
  353. A: Array [mrb_value]
  354. H: Hash [mrb_value]
  355. s: String [char*,int]
  356. z: String [char*]
  357. a: Array [mrb_value*,int]
  358. f: Float [mrb_float]
  359. i: Integer [mrb_int]
  360. n: Symbol [mrb_sym]
  361. &: Block [mrb_value]
  362. *: rest argument [mrb_value*,int]
  363. |: optional
  364. */
  365. #define RH_EVARGS_MAX 32
  366. /* Returns the current number of the joystick, that is it's index in the allegro
  367. * JS list. Too bad but this number may change. Returns -1 if not found; */
  368. static int joystick_nr(ALLEGRO_JOYSTICK * stick) {
  369. int index;
  370. ALLEGRO_JOYSTICK * aid;
  371. for(index = 0 ; index < al_get_num_joysticks(); index ++) {
  372. aid = al_get_joystick(index);
  373. if (aid == stick) return index;
  374. }
  375. return -1;
  376. }
  377. /* Send the even to the ruby main "on_poll" */
  378. int rh_poll_event(mrb_state * mrb, ALLEGRO_EVENT * event) {
  379. State * state = state_get();
  380. mrb_value event_args[RH_EVARGS_MAX];
  381. int nargs = 0;
  382. if (!event) return FALSE;
  383. switch (event->type) {
  384. case ALLEGRO_EVENT_JOYSTICK_AXIS:
  385. nargs =
  386. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiif", "joystick_axis",
  387. event->any.timestamp,
  388. joystick_nr(event->joystick.id), event->joystick.stick, event->joystick.axis, event->joystick.pos);
  389. break;
  390. case ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN:
  391. nargs =
  392. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiif", "joystick_button_down",
  393. event->any.timestamp,
  394. joystick_nr(event->joystick.id), event->joystick.button);
  395. break;
  396. case ALLEGRO_EVENT_JOYSTICK_BUTTON_UP:
  397. nargs =
  398. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiif", "joystick_button_up",
  399. event->any.timestamp,
  400. joystick_nr(event->joystick.id), event->joystick.button);
  401. break;
  402. case ALLEGRO_EVENT_JOYSTICK_CONFIGURATION:
  403. nargs =
  404. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiif", "joystick_configuration",
  405. event->any.timestamp);
  406. break;
  407. case ALLEGRO_EVENT_KEY_DOWN:
  408. nargs =
  409. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfi", "key_down",
  410. event->any.timestamp,
  411. event->keyboard.keycode );
  412. break;
  413. case ALLEGRO_EVENT_KEY_UP:
  414. nargs =
  415. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfi", "key_up",
  416. event->any.timestamp,
  417. event->keyboard.keycode );
  418. break;
  419. case ALLEGRO_EVENT_KEY_CHAR:
  420. nargs =
  421. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiib", "key_char",
  422. event->any.timestamp,
  423. event->keyboard.keycode, event->keyboard.unichar,
  424. event->keyboard.modifiers, event->keyboard.repeat
  425. );
  426. break;
  427. case ALLEGRO_EVENT_MOUSE_AXES:
  428. nargs =
  429. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiiiiiii", "mouse_axes",
  430. event->any.timestamp,
  431. event->mouse.x, event->mouse.y, event->mouse.z, event->mouse.w,
  432. event->mouse.dx, event->mouse.dy, event->mouse.dz, event->mouse.dw
  433. );
  434. break;
  435. case ALLEGRO_EVENT_MOUSE_WARPED:
  436. nargs =
  437. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiiiiiii", "mouse_warped",
  438. event->any.timestamp,
  439. event->mouse.x, event->mouse.y, event->mouse.z, event->mouse.w,
  440. event->mouse.dx, event->mouse.dy, event->mouse.dz, event->mouse.dw
  441. );
  442. break;
  443. case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
  444. nargs =
  445. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiiii", "mouse_button_down",
  446. event->any.timestamp,
  447. event->mouse.x, event->mouse.y, event->mouse.z, event->mouse.w,
  448. event->mouse.button
  449. );
  450. break;
  451. case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
  452. nargs =
  453. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiiii", "mouse_button_up",
  454. event->any.timestamp,
  455. event->mouse.x, event->mouse.y, event->mouse.z, event->mouse.w,
  456. event->mouse.button
  457. );
  458. break;
  459. case ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY:
  460. nargs =
  461. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiii", "mouse_enter_display",
  462. event->any.timestamp,
  463. event->mouse.x, event->mouse.y, event->mouse.z, event->mouse.w
  464. );
  465. break;
  466. case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
  467. nargs =
  468. rh_args(mrb, event_args, RH_EVARGS_MAX, "Yfiiii", "mouse_leave_display",
  469. event->any.timestamp,
  470. event->mouse.x, event->mouse.y, event->mouse.z, event->mouse.w
  471. );
  472. break;
  473. default:
  474. nargs = rh_args(mrb, event_args, RH_EVARGS_MAX, "Yf", "unknown",
  475. event->any.timestamp
  476. );
  477. break;
  478. }
  479. rh_run_toplevel_args(state_ruby(state), "eruta_on_poll", nargs, event_args);
  480. return TRUE;
  481. }
  482. /* Polls the event queue and while events are available, send them to the ruby
  483. main "eruta_on_poll" */
  484. int rh_poll_events(mrb_state * mrb, ALLEGRO_EVENT_QUEUE * queue) {
  485. ALLEGRO_EVENT event;
  486. while(al_get_next_event(queue, &event)) {
  487. rh_poll_event(mrb, &event);
  488. }
  489. return TRUE;
  490. }
  491. /* Tries to (re-)load the main ruby file, output to console. */
  492. int rh_load_main() {
  493. State * state = state_get();
  494. // Try to load the main ruby file.
  495. return rh_run_script(state_ruby(state), "main.rb");
  496. }
  497. /** For execution of ruby strings by the console */
  498. int rh_run_console_command(struct zori_console * console, const char * command, void * extra)
  499. {
  500. int res;
  501. LOG_ENABLE_CONSOLE();
  502. res = rh_dostring(state_ruby(state_get()), command);
  503. LOG_DISABLE_CONSOLE();
  504. (void) console;
  505. (void) extra;
  506. return res;
  507. }