<commit_before>#include <vector>
#include <thread>
#include <mutex>
#include <algorithm>
#include <signal.h>

#include <ev3/servo.h>

namespace ev3cv {

namespace {
std::vector<servo *> servos;
std::mutex servos_lock;

std::thread controller_thread;
}

void controller_main() {
  // Clock to use for controllers.
  typedef std::chrono::high_resolution_clock clock;

  // Sampling period for the controllers.
  static const std::chrono::milliseconds dt(10);

  auto t0 = clock::now();
  for(auto t = t0; ; t += dt) {
    if (dt.count() > 0) {
      std::lock_guard<std::mutex> lock(servos_lock);
      for (auto i : servos) {
        i->tick(dt.count());
      }
      if (servos.empty())
        break;
    }
    std::this_thread::sleep_until(t);
  }
}

servo::servo(const ev3dev::port_type &port) : m_(port), pid_(5000, 5000, 200, 2, 200) {
  reset();

  {
    std::lock_guard<std::mutex> lock(servos_lock);
    servos.push_back(this);
  }

  // If we don't have a controller thread, make one.
  if (!controller_thread.joinable()) {
    std::thread new_thread(controller_main);
    std::swap(controller_thread, new_thread);
  }
}

servo::~servo() {
  servos_lock.lock();
  servos.erase(std::find(servos.begin(), servos.end(), this));

  // If there are no more live motors, wait for the controller thread to complete.
  if (servos.empty()) {
    servos_lock.unlock();
    controller_thread.join();
  } else {
    servos_lock.unlock();
  }

  m_.reset();
}

void servo::run() {
  {
    std::lock_guard<std::mutex> lock(this->lock_);
    pid_.reset();
  }
  m_.set_run_mode(ev3dev::motor::run_mode_forever);
  tick(0);
  m_.run();
}

void servo::stop(bool hold) {
  std::lock_guard<std::mutex> lock(this->lock_);
  m_.set_stop_mode(hold ? ev3dev::motor::stop_mode_hold : ev3dev::motor::stop_mode_coast);
  m_.stop();
  pid_.reset();
}

void servo::reset(int position) {
  std::lock_guard<std::mutex> lock(this->lock_);
  m_.reset();
  m_.set_position(position);
  pid_.reset();
  max_duty_cycle_ = 100;
}

void servo::tick(int dt) {
  std::lock_guard<std::mutex> lock(this->lock_);
  int x = position();
  if (sp_fn_) {
    t_ += dt;
    pid_.set_setpoint(sp_fn_(x, t_, dt));
  }
  int y = pid_.tick(x, dt)/1024;
  m_.set_duty_cycle_setpoint(clamp(y, -max_duty_cycle_, max_duty_cycle_));
}

int servo::position_setpoint() const {
  return pid_.setpoint();
}

void servo::set_position_setpoint(int sp) {
  std::lock_guard<std::mutex> lock(this->lock_);
  sp_fn_ = nullptr;
  pid_.set_setpoint(sp);
}

void servo::set_position_setpoint(std::function<int(int, int, int)> sp_fn) {
  std::lock_guard<std::mutex> lock(this->lock_);
  sp_fn_ = sp_fn;
  t_ = 0;
  pid_.set_setpoint(sp_fn(position(), t_, 0));
}

void servo::set_max_duty_cycle(int x) {
  std::lock_guard<std::mutex> lock(this->lock_);
  max_duty_cycle_ = x;
}

}  // namespace ev3cv<commit_msg>Tweaked integral limit<commit_after>#include <vector>
#include <thread>
#include <mutex>
#include <algorithm>
#include <signal.h>

#include <ev3/servo.h>

namespace ev3cv {

namespace {
std::vector<servo *> servos;
std::mutex servos_lock;

std::thread controller_thread;
}

void controller_main() {
  // Clock to use for controllers.
  typedef std::chrono::high_resolution_clock clock;

  // Sampling period for the controllers.
  static const std::chrono::milliseconds dt(10);

  auto t0 = clock::now();
  for(auto t = t0; ; t += dt) {
    if (dt.count() > 0) {
      std::lock_guard<std::mutex> lock(servos_lock);
      for (auto i : servos) {
        i->tick(dt.count());
      }
      if (servos.empty())
        break;
    }
    std::this_thread::sleep_until(t);
  }
}

servo::servo(const ev3dev::port_type &port) : m_(port), pid_(5000, 5000, 200, 2, 5000) {
  reset();

  {
    std::lock_guard<std::mutex> lock(servos_lock);
    servos.push_back(this);
  }

  // If we don't have a controller thread, make one.
  if (!controller_thread.joinable()) {
    std::thread new_thread(controller_main);
    std::swap(controller_thread, new_thread);
  }
}

servo::~servo() {
  servos_lock.lock();
  servos.erase(std::find(servos.begin(), servos.end(), this));

  // If there are no more live motors, wait for the controller thread to complete.
  if (servos.empty()) {
    servos_lock.unlock();
    controller_thread.join();
  } else {
    servos_lock.unlock();
  }

  m_.reset();
}

void servo::run() {
  {
    std::lock_guard<std::mutex> lock(this->lock_);
    pid_.reset();
  }
  m_.set_run_mode(ev3dev::motor::run_mode_forever);
  tick(0);
  m_.run();
}

void servo::stop(bool hold) {
  std::lock_guard<std::mutex> lock(this->lock_);
  m_.set_stop_mode(hold ? ev3dev::motor::stop_mode_hold : ev3dev::motor::stop_mode_coast);
  m_.stop();
  pid_.reset();
}

void servo::reset(int position) {
  std::lock_guard<std::mutex> lock(this->lock_);
  m_.reset();
  m_.set_position(position);
  pid_.reset();
  max_duty_cycle_ = 100;
}

void servo::tick(int dt) {
  std::lock_guard<std::mutex> lock(this->lock_);
  int x = position();
  if (sp_fn_) {
    t_ += dt;
    pid_.set_setpoint(sp_fn_(x, t_, dt));
  }
  int y = pid_.tick(x, dt)/1024;
  m_.set_duty_cycle_setpoint(clamp(y, -max_duty_cycle_, max_duty_cycle_));
}

int servo::position_setpoint() const {
  return pid_.setpoint();
}

void servo::set_position_setpoint(int sp) {
  std::lock_guard<std::mutex> lock(this->lock_);
  sp_fn_ = nullptr;
  pid_.set_setpoint(sp);
}

void servo::set_position_setpoint(std::function<int(int, int, int)> sp_fn) {
  std::lock_guard<std::mutex> lock(this->lock_);
  sp_fn_ = sp_fn;
  t_ = 0;
  pid_.set_setpoint(sp_fn(position(), t_, 0));
}

void servo::set_max_duty_cycle(int x) {
  std::lock_guard<std::mutex> lock(this->lock_);
  max_duty_cycle_ = x;
}

}  // namespace ev3cv<|endoftext|>


<commit_before>/*
 * execprocd.cpp
 *
 *  Created on: Sep 10, 2014
 *      Author: matheus
 */

#include <signal.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <list>
#include <map>
#include <string>
#include <utility>

#include "defines.hpp"
#include "Message.hpp"
#include "MessageBox.hpp"
#include "ProcessLauncher.hpp"
#include "Time.hpp"

using namespace std;

struct Process {
  int proc_id;
  pid_t pid;
  key_t key;
  int nchange;
  Time::type initial_time, final_time;
  Process(int proc_id = 0, pid_t pid = 0, key_t key = 0) :
  proc_id(proc_id),
  pid(pid), key(key), nchange(0), initial_time(Time::get()), final_time(0)
  {

  }
};

struct Schedule {
  Process process;
  useconds_t quantum;
  Schedule(const Process& process, useconds_t quantum) :
  process(process), quantum(quantum)
  {

  }
};

bool quit = false;
MessageInbox* inbox = NULL;
ReportMessage rep;
list<Process> queues[3];
map<int, Process> dead_processes;
int next_proc_id = 1;
bool is_running_proc = false;
Process running_proc;
bool running_proc_error = false;
map<int, int> changes;

inline useconds_t get_quantum(int priority) {
  switch (priority) {
    case PRIORITY_HIGH: return QUANTUM_HIGH;
    case PRIORITY_MED:  return QUANTUM_MED;
    case PRIORITY_LOW:  return QUANTUM_LOW;
    default:            return QUANTUM_NA;
  }
}

void notify_launcher(const Process& process) {
  MessageOutbox outbox(process.key);
  Message execinfomsg(Message::EXECINFO);
  execinfomsg.content.info.wclock = process.final_time-process.initial_time;
  execinfomsg.content.info.nchange = process.nchange;
  outbox.send(execinfomsg);
}

Schedule choose_process() {
  for (int priority = PRIORITY_HIGH; priority <= PRIORITY_LOW; priority++) {
    if (queues[priority].size()) {
      Process p = queues[priority].front();
      queues[priority].pop_front();
      return Schedule(p, get_quantum(priority));
    }
  }
  return Schedule(Process(0, 0), 0);
}

void execute_process(const ExecMessage& msg) {
  int proc_id = next_proc_id++;
  ProcessLauncher launcher(msg.bufsiz, msg.shmkey);
  pid_t pid;

  // the actual process
  if ((pid = fork()) == 0) {
    raise(SIGSTOP);
    chdir(launcher.dir.c_str());
    if (execv(launcher.argv[0], launcher.argv) < 0) {
      launcher.freeargv();

      // notify execution error to execprocd and execproc
      Message execerrormsg(Message::EXECERROR);
      execerrormsg.content.error.proc_id = proc_id;
      MessageOutbox outbox(KEY_EXECPROCD);
      outbox.send(execerrormsg);
      outbox = MessageOutbox(msg.msgkey);
      outbox.send(execerrormsg);

      exit(0);
    }
  }

  launcher.freeargv();

  // incrementing number of executed processes
  rep.nexec++;

  // sending acknowledgement message
  Message ackmsg(Message::EXECACK);
  ackmsg.content.ack.proc_id = proc_id;
  MessageOutbox outbox(msg.msgkey);
  outbox.send(ackmsg);

  // enqueuing process
  queues[msg.priority].push_back(
    Process(ackmsg.content.ack.proc_id, pid, msg.msgkey)
  );
}

void handle_execerror(const ExecErrorMessage& msg) {
  // decrementing number of executed processes
  rep.nexec--;
  rep.nchange -= changes[msg.proc_id];

  // if the process is running
  if (is_running_proc && running_proc.proc_id == msg.proc_id) {
    running_proc_error = true;
  }
  // if the process is already dead
  else if (dead_processes.find(msg.proc_id) != dead_processes.end()) {
    dead_processes.erase(msg.proc_id);
  }
  // if the process is enqueued
  else {
    // search process in all queues
    for (int priority = PRIORITY_HIGH; priority <= PRIORITY_LOW; priority++) {
      bool found = false;

      list<Process>& pqueue = queues[priority];

      // search process in the current queue
      for (list<Process>::iterator it = pqueue.begin(); it != pqueue.end();) {
        if (it->proc_id == msg.proc_id) {
          found = true;
          pqueue.erase(it);
          break;
        }
        else {
          it++;
        }
      }

      // stop searching if the process was found
      if (found) {
        break;
      }
    }
  }
}

