<commit_before>#include "k/context.h"

#include "etl/armv7m/instructions.h"
#include "etl/armv7m/mpu.h"
#include "etl/armv7m/types.h"

#include "k/address_range.h"
#include "k/context_layout.h"
#include "k/ipc.h"
#include "k/object_table.h"
#include "k/registers.h"
#include "k/reply_sender.h"
#include "k/unprivileged.h"

using etl::armv7m::Word;

namespace k {

/*******************************************************************************
 * Global objects
 */

Context * current;
List<Context> runnable;
bool switch_pending;

static void do_deferred_switch() {
  if (!switch_pending) return;

  switch_pending = false;

  while (runnable.is_empty()) {
    etl::armv7m::wait_for_interrupt();
  }

  current = runnable.peek().ref()->owner;
}

static void pend_switch() {
  switch_pending = true;
}

/*******************************************************************************
 * Context-specific stuff
 */

Context::Context()
  : _stack{nullptr},
    _keys{},
    _ctx_item{this},
    _sender_item{this},
    _saved_brand{0} {}

void Context::nullify_exchanged_keys(unsigned preserved) {
  // Had to do this somewhere, this is as good a place as any.
  // (The fields in question are private, so this can't be at top level.)
  // (Putting it in the ctor hits the ill-defined non-trivial ctor rules.)
  static_assert(K_CONTEXT_SAVE_OFFSET == __builtin_offsetof(Context, _save),
                "K_CONTEXT_SAVE_OFFSET is wrong");

  // Right, actual implementation now:
  for (unsigned i = preserved; i < config::n_message_keys; ++i) {
    _keys[i].nullify();
  }
}

Descriptor Context::get_descriptor() const {
  return _save.sys.m.d0;
}

void Context::do_syscall() {
  switch (get_descriptor().get_sysnum()) {
    case 0:  // IPC
      do_ipc();
      break;

    case 1:  // Copy Key
      do_copy_key();
      break;

    default:
      do_bad_sys();
      break;
  }
}

void Context::do_ipc() {
  auto d = get_descriptor();

  // Perform first phase of IPC.
  if (d.get_send_enabled()) {
    key(d.get_target()).deliver_from(this);
  } else if (d.get_receive_enabled()) {
    key(d.get_source()).get()->deliver_to(this);
  } else {
    // Simply return with registers unchanged.
    // (Weirdo.)
  }

  do_deferred_switch();
}

void Context::do_copy_key() {
  auto d = get_descriptor();
  key(d.get_target()) = key(d.get_source());
}

void Context::do_bad_sys() {
  put_message(0, Message::failure(Exception::bad_syscall));
}

void Context::complete_receive(BlockingSender * sender) {
  complete_receive_core(sender->get_saved_brand(), sender);
}

void Context::complete_receive_core(Brand brand, Sender * sender) {
  put_message(brand, sender->get_message());

  for (unsigned i = 0; i < config::n_message_keys; ++i) {
    key(i) = sender->get_message_key(i);
  }

  sender->complete_send();
}

void Context::complete_receive(Exception e, uint32_t param) {
  put_message(0, Message::failure(e, param));
  nullify_exchanged_keys();
}

void Context::block_in_receive(List<Context> & list) {
  ETL_ASSERT(this == current);

  // TODO should we decide to permit non-blocking recieves... here's the spot.
  _ctx_item.unlink();
  list.insert(&_ctx_item);

  pend_switch();
}

void Context::complete_blocked_receive(Brand brand, Sender * sender) {
  _ctx_item.unlink();  // from the receiver list
  runnable.insert(&_ctx_item);
  complete_receive_core(brand, sender);

  pend_switch();
}

void Context::complete_blocked_receive(Exception e, uint32_t param) {
  _ctx_item.unlink();  // from the receiver list
  runnable.insert(&_ctx_item);
  complete_receive(e, param);

  pend_switch();
}

void Context::put_message(Brand brand, Message const & m) {
  _save.sys.m = m;
  _save.sys.m.d0 = _save.sys.m.d0.sanitized();
  _save.sys.b = brand;
}

void Context::apply_to_mpu() {
  using etl::armv7m::mpu;

  for (unsigned i = 0; i < config::n_task_regions; ++i) {
    mpu.write_rnr(i);
    auto object = _memory_regions[i].get();
    if (object->is_address_range()) {
      auto range = static_cast<AddressRange *>(object);
      auto region = range->get_region_for_brand(_memory_regions[i].get_brand());
      mpu.write_rbar(region.rbar);
      mpu.write_rasr(region.rasr);
    } else {
      mpu.write_rasr(0);
      mpu.write_rbar(0);
    }
  }
}

/*******************************************************************************
 * Implementation of Sender and BlockingSender
 */

Priority Context::get_priority() const {
  return _priority;
}

Message Context::get_message() {
  return _save.sys.m;
}

void Context::complete_send() {
  auto d = get_descriptor();

  if (d.get_receive_enabled()) {
    auto source = d.is_call() ? make_reply_key()
                              : key(d.get_source());
    source.get()->deliver_to(this);
  }
}

void Context::complete_send(Exception e, uint32_t param) {
  // We may have distributed a key to our reply gate earlier in the send phase.
  if (get_descriptor().is_call()) {
    // If so, revoke it, since the send has been cancelled.
    object_table.invalidate(_reply_gate_index);
  }
  // Deliver the exception.
  put_message(0, Message::failure(e, param));
  // Avoid looking like we delivered any pre-existing keys.
  nullify_exchanged_keys();
}

void Context::block_in_send(Brand brand, List<BlockingSender> & list) {
  ETL_ASSERT(this == current);

  if (get_descriptor().get_block()) {
    _saved_brand = brand;
    list.insert(&_sender_item);
    _ctx_item.unlink();

    pend_switch();
  } else {
    // Unprivileged code is unwilling to block for delivery.
    complete_send(Exception::would_block);
  }
}

Brand Context::get_saved_brand() const {
  return _saved_brand;
}

void Context::complete_blocked_send() {
  runnable.insert(&_ctx_item);
  complete_send();
  pend_switch();
}

void Context::complete_blocked_send(Exception e, uint32_t param) {
  runnable.insert(&_ctx_item);
  complete_send(e, param);
  pend_switch();
}

Key Context::get_message_key(unsigned index) {
  if (index == 0) {
    // Special handling of reply key
    auto d = get_descriptor();
    if (d.is_call()) {
      return make_reply_key();
    } else {
      return Key::null();
    }
  } else {
    // Other keys
    return key(index);
  }
}

Key Context::make_reply_key() const {
  auto maybe_key = object_table[_reply_gate_index].ptr->make_key(0);
  if (maybe_key) return maybe_key.ref();
  return Key::null();
}

/*******************************************************************************
 * Implementation of Object
 */

void Context::deliver_from(Brand brand, Sender * sender) {
  Message m = sender->get_message();
  switch (m.d0.get_selector()) {
    case 0:
      read_register(brand, sender, m);
      break;

    case 1:
      write_register(brand, sender, m);
      break;

    case 2:
      read_key(brand, sender, m);
      break;

    case 3:
      write_key(brand, sender, m);
      break;

    case 4:
      read_region(brand, sender, m);
      break;

    case 5:
      write_region(brand, sender, m);
      break;

    default:
      sender->complete_send(Exception::bad_operation, m.d0.get_selector());
      break;
  }
}

void Context::read_register(Brand,
                            Sender * sender,
                            Message const & arg) {
  ReplySender reply_sender{0};  // TODO priority
  switch (arg.d1) {
    case 13:
      reply_sender.set_message({
          Descriptor::zero(),
          reinterpret_cast<Word>(_stack),
          });
      break;

#define GP_EF(n) \
    case n: { \
      apply_to_mpu(); \
      auto r = uload(&_stack->r ## n); \
      current->apply_to_mpu(); \
      if (r.is_error()) { \
        reply_sender.set_message(Message::failure(Exception::fault)); \
      } else { \
        reply_sender.set_message({ \
            Descriptor::zero(), \
            r.ref(), \
          }); \
      } \
      break; \
    }
    GP_EF(0);
    GP_EF(1);
    GP_EF(2);
    GP_EF(3);
    GP_EF(12);
    GP_EF(14);
    GP_EF(15);
#undef GP_EF

    case 16: {
      apply_to_mpu();
      auto r = uload(&_stack->psr);
      current->apply_to_mpu();
      if (r.is_error()) {
        reply_sender.set_message(Message::failure(Exception::fault));
      } else {
        reply_sender.set_message({
            Descriptor::zero(),
            r.ref(),
          });
      }
      break;
    }

    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
    case 11:
      reply_sender.set_message({Descriptor::zero(), _save.raw[arg.d1 - 4]});
      break;

    default:
      reply_sender.set_message(Message::failure(Exception::index_out_of_range));
      break;
  }

  auto reply = sender->get_message_key(0);
  sender->complete_send();

  reply.deliver_from(&reply_sender);
}

void Context::write_register(Brand,
                             Sender * sender,
                             Message const & arg) {
  auto r = arg.d1;
  auto v = arg.d2;

  ReplySender reply_sender{0};  // TODO priority

  switch (r) {
    case 13:
      _stack = reinterpret_cast<decltype(_stack)>(v);
      break;

#define GP_EF(n) \
    case n: { \
      auto r = ustore(&_stack->r ## n, v); \
      if (r != SysResult::success) { \
        reply_sender.set_message(Message::failure(Exception::fault)); \
      } \
      break; \
    }
    GP_EF(0);
    GP_EF(1);
    GP_EF(2);
    GP_EF(3);
    GP_EF(12);
    GP_EF(14);
    GP_EF(15);
#undef GP

    case 16: {
      auto r = ustore(&_stack->psr, v);
      if (r != SysResult::success) {
        reply_sender.set_message(Message::failure(Exception::fault));
      }
      break;
    }

    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
    case 11:
      _save.raw[r - 4] = v;
      break;

    default:
      reply_sender.set_message(Message::failure(Exception::index_out_of_range));
      break;
  }

  auto reply = sender->get_message_key(0);
  sender->complete_send();

  reply.deliver_from(&reply_sender);
}

void Context::read_key(Brand,
                       Sender * sender,
                       Message const & arg) {
  auto r = arg.d1;
  auto reply = sender->get_message_key(0);
  sender->complete_send();

  ReplySender reply_sender{0};  // TODO priority
  if (r >= config::n_task_keys) {
    reply_sender.set_message(Message::failure(Exception::index_out_of_range));
  } else {
    reply_sender.set_key(1, key(r));
  }
  reply.deliver_from(&reply_sender);
}

void Context::write_key(Brand,
                        Sender * sender,
                        Message const & arg) {
  auto r = arg.d1;

  auto reply = sender->get_message_key(0);
  auto new_key = sender->get_message_key(1);
  sender->complete_send();

  ReplySender reply_sender{0};  // TODO priority
  if (r >= config::n_task_keys) {
    reply_sender.set_message(Message::failure(Exception::index_out_of_range));
  } else {
    key(r) = new_key;
  }
  reply.deliver_from(&reply_sender);
}

void Context::read_region(Brand,
                          Sender * sender,
                          Message const & arg) {
  auto n = arg.d1;
  auto reply = sender->get_message_key(0);
  sender->complete_send();

  ReplySender reply_sender{0};  // TODO priority
  if (n < config::n_task_regions) {
    reply_sender.set_key(1, _memory_regions[n]);
  } else {
    reply_sender.set_message(Message::failure(Exception::index_out_of_range));
  }
  reply.deliver_from(&reply_sender);
}

void Context::write_region(Brand,
                           Sender * sender,
                           Message const & arg) {
  auto n = arg.d1;
  auto reply = sender->get_message_key(0);
  auto object_key = sender->get_message_key(1);
  sender->complete_send();

  ReplySender reply_sender{0};  // TODO priority

  if (n < config::n_task_regions) {
    _memory_regions[n] = object_key;
  } else {
    reply_sender.set_message(Message::failure(Exception::index_out_of_range));
  }

  if (current == this) apply_to_mpu();

  reply.deliver_from(&reply_sender);
}

}  // namespace k
<commit_msg>k/context: initialize _priority (oops)<commit_after>#include "k/context.h"

#include "etl/armv7m/instructions.h"
#include "etl/armv7m/mpu.h"
#include "etl/armv7m/types.h"

#include "k/address_range.h"
#include "k/context_layout.h"
#include "k/ipc.h"
#include "k/object_table.h"
#include "k/registers.h"
#include "k/reply_sender.h"
#include "k/unprivileged.h"

using etl::armv7m::Word;

namespace k {

/*******************************************************************************
 * Global objects
 */

Context * current;
List<Context> runnable;
bool switch_pending;

static void do_deferred_switch() {
  if (!switch_pending) return;

  switch_pending = false;

  while (runnable.is_empty()) {
    etl::armv7m::wait_for_interrupt();
  }

  current = runnable.peek().ref()->owner;
}

static void pend_switch() {
  switch_pending = true;
}

/*******************************************************************************
 * Context-specific stuff
 */

Context::Context()
  : _stack{nullptr},
    _keys{},
    _ctx_item{this},
    _sender_item{this},
    _priority{0},
    _saved_brand{0} {}

void Context::nullify_exchanged_keys(unsigned preserved) {
  // Had to do this somewhere, this is as good a place as any.
  // (The fields in question are private, so this can't be at top level.)
  // (Putting it in the ctor hits the ill-defined non-trivial ctor rules.)
  static_assert(K_CONTEXT_SAVE_OFFSET == __builtin_offsetof(Context, _save),
                "K_CONTEXT_SAVE_OFFSET is wrong");

  // Right, actual implementation now:
  for (unsigned i = preserved; i < config::n_message_keys; ++i) {
    _keys[i].nullify();
  }
}

Descriptor Context::get_descriptor() const {
  return _save.sys.m.d0;
}

void Context::do_syscall() {
  switch (get_descriptor().get_sysnum()) {
    case 0:  // IPC
      do_ipc();
      break;

    case 1:  // Copy Key
      do_copy_key();
      break;

    default:
      do_bad_sys();
      break;
  }
}

void Context::do_ipc() {
  auto d = get_descriptor();

  // Perform first phase of IPC.
  if (d.get_send_enabled()) {
    key(d.get_target()).deliver_from(this);
  } else if (d.get_receive_enabled()) {
    key(d.get_source()).get()->deliver_to(this);
  } else {
    // Simply return with registers unchanged.
    // (Weirdo.)
  }

  do_deferred_switch();
}

void Context::do_copy_key() {
  auto d = get_descriptor();
  key(d.get_target()) = key(d.get_source());
}

void Context::do_bad_sys() {
  put_message(0, Message::failure(Exception::bad_syscall));
}

void Context::complete_receive(BlockingSender * sender) {
  complete_receive_core(sender->get_saved_brand(), sender);
}

void Context::complete_receive_core(Brand brand, Sender * sender) {
  put_message(brand, sender->get_message());

  for (unsigned i = 0; i < config::n_message_keys; ++i) {
    key(i) = sender->get_message_key(i);
  }

  sender->complete_send();
}

void Context::complete_receive(Exception e, uint32_t param) {
  put_message(0, Message::failure(e, param));
  nullify_exchanged_keys();
}

void Context::block_in_receive(List<Context> & list) {
  ETL_ASSERT(this == current);

  // TODO should we decide to permit non-blocking recieves... here's the spot.
  _ctx_item.unlink();
  list.insert(&_ctx_item);

  pend_switch();
}

void Context::complete_blocked_receive(Brand brand, Sender * sender) {
  _ctx_item.unlink();  // from the receiver list
  runnable.insert(&_ctx_item);
  complete_receive_core(brand, sender);

  pend_switch();
}

void Context::complete_blocked_receive(Exception e, uint32_t param) {
  _ctx_item.unlink();  // from the receiver list
  runnable.insert(&_ctx_item);
  complete_receive(e, param);

  pend_switch();
}

void Context::put_message(Brand brand, Message const & m) {
  _save.sys.m = m;
  _save.sys.m.d0 = _save.sys.m.d0.sanitized();
  _save.sys.b = brand;
}

void Context::apply_to_mpu() {
  using etl::armv7m::mpu;

  for (unsigned i = 0; i < config::n_task_regions; ++i) {
    mpu.write_rnr(i);
    auto object = _memory_regions[i].get();
    if (object->is_address_range()) {
      auto range = static_cast<AddressRange *>(object);
      auto region = range->get_region_for_brand(_memory_regions[i].get_brand());
      mpu.write_rbar(region.rbar);
      mpu.write_rasr(region.rasr);
    } else {
      mpu.write_rasr(0);
      mpu.write_rbar(0);
    }
  }
}

/*******************************************************************************
 * Implementation of Sender and BlockingSender
 */

Priority Context::get_priority() const {
  return _priority;
}

Message Context::get_message() {
  return _save.sys.m;
}

void Context::complete_send() {
  auto d = get_descriptor();

  if (d.get_receive_enabled()) {
    auto source = d.is_call() ? make_reply_key()
                              : key(d.get_source());
    source.get()->deliver_to(this);
  }
}

void Context::complete_send(Exception e, uint32_t param) {
  // We may have distributed a key to our reply gate earlier in the send phase.
  if (get_descriptor().is_call()) {
    // If so, revoke it, since the send has been cancelled.
    object_table.invalidate(_reply_gate_index);
  }
  // Deliver the exception.
  put_message(0, Message::failure(e, param));
  // Avoid looking like we delivered any pre-existing keys.
  nullify_exchanged_keys();
}

void Context::block_in_send(Brand brand, List<BlockingSender> & list) {
  ETL_ASSERT(this == current);

  if (get_descriptor().get_block()) {
    _saved_brand = brand;
    list.insert(&_sender_item);
    _ctx_item.unlink();

    pend_switch();
  } else {
    // Unprivileged code is unwilling to block for delivery.
    complete_send(Exception::would_block);
  }
}

Brand Context::get_saved_brand() const {
  return _saved_brand;
}

void Context::complete_blocked_send() {
  runnable.insert(&_ctx_item);
  complete_send();
  pend_switch();
}

void Context::complete_blocked_send(Exception e, uint32_t param) {
  runnable.insert(&_ctx_item);
  complete_send(e, param);
  pend_switch();
}

Key Context::get_message_key(unsigned index) {
  if (index == 0) {
    // Special handling of reply key
    auto d = get_descriptor();
    if (d.is_call()) {
      return make_reply_key();
    } else {
      return Key::null();
    }
  } else {
    // Other keys
    return key(index);
  }
}

Key Context::make_reply_key() const {
  auto maybe_key = object_table[_reply_gate_index].ptr->make_key(0);
  if (maybe_key) return maybe_key.ref();
  return Key::null();
}

/*******************************************************************************
 * Implementation of Object
 */

void Context::deliver_from(Brand brand, Sender * sender) {
  Message m = sender->get_message();
  switch (m.d0.get_selector()) {
    case 0:
      read_register(brand, sender, m);
      break;

    case 1:
      write_register(brand, sender, m);
      break;

    case 2:
      read_key(brand, sender, m);
      break;

    case 3:
      write_key(brand, sender, m);
      break;

    case 4:
      read_region(brand, sender, m);
      break;

    case 5:
      write_region(brand, sender, m);
      break;

    default:
      sender->complete_send(Exception::bad_operation, m.d0.get_selector());
      break;
  }
}

void Context::read_register(Brand,
                            Sender * sender,
                            Message const & arg) {
  ReplySender reply_sender{0};  // TODO priority
  switch (arg.d1) {
    case 13:
      reply_sender.set_message({
          Descriptor::zero(),
          reinterpret_cast<Word>(_stack),
          });
      break;

#define GP_EF(n) \
    case n: { \
      apply_to_mpu(); \
      auto r = uload(&_stack->r ## n); \
      current->apply_to_mpu(); \
      if (r.is_error()) { \
        reply_sender.set_message(Message::failure(Exception::fault)); \
      } else { \
        reply_sender.set_message({ \
            Descriptor::zero(), \
            r.ref(), \
          }); \
      } \
      break; \
    }
    GP_EF(0);
    GP_EF(1);
    GP_EF(2);
    GP_EF(3);
    GP_EF(12);
    GP_EF(14);
    GP_EF(15);
#undef GP_EF

    case 16: {
      apply_to_mpu();
      auto r = uload(&_stack->psr);
      current->apply_to_mpu();
      if (r.is_error()) {
        reply_sender.set_message(Message::failure(Exception::fault));
      } else {
        reply_sender.set_message({
            Descriptor::zero(),
            r.ref(),
          });
      }
      break;
    }

    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
    case 11:
      reply_sender.set_message({Descriptor::zero(), _save.raw[arg.d1 - 4]});
      break;

    default:
      reply_sender.set_message(Message::failure(Exception::index_out_of_range));
      break;
  }

  auto reply = sender->get_message_key(0);
  sender->complete_send();

  reply.deliver_from(&reply_sender);
}

void Context::write_register(Brand,
                             Sender * sender,
                             Message const & arg) {
  auto r = arg.d1;
  auto v = arg.d2;

  ReplySender reply_sender{0};  // TODO priority

  switch (r) {
    case 13:
      _stack = reinterpret_cast<decltype(_stack)>(v);
      break;

#define GP_EF(n) \
    case n: { \
      auto r = ustore(&_stack->r ## n, v); \
      if (r != SysResult::success) { \
        reply_sender.set_message(Message::failure(Exception::fault)); \
      } \
      break; \
    }
    GP_EF(0);
    GP_EF(1);
    GP_EF(2);
    GP_EF(3);
    GP_EF(12);
    GP_EF(14);
    GP_EF(15);
#undef GP

    case 16: {
      auto r = ustore(&_stack->psr, v);
      if (r != SysResult::success) {
        reply_sender.set_message(Message::failure(Exception::fault));
      }
      break;
    }

    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
    case 11:
      _save.raw[r - 4] = v;
      break;

    default:
      reply_sender.set_message(Message::failure(Exception::index_out_of_range));
      break;
  }

  auto reply = sender->get_message_key(0);
  sender->complete_send();

  reply.deliver_from(&reply_sender);
}

void Context::read_key(Brand,
                       Sender * sender,
                       Message const & arg) {
  auto r = arg.d1;
  auto reply = sender->get_message_key(0);
  sender->complete_send();

  ReplySender reply_sender{0};  // TODO priority
  if (r >= config::n_task_keys) {
    reply_sender.set_message(Message::failure(Exception::index_out_of_range));
  } else {
    reply_sender.set_key(1, key(r));
  }
  reply.deliver_from(&reply_sender);
}

void Context::write_key(Brand,
                        Sender * sender,
                        Message const & arg) {
  auto r = arg.d1;

  auto reply = sender->get_message_key(0);
  auto new_key = sender->get_message_key(1);
  sender->complete_send();

  ReplySender reply_sender{0};  // TODO priority
  if (r >= config::n_task_keys) {
    reply_sender.set_message(Message::failure(Exception::index_out_of_range));
  } else {
    key(r) = new_key;
  }
  reply.deliver_from(&reply_sender);
}

void Context::read_region(Brand,
                          Sender * sender,
                          Message const & arg) {
  auto n = arg.d1;
  auto reply = sender->get_message_key(0);
  sender->complete_send();

  ReplySender reply_sender{0};  // TODO priority
  if (n < config::n_task_regions) {
    reply_sender.set_key(1, _memory_regions[n]);
  } else {
    reply_sender.set_message(Message::failure(Exception::index_out_of_range));
  }
  reply.deliver_from(&reply_sender);
}

void Context::write_region(Brand,
                           Sender * sender,
                           Message const & arg) {
  auto n = arg.d1;
  auto reply = sender->get_message_key(0);
  auto object_key = sender->get_message_key(1);
  sender->complete_send();

  ReplySender reply_sender{0};  // TODO priority

  if (n < config::n_task_regions) {
    _memory_regions[n] = object_key;
  } else {
    reply_sender.set_message(Message::failure(Exception::index_out_of_range));
  }

  if (current == this) apply_to_mpu();

  reply.deliver_from(&reply_sender);
}

}  // namespace k
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDataArray.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "vtkDataArray.h"
#include "vtkBitArray.h"
#include "vtkCharArray.h"
#include "vtkUnsignedCharArray.h"
#include "vtkShortArray.h"
#include "vtkUnsignedShortArray.h"
#include "vtkIntArray.h"
#include "vtkUnsignedIntArray.h"
#include "vtkLongArray.h"
#include "vtkUnsignedLongArray.h"
#include "vtkFloatArray.h"
#include "vtkDoubleArray.h"
#include "vtkIdTypeArray.h"
#include "vtkLookupTable.h"
#include "vtkCriticalSection.h"
#include "vtkIdList.h"

unsigned long vtkDataArray::ArrayNamePostfix = 0;

static vtkSimpleCriticalSection DataArrayCritSec;

// Construct object with default tuple dimension (number of components) of 1.
vtkDataArray::vtkDataArray(vtkIdType numComp)
{
  this->Size = 0;
  this->MaxId = -1;
  this->LookupTable = NULL;

  this->NumberOfComponents = (numComp < 1 ? 1 : numComp);
  this->Name = 0;
  DataArrayCritSec.Lock();
  ostrstream buf;
  buf << "Array_";
  buf << vtkDataArray::ArrayNamePostfix << ends;
  vtkDataArray::ArrayNamePostfix++;
  this->SetName(buf.str());
  delete[] buf.str();
  DataArrayCritSec.Unlock();
}

vtkDataArray::~vtkDataArray()
{
  if ( this->LookupTable )
    {
    this->LookupTable->Delete();
    }
  delete[] this->Name;
}

void vtkDataArray::SetName(const char* name)
{
  if (!name)
    {
    vtkWarningMacro("Array name can not be NULL.");
    return;
    }
  delete[] this->Name;
  this->Name = 0;
  int size = strlen(name);
  this->Name = new char[size+1];
  strcpy(this->Name, name);
}

const char* vtkDataArray::GetName()
{
  return this->Name;
}

void vtkDataArray::DeepCopy(vtkDataArray *da)
{
  if ( this != da )
    {
    int numTuples = da->GetNumberOfTuples();
    this->NumberOfComponents = da->NumberOfComponents;
    this->SetNumberOfTuples(numTuples);

    for (int i=0; i < numTuples; i++)
      {
      this->SetTuple(i, da->GetTuple(i));
      }
    }
}

// These can be overridden for more efficiency
float vtkDataArray::GetComponent(const vtkIdType i, const int j)
{
  float *tuple=new float[this->NumberOfComponents], c;

  this->GetTuple(i,tuple);
  c =  tuple[j];
  delete [] tuple;

  return c;
}

void vtkDataArray::SetComponent(const vtkIdType i, const int j, const float c)
{
  float *tuple=new float[this->NumberOfComponents];

  if ( i < this->GetNumberOfTuples() )
    {
    this->GetTuple(i,tuple);
    }
  else
    {
    for (int k=0; k<this->NumberOfComponents; k++)
      {
      tuple[k] = 0.0;
      }
    }

  tuple[j] = c;
  this->SetTuple(i,tuple);

  delete [] tuple;
}

void vtkDataArray::InsertComponent(const vtkIdType i, const int j,
                                   const float c)
{
  float *tuple=new float[this->NumberOfComponents];

  if ( i < this->GetNumberOfTuples() )
    {
    this->GetTuple(i,tuple);
    }
  else
    {
    for (int k=0; k<this->NumberOfComponents; k++)
      {
      tuple[k] = 0.0;
      }
    }

  tuple[j] = c;
  this->InsertTuple(i,tuple);

  delete [] tuple;
}

void vtkDataArray::GetData(vtkIdType tupleMin, vtkIdType tupleMax, int compMin,
			   int compMax, vtkFloatArray* data)
{
  int i, j;
  int numComp=this->GetNumberOfComponents();
  float *tuple=new float[numComp];
  float *ptr=data->WritePointer(0,(tupleMax-tupleMin+1)*(compMax-compMin+1));

  for (j=tupleMin; j <= tupleMax; j++)
    {
    this->GetTuple(j,tuple);
    for (i=compMin; i <= compMax; i++)
      {
      *ptr++ = tuple[i];
      }
    }
  delete [] tuple;
}

void vtkDataArray::CreateDefaultLookupTable()
{
  if ( this->LookupTable )
    {
    this->LookupTable->UnRegister(this);
    }
  this->LookupTable = vtkLookupTable::New();
  // make sure it is built
  // otherwise problems with InsertScalar trying to map through
  // non built lut
  this->LookupTable->Build();
  this->LookupTable->Register(this);
}

void vtkDataArray::SetLookupTable(vtkLookupTable* lut)
{
  if ( this->LookupTable != lut )
    {
    if ( this->LookupTable )
      {
      this->LookupTable->UnRegister(this);
      }
    this->LookupTable = lut;
    this->LookupTable->Register(this);
    this->Modified();
    }
}

// default double behaviour
void vtkDataArray::GetTuple(const vtkIdType i, double * tuple)
{
  int c;
  int numComp=this->GetNumberOfComponents();
  float *ftuple=new float[numComp];
  this->GetTuple(i,ftuple);
  for (c = 0; c < numComp;  c++)
    {
    tuple[c] = ftuple[c];
    }
  delete [] ftuple;
}

void vtkDataArray::SetTuple(const vtkIdType i, const double * tuple)
{
  int c;
  int numComp=this->GetNumberOfComponents();
  float *ftuple=new float[numComp];
  for (c = 0; c < numComp;  c++)
    {
    ftuple[c] = (float)(tuple[c]);
    }
  this->SetTuple(i,ftuple);
  delete [] ftuple;
}

void vtkDataArray::InsertTuple(const vtkIdType i, const double * tuple)
{
  int c;
  int numComp=this->GetNumberOfComponents();
  float *ftuple=new float[numComp];
  for (c = 0; c < numComp;  c++)
    {
    ftuple[c] = (float)(tuple[c]);
    }
  this->InsertTuple(i,ftuple);
  delete [] ftuple;
}

vtkIdType vtkDataArray::InsertNextTuple(const double * tuple)
{
  int c;
  int numComp=this->GetNumberOfComponents();
  float *ftuple=new float[numComp];
  for (c = 0; c < numComp;  c++)
    {
    ftuple[c] = (float)(tuple[c]);
    }
  int ret = this->InsertNextTuple(ftuple);
  delete [] ftuple;
  return ret;
}

unsigned long vtkDataArray::GetActualMemorySize()
{
  unsigned long numPrims;
  float size = 0.0;
  numPrims = this->GetNumberOfTuples() * this->GetNumberOfComponents();

  switch (this->GetDataType())
    {
    case VTK_BIT:
      size = (float)sizeof(char)/8.0;
      break;

    case VTK_CHAR:
      size = (float)sizeof(char);
      break;

    case VTK_UNSIGNED_CHAR:
      size = (float)sizeof(unsigned char);
      break;

    case VTK_SHORT:
      size = (float)sizeof(short);
      break;

    case VTK_UNSIGNED_SHORT:
      size = (float)sizeof(unsigned short);
      break;

    case VTK_INT:
      size = (float)sizeof(int);
      break;

    case VTK_UNSIGNED_INT:
      size = (float)sizeof(unsigned int);
      break;

    case VTK_LONG:
      size = (float)sizeof(long);
      break;

    case VTK_UNSIGNED_LONG:
      size = (float)sizeof(unsigned long);
      break;

    case VTK_FLOAT:
      size = (float)sizeof(float);
      break;

    case VTK_DOUBLE:
      size = (float)sizeof(double);
      break;

    case VTK_ID_TYPE:
      size = (float)sizeof(vtkIdType);
      break;

    default:
      vtkErrorMacro(<<"Unsupported data type!");
    }

  return (unsigned long)ceil((size * numPrims)/1000.0); //kilobytes
}

vtkDataArray* vtkDataArray::CreateDataArray(int dataType)
{
  switch (dataType)
    {
    case VTK_BIT:
      return vtkBitArray::New();

    case VTK_CHAR:
      return vtkCharArray::New();

    case VTK_UNSIGNED_CHAR:
      return vtkUnsignedCharArray::New();

    case VTK_SHORT:
      return vtkShortArray::New();

    case VTK_UNSIGNED_SHORT:
      return vtkUnsignedShortArray::New();

    case VTK_INT:
      return vtkIntArray::New();

    case VTK_UNSIGNED_INT:
      return vtkUnsignedIntArray::New();

    case VTK_LONG:
      return vtkLongArray::New();

    case VTK_UNSIGNED_LONG:
      return vtkUnsignedLongArray::New();

    case VTK_FLOAT:
      return vtkFloatArray::New();

    case VTK_DOUBLE:
      return vtkDoubleArray::New();

    case VTK_ID_TYPE:
      return vtkIdTypeArray::New();

    default:
      vtkGenericWarningMacro(<<"Unsupported data type! Setting to VTK_FLOAT");
      return vtkFloatArray::New();
    }
}

template <class IT, class OT>
static void CopyTuples(IT* input, OT* output, int nComp, vtkIdList* ptIds )
{
  int i, j;
  int num=ptIds->GetNumberOfIds();
  for (i=0; i<num; i++)
    {
    for (j=0; j<nComp; j++)
      {
      output[i*nComp+j] = static_cast<OT>(input[ptIds->GetId(i)*nComp+j]);
      }
    }
}

template <class IT>
static void CopyTuples1(IT* input, vtkDataArray* output, vtkIdList* ptIds)
{
  switch (output->GetDataType())
    {
    vtkTemplateMacro4(CopyTuples, input, (VTK_TT *)output->GetVoidPointer(0),
		      output->GetNumberOfComponents(), ptIds );

    default:
      vtkGenericWarningMacro(<<"Sanity check failed: Unsupported data type.");
      return;
    }
}

void vtkDataArray::GetTuples(vtkIdList *ptIds, vtkDataArray *da)
{

  if ((da->GetNumberOfComponents() != this->GetNumberOfComponents()))
    {
    vtkWarningMacro("Number of components for input and output do not match");
    return;
    }

  switch (this->GetDataType())
    {
    vtkTemplateMacro3(CopyTuples1, (VTK_TT *)this->GetVoidPointer(0), da,
		      ptIds );

    default:
      vtkErrorMacro(<<"Sanity check failed: Unsupported data type.");
      return;
    }
}

void vtkDataArray::FillComponent(const int j, const float c)
{
  if (j < 0 || j >= this->GetNumberOfComponents())
    {
    vtkErrorMacro(<< "Specified component " << j << " is not in [0, "
    << this->GetNumberOfComponents() << ")" );
    return;
    }

  vtkIdType i;

  for (i = 0; i < this->GetNumberOfTuples(); i++)
    {
    this->SetComponent(i, j, c);
    }
}

void vtkDataArray::CopyComponent(const int j, vtkDataArray *from,
                                 const int fromComponent)
{
  if (this->GetNumberOfTuples() != from->GetNumberOfTuples())
    {
    vtkErrorMacro(<< "Number of tuples in 'from' ("
    << from->GetNumberOfTuples() << ") and 'to' ("
    << this->GetNumberOfTuples() << ") do not match.");
    return;
    }

  if (j < 0 || j >= this->GetNumberOfComponents())
    {
    vtkErrorMacro(<< "Specified component " << j << " in 'to' array is not in [0, "
    << this->GetNumberOfComponents() << ")" );
    return;
    }

  if (fromComponent < 0 || fromComponent >= from->GetNumberOfComponents())
    {
    vtkErrorMacro(<< "Specified component " << fromComponent << " in 'from' array is not in [0, "
    << from->GetNumberOfComponents() << ")" );
    return;
    }

  vtkIdType i;
  for (i = 0; i < this->GetNumberOfTuples(); i++)
    {
    this->SetComponent(i, j, from->GetComponent(i, fromComponent));
    }
}

void vtkDataArray::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkObject::PrintSelf(os,indent);

  os << indent << "Name: " << this->Name << "\n";
  os << indent << "Number Of Components: " << this->NumberOfComponents << "\n";
  os << indent << "Number Of Tuples: " << this->GetNumberOfTuples() << "\n";
  os << indent << "Size: " << this->Size << "\n";
  os << indent << "MaxId: " << this->MaxId << "\n";
  if ( this->LookupTable )
    {
    os << indent << "Lookup Table:\n";
    this->LookupTable->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "LookupTable: (none)\n";
    }
}
<commit_msg>Support for bit arrays if GetTuples()<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDataArray.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "vtkDataArray.h"
#include "vtkBitArray.h"
#include "vtkCharArray.h"
#include "vtkUnsignedCharArray.h"
#include "vtkShortArray.h"
#include "vtkUnsignedShortArray.h"
#include "vtkIntArray.h"
#include "vtkUnsignedIntArray.h"
#include "vtkLongArray.h"
#include "vtkUnsignedLongArray.h"
#include "vtkFloatArray.h"
#include "vtkDoubleArray.h"
#include "vtkIdTypeArray.h"
#include "vtkLookupTable.h"
#include "vtkCriticalSection.h"
#include "vtkIdList.h"

unsigned long vtkDataArray::ArrayNamePostfix = 0;

static vtkSimpleCriticalSection DataArrayCritSec;

// Construct object with default tuple dimension (number of components) of 1.
vtkDataArray::vtkDataArray(vtkIdType numComp)
{
  this->Size = 0;
  this->MaxId = -1;
  this->LookupTable = NULL;

  this->NumberOfComponents = (numComp < 1 ? 1 : numComp);
  this->Name = 0;
  DataArrayCritSec.Lock();
  ostrstream buf;
  buf << "Array_";
  buf << vtkDataArray::ArrayNamePostfix << ends;
  vtkDataArray::ArrayNamePostfix++;
  this->SetName(buf.str());
  delete[] buf.str();
  DataArrayCritSec.Unlock();
}

vtkDataArray::~vtkDataArray()
{
  if ( this->LookupTable )
    {
    this->LookupTable->Delete();
    }
  delete[] this->Name;
}

void vtkDataArray::SetName(const char* name)
{
  if (!name)
    {
    vtkWarningMacro("Array name can not be NULL.");
    return;
    }
  delete[] this->Name;
  this->Name = 0;
  int size = strlen(name);
  this->Name = new char[size+1];
  strcpy(this->Name, name);
}

const char* vtkDataArray::GetName()
{
  return this->Name;
}

void vtkDataArray::DeepCopy(vtkDataArray *da)
{
  if ( this != da )
    {
    int numTuples = da->GetNumberOfTuples();
    this->NumberOfComponents = da->NumberOfComponents;
    this->SetNumberOfTuples(numTuples);

    for (int i=0; i < numTuples; i++)
      {
      this->SetTuple(i, da->GetTuple(i));
      }
    }
}

// These can be overridden for more efficiency
float vtkDataArray::GetComponent(const vtkIdType i, const int j)
{
  float *tuple=new float[this->NumberOfComponents], c;

  this->GetTuple(i,tuple);
  c =  tuple[j];
  delete [] tuple;

  return c;
}

void vtkDataArray::SetComponent(const vtkIdType i, const int j, const float c)
{
  float *tuple=new float[this->NumberOfComponents];

  if ( i < this->GetNumberOfTuples() )
    {
    this->GetTuple(i,tuple);
    }
  else
    {
    for (int k=0; k<this->NumberOfComponents; k++)
      {
      tuple[k] = 0.0;
      }
    }

  tuple[j] = c;
  this->SetTuple(i,tuple);

  delete [] tuple;
}

void vtkDataArray::InsertComponent(const vtkIdType i, const int j,
                                   const float c)
{
  float *tuple=new float[this->NumberOfComponents];

  if ( i < this->GetNumberOfTuples() )
    {
    this->GetTuple(i,tuple);
    }
  else
    {
    for (int k=0; k<this->NumberOfComponents; k++)
      {
      tuple[k] = 0.0;
      }
    }

  tuple[j] = c;
  this->InsertTuple(i,tuple);

  delete [] tuple;
}

void vtkDataArray::GetData(vtkIdType tupleMin, vtkIdType tupleMax, int compMin,
			   int compMax, vtkFloatArray* data)
{
  int i, j;
  int numComp=this->GetNumberOfComponents();
  float *tuple=new float[numComp];
  float *ptr=data->WritePointer(0,(tupleMax-tupleMin+1)*(compMax-compMin+1));

  for (j=tupleMin; j <= tupleMax; j++)
    {
    this->GetTuple(j,tuple);
    for (i=compMin; i <= compMax; i++)
      {
      *ptr++ = tuple[i];
      }
    }
  delete [] tuple;
}

void vtkDataArray::CreateDefaultLookupTable()
{
  if ( this->LookupTable )
    {
    this->LookupTable->UnRegister(this);
    }
  this->LookupTable = vtkLookupTable::New();
  // make sure it is built
  // otherwise problems with InsertScalar trying to map through
  // non built lut
  this->LookupTable->Build();
  this->LookupTable->Register(this);
}

void vtkDataArray::SetLookupTable(vtkLookupTable* lut)
{
  if ( this->LookupTable != lut )
    {
    if ( this->LookupTable )
      {
      this->LookupTable->UnRegister(this);
      }
    this->LookupTable = lut;
    this->LookupTable->Register(this);
    this->Modified();
    }
}

// default double behaviour
void vtkDataArray::GetTuple(const vtkIdType i, double * tuple)
{
  int c;
  int numComp=this->GetNumberOfComponents();
  float *ftuple=new float[numComp];
  this->GetTuple(i,ftuple);
  for (c = 0; c < numComp;  c++)
    {
    tuple[c] = ftuple[c];
    }
  delete [] ftuple;
}

void vtkDataArray::SetTuple(const vtkIdType i, const double * tuple)
{
  int c;
  int numComp=this->GetNumberOfComponents();
  float *ftuple=new float[numComp];
  for (c = 0; c < numComp;  c++)
    {
    ftuple[c] = (float)(tuple[c]);
    }
  this->SetTuple(i,ftuple);
  delete [] ftuple;
}

void vtkDataArray::InsertTuple(const vtkIdType i, const double * tuple)
{
  int c;
  int numComp=this->GetNumberOfComponents();
  float *ftuple=new float[numComp];
  for (c = 0; c < numComp;  c++)
    {
    ftuple[c] = (float)(tuple[c]);
    }
  this->InsertTuple(i,ftuple);
  delete [] ftuple;
}

vtkIdType vtkDataArray::InsertNextTuple(const double * tuple)
{
  int c;
  int numComp=this->GetNumberOfComponents();
  float *ftuple=new float[numComp];
  for (c = 0; c < numComp;  c++)
    {
    ftuple[c] = (float)(tuple[c]);
    }
  int ret = this->InsertNextTuple(ftuple);
  delete [] ftuple;
  return ret;
}

unsigned long vtkDataArray::GetActualMemorySize()
{
  unsigned long numPrims;
  float size = 0.0;
  numPrims = this->GetNumberOfTuples() * this->GetNumberOfComponents();

  switch (this->GetDataType())
    {
    case VTK_BIT:
      size = (float)sizeof(char)/8.0;
      break;

    case VTK_CHAR:
      size = (float)sizeof(char);
      break;

    case VTK_UNSIGNED_CHAR:
      size = (float)sizeof(unsigned char);
      break;

    case VTK_SHORT:
      size = (float)sizeof(short);
      break;

    case VTK_UNSIGNED_SHORT:
      size = (float)sizeof(unsigned short);
      break;

    case VTK_INT:
      size = (float)sizeof(int);
      break;

    case VTK_UNSIGNED_INT:
      size = (float)sizeof(unsigned int);
      break;

    case VTK_LONG:
      size = (float)sizeof(long);
      break;

    case VTK_UNSIGNED_LONG:
      size = (float)sizeof(unsigned long);
      break;

    case VTK_FLOAT:
      size = (float)sizeof(float);
      break;

    case VTK_DOUBLE:
      size = (float)sizeof(double);
      break;

    case VTK_ID_TYPE:
      size = (float)sizeof(vtkIdType);
      break;

    default:
      vtkErrorMacro(<<"Unsupported data type!");
    }

  return (unsigned long)ceil((size * numPrims)/1000.0); //kilobytes
}

vtkDataArray* vtkDataArray::CreateDataArray(int dataType)
{
  switch (dataType)
    {
    case VTK_BIT:
      return vtkBitArray::New();

    case VTK_CHAR:
      return vtkCharArray::New();

    case VTK_UNSIGNED_CHAR:
      return vtkUnsignedCharArray::New();

    case VTK_SHORT:
      return vtkShortArray::New();

    case VTK_UNSIGNED_SHORT:
      return vtkUnsignedShortArray::New();

    case VTK_INT:
      return vtkIntArray::New();

    case VTK_UNSIGNED_INT:
      return vtkUnsignedIntArray::New();

    case VTK_LONG:
      return vtkLongArray::New();

    case VTK_UNSIGNED_LONG:
      return vtkUnsignedLongArray::New();

    case VTK_FLOAT:
      return vtkFloatArray::New();

    case VTK_DOUBLE:
      return vtkDoubleArray::New();

    case VTK_ID_TYPE:
      return vtkIdTypeArray::New();

    default:
      vtkGenericWarningMacro(<<"Unsupported data type! Setting to VTK_FLOAT");
      return vtkFloatArray::New();
    }
}

template <class IT, class OT>
static void CopyTuples(IT* input, OT* output, int nComp, vtkIdList* ptIds )
{
  int i, j;
  int num=ptIds->GetNumberOfIds();
  for (i=0; i<num; i++)
    {
    for (j=0; j<nComp; j++)
      {
      output[i*nComp+j] = static_cast<OT>(input[ptIds->GetId(i)*nComp+j]);
      }
    }
}

template <class IT>
static void CopyTuples1(IT* input, vtkDataArray* output, vtkIdList* ptIds)
{
  switch (output->GetDataType())
    {
    vtkTemplateMacro4(CopyTuples, input, (VTK_TT *)output->GetVoidPointer(0),
		      output->GetNumberOfComponents(), ptIds );

    default:
      vtkGenericWarningMacro(<<"Sanity check failed: Unsupported data type.");
      return;
    }
}

void vtkDataArray::GetTuples(vtkIdList *ptIds, vtkDataArray *da)
{

  if ((da->GetNumberOfComponents() != this->GetNumberOfComponents()))
    {
    vtkWarningMacro("Number of components for input and output do not match");
    return;
    }

  switch (this->GetDataType())
    {
    vtkTemplateMacro3(CopyTuples1, (VTK_TT *)this->GetVoidPointer(0), da,
		      ptIds );
    // This is not supported by the template macro.
    // Switch to using the float interface.
    case VTK_BIT:
      {
      vtkIdType num=ptIds->GetNumberOfIds();
      for (vtkIdType i=0; i<num; i++)
        {
        da->SetTuple(i,this->GetTuple(ptIds->GetId(i)));
        }
      }
      break;
    default:
      vtkErrorMacro(<<"Sanity check failed: Unsupported data type.");
      return;
    }
}

void vtkDataArray::FillComponent(const int j, const float c)
{
  if (j < 0 || j >= this->GetNumberOfComponents())
    {
    vtkErrorMacro(<< "Specified component " << j << " is not in [0, "
    << this->GetNumberOfComponents() << ")" );
    return;
    }

  vtkIdType i;

  for (i = 0; i < this->GetNumberOfTuples(); i++)
    {
    this->SetComponent(i, j, c);
    }
}

void vtkDataArray::CopyComponent(const int j, vtkDataArray *from,
                                 const int fromComponent)
{
  if (this->GetNumberOfTuples() != from->GetNumberOfTuples())
    {
    vtkErrorMacro(<< "Number of tuples in 'from' ("
    << from->GetNumberOfTuples() << ") and 'to' ("
    << this->GetNumberOfTuples() << ") do not match.");
    return;
    }

  if (j < 0 || j >= this->GetNumberOfComponents())
    {
    vtkErrorMacro(<< "Specified component " << j << " in 'to' array is not in [0, "
    << this->GetNumberOfComponents() << ")" );
    return;
    }

  if (fromComponent < 0 || fromComponent >= from->GetNumberOfComponents())
    {
    vtkErrorMacro(<< "Specified component " << fromComponent << " in 'from' array is not in [0, "
    << from->GetNumberOfComponents() << ")" );
    return;
    }

  vtkIdType i;
  for (i = 0; i < this->GetNumberOfTuples(); i++)
    {
    this->SetComponent(i, j, from->GetComponent(i, fromComponent));
    }
}

void vtkDataArray::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkObject::PrintSelf(os,indent);

  os << indent << "Name: " << this->Name << "\n";
  os << indent << "Number Of Components: " << this->NumberOfComponents << "\n";
  os << indent << "Number Of Tuples: " << this->GetNumberOfTuples() << "\n";
  os << indent << "Size: " << this->Size << "\n";
  os << indent << "MaxId: " << this->MaxId << "\n";
  if ( this->LookupTable )
    {
    os << indent << "Lookup Table:\n";
    this->LookupTable->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "LookupTable: (none)\n";
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS.  All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
//
// This sample application demonstrates how to use the matroska parser
// library, which allows clients to handle a matroska format file.

#include "mkvreader.hpp"
#include "mkvparser.hpp"

static const wchar_t* utf8towcs(const char* str)
{
    if (str == NULL)
        return NULL;

    //TODO: this probably requires that the locale be
    //configured somehow:

    const size_t size = mbstowcs(NULL, str, 0);

    if (size == 0)
        return NULL;

    wchar_t* const val = new wchar_t[size+1];

    mbstowcs(val, str, size);
    val[size] = L'\0';

    return val;
}

int main(int argc, char* argv[])
{
    if (argc == 1)
    {
        printf("\t\t\tMkv Parser Sample Application\n");
        printf("\t\t\tUsage: \n");
        printf("\t\t\t  ./sample [input file] \n");
        printf("\t\t\t  ./sample sample.mkv \n");
        return -1;
    }

    using namespace mkvparser;

    MkvReader reader;

    if (reader.Open(argv[1]))
    {
        printf("\n Filename is invalid or error while opening.\n");
        return -1;
    }

    int maj, min, build, rev;

    GetVersion(maj, min, build, rev);
    printf("\t\t libmkv verison: %d.%d.%d.%d\n", maj, min, build, rev);

    long long pos = 0;

    EBMLHeader ebmlHeader;

    ebmlHeader.Parse(&reader, pos);

    printf("\t\t\t    EBML Header\n");
    printf("\t\tEBML Version\t\t: %lld\n", ebmlHeader.m_version);
    printf("\t\tEBML MaxIDLength\t: %lld\n", ebmlHeader.m_maxIdLength);
    printf("\t\tEBML MaxSizeLength\t: %lld\n", ebmlHeader.m_maxSizeLength);
    printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);
    printf("\t\tPos\t\t\t: %lld\n", pos);

    mkvparser::Segment* pSegment;

    long long ret = mkvparser::Segment::CreateInstance(&reader, pos, pSegment);
    if (ret)
    {
        printf("\n Segment::CreateInstance() failed.");
        return -1;
    }

    ret  = pSegment->Load();
    if (ret < 0)
    {
        printf("\n Segment::Load() failed.");
        return -1;
    }

    const SegmentInfo* const pSegmentInfo = pSegment->GetInfo();

    const long long timeCodeScale = pSegmentInfo->GetTimeCodeScale();
    const long long duration_ns = pSegmentInfo->GetDuration();

    const char* const pTitle_ = pSegmentInfo->GetTitleAsUTF8();
    const wchar_t* const pTitle = utf8towcs(pTitle_);

    const char* const pMuxingApp_ = pSegmentInfo->GetMuxingAppAsUTF8();
    const wchar_t* const pMuxingApp = utf8towcs(pMuxingApp_);

    const char* const pWritingApp_ = pSegmentInfo->GetWritingAppAsUTF8();
    const wchar_t* const pWritingApp = utf8towcs(pWritingApp_);

    printf("\n");
    printf("\t\t\t   Segment Info\n");
    printf("\t\tTimeCodeScale\t\t: %lld \n", timeCodeScale);
    printf("\t\tDuration\t\t: %lld\n", duration_ns);

    const double duration_sec = double(duration_ns) / 1000000000;
    printf("\t\tDuration(secs)\t\t: %7.3f\n", duration_sec);

    if (pTitle == NULL)
        printf("\t\tTrack Name\t\t: NULL\n");
    else
        printf("\t\tTrack Name\t\t: %ls\n", pTitle);

    if (pMuxingApp == NULL)
        printf("\t\tMuxing App\t\t: NULL\n");
    else
        printf("\t\tMuxing App\t\t: %ls\n", pMuxingApp);

    if (pWritingApp == NULL)
        printf("\t\tWriting App\t\t: NULL\n");
    else
        printf("\t\tWriting App\t\t: %ls\n", pWritingApp);

    // pos of segment payload
    printf("\t\tPosition(Segment)\t: %lld\n", pSegment->m_start);

    // size of segment payload
    printf("\t\tSize(Segment)\t\t: %lld\n", pSegment->m_size);

    mkvparser::Tracks* const pTracks = pSegment->GetTracks();

    unsigned long i = 0;
    const unsigned long j = pTracks->GetTracksCount();

    enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };

    printf("\n\t\t\t   Track Info\n");

    while (i != j)
    {
        const Track* const pTrack = pTracks->GetTrackByIndex(i++);

        if (pTrack == NULL)
            continue;

        const long long trackType_ = pTrack->GetType();
        unsigned long trackType = static_cast<unsigned long>(trackType_);

        unsigned long trackNumber = pTrack->GetNumber();
        const wchar_t* const pTrackName = utf8towcs(pTrack->GetNameAsUTF8());

        printf("\t\tTrack Type\t\t: %ld\n", trackType);
        printf("\t\tTrack Number\t\t: %ld\n", trackNumber);

        if (pTrackName == NULL)
            printf("\t\tTrack Name\t\t: NULL\n");
        else
            printf("\t\tTrack Name\t\t: %ls \n", pTrackName);

        const char* const pCodecId = pTrack->GetCodecId();

        if (pCodecId == NULL)
            printf("\t\tCodec Id\t\t: NULL\n");
        else
            printf("\t\tCodec Id\t\t: %s\n", pCodecId);

        const char* const pCodecName_ = pTrack->GetCodecNameAsUTF8();
        const wchar_t* const pCodecName = utf8towcs(pCodecName_);

        if (pCodecName == NULL)
            printf("\t\tCodec Name\t\t: NULL\n");
        else
            printf("\t\tCodec Name\t\t: %ls\n", pCodecName);

        if (trackType == VIDEO_TRACK)
        {
            const VideoTrack* const pVideoTrack =
                static_cast<const VideoTrack*>(pTrack);

            const long long width =  pVideoTrack->GetWidth();
            printf("\t\tVideo Width\t\t: %lld\n", width);

            const long long height = pVideoTrack->GetHeight();
            printf("\t\tVideo Height\t\t: %lld\n", height);

            const double rate = pVideoTrack->GetFrameRate();
            printf("\t\tVideo Rate\t\t: %f\n",rate);
        }

        if (trackType == AUDIO_TRACK)
        {
            const AudioTrack* const pAudioTrack =
                static_cast<const AudioTrack*>(pTrack);

            const long long channels =  pAudioTrack->GetChannels();
            printf("\t\tAudio Channels\t\t: %lld\n", channels);

            const long long bitDepth = pAudioTrack->GetBitDepth();
            printf("\t\tAudio BitDepth\t\t: %lld\n", bitDepth);

            const double sampleRate = pAudioTrack->GetSamplingRate();
            printf("\t\tAddio Sample Rate\t: %.3f\n", sampleRate);
        }
    }

    printf("\n\n\t\t\t   Cluster Info\n");
    const unsigned long clusterCount = pSegment->GetCount();

    printf("\t\tCluster Count\t: %ld\n\n", clusterCount);

    if (clusterCount == 0)
    {
        printf("\t\tSegment has no clusters.\n");
        delete pSegment;
        return -1;
    }

    mkvparser::Cluster* pCluster = pSegment->GetFirst();

    while ((pCluster != NULL) && !pCluster->EOS())
    {
        const long long timeCode = pCluster->GetTimeCode();
        printf("\t\tCluster Time Code\t: %lld\n", timeCode);

        const long long time_ns = pCluster->GetTime();
        printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);

        const BlockEntry* pBlockEntry = pCluster->GetFirst();

        while ((pBlockEntry != NULL) && !pBlockEntry->EOS())
        {
            const Block* const pBlock  = pBlockEntry->GetBlock();
            const unsigned long trackNum = pBlock->GetTrackNumber();
            const Track* const pTrack = pTracks->GetTrackByNumber(trackNum);
            const long long trackType = pTrack->GetType();
            const long size = pBlock->GetSize();
            const long long offset = pBlock->GetOffset();
            const long long time_ns = pBlock->GetTime(pCluster);

            printf("\t\t\tBlock\t\t:%s,%15ld,%15llx,%s,%15lld\n",
                   (trackType == VIDEO_TRACK) ? "V" : "A",
                   size,
                   offset,
                   pBlock->IsKey() ? "I" : "P",
                   time_ns);

            pBlockEntry = pCluster->GetNext(pBlockEntry);
        }

        pCluster = pSegment->GetNext(pCluster);
    }

    delete pSegment;
    return 0;

}
<commit_msg>updated to handle a laced webm<commit_after>// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS.  All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
//
// This sample application demonstrates how to use the matroska parser
// library, which allows clients to handle a matroska format file.

#include "mkvreader.hpp"
#include "mkvparser.hpp"

static const wchar_t* utf8towcs(const char* str)
{
    if (str == NULL)
        return NULL;

    //TODO: this probably requires that the locale be
    //configured somehow:

    const size_t size = mbstowcs(NULL, str, 0);

    if (size == 0)
        return NULL;

    wchar_t* const val = new wchar_t[size+1];

    mbstowcs(val, str, size);
    val[size] = L'\0';

    return val;
}

int main(int argc, char* argv[])
{
    if (argc == 1)
    {
        printf("\t\t\tMkv Parser Sample Application\n");
        printf("\t\t\tUsage: \n");
        printf("\t\t\t  ./sample [input file] \n");
        printf("\t\t\t  ./sample sample.mkv \n");
        return -1;
    }

    using namespace mkvparser;

    MkvReader reader;

    if (reader.Open(argv[1]))
    {
        printf("\n Filename is invalid or error while opening.\n");
        return -1;
    }

    int maj, min, build, rev;

    GetVersion(maj, min, build, rev);
    printf("\t\t libmkv verison: %d.%d.%d.%d\n", maj, min, build, rev);

    long long pos = 0;

    EBMLHeader ebmlHeader;

    ebmlHeader.Parse(&reader, pos);

    printf("\t\t\t    EBML Header\n");
    printf("\t\tEBML Version\t\t: %lld\n", ebmlHeader.m_version);
    printf("\t\tEBML MaxIDLength\t: %lld\n", ebmlHeader.m_maxIdLength);
    printf("\t\tEBML MaxSizeLength\t: %lld\n", ebmlHeader.m_maxSizeLength);
    printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);
    printf("\t\tPos\t\t\t: %lld\n", pos);

