<commit_before>#include <stdlib.h>
#include "nan.h"
#include "v8-debug.h"

namespace nodex {

  class Debug {
    public:

      static NAN_METHOD(Call) {
        NanScope();

        if (args.Length() < 1) {
          return NanThrowError("Error");
        }

        v8::Handle<v8::Function> fn = v8::Handle<v8::Function>::Cast(args[0]);
        v8::Debug::Call(fn);

        NanReturnUndefined();
      };

      static NAN_METHOD(Signal) {
        NanScope();

        int length = args[0]->ToString()->Length();
        const char* msg = *NanUtf8String(args[0]);

        uint16_t* command = new uint16_t[length + 1];
        for (int i = 0; i < length; i++)
          command[i] = msg[i];
        command[length] = '\0';
#if (NODE_MODULE_VERSION > 0x000B)
        v8::Isolate* debug_isolate = v8::Debug::GetDebugContext()->GetIsolate();
        v8::Debug::SendCommand(debug_isolate, command, length);
#else
        v8::Debug::SendCommand(command, length);
#endif
        delete[] command;
        NanReturnUndefined();
      };

      static NAN_METHOD(RunScript) {
        NanScope();

        v8::Local<v8::String> script_source(args[0]->ToString());
        if (script_source.IsEmpty())
          NanReturnUndefined();
        v8::Context::Scope context_scope(v8::Debug::GetDebugContext());
        v8::Local<v8::Script> script = v8::Script::Compile(script_source);
        if (script.IsEmpty())
          NanReturnUndefined();

        NanReturnValue(script->Run());
      };

      static NAN_METHOD(AllowNatives) {
        NanScope();

        const char allow_natives_syntax[] = "--allow_natives_syntax";
        v8::V8::SetFlagsFromString(allow_natives_syntax, sizeof(allow_natives_syntax) - 1);

        NanReturnUndefined();
      }

      static v8::Handle<v8::Object> createExceptionDetails(v8::Handle<v8::Message> message) {
        NanEscapableScope();

        v8::Handle<v8::Object> exceptionDetails = NanNew<v8::Object>();
        exceptionDetails->Set(NanNew<v8::String>("text"), message->Get());

#if (NODE_MODULE_VERSION > 0x000E)
        exceptionDetails->Set(NanNew<v8::String>("url"), message->GetScriptOrigin().ResourceName());
        exceptionDetails->Set(NanNew<v8::String>("scriptId"), NanNew<v8::Integer>(message->GetScriptOrigin().ScriptID()->Value()));
#else
        exceptionDetails->Set(NanNew<v8::String>("url"), message->GetScriptResourceName());
#endif
        exceptionDetails->Set(NanNew<v8::String>("line"), NanNew<v8::Integer>(message->GetLineNumber()));
        exceptionDetails->Set(NanNew<v8::String>("column"), NanNew<v8::Integer>(message->GetStartColumn()));

        if (!message->GetStackTrace().IsEmpty())
          exceptionDetails->Set(NanNew<v8::String>("stackTrace"), message->GetStackTrace()->AsArray());
        else
          exceptionDetails->Set(NanNew<v8::String>("stackTrace"), NanUndefined());

        return NanEscapeScope(exceptionDetails);
      };

      static NAN_METHOD(EvaluateWithExceptionDetails) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");

        v8::Local<v8::String> expression = args[0]->ToString();
        if (expression.IsEmpty())
          return NanThrowTypeError("The argument must be a string.");

        v8::TryCatch tryCatch;
        v8::Handle<v8::Value> result = NanRunScript(NanCompileScript(expression));

        v8::Local<v8::Object> wrappedResult = NanNew<v8::Object>();
        if (tryCatch.HasCaught()) {
          wrappedResult->Set(NanNew<v8::String>("result"), tryCatch.Exception());
          wrappedResult->Set(NanNew<v8::String>("exceptionDetails"), createExceptionDetails(tryCatch.Message()));
        } else {
          wrappedResult->Set(NanNew<v8::String>("result"), result);
          wrappedResult->Set(NanNew<v8::String>("exceptionDetails"), NanUndefined());
        }

        NanReturnValue(wrappedResult);
      };

      static NAN_METHOD(SetNonEnumProperty) {
        NanScope();

        if (args.Length() < 3)
          return NanThrowError("Three arguments expected.");
        if (!args[0]->IsObject())
          return NanThrowTypeError("Argument 0 must be an object.");
        if (!args[1]->IsString())
          return NanThrowTypeError("Argument 1 must be a string.");

        v8::Local<v8::Object> object = args[0]->ToObject();
        object->ForceSet(args[1], args[2], v8::DontEnum);

        NanReturnUndefined();
      };

      static NAN_METHOD(Subtype) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");

        v8::Handle<v8::Value> value = args[0];
        if (value->IsArray())
          NanReturnValue(NanNew<v8::String>("array"));
#if (NODE_MODULE_VERSION > 0x000B)
        if (value->IsTypedArray())
          NanReturnValue(NanNew<v8::String>("array"));
#endif
        if (value->IsDate())
          NanReturnValue(NanNew<v8::String>("date"));

        if (value->IsRegExp())
          NanReturnValue(NanNew<v8::String>("regexp"));

        if (value->IsNativeError())
          NanReturnValue(NanNew<v8::String>("error"));
#if (NODE_MODULE_VERSION > 0x000E)
        if (value->IsArgumentsObject())
          NanReturnValue(NanNew<v8::String>("array"));

        if (value->IsMap() || value->IsWeakMap())
          NanReturnValue(NanNew<v8::String>("map"));

        if (value->IsSet() || value->IsWeakSet())
          NanReturnValue(NanNew<v8::String>("set"));

        if (value->IsMapIterator() || value->IsSetIterator())
          NanReturnValue(NanNew<v8::String>("iterator"));
#endif
        NanReturnUndefined();
      };

      static v8::Local<v8::String> functionDisplayName(v8::Handle<v8::Function> function) {
        NanEscapableScope();

        v8::Handle<v8::Value> value;
#if (NODE_MODULE_VERSION > 0x000B)
        value = function->GetDisplayName();
        if (value->IsString() && value->ToString()->Length())
          return NanEscapeScope(value->ToString());
#endif
        value = function->GetName();
        if (value->IsString() && value->ToString()->Length())
          return NanEscapeScope(value->ToString());

        value = function->GetInferredName();
        if (value->IsString() && value->ToString()->Length())
          return NanEscapeScope(value->ToString());

        return NanEscapeScope(NanNew<v8::String>(""));
      };

      static NAN_METHOD(InternalConstructorName) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");
        if (!args[0]->IsObject())
          return NanThrowTypeError("The argument must be an object.");

        v8::Local<v8::Object> object = args[0]->ToObject();
        v8::Local<v8::String> result = object->GetConstructorName();

        char* result_type;
        if (result.IsEmpty() || result->IsNull() || result->IsUndefined())
          result_type = "";
        else
          result_type = *NanUtf8String(args[0]);

        if (!result.IsEmpty() && result_type == "Object") {
          v8::Local<v8::String> constructorSymbol = NanNew<v8::String>("constructor");
          if (object->HasRealNamedProperty(constructorSymbol) && !object->HasRealNamedCallbackProperty(constructorSymbol)) {
            v8::TryCatch tryCatch;
            v8::Local<v8::Value> constructor = object->GetRealNamedProperty(constructorSymbol);
            if (!constructor.IsEmpty() && constructor->IsFunction()) {
              v8::Local<v8::String> constructorName = functionDisplayName(v8::Handle<v8::Function>::Cast(constructor));
              if (!constructorName.IsEmpty() && !tryCatch.HasCaught())
                result = constructorName;
            }
          }
          if (result_type == "Object" && object->IsFunction())
            result = NanNew<v8::String>("Function");
        }

        NanReturnValue(result);
      }

      static NAN_METHOD(FunctionDetailsWithoutScopes) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");

        if (!args[0]->IsFunction())
          return NanThrowTypeError("The argument must be a function.");

        v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(args[0]);
        int lineNumber = function->GetScriptLineNumber();
        int columnNumber = function->GetScriptColumnNumber();

        v8::Local<v8::Object> location = NanNew<v8::Object>();
        location->Set(NanNew<v8::String>("lineNumber"), NanNew<v8::Integer>(lineNumber));
        location->Set(NanNew<v8::String>("columnNumber"), NanNew<v8::Integer>(columnNumber));
#if (NODE_MODULE_VERSION > 0x000B)
        location->Set(NanNew<v8::String>("scriptId"),
          NanNew<v8::Integer>(function->ScriptId())->ToString());
#else
        location->Set(NanNew<v8::String>("scriptId"),
          NanNew<v8::Integer>(function->GetScriptId()->ToInt32()->Value())->ToString());
#endif
        v8::Local<v8::Object> result = NanNew<v8::Object>();
        result->Set(NanNew<v8::String>("location"), location);

        v8::Handle<v8::String> name = functionDisplayName(function);
        result->Set(NanNew<v8::String>("functionName"), name.IsEmpty() ? NanNew<v8::String>("") : name);

        NanReturnValue(result);
      }

      static NAN_METHOD(CallFunction) {
        NanScope();

        if (args.Length() < 2 || args.Length() > 3)
          return NanThrowError("Two or three arguments expected.");
        if (!args[0]->IsFunction())
          return NanThrowTypeError("Argument 0 must be a function.");

        v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(args[0]);
#if (NODE_MODULE_VERSION > 0x000B)
        v8::Handle<v8::Value> receiver = args[1];
#else
        v8::Handle<v8::Object> receiver = args[1]->ToObject();
#endif

        if (args.Length() < 3 || args[2]->IsUndefined()) {
          v8::Local<v8::Value> result = function->Call(receiver, 0, NULL);
          NanReturnValue(result);
        }

        if (!args[2]->IsArray())
          return NanThrowTypeError("Argument 2 must be an array.");

        v8::Handle<v8::Array> arguments = v8::Handle<v8::Array>::Cast(args[2]);
        size_t argc = arguments->Length();
        v8::Handle<v8::Value> *argv = new v8::Handle<v8::Value>[argc];
        for (size_t i = 0; i < argc; ++i)
            argv[i] = arguments->Get(i);

        v8::Local<v8::Value> result = function->Call(receiver, argc, argv);

        delete [] argv;
        NanReturnValue(result);
      };

      static NAN_METHOD(Eval) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");

        v8::Local<v8::String> expression = args[0]->ToString();
        if (expression.IsEmpty())
          return NanThrowTypeError("The argument must be a string.");

        v8::TryCatch tryCatch;
        v8::Handle<v8::Script> script = v8::Script::Compile(expression);
        if (tryCatch.HasCaught())
          return NanThrowError(tryCatch.ReThrow());

        v8::Handle<v8::Value> result = NanRunScript(script);
        if (tryCatch.HasCaught())
          return NanThrowError(tryCatch.ReThrow());

        NanReturnValue(result);
      };

    private:
      Debug() {}
      ~Debug() {}
  };

  void Initialize(v8::Handle<v8::Object> target) {
    NanScope();

    NODE_SET_METHOD(target, "call", Debug::Call);
    NODE_SET_METHOD(target, "signal", Debug::Signal);
    NODE_SET_METHOD(target, "runScript", Debug::RunScript);
    NODE_SET_METHOD(target, "allowNatives", Debug::RunScript);

    v8::Local<v8::Object> InjectedScriptHost = NanNew<v8::Object>();
    NODE_SET_METHOD(InjectedScriptHost, "eval", Debug::Eval);
    NODE_SET_METHOD(InjectedScriptHost, "evaluateWithExceptionDetails", Debug::EvaluateWithExceptionDetails);
    NODE_SET_METHOD(InjectedScriptHost, "setNonEnumProperty", Debug::SetNonEnumProperty);
    NODE_SET_METHOD(InjectedScriptHost, "subtype", Debug::Subtype);
    NODE_SET_METHOD(InjectedScriptHost, "internalConstructorName", Debug::InternalConstructorName);
    NODE_SET_METHOD(InjectedScriptHost, "functionDetailsWithoutScopes", Debug::FunctionDetailsWithoutScopes);
    NODE_SET_METHOD(InjectedScriptHost, "callFunction", Debug::CallFunction);

    target->Set(NanNew<v8::String>("InjectedScriptHost"), InjectedScriptHost);
  }

  NODE_MODULE(debug, Initialize)
}
<commit_msg>Fix Linux compatibility<commit_after>#include <stdlib.h>
#include "nan.h"
#include "v8-debug.h"