void stop_process(const StopMessage& msg) {
  Process p;

  // check if process is not in the dead pool
  map<int, Process>::iterator it = dead_processes.find(msg.proc_id);
  if (it == dead_processes.end()) {
    Time::type final_time = Time::get();

    // search process in all queues
    for (int priority = PRIORITY_HIGH; priority <= PRIORITY_LOW; priority++) {
      list<Process>& pqueue = queues[priority];

      // search process in the current queue
      for (list<Process>::iterator it = pqueue.begin(); it != pqueue.end();) {
        if (it->proc_id == msg.proc_id) {
          p = *it;
          p.final_time = final_time;
          pqueue.erase(it);
          break;
        }
        else {
          it++;
        }
      }

      // stop searching if the process was found
      if (p.proc_id) {
        break;
      }
    }
  }

  // check if the process to stop is the process running
  if (!p.proc_id && is_running_proc && running_proc.proc_id == msg.proc_id) {
    p = running_proc;
  }

  // if the process exists, it is not in the dead pool
  if (p.proc_id) {
    kill(p.pid, SIGKILL);
    waitpid(p.pid, NULL, 0);
    p.final_time = Time::get();
    rep.nstop++;
    dead_processes[p.proc_id] = p;
    notify_launcher(p);
  }
  // if the process is in the dead pool
  else if (it != dead_processes.end()) {
    p = it->second;
  }

  // answer exec info
  MessageOutbox outbox(msg.key);
  Message execinfomsg(p.proc_id ? Message::EXECINFO : Message::NOTFOUND);
  execinfomsg.content.info.wclock = p.final_time - p.initial_time;
  execinfomsg.content.info.nchange = p.nchange;
  outbox.send(execinfomsg);
}

void killall() {
  for (int priority = PRIORITY_HIGH; priority <= PRIORITY_LOW; priority++) {
    list<Process>& pqueue = queues[priority];
    while (pqueue.size()) {
      Process p = pqueue.front();
      p.final_time = Time::get();
      pqueue.pop_front();
      kill(p.pid, SIGKILL);
      notify_launcher(p);
    }
  }
}

void process_messages() {
  Message msg;
  while (inbox->recv(msg)) {
    switch (msg.type) {
      case Message::EXEC:
        execute_process(msg.content.exec);
        break;

      case Message::EXECERROR:
        handle_execerror(msg.content.error);
        break;

      case Message::STOP:
        stop_process(msg.content.stop);
        break;

      case Message::TERM:
        quit = true;
        {
          Message repmsg(Message::REPORT);
          repmsg.content.report = rep;
          MessageOutbox outbox(msg.content.term.key);
          outbox.send(repmsg);
        }
        killall();
        return;

      default:
        break;
    }
  }
}

void execprocd(int argc, char** argv) {
  // check if procexecd is already running
  inbox = new MessageInbox(KEY_EXECPROCD);
  if (inbox->getKey() == 0) {
    fprintf(stderr, "execprocd: already running\n");
    delete inbox;
    return;
  }

  // run in background
  if (fork()) {
    return;
  }

  // initialize report information
  memset(&rep, 0, sizeof(ReportMessage));

  // keep scheduling until termination message is sent
  srand(time(NULL));
  while (!quit) {
    Schedule schedule = choose_process();
    if (schedule.quantum) {
      running_proc = schedule.process;
      is_running_proc = true;

      // calculate quantum final time
      Time::type t = Time::get() + schedule.quantum;

      kill(schedule.process.pid, SIGCONT);

      // wait until quantum is over or until process is killed
      while (
        Time::get() < t &&
        waitpid(schedule.process.pid, NULL, WNOHANG) != schedule.process.pid &&
        !running_proc_error
      ) {
        Time::sleep(SLEEP_WAITFAST);
        process_messages();
      }

      // if executable file was not found
      if (running_proc_error) {
        running_proc_error = false;
      }
      // if the process is alive, recalculate priority and push to queue
      else if (kill(schedule.process.pid, 0) >= 0) {
        kill(schedule.process.pid, SIGSTOP);
        schedule.process.nchange++;
        rep.nchange++;
        changes[schedule.process.proc_id]++;
        queues[rand()%3].push_back(schedule.process);
      }
      // if the process is dead, mark final time, put in dead pool and notify
      else if (
        dead_processes.find(schedule.process.proc_id) == dead_processes.end()
      ) {
        schedule.process.final_time = Time::get();
        dead_processes[schedule.process.proc_id] = schedule.process;
        notify_launcher(schedule.process);
      }

      is_running_proc = false;
    }
    else {
      Time::sleep(SLEEP_WAIT);
      process_messages();
    }
  }

  // destroy socket
  delete inbox;
}
<commit_msg>Fixing bug<commit_after>/*
 * execprocd.cpp
 *
 *  Created on: Sep 10, 2014
 *      Author: matheus
 */

#include <signal.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <list>
#include <map>
#include <string>
#include <utility>

#include "defines.hpp"
#include "Message.hpp"
#include "MessageBox.hpp"
#include "ProcessLauncher.hpp"
#include "Time.hpp"

using namespace std;

struct Process {
  int proc_id;
  pid_t pid;
  key_t key;
  int nchange;
  Time::type initial_time, final_time;
  Process(int proc_id = 0, pid_t pid = 0, key_t key = 0) :
  proc_id(proc_id),
  pid(pid), key(key), nchange(0), initial_time(Time::get()), final_time(0)
  {

  }
};

struct Schedule {
  Process process;
  useconds_t quantum;
  Schedule(const Process& process, useconds_t quantum) :
  process(process), quantum(quantum)
  {

  }
};

bool quit = false;
MessageInbox* inbox = NULL;
ReportMessage rep;
list<Process> queues[3];
map<int, Process> dead_processes;
int next_proc_id = 1;
bool is_running_proc = false;
Process running_proc;
bool running_proc_error = false;
map<int, int> changes;

inline useconds_t get_quantum(int priority) {
  switch (priority) {
    case PRIORITY_HIGH: return QUANTUM_HIGH;
    case PRIORITY_MED:  return QUANTUM_MED;
    case PRIORITY_LOW:  return QUANTUM_LOW;
    default:            return QUANTUM_NA;
  }
}

void notify_launcher(const Process& process) {
  MessageOutbox outbox(process.key);
  Message execinfomsg(Message::EXECINFO);
  execinfomsg.content.info.wclock = process.final_time-process.initial_time;
  execinfomsg.content.info.nchange = process.nchange;
  outbox.send(execinfomsg);
}

Schedule choose_process() {
  for (int priority = PRIORITY_HIGH; priority <= PRIORITY_LOW; priority++) {
    if (queues[priority].size()) {
      Process p = queues[priority].front();
      queues[priority].pop_front();
      return Schedule(p, get_quantum(priority));
    }
  }
  return Schedule(Process(0, 0), 0);
}

void execute_process(const ExecMessage& msg) {
  int proc_id = next_proc_id++;
  ProcessLauncher launcher(msg.bufsiz, msg.shmkey);
  pid_t pid;

  // the actual process
  if ((pid = fork()) == 0) {
    raise(SIGSTOP);
    chdir(launcher.dir.c_str());
    if (execv(launcher.argv[0], launcher.argv) < 0) {
      launcher.freeargv();

      // notify execution error to execprocd and execproc
      Message execerrormsg(Message::EXECERROR);
      execerrormsg.content.error.proc_id = proc_id;
      MessageOutbox outbox(KEY_EXECPROCD);
      outbox.send(execerrormsg);
      outbox = MessageOutbox(msg.msgkey);
      outbox.send(execerrormsg);

      exit(0);
    }
  }

  launcher.freeargv();

  // incrementing number of executed processes
  rep.nexec++;

  // sending acknowledgement message
  Message ackmsg(Message::EXECACK);
  ackmsg.content.ack.proc_id = proc_id;
  MessageOutbox outbox(msg.msgkey);
  outbox.send(ackmsg);

  // enqueuing process
  queues[msg.priority].push_back(
    Process(ackmsg.content.ack.proc_id, pid, msg.msgkey)
  );
}

void handle_execerror(const ExecErrorMessage& msg) {
  // decrementing number of executed processes
  rep.nexec--;
  rep.nchange -= changes[msg.proc_id];

  // if the process is running
  if (is_running_proc && running_proc.proc_id == msg.proc_id) {
    running_proc_error = true;
  }
  // if the process is already dead
  else if (dead_processes.find(msg.proc_id) != dead_processes.end()) {
    dead_processes.erase(msg.proc_id);
  }
  // if the process is enqueued
  else {
    // search process in all queues
    for (int priority = PRIORITY_HIGH; priority <= PRIORITY_LOW; priority++) {
      bool found = false;

      list<Process>& pqueue = queues[priority];

      // search process in the current queue
      for (list<Process>::iterator it = pqueue.begin(); it != pqueue.end();) {
        if (it->proc_id == msg.proc_id) {
          found = true;
          pqueue.erase(it);
          break;
        }
        else {
          it++;
        }
      }

      // stop searching if the process was found
      if (found) {
        break;
      }
    }
  }
}

void stop_process(const StopMessage& msg) {
  Process p;

  // check if process is not in the dead pool
  map<int, Process>::iterator it = dead_processes.find(msg.proc_id);
  if (it == dead_processes.end()) {
    Time::type final_time = Time::get();

    // search process in all queues
    for (int priority = PRIORITY_HIGH; priority <= PRIORITY_LOW; priority++) {
      list<Process>& pqueue = queues[priority];

      // search process in the current queue
      for (list<Process>::iterator it = pqueue.begin(); it != pqueue.end();) {
        if (it->proc_id == msg.proc_id) {
          p = *it;
          p.final_time = final_time;
          pqueue.erase(it);
          break;
        }
        else {
          it++;
        }
      }

      // stop searching if the process was found
      if (p.proc_id) {
        break;
      }
    }
  }

  // check if the process to stop is the process running
  if (!p.proc_id && is_running_proc && running_proc.proc_id == msg.proc_id) {
    p = running_proc;
  }

  // if the process exists, it is not in the dead pool
  if (p.proc_id) {
    kill(p.pid, SIGKILL);
    waitpid(p.pid, NULL, 0);
    p.final_time = Time::get();
    rep.nstop++;
    dead_processes[p.proc_id] = p;
    notify_launcher(p);
  }
  // if the process is in the dead pool
  else if (it != dead_processes.end()) {
    p = it->second;
  }

  // answer exec info
  MessageOutbox outbox(msg.key);
  Message execinfomsg(p.proc_id ? Message::EXECINFO : Message::NOTFOUND);
  execinfomsg.content.info.wclock = p.final_time - p.initial_time;
  execinfomsg.content.info.nchange = p.nchange;
  outbox.send(execinfomsg);
}

void killall() {
  // queues
  for (int priority = PRIORITY_HIGH; priority <= PRIORITY_LOW; priority++) {
    list<Process>& pqueue = queues[priority];
    while (pqueue.size()) {
      Process p = pqueue.front();
      p.final_time = Time::get();
      pqueue.pop_front();
      kill(p.pid, SIGKILL);
      notify_launcher(p);
    }
  }

  // running
  if (is_running_proc) {
    running_proc.final_time = Time::get();
    kill(running_proc.pid, SIGKILL);
    notify_launcher(running_proc);
  }
}

void process_messages() {
  Message msg;
  while (inbox->recv(msg)) {
    switch (msg.type) {
      case Message::EXEC:
        execute_process(msg.content.exec);
        break;

      case Message::EXECERROR:
        handle_execerror(msg.content.error);
        break;

      case Message::STOP:
        stop_process(msg.content.stop);
        break;

      case Message::TERM:
        quit = true;
        {
          Message repmsg(Message::REPORT);
          repmsg.content.report = rep;
          MessageOutbox outbox(msg.content.term.key);
          outbox.send(repmsg);
        }
        killall();
        return;

      default:
        break;
    }
  }
}

