<commit_before>//===--- XPCService.cpp ---------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "sourcekitd/Internal-XPC.h"
#include "sourcekitd/Logging.h"
#include "sourcekitd/XpcTracing.h"

#include "SourceKit/Core/LLVM.h"
#include "SourceKit/Support/Concurrency.h"
#include "SourceKit/Support/UIdent.h"
#include "SourceKit/Support/Logging.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Threading.h"

#include <xpc/xpc.h>

using namespace SourceKit;
using namespace sourcekitd;

static xpc_connection_t MainConnection = nullptr;

void sourcekitd::postNotification(sourcekitd_response_t Notification) {
  xpc_connection_t peer = MainConnection;
  if (!peer)
    goto done;

  {
    xpc_object_t contents = xpc_array_create(nullptr, 0);
    xpc_array_set_uint64(contents, XPC_ARRAY_APPEND,
                         (uint64_t)xpc::Message::Notification);
    xpc_array_set_value(contents, XPC_ARRAY_APPEND, Notification);

    xpc_object_t msg = xpc_dictionary_create(nullptr, nullptr, 0);
    xpc_dictionary_set_value(msg, xpc::KeyInternalMsg, contents);
    xpc_release(contents);

    xpc_connection_send_message(peer, msg);
    xpc_release(msg);
  }

done:
  // The function accepted ownership.
  xpc_release(Notification);
}

namespace {
/// \brief Associates sourcekitd_uid_t to a UIdent.
class SKUIDToUIDMap {
  typedef llvm::DenseMap<void *, UIdent> MapTy;
  MapTy Map;
  WorkQueue Queue{ WorkQueue::Dequeuing::Concurrent, "UIDMap" };

public:
  UIdent get(sourcekitd_uid_t SKDUID);
  void set(sourcekitd_uid_t SKDUID, UIdent UID);
};
}

static SKUIDToUIDMap UIDMap;

sourcekitd_uid_t sourcekitd::SKDUIDFromUIdent(UIdent UID) {
  if (void *Tag = UID.getTag())
    return reinterpret_cast<sourcekitd_uid_t>(Tag);

  // FIXME: The following should run in the synchronous dispatch queue of the
  // connection. But does it matter, since if MainConnection is null or gets
  // destroyed it means the client crashed ?
  xpc_connection_t peer = MainConnection;
  if (!peer)
    return nullptr;

  xpc_object_t contents = xpc_array_create(nullptr, 0);
  xpc_array_set_uint64(contents, XPC_ARRAY_APPEND,
                       (uint64_t)xpc::Message::UIDSynchronization);
  xpc_array_set_string(contents, XPC_ARRAY_APPEND, UID.c_str());

  xpc_object_t msg = xpc_dictionary_create(nullptr, nullptr,  0);
  xpc_dictionary_set_value(msg, xpc::KeyInternalMsg, contents);
  xpc_release(contents);

  xpc_object_t reply = xpc_connection_send_message_with_reply_sync(peer, msg);
  xpc_release(msg);
  if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
    xpc_release(reply);
    return nullptr;
  }

  assert(xpc_get_type(reply) == XPC_TYPE_DICTIONARY);
  uint64_t val = xpc_dictionary_get_uint64(reply, xpc::KeyMsgResponse);
  xpc_release(reply);

  sourcekitd_uid_t skduid = sourcekitd_uid_t(val);
  UID.setTag(skduid);
  UIDMap.set(skduid, UID);
  return skduid;
}

UIdent sourcekitd::UIdentFromSKDUID(sourcekitd_uid_t SKDUID) {
  // This should be used only for debugging/logging purposes.

  UIdent UID = UIDMap.get(SKDUID);
  if (UID.isValid())
    return UID;

  xpc_connection_t Peer = MainConnection;
  if (!Peer)
    return UIdent();

  xpc_object_t contents = xpc_array_create(nullptr, 0);
  xpc_array_set_uint64(contents, XPC_ARRAY_APPEND,
                       (uint64_t)xpc::Message::UIDSynchronization);
  xpc_array_set_uint64(contents, XPC_ARRAY_APPEND, uintptr_t(SKDUID));

  xpc_object_t msg = xpc_dictionary_create(nullptr, nullptr,  0);
  xpc_dictionary_set_value(msg, xpc::KeyInternalMsg, contents);
  xpc_release(contents);

  xpc_object_t reply = xpc_connection_send_message_with_reply_sync(Peer, msg);
  xpc_release(msg);
  if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
    xpc_release(reply);
    return UIdent();
  }

  assert(xpc_get_type(reply) == XPC_TYPE_DICTIONARY);
  const char *Str = xpc_dictionary_get_string(reply, xpc::KeyMsgResponse);

  UID = UIdent(Str);
  UID.setTag(SKDUID);
  UIDMap.set(SKDUID, UID);

  xpc_release(reply);
  return UID;
}

void anchorForGetMainExecutableInXPCService() {}

namespace {
/// Responsible for replying to an XPC request.
class XPCResponder {
  xpc_connection_t Peer;
  xpc_object_t Event;
  bool Responded = false;

public:
  XPCResponder(xpc_object_t event, xpc_connection_t peer)
    : Peer(xpc_connection_t(xpc_retain(peer))), Event(xpc_retain(event)) {}

  ~XPCResponder() {
    if (!Responded) {
      LOG_WARN_FUNC("failed to respond to request");
      sendReply(createErrorRequestFailed("Internal error: no response was "
                                         "provided for the request"));
    }
    xpc_release(Event);
    xpc_release(Peer);
  }

  /// Accepts ownership of the response object.
  void sendReply(sourcekitd_response_t response) {
    if (Responded) {
      LOG_WARN_FUNC("tried to respond to an already handled request");
      return;
    }

    xpc_object_t reply = xpc_dictionary_create_reply(Event);
    xpc_dictionary_set_value(reply, xpc::KeyMsgResponse, response);
    xpc_release(response);

    xpc_connection_send_message(Peer, reply);
    xpc_release(reply);
    Responded = true;
  }
};
}

std::string sourcekitd::getRuntimeLibPath() {
  std::string MainExePath = llvm::sys::fs::getMainExecutable("sourcekit",
             reinterpret_cast<void *>(&anchorForGetMainExecutableInXPCService));
#ifdef SOURCEKIT_UNVERSIONED_FRAMEWORK_BUNDLE
  // MainExePath points to "lib/sourcekitd.framework/XPCServices/
  //                       SourceKitService.xpc/SourceKitService"
  const unsigned MainExeLibNestingLevel = 4;
#else
  // MainExePath points to "lib/sourcekitd.framework/Versions/Current/XPCServices/
  //                       SourceKitService.xpc/Contents/MacOS/SourceKitService"
  const unsigned MainExeLibNestingLevel = 8;
#endif

  // Get it to lib.
  StringRef Path = MainExePath;
  for (unsigned i = 0; i < MainExeLibNestingLevel; ++i)
    Path = llvm::sys::path::parent_path(Path);
  return Path;
}

static void sourcekitdServer_peer_event_handler(xpc_connection_t peer,
                                            xpc_object_t event) {
  xpc_type_t type = xpc_get_type(event);
  if (type == XPC_TYPE_ERROR) {
    if (event == XPC_ERROR_CONNECTION_INVALID) {
      // The client process on the other end of the connection has either
      // crashed or cancelled the connection. After receiving this error,
      // the connection is in an invalid state, and we do not need to
      // call xpc_connection_cancel(). Tear down any associated state
      // here.
      sourcekitd::shutdown();
      xpc_transaction_end();
    } else if (event == XPC_ERROR_TERMINATION_IMMINENT) {
      // Handle per-connection termination cleanup.
      xpc_connection_cancel(peer);
    }

  } else {
    assert(type == XPC_TYPE_DICTIONARY);
    // Handle the message
    xpc_retain(event);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
    ^{
      xpc_object_t contents = xpc_dictionary_get_value(event, "msg");

      if (!contents) {
        // Ping back.
        contents = xpc_dictionary_get_value(event, "ping");
        assert(contents && "unexpected message");
        xpc_object_t reply = xpc_dictionary_create_reply(event);
        assert(reply);
        xpc_connection_send_message(peer, reply);
        xpc_release(reply);
        return;
      }

      auto Responder = std::make_shared<XPCResponder>(event, peer);
      xpc_release(event);

      assert(xpc_get_type(contents) == XPC_TYPE_ARRAY);
      sourcekitd_object_t req = xpc_array_get_value(contents, 0);
      sourcekitd::handleRequest(req,
        [Responder](sourcekitd_response_t response) {
          Responder->sendReply(response);
        });
    });
  }
}

static void getInitializationInfo(xpc_connection_t peer) {
  xpc_object_t contents = xpc_array_create(nullptr, 0);
  xpc_array_set_uint64(contents, XPC_ARRAY_APPEND,
                       (uint64_t)xpc::Message::Initialization);

  xpc_object_t msg = xpc_dictionary_create(nullptr, nullptr,  0);
  xpc_dictionary_set_value(msg, xpc::KeyInternalMsg, contents);
  xpc_release(contents);

  xpc_object_t reply = xpc_connection_send_message_with_reply_sync(peer, msg);
  xpc_release(msg);
  if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
    xpc_release(reply);
    return;
  }

  assert(xpc_get_type(reply) == XPC_TYPE_DICTIONARY);
  uint64_t Delay = xpc_dictionary_get_uint64(reply, xpc::KeySemaEditorDelay);
  uint64_t TracingEnabled = xpc_dictionary_get_uint64(reply,
                                                      xpc::KeyTracingEnabled);
  xpc_release(reply);

  if (Delay != 0) {
    llvm::SmallString<4> Buf;
    {
      llvm::raw_svector_ostream OS(Buf);
      OS << Delay;
    }
    setenv("SOURCEKIT_DELAY_SEMA_EDITOR", Buf.c_str(), /*overwrite=*/1);
  }

  if (TracingEnabled) {
    SourceKit::trace::enable();
  }
}

static void sourcekitdServer_event_handler(xpc_connection_t peer) {
  // Keep the service alive even when idle.
  xpc_transaction_begin();

  // By defaults, new connections will target the default dispatch
  // concurrent queue.
  xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
    sourcekitdServer_peer_event_handler(peer, event);
  });

  MainConnection = peer;

  // This will tell the connection to begin listening for events. If you
  // have some other initialization that must be done asynchronously, then
  // you can defer this call until after that initialization is done.
  xpc_connection_resume(peer);

  dispatch_async(dispatch_get_main_queue(), ^{
    getInitializationInfo(MainConnection);
  });
}

static void fatal_error_handler(void *user_data, const std::string& reason,
                                bool gen_crash_diag) {
  // Write the result out to stderr avoiding errs() because raw_ostreams can
  // call report_fatal_error.
  fprintf(stderr, "SOURCEKITD SERVER FATAL ERROR: %s\n", reason.c_str());
  ::abort();
}

int main(int argc, const char *argv[]) {
  llvm::install_fatal_error_handler(fatal_error_handler, 0);
  sourcekitd::enableLogging("sourcekit-serv");
  sourcekitd::initialize();
  sourcekitd::trace::initialize();

  // Increase the file descriptor limit.
  // FIXME: Portability ?
  static const size_t FDLimit = 4096;
  struct rlimit l;
  if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
    if (l.rlim_cur < FDLimit) {
      l.rlim_cur = FDLimit;
      if (setrlimit(RLIMIT_NOFILE, &l) == 0) {
        LOG_INFO_FUNC(Low, "bumped file descriptor limit to " << FDLimit);
      } else {
        LOG_WARN_FUNC("setrlimit failed: " << llvm::sys::StrError());
      }
    }
  } else {
    LOG_WARN_FUNC("getrlimit failed: " << llvm::sys::StrError());
  }

  xpc_main(sourcekitdServer_event_handler);
  return 0;
}

