<commit_before>//
// Licensed to Green Energy Corp (www.greenenergycorp.com) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Green Enery Corp 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.
//
#include "StartupTasks.h"

#include "APDU.h"
#include "ObjectReadIterator.h"
#include "PointClass.h"
#include <APL/ITimeSource.h>
#include <APL/Logger.h>

namespace apl
{
namespace dnp
{

/* ------ Clear Restart ------- */

ClearRestartIIN::ClearRestartIIN(Logger* apLogger) :
	SimpleRspBase(apLogger)
{}

void ClearRestartIIN::ConfigureRequest(APDU& arAPDU)
{
	arAPDU.Set(FC_WRITE);
	Group80Var1* pObj = Group80Var1::Inst(); // Internal indications object
	ObjectWriteIterator i = arAPDU.WriteContiguous(pObj, 7, 7); // index 7 == device restart
	pObj->Write(*i, 7, 7, false);
}

/* ------ Configure Unsol ------- */

ConfigureUnsol::ConfigureUnsol(Logger* apLogger) :
	SimpleRspBase(apLogger),
	mIsEnable(false),
	mClassMask(0)
{}

void ConfigureUnsol::Set(bool aIsEnable, int aClassMask)
{
	mIsEnable = aIsEnable;
	mClassMask = aClassMask;
}

void ConfigureUnsol::ConfigureRequest(APDU& arAPDU)
{
	arAPDU.Set(mIsEnable ? FC_ENABLE_UNSOLICITED : FC_DISABLE_UNSOLICITED);
	if(mClassMask & PC_CLASS_1) arAPDU.DoPlaceholderWrite(Group60Var2::Inst());
	if(mClassMask & PC_CLASS_2) arAPDU.DoPlaceholderWrite(Group60Var3::Inst());
	if(mClassMask & PC_CLASS_3) arAPDU.DoPlaceholderWrite(Group60Var4::Inst());
}

/* ------ Time Sync ------- */

TimeSync::TimeSync(Logger* apLogger, ITimeSource* apTimeSrc) :
	SingleRspBase(apLogger),
	mpTimeSrc(apTimeSrc),
	mDelay(-1)
{}

void TimeSync::Init()
{
	mDelay = -1;
}

void TimeSync::ConfigureRequest(APDU& arAPDU)
{
	if(mDelay < 0) {
		arAPDU.Set(FC_DELAY_MEASURE);
		mStart = mpTimeSrc->GetUTC();
	}
	else {
		arAPDU.Set(FC_WRITE);
		ObjectWriteIterator owi = arAPDU.WriteContiguous(Group50Var1::Inst(), 0, 0, QC_1B_CNT);
		Group50Var1::Inst()->mTime.Set(*owi, mpTimeSrc->GetTimeStampUTC() + mDelay);
	}
}

TaskResult TimeSync::_OnFinalResponse(const APDU& arAPDU)
{
	if(mDelay < 0) {
		ptime now = mpTimeSrc->GetUTC();

		HeaderReadIterator hri = arAPDU.BeginRead();
		if(hri.Count() != 1) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexcpected header count");
			return TR_FAIL;
		}

		if(!hri->GetBaseObject()->Equals(Group52Var2::Inst())) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexpected object: " << hri->GetBaseObject()->Name());
			return TR_FAIL;
		}

		ObjectReadIterator ori = hri.BeginRead();
		if(ori.Count() != 1) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas got more than 1 object in response");
			return TR_FAIL;
		}

		millis_t send_rcv_time = (now - mStart).total_milliseconds();
		millis_t rtu_turn_around = Group52Var2::Inst()->mTime.Get(*ori);

		// The later shouldn't happen, but could cause a negative delay which would
		// result in a weird time setting
		mDelay = (send_rcv_time >= rtu_turn_around) ? (send_rcv_time - rtu_turn_around) / 2 : 0;

		return TR_CONTINUE;
	}
	else {
		return TR_SUCCESS;
	}
}

}
} //ens ns

<commit_msg>Fix for 'malformed packet' during session startup<commit_after>//
// Licensed to Green Energy Corp (www.greenenergycorp.com) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Green Enery Corp 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.
//
#include "StartupTasks.h"

#include "APDU.h"
#include "ObjectReadIterator.h"
#include "PointClass.h"
#include <APL/ITimeSource.h>
#include <APL/Logger.h>

namespace apl
{
namespace dnp
{

/* ------ Clear Restart ------- */

ClearRestartIIN::ClearRestartIIN(Logger* apLogger) :
	SimpleRspBase(apLogger)
{}

void ClearRestartIIN::ConfigureRequest(APDU& arAPDU)
{
	arAPDU.Set(FC_WRITE);
	Group80Var1* pObj = Group80Var1::Inst(); // Internal indications object
	ObjectWriteIterator i = arAPDU.WriteContiguous(pObj, 7, 7); // index 7 == device restart
	pObj->Write(*i, 7, 7, false);
}

/* ------ Configure Unsol ------- */

ConfigureUnsol::ConfigureUnsol(Logger* apLogger) :
	SimpleRspBase(apLogger),
	mIsEnable(false),
	mClassMask(0)
{}

void ConfigureUnsol::Set(bool aIsEnable, int aClassMask)
{
	mIsEnable = aIsEnable;
	mClassMask = aClassMask;
}

void ConfigureUnsol::ConfigureRequest(APDU& arAPDU)
{
	if (mClassMask == 0 || !mIsEnable) {
		arAPDU.Set(FC_DISABLE_UNSOLICITED);
		arAPDU.DoPlaceholderWrite(Group60Var2::Inst());
		arAPDU.DoPlaceholderWrite(Group60Var3::Inst());
		arAPDU.DoPlaceholderWrite(Group60Var4::Inst());
	} else {
		arAPDU.Set(FC_ENABLE_UNSOLICITED);
		if (mClassMask & PC_CLASS_1)
			arAPDU.DoPlaceholderWrite(Group60Var2::Inst());
		if (mClassMask & PC_CLASS_2)
			arAPDU.DoPlaceholderWrite(Group60Var3::Inst());
		if (mClassMask & PC_CLASS_3)
			arAPDU.DoPlaceholderWrite(Group60Var4::Inst());
	}
}

/* ------ Time Sync ------- */

TimeSync::TimeSync(Logger* apLogger, ITimeSource* apTimeSrc) :
	SingleRspBase(apLogger),
	mpTimeSrc(apTimeSrc),
	mDelay(-1)
{}

void TimeSync::Init()
{
	mDelay = -1;
}

void TimeSync::ConfigureRequest(APDU& arAPDU)
{
	if(mDelay < 0) {
		arAPDU.Set(FC_DELAY_MEASURE);
		mStart = mpTimeSrc->GetUTC();
	}
	else {
		arAPDU.Set(FC_WRITE);
		ObjectWriteIterator owi = arAPDU.WriteContiguous(Group50Var1::Inst(), 0, 0, QC_1B_CNT);
		Group50Var1::Inst()->mTime.Set(*owi, mpTimeSrc->GetTimeStampUTC() + mDelay);
	}
}

TaskResult TimeSync::_OnFinalResponse(const APDU& arAPDU)
{
	if(mDelay < 0) {
		ptime now = mpTimeSrc->GetUTC();

		HeaderReadIterator hri = arAPDU.BeginRead();
		if(hri.Count() != 1) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexcpected header count");
			return TR_FAIL;
		}

		if(!hri->GetBaseObject()->Equals(Group52Var2::Inst())) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexpected object: " << hri->GetBaseObject()->Name());
			return TR_FAIL;
		}

		ObjectReadIterator ori = hri.BeginRead();
		if(ori.Count() != 1) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas got more than 1 object in response");
			return TR_FAIL;
		}

		millis_t send_rcv_time = (now - mStart).total_milliseconds();
		millis_t rtu_turn_around = Group52Var2::Inst()->mTime.Get(*ori);

		// The later shouldn't happen, but could cause a negative delay which would
		// result in a weird time setting
		mDelay = (send_rcv_time >= rtu_turn_around) ? (send_rcv_time - rtu_turn_around) / 2 : 0;

		return TR_CONTINUE;
	}
	else {
		return TR_SUCCESS;
	}
}

}
} //ens ns

<|endoftext|>


<commit_before>//
//  SpectrumTAP.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 19/03/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#include "ZXSpectrumTAP.hpp"

using namespace Storage::Tape;

/*
	The understanding of idiomatic Spectrum data encoding below
	is taken from the TZX specifications at
	https://worldofspectrum.net/features/TZXformat.html ;
	specifics of the TAP encoding were gained from
	https://sinclair.wiki.zxnet.co.uk/wiki/TAP_format
*/

ZXSpectrumTAP::ZXSpectrumTAP(const std::string &file_name) :
	file_(file_name)
{
	// Check for a continuous series of blocks through to
	// file end, alternating header and data.
	uint8_t next_block_type = 0x00;
	while(true) {
		const uint16_t block_length = file_.get16le();
		const uint8_t block_type = file_.get8();
		if(file_.eof()) throw ErrorNotZXSpectrumTAP;

		if(block_type != next_block_type) {
			throw ErrorNotZXSpectrumTAP;
		}
		next_block_type ^= 0xff;

		file_.seek(block_length - 1, SEEK_CUR);
		if(file_.tell() == file_.stats().st_size) break;
	}

	virtual_reset();
}

bool ZXSpectrumTAP::is_at_end() {
	return file_.tell() == file_.stats().st_size;
}

void ZXSpectrumTAP::virtual_reset() {
	file_.seek(0, SEEK_SET);
	read_next_block();
}