void execprocd(int argc, char** argv) {
  // check if procexecd is already running
  inbox = new MessageInbox(KEY_EXECPROCD);
  if (inbox->getKey() == 0) {
    fprintf(stderr, "execprocd: already running\n");
    delete inbox;
    return;
  }

  // run in background
  if (fork()) {
    return;
  }

  // initialize report information
  memset(&rep, 0, sizeof(ReportMessage));

  // keep scheduling until termination message is sent
  srand(time(NULL));
  while (!quit) {
    Schedule schedule = choose_process();
    if (schedule.quantum) {
      running_proc = schedule.process;
      is_running_proc = true;

      // calculate quantum final time
      Time::type t = Time::get() + schedule.quantum;

      kill(schedule.process.pid, SIGCONT);

      // wait until quantum is over or until process is killed
      while (
        Time::get() < t &&
        waitpid(schedule.process.pid, NULL, WNOHANG) != schedule.process.pid &&
        !running_proc_error
      ) {
        Time::sleep(SLEEP_WAITFAST);
        process_messages();
      }

      // if executable file was not found
      if (running_proc_error) {
        running_proc_error = false;
      }
      // if the process is alive, recalculate priority and push to queue
      else if (kill(schedule.process.pid, 0) >= 0) {
        kill(schedule.process.pid, SIGSTOP);
        schedule.process.nchange++;
        rep.nchange++;
        changes[schedule.process.proc_id]++;
        queues[rand()%3].push_back(schedule.process);
      }
      // if the process is dead, mark final time, put in dead pool and notify
      else if (
        dead_processes.find(schedule.process.proc_id) == dead_processes.end()
      ) {
        schedule.process.final_time = Time::get();
        dead_processes[schedule.process.proc_id] = schedule.process;
        notify_launcher(schedule.process);
      }

      is_running_proc = false;
    }
    else {
      Time::sleep(SLEEP_WAIT);
      process_messages();
    }
  }

  // destroy socket
  delete inbox;
}
<|endoftext|>


<commit_before>#include "player.h"

#include "common/log.h"

#define PLAYER_CAPSULE_HEIGHT 1.8f
#define PLAYER_CAPSULE_RADIUS 0.25f

// 75 kg mass person
#define PLAYER_MASS 75.0f

namespace redc
{
  Player_Controller::Player_Controller() : inited_(false), ghost_(),
                                           shape_(PLAYER_CAPSULE_RADIUS,
                                                  PLAYER_CAPSULE_HEIGHT),
                                           jump_velocity_() {}

  // They are expected to add the action to the dynamics world and then this
  // will be called, then we init then we start
  void Player_Controller::updateAction(btCollisionWorld* world, btScalar dt)
  {
    if(!inited_)
    {
      // Initialize velocity and impulse to zero
      jump_velocity_.setZero();

      last_normal_.setZero();

      // Set it to a unit vector going straight upwards
      last_normal_.setY(1.0f);

      // Player state
      state = Player_State::Grounded;

      // Transform
      btTransform trans;
      trans.setIdentity();
      trans.setOrigin(btVector3(0.0f, 1.5f, 0.0f));
      ghost_.setWorldTransform(trans);

      // Shape
      ghost_.setCollisionShape(&shape_);

      // Flags
      ghost_.setCollisionFlags(ghost_.getCollisionFlags() |
                               btCollisionObject::CF_KINEMATIC_OBJECT);
      ghost_.setActivationState(DISABLE_DEACTIVATION);

      // Ghost callback, this updates any ghost object with any and all objects
      // it collides with so later on we can collision dispatching on only those
      // pairs (and get contacts back, etc).

      // **Important:** Add this before adding the ghost object, otherwise the
      // ghost object will not get notified and dispatching collisions of the
      // ghost object will literally ignore all collisions with the world. This
      // actually bit me in the butt before these two statements were
      // re-ordered. Interesting because even though the objects were actually
      // colliding, the (pair caching) ghost object was not dispatching the
      // ghost-map collisions.
      world->getPairCache()->setInternalGhostPairCallback(&ghost_cb_);

      // Add to world
      world->addCollisionObject(&ghost_);

      inited_ = true;
      return;
    }

    // Current world transform
    auto xform = ghost_.getWorldTransform();
    // Current position
    auto pos = xform.getOrigin();

    // Updates the ghost object. Suffixed with an underscore so we know it's
    // private... to this function.
    auto update_ghost_transform_ = [&]()
    {
      xform.setOrigin(pos);
      ghost_.setWorldTransform(xform);
    };

    // ===
    // Ray tracing floor-collision handling
    // ===
    {
      // First trace a ray from the player to the near-ground. If we hit
      // something we should consider the player on the ground, that means we no
      // longer have to apply gravity, for example.

      // How far should the ray extend past the bottom of the ghost object.
      constexpr float shoe_size = 0.7f;

      auto start_pos = pos;
      start_pos.setY(pos.getY() - PLAYER_CAPSULE_HEIGHT / 2.0f);

      auto end_pos = pos;
      end_pos.setY(start_pos.getY() - shoe_size);

      // Redundancy whhyyyyy
      btCollisionWorld::ClosestRayResultCallback ground_ray(start_pos, end_pos);
      world->rayTest(start_pos, end_pos, ground_ray);

      if(ground_ray.hasHit())
      {
        // What is the player doing?

        // Notes:

        // This section used to reset the player's y position to the ray
        // intersection point, the issue is that it would interfere with the
        // penetration recovery and cause a constant switch from the player
        // being grounded to being registered as jumping. The ray trace ended up
        // locking it too close to the ground and then the recover would push it
        // up too far such that next frame we switched to jumping, etc.

        // Anyways it works better now because we still use the player state to
        // decide whether or not to apply gravity but we don't accidentally move
        // the player and cause strange unexpected changes. The penetration
        // recovery works well enough that it can handle moving the player above
        // the floor just fine. After that, as long as gravity isn't applied the
        // player remains stable.

        // One issue that I'm seeing now that due to a large value for
        // shoe_size, the player can get stuck low down in the range of
        // allowable heights and then a jump becomes ineffective because even
        // after that one tick of movement the player is still in the allowable
        // range, which means the player is immediately considered to be on the
        // ground. Of course, currently that means velocity is not applied.
        if(state == Player_State::Jumping) state = Player_State::Grounded;

        last_normal_ = ground_ray.m_hitNormalWorld;
      }

      // No ground?
      else
      {
        state = Player_State::Jumping;
      }

      update_ghost_transform_();
    }

    // ===
    // Handle input
    // ===

    {
      btVector3 local_dpos;
      local_dpos.setZero();

      if(input_ref_->forward)
      {
        local_dpos.setX(-1.0f);
      }
      if(input_ref_->backward)
      {
        local_dpos.setX(+1.0f);
      }
      if(input_ref_->strafe_left)
      {
        local_dpos.setZ(+1.0f);
      }
      if(input_ref_->strafe_right)
      {
        local_dpos.setZ(-1.0f);
      }

      if(input_ref_->jump && state == Player_State::Grounded)
      {
        jump_velocity_ = btVector3(0.0f, 4.0f, 0.0f);
        state = Player_State::Jumping;
      }

      auto active_normal = last_normal_;
      if(state == Player_State::Jumping)
      {
        active_normal.setZero();
        active_normal.setY(1.0f);
      }

      if(FLT_EPSILON < btFabs(local_dpos.length()))
      {
        auto movement = btMatrix3x3(xform.getRotation()) * local_dpos;
        pos += movement.cross(active_normal) * btScalar(0.1f);
      }

      update_ghost_transform_();
    }

    // ===
    // Apply gravity to the velocity if necessary
    // ===

    // When we are in the air, adjust the velocity change due to gravity.
    if(state == Player_State::Jumping)
    {
      // Adjust the air velocity of the player
      jump_velocity_ += btVector3(0.0f, -9.81f, 0.0f) * dt;
    }
    else
    {
      jump_velocity_.setZero();
    }

    // ===
    // Integrate the velocity
    // ===
    if(state != Player_State::Grounded)
    {
      pos += jump_velocity_ * dt;
      update_ghost_transform_();
    }

    // ===
    // Recover the player from any intersection with the map
    //
    // Inspired very heavily by the btKinematicCharacterController.
    // See http://bulletphysics.org/Bullet/BulletFull/btKinematicCharacterController_8cpp_source.html
    // for reference, license, etc.
    // ===

    // Here we must refresh the overlapping paircache as the penetrating
    // movement itself or the previous recovery iteration might have used
    // setWorldTransform and pushed us into an object that is not in the
    // previous cache contents from the last timestep, as will happen if we are
    // pushed into a new AABB overlap. Unhandled this means the next convex
    // sweep gets stuck.

    // Do this by calling the broadphase's setAabb with the moved AABB, this
    // will update the broadphase paircache and the ghostobject's internal
    // paircache at the same time. /BW
    btVector3 minAabb, maxAabb;
    shape_.getAabb(ghost_.getWorldTransform(), minAabb, maxAabb);
    world->getBroadphase()->setAabb(ghost_.getBroadphaseHandle(),
                                    minAabb, maxAabb, world->getDispatcher());

    // Added Notes:

    // The ghost object already knows what it's colliding with but doesn't have
    // any collision manifolds (lists of intersecting points between a pair of
    // objects). Basically, the ghost pair cache and the world pair cache are
    // kept mostly up to date thanks to the btGhostPairCallback set in the
    // world's pair cache above, but the pair objects (and algorithm impl.,
    // which store the collision manifold) are actually different, even if the
    // objects that the pair consists of (or more specifically broadphase
    // proxies) are the same. As a result, we can't pass the world pair cache to
    // do the processing because it will only generate contact points for the
    // pairs of objects in the world. As a result, the contact points (or
    // manifold) will not be accessible from the ghost pair cache, (whose
    // contact points have not been calculated).
    auto ghost_cache = ghost_.getOverlappingPairCache();
    world->getDispatcher()->dispatchAllCollisionPairs(ghost_cache,
                                                      world->getDispatchInfo(),
                                                      world->getDispatcher());

    bool penetration = false;

    for (int i = 0; i < ghost_cache->getNumOverlappingPairs(); i++)
    {
      btManifoldArray manifolds;

      btBroadphasePair* pair = &ghost_cache->getOverlappingPairArray()[i];

      btCollisionObject* obj0 = static_cast<btCollisionObject*>(
              pair->m_pProxy0->m_clientObject);
      btCollisionObject* obj1 = static_cast<btCollisionObject*>(
              pair->m_pProxy1->m_clientObject);

      // Both objects must not have collision response.
      if ((obj0 && !obj0->hasContactResponse()) ||
          (obj1 && !obj1->hasContactResponse()))
      {
        continue;
      }

      if (pair->m_algorithm)
      {
        pair->m_algorithm->getAllContactManifolds(manifolds);
      }

      for (int j = 0; j < manifolds.size(); j++)
      {
        btPersistentManifold* manifold = manifolds[j];
        btScalar sign =
          manifold->getBody0() == &ghost_ ? btScalar(-1.0) : btScalar(1.0);

        for (int p = 0; p < manifold->getNumContacts(); p++)
        {
          const btManifoldPoint& pt = manifold->getContactPoint(p);

          btScalar dist = pt.getDistance();

          if (dist < 0.0)
          {
            // Added notes:

            // This solution of pushing the character away from objects is okay
            // but it is not really practical when the player is standing still
            // The character often glitches around and it's only that measly
            // multiplication by 0.2 that keeps the whole thing somewhat decent
            // and smooth. The smoothing does work against walls though, so this
            // should be considered this codes most important reason for being
            // here. Floor collision, jumping, stepping, etc should all probably
            // be done with a raytrace and a state machine, etc.
            pos += pt.m_normalWorldOnB * sign * dist * btScalar(0.5);
            penetration = true;
          }
        }
      }
    }

    if(penetration) update_ghost_transform_();
  }