UIdent SKUIDToUIDMap::get(sourcekitd_uid_t SKDUID) {
  UIdent UID;
  Queue.dispatchSync([&]{
    MapTy::iterator It = Map.find(SKDUID);
    if (It != Map.end())
      UID = It->second;
  });

  return UID;
}

void SKUIDToUIDMap::set(sourcekitd_uid_t SKDUID, UIdent UID) {
  Queue.dispatchBarrier([=]{
    this->Map[SKDUID] = UID;
  });
}

void sourcekitd::trace::sendTraceMessage(trace::sourcekitd_trace_message_t Msg) {
  if (!SourceKit::trace::enabled()) {
    xpc_release(Msg);
    return;
  }

  xpc_connection_t Peer = MainConnection;
  if (!Peer) {
    SourceKit::trace::disable();
    xpc_release(Msg);
    return;
  }

  xpc_object_t Contents = xpc_array_create(nullptr, 0);
  xpc_array_set_uint64(Contents, XPC_ARRAY_APPEND,
                       static_cast<uint64_t>(xpc::Message::TraceMessage));
  xpc_array_set_uint64(Contents, XPC_ARRAY_APPEND,
                       trace::getTracingSession());
  xpc_array_set_value(Contents, XPC_ARRAY_APPEND, Msg);
  xpc_release(Msg);

  xpc_object_t Message = xpc_dictionary_create(nullptr, nullptr,  0);
  xpc_dictionary_set_value(Message, xpc::KeyInternalMsg, Contents);
  xpc_release(Contents);

  xpc_object_t Reply =
    xpc_connection_send_message_with_reply_sync(Peer, Message);
  xpc_release(Message);

  if (xpc_get_type(Reply) == XPC_TYPE_ERROR) {
    SourceKit::trace::disable();
    xpc_release(Reply);
    return;
  }

  xpc_release(Reply);
}

<commit_msg>[SourceKit] Avoid calling "sourcekitd::shutdown()" on the service side, when the connection closes.<commit_after>//===--- XPCService.cpp ---------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "sourcekitd/Internal-XPC.h"
#include "sourcekitd/Logging.h"
#include "sourcekitd/XpcTracing.h"

#include "SourceKit/Core/LLVM.h"
#include "SourceKit/Support/Concurrency.h"
#include "SourceKit/Support/UIdent.h"
#include "SourceKit/Support/Logging.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Threading.h"

#include <xpc/xpc.h>

using namespace SourceKit;
using namespace sourcekitd;

static xpc_connection_t MainConnection = nullptr;

void sourcekitd::postNotification(sourcekitd_response_t Notification) {
  xpc_connection_t peer = MainConnection;
  if (!peer)
    goto done;

  {
    xpc_object_t contents = xpc_array_create(nullptr, 0);
    xpc_array_set_uint64(contents, XPC_ARRAY_APPEND,
                         (uint64_t)xpc::Message::Notification);
    xpc_array_set_value(contents, XPC_ARRAY_APPEND, Notification);

    xpc_object_t msg = xpc_dictionary_create(nullptr, nullptr, 0);
    xpc_dictionary_set_value(msg, xpc::KeyInternalMsg, contents);
    xpc_release(contents);

    xpc_connection_send_message(peer, msg);
    xpc_release(msg);
  }

done:
  // The function accepted ownership.
  xpc_release(Notification);
}

namespace {
/// \brief Associates sourcekitd_uid_t to a UIdent.
class SKUIDToUIDMap {
  typedef llvm::DenseMap<void *, UIdent> MapTy;
  MapTy Map;
  WorkQueue Queue{ WorkQueue::Dequeuing::Concurrent, "UIDMap" };

public:
  UIdent get(sourcekitd_uid_t SKDUID);
  void set(sourcekitd_uid_t SKDUID, UIdent UID);
};
}

static SKUIDToUIDMap UIDMap;

sourcekitd_uid_t sourcekitd::SKDUIDFromUIdent(UIdent UID) {
  if (void *Tag = UID.getTag())
    return reinterpret_cast<sourcekitd_uid_t>(Tag);

  // FIXME: The following should run in the synchronous dispatch queue of the
  // connection. But does it matter, since if MainConnection is null or gets
  // destroyed it means the client crashed ?
  xpc_connection_t peer = MainConnection;
  if (!peer)
    return nullptr;

  xpc_object_t contents = xpc_array_create(nullptr, 0);
  xpc_array_set_uint64(contents, XPC_ARRAY_APPEND,
                       (uint64_t)xpc::Message::UIDSynchronization);
  xpc_array_set_string(contents, XPC_ARRAY_APPEND, UID.c_str());

  xpc_object_t msg = xpc_dictionary_create(nullptr, nullptr,  0);
  xpc_dictionary_set_value(msg, xpc::KeyInternalMsg, contents);
  xpc_release(contents);

  xpc_object_t reply = xpc_connection_send_message_with_reply_sync(peer, msg);
  xpc_release(msg);
  if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
    xpc_release(reply);
    return nullptr;
  }

  assert(xpc_get_type(reply) == XPC_TYPE_DICTIONARY);
  uint64_t val = xpc_dictionary_get_uint64(reply, xpc::KeyMsgResponse);
  xpc_release(reply);

  sourcekitd_uid_t skduid = sourcekitd_uid_t(val);
  UID.setTag(skduid);
  UIDMap.set(skduid, UID);
  return skduid;
}

UIdent sourcekitd::UIdentFromSKDUID(sourcekitd_uid_t SKDUID) {
  // This should be used only for debugging/logging purposes.

  UIdent UID = UIDMap.get(SKDUID);
  if (UID.isValid())
    return UID;

  xpc_connection_t Peer = MainConnection;
  if (!Peer)
    return UIdent();

  xpc_object_t contents = xpc_array_create(nullptr, 0);
  xpc_array_set_uint64(contents, XPC_ARRAY_APPEND,
                       (uint64_t)xpc::Message::UIDSynchronization);
  xpc_array_set_uint64(contents, XPC_ARRAY_APPEND, uintptr_t(SKDUID));

  xpc_object_t msg = xpc_dictionary_create(nullptr, nullptr,  0);
  xpc_dictionary_set_value(msg, xpc::KeyInternalMsg, contents);
  xpc_release(contents);

  xpc_object_t reply = xpc_connection_send_message_with_reply_sync(Peer, msg);
  xpc_release(msg);
  if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
    xpc_release(reply);
    return UIdent();
  }

  assert(xpc_get_type(reply) == XPC_TYPE_DICTIONARY);
  const char *Str = xpc_dictionary_get_string(reply, xpc::KeyMsgResponse);

  UID = UIdent(Str);
  UID.setTag(SKDUID);
  UIDMap.set(SKDUID, UID);

  xpc_release(reply);
  return UID;
}

void anchorForGetMainExecutableInXPCService() {}

namespace {
/// Responsible for replying to an XPC request.
class XPCResponder {
  xpc_connection_t Peer;
  xpc_object_t Event;
  bool Responded = false;

public:
  XPCResponder(xpc_object_t event, xpc_connection_t peer)
    : Peer(xpc_connection_t(xpc_retain(peer))), Event(xpc_retain(event)) {}

  ~XPCResponder() {
    if (!Responded) {
      LOG_WARN_FUNC("failed to respond to request");
      sendReply(createErrorRequestFailed("Internal error: no response was "
                                         "provided for the request"));
    }
    xpc_release(Event);
    xpc_release(Peer);
  }

  /// Accepts ownership of the response object.
  void sendReply(sourcekitd_response_t response) {
    if (Responded) {
      LOG_WARN_FUNC("tried to respond to an already handled request");
      return;
    }

    xpc_object_t reply = xpc_dictionary_create_reply(Event);
    xpc_dictionary_set_value(reply, xpc::KeyMsgResponse, response);
    xpc_release(response);

    xpc_connection_send_message(Peer, reply);
    xpc_release(reply);
    Responded = true;
  }
};
}

std::string sourcekitd::getRuntimeLibPath() {
  std::string MainExePath = llvm::sys::fs::getMainExecutable("sourcekit",
             reinterpret_cast<void *>(&anchorForGetMainExecutableInXPCService));
#ifdef SOURCEKIT_UNVERSIONED_FRAMEWORK_BUNDLE
  // MainExePath points to "lib/sourcekitd.framework/XPCServices/
  //                       SourceKitService.xpc/SourceKitService"
  const unsigned MainExeLibNestingLevel = 4;
#else
  // MainExePath points to "lib/sourcekitd.framework/Versions/Current/XPCServices/
  //                       SourceKitService.xpc/Contents/MacOS/SourceKitService"
  const unsigned MainExeLibNestingLevel = 8;
#endif

  // Get it to lib.
  StringRef Path = MainExePath;
  for (unsigned i = 0; i < MainExeLibNestingLevel; ++i)
    Path = llvm::sys::path::parent_path(Path);
  return Path;
}

static void sourcekitdServer_peer_event_handler(xpc_connection_t peer,
                                            xpc_object_t event) {
  xpc_type_t type = xpc_get_type(event);
  if (type == XPC_TYPE_ERROR) {
    if (event == XPC_ERROR_CONNECTION_INVALID) {
      // The client process on the other end of the connection has either
      // crashed or cancelled the connection. After receiving this error,
      // the connection is in an invalid state, and we do not need to
      // call xpc_connection_cancel().
      // No need to call sourcekitd::shutdown() since the process is going down
      // anyway, plus if we get a new connection before the process closes then
      // we will fail to re-initialize properly since the initialize call is at
      // main.
      xpc_transaction_end();
    } else if (event == XPC_ERROR_TERMINATION_IMMINENT) {
      // Handle per-connection termination cleanup.
      xpc_connection_cancel(peer);
    }

  } else {
    assert(type == XPC_TYPE_DICTIONARY);
    // Handle the message
    xpc_retain(event);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
    ^{
      xpc_object_t contents = xpc_dictionary_get_value(event, "msg");

      if (!contents) {
        // Ping back.
        contents = xpc_dictionary_get_value(event, "ping");
        assert(contents && "unexpected message");
        xpc_object_t reply = xpc_dictionary_create_reply(event);
        assert(reply);
        xpc_connection_send_message(peer, reply);
        xpc_release(reply);
        return;
      }

      auto Responder = std::make_shared<XPCResponder>(event, peer);
      xpc_release(event);

      assert(xpc_get_type(contents) == XPC_TYPE_ARRAY);
      sourcekitd_object_t req = xpc_array_get_value(contents, 0);
      sourcekitd::handleRequest(req,
        [Responder](sourcekitd_response_t response) {
          Responder->sendReply(response);
        });
    });
  }
}

static void getInitializationInfo(xpc_connection_t peer) {
  xpc_object_t contents = xpc_array_create(nullptr, 0);
  xpc_array_set_uint64(contents, XPC_ARRAY_APPEND,
                       (uint64_t)xpc::Message::Initialization);

  xpc_object_t msg = xpc_dictionary_create(nullptr, nullptr,  0);
  xpc_dictionary_set_value(msg, xpc::KeyInternalMsg, contents);
  xpc_release(contents);

  xpc_object_t reply = xpc_connection_send_message_with_reply_sync(peer, msg);
  xpc_release(msg);
  if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
    xpc_release(reply);
    return;
  }

  assert(xpc_get_type(reply) == XPC_TYPE_DICTIONARY);
  uint64_t Delay = xpc_dictionary_get_uint64(reply, xpc::KeySemaEditorDelay);
  uint64_t TracingEnabled = xpc_dictionary_get_uint64(reply,
                                                      xpc::KeyTracingEnabled);
  xpc_release(reply);

  if (Delay != 0) {
    llvm::SmallString<4> Buf;
    {
      llvm::raw_svector_ostream OS(Buf);
      OS << Delay;
    }
    setenv("SOURCEKIT_DELAY_SEMA_EDITOR", Buf.c_str(), /*overwrite=*/1);
  }

  if (TracingEnabled) {
    SourceKit::trace::enable();
  }
}

