Index: /trunk/FACT++/src/InterpreterV8.cc
===================================================================
--- /trunk/FACT++/src/InterpreterV8.cc	(revision 14049)
+++ /trunk/FACT++/src/InterpreterV8.cc	(revision 14049)
@@ -0,0 +1,293 @@
+#include "InterpreterV8.h"
+
+InterpreterV8 *InterpreterV8::This = 0;
+
+#ifdef HAVE_V8
+
+#include <v8.h>
+#include <fstream>
+#include <sstream>
+#include <iomanip>
+
+using namespace std;
+using namespace v8;
+
+void InterpreterV8::ReportException(TryCatch* try_catch)
+{
+    const HandleScope handle_scope;
+
+    const String::Utf8Value exception(try_catch->Exception());
+
+    const Handle<Message> message = try_catch->Message();
+
+    // Print (filename):(line number): (message).
+    const String::Utf8Value filename(message->GetScriptResourceName());
+
+    ostringstream out;
+
+    if (*filename)
+        out << *filename;
+    if (!message.IsEmpty())
+        out << ": l. " << message->GetLineNumber();
+    if (*exception)
+        out << ": " << *exception;
+
+    JsException(out.str());
+
+    if (message.IsEmpty())
+        return;
+
+    // Print line of source code.
+    const String::Utf8Value sourceline(message->GetSourceLine());
+    if (*sourceline)
+        JsException(*sourceline);
+
+    // Print wavy underline (GetUnderline is deprecated).
+    const int start = message->GetStartColumn();
+    const int end   = message->GetEndColumn();
+
+    out.str("");
+    out << setfill(' ') <<  setw(start)     << ' ';
+    out << setfill('^') <<  setw(end-start) << '^';
+
+    JsException(out.str());
+
+    String::Utf8Value stack_trace(try_catch->StackTrace());
+    if (stack_trace.length()<=0)
+        return;
+
+    if (*stack_trace)
+        JsException(string("\n")+*stack_trace);
+}
+
+// Executes a string within the current v8 context.
+bool InterpreterV8::ExecuteStringNT(const Handle<String> &code, const Handle<Value> &file)
+{
+    if (code.IsEmpty())
+        return true;
+
+    const HandleScope handle_scope;
+
+    const Handle<Script> script = Script::Compile(code, file);
+    if (script.IsEmpty())
+        return false;
+
+    const Handle<Value> result = script->Run();
+    if (result.IsEmpty())
+        return false;
+
+    // If all went well and the result wasn't undefined then print
+    // the returned value.
+    if (!result->IsUndefined())
+        JsResult(*String::Utf8Value(result));
+
+    return true;
+}
+
+bool InterpreterV8::ExecuteCode(const Handle<String> &code, const Handle<Value> &file)
+{
+    TryCatch exception;
+
+    const bool rc = ExecuteStringNT(code, file);
+
+    if (!exception.CanContinue())
+        return false;
+
+    if (exception.HasCaught())
+    {
+        ReportException(&exception);
+        return false;
+    }
+    return rc;
+}
+
+bool InterpreterV8::ExecuteCode(const string &code, const string &file)
+{
+    return ExecuteCode(String::New(code.c_str(), code.size()),
+                         String::New(file.c_str()));
+}
+
+bool InterpreterV8::ExecuteFile(const string &name)
+{
+    ifstream fin(name.c_str());
+    if (!fin)
+    {
+        JsException("Error - Could not open file '"+name+"'");
+        return false;
+    }
+
+    string buffer;
+    if (!getline(fin, buffer, '\0'))
+        return true;
+
+    if (fin.fail())
+    {
+        JsException("Error - reading file.");
+        return false;
+    }
+
+    return ExecuteCode(buffer, name);
+}
+
+Handle<Value> InterpreterV8::FuncWait(const Arguments& args)
+{
+    if (args.Length()!=2 && args.Length()!=3)
+        return ThrowException(String::New("Number of arguments must be 2 or 3."));
+
+    if (!args[0]->IsString())
+        return ThrowException(String::New("Argument 1 not a string."));
+
+    if (!args[1]->IsInt32())
+        return ThrowException(String::New("Argument 2 not an int32."));
+
+    if (args.Length()==3 && !args[2]->IsUint32())
+        return ThrowException(String::New("Argument 3 not an uint32."));
+
+    const string   server   = *String::Utf8Value(args[0]);
+    const  int32_t state    = args[1]->Int32Value();
+    const uint32_t millisec = args.Length()==3 ? args[2]->Int32Value() : 0;
+
+    const int rc = JsWait(server, state, millisec);
+
+    if (rc==0 || rc==1)
+        return Boolean::New(rc);
+
+    return ThrowException(String::New(("Waitig for state "+to_string(state)+" of server '"+server+"' failed.").c_str()));
+}
+
+Handle<Value> InterpreterV8::FuncSend(const Arguments& args)
+{
+    if (args.Length()==0)
+        return ThrowException(String::New("Number of arguments must be at least 1."));
+
+    if (!args[0]->IsString())
+        return ThrowException(String::New("Argument 1 must be a string."));
+
+    const HandleScope handle_scope;
+
+    const String::Utf8Value str(args[0]);
+
+    string command = *str;
+
+    for (int i=1; i<args.Length(); i++)
+    {
+        const String::Utf8Value arg(args[i]);
+        command += " \""+string(*arg)+"\"";
+    }
+
+    return Boolean::New(JsSend(command));
+}
+
+Handle<Value> InterpreterV8::FuncSleep(const Arguments& args)
+{
+    if (args.Length()!=1)
+        return ThrowException(String::New("Number of arguments must be exactly 1."));
+
+    if (!args[0]->IsUint32())
+        return ThrowException(String::New("Argument 1 must be an uint32."));
+
+    const HandleScope handle_scope;
+
+    JsSleep(args[0]->Int32Value());
+
+    return Undefined();
+}
+
+// The callback that is invoked by v8 whenever the JavaScript 'print'
+// function is called.  Prints its arguments on stdout separated by
+// spaces and ending with a newline.
+Handle<Value> InterpreterV8::FuncPrint(const Arguments& args)
+{
+    for (int i=0; i<args.Length(); i++)
+    {
+        const HandleScope handle_scope;
+
+        const String::Utf8Value str(args[i]);
+        if (*str)
+            JsPrint(*str);
+    }
+    return Undefined();
+}
+
+// The callback that is invoked by v8 whenever the JavaScript 'load'
+// function is called.  Loads, compiles and executes its argument
+// JavaScript file.
+Handle<Value> InterpreterV8::FuncInclude(const Arguments& args)
+{
+    for (int i = 0; i<args.Length(); i++)
+    {
+        const HandleScope handle_scope;
+
+        const String::Utf8Value file(args[i]);
+        if (*file == NULL)
+            return ThrowException(String::New(("Error loading file '"+string(*file)+"'").c_str()));
+
+        if (!ExecuteFile(*file))
+            return ThrowException(String::New(("Execution of '"+string(*file)+"' failed").c_str()));
+    }
+    return Undefined();
+}
+
+Handle<Value> InterpreterV8::FuncVersion(const Arguments&)
+{
+    return String::New(V8::GetVersion());
+}
+
+bool InterpreterV8::JsRun(const string &filename)
+{
+    v8::Locker locker;
+    fThreadId = V8::GetCurrentThreadId();
+
+    JsLoad(filename);
+
+    HandleScope handle_scope;
+
+    // Create a template for the global object.
+    Handle<ObjectTemplate> dim = ObjectTemplate::New();
+    dim->Set(String::New("print"),   FunctionTemplate::New(WrapPrint),   ReadOnly);
+    dim->Set(String::New("wait"),    FunctionTemplate::New(WrapWait),    ReadOnly);
+    dim->Set(String::New("send"),    FunctionTemplate::New(WrapSend),    ReadOnly);
+
+    Handle<ObjectTemplate> global = ObjectTemplate::New();
+    global->Set(String::New("dim"), dim, ReadOnly);
+    global->Set(String::New("include"), FunctionTemplate::New(WrapInclude),                ReadOnly);
+    global->Set(String::New("sleep"),   FunctionTemplate::New(WrapSleep),                  ReadOnly);
+    global->Set(String::New("version"), FunctionTemplate::New(InterpreterV8::FuncVersion), ReadOnly);
+
+    // Persistent
+    Handle<Context> context = Context::New(NULL, global);
+    if (context.IsEmpty())
+    {
+        //printf("Error creating context\n");
+        return false;
+    }
+
+    JsStart(filename);
+
+    v8::Context::Scope scope(context);
+    //context->Enter();
+
+    v8::Locker::StartPreemption(10);
+    const bool rc = ExecuteFile(filename);
+    v8::Locker::StopPreemption();
+
+    //context->Exit();
+
+    JsEnd(filename);
+
+    //context.Dispose();
+
+    return rc;
+}
+
+void InterpreterV8::JsStop()
+{
+    v8::Locker locker;
+    //cout << "Terminate " << fThreadId << endl;
+    if (fThreadId>=0)
+        v8::V8::TerminateExecution(fThreadId);
+    //cout << "Terminate " << fThreadId << endl;
+    v8::Unlocker unlocker;
+}
+
+#endif
Index: /trunk/FACT++/src/InterpreterV8.h
===================================================================
--- /trunk/FACT++/src/InterpreterV8.h	(revision 14049)
+++ /trunk/FACT++/src/InterpreterV8.h	(revision 14049)
@@ -0,0 +1,67 @@
+#ifndef FACT_InterpreterV8
+#define FACT_InterpreterV8
+
+#include <string>
+
+#ifdef HAVE_V8
+#include <v8.h>
+#endif
+
+class InterpreterV8
+{
+    static InterpreterV8 *This;
+
+    int fThreadId;
+
+#ifdef HAVE_V8
+    void ReportException(v8::TryCatch* try_catch);
+    bool ExecuteStringNT(const v8::Handle<v8::String> &code, const v8::Handle<v8::Value>  &file);
+    bool ExecuteCode(const v8::Handle<v8::String> &code, const v8::Handle<v8::Value>  &file);
+    bool ExecuteCode(const std::string &code, const std::string &file="");
+    bool ExecuteFile(const std::string &name);
+
+    v8::Handle<v8::Value> FuncWait(const v8::Arguments& args);
+    v8::Handle<v8::Value> FuncSend(const v8::Arguments& args);
+    v8::Handle<v8::Value> FuncSleep(const v8::Arguments& args);
+    v8::Handle<v8::Value> FuncPrint(const v8::Arguments& args);
+    v8::Handle<v8::Value> FuncInclude(const v8::Arguments& args);
+
+    static v8::Handle<v8::Value> FuncVersion(const v8::Arguments&);
+    static v8::Handle<v8::Value> WrapInclude(const v8::Arguments &args) { if (This) return This->FuncInclude(args); else return v8::Undefined(); }
+    static v8::Handle<v8::Value> WrapPrint(const v8::Arguments &args)   { if (This) return This->FuncPrint(args);   else return v8::Undefined(); }
+    static v8::Handle<v8::Value> WrapWait(const v8::Arguments &args)    { if (This) return This->FuncWait(args);    else return v8::Undefined(); }
+    static v8::Handle<v8::Value> WrapSend(const v8::Arguments &args)    { if (This) return This->FuncSend(args);    else return v8::Undefined(); }
+    static v8::Handle<v8::Value> WrapSleep(const v8::Arguments &args)   { if (This) return This->FuncSleep(args);   else return v8::Undefined(); }
+#endif
+
+public:
+    InterpreterV8() : fThreadId(-1)
+    {
+        This = this;
+    }
+    virtual ~InterpreterV8()
+    {
+        This = 0;
+        // v8::Dispose();
+    }
+
+    virtual void JsLoad(const std::string &) { }
+    virtual void JsStart(const std::string &) { }
+    virtual void JsEnd(const std::string &) { }
+    virtual void JsPrint(const std::string &) { }
+    virtual void JsResult(const std::string &) { }
+    virtual void JsException(const std::string &) { }
+    virtual bool JsSend(const std::string &) { return true; }
+    virtual void JsSleep(uint32_t) { }
+    virtual int  JsWait(const std::string &, int32_t, uint32_t) { return -1; };
+
+    bool JsRun(const std::string &filename);
+    void JsStop();
+};
+
+#ifndef HAVE_V8
+inline bool InterpreterV8::JsRun(const std::string &) { return false; }
+inline void InterpreterV8::JsStop() { }
+#endif
+
+#endif