    mkvparser::Segment* pSegment;

    long long ret = mkvparser::Segment::CreateInstance(&reader, pos, pSegment);
    if (ret)
    {
        printf("\n Segment::CreateInstance() failed.");
        return -1;
    }

    ret  = pSegment->Load();
    if (ret < 0)
    {
        printf("\n Segment::Load() failed.");
        return -1;
    }

    const SegmentInfo* const pSegmentInfo = pSegment->GetInfo();

    const long long timeCodeScale = pSegmentInfo->GetTimeCodeScale();
    const long long duration_ns = pSegmentInfo->GetDuration();

    const char* const pTitle_ = pSegmentInfo->GetTitleAsUTF8();
    const wchar_t* const pTitle = utf8towcs(pTitle_);

    const char* const pMuxingApp_ = pSegmentInfo->GetMuxingAppAsUTF8();
    const wchar_t* const pMuxingApp = utf8towcs(pMuxingApp_);

    const char* const pWritingApp_ = pSegmentInfo->GetWritingAppAsUTF8();
    const wchar_t* const pWritingApp = utf8towcs(pWritingApp_);

    printf("\n");
    printf("\t\t\t   Segment Info\n");
    printf("\t\tTimeCodeScale\t\t: %lld \n", timeCodeScale);
    printf("\t\tDuration\t\t: %lld\n", duration_ns);