Tape::Pulse ZXSpectrumTAP::virtual_get_next_pulse() {
	// Adopt a general pattern of high then low.
	Pulse pulse;
	pulse.type = (distance_into_phase_ & 1) ? Pulse::Type::High : Pulse::Type::Low;

	switch(phase_) {
		default: break;

		case Phase::PilotTone: {
			// Output: pulses of length 2168;
			// 8063 pulses if block type is 0, otherwise 3223;
			// then a 667-length pulse followed by a 735-length pulse.

			pulse.length = Time(271, 437'500);	// i.e. 2168 / 3'500'000
			++distance_into_phase_;

			// Check whether in the last two.
			if(distance_into_phase_ >= (block_type_ ? 8063 : 3223)) {
				pulse.length = (distance_into_phase_ & 1) ? Time(667, 3'500'000) : Time(735, 3'500'000);

				// Check whether this is the last one.
				if(distance_into_phase_ == (block_type_ ? 8064 : 3224)) {
					distance_into_phase_ = 0;
					phase_ = Phase::Data;
				}
			}
		} break;

		case Phase::Data: {
			// Output two pulses of length 855 for a 0; two of length 1710 for a 1,
			// from MSB to LSB.
			pulse.length = (data_byte_ & 0x80) ? Time(1710, 3'500'000) : Time(855, 3'500'000);
			++distance_into_phase_;

			if(!(distance_into_phase_ & 1)) {
				data_byte_ <<= 1;
			}

			if(!(distance_into_phase_ & 15)) {
				if((distance_into_phase_ >> 4) == block_length_) {
					if(block_type_) {
						distance_into_phase_ = 0;
						phase_ = Phase::Gap;
					} else {
						read_next_block();
					}
				} else {
					data_byte_ = file_.get8();
				}
			}
		} break;

		case Phase::Gap:
			Pulse gap;
			gap.type = Pulse::Type::Zero;
			gap.length = Time(1);

			read_next_block();
		return gap;
	}

	return pulse;
}

void ZXSpectrumTAP::read_next_block() {
	if(is_at_end()) {
		phase_ = Phase::Gap;
	} else {
		block_length_ = file_.get16le();
		data_byte_ = block_type_ = file_.get8();
		phase_ = Phase::PilotTone;
	}
	distance_into_phase_ = 0;
}
<commit_msg>Relaxes test for a valid TAP.<commit_after>//
//  SpectrumTAP.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 19/03/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#include "ZXSpectrumTAP.hpp"

using namespace Storage::Tape;

/*
	The understanding of idiomatic Spectrum data encoding below
	is taken from the TZX specifications at
	https://worldofspectrum.net/features/TZXformat.html ;
	specifics of the TAP encoding were gained from
	https://sinclair.wiki.zxnet.co.uk/wiki/TAP_format
*/

ZXSpectrumTAP::ZXSpectrumTAP(const std::string &file_name) :
	file_(file_name)
{
	// Check for a continuous series of blocks through to
	// exactly file end.
	//
	// To consider: could also check those blocks of type 0
	// and type ff for valid checksums?
	while(true) {
		const uint16_t block_length = file_.get16le();
		if(file_.eof()) throw ErrorNotZXSpectrumTAP;

		file_.seek(block_length, SEEK_CUR);
		if(file_.tell() == file_.stats().st_size) break;
	}

	virtual_reset();
}

bool ZXSpectrumTAP::is_at_end() {
	return file_.tell() == file_.stats().st_size;
}

void ZXSpectrumTAP::virtual_reset() {
	file_.seek(0, SEEK_SET);
	read_next_block();
}

Tape::Pulse ZXSpectrumTAP::virtual_get_next_pulse() {
	// Adopt a general pattern of high then low.
	Pulse pulse;
	pulse.type = (distance_into_phase_ & 1) ? Pulse::Type::High : Pulse::Type::Low;

	switch(phase_) {
		default: break;

		case Phase::PilotTone: {
			// Output: pulses of length 2168;
			// 8063 pulses if block type is 0, otherwise 3223;
			// then a 667-length pulse followed by a 735-length pulse.

			pulse.length = Time(271, 437'500);	// i.e. 2168 / 3'500'000
			++distance_into_phase_;

			// Check whether in the last two.
			if(distance_into_phase_ >= (block_type_ ? 8063 : 3223)) {
				pulse.length = (distance_into_phase_ & 1) ? Time(667, 3'500'000) : Time(735, 3'500'000);

				// Check whether this is the last one.
				if(distance_into_phase_ == (block_type_ ? 8064 : 3224)) {
					distance_into_phase_ = 0;
					phase_ = Phase::Data;
				}
			}
		} break;

		case Phase::Data: {
			// Output two pulses of length 855 for a 0; two of length 1710 for a 1,
			// from MSB to LSB.
			pulse.length = (data_byte_ & 0x80) ? Time(1710, 3'500'000) : Time(855, 3'500'000);
			++distance_into_phase_;

			if(!(distance_into_phase_ & 1)) {
				data_byte_ <<= 1;
			}

			if(!(distance_into_phase_ & 15)) {
				if((distance_into_phase_ >> 4) == block_length_) {
					if(block_type_) {
						distance_into_phase_ = 0;
						phase_ = Phase::Gap;
					} else {
						read_next_block();
					}
				} else {
					data_byte_ = file_.get8();
				}
			}
		} break;

		case Phase::Gap:
			Pulse gap;
			gap.type = Pulse::Type::Zero;
			gap.length = Time(1);

			read_next_block();
		return gap;
	}

	return pulse;
}

void ZXSpectrumTAP::read_next_block() {
	if(is_at_end()) {
		phase_ = Phase::Gap;
	} else {
		block_length_ = file_.get16le();
		data_byte_ = block_type_ = file_.get8();
		phase_ = Phase::PilotTone;
	}
	distance_into_phase_ = 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "clientversion.h"

#include "tinyformat.h"

#include <string>

/**
 * Name of client reported in the 'version' message. Report the same name
 * for both bitcoind and bitcoin-core, to make it harder for attackers to
 * target servers or GUI users specifically.
 */
const std::string CLIENT_NAME("Satoshi");

/**
 * Client version number
 */
#define CLIENT_VERSION_SUFFIX ""

/**
 * The following part of the code determines the CLIENT_BUILD variable.
 * Several mechanisms are used for this:
 * * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
 *   generated by the build environment, possibly containing the output
 *   of git-describe in a macro called BUILD_DESC
 * * secondly, if this is an exported version of the code, GIT_ARCHIVE will
 *   be defined (automatically using the export-subst git attribute), and
 *   GIT_COMMIT will contain the commit id.
 * * then, three options exist for determining CLIENT_BUILD:
 *   * if BUILD_DESC is defined, use that literally (output of git-describe)
 *   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
 *   * otherwise, use v[maj].[min].[rev].[build]-unk
 * finally CLIENT_VERSION_SUFFIX is added
 */

//! First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#include "build.h"
#endif

//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
#ifdef GIT_ARCHIVE
#define GIT_COMMIT_ID "$Format:%h$"
#define GIT_COMMIT_DATE "$Format:%cD$"
#endif

#define BUILD_DESC_WITH_SUFFIX(maj, min, rev, build, suffix) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-" DO_STRINGIZE(suffix)

#define BUILD_DESC_FROM_COMMIT(maj, min, rev, build, commit) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-g" commit

#define BUILD_DESC_FROM_UNKNOWN(maj, min, rev, build) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk"

#ifndef BUILD_DESC
#ifdef BUILD_SUFFIX
#define BUILD_DESC BUILD_DESC_WITH_SUFFIX(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, BUILD_SUFFIX)
#elif defined(GIT_COMMIT_ID)
#define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
#else
#define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
#endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);

static std::string FormatVersion(int nVersion)
{
    if (nVersion % 100 == 0)
        return strprintf("%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100);
    else
        return strprintf("%d.%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, nVersion % 100);
}

std::string FormatFullVersion()
{
    return CLIENT_BUILD;
}

/**
 * Format the subversion field according to BIP 14 spec (https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki)
 */
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)
{
    std::ostringstream ss;
    ss << "/";
    ss << name << ":" << FormatVersion(nClientVersion);
    if (!comments.empty())
    {
        std::vector<std::string>::const_iterator it(comments.begin());
        ss << "(" << *it;
        for(++it; it != comments.end(); ++it)
            ss << "; " << *it;
        ss << ")";
    }
    ss << "/";
    return ss.str();
}
<commit_msg>Correct typo in comments<commit_after>// Copyright (c) 2012-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "clientversion.h"

#include "tinyformat.h"

#include <string>

/**
 * Name of client reported in the 'version' message. Report the same name
 * for both bitcoind and bitcoin-qt, to make it harder for attackers to
 * target servers or GUI users specifically.
 */
const std::string CLIENT_NAME("Satoshi");

/**
 * Client version number
 */
#define CLIENT_VERSION_SUFFIX ""

/**
 * The following part of the code determines the CLIENT_BUILD variable.
 * Several mechanisms are used for this:
 * * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
 *   generated by the build environment, possibly containing the output
 *   of git-describe in a macro called BUILD_DESC
 * * secondly, if this is an exported version of the code, GIT_ARCHIVE will
 *   be defined (automatically using the export-subst git attribute), and
 *   GIT_COMMIT will contain the commit id.
 * * then, three options exist for determining CLIENT_BUILD:
 *   * if BUILD_DESC is defined, use that literally (output of git-describe)
 *   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
 *   * otherwise, use v[maj].[min].[rev].[build]-unk
 * finally CLIENT_VERSION_SUFFIX is added
 */

//! First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#include "build.h"
#endif

//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
#ifdef GIT_ARCHIVE
#define GIT_COMMIT_ID "$Format:%h$"
#define GIT_COMMIT_DATE "$Format:%cD$"
#endif

#define BUILD_DESC_WITH_SUFFIX(maj, min, rev, build, suffix) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-" DO_STRINGIZE(suffix)

#define BUILD_DESC_FROM_COMMIT(maj, min, rev, build, commit) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-g" commit

#define BUILD_DESC_FROM_UNKNOWN(maj, min, rev, build) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk"

#ifndef BUILD_DESC
#ifdef BUILD_SUFFIX
#define BUILD_DESC BUILD_DESC_WITH_SUFFIX(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, BUILD_SUFFIX)
#elif defined(GIT_COMMIT_ID)
#define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
#else
#define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
#endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);

static std::string FormatVersion(int nVersion)
{
    if (nVersion % 100 == 0)
        return strprintf("%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100);
    else
        return strprintf("%d.%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, nVersion % 100);
}

std::string FormatFullVersion()
{
    return CLIENT_BUILD;
}

/**
 * Format the subversion field according to BIP 14 spec (https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki)
 */
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)
{
    std::ostringstream ss;
    ss << "/";
    ss << name << ":" << FormatVersion(nClientVersion);
    if (!comments.empty())
    {
        std::vector<std::string>::const_iterator it(comments.begin());
        ss << "(" << *it;
        for(++it; it != comments.end(); ++it)
            ss << "; " << *it;
        ss << ")";
    }
    ss << "/";
    return ss.str();
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/thread/FixedSizeThreadPool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/VFS.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-http/VFSFileServlet.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/SSTableServlet.h"
#include "fnord-eventdb/EventDBServlet.h"
#include "fnord-eventdb/TableRepository.h"
#include "fnord-eventdb/TableJanitor.h"
#include "fnord-eventdb/TableReplication.h"
#include "fnord-eventdb/ArtifactReplication.h"
#include "fnord-eventdb/NumericBoundsSummary.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "common.h"
#include "schemas.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "analytics/AnalyticsServlet.h"
#include "analytics/CTRByPageServlet.h"
#include "analytics/CTRStatsServlet.h"
#include "analytics/CTRByPositionQuery.h"
#include "analytics/CTRByPageQuery.h"
#include "analytics/TopSearchQueriesQuery.h"
#include "analytics/DiscoveryKPIQuery.h"
#include "analytics/DiscoveryCategoryStatsQuery.h"
#include "analytics/AnalyticsQueryEngine.h"
#include "analytics/AnalyticsQueryEngine.h"

using namespace fnord;

std::atomic<bool> shutdown_sig;
fnord::thread::EventLoop ev;

void quit(int n) {
  shutdown_sig = true;
  fnord::logInfo("cm.chunkserver", "Shutting down...");
  // FIXPAUL: wait for http server stop...
  ev.shutdown();
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  /* shutdown hook */
  shutdown_sig = false;
  struct sigaction sa;
  memset(&sa, 0, sizeof(struct sigaction));
  sa.sa_handler = quit;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGQUIT, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "http_port",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8000",
      "Start the public http server on this port",
      "<port>");

  flags.defineFlag(
      "readonly",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "readonly",
      "readonly");

  flags.defineFlag(
      "replica",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "replica id",
      "<id>");

  flags.defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "datadir path",
      "<path>");

  flags.defineFlag(
      "replicate_from",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "url",
      "<url>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* start http server */
  fnord::thread::ThreadPool tpool;
  fnord::thread::FixedSizeThreadPool wpool(8);
  fnord::http::HTTPRouter http_router;
  fnord::http::HTTPServer http_server(&http_router, &ev);
  http_server.listen(flags.getInt("http_port"));

  /* eventdb */
  auto dir = flags.getString("datadir");
  auto readonly = flags.isSet("readonly");
  auto replica = flags.getString("replica");

  Set<String> tbls  = { "dawanda_joined_sessions", "joined_sessions-dawanda" };
  http::HTTPConnectionPool http(&ev);
  eventdb::ArtifactIndex artifacts(dir, replica, readonly);
  eventdb::TableRepository table_repo(
      &artifacts,
      dir,
      replica,
      readonly,
      &wpool);

  auto joined_sessions_schema = joinedSessionsSchema();
  for (const auto& tbl : tbls) {
    table_repo.addTable(tbl, joined_sessions_schema);
  }

  if (!readonly) {
    for (const auto& tbl : tbls) {
      auto joined_sessions_table =table_repo.findTableWriter(tbl);

      joined_sessions_table->addSummary(
          [joined_sessions_schema] () -> RefPtr<eventdb::TableChunkSummaryBuilder> {
            return new eventdb::NumericBoundsSummaryBuilder(
                "queries.time-bounds",
                joined_sessions_schema.id("queries.time"));
          });
    }
  }

  eventdb::TableReplication table_replication(&http);
  eventdb::ArtifactReplication artifact_replication(
      &artifacts,
      &http,
      &wpool,
      8);

  for (const auto& rep : flags.getStrings("replicate_from")) {
    for (const auto& tbl : tbls) {
      table_replication.replicateTableFrom(
          table_repo.findTableWriter(tbl),
          URI(StringUtil::format("http://$0:7003/eventdb", rep)));
    }

    artifact_replication.addSource(
        URI(StringUtil::format("http://$0:7005/chunks", rep)));
  }

  eventdb::TableJanitor table_janitor(&table_repo);
  if (!readonly) {
    table_janitor.start();
    table_replication.start();
    artifact_replication.start();
  }

  eventdb::EventDBServlet eventdb_servlet(&table_repo);

  /* analytics */
  cm::AnalyticsQueryEngine analytics(32, dir, &table_repo);
  cm::AnalyticsServlet analytics_servlet(&analytics);
  http_router.addRouteByPrefixMatch("/analytics", &analytics_servlet, &tpool);
  http_router.addRouteByPrefixMatch("/eventdb", &eventdb_servlet, &tpool);

  analytics.registerQueryFactory("ctr_by_position", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPositionQuery(scan, segments);
  });

  analytics.registerQueryFactory("ctr_by_page", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPageQuery(scan, segments);
  });

  analytics.registerQueryFactory("discovery_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryKPIQuery(
        scan,
        segments,
        query.start_time,
        query.end_time);
  });

  analytics.registerQueryFactory("discovery_category0_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category1",
        "queries.category1",
        params);
  });

  analytics.registerQueryFactory("discovery_category1_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category1",
        "queries.category2",
        params);
  });

  analytics.registerQueryFactory("discovery_category2_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category2",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("discovery_category3_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category3",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("top_search_queries", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::TopSearchQueriesQuery(scan, segments, params);
  });

  ev.run();

  if (!readonly) {
    table_janitor.stop();
    table_janitor.check();
    table_replication.stop();
    artifact_replication.stop();
  }

  fnord::logInfo("cm.chunkserver", "Exiting...");

  exit(0);
}

