/*
* rubyIntersect.cpp
*
* Created on: Jan 25, 2009
* Author: Thyth
*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "ruby.h"
#include "processChecker.h"
#include "hexStream.h"
namespace Ruby
{
VALUE rb_tsEval(VALUE self, VALUE exec);
VALUE str2val(const char *s);
char* val2str(VALUE v);
void init();
VALUE out(VALUE self, VALUE str);
VALUE out(VALUE self, VALUE str)
{
char* output = hex_encode(val2str(str));
if (self == rb_stdout)
printf("output: %s\n", output);
else
printf("error: %s\n", output);
fflush(stdout);
free(output);
return rb_fix_new(RSTRING(str)->len * sizeof(RSTRING(str)->ptr[0]));
}
// Print to ruby AND t2 consoles
void error(const char *fmt, ...)
{
va_list argptr;
va_start(argptr, fmt);
char* errorBuffer = (char*)calloc(16384, sizeof(char));
sprintf(errorBuffer, fmt, argptr);
va_end(argptr);
char* output = hex_encode(errorBuffer);
printf("error: %s\n", output);
fflush(stdout);
free(output);
free(errorBuffer);
}
// Display exception info...
void exception()
{
VALUE mesg = rb_obj_as_string(rb_gv_get("$!"));
error("%s", val2str(mesg));
}
// Convert VALUE to char*
char* val2str(VALUE v)
{
if (NIL_P(v))
return "nil";
return STR2CSTR(rb_funcall(v, rb_intern("to_s"), 0));
}
// Convert char* to VALUE
VALUE str2val(const char *s)
{
if (s == NULL)
return Qnil;
return rb_str_new2(s);
}
// Let's evaluate some t-script from ruby!
VALUE rb_tsEval(VALUE self, VALUE exec)
{
char* output = hex_encode(val2str(exec));
printf("console: %s\n", output);
fflush(stdout);
free(output);
return str2val("nil");
}
VALUE rb_exit(VALUE self, VALUE exec)
{
exit(0);
}
void doEval(char* string)
{
int err = 0;
rb_eval_string_protect(string, &err);
if (err)
{
error("Runtime error (%d)", err);
//exception(); // seems to be causing crashes
}
}
void init()
{
rb_define_singleton_method(rb_stdout, "write", RUBY_METHOD_FUNC(out), 1);
rb_define_singleton_method(rb_stderr, "write", RUBY_METHOD_FUNC(out), 1);
rb_define_global_function("tsEval", RUBY_METHOD_FUNC(rb_tsEval), 1);
rb_define_global_function("exit", RUBY_METHOD_FUNC(rb_exit), 0);
}
}
int parent_pid;
DWORD WINAPI gameCrashDetectThread(void* arg)
{
while (1)
{
if (!processActive(parent_pid))
{
// parent process has been terminated. terminate interpreter
//abort();
ExitProcess(0);
}
// sleep for 5 seconds before checking again
Sleep(5000);
}
}
int main(int argc, char *argv[])
{
// start the process watch thread to see if the parent game process has terminated
if (argc != 2)
{
MessageBoxA(NULL,
"Ruby Interpreter parent process connection failed.",
"Fatal Error",
MB_ICONERROR | MB_OK);
exit(1);
}
parent_pid = atoi(argv[1]);
// spawn a thread
CreateThread(NULL, 0, gameCrashDetectThread, NULL, 0, NULL);
// initialize the embedded ruby interpreter
ruby_init();
ruby_init_loadpath();
ruby_script("embedded");
Ruby::init();
// being processing standard in and out
char* buffer = (char*)malloc(8388608);
while (true)
{
fgets(buffer, 8388608, stdin);
char* decoded = hex_decode(buffer);
//printf("Decoded: %s\n", decoded);
Ruby::doEval(decoded);
free(decoded);
printf("done: \n");
fflush(stdout);
}
return 0;
}