    const double duration_sec = double(duration_ns) / 1000000000;
    printf("\t\tDuration(secs)\t\t: %7.3f\n", duration_sec);

    if (pTitle == NULL)
        printf("\t\tTrack Name\t\t: NULL\n");
    else
        printf("\t\tTrack Name\t\t: %ls\n", pTitle);

    if (pMuxingApp == NULL)
        printf("\t\tMuxing App\t\t: NULL\n");
    else
        printf("\t\tMuxing App\t\t: %ls\n", pMuxingApp);

    if (pWritingApp == NULL)
        printf("\t\tWriting App\t\t: NULL\n");
    else
        printf("\t\tWriting App\t\t: %ls\n", pWritingApp);

    // pos of segment payload
    printf("\t\tPosition(Segment)\t: %lld\n", pSegment->m_start);

    // size of segment payload
    printf("\t\tSize(Segment)\t\t: %lld\n", pSegment->m_size);

    mkvparser::Tracks* const pTracks = pSegment->GetTracks();

    unsigned long i = 0;
    const unsigned long j = pTracks->GetTracksCount();

    enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };

    printf("\n\t\t\t   Track Info\n");

    while (i != j)
    {
        const Track* const pTrack = pTracks->GetTrackByIndex(i++);

        if (pTrack == NULL)
            continue;

        const long long trackType_ = pTrack->GetType();
        unsigned long trackType = static_cast<unsigned long>(trackType_);

        unsigned long trackNumber = pTrack->GetNumber();
        const wchar_t* const pTrackName = utf8towcs(pTrack->GetNameAsUTF8());

        printf("\t\tTrack Type\t\t: %ld\n", trackType);
        printf("\t\tTrack Number\t\t: %ld\n", trackNumber);

        if (pTrackName == NULL)
            printf("\t\tTrack Name\t\t: NULL\n");
        else
            printf("\t\tTrack Name\t\t: %ls \n", pTrackName);

        const char* const pCodecId = pTrack->GetCodecId();

        if (pCodecId == NULL)
            printf("\t\tCodec Id\t\t: NULL\n");
        else
            printf("\t\tCodec Id\t\t: %s\n", pCodecId);

        const char* const pCodecName_ = pTrack->GetCodecNameAsUTF8();
        const wchar_t* const pCodecName = utf8towcs(pCodecName_);

        if (pCodecName == NULL)
            printf("\t\tCodec Name\t\t: NULL\n");
        else
            printf("\t\tCodec Name\t\t: %ls\n", pCodecName);

        if (trackType == VIDEO_TRACK)
        {
            const VideoTrack* const pVideoTrack =
                static_cast<const VideoTrack*>(pTrack);

            const long long width =  pVideoTrack->GetWidth();
            printf("\t\tVideo Width\t\t: %lld\n", width);

            const long long height = pVideoTrack->GetHeight();
            printf("\t\tVideo Height\t\t: %lld\n", height);

            const double rate = pVideoTrack->GetFrameRate();
            printf("\t\tVideo Rate\t\t: %f\n",rate);
        }

        if (trackType == AUDIO_TRACK)
        {
            const AudioTrack* const pAudioTrack =
                static_cast<const AudioTrack*>(pTrack);

            const long long channels =  pAudioTrack->GetChannels();
            printf("\t\tAudio Channels\t\t: %lld\n", channels);

            const long long bitDepth = pAudioTrack->GetBitDepth();
            printf("\t\tAudio BitDepth\t\t: %lld\n", bitDepth);

            const double sampleRate = pAudioTrack->GetSamplingRate();
            printf("\t\tAddio Sample Rate\t: %.3f\n", sampleRate);
        }
    }

    printf("\n\n\t\t\t   Cluster Info\n");
    const unsigned long clusterCount = pSegment->GetCount();

    printf("\t\tCluster Count\t: %ld\n\n", clusterCount);

    if (clusterCount == 0)
    {
        printf("\t\tSegment has no clusters.\n");
        delete pSegment;
        return -1;
    }

    const mkvparser::Cluster* pCluster = pSegment->GetFirst();

    while ((pCluster != NULL) && !pCluster->EOS())
    {
        const long long timeCode = pCluster->GetTimeCode();
        printf("\t\tCluster Time Code\t: %lld\n", timeCode);

        const long long time_ns = pCluster->GetTime();
        printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);

        const BlockEntry* pBlockEntry = pCluster->GetFirst();

        while ((pBlockEntry != NULL) && !pBlockEntry->EOS())
        {
            const Block* const pBlock  = pBlockEntry->GetBlock();
            const unsigned long trackNum = pBlock->GetTrackNumber();
            const Track* const pTrack = pTracks->GetTrackByNumber(trackNum);
            const long long trackType = pTrack->GetType();
            const int frameCount = pBlock->GetFrameCount();
            const long long time_ns = pBlock->GetTime(pCluster);

            printf("\t\t\tBlock\t\t:%s,%s,%15lld\n",
                   (trackType == VIDEO_TRACK) ? "V" : "A",
                   pBlock->IsKey() ? "I" : "P",
                   time_ns);

            for (int i = 0; i < frameCount; ++i)
            {
                const Block::Frame& theFrame = pBlock->GetFrame(i);
                const long size = theFrame.len;
                const long offset = theFrame.pos;
                printf("\t\t\t %15ld,%15lx\n", size, offset);
            }

            pBlockEntry = pCluster->GetNext(pBlockEntry);
        }

        pCluster = pSegment->GetNext(pCluster);
    }

    delete pSegment;
    return 0;

}
<|endoftext|>