  void Player_Controller::apply_delta_yaw(double yaw)
  {
    auto xform = ghost_.getWorldTransform();
    auto rot = xform.getRotation();
    rot *= btQuaternion(-yaw, 0.0f, 0.0f);
    xform.setRotation(rot);
    ghost_.setWorldTransform(xform);
  }
  void Player_Controller::apply_delta_pitch(double pitch)
  {
    // We don't care about pitch as of now from a physics standpoint
    /*
    auto xform = ghost_.getWorldTransform();
    auto rot = xform.getRotation();
    rot *= btQuaternion(0.0f, pitch, 0.0f);
    ghost_.setWorldTransform(xform);
    */
  }
}
<commit_msg>Raise initial spawn height and jump height<commit_after>#include "player.h"

#include "common/log.h"

#define PLAYER_CAPSULE_HEIGHT 1.8f
#define PLAYER_CAPSULE_RADIUS 0.25f

// 75 kg mass person
#define PLAYER_MASS 75.0f

namespace redc
{
  Player_Controller::Player_Controller() : inited_(false), ghost_(),
                                           shape_(PLAYER_CAPSULE_RADIUS,
                                                  PLAYER_CAPSULE_HEIGHT),
                                           jump_velocity_() {}

  // They are expected to add the action to the dynamics world and then this
  // will be called, then we init then we start
  void Player_Controller::updateAction(btCollisionWorld* world, btScalar dt)
  {
    if(!inited_)
    {
      // Initialize velocity and impulse to zero
      jump_velocity_.setZero();

      last_normal_.setZero();

      // Set it to a unit vector going straight upwards
      last_normal_.setY(1.0f);

      // Player state
      state = Player_State::Grounded;

      // Transform
      btTransform trans;
      trans.setIdentity();
      trans.setOrigin(btVector3(0.0f, 4.5f, 0.0f));
      ghost_.setWorldTransform(trans);

      // Shape
      ghost_.setCollisionShape(&shape_);

      // Flags
      ghost_.setCollisionFlags(ghost_.getCollisionFlags() |
                               btCollisionObject::CF_KINEMATIC_OBJECT);
      ghost_.setActivationState(DISABLE_DEACTIVATION);

      // Ghost callback, this updates any ghost object with any and all objects
      // it collides with so later on we can collision dispatching on only those
      // pairs (and get contacts back, etc).

      // **Important:** Add this before adding the ghost object, otherwise the
      // ghost object will not get notified and dispatching collisions of the
      // ghost object will literally ignore all collisions with the world. This
      // actually bit me in the butt before these two statements were
      // re-ordered. Interesting because even though the objects were actually
      // colliding, the (pair caching) ghost object was not dispatching the
      // ghost-map collisions.
      world->getPairCache()->setInternalGhostPairCallback(&ghost_cb_);

      // Add to world
      world->addCollisionObject(&ghost_);

      inited_ = true;
      return;
    }

    // Current world transform
    auto xform = ghost_.getWorldTransform();
    // Current position
    auto pos = xform.getOrigin();

    // Updates the ghost object. Suffixed with an underscore so we know it's
    // private... to this function.
    auto update_ghost_transform_ = [&]()
    {
      xform.setOrigin(pos);
      ghost_.setWorldTransform(xform);
    };

    // ===
    // Ray tracing floor-collision handling
    // ===
    {
      // First trace a ray from the player to the near-ground. If we hit
      // something we should consider the player on the ground, that means we no
      // longer have to apply gravity, for example.

      // How far should the ray extend past the bottom of the ghost object.
      constexpr float shoe_size = 0.7f;

      auto start_pos = pos;
      start_pos.setY(pos.getY() - PLAYER_CAPSULE_HEIGHT / 2.0f);

      auto end_pos = pos;
      end_pos.setY(start_pos.getY() - shoe_size);

      // Redundancy whhyyyyy
      btCollisionWorld::ClosestRayResultCallback ground_ray(start_pos, end_pos);
      world->rayTest(start_pos, end_pos, ground_ray);

      if(ground_ray.hasHit())
      {
        // What is the player doing?

        // Notes:

        // This section used to reset the player's y position to the ray
        // intersection point, the issue is that it would interfere with the
        // penetration recovery and cause a constant switch from the player
        // being grounded to being registered as jumping. The ray trace ended up
        // locking it too close to the ground and then the recover would push it
        // up too far such that next frame we switched to jumping, etc.

        // Anyways it works better now because we still use the player state to
        // decide whether or not to apply gravity but we don't accidentally move
        // the player and cause strange unexpected changes. The penetration
        // recovery works well enough that it can handle moving the player above
        // the floor just fine. After that, as long as gravity isn't applied the
        // player remains stable.

        // One issue that I'm seeing now that due to a large value for
        // shoe_size, the player can get stuck low down in the range of
        // allowable heights and then a jump becomes ineffective because even
        // after that one tick of movement the player is still in the allowable
        // range, which means the player is immediately considered to be on the
        // ground. Of course, currently that means velocity is not applied.
        if(state == Player_State::Jumping) state = Player_State::Grounded;

        last_normal_ = ground_ray.m_hitNormalWorld;
      }

      // No ground?
      else
      {
        state = Player_State::Jumping;
      }

      update_ghost_transform_();
    }

    // ===
    // Handle input
    // ===

    {
      btVector3 local_dpos;
      local_dpos.setZero();

      if(input_ref_->forward)
      {
        local_dpos.setX(-1.0f);
      }
      if(input_ref_->backward)
      {
        local_dpos.setX(+1.0f);
      }
      if(input_ref_->strafe_left)
      {
        local_dpos.setZ(+1.0f);
      }
      if(input_ref_->strafe_right)
      {
        local_dpos.setZ(-1.0f);
      }

      if(input_ref_->jump && state == Player_State::Grounded)
      {
        jump_velocity_ = btVector3(0.0f, 6.0f, 0.0f);
        state = Player_State::Jumping;
      }

      auto active_normal = last_normal_;
      if(state == Player_State::Jumping)
      {
        active_normal.setZero();
        active_normal.setY(1.0f);
      }

      if(FLT_EPSILON < btFabs(local_dpos.length()))
      {
        auto movement = btMatrix3x3(xform.getRotation()) * local_dpos;
        pos += movement.cross(active_normal) * btScalar(0.1f);
      }

      update_ghost_transform_();
    }

    // ===
    // Apply gravity to the velocity if necessary
    // ===

    // When we are in the air, adjust the velocity change due to gravity.
    if(state == Player_State::Jumping)
    {
      // Adjust the air velocity of the player
      jump_velocity_ += btVector3(0.0f, -9.81f, 0.0f) * dt;
    }
    else
    {
      jump_velocity_.setZero();
    }

    // ===
    // Integrate the velocity
    // ===
    if(state != Player_State::Grounded)
    {
      pos += jump_velocity_ * dt;
      update_ghost_transform_();
    }

    // ===
    // Recover the player from any intersection with the map
    //
    // Inspired very heavily by the btKinematicCharacterController.
    // See http://bulletphysics.org/Bullet/BulletFull/btKinematicCharacterController_8cpp_source.html
    // for reference, license, etc.
    // ===

    // Here we must refresh the overlapping paircache as the penetrating
    // movement itself or the previous recovery iteration might have used
    // setWorldTransform and pushed us into an object that is not in the
    // previous cache contents from the last timestep, as will happen if we are
    // pushed into a new AABB overlap. Unhandled this means the next convex
    // sweep gets stuck.

    // Do this by calling the broadphase's setAabb with the moved AABB, this
    // will update the broadphase paircache and the ghostobject's internal
    // paircache at the same time. /BW
    btVector3 minAabb, maxAabb;
    shape_.getAabb(ghost_.getWorldTransform(), minAabb, maxAabb);
    world->getBroadphase()->setAabb(ghost_.getBroadphaseHandle(),
                                    minAabb, maxAabb, world->getDispatcher());

    // Added Notes:

    // The ghost object already knows what it's colliding with but doesn't have
    // any collision manifolds (lists of intersecting points between a pair of
    // objects). Basically, the ghost pair cache and the world pair cache are
    // kept mostly up to date thanks to the btGhostPairCallback set in the
    // world's pair cache above, but the pair objects (and algorithm impl.,
    // which store the collision manifold) are actually different, even if the
    // objects that the pair consists of (or more specifically broadphase
    // proxies) are the same. As a result, we can't pass the world pair cache to
    // do the processing because it will only generate contact points for the
    // pairs of objects in the world. As a result, the contact points (or
    // manifold) will not be accessible from the ghost pair cache, (whose
    // contact points have not been calculated).
    auto ghost_cache = ghost_.getOverlappingPairCache();
    world->getDispatcher()->dispatchAllCollisionPairs(ghost_cache,
                                                      world->getDispatchInfo(),
                                                      world->getDispatcher());

    bool penetration = false;

    for (int i = 0; i < ghost_cache->getNumOverlappingPairs(); i++)
    {
      btManifoldArray manifolds;

      btBroadphasePair* pair = &ghost_cache->getOverlappingPairArray()[i];

      btCollisionObject* obj0 = static_cast<btCollisionObject*>(
              pair->m_pProxy0->m_clientObject);
      btCollisionObject* obj1 = static_cast<btCollisionObject*>(
              pair->m_pProxy1->m_clientObject);

      // Both objects must not have collision response.
      if ((obj0 && !obj0->hasContactResponse()) ||
          (obj1 && !obj1->hasContactResponse()))
      {
        continue;
      }

      if (pair->m_algorithm)
      {
        pair->m_algorithm->getAllContactManifolds(manifolds);
      }

      for (int j = 0; j < manifolds.size(); j++)
      {
        btPersistentManifold* manifold = manifolds[j];
        btScalar sign =
          manifold->getBody0() == &ghost_ ? btScalar(-1.0) : btScalar(1.0);

        for (int p = 0; p < manifold->getNumContacts(); p++)
        {
          const btManifoldPoint& pt = manifold->getContactPoint(p);

          btScalar dist = pt.getDistance();

          if (dist < 0.0)
          {
            // Added notes:

            // This solution of pushing the character away from objects is okay
            // but it is not really practical when the player is standing still
            // The character often glitches around and it's only that measly
            // multiplication by 0.2 that keeps the whole thing somewhat decent
            // and smooth. The smoothing does work against walls though, so this
            // should be considered this codes most important reason for being
            // here. Floor collision, jumping, stepping, etc should all probably
            // be done with a raytrace and a state machine, etc.
            pos += pt.m_normalWorldOnB * sign * dist * btScalar(0.5);
            penetration = true;
          }
        }
      }
    }

    if(penetration) update_ghost_transform_();
  }