<commit_msg>put replication on it's own threadpool<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/thread/FixedSizeThreadPool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/VFS.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-http/VFSFileServlet.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/SSTableServlet.h"
#include "fnord-eventdb/EventDBServlet.h"
#include "fnord-eventdb/TableRepository.h"
#include "fnord-eventdb/TableJanitor.h"
#include "fnord-eventdb/TableReplication.h"
#include "fnord-eventdb/ArtifactReplication.h"
#include "fnord-eventdb/NumericBoundsSummary.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "common.h"
#include "schemas.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "analytics/AnalyticsServlet.h"
#include "analytics/CTRByPageServlet.h"
#include "analytics/CTRStatsServlet.h"
#include "analytics/CTRByPositionQuery.h"
#include "analytics/CTRByPageQuery.h"
#include "analytics/TopSearchQueriesQuery.h"
#include "analytics/DiscoveryKPIQuery.h"
#include "analytics/DiscoveryCategoryStatsQuery.h"
#include "analytics/AnalyticsQueryEngine.h"
#include "analytics/AnalyticsQueryEngine.h"

using namespace fnord;

std::atomic<bool> shutdown_sig;
fnord::thread::EventLoop ev;

void quit(int n) {
  shutdown_sig = true;
  fnord::logInfo("cm.chunkserver", "Shutting down...");
  // FIXPAUL: wait for http server stop...
  ev.shutdown();
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  /* shutdown hook */
  shutdown_sig = false;
  struct sigaction sa;
  memset(&sa, 0, sizeof(struct sigaction));
  sa.sa_handler = quit;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGQUIT, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "http_port",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8000",
      "Start the public http server on this port",
      "<port>");

  flags.defineFlag(
      "readonly",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "readonly",
      "readonly");

  flags.defineFlag(
      "replica",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "replica id",
      "<id>");

  flags.defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "datadir path",
      "<path>");

  flags.defineFlag(
      "replicate_from",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "url",
      "<url>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* start http server */
  fnord::thread::ThreadPool tpool;
  fnord::thread::FixedSizeThreadPool wpool(8);
  fnord::thread::FixedSizeThreadPool repl_wpool(8);
  fnord::http::HTTPRouter http_router;
  fnord::http::HTTPServer http_server(&http_router, &ev);
  http_server.listen(flags.getInt("http_port"));

  /* eventdb */
  auto dir = flags.getString("datadir");
  auto readonly = flags.isSet("readonly");
  auto replica = flags.getString("replica");

  Set<String> tbls  = { "dawanda_joined_sessions", "joined_sessions-dawanda" };
  http::HTTPConnectionPool http(&ev);
  eventdb::ArtifactIndex artifacts(dir, replica, readonly);
  eventdb::TableRepository table_repo(
      &artifacts,
      dir,
      replica,
      readonly,
      &wpool);

  auto joined_sessions_schema = joinedSessionsSchema();
  for (const auto& tbl : tbls) {
    table_repo.addTable(tbl, joined_sessions_schema);
  }

  if (!readonly) {
    for (const auto& tbl : tbls) {
      auto joined_sessions_table =table_repo.findTableWriter(tbl);

      joined_sessions_table->addSummary(
          [joined_sessions_schema] () -> RefPtr<eventdb::TableChunkSummaryBuilder> {
            return new eventdb::NumericBoundsSummaryBuilder(
                "queries.time-bounds",
                joined_sessions_schema.id("queries.time"));
          });
    }
  }

  eventdb::TableReplication table_replication(&http);
  eventdb::ArtifactReplication artifact_replication(
      &artifacts,
      &http,
      &repl_wpool,
      8);

  for (const auto& rep : flags.getStrings("replicate_from")) {
    for (const auto& tbl : tbls) {
      table_replication.replicateTableFrom(
          table_repo.findTableWriter(tbl),
          URI(StringUtil::format("http://$0:7003/eventdb", rep)));
    }

    artifact_replication.addSource(
        URI(StringUtil::format("http://$0:7005/chunks", rep)));
  }

  eventdb::TableJanitor table_janitor(&table_repo);
  if (!readonly) {
    table_janitor.start();
    table_replication.start();
    artifact_replication.start();
  }

  eventdb::EventDBServlet eventdb_servlet(&table_repo);

  /* analytics */
  cm::AnalyticsQueryEngine analytics(32, dir, &table_repo);
  cm::AnalyticsServlet analytics_servlet(&analytics);
  http_router.addRouteByPrefixMatch("/analytics", &analytics_servlet, &tpool);
  http_router.addRouteByPrefixMatch("/eventdb", &eventdb_servlet, &tpool);

  analytics.registerQueryFactory("ctr_by_position", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPositionQuery(scan, segments);
  });

  analytics.registerQueryFactory("ctr_by_page", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPageQuery(scan, segments);
  });

  analytics.registerQueryFactory("discovery_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryKPIQuery(
        scan,
        segments,
        query.start_time,
        query.end_time);
  });

  analytics.registerQueryFactory("discovery_category0_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category1",
        "queries.category1",
        params);
  });

  analytics.registerQueryFactory("discovery_category1_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category1",
        "queries.category2",
        params);
  });

  analytics.registerQueryFactory("discovery_category2_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category2",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("discovery_category3_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category3",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("top_search_queries", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::TopSearchQueriesQuery(scan, segments, params);
  });

  ev.run();

  if (!readonly) {
    table_janitor.stop();
    table_janitor.check();
    table_replication.stop();
    artifact_replication.stop();
  }

  fnord::logInfo("cm.chunkserver", "Exiting...");

  exit(0);
}

<|endoftext|>


<commit_before>#ifdef __wasm__

#include <cstdint>

namespace {

struct Tetra
{
    [[gnu::mode(TF)]] typedef float Real;

    unsigned __int128 mantissa: 112;
    unsigned int exp : 15;
    unsigned int sign:  1;

    Tetra(Real);

    explicit operator Real() const;
    explicit operator __int128() const;
    explicit operator bool() const;

    bool isnan() const;
};

Tetra::Tetra(Real real)
{
    static_assert(sizeof(Tetra) == sizeof(Real), "Bug: [[gnu::mode(TF)]] float does not fit Tetra.");
    __builtin_memcpy(this, &real, sizeof(Tetra));
}

Tetra::operator Real() const
{
    Real result;
    __builtin_memcpy(&result, this, sizeof(Tetra));
    return result;
}

Tetra::operator __int128() const
{
    __int128 result;
    __builtin_memcpy(&result, this, sizeof(Tetra));
    return result;
}

Tetra::operator bool() const
{
    return exp || mantissa;
}

bool Tetra::isnan() const
{
    return exp == 0x7fff && mantissa;
}

} // namespace

bool isunordered(Tetra a, Tetra b)
{
    return Tetra(a).isnan() || Tetra(b).isnan();
}

bool operator==(Tetra a, Tetra b)
{
    return (__int128(a) == __int128(b) && !a.isnan()) || !(a || b);
}

extern "C" {

int __unordtf2(Tetra::Real a, Tetra::Real b)
{
    return isunordered(Tetra(a), Tetra(b));
}

int __eqtf2(Tetra::Real a, Tetra::Real b)
{
    return Tetra(a) == Tetra(b);
}

int __netf2(Tetra::Real a, Tetra::Real b)
{
    return !__eqtf2(a, b);
}

} // extern "C"

#endif // __wasm__
<commit_msg>Casting with member function is more explicit than conversion<commit_after>#ifdef __wasm__

#include <cstdint>

namespace {

struct Tetra
{
    [[gnu::mode(TF)]] typedef float Real;

    unsigned __int128 mantissa: 112;
    unsigned int exp : 15;
    unsigned int sign:  1;

    Tetra(Real);

    explicit operator Real() const;
    explicit operator bool() const;

    __int128 bits() const;
    bool isnan() const;
};

Tetra::Tetra(Real real)
{
    static_assert(sizeof(Tetra) == sizeof(Real), "Bug: [[gnu::mode(TF)]] float does not fit Tetra.");
    __builtin_memcpy(this, &real, sizeof(Tetra));
}

Tetra::operator Real() const
{
    Real result;
    __builtin_memcpy(&result, this, sizeof(Tetra));
    return result;
}

Tetra::operator bool() const
{
    return exp || mantissa;
}

__int128 Tetra::bits() const
{
    __int128 result;
    __builtin_memcpy(&result, this, sizeof(Tetra));
    return result;
}

bool Tetra::isnan() const
{
    return exp == 0x7fff && mantissa;
}

} // namespace

