text:
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.
//
// The following only applies to changes made to this file as part of YugaByte development.
//
// Portions Copyright (c) YugaByte, 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 <chrono>
#include <iostream>

#include <boost/optional/optional.hpp>
#include <glog/logging.h>

#ifdef TCMALLOC_ENABLED
#include <gperftools/malloc_extension.h>
#endif

#include "yb/consensus/log_util.h"
#include "yb/consensus/consensus_queue.h"

#include "yb/encryption/header_manager_impl.h"
#include "yb/encryption/encrypted_file_factory.h"
#include "yb/encryption/universe_key_manager.h"

#include "yb/yql/cql/cqlserver/cql_server.h"
#include "yb/yql/pgwrapper/pg_wrapper.h"
#include "yb/yql/redis/redisserver/redis_server.h"

#include "yb/gutil/strings/substitute.h"
#include "yb/master/call_home.h"
#include "yb/rpc/io_thread_pool.h"
#include "yb/rpc/scheduler.h"
#include "yb/server/skewed_clock.h"
#include "yb/server/secure.h"
#include "yb/tserver/factory.h"
#include "yb/tserver/tablet_server.h"

#include "yb/util/flags.h"
#include "yb/util/init.h"
#include "yb/util/logging.h"
#include "yb/util/main_util.h"
#include "yb/util/result.h"
#include "yb/util/ulimit_util.h"
#include "yb/util/size_literals.h"
#include "yb/util/net/net_util.h"
#include "yb/util/status_log.h"
#include "yb/util/debug/trace_event.h"

#include "yb/rocksutil/rocksdb_encrypted_file_factory.h"

#include "yb/tserver/server_main_util.h"

using namespace std::placeholders;

using yb::redisserver::RedisServer;
using yb::redisserver::RedisServerOptions;

using yb::cqlserver::CQLServer;
using yb::cqlserver::CQLServerOptions;

using yb::pgwrapper::PgProcessConf;
using yb::pgwrapper::PgWrapper;
using yb::pgwrapper::PgSupervisor;

using namespace yb::size_literals;  // NOLINT

DEFINE_bool(start_redis_proxy, true, "Starts a redis proxy along with the tablet server");

DEFINE_bool(start_cql_proxy, true, "Starts a CQL proxy along with the tablet server");
DEFINE_string(cql_proxy_broadcast_rpc_address, "",
              "RPC address to broadcast to other nodes. This is the broadcast_address used in the"
                  " system.local table");

DECLARE_string(rpc_bind_addresses);
DECLARE_bool(callhome_enabled);
DECLARE_int32(webserver_port);
DECLARE_int32(logbuflevel);
DECLARE_int32(stderrthreshold);

DECLARE_string(redis_proxy_bind_address);
DECLARE_int32(redis_proxy_webserver_port);

DECLARE_string(cql_proxy_bind_address);
DECLARE_int32(cql_proxy_webserver_port);

DECLARE_string(pgsql_proxy_bind_address);
DECLARE_bool(start_pgsql_proxy);
DECLARE_bool(enable_ysql);

DECLARE_int64(remote_bootstrap_rate_limit_bytes_per_sec);

DECLARE_bool(use_client_to_server_encryption);
DECLARE_string(certs_dir);
DECLARE_string(certs_for_client_dir);
DECLARE_string(cert_node_filename);
DECLARE_string(ysql_hba_conf);
DECLARE_string(ysql_pg_conf);
DECLARE_string(metric_node_name);

// Deprecated because it's misspelled.  But if set, this flag takes precedence over
// remote_bootstrap_rate_limit_bytes_per_sec for compatibility.
DECLARE_int64(remote_boostrap_rate_limit_bytes_per_sec);

namespace yb {
namespace tserver {
namespace {

void SetProxyAddress(std::string* flag, const std::string& name, uint16_t port) {
  if (flag->empty()) {
    std::vector<HostPort> bind_addresses;
    Status status = HostPort::ParseStrings(FLAGS_rpc_bind_addresses, 0, &bind_addresses);
    LOG_IF(DFATAL, !status.ok()) << "Bad public IPs " << FLAGS_rpc_bind_addresses << ": " << status;
    if (!bind_addresses.empty()) {
      for (auto& addr : bind_addresses) {
        addr.set_port(port);
      }
      *flag = HostPort::ToCommaSeparatedString(bind_addresses);
      LOG(INFO) << "Reset " << name << " bind address to " << *flag;
    }
  }
}

// Helper function to set the proxy rpc addresses based on rpc_bind_addresses.
void SetProxyAddresses() {
  LOG(INFO) << "Using parsed rpc = " << FLAGS_rpc_bind_addresses;
  SetProxyAddress(&FLAGS_redis_proxy_bind_address, "YEDIS", RedisServer::kDefaultPort);
  SetProxyAddress(&FLAGS_cql_proxy_bind_address, "YCQL", CQLServer::kDefaultPort);
  SetProxyAddress(&FLAGS_pgsql_proxy_bind_address, "YSQL", PgProcessConf::kDefaultPort);
}

int TabletServerMain(int argc, char** argv) {
#ifndef NDEBUG
  HybridTime::TEST_SetPrettyToString(true);
#endif

  // Reset some default values before parsing gflags.
  FLAGS_rpc_bind_addresses = strings::Substitute("0.0.0.0:$0",
                                                 TabletServer::kDefaultPort);
  FLAGS_webserver_port = TabletServer::kDefaultWebPort;
  FLAGS_redis_proxy_webserver_port = RedisServer::kDefaultWebPort;
  FLAGS_cql_proxy_webserver_port = CQLServer::kDefaultWebPort;

  string host_name;
  if (GetHostname(&host_name).ok()) {
    FLAGS_metric_node_name = strings::Substitute("$0:$1", host_name, TabletServer::kDefaultWebPort);
  } else {
    LOG(INFO) << "Failed to get tablet's host name, keeping default metric_node_name";
  }

  LOG_AND_RETURN_FROM_MAIN_NOT_OK(MasterTServerParseFlagsAndInit(
      TabletServerOptions::kServerType, &argc, &argv));

  SetProxyAddresses();

  // Object that manages the universe key registry used for encrypting and decrypting data keys.
  // Copies are given to each Env.
  auto universe_key_manager = std::make_unique<encryption::UniverseKeyManager>();
  // Encrypted env for all non-rocksdb file i/o operations.
  std::unique_ptr<yb::Env> env =
      NewEncryptedEnv(DefaultHeaderManager(universe_key_manager.get()));
  // Encrypted env for all rocksdb file i/o operations.
  std::unique_ptr<rocksdb::Env> rocksdb_env =
      NewRocksDBEncryptedEnv(DefaultHeaderManager(universe_key_manager.get()));

  auto tablet_server_options = TabletServerOptions::CreateTabletServerOptions();
  LOG_AND_RETURN_FROM_MAIN_NOT_OK(tablet_server_options);
  tablet_server_options->env = env.get();
  tablet_server_options->rocksdb_env = rocksdb_env.get();
  tablet_server_options->universe_key_manager = universe_key_manager.get();
  enterprise::Factory factory;

  auto server = factory.CreateTabletServer(*tablet_server_options);

  // ----------------------------------------------------------------------------------------------
  // Starting to instantiate servers
  // ----------------------------------------------------------------------------------------------

  LOG(INFO) << "Initializing tablet server...";
  LOG_AND_RETURN_FROM_MAIN_NOT_OK(server->Init());
  LOG(INFO) << "Starting tablet server...";
  UlimitUtil::InitUlimits();
  LOG(INFO) << "ulimit cur(max)..." << UlimitUtil::GetUlimitInfo();
  LOG_AND_RETURN_FROM_MAIN_NOT_OK(server->Start());
  LOG(INFO) << "Tablet server successfully started.";

  std::unique_ptr<CallHome> call_home;
  call_home = std::make_unique<CallHome>(server.get(), ServerType::TSERVER);
  call_home->ScheduleCallHome();

  std::unique_ptr<PgSupervisor> pg_supervisor;
  if (FLAGS_start_pgsql_proxy || FLAGS_enable_ysql) {
    auto pg_process_conf_result = PgProcessConf::CreateValidateAndRunInitDb(
        FLAGS_pgsql_proxy_bind_address,
        tablet_server_options->fs_opts.data_paths.front() + "/pg_data",
        server->GetSharedMemoryFd());
    LOG_AND_RETURN_FROM_MAIN_NOT_OK(pg_process_conf_result);
    auto& pg_process_conf = *pg_process_conf_result;
    pg_process_conf.master_addresses = tablet_server_options->master_addresses_flag;
    pg_process_conf.certs_dir = FLAGS_certs_dir.empty()
        ? server::DefaultCertsDir(*server->fs_manager())
        : FLAGS_certs_dir;
    pg_process_conf.certs_for_client_dir = FLAGS_certs_for_client_dir.empty()
        ? pg_process_conf.certs_dir
        : FLAGS_certs_for_client_dir;
    pg_process_conf.enable_tls = FLAGS_use_client_to_server_encryption;

    // Follow the same logic as elsewhere, check FLAGS_cert_node_filename then
    // server_broadcast_addresses then rpc_bind_addresses.
    if (!FLAGS_cert_node_filename.empty()) {
      pg_process_conf.cert_base_name = FLAGS_cert_node_filename;
    } else {
      const auto server_broadcast_addresses =
          HostPort::ParseStrings(server->options().server_broadcast_addresses, 0);
      LOG_AND_RETURN_FROM_MAIN_NOT_OK(server_broadcast_addresses);
      const auto rpc_bind_addresses =
          HostPort::ParseStrings(server->options().rpc_opts.rpc_bind_addresses, 0);
      LOG_AND_RETURN_FROM_MAIN_NOT_OK(rpc_bind_addresses);
      pg_process_conf.cert_base_name = !server_broadcast_addresses->empty()
                                     ? server_broadcast_addresses->front().host()
                                     : rpc_bind_addresses->front().host();
    }
    LOG(INFO) << "Starting PostgreSQL server listening on "
              << pg_process_conf.listen_addresses << ", port " << pg_process_conf.pg_port;

    pg_supervisor = std::make_unique<PgSupervisor>(pg_process_conf, server.get());
    LOG_AND_RETURN_FROM_MAIN_NOT_OK(pg_supervisor->Start());
  }

  std::unique_ptr<RedisServer> redis_server;
  if (FLAGS_start_redis_proxy) {
    RedisServerOptions redis_server_options;
    redis_server_options.rpc_opts.rpc_bind_addresses = FLAGS_redis_proxy_bind_address;
    redis_server_options.webserver_opts.port = FLAGS_redis_proxy_webserver_port;
    redis_server_options.master_addresses_flag = tablet_server_options->master_addresses_flag;
    redis_server_options.SetMasterAddresses(tablet_server_options->GetMasterAddresses());
    redis_server_options.dump_info_path =
        (tablet_server_options->dump_info_path.empty()
             ? ""
             : tablet_server_options->dump_info_path + "-redis");
    redis_server.reset(new RedisServer(redis_server_options, server.get()));
    LOG(INFO) << "Starting redis server...";
    LOG_AND_RETURN_FROM_MAIN_NOT_OK(redis_server->Start());
    LOG(INFO) << "Redis server successfully started.";
  }

  // TODO(neil): After CQL server is starting, it blocks this thread from moving on.
  // This should be fixed such that all processes or service by tablet server are treated equally
  // by using different threads for each process.
  std::unique_ptr<CQLServer> cql_server;
  if (FLAGS_start_cql_proxy) {
    CQLServerOptions cql_server_options;
    cql_server_options.rpc_opts.rpc_bind_addresses = FLAGS_cql_proxy_bind_address;
    cql_server_options.broadcast_rpc_address = FLAGS_cql_proxy_broadcast_rpc_address;
    cql_server_options.webserver_opts.port = FLAGS_cql_proxy_webserver_port;
    cql_server_options.master_addresses_flag = tablet_server_options->master_addresses_flag;
    cql_server_options.SetMasterAddresses(tablet_server_options->GetMasterAddresses());
    cql_server_options.dump_info_path =
        (tablet_server_options->dump_info_path.empty()
             ? ""
             : tablet_server_options->dump_info_path + "-cql");
    boost::asio::io_service io;
    cql_server = factory.CreateCQLServer(cql_server_options, &io, server.get());
    LOG(INFO) << "Starting CQL server...";
    LOG_AND_RETURN_FROM_MAIN_NOT_OK(cql_server->Start());
    LOG(INFO) << "CQL server successfully started.";

    // Should run forever unless there are some errors.
    boost::system::error_code ec;
    io.run(ec);
    if (ec) {
      LOG(WARNING) << "IO service run failure: " << ec;
    }

    LOG (WARNING) << "CQL Server shutting down";
    cql_server->Shutdown();
  }

  while (true) {
    SleepFor(MonoDelta::FromSeconds(60));
  }

  return 0;
}

}  // namespace
}  // namespace tserver
}  // namespace yb