  void Player_Controller::apply_delta_yaw(double yaw)
  {
    auto xform = ghost_.getWorldTransform();
    auto rot = xform.getRotation();
    rot *= btQuaternion(-yaw, 0.0f, 0.0f);
    xform.setRotation(rot);
    ghost_.setWorldTransform(xform);
  }
  void Player_Controller::apply_delta_pitch(double pitch)
  {
    // We don't care about pitch as of now from a physics standpoint
    /*
    auto xform = ghost_.getWorldTransform();
    auto rot = xform.getRotation();
    rot *= btQuaternion(0.0f, pitch, 0.0f);
    ghost_.setWorldTransform(xform);
    */
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: dif.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2004-06-04 10:52:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _DIF_HXX
#define _DIF_HXX

#ifndef _TOOLS_DEBUG_HXX //autogen
#include <tools/debug.hxx>
#endif

#ifndef _LIST_HXX //autogen
#include <tools/list.hxx>
#endif

#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif

#ifndef SC_SCGLOB_HXX
#include "global.hxx"
#endif

#ifndef SC_ADDRESS_HXX
#include "address.hxx"
#endif

class SvStream;
class SvNumberFormatter;
class ScDocument;
class ScPatternAttr;

extern const sal_Unicode pKeyTABLE[];
extern const sal_Unicode pKeyVECTORS[];
extern const sal_Unicode pKeyTUPLES[];
extern const sal_Unicode pKeyDATA[];
extern const sal_Unicode pKeyBOT[];
extern const sal_Unicode pKeyEOD[];
extern const sal_Unicode pKeyTRUE[];
extern const sal_Unicode pKeyFALSE[];
extern const sal_Unicode pKeyNA[];
extern const sal_Unicode pKeyV[];
extern const sal_Unicode pKey1_0[];

enum TOPIC
{
    T_UNKNOWN,
    T_TABLE, T_VECTORS, T_TUPLES, T_DATA, T_LABEL, T_COMMENT, T_SIZE,
    T_PERIODICITY, T_MAJORSTART, T_MINORSTART, T_TRUELENGTH, T_UINITS,
    T_DISPLAYUNITS,
    T_END
};

enum DATASET { D_BOT, D_EOD, D_NUMERIC, D_STRING, D_UNKNOWN, D_SYNT_ERROR };

class DifParser
{
public:
    String              aData;
    double              fVal;
    UINT32              nVector;
    UINT32              nVal;
    UINT32              nNumFormat;
    CharSet             eCharSet;
private:
    SvNumberFormatter*  pNumFormatter;
    SvStream&           rIn;
    BOOL                bPlain;

    static inline BOOL  IsBOT( const sal_Unicode* pRef );
    static inline BOOL  IsEOD( const sal_Unicode* pRef );
    static inline BOOL  Is1_0( const sal_Unicode* pRef );
public:
                        DifParser( SvStream&, const UINT32 nOption, ScDocument&, CharSet );

    TOPIC               GetNextTopic( void );

    DATASET             GetNextDataset( void );

    const sal_Unicode*  ScanIntVal( const sal_Unicode* pStart, UINT32& rRet );
    BOOL                ScanFloatVal( const sal_Unicode* pStart );

    inline BOOL         IsNumber( const sal_Unicode cChar );
    inline BOOL         IsNumberEnding( const sal_Unicode cChar );

    static inline BOOL  IsV( const sal_Unicode* pRef );

    inline BOOL         IsPlain( void ) const;
};

inline BOOL DifParser::IsBOT( const sal_Unicode* pRef )
{
    return  (   pRef[ 0 ] == pKeyBOT[0] &&
                pRef[ 1 ] == pKeyBOT[1] &&
                pRef[ 2 ] == pKeyBOT[2] &&
                pRef[ 3 ] == pKeyBOT[3] );
}

inline BOOL DifParser::IsEOD( const sal_Unicode* pRef )
{
    return  (   pRef[ 0 ] == pKeyEOD[0] &&
                pRef[ 1 ] == pKeyEOD[1] &&
                pRef[ 2 ] == pKeyEOD[2] &&
                pRef[ 3 ] == pKeyEOD[3] );
}

inline BOOL DifParser::Is1_0( const sal_Unicode* pRef )
{
    return  (   pRef[ 0 ] == pKey1_0[0] &&
                pRef[ 1 ] == pKey1_0[1] &&
                pRef[ 2 ] == pKey1_0[2] &&
                pRef[ 3 ] == pKey1_0[3] );
}

inline BOOL DifParser::IsV( const sal_Unicode* pRef )
{
    return  (   pRef[ 0 ] == pKeyV[0] &&
                pRef[ 1 ] == pKeyV[1]   );
}

inline BOOL DifParser::IsNumber( const sal_Unicode cChar )
{
    return ( cChar >= '0' && cChar <= '9' );
}

inline BOOL DifParser::IsNumberEnding( const sal_Unicode cChar )
{
    return ( cChar == 0x00 );
}

inline BOOL DifParser::IsPlain( void ) const
{
    return bPlain;
}

class DifAttrCache;
class ScPatternAttr;

class DifColumn : private List
{
private:
    friend class DifAttrCache;
    struct ENTRY
    {
        UINT32          nNumFormat;

        SCROW           nStart;
        SCROW           nEnd;
    };

    ENTRY*              pAkt;

    inline              DifColumn( void );
                        ~DifColumn();
    void                SetLogical( SCROW nRow );
    void                SetNumFormat( SCROW nRow, const UINT32 nNumFormat );
    void                NewEntry( const SCROW nPos, const UINT32 nNumFormat );
    void                Apply( ScDocument&, const SCCOL nCol, const SCTAB nTab, const ScPatternAttr& );
    void                Apply( ScDocument &rDoc, const SCCOL nCol, const SCTAB nTab );
public:     // geht niemanden etwas an...
};

inline DifColumn::DifColumn( void )
{
    pAkt = NULL;
}

class DifAttrCache
{
private:
    DifColumn**         ppCols;
    BOOL                bPlain;
public:
                        DifAttrCache( const BOOL bPlain );
                        ~DifAttrCache();
    inline void         SetLogical( const SCCOL nCol, const SCROW nRow );
    void                SetNumFormat( const SCCOL nCol, const SCROW nRow, const UINT32 nNumFormat );
    void                Apply( ScDocument&, SCTAB nTab );
};

inline void DifAttrCache::SetLogical( const SCCOL nCol, const SCROW nRow )
{
    DBG_ASSERT( ValidCol(nCol), "-DifAttrCache::SetLogical(): Col zu gross!" );
    DBG_ASSERT( bPlain, "*DifAttrCache::SetLogical(): muss Plain sein!" );

    if( !ppCols[ nCol ] )
        ppCols[ nCol ] = new DifColumn;
    ppCols[ nCol ]->SetLogical( nRow );
}

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.4.452); FILE MERGED 2005/09/05 15:02:38 rt 1.4.452.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dif.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 19:15:23 $
 *
 *  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 _DIF_HXX
#define _DIF_HXX

#ifndef _TOOLS_DEBUG_HXX //autogen
#include <tools/debug.hxx>
#endif

#ifndef _LIST_HXX //autogen
#include <tools/list.hxx>
#endif

#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif

#ifndef SC_SCGLOB_HXX
#include "global.hxx"
#endif

#ifndef SC_ADDRESS_HXX
#include "address.hxx"
#endif

class SvStream;
class SvNumberFormatter;
class ScDocument;
class ScPatternAttr;

extern const sal_Unicode pKeyTABLE[];
extern const sal_Unicode pKeyVECTORS[];
extern const sal_Unicode pKeyTUPLES[];
extern const sal_Unicode pKeyDATA[];
extern const sal_Unicode pKeyBOT[];
extern const sal_Unicode pKeyEOD[];
extern const sal_Unicode pKeyTRUE[];
extern const sal_Unicode pKeyFALSE[];
extern const sal_Unicode pKeyNA[];
extern const sal_Unicode pKeyV[];
extern const sal_Unicode pKey1_0[];

enum TOPIC
{
    T_UNKNOWN,
    T_TABLE, T_VECTORS, T_TUPLES, T_DATA, T_LABEL, T_COMMENT, T_SIZE,
    T_PERIODICITY, T_MAJORSTART, T_MINORSTART, T_TRUELENGTH, T_UINITS,
    T_DISPLAYUNITS,
    T_END
};

enum DATASET { D_BOT, D_EOD, D_NUMERIC, D_STRING, D_UNKNOWN, D_SYNT_ERROR };

class DifParser
{
public:
    String              aData;
    double              fVal;
    UINT32              nVector;
    UINT32              nVal;
    UINT32              nNumFormat;
    CharSet             eCharSet;
private:
    SvNumberFormatter*  pNumFormatter;
    SvStream&           rIn;
    BOOL                bPlain;

    static inline BOOL  IsBOT( const sal_Unicode* pRef );
    static inline BOOL  IsEOD( const sal_Unicode* pRef );
    static inline BOOL  Is1_0( const sal_Unicode* pRef );
public:
                        DifParser( SvStream&, const UINT32 nOption, ScDocument&, CharSet );

    TOPIC               GetNextTopic( void );

    DATASET             GetNextDataset( void );

    const sal_Unicode*  ScanIntVal( const sal_Unicode* pStart, UINT32& rRet );
    BOOL                ScanFloatVal( const sal_Unicode* pStart );

    inline BOOL         IsNumber( const sal_Unicode cChar );
    inline BOOL         IsNumberEnding( const sal_Unicode cChar );

    static inline BOOL  IsV( const sal_Unicode* pRef );

    inline BOOL         IsPlain( void ) const;
};

inline BOOL DifParser::IsBOT( const sal_Unicode* pRef )
{
    return  (   pRef[ 0 ] == pKeyBOT[0] &&
                pRef[ 1 ] == pKeyBOT[1] &&
                pRef[ 2 ] == pKeyBOT[2] &&
                pRef[ 3 ] == pKeyBOT[3] );
}

inline BOOL DifParser::IsEOD( const sal_Unicode* pRef )
{
    return  (   pRef[ 0 ] == pKeyEOD[0] &&
                pRef[ 1 ] == pKeyEOD[1] &&
                pRef[ 2 ] == pKeyEOD[2] &&
                pRef[ 3 ] == pKeyEOD[3] );
}

inline BOOL DifParser::Is1_0( const sal_Unicode* pRef )
{
    return  (   pRef[ 0 ] == pKey1_0[0] &&
                pRef[ 1 ] == pKey1_0[1] &&
                pRef[ 2 ] == pKey1_0[2] &&
                pRef[ 3 ] == pKey1_0[3] );
}

inline BOOL DifParser::IsV( const sal_Unicode* pRef )
{
    return  (   pRef[ 0 ] == pKeyV[0] &&
                pRef[ 1 ] == pKeyV[1]   );
}

inline BOOL DifParser::IsNumber( const sal_Unicode cChar )
{
    return ( cChar >= '0' && cChar <= '9' );
}

inline BOOL DifParser::IsNumberEnding( const sal_Unicode cChar )
{
    return ( cChar == 0x00 );
}

inline BOOL DifParser::IsPlain( void ) const
{
    return bPlain;
}

class DifAttrCache;
class ScPatternAttr;

class DifColumn : private List
{
private:
    friend class DifAttrCache;
    struct ENTRY
    {
        UINT32          nNumFormat;

        SCROW           nStart;
        SCROW           nEnd;
    };

    ENTRY*              pAkt;