bool isunordered(Tetra a, Tetra b)
{
    return Tetra(a).isnan() || Tetra(b).isnan();
}

bool operator==(Tetra a, Tetra b)
{
    return (a.bits() == b.bits() && !a.isnan()) || !(a || b);
}

extern "C" {

int __unordtf2(Tetra::Real a, Tetra::Real b)
{
    return isunordered(Tetra(a), Tetra(b));
}

int __eqtf2(Tetra::Real a, Tetra::Real b)
{
    return Tetra(a) == Tetra(b);
}

int __netf2(Tetra::Real a, Tetra::Real b)
{
    return !__eqtf2(a, b);
}

} // extern "C"

#endif // __wasm__
<|endoftext|>


<commit_before>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgAnimation/Timeline>

using namespace osgAnimation;

Timeline::Timeline()
{
    _lastUpdate = 0;
    _currentFrame = 0;
    _fps = 25;
    _speed = 1.0;
    _state = Stop;
    _initFirstFrame = false;
    _previousFrameEvaluated = 0;
    _evaluating = 0;
    _numberFrame = -1; // something like infinity
    setName("Timeline");
}

Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, op),
    _actions(nc._actions)
{
    _lastUpdate = 0;
    _currentFrame = 0;
    _fps = 25;
    _speed = 1.0;
    _state = Stop;
    _initFirstFrame = false;
    _previousFrameEvaluated = 0;
    _evaluating = 0;
    _numberFrame = -1; // something like infinity
    setName("Timeline");
}
<commit_msg>From Cedric Pinson, warning fix.<commit_after>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgAnimation/Timeline>
#include <limits.h>

using namespace osgAnimation;

Timeline::Timeline()
{
    _lastUpdate = 0;
    _currentFrame = 0;
    _fps = 25;
    _speed = 1.0;
    _state = Stop;
    _initFirstFrame = false;
    _previousFrameEvaluated = 0;
    _evaluating = 0;
    _numberFrame = UINT_MAX; // something like infinity
    setName("Timeline");
}

Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, op),
    _actions(nc._actions)
{
    _lastUpdate = 0;
    _currentFrame = 0;
    _fps = 25;
    _speed = 1.0;
    _state = Stop;
    _initFirstFrame = false;
    _previousFrameEvaluated = 0;
    _evaluating = 0;
    _numberFrame = UINT_MAX; // something like infinity
    setName("Timeline");
}
<|endoftext|>


<commit_before>#include "mDebuglib.hpp"

namespace DebugLib
{

#ifdef DEBUG_LIB_FILE_LOG
    ::std::ofstream DEBUG_LIB_LOG_FILE_VAR_NAME(DEBUG_LIB_LOG_FILE_NAME, ::std::fstream::app | ::std::fstream::out);
#endif

#ifdef DEBUG_LIB_THREAD_SAFETY
    ::std::mutex DEBUG_LIB_MUTEX_VAR_NAME;
#endif

    class LogLevel
    {
	public:

		LogLevel(::DebugLib::Level level) : logLevel(level) {}

    protected:
		friend Level DebugLib::GetGlobalLogLevel();
		friend bool DebugLib::try_SetGlobalLogLevel(Level l);
		friend void DebugLib::SetGlobalLogLevel(Level l);
#ifdef DEBUG_LIB_THREAD_SAFETY
		Level getLogLevel()
		{
			return static_cast<Level>(logLevel.load());
		}

		bool try_SetLogLevel(Level l)
		{
			int dummy = logLevel.load();
			return logLevel.compare_exchange_strong(dummy, static_cast<int>(l));
		}

		void setLogLevel(Level l)
		{
			int dummy = logLevel.load();
			while (!logLevel.compare_exchange_weak(dummy, static_cast<int>(l)));
		}
	private:
		std::atomic<int>  logLevel;
#else
		Level getLogLevel()
		{
			return static_cast<Level>(logLevel);
		}

		bool try_SetLogLevel(Level l)
		{
			logLevel = static_cast<int>(l);
			return true;
		}

		void setLogLevel(Level l)
		{
			logLevel = static_cast<int>(l);
		}
	private:
		int logLevel;
#endif
		LogLevel(const LogLevel&) {}
		LogLevel& operator=(const LogLevel&) { return *this; }
		//* (//* -> /* (remove first slash) if C++98 is used)
		LogLevel(LogLevel&&) {}
		LogLevel& operator=(LogLevel&&) { return *this; }
		//*/
	};
}

static DebugLib::LogLevel Debug_Lib_Log_State__(DEBUG_LIB_DEFAULT_LOG_LEVEL);

DebugLib::Level DebugLib::GetGlobalLogLevel()
{
    return Debug_Lib_Log_State__.getLogLevel();
}

bool DebugLib::try_SetGlobalLogLevel(DebugLib::Level l)
{
    return Debug_Lib_Log_State__.try_SetLogLevel(l);
}

void DebugLib::SetGlobalLogLevel(DebugLib::Level l)
{
	Debug_Lib_Log_State__.setLogLevel(l);
}<commit_msg>Include corrected.<commit_after>#include <DebugLib/mDebugLib.hpp>

namespace DebugLib
{

#ifdef DEBUG_LIB_FILE_LOG
    ::std::ofstream DEBUG_LIB_LOG_FILE_VAR_NAME(DEBUG_LIB_LOG_FILE_NAME, ::std::fstream::app | ::std::fstream::out);
#endif

#ifdef DEBUG_LIB_THREAD_SAFETY
    ::std::mutex DEBUG_LIB_MUTEX_VAR_NAME;
#endif

    class LogLevel
    {
	public:

		LogLevel(::DebugLib::Level level) : logLevel(level) {}

    protected:
		friend Level DebugLib::GetGlobalLogLevel();
		friend bool DebugLib::try_SetGlobalLogLevel(Level l);
		friend void DebugLib::SetGlobalLogLevel(Level l);
#ifdef DEBUG_LIB_THREAD_SAFETY
		Level getLogLevel()
		{
			return static_cast<Level>(logLevel.load());
		}

		bool try_SetLogLevel(Level l)
		{
			int dummy = logLevel.load();
			return logLevel.compare_exchange_strong(dummy, static_cast<int>(l));
		}

		void setLogLevel(Level l)
		{
			int dummy = logLevel.load();
			while (!logLevel.compare_exchange_weak(dummy, static_cast<int>(l)));
		}
	private:
		std::atomic<int>  logLevel;
#else
		Level getLogLevel()
		{
			return static_cast<Level>(logLevel);
		}

		bool try_SetLogLevel(Level l)
		{
			logLevel = static_cast<int>(l);
			return true;
		}

		void setLogLevel(Level l)
		{
			logLevel = static_cast<int>(l);
		}
	private:
		int logLevel;
#endif
		LogLevel(const LogLevel&) {}
		LogLevel& operator=(const LogLevel&) { return *this; }
		//* (//* -> /* (remove first slash) if C++98 is used)
		LogLevel(LogLevel&&) {}
		LogLevel& operator=(LogLevel&&) { return *this; }
		//*/
	};
}

static DebugLib::LogLevel Debug_Lib_Log_State__(DEBUG_LIB_DEFAULT_LOG_LEVEL);

DebugLib::Level DebugLib::GetGlobalLogLevel()
{
    return Debug_Lib_Log_State__.getLogLevel();
}

bool DebugLib::try_SetGlobalLogLevel(DebugLib::Level l)
{
    return Debug_Lib_Log_State__.try_SetLogLevel(l);
}

void DebugLib::SetGlobalLogLevel(DebugLib::Level l)
{
	Debug_Lib_Log_State__.setLogLevel(l);
}<|endoftext|>