namespace nodex {

  class Debug {
    public:

      static NAN_METHOD(Call) {
        NanScope();

        if (args.Length() < 1) {
          return NanThrowError("Error");
        }

        v8::Handle<v8::Function> fn = v8::Handle<v8::Function>::Cast(args[0]);
        v8::Debug::Call(fn);

        NanReturnUndefined();
      };

      static NAN_METHOD(Signal) {
        NanScope();

        v8::String::Value command(args[0]);
#if (NODE_MODULE_VERSION > 0x000B)
        v8::Isolate* debug_isolate = v8::Debug::GetDebugContext()->GetIsolate();
        v8::Debug::SendCommand(debug_isolate, *command, command.length());
#else
        v8::Debug::SendCommand(*command, command.length());
#endif
        NanReturnUndefined();
      };

      static NAN_METHOD(RunScript) {
        NanScope();

        v8::Local<v8::String> script_source(args[0]->ToString());
        if (script_source.IsEmpty())
          NanReturnUndefined();
        v8::Context::Scope context_scope(v8::Debug::GetDebugContext());
        v8::Local<v8::Script> script = v8::Script::Compile(script_source);
        if (script.IsEmpty())
          NanReturnUndefined();

        NanReturnValue(script->Run());
      };

      static NAN_METHOD(AllowNatives) {
        NanScope();

        const char allow_natives_syntax[] = "--allow_natives_syntax";
        v8::V8::SetFlagsFromString(allow_natives_syntax, sizeof(allow_natives_syntax) - 1);

        NanReturnUndefined();
      }

      static v8::Handle<v8::Object> createExceptionDetails(v8::Handle<v8::Message> message) {
        NanEscapableScope();

        v8::Handle<v8::Object> exceptionDetails = NanNew<v8::Object>();
        exceptionDetails->Set(NanNew<v8::String>("text"), message->Get());

#if (NODE_MODULE_VERSION > 0x000E)
        exceptionDetails->Set(NanNew<v8::String>("url"), message->GetScriptOrigin().ResourceName());
        exceptionDetails->Set(NanNew<v8::String>("scriptId"), NanNew<v8::Integer>(message->GetScriptOrigin().ScriptID()->Value()));
#else
        exceptionDetails->Set(NanNew<v8::String>("url"), message->GetScriptResourceName());
#endif
        exceptionDetails->Set(NanNew<v8::String>("line"), NanNew<v8::Integer>(message->GetLineNumber()));
        exceptionDetails->Set(NanNew<v8::String>("column"), NanNew<v8::Integer>(message->GetStartColumn()));

        if (!message->GetStackTrace().IsEmpty())
          exceptionDetails->Set(NanNew<v8::String>("stackTrace"), message->GetStackTrace()->AsArray());
        else
          exceptionDetails->Set(NanNew<v8::String>("stackTrace"), NanUndefined());

        return NanEscapeScope(exceptionDetails);
      };

      static NAN_METHOD(EvaluateWithExceptionDetails) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");

        v8::Local<v8::String> expression = args[0]->ToString();
        if (expression.IsEmpty())
          return NanThrowTypeError("The argument must be a string.");

        v8::TryCatch tryCatch;
        v8::Handle<v8::Value> result = NanRunScript(NanCompileScript(expression));

        v8::Local<v8::Object> wrappedResult = NanNew<v8::Object>();
        if (tryCatch.HasCaught()) {
          wrappedResult->Set(NanNew<v8::String>("result"), tryCatch.Exception());
          wrappedResult->Set(NanNew<v8::String>("exceptionDetails"), createExceptionDetails(tryCatch.Message()));
        } else {
          wrappedResult->Set(NanNew<v8::String>("result"), result);
          wrappedResult->Set(NanNew<v8::String>("exceptionDetails"), NanUndefined());
        }

        NanReturnValue(wrappedResult);
      };

      static NAN_METHOD(SetNonEnumProperty) {
        NanScope();

        if (args.Length() < 3)
          return NanThrowError("Three arguments expected.");
        if (!args[0]->IsObject())
          return NanThrowTypeError("Argument 0 must be an object.");
        if (!args[1]->IsString())
          return NanThrowTypeError("Argument 1 must be a string.");

        v8::Local<v8::Object> object = args[0]->ToObject();
        object->ForceSet(args[1], args[2], v8::DontEnum);

        NanReturnUndefined();
      };

      static NAN_METHOD(Subtype) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");

        v8::Handle<v8::Value> value = args[0];
        if (value->IsArray())
          NanReturnValue(NanNew<v8::String>("array"));
#if (NODE_MODULE_VERSION > 0x000B)
        if (value->IsTypedArray())
          NanReturnValue(NanNew<v8::String>("array"));
#endif
        if (value->IsDate())
          NanReturnValue(NanNew<v8::String>("date"));

        if (value->IsRegExp())
          NanReturnValue(NanNew<v8::String>("regexp"));

        if (value->IsNativeError())
          NanReturnValue(NanNew<v8::String>("error"));
#if (NODE_MODULE_VERSION > 0x000E)
        if (value->IsArgumentsObject())
          NanReturnValue(NanNew<v8::String>("array"));

        if (value->IsMap() || value->IsWeakMap())
          NanReturnValue(NanNew<v8::String>("map"));

        if (value->IsSet() || value->IsWeakSet())
          NanReturnValue(NanNew<v8::String>("set"));

        if (value->IsMapIterator() || value->IsSetIterator())
          NanReturnValue(NanNew<v8::String>("iterator"));
#endif
        NanReturnUndefined();
      };

      static v8::Local<v8::String> functionDisplayName(v8::Handle<v8::Function> function) {
        NanEscapableScope();

        v8::Handle<v8::Value> value;
#if (NODE_MODULE_VERSION > 0x000B)
        value = function->GetDisplayName();
        if (value->IsString() && value->ToString()->Length())
          return NanEscapeScope(value->ToString());
#endif
        value = function->GetName();
        if (value->IsString() && value->ToString()->Length())
          return NanEscapeScope(value->ToString());

        value = function->GetInferredName();
        if (value->IsString() && value->ToString()->Length())
          return NanEscapeScope(value->ToString());

        return NanEscapeScope(NanNew<v8::String>(""));
      };

      static NAN_METHOD(InternalConstructorName) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");
        if (!args[0]->IsObject())
          return NanThrowTypeError("The argument must be an object.");

        v8::Local<v8::Object> object = args[0]->ToObject();
        v8::Local<v8::String> result = object->GetConstructorName();

        char* result_type;
        if (result.IsEmpty() || result->IsNull() || result->IsUndefined())
          result_type = "";
        else
          result_type = *NanUtf8String(args[0]);

        if (!result.IsEmpty() && result_type == "Object") {
          v8::Local<v8::String> constructorSymbol = NanNew<v8::String>("constructor");
          if (object->HasRealNamedProperty(constructorSymbol) && !object->HasRealNamedCallbackProperty(constructorSymbol)) {
            v8::TryCatch tryCatch;
            v8::Local<v8::Value> constructor = object->GetRealNamedProperty(constructorSymbol);
            if (!constructor.IsEmpty() && constructor->IsFunction()) {
              v8::Local<v8::String> constructorName = functionDisplayName(v8::Handle<v8::Function>::Cast(constructor));
              if (!constructorName.IsEmpty() && !tryCatch.HasCaught())
                result = constructorName;
            }
          }
          if (result_type == "Object" && object->IsFunction())
            result = NanNew<v8::String>("Function");
        }

        NanReturnValue(result);
      }

      static NAN_METHOD(FunctionDetailsWithoutScopes) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");

        if (!args[0]->IsFunction())
          return NanThrowTypeError("The argument must be a function.");

        v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(args[0]);
        int lineNumber = function->GetScriptLineNumber();
        int columnNumber = function->GetScriptColumnNumber();

        v8::Local<v8::Object> location = NanNew<v8::Object>();
        location->Set(NanNew<v8::String>("lineNumber"), NanNew<v8::Integer>(lineNumber));
        location->Set(NanNew<v8::String>("columnNumber"), NanNew<v8::Integer>(columnNumber));
#if (NODE_MODULE_VERSION > 0x000B)
        location->Set(NanNew<v8::String>("scriptId"),
          NanNew<v8::Integer>(function->ScriptId())->ToString());
#else
        location->Set(NanNew<v8::String>("scriptId"),
          NanNew<v8::Integer>(function->GetScriptId()->ToInt32()->Value())->ToString());
#endif
        v8::Local<v8::Object> result = NanNew<v8::Object>();
        result->Set(NanNew<v8::String>("location"), location);

        v8::Handle<v8::String> name = functionDisplayName(function);
        result->Set(NanNew<v8::String>("functionName"), name.IsEmpty() ? NanNew<v8::String>("") : name);

        NanReturnValue(result);
      }

      static NAN_METHOD(CallFunction) {
        NanScope();

        if (args.Length() < 2 || args.Length() > 3)
          return NanThrowError("Two or three arguments expected.");
        if (!args[0]->IsFunction())
          return NanThrowTypeError("Argument 0 must be a function.");

        v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(args[0]);
#if (NODE_MODULE_VERSION > 0x000B)
        v8::Handle<v8::Value> receiver = args[1];
#else
        v8::Handle<v8::Object> receiver = args[1]->ToObject();
#endif

        if (args.Length() < 3 || args[2]->IsUndefined()) {
          v8::Local<v8::Value> result = function->Call(receiver, 0, NULL);
          NanReturnValue(result);
        }

        if (!args[2]->IsArray())
          return NanThrowTypeError("Argument 2 must be an array.");

        v8::Handle<v8::Array> arguments = v8::Handle<v8::Array>::Cast(args[2]);
        size_t argc = arguments->Length();
        v8::Handle<v8::Value> *argv = new v8::Handle<v8::Value>[argc];
        for (size_t i = 0; i < argc; ++i)
            argv[i] = arguments->Get(i);

        v8::Local<v8::Value> result = function->Call(receiver, argc, argv);

        delete [] argv;
        NanReturnValue(result);
      };

      static NAN_METHOD(Eval) {
        NanScope();

        if (args.Length() < 1)
          return NanThrowError("One argument expected.");

        v8::Local<v8::String> expression = args[0]->ToString();
        if (expression.IsEmpty())
          return NanThrowTypeError("The argument must be a string.");

        v8::TryCatch tryCatch;
        v8::Handle<v8::Script> script = v8::Script::Compile(expression);
        if (tryCatch.HasCaught())
          return NanThrowError(tryCatch.ReThrow());

        v8::Handle<v8::Value> result = NanRunScript(script);
        if (tryCatch.HasCaught())
          return NanThrowError(tryCatch.ReThrow());

        NanReturnValue(result);
      };

    private:
      Debug() {}
      ~Debug() {}
  };

  void Initialize(v8::Handle<v8::Object> target) {
    NanScope();

    NODE_SET_METHOD(target, "call", Debug::Call);
    NODE_SET_METHOD(target, "signal", Debug::Signal);
    NODE_SET_METHOD(target, "runScript", Debug::RunScript);
    NODE_SET_METHOD(target, "allowNatives", Debug::RunScript);

    v8::Local<v8::Object> InjectedScriptHost = NanNew<v8::Object>();
    NODE_SET_METHOD(InjectedScriptHost, "eval", Debug::Eval);
    NODE_SET_METHOD(InjectedScriptHost, "evaluateWithExceptionDetails", Debug::EvaluateWithExceptionDetails);
    NODE_SET_METHOD(InjectedScriptHost, "setNonEnumProperty", Debug::SetNonEnumProperty);
    NODE_SET_METHOD(InjectedScriptHost, "subtype", Debug::Subtype);
    NODE_SET_METHOD(InjectedScriptHost, "internalConstructorName", Debug::InternalConstructorName);
    NODE_SET_METHOD(InjectedScriptHost, "functionDetailsWithoutScopes", Debug::FunctionDetailsWithoutScopes);
    NODE_SET_METHOD(InjectedScriptHost, "callFunction", Debug::CallFunction);

    target->Set(NanNew<v8::String>("InjectedScriptHost"), InjectedScriptHost);
  }

  NODE_MODULE(debug, Initialize)
}
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//
// Demo Borland + vtk Project,
//
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