    inline              DifColumn( void );
                        ~DifColumn();
    void                SetLogical( SCROW nRow );
    void                SetNumFormat( SCROW nRow, const UINT32 nNumFormat );
    void                NewEntry( const SCROW nPos, const UINT32 nNumFormat );
    void                Apply( ScDocument&, const SCCOL nCol, const SCTAB nTab, const ScPatternAttr& );
    void                Apply( ScDocument &rDoc, const SCCOL nCol, const SCTAB nTab );
public:     // geht niemanden etwas an...
};

inline DifColumn::DifColumn( void )
{
    pAkt = NULL;
}

class DifAttrCache
{
private:
    DifColumn**         ppCols;
    BOOL                bPlain;
public:
                        DifAttrCache( const BOOL bPlain );
                        ~DifAttrCache();
    inline void         SetLogical( const SCCOL nCol, const SCROW nRow );
    void                SetNumFormat( const SCCOL nCol, const SCROW nRow, const UINT32 nNumFormat );
    void                Apply( ScDocument&, SCTAB nTab );
};

inline void DifAttrCache::SetLogical( const SCCOL nCol, const SCROW nRow )
{
    DBG_ASSERT( ValidCol(nCol), "-DifAttrCache::SetLogical(): Col zu gross!" );
    DBG_ASSERT( bPlain, "*DifAttrCache::SetLogical(): muss Plain sein!" );

    if( !ppCols[ nCol ] )
        ppCols[ nCol ] = new DifColumn;
    ppCols[ nCol ]->SetLogical( nRow );
}

#endif

<|endoftext|>


<commit_before>/*
   Copyright (c) 2010, The Mineserver Project
   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 the name of the The Mineserver Project nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 "plugin.h"
#include "blocks/basic.h"
#include "blocks/falling.h"
#include "blocks/torch.h"
#include "blocks/plant.h"
#include "blocks/snow.h"
#include "blocks/liquid.h"
#include "blocks/fire.h"
#include "blocks/stair.h"
#include "blocks/door.h"

Plugin &Plugin::get()
{
  static Plugin instance;
  return instance;
}

void Plugin::init()
{
   // Set default behaviours
   Callback call;
   /* FIXME: must remember to delete any memory we create here upon server stop */

   BlockBasic* basicblock = new BlockBasic();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   setBlockCallback(BLOCK_STONE, call);
   setBlockCallback(BLOCK_GRASS, call);
   setBlockCallback(BLOCK_DIRT, call);
   setBlockCallback(BLOCK_COBBLESTONE, call);
   setBlockCallback(BLOCK_WOOD, call);
   setBlockCallback(BLOCK_LOG, call);
   setBlockCallback(BLOCK_SOIL, call);
   /* cloth */
   setBlockCallback(BLOCK_RED_CLOTH, call);
   setBlockCallback(BLOCK_ORANGE_CLOTH, call);
   setBlockCallback(BLOCK_YELLOW_CLOTH, call);
   setBlockCallback(BLOCK_LIME_CLOTH, call);
   setBlockCallback(BLOCK_GREEN_CLOTH, call);
   setBlockCallback(BLOCK_AQUA_GREEN_CLOTH, call);
   setBlockCallback(BLOCK_CYAN_CLOTH, call);
   setBlockCallback(BLOCK_BLUE_CLOTH, call);
   setBlockCallback(BLOCK_PURPLE_CLOTH, call);
   setBlockCallback(BLOCK_INDIGO_CLOTH, call);
   setBlockCallback(BLOCK_VIOLET_CLOTH, call);
   setBlockCallback(BLOCK_MAGENTA_CLOTH, call);
   setBlockCallback(BLOCK_PINK_CLOTH, call);
   setBlockCallback(BLOCK_BLACK_CLOTH, call);
   setBlockCallback(BLOCK_GRAY_CLOTH, call);
   setBlockCallback(BLOCK_WHITE_CLOTH, call);
   /* metals */
   setBlockCallback(BLOCK_GOLD_BLOCK, call);
   setBlockCallback(BLOCK_IRON_BLOCK, call);

   setBlockCallback(BLOCK_DOUBLE_STEP, call);
   setBlockCallback(BLOCK_STEP, call);
   setBlockCallback(BLOCK_BRICK, call);
   setBlockCallback(BLOCK_BOOKSHELF, call);
   setBlockCallback(BLOCK_MOSSY_COBBLESTONE, call);
   setBlockCallback(BLOCK_OBSIDIAN, call);
   setBlockCallback(BLOCK_MOB_SPAWNER, call);
   setBlockCallback(BLOCK_DIAMOND_BLOCK, call);
   setBlockCallback(BLOCK_PUMPKIN, call);
   setBlockCallback(BLOCK_SIGN_POST, call);
   setBlockCallback(BLOCK_CLAY, call);
   setBlockCallback(BLOCK_NETHERSTONE, call);
   setBlockCallback(BLOCK_LIGHTSTONE, call);
   setBlockCallback(BLOCK_JACK_O_LANTERN, call);
   setBlockCallback(BLOCK_JUKEBOX, call);
   setBlockCallback(BLOCK_MINECART_TRACKS, call);

   /* Falling blocks (sand, etc) */
   call.reset();
   BlockFalling* fallingblock = new BlockFalling();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockFalling, &BlockFalling::onPlace>(fallingblock));
   call.add("onNeighbourBroken", Function::from_method<BlockFalling, &BlockFalling::onNeighbourBroken>(fallingblock));
   setBlockCallback(BLOCK_SAND, call);
   setBlockCallback(BLOCK_SLOW_SAND, call);
   setBlockCallback(BLOCK_GRAVEL, call);

   /* Torches */
   call.reset();
   BlockTorch* torchblock = new BlockTorch();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   call.add("onNeighbourBroken", Function::from_method<BlockTorch, &BlockTorch::onNeighbourBroken>(torchblock));
   call.add("onReplace", Function::from_method<BlockBasic, &BlockBasic::onReplace>(basicblock));
   setBlockCallback(BLOCK_TORCH, call);
   setBlockCallback(BLOCK_REDSTONE_TORCH_OFF, call);
   setBlockCallback(BLOCK_REDSTONE_TORCH_ON, call);

   /* Plants */
   call.reset();
   BlockPlant* plantblock = new BlockPlant();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   call.add("onNeighbourBroken", Function::from_method<BlockPlant, &BlockPlant::onNeighbourBroken>(plantblock));
   call.add("onReplace", Function::from_method<BlockBasic, &BlockBasic::onReplace>(basicblock));
   setBlockCallback(BLOCK_YELLOW_FLOWER, call);
   setBlockCallback(BLOCK_RED_ROSE, call);
   setBlockCallback(BLOCK_BROWN_MUSHROOM, call);
   setBlockCallback(BLOCK_RED_MUSHROOM, call);
   setBlockCallback(BLOCK_CROPS, call);
   setBlockCallback(BLOCK_CACTUS, call);
   setBlockCallback(BLOCK_REED, call);
   setBlockCallback(BLOCK_SAPLING, call);

   /* Snow */
   call.reset();
   BlockSnow* snowblock = new BlockSnow();
   call.add("onNeighbourBroken", Function::from_method<BlockSnow, &BlockSnow::onNeighbourBroken>(snowblock));
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   setBlockCallback(BLOCK_SNOW, call);

   /* Fire and Water */
   call.reset();
   BlockLiquid* liquidblock = new BlockLiquid();
   call.add("onPlace", Function::from_method<BlockLiquid, &BlockLiquid::onPlace>(liquidblock));
   call.add("onNeighbourBroken", Function::from_method<BlockLiquid, &BlockLiquid::onNeighbourBroken>(liquidblock));
   call.add("onReplace", Function::from_method<BlockLiquid, &BlockLiquid::onReplace>(liquidblock));
   setBlockCallback(BLOCK_WATER, call);
   setBlockCallback(BLOCK_STATIONARY_WATER, call);
   setBlockCallback(BLOCK_LAVA, call);
   setBlockCallback(BLOCK_STATIONARY_LAVA, call);

   /* Fire */
   call.reset();
   BlockFire* fireblock = new BlockFire();
   call.add("onPlace", Function::from_method<BlockFire, &BlockFire::onPlace>(fireblock));
   setBlockCallback(BLOCK_FIRE, call);

   /* Stairs */
   call.reset();
   BlockStair* stairblock = new BlockStair();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockStair, &BlockStair::onPlace>(stairblock));
   call.add("onNeighbourBroken", Function::from_method<BlockStair, &BlockStair::onNeighbourBroken>(stairblock));
   setBlockCallback(BLOCK_WOODEN_STAIRS, call);
   setBlockCallback(BLOCK_COBBLESTONE_STAIRS, call);

   /* TNT */
   call.reset();
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   setBlockCallback(BLOCK_TNT, call);

   /* Containers */
   call.reset();
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   setBlockCallback(BLOCK_CHEST, call);
   setBlockCallback(BLOCK_WORKBENCH, call);
   setBlockCallback(BLOCK_FURNACE, call);
  /* TODO: Needs this? BLOCK_BURNING_FURNACE */

   /* Doors */
   call.reset();
   BlockDoor* doorblock = new BlockDoor();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockDoor, &BlockDoor::onPlace>(doorblock));
   setBlockCallback(BLOCK_WOODEN_DOOR, call);
   setBlockCallback(BLOCK_IRON_DOOR, call);

  /* TODO: Unimplemented */
  /* BLOCK_LEAVES */
  /* BLOCK_SPONGE */
  /* BLOCK_REDSTONE_WIRE */
  /* BLOCK_PORTAL */
  /* BLOCK_GOLD_ORE, BLOCK_IRON_ORE, BLOCK_COAL_ORE, BLOCK_DIAMOND_ORE, BLOCK_GLOWING_REDSTONE_ORE, BLOCK_REDSTONE_ORE */
  /* BLOCK_WALL_SIGN */
  /* BLOCK_LADDER */
  /* BLOCK_LEVER, BLOCK_STONE_BUTTON */
  /* BLOCK_WOODEN_PRESSURE_PLATE, BLOCK_STONE_PRESSURE_PLATE */
  /* BLOCK_FENCE */
  /* BLOCK_ICE */
  /* BLOCK_SNOW_BLOCK */
}

void Plugin::setBlockCallback(const int type, Callback call)
{
   removeBlockCallback(type);
   blockevents.insert(std::pair<int, Callback>(type, call));
}

Callback Plugin::getBlockCallback(const int type)
{
   for (Callbacks::iterator iter = blockevents.begin(); iter != blockevents.end(); iter++)
   {
      if ((*iter).first == type)
      {
         return (*iter).second;
      }
   }

   Callback call;
   return call;
}