static void sourcekitdServer_event_handler(xpc_connection_t peer) {
  // Keep the service alive even when idle.
  xpc_transaction_begin();

  // By defaults, new connections will target the default dispatch
  // concurrent queue.
  xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
    sourcekitdServer_peer_event_handler(peer, event);
  });

  MainConnection = peer;

  // This will tell the connection to begin listening for events. If you
  // have some other initialization that must be done asynchronously, then
  // you can defer this call until after that initialization is done.
  xpc_connection_resume(peer);

  dispatch_async(dispatch_get_main_queue(), ^{
    getInitializationInfo(MainConnection);
  });
}

static void fatal_error_handler(void *user_data, const std::string& reason,
                                bool gen_crash_diag) {
  // Write the result out to stderr avoiding errs() because raw_ostreams can
  // call report_fatal_error.
  fprintf(stderr, "SOURCEKITD SERVER FATAL ERROR: %s\n", reason.c_str());
  ::abort();
}

int main(int argc, const char *argv[]) {
  llvm::install_fatal_error_handler(fatal_error_handler, 0);
  sourcekitd::enableLogging("sourcekit-serv");
  sourcekitd::initialize();
  sourcekitd::trace::initialize();

  // Increase the file descriptor limit.
  // FIXME: Portability ?
  static const size_t FDLimit = 4096;
  struct rlimit l;
  if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
    if (l.rlim_cur < FDLimit) {
      l.rlim_cur = FDLimit;
      if (setrlimit(RLIMIT_NOFILE, &l) == 0) {
        LOG_INFO_FUNC(Low, "bumped file descriptor limit to " << FDLimit);
      } else {
        LOG_WARN_FUNC("setrlimit failed: " << llvm::sys::StrError());
      }
    }
  } else {
    LOG_WARN_FUNC("getrlimit failed: " << llvm::sys::StrError());
  }

  xpc_main(sourcekitdServer_event_handler);
  return 0;
}

UIdent SKUIDToUIDMap::get(sourcekitd_uid_t SKDUID) {
  UIdent UID;
  Queue.dispatchSync([&]{
    MapTy::iterator It = Map.find(SKDUID);
    if (It != Map.end())
      UID = It->second;
  });

  return UID;
}

void SKUIDToUIDMap::set(sourcekitd_uid_t SKDUID, UIdent UID) {
  Queue.dispatchBarrier([=]{
    this->Map[SKDUID] = UID;
  });
}

void sourcekitd::trace::sendTraceMessage(trace::sourcekitd_trace_message_t Msg) {
  if (!SourceKit::trace::enabled()) {
    xpc_release(Msg);
    return;
  }

  xpc_connection_t Peer = MainConnection;
  if (!Peer) {
    SourceKit::trace::disable();
    xpc_release(Msg);
    return;
  }

  xpc_object_t Contents = xpc_array_create(nullptr, 0);
  xpc_array_set_uint64(Contents, XPC_ARRAY_APPEND,
                       static_cast<uint64_t>(xpc::Message::TraceMessage));
  xpc_array_set_uint64(Contents, XPC_ARRAY_APPEND,
                       trace::getTracingSession());
  xpc_array_set_value(Contents, XPC_ARRAY_APPEND, Msg);
  xpc_release(Msg);

  xpc_object_t Message = xpc_dictionary_create(nullptr, nullptr,  0);
  xpc_dictionary_set_value(Message, xpc::KeyInternalMsg, Contents);
  xpc_release(Contents);

  xpc_object_t Reply =
    xpc_connection_send_message_with_reply_sync(Peer, Message);
  xpc_release(Message);

  if (xpc_get_type(Reply) == XPC_TYPE_ERROR) {
    SourceKit::trace::disable();
    xpc_release(Reply);
    return;
  }

  xpc_release(Reply);
}

<|endoftext|>


<commit_before>#include <sender.hpp>
#include <serialization.hpp>

#include <boost/asio/io_service.hpp>

using boost::asio::ip::tcp;

NetworkSender::NetworkSender(std::shared_ptr<ReplicaSet> replicaset_)
    : io_service_(),
      socket_(io_service_),
      replicaset(replicaset_)
{
}

NetworkSender::NetworkSender()
    : io_service_(),
      socket_(io_service_),
      replicaset(new ReplicaSet())
{
}

NetworkSender::~NetworkSender()
{
    io_service_.post([this]() { socket_.close(); } );
}

void
NetworkSender::Reply(Message message)
{
    tcp::resolver resolver(io_service_);
    auto endpoint = resolver.resolve(
                        {
                            message.to.hostname,
                            std::to_string(message.to.port)
                        });
    boost::asio::async_connect(socket_, endpoint,
        [this, message](boost::system::error_code ec, tcp::resolver::iterator)
        {
            if (!ec)
            {
                // 1. serialize message
                std::string message_str = Serialize(message).str();

                // 2. write message
                boost::asio::write(
                    socket_,
                    boost::asio::buffer(
                        message_str.c_str(),
                        message_str.size()));
            }
        });
}

void
NetworkSender::ReplyAll(Message message)
{
    for (auto r : *replicaset)
    {
        Message m = message;
        m.to = r;
        Reply(m);
    }
}
<commit_msg>Update network sender to execute synchronous write operations<commit_after>#include <sender.hpp>
#include <serialization.hpp>

#include <boost/asio/io_service.hpp>

using boost::asio::ip::tcp;

NetworkSender::NetworkSender(std::shared_ptr<ReplicaSet> replicaset_)
    : io_service_(),
      socket_(io_service_),
      replicaset(replicaset_)
{
}

NetworkSender::NetworkSender()
    : io_service_(),
      socket_(io_service_),
      replicaset(new ReplicaSet())
{
}

NetworkSender::~NetworkSender()
{
    socket_.close();
}

void
NetworkSender::Reply(Message message)
{
    tcp::resolver resolver(io_service_);
    auto endpoint = resolver.resolve(
                        {
                            message.to.hostname,
                            std::to_string(message.to.port)
                        });
    boost::asio::connect(socket_, endpoint);

    // 1. serialize message
    std::string message_str = Serialize(message).str();

    // 2. write message
    boost::asio::write(socket_, boost::asio::buffer(message_str.c_str(), message_str.size()));
}

void
NetworkSender::ReplyAll(Message message)
{
    for (auto r : *replicaset)
    {
        Message m = message;
        m.to = r;
        Reply(m);
    }
}
<|endoftext|>


<commit_before>#include "zonotope_halfspaces.hpp"

#include <gmpxx.h>
#include <iostream>

int main() {
  using namespace std;

  typedef mpz_class NT;

  int n_tests;
  cin >> n_tests;
  for ( int t = 0; t < n_tests; ++t ) {
    int n, d;
    cin >> n >> d;
    vector<vector<NT> > generators ( n, vector<NT> ( d ) );
    for ( int i = 0; i < n; ++i ) {
      for ( int j = 0; j < d; ++j ) {
        cin >> generators[i][j];
      }
    }

    set<Hyperplane<NT> > halfspaces = zonotope_halfspaces<NT> (generators);
    cout << "n=" << n << " "
         << "d=" << d << " "
         << "ieqs=" << halfspaces.size() << "\n";
  }

  return 0;
}
<commit_msg>Update the halfspaces test to also test `long` input/output<commit_after>#include "zonotope_halfspaces.hpp"

#include <gmpxx.h>
#include <iostream>

int main() {
  using namespace std;

  int n_tests;
  cin >> n_tests;
  for ( int t = 0; t < n_tests; ++t ) {
    int n, d;
    cin >> n >> d;

    vector<vector<mpz_class> >
      generators_mpz ( n, vector<mpz_class> ( d ) );

    vector<vector<long> >
      generators_long ( n, vector<long> ( d ) );

    for ( int k = 0; k < n; ++k ) {
      for ( int i = 0; i < d; ++i ) {
        cin >> generators_long[k][i];
        generators_mpz[k][i] = generators_long[k][i];
      }
    }

    set<Hyperplane<mpz_class> > halfspaces_mpz;
    zonotope_halfspaces<mpz_class> (generators_mpz, halfspaces_mpz);

    set<Hyperplane<long> > halfspaces_long;
    zonotope_halfspaces<long> (generators_long, halfspaces_long);

    cout << "n=" << n << " "
         << "d=" << d << " "
         << "ieqs=" << halfspaces_mpz.size() << " "
         << "ieqs_long=" << halfspaces_long.size() << "\n";
  }

  return 0;
}
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Aki "lethalbit" Van Ness <aki@yosyshq.com> <aki@lethalbit.net>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

// MYAU - Metadata for Yosys-Assisted Utilities