int main(int argc, char** argv) {
  return yb::tserver::TabletServerMain(argc, argv);
}

max_stars_repo_name: asad-awadia/yugabyte-db

max_issues_repo_name: asad-awadia/yugabyte-db

max_forks_repo_name: asad-awadia/yugabyte-db


text:
/**
 * Canary - A free and open-source MMORPG server emulator
 * Copyright (C) 2021 OpenTibiaBR <opentibiabr@outlook.com>
 *
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "otpch.h"

#include <boost/range/adaptor/reversed.hpp>

#include "game/game.h"
#include "game/movement/position.h"
#include "lua/functions/map/position_functions.hpp"

int PositionFunctions::luaPositionCreate(lua_State* L) {
	// Position([x = 0[, y = 0[, z = 0[, stackpos = 0]]]])
	// Position([position])
	if (lua_gettop(L) <= 1) {
		pushPosition(L, Position());
		return 1;
	}

	int32_t stackpos;
	if (isTable(L, 2)) {
		const Position& position = getPosition(L, 2, stackpos);
		pushPosition(L, position, stackpos);
	} else {
		uint16_t x = getNumber<uint16_t>(L, 2, 0);
		uint16_t y = getNumber<uint16_t>(L, 3, 0);
		uint8_t z = getNumber<uint8_t>(L, 4, 0);
		stackpos = getNumber<int32_t>(L, 5, 0);

		pushPosition(L, Position(x, y, z), stackpos);
	}
	return 1;
}

int PositionFunctions::luaPositionAdd(lua_State* L) {
	// positionValue = position + positionEx
	int32_t stackpos;
	const Position& position = getPosition(L, 1, stackpos);

	Position positionEx;
	if (stackpos == 0) {
		positionEx = getPosition(L, 2, stackpos);
	} else {
		positionEx = getPosition(L, 2);
	}

	pushPosition(L, position + positionEx, stackpos);
	return 1;
}

int PositionFunctions::luaPositionSub(lua_State* L) {
	// positionValue = position - positionEx
	int32_t stackpos;
	const Position& position = getPosition(L, 1, stackpos);

	Position positionEx;
	if (stackpos == 0) {
		positionEx = getPosition(L, 2, stackpos);
	} else {
		positionEx = getPosition(L, 2);
	}

	pushPosition(L, position - positionEx, stackpos);
	return 1;
}

int PositionFunctions::luaPositionCompare(lua_State* L) {
	// position == positionEx
	const Position& positionEx = getPosition(L, 2);
	const Position& position = getPosition(L, 1);
	pushBoolean(L, position == positionEx);
	return 1;
}

int PositionFunctions::luaPositionGetDistance(lua_State* L) {
	// position:getDistance(positionEx)
	const Position& positionEx = getPosition(L, 2);
	const Position& position = getPosition(L, 1);
	lua_pushnumber(L, std::max<int32_t>(
		std::max<int32_t>(
			std::abs(Position::getDistanceX(position, positionEx)),
			std::abs(Position::getDistanceY(position, positionEx))
		),
		std::abs(Position::getDistanceZ(position, positionEx))
	));
	return 1;
}

int PositionFunctions::luaPositionGetPathTo(lua_State* L) {
	// position:getPathTo(pos[, minTargetDist = 0[, maxTargetDist = 1[, fullPathSearch = true[, clearSight = true[, maxSearchDist = 0]]]]])
	const Position& pos = getPosition(L, 1);
	const Position& position = getPosition(L, 2);

	FindPathParams fpp;
	fpp.minTargetDist = getNumber<int32_t>(L, 3, 0);
	fpp.maxTargetDist = getNumber<int32_t>(L, 4, 1);
	fpp.fullPathSearch = getBoolean(L, 5, fpp.fullPathSearch);
	fpp.clearSight = getBoolean(L, 6, fpp.clearSight);
	fpp.maxSearchDist = getNumber<int32_t>(L, 7, fpp.maxSearchDist);

	std::forward_list<Direction> dirList;
	if (g_game().map.getPathMatching(pos, dirList, FrozenPathingConditionCall(position), fpp)) {
		lua_newtable(L);

		int index = 0;
		for (Direction dir : dirList) {
			lua_pushnumber(L, dir);
			lua_rawseti(L, -2, ++index);
		}
	}
	else {
		pushBoolean(L, false);
	}
	return 1;
}

int PositionFunctions::luaPositionIsSightClear(lua_State* L) {
	// position:isSightClear(positionEx[, sameFloor = true])
	bool sameFloor = getBoolean(L, 3, true);
	const Position& positionEx = getPosition(L, 2);
	const Position& position = getPosition(L, 1);
	pushBoolean(L, g_game().isSightClear(position, positionEx, sameFloor));
	return 1;
}

int PositionFunctions::luaPositionSendMagicEffect(lua_State* L) {
	// position:sendMagicEffect(magicEffect[, player = nullptr])
	SpectatorHashSet spectators;
	if (lua_gettop(L) >= 3) {
		Player* player = getPlayer(L, 3);
		if (player) {
			spectators.insert(player);
		}
	}

	MagicEffectClasses magicEffect = getNumber<MagicEffectClasses>(L, 2);
	const Position& position = getPosition(L, 1);
	if (!spectators.empty()) {
		Game::addMagicEffect(spectators, position, magicEffect);
	} else {
		g_game().addMagicEffect(position, magicEffect);
	}

	pushBoolean(L, true);
	return 1;
}

int PositionFunctions::luaPositionSendDistanceEffect(lua_State* L) {
	// position:sendDistanceEffect(positionEx, distanceEffect[, player = nullptr])
	SpectatorHashSet spectators;
	if (lua_gettop(L) >= 4) {
		Player* player = getPlayer(L, 4);
		if (player) {
			spectators.insert(player);
		}
	}

	ShootType_t distanceEffect = getNumber<ShootType_t>(L, 3);
	const Position& positionEx = getPosition(L, 2);
	const Position& position = getPosition(L, 1);
	if (!spectators.empty()) {
		Game::addDistanceEffect(spectators, position, positionEx, distanceEffect);
	} else {
		g_game().addDistanceEffect(position, positionEx, distanceEffect);
	}

	pushBoolean(L, true);
	return 1;
}

ext: cpp

max_stars_repo_name: Waclaw-I/BagnoOTS

max_issues_repo_name: Waclaw-I/BagnoOTS

max_forks_repo_name: Waclaw-I/BagnoOTS


text:
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp>

#include "base58.h"
#include "bitcoinrpc.h"
#include "db.h"
#include "init.h"
#include "net.h"
#include "wallet.h"
#include "freespeech.h"

using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace json_spirit;

//
// Utilities: convert hex-encoded Values
// (throws error if not hex).
//
uint256 ParseHashV(const Value& v, string strName)
{
    string strHex;
    if (v.type() == str_type)
        strHex = v.get_str();
    if (!IsHex(strHex)) // Note: IsHex("") is false
        throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
    uint256 result;
    result.SetHex(strHex);
    return result;
}
uint256 ParseHashO(const Object& o, string strKey)
{
    return ParseHashV(find_value(o, strKey), strKey);
}
vector<unsigned char> ParseHexV(const Value& v, string strName)
{
    string strHex;
    if (v.type() == str_type)
        strHex = v.get_str();
    if (!IsHex(strHex))
        throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
    return ParseHex(strHex);
}
vector<unsigned char> ParseHexO(const Object& o, string strKey)
{
    return ParseHexV(find_value(o, strKey), strKey);
}

void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
{
    txnouttype type;
    vector<CTxDestination> addresses;
    int nRequired;

    out.push_back(Pair("asm", scriptPubKey.ToString()));
    out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));

    if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
    {
        out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
        return;
    }

    out.push_back(Pair("reqSigs", nRequired));
    out.push_back(Pair("type", GetTxnOutputType(type)));

    Array a;
    BOOST_FOREACH(const CTxDestination& addr, addresses)
        a.push_back(CBitcoinAddress(addr).ToString());
    out.push_back(Pair("addresses", a));
}

void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
{
    entry.push_back(Pair("txid", tx.GetUsernameHash().GetHex()));
    entry.push_back(Pair("version", tx.nVersion));
    entry.push_back(Pair("message", tx.message.ExtractPushDataString(0)));
    entry.push_back(Pair("username", tx.userName.ExtractPushDataString(0)));
    std::vector< std::vector<unsigned char> > vData;
    if( tx.pubKey.ExtractPushData(vData) ) {
        Array o;
        BOOST_FOREACH(std::vector<unsigned char> vch, vData) {
          o.push_back(HexStr(vch));
        }
        entry.push_back(Pair("pubKey", o));
    }
    entry.push_back(Pair("nonce", (int) tx.nNonce));

    if (hashBlock != 0)
    {
        entry.push_back(Pair("blockhash", hashBlock.GetHex()));
        map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
        if (mi != mapBlockIndex.end() && (*mi).second)
        {
            CBlockIndex* pindex = (*mi).second;
            if (pindex->IsInMainChain())
            {
                entry.push_back(Pair("height", pindex->nHeight));
                entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
                entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
                entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
            }
            else
                entry.push_back(Pair("confirmations", 0));
        }
    }
}

Value getrawtransaction(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getrawtransaction <username> [verbose=0]\n"
            "If verbose=0, returns a string that is\n"
            "serialized, hex-encoded data for <txid>.\n"
            "If verbose is non-zero, returns an Object\n"
            "with information about transaction.");

    //uint256 hash = ParseHashV(params[0], "parameter 1");
    std::string username = params[0].get_str();

    bool fVerbose = false;
    if (params.size() > 1)
        fVerbose = (params[1].get_int() != 0);

    CTransaction tx;
    uint256 hashBlock = 0;
    if (!GetTransaction(username, tx, hashBlock))
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");

    CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    ssTx << tx;
    string strHex = HexStr(ssTx.begin(), ssTx.end());

    if (!fVerbose)
        return strHex;

    Object result;
    result.push_back(Pair("hex", strHex));
    TxToJSON(tx, hashBlock, result);
    return result;
}

Value createrawtransaction(const Array& params, bool fHelp)
{
    if (fHelp || (params.size() != 2 && params.size() != 3))
        throw runtime_error(
            "createrawtransaction <username> <pubKey> [signedByOldKey]\n"
            "Create a transaction registering a new user\n"
            "Returns hex-encoded raw transaction.\n"
            "it is not stored in the wallet or transmitted to the network.");

    CTransaction rawTx;

    if (params[0].type() != str_type)
      throw JSONRPCError(RPC_INVALID_PARAMETER, "username must be string");
    string username = params[0].get_str();
    rawTx.userName = CScript() << vector<unsigned char>((const unsigned char*)username.data(), (const unsigned char*)username.data() + username.size());

    vector<unsigned char> vch(ParseHexV(params[1], "pubkey"));
    CPubKey pubkey(vch);
    if( !pubkey.IsValid() )
      throw JSONRPCError(RPC_INTERNAL_ERROR, "pubkey is not valid");

    rawTx.pubKey << vch;
    if( params.size() > 2) {
        vector<unsigned char> vchSign(ParseHexV(params[2], "signedByOldKey"));
        rawTx.pubKey << vchSign;
    }

    DoTxProofOfWork(rawTx);

    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
    ss << rawTx;
    return HexStr(ss.begin(), ss.end());
}

Value decoderawtransaction(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "decoderawtransaction <hex string>\n"
            "Return a JSON object representing the serialized, hex-encoded transaction.");

    vector<unsigned char> txData(ParseHexV(params[0], "argument"));
    CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
    CTransaction tx;
    try {
        ssData >> tx;
    }
    catch (std::exception &e) {
        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
    }

    Object result;
    TxToJSON(tx, 0, result);

    return result;
}

Value sendrawtransaction(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 1)
        throw runtime_error(
            "sendrawtransaction <hex string>\n"
            "Submits raw transaction (serialized, hex-encoded) to local node and network.");

    // parse hex string from parameter
    vector<unsigned char> txData(ParseHexV(params[0], "parameter"));
    CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
    CTransaction tx;

    // deserialize binary data stream
    try {
        ssData >> tx;
    }
    catch (std::exception &e) {
        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
    }
    uint256 hashTx = tx.GetHash();

    bool fHave = false;
    uint256 hashBlock;
    CTransaction tx2;
    fHave = GetTransaction(tx.GetUsername(), tx2, hashBlock);

    // treat replacement as !fHave
    if( fHave && verifyDuplicateOrReplacementTx(tx, false, true) ) {
        printf("sendrawtransaction: is ReplacementTx true\n");
        fHave = false;
    }

    if (!fHave) {
        // push to local node
        CValidationState state;
        if (!mempool.accept(state, tx, false, NULL))
            throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state
    }
    if (fHave) {
        if (hashBlock != uint256())
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain");
        if (tx.GetHash() != tx2.GetHash())
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "conflict transaction detected (same user, different tx)");
        // Not in block, but already in the memory pool; will drop
        // through to re-relay it.
    } else {
        SyncWithWallets(hashTx, tx, NULL, true);
    }
    RelayTransaction(tx, hashTx);

    return hashTx.GetHex();
}

Value sendnewusertransaction(const Array& params, bool fHelp)
{
  if (fHelp || params.size() != 1)
      throw runtime_error(
          "sendnewusertransaction <username>\n"
          "Send a transaction registering a previously created new user\n"
          "using createwalletuser or imported to the wallet\n"
          "Submits raw transaction (serialized, hex-encoded) to local node and network.");

  if (params[0].type() != str_type)
    throw JSONRPCError(RPC_INVALID_PARAMETER, "username must be string");
  string strUsername = params[0].get_str();

  CKeyID oldKeyID;
  bool replaceKey = pwalletMain->GetKeyIdBeingReplaced(strUsername, oldKeyID);

  CKeyID keyID;
  if( !pwalletMain->GetKeyIdFromUsername(strUsername, keyID) )
    throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Error: username must exist in wallet");

  CPubKey pubkey;
  if( !pwalletMain->GetPubKey(keyID, pubkey) )
    throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Error: no public key found");

  // [MF] prevent redoing POW and resending an existing transaction
  CTransaction txOut;
  uint256 hashBlock;
  bool userInTxIndex = GetTransaction(strUsername, txOut, hashBlock);
  if( !replaceKey && userInTxIndex )
      throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Error: this username exists in tx database");
  if( replaceKey && !userInTxIndex )
      throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Error: key replacemente requires old key in tx database");

  Array createTxParams;
  createTxParams.push_back(strUsername);
  createTxParams.push_back(HexStr(pubkey));
  if( replaceKey ) {
    string newPubKey((const char *)pubkey.begin(), static_cast<size_t>(pubkey.size()));
    string signedByOldKey;
    signedByOldKey = createSignature(newPubKey, oldKeyID);
    createTxParams.push_back(HexStr(signedByOldKey));
  }
  Value txValue = createrawtransaction(createTxParams, false);

  if( replaceKey ) {
      pwalletMain->ForgetReplacementMap(strUsername);
  }

  std::string strTxHex = txValue.get_str();
  Array sendTxParams;
  sendTxParams.push_back(strTxHex);
  return sendrawtransaction(sendTxParams, false);
}

max_stars_repo_name: latcoin/freespeech

max_issues_repo_name: latcoin/freespeech

max_forks_repo_name: latcoin/freespeech


text:
// Copyright (C) 2014 The Regents of the University of California (Regents).
// 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 Regents or University of California 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 HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include "theia/sfm/filter_view_graph_cycles_by_rotation.h"

#include <ceres/rotation.h>
#include <Eigen/Core>
#include <glog/logging.h>
#include <unordered_map>
#include <vector>

#include "theia/math/util.h"
#include "theia/util/hash.h"
#include "theia/sfm/twoview_info.h"
#include "theia/sfm/types.h"
#include "theia/sfm/view_graph/triplet_extractor.h"
#include "theia/sfm/view_graph/view_graph.h"
#include "theia/sfm/view_triplet.h"

namespace theia {

namespace {

double ComputeLoopRotationError(const ViewTriplet& triplet) {
  // Get relative rotation matrices.
  Eigen::Matrix3d rotation1_2, rotation1_3, rotation2_3;
  ceres::AngleAxisToRotationMatrix(
      triplet.info_one_two.rotation_2.data(),
      ceres::ColumnMajorAdapter3x3(rotation1_2.data()));
  ceres::AngleAxisToRotationMatrix(
      triplet.info_one_three.rotation_2.data(),
      ceres::ColumnMajorAdapter3x3(rotation1_3.data()));
  ceres::AngleAxisToRotationMatrix(
      triplet.info_two_three.rotation_2.data(),
      ceres::ColumnMajorAdapter3x3(rotation2_3.data()));

  // Compute loop rotation.
  const Eigen::Matrix3d loop_rotation =
      rotation2_3 * rotation1_2 * rotation1_3.transpose();
  Eigen::Vector3d loop_rotation_angle_axis;
  ceres::RotationMatrixToAngleAxis(
      ceres::ColumnMajorAdapter3x3(loop_rotation.data()),
      loop_rotation_angle_axis.data());

  // Return the angle of the loop rotation which is the error of the
  // concatenated triplet rotation.
  return RadToDeg(loop_rotation_angle_axis.norm());
}

void RemoveTripletEdgesFromInvalidViewPairs(
    const ViewTriplet& triplet,
    std::unordered_set<ViewIdPair>* invalid_view_pairs) {
  invalid_view_pairs->erase(
      ViewIdPair(triplet.view_ids[0], triplet.view_ids[1]));
  invalid_view_pairs->erase(
      ViewIdPair(triplet.view_ids[0], triplet.view_ids[2]));
  invalid_view_pairs->erase(
      ViewIdPair(triplet.view_ids[1], triplet.view_ids[2]));
}

}  // namespace

void FilterViewGraphCyclesByRotation(const double max_loop_error_degrees,
                                     ViewGraph* view_graph) {
  const std::unordered_map<ViewIdPair, TwoViewInfo>& view_pairs =
      view_graph->GetAllEdges();

  // Find all triplets.
  TripletExtractor triplet_extractor;
  std::vector<std::vector<ViewTriplet> > connected_triplets;
  CHECK(triplet_extractor.ExtractTripletsFromViewPairs(view_pairs,
                                                       &connected_triplets))
      << "Could not extract triplets from view pairs.";

  // Create a list of invalid view pairs. View pairs deemed valid will be
  // removed from this list.
  std::unordered_set<ViewIdPair> invalid_view_pairs;
  invalid_view_pairs.reserve(view_pairs.size());
  for (const auto& view_pair : view_pairs) {
    invalid_view_pairs.insert(view_pair.first);
  }

  // Examine the cycles of size 3 to determine invalid view pairs from the
  // rotations.
  for (const auto& triplets : connected_triplets) {
    for (const ViewTriplet& triplet : triplets) {
      // Compute loop rotation error.
      const double loop_rotation_error_degrees =
          ComputeLoopRotationError(triplet);
      LOG(INFO) << "Loop rotation error = " << loop_rotation_error_degrees;
      // Add the view pairs to the list of valid view pairs if the loop error is
      // within the designated tolerance.
      if (loop_rotation_error_degrees < max_loop_error_degrees) {
        RemoveTripletEdgesFromInvalidViewPairs(triplet, &invalid_view_pairs);
      }
    }
  }

  VLOG(1) << "Removing " << invalid_view_pairs.size() << " of "
          << view_pairs.size() << " view pairs from loop rotation filtering.";

  // Remove any view pairs not in the list of valid edges.
  for (const ViewIdPair& view_pair_id : invalid_view_pairs) {
    view_graph->RemoveEdge(view_pair_id.first, view_pair_id.second);
  }
}

}  // namespace theia

ext: cc


text:
// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <config.h>
#include <asiolink/io_address.h>
#include <dhcp/duid.h>
#include <dhcp_ddns/ncr_msg.h>
#include <dhcpsrv/ncr_generator.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/d2_client_mgr.h>
#include <dhcpsrv/lease.h>

#include <ctime>
#include <boost/bind.hpp>
#include <gtest/gtest.h>

#include <stdint.h>
#include <string>

using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::dhcp_ddns;

namespace {

/// @brief Base test fixture class for testing generation of the name
/// change requests from leases.
///
/// @tparam LeasePtrType One of the @c Lease4Ptr or @c Lease6Ptr.
template<typename LeasePtrType>
class NCRGeneratorTest : public ::testing::Test {
public:

    /// @brief Reference to the D2 client manager.
    D2ClientMgr& d2_mgr_;

    /// @brief Pointer to the lease object used by the tests.
    LeasePtrType lease_;

    /// @brief Constructor.
    NCRGeneratorTest()
        : d2_mgr_(CfgMgr::instance().getD2ClientMgr()), lease_() {
    }

    /// @brief Initializes the lease pointer used by the tests and starts D2.
    ///
    /// This method initializes the pointer to the lease which will be used
    /// throughout the tests. Because the lease may be either a v4 or v6 lease
    /// it calls a virtual function @c initLease, which must be implemented
    /// in the derived classes as appropriate. Note that lease object can't
    /// be initialized in the constructor, because it is not allowed to
    /// call virtual functions in the constructors. Hence, the @c SetUp
    /// function is needed.
    virtual void SetUp() {
        // Base class SetUp.
        ::testing::Test::SetUp();
        // Initialize lease_ object.
        initLease();
        // Start D2 by default.
        enableD2();
    }

    /// @brief Stops D2.
    virtual void TearDown() {
        // Stop D2 if running.
        disableD2();
        // Base class TearDown.
        ::testing::Test::TearDown();
    }

    /// @brief Enables DHCP-DDNS updates.
    ///
    /// Replaces the current D2ClientConfiguration with a configuration
    /// which has updates enabled and the control options set based upon
    /// the bit mask of options.
    void enableD2() {
        D2ClientConfigPtr cfg(new D2ClientConfig());
        ASSERT_NO_THROW(cfg->enableUpdates(true));
        ASSERT_NO_THROW(CfgMgr::instance().setD2ClientConfig(cfg));
        d2_mgr_.startSender(boost::bind(&NCRGeneratorTest::d2ErrorHandler, this,
                                        _1, _2));
    }

    /// @brief Disables DHCP-DDNS updates.
    void disableD2() {
        d2_mgr_.stopSender();
        // Default constructor creates a config with DHCP-DDNS updates
        // disabled.
        D2ClientConfigPtr cfg(new D2ClientConfig());
        CfgMgr::instance().setD2ClientConfig(cfg);
    }

    /// @brief No-op error handler for D2.
    void d2ErrorHandler(const NameChangeSender::Result, NameChangeRequestPtr&) {
        // no-op
    }

    /// @brief Abstract method to initialize @c lease_ object.
    virtual void initLease() = 0;

    /// @brief Verify that NameChangeRequest holds valid values.
    ///
    /// This function picks first NameChangeRequest from the internal server's
    /// queue and checks that it holds valid parameters. The NameChangeRequest
    /// is removed from the queue.
    ///
    /// @param type An expected type of the NameChangeRequest (Add or Remove).
    /// @param reverse An expected setting of the reverse update flag.
    /// @param forward An expected setting of the forward update flag.
    /// @param addr A string representation of the IPv6 address held in the
    /// NameChangeRequest.
    /// @param dhcid An expected DHCID value.
    /// @note This value is the value that is produced by
    /// dhcp_ddns::D2Dhcid::createDigest() with the appropriate arguments. This
    /// method uses encryption tools to produce the value which cannot be
    /// easily duplicated by hand.  It is more or less necessary to generate
    /// these values programmatically and place them here. Should the
    /// underlying implementation of createDigest() change these test values
    /// will likely need to be updated as well.
    /// @param expires A timestamp when the lease associated with the
    /// NameChangeRequest expires.
    /// @param len A valid lifetime of the lease associated with the
    /// NameChangeRequest.
    /// @param fqdn The expected string value of the FQDN, if blank the
    /// check is skipped
    void verifyNameChangeRequest(const isc::dhcp_ddns::NameChangeType type,
                                 const bool reverse, const bool forward,
                                 const std::string& addr,
                                 const std::string& dhcid,
                                 const uint64_t expires,
                                 const uint16_t len,
                                 const std::string& fqdn="") {
        NameChangeRequestPtr ncr;
        ASSERT_NO_THROW(ncr = CfgMgr::instance().getD2ClientMgr().peekAt(0));
        ASSERT_TRUE(ncr);

        EXPECT_EQ(type, ncr->getChangeType());
        EXPECT_EQ(forward, ncr->isForwardChange());
        EXPECT_EQ(reverse, ncr->isReverseChange());
        EXPECT_EQ(addr, ncr->getIpAddress());
        EXPECT_EQ(dhcid, ncr->getDhcid().toStr());
        EXPECT_EQ(expires, ncr->getLeaseExpiresOn());
        EXPECT_EQ(len, ncr->getLeaseLength());
        EXPECT_EQ(isc::dhcp_ddns::ST_NEW, ncr->getStatus());

        if (!fqdn.empty()) {
           EXPECT_EQ(fqdn, ncr->getFqdn());
        }

        // Process the message off the queue
        ASSERT_NO_THROW(CfgMgr::instance().getD2ClientMgr().runReadyIO());
    }

    /// @brief Sets the FQDN information for a lease and queues an NCR.
    ///
    /// @param fwd Perform forward update.
    /// @param rev Perform reverse update.
    /// @param fqdn Hostname.
    void queueRemovalNCR(const bool fwd, const bool rev, const std::string& fqdn) {
        lease_->fqdn_fwd_ = fwd;
        lease_->fqdn_rev_ = rev;
        lease_->hostname_ = fqdn;

        /// Send NCR to D2.
        ASSERT_NO_THROW(queueNCR(CHG_REMOVE, lease_));
    }

    /// @brief Sets the FQDN information for a lease and queues an NCR.
    ///
    /// @param chg_type Name change type.
    /// @param fwd Perform forward update.
    /// @param rev Perform reverse update.
    /// @param fqdn Hostname.
    void sendNCR(const NameChangeType chg_type, const bool fwd, const bool rev,
                 const std::string& fqdn) {
        lease_->fqdn_fwd_ = fwd;
        lease_->fqdn_rev_ = rev;
        lease_->hostname_ = fqdn;

        /// Send NCR to D2.
        ASSERT_NO_THROW(queueNCR(chg_type, lease_));
    }

    /// @brief Test that for the given values the NCR is not generated.
    ///
    /// @param chg_type Name change type.
    /// @param fwd Perform forward update.
    /// @param rev Perform reverse update.
    /// @param fqdn Hostname.
    void testNoUpdate(const NameChangeType chg_type, const bool fwd, const bool rev,
                      const std::string& fqdn) {
        ASSERT_NO_FATAL_FAILURE(sendNCR(chg_type, fwd, rev, fqdn));
        ASSERT_EQ(0, d2_mgr_.getQueueSize());
    }

    /// @brief Test that sending an NCR while DNS updates would not throw.
    ///
    /// @param chg_type Name change type.
    void testD2Disabled(const NameChangeType chg_type) {
        // Disable DDNS updates.
        disableD2();
        ASSERT_NO_FATAL_FAILURE(sendNCR(chg_type, true, true, "MYHOST.example.com."));
    }

    /// @brief Test that NCR is generated as expected.
    ///
    /// @param chg_type Name change type.
    /// @param fwd Perform forward update.
    /// @param rev Perform reverse update.
    /// @param fqdn Hostname.
    /// @param exp_dhcid Expected DHCID.
    void testNCR(const NameChangeType chg_type, const bool fwd, const bool rev,
                 const std::string& fqdn, const std::string exp_dhcid) {
        // Queue NCR.
        ASSERT_NO_FATAL_FAILURE(sendNCR(chg_type, fwd, rev, fqdn));
        // Expecting one NCR be generated.
        ASSERT_EQ(1, d2_mgr_.getQueueSize());
        // Check the details of the NCR.
        verifyNameChangeRequest(chg_type, rev, fwd, lease_->addr_.toText(), exp_dhcid,
                                lease_->cltt_ + lease_->valid_lft_,
                                lease_->valid_lft_);
    }

    /// @brief Test that calling queueNCR for NULL lease doesn't cause
    /// an exception.
    ///
    /// @param chg_type Name change type.
    void testNullLease(const NameChangeType chg_type) {
        lease_.reset();
        ASSERT_NO_FATAL_FAILURE(queueNCR(chg_type, lease_));
        EXPECT_EQ(0, d2_mgr_.getQueueSize());
    }
};

/// @brief Test fixture class implementation for DHCPv6.
class NCRGenerator6Test : public NCRGeneratorTest<Lease6Ptr> {
public:

    /// @brief Pointer to the DUID used in the tests.
    DuidPtr duid_;

    /// @brief Constructor.
    ///
    /// Initializes DUID.
    NCRGenerator6Test()
        : duid_() {
        duid_.reset(new DUID(DUID::fromText("01:02:03:04:05:06:07:08:09")));
    }

    /// @brief Implementation of the method creating DHCPv6 lease instance.
    virtual void initLease() {
        lease_.reset(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
                                duid_, 1234, 501, 502, 1, HWAddrPtr(), 0));
    }
};

// Test creation of the NameChangeRequest for both forward and reverse
// mapping for the given lease.
TEST_F(NCRGenerator6Test, fwdRev) {
    // Part of the domain name is in upper case, to test that it gets converted
    // to lower case before DHCID is computed. So, we should get the same DHCID
    // as if we typed domain-name in lower case.
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNCR(CHG_REMOVE, true, true, "MYHOST.example.com.",
                "000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3"
                "D0ECCEA5E0DD71730F392119A");
    }

    // Now try the same test with all lower case.
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNCR(CHG_REMOVE, true, true, "myhost.example.com.",
                "000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3"
                "D0ECCEA5E0DD71730F392119A");
    }

    {
        SCOPED_TRACE("case CHG_ADD");
        testNCR(CHG_ADD, true, true, "MYHOST.example.com.",
                "000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3"
                "D0ECCEA5E0DD71730F392119A");
    }

    {
        SCOPED_TRACE("case CHG_ADD");
        testNCR(CHG_ADD, true, true, "myhost.example.com.",
                "000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3"
                "D0ECCEA5E0DD71730F392119A");
    }

}

// Checks that NameChangeRequests are not created when ddns updates are disabled.
TEST_F(NCRGenerator6Test, d2Disabled) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testD2Disabled(CHG_REMOVE);
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testD2Disabled(CHG_ADD);
    }
}

// Test creation of the NameChangeRequest for reverse mapping in the
// given lease.
TEST_F(NCRGenerator6Test, revOnly) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNCR(CHG_REMOVE, false, true, "myhost.example.com.",
                "000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3"
                "D0ECCEA5E0DD71730F392119A");
    }

    {
        SCOPED_TRACE("case CHG_ADD");
        testNCR(CHG_ADD, false, true, "myhost.example.com.",
                "000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3"
                "D0ECCEA5E0DD71730F392119A");
    }
}

// Test creation of the NameChangeRequest for forward mapping in the
// given lease.
TEST_F(NCRGenerator6Test, fwdOnly) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNCR(CHG_REMOVE, true, false, "myhost.example.com.",
                "000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3"
                "D0ECCEA5E0DD71730F392119A");
    }

    {
        SCOPED_TRACE("case CHG_ADD");
        testNCR(CHG_ADD, true, false, "myhost.example.com.",
                "000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3"
                "D0ECCEA5E0DD71730F392119A");
    }
}

// Test that NameChangeRequest is not generated when neither forward
// nor reverse DNS update has been performed for a lease.
TEST_F(NCRGenerator6Test, noFwdRevUpdate) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNoUpdate(CHG_REMOVE, false, false, "myhost.example.com.");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNoUpdate(CHG_ADD, false, false, "myhost.example.com.");
    }
}

// Test that NameChangeRequest is not generated if the hostname hasn't been
// specified for a lease for which forward and reverse mapping has been set.
TEST_F(NCRGenerator6Test, noHostname) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNoUpdate(CHG_REMOVE, false, false, "");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNoUpdate(CHG_ADD, false, false, "");
    }
}

// Test that NameChangeRequest is not generated if an invalid hostname has
// been specified for a lease for which forward and reverse mapping has been
// set.
TEST_F(NCRGenerator6Test, wrongHostname) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNoUpdate(CHG_REMOVE, false, false, "myhost...example.com.");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNoUpdate(CHG_ADD, false, false, "myhost...example.com.");
    }
}

// Test that NameChangeRequest is not generated if the lease is not an
// address lease, i.e. is a prefix.
TEST_F(NCRGenerator6Test, wrongLeaseType) {
    // Change lease type to delegated prefix.
    lease_->type_ = Lease::TYPE_PD;

    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNoUpdate(CHG_REMOVE, true, true, "myhost.example.org.");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNoUpdate(CHG_ADD, true, true, "myhost.example.org.");
    }
}

// Test that NameChangeRequest is not generated if the lease is NULL,
// and that the call to queueNCR doesn't cause an exception or
// assertion.
TEST_F(NCRGenerator6Test, nullLease) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNullLease(CHG_REMOVE);
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNullLease(CHG_ADD);
    }
}

/// @brief Test fixture class implementation for DHCPv4.
class NCRGenerator4Test : public NCRGeneratorTest<Lease4Ptr> {
public:

    /// @brief Pointer to HW address used by the tests.
    HWAddrPtr hwaddr_;

    /// @brief Constructor.
    ///
    /// Initializes HW address.
    NCRGenerator4Test()
        : hwaddr_(new HWAddr(HWAddr::fromText("01:02:03:04:05:06"))) {
    }

    /// @brief Implementation of the method creating DHCPv4 lease instance.
    virtual void initLease() {
        lease_.reset(new Lease4(IOAddress("192.0.2.1"), hwaddr_, ClientIdPtr(),
                                100, time(NULL), 1));
    }
};

// Test creation of the NameChangeRequest for both forward and reverse
// mapping for the given lease.
TEST_F(NCRGenerator4Test, fwdRev) {
    // Part of the domain name is in upper case, to test that it gets converted
    // to lower case before DHCID is computed. So, we should get the same DHCID
    // as if we typed domain-name in lower case.
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNCR(CHG_REMOVE, true, true, "MYHOST.example.com.",
                "000001E356D43E5F0A496D65BCA24D982D646140813E3"
                "B03AB370BFF46BFA309AE7BFD");
    }

    // Now try the same with all lower case.
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNCR(CHG_REMOVE, true, true, "myhost.example.com.",
                "000001E356D43E5F0A496D65BCA24D982D646140813E3"
                "B03AB370BFF46BFA309AE7BFD");
    }

    {
        SCOPED_TRACE("case CHG_ADD");
        testNCR(CHG_ADD, true, true, "MYHOST.example.com.",
                "000001E356D43E5F0A496D65BCA24D982D646140813E3"
                "B03AB370BFF46BFA309AE7BFD");
    }

    {
        SCOPED_TRACE("case CHG_ADD");
        testNCR(CHG_ADD, true, true, "myhost.example.com.",
                "000001E356D43E5F0A496D65BCA24D982D646140813E3"
                "B03AB370BFF46BFA309AE7BFD");
    }
}

// Checks that NameChangeRequests are not created when ddns updates are disabled.
TEST_F(NCRGenerator4Test, d2Disabled) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testD2Disabled(CHG_REMOVE);
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testD2Disabled(CHG_ADD);
    }
}

// Test creation of the NameChangeRequest for reverse mapping in the
// given lease.
TEST_F(NCRGenerator4Test, revOnly) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNCR(CHG_REMOVE, false, true, "myhost.example.com.",
                "000001E356D43E5F0A496D65BCA24D982D646140813E3B"
                "03AB370BFF46BFA309AE7BFD");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNCR(CHG_ADD, false, true, "myhost.example.com.",
                "000001E356D43E5F0A496D65BCA24D982D646140813E3B"
                "03AB370BFF46BFA309AE7BFD");
    }
}

// Test creation of the NameChangeRequest for forward mapping in the
// given lease.
TEST_F(NCRGenerator4Test, fwdOnly) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNCR(CHG_REMOVE, true, false, "myhost.example.com.",
                "000001E356D43E5F0A496D65BCA24D982D646140813E3B"
                "03AB370BFF46BFA309AE7BFD");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNCR(CHG_ADD, true, false, "myhost.example.com.",
                "000001E356D43E5F0A496D65BCA24D982D646140813E3B"
                "03AB370BFF46BFA309AE7BFD");
    }
}

// Test that NameChangeRequest is not generated when neither forward
// nor reverse DNS update has been performed for a lease.
TEST_F(NCRGenerator4Test, noFwdRevUpdate) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNoUpdate(CHG_REMOVE, false, false, "myhost.example.com.");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNoUpdate(CHG_ADD, false, false, "myhost.example.com.");
    }
}

// Test that NameChangeRequest is not generated if the hostname hasn't been
// specified for a lease for which forward and reverse mapping has been set.
TEST_F(NCRGenerator4Test, noHostname) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNoUpdate(CHG_REMOVE, false, false, "");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNoUpdate(CHG_ADD, false, false, "");
    }
}

// Test that NameChangeRequest is not generated if the invalid hostname has
// been specified for a lease for which forward and reverse mapping has been
// set.
TEST_F(NCRGenerator4Test, wrongHostname) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNoUpdate(CHG_REMOVE, false, false, "myhost...example.org.");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNoUpdate(CHG_ADD, false, false, "myhost...example.org.");
    }
}

// Test that the correct NameChangeRequest is generated when the lease
// includes client identifier.
TEST_F(NCRGenerator4Test, useClientId) {
    lease_->client_id_ = ClientId::fromText("01:01:01:01");

    ASSERT_NO_FATAL_FAILURE(queueRemovalNCR(true, true, "myhost.example.com."));
    ASSERT_EQ(1, d2_mgr_.getQueueSize());

    verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
                            "192.0.2.1",
                            "000101C7AA5420483BDA99C437636EA7DA2FE18"
                            "31C9679FEB031C360CA571298F3D1FA",
                            lease_->cltt_ + lease_->valid_lft_, 100);
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNCR(CHG_REMOVE, true, true, "myhost.example.com.",
                "000101C7AA5420483BDA99C437636EA7DA2FE1831C9679"
                "FEB031C360CA571298F3D1FA");
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNCR(CHG_ADD, true, true, "myhost.example.com.",
                "000101C7AA5420483BDA99C437636EA7DA2FE1831C9679"
                "FEB031C360CA571298F3D1FA");
    }
}

// Test that NameChangeRequest is not generated if the lease is NULL,
// and that the call to queueNCR doesn't cause an exception or
// assertion.
TEST_F(NCRGenerator4Test, nullLease) {
    {
        SCOPED_TRACE("case CHG_REMOVE");
        testNullLease(CHG_REMOVE);
    }
    {
        SCOPED_TRACE("case CHG_ADD");
        testNullLease(CHG_ADD);
    }
}

} // end of anonymous namespace


text:
/* Unit testing for outcomes
(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (7 commits)

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#include <boost/outcome/outcome.hpp>
#include <boost/outcome/try.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_monitor.hpp>

BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_propagate, "Tests that the outcome propagates errors between different editions of itself")
{
  using namespace BOOST_OUTCOME_V2_NAMESPACE;
  {
    auto t0 = [&](int a) { return result<long>(boost::system::error_code(a, boost::system::generic_category())); };
    auto t1 = [&](int a) {
      result<double> f(t0(a));  // double is constructible from long
      BOOST_CHECK(!f.has_value());
      BOOST_CHECK(f.has_error());
      return f;
    };
    auto t2 = [&](int a) {
      result<void> f(t1(a).error());
      BOOST_CHECK(!f.has_value());
      BOOST_CHECK(f.has_error());
      return f;
    };
    auto t3 = [&](int a) {
      outcome<std::string> f(t2(a));
      BOOST_CHECK(!f.has_value());
      BOOST_CHECK(f.has_error());
      return f;
    };
    BOOST_CHECK(t3(5).error().value() == 5);
    result<int> a2{result<void>(in_place_type<void>)};
    result<int> a3{result<void>(boost::system::error_code(5, boost::system::generic_category()))};
    BOOST_CHECK(a2.has_value());
    BOOST_CHECK(!a2.has_error());
    BOOST_CHECK(!a3.has_value());
    BOOST_CHECK(a3.has_error());
  }
  {
    auto t0 = [&](int a) { return result<long>(a); };
    auto t1 = [&](int a) -> result<std::string> {
      BOOST_OUTCOME_TRY(f, (t0(a)));
      return std::to_string(f);
    };
    BOOST_CHECK(t1(5).value() == "5");
  }
  {
    auto t0 = [&](int a) { return result<long>(a); };
    auto t1 = [&](int a) -> outcome<std::string> {
      BOOST_OUTCOME_TRY(f, (t0(a)));
      return std::to_string(f);
    };
    BOOST_CHECK(t1(5).value() == "5");
  }
  {
    auto t0 = [&](int a) -> result<long> { return result<long>(a); };
    auto t1 = [&](int a) -> outcome<void> {
      BOOST_OUTCOME_TRY((t0(a)));
      return outcome<void>(in_place_type<void>);
    };
    (void) t1(5);
  }
}

max_issues_repo_name: qingkouwei/mediaones

max_forks_repo_name: qingkouwei/mediaones


text:
// Author(s): Wieger Wesselink
// Copyright: see the accompanying file COPYING or copy at
// https://svn.win.tue.nl/trac/MCRL2/browser/trunk/COPYING
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
/// \file mcrl2parse.cpp
/// \brief tool for testing the new parser

#define TOOLNAME "mcrl2parse"
#define AUTHOR "Wieger Wesselink"

#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>

#include <boost/algorithm/string/trim.hpp>

#include "mcrl2/bes/boolean_equation_system.h"
#include "mcrl2/bes/parse.h"
#include "mcrl2/bes/print.h"
#include "mcrl2/core/parse.h"
#include "mcrl2/core/detail/dparser_functions.h"
#include "mcrl2/core/parser_utility.h"
#include "mcrl2/data/parse.h"
#include "mcrl2/data/typecheck.h"
#include "mcrl2/lps/linearise.h"
#include "mcrl2/lps/parse.h"
#include "mcrl2/lps/specification.h"
#include "mcrl2/lps/typecheck.h"
#include "mcrl2/modal_formula/parse.h"
#include "mcrl2/modal_formula/typecheck.h"
#include "mcrl2/pbes/parse.h"
#include "mcrl2/pbes/print.h"
#include "mcrl2/pbes/typecheck.h"
#include "mcrl2/process/parse.h"
#include "mcrl2/process/print.h"
#include "mcrl2/process/process_specification.h"
#include "mcrl2/process/typecheck.h"
#include "mcrl2/utilities/detail/separate_keyword_section.h"
#include "mcrl2/utilities/input_tool.h"

using namespace mcrl2;
using namespace mcrl2::utilities;
using namespace mcrl2::utilities::tools;

// ---------------------------------------------------------------------------------------
//       function                |     additional inputs              | keywords
// -------------------------------------------------------------------|-------------------
// parse_sort_expression         | data_specification                 | sortexpr
// parse_data_expression         | data_specification variable_vector | dataexpr variables
// parse_data_specification      |                                    |
// parse_process_expression      | process_specification              | procexpr
// parse_process_specification   |                                    |
// parse_boolean_expression      |                                    |
// parse_boolean_equation_system |                                    |
// parse_pbes_expression         | pbes_specification                 | pbesexpr
// parse_pbes                    |                                    |
// parse_state_formula           | action_specification               | statefrm
// parse_action_formula          | action_specification               | actfrm
// parse_regular_formula         | action_specification               | regfrm
// parse_multi_action            | action_specification               | multact

inline
std::vector<std::string> data_specification_keywords()
{
  std::vector<std::string> result;
  result.push_back("sort");
  result.push_back("var");
  result.push_back("eqn");
  result.push_back("map");
  result.push_back("cons");
  return result;
}

inline
std::vector<std::string> action_specification_keywords()
{
  std::vector<std::string> result;
  result.push_back("sort");
  result.push_back("var");
  result.push_back("eqn");
  result.push_back("map");
  result.push_back("cons");
  result.push_back("act");
  result.push_back("glob");
  result.push_back("proc");
  result.push_back("init");
  return result;
}

inline
std::vector<std::string> process_specification_keywords()
{
  return action_specification_keywords();
}

inline
std::vector<std::string> pbes_specification_keywords()
{
  std::vector<std::string> result;
  result.push_back("sort");
  result.push_back("var");
  result.push_back("eqn");
  result.push_back("map");
  result.push_back("cons");
  result.push_back("glob");
  result.push_back("pbes");
  result.push_back("init");
  return result;
}

inline
bool has_keyword(const std::string& text, const std::string& keyword)
{
  // inefficient implementation, to avoid the introduction of a regex search function
  std::vector<std::string> words = utilities::regex_split("dummy " + text, "\\b" + keyword + "\\b");
  return words.size() > 1;
}

inline
void separate_data_specification(const std::string& text, const std::string& keyword, data::data_specification& dataspec, std::string& keyword_text)
{
  if (!has_keyword(text, keyword))
  {
    keyword_text = text;
    dataspec = data::data_specification();
  }
  else
  {
    std::pair<std::string, std::string> result = utilities::detail::separate_keyword_section(text, keyword, data_specification_keywords());
    keyword_text = result.first.substr(keyword.size());
    dataspec = data::parse_data_specification(result.second);
  }
}

inline
void separate_data_specification(const std::string& text, const std::string& keyword1, const std::string& keyword2, data::data_specification& dataspec, std::string& keyword1_text, std::string& keyword2_text)
{
  std::string data_spec_text;
  if (!has_keyword(text, keyword1))
  {
    keyword1_text = text;
    keyword2_text = "";
  }
  else
  {
    std::vector<std::string> keywords = data_specification_keywords();
    keywords.push_back(keyword1);

    std::pair<std::string, std::string> result = utilities::detail::separate_keyword_section(text, keyword1, keywords);
    keyword1_text = result.first.substr(keyword1.size());
    data_spec_text = result.second;
    if (has_keyword(result.second, keyword2))
    {
      result = utilities::detail::separate_keyword_section(result.second, keyword2, data_specification_keywords());
      keyword2_text = result.first.substr(keyword2.size());
      data_spec_text = result.second;
    }
    else
    {
      keyword2_text = "";
    }
    dataspec = data::parse_data_specification(data_spec_text);
  }
}

inline
void separate_action_specification(const std::string& text, const std::string& keyword, lps::specification& spec, std::string& keyword_text)
{
  if (!has_keyword(text, keyword))
  {
    keyword_text = text;
    spec = lps::specification();
  }
  else
  {
    std::pair<std::string, std::string> result = utilities::detail::separate_keyword_section(text, keyword, action_specification_keywords());
    if (!has_keyword(result.second, "init"))
    {
      result.second = result.second + "\ninit delta;\n";
    }
    keyword_text = result.first.substr(keyword.size());
    spec=remove_stochastic_operators(lps::linearise(result.second));
  }
}

inline
void separate_process_specification(const std::string& text, const std::string& keyword, process::process_specification& procspec, std::string& keyword_text)
{
  if (!has_keyword(text, keyword))
  {
    keyword_text = text;
    procspec = process::process_specification();
  }
  else
  {
    std::pair<std::string, std::string> result = utilities::detail::separate_keyword_section(text, keyword, process_specification_keywords());
    keyword_text = result.first.substr(keyword.size());
    std::string ptext = result.second;
    if (!has_keyword(ptext, "init"))
    {
      ptext = ptext + "\ninit delta;";
    }
    procspec = process::parse_process_specification(ptext, false);
  }
}

inline
void separate_pbes_specification(const std::string& text, const std::string& keyword, pbes_system::pbes& pbesspec, std::string& keyword_text)
{
  if (!has_keyword(text, keyword))
  {
    keyword_text = text;
    pbesspec = pbes_system::pbes();
  }
  else
  {
    std::pair<std::string, std::string> result = utilities::detail::separate_keyword_section(text, keyword, pbes_specification_keywords());
    keyword_text = result.first.substr(keyword.size());
    pbesspec = pbes_system::parse_pbes(result.second);
  }
}

inline
data::variable_vector parse_data_variables(const std::string& text, const data::data_specification& dataspec)
{
  data::variable_vector result;
  if (boost::algorithm::trim_copy(text).empty())
  {
    return result;
  }
  data::parse_variables(text, std::back_inserter(result), dataspec);
  return result;
}

typedef enum {
  actfrm_e,
  besexpr_e,
  besspec_e,
  dataexpr_e,
  dataspec_e,
  mcrl2spec_e,
  multact_e,
  pbesexpr_e,
  pbesspec_e,
  procexpr_e,
  regfrm_e,
  sortexpr_e,
  statefrm_e
} file_type_t;

inline
file_type_t parse_file_type(const std::string& type)
{
  if      (type == "actfrm"   )   { return actfrm_e   ; }
  else if (type == "besexpr"  )   { return besexpr_e  ; }
  else if (type == "besspec"  )   { return besspec_e  ; }
  else if (type == "dataexpr" )   { return dataexpr_e ; }
  else if (type == "dataspec" )   { return dataspec_e ; }
  else if (type == "mcrl2spec")   { return mcrl2spec_e; }
  else if (type == "multact"  )   { return multact_e  ; }
  else if (type == "pbesexpr" )   { return pbesexpr_e ; }
  else if (type == "pbesspec" )   { return pbesspec_e ; }
  else if (type == "procexpr" )   { return procexpr_e ; }
  else if (type == "regfrm"   )   { return regfrm_e   ; }
  else if (type == "sortexpr" )   { return sortexpr_e ; }
  else if (type == "statefrm" )   { return statefrm_e ; }
  else
  {
    throw mcrl2::runtime_error("unknown file type specified (got `" + type + "')");
  }
}

inline
std::string print_file_type(const file_type_t type)
{
  switch(type)
  {
    case actfrm_e: return "actfrm";
    case besexpr_e: return "besexpr";
    case besspec_e: return "besspec";
    case dataexpr_e: return "dataexpr";
    case dataspec_e: return "dataspec";
    case mcrl2spec_e: return "mcrl2spec";
    case multact_e: return "multact";
    case pbesexpr_e: return "pbesexpr";
    case pbesspec_e: return "pbesspec";
    case procexpr_e: return "procexpr";
    case regfrm_e: return "regfrm";
    case sortexpr_e: return "sortexpr";
    case statefrm_e: return "statefrm";
  }
  throw mcrl2::runtime_error("unknown file type");
}

inline
std::string description(const file_type_t type)
{
  switch(type)
  {
    case actfrm_e: return "for an action formula";
    case besexpr_e: return "for a BES expression";
    case besspec_e: return "for a BES specification";
    case dataexpr_e: return "for a data expression";
    case dataspec_e: return "for a data specification";
    case mcrl2spec_e: return "for an mCRL2 specification";
    case multact_e: return "for a multi action";
    case pbesexpr_e: return "for a PBES expression";
    case pbesspec_e: return "for a PBES specification";
    case procexpr_e: return "for a process expression";
    case regfrm_e: return "for a regular formula";
    case sortexpr_e: return "for a sort expression";
    case statefrm_e: return "for a state formula";
  }
  throw mcrl2::runtime_error("unknown file type");
}

inline
std::istream& operator>>(std::istream& is, file_type_t& type)
{
  try
  {
    std::string s;
    is >> s;
    type = parse_file_type(s);
  }
  catch(mcrl2::runtime_error&)
  {
    is.setstate(std::ios_base::failbit);
  }
  return is;
}

inline
std::ostream& operator<<(std::ostream& os, const file_type_t type)
{
  os << print_file_type(type);
  return os;
}

class mcrl2parse_tool : public input_tool
{
  typedef input_tool super;

  protected:
    std::string text;
    file_type_t file_type;
    bool partial_parses;
    bool print_tree;
    bool check_parser;
    bool check_printer;
    bool aterm_format;
    bool warn;

    bool dot;

    void add_options(interface_description& desc)
    {
      super::add_options(desc);
      desc.add_option("expression",
           make_optional_argument("EXPR", ""),
             "parse EXPR instead of a file",
             'e'
           );
      desc.add_option("filetype",
           make_enum_argument<file_type_t>("NAME")
                      .add_value(actfrm_e)
                      .add_value(besexpr_e)
                      .add_value(besspec_e)
                      .add_value(dataexpr_e)
                      .add_value(dataspec_e)
                      .add_value(mcrl2spec_e, true)
                      .add_value(multact_e)
                      .add_value(pbesexpr_e)
                      .add_value(pbesspec_e)
                      .add_value(procexpr_e)
                      .add_value(regfrm_e)
                      .add_value(sortexpr_e)
                      .add_value(statefrm_e),
             "input has the file type NAME:", 'f');
      desc.add_option("partial-parses", "allow partial parses");
      desc.add_option("print-tree", "print parse tree", 't');
      desc.add_option("check-parser", "compare the results of the old and new parser", 'p');
      desc.add_option("check-printer", "compare the results of the old and new pretty printer", 'P');
      desc.add_option("aterm-format", "compare the results in aterm format", 'a');
      desc.add_option("warn", "generate warnings", 'w');

      desc.add_option("dot", "load a dot file using the old and the new parser and check the result");
    }

    void parse_options(const command_line_parser& parser)
    {
      super::parse_options(parser);
      file_type = parser.option_argument_as<file_type_t>("filetype");
      partial_parses = 0 < parser.options.count("partial-parses");
      print_tree     = 0 < parser.options.count("print-tree");
      check_parser   = 0 < parser.options.count("check-parser");
      check_printer  = 0 < parser.options.count("check-printer");
      aterm_format   = 0 < parser.options.count("aterm-format");
      warn           = 0 < parser.options.count("warn");
      text = parser.option_argument("expression");
    }

    std::string read_text(std::istream& from)
    {
      std::ostringstream out;
      std::string s;
      while (std::getline(from, s))
      {
        out << s << std::endl;
      }
      return out.str();
    }

  public:

    mcrl2parse_tool() : super(
        TOOLNAME,
        AUTHOR,
        "parses a string containing an mCRL2 data structure",
        "Parses the text in the file INFILE. If INFILE is not present, standard input is used."
       )
    { }

    bool run()
    {
      if (text.empty())
      {
        if (input_filename().empty())
        {
          text = read_text(std::cin);
        }
        else
        {
          std::ifstream from(input_filename().c_str());
          text = read_text(from);
        }
      }

      data::data_specification dataspec;
      lps::specification lpsspec;
      process::process_specification procspec;
      pbes_system::pbes pbesspec;

      core::parser p(parser_tables_mcrl2, core::detail::ambiguity_fn, core::detail::syntax_error_fn);
      unsigned int start_symbol_index = 0;
      switch(file_type)
      {
        case actfrm_e   : { start_symbol_index = p.start_symbol_index("ActFrm"); break; }
        case besexpr_e  : { start_symbol_index = p.start_symbol_index("BesExpr"); break; }
        case besspec_e  : { start_symbol_index = p.start_symbol_index("BesSpec"); break; }
        case dataexpr_e : { start_symbol_index = p.start_symbol_index("DataExpr"); break; }
        case dataspec_e : { start_symbol_index = p.start_symbol_index("DataSpec"); break; }
        case mcrl2spec_e: { start_symbol_index = p.start_symbol_index("mCRL2Spec"); break; }
        case multact_e  : { start_symbol_index = p.start_symbol_index("MultAct"); break; }
        case pbesexpr_e : { start_symbol_index = p.start_symbol_index("PbesExpr"); break; }
        case pbesspec_e : { start_symbol_index = p.start_symbol_index("PbesSpec"); break; }
        case procexpr_e : { start_symbol_index = p.start_symbol_index("ProcExpr"); break; }
        case regfrm_e   : { start_symbol_index = p.start_symbol_index("RegFrm"); break; }
        case sortexpr_e : { start_symbol_index = p.start_symbol_index("SortExpr"); break; }
        case statefrm_e : { start_symbol_index = p.start_symbol_index("StateFrm"); break; }
      }

      try
      {
        if (print_tree)
        {
          core::parse_node node = p.parse(text, start_symbol_index, partial_parses);
          p.print_tree(node);
        }

        if (warn)
        {
          core::parse_node node = p.parse(text, start_symbol_index, partial_parses);
          core::warn_and_or(node);
          core::warn_left_merge_merge(node);
        }

        if (check_parser)
        {
          switch(file_type)
          {
            case actfrm_e   :
            {
              separate_action_specification(text, "actfrm", lpsspec, text);
              action_formulas::action_formula x = action_formulas::detail::parse_action_formula(text);
              const atermpp::aterm_appl& a = x;
              if (aterm_format)
              {
                std::cout << a << std::endl;
              }
              else
              {
                std::cout << action_formulas::pp(x) << std::endl;
              }
              break;
            }
            case besexpr_e  :
            {
              bes::boolean_expression x = bes::detail::parse_boolean_expression_new(text);
              const atermpp::aterm_appl& a = x;
              if (aterm_format)
              {
                std::cout << a << std::endl;
              }
              else
              {
                std::cout << bes::pp(x) << std::endl;
              }
              break;
            }
            case besspec_e  :
            {
              bes::boolean_equation_system x = bes::detail::parse_boolean_equation_system_new(text);
              atermpp::aterm_appl a = bes::boolean_equation_system_to_aterm(x);
              if (aterm_format)
              {
                std::cout << a << std::endl;
              }
              else
              {
                std::cout << bes::pp(x) << std::endl;
              }
              break;
            }
            case dataexpr_e :
            {
              std::string variable_text;
              separate_data_specification(text, "dataexpr", "variables", dataspec, text, variable_text);
              data::variable_vector v = parse_data_variables(variable_text, dataspec);
              data::data_expression x = data::parse_data_expression(text, v, dataspec);
              if (aterm_format)
              {
                std::cout << x << std::endl;
              }
              else
              {
                std::cout << data::pp(x) << std::endl;
              }
              break;
            }
            case dataspec_e :
            {
              data::data_specification x = data::parse_data_specification(text);
              if (aterm_format)
              {
                std::cout << data::detail::data_specification_to_aterm_data_spec(x) << std::endl;
              }
              else
              {
                std::cout << data::pp(x) << std::endl;
              }
              break;
            }
            case mcrl2spec_e:
            {
              process::process_specification x = process::detail::parse_process_specification_new(text);
              process::detail::complete_process_specification(x, false);
              if (aterm_format)
              {
                std::cout << process::process_specification_to_aterm(x) << std::endl;
              }
              else
              {
                std::cout << process::pp(x) << std::endl;
              }
              break;
            }
            case multact_e  :
            {
              separate_action_specification(text, "multact", lpsspec, text);
              process::untyped_multi_action y = lps::detail::parse_multi_action_new(text);
              lps::multi_action x = lps::detail::complete_multi_action(y, lpsspec.action_labels(), lpsspec.data());
              if (aterm_format)
              {
                std::cout << lps::detail::multi_action_to_aterm(x) << std::endl;
              }
              else
              {
                std::cout << lps::pp(x) << std::endl;
              }
              break;
            }
            case pbesexpr_e :
            {
              separate_pbes_specification(text, "pbesexpr", pbesspec, text);
              pbes_system::pbes_expression x = pbes_system::detail::parse_pbes_expression_new(text);
              if (aterm_format)
              {
                std::cout << x << std::endl;
              }
              else
              {
                std::cout << pbes_system::pp(x) << std::endl;
              }
              break;
            }
            case pbesspec_e :
            {
              pbes_system::pbes x = pbes_system::detail::parse_pbes_new(text).construct_pbes();
              pbes_system::detail::complete_pbes(x);
              if (aterm_format)
              {
                std::cout << pbes_system::pbes_to_aterm(x) << std::endl;
              }
              else
              {
                std::cout << pbes_system::pp(x) << std::endl;
              }
              break;
            }
            case procexpr_e :
            {
              separate_process_specification(text, "procexpr", procspec, text);
              process::process_expression x = process::detail::parse_process_expression_new(text);
              if (aterm_format)
              {
                std::cout << x << std::endl;
              }
              else
              {
                std::cout << process::pp(x) << std::endl;
              }
              break;
            }
            case regfrm_e   :
            {
              separate_action_specification(text, "regfrm", lpsspec, text);
              regular_formulas::regular_formula x = regular_formulas::detail::parse_regular_formula(text);
              if (aterm_format)
              {
                std::cout << x << std::endl;
              }
              else
              {
                std::cout << regular_formulas::pp(x) << std::endl;
              }
              break;
            }
            case sortexpr_e :
            {
              separate_data_specification(text, "sortexpr", dataspec, text);
              data::sort_expression x = data::parse_sort_expression(text, dataspec);
              if (aterm_format)
              {
                std::cout << x << std::endl;
              }
              else
              {
                std::cout << data::pp(x) << std::endl;
              }
              break;
            }
            case statefrm_e :
            {
              separate_action_specification(text, "statefrm", lpsspec, text);
              state_formulas::parse_state_formula_options options;
              options.check_monotonicity = false;
              options.resolve_name_clashes = false;
              state_formulas::state_formula x = state_formulas::parse_state_formula(text, lpsspec, options);
              if (aterm_format)
              {
                std::cout << x << std::endl;
              }
              else
              {
                std::cout << state_formulas::pp(x) << std::endl;
              }
              break;
            }
          }
        }

        if (check_printer)
        {
          switch(file_type)
          {
            case actfrm_e   :
            {
              separate_action_specification(text, "actfrm", lpsspec, text);
              action_formulas::action_formula x = action_formulas::detail::parse_action_formula(text);
              std::cout << action_formulas::pp(x) << std::endl;
              break;
            }
            case besexpr_e  :
            {
              bes::boolean_expression x = bes::detail::parse_boolean_expression_new(text);
              std::cout << bes::pp(x) << std::endl;
              break;
            }
            case besspec_e  :
            {
              bes::boolean_equation_system x = bes::detail::parse_boolean_equation_system_new(text);
              std::cout << bes::pp(x) << std::endl;
              break;
            }
            case dataexpr_e :
            {
              std::string variable_text;
              separate_data_specification(text, "dataexpr", "variables", dataspec, text, variable_text);
              data::variable_vector v = parse_data_variables(variable_text, dataspec);
              data::data_expression x = data::parse_data_expression(text, v, dataspec);
              std::cout << data::pp(x) << std::endl;
              break;
            }
            case dataspec_e :
            {
              data::data_specification x = data::parse_data_specification(text);
              std::cout << data::pp(x) << std::endl;
              break;
            }
            case mcrl2spec_e:
            {
              process::process_specification x = process::parse_process_specification(text, false);
              std::cout << process::pp(x) << std::endl;
              break;
            }
            case multact_e  :
            {
              separate_action_specification(text, "multact", lpsspec, text);
              lps::multi_action x = lps::parse_multi_action(text, lpsspec.action_labels(), lpsspec.data());
              std::cout << lps::pp(x) << std::endl;
              break;
            }
            case pbesexpr_e :
            {
              std::cout << "Warning: this test may fail due to the absence of a type checker" << std::endl;
              separate_pbes_specification(text, "pbesexpr", pbesspec, text);
              pbes_system::pbes_expression x = pbes_system::detail::parse_pbes_expression_new(text);
              std::cout << pbes_system::pp(x) << std::endl;
              break;
            }
            case pbesspec_e :
            {
              pbes_system::pbes x = pbes_system::parse_pbes(text);
              std::cout << pbes_system::pp(x) << std::endl;
              break;
            }
            case procexpr_e :
            {
              separate_process_specification(text, "procexpr", procspec, text);
              process::process_expression x = process::parse_process_expression(text, process::pp(procspec));
              std::cout << process::pp(x) << std::endl;
              break;
            }
            case regfrm_e   :
            {
              separate_action_specification(text, "regfrm", lpsspec, text);
              regular_formulas::regular_formula x = regular_formulas::detail::parse_regular_formula(text);
              std::cout << regular_formulas::pp(x) << std::endl;
              break;
            }
            case sortexpr_e :
            {
              separate_data_specification(text, "sortexpr", dataspec, text);
              data::sort_expression x = data::parse_sort_expression(text, dataspec);
              std::cout << data::pp(x) << std::endl;
              break;
            }
            case statefrm_e :
            {
              separate_action_specification(text, "statefrm", lpsspec, text);
              state_formulas::parse_state_formula_options options;
              options.check_monotonicity = false;
              options.resolve_name_clashes = false;
              state_formulas::state_formula x = state_formulas::parse_state_formula(text, lpsspec, options);
              std::cout << state_formulas::pp(x) << std::endl;
              break;
            }
          }
        }
      }
      catch (std::exception& e)
      {
        std::cout << "Exception during parsing: " << e.what() << std::endl;
      }

      return true;
    }

};

int main(int argc, char** argv)
{
  return mcrl2parse_tool().execute(argc, argv);
}