bool Plugin::removeBlockCallback(const int type)
{
   for (Callbacks::iterator iter = blockevents.begin(); iter != blockevents.end(); ++iter)
   {
      if (iter->first == type)
      {
           delete &iter->first;
           blockevents.erase(iter);
           return true;
      }
   }
   return false;
}
<commit_msg>Added fence block events<commit_after>/*
   Copyright (c) 2010, The Mineserver Project
   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 the name of the The Mineserver Project nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 "plugin.h"
#include "blocks/basic.h"
#include "blocks/falling.h"
#include "blocks/torch.h"
#include "blocks/plant.h"
#include "blocks/snow.h"
#include "blocks/liquid.h"
#include "blocks/fire.h"
#include "blocks/stair.h"
#include "blocks/door.h"

Plugin &Plugin::get()
{
  static Plugin instance;
  return instance;
}

void Plugin::init()
{
   // Set default behaviours
   Callback call;
   /* FIXME: must remember to delete any memory we create here upon server stop */

   BlockBasic* basicblock = new BlockBasic();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   setBlockCallback(BLOCK_STONE, call);
   setBlockCallback(BLOCK_GRASS, call);
   setBlockCallback(BLOCK_DIRT, call);
   setBlockCallback(BLOCK_COBBLESTONE, call);
   setBlockCallback(BLOCK_WOOD, call);
   setBlockCallback(BLOCK_LOG, call);
   setBlockCallback(BLOCK_SOIL, call);
   /* cloth */
   setBlockCallback(BLOCK_RED_CLOTH, call);
   setBlockCallback(BLOCK_ORANGE_CLOTH, call);
   setBlockCallback(BLOCK_YELLOW_CLOTH, call);
   setBlockCallback(BLOCK_LIME_CLOTH, call);
   setBlockCallback(BLOCK_GREEN_CLOTH, call);
   setBlockCallback(BLOCK_AQUA_GREEN_CLOTH, call);
   setBlockCallback(BLOCK_CYAN_CLOTH, call);
   setBlockCallback(BLOCK_BLUE_CLOTH, call);
   setBlockCallback(BLOCK_PURPLE_CLOTH, call);
   setBlockCallback(BLOCK_INDIGO_CLOTH, call);
   setBlockCallback(BLOCK_VIOLET_CLOTH, call);
   setBlockCallback(BLOCK_MAGENTA_CLOTH, call);
   setBlockCallback(BLOCK_PINK_CLOTH, call);
   setBlockCallback(BLOCK_BLACK_CLOTH, call);
   setBlockCallback(BLOCK_GRAY_CLOTH, call);
   setBlockCallback(BLOCK_WHITE_CLOTH, call);
   /* metals */
   setBlockCallback(BLOCK_GOLD_BLOCK, call);
   setBlockCallback(BLOCK_IRON_BLOCK, call);

   setBlockCallback(BLOCK_DOUBLE_STEP, call);
   setBlockCallback(BLOCK_STEP, call);
   setBlockCallback(BLOCK_BRICK, call);
   setBlockCallback(BLOCK_BOOKSHELF, call);
   setBlockCallback(BLOCK_MOSSY_COBBLESTONE, call);
   setBlockCallback(BLOCK_OBSIDIAN, call);
   setBlockCallback(BLOCK_MOB_SPAWNER, call);
   setBlockCallback(BLOCK_DIAMOND_BLOCK, call);
   setBlockCallback(BLOCK_PUMPKIN, call);
   setBlockCallback(BLOCK_SIGN_POST, call);
   setBlockCallback(BLOCK_CLAY, call);
   setBlockCallback(BLOCK_NETHERSTONE, call);
   setBlockCallback(BLOCK_LIGHTSTONE, call);
   setBlockCallback(BLOCK_JACK_O_LANTERN, call);
   setBlockCallback(BLOCK_JUKEBOX, call);
   setBlockCallback(BLOCK_MINECART_TRACKS, call);
   setBlockCallback(BLOCK_FENCE, call);

   /* Falling blocks (sand, etc) */
   call.reset();
   BlockFalling* fallingblock = new BlockFalling();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockFalling, &BlockFalling::onPlace>(fallingblock));
   call.add("onNeighbourBroken", Function::from_method<BlockFalling, &BlockFalling::onNeighbourBroken>(fallingblock));
   setBlockCallback(BLOCK_SAND, call);
   setBlockCallback(BLOCK_SLOW_SAND, call);
   setBlockCallback(BLOCK_GRAVEL, call);

   /* Torches */
   call.reset();
   BlockTorch* torchblock = new BlockTorch();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   call.add("onNeighbourBroken", Function::from_method<BlockTorch, &BlockTorch::onNeighbourBroken>(torchblock));
   call.add("onReplace", Function::from_method<BlockBasic, &BlockBasic::onReplace>(basicblock));
   setBlockCallback(BLOCK_TORCH, call);
   setBlockCallback(BLOCK_REDSTONE_TORCH_OFF, call);
   setBlockCallback(BLOCK_REDSTONE_TORCH_ON, call);

   /* Plants */
   call.reset();
   BlockPlant* plantblock = new BlockPlant();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   call.add("onNeighbourBroken", Function::from_method<BlockPlant, &BlockPlant::onNeighbourBroken>(plantblock));
   call.add("onReplace", Function::from_method<BlockBasic, &BlockBasic::onReplace>(basicblock));
   setBlockCallback(BLOCK_YELLOW_FLOWER, call);
   setBlockCallback(BLOCK_RED_ROSE, call);
   setBlockCallback(BLOCK_BROWN_MUSHROOM, call);
   setBlockCallback(BLOCK_RED_MUSHROOM, call);
   setBlockCallback(BLOCK_CROPS, call);
   setBlockCallback(BLOCK_CACTUS, call);
   setBlockCallback(BLOCK_REED, call);
   setBlockCallback(BLOCK_SAPLING, call);

   /* Snow */
   call.reset();
   BlockSnow* snowblock = new BlockSnow();
   call.add("onNeighbourBroken", Function::from_method<BlockSnow, &BlockSnow::onNeighbourBroken>(snowblock));
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   setBlockCallback(BLOCK_SNOW, call);

   /* Fire and Water */
   call.reset();
   BlockLiquid* liquidblock = new BlockLiquid();
   call.add("onPlace", Function::from_method<BlockLiquid, &BlockLiquid::onPlace>(liquidblock));
   call.add("onNeighbourBroken", Function::from_method<BlockLiquid, &BlockLiquid::onNeighbourBroken>(liquidblock));
   call.add("onReplace", Function::from_method<BlockLiquid, &BlockLiquid::onReplace>(liquidblock));
   setBlockCallback(BLOCK_WATER, call);
   setBlockCallback(BLOCK_STATIONARY_WATER, call);
   setBlockCallback(BLOCK_LAVA, call);
   setBlockCallback(BLOCK_STATIONARY_LAVA, call);

   /* Fire */
   call.reset();
   BlockFire* fireblock = new BlockFire();
   call.add("onPlace", Function::from_method<BlockFire, &BlockFire::onPlace>(fireblock));
   setBlockCallback(BLOCK_FIRE, call);

   /* Stairs */
   call.reset();
   BlockStair* stairblock = new BlockStair();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockStair, &BlockStair::onPlace>(stairblock));
   call.add("onNeighbourBroken", Function::from_method<BlockStair, &BlockStair::onNeighbourBroken>(stairblock));
   setBlockCallback(BLOCK_WOODEN_STAIRS, call);
   setBlockCallback(BLOCK_COBBLESTONE_STAIRS, call);

   /* TNT */
   call.reset();
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   setBlockCallback(BLOCK_TNT, call);

   /* Containers */
   call.reset();
   call.add("onPlace", Function::from_method<BlockBasic, &BlockBasic::onPlace>(basicblock));
   setBlockCallback(BLOCK_CHEST, call);
   setBlockCallback(BLOCK_WORKBENCH, call);
   setBlockCallback(BLOCK_FURNACE, call);
  /* TODO: Needs this? BLOCK_BURNING_FURNACE */

   /* Doors */
   call.reset();
   BlockDoor* doorblock = new BlockDoor();
   call.add("onBroken", Function::from_method<BlockBasic, &BlockBasic::onBroken>(basicblock));
   call.add("onPlace", Function::from_method<BlockDoor, &BlockDoor::onPlace>(doorblock));
   setBlockCallback(BLOCK_WOODEN_DOOR, call);
   setBlockCallback(BLOCK_IRON_DOOR, call);

  /* TODO: Unimplemented */
  /* BLOCK_LEAVES */
  /* BLOCK_SPONGE */
  /* BLOCK_REDSTONE_WIRE */
  /* BLOCK_PORTAL */
  /* BLOCK_GOLD_ORE, BLOCK_IRON_ORE, BLOCK_COAL_ORE, BLOCK_DIAMOND_ORE, BLOCK_GLOWING_REDSTONE_ORE, BLOCK_REDSTONE_ORE */
  /* BLOCK_WALL_SIGN */
  /* BLOCK_LADDER */
  /* BLOCK_LEVER, BLOCK_STONE_BUTTON */
  /* BLOCK_WOODEN_PRESSURE_PLATE, BLOCK_STONE_PRESSURE_PLATE */
  /* BLOCK_ICE */
  /* BLOCK_SNOW_BLOCK */
}

void Plugin::setBlockCallback(const int type, Callback call)
{
   removeBlockCallback(type);
   blockevents.insert(std::pair<int, Callback>(type, call));
}

Callback Plugin::getBlockCallback(const int type)
{
   for (Callbacks::iterator iter = blockevents.begin(); iter != blockevents.end(); iter++)
   {
      if ((*iter).first == type)
      {
         return (*iter).second;
      }
   }

   Callback call;
   return call;
}

bool Plugin::removeBlockCallback(const int type)
{
   for (Callbacks::iterator iter = blockevents.begin(); iter != blockevents.end(); ++iter)
   {
      if (iter->first == type)
      {
           delete &iter->first;
           blockevents.erase(iter);
           return true;
      }
   }
   return false;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: sortdlg.hxx,v $
 *
 *  $Revision: 1.1.1.1 $
 *
 *  last change: $Author: hr $ $Date: 2000-09-18 16:45:01 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SC_SORTDLG_HXX
#define SC_SORTDLG_HXX

#ifndef _SFXTABDLG_HXX //autogen
#include <sfx2/tabdlg.hxx>
#endif

#ifndef _SFX_HXX
#endif

//==================================================================

class ScSortDlg : public SfxTabDialog
{
public:
                ScSortDlg( Window*           pParent,
                           const SfxItemSet* pArgSet );
                ~ScSortDlg();

    void    SetHeaders( BOOL bHeaders );
    void    SetByRows ( BOOL bByRows );
    BOOL    GetHeaders() const;
    BOOL    GetByRows () const;

private:
    BOOL    bIsHeaders;
    BOOL    bIsByRows;
};

inline void ScSortDlg::SetHeaders( BOOL bHeaders )  { bIsHeaders = bHeaders; }
inline void ScSortDlg::SetByRows ( BOOL bByRows  )  { bIsByRows = bByRows; }
inline BOOL ScSortDlg::GetHeaders() const           { return bIsHeaders; }
inline BOOL ScSortDlg::GetByRows () const           { return bIsByRows; }

#endif // SC_SORTDLG_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.1.1.1.942); FILE MERGED 2005/09/05 15:05:51 rt 1.1.1.1.942.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sortdlg.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 21:51:47 $
 *
 *  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 SC_SORTDLG_HXX
#define SC_SORTDLG_HXX

#ifndef _SFXTABDLG_HXX //autogen
#include <sfx2/tabdlg.hxx>
#endif

#ifndef _SFX_HXX
#endif

//==================================================================

class ScSortDlg : public SfxTabDialog
{
public:
                ScSortDlg( Window*           pParent,
                           const SfxItemSet* pArgSet );
                ~ScSortDlg();

    void    SetHeaders( BOOL bHeaders );
    void    SetByRows ( BOOL bByRows );
    BOOL    GetHeaders() const;
    BOOL    GetByRows () const;

private:
    BOOL    bIsHeaders;
    BOOL    bIsByRows;
};

inline void ScSortDlg::SetHeaders( BOOL bHeaders )  { bIsHeaders = bHeaders; }
inline void ScSortDlg::SetByRows ( BOOL bByRows  )  { bIsByRows = bByRows; }
inline BOOL ScSortDlg::GetHeaders() const           { return bIsHeaders; }
inline BOOL ScSortDlg::GetByRows () const           { return bIsByRows; }

#endif // SC_SORTDLG_HXX

<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "miniport.h"  // NOLINT: include directory

#include <ndis.h>

#include "adapter.h"  // NOLINT: include directory
#include "oid.h"      // NOLINT: include directory
#include "trace.h"    // NOLINT: include directory

#include "miniport.tmh"  // NOLINT: trace message header

NDIS_HANDLE DriverHandle = nullptr;

// Driver Entry Point. Called by kernel to register driver object.
// Arguments:
//   DriverObject - Pointer to driver object created by system.
//   RegistryPath - Pointer to the Unicode name of the registry path.
//
// Returns:
//   NT Status code.
NDIS_STATUS
DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
            _In_ PUNICODE_STRING RegistryPath) {
  PAGED_CODE();

  NDIS_MINIPORT_DRIVER_CHARACTERISTICS driver_chars;

  WPP_INIT_TRACING(DriverObject, RegistryPath);

  DEBUGP(GVNIC_VERBOSE, "---> DriverEntry - Version %u.%u",
         MAJOR_DRIVER_VERSION, MINOR_DRIVER_VERSION);

  NdisZeroMemory(&driver_chars, sizeof(driver_chars));

#if NDIS_SUPPORT_NDIS620
  driver_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
  driver_chars.Header.Size =
      NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
  driver_chars.Header.Revision =
      NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
#elif NDIS_SUPPORT_NDIS6
  driver_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
  driver_chars.Header.Size =
      NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
  driver_chars.Header.Revision =
      NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
#endif  // NDIS MINIPORT VERSION

  driver_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
  driver_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;

  driver_chars.MajorDriverVersion =
      static_cast<UINT8>(MAJOR_DRIVER_VERSION & 0xFF);
  driver_chars.MinorDriverVersion =
      static_cast<UINT8>(MINOR_DRIVER_VERSION & 0xFF);

  driver_chars.Flags = 0;

  // Optional Handlers
  driver_chars.SetOptionsHandler = GvnicSetOptions;
  // Not required for virtual driver.
  driver_chars.CheckForHangHandlerEx = NULL;
  driver_chars.ResetHandlerEx = NULL;

  // Required Handlers
  driver_chars.InitializeHandlerEx = GvnicInitialize;
  driver_chars.HaltHandlerEx = GvnicHalt;
  driver_chars.UnloadHandler = DriverUnload;
  driver_chars.PauseHandler = GvnicPause;
  driver_chars.RestartHandler = GvnicRestart;
  driver_chars.OidRequestHandler = GvnicOidRequest;
  driver_chars.SendNetBufferListsHandler = GvnicSendNetBufferLists;
  driver_chars.ReturnNetBufferListsHandler = GvnicReturnNetBufferLists;
  driver_chars.CancelSendHandler = GvnicCancelSendNetBufferLists;
  driver_chars.DevicePnPEventNotifyHandler = GvnicDevicePnPEvent;
  driver_chars.ShutdownHandlerEx = GvnicAdapterShutdown;
  driver_chars.CancelOidRequestHandler = GvnicOidCancelRequest;

#if NDIS_SUPPORT_NDIS61
  driver_chars.DirectOidRequestHandler = NULL;
  driver_chars.CancelDirectOidRequestHandler = NULL;
#endif  // NDIS_SUPPORT_NDIS61

  NDIS_STATUS status = NdisMRegisterMiniportDriver(
      DriverObject, RegistryPath, NULL, &driver_chars, &DriverHandle);
  if (status != NDIS_STATUS_SUCCESS) {
    DEBUGP(GVNIC_ERROR, "NdisMRegisterMiniportDriver failed: %d\n", status);
    DriverUnload(DriverObject);
  }

  DEBUGP(GVNIC_VERBOSE, "<--- DriverEntry status 0x%08x\n", status);
  return status;
}