#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/cellaigs.h"
#include "kernel/log.h"
#include <string>
#include <unordered_map>
#include <vector>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct MetadataWriter
{
    private:
        std::ostream &f;
        bool _use_selection;
        std::unordered_map<std::string, std::vector<Cell*>> _cells{};

        // XXX(aki): this was pulled from the json backend, needs to be pulled
        // out possibly into some sort of utilities file, or integrated into rtlil.h
        // directly
        string get_string(string str)
        {
            string newstr = "\"";
            for (char c : str) {
                if (c == '\\')
                    newstr += c;
                newstr += c;
            }
            return newstr + "\"";
        }

        // XXX(aki): I know this is far from ideal but i'm out of spoons and cant focus so
        // it'll have to do for now,
        void coalesce_cells(Module* mod)
        {
            for (auto cell : mod->cells()) {
                const auto cell_type = get_string(RTLIL::unescape_id(cell->type));

                if (_cells.find(cell_type) == _cells.end())
                    _cells.emplace(cell_type, std::vector<Cell*>());

                _cells.at(cell_type).push_back(cell);
            }
        }

    public:
    MetadataWriter(std::ostream &f, bool use_selection) noexcept: f(f), _use_selection(use_selection) { }

    void write_metadata(Design *design)
    {
        log_assert(design != nullptr);

        design->sort();

        f << stringf("{\n");
        f << stringf("  \"generator\": %s,\n", get_string(yosys_version_str).c_str());
        // XXX(aki): Replace this with a proper version info eventually:tm:
        f << stringf("  \"version\": \"0.0.0\",\n");
        f << stringf("  \"modules\": [\n");

        bool first{true};
        for (auto mod : _use_selection ? design->selected_modules() : design->modules()) {
            if (!first)
                f << stringf(",\n");
            write_module(mod);

            f << stringf("\n");

            first = false;
        }

        f << stringf("  ]\n");
        f << stringf("}\n");
    }

    void write_module(Module* mod)
    {
        log_assert(mod != nullptr);

        coalesce_cells(mod);

        f << stringf("    {\n");
        f << stringf("      \"name\": %s,\n", get_string(RTLIL::unescape_id(mod->name)).c_str());
        f << stringf("      \"cell_sorts\": [\n");

        bool first_sort{true};
        for (auto& sort : _cells) {
            if (!first_sort)
                f << stringf(",\n");

            write_cell_sort(sort);

            first_sort = false;
        }
        f << stringf("\n");

        f << stringf("      ],\n");
        f << stringf("      \"connections\": [\n");

        f << stringf("      ]\n");
        f << stringf("    }");
    }

    void write_cell_sort(std::pair<const std::string, std::vector<Cell*>>& sort)
    {
        const auto port_cell = sort.second.front();

        f << stringf("        {\n");
        f << stringf("          \"type\": %s,\n", sort.first.c_str());
        f << stringf("          \"ports\": [\n");

        bool first_port{true};
        for (auto con : port_cell->connections()) {
            if (!first_port)
                f << stringf(",\n");

            f << stringf("          {\n");
            f << stringf("            \"name\": %s,\n", get_string(RTLIL::unescape_id(con.first)).c_str());
            f << stringf("            \"direction\": \"");
            if (port_cell->input(con.first))
                f << stringf("i");
            if (port_cell->input(con.first))
                f << stringf("o");
            f << stringf("\",\n");
            if (con.second.size() == 1)
                f << stringf("            \"range\": [0, 0]\n");
            else
                f << stringf("            \"range\": [%d, %d]\n", con.second.size(), 0);
            f << stringf("          }");

            first_port = false;
        }
        f << stringf("\n");

        f << stringf("          ],\n          \"cells\": [\n");
        bool first_cell{true};
        for (auto& cell : sort.second) {
            if (!first_cell)
                f << stringf(",\n");

            write_cell(cell);

            first_cell = false;
        }
        f << stringf("\n");
        f << stringf("          ]\n");
        f << stringf("        }");
    }

    void write_cell(Cell* cell)
    {
        log_assert(cell != nullptr);

        f << stringf("            {\n");
        f << stringf("              \"name\": %s,\n", get_string(RTLIL::unescape_id(cell->name)).c_str());
        f << stringf("              \"attributes\": {\n");

        bool first_attr{true};
        for (auto& attr : cell->attributes) {
            if (!first_attr)
                f << stringf(",\n");
            const auto attr_val = attr.second.decode_string();
            if (attr_val.size() > 0)
                f << stringf("                %s: \"%s\"\n", get_string(RTLIL::unescape_id(attr.first)).c_str(), attr_val.c_str());
            else
                f << stringf("                %s: true\n", get_string(RTLIL::unescape_id(attr.first)).c_str());

            first_attr = false;
        }

        f << stringf("              },\n");
        f << stringf("              \"parameters\": {\n");

        bool first_param{true};
        for (auto& param : cell->parameters) {
            if (!first_param)
                f << stringf(",\n");
            const auto param_val = param.second.decode_string();
            if (param_val.size() > 0)
                f << stringf("                %s: \"%s\"\n", get_string(RTLIL::unescape_id(param.first)).c_str(), param_val.c_str());
            else
                f << stringf("                %s: true\n", get_string(RTLIL::unescape_id(param.first)).c_str());

            first_param = false;
        }

        f << stringf("              },\n");
        f << stringf("            }");
    }
};

struct MetadataBackend : public Backend {
    MetadataBackend() : Backend("metadata", "generate design metadata") { }
    void help() override
    {
        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
        log("\n");
        log("    metadata [options] [selection]\n");
        log("\n");
        log("Write a JSON metadata for the current design\n");
        log("\n");
        log("\n");
    }

    void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
    {
        size_t argidx{1};
        extra_args(f, filename, args, argidx);

        log_header(design, "Executing metadata backend.\n");

        MetadataWriter metadata_writier(*f, false);
        metadata_writier.write_metadata(design);
    }

} MetadataBackend;

struct MetadataPass : public Pass {
    MetadataPass() : Pass("metadata", "write design metadata") { }

    void help() override
    {
        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
        log("\n");
        log("    metadata [options] [selection]\n");
        log("\n");
        log("Write a JSON metadata for the current design\n");
        log("\n");
        log("    -o <filename>\n");
        log("        write to the specified file.\n");
        log("\n");
        log("See 'help write_metadata' for a description of the JSON format used.\n");
        log("\n");
    }
    void execute(std::vector<std::string> args, RTLIL::Design *design) override
    {
        std::string filename{};

        size_t argidx;
        for (argidx = 1; argidx < args.size(); argidx++)
        {
            if (args[argidx] == "-o" && argidx+1 < args.size()) {
                filename = args[++argidx];
                continue;
            }
            break;
        }
        extra_args(args, argidx, design);

        std::ostream *f;
        std::stringstream buf;

        if (!filename.empty()) {
            rewrite_filename(filename);
            std::ofstream *ff = new std::ofstream;
            ff->open(filename.c_str(), std::ofstream::trunc);
            if (ff->fail()) {
                delete ff;
                log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
            }
            f = ff;
        } else {
            f = &buf;
        }

        MetadataWriter metadata_writier(*f, false);
        metadata_writier.write_metadata(design);

        if (!filename.empty()) {
            delete f;
        } else {
            log("%s", buf.str().c_str());
        }
    }

} MetadataPass;

PRIVATE_NAMESPACE_END
<commit_msg>pass metadata: some more rough work on dumping the parameters and attributes<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Aki "lethalbit" Van Ness <aki@yosyshq.com> <aki@lethalbit.net>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

// MYAU - Metadata for Yosys-Assisted Utilities

#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/cellaigs.h"
#include "kernel/log.h"
#include <string>
#include <unordered_map>
#include <vector>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct MetadataWriter
{
    private:
        std::ostream &f;
        bool _use_selection;
        std::unordered_map<std::string, std::vector<Cell*>> _cells{};

        // XXX(aki): this was pulled from the json backend, needs to be pulled
        // out possibly into some sort of utilities file, or integrated into rtlil.h
        // directly
        string get_string(string str)
        {
            string newstr = "\"";
            for (char c : str) {
                if (c == '\\')
                    newstr += c;
                newstr += c;
            }
            return newstr + "\"";
        }

        // XXX(aki): I know this is far from ideal but i'm out of spoons and cant focus so
        // it'll have to do for now,
        void coalesce_cells(Module* mod)
        {
            for (auto cell : mod->cells()) {
                const auto cell_type = get_string(RTLIL::unescape_id(cell->type));

                if (_cells.find(cell_type) == _cells.end())
                    _cells.emplace(cell_type, std::vector<Cell*>());

                _cells.at(cell_type).push_back(cell);
            }
        }

    public:
    MetadataWriter(std::ostream &f, bool use_selection) noexcept: f(f), _use_selection(use_selection) { }

    void write_metadata(Design *design)
    {
        log_assert(design != nullptr);

        design->sort();

        f << stringf("{\n");
        f << stringf("  \"generator\": %s,\n", get_string(yosys_version_str).c_str());
        // XXX(aki): Replace this with a proper version info eventually:tm:
        f << stringf("  \"version\": \"0.0.0\",\n");
        f << stringf("  \"modules\": [\n");

        bool first{true};
        for (auto mod : _use_selection ? design->selected_modules() : design->modules()) {
            if (!first)
                f << stringf(",\n");
            write_module(mod);

            f << stringf("\n");

            first = false;
        }

        f << stringf("  ]\n");
        f << stringf("}\n");
    }

    void write_module(Module* mod)
    {
        log_assert(mod != nullptr);

        coalesce_cells(mod);

        f << stringf("    {\n");
        f << stringf("      \"name\": %s,\n", get_string(RTLIL::unescape_id(mod->name)).c_str());
        f << stringf("      \"cell_sorts\": [\n");

        bool first_sort{true};
        for (auto& sort : _cells) {
            if (!first_sort)
                f << stringf(",\n");

            write_cell_sort(sort);

            first_sort = false;
        }
        f << stringf("\n");

        f << stringf("      ],\n");
        f << stringf("      \"connections\": [\n");

        f << stringf("      ]\n");
        f << stringf("    }");
    }

    void write_cell_sort(std::pair<const std::string, std::vector<Cell*>>& sort)
    {
        const auto port_cell = sort.second.front();

        f << stringf("        {\n");
        f << stringf("          \"type\": %s,\n", sort.first.c_str());
        f << stringf("          \"ports\": [\n");

        bool first_port{true};
        for (auto con : port_cell->connections()) {
            if (!first_port)
                f << stringf(",\n");

            f << stringf("          {\n");
            f << stringf("            \"name\": %s,\n", get_string(RTLIL::unescape_id(con.first)).c_str());
            f << stringf("            \"direction\": \"");
            if (port_cell->input(con.first))
                f << stringf("i");
            if (port_cell->input(con.first))
                f << stringf("o");
            f << stringf("\",\n");
            if (con.second.size() == 1)
                f << stringf("            \"range\": [0, 0]\n");
            else
                f << stringf("            \"range\": [%d, %d]\n", con.second.size(), 0);
            f << stringf("          }");

            first_port = false;
        }
        f << stringf("\n");

        f << stringf("          ],\n          \"cells\": [\n");
        bool first_cell{true};
        for (auto& cell : sort.second) {
            if (!first_cell)
                f << stringf(",\n");

            write_cell(cell);

            first_cell = false;
        }
        f << stringf("\n");
        f << stringf("          ]\n");
        f << stringf("        }");
    }

    void write_cell(Cell* cell)
    {
        log_assert(cell != nullptr);

        f << stringf("            {\n");
        f << stringf("              \"name\": %s,\n", get_string(RTLIL::unescape_id(cell->name)).c_str());
        f << stringf("              \"attributes\": {\n");

        bool first_attr{true};
        for (auto& attr : cell->attributes) {
            if (!first_attr)
                f << stringf(",\n");
            const auto attr_val = attr.second;
            if (!attr_val.empty())
                f << stringf("                %s: \"%s\"\n", get_string(RTLIL::unescape_id(attr.first)).c_str(), attr_val.decode_string().c_str());
            else
                f << stringf("                %s: true\n", get_string(RTLIL::unescape_id(attr.first)).c_str());

            first_attr = false;
        }

        f << stringf("              },\n");
        f << stringf("              \"parameters\": {\n");

        bool first_param{true};
        for (auto& param : cell->parameters) {
            if (!first_param)
                f << stringf(",\n");
            const auto param_val = param.second;
            if (!param_val.empty())
                f << stringf("                %s: \"%s\"\n", get_string(RTLIL::unescape_id(param.first)).c_str(), param_val.decode_string().c_str());
            else
                f << stringf("                %s: true\n", get_string(RTLIL::unescape_id(param.first)).c_str());

            first_param = false;
        }

        f << stringf("              },\n");
        f << stringf("            }");
    }
};

struct MetadataBackend : public Backend {
    MetadataBackend() : Backend("metadata", "generate design metadata") { }
    void help() override
    {
        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
        log("\n");
        log("    metadata [options] [selection]\n");
        log("\n");
        log("Write a JSON metadata for the current design\n");
        log("\n");
        log("\n");
    }

    void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
    {
        size_t argidx{1};
        extra_args(f, filename, args, argidx);

        log_header(design, "Executing metadata backend.\n");

        MetadataWriter metadata_writier(*f, false);
        metadata_writier.write_metadata(design);
    }

} MetadataBackend;

struct MetadataPass : public Pass {
    MetadataPass() : Pass("metadata", "write design metadata") { }