<commit_before>// This file is part of the "x0" project, http://xzero.io/
//   (c) 2009-2014 Christian Parpart <trapni@gmail.com>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <initializer_list>
#include <vector>
#include <fstream>
#include <iostream>
#include <string>

// supervisor [-f|--fork] [-p|--pidfile=PATH] -- cmd ...
//
// -f,--fork            whether to fork the supervisor process into background
// -p,--pidfile=PATH    location to store the current supervisor PID
// -r,--restart         Automatically restart program, if crashed.
// -c,--cgroups         Use cgroups to track PIDs
//
// Examples:
//     supervisor /usr/sbin/x0d --no-fork
//     supervisor -p /var/run/xzero/supervisor.pid -- /usr/sbin/x0d --no-fork

class PidTracker {
 public:
  PidTracker();
  ~PidTracker();

  void add(int pid);
  std::vector<int> get();
  void dump();
};

PidTracker::PidTracker() {
  char path[80];
  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor", getpid());
  int rv = mkdir(path, 0777);

  if (rv < 0) {
    perror("PidTracker: mkdir");
  }
}

PidTracker::~PidTracker() {
  char path[80];
  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor", getpid());
  rmdir(path);
}

void PidTracker::add(int pid) {
  char path[80];
  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor/tasks",
           getpid());

  char buf[64];
  ssize_t n = snprintf(buf, sizeof(buf), "%d", pid);

  int fd = open(path, O_WRONLY);
  write(fd, buf, n);
  close(fd);
}