<commit_before>/*
 * This file is part of TelepathyQt4Yell
 *
 * Copyright © 2009-2011 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright © 2009 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4Yell/Farstream/Channel>

#include "TelepathyQt4Yell/Farstream/_gen/channel.moc.hpp"

#include <TelepathyQt4/Channel>
#include <TelepathyQt4/Connection>

#include <TelepathyQt4Yell/CallChannel>
#include <TelepathyQt4Yell/Farstream/global.h>

#include <telepathy-glib/channel.h>
#include <telepathy-glib/connection.h>
#include <telepathy-glib/dbus.h>

#include <gst/gst.h>

namespace Tpy
{

struct TELEPATHY_QT4_YELL_FS_NO_EXPORT PendingTfChannel::Private
{
    Private(const CallChannelPtr &channel)
        : mChannel(channel),
          mTfChannel(0)
    {
    }

    static void onTfChannelNewFinish(GObject *sourceObject, GAsyncResult *res, gpointer userData);

    CallChannelPtr mChannel;
    TfChannel *mTfChannel;
};

PendingTfChannel::PendingTfChannel(const FarstreamChannelFactoryPtr &fcf,
        const CallChannelPtr &channel)
    : Tp::PendingOperation(fcf),
      mPriv(new PendingTfChannel::Private(channel))
{
    if (!mPriv->mChannel->handlerStreamingRequired()) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Handler streaming not required"));
        return;
    }

    TpDBusDaemon *dbus = tp_dbus_daemon_dup(0);
    if (!dbus) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to connect to D-Bus"));
        return;
    }

    Tp::ConnectionPtr connection = mPriv->mChannel->connection();
    if (connection.isNull()) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Connection not available"));
        g_object_unref(dbus);
        return;
    }

    TpConnection *gconnection = tp_connection_new(dbus,
            connection->busName().toAscii(),
            connection->objectPath().toAscii(),
            0);
    g_object_unref(dbus);
    dbus = 0;
    if (!gconnection) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to construct TpConnection"));
        return;
    }

    TpChannel *gchannel = tp_channel_new(gconnection,
            channel->objectPath().toAscii(),
            TP_QT4_YELL_IFACE_CHANNEL_TYPE_CALL.latin1(),
            (TpHandleType) channel->targetHandleType(),
            channel->targetHandle(),
            0);
    g_object_unref(gconnection);
    gconnection = 0;
    if (!gchannel) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to construct TpChannel"));
        return;
    }

    tf_channel_new_async(gchannel, PendingTfChannel::Private::onTfChannelNewFinish, this);
    g_object_unref(gchannel);
}

PendingTfChannel::~PendingTfChannel()
{
    delete mPriv;
}

void PendingTfChannel::Private::onTfChannelNewFinish(GObject *sourceObject,
        GAsyncResult *res, gpointer userData)
{
    qDebug() << "PendingTfChannel::Private::onTfChannelNewFinish: ";
    qDebug() << "    sourceObject=" << sourceObject;
    qDebug() << "    result=" << res;

    PendingTfChannel *self = reinterpret_cast<PendingTfChannel *>(userData);

    GError *error = NULL;
    TfChannel *ret = TF_CHANNEL(g_async_initable_new_finish(
                G_ASYNC_INITABLE(sourceObject), res, &error));
    if (error) {
        qDebug() << "PendingTfChannel::Private::onTfChannelNewFinish: error " << error->message;
        g_clear_error(&error);
        self->setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE, QLatin1String(error->message));
        return;
    }

    self->mPriv->mTfChannel = ret;
    self->setFinished();
}

TfChannel *PendingTfChannel::tfChannel() const
{
    return mPriv->mTfChannel;
}

FarstreamChannelFactoryPtr FarstreamChannelFactory::create()
{
    return FarstreamChannelFactoryPtr(new FarstreamChannelFactory());
}

FarstreamChannelFactory::FarstreamChannelFactory()
    : mPriv(0)
{
}

FarstreamChannelFactory::~FarstreamChannelFactory()
{
}

PendingTfChannel *FarstreamChannelFactory::createTfChannel(const CallChannelPtr &channel)
{
    PendingTfChannel *ptf = new PendingTfChannel(FarstreamChannelFactoryPtr(this), channel);
    return ptf;
}

} // Tpy
<commit_msg>Fix trivial use-after-free crash<commit_after>/*
 * This file is part of TelepathyQt4Yell
 *
 * Copyright © 2009-2011 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright © 2009 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4Yell/Farstream/Channel>

#include "TelepathyQt4Yell/Farstream/_gen/channel.moc.hpp"

#include <TelepathyQt4/Channel>
#include <TelepathyQt4/Connection>

#include <TelepathyQt4Yell/CallChannel>
#include <TelepathyQt4Yell/Farstream/global.h>

#include <telepathy-glib/channel.h>
#include <telepathy-glib/connection.h>
#include <telepathy-glib/dbus.h>

#include <gst/gst.h>

namespace Tpy
{

struct TELEPATHY_QT4_YELL_FS_NO_EXPORT PendingTfChannel::Private
{
    Private(const CallChannelPtr &channel)
        : mChannel(channel),
          mTfChannel(0)
    {
    }

    static void onTfChannelNewFinish(GObject *sourceObject, GAsyncResult *res, gpointer userData);

    CallChannelPtr mChannel;
    TfChannel *mTfChannel;
};

PendingTfChannel::PendingTfChannel(const FarstreamChannelFactoryPtr &fcf,
        const CallChannelPtr &channel)
    : Tp::PendingOperation(fcf),
      mPriv(new PendingTfChannel::Private(channel))
{
    if (!mPriv->mChannel->handlerStreamingRequired()) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Handler streaming not required"));
        return;
    }

    TpDBusDaemon *dbus = tp_dbus_daemon_dup(0);
    if (!dbus) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to connect to D-Bus"));
        return;
    }

    Tp::ConnectionPtr connection = mPriv->mChannel->connection();
    if (connection.isNull()) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Connection not available"));
        g_object_unref(dbus);
        return;
    }

    TpConnection *gconnection = tp_connection_new(dbus,
            connection->busName().toAscii(),
            connection->objectPath().toAscii(),
            0);
    g_object_unref(dbus);
    dbus = 0;
    if (!gconnection) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to construct TpConnection"));
        return;
    }

    TpChannel *gchannel = tp_channel_new(gconnection,
            channel->objectPath().toAscii(),
            TP_QT4_YELL_IFACE_CHANNEL_TYPE_CALL.latin1(),
            (TpHandleType) channel->targetHandleType(),
            channel->targetHandle(),
            0);
    g_object_unref(gconnection);
    gconnection = 0;
    if (!gchannel) {
        setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to construct TpChannel"));
        return;
    }

    tf_channel_new_async(gchannel, PendingTfChannel::Private::onTfChannelNewFinish, this);
    g_object_unref(gchannel);
}

PendingTfChannel::~PendingTfChannel()
{
    delete mPriv;
}

void PendingTfChannel::Private::onTfChannelNewFinish(GObject *sourceObject,
        GAsyncResult *res, gpointer userData)
{
    qDebug() << "PendingTfChannel::Private::onTfChannelNewFinish: ";
    qDebug() << "    sourceObject=" << sourceObject;
    qDebug() << "    result=" << res;

    PendingTfChannel *self = reinterpret_cast<PendingTfChannel *>(userData);

    GError *error = NULL;
    TfChannel *ret = TF_CHANNEL(g_async_initable_new_finish(
                G_ASYNC_INITABLE(sourceObject), res, &error));
    if (error) {
        qDebug() << "PendingTfChannel::Private::onTfChannelNewFinish: error " << error->message;
        self->setFinishedWithError(TP_QT4_ERROR_NOT_AVAILABLE, QLatin1String(error->message));
        g_clear_error(&error);
        return;
    }

    self->mPriv->mTfChannel = ret;
    self->setFinished();
}

TfChannel *PendingTfChannel::tfChannel() const
{
    return mPriv->mTfChannel;
}

FarstreamChannelFactoryPtr FarstreamChannelFactory::create()
{
    return FarstreamChannelFactoryPtr(new FarstreamChannelFactory());
}

FarstreamChannelFactory::FarstreamChannelFactory()
    : mPriv(0)
{
}

FarstreamChannelFactory::~FarstreamChannelFactory()
{
}

PendingTfChannel *FarstreamChannelFactory::createTfChannel(const CallChannelPtr &channel)
{
    PendingTfChannel *ptf = new PendingTfChannel(FarstreamChannelFactoryPtr(this), channel);
    return ptf;
}

} // Tpy
<|endoftext|>


<commit_before>/***********************************************************************
 connection.cpp - Implements the Connection class.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and
 (c) 2004-2007 by Educational Technology Resources, Inc.  Others may
 also hold copyrights on code in this file.  See the CREDITS file in
 the top directory of the distribution for details.

 This file is part of MySQL++.

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

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#define MYSQLPP_NOT_HEADER
#include "connection.h"

#include "dbdriver.h"
#include "query.h"
#include "result.h"

using namespace std;

namespace mysqlpp {

Connection::Connection(bool te) :
OptionalExceptions(te),
driver_(new DBDriver()),
copacetic_(true)
{
}

Connection::Connection(cchar* db, cchar* server, cchar* user,
		cchar* password, unsigned int port) :
OptionalExceptions(),
driver_(new DBDriver()),
copacetic_(true)
{
	connect(db, server, user, password);
}

Connection::Connection(const Connection& other) :
OptionalExceptions(),
driver_(new DBDriver(*other.driver_))
{
	copy(other);
}

Connection::~Connection()
{
	disconnect();
	delete driver_;
}

void
Connection::build_error_message(const char* core)
{
	error_message_ = "Can't ";
	error_message_ += core;
	error_message_ += " while disconnected";
}

std::string
Connection::client_version() const
{
	return driver_->client_version();
}

bool
Connection::connect(cchar* db, cchar* server, cchar* user,
		cchar* password, unsigned int port)
{
	// Figure out what the server parameter means, then try to establish
	// the connection.
	error_message_.clear();
	string host, socket_name;
	copacetic_ = parse_ipc_method(server, host, port, socket_name) &&
			driver_->connect(host.c_str(),
			(socket_name.empty() ? 0 : socket_name.c_str()), port, db,
			user, password);

	// If it failed, decide how to tell the user
	if (!copacetic_ && throw_exceptions()) {
		throw ConnectionFailed(error(), errnum());
	}
	else {
		return copacetic_;
	}
}

bool
Connection::connected() const
{
	return driver_->connected();
}

void
Connection::copy(const Connection& other)
{
	error_message_.clear();
	set_exceptions(other.throw_exceptions());
	driver_->copy(*other.driver_);
}

bool
Connection::create_db(const std::string& db)
{
	error_message_.clear();
	Query q(this, throw_exceptions());
	q << "CREATE DATABASE " << db;
	return q.exec();
}

void
Connection::disconnect()
{
	error_message_.clear();
	driver_->disconnect();
}

bool
Connection::drop_db(const std::string& db)
{
	error_message_.clear();
	Query q(this, throw_exceptions());
	q << "DROP DATABASE " << db;
	return q.exec();
}

void
Connection::enable_ssl(const char* key, const char* cert,
		const char* ca, const char* capath, const char* cipher) const
{
	error_message_ = driver_->enable_ssl(key, cert, ca, capath, cipher);
}

int
Connection::errnum()
{
	return driver_->errnum();
}

const char*
Connection::error() const
{
	return error_message_.size() ? error_message_.c_str() : driver_->error();
}

std::string
Connection::ipc_info() const
{
	return driver_->ipc_info();
}

bool
Connection::kill(unsigned long tid) const
{
	error_message_.clear();
	return driver_->kill(tid);
}

Connection&
Connection::operator=(const Connection& rhs)
{
	copy(rhs);
	return *this;
}

bool
Connection::option_error_check(option::Type o) const
{
	if (error_message_.empty()) {
		return true;
	}
	else {
		if (throw_exceptions()) {
			throw BadOption(error_message_, o);
		}
		return false;
	}
}

bool
Connection::option_set(option::Type o) const
{
	return driver_->option_set(o);
}

bool
Connection::parse_ipc_method(const char* server, string& host,
		unsigned int& port, string& socket_name)
{
	// NOTE: This routine has no connection type knowledge.  It can only
	// recognize a 0 value for the server parameter.  All substantial
	// tests are delegated to our specialized subclasses, which figure
	// out what kind of connection the server address denotes.  We do
	// the platform-specific tests first as they're the most reliable.

	if (server == 0) {
		// Just take all the defaults
		return true;
	}
	else if (WindowsNamedPipeConnection::is_wnp(server)) {
		// Use Windows named pipes
		host = server;
		return true;
	}
	else if (UnixDomainSocketConnection::is_socket(server)) {
		// Use Unix domain sockets
		socket_name = server;
		return true;
	}
	else {
		// Failing above, it can only be some kind of TCP/IP address.
		host = server;
		return TCPConnection::parse_address(host, port, error_message_);
	}
}

bool
Connection::ping()
{
	if (connected()) {
		error_message_.clear();
		return driver_->ping();
	}
	else {
		// Not connected, and we've forgotten everything we need in
		// order to re-connect, if we once were connected.
		build_error_message("ping database server");
		return false;
	}
}

int
Connection::protocol_version() const
{
	return driver_->protocol_version();
}

Query
Connection::query(const char* qstr)
{
	return Query(this, throw_exceptions(), qstr);
}

Query
Connection::query(const std::string& qstr)
{
	return query(qstr.c_str());
}

bool
Connection::select_db(const std::string& db)
{
	error_message_.clear();
	if (connected()) {
		if (driver_->select_db(db.c_str())) {
			return true;
		}
		else {
			if (throw_exceptions()) {
				throw DBSelectionFailed(error(), errnum());
			}
			return false;
		}
	}
	else {
		build_error_message("select a database");
		if (throw_exceptions()) {
			throw DBSelectionFailed(error_message_.c_str());
		}
		return false;
	}
}

std::string
Connection::server_status() const
{
	return driver_->server_status();
}

std::string
Connection::server_version() const
{
	return driver_->server_version();
}

bool
Connection::set_option(option::Type o)
{
	error_message_ = driver_->set_option(o);
	return option_error_check(o);
}

bool
Connection::set_option(option::Type o, const char* arg)
{
	error_message_ = driver_->set_option(o, arg);
	return option_error_check(o);
}

bool
Connection::set_option(option::Type o, unsigned int arg)
{
	error_message_ = driver_->set_option(o, arg);
	return option_error_check(o);
}

bool
Connection::set_option(option::Type o, bool arg)
{
	error_message_ = driver_->set_option(o, arg);
	return option_error_check(o);
}

bool
Connection::shutdown()
{
	error_message_.clear();
	if (connected()) {
		if (driver_->shutdown()) {
			return true;
		}
		else {
			if (throw_exceptions()) {
				throw ConnectionFailed(error(), errnum());
			}
			return false;
		}
	}
	else {
		build_error_message("shutdown database server");
		if (throw_exceptions()) {
			throw ConnectionFailed(error_message_.c_str());
		}
		return false;
	}
}

bool
Connection::thread_aware() const
{
	return driver_->thread_aware();
}

void
Connection::thread_end()
{
	driver_->thread_end();
}

unsigned long
Connection::thread_id()
{
	return driver_->thread_id();
}

bool
Connection::thread_start()
{
	return driver_->thread_start();
}

} // end namespace mysqlpp

<commit_msg>The Connection ctor that establishes a connection at the same time accepts a port parameter, but wasn't passing it to connect().  Fixed.<commit_after>/***********************************************************************
 connection.cpp - Implements the Connection class.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and
 (c) 2004-2007 by Educational Technology Resources, Inc.  Others may
 also hold copyrights on code in this file.  See the CREDITS file in
 the top directory of the distribution for details.

 This file is part of MySQL++.

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

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#define MYSQLPP_NOT_HEADER
#include "connection.h"

#include "dbdriver.h"
#include "query.h"
#include "result.h"

using namespace std;

namespace mysqlpp {

Connection::Connection(bool te) :
OptionalExceptions(te),
driver_(new DBDriver()),
copacetic_(true)
{
}

Connection::Connection(cchar* db, cchar* server, cchar* user,
		cchar* password, unsigned int port) :
OptionalExceptions(),
driver_(new DBDriver()),
copacetic_(true)
{
	connect(db, server, user, password, port);
}

Connection::Connection(const Connection& other) :
OptionalExceptions(),
driver_(new DBDriver(*other.driver_))
{
	copy(other);
}

Connection::~Connection()
{
	disconnect();
	delete driver_;
}

void
Connection::build_error_message(const char* core)
{
	error_message_ = "Can't ";
	error_message_ += core;
	error_message_ += " while disconnected";
}

std::string
Connection::client_version() const
{
	return driver_->client_version();
}

bool
Connection::connect(cchar* db, cchar* server, cchar* user,
		cchar* password, unsigned int port)
{
	// Figure out what the server parameter means, then try to establish
	// the connection.
	error_message_.clear();
	string host, socket_name;
	copacetic_ = parse_ipc_method(server, host, port, socket_name) &&
			driver_->connect(host.c_str(),
			(socket_name.empty() ? 0 : socket_name.c_str()), port, db,
			user, password);

	// If it failed, decide how to tell the user
	if (!copacetic_ && throw_exceptions()) {
		throw ConnectionFailed(error(), errnum());
	}
	else {
		return copacetic_;
	}
}

bool
Connection::connected() const
{
	return driver_->connected();
}

void
Connection::copy(const Connection& other)
{
	error_message_.clear();
	set_exceptions(other.throw_exceptions());
	driver_->copy(*other.driver_);
}

bool
Connection::create_db(const std::string& db)
{
	error_message_.clear();
	Query q(this, throw_exceptions());
	q << "CREATE DATABASE " << db;
	return q.exec();
}

void
Connection::disconnect()
{
	error_message_.clear();
	driver_->disconnect();
}

bool
Connection::drop_db(const std::string& db)
{
	error_message_.clear();
	Query q(this, throw_exceptions());
	q << "DROP DATABASE " << db;
	return q.exec();
}

void
Connection::enable_ssl(const char* key, const char* cert,
		const char* ca, const char* capath, const char* cipher) const
{
	error_message_ = driver_->enable_ssl(key, cert, ca, capath, cipher);
}

int
Connection::errnum()
{
	return driver_->errnum();
}

const char*
Connection::error() const
{
	return error_message_.size() ? error_message_.c_str() : driver_->error();
}

std::string
Connection::ipc_info() const
{
	return driver_->ipc_info();
}

bool
Connection::kill(unsigned long tid) const
{
	error_message_.clear();
	return driver_->kill(tid);
}

Connection&
Connection::operator=(const Connection& rhs)
{
	copy(rhs);
	return *this;
}

bool
Connection::option_error_check(option::Type o) const
{
	if (error_message_.empty()) {
		return true;
	}
	else {
		if (throw_exceptions()) {
			throw BadOption(error_message_, o);
		}
		return false;
	}
}

bool
Connection::option_set(option::Type o) const
{
	return driver_->option_set(o);
}

bool
Connection::parse_ipc_method(const char* server, string& host,
		unsigned int& port, string& socket_name)
{
	// NOTE: This routine has no connection type knowledge.  It can only
	// recognize a 0 value for the server parameter.  All substantial
	// tests are delegated to our specialized subclasses, which figure
	// out what kind of connection the server address denotes.  We do
	// the platform-specific tests first as they're the most reliable.

	if (server == 0) {
		// Just take all the defaults
		return true;
	}
	else if (WindowsNamedPipeConnection::is_wnp(server)) {
		// Use Windows named pipes
		host = server;
		return true;
	}
	else if (UnixDomainSocketConnection::is_socket(server)) {
		// Use Unix domain sockets
		socket_name = server;
		return true;
	}
	else {
		// Failing above, it can only be some kind of TCP/IP address.
		host = server;
		return TCPConnection::parse_address(host, port, error_message_);
	}
}

bool
Connection::ping()
{
	if (connected()) {
		error_message_.clear();
		return driver_->ping();
	}
	else {
		// Not connected, and we've forgotten everything we need in
		// order to re-connect, if we once were connected.
		build_error_message("ping database server");
		return false;
	}
}

int
Connection::protocol_version() const
{
	return driver_->protocol_version();
}

Query
Connection::query(const char* qstr)
{
	return Query(this, throw_exceptions(), qstr);
}

Query
Connection::query(const std::string& qstr)
{
	return query(qstr.c_str());
}

bool
Connection::select_db(const std::string& db)
{
	error_message_.clear();
	if (connected()) {
		if (driver_->select_db(db.c_str())) {
			return true;
		}
		else {
			if (throw_exceptions()) {
				throw DBSelectionFailed(error(), errnum());
			}
			return false;
		}
	}
	else {
		build_error_message("select a database");
		if (throw_exceptions()) {
			throw DBSelectionFailed(error_message_.c_str());
		}
		return false;
	}
}

std::string
Connection::server_status() const
{
	return driver_->server_status();
}

std::string
Connection::server_version() const
{
	return driver_->server_version();
}

bool
Connection::set_option(option::Type o)
{
	error_message_ = driver_->set_option(o);
	return option_error_check(o);
}

bool
Connection::set_option(option::Type o, const char* arg)
{
	error_message_ = driver_->set_option(o, arg);
	return option_error_check(o);
}

bool
Connection::set_option(option::Type o, unsigned int arg)
{
	error_message_ = driver_->set_option(o, arg);
	return option_error_check(o);
}

bool
Connection::set_option(option::Type o, bool arg)
{
	error_message_ = driver_->set_option(o, arg);
	return option_error_check(o);
}

bool
Connection::shutdown()
{
	error_message_.clear();
	if (connected()) {
		if (driver_->shutdown()) {
			return true;
		}
		else {
			if (throw_exceptions()) {
				throw ConnectionFailed(error(), errnum());
			}
			return false;
		}
	}
	else {
		build_error_message("shutdown database server");
		if (throw_exceptions()) {
			throw ConnectionFailed(error_message_.c_str());
		}
		return false;
	}
}

bool
Connection::thread_aware() const
{
	return driver_->thread_aware();
}

void
Connection::thread_end()
{
	driver_->thread_end();
}

unsigned long
Connection::thread_id()
{
	return driver_->thread_id();
}

bool
Connection::thread_start()
{
	return driver_->thread_start();
}

} // end namespace mysqlpp

<|endoftext|>


<commit_before>//
// vtTerrainScene - Container class for all of the terrains loaded
//
// Copyright (c) 2001-2003 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "vtdata/vtLog.h"
#include "TerrainScene.h"
#include "Light.h"
#include "SkyDome.h"
#include "Terrain.h"
#include "TimeEngines.h"

///////////////////////////////////////////////////////////////////////

// All terrains share a static data path and content manager
//vtStringArray vtGetDataPath();
//vtContentManager3d vtGetContent;
vtTerrainScene *vtTerrainScene::s_pTerrainScene;

///////////////////////////////////////////////////////////////////////
/**
 * A small engine that allows the SkyDome to stay around the Camera.
 */
