<commit_before>/*
	This file is part of cpp-ethereum.

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

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file whisperTopic.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */
#include <functional>

#include <boost/test/unit_test.hpp>

#include <libp2p/Host.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;

BOOST_AUTO_TEST_SUITE(whisper)

BOOST_AUTO_TEST_CASE(topic)
{
	cnote << "Testing Whisper...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	Host host1("Test", NetworkPreferences("127.0.0.1", 30303, false));
	host1.setIdealPeerCount(1);
	auto whost1 = host1.registerCapability(new WhisperHost());
	host1.start();

	bool host1Ready = false;
	unsigned result = 0;
	std::thread listener([&]()
	{
		setThreadName("other");

		/// Only interested in odd packets
		auto w = whost1->installWatch(BuildTopicMask("odd"));
		host1Ready = true;
		set<unsigned> received;
		for (int iterout = 0, last = 0; iterout < 200 && last < 81; ++iterout)
		{
			for (auto i: whost1->checkWatch(w))
			{
				Message msg = whost1->envelope(i).open(whost1->fullTopic(w));
				last = RLP(msg.payload()).toInt<unsigned>();
				if (received.count(last))
					continue;
				received.insert(last);
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
				result += last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}

	});

	Host host2("Test", NetworkPreferences("127.0.0.1", 30300, false));
	host1.setIdealPeerCount(1);
	auto whost2 = host2.registerCapability(new WhisperHost());
	host2.start();

	while (!host1.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(5));
	host2.addNode(host1.id(), bi::address::from_string("127.0.0.1"), 30303, 30303);

	// wait for nodes to connect
	this_thread::sleep_for(chrono::milliseconds(1000));

	while (!host1Ready)
		this_thread::sleep_for(chrono::milliseconds(10));

	KeyPair us = KeyPair::create();
	for (int i = 0; i < 10; ++i)
	{
		whost2->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	listener.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
}

BOOST_AUTO_TEST_CASE(forwarding)
{
	cnote << "Testing Whisper forwarding...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	// Host must be configured not to share peers.
	Host host1("Listner", NetworkPreferences("127.0.0.1", 30303, false));
	host1.setIdealPeerCount(0);
	auto whost1 = host1.registerCapability(new WhisperHost());
	host1.start();
	while (!host1.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(2));

	unsigned result = 0;
	bool done = false;

	bool startedListener = false;
	std::thread listener([&]()
	{
		setThreadName("listener");

		startedListener = true;

		/// Only interested in odd packets
		auto w = whost1->installWatch(BuildTopicMask("test"));

		for (int i = 0; i < 200 && !result; ++i)
		{
			for (auto i: whost1->checkWatch(w))
			{
				Message msg = whost1->envelope(i).open(whost1->fullTopic(w));
				unsigned last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
				result = last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	// Host must be configured not to share peers.
	Host host2("Forwarder", NetworkPreferences("127.0.0.1", 30305, false));
	host2.setIdealPeerCount(1);
	auto whost2 = host2.registerCapability(new WhisperHost());
	host2.start();
	while (!host2.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(2));

	Public fwderid;
	bool startedForwarder = false;
	std::thread forwarder([&]()
	{
		setThreadName("forwarder");

		while (!startedListener)
			this_thread::sleep_for(chrono::milliseconds(50));

		this_thread::sleep_for(chrono::milliseconds(500));
		host2.addNode(host1.id(), bi::address::from_string("127.0.0.1"), 30303, 30303);

		startedForwarder = true;

		/// Only interested in odd packets
		auto w = whost2->installWatch(BuildTopicMask("test"));

		while (!done)
		{
			for (auto i: whost2->checkWatch(w))
			{
				Message msg = whost2->envelope(i).open(whost2->fullTopic(w));
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!startedForwarder)
		this_thread::sleep_for(chrono::milliseconds(50));

	Host ph("Sender", NetworkPreferences("127.0.0.1", 30300, false));
	ph.setIdealPeerCount(1);
	shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
	ph.start();
	ph.addNode(host2.id(), bi::address::from_string("127.0.0.1"), 30305, 30305);
	while (!ph.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(10));

	KeyPair us = KeyPair::create();
	wh->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
	this_thread::sleep_for(chrono::milliseconds(250));

	listener.join();
	done = true;
	forwarder.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1);
}

BOOST_AUTO_TEST_CASE(asyncforwarding)
{
	cnote << "Testing Whisper async forwarding...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 2;

	unsigned result = 0;
	bool done = false;

	// Host must be configured not to share peers.
	Host host1("Forwarder", NetworkPreferences("127.0.0.1", 30305, false));
	host1.setIdealPeerCount(1);
	auto whost1 = host1.registerCapability(new WhisperHost());
	host1.start();
	while (!host1.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(2));

	bool startedForwarder = false;
	std::thread forwarder([&]()
	{
		setThreadName("forwarder");

		this_thread::sleep_for(chrono::milliseconds(500));
//		ph.addNode("127.0.0.1", 30303, 30303);

		startedForwarder = true;

		/// Only interested in odd packets
		auto w = whost1->installWatch(BuildTopicMask("test"));

		while (!done)
		{
			for (auto i: whost1->checkWatch(w))
			{
				Message msg = whost1->envelope(i).open(whost1->fullTopic(w));
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!startedForwarder)
		this_thread::sleep_for(chrono::milliseconds(2));

	{
		Host host2("Sender", NetworkPreferences("127.0.0.1", 30300, false));
		host2.setIdealPeerCount(1);
		shared_ptr<WhisperHost> whost2 = host2.registerCapability(new WhisperHost());
		host2.start();
		while (!host2.haveNetwork())
			this_thread::sleep_for(chrono::milliseconds(2));
		host2.addNode(host1.id(), bi::address::from_string("127.0.0.1"), 30305, 30305);

		while (!host2.peerCount())
			this_thread::sleep_for(chrono::milliseconds(5));

		KeyPair us = KeyPair::create();
		whost2->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	{
		Host ph("Listener", NetworkPreferences("127.0.0.1", 30300, false));
		ph.setIdealPeerCount(1);
		shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
		ph.start();
		while (!ph.haveNetwork())
			this_thread::sleep_for(chrono::milliseconds(2));
		ph.addNode(host1.id(), bi::address::from_string("127.0.0.1"), 30305, 30305);

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		for (int i = 0; i < 200 && !result; ++i)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				unsigned last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
				result = last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	}

	done = true;
	forwarder.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>update whisper test to use fixture for new network code, to allow private addresses and encapsulate host/port information in NodeIPEndpoint.<commit_after>/*
	This file is part of cpp-ethereum.

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

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file whisperTopic.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */
#include <functional>

#include <boost/test/unit_test.hpp>

#include <libp2p/Host.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;

struct P2PFixture
{
	P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true; }
	~P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; }
};

BOOST_FIXTURE_TEST_SUITE(whisper, P2PFixture)

BOOST_AUTO_TEST_CASE(topic)
{
	cnote << "Testing Whisper...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	Host host1("Test", NetworkPreferences("127.0.0.1", 30303, false));
	host1.setIdealPeerCount(1);
	auto whost1 = host1.registerCapability(new WhisperHost());
	host1.start();

	bool host1Ready = false;
	unsigned result = 0;
	std::thread listener([&]()
	{
		setThreadName("other");

		/// Only interested in odd packets
		auto w = whost1->installWatch(BuildTopicMask("odd"));
		host1Ready = true;
		set<unsigned> received;
		for (int iterout = 0, last = 0; iterout < 200 && last < 81; ++iterout)
		{
			for (auto i: whost1->checkWatch(w))
			{
				Message msg = whost1->envelope(i).open(whost1->fullTopic(w));
				last = RLP(msg.payload()).toInt<unsigned>();
				if (received.count(last))
					continue;
				received.insert(last);
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
				result += last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}

	});

	Host host2("Test", NetworkPreferences("127.0.0.1", 30300, false));
	host1.setIdealPeerCount(1);
	auto whost2 = host2.registerCapability(new WhisperHost());
	host2.start();

	while (!host1.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(5));
	host2.addNode(host1.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30303, 30303));

	// wait for nodes to connect
	this_thread::sleep_for(chrono::milliseconds(1000));

	while (!host1Ready)
		this_thread::sleep_for(chrono::milliseconds(10));

	KeyPair us = KeyPair::create();
	for (int i = 0; i < 10; ++i)
	{
		whost2->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	listener.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
}

BOOST_AUTO_TEST_CASE(forwarding)
{
	cnote << "Testing Whisper forwarding...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 0;

	// Host must be configured not to share peers.
	Host host1("Listner", NetworkPreferences("127.0.0.1", 30303, false));
	host1.setIdealPeerCount(0);
	auto whost1 = host1.registerCapability(new WhisperHost());
	host1.start();
	while (!host1.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(2));

	unsigned result = 0;
	bool done = false;

	bool startedListener = false;
	std::thread listener([&]()
	{
		setThreadName("listener");

		startedListener = true;

		/// Only interested in odd packets
		auto w = whost1->installWatch(BuildTopicMask("test"));

		for (int i = 0; i < 200 && !result; ++i)
		{
			for (auto i: whost1->checkWatch(w))
			{
				Message msg = whost1->envelope(i).open(whost1->fullTopic(w));
				unsigned last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
				result = last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	// Host must be configured not to share peers.
	Host host2("Forwarder", NetworkPreferences("127.0.0.1", 30305, false));
	host2.setIdealPeerCount(1);
	auto whost2 = host2.registerCapability(new WhisperHost());
	host2.start();
	while (!host2.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(2));

	Public fwderid;
	bool startedForwarder = false;
	std::thread forwarder([&]()
	{
		setThreadName("forwarder");

		while (!startedListener)
			this_thread::sleep_for(chrono::milliseconds(50));

		this_thread::sleep_for(chrono::milliseconds(500));
		host2.addNode(host1.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30303, 30303));

		startedForwarder = true;

		/// Only interested in odd packets
		auto w = whost2->installWatch(BuildTopicMask("test"));

		while (!done)
		{
			for (auto i: whost2->checkWatch(w))
			{
				Message msg = whost2->envelope(i).open(whost2->fullTopic(w));
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!startedForwarder)
		this_thread::sleep_for(chrono::milliseconds(50));

	Host ph("Sender", NetworkPreferences("127.0.0.1", 30300, false));
	ph.setIdealPeerCount(1);
	shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
	ph.start();
	ph.addNode(host2.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30305, 30305));
	while (!ph.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(10));

	KeyPair us = KeyPair::create();
	wh->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
	this_thread::sleep_for(chrono::milliseconds(250));

	listener.join();
	done = true;
	forwarder.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1);
}

BOOST_AUTO_TEST_CASE(asyncforwarding)
{
	cnote << "Testing Whisper async forwarding...";
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 2;

	unsigned result = 0;
	bool done = false;

	// Host must be configured not to share peers.
	Host host1("Forwarder", NetworkPreferences("127.0.0.1", 30305, false));
	host1.setIdealPeerCount(1);
	auto whost1 = host1.registerCapability(new WhisperHost());
	host1.start();
	while (!host1.haveNetwork())
		this_thread::sleep_for(chrono::milliseconds(2));

	bool startedForwarder = false;
	std::thread forwarder([&]()
	{
		setThreadName("forwarder");

		this_thread::sleep_for(chrono::milliseconds(500));

		startedForwarder = true;

		/// Only interested in odd packets
		auto w = whost1->installWatch(BuildTopicMask("test"));

		while (!done)
		{
			for (auto i: whost1->checkWatch(w))
			{
				Message msg = whost1->envelope(i).open(whost1->fullTopic(w));
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	});

	while (!startedForwarder)
		this_thread::sleep_for(chrono::milliseconds(2));

	{
		Host host2("Sender", NetworkPreferences("127.0.0.1", 30300, false));
		host2.setIdealPeerCount(1);
		shared_ptr<WhisperHost> whost2 = host2.registerCapability(new WhisperHost());
		host2.start();
		while (!host2.haveNetwork())
			this_thread::sleep_for(chrono::milliseconds(2));
		host2.addNode(host1.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30305, 30305));

		while (!host2.peerCount())
			this_thread::sleep_for(chrono::milliseconds(5));

		KeyPair us = KeyPair::create();
		whost2->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
		this_thread::sleep_for(chrono::milliseconds(250));
	}

	{
		Host ph("Listener", NetworkPreferences("127.0.0.1", 30300, false));
		ph.setIdealPeerCount(1);
		shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
		ph.start();
		while (!ph.haveNetwork())
			this_thread::sleep_for(chrono::milliseconds(2));
		ph.addNode(host1.id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30305, 30305));

		/// Only interested in odd packets
		auto w = wh->installWatch(BuildTopicMask("test"));

		for (int i = 0; i < 200 && !result; ++i)
		{
			for (auto i: wh->checkWatch(w))
			{
				Message msg = wh->envelope(i).open(wh->fullTopic(w));
				unsigned last = RLP(msg.payload()).toInt<unsigned>();
				cnote << "New message from:" << msg.from() << RLP(msg.payload()).toInt<unsigned>();
				result = last;
			}
			this_thread::sleep_for(chrono::milliseconds(50));
		}
	}

	done = true;
	forwarder.join();
	g_logVerbosity = oldLogVerbosity;

	BOOST_REQUIRE_EQUAL(result, 1);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>
#ifdef CAD

#include "cad.h"

moab::DagMC* DAGMC;

void load_cad_geometry_c()
{
  if(!DAGMC) {
    DAGMC = new moab::DagMC();
  }

  moab::ErrorCode rval = DAGMC->load_file("dagmc.h5m");
  MB_CHK_ERR_CONT(rval);

  rval = DAGMC->init_OBBTree();
  MB_CHK_ERR_CONT(rval);

  int32_t cad_univ_id = 0; // universe is always 0 for CAD

  // initialize cell objects
  openmc::n_cells = DAGMC->num_entities(3);
  for(int i = 0; i < openmc::n_cells; i++)
    {
      // set cell ids using global IDs
      openmc::CADCell* c = new openmc::CADCell();
      c->id_ = DAGMC->id_by_index(3, i+1);
      c->dagmc_ptr = DAGMC;
      c->universe_ = cad_univ_id; // set to zero for now
      c->material_.push_back(40); // TEMPORARY
      openmc::global_cells.push_back(c);
      openmc::cell_map[c->id_] = c->id;

      // Populate the Universe vector and dict
      auto it = openmc::universe_map.find(cad_univ_id);
      if (it == openmc::universe_map.end()) {
	openmc::global_universes.push_back(new openmc::Universe());
	openmc::global_universes.back()-> id = cad_univ_id;
	openmc::global_universes.back()->cells.push_back(i);
	openmc::universe_map[cad_univ_id] = openmc::global_universes.size() - 1;
      }
      else {
	openmc::global_universes[it->second]->cells.push_back(i);
      }
    }

  // initialize surface objects
  openmc::n_surfaces = DAGMC->num_entities(2);
  openmc::surfaces_c = new openmc::Surface*[openmc::n_surfaces];

  for(int i = 0; i < openmc::n_surfaces; i++)
    {
      // set cell ids using global IDs
      openmc::CADSurface* s = new openmc::CADSurface();
      s->id = DAGMC->id_by_index(2, i+1);
      s->dagmc_ptr = DAGMC;
      s->bc = openmc::BC_TRANSMIT;
      openmc::surfaces_c[i] = s;
      openmc::surface_map[s->id] = s->id;
    }

  return;
}

void free_memory_cad_c()
{
  delete DAGMC;
}

#endif
<commit_msg>Set material by property.<commit_after>
#ifdef CAD

#include "cad.h"

moab::DagMC* DAGMC;

void load_cad_geometry_c()
{
  if(!DAGMC) {
    DAGMC = new moab::DagMC();
  }

  int32_t cad_univ_id = 0; // universe is always 0 for CAD

  moab::ErrorCode rval = DAGMC->load_file("dagmc.h5m");
  MB_CHK_ERR_CONT(rval);

  rval = DAGMC->init_OBBTree();
  MB_CHK_ERR_CONT(rval);

  std::vector< std::string > prop_keywords;
  prop_keywords.push_back("mat");

  std::map<std::string, std::string> ph;
  DAGMC->parse_properties(prop_keywords, ph, ":");
  MB_CHK_ERR_CONT(rval);

  // initialize cell objects
  openmc::n_cells = DAGMC->num_entities(3);
  for(int i = 0; i < openmc::n_cells; i++)
    {
      moab::EntityHandle vol_handle = DAGMC->entity_by_index(3, i+1);
      // set cell ids using global IDs
      openmc::CADCell* c = new openmc::CADCell();
      c->id_ = DAGMC->id_by_index(3, i+1);
      c->dagmc_ptr = DAGMC;
      c->universe_ = cad_univ_id; // set to zero for now

      if(DAGMC->has_prop(vol_handle, "mat")){
	std::string mat_value;

	rval = DAGMC->prop_value(vol_handle, "mat", mat_value);
	MB_CHK_ERR_CONT(rval);
	int mat_id = std::stoi(mat_value);
	c->material_.push_back(mat_id);
      }
      else {
	c->material_.push_back(40); // TO-DO: add void material here
      }

      c->fill_ = openmc::C_NONE;
      openmc::global_cells.push_back(c);
      openmc::cell_map[c->id_] = c->id_;

      // Populate the Universe vector and dict
      auto it = openmc::universe_map.find(cad_univ_id);
      if (it == openmc::universe_map.end()) {
	openmc::global_universes.push_back(new openmc::Universe());
	openmc::global_universes.back()-> id = cad_univ_id;
	openmc::global_universes.back()->cells.push_back(i);
	openmc::universe_map[cad_univ_id] = openmc::global_universes.size() - 1;
      }
      else {
	openmc::global_universes[it->second]->cells.push_back(i);
      }
    }

  // initialize surface objects
  openmc::n_surfaces = DAGMC->num_entities(2);
  openmc::surfaces_c = new openmc::Surface*[openmc::n_surfaces];

  for(int i = 0; i < openmc::n_surfaces; i++)
    {
      // set cell ids using global IDs
      openmc::CADSurface* s = new openmc::CADSurface();
      s->id = DAGMC->id_by_index(2, i+1);
      s->dagmc_ptr = DAGMC;
      s->bc = openmc::BC_TRANSMIT;
      openmc::surfaces_c[i] = s;
      openmc::surface_map[s->id] = s->id;
    }

  return;
}

void free_memory_cad_c()
{
  delete DAGMC;
}

#endif
<|endoftext|>


<commit_before>#include <boost/python.hpp>
#include <boost/optional/optional.hpp>

#include <nix.hpp>
#include <transmorgify.hpp>
#include <accessors.hpp>

#include <PyEntity.hpp>

using namespace boost::python;
using namespace nix;
using namespace base;
using namespace nixpy;

BOOST_PYTHON_MODULE(core)
{
    PyFile::do_export();

    PySection::do_export();
    PyProperty::do_export();
    PyValue::do_export();

    PyBlock::do_export();
    PySource::do_export();
    PyDataArray::do_export();
    PyDimensions::do_export();

    PyEntityWithSources<ISimpleTag>::do_export("SimpleTag");
    class_<SimpleTag, bases<EntityWithSources<ISimpleTag>>>("SimpleTag");
    to_python_converter<std::vector<SimpleTag>, vector_transmogrify<SimpleTag>>();
    to_python_converter<boost::optional<SimpleTag>, option_transmogrify<SimpleTag>>();

    PyEntityWithSources<IDataTag>::do_export("DataTag");
    class_<DataTag, bases<EntityWithSources<IDataTag>>>("DataTag");
    to_python_converter<std::vector<DataTag>, vector_transmogrify<DataTag>>();
    to_python_converter<boost::optional<DataTag>, option_transmogrify<DataTag>>();

    class_<Feature>("Feature");

    // TODO enum class LinkType

    to_python_converter<boost::optional<std::string>, option_transmogrify<std::string>>();
    option_transmogrify<std::string>::register_from_python();

    to_python_converter<std::vector<std::string>, vector_transmogrify<std::string>>();
    vector_transmogrify<std::string>::register_from_python();

    to_python_converter<std::vector<double>, vector_transmogrify<double>>();
    vector_transmogrify<double>::register_from_python();

    to_python_converter<boost::optional<double>, option_transmogrify<double>>();
    option_transmogrify<double>::register_from_python();
}
<commit_msg>core: configure doc strings<commit_after>#include <boost/python.hpp>
#include <boost/optional/optional.hpp>

#include <nix.hpp>
#include <transmorgify.hpp>
#include <accessors.hpp>

#include <PyEntity.hpp>

using namespace boost::python;
using namespace nix;
using namespace base;
using namespace nixpy;

BOOST_PYTHON_MODULE(core)
{
    // set options for doc strings
    // show user defined / show py signatures / don't show cpp signatures
    docstring_options local_docstring_options(true, true, false);

    PyFile::do_export();

    PySection::do_export();
    PyProperty::do_export();
    PyValue::do_export();

    PyBlock::do_export();
    PySource::do_export();
    PyDataArray::do_export();
    PyDimensions::do_export();

    PyEntityWithSources<ISimpleTag>::do_export("SimpleTag");
    class_<SimpleTag, bases<EntityWithSources<ISimpleTag>>>("SimpleTag");
    to_python_converter<std::vector<SimpleTag>, vector_transmogrify<SimpleTag>>();
    to_python_converter<boost::optional<SimpleTag>, option_transmogrify<SimpleTag>>();

    PyEntityWithSources<IDataTag>::do_export("DataTag");
    class_<DataTag, bases<EntityWithSources<IDataTag>>>("DataTag");
    to_python_converter<std::vector<DataTag>, vector_transmogrify<DataTag>>();
    to_python_converter<boost::optional<DataTag>, option_transmogrify<DataTag>>();

    class_<Feature>("Feature");

    // TODO enum class LinkType

    to_python_converter<boost::optional<std::string>, option_transmogrify<std::string>>();
    option_transmogrify<std::string>::register_from_python();

    to_python_converter<std::vector<std::string>, vector_transmogrify<std::string>>();
    vector_transmogrify<std::string>::register_from_python();

    to_python_converter<std::vector<double>, vector_transmogrify<double>>();
    vector_transmogrify<double>::register_from_python();

    to_python_converter<boost::optional<double>, option_transmogrify<double>>();
    option_transmogrify<double>::register_from_python();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2008, 2009 Google Inc.
 * Copyright 2007 Nintendo Co., Ltd.
 *
 * 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 "cplusplus.h"
#include "info.h"

class Cxx : public CPlusPlus
{
    void visitInterfaceElement(const Interface* interface, Node* element)
    {
        if (element->isSequence(interface) || element->isNative(interface))
        {
            return;
        }
        optionalStage = 0;
        do
        {
            optionalCount = 0;
            writetab();
            element->accept(this);
            write(";\n");
            ++optionalStage;
        } while (optionalStage <= optionalCount);
    }

public:
    Cxx(FILE* file, const char* stringTypeName = "char*", bool useExceptions = true) :
        CPlusPlus(file, stringTypeName, useExceptions)
    {
    }

    virtual void at(const StructType* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }
        write("struct %s", node->getName().c_str());
        if (!node->isLeaf())
        {
            writeln("");
            writeln("{");
            indent();
            printChildren(node);
            unindent();
            writetab();
            write("}");
        }
    }

    virtual void at(const ExceptDcl* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }
        write("struct %s", node->getName().c_str());
        writeln("");
        writeln("{");
        indent();
        printChildren(node);
        unindent();
        writetab();
        write("}");
    }

    virtual void at(const Interface* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }
        write("class %s", node->getName().c_str());
        if (node->getExtends())
        {
            write(" : ");
            prefix = "public ";
            node->getExtends()->accept(this);
            prefix = "";
        }
        if (!node->isLeaf())
        {
            writeln("");
            writeln("{");
            writeln("public:");
            indent();

            for (NodeList::iterator i = node->begin(); i != node->end(); ++i)
            {
                visitInterfaceElement(node, *i);
            }

            // Expand mixins
            for (std::list<const Interface*>::const_iterator i = node->getMixins()->begin();
                 i != node->getMixins()->end();
                 ++i)
            {
                writeln("// %s", (*i)->getName().c_str());
                for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j)
                {
                    visitInterfaceElement(*i, *j);
                }
            }

            writeln("static const char* iid()");
            writeln("{");
            indent();
                writeln("static const char* const name = \"%s\";",
                        node->getQualifiedName().c_str());
                writeln("return name;");
            unindent();
            writeln("}");

            writeln("static const char* info()");
            writeln("{");
            indent();
                writetab();
                write("static const char* const info = ");
                indent();
                Info info(this, moduleName);
                const_cast<Interface*>(node)->accept(&info);
                write(";\n");
                unindent();
                writeln("return info;");
            unindent();
            writeln("}");

            if (Interface* constructor = node->getConstructor())
            {
                // Process constructors.
                constructorMode = true;
                for (NodeList::iterator i = constructor->begin();
                     i != constructor->end();
                     ++i)
                {
                    writetab();
                    (*i)->accept(this);
                }
                constructorMode = false;
                writeln("static Constructor* getConstructor()");
                writeln("{");
                indent();
                    writeln("return constructor;");
                unindent();
                writeln("}");
                writeln("static void setConstructor(Constructor* ctor)");
                writeln("{");
                indent();
                    writeln("constructor = ctor;");
                unindent();
                writeln("}");
                unindent();
                writeln("private:");
                indent();
                writeln("static Constructor* constructor;");
            }

            unindent();
            writetab();
            write("}");
        }

        if (node->getConstructor())
        {
            write(";\n\n");
            writetab();
            write("%s::Constructor* %s::constructor __attribute__((weak))",
                  node->getName().c_str(), node->getName().c_str());
        }
    }

    virtual void at(const NativeType* node)
    {
        if (node->getName() == "void_pointer")
        {
            write("void*");
        }
        else
        {
            write("%s", node->getName().c_str());
        }
    }

    virtual void at(const BinaryExpr* node)
    {
        node->getLeft()->accept(this);
        write(" %s ", node->getName().c_str());
        node->getRight()->accept(this);
    }

    virtual void at(const UnaryExpr* node)
    {
        write("%s", node->getName().c_str());
        NodeList::iterator elem = node->begin();
        (*elem)->accept(this);
    }

    virtual void at(const GroupingExpression* node)
    {
        write("(");
        NodeList::iterator elem = node->begin();
        (*elem)->accept(this);
        write(")");
    }

    virtual void at(const Literal* node)
    {
        if (node->getName() == "TRUE")
        {
            write("true");
        }
        else if (node->getName() == "FALSE")
        {
            write("false");
        }
        else
        {
            write("%s", node->getName().c_str());
        }
    }

    virtual void at(const Member* node)
    {
        if (node->isTypedef(node->getParent()))
        {
            write("typedef ");
        }
        if (node->isInterface(node->getParent()))
        {
            node->getSpec()->accept(this);
            write(" %s", node->getName().c_str());
        }
        else
        {
            node->getSpec()->accept(this);
            write(" %s", node->getName().c_str());
        }
    }

    virtual void at(const ArrayDcl* node)
    {
        assert(!node->isLeaf());

        at(static_cast<const Member*>(node));
        for (NodeList::iterator i = node->begin(); i != node->end(); ++i)
        {
            write("[");
            (*i)->accept(this);
            write("]");
        }
    }

    virtual void at(const ConstDcl* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }
        write("static const ");
        at(static_cast<const Member*>(node));
        write(" = ");
        node->getExp()->accept(this);
    }

    virtual void at(const Attribute* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }

        // getter
        CPlusPlus::getter(node);
        write(" = 0");

        if (!node->isReadonly() || node->isPutForwards() || node->isReplaceable())
        {
            // setter
            write(";\n");
            writetab();
            CPlusPlus::setter(node);
            write(" = 0");
        }
    }

    virtual void at(const OpDcl* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }

        CPlusPlus::at(node);

        if (!constructorMode)
        {
            write(" = 0");
        }
        else
        {
            writeln("");
            writeln("{");
            indent();
                writeln("if (constructor)");
                indent();
                    writetab();
                    write("constructor->createInstance(");
                    for (NodeList::iterator i = node->begin(); i != node->end(); ++i)
                    {
                        if (i != node->begin())
                        {
                            write(", ");
                        }
                        write("%s", (*i)->getName().c_str());
                    }
                    write(");");
                    writeln("");
                unindent();
            unindent();
            writeln("}");
        }
    }
};

class Import : public Visitor
{
    FILE* file;
    bool printed;

public:
    Import(FILE* file) :
        file(file),
        printed(false)
    {
    }

    virtual void at(const Node* node)
    {
        if (1 < node->getRank())
        {
            return;
        }
        visitChildren(node);
    }

    virtual void at(const Include* node)
    {
        if (1 < node->getRank())
        {
            return;
        }
        if (node->isSystem())
        {
            fprintf(file, "#include <%s>\n", getOutputFilename(node->getName().c_str(), "h").c_str());
        }
        else
        {
            fprintf(file, "#include \"%s\"\n", getOutputFilename(node->getName().c_str(), "h").c_str());
        }
        printed = true;
    }

    bool hasPrinted() const
    {
        return printed;
    }
};

class Predeclaration : public Visitor
{
    FILE* file;

public:
    Predeclaration(FILE* file) :
        file(file)
    {
    }

    virtual void at(const Node* node)
    {
        if (1 < node->getRank())
        {
            return;
        }
        visitChildren(node);
    }

    virtual void at(const Module* node)
    {
        if (!node->hasPredeclarations())
        {
            return;
        }
        if (0 < node->getName().size())
        {
            fprintf(file, "namespace %s\n", node->getName().c_str());
            fprintf(file, "{\n");
                visitChildren(node);
            fprintf(file, "}\n\n");
        }
        else
        {
            visitChildren(node);
        }
    }

    virtual void at(const Interface* node)
    {
        if (1 < node->getRank() || !node->isLeaf())
        {
            return;
        }
        fprintf(file, "    class %s;\n", node->getName().c_str());
    }
};

void printCxx(const std::string& filename, const char* stringTypeName, bool useExceptions)
{
    printf("# %s\n", filename.c_str());

    FILE* file = fopen(filename.c_str(), "w");
    if (!file)
    {
        return;
    }

    std::string included = getIncludedName(filename);
    fprintf(file, "// Generated by esidl %s.\n\n", VERSION);
    fprintf(file, "#ifndef %s\n", included.c_str());
    fprintf(file, "#define %s\n\n", included.c_str());

    Import import(file);
    getSpecification()->accept(&import);
    if (import.hasPrinted())
    {
        fprintf(file, "\n");
    }

    if (!Node::getFlatNamespace())
    {
        Predeclaration predeclaration(file);
        getSpecification()->accept(&predeclaration);
    }

    Cxx cxx(file, stringTypeName, useExceptions);
    getSpecification()->accept(&cxx);

    fprintf(file, "#endif  // %s\n", included.c_str());

    fclose(file);
}
<commit_msg>(createInstance) : Return 0 if constructor is not set.<commit_after>/*
 * Copyright 2008, 2009 Google Inc.
 * Copyright 2007 Nintendo Co., Ltd.
 *
 * 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 "cplusplus.h"
#include "info.h"

class Cxx : public CPlusPlus
{
    void visitInterfaceElement(const Interface* interface, Node* element)
    {
        if (element->isSequence(interface) || element->isNative(interface))
        {
            return;
        }
        optionalStage = 0;
        do
        {
            optionalCount = 0;
            writetab();
            element->accept(this);
            write(";\n");
            ++optionalStage;
        } while (optionalStage <= optionalCount);
    }

public:
    Cxx(FILE* file, const char* stringTypeName = "char*", bool useExceptions = true) :
        CPlusPlus(file, stringTypeName, useExceptions)
    {
    }

    virtual void at(const StructType* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }
        write("struct %s", node->getName().c_str());
        if (!node->isLeaf())
        {
            writeln("");
            writeln("{");
            indent();
            printChildren(node);
            unindent();
            writetab();
            write("}");
        }
    }

    virtual void at(const ExceptDcl* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }
        write("struct %s", node->getName().c_str());
        writeln("");
        writeln("{");
        indent();
        printChildren(node);
        unindent();
        writetab();
        write("}");
    }

    virtual void at(const Interface* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }
        write("class %s", node->getName().c_str());
        if (node->getExtends())
        {
            write(" : ");
            prefix = "public ";
            node->getExtends()->accept(this);
            prefix = "";
        }
        if (!node->isLeaf())
        {
            writeln("");
            writeln("{");
            writeln("public:");
            indent();

            for (NodeList::iterator i = node->begin(); i != node->end(); ++i)
            {
                visitInterfaceElement(node, *i);
            }

            // Expand mixins
            for (std::list<const Interface*>::const_iterator i = node->getMixins()->begin();
                 i != node->getMixins()->end();
                 ++i)
            {
                writeln("// %s", (*i)->getName().c_str());
                for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j)
                {
                    visitInterfaceElement(*i, *j);
                }
            }

            writeln("static const char* iid()");
            writeln("{");
            indent();
                writeln("static const char* const name = \"%s\";",
                        node->getQualifiedName().c_str());
                writeln("return name;");
            unindent();
            writeln("}");

            writeln("static const char* info()");
            writeln("{");
            indent();
                writetab();
                write("static const char* const info = ");
                indent();
                Info info(this, moduleName);
                const_cast<Interface*>(node)->accept(&info);
                write(";\n");
                unindent();
                writeln("return info;");
            unindent();
            writeln("}");

            if (Interface* constructor = node->getConstructor())
            {
                // Process constructors.
                constructorMode = true;
                for (NodeList::iterator i = constructor->begin();
                     i != constructor->end();
                     ++i)
                {
                    writetab();
                    (*i)->accept(this);
                }
                constructorMode = false;
                writeln("static Constructor* getConstructor()");
                writeln("{");
                indent();
                    writeln("return constructor;");
                unindent();
                writeln("}");
                writeln("static void setConstructor(Constructor* ctor)");
                writeln("{");
                indent();
                    writeln("constructor = ctor;");
                unindent();
                writeln("}");
                unindent();
                writeln("private:");
                indent();
                writeln("static Constructor* constructor;");
            }

            unindent();
            writetab();
            write("}");
        }

        if (node->getConstructor())
        {
            write(";\n\n");
            writetab();
            write("%s::Constructor* %s::constructor __attribute__((weak))",
                  node->getName().c_str(), node->getName().c_str());
        }
    }

    virtual void at(const NativeType* node)
    {
        if (node->getName() == "void_pointer")
        {
            write("void*");
        }
        else
        {
            write("%s", node->getName().c_str());
        }
    }

    virtual void at(const BinaryExpr* node)
    {
        node->getLeft()->accept(this);
        write(" %s ", node->getName().c_str());
        node->getRight()->accept(this);
    }

    virtual void at(const UnaryExpr* node)
    {
        write("%s", node->getName().c_str());
        NodeList::iterator elem = node->begin();
        (*elem)->accept(this);
    }

    virtual void at(const GroupingExpression* node)
    {
        write("(");
        NodeList::iterator elem = node->begin();
        (*elem)->accept(this);
        write(")");
    }

    virtual void at(const Literal* node)
    {
        if (node->getName() == "TRUE")
        {
            write("true");
        }
        else if (node->getName() == "FALSE")
        {
            write("false");
        }
        else
        {
            write("%s", node->getName().c_str());
        }
    }

    virtual void at(const Member* node)
    {
        if (node->isTypedef(node->getParent()))
        {
            write("typedef ");
        }
        if (node->isInterface(node->getParent()))
        {
            node->getSpec()->accept(this);
            write(" %s", node->getName().c_str());
        }
        else
        {
            node->getSpec()->accept(this);
            write(" %s", node->getName().c_str());
        }
    }

    virtual void at(const ArrayDcl* node)
    {
        assert(!node->isLeaf());

        at(static_cast<const Member*>(node));
        for (NodeList::iterator i = node->begin(); i != node->end(); ++i)
        {
            write("[");
            (*i)->accept(this);
            write("]");
        }
    }

    virtual void at(const ConstDcl* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }
        write("static const ");
        at(static_cast<const Member*>(node));
        write(" = ");
        node->getExp()->accept(this);
    }

    virtual void at(const Attribute* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }

        // getter
        CPlusPlus::getter(node);
        write(" = 0");

        if (!node->isReadonly() || node->isPutForwards() || node->isReplaceable())
        {
            // setter
            write(";\n");
            writetab();
            CPlusPlus::setter(node);
            write(" = 0");
        }
    }

    virtual void at(const OpDcl* node)
    {
        if (node->getJavadoc().size())
        {
            write("%s\n", node->getJavadoc().c_str());
            writetab();
        }

        CPlusPlus::at(node);

        if (!constructorMode)
        {
            write(" = 0");
        }
        else
        {
            writeln("");
            writeln("{");
            indent();
                writeln("if (constructor)");
                indent();
                    writetab();
                    write("constructor->createInstance(");
                    for (NodeList::iterator i = node->begin(); i != node->end(); ++i)
                    {
                        if (i != node->begin())
                        {
                            write(", ");
                        }
                        write("%s", (*i)->getName().c_str());
                    }
                    write(");");
                    writeln("");
                unindent();
                writeln("else");
                indent();
                    writeln("return 0;");
                unindent();
            unindent();
            writeln("}");
        }
    }
};

class Import : public Visitor
{
    FILE* file;
    bool printed;

public:
    Import(FILE* file) :
        file(file),
        printed(false)
    {
    }

    virtual void at(const Node* node)
    {
        if (1 < node->getRank())
        {
            return;
        }
        visitChildren(node);
    }

    virtual void at(const Include* node)
    {
        if (1 < node->getRank())
        {
            return;
        }
        if (node->isSystem())
        {
            fprintf(file, "#include <%s>\n", getOutputFilename(node->getName().c_str(), "h").c_str());
        }
        else
        {
            fprintf(file, "#include \"%s\"\n", getOutputFilename(node->getName().c_str(), "h").c_str());
        }
        printed = true;
    }

    bool hasPrinted() const
    {
        return printed;
    }
};

class Predeclaration : public Visitor
{
    FILE* file;

public:
    Predeclaration(FILE* file) :
        file(file)
    {
    }

    virtual void at(const Node* node)
    {
        if (1 < node->getRank())
        {
            return;
        }
        visitChildren(node);
    }

    virtual void at(const Module* node)
    {
        if (!node->hasPredeclarations())
        {
            return;
        }
        if (0 < node->getName().size())
        {
            fprintf(file, "namespace %s\n", node->getName().c_str());
            fprintf(file, "{\n");
                visitChildren(node);
            fprintf(file, "}\n\n");
        }
        else
        {
            visitChildren(node);
        }
    }

    virtual void at(const Interface* node)
    {
        if (1 < node->getRank() || !node->isLeaf())
        {
            return;
        }
        fprintf(file, "    class %s;\n", node->getName().c_str());
    }
};

void printCxx(const std::string& filename, const char* stringTypeName, bool useExceptions)
{
    printf("# %s\n", filename.c_str());

    FILE* file = fopen(filename.c_str(), "w");
    if (!file)
    {
        return;
    }

    std::string included = getIncludedName(filename);
    fprintf(file, "// Generated by esidl %s.\n\n", VERSION);
    fprintf(file, "#ifndef %s\n", included.c_str());
    fprintf(file, "#define %s\n\n", included.c_str());

    Import import(file);
    getSpecification()->accept(&import);
    if (import.hasPrinted())
    {
        fprintf(file, "\n");
    }

    if (!Node::getFlatNamespace())
    {
        Predeclaration predeclaration(file);
        getSpecification()->accept(&predeclaration);
    }

    Cxx cxx(file, stringTypeName, useExceptions);
    getSpecification()->accept(&cxx);

    fprintf(file, "#endif  // %s\n", included.c_str());

    fclose(file);
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc
 *
 *   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 "config.h"
#include "couch_btree.h"
#include "internal.h"
#include "util.h"

#include <libcouchstore/couch_db.h>
#include <platform/cb_malloc.h>

#include <getopt.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <iomanip>
#include <string>
#include <sstream>

static void usage(void) {
    printf("USAGE: couch_dbck [options] "
           "source_filename [destination_filename]\n");
    printf("\nOptions:\n");
    printf("    -s, --stale       "
           "Recover from stale commits if corruption detected.\n");
    printf("    -v, --verbose     "
           "Display detailed messages.\n");
    printf("    -j, --json        "
           "Display corrupt document info as JSON objects "
           "(one per line).\n");
    exit(EXIT_FAILURE);
}

struct recovery_options {
    // Source file name.
    std::string src_filename;
    // Destination (recovered) file name.
    std::string dst_filename;
    // If set, check whether or not doc body is corrupted.
    bool detect_corrupt_docbody = true;
    // If set, recover using old data from stale commits.
    bool enable_rewind = false;
    // If set, print out detailed messages.
    bool verbose_msg = false;
    // If set, print verbose messages as JSON objects.
    bool json = false;
};

struct recover_file_hook_param {
    // Number of documents referred to by index.
    uint64_t num_visited_docs = 0;
    // Number of corrupted documents.
    uint64_t num_corrupted_docs = 0;
    // Recovery options.
    recovery_options* options = nullptr;
    // DB handle for source file.
    Db* db_src = nullptr;
};

std::string get_printable_string(const sized_buf& buf) {
    std::string ret;
    for (size_t i=0; i<buf.size; ++i) {
        if (0x20 <= buf.buf[i] && buf.buf[i] <= 0x7d) {
            // Printable character.
            ret += buf.buf[i];
        } else {
            // Otherwise: dump hex.
            std::stringstream ss;
            ss << "(0x" << std::setfill('0') << std::setw(2)
               << std::hex << static_cast<size_t>(buf.buf[i]) << ") ";
            ret += ss.str();
        }
    }
    return ret;
}

static int recover_file_hook(Db* target,
                             DocInfo *docinfo,
                             sized_buf item,
                             void *ctx) {
    (void)item;
    recover_file_hook_param* param =
            reinterpret_cast<recover_file_hook_param*>(ctx);
    if (!docinfo) {
        // End of compaction.
        return 0;
    }

    param->num_visited_docs++;

    couchstore_error_t errcode;
    Doc* cur_doc;

    if (docinfo->deleted) {
        // Deleted doc.
        return 0;
    }

    // Open doc body.
    errcode = couchstore_open_doc_with_docinfo(
            param->db_src, docinfo, &cur_doc, 0x0);
    if (errcode != COUCHSTORE_SUCCESS) {
        // Document is corrupted.
        if (param->options->verbose_msg) {
            std::string fmt;
            if (param->options->json) {
                fmt = "{"
                      R"("type":"corrupted document",)"
                      R"("error code":%d,)"
                      R"("error message":"%s",)"
                      R"("id":"%s",)"
                      R"("bp")" ":%" PRIu64 ","
                      R"("size":%zu,)"
                      R"("seq")" ":%" PRIu64
                      "}\n";
            } else {
                fmt = "Corrupted document "
                      "(error code %d, %s): "
                      "id '%s', "
                      "bp %" PRIu64 ", "
                      "size %zu, "
                      "seq %" PRIu64
                      "\n";
            }

            fprintf(stdout, fmt.c_str(),
                    errcode, couchstore_strerror(errcode),
                    get_printable_string(docinfo->id).c_str(),
                    docinfo->bp,
                    docinfo->size,
                    docinfo->db_seq);
        }
        param->num_corrupted_docs++;
    } else {
        couchstore_free_document(cur_doc);
    }

    return 0;
}

struct rewind_request {
    // Recovery options.
    recovery_options* options = nullptr;
    // DB handle for source file.
    Db *db_src = nullptr;
    // DB handle for recovered file.
    Db *db_recovered = nullptr;
    // Total number of old documents recovered from all stale commits.
    uint64_t total_num_docs_recovered = 0;
};

struct rewind_hook_param {
    // Recovery options.
    recovery_options* options = nullptr;
    // DB handle for source file.
    Db *db_src = nullptr;
    // DB handle for recovered file.
    Db *db_dst = nullptr;
    // Number of documents recovered from this specific commit.
    uint64_t num_docs_recovered = 0;
};

static int rewind_hook(Db *db,
                       int depth,
                       const DocInfo* doc_info,
                       uint64_t subtree_size,
                       const sized_buf* reduce_value,
                       void *ctx) {
    rewind_hook_param* param =
            reinterpret_cast<rewind_hook_param*>(ctx);
    if (!doc_info) {
        return 0;
    }

    DocInfo* doc_info_dst;
    couchstore_error_t errcode;
    errcode = couchstore_docinfo_by_id(param->db_dst,
                                       doc_info->id.buf,
                                       doc_info->id.size,
                                       &doc_info_dst);
    if (errcode != COUCHSTORE_SUCCESS) {
        // The doc exists in stale commit (of corrupted file) only.
        // Copy it into the destination file.
        Doc* cur_doc;
        errcode = couchstore_open_doc_with_docinfo(
                param->db_src, (DocInfo*)doc_info, &cur_doc, 0x0);
        if (errcode != COUCHSTORE_SUCCESS) {
            return 0;
        }

        if (param->options->verbose_msg) {
            std::string fmt;
            if (param->options->json) {
                fmt = "{"
                      R"("type":"recovered document",)"
                      R"("id":"%s",)"
                      R"("bp")" ":%" PRIu64 ","
                      R"("size")" ":%zu,"
                      R"("seq")" ":%" PRIu64
                      "}\n";
            } else {
                fmt = "Recovered document '%s', "
                      "prev bp %" PRIu64 ", "
                      "prev size %zu, "
                      "prev seq num %" PRIu64
                      "\n";
            }

            fprintf(stdout, fmt.c_str(),
                    get_printable_string(doc_info->id).c_str(),
                    doc_info->bp,
                    doc_info->size,
                    doc_info->db_seq);
        }

        couchstore_save_document(param->db_dst,
                                 cur_doc,
                                 (DocInfo*)doc_info,
                                 COUCHSTORE_SEQUENCE_AS_IS);
        param->num_docs_recovered++;
        couchstore_free_document(cur_doc);
    } else {
        couchstore_free_docinfo(doc_info_dst);
    }
    return 0;
}

static void rewind_and_get_stale_data(rewind_request& rq) {
    couchstore_error_t errcode;
    size_t num_rewind = 0;
    Db *db = nullptr;

    errcode = couchstore_open_db_ex(rq.options->src_filename.c_str(),
                                    COUCHSTORE_OPEN_FLAG_RDONLY,
                                    couchstore_get_default_file_ops(),
                                    &db);

    while (errcode == COUCHSTORE_SUCCESS) {
        errcode = couchstore_rewind_db_header(db);
        if (errcode != COUCHSTORE_SUCCESS) {
            db = nullptr;
            break;
        }
        num_rewind++;

        rewind_hook_param rewind_param;
        rewind_param.options = rq.options;
        rewind_param.db_dst = rq.db_recovered;
        rewind_param.db_src = rq.db_src;

        // Walk ID tree and find any documents
        // that exist in stale commit only.
        couchstore_walk_id_tree(db,
                                nullptr,
                                COUCHSTORE_TOLERATE_CORRUPTION,
                                rewind_hook,
                                &rewind_param);
        if (rewind_param.num_docs_recovered) {
            fprintf(stderr, "%" PRIu64 " documents recovered "
                    "from stale header #%zu.\n",
                    rewind_param.num_docs_recovered,
                    num_rewind);
            rq.total_num_docs_recovered += rewind_param.num_docs_recovered;
        }
    };

    if (!num_rewind) {
        fprintf(stderr, "No stale header to read.\n");
    }

    if (db) {
        couchstore_close_file(db);
        couchstore_free_db(db);
    }
}

static int recover_file(recovery_options& options) {
    fprintf(stderr, "Recover from file %s to file %s\n",
            options.src_filename.c_str(),
            options.dst_filename.c_str());

    if (options.src_filename == options.dst_filename) {
        // Both filenames shouldn't be the same.
        usage();
    }

    // Source (may be corrupted) DB.
    Db *db_src = nullptr;
    // DB after recovery.
    Db *db_recovered = nullptr;
    // Another handle for source DB.
    Db *db_src_alt = nullptr;

    couchstore_error_t errcode = COUCHSTORE_SUCCESS;
    couchstore_error_t errcode_compaction = COUCHSTORE_SUCCESS;
    bool error_detected = false;

    recover_file_hook_param param;
    param.options = &options;

    // Open source file.
    errcode = couchstore_open_db_ex(options.src_filename.c_str(),
                                    COUCHSTORE_OPEN_FLAG_RDONLY,
                                    couchstore_get_default_file_ops(),
                                    &db_src);
    error_pass(errcode);

    // Open source file for rewind.
    errcode = couchstore_open_db_ex(options.src_filename.c_str(),
                                    COUCHSTORE_OPEN_FLAG_RDONLY,
                                    couchstore_get_default_file_ops(),
                                    &db_src_alt);
    error_pass(errcode);
    param.db_src = db_src_alt;

    // Compact with recovery mode.
    errcode_compaction = couchstore_compact_db_ex(
            db_src,
            options.dst_filename.c_str(),
            COUCHSTORE_COMPACT_RECOVERY_MODE,
            recover_file_hook,
            nullptr,
            &param,
            couchstore_get_default_file_ops());

    // Open recovered file.
    errcode = couchstore_open_db_ex(options.dst_filename.c_str(),
                                    0x0,
                                    couchstore_get_default_file_ops(),
                                    &db_recovered);
    DbInfo dbinfo;
    couchstore_db_info(db_recovered, &dbinfo);

    if (errcode_compaction == COUCHSTORE_SUCCESS) {
        fprintf(stderr, "No corruption detected in index.\n");
    } else {
        fprintf(stderr,
                "Corrupted index node detected "
                "(error code %d, %s).\n",
                errcode_compaction,
                couchstore_strerror(errcode_compaction));
        error_detected = true;
    }
    fprintf(stderr, "Total %" PRIu64 " documents are referred to by index.\n",
            param.num_visited_docs);

    if (param.num_corrupted_docs) {
        fprintf(stderr, "Total %" PRIu64 " documents corrupted.\n",
                param.num_corrupted_docs);
        error_detected = true;
    } else {
        fprintf(stderr, "No corruption detected in documents.\n");
    }

    fprintf(stderr, "Total %" PRIu64 " documents recovered.\n",
            dbinfo.doc_count);

    // If error detected, and flag is set, traverse stale commits.
    if (error_detected && options.enable_rewind) {
        rewind_request rwrq;
        rwrq.options = &options;
        rwrq.db_recovered = db_recovered;
        rwrq.db_src = db_src_alt;

        fprintf(stderr,
                "We are going to recover missing documents "
                "from stale commits..\n");
        rewind_and_get_stale_data(rwrq);

        if (rwrq.total_num_docs_recovered) {
            fprintf(stderr,
                    "Total %" PRIu64 " documents recovered "
                    "from stale headers.\n",
                    rwrq.total_num_docs_recovered);
            error_pass(couchstore_commit(db_recovered));
        }
    }

cleanup:
    if (db_src) {
        couchstore_close_file(db_src);
        couchstore_free_db(db_src);
    }
    if (db_recovered) {
        couchstore_close_file(db_recovered);
        couchstore_free_db(db_recovered);
    }
    if (db_src_alt) {
        couchstore_close_file(db_src_alt);
        couchstore_free_db(db_src_alt);
    }

    return errcode;
}

int main(int argc, char **argv)
{
    struct option long_options[] =
    {
        {"stale",   no_argument, 0, 's'},
        {"verbose", no_argument, 0, 'v'},
        {"json",    no_argument, 0, 'j'},
        {nullptr,   0,           0, 0}
    };

    recovery_options options;
    int opt;

    while ( (opt = getopt_long(argc, argv, "svj",
                               long_options, nullptr)) != -1 )  {
        switch (opt) {
        case 's': // stale
            options.enable_rewind = true;
            break;
        case 'v': // verbose
            options.verbose_msg = true;
            break;
        case 'j': // json
            options.json = true;
            break;

        default:
            usage();
        }
    }

    if (argc - optind < 1) {
        // After option fields, one or two more fields
        // (for src/dst files) should exist.
        usage();
    }

    options.src_filename = argv[optind];
    if (argc - optind == 1) {
        // Destination file name is not given, automatically set it.
        options.dst_filename = options.src_filename + ".recovered";
    } else {
        options.dst_filename = argv[optind+1];
    }

    int errcode = recover_file(options);

    if (errcode == 0) {
        exit(EXIT_SUCCESS);
    } else {
        exit(EXIT_FAILURE);
    }
}

<commit_msg>Fix Valgrind error in dbck<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc
 *
 *   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 "config.h"
#include "couch_btree.h"
#include "internal.h"
#include "util.h"

#include <libcouchstore/couch_db.h>
#include <platform/cb_malloc.h>

#include <getopt.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <iomanip>
#include <string>
#include <sstream>

static void usage(void) {
    printf("USAGE: couch_dbck [options] "
           "source_filename [destination_filename]\n");
    printf("\nOptions:\n");
    printf("    -s, --stale       "
           "Recover from stale commits if corruption detected.\n");
    printf("    -v, --verbose     "
           "Display detailed messages.\n");
    printf("    -j, --json        "
           "Display corrupt document info as JSON objects "
           "(one per line).\n");
    exit(EXIT_FAILURE);
}

struct recovery_options {
    // Source file name.
    std::string src_filename;
    // Destination (recovered) file name.
    std::string dst_filename;
    // If set, check whether or not doc body is corrupted.
    bool detect_corrupt_docbody = true;
    // If set, recover using old data from stale commits.
    bool enable_rewind = false;
    // If set, print out detailed messages.
    bool verbose_msg = false;
    // If set, print verbose messages as JSON objects.
    bool json = false;
};

struct recover_file_hook_param {
    // Number of documents referred to by index.
    uint64_t num_visited_docs = 0;
    // Number of corrupted documents.
    uint64_t num_corrupted_docs = 0;
    // Recovery options.
    recovery_options* options = nullptr;
    // DB handle for source file.
    Db* db_src = nullptr;
};

std::string get_printable_string(const sized_buf& buf) {
    std::string ret;
    for (size_t i=0; i<buf.size; ++i) {
        if (0x20 <= buf.buf[i] && buf.buf[i] <= 0x7d) {
            // Printable character.
            ret += buf.buf[i];
        } else {
            // Otherwise: dump hex.
            std::stringstream ss;
            ss << "(0x" << std::setfill('0') << std::setw(2)
               << std::hex << static_cast<size_t>(buf.buf[i]) << ") ";
            ret += ss.str();
        }
    }
    return ret;
}

static int recover_file_hook(Db* target,
                             DocInfo *docinfo,
                             sized_buf item,
                             void *ctx) {
    (void)item;
    recover_file_hook_param* param =
            reinterpret_cast<recover_file_hook_param*>(ctx);
    if (!docinfo) {
        // End of compaction.
        return 0;
    }

    param->num_visited_docs++;

    couchstore_error_t errcode;
    Doc* cur_doc;

    if (docinfo->deleted) {
        // Deleted doc.
        return 0;
    }

    // Open doc body.
    errcode = couchstore_open_doc_with_docinfo(
            param->db_src, docinfo, &cur_doc, 0x0);
    if (errcode != COUCHSTORE_SUCCESS) {
        // Document is corrupted.
        if (param->options->verbose_msg) {
            std::string fmt;
            if (param->options->json) {
                fmt = "{"
                      R"("type":"corrupted document",)"
                      R"("error code":%d,)"
                      R"("error message":"%s",)"
                      R"("id":"%s",)"
                      R"("bp")" ":%" PRIu64 ","
                      R"("size":%zu,)"
                      R"("seq")" ":%" PRIu64
                      "}\n";
            } else {
                fmt = "Corrupted document "
                      "(error code %d, %s): "
                      "id '%s', "
                      "bp %" PRIu64 ", "
                      "size %zu, "
                      "seq %" PRIu64
                      "\n";
            }

            fprintf(stdout, fmt.c_str(),
                    errcode, couchstore_strerror(errcode),
                    get_printable_string(docinfo->id).c_str(),
                    docinfo->bp,
                    docinfo->size,
                    docinfo->db_seq);
        }
        param->num_corrupted_docs++;
    } else {
        couchstore_free_document(cur_doc);
    }

    return 0;
}

struct rewind_request {
    // Recovery options.
    recovery_options* options = nullptr;
    // DB handle for source file.
    Db *db_src = nullptr;
    // DB handle for recovered file.
    Db *db_recovered = nullptr;
    // Total number of old documents recovered from all stale commits.
    uint64_t total_num_docs_recovered = 0;
};

struct rewind_hook_param {
    // Recovery options.
    recovery_options* options = nullptr;
    // DB handle for source file.
    Db *db_src = nullptr;
    // DB handle for recovered file.
    Db *db_dst = nullptr;
    // Number of documents recovered from this specific commit.
    uint64_t num_docs_recovered = 0;
};

static int rewind_hook(Db *db,
                       int depth,
                       const DocInfo* doc_info,
                       uint64_t subtree_size,
                       const sized_buf* reduce_value,
                       void *ctx) {
    rewind_hook_param* param =
            reinterpret_cast<rewind_hook_param*>(ctx);
    if (!doc_info) {
        return 0;
    }

    DocInfo* doc_info_dst;
    couchstore_error_t errcode;
    errcode = couchstore_docinfo_by_id(param->db_dst,
                                       doc_info->id.buf,
                                       doc_info->id.size,
                                       &doc_info_dst);
    if (errcode != COUCHSTORE_SUCCESS) {
        // The doc exists in stale commit (of corrupted file) only.
        // Copy it into the destination file.
        Doc* cur_doc;
        errcode = couchstore_open_doc_with_docinfo(
                param->db_src, (DocInfo*)doc_info, &cur_doc, 0x0);
        if (errcode != COUCHSTORE_SUCCESS) {
            return 0;
        }

        if (param->options->verbose_msg) {
            std::string fmt;
            if (param->options->json) {
                fmt = "{"
                      R"("type":"recovered document",)"
                      R"("id":"%s",)"
                      R"("bp")" ":%" PRIu64 ","
                      R"("size")" ":%zu,"
                      R"("seq")" ":%" PRIu64
                      "}\n";
            } else {
                fmt = "Recovered document '%s', "
                      "prev bp %" PRIu64 ", "
                      "prev size %zu, "
                      "prev seq num %" PRIu64
                      "\n";
            }

            fprintf(stdout, fmt.c_str(),
                    get_printable_string(doc_info->id).c_str(),
                    doc_info->bp,
                    doc_info->size,
                    doc_info->db_seq);
        }

        couchstore_save_document(param->db_dst,
                                 cur_doc,
                                 (DocInfo*)doc_info,
                                 COUCHSTORE_SEQUENCE_AS_IS);
        param->num_docs_recovered++;
        couchstore_free_document(cur_doc);
    } else {
        couchstore_free_docinfo(doc_info_dst);
    }
    return 0;
}

static void rewind_and_get_stale_data(rewind_request& rq) {
    couchstore_error_t errcode;
    size_t num_rewind = 0;
    Db *db = nullptr;

    errcode = couchstore_open_db_ex(rq.options->src_filename.c_str(),
                                    COUCHSTORE_OPEN_FLAG_RDONLY,
                                    couchstore_get_default_file_ops(),
                                    &db);

    while (errcode == COUCHSTORE_SUCCESS) {
        errcode = couchstore_rewind_db_header(db);
        if (errcode != COUCHSTORE_SUCCESS) {
            db = nullptr;
            break;
        }
        num_rewind++;

        rewind_hook_param rewind_param;
        rewind_param.options = rq.options;
        rewind_param.db_dst = rq.db_recovered;
        rewind_param.db_src = rq.db_src;

        // Walk ID tree and find any documents
        // that exist in stale commit only.
        couchstore_walk_id_tree(db,
                                nullptr,
                                COUCHSTORE_TOLERATE_CORRUPTION,
                                rewind_hook,
                                &rewind_param);
        if (rewind_param.num_docs_recovered) {
            fprintf(stderr, "%" PRIu64 " documents recovered "
                    "from stale header #%zu.\n",
                    rewind_param.num_docs_recovered,
                    num_rewind);
            rq.total_num_docs_recovered += rewind_param.num_docs_recovered;
        }
    };

    if (!num_rewind) {
        fprintf(stderr, "No stale header to read.\n");
    }

    if (db) {
        couchstore_close_file(db);
        couchstore_free_db(db);
    }
}

static int recover_file(recovery_options& options) {
    fprintf(stderr, "Recover from file %s to file %s\n",
            options.src_filename.c_str(),
            options.dst_filename.c_str());

    if (options.src_filename == options.dst_filename) {
        // Both filenames shouldn't be the same.
        usage();
    }

    // Source (may be corrupted) DB.
    Db *db_src = nullptr;
    // DB after recovery.
    Db *db_recovered = nullptr;
    // Another handle for source DB.
    Db *db_src_alt = nullptr;

    couchstore_error_t errcode = COUCHSTORE_SUCCESS;
    couchstore_error_t errcode_compaction = COUCHSTORE_SUCCESS;
    bool error_detected = false;

    recover_file_hook_param param;
    param.options = &options;

    // Open source file.
    errcode = couchstore_open_db_ex(options.src_filename.c_str(),
                                    COUCHSTORE_OPEN_FLAG_RDONLY,
                                    couchstore_get_default_file_ops(),
                                    &db_src);
    error_pass(errcode);

    // Open source file for rewind.
    errcode = couchstore_open_db_ex(options.src_filename.c_str(),
                                    COUCHSTORE_OPEN_FLAG_RDONLY,
                                    couchstore_get_default_file_ops(),
                                    &db_src_alt);
    error_pass(errcode);
    param.db_src = db_src_alt;

    // Compact with recovery mode.
    errcode_compaction = couchstore_compact_db_ex(
            db_src,
            options.dst_filename.c_str(),
            COUCHSTORE_COMPACT_RECOVERY_MODE,
            recover_file_hook,
            nullptr,
            &param,
            couchstore_get_default_file_ops());

    // Open recovered file.
    errcode = couchstore_open_db_ex(options.dst_filename.c_str(),
                                    0x0,
                                    couchstore_get_default_file_ops(),
                                    &db_recovered);
    DbInfo dbinfo;
    couchstore_db_info(db_recovered, &dbinfo);

    if (errcode_compaction == COUCHSTORE_SUCCESS) {
        fprintf(stderr, "No corruption detected in index.\n");
    } else {
        fprintf(stderr,
                "Corrupted index node detected "
                "(error code %d, %s).\n",
                errcode_compaction,
                couchstore_strerror(errcode_compaction));
        error_detected = true;
    }
    fprintf(stderr, "Total %" PRIu64 " documents are referred to by index.\n",
            param.num_visited_docs);

    if (param.num_corrupted_docs) {
        fprintf(stderr, "Total %" PRIu64 " documents corrupted.\n",
                param.num_corrupted_docs);
        error_detected = true;
    } else {
        fprintf(stderr, "No corruption detected in documents.\n");
    }

    fprintf(stderr, "Total %" PRIu64 " documents recovered.\n",
            dbinfo.doc_count);

    // If error detected, and flag is set, traverse stale commits.
    if (error_detected && options.enable_rewind) {
        rewind_request rwrq;
        rwrq.options = &options;
        rwrq.db_recovered = db_recovered;
        rwrq.db_src = db_src_alt;

        fprintf(stderr,
                "We are going to recover missing documents "
                "from stale commits..\n");
        rewind_and_get_stale_data(rwrq);

        if (rwrq.total_num_docs_recovered) {
            fprintf(stderr,
                    "Total %" PRIu64 " documents recovered "
                    "from stale headers.\n",
                    rwrq.total_num_docs_recovered);
            error_pass(couchstore_commit(db_recovered));
        }
    }

cleanup:
    if (db_src) {
        couchstore_close_file(db_src);
        couchstore_free_db(db_src);
    }
    if (db_recovered) {
        couchstore_close_file(db_recovered);
        couchstore_free_db(db_recovered);
    }
    if (db_src_alt) {
        couchstore_close_file(db_src_alt);
        couchstore_free_db(db_src_alt);
    }

    return errcode;
}

int main(int argc, char **argv)
{
    struct option long_options[] =
    {
        {"stale",   no_argument, 0, 's'},
        {"verbose", no_argument, 0, 'v'},
        {"json",    no_argument, 0, 'j'},
        {nullptr,   0,           0, 0}
    };

    recovery_options options;
    int opt;

    while ( (opt = getopt_long(argc, argv, "svj",
                               long_options, nullptr)) != -1 )  {
        switch (opt) {
        case 's': // stale
            options.enable_rewind = true;
            break;
        case 'v': // verbose
            options.verbose_msg = true;
            break;
        case 'j': // json
            options.json = true;
            break;

        default:
            usage();
        }
    }

    if (argc - optind < 1) {
        // After option fields, one or two more fields
        // (for src/dst files) should exist.
        usage();
    }

    options.src_filename = argv[optind];
    if (argc - optind == 1) {
        // Destination file name is not given, automatically set it.
        options.dst_filename = options.src_filename + ".recovered";
    } else {
        options.dst_filename = argv[optind+1];
    }

    int errcode = recover_file(options);

    if (errcode == 0) {
        return EXIT_SUCCESS;
    } else {
        return EXIT_FAILURE;
    }
}

<|endoftext|>


<commit_before>#include "CppUnitTest.h"
#include <string>
#include <vector>
#include <array>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace std;

namespace algo
{
    template<class Traits>
    class tokens
    {
        typedef vector<typename Traits::type> token_vector;
        token_vector tokens_;

    public:
        typedef typename token_vector::iterator iterator;
        typedef typename token_vector::const_iterator const_iterator;
        typedef typename Traits::type token_type;

        tokens() {}
        explicit tokens(size_t count) : tokens_(count) {}
        tokens(std::initializer_list<token_type> init) : tokens_(init) {}
        bool empty() const { return tokens_.size() == 0; }
        size_t size() const { return tokens_.size(); }
        token_type& operator[](size_t i) { return tokens_[i]; };
        const token_type& operator[](size_t i) const { return const_cast<tokens&>(*this)[i]; };

        iterator begin() { return tokens_.begin(); }
        const_iterator begin() const { return tokens_.begin(); }
        const_iterator cbegin() const { return tokens_.cbegin(); }
        iterator end() { return tokens_.end(); }
        const_iterator end() const { return tokens_.end(); }
        const_iterator cend() const { return tokens_.cend(); }

        void from_string(string s)
        {
            auto newTokens = Traits::tokenize(s);
            tokens_.insert(tokens_.end(), newTokens.begin(), newTokens.end());
        }
    };
}

namespace algo { namespace spec
{
    struct s { string val; };

    template<size_t N>
    struct test_token_traits
    {
        typedef s type;
        static array<s, N> tokenize(const string&) { return array<s, N>(); }
    };

    template<size_t N>
    using test_tokens = tokens<test_token_traits<N>>;

    TEST_CLASS(can_recognize_tokens)
	{
	public:

        TEST_METHOD(should_not_have_any_tokens_when_default_constructed)
		{
            test_tokens<0> testTokens;
            Assert::IsTrue(testTokens.empty());
		}

        TEST_METHOD(should_recognize_a_token_in_a_string)
        {
            test_tokens<1> testTokens;
            testTokens.from_string("irrelevant");
            Assert::IsFalse(testTokens.empty());
        }

        TEST_METHOD(should_recognize_more_than_one_token_in_a_string)
        {
            test_tokens<3> testTokens;
            testTokens.from_string("irrelevant");
            Assert::AreEqual(3U, testTokens.size());
        }

        TEST_METHOD(should_accumulate_tokens_from_successive_strings)
        {
            test_tokens<2> testTokens(3);
            testTokens.from_string("irrelevant");
            Assert::AreEqual(5U, testTokens.size());
        }

        TEST_METHOD(should_be_able_to_enumerate_tokens)
        {
            test_tokens<0> testTokens(3);
            size_t i = 0;
            for (s tok : testTokens) { ++i; }
            Assert::AreEqual(3U, i);
        }

        TEST_METHOD(should_be_able_to_enumerate_const_tokens_from_a_const_container)
        {
            const test_tokens<0> testTokens(3);
            size_t i = 0;
            for (const s tok : testTokens) { ++i; }
            Assert::AreEqual(3U, i);
        }

        TEST_METHOD(should_be_able_to_enumerate_const_tokens_from_a_non_const_container)
        {
            typedef test_tokens<0>::const_iterator const_iter;
            test_tokens<0> testTokens(3);
            size_t i = 0;
            for (const_iter it = testTokens.cbegin(); it != testTokens.cend(); ++it) { ++i; }
            Assert::AreEqual(3U, i);
        }

        TEST_METHOD(should_be_able_to_access_tokens_by_their_index)
        {
            test_tokens<0> testTokens = { { "one" }, { "two" }, { "three" } };
            Assert::AreEqual("one", testTokens[0].val.c_str());
            Assert::AreEqual("two", testTokens[1].val.c_str());
            Assert::AreEqual("three", testTokens[2].val.c_str());
        }

        TEST_METHOD(should_be_able_to_access_tokens_from_a_const_container_by_ther_index)
        {
            const test_tokens<0> testTokens = { { "one" } };
            Assert::AreEqual("one", testTokens[0].val.c_str());
        }

    };
}}
<commit_msg>rename a test<commit_after>#include "CppUnitTest.h"
#include <string>
#include <vector>
#include <array>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace std;

namespace algo
{
    template<class Traits>
    class tokens
    {
        typedef vector<typename Traits::type> token_vector;
        token_vector tokens_;

    public:
        typedef typename token_vector::iterator iterator;
        typedef typename token_vector::const_iterator const_iterator;
        typedef typename Traits::type token_type;

        tokens() {}
        explicit tokens(size_t count) : tokens_(count) {}
        tokens(std::initializer_list<token_type> init) : tokens_(init) {}
        bool empty() const { return tokens_.size() == 0; }
        size_t size() const { return tokens_.size(); }
        token_type& operator[](size_t i) { return tokens_[i]; };
        const token_type& operator[](size_t i) const { return const_cast<tokens&>(*this)[i]; };

        iterator begin() { return tokens_.begin(); }
        const_iterator begin() const { return tokens_.begin(); }
        const_iterator cbegin() const { return tokens_.cbegin(); }
        iterator end() { return tokens_.end(); }
        const_iterator end() const { return tokens_.end(); }
        const_iterator cend() const { return tokens_.cend(); }

        void from_string(string s)
        {
            auto newTokens = Traits::tokenize(s);
            tokens_.insert(tokens_.end(), newTokens.begin(), newTokens.end());
        }
    };
}

namespace algo { namespace spec
{
    struct s { string val; };

    template<size_t N>
    struct test_token_traits
    {
        typedef s type;
        static array<s, N> tokenize(const string&) { return array<s, N>(); }
    };

    template<size_t N>
    using test_tokens = tokens<test_token_traits<N>>;

    TEST_CLASS(can_recognize_tokens)
	{
	public:

        TEST_METHOD(should_not_have_any_tokens_when_default_constructed)
		{
            test_tokens<0> testTokens;
            Assert::IsTrue(testTokens.empty());
		}

        TEST_METHOD(should_recognize_a_token_in_a_string)
        {
            test_tokens<1> testTokens;
            testTokens.from_string("irrelevant");
            Assert::AreEqual(1U, testTokens.size());
        }

        TEST_METHOD(should_recognize_more_than_one_token_in_a_string)
        {
            test_tokens<3> testTokens;
            testTokens.from_string("irrelevant");
            Assert::AreEqual(3U, testTokens.size());
        }

        TEST_METHOD(should_accumulate_tokens_from_successive_strings)
        {
            test_tokens<2> testTokens(3);
            testTokens.from_string("irrelevant");
            Assert::AreEqual(5U, testTokens.size());
        }

        TEST_METHOD(should_be_able_to_enumerate_tokens)
        {
            test_tokens<0> testTokens(3);
            size_t i = 0;
            for (s tok : testTokens) { ++i; }
            Assert::AreEqual(3U, i);
        }

        TEST_METHOD(should_be_able_to_enumerate_const_tokens_from_a_const_container)
        {
            const test_tokens<0> testTokens(3);
            size_t i = 0;
            for (const s tok : testTokens) { ++i; }
            Assert::AreEqual(3U, i);
        }

        TEST_METHOD(should_be_able_to_enumerate_const_tokens_from_a_non_const_container)
        {
            typedef test_tokens<0>::const_iterator const_iter;
            test_tokens<0> testTokens(3);
            size_t i = 0;
            for (const_iter it = testTokens.cbegin(); it != testTokens.cend(); ++it) { ++i; }
            Assert::AreEqual(3U, i);
        }

        TEST_METHOD(should_be_able_to_access_tokens_by_their_index)
        {
            test_tokens<0> testTokens = { { "one" }, { "two" }, { "three" } };
            Assert::AreEqual("one", testTokens[0].val.c_str());
            Assert::AreEqual("two", testTokens[1].val.c_str());
            Assert::AreEqual("three", testTokens[2].val.c_str());
        }

        TEST_METHOD(should_be_able_to_access_tokens_from_a_const_container_by_ther_index)
        {
            const test_tokens<0> testTokens = { { "one" } };
            Assert::AreEqual("one", testTokens[0].val.c_str());
        }

    };
}}
<|endoftext|>