std::vector<int> PidTracker::get() {
  std::vector<int> result;

  char path[80];
  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor/tasks",
           getpid());

  std::ifstream tasksFile(path);
  std::string line;

  while (std::getline(tasksFile, line)) {
    result.push_back(stoi(line));
  }

  return result;
}

void PidTracker::dump() {
  printf("PID tracking: ");
  const auto pids = get();
  for (int pid : pids) {
    printf(" %d", pid);
  }
  printf("\n");
}

static PidTracker pidTracker;
static int childPid = 0;
static int lastSignum = 0;
static std::string programPath;
static std::vector<std::string> programArgs;
static int retryCount = 5;

void runProgram() {
  printf("Running program...\n");

  pid_t pid = fork();

  if (pid < 0) {
    fprintf(stderr, "fork failed. %s\n", strerror(errno));
    abort();
  } else if (pid > 0) {  // parent
    childPid = pid;
    pidTracker.add(pid);
    printf("supervisor: child pid is %d\n", pid);
    pidTracker.dump();

    if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
      fprintf(stderr, "supervisor: prctl(PR_SET_CHILD_SUBREAPER) failed. %s",
              strerror(errno));
    }
  } else {  // child
    std::vector<char*> argv;
    argv.push_back(const_cast<char*>(programPath.c_str()));
    for (const std::string& arg : programArgs) {
      argv.push_back(const_cast<char*>(arg.c_str()));
    }
    argv.push_back(nullptr);

    execvp(programPath.c_str(), argv.data());
    fprintf(stderr, "execvp failed. %s\n", strerror(errno));
    abort();
  }
}