    void help() override
    {
        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
        log("\n");
        log("    metadata [options] [selection]\n");
        log("\n");
        log("Write a JSON metadata for the current design\n");
        log("\n");
        log("    -o <filename>\n");
        log("        write to the specified file.\n");
        log("\n");
        log("See 'help write_metadata' for a description of the JSON format used.\n");
        log("\n");
    }
    void execute(std::vector<std::string> args, RTLIL::Design *design) override
    {
        std::string filename{};

        size_t argidx;
        for (argidx = 1; argidx < args.size(); argidx++)
        {
            if (args[argidx] == "-o" && argidx+1 < args.size()) {
                filename = args[++argidx];
                continue;
            }
            break;
        }
        extra_args(args, argidx, design);

        std::ostream *f;
        std::stringstream buf;

        if (!filename.empty()) {
            rewrite_filename(filename);
            std::ofstream *ff = new std::ofstream;
            ff->open(filename.c_str(), std::ofstream::trunc);
            if (ff->fail()) {
                delete ff;
                log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
            }
            f = ff;
        } else {
            f = &buf;
        }

        MetadataWriter metadata_writier(*f, false);
        metadata_writier.write_metadata(design);

        if (!filename.empty()) {
            delete f;
        } else {
            log("%s", buf.str().c_str());
        }
    }

} MetadataPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>/*
    Copyright 2002-2013 CEA LIST

    This file is part of LIMA.

    LIMA is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    LIMA 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with LIMA.  If not, see <http://www.gnu.org/licenses/>
*/
/************************************************************************
 *
 * @file       ExternalProcessUnit.cpp
 * @author     besancon (besanconr@zoe.cea.fr)
 * @date       Mon Jan 17 2011
 * copyright   Copyright (C) 2011 by CEA LIST (LVIC)
 *
 ***********************************************************************/

#include "ExternalProcessUnit.h"

#include "common/AbstractFactoryPattern/SimpleFactory.h"
#include "linguisticProcessing/common/annotationGraph/AnnotationData.h"
#include "common/XMLConfigurationFiles/xmlConfigurationFileExceptions.h"
#include "common/time/traceUtils.h"
#include "linguisticProcessing/core/LinguisticProcessors/LinguisticMetaData.h"
#include "linguisticProcessing/core/LinguisticResources/AbstractResource.h"
#include "linguisticProcessing/core/LinguisticResources/LinguisticResources.h"
#include "linguisticProcessing/core/LinguisticAnalysisStructure/AnalysisGraph.h"
#include "linguisticProcessing/core/TextSegmentation/SegmentationData.h"
#include "linguisticProcessing/client/AnalysisHandlers/SimpleStreamHandler.h"

//#include "boost/process.hpp"
#include <QtCore/QProcess>

#include <fstream>

//namespace bp = ::boost::process;

using namespace std;

namespace Lima {
namespace LinguisticProcessing {

#define DEFAULT_TEMPFILE "/tmp/lp_external_tmp"

SimpleFactory<MediaProcessUnit,ExternalProcessUnit> ExternalProcessUnitFactory(EXTERNALPROCESSUNIT_CLASSID);

ExternalProcessUnit::ExternalProcessUnit():
MediaProcessUnit(),
m_dumper(),
m_loader(),
m_commandLine(),
m_useTemporaryFile(true),
m_cleanTemporaryFile(true),
m_tmpFileName(DEFAULT_TEMPFILE),
m_handler(0),
m_out(0),
m_inputSuffix(),
m_outputSuffix()
{
}

ExternalProcessUnit::~ExternalProcessUnit()
{
}

//************************************************************************
bool
getBooleanParameter(Common::XMLConfigurationFiles::GroupConfigurationStructure& unitConfiguration,
                    const std::string& param) {
  string value=unitConfiguration.getParamsValueAtKey(param);
  if (value == "yes" ||
    value == "true" ||
    value == "1") {
    return true;
  }
  return false;
}

void ExternalProcessUnit::init(
  Common::XMLConfigurationFiles::GroupConfigurationStructure& unitConfiguration,
  Manager* manager)

{
  LOGINIT("LP:External");
  LDEBUG << "Initialization";

  MediaId language=manager->getInitializationParameters().media;
  try {
    string dumperName=unitConfiguration.getParamsValueAtKey("dumper");
    // create the dumper
    m_dumper=manager->getObject(dumperName);
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    LERROR << "Missing 'dumper' parameter in ExternalProcessUnit group for language "
           << (int)language << " !";
    throw InvalidConfiguration();
  }

  try {
    string loaderName=unitConfiguration.getParamsValueAtKey("loader");
    // create the loader
    m_loader=manager->getObject(loaderName);
  }
  catch (InvalidConfiguration& ) {
    m_loader = 0;
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    LERROR << "Missing 'loader' parameter in ExternalProcessUnit group for language "
           << (int)language << " !";
    throw InvalidConfiguration();
  }

  try {
    m_inputSuffix=QString::fromUtf8(unitConfiguration.getParamsValueAtKey("inputSuffix").c_str());
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_outputSuffix=QString::fromUtf8(unitConfiguration.getParamsValueAtKey("outputSuffix").c_str());
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_useTemporaryFile=getBooleanParameter(unitConfiguration,"useTmpFile");
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_cleanTemporaryFile=getBooleanParameter(unitConfiguration,"cleanTmpFile");
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_tmpFileName=unitConfiguration.getParamsValueAtKey("tmpFileName");
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_commandLine=QString::fromUtf8(unitConfiguration.getParamsValueAtKey("command").c_str());
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    LERROR << "Missing 'command' parameter in ExternalProcessUnit group for language "
           << (int)language << " !";
    throw InvalidConfiguration();
  }
}

LimaStatusCode ExternalProcessUnit::process(AnalysisContent& analysis) const
{
  TimeUtils::updateCurrentTime();
  LOGINIT("LP:External");
  LINFO << "ExternalProcessUnit: start";

  LinguisticMetaData* metadata=static_cast<LinguisticMetaData*>(analysis.getData("LinguisticMetaData"));
  if (metadata == 0) {
      LERROR << "no LinguisticMetaData ! abort";
      return MISSING_DATA;
  }

  LimaStatusCode returnCode(SUCCESS_ID);

  // produce temporary file with the given dumper
  LDEBUG << "ExternalProcessUnit: write tmp file";
  returnCode=m_dumper->process(analysis);
  if (returnCode!=SUCCESS_ID) {
    LERROR << "ExternalProcessUnit: failed to dump data to temporary file";
    return returnCode;
  }

  QString fileName = QString::fromUtf8(metadata->getMetaData("FileName").c_str());
  QString inputFilename, outputFilename;
  // apply command line
  LDEBUG << "ExternalProcessUnit: apply external program";
  QString commandLine = m_commandLine;
  if (!m_inputSuffix.isEmpty())
  {
    inputFilename = fileName+ m_inputSuffix;
  }
  if (!m_outputSuffix.isEmpty())
  {
    outputFilename = fileName + m_outputSuffix;
  }
//   commandLine = commandLine.arg(inputFilename).arg(outputFilename);
  LDEBUG << "Launching " << commandLine;
  QProcess::execute(commandLine);

  if (m_loader != 0) {
    // load results from the external program with the given loader
    LDEBUG << "ExternalProcessUnit: read results";
    returnCode=m_loader->process(analysis);
    if (returnCode!=SUCCESS_ID) {
      LERROR << "ExternalProcessUnit: failed to load data from temporary file";
      return returnCode;
    }
  }
  else {
    LWARN << "ExternalProcessUnit: no loader defined for the current external process unit";
  }

  TimeUtils::logElapsedTime("ExternalProcessUnit");
  return returnCode;
}

} // end namespace
} // end namespace
<commit_msg>Uncomment the line to launch the srl command with arguments<commit_after>/*
    Copyright 2002-2013 CEA LIST

    This file is part of LIMA.

    LIMA is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    LIMA 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with LIMA.  If not, see <http://www.gnu.org/licenses/>
*/
/************************************************************************
 *
 * @file       ExternalProcessUnit.cpp
 * @author     besancon (besanconr@zoe.cea.fr)
 * @date       Mon Jan 17 2011
 * copyright   Copyright (C) 2011 by CEA LIST (LVIC)
 *
 ***********************************************************************/

#include "ExternalProcessUnit.h"

#include "common/AbstractFactoryPattern/SimpleFactory.h"
#include "linguisticProcessing/common/annotationGraph/AnnotationData.h"
#include "common/XMLConfigurationFiles/xmlConfigurationFileExceptions.h"
#include "common/time/traceUtils.h"
#include "linguisticProcessing/core/LinguisticProcessors/LinguisticMetaData.h"
#include "linguisticProcessing/core/LinguisticResources/AbstractResource.h"
#include "linguisticProcessing/core/LinguisticResources/LinguisticResources.h"
#include "linguisticProcessing/core/LinguisticAnalysisStructure/AnalysisGraph.h"
#include "linguisticProcessing/core/TextSegmentation/SegmentationData.h"
#include "linguisticProcessing/client/AnalysisHandlers/SimpleStreamHandler.h"

//#include "boost/process.hpp"
#include <QtCore/QProcess>

#include <fstream>

//namespace bp = ::boost::process;

using namespace std;

namespace Lima {
namespace LinguisticProcessing {

#define DEFAULT_TEMPFILE "/tmp/lp_external_tmp"

SimpleFactory<MediaProcessUnit,ExternalProcessUnit> ExternalProcessUnitFactory(EXTERNALPROCESSUNIT_CLASSID);

ExternalProcessUnit::ExternalProcessUnit():
MediaProcessUnit(),
m_dumper(),
m_loader(),
m_commandLine(),
m_useTemporaryFile(true),
m_cleanTemporaryFile(true),
m_tmpFileName(DEFAULT_TEMPFILE),
m_handler(0),
m_out(0),
m_inputSuffix(),
m_outputSuffix()
{
}

ExternalProcessUnit::~ExternalProcessUnit()
{
}

//************************************************************************
bool
getBooleanParameter(Common::XMLConfigurationFiles::GroupConfigurationStructure& unitConfiguration,
                    const std::string& param) {
  string value=unitConfiguration.getParamsValueAtKey(param);
  if (value == "yes" ||
    value == "true" ||
    value == "1") {
    return true;
  }
  return false;
}

void ExternalProcessUnit::init(
  Common::XMLConfigurationFiles::GroupConfigurationStructure& unitConfiguration,
  Manager* manager)

{
  LOGINIT("LP:External");
  LDEBUG << "Initialization";

  MediaId language=manager->getInitializationParameters().media;
  try {
    string dumperName=unitConfiguration.getParamsValueAtKey("dumper");
    // create the dumper
    m_dumper=manager->getObject(dumperName);
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    LERROR << "Missing 'dumper' parameter in ExternalProcessUnit group for language "
           << (int)language << " !";
    throw InvalidConfiguration();
  }

  try {
    string loaderName=unitConfiguration.getParamsValueAtKey("loader");
    // create the loader
    m_loader=manager->getObject(loaderName);
  }
  catch (InvalidConfiguration& ) {
    m_loader = 0;
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    LERROR << "Missing 'loader' parameter in ExternalProcessUnit group for language "
           << (int)language << " !";
    throw InvalidConfiguration();
  }

  try {
    m_inputSuffix=QString::fromUtf8(unitConfiguration.getParamsValueAtKey("inputSuffix").c_str());
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_outputSuffix=QString::fromUtf8(unitConfiguration.getParamsValueAtKey("outputSuffix").c_str());
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_useTemporaryFile=getBooleanParameter(unitConfiguration,"useTmpFile");
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_cleanTemporaryFile=getBooleanParameter(unitConfiguration,"cleanTmpFile");
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_tmpFileName=unitConfiguration.getParamsValueAtKey("tmpFileName");
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    // optional parameter: keep default value
  }

  try {
    m_commandLine=QString::fromUtf8(unitConfiguration.getParamsValueAtKey("command").c_str());
  }
  catch (Common::XMLConfigurationFiles::NoSuchParam& ) {
    LERROR << "Missing 'command' parameter in ExternalProcessUnit group for language "
           << (int)language << " !";
    throw InvalidConfiguration();
  }
}

LimaStatusCode ExternalProcessUnit::process(AnalysisContent& analysis) const
{
  TimeUtils::updateCurrentTime();
  LOGINIT("LP:External");
  LINFO << "ExternalProcessUnit: start";

  LinguisticMetaData* metadata=static_cast<LinguisticMetaData*>(analysis.getData("LinguisticMetaData"));
  if (metadata == 0) {
      LERROR << "no LinguisticMetaData ! abort";
      return MISSING_DATA;
  }

  LimaStatusCode returnCode(SUCCESS_ID);

  // produce temporary file with the given dumper
  LDEBUG << "ExternalProcessUnit: write tmp file";
  returnCode=m_dumper->process(analysis);
  if (returnCode!=SUCCESS_ID) {
    LERROR << "ExternalProcessUnit: failed to dump data to temporary file";
    return returnCode;
  }

  QString fileName = QString::fromUtf8(metadata->getMetaData("FileName").c_str());
  QString inputFilename, outputFilename;
  // apply command line
  LDEBUG << "ExternalProcessUnit: apply external program";
  QString commandLine = m_commandLine;
  if (!m_inputSuffix.isEmpty())
  {
    inputFilename = fileName+ m_inputSuffix;
  }
  if (!m_outputSuffix.isEmpty())
  {
    outputFilename = fileName + m_outputSuffix;
  }
  commandLine = commandLine.arg(inputFilename).arg(outputFilename);
  LDEBUG << "Launching " << commandLine;
  QProcess::execute(commandLine);

  if (m_loader != 0) {
    // load results from the external program with the given loader
    LDEBUG << "ExternalProcessUnit: read results";
    returnCode=m_loader->process(analysis);
    if (returnCode!=SUCCESS_ID) {
      LERROR << "ExternalProcessUnit: failed to load data from temporary file";
      return returnCode;
    }
  }
  else {
    LWARN << "ExternalProcessUnit: no loader defined for the current external process unit";
  }

  TimeUtils::logElapsedTime("ExternalProcessUnit");
  return returnCode;
}

} // end namespace
} // end namespace
<|endoftext|>