// Unload Driver. Free all allocated resources, etc.
//
// Arguments:
//   DriverObject - pointer to a driver object.
_Use_decl_annotations_ VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject) {
  PAGED_CODE();
  DEBUGP(GVNIC_VERBOSE, "---> DriverUnload");

  if (DriverHandle != nullptr) {
    DEBUGP(GVNIC_VERBOSE, "Calling NdisMDeregisterMiniportDriver...");
    NdisMDeregisterMiniportDriver(DriverHandle);
  }

  DEBUGP(GVNIC_VERBOSE, "<--- DriverUnload");
  WPP_CLEANUP(DriverObject);
}

// The entry point for the caller's MiniportSetOptions to register optional
// services.
//
// Arguments:
//   miniport_driver_handle - A handle that identifies this miniport driver.
//   miniport_driver_context - The handle identifies the driver context area.
//
// Returns:
//   NT Status code.
_Use_decl_annotations_ NDIS_STATUS
GvnicSetOptions(_In_ NDIS_HANDLE miniport_driver_handle,
                _In_ NDIS_HANDLE miniport_driver_context) {
  PAGED_CODE();
  UNREFERENCED_PARAMETER(miniport_driver_context);
  DEBUGP(GVNIC_VERBOSE, "---> GvnicSetOptions\n");

  NDIS_MINIPORT_PNP_CHARACTERISTICS pnp_chars;
  pnp_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_PNP_CHARACTERISTICS;
  pnp_chars.Header.Revision = NDIS_MINIPORT_PNP_CHARACTERISTICS_REVISION_1;
  pnp_chars.Header.Size = NDIS_SIZEOF_MINIPORT_PNP_CHARACTERISTICS_REVISION_1;
  pnp_chars.MiniportAddDeviceHandler = GvnicAddDevice;
  pnp_chars.MiniportRemoveDeviceHandler = GvnicRemoveDevice;
  pnp_chars.MiniportStartDeviceHandler = GvnicStartDevice;
  pnp_chars.MiniportFilterResourceRequirementsHandler = GvnicFilterResource;

  NDIS_STATUS status = NdisSetOptionalHandlers(
      miniport_driver_handle, (PNDIS_DRIVER_OPTIONAL_HANDLERS)&pnp_chars);

  DEBUGP(GVNIC_INFO, "<--- GvnicSetOptions status = 0x%08x\n", status);
  return status;
}
<commit_msg>Internal change<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "miniport.h"  // NOLINT: include directory

#include <ndis.h>

#include "adapter.h"  // NOLINT: include directory
#include "oid.h"      // NOLINT: include directory
#include "trace.h"    // NOLINT: include directory

#include "miniport.tmh"  // NOLINT: trace message header

NDIS_HANDLE DriverHandle = nullptr;

// Driver Entry Point. Called by kernel to register driver object.
// Arguments:
//   DriverObject - Pointer to driver object created by system.
//   RegistryPath - Pointer to the Unicode name of the registry path.
//
// Returns:
//   NT Status code.
NDIS_STATUS
DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
            _In_ PUNICODE_STRING RegistryPath) {
  PAGED_CODE();

  NDIS_MINIPORT_DRIVER_CHARACTERISTICS driver_chars;

  WPP_INIT_TRACING(DriverObject, RegistryPath);

  DEBUGP(GVNIC_VERBOSE,
         "*** Start of gVNIC verbose log. To disable this, clear the 0x7 bit.");
  DEBUGP(GVNIC_INFO,
         "*** Start of gVNIC info log. To disable this, clear the 0x4 bit.");
  DEBUGP(GVNIC_WARNING,
         "*** Start of gVNIC warning log. To disable this, clear the 0x2 bit.");
  DEBUGP(GVNIC_ERROR,
         "*** Start of gVNIC error log. To disable this, clear the 0x1 bit.");

  DEBUGP(GVNIC_VERBOSE, "---> DriverEntry - Version %u.%u",
         MAJOR_DRIVER_VERSION, MINOR_DRIVER_VERSION);

  NdisZeroMemory(&driver_chars, sizeof(driver_chars));

#if NDIS_SUPPORT_NDIS620
  driver_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
  driver_chars.Header.Size =
      NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
  driver_chars.Header.Revision =
      NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
#elif NDIS_SUPPORT_NDIS6
  driver_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
  driver_chars.Header.Size =
      NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
  driver_chars.Header.Revision =
      NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
#endif  // NDIS MINIPORT VERSION

  driver_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
  driver_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;

  driver_chars.MajorDriverVersion =
      static_cast<UINT8>(MAJOR_DRIVER_VERSION & 0xFF);
  driver_chars.MinorDriverVersion =
      static_cast<UINT8>(MINOR_DRIVER_VERSION & 0xFF);

  driver_chars.Flags = 0;

  // Optional Handlers
  driver_chars.SetOptionsHandler = GvnicSetOptions;
  // Not required for virtual driver.
  driver_chars.CheckForHangHandlerEx = NULL;
  driver_chars.ResetHandlerEx = NULL;

  // Required Handlers
  driver_chars.InitializeHandlerEx = GvnicInitialize;
  driver_chars.HaltHandlerEx = GvnicHalt;
  driver_chars.UnloadHandler = DriverUnload;
  driver_chars.PauseHandler = GvnicPause;
  driver_chars.RestartHandler = GvnicRestart;
  driver_chars.OidRequestHandler = GvnicOidRequest;
  driver_chars.SendNetBufferListsHandler = GvnicSendNetBufferLists;
  driver_chars.ReturnNetBufferListsHandler = GvnicReturnNetBufferLists;
  driver_chars.CancelSendHandler = GvnicCancelSendNetBufferLists;
  driver_chars.DevicePnPEventNotifyHandler = GvnicDevicePnPEvent;
  driver_chars.ShutdownHandlerEx = GvnicAdapterShutdown;
  driver_chars.CancelOidRequestHandler = GvnicOidCancelRequest;

#if NDIS_SUPPORT_NDIS61
  driver_chars.DirectOidRequestHandler = NULL;
  driver_chars.CancelDirectOidRequestHandler = NULL;
#endif  // NDIS_SUPPORT_NDIS61

  NDIS_STATUS status = NdisMRegisterMiniportDriver(
      DriverObject, RegistryPath, NULL, &driver_chars, &DriverHandle);
  if (status != NDIS_STATUS_SUCCESS) {
    DEBUGP(GVNIC_ERROR, "NdisMRegisterMiniportDriver failed: %d\n", status);
    DriverUnload(DriverObject);
  }

  DEBUGP(GVNIC_VERBOSE, "<--- DriverEntry status 0x%08x\n", status);
  return status;
}

// Unload Driver. Free all allocated resources, etc.
//
// Arguments:
//   DriverObject - pointer to a driver object.
_Use_decl_annotations_ VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject) {
  PAGED_CODE();
  DEBUGP(GVNIC_VERBOSE, "---> DriverUnload");

  if (DriverHandle != nullptr) {
    DEBUGP(GVNIC_VERBOSE, "Calling NdisMDeregisterMiniportDriver...");
    NdisMDeregisterMiniportDriver(DriverHandle);
  }

  DEBUGP(GVNIC_VERBOSE, "<--- DriverUnload");
  WPP_CLEANUP(DriverObject);
}

// The entry point for the caller's MiniportSetOptions to register optional
// services.
//
// Arguments:
//   miniport_driver_handle - A handle that identifies this miniport driver.
//   miniport_driver_context - The handle identifies the driver context area.
//
// Returns:
//   NT Status code.
_Use_decl_annotations_ NDIS_STATUS
GvnicSetOptions(_In_ NDIS_HANDLE miniport_driver_handle,
                _In_ NDIS_HANDLE miniport_driver_context) {
  PAGED_CODE();
  UNREFERENCED_PARAMETER(miniport_driver_context);
  DEBUGP(GVNIC_VERBOSE, "---> GvnicSetOptions\n");

  NDIS_MINIPORT_PNP_CHARACTERISTICS pnp_chars;
  pnp_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_PNP_CHARACTERISTICS;
  pnp_chars.Header.Revision = NDIS_MINIPORT_PNP_CHARACTERISTICS_REVISION_1;
  pnp_chars.Header.Size = NDIS_SIZEOF_MINIPORT_PNP_CHARACTERISTICS_REVISION_1;
  pnp_chars.MiniportAddDeviceHandler = GvnicAddDevice;
  pnp_chars.MiniportRemoveDeviceHandler = GvnicRemoveDevice;
  pnp_chars.MiniportStartDeviceHandler = GvnicStartDevice;
  pnp_chars.MiniportFilterResourceRequirementsHandler = GvnicFilterResource;

  NDIS_STATUS status = NdisSetOptionalHandlers(
      miniport_driver_handle, (PNDIS_DRIVER_OPTIONAL_HANDLERS)&pnp_chars);

  DEBUGP(GVNIC_INFO, "<--- GvnicSetOptions status = 0x%08x\n", status);
  return status;
}
<|endoftext|>