void restartProgram() {
  pidTracker.dump();
  const auto pids = pidTracker.get();
  if (pids.size() == 1) {
    childPid = pids[0];
    printf("supervisor: reattaching to child PID %d\n", childPid);
    return;
  }

  printf("Restarting program (retry count: %d)\n", retryCount);

  if (retryCount == 0) {
    throw EXIT_FAILURE;
  }

  retryCount--;
  runProgram();
}

void sighandler(int signum) {
  lastSignum = signum;

  if (childPid) {
    printf("Signal %s (%d) received. Forwarding to child PID %d.\n",
           strsignal(signum), signum, childPid);

    // forward to child process
    kill(childPid, signum);
  }
}

bool parseArgs(int argc, const char* argv[]) {
  if (argc <= 1) {
    fprintf(stderr, "usage error\n");
    return false;
  }

  int i = 1;

  programPath = argv[i];
  i++;

  while (argv[i] != nullptr) {
    programArgs.push_back(argv[i]);
    i++;
  }

  return true;
}

int main(int argc, const char* argv[]) {
  try {
    if (!parseArgs(argc, argv)) return 1;

    printf("Installing signal handler...\n");
    for (int sig : {SIGINT, SIGTERM, SIGQUIT, SIGHUP}) {
      signal(sig, &sighandler);
    }

    // if (setsid() < 0) {
    //   fprintf(stderr, "Error creating session. %s\n", strerror(errno));
    //   return EXIT_FAILURE;
    // }

    if (setpgrp() < 0) {
      fprintf(stderr, "Error creating process group. %s\n", strerror(errno));
      return EXIT_FAILURE;
    }

    runProgram();

    for (;;) {
      int status = 0;
      if (waitpid(childPid, &status, 0) < 0) {
        perror("waitpid");
        throw EXIT_FAILURE;
      }

      if (WIFEXITED(status)) {
        printf("Child %d terminated with exit code %d\n", childPid,
               WEXITSTATUS(status));
        restartProgram();
      }

      if (WIFSIGNALED(status)) {
        printf("Child %d terminated with signal %s (%d)\n", childPid,
               strsignal(WTERMSIG(status)), WTERMSIG(status));
        restartProgram();
      }

      fprintf(stderr, "Child %d terminated. Status code %d\n", childPid,
              status);
      restartProgram();
    }
  }
  catch (int exitCode) {
    return exitCode;
  }
}