<commit_before>#include "server.h"
#include "unique_fd.h"

#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <cstring>
#include <sstream>
#include <fstream>
#include <thread>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

namespace
{

const int fail = -1;
const int inet_aton_fail = 0;

static bool terminated = false;

void termination(int signum)
{
    terminated = true;
}

bool setSignalsHandlers()
{
    struct sigaction sa;
    sa.sa_handler = termination;
    sigaddset(&sa.sa_mask, SIGTERM);
    sigaddset(&sa.sa_mask, SIGINT);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    if (sigaction(SIGINT, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    return true;
}

bool init(const http_server::Options& options)
{

    if (options.daemon()) {
        if (daemon(0, 1) == fail) {
            perror("daemon");
            return false;
        }
    }

    if (options.verbose()) {
        std::cout << "The server started as "
                  << (options.daemon()? "daemon": "application")
                  << std::endl;
        std::cout << "pid = " << getpid() << std::endl;
    }

    return setSignalsHandlers();
}

aux::UniqueFd makeListeningSocket()
{
    //aux::UniqueFd sd {socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)};
    aux::UniqueFd sockfd {socket(AF_INET, SOCK_STREAM, 0)};
    if (!sockfd) {
        perror("socket");
        return aux::UniqueFd();
    }

    const int yes = 1;
    if (setsockopt(sockfd, SOL_SOCKET,
                   SO_REUSEADDR, &yes, sizeof(yes)) == fail) {
        perror("setsockopt");
        return aux::UniqueFd();
    }

    return sockfd;
}

bool startListen(const aux::UniqueFd& sockfd, const http_server::Options& options)
{
    struct sockaddr_in addr_in;
    addr_in.sin_family = AF_INET;
    addr_in.sin_port = htons(options.port());
    if (inet_aton(options.ip(), &addr_in.sin_addr) == inet_aton_fail) {
        std::cerr << "inet_aton: " << "The address '"
                  << options.ip() << "' is wrong" << std::endl;
        return false;
    }

    if (options.verbose()) {
        std::cout << "Listening: "
                  << inet_ntoa(addr_in.sin_addr) << ":" << ntohs(addr_in.sin_port)
                  << std::endl;
    }

    if (bind(sockfd,
             reinterpret_cast<struct sockaddr*>(&addr_in),
             sizeof(addr_in)) == fail) {
        perror("bind");
        return false;
    }

    if (listen(sockfd, SOMAXCONN) == fail) {
        perror("listen");
        return false;
    }

    return true;
}

void outputBinaryData(const char * data, size_t size)
{
    std::cout << std::setfill('0');
    for(size_t i = 0; i < size; ++i)
        std::cout << std::setw(2) << std::hex
                  << static_cast<int>(data[i]) << " ";
    std::cout << std::setfill(' ');
    std::cout << std::dec;
    std::cout << std::endl;
    std::cout << std::endl;
}

int sendData(int sockfd, const char * data, size_t size, bool verbose, std::ofstream& logout)
{
    logout << std::string(data, size);

    if (verbose)
    {
        std::cout << "Send: ";
        outputBinaryData(data, size);
    }

    int res = send(sockfd, data, size, 0);
    if (res == -1)
        perror("send");

    return res;
}

int sendBadRequest(int sockfd, bool verbose, std::ofstream& logout)
{
    static const char badRequest[] = "HTTP/1.0 400 Bad Request\r\n"
                                     "Content-Type: text/html\r\n"
                                     "Content-Length: 43\r\n"
                                     "\r\n"
                                     "400 Bad Request\r\n";

    return sendData(sockfd, badRequest, sizeof(badRequest) - 1, verbose, logout);
}

int sendNotFound(int sockfd, bool verbose, std::ofstream& logout)
{
    static const char notFound[] = "HTTP/1.0 404 Not Found\r\n"
                                   "Content-Type: text/html\r\n"
                                   "Content-Length: 41\r\n"
                                   "\r\n"
                                   "404 Not Found\r\n";

    return sendData(sockfd, notFound, sizeof(notFound) - 1, verbose, logout);
}

int sendAnswer(int sockfd, const std::string& data, bool verbose, std::ofstream& logout)
{
    std::ostringstream os;
    os << "HTTP/1.0 200 OK\r\n"
       << "Content-Type: text/html\r\n"
       << "Content-Length: " << data.length() << "\r\n"
       << "\r\n"
       << data;

    return sendData(sockfd, os.str().c_str(), os.str().length(), verbose, logout);
}

void clientWorker(aux::UniqueFd&& sockfd,
                  const sockaddr_in peerAddr,
                  const http_server::Options& options)
{
    aux::UniqueFd clientfd(std::move(sockfd));

    std::string logName;
    {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        std::ostringstream os;
        os << "/tmp/" << tv.tv_sec << "_" << tv.tv_usec << ".log";
        logName = os.str();
        os.str("");
    }

    std::ofstream logout(logName);

    if (options.verbose()) {
        std::cout << "Connection with: "
                  << inet_ntoa(peerAddr.sin_addr)
                  << ":" << ntohs(peerAddr.sin_port)
                  << std::endl;
    }
    logout << "Connection with: "
           << inet_ntoa(peerAddr.sin_addr)
           << ":" << ntohs(peerAddr.sin_port)
           << "\n" << std::endl;

    char buf[1024];
    ssize_t received = recv(clientfd, &buf, sizeof(buf), 0);
    switch (received)
    {
        case -1:
            perror("recv");
            break;
        case 0:
            break;
        default:
            if (options.verbose()) {
                std::cout << "Received: ";
                outputBinaryData(buf, received);
            }

            logout << std::string(buf, received);
            logout.flush();

            const char* getLine = std::strtok(buf, "\r\n");

            if ((getLine == NULL) || (strncmp(getLine, "GET ", 4) != 0))
            {
                sendBadRequest(clientfd, options.verbose(), logout);
                return;
            }

            const char* protocolStr = std::strrchr(getLine, 'H');
            if ((protocolStr == NULL) || (std::strncmp(protocolStr, "HTTP/", 5) != 0))
            {
                sendBadRequest(clientfd, options.verbose(), logout);
                return;
            }

            std::string filename(getLine + 4, protocolStr - getLine - 5);

            std::filebuf file;
            if (file.open(options.directory() + filename, std::ios_base::in) == nullptr)
            {
                sendNotFound(clientfd, options.verbose(), logout);
                return;
            }

            using std::ios_base;
            auto posEnd = file.pubseekoff(0, ios_base::end);
            file.pubseekpos(0);

            //sendAnswer(clientfd, filename, options.verbose());

            if (options.verbose())
                std::cout << "Sending header..." << std::endl;

            std::ostringstream os;
            int fileSize = posEnd;
            os << "HTTP/1.0 200 OK\r\n"
               << "Content-Type: text/html\r\n"
               << "Content-Length: " << (fileSize - 1) << "\r\n"
               << "\r\n";

            int read = 0;
            do
            {
                read = file.sgetn(buf, sizeof(buf));
                os << std::string(buf, read);
            } while(read == sizeof(buf));

            if (sendData(clientfd, os.str().c_str(), os.str().length(), options.verbose(), logout) == -1)
                return;
/*
            if (options.verbose())
                std::cout << "Sending content..." << std::endl;
            int read = 0;
            do
            {
                read = file.sgetn(buf, sizeof(buf));
                if (sendData(clientfd, buf, read, options.verbose()) == -1)
                    return;
            } while(read == sizeof(buf));
*/
            break;
    }
}

} /* anonymous namespace */

int http_server::run(const http_server::Options& options)
{
    if (!init(options))
        return EXIT_FAILURE;

    aux::UniqueFd sockfd { makeListeningSocket() };
    if (!sockfd)
        return EXIT_FAILURE;

    if (!startListen(sockfd, options))
        return EXIT_FAILURE;

    std::ofstream logout("/tmp/mainfinal.log");
    logout << "start" << std::endl;

    while(!terminated) {
        struct sockaddr_in peerAddr;
        socklen_t peerAddrSize = sizeof(peerAddr);
        aux::UniqueFd clientfd {
            accept(sockfd,
                   reinterpret_cast<sockaddr*>(&peerAddr),
                   &peerAddrSize)
            };

        if (clientfd) {
            //clientWorker(std::move(clientfd), peerAddr, options);
            logout << "Connection with: "
                   << inet_ntoa(peerAddr.sin_addr)
                   << ":" << ntohs(peerAddr.sin_port)
                   << "\n" << std::endl;
            std::thread t(clientWorker, std::move(clientfd), peerAddr, options);
            t.detach();
        } else {
            perror("accept");
        }
    }

    if (options.verbose())
        std::cout << "The server stoped" << std::endl;

    logout << "stop\n";
    logout.close();

    return 0;
}

<commit_msg>single log<commit_after>#include "server.h"
#include "unique_fd.h"

#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <cstring>
#include <sstream>
#include <fstream>
#include <thread>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

namespace
{

const int fail = -1;
const int inet_aton_fail = 0;

static bool terminated = false;

void termination(int signum)
{
    terminated = true;
}

bool setSignalsHandlers()
{
    struct sigaction sa;
    sa.sa_handler = termination;
    sigaddset(&sa.sa_mask, SIGTERM);
    sigaddset(&sa.sa_mask, SIGINT);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    if (sigaction(SIGINT, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    return true;
}

bool init(const http_server::Options& options)
{

    if (options.daemon()) {
        if (daemon(0, 1) == fail) {
            perror("daemon");
            return false;
        }
    }

    if (options.verbose()) {
        std::cout << "The server started as "
                  << (options.daemon()? "daemon": "application")
                  << std::endl;
        std::cout << "pid = " << getpid() << std::endl;
    }

    return setSignalsHandlers();
}

aux::UniqueFd makeListeningSocket()
{
    //aux::UniqueFd sd {socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)};
    aux::UniqueFd sockfd {socket(AF_INET, SOCK_STREAM, 0)};
    if (!sockfd) {
        perror("socket");
        return aux::UniqueFd();
    }

    const int yes = 1;
    if (setsockopt(sockfd, SOL_SOCKET,
                   SO_REUSEADDR, &yes, sizeof(yes)) == fail) {
        perror("setsockopt");
        return aux::UniqueFd();
    }

    return sockfd;
}

bool startListen(const aux::UniqueFd& sockfd, const http_server::Options& options)
{
    struct sockaddr_in addr_in;
    addr_in.sin_family = AF_INET;
    addr_in.sin_port = htons(options.port());
    if (inet_aton(options.ip(), &addr_in.sin_addr) == inet_aton_fail) {
        std::cerr << "inet_aton: " << "The address '"
                  << options.ip() << "' is wrong" << std::endl;
        return false;
    }

    if (options.verbose()) {
        std::cout << "Listening: "
                  << inet_ntoa(addr_in.sin_addr) << ":" << ntohs(addr_in.sin_port)
                  << std::endl;
    }

    if (bind(sockfd,
             reinterpret_cast<struct sockaddr*>(&addr_in),
             sizeof(addr_in)) == fail) {
        perror("bind");
        return false;
    }

    if (listen(sockfd, SOMAXCONN) == fail) {
        perror("listen");
        return false;
    }

    return true;
}

void outputBinaryData(const char * data, size_t size)
{
    std::cout << std::setfill('0');
    for(size_t i = 0; i < size; ++i)
        std::cout << std::setw(2) << std::hex
                  << static_cast<int>(data[i]) << " ";
    std::cout << std::setfill(' ');
    std::cout << std::dec;
    std::cout << std::endl;
    std::cout << std::endl;
}

int sendData(int sockfd, const char * data, size_t size, bool verbose, std::ofstream& logout)
{
    logout << std::string(data, size);

    if (verbose)
    {
        std::cout << "Send: ";
        outputBinaryData(data, size);
    }

    int res = send(sockfd, data, size, 0);
    if (res == -1)
        perror("send");

    return res;
}

int sendBadRequest(int sockfd, bool verbose, std::ofstream& logout)
{
    static const char badRequest[] = "HTTP/1.0 400 Bad Request\r\n"
                                     "Content-Type: text/html\r\n"
                                     "Content-Length: 43\r\n"
                                     "\r\n"
                                     "400 Bad Request\r\n";

    return sendData(sockfd, badRequest, sizeof(badRequest) - 1, verbose, logout);
}

int sendNotFound(int sockfd, bool verbose, std::ofstream& logout)
{
    static const char notFound[] = "HTTP/1.0 404 Not Found\r\n"
                                   "Content-Type: text/html\r\n"
                                   "Content-Length: 41\r\n"
                                   "\r\n"
                                   "404 Not Found\r\n";

    return sendData(sockfd, notFound, sizeof(notFound) - 1, verbose, logout);
}

int sendAnswer(int sockfd, const std::string& data, bool verbose, std::ofstream& logout)
{
    std::ostringstream os;
    os << "HTTP/1.0 200 OK\r\n"
       << "Content-Type: text/html\r\n"
       << "Content-Length: " << data.length() << "\r\n"
       << "\r\n"
       << data;

    return sendData(sockfd, os.str().c_str(), os.str().length(), verbose, logout);
}

void clientWorker(aux::UniqueFd&& sockfd,
                  const sockaddr_in peerAddr,
                  const http_server::Options& options,
                  std::ofstream& logout
                  )
{
    aux::UniqueFd clientfd(std::move(sockfd));

    std::string logName;
    {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        std::ostringstream os;
        os << "/tmp/" << tv.tv_sec << "_" << tv.tv_usec << ".log";
        logName = os.str();
        os.str("");
    }

    //std::ofstream logout(logName);

    if (options.verbose()) {
        std::cout << "Connection with: "
                  << inet_ntoa(peerAddr.sin_addr)
                  << ":" << ntohs(peerAddr.sin_port)
                  << std::endl;
    }
    logout << "Connection with: "
           << inet_ntoa(peerAddr.sin_addr)
           << ":" << ntohs(peerAddr.sin_port)
           << "\n" << std::endl;

    char buf[1024];
    ssize_t received = recv(clientfd, &buf, sizeof(buf), 0);
    switch (received)
    {
        case -1:
            perror("recv");
            break;
        case 0:
            break;
        default:
            if (options.verbose()) {
                std::cout << "Received: ";
                outputBinaryData(buf, received);
            }

            logout << std::string(buf, received);
            logout.flush();

            const char* getLine = std::strtok(buf, "\r\n");

            if ((getLine == NULL) || (strncmp(getLine, "GET ", 4) != 0))
            {
                sendBadRequest(clientfd, options.verbose(), logout);
                return;
            }

            const char* protocolStr = std::strrchr(getLine, 'H');
            if ((protocolStr == NULL) || (std::strncmp(protocolStr, "HTTP/", 5) != 0))
            {
                sendBadRequest(clientfd, options.verbose(), logout);
                return;
            }

            std::string filename(getLine + 4, protocolStr - getLine - 5);

            std::filebuf file;
            if (file.open(options.directory() + filename, std::ios_base::in) == nullptr)
            {
                sendNotFound(clientfd, options.verbose(), logout);
                return;
            }

            using std::ios_base;
            auto posEnd = file.pubseekoff(0, ios_base::end);
            file.pubseekpos(0);

            //sendAnswer(clientfd, filename, options.verbose());

            if (options.verbose())
                std::cout << "Sending header..." << std::endl;

            std::ostringstream os;
            int fileSize = posEnd;
            os << "HTTP/1.0 200 OK\r\n"
               << "Content-Type: text/html\r\n"
               << "Content-Length: " << (fileSize - 1) << "\r\n"
               << "\r\n";

            int read = 0;
            do
            {
                read = file.sgetn(buf, sizeof(buf));
                os << std::string(buf, read);
            } while(read == sizeof(buf));

            if (sendData(clientfd, os.str().c_str(), os.str().length(), options.verbose(), logout) == -1)
                return;
/*
            if (options.verbose())
                std::cout << "Sending content..." << std::endl;
            int read = 0;
            do
            {
                read = file.sgetn(buf, sizeof(buf));
                if (sendData(clientfd, buf, read, options.verbose()) == -1)
                    return;
            } while(read == sizeof(buf));
*/
            break;
    }
}

} /* anonymous namespace */

int http_server::run(const http_server::Options& options)
{
    if (!init(options))
        return EXIT_FAILURE;

    aux::UniqueFd sockfd { makeListeningSocket() };
    if (!sockfd)
        return EXIT_FAILURE;

    if (!startListen(sockfd, options))
        return EXIT_FAILURE;

    std::ofstream logout("/tmp/mainfinal.log");
    logout << "start" << std::endl;

    while(!terminated) {
        struct sockaddr_in peerAddr;
        socklen_t peerAddrSize = sizeof(peerAddr);
        aux::UniqueFd clientfd {
            accept(sockfd,
                   reinterpret_cast<sockaddr*>(&peerAddr),
                   &peerAddrSize)
            };

        if (clientfd) {
            //clientWorker(std::move(clientfd), peerAddr, options);
            logout << "Connection with: "
                   << inet_ntoa(peerAddr.sin_addr)
                   << ":" << ntohs(peerAddr.sin_port)
                   << "\n" << std::endl;
            std::thread t(clientWorker, std::move(clientfd), peerAddr, options, std::ref(logout));
            t.detach();
        } else {
            perror("accept");
        }
    }

    if (options.verbose())
        std::cout << "The server stoped" << std::endl;

    logout << "stop\n";
    logout.close();

    return 0;
}

<|endoftext|>


<commit_before>#ifndef SAVE_STATE_H
# define SAVE_STATE_H
# pragma once

struct statebuf
{
  void* sp;
  void* label;
};

#if defined(__GNUC__)
inline bool __attribute__((always_inline)) savestate(statebuf& ssb) noexcept
{
	bool r;

#if defined(i386) || defined(__i386) || defined(__i386__)
	asm volatile (
		"movl %%esp, %0\n\t" // store sp
		"movl $1f, %1\n\t" // store label
		"movb $0, %2\n\t" // return false
		"jmp 2f\n\t"
		"1:movb $1, %2\n\t" // return true
		"2:"
		: "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
		:
		: "memory"
	);
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
	asm volatile (
		"movq %%rsp, %0\n\t" // store sp
		"movq $1f, %1\n\t" // store label
		"movb $0, %2\n\t" // return false
		"jmp 2f\n\t"
		"1:movb $1, %2\n\t" // return true
		"2:"
		: "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
		:
		: "memory"
	);
#elif defined(__arm__)
  asm volatile (
    "str sp, %0"
    "b 2f\n\t"
    "2:"
    : "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
    :
    : "memory"
  );
#endif

	return r;
}
#elif defined(_MSC_VER)
__forceinline bool savestate(statebuf& ssb) noexcept
{
	bool r;

	__asm {
		push ebp
		mov ebx, ssb
		mov [ebx]ssb.sp, esp
		mov [ebx]ssb.label, offset _1f
		mov r, 0x0
		jmp _2f
		_1f: pop ebp
			 mov r, 0x1
		_2f:
	}

	return r;
}
#else
# error "unsupported compiler"
#endif

#if defined(__GNUC__)
#if defined(i386) || defined(__i386) || defined(__i386__)
#define restorestate(SSB)          \
  asm volatile (                   \
    "movl %0, %%esp\n\t"           \
    "jmp *%1"                      \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
#define restorestate(SSB)          \
  asm volatile (                   \
    "movq %0, %%rsp\n\t"           \
    "jmp *%1"                      \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#elif defined(__arm__)
#define restorestate(SSB)          \
  asm volatile (                   \
    "ldr sp, %0\n\t"               \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#else
# error "unsupported architecture"
#endif
#elif defined(_MSC_VER)
#define restorestate(SSB)   \
  __asm mov ebx, this       \
  __asm add ebx, [SSB]      \
  __asm mov esp, [ebx]SSB.sp\
  __asm jmp [ebx]SSB.label
#else
# error "unsupported compiler"
#endif

#endif // SAVE_STATE_H
<commit_msg>some fixes<commit_after>#ifndef SAVE_STATE_H
# define SAVE_STATE_H
# pragma once

struct statebuf
{
  void* sp;
  void* label;
};

#if defined(__GNUC__)
inline bool __attribute__((always_inline)) savestate(statebuf& ssb) noexcept
{
	bool r;

#if defined(i386) || defined(__i386) || defined(__i386__)
	asm volatile (
		"movl %%esp, %0\n\t" // store sp
		"movl $1f, %1\n\t" // store label
		"movb $0, %2\n\t" // return false
		"jmp 2f\n\t"
		"1:movb $1, %2\n\t" // return true
		"2:"
		: "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
		:
		: "memory"
	);
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
	asm volatile (
		"movq %%rsp, %0\n\t" // store sp
		"movq $1f, %1\n\t" // store label
		"movb $0, %2\n\t" // return false
		"jmp 2f\n\t"
		"1:movb $1, %2\n\t" // return true
		"2:"
		: "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
		:
		: "memory"
	);
#elif defined(__arm__)
  asm volatile (
    "str sp, %0\n\t"
    "b 2f\n\t"
    "2:"
    : "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
    :
    : "memory"
  );
#endif

	return r;
}
#elif defined(_MSC_VER)
__forceinline bool savestate(statebuf& ssb) noexcept
{
	bool r;

	__asm {
		push ebp
		mov ebx, ssb
		mov [ebx]ssb.sp, esp
		mov [ebx]ssb.label, offset _1f
		mov r, 0x0
		jmp _2f
		_1f: pop ebp
			 mov r, 0x1
		_2f:
	}

	return r;
}
#else
# error "unsupported compiler"
#endif

#if defined(__GNUC__)
#if defined(i386) || defined(__i386) || defined(__i386__)
#define restorestate(SSB)          \
  asm volatile (                   \
    "movl %0, %%esp\n\t"           \
    "jmp *%1"                      \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
#define restorestate(SSB)          \
  asm volatile (                   \
    "movq %0, %%rsp\n\t"           \
    "jmp *%1"                      \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#elif defined(__arm__)
#define restorestate(SSB)          \
  asm volatile (                   \
    "ldr sp, %0\n\t"               \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#else
# error "unsupported architecture"
#endif
#elif defined(_MSC_VER)
#define restorestate(SSB)   \
  __asm mov ebx, this       \
  __asm add ebx, [SSB]      \
  __asm mov esp, [ebx]SSB.sp\
  __asm jmp [ebx]SSB.label
#else
# error "unsupported compiler"
#endif

#endif // SAVE_STATE_H
<|endoftext|>


<commit_before>#ifdef SHRINK

#include "internal.hpp"
#include "macros.hpp"

#include <algorithm>

namespace CaDiCaL {

// This is an extended minimization which goes over all alternative reasons
// as first explored in PrecoSAT and discussed by Allen Van Gelder later.
// The most important observation in PrecoSAT was that alternative reasons
// for resolution need to have all literals but one set to false and thus
// the true literal will be watched.  It subsumes clause minimization, but
// is more expensive and thus should be called only on clauses for which
// shrinking is useful (such as small clauses with small glue).  As in
// PrecoSAT we restrict traversal to follow the topological assignment order
// to avoid cycles (which would yield unsound removals).

bool Internal::shrink_literal (int lit, int depth) {
  assert (val (lit) > 0);
  Flags & f = flags (lit);
  Var & v = var (lit);
  if (!v.level || f.removable || f.clause) return true;
  if (!v.reason || f.poison || v.level == level) return false;
  const Level & l = control[v.level];
  if (!depth && l.seen < 2) return false;
  if (v.trail <= l.trail) return false;
  if (depth > opts.shrinkdepth) return false;
  bool remove = false;
  Watches & ws = watches (lit);

  // The difference to 'minimize_literal' is here, where we iterate over all
  // clauses watches by 'lit' instead of 'just' the reason clause except for
  // '(!!!)' where we have to make sure that we respect assignment order in
  // resolutions to avoid cyclic derivations.  For the actual reason this
  // test is not necessary.

  const const_watch_iterator eow = ws.end ();
  const_watch_iterator i;
  for (i = ws.begin (); !remove && i != eow; i++) {
    Clause * c = i->clause;
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    bool failed = false;
    int lit_trail = var (lit).trail;
    for (j = c->begin (); !failed && j != eoc; j++) {
      int other = *j;
      if (other == lit) continue;
      else if (val (other) >= 0) failed = true;
      else if (var (other).trail > lit_trail) failed = true;  // (!!!)
      else failed = !shrink_literal (-other, depth+1);
    }
    if (!failed) remove = true;
  }

  if (remove) f.removable = true; else f.poison = true;
  minimized.push_back (lit);
  if (!depth) LOG ("shrinking %d %s", lit, remove ? "succeeded" : "failed");
  return remove;
}

void Internal::shrink_clause () {
  START (shrink);
  LOG (clause, "shrinking minimized first UIP clause");
  stats.shrinktried += clause.size ();
  sort (clause.begin (), clause.end (), trail_smaller (this));
  assert (minimized.empty ());
  int_iterator j = clause.begin ();
  for (const_int_iterator i = j; i != clause.end (); i++)
    if (shrink_literal (-*i)) stats.shrunken++;
    else flags (*j++ = *i).clause = true;
  LOG ("shrunken %d literals", (long)(clause.end () - j));
  clause.resize (j - clause.begin ());
  clear_minimized ();
  check_learned_clause ();
  STOP (shrink);
}

};

#endif
<commit_msg>shrink<commit_after>#ifdef SHRINK

#include "internal.hpp"
#include "macros.hpp"

#include <algorithm>

namespace CaDiCaL {

// This is an extended minimization which goes over all alternative reasons
// as first explored in PrecoSAT and discussed by Allen Van Gelder later.
// The most important observation in PrecoSAT was that alternative reasons
// for resolution need to have all literals but one set to false and thus
// the true literal will be watched.  It subsumes clause minimization, but
// is more expensive and thus should be called only on clauses for which
// shrinking is useful (such as small clauses with small glue).  As in
// PrecoSAT we restrict traversal to follow the topological assignment order
// to avoid cycles (which could yield unsound removals).

bool Internal::shrink_literal (int lit, int depth) {
  assert (val (lit) > 0);
  Flags & f = flags (lit);
  Var & v = var (lit);
  if (!v.level || f.removable || f.clause) return true;
  if (!v.reason || f.poison || v.level == level) return false;
  const Level & l = control[v.level];
  if (!depth && l.seen < 2) return false;
  if (v.trail <= l.trail) return false;
  if (depth > opts.shrinkdepth) return false;
  bool remove = false;
  Watches & ws = watches (lit);

  // The difference to 'minimize_literal' is here, where we iterate over all
  // clauses watched by 'lit' instead of 'just' the reason clause except for
  // '(!!!)' where we have to make sure that we respect assignment order in
  // resolutions to avoid cyclic derivations.  For the actual reason this
  // test is not necessary.

  const const_watch_iterator eow = ws.end ();
  const_watch_iterator i;
  for (i = ws.begin (); !remove && i != eow; i++) {
    Clause * c = i->clause;
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    bool failed = false;
    int lit_trail = var (lit).trail;
    for (j = c->begin (); !failed && j != eoc; j++) {
      int other = *j;
      if (other == lit) continue;
      else if (val (other) >= 0) failed = true;
      else if (var (other).trail > lit_trail) failed = true;  // (!!!)
      else failed = !shrink_literal (-other, depth+1);
    }
    if (!failed) remove = true;
  }

  if (remove) f.removable = true; else f.poison = true;
  minimized.push_back (lit);
  if (!depth) LOG ("shrinking %d %s", lit, remove ? "succeeded" : "failed");
  return remove;
}

void Internal::shrink_clause () {
  START (shrink);
  LOG (clause, "shrinking minimized first UIP clause");
  stats.shrinktried += clause.size ();
  sort (clause.begin (), clause.end (), trail_smaller (this));
  assert (minimized.empty ());
  int_iterator j = clause.begin ();
  for (const_int_iterator i = j; i != clause.end (); i++)
    if (shrink_literal (-*i)) stats.shrunken++;
    else flags (*j++ = *i).clause = true;
  LOG ("shrunken %d literals", (long)(clause.end () - j));
  clause.resize (j - clause.begin ());
  clear_minimized ();
  check_learned_clause ();
  STOP (shrink);
}

};

#endif
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 * Copyright (c) 2011 Laszlo Papp <djszapi@archlinux.us>
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "propertiesdock.h"

#include "widgets/propertywidget.h"
#include "objectmanager.h"
#include "historymanager.h"

#include <engine/game.h>
#include <engine/component.h>

using namespace GluonCreator;

class PropertiesDock::PropertiesDockPrivate
{
    public:
        PropertiesDockPrivate() { }

        PropertyWidget* widget;
};

PropertiesDock::PropertiesDock( const QString& title, QWidget* parent, Qt::WindowFlags flags )
    : QDockWidget( title, parent, flags ), d( new PropertiesDockPrivate )
{
    setObjectName( "PropertiesDock" );

    d->widget = new PropertyWidget( this );
    setWidget( d->widget );

    connect( SelectionManager::instance(), SIGNAL( selectionChanged( SelectionManager::SelectionList ) ), SLOT( selectionChanged( SelectionManager::SelectionList ) ) );
    connect( d->widget, SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ), SLOT( propertyChanged( QObject*, QString, QVariant, QVariant ) ) );
    connect( ObjectManager::instance(), SIGNAL( newComponent( GluonEngine::Component* ) ), SLOT( newComponent( GluonEngine::Component* ) ) );
}

PropertiesDock::~PropertiesDock()
{
    delete d;
}

void PropertiesDock::selectionChanged( SelectionManager::SelectionList selection )
{
    if( selection.empty() )
        d->widget->clear();
    else
        d->widget->setObject( selection.at( 0 ) );
}

void PropertiesDock::newComponent( GluonEngine::Component* comp )
{
    if( comp->parent() == d->widget->object() )
    {
        d->widget->setObject( d->widget->object() );
    }
}

void PropertiesDock::propertyChanged( QObject* object, QString property, QVariant oldValue, QVariant newValue )
{
    GluonCore::GluonObject* obj = qobject_cast<GluonCore::GluonObject*>( object );

    if( obj )
        ObjectManager::instance()->changeProperty( obj, property, oldValue, newValue );
}

<commit_msg>A little cleanup in the properties dock<commit_after>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 * Copyright (c) 2011 Laszlo Papp <djszapi@archlinux.us>
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "propertiesdock.h"

#include "widgets/propertywidget.h"
#include "objectmanager.h"
#include "historymanager.h"

#include <engine/game.h>
#include <engine/component.h>

using namespace GluonCreator;

class PropertiesDock::PropertiesDockPrivate
{
    public:
        PropertiesDockPrivate(PropertyWidget* widget)
            : widget(widget)
        { }

        PropertyWidget* widget;
};

PropertiesDock::PropertiesDock( const QString& title, QWidget* parent, Qt::WindowFlags flags )
    : QDockWidget( title, parent, flags )
    , d( new PropertiesDockPrivate( new PropertyWidget( this ) ) )
{
    setObjectName( "PropertiesDock" );

    setWidget( d->widget );

    connect( SelectionManager::instance(), SIGNAL( selectionChanged( SelectionManager::SelectionList ) ), SLOT( selectionChanged( SelectionManager::SelectionList ) ) );
    connect( d->widget, SIGNAL( propertyChanged( QObject*, QString, QVariant, QVariant ) ), SLOT( propertyChanged( QObject*, QString, QVariant, QVariant ) ) );
    connect( ObjectManager::instance(), SIGNAL( newComponent( GluonEngine::Component* ) ), SLOT( newComponent( GluonEngine::Component* ) ) );
}

PropertiesDock::~PropertiesDock()
{
    delete d;
}

void PropertiesDock::selectionChanged( SelectionManager::SelectionList selection )
{
    d->widget->clear();
    if( !selection.empty() )
        d->widget->setObject( selection.at( 0 ) );
}

void PropertiesDock::newComponent( GluonEngine::Component* comp )
{
    if( comp->parent() == d->widget->object() )
    {
        d->widget->setObject( d->widget->object() );
    }
}

void PropertiesDock::propertyChanged( QObject* object, QString property, QVariant oldValue, QVariant newValue )
{
    GluonCore::GluonObject* obj = qobject_cast<GluonCore::GluonObject*>( object );

    if( obj )
        ObjectManager::instance()->changeProperty( obj, property, oldValue, newValue );
}

<|endoftext|>