class vtSkyTrackEngine : public vtEngine
{
public:
	vtSkyTrackEngine();
	virtual void Eval();
	vtCamera *m_pCamera;
};

vtSkyTrackEngine::vtSkyTrackEngine() : vtEngine()
{
	m_pCamera = NULL;
}

void vtSkyTrackEngine::Eval()
{
	// get the location of the camera and the target (skydome)
	vtTransform *pTarget = (vtTransform *) GetTarget();
	if (!pTarget || !m_pCamera)
		return;
	FPoint3 pos1 = m_pCamera->GetTrans();
	FPoint3 pos2 = pTarget->GetTrans();

	// move the target (skydome) to be centers in XZ on the camera
	pos2.x = pos1.x;
	pos2.z = pos1.z;
	pTarget->SetTrans(pos2);
}

///////////////////////////////////////////////////////////////////////
//
// vtTerrainScene class
//

vtTerrainScene::vtTerrainScene()
{
	s_pTerrainScene = this;

	horizon_color.Set(0.70f, 0.85f, 1.0f);
	azimuth_color.Set(0.12f, 0.32f, 0.70f);

	m_pTop = NULL;
	m_pSkyDome = NULL;
	m_pFirstTerrain = NULL;
	m_pCurrentTerrain = NULL;
	m_pTime = NULL;
	m_pSkyTrack = NULL;
	m_pSunLight = NULL;
	m_pAtmosphereGroup = NULL;

	m_fCatenaryFactor = 140.0;	// a default value
}

vtTerrainScene::~vtTerrainScene()
{
	for (unsigned int i = 0; i < m_StructObjs.GetSize(); i++)
		delete m_StructObjs[i];
}

void vtTerrainScene::CleanupScene()
{
	vtGetScene()->RemoveEngine(m_pTime);
	vtGetScene()->RemoveEngine(m_pSkyTrack);

	delete m_pTime;
	delete m_pSkyTrack;

	// no need to do this explicitly, it is done by releasing the scenegraph
	// if (m_pSkyDome)
	// 	m_pSkyDome->Destroy();

	while (m_pFirstTerrain)
	{
		vtTerrain *del = m_pFirstTerrain;
		m_pFirstTerrain = m_pFirstTerrain->GetNext();
		delete del;
	}
	m_pFirstTerrain = NULL;
	m_pCurrentTerrain = NULL;

	// get anything left at the top of the scene graph
	if (m_pTop)
		m_pTop->Release();

	// free some statics
	vtStructure3d::ReleaseSharedMaterials();
	vtRoute::ReleaseMaterials();
}