// vim:ts=2:sw=2
<commit_msg>supervisor: update<commit_after>// This file is part of the "x0" project, http://xzero.io/
//   (c) 2009-2014 Christian Parpart <trapni@gmail.com>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <getopt.h>
#include <initializer_list>
#include <vector>
#include <fstream>
#include <iostream>
#include <string>

// {{{ PidTracker
class PidTracker {
 public:
  PidTracker();
  ~PidTracker();

  void add(int pid);
  std::vector<int> get();
  void dump();
};

PidTracker::PidTracker() {
  char path[80];
  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor", getpid());
  int rv = mkdir(path, 0777);

  if (rv < 0) {
    perror("PidTracker: mkdir");
  }
}

PidTracker::~PidTracker() {
  char path[80];
  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor", getpid());
  rmdir(path);
}

void PidTracker::add(int pid) {
  char path[80];
  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor/tasks",
           getpid());

  char buf[64];
  ssize_t n = snprintf(buf, sizeof(buf), "%d", pid);

  int fd = open(path, O_WRONLY);
  write(fd, buf, n);
  close(fd);
}

std::vector<int> PidTracker::get() {
  std::vector<int> result;

  char path[80];
  snprintf(path, sizeof(path), "/sys/fs/cgroup/cpu/%d.supervisor/tasks",
           getpid());

  std::ifstream tasksFile(path);
  std::string line;

  while (std::getline(tasksFile, line)) {
    result.push_back(stoi(line));
  }

  return result;
}

void PidTracker::dump() {
  printf("PID tracking dump: ");
  const auto pids = get();
  for (int pid : pids) {
    printf(" %d", pid);
  }
  printf("\n");
}
// }}}

static std::vector<int> forwardingSignals;
static PidTracker pidTracker;
static int childPid = 0;
static int lastSignum = 0;
static std::string programPath;
static std::vector<std::string> programArgs;
static int retryCount = 5;

void runProgram() {
  printf("Running program...\n");

  pid_t pid = fork();

  if (pid < 0) {
    fprintf(stderr, "fork failed. %s\n", strerror(errno));
    abort();
  } else if (pid > 0) {  // parent
    childPid = pid;
    pidTracker.add(pid);
    printf("supervisor: child pid is %d\n", pid);
    pidTracker.dump();

    if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
      fprintf(stderr, "supervisor: prctl(PR_SET_CHILD_SUBREAPER) failed. %s",
              strerror(errno));

      // if this one fails, we can still be functional to *SOME* degree,
      // like, auto-restarting still works, but
      // the supervised child is forking to re-exec, that'll not work then.
    }
  } else {  // child
    std::vector<char*> argv;
    argv.push_back(const_cast<char*>(programPath.c_str()));
    for (const std::string& arg : programArgs) {
      argv.push_back(const_cast<char*>(arg.c_str()));
    }
    argv.push_back(nullptr);

    execvp(programPath.c_str(), argv.data());
    fprintf(stderr, "execvp failed. %s\n", strerror(errno));
    abort();
  }
}

void restartProgram() {
  pidTracker.dump();
  const auto pids = pidTracker.get();
  if (pids.size() == 1) {
    childPid = pids[0];
    printf("supervisor: reattaching to child PID %d\n", childPid);
    return;
  }

  printf("Restarting program (retry count: %d)\n", retryCount);

  if (retryCount == 0) {
    throw EXIT_FAILURE;
  }

  retryCount--;
  runProgram();
}

void sighandler(int signum) {
  lastSignum = signum;

  if (childPid) {
    printf("Signal %s (%d) received. Forwarding to child PID %d.\n",
           strsignal(signum), signum, childPid);

    // forward to child process
    kill(childPid, signum);
  }
}

void printHelp() {
  printf(
      "supervisor: a process supervising tool\n"
      "  (c) 2009-2014 Christian Parpart <trapni@gmail.com>\n"
      "\n"
      "usage:\n"
      "  supervisor [-f|--fork] [-p|--pidfile=PATH] -- cmd ...\n"
      "\n"
      "options:\n"
      "  -f,--fork          whether to fork and daemonize the supervisor\n"
      "                     process into background\n"
      "  -p,--pidfile=PATH  location to store the current supervisor PID\n"
      "  -r,--restart       Automatically restart program, if crashed.\n"
      "  -d,--delay=SECONDS Number of seconds to wait before we retry\n"
      "                     to restart the application.\n"
      "  -s,--signal=SIGNAL Adds given signal to the list of signals\n"
      "                     to forward to the supervised program.\n"
      "                     Defaults to (INT, TERM, QUIT, USR1, USR2, HUP)\n"
      "  -P,--child-pidfile=PATH\n"
      "                     Path to the child process' managed PID file.\n"
      "                     The supervisor is watching this file for updates.\n"
      "\n"
      "Examples:\n"
      "    supervisor -- /usr/sbin/x0d --no-fork\n"
      "    supervisor -p /var/run/xzero/supervisor.pid -- /usr/sbin/x0d\\\n"
      "               --no-fork\n"
      "\n");
}

bool parseArgs(int argc, const char* argv[]) {
  if (argc <= 1) {
    printHelp();
    return false;
  }
  // TODO: use getopt_long

  int i = 1;

  programPath = argv[i];
  i++;

  while (argv[i] != nullptr) {
    programArgs.push_back(argv[i]);
    i++;
  }

  return true;
}

int main(int argc, const char* argv[]) {
  try {
    if (!parseArgs(argc, argv)) return 1;

    printf("Installing signal handler...\n");
    for (int sig : {SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGUSR1, SIGUSR2}) {
      signal(sig, &sighandler);
    }

    // if (setsid() < 0) {
    //   fprintf(stderr, "Error creating session. %s\n", strerror(errno));
    //   return EXIT_FAILURE;
    // }

    if (setpgrp() < 0) {
      fprintf(stderr, "Error creating process group. %s\n", strerror(errno));
      return EXIT_FAILURE;
    }

    runProgram();

    for (;;) {
      int status = 0;
      if (waitpid(childPid, &status, 0) < 0) {
        perror("waitpid");
        throw EXIT_FAILURE;
      }

      if (WIFEXITED(status)) {
        printf("Child %d terminated with exit code %d\n", childPid,
               WEXITSTATUS(status));
        restartProgram();
      }

      if (WIFSIGNALED(status)) {
        printf("Child %d terminated with signal %s (%d)\n", childPid,
               strsignal(WTERMSIG(status)), WTERMSIG(status));
        restartProgram();
      }

      fprintf(stderr, "Child %d terminated. Status code %d\n", childPid,
              status);
      restartProgram();
    }
  }
  catch (int exitCode) {
    return exitCode;
  }
}

// vim:ts=2:sw=2
<|endoftext|>