//---------------------------------------------------------------------------
#include "Form_Test.h"
//
#include "vtkTriangleFilter.h"
#include "vtkShrinkPolyData.h"
#include "vtkSphereSource.h"
#include "vtkElevationFilter.h"
#include "vtkPolyDataMapper.h"
#include "vtkPolyData.h"
#include "vtkActor.h"
//---------------------------------------------------------------------------

#pragma package(smart_init)
#pragma link "vtkBorlandRenderWindow"
#pragma resource "*.dfm"

TVTK_Form *VTK_Form;
//---------------------------------------------------------------------------
__fastcall TVTK_Form::TVTK_Form(TComponent* Owner) : TForm(Owner) {
  shrink = NULL;
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::FormDestroy(TObject *Sender) {
  vtkRenderer* ren1 = vtkWindow1->GetRenderer();
  ren1->GetProps()->RemoveAllItems();
  if (shrink) shrink->Delete();
}
//---------------------------------------------------------------------------

void __fastcall TVTK_Form::HeaderControl1SectionClick(THeaderControl *HeaderControl, THeaderSection *Section) {
    if (Section->Text=="Mode") {
        TPoint p = HeaderControl->ClientToScreen(TPoint(0,0));
        ModeMenu->Popup(p.x + Section->Left, p.y - 0);
    }
    else if (Section->Text=="Window") {
        TPoint p = HeaderControl->ClientToScreen(TPoint(0,0));
        WindowMenu->Popup(p.x + Section->Left, p.y - 0);
    }
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::TrackBallMode1Click(TObject *Sender) {
    if (Sender==JoystickMode1) {
        vtkWindow1->SetInteractorMode(IM_JoystickCamera);
        JoystickMode1->Checked = true;
    }
    if (Sender==TrackBallMode1) {
        vtkWindow1->SetInteractorMode(IM_TrackballCamera);
        TrackBallMode1->Checked = true;
    }
    if (Sender==FlightMode1) {
        vtkWindow1->SetInteractorMode(IM_Flight);
        FlightMode1->Checked = true;
    }
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::BackgroundColour1Click(TObject *Sender) {
    if (!backgroundcolor->Execute()) return;
    DWORD  L = ColorToRGB(backgroundcolor->Color);
    float rgb[3] = { GetRValue(L)/255.0, GetGValue(L)/255.0, GetBValue(L)/255.0 };
    vtkWindow1->GetRenderer()->SetBackground(rgb);
    vtkWindow1->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::ResetCamera1Click(TObject *Sender) {
    vtkWindow1->GetRenderer()->ResetCamera();
    vtkWindow1->Invalidate();
}
//---------------------------------------------------------------------------
//
//
// Here's a demo
//
//
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::bc1Click(TObject *Sender) {

    if (shrink) return;
    //
    vtkSphereSource *sphere = vtkSphereSource::New();
      sphere->SetThetaResolution(36.0);
      sphere->SetPhiResolution(18.0);
      sphere->SetRadius(1.0);

    shrink = vtkShrinkPolyData::New();
      shrink->SetShrinkFactor( ShrinkScroll->Position/100.0 );
      shrink->SetInput( sphere->GetOutput() );

    vtkElevationFilter *elev = vtkElevationFilter::New();
      elev->SetInput( shrink->GetOutput() );
        elev->SetLowPoint(-1,-1,-1);
        elev->SetHighPoint( 1, 1, 1);
        elev->SetScalarRange(0,1);

    vtkPolyDataMapper *aMapper = vtkPolyDataMapper::New();
      aMapper->SetInput( elev->GetPolyDataOutput() );
        aMapper->SetScalarRange(0,1);

    vtkActor *anActor = vtkActor::New();
      anActor->SetMapper(aMapper);

    // Use these functions to get the actual RenderWindow/Renderers
    vtkWindow1->GetRenderer()->AddActor(anActor);

    // we don't need these any more, they are reference counted by the
    // pipeline and we can delete them, They'll be destructed when everything
    // finishes
    anActor->Delete();
    aMapper->Delete();
    sphere->Delete();
    elev->Delete();
    // we'll keep a pointer to the shrinkfilter so we can use our scroller

    vtkWindow1->GetRenderer()->ResetCamera();
    vtkWindow1->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::ShrinkScrollChange(TObject *Sender) {
    if (!shrink) return;
    shrink->SetShrinkFactor( ShrinkScroll->Position/100.0 );
    vtkWindow1->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::vtkWindow1Enter(TObject *Sender)
{
    BorderWindow->Color = clMaroon;
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::vtkWindow1Exit(TObject *Sender)
{
    BorderWindow->Color = clBtnFace;
}
//---------------------------------------------------------------------------

<commit_msg>FIX: additional comments, style changes, two bug fixes<commit_after>//---------------------------------------------------------------------------
//
// Demo Borland + vtk Project,
//
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

//---------------------------------------------------------------------------
#include "Form_Test.h"
//
#include "vtkActor.h"
#include "vtkAssemblyPath.h"
#include "vtkAssemblyNode.h"
#include "vtkElevationFilter.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkShrinkPolyData.h"
#include "vtkSphereSource.h"
#include "vtkTriangleFilter.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)
#pragma link "vtkBorlandRenderWindow"
#pragma resource "*.dfm"

TVTK_Form *VTK_Form;
//---------------------------------------------------------------------------
__fastcall TVTK_Form::TVTK_Form(TComponent* Owner) : TForm(Owner)
{
  shrink = NULL;
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::FormDestroy(TObject *Sender)
{
  if (shrink)
    {
    shrink->Delete();
    }

  // The release of graphics resources is required here in
  // the event that an actor is switched between solid
  // and wireframe representations.  This cannot be implemented within
  // vtkBorlandRenderWindow, since ReleaseGraphicsResources, when called
  // by a vtkProp's mapper, will cause the internal vtkWin32OpenGLRenderWindow
  // to fail during MakeCurrent.

  vtkPropCollection *pc;
  vtkProp *aProp, *aPart;
  vtkAssemblyPath *path;
  vtkRenderer* ren1 = vtkWindow1->GetRenderer();
  vtkRenderWindow* renwin = vtkWindow1->GetRenderWindow();
  pc = ren1->GetProps();
  for (pc->InitTraversal(); (aProp = pc->GetNextProp()); )
    {
    for (aProp->InitPathTraversal(); (path=aProp->GetNextPath()); )
      {
      aPart=(vtkProp *)path->GetLastNode()->GetProp();
      aPart->ReleaseGraphicsResources(renwin);
      }
    }
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::HeaderControl1SectionClick(THeaderControl *HeaderControl, THeaderSection *Section)
{
  if (Section->Text=="Mode")
    {
    TPoint p = HeaderControl->ClientToScreen(TPoint(0,0));
    ModeMenu->Popup(p.x + Section->Left, p.y - 0);
    }
  else if (Section->Text=="Window")
    {
    TPoint p = HeaderControl->ClientToScreen(TPoint(0,0));
    WindowMenu->Popup(p.x + Section->Left, p.y - 0);
    }
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::TrackBallMode1Click(TObject *Sender)
{
  if (Sender==JoystickMode1)
    {
    vtkWindow1->SetInteractorMode(IM_JoystickCamera);
    JoystickMode1->Checked = true;
    }
  if (Sender==TrackBallMode1)
    {
    vtkWindow1->SetInteractorMode(IM_TrackballCamera);
    TrackBallMode1->Checked = true;
    }
  if (Sender==FlightMode1)
    {
    vtkWindow1->SetInteractorMode(IM_Flight);
    FlightMode1->Checked = true;
    }
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::BackgroundColour1Click(TObject *Sender)
{
  if (!backgroundcolor->Execute())
    {
    return;
    }
  DWORD  L = ColorToRGB(backgroundcolor->Color);
  float rgb[3] = { GetRValue(L)/255.0, GetGValue(L)/255.0, GetBValue(L)/255.0 };
  vtkWindow1->GetRenderer()->SetBackground(rgb);
  vtkWindow1->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::ResetCamera1Click(TObject *Sender)
{
  vtkWindow1->GetRenderer()->ResetCamera();
  vtkWindow1->Invalidate();
}
//---------------------------------------------------------------------------
//
//
// Here's a demo
//
//
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::bc1Click(TObject *Sender)
{
  if (shrink)
    {
    return;
    }

  vtkSphereSource *sphere = vtkSphereSource::New();
    sphere->SetThetaResolution(36.0);
    sphere->SetPhiResolution(18.0);
    sphere->SetRadius(1.0);

  shrink = vtkShrinkPolyData::New();
    shrink->SetShrinkFactor( ShrinkScroll->Position/100.0 );
    shrink->SetInput( sphere->GetOutput() );

  vtkElevationFilter *elev = vtkElevationFilter::New();
    elev->SetInput( shrink->GetOutput() );
    elev->SetLowPoint(-1,-1,-1);
    elev->SetHighPoint( 1, 1, 1);
    elev->SetScalarRange(0,1);

  vtkPolyDataMapper *aMapper = vtkPolyDataMapper::New();
    aMapper->SetInput( elev->GetPolyDataOutput() );
    aMapper->SetScalarRange(0,1);

  vtkActor *anActor = vtkActor::New();
    anActor->SetMapper(aMapper);

  // Use these functions to get the actual RenderWindow/Renderers.
  vtkWindow1->GetRenderer()->AddActor(anActor);

  // We don't need these any more, they are reference counted by the
  // pipeline and we can delete them. They'll be destructed when everything
  // finishes.  We'll keep a pointer to the shrinkfilter so we can use our
  // scroller.

  anActor->Delete();
  aMapper->Delete();
  sphere->Delete();
  elev->Delete();

  vtkWindow1->GetRenderer()->ResetCamera();
  vtkWindow1->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::ShrinkScrollChange(TObject *Sender)
{
  if (!shrink)
    {
    return;
    }
  shrink->SetShrinkFactor( ShrinkScroll->Position/100.0 );
  vtkWindow1->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::vtkWindow1Enter(TObject *Sender)
{
  BorderWindow->Color = clMaroon;
}
//---------------------------------------------------------------------------
void __fastcall TVTK_Form::vtkWindow1Exit(TObject *Sender)
{
  BorderWindow->Color = clBtnFace;
}
//---------------------------------------------------------------------------

void __fastcall TVTK_Form::FormShow(TObject *Sender)
{
  // These calls are made to enforce creation of the internal
  // vtk components of the vtkBorlandRenderWindow.  If this were
  // not done, clicking on the component would attempt to pass
  // window messages to non-existent entities.  This behaviour
  // could be changed in future.

  vtkRenderWindowInteractor * iact = vtkWindow1->GetInteractor();
  vtkRenderer* ren1 = vtkWindow1->GetRenderer();
}
//---------------------------------------------------------------------------

<|endoftext|>


<commit_before>/*
 * Jamoma OSC Receiver
 * Copyright © 2011, Théo de la Hogue
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTOscSocket.h"

TTPtr TTOscSocketListener(TTPtr anArgument)
{
	TTOscSocketPtr anOscSocket= (TTOscSocketPtr) anArgument;

	anOscSocket->mSocketListener = new UdpListeningReceiveSocket(IpEndpointName(IpEndpointName::ANY_ADDRESS, anOscSocket->mPort), anOscSocket);
	anOscSocket->mSocketListener->Run();

	return NULL;
}

TTOscSocket::TTOscSocket(const TTObjectBasePtr owner, const TTUInt16 port)
{
	mOwner = owner;
	mPort = port;

	mSocketListener = NULL;
	mSocketListenerThread = new TTThread(TTOscSocketListener, this);

	mSocketTransmitter = NULL;
}

TTOscSocket::TTOscSocket(const TTString& address, const TTUInt16 port)
{
	mAddress = address;
	mPort = port;

	mSocketTransmitter = new UdpTransmitSocket(IpEndpointName(address.data(), port));

	mSocketListener = NULL;
}

TTOscSocket::~TTOscSocket()
{
	unsigned int usecToStopTheSelect = 20000;

	if (mSocketListener) {

		mSocketListener->AsynchronousBreak();

#ifdef TT_PLATFORM_WIN
		Sleep(usecToStopTheSelect/1000);
#else
		usleep(usecToStopTheSelect);
#endif

		delete mSocketListener;
		mSocketListener = NULL;
	}

	if (mSocketTransmitter) {

		delete mSocketTransmitter;
		mSocketTransmitter = NULL;
	}
}

void TTOscSocket::ProcessMessage(const osc::ReceivedMessage&m, const IpEndpointName& remoteEndPoint)
{
	TTValue		receivedMessage = TTSymbol(m.AddressPattern());

	osc::ReceivedMessage::const_iterator arguments = m.ArgumentsBegin(); // get arguments

	while (arguments != m.ArgumentsEnd()) {

		if (arguments->IsChar())
			receivedMessage.append(arguments->AsChar());

		else if (arguments->IsInt32()) {
			TTInt32 i = arguments->AsInt32();
			receivedMessage.append((TTInt64)i);

		} else if (arguments->IsFloat())
			receivedMessage.append(arguments->AsFloat());

		else if (arguments->IsString())
			receivedMessage.append(TTSymbol(arguments->AsString()));

		arguments++;
	}

	this->mOwner->sendMessage(TTSymbol("oscSocketReceive"), receivedMessage, kTTValNONE);
}

TTErr TTOscSocket::SendMessage(TTSymbol& message, const TTValue& arguments)
{
	TTUInt32 bufferSize = computeMessageSize(message, arguments);

	if (!bufferSize)
		return kTTErrGeneric;

#ifdef TT_PLATFORM_WIN
	char* buffer = (char*)malloc(bufferSize);
#else
	char buffer[bufferSize];
#endif

	osc::OutboundPacketStream oscStream(buffer, bufferSize);

	oscStream << osc::BeginMessage(message.c_str());

	TTSymbol		symValue;
	TTInt32			intValue;
	TTFloat64		floatValue;
	TTBoolean		booleanValue;
	TTDataType		valueType;

	for (TTUInt32 i = 0; i < arguments.getSize(); ++i) {
		valueType = arguments.getType(i);

		if (valueType == kTypeSymbol|| arguments.getType(i) == kTypeAddress) {
			arguments.get(i, symValue);
			oscStream << symValue.c_str();
		}
		else if (valueType == kTypeBoolean) {
			arguments.get(i, booleanValue);
			oscStream << booleanValue;
		}
		else if (valueType == kTypeUInt8 || valueType == kTypeUInt16 || valueType == kTypeUInt32 || valueType == kTypeUInt64) {
			arguments.get(i, intValue);
			oscStream << intValue;
		}
		else if (valueType == kTypeInt8 || valueType == kTypeInt16 || valueType == kTypeInt32 || valueType == kTypeInt64) {
			arguments.get(i, intValue);
			oscStream << intValue;
		}
		else if (valueType == kTypeFloat32 || valueType == kTypeFloat64) {
			arguments.get(i, floatValue);
			oscStream << (float)floatValue;
		}
		else
			return kTTErrGeneric;
	}

	oscStream << osc::EndMessage;

	mSocketTransmitter->Send(oscStream.Data(), oscStream.Size());
	oscStream.Clear();

	return kTTErrNone;
}

TTUInt32 TTOscSocket::computeMessageSize(TTSymbol& message, const TTValue& arguments)
 {
	 TTUInt32 result = 0;

	 result += 8;														//#bundle
	 result += 8;														//timetag
	 result += 4;														//datasize

	 TTUInt32 messageSize = message.string().size();
	 messageSize += 1;													// /0 for end of string

	 result += ((messageSize/4) + 1) * 4;

	 TTUInt32 argumentSize = arguments.getSize();
	 argumentSize += 1;													// , for indicating this is an argument string information

	 result += ((argumentSize/4) + 1) * 4;								// ArgumentTag Size

	 for (TTUInt32 i = 0; i < arguments.getSize(); ++i) {

		 if (arguments.getType(i) == kTypeSymbol || arguments.getType(i) == kTypeAddress) {

			 TTSymbol symValue;
			 arguments.get(i, symValue);
			 TTUInt32 stringSize = symValue.string().size();
			 stringSize += 1;											// /0 for end of string
			 result += ((stringSize/4) + 1) * 4;						// String Size
		 }
		 else if (arguments.getType(i) == kTypeBoolean) {
			 result += 1;												// Boolean size
		 }
		 else if (arguments.getType(i) == kTypeUInt8 || arguments.getType(i) == kTypeInt8) {
			 result += 2;												// Int8 size
		 }
		 else if (arguments.getType(i) == kTypeUInt16 || arguments.getType(i) == kTypeInt16) {
			 result += 4;												// Int16 size
		 }
		 else if (arguments.getType(i) == kTypeUInt32 || arguments.getType(i) == kTypeInt32 || arguments.getType(i) == kTypeFloat32) {
			 result += 4;												// Float32/Int32 size
		 }
		 else if (arguments.getType(i) == kTypeUInt64 || arguments.getType(i) == kTypeInt64 || arguments.getType(i) == kTypeFloat64) {
			 result += 8;												// Float64/Int64 size
		 }
		 else
			 return 0;													// Error
	 }

	 return result;
 }<commit_msg>Removing kTypeAddress<commit_after>/*
 * Jamoma OSC Receiver
 * Copyright © 2011, Théo de la Hogue
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTOscSocket.h"

TTPtr TTOscSocketListener(TTPtr anArgument)
{
	TTOscSocketPtr anOscSocket= (TTOscSocketPtr) anArgument;

	anOscSocket->mSocketListener = new UdpListeningReceiveSocket(IpEndpointName(IpEndpointName::ANY_ADDRESS, anOscSocket->mPort), anOscSocket);
	anOscSocket->mSocketListener->Run();

	return NULL;
}

TTOscSocket::TTOscSocket(const TTObjectBasePtr owner, const TTUInt16 port)
{
	mOwner = owner;
	mPort = port;

	mSocketListener = NULL;
	mSocketListenerThread = new TTThread(TTOscSocketListener, this);

	mSocketTransmitter = NULL;
}

TTOscSocket::TTOscSocket(const TTString& address, const TTUInt16 port)
{
	mAddress = address;
	mPort = port;

	mSocketTransmitter = new UdpTransmitSocket(IpEndpointName(address.data(), port));

	mSocketListener = NULL;
}

TTOscSocket::~TTOscSocket()
{
	unsigned int usecToStopTheSelect = 20000;

	if (mSocketListener) {

		mSocketListener->AsynchronousBreak();

#ifdef TT_PLATFORM_WIN
		Sleep(usecToStopTheSelect/1000);
#else
		usleep(usecToStopTheSelect);
#endif

		delete mSocketListener;
		mSocketListener = NULL;
	}

	if (mSocketTransmitter) {

		delete mSocketTransmitter;
		mSocketTransmitter = NULL;
	}
}

void TTOscSocket::ProcessMessage(const osc::ReceivedMessage&m, const IpEndpointName& remoteEndPoint)
{
	TTValue		receivedMessage = TTSymbol(m.AddressPattern());

	osc::ReceivedMessage::const_iterator arguments = m.ArgumentsBegin(); // get arguments

	while (arguments != m.ArgumentsEnd()) {

		if (arguments->IsChar())
			receivedMessage.append(arguments->AsChar());

		else if (arguments->IsInt32()) {
			TTInt32 i = arguments->AsInt32();
			receivedMessage.append((TTInt64)i);

		} else if (arguments->IsFloat())
			receivedMessage.append(arguments->AsFloat());

		else if (arguments->IsString())
			receivedMessage.append(TTSymbol(arguments->AsString()));

		arguments++;
	}

	this->mOwner->sendMessage(TTSymbol("oscSocketReceive"), receivedMessage, kTTValNONE);
}

TTErr TTOscSocket::SendMessage(TTSymbol& message, const TTValue& arguments)
{
	TTUInt32 bufferSize = computeMessageSize(message, arguments);

	if (!bufferSize)
		return kTTErrGeneric;

#ifdef TT_PLATFORM_WIN
	char* buffer = (char*)malloc(bufferSize);
#else
	char buffer[bufferSize];
#endif

	osc::OutboundPacketStream oscStream(buffer, bufferSize);

	oscStream << osc::BeginMessage(message.c_str());

	TTSymbol		symValue;
	TTInt32			intValue;
	TTFloat64		floatValue;
	TTBoolean		booleanValue;
	TTDataType		valueType;

	for (TTUInt32 i = 0; i < arguments.getSize(); ++i) {
		valueType = arguments.getType(i);

		if (valueType == kTypeSymbol) {
			arguments.get(i, symValue);
			oscStream << symValue.c_str();
		}
		else if (valueType == kTypeBoolean) {
			arguments.get(i, booleanValue);
			oscStream << booleanValue;
		}
		else if (valueType == kTypeUInt8 || valueType == kTypeUInt16 || valueType == kTypeUInt32 || valueType == kTypeUInt64) {
			arguments.get(i, intValue);
			oscStream << intValue;
		}
		else if (valueType == kTypeInt8 || valueType == kTypeInt16 || valueType == kTypeInt32 || valueType == kTypeInt64) {
			arguments.get(i, intValue);
			oscStream << intValue;
		}
		else if (valueType == kTypeFloat32 || valueType == kTypeFloat64) {
			arguments.get(i, floatValue);
			oscStream << (float)floatValue;
		}
		else
			return kTTErrGeneric;
	}

	oscStream << osc::EndMessage;

	mSocketTransmitter->Send(oscStream.Data(), oscStream.Size());
	oscStream.Clear();

	return kTTErrNone;
}

TTUInt32 TTOscSocket::computeMessageSize(TTSymbol& message, const TTValue& arguments)
 {
	 TTUInt32 result = 0;

	 result += 8;														//#bundle
	 result += 8;														//timetag
	 result += 4;														//datasize

	 TTUInt32 messageSize = message.string().size();
	 messageSize += 1;													// /0 for end of string

	 result += ((messageSize/4) + 1) * 4;

	 TTUInt32 argumentSize = arguments.getSize();
	 argumentSize += 1;													// , for indicating this is an argument string information

	 result += ((argumentSize/4) + 1) * 4;								// ArgumentTag Size

	 for (TTUInt32 i = 0; i < arguments.getSize(); ++i) {

		 if (arguments.getType(i) == kTypeSymbol) {

			 TTSymbol symValue;
			 arguments.get(i, symValue);
			 TTUInt32 stringSize = symValue.string().size();
			 stringSize += 1;											// /0 for end of string
			 result += ((stringSize/4) + 1) * 4;						// String Size
		 }
		 else if (arguments.getType(i) == kTypeBoolean) {
			 result += 1;												// Boolean size
		 }
		 else if (arguments.getType(i) == kTypeUInt8 || arguments.getType(i) == kTypeInt8) {
			 result += 2;												// Int8 size
		 }
		 else if (arguments.getType(i) == kTypeUInt16 || arguments.getType(i) == kTypeInt16) {
			 result += 4;												// Int16 size
		 }
		 else if (arguments.getType(i) == kTypeUInt32 || arguments.getType(i) == kTypeInt32 || arguments.getType(i) == kTypeFloat32) {
			 result += 4;												// Float32/Int32 size
		 }
		 else if (arguments.getType(i) == kTypeUInt64 || arguments.getType(i) == kTypeInt64 || arguments.getType(i) == kTypeFloat64) {
			 result += 8;												// Float64/Int64 size
		 }
		 else
			 return 0;													// Error
	 }

	 return result;
 }<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010-2014 Jeremy Lainé
 * Contact: https://github.com/jlaine/qdjango
 *
 * This file is part of the QDjango Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

#include <QDebug>
#include <QLocalServer>
#include <QLocalSocket>
#include <QTcpServer>
#include <QTcpSocket>

#include "QDjangoFastCgiServer.h"
#include "QDjangoFastCgiServer_p.h"
#include "QDjangoHttpController.h"
#include "QDjangoHttpRequest.h"
#include "QDjangoHttpRequest_p.h"
#include "QDjangoHttpResponse.h"
#include "QDjangoHttpResponse_p.h"
#include "QDjangoHttpServer.h"
#include "QDjangoUrlResolver.h"

//#define QDJANGO_DEBUG_FCGI

#ifdef QDJANGO_DEBUG_FCGI
static void hDebug(FCGI_Header *header, const char *dir)
{
    const quint16 requestId = (header->requestIdB1 << 8) | header->requestIdB0;
    const quint16 contentLength = (header->contentLengthB1 << 8) | header->contentLengthB0;

    qDebug("--- FCGI Record %s ---", dir);
    qDebug("version: %i", header->version);
    qDebug("type: %i", header->type);
    qDebug("requestId: %i", requestId);
    qDebug("contentLength: %i", contentLength);
    qDebug("paddingLength: %i", header->paddingLength);
}
#endif

/// \cond

QDjangoFastCgiConnection::QDjangoFastCgiConnection(QIODevice *device, QDjangoFastCgiServer *server)
    : QObject(server),
    m_device(device),
    m_inputPos(0),
    m_pendingRequest(0),
    m_pendingRequestId(0),
    m_server(server)
{
    bool check;
    Q_UNUSED(check);

    m_device->setParent(this);
    check = connect(m_device, SIGNAL(disconnected()),
                    this, SIGNAL(closed()));
    Q_ASSERT(check);

    check = connect(m_device, SIGNAL(bytesWritten(qint64)),
                    this, SLOT(_q_bytesWritten(qint64)));
    Q_ASSERT(check);

    check = connect(m_device, SIGNAL(readyRead()),
                    this, SLOT(_q_readyRead()));
    Q_ASSERT(check);
}

QDjangoFastCgiConnection::~QDjangoFastCgiConnection()
{
    if (m_pendingRequest)
        delete m_pendingRequest;
}

void QDjangoFastCgiConnection::writeResponse(quint16 requestId, QDjangoHttpResponse *response)
{
    // serialise HTTP response
    QString httpHeader = QString::fromLatin1("Status: %1 %2\r\n").arg(response->d->statusCode).arg(response->d->reasonPhrase);
    QList<QPair<QString, QString> >::ConstIterator it = response->d->headers.constBegin();
    while (it != response->d->headers.constEnd()) {
        httpHeader += (*it).first + QLatin1String(": ") + (*it).second + QLatin1String("\r\n");
        ++it;
    }
    const QByteArray data = httpHeader.toUtf8() + "\r\n" + response->d->body;

    const char *ptr = data.constData();
    FCGI_Header *header = (FCGI_Header*)m_outputBuffer;
    memset(header, 0, FCGI_HEADER_LEN);
    header->version = 1;
    header->requestIdB1 = (requestId >> 8) & 0xff;
    header->requestIdB0 = (requestId & 0xff);

    for (qint64 bytesRemaining = data.size(); ; ) {
        const quint16 contentLength = qMin(bytesRemaining, qint64(32768));

        header->type = FCGI_STDOUT;
        header->contentLengthB1 = (contentLength >> 8) & 0xff;
        header->contentLengthB0 = (contentLength & 0xff);
        memcpy(m_outputBuffer + FCGI_HEADER_LEN, ptr, contentLength);
        m_device->write(m_outputBuffer, FCGI_HEADER_LEN + contentLength);
#ifdef QDJANGO_DEBUG_FCGI
        hDebug(header, "sent");
        qDebug("[STDOUT]");
#endif

        if (contentLength > 0) {
            ptr += contentLength;
            bytesRemaining -= contentLength;
        } else {
            break;
        }
    }

    quint16 contentLength = 8;
    header->type = FCGI_END_REQUEST;
    header->contentLengthB1 = (contentLength >> 8) & 0xff;
    header->contentLengthB0 = (contentLength & 0xff);
    memset(m_outputBuffer + FCGI_HEADER_LEN, 0, contentLength);
    m_device->write(m_outputBuffer, FCGI_HEADER_LEN + contentLength);
#ifdef QDJANGO_DEBUG_FCGI
    hDebug(header, "sent");
    qDebug("[END REQUEST]");
#endif
}

/** When bytes have been written, check whether we need to close
 *  the connection.
 *
 * @param bytes
 */
void QDjangoFastCgiConnection::_q_bytesWritten(qint64 bytes)
{
    Q_UNUSED(bytes);
    if (!m_device->bytesToWrite()) {
        m_device->close();
        emit closed();
    }
}

void QDjangoFastCgiConnection::_q_readyRead()
{
    while (m_device->bytesAvailable()) {
        // read record header
        if (m_inputPos < FCGI_HEADER_LEN) {
            const qint64 length = m_device->read(m_inputBuffer + m_inputPos, FCGI_HEADER_LEN - m_inputPos);
            if (length < 0) {
                qWarning("Failed to read header from socket");
                m_device->close();
                emit closed();
                return;
            }
            m_inputPos += length;
            if (m_inputPos < FCGI_HEADER_LEN)
                return;
        }

        // read record body
        FCGI_Header *header = (FCGI_Header*)m_inputBuffer;
        const quint16 contentLength = (header->contentLengthB1 << 8) | header->contentLengthB0;
        const quint16 bodyLength = contentLength + header->paddingLength;
        const qint64 length = m_device->read(m_inputBuffer + m_inputPos, bodyLength + FCGI_HEADER_LEN - m_inputPos);
        if (length < 0) {
            qWarning("Failed to read body from socket");
            m_device->close();
            emit closed();
            return;
        }
        m_inputPos += length;
        if (m_inputPos < FCGI_HEADER_LEN + bodyLength)
            return;
        m_inputPos = 0;

        // process record
#ifdef QDJANGO_DEBUG_FCGI
        hDebug(header, "received");
#endif
        const quint16 requestId = (header->requestIdB1 << 8) | header->requestIdB0;
        char *p = m_inputBuffer + FCGI_HEADER_LEN;
        switch (header->type) {
        case FCGI_BEGIN_REQUEST: {
#ifdef QDJANGO_DEBUG_FCGI
            const quint16 role = (p[0] << 8) | p[1];
            qDebug("[BEGIN REQUEST]");
            qDebug("role: %i", role);
            qDebug("flags: %i", p[2]);
#endif
            if (m_pendingRequest) {
                qWarning("Received FCGI_BEGIN_REQUEST inside a request");
                m_device->close();
                emit closed();
                break;
            }
            m_pendingRequest = new QDjangoHttpRequest;
            m_pendingRequestId = requestId;
            break;
        }
        case FCGI_ABORT_REQUEST:
            m_device->close();
            emit closed();
            break;
        case FCGI_PARAMS:
#ifdef QDJANGO_DEBUG_FCGI
            qDebug("[PARAMS]");
#endif
            if (!m_pendingRequest || requestId != m_pendingRequestId) {
                qWarning("Received FCGI_PARAMS outside a request");
                m_device->close();
                emit closed();
                break;
            }

            while (p < m_inputBuffer + FCGI_HEADER_LEN + contentLength) {
                quint32 nameLength;
                quint32 valueLength;
                if (p[0] >> 7) {
                    nameLength = ((p[0] & 0x7f) << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
                    p += 4;
                } else {
                    nameLength = p[0];
                    p++;
                }
                if (p[0] >> 7) {
                    valueLength = ((p[0] & 0x7f) << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
                    p += 4;
                } else {
                    valueLength = p[0];
                    p++;
                }
                const QByteArray name(p, nameLength);
                p += nameLength;
                const QByteArray value(p, valueLength);
                p += valueLength;

#ifdef QDJANGO_DEBUG_FCGI
                qDebug() << name << ":" << value;
#endif
                if (name == "PATH_INFO") {
                    m_pendingRequest->d->path = QString::fromUtf8(value);
                } else if (name == "REQUEST_METHOD") {
                    m_pendingRequest->d->method = QString::fromUtf8(value);
                }
                m_pendingRequest->d->meta.insert(QString::fromLatin1(name), QString::fromUtf8(value));
            }
            break;
        case FCGI_STDIN:
#ifdef QDJANGO_DEBUG_FCGI
            qDebug("[STDIN]");
#endif
            if (!m_pendingRequest || requestId != m_pendingRequestId) {
                qWarning("Received FCGI_STDIN outside a request");
                m_device->close();
                emit closed();
                break;
            }

            if (contentLength) {
                m_pendingRequest->d->buffer.append(p, contentLength);
            } else {
                QDjangoHttpRequest *request = m_pendingRequest;
                const quint16 requestId = m_pendingRequestId;

                m_pendingRequest = 0;
                m_pendingRequestId = 0;

                QDjangoHttpResponse *response = m_server->urls()->respond(*request, request->path());
                writeResponse(requestId, response);
            }
            break;
        default:
            qWarning("Unhandled request type %i", header->type);
            break;
        }
    }
}

/// \endcond

class QDjangoFastCgiServerPrivate
{
public:
    QDjangoFastCgiServerPrivate(QDjangoFastCgiServer *qq);
    QLocalServer *localServer;
    QTcpServer *tcpServer;
    QDjangoUrlResolver *urlResolver;

private:
    QDjangoFastCgiServer *q;
};

QDjangoFastCgiServerPrivate::QDjangoFastCgiServerPrivate(QDjangoFastCgiServer *qq)
    : localServer(0),
    tcpServer(0),
    q(qq)
{
    urlResolver = new QDjangoUrlResolver(q);
}

/** Constructs a new FastCGI server.
 */
QDjangoFastCgiServer::QDjangoFastCgiServer(QObject *parent)
    : QObject(parent)
{
    d = new QDjangoFastCgiServerPrivate(this);
}

/** Destroys the FastCGI server.
 */
QDjangoFastCgiServer::~QDjangoFastCgiServer()
{
    delete d;
}

/** Closes the server. The server will no longer listen for
 *  incoming connections.
 */
void QDjangoFastCgiServer::close()
{
    if (d->localServer)
        d->localServer->close();
    if (d->tcpServer)
        d->tcpServer->close();
}

/** Tells the server to listen for incoming connections on the given
 *  local socket.
 */
bool QDjangoFastCgiServer::listen(const QString &name)
{
    if (!d->localServer) {
        bool check;
        Q_UNUSED(check);

        d->localServer = new QLocalServer(this);
        check = connect(d->localServer, SIGNAL(newConnection()),
                        this, SLOT(_q_newLocalConnection()));
        Q_ASSERT(check);
    }

    return d->localServer->listen(name);
}

/** Tells the server to listen for incoming TCP connections on the given
 *  \a address and \a port.
 */
bool QDjangoFastCgiServer::listen(const QHostAddress &address, quint16 port)
{
    if (!d->tcpServer) {
        bool check;
        Q_UNUSED(check);

        d->tcpServer = new QTcpServer(this);
        check = connect(d->tcpServer, SIGNAL(newConnection()),
                        this, SLOT(_q_newTcpConnection()));
        Q_ASSERT(check);
    }

    return d->tcpServer->listen(address, port);
}

/** Returns the root URL resolver for the server, which dispatches
 *  requests to handlers.
 */
QDjangoUrlResolver* QDjangoFastCgiServer::urls() const
{
    return d->urlResolver;
}

void QDjangoFastCgiServer::_q_newLocalConnection()
{
    bool check;
    Q_UNUSED(check);

    QLocalSocket *socket;
    while ((socket = d->localServer->nextPendingConnection()) != 0) {
#ifdef QDJANGO_DEBUG_FCGI
        qDebug("New local connection");
#endif
        QDjangoFastCgiConnection *connection = new QDjangoFastCgiConnection(socket, this);
        check = connect(connection, SIGNAL(closed()),
                        connection, SLOT(deleteLater()));
        Q_ASSERT(check);
    }
}
void QDjangoFastCgiServer::_q_newTcpConnection()
{
    bool check;
    Q_UNUSED(check);

    QTcpSocket *socket;
    while ((socket = d->tcpServer->nextPendingConnection()) != 0) {
#ifdef QDJANGO_DEBUG_FCGI
        qDebug("New TCP connection");
#endif
        QDjangoFastCgiConnection *connection = new QDjangoFastCgiConnection(socket, this);
        check = connect(connection, SIGNAL(closed()),
                        connection, SLOT(deleteLater()));
        Q_ASSERT(check);
    }
}
<commit_msg>make fcgi server support REQUEST_URI<commit_after>/*
 * Copyright (C) 2010-2014 Jeremy Lainé
 * Contact: https://github.com/jlaine/qdjango
 *
 * This file is part of the QDjango Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

#include <QDebug>
#include <QLocalServer>
#include <QLocalSocket>
#include <QTcpServer>
#include <QTcpSocket>
#include <QUrl>

#include "QDjangoFastCgiServer.h"
#include "QDjangoFastCgiServer_p.h"
#include "QDjangoHttpController.h"
#include "QDjangoHttpRequest.h"
#include "QDjangoHttpRequest_p.h"
#include "QDjangoHttpResponse.h"
#include "QDjangoHttpResponse_p.h"
#include "QDjangoHttpServer.h"
#include "QDjangoUrlResolver.h"

//#define QDJANGO_DEBUG_FCGI

#ifdef QDJANGO_DEBUG_FCGI
static void hDebug(FCGI_Header *header, const char *dir)
{
    const quint16 requestId = (header->requestIdB1 << 8) | header->requestIdB0;
    const quint16 contentLength = (header->contentLengthB1 << 8) | header->contentLengthB0;

    qDebug("--- FCGI Record %s ---", dir);
    qDebug("version: %i", header->version);
    qDebug("type: %i", header->type);
    qDebug("requestId: %i", requestId);
    qDebug("contentLength: %i", contentLength);
    qDebug("paddingLength: %i", header->paddingLength);
}
#endif

/// \cond

QDjangoFastCgiConnection::QDjangoFastCgiConnection(QIODevice *device, QDjangoFastCgiServer *server)
    : QObject(server),
    m_device(device),
    m_inputPos(0),
    m_pendingRequest(0),
    m_pendingRequestId(0),
    m_server(server)
{
    bool check;
    Q_UNUSED(check);

    m_device->setParent(this);
    check = connect(m_device, SIGNAL(disconnected()),
                    this, SIGNAL(closed()));
    Q_ASSERT(check);

    check = connect(m_device, SIGNAL(bytesWritten(qint64)),
                    this, SLOT(_q_bytesWritten(qint64)));
    Q_ASSERT(check);

    check = connect(m_device, SIGNAL(readyRead()),
                    this, SLOT(_q_readyRead()));
    Q_ASSERT(check);
}

QDjangoFastCgiConnection::~QDjangoFastCgiConnection()
{
    if (m_pendingRequest)
        delete m_pendingRequest;
}

void QDjangoFastCgiConnection::writeResponse(quint16 requestId, QDjangoHttpResponse *response)
{
    // serialise HTTP response
    QString httpHeader = QString::fromLatin1("Status: %1 %2\r\n").arg(response->d->statusCode).arg(response->d->reasonPhrase);
    QList<QPair<QString, QString> >::ConstIterator it = response->d->headers.constBegin();
    while (it != response->d->headers.constEnd()) {
        httpHeader += (*it).first + QLatin1String(": ") + (*it).second + QLatin1String("\r\n");
        ++it;
    }
    const QByteArray data = httpHeader.toUtf8() + "\r\n" + response->d->body;

    const char *ptr = data.constData();
    FCGI_Header *header = (FCGI_Header*)m_outputBuffer;
    memset(header, 0, FCGI_HEADER_LEN);
    header->version = 1;
    header->requestIdB1 = (requestId >> 8) & 0xff;
    header->requestIdB0 = (requestId & 0xff);

    for (qint64 bytesRemaining = data.size(); ; ) {
        const quint16 contentLength = qMin(bytesRemaining, qint64(32768));

        header->type = FCGI_STDOUT;
        header->contentLengthB1 = (contentLength >> 8) & 0xff;
        header->contentLengthB0 = (contentLength & 0xff);
        memcpy(m_outputBuffer + FCGI_HEADER_LEN, ptr, contentLength);
        m_device->write(m_outputBuffer, FCGI_HEADER_LEN + contentLength);
#ifdef QDJANGO_DEBUG_FCGI
        hDebug(header, "sent");
        qDebug("[STDOUT]");
#endif

        if (contentLength > 0) {
            ptr += contentLength;
            bytesRemaining -= contentLength;
        } else {
            break;
        }
    }

    quint16 contentLength = 8;
    header->type = FCGI_END_REQUEST;
    header->contentLengthB1 = (contentLength >> 8) & 0xff;
    header->contentLengthB0 = (contentLength & 0xff);
    memset(m_outputBuffer + FCGI_HEADER_LEN, 0, contentLength);
    m_device->write(m_outputBuffer, FCGI_HEADER_LEN + contentLength);
#ifdef QDJANGO_DEBUG_FCGI
    hDebug(header, "sent");
    qDebug("[END REQUEST]");
#endif
}

/** When bytes have been written, check whether we need to close
 *  the connection.
 *
 * @param bytes
 */
void QDjangoFastCgiConnection::_q_bytesWritten(qint64 bytes)
{
    Q_UNUSED(bytes);
    if (!m_device->bytesToWrite()) {
        m_device->close();
        emit closed();
    }
}

void QDjangoFastCgiConnection::_q_readyRead()
{
    while (m_device->bytesAvailable()) {
        // read record header
        if (m_inputPos < FCGI_HEADER_LEN) {
            const qint64 length = m_device->read(m_inputBuffer + m_inputPos, FCGI_HEADER_LEN - m_inputPos);
            if (length < 0) {
                qWarning("Failed to read header from socket");
                m_device->close();
                emit closed();
                return;
            }
            m_inputPos += length;
            if (m_inputPos < FCGI_HEADER_LEN)
                return;
        }

        // read record body
        FCGI_Header *header = (FCGI_Header*)m_inputBuffer;
        const quint16 contentLength = (header->contentLengthB1 << 8) | header->contentLengthB0;
        const quint16 bodyLength = contentLength + header->paddingLength;
        const qint64 length = m_device->read(m_inputBuffer + m_inputPos, bodyLength + FCGI_HEADER_LEN - m_inputPos);
        if (length < 0) {
            qWarning("Failed to read body from socket");
            m_device->close();
            emit closed();
            return;
        }
        m_inputPos += length;
        if (m_inputPos < FCGI_HEADER_LEN + bodyLength)
            return;
        m_inputPos = 0;

        // process record
#ifdef QDJANGO_DEBUG_FCGI
        hDebug(header, "received");
#endif
        const quint16 requestId = (header->requestIdB1 << 8) | header->requestIdB0;
        char *p = m_inputBuffer + FCGI_HEADER_LEN;
        switch (header->type) {
        case FCGI_BEGIN_REQUEST: {
#ifdef QDJANGO_DEBUG_FCGI
            const quint16 role = (p[0] << 8) | p[1];
            qDebug("[BEGIN REQUEST]");
            qDebug("role: %i", role);
            qDebug("flags: %i", p[2]);
#endif
            if (m_pendingRequest) {
                qWarning("Received FCGI_BEGIN_REQUEST inside a request");
                m_device->close();
                emit closed();
                break;
            }
            m_pendingRequest = new QDjangoHttpRequest;
            m_pendingRequestId = requestId;
            break;
        }
        case FCGI_ABORT_REQUEST:
            m_device->close();
            emit closed();
            break;
        case FCGI_PARAMS:
#ifdef QDJANGO_DEBUG_FCGI
            qDebug("[PARAMS]");
#endif
            if (!m_pendingRequest || requestId != m_pendingRequestId) {
                qWarning("Received FCGI_PARAMS outside a request");
                m_device->close();
                emit closed();
                break;
            }

            while (p < m_inputBuffer + FCGI_HEADER_LEN + contentLength) {
                quint32 nameLength;
                quint32 valueLength;
                if (p[0] >> 7) {
                    nameLength = ((p[0] & 0x7f) << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
                    p += 4;
                } else {
                    nameLength = p[0];
                    p++;
                }
                if (p[0] >> 7) {
                    valueLength = ((p[0] & 0x7f) << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
                    p += 4;
                } else {
                    valueLength = p[0];
                    p++;
                }
                const QByteArray name(p, nameLength);
                p += nameLength;
                const QByteArray value(p, valueLength);
                p += valueLength;

#ifdef QDJANGO_DEBUG_FCGI
                qDebug() << name << ":" << value;
#endif
                if (name == "PATH_INFO") {
                    m_pendingRequest->d->path = QString::fromUtf8(value);
                } else if (name == "REQUEST_URI") {
                    m_pendingRequest->d->path = QUrl(QString::fromUtf8(value)).path();
                } else if (name == "REQUEST_METHOD") {
                    m_pendingRequest->d->method = QString::fromUtf8(value);
                }
                m_pendingRequest->d->meta.insert(QString::fromLatin1(name), QString::fromUtf8(value));
            }
            break;
        case FCGI_STDIN:
#ifdef QDJANGO_DEBUG_FCGI
            qDebug("[STDIN]");
#endif
            if (!m_pendingRequest || requestId != m_pendingRequestId) {
                qWarning("Received FCGI_STDIN outside a request");
                m_device->close();
                emit closed();
                break;
            }

            if (contentLength) {
                m_pendingRequest->d->buffer.append(p, contentLength);
            } else {
                QDjangoHttpRequest *request = m_pendingRequest;
                const quint16 requestId = m_pendingRequestId;

                m_pendingRequest = 0;
                m_pendingRequestId = 0;

                QDjangoHttpResponse *response = m_server->urls()->respond(*request, request->path());
                writeResponse(requestId, response);
            }
            break;
        default:
            qWarning("Unhandled request type %i", header->type);
            break;
        }
    }
}

/// \endcond

class QDjangoFastCgiServerPrivate
{
public:
    QDjangoFastCgiServerPrivate(QDjangoFastCgiServer *qq);
    QLocalServer *localServer;
    QTcpServer *tcpServer;
    QDjangoUrlResolver *urlResolver;

private:
    QDjangoFastCgiServer *q;
};

QDjangoFastCgiServerPrivate::QDjangoFastCgiServerPrivate(QDjangoFastCgiServer *qq)
    : localServer(0),
    tcpServer(0),
    q(qq)
{
    urlResolver = new QDjangoUrlResolver(q);
}

/** Constructs a new FastCGI server.
 */
QDjangoFastCgiServer::QDjangoFastCgiServer(QObject *parent)
    : QObject(parent)
{
    d = new QDjangoFastCgiServerPrivate(this);
}

/** Destroys the FastCGI server.
 */
QDjangoFastCgiServer::~QDjangoFastCgiServer()
{
    delete d;
}

/** Closes the server. The server will no longer listen for
 *  incoming connections.
 */
void QDjangoFastCgiServer::close()
{
    if (d->localServer)
        d->localServer->close();
    if (d->tcpServer)
        d->tcpServer->close();
}

/** Tells the server to listen for incoming connections on the given
 *  local socket.
 */
bool QDjangoFastCgiServer::listen(const QString &name)
{
    if (!d->localServer) {
        bool check;
        Q_UNUSED(check);

        d->localServer = new QLocalServer(this);
        check = connect(d->localServer, SIGNAL(newConnection()),
                        this, SLOT(_q_newLocalConnection()));
        Q_ASSERT(check);
    }

    return d->localServer->listen(name);
}

/** Tells the server to listen for incoming TCP connections on the given
 *  \a address and \a port.
 */
bool QDjangoFastCgiServer::listen(const QHostAddress &address, quint16 port)
{
    if (!d->tcpServer) {
        bool check;
        Q_UNUSED(check);

        d->tcpServer = new QTcpServer(this);
        check = connect(d->tcpServer, SIGNAL(newConnection()),
                        this, SLOT(_q_newTcpConnection()));
        Q_ASSERT(check);
    }

    return d->tcpServer->listen(address, port);
}

/** Returns the root URL resolver for the server, which dispatches
 *  requests to handlers.
 */
QDjangoUrlResolver* QDjangoFastCgiServer::urls() const
{
    return d->urlResolver;
}

void QDjangoFastCgiServer::_q_newLocalConnection()
{
    bool check;
    Q_UNUSED(check);

    QLocalSocket *socket;
    while ((socket = d->localServer->nextPendingConnection()) != 0) {
#ifdef QDJANGO_DEBUG_FCGI
        qDebug("New local connection");
#endif
        QDjangoFastCgiConnection *connection = new QDjangoFastCgiConnection(socket, this);
        check = connect(connection, SIGNAL(closed()),
                        connection, SLOT(deleteLater()));
        Q_ASSERT(check);
    }
}
void QDjangoFastCgiServer::_q_newTcpConnection()
{
    bool check;
    Q_UNUSED(check);

    QTcpSocket *socket;
    while ((socket = d->tcpServer->nextPendingConnection()) != 0) {
#ifdef QDJANGO_DEBUG_FCGI
        qDebug("New TCP connection");
#endif
        QDjangoFastCgiConnection *connection = new QDjangoFastCgiConnection(socket, this);
        check = connect(connection, SIGNAL(closed()),
                        connection, SLOT(deleteLater()));
        Q_ASSERT(check);
    }
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2014-2016 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/qt/widgets/properties/syntaxhighlighter.h>
#include <inviwo/core/util/settings/systemsettings.h>
#include <inviwo/core/common/inviwomodule.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/util/settings/systemsettings.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QTextDocument>
#include <QTextBlock>
#include <warn/pop>

static const char* python_keywords[] = {
    "\\band\\b",      "\\bas\\b",     "\\bassert\\b",  "\\bbreak\\b", "\\bclass\\b",
    "\\bcontinue\\b", "\\bdef\\b",    "\\bdel\\b",     "\\belif\\b",  "\\belse\\b",
    "\\bexcept\\b",   "\\bexec\\b",   "\\bfinally\\b", "\\bfor\\b",   "\\bfrom\\b",
    "\\bglobal\\b",   "\\bif\\b",     "\\bimport\\b",  "\\bin\\b",    "\\bis\\b",
    "\\blambda\\b",   "\\bnot\\b",    "\\bor\\b",      "\\bpass\\b",  "\\bprint\\b",
    "\\braise\\b",    "\\breturn\\b", "\\btry\\b",     "\\bwhile\\b", "\\bwith\\b",
    "\\byield\\b"};

namespace inviwo {

class PythonCommentFormater : public SyntaxFormater {
public:
    PythonCommentFormater(const QTextCharFormat& format)
        : format_(format){}

    virtual Result eval(const QString& text, const int& previousBlockState) override {
        Result res;
        res.format = &format_;
        auto index = text.indexOf('#');
        if (index != -1) {
            res.start.push_back(index);
            res.length.push_back(text.size() - index);
            return res;
        }

        return res;
    }

private:
    QTextCharFormat format_;
};

class PythonKeywordFormater : public SyntaxFormater {
public:
    virtual Result eval(const QString& text, const int& previousBlockState) override {
        Result result;
        result.format = &format_;
        std::vector<QRegExp>::iterator reg;

        for (reg = regexps_.begin(); reg != regexps_.end(); ++reg) {
            int pos = 0;

            while ((pos = reg->indexIn(text, pos)) != -1) {
                result.start.push_back(pos);
                pos += std::max(1, reg->matchedLength());
                result.length.push_back(reg->matchedLength());
            }
        }

        return result;
    }

    PythonKeywordFormater(const QTextCharFormat& format, const char** keywords) : format_(format) {
        int i = -1;

        while (keywords[++i]) regexps_.push_back(QRegExp(keywords[i]));
    }

private:
    QTextCharFormat format_;
    std::vector<QRegExp> regexps_;
};

static inline QColor ivec4toQtColor(const ivec4& i) { return QColor(i.r, i.g, i.b, i.a); }

template <>
void SyntaxHighligther::loadConfig<Python>() {
    auto sysSettings = InviwoApplication::getPtr()->getSettingsByType<SystemSettings>();

    QColor textColor = ivec4toQtColor(sysSettings->pyTextColor_.get());
    QColor bgColor = ivec4toQtColor(sysSettings->pyBGColor_.get());
    defaultFormat_.setBackground(bgColor);
    defaultFormat_.setForeground(textColor);
    QTextCharFormat typeformat, commentformat;
    typeformat.setBackground(bgColor);
    typeformat.setForeground(ivec4toQtColor(sysSettings->pyTypeColor_.get()));
    commentformat.setBackground(bgColor);
    commentformat.setForeground(ivec4toQtColor(sysSettings->pyCommentsColor_.get()));
    if (formaters_.empty())
        sysSettings->pythonSyntax_.onChange(this, &SyntaxHighligther::loadConfig<Python>);
    else {
        while (!formaters_.empty()) {
            delete formaters_.back();
            formaters_.pop_back();
        }
    }
    formaters_.push_back(new PythonKeywordFormater(typeformat, python_keywords));
    formaters_.push_back(new PythonCommentFormater(commentformat));
}

}  // namespace
<commit_msg>Qt: PythonHighlighter: Using vector instead of char* array to prevent crashes, closes inviwo/inviwo-dev#1289<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2014-2016 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/qt/widgets/properties/syntaxhighlighter.h>
#include <inviwo/core/util/settings/systemsettings.h>
#include <inviwo/core/common/inviwomodule.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/util/settings/systemsettings.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QTextDocument>
#include <QTextBlock>
#include <warn/pop>

static const std::vector<std::string>  python_keywords = {
    "\\band\\b",      "\\bas\\b",     "\\bassert\\b",  "\\bbreak\\b", "\\bclass\\b",
    "\\bcontinue\\b", "\\bdef\\b",    "\\bdel\\b",     "\\belif\\b",  "\\belse\\b",
    "\\bexcept\\b",   "\\bexec\\b",   "\\bfinally\\b", "\\bfor\\b",   "\\bfrom\\b",
    "\\bglobal\\b",   "\\bif\\b",     "\\bimport\\b",  "\\bin\\b",    "\\bis\\b",
    "\\blambda\\b",   "\\bnot\\b",    "\\bor\\b",      "\\bpass\\b",  "\\bprint\\b",
    "\\braise\\b",    "\\breturn\\b", "\\btry\\b",     "\\bwhile\\b", "\\bwith\\b",
    "\\byield\\b"};

namespace inviwo {

class PythonCommentFormater : public SyntaxFormater {
public:
    PythonCommentFormater(const QTextCharFormat& format)
        : format_(format){}

    virtual Result eval(const QString& text, const int& previousBlockState) override {
        Result res;
        res.format = &format_;
        auto index = text.indexOf('#');
        if (index != -1) {
            res.start.push_back(index);
            res.length.push_back(text.size() - index);
            return res;
        }

        return res;
    }

private:
    QTextCharFormat format_;
};

class PythonKeywordFormater : public SyntaxFormater {
public:
    virtual Result eval(const QString& text, const int& previousBlockState) override {
        Result result;
        result.format = &format_;
        std::vector<QRegExp>::iterator reg;

        for (reg = regexps_.begin(); reg != regexps_.end(); ++reg) {
            int pos = 0;

            while ((pos = reg->indexIn(text, pos)) != -1) {
                result.start.push_back(pos);
                pos += std::max(1, reg->matchedLength());
                result.length.push_back(reg->matchedLength());
            }
        }

        return result;
    }

    PythonKeywordFormater(const QTextCharFormat& format, const std::vector<std::string> &keywords) : format_(format) {
        int i = -1;

        for (const auto &key : keywords) {
            regexps_.push_back(QRegExp(key.c_str()));
        }
    }

private:
    QTextCharFormat format_;
    std::vector<QRegExp> regexps_;
};

static inline QColor ivec4toQtColor(const ivec4& i) { return QColor(i.r, i.g, i.b, i.a); }

template <>
void SyntaxHighligther::loadConfig<Python>() {
    auto sysSettings = InviwoApplication::getPtr()->getSettingsByType<SystemSettings>();

    QColor textColor = ivec4toQtColor(sysSettings->pyTextColor_.get());
    QColor bgColor = ivec4toQtColor(sysSettings->pyBGColor_.get());
    defaultFormat_.setBackground(bgColor);
    defaultFormat_.setForeground(textColor);
    QTextCharFormat typeformat, commentformat;
    typeformat.setBackground(bgColor);
    typeformat.setForeground(ivec4toQtColor(sysSettings->pyTypeColor_.get()));
    commentformat.setBackground(bgColor);
    commentformat.setForeground(ivec4toQtColor(sysSettings->pyCommentsColor_.get()));
    if (formaters_.empty())
        sysSettings->pythonSyntax_.onChange(this, &SyntaxHighligther::loadConfig<Python>);
    else {
        while (!formaters_.empty()) {
            delete formaters_.back();
            formaters_.pop_back();
        }
    }
    formaters_.push_back(new PythonKeywordFormater(typeformat, python_keywords));
    formaters_.push_back(new PythonCommentFormater(commentformat));
}

}  // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2011 Seiya Tokui <beam.web@gmail.com>. All Rights Reserved.
// This source code is distributed under MIT License in LICENSE file.

#ifndef ELOG_ELOG_HPP_
#define ELOG_ELOG_HPP_

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <type_traits>
#include <utility>

#ifdef _WIN32
# include <windows.h>
#else
# include <sys/time.h>
#endif

namespace LOG
{

// utility

template<typename T, typename U = void>
struct enable_if_exist
{
  typedef U type;
};

template<typename T>
struct identity
{
  typedef T type;
};

template<typename T,
         typename enable_if_exist<typename T::value_type, int>::type = 0,
         typename enable_if_exist<typename T::iterator, int>::type = 0>
std::true_type
is_range_fn(int);

template<typename T,
          typename std::enable_if<std::is_array<T>::value, int>::type = 0>
std::true_type
is_range_fn(int);

template<typename>
std::false_type
is_range_fn(...);

template<typename T>
struct is_range
    : identity<decltype(is_range_fn<T>(0))>::type
{};

template<typename T,
         typename enable_if_exist<typename T::first_type>::type = 0,
         typename enable_if_exist<typename T::second_type>::type = 0>
std::true_type
is_pair_fn(int);

template<typename T>
std::false_type
is_pair_fn(...);

template<typename T>
struct is_pair
    : identity<decltype(is_pair_fn<T>(0))>::type
{};

// time

inline double
gettime_sec()
{
#ifdef _WIN32
  LARGE_INTEGER t, f;
  QueryPerformanceCounter(&t);
  QueryPerformanceFrequency(&f);
  return t.QuadPart * 1.0 / f.QuadPart;
#else
  timeval tv;
  gettimeofday(&tv, 0);
  return tv.tv_sec + tv.tv_usec * 1e-6;
#endif
}

template<typename Stream>
void
pritty_print_time(Stream& stream, double sec)
{
  long long min = sec / 60;
  sec -= min * 60;
  long long hour = min / 60;
  min -= hour * 60;
  long long day = hour / 24;
  hour -= day * 24;

  if (min > 0) {
    if (hour > 0) {
      if (day > 0) stream << day << "d ";
      stream << hour << "h ";
    }
    stream << min << "m ";
  }
  stream << sec << "s";
}

// print value to output stream

template<typename T, typename Stream>
void
pritty_print_internal(const T& t, Stream& stream, ...)
{ stream << t; }

template<typename T,
         typename Stream,
         typename std::enable_if<is_pair<T>::value, int>::type = 0>
void
pritty_print_internal(const T& pair, Stream& stream, int)
{
  stream << '(';
  pritty_print_internal(pair.first, stream, 0);
  stream << ", ";
  pritty_print_internal(pair.second, stream, 0);
  stream << ')';
}

template<typename T,
         typename Stream,
         typename std::enable_if<is_range<T>::value, int>::type = 0>
void
pritty_print_internal(const T& range, Stream& stream, int)
{
  stream << '[';

  bool is_tail = false;
  for (const auto& elem : range) {
    if (is_tail) stream << ", ";

    is_tail = true;
    pritty_print_internal(elem, stream, 0);
  }

  stream << ']';
}

template<typename Stream>
void
pritty_print_internal(signed char t, Stream& stream, int)
{ stream << static_cast<int>(t); }

template<typename Stream>
void
pritty_print_internal(unsigned char t, Stream& stream, int)
{ stream << static_cast<unsigned int>(t); }

template<typename T, typename Stream>
void
pritty_print(const T& t, Stream& stream)
{ pritty_print_internal(t, stream, 0); }

// argument list to stream
template<typename Stream>
Stream&
print_arguments(Stream& stream)
{ return stream; }

template<typename Stream, typename T, typename ... Args>
Stream&
print_arguments(Stream& stream, const T& t, Args... args)
{
  stream << t;
  return print_arguments(stream, args...);
}

// logger

struct logger_base
{
  virtual
  ~logger_base()
  {};

  virtual
  void
  write(const std::string& message) const = 0;
};

// TODO: Support multi-thread use
struct stream_logger
    : logger_base
{
  stream_logger()
      : os_(&std::clog)
  {}

  void
  set_stream(std::ostream& os)
  { os_ = &os; }

  virtual
  void
  write(const std::string& message) const
  { (*os_) << message; }

 private:
  std::ostream* os_;
};

enum avoid_odr
{ AVOID_ODR };

template<typename T, avoid_odr = AVOID_ODR>
struct static_holder
{ static T value; };

template<typename T, avoid_odr A>
T static_holder<T, A>::value;

struct global_logger_holder
{
  global_logger_holder()
      : logger(&static_holder<stream_logger>::value)
  {}

  logger_base* logger;
};

inline
logger_base&
get_logger()
{ return *static_holder<global_logger_holder>::value.logger; }

inline
void
set_stream(std::ostream& os)
{ static_holder<stream_logger>::value.set_stream(os); }

// message construction

struct message_builder
{
  template<typename T>
  void
  operator()(const T& t)
  { pritty_print(t, oss_); }

  std::string
  get() const
  { return oss_.str(); }

 private:
  std::ostringstream oss_;
};

struct log_emitter
{
  log_emitter()
      : logger_(get_logger())
  {}

  explicit
  log_emitter(logger_base& logger)
      : logger_(logger)
  {}

  template<typename T>
  log_emitter&
  operator<<(const T& t)
  {
    message_builder_(t);
    return *this;
  }

  log_emitter&
  self()
  { return *this; }

  void
  emit() const
  { logger_.write(message_builder_.get()); }

 private:
  logger_base& logger_;
  message_builder message_builder_;
};

struct log_emission_trigger
{
  void
  operator&(const log_emitter& emitter) const
  { emitter.emit(); }
};

struct check_error
    : std::exception
{};

struct check_emission_trigger
{
  void
  operator&(const log_emitter& emitter) const
  {
    emitter.emit();
    throw check_error();
  }
};

// benchmark

struct benchmark
{
  benchmark()
      : logger_(get_logger()),
        start_sec_(gettime_sec()),
        done_(false)
  {}

  explicit
  benchmark(logger_base& logger)
      : logger_(logger),
        start_sec_(gettime_sec()),
        done_(false)
  {}

  explicit
  operator bool() const
  { return false; }

  ~benchmark()
  { if (!done_) push_message(); }

  template<typename T>
  benchmark&
  operator<<(const T& t)
  {
    title_builder_ << t;
    return *this;
  }

  double
  gettime() const
  { return gettime_sec() - start_sec_; }

  void
  push_message()
  {
    done_ = true;
    const auto duration = gettime_sec() - start_sec_;

    log_emitter emitter(logger_);
    emitter << title_builder_.get() << ": " << duration << " sec";
    if (duration >= 60) {
      emitter << " (";
      pritty_print_time(emitter, duration);
      emitter << ")";
    }
    emitter.emit();
  }

 private:
  logger_base& logger_;
  double start_sec_;

  message_builder title_builder_;

  bool done_;
};

}  // namespace LOG

#define LOG() ::LOG::log_emission_trigger() & ::LOG::log_emitter().self()

#define CHECK(cond) \
  (cond) ? (void)0 : \
  ::LOG::check_emission_trigger() & ::LOG::log_emitter().self();

#define BENCHMARK(varname, ...) \
  if (auto varname = ::LOG::benchmark()); \
  else if (!&::LOG::print_arguments(varname, __VA_ARGS__)); else

#endif  // ELOG_ELOG_HPP_
<commit_msg>fix coding rule<commit_after>// Copyright (c) 2011 Seiya Tokui <beam.web@gmail.com>. All Rights Reserved.
// This source code is distributed under MIT License in LICENSE file.

#ifndef ELOG_ELOG_HPP_
#define ELOG_ELOG_HPP_

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <type_traits>
#include <utility>

#ifdef _WIN32
# include <windows.h>
#else
# include <sys/time.h>
#endif

namespace LOG
{

// utility

template<typename T, typename U = void>
struct enable_if_exist
{ typedef U type; };

template<typename T>
struct identity
{ typedef T type; };

template<typename T,
         typename enable_if_exist<typename T::value_type, int>::type = 0,
         typename enable_if_exist<typename T::iterator, int>::type = 0>
std::true_type
is_range_fn(int);

template<typename T,
          typename std::enable_if<std::is_array<T>::value, int>::type = 0>
std::true_type
is_range_fn(int);

template<typename>
std::false_type
is_range_fn(...);

template<typename T>
struct is_range
    : identity<decltype(is_range_fn<T>(0))>::type
{};

template<typename T,
         typename enable_if_exist<typename T::first_type>::type = 0,
         typename enable_if_exist<typename T::second_type>::type = 0>
std::true_type
is_pair_fn(int);

template<typename T>
std::false_type
is_pair_fn(...);

template<typename T>
struct is_pair
    : identity<decltype(is_pair_fn<T>(0))>::type
{};

// time

inline double
gettime_sec()
{
#ifdef _WIN32
  LARGE_INTEGER t, f;
  QueryPerformanceCounter(&t);
  QueryPerformanceFrequency(&f);
  return t.QuadPart * 1.0 / f.QuadPart;
#else
  timeval tv;
  gettimeofday(&tv, 0);
  return tv.tv_sec + tv.tv_usec * 1e-6;
#endif
}

template<typename Stream>
void
pritty_print_time(Stream& stream, double sec)
{
  long long min = sec / 60;
  sec -= min * 60;
  long long hour = min / 60;
  min -= hour * 60;
  long long day = hour / 24;
  hour -= day * 24;

  if (min > 0) {
    if (hour > 0) {
      if (day > 0) stream << day << "d ";
      stream << hour << "h ";
    }
    stream << min << "m ";
  }
  stream << sec << "s";
}

// print value to output stream

template<typename T, typename Stream>
void
pritty_print_internal(const T& t, Stream& stream, ...)
{ stream << t; }

template<typename T,
         typename Stream,
         typename std::enable_if<is_pair<T>::value, int>::type = 0>
void
pritty_print_internal(const T& pair, Stream& stream, int)
{
  stream << '(';
  pritty_print_internal(pair.first, stream, 0);
  stream << ", ";
  pritty_print_internal(pair.second, stream, 0);
  stream << ')';
}

template<typename T,
         typename Stream,
         typename std::enable_if<is_range<T>::value, int>::type = 0>
void
pritty_print_internal(const T& range, Stream& stream, int)
{
  stream << '[';

  bool is_tail = false;
  for (const auto& elem : range) {
    if (is_tail) stream << ", ";

    is_tail = true;
    pritty_print_internal(elem, stream, 0);
  }

  stream << ']';
}

template<typename Stream>
void
pritty_print_internal(signed char t, Stream& stream, int)
{ stream << static_cast<int>(t); }

template<typename Stream>
void
pritty_print_internal(unsigned char t, Stream& stream, int)
{ stream << static_cast<unsigned int>(t); }

template<typename T, typename Stream>
void
pritty_print(const T& t, Stream& stream)
{ pritty_print_internal(t, stream, 0); }

// argument list to stream
template<typename Stream>
Stream&
print_arguments(Stream& stream)
{ return stream; }

template<typename Stream, typename T, typename ... Args>
Stream&
print_arguments(Stream& stream, const T& t, Args... args)
{
  stream << t;
  return print_arguments(stream, args...);
}

// logger

struct logger_base
{
  virtual
  ~logger_base()
  {};

  virtual
  void
  write(const std::string& message) const = 0;
};

// TODO: Support multi-thread use
struct stream_logger
    : logger_base
{
  stream_logger()
      : os_(&std::clog)
  {}

  void
  set_stream(std::ostream& os)
  { os_ = &os; }

  virtual
  void
  write(const std::string& message) const
  { (*os_) << message; }

 private:
  std::ostream* os_;
};

enum avoid_odr
{ AVOID_ODR };

template<typename T, avoid_odr = AVOID_ODR>
struct static_holder
{ static T value; };

template<typename T, avoid_odr A>
T static_holder<T, A>::value;

struct global_logger_holder
{
  global_logger_holder()
      : logger(&static_holder<stream_logger>::value)
  {}

  logger_base* logger;
};

inline
logger_base&
get_logger()
{ return *static_holder<global_logger_holder>::value.logger; }

inline
void
set_stream(std::ostream& os)
{ static_holder<stream_logger>::value.set_stream(os); }

// message construction

struct message_builder
{
  template<typename T>
  void
  operator()(const T& t)
  { pritty_print(t, oss_); }

  std::string
  get() const
  { return oss_.str(); }

 private:
  std::ostringstream oss_;
};

struct log_emitter
{
  log_emitter()
      : logger_(get_logger())
  {}

  explicit
  log_emitter(logger_base& logger)
      : logger_(logger)
  {}

  template<typename T>
  log_emitter&
  operator<<(const T& t)
  {
    message_builder_(t);
    return *this;
  }

  log_emitter&
  self()
  { return *this; }

  void
  emit() const
  { logger_.write(message_builder_.get()); }

 private:
  logger_base& logger_;
  message_builder message_builder_;
};

struct log_emission_trigger
{
  void
  operator&(const log_emitter& emitter) const
  { emitter.emit(); }
};

struct check_error
    : std::exception
{};

struct check_emission_trigger
{
  void
  operator&(const log_emitter& emitter) const
  {
    emitter.emit();
    throw check_error();
  }
};

// benchmark

struct benchmark
{
  benchmark()
      : logger_(get_logger()),
        start_sec_(gettime_sec()),
        done_(false)
  {}

  explicit
  benchmark(logger_base& logger)
      : logger_(logger),
        start_sec_(gettime_sec()),
        done_(false)
  {}

  explicit
  operator bool() const
  { return false; }

  ~benchmark()
  { if (!done_) push_message(); }

  template<typename T>
  benchmark&
  operator<<(const T& t)
  {
    title_builder_ << t;
    return *this;
  }

  double
  gettime() const
  { return gettime_sec() - start_sec_; }

  void
  push_message()
  {
    done_ = true;
    const auto duration = gettime_sec() - start_sec_;

    log_emitter emitter(logger_);
    emitter << title_builder_.get() << ": " << duration << " sec";
    if (duration >= 60) {
      emitter << " (";
      pritty_print_time(emitter, duration);
      emitter << ")";
    }
    emitter.emit();
  }

 private:
  logger_base& logger_;
  double start_sec_;

  message_builder title_builder_;

  bool done_;
};

}  // namespace LOG

#define LOG() ::LOG::log_emission_trigger() & ::LOG::log_emitter().self()

#define CHECK(cond) \
  (cond) ? (void)0 : \
  ::LOG::check_emission_trigger() & ::LOG::log_emitter().self();

#define BENCHMARK(varname, ...) \
  if (auto varname = ::LOG::benchmark()); \
  else if (!&::LOG::print_arguments(varname, __VA_ARGS__)); \
  else

#endif  // ELOG_ELOG_HPP_
<|endoftext|>