void vtTerrainScene::_CreateSky()
{
	// create the sun
	VTLOG(" Creating Main Light\n");
	vtLight *pLight = new vtLight();
	pLight->SetName2("Main Light");
	m_pSunLight = new vtMovLight(pLight);
	m_pSunLight->SetName2("SunLight");
	m_pTop->AddChild(m_pSunLight);

	VTLOG(" Creating SkyDome\n");
	m_pAtmosphereGroup = new vtGroup();
	m_pAtmosphereGroup->SetName2("Atmosphere Group");
	m_pTop->AddChild(m_pAtmosphereGroup);

	// 'bsc' is the Bright Star Catalog
	vtString bsc = FindFileOnPaths(m_DataPaths, "Sky/bsc.data");
	vtString sun = FindFileOnPaths(m_DataPaths, "Sky/glow2.png");
	vtString moon = FindFileOnPaths(m_DataPaths, "Sky/moon5_256.png");

	VTLOG("  Stars: '%s'\n", (const char *) bsc);
	VTLOG("    Sun: '%s'\n", (const char *) sun);
	VTLOG("   Moon: '%s'\n", (const char *) moon);

	// create a day-night dome
	m_pSkyDome = new vtSkyDome();
	m_pSkyDome->Create(bsc, 3, 1.0f, sun, moon);	// initially unit radius
	m_pSkyDome->SetDayColors(horizon_color, azimuth_color);
	m_pSkyDome->SetName2("The Sky");
	m_pSkyDome->SetSunLight(GetSunLight());
	m_pAtmosphereGroup->AddChild(m_pSkyDome);

	m_pSkyTrack = new vtSkyTrackEngine();
	m_pSkyTrack->SetName2("Sky-Camera-Following");
	m_pSkyTrack->m_pCamera = vtGetScene()->GetCamera();
	m_pSkyTrack->SetTarget(m_pSkyDome);
	vtGetScene()->AddEngine(m_pSkyTrack);

	vtGetScene()->SetBgColor(horizon_color);
}

/**
 * Find a terrain whose name begins with a given string.
 */
vtTerrain *vtTerrainScene::FindTerrainByName(const char *name)
{
	for (vtTerrain *pTerr = m_pFirstTerrain; pTerr; pTerr=pTerr->GetNext())
	{
		if (pTerr->GetName() == name)
			return pTerr;
	}
	return NULL;
}

void vtTerrainScene::_CreateEngines()
{
	// Set Time in motion
	m_pTime = new TimeEngine();
	m_pTime->SetTarget((TimeTarget *)this);
	m_pTime->SetName2("Terrain Time");
	m_pTime->SetEnabled(false);
	vtGetScene()->AddEngine(m_pTime);
}

/**
 * Call this method once before adding any terrains, to initialize
 * the vtTerrainScene object.
 */
vtGroup *vtTerrainScene::BeginTerrainScene()
{
	VTLOG("BeginTerrainScene:\n");
	_CreateEngines();

	m_pTop = new vtGroup();
	m_pTop->SetName2("All Terrain");

	// create sky group - this holds all celestial objects
	_CreateSky();

	return m_pTop;
}

/**
 * Adds a terrain to the scene.
 */
void vtTerrainScene::AppendTerrain(vtTerrain *pTerrain)
{
	// add to linked list
	pTerrain->SetNext(m_pFirstTerrain);
	m_pFirstTerrain = pTerrain;
}

/**
 * BuildTerrain constructs all geometry, textures and objects for a given terrain.
 *
 * \param pTerrain	The terrain to build.
 * \returns			A vtGroup which is the top of the terrain's scene graph.
 */
vtGroup *vtTerrainScene::BuildTerrain(vtTerrain *pTerrain)
{
	if (!pTerrain->CreateStep1())
		return NULL;

	// Set time to that of the new terrain
	m_pSkyDome->SetTime(pTerrain->GetInitialTime());

	// Tell the skydome where on the planet we are
	DPoint2 geo = pTerrain->GetCenterGeoLocation();
	m_pSkyDome->SetGeoLocation(geo);

	if (!pTerrain->CreateStep2(GetSunLight()))
		return NULL;

	if (!pTerrain->CreateStep3())
		return NULL;

	if (!pTerrain->CreateStep4())
		return NULL;

	if (!pTerrain->CreateStep5())
		return NULL;

	return pTerrain->GetTopGroup();
}

/**
 * Set the current Terrain for the scene.  There can only be one terrain
 * active a at time.  If you have more than one terrain, you can use this
 * method to switch between them.
 */
void vtTerrainScene::SetCurrentTerrain(vtTerrain *pTerrain)
{
	if (m_pCurrentTerrain != NULL)
	{
		// turn off the scene graph of the previous terrain
		m_pCurrentTerrain->Enable(false);

		// turn off the engines specific to the previous terrain
		m_pCurrentTerrain->ActivateEngines(false);
	}
	m_pCurrentTerrain = pTerrain;

	// if setting to no terrain nothing more to do
	if (!pTerrain)
	{
		m_pSkyDome->SetEnabled(false);
		m_pTime->SetEnabled(false);
		return;
	}

	// switch
	m_pTop->AddChild(m_pCurrentTerrain->GetTopGroup());
	m_pCurrentTerrain->Enable(true);

	TParams &param = m_pCurrentTerrain->GetParams();

	// switch to the projection of this terrain
	m_pCurrentTerrain->SetGlobalProjection();

	// Set background color to match the ocean
	vtGetScene()->SetBgColor(m_pCurrentTerrain->GetOceanColor());

	// Turn on the engines specific to the new terrain
	m_pCurrentTerrain->ActivateEngines(true);

	// Setup the time engine for the new terrain
	vtTime localtime = pTerrain->GetInitialTime();

	// handle the atmosphere
	_UpdateSkydomeForTerrain(pTerrain);

	m_pCurrentTerrain->SetFog(param.GetValueBool(STR_FOG));

	// Update the time engine, which also calls us back to update the skydome
	m_pTime->SetTime(localtime);
	if (param.GetValueBool(STR_TIMEON))
		m_pTime->SetSpeed(param.GetValueFloat(STR_TIMESPEED));
	else
		m_pTime->SetSpeed(0.0f);
	m_pTime->SetEnabled(true);
}

void vtTerrainScene::_UpdateSkydomeForTerrain(vtTerrain *pTerrain)
{
	TParams &param = m_pCurrentTerrain->GetParams();

	// move the sky to fit the new current terrain
	// use 5x larger than terrain's maximum dimension
	vtHeightField3d *hf = pTerrain->GetHeightField();
	FRECT world_ext = hf->m_WorldExtents;
	float radius;
	float width = world_ext.Width();
	float depth = world_ext.Height();
	float minheight, maxheight;
	hf->GetHeightExtents(minheight, maxheight);

	radius = width;
	if (radius < depth)
		radius = depth;
	if (radius < maxheight)
		radius = maxheight;

	radius *= 5;
	float max_radius = 450000;
	if (radius > max_radius)
		radius = max_radius;
	m_pSkyDome->Identity();
	m_pSkyDome->Scale3(radius, radius, radius);

	// Tell the skydome where on the planet we are
	DPoint2 geo = pTerrain->GetCenterGeoLocation();
	m_pSkyDome->SetGeoLocation(geo);

	// Does this terrain want to show the skydome?
	bool bDoSky = param.GetValueBool(STR_SKY);

	m_pSkyDome->SetEnabled(bDoSky);
	if (bDoSky)
	{
		vtString fname = param.GetValueString(STR_SKYTEXTURE, true);
		if (fname != "")
		{
			vtString filename = "Sky/";
			filename += fname;
			vtString skytex = FindFileOnPaths(m_DataPaths, filename);
			if (skytex != "")
				m_pSkyDome->SetTexture(skytex);
		}
	}
}

void vtTerrainScene::SetTime(const vtTime &time)
{
	if (m_pSkyDome)
	{
		// TODO? Convert to local time?
		m_pSkyDome->SetTime(time);
//		m_pSkyDome->ApplyDayColors();
// TODO? Update the fog color to match the color of the horizon.
	}
}

vtUtilStruct *vtTerrainScene::LoadUtilStructure(const vtString &name)
{
	// Check to see if it's already loaded
	unsigned int i;
	for (i = 0; i < m_StructObjs.GetSize(); i++)
	{
		if (m_StructObjs[i]->m_sStructName == name)
			return m_StructObjs[i];
	}

	// If not, look for it in the global content manager
	vtItem *item = m_Content.FindItemByName(name);
	vtNode *node = m_Content.CreateNodeFromItemname(name);

	if (node == NULL)
		return NULL;

	// create new util structure
	vtUtilStruct *stnew = new vtUtilStruct;
	stnew->m_pTower = node;
	stnew->m_pTower->SetName2(name);
	stnew->m_sStructName = name;

	// get wire info
	for (i = 0; i < item->NumTags(); i++)
	{
		vtTag *tag = item->GetTag(i);
		if (tag->name == "wire_info")
		{
			// parse wire locations
			FPoint3 p1, p2;
			sscanf(tag->value, "%f, %f, %f, %f, %f, %f",
				&p1.x, &p1.y, &p1.z, &p2.x, &p2.y, &p2.z);
			stnew->m_fpWireAtt1.Append(p1);
			stnew->m_fpWireAtt2.Append(p2);
			stnew->m_iNumWires ++;
		}
	}

	m_StructObjs.Append(stnew);
	return stnew;
}

//
// Global helper function
//
vtTerrainScene *vtGetTS()
{
	return vtTerrainScene::s_pTerrainScene;
}

const vtStringArray &vtGetDataPath()
{
	return vtTerrainScene::s_pTerrainScene->m_DataPaths;
}

vtContentManager3d &vtGetContent()
{
	return vtTerrainScene::s_pTerrainScene->m_Content;
}

<commit_msg>fixed locale sensitivity with wire positions<commit_after>//
// vtTerrainScene - Container class for all of the terrains loaded
//
// Copyright (c) 2001-2003 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "vtdata/vtLog.h"
#include "TerrainScene.h"
#include "Light.h"
#include "SkyDome.h"
#include "Terrain.h"
#include "TimeEngines.h"

///////////////////////////////////////////////////////////////////////

// All terrains share a static data path and content manager
//vtStringArray vtGetDataPath();
//vtContentManager3d vtGetContent;
vtTerrainScene *vtTerrainScene::s_pTerrainScene;

///////////////////////////////////////////////////////////////////////
/**
 * A small engine that allows the SkyDome to stay around the Camera.
 */
class vtSkyTrackEngine : public vtEngine
{
public:
	vtSkyTrackEngine();
	virtual void Eval();
	vtCamera *m_pCamera;
};

vtSkyTrackEngine::vtSkyTrackEngine() : vtEngine()
{
	m_pCamera = NULL;
}

void vtSkyTrackEngine::Eval()
{
	// get the location of the camera and the target (skydome)
	vtTransform *pTarget = (vtTransform *) GetTarget();
	if (!pTarget || !m_pCamera)
		return;
	FPoint3 pos1 = m_pCamera->GetTrans();
	FPoint3 pos2 = pTarget->GetTrans();

	// move the target (skydome) to be centers in XZ on the camera
	pos2.x = pos1.x;
	pos2.z = pos1.z;
	pTarget->SetTrans(pos2);
}

///////////////////////////////////////////////////////////////////////
//
// vtTerrainScene class
//

vtTerrainScene::vtTerrainScene()
{
	s_pTerrainScene = this;

	horizon_color.Set(0.70f, 0.85f, 1.0f);
	azimuth_color.Set(0.12f, 0.32f, 0.70f);

	m_pTop = NULL;
	m_pSkyDome = NULL;
	m_pFirstTerrain = NULL;
	m_pCurrentTerrain = NULL;
	m_pTime = NULL;
	m_pSkyTrack = NULL;
	m_pSunLight = NULL;
	m_pAtmosphereGroup = NULL;

	m_fCatenaryFactor = 140.0;	// a default value
}