<commit_before><commit_msg>set correct new version of beam energy (as we store it in this new version), pp should be p-p in GRP<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dragmt3d.hxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _E3D_DRAGMT3D_HXX
#define _E3D_DRAGMT3D_HXX

#include <svx/svddrgmt.hxx>
#include <svx/view3d.hxx>
#include <basegfx/polygon/b3dpolygon.hxx>
#include <vcl/timer.hxx>

class E3dScene;

/*************************************************************************
|*
|* Parameter fuer Interaktion eines 3D-Objektes
|*
\************************************************************************/

class E3dDragMethodUnit
{
public:
    E3dObject*          p3DObj;
    basegfx::B3DPolygon         aWireframePoly;
    basegfx::B3DHomMatrix           aDisplayTransform;
    basegfx::B3DHomMatrix           aInvDisplayTransform;
    basegfx::B3DHomMatrix            aInitTransform;
    basegfx::B3DHomMatrix           aTransform;
    INT32               nStartAngle;
    INT32               nLastAngle;

    // TimingVars
    UINT8                       nOrigQuality;

    E3dDragMethodUnit() {}
};

/*************************************************************************
|*
|* Parameter fuer Interaktion eines 3D-Objektes
|*
\************************************************************************/

SV_DECL_PTRARR_DEL(E3dDragMethodUnitGroup, E3dDragMethodUnit*, 1, 3)

/*************************************************************************
|*
|* Ableitung von SdrDragMethod fuer 3D-Objekte
|*
\************************************************************************/

class E3dDragMethod : public SdrDragMethod
{
protected:
    E3dDragMethodUnitGroup      aGrp;
    E3dDragConstraint           eConstraint;
    Point                       aLastPos;
    Rectangle                   aFullBound;
    BOOL                        bMoveFull;
    BOOL                        bMovedAtAll;
    Timer                       aCallbackTimer;

public:
    TYPEINFO();
    E3dDragMethod(SdrDragView &rView,
        const SdrMarkList& rMark,
        E3dDragConstraint eConstr = E3DDRAG_CONSTR_XYZ,
        BOOL bFull=FALSE);

    virtual void TakeComment(String& rStr) const;

    virtual FASTBOOL Beg();
    virtual void Mov(const Point& rPnt);
    virtual void Brk();
    virtual FASTBOOL End(FASTBOOL bCopy);

    //virtual void DrawXor(XOutputDevice& rXOut, FASTBOOL bFull) const;
    E3dView& Get3DView()  { return (E3dView&)rView;  }

    DECL_LINK(TimerInterruptHdl, void*);

    // for migration from XOR to overlay
    virtual void CreateOverlayGeometry(::sdr::overlay::OverlayManager& rOverlayManager, ::sdr::overlay::OverlayObjectList& rOverlayList);
};

/*************************************************************************
|*
|* Ableitung von SdrDragMethod zum Drehen von 3D-Objekten
|*
\************************************************************************/

class E3dDragRotate : public E3dDragMethod
{
    basegfx::B3DPoint           aGlobalCenter;

public:
    TYPEINFO();
    E3dDragRotate(SdrDragView &rView,
        const SdrMarkList& rMark,
        E3dDragConstraint eConstr = E3DDRAG_CONSTR_XYZ,
        BOOL bFull=FALSE);

    virtual void Mov(const Point& rPnt);
    virtual Pointer GetPointer() const;
};

/*************************************************************************
|*
|* Ableitung von SdrDragMethod zum Verschieben von 3D-Subobjekten
|*
\************************************************************************/

class E3dDragMove : public E3dDragMethod
{
    SdrHdlKind              eWhatDragHdl;
    Point                   aScaleFixPos;

public:
    TYPEINFO();
    E3dDragMove(SdrDragView &rView,
        const SdrMarkList& rMark,
        SdrHdlKind eDrgHdl = HDL_MOVE,
        E3dDragConstraint eConstr = E3DDRAG_CONSTR_XYZ,
        BOOL bFull=FALSE);

    virtual void Mov(const Point& rPnt);
    virtual Pointer GetPointer() const;
};

#endif          // _E3D_DRAGMT3D_HXX
<commit_msg>INTEGRATION: CWS aw033 (1.7.58); FILE MERGED 2008/07/10 12:58:57 aw 1.7.58.1: #i39532# XOutputDevice removed, PrepareDelete removed<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dragmt3d.hxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _E3D_DRAGMT3D_HXX
#define _E3D_DRAGMT3D_HXX

#include <svx/svddrgmt.hxx>
#include <svx/view3d.hxx>
#include <basegfx/polygon/b3dpolygon.hxx>
#include <vcl/timer.hxx>

class E3dScene;

/*************************************************************************
|*
|* Parameter fuer Interaktion eines 3D-Objektes
|*
\************************************************************************/

class E3dDragMethodUnit
{
public:
    E3dObject*          p3DObj;
    basegfx::B3DPolygon         aWireframePoly;
    basegfx::B3DHomMatrix           aDisplayTransform;
    basegfx::B3DHomMatrix           aInvDisplayTransform;
    basegfx::B3DHomMatrix            aInitTransform;
    basegfx::B3DHomMatrix           aTransform;
    INT32               nStartAngle;
    INT32               nLastAngle;

    // TimingVars
    UINT8                       nOrigQuality;

    E3dDragMethodUnit() {}
};

/*************************************************************************
|*
|* Parameter fuer Interaktion eines 3D-Objektes
|*
\************************************************************************/

SV_DECL_PTRARR_DEL(E3dDragMethodUnitGroup, E3dDragMethodUnit*, 1, 3)

/*************************************************************************
|*
|* Ableitung von SdrDragMethod fuer 3D-Objekte
|*
\************************************************************************/

class E3dDragMethod : public SdrDragMethod
{
protected:
    E3dDragMethodUnitGroup      aGrp;
    E3dDragConstraint           eConstraint;
    Point                       aLastPos;
    Rectangle                   aFullBound;
    BOOL                        bMoveFull;
    BOOL                        bMovedAtAll;
    Timer                       aCallbackTimer;

public:
    TYPEINFO();
    E3dDragMethod(SdrDragView &rView,
        const SdrMarkList& rMark,
        E3dDragConstraint eConstr = E3DDRAG_CONSTR_XYZ,
        BOOL bFull=FALSE);

    virtual void TakeComment(String& rStr) const;

    virtual FASTBOOL Beg();
    virtual void Mov(const Point& rPnt);
    virtual void Brk();
    virtual FASTBOOL End(FASTBOOL bCopy);

    E3dView& Get3DView()  { return (E3dView&)rView;  }

    DECL_LINK(TimerInterruptHdl, void*);

    // for migration from XOR to overlay
    virtual void CreateOverlayGeometry(::sdr::overlay::OverlayManager& rOverlayManager, ::sdr::overlay::OverlayObjectList& rOverlayList);
};

/*************************************************************************
|*
|* Ableitung von SdrDragMethod zum Drehen von 3D-Objekten
|*
\************************************************************************/

class E3dDragRotate : public E3dDragMethod
{
    basegfx::B3DPoint           aGlobalCenter;

public:
    TYPEINFO();
    E3dDragRotate(SdrDragView &rView,
        const SdrMarkList& rMark,
        E3dDragConstraint eConstr = E3DDRAG_CONSTR_XYZ,
        BOOL bFull=FALSE);

    virtual void Mov(const Point& rPnt);
    virtual Pointer GetPointer() const;
};

/*************************************************************************
|*
|* Ableitung von SdrDragMethod zum Verschieben von 3D-Subobjekten
|*
\************************************************************************/

class E3dDragMove : public E3dDragMethod
{
    SdrHdlKind              eWhatDragHdl;
    Point                   aScaleFixPos;

public:
    TYPEINFO();
    E3dDragMove(SdrDragView &rView,
        const SdrMarkList& rMark,
        SdrHdlKind eDrgHdl = HDL_MOVE,
        E3dDragConstraint eConstr = E3DDRAG_CONSTR_XYZ,
        BOOL bFull=FALSE);

    virtual void Mov(const Point& rPnt);
    virtual Pointer GetPointer() const;
};

#endif          // _E3D_DRAGMT3D_HXX
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: editund2.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2006-01-10 14:44:37 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _EDITUND2_HXX
#define _EDITUND2_HXX

#ifndef INCLUDED_SVXDLLAPI_H
#include "svx/svxdllapi.h"
#endif

#ifndef _UNDO_HXX
#include <svtools/undo.hxx>
#endif

class ImpEditEngine;

class SVX_DLLPUBLIC EditUndoManager : public SfxUndoManager
{
private:
    ImpEditEngine*  pImpEE;
public:
                    EditUndoManager( ImpEditEngine* pImpEE );

    virtual BOOL    Undo( USHORT nCount=1 );
    virtual BOOL    Redo( USHORT nCount=1 );
};

// -----------------------------------------------------------------------
// EditUndo
// ------------------------------------------------------------------------
class SVX_DLLPUBLIC EditUndo : public SfxUndoAction
{
private:
    USHORT          nId;
    ImpEditEngine*  pImpEE;

public:
                    TYPEINFO();
                    EditUndo( USHORT nI, ImpEditEngine* pImpEE );
    virtual         ~EditUndo();

    ImpEditEngine*  GetImpEditEngine() const    { return pImpEE; }

    virtual void    Undo()      = 0;
    virtual void    Redo()      = 0;
    virtual void    Repeat()    = 0;

    virtual BOOL    CanRepeat(SfxRepeatTarget&) const;
    virtual String  GetComment() const;
    virtual USHORT  GetId() const;
};

#endif  // _EDITUND2_HXX

<commit_msg>INTEGRATION: CWS sb59 (1.3.308); FILE MERGED 2006/08/04 11:23:13 cl 1.3.308.2: fixed compiler warnings 2006/08/03 13:47:01 cl 1.3.308.1: removed compiler warnings<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: editund2.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 11:40:22 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _EDITUND2_HXX
#define _EDITUND2_HXX

#ifndef INCLUDED_SVXDLLAPI_H
#include "svx/svxdllapi.h"
#endif

#ifndef _UNDO_HXX
#include <svtools/undo.hxx>
#endif

class ImpEditEngine;

class SVX_DLLPUBLIC EditUndoManager : public SfxUndoManager
{
    using SfxUndoManager::Undo;
    using SfxUndoManager::Redo;

private:
    ImpEditEngine*  pImpEE;
public:
                    EditUndoManager( ImpEditEngine* pImpEE );

    virtual BOOL    Undo( USHORT nCount=1 );
    virtual BOOL    Redo( USHORT nCount=1 );
};

// -----------------------------------------------------------------------
// EditUndo
// ------------------------------------------------------------------------
class SVX_DLLPUBLIC EditUndo : public SfxUndoAction
{
private:
    USHORT          nId;
    ImpEditEngine*  pImpEE;

public:
                    TYPEINFO();
                    EditUndo( USHORT nI, ImpEditEngine* pImpEE );
    virtual         ~EditUndo();

    ImpEditEngine*  GetImpEditEngine() const    { return pImpEE; }

    virtual void    Undo()      = 0;
    virtual void    Redo()      = 0;

    virtual BOOL    CanRepeat(SfxRepeatTarget&) const;
    virtual String  GetComment() const;
    virtual USHORT  GetId() const;
};

#endif  // _EDITUND2_HXX

<|endoftext|>