vtTerrainScene::~vtTerrainScene()
{
	for (unsigned int i = 0; i < m_StructObjs.GetSize(); i++)
		delete m_StructObjs[i];
}

void vtTerrainScene::CleanupScene()
{
	vtGetScene()->RemoveEngine(m_pTime);
	vtGetScene()->RemoveEngine(m_pSkyTrack);

	delete m_pTime;
	delete m_pSkyTrack;

	// no need to do this explicitly, it is done by releasing the scenegraph
	// if (m_pSkyDome)
	// 	m_pSkyDome->Destroy();

	while (m_pFirstTerrain)
	{
		vtTerrain *del = m_pFirstTerrain;
		m_pFirstTerrain = m_pFirstTerrain->GetNext();
		delete del;
	}
	m_pFirstTerrain = NULL;
	m_pCurrentTerrain = NULL;

	// get anything left at the top of the scene graph
	if (m_pTop)
		m_pTop->Release();

	// free some statics
	vtStructure3d::ReleaseSharedMaterials();
	vtRoute::ReleaseMaterials();
}

void vtTerrainScene::_CreateSky()
{
	// create the sun
	VTLOG(" Creating Main Light\n");
	vtLight *pLight = new vtLight();
	pLight->SetName2("Main Light");
	m_pSunLight = new vtMovLight(pLight);
	m_pSunLight->SetName2("SunLight");
	m_pTop->AddChild(m_pSunLight);

	VTLOG(" Creating SkyDome\n");
	m_pAtmosphereGroup = new vtGroup();
	m_pAtmosphereGroup->SetName2("Atmosphere Group");
	m_pTop->AddChild(m_pAtmosphereGroup);

	// 'bsc' is the Bright Star Catalog
	vtString bsc = FindFileOnPaths(m_DataPaths, "Sky/bsc.data");
	vtString sun = FindFileOnPaths(m_DataPaths, "Sky/glow2.png");
	vtString moon = FindFileOnPaths(m_DataPaths, "Sky/moon5_256.png");

	VTLOG("  Stars: '%s'\n", (const char *) bsc);
	VTLOG("    Sun: '%s'\n", (const char *) sun);
	VTLOG("   Moon: '%s'\n", (const char *) moon);

	// create a day-night dome
	m_pSkyDome = new vtSkyDome();
	m_pSkyDome->Create(bsc, 3, 1.0f, sun, moon);	// initially unit radius
	m_pSkyDome->SetDayColors(horizon_color, azimuth_color);
	m_pSkyDome->SetName2("The Sky");
	m_pSkyDome->SetSunLight(GetSunLight());
	m_pAtmosphereGroup->AddChild(m_pSkyDome);

	m_pSkyTrack = new vtSkyTrackEngine();
	m_pSkyTrack->SetName2("Sky-Camera-Following");
	m_pSkyTrack->m_pCamera = vtGetScene()->GetCamera();
	m_pSkyTrack->SetTarget(m_pSkyDome);
	vtGetScene()->AddEngine(m_pSkyTrack);

	vtGetScene()->SetBgColor(horizon_color);
}

/**
 * Find a terrain whose name begins with a given string.
 */
vtTerrain *vtTerrainScene::FindTerrainByName(const char *name)
{
	for (vtTerrain *pTerr = m_pFirstTerrain; pTerr; pTerr=pTerr->GetNext())
	{
		if (pTerr->GetName() == name)
			return pTerr;
	}
	return NULL;
}

void vtTerrainScene::_CreateEngines()
{
	// Set Time in motion
	m_pTime = new TimeEngine();
	m_pTime->SetTarget((TimeTarget *)this);
	m_pTime->SetName2("Terrain Time");
	m_pTime->SetEnabled(false);
	vtGetScene()->AddEngine(m_pTime);
}

/**
 * Call this method once before adding any terrains, to initialize
 * the vtTerrainScene object.
 */
vtGroup *vtTerrainScene::BeginTerrainScene()
{
	VTLOG("BeginTerrainScene:\n");
	_CreateEngines();

	m_pTop = new vtGroup();
	m_pTop->SetName2("All Terrain");

	// create sky group - this holds all celestial objects
	_CreateSky();

	return m_pTop;
}

/**
 * Adds a terrain to the scene.
 */
void vtTerrainScene::AppendTerrain(vtTerrain *pTerrain)
{
	// add to linked list
	pTerrain->SetNext(m_pFirstTerrain);
	m_pFirstTerrain = pTerrain;
}

/**
 * BuildTerrain constructs all geometry, textures and objects for a given terrain.
 *
 * \param pTerrain	The terrain to build.
 * \returns			A vtGroup which is the top of the terrain's scene graph.
 */
vtGroup *vtTerrainScene::BuildTerrain(vtTerrain *pTerrain)
{
	if (!pTerrain->CreateStep1())
		return NULL;

	// Set time to that of the new terrain
	m_pSkyDome->SetTime(pTerrain->GetInitialTime());

	// Tell the skydome where on the planet we are
	DPoint2 geo = pTerrain->GetCenterGeoLocation();
	m_pSkyDome->SetGeoLocation(geo);

	if (!pTerrain->CreateStep2(GetSunLight()))
		return NULL;

	if (!pTerrain->CreateStep3())
		return NULL;

	if (!pTerrain->CreateStep4())
		return NULL;

	if (!pTerrain->CreateStep5())
		return NULL;

	return pTerrain->GetTopGroup();
}

/**
 * Set the current Terrain for the scene.  There can only be one terrain
 * active a at time.  If you have more than one terrain, you can use this
 * method to switch between them.
 */
void vtTerrainScene::SetCurrentTerrain(vtTerrain *pTerrain)
{
	if (m_pCurrentTerrain != NULL)
	{
		// turn off the scene graph of the previous terrain
		m_pCurrentTerrain->Enable(false);

		// turn off the engines specific to the previous terrain
		m_pCurrentTerrain->ActivateEngines(false);
	}
	m_pCurrentTerrain = pTerrain;

	// if setting to no terrain nothing more to do
	if (!pTerrain)
	{
		m_pSkyDome->SetEnabled(false);
		m_pTime->SetEnabled(false);
		return;
	}

	// switch
	m_pTop->AddChild(m_pCurrentTerrain->GetTopGroup());
	m_pCurrentTerrain->Enable(true);

	TParams &param = m_pCurrentTerrain->GetParams();

	// switch to the projection of this terrain
	m_pCurrentTerrain->SetGlobalProjection();

	// Set background color to match the ocean
	vtGetScene()->SetBgColor(m_pCurrentTerrain->GetOceanColor());

	// Turn on the engines specific to the new terrain
	m_pCurrentTerrain->ActivateEngines(true);

	// Setup the time engine for the new terrain
	vtTime localtime = pTerrain->GetInitialTime();

	// handle the atmosphere
	_UpdateSkydomeForTerrain(pTerrain);

	m_pCurrentTerrain->SetFog(param.GetValueBool(STR_FOG));

	// Update the time engine, which also calls us back to update the skydome
	m_pTime->SetTime(localtime);
	if (param.GetValueBool(STR_TIMEON))
		m_pTime->SetSpeed(param.GetValueFloat(STR_TIMESPEED));
	else
		m_pTime->SetSpeed(0.0f);
	m_pTime->SetEnabled(true);
}

void vtTerrainScene::_UpdateSkydomeForTerrain(vtTerrain *pTerrain)
{
	TParams &param = m_pCurrentTerrain->GetParams();

	// move the sky to fit the new current terrain
	// use 5x larger than terrain's maximum dimension
	vtHeightField3d *hf = pTerrain->GetHeightField();
	FRECT world_ext = hf->m_WorldExtents;
	float radius;
	float width = world_ext.Width();
	float depth = world_ext.Height();
	float minheight, maxheight;
	hf->GetHeightExtents(minheight, maxheight);

	radius = width;
	if (radius < depth)
		radius = depth;
	if (radius < maxheight)
		radius = maxheight;

	radius *= 5;
	float max_radius = 450000;
	if (radius > max_radius)
		radius = max_radius;
	m_pSkyDome->Identity();
	m_pSkyDome->Scale3(radius, radius, radius);

	// Tell the skydome where on the planet we are
	DPoint2 geo = pTerrain->GetCenterGeoLocation();
	m_pSkyDome->SetGeoLocation(geo);

	// Does this terrain want to show the skydome?
	bool bDoSky = param.GetValueBool(STR_SKY);

	m_pSkyDome->SetEnabled(bDoSky);
	if (bDoSky)
	{
		vtString fname = param.GetValueString(STR_SKYTEXTURE, true);
		if (fname != "")
		{
			vtString filename = "Sky/";
			filename += fname;
			vtString skytex = FindFileOnPaths(m_DataPaths, filename);
			if (skytex != "")
				m_pSkyDome->SetTexture(skytex);
		}
	}
}

void vtTerrainScene::SetTime(const vtTime &time)
{
	if (m_pSkyDome)
	{
		// TODO? Convert to local time?
		m_pSkyDome->SetTime(time);
//		m_pSkyDome->ApplyDayColors();
// TODO? Update the fog color to match the color of the horizon.
	}
}

vtUtilStruct *vtTerrainScene::LoadUtilStructure(const vtString &name)
{
	VTLOG("LoadUtilStructure '%s'\n", (const char *)name);

	// Check to see if it's already loaded
	unsigned int i;
	for (i = 0; i < m_StructObjs.GetSize(); i++)
	{
		if (m_StructObjs[i]->m_sStructName == name)
		{
			VTLOG("  already loaded.\n");
			return m_StructObjs[i];
		}
	}

	// If not, look for it in the global content manager
	vtItem *item = m_Content.FindItemByName(name);
	VTLOG(item != NULL ? " Item Found.\n" : "Item not found.\n");
	vtNode *node = m_Content.CreateNodeFromItemname(name);
	VTLOG(node != NULL ? " Node Loaded.\n" : "Node not Loaded.\n");

	if (node == NULL)
		return NULL;

	// create new util structure
	vtUtilStruct *stnew = new vtUtilStruct;
	stnew->m_pTower = node;
	stnew->m_pTower->SetName2(name);
	stnew->m_sStructName = name;

	// Avoid trouble with '.' and ',' in Europe
	LocaleWrap normal_numbers(LC_NUMERIC, "C");

	// get wire info
	for (i = 0; i < item->NumTags(); i++)
	{
		vtTag *tag = item->GetTag(i);
		if (tag->name == "wire_info")
		{
			// parse wire locations
			FPoint3 p1, p2;
			sscanf(tag->value, "%f, %f, %f, %f, %f, %f",
				&p1.x, &p1.y, &p1.z, &p2.x, &p2.y, &p2.z);
			stnew->m_fpWireAtt1.Append(p1);
			stnew->m_fpWireAtt2.Append(p2);
			stnew->m_iNumWires ++;
		}
	}

	m_StructObjs.Append(stnew);
	return stnew;
}

//
// Global helper function
//
vtTerrainScene *vtGetTS()
{
	return vtTerrainScene::s_pTerrainScene;
}

const vtStringArray &vtGetDataPath()
{
	return vtTerrainScene::s_pTerrainScene->m_DataPaths;
}

vtContentManager3d &vtGetContent()
{
	return vtTerrainScene::s_pTerrainScene->m_Content;
}

<|endoftext|>