<commit_before>#pragma once
#include <cstdint>
#include <iostream>
#include <iomanip>

#include "instruction_procedures.h"
#include "decoder.h"
#include "memory.h"
#include "global_registers.h"
#include "register_procedures.h"

using namespace std;

void Format(AddressingMode addressingMode)
{
	switch (addressingMode)
	{
	case Immediate:
		cout << "#$" << setw(2) << setfill('0') << uppercase << hex;
		break;
	case ZeroPage:
	case ZeroPageX:
	case ZeroPageY:
	case Relative:
		cout << "$" << setw(2) << setfill('0') << uppercase << hex;
		break;
	case Absolute:
	case AbsoluteX:
	case AbsoluteY:
		cout << "$" << setw(4) << setfill('0') << uppercase << hex;
		break;
	case ZeroPageIndirectX:
	case ZeroPageIndirectY:
		cout << '(' << '$' << setw(4) << setfill('0') << uppercase << hex;
		break;
	}

	//Anything else does not need special formatting
}

void PrintOperands(AddressingMode addressingMode, uint8_t operands[])
{
	Format(addressingMode);

	uint16_t operand;
	switch (addressingMode)
	{
	case Immediate:
		cout << (int)operands[0];
		break;
	case ZeroPage:
		cout << (int)operands[0];
		break;
	case ZeroPageX:
		cout << (int)operands[0] << ",X";
		break;
	case ZeroPageY:
		cout << (int)operands[0] << ",Y";
	case Relative:
		cout << (int)operands[0];
		break;
	case Absolute:
		operand = (uint16_t)operands[1] << 8 | operands[0];
		cout << operand;
		break;
	case AbsoluteX:
		operand = (uint16_t)operands[1] << 8 | operands[0];
		cout << operand << ",X";
		break;
	case AbsoluteY:
		operand = (uint16_t)operands[1] << 8 | operands[0];
		cout << operand << ",Y";
		break;
	case ZeroPageIndirectX:
		cout << (int)operands[0] << ",X)";
		break;
	case ZeroPageIndirectY:
		cout << (int)operands[0] << "),Y";
		break;
	}

	cout << endl;

}

uint16_t _8_to_16(uint8_t high, uint8_t low)
{
	return (uint16_t)high << 8 | low;
}

uint16_t _calculate_address(AddressingMode addressingMode, uint8_t operands[])
{
	switch (addressingMode)
	{
	case Absolute:
		return _8_to_16(operands[1], operands[0]);
	case ZeroPage:
		return operands[0];
	case Relative:
		return _8_to_16(reg::PCH, reg::PCL) + (int8_t)operands[0];
	case AbsoluteX:
		return reg::X + (int16_t)_8_to_16(operands[1], operands[0]);
	case AbsoluteY:
		return reg::Y + (int16_t)_8_to_16(operands[1], operands[0]);
	case ZeroPageX:
		return (uint16_t)((reg::X + operands[0]) % 0xFF);
	case ZeroPageY:
		return (uint16_t)((reg::Y + operands[0]) % 0xFF);
	case ZeroPageIndirectX:
		return _8_to_16(mem[reg::X + operands[0] + 1], mem[reg::X + operands[0]]);
	case ZeroPageIndirectY:
		return _8_to_16(mem[reg::Y + operands[0] + 1], mem[reg::Y + operands[0]]);
	default:
		return 0;
	}
}

// Should not be used with addressing modes Accumulator and Implied.
uint8_t& _fetch_operand(AddressingMode addressingMode, uint8_t operands[])
{
	switch (addressingMode)
	{
	case Immediate:
		return operands[0];
	default:
		return mem[_calculate_address(addressingMode, operands)];
	}
}

void _push_onto_stack(uint8_t operand)
{
	mem[reg::SP + 0x100] = operand;
	reg::SP--;
}

uint8_t _pull_from_stack()
{
	return mem[++reg::SP];
}

void ProcADC(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	if (!GetFlagD())
	{
		bool bit7 = (reg::Accumulator & (1 << 7)) != 0;
		uint8_t oldAcc = reg::Accumulator;
		if (reg::Accumulator + operand > 255)
			SetFlagC(true);
		else
			SetFlagC(false);

		reg::Accumulator += operand;

		SetFlagN((reg::Accumulator & (1 << 7)) != 0); // Put bit 7 in S flag
		SetFlagZ(!reg::Accumulator);
		//TODO: Implement overflow flag setting
	}
}

void ProcAND(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::Accumulator = reg::Accumulator & operand;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);
}

void ProcASL(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = (addressingMode == Accumulator) ? reg::Accumulator : _fetch_operand(addressingMode, operands);

	SetFlagC((operand & (1 << 7)) != 0);
	SetFlagN((operand & (1 << 6)) != 0);

	operand <<= 1;

	SetFlagZ(operand == 0);
}

void ProcBCC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BCC ";
	PrintOperands(addressingMode, operands);
}

void ProcBCS(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BCS ";
	PrintOperands(addressingMode, operands);
}

void ProcBEQ(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BEQ ";
	PrintOperands(addressingMode, operands);
}

void ProcBIT(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BIT ";
	PrintOperands(addressingMode, operands);
}

void ProcBMI(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BMI ";
	PrintOperands(addressingMode, operands);
}

void ProcBNE(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BNE ";
	PrintOperands(addressingMode, operands);
}

void ProcBPL(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BPL ";
	PrintOperands(addressingMode, operands);
}

void ProcBRK(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BRK ";
	PrintOperands(addressingMode, operands);
}

void ProcBVC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BVC ";
	PrintOperands(addressingMode, operands);
}

void ProcBVS(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BVS ";
	PrintOperands(addressingMode, operands);
}

void ProcCLC(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagC(false);
}

void ProcCLD(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagD(false);
}

void ProcCLI(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagI(false);
}

void ProcCLV(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagV(false);
}

void ProcCMP(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t &operand = _fetch_operand(addressingMode, operands);
	SetFlagZ(operand == reg::Accumulator);
	SetFlagN(reg::Accumulator < operand);
	SetFlagC(reg::Accumulator >= operand);
}

void ProcCPX(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "CPX ";
	PrintOperands(addressingMode, operands);
}

void ProcCPY(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "CPY ";
	PrintOperands(addressingMode, operands);
}

void ProcDEC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "DEC ";
	PrintOperands(addressingMode, operands);
}

void ProcDEX(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "DEX ";
	PrintOperands(addressingMode, operands);
}

void ProcDEY(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "DEY ";
	PrintOperands(addressingMode, operands);
}

void ProcEOR(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "EOR ";
	PrintOperands(addressingMode, operands);
}

void ProcINC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "INC ";
	PrintOperands(addressingMode, operands);
}

void ProcINX(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "INX ";
	PrintOperands(addressingMode, operands);
}

void ProcINY(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "INY ";
	PrintOperands(addressingMode, operands);
}

void ProcJMP(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "JMP ";
	PrintOperands(addressingMode, operands);
}

void ProcJSR(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "JSR ";
	PrintOperands(addressingMode, operands);
}

void ProcLDA(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::Accumulator = operand;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);
}

void ProcLDX(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::X = operand;
	SetFlagZ(reg::X == 0);
	SetFlagN((reg::X & (1 << 7)) != 0);
}

void ProcLDY(AddressingMode addressingMode, uint8_t operands[])
{
    uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::Y= operand;
	SetFlagN((reg::Y & (1 << 7)) != 0);
	SetFlagZ(reg::Y == 0);
}

void ProcLSR(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "LSR ";
	PrintOperands(addressingMode, operands);
}

void ProcNOP(AddressingMode addressingMode, uint8_t operands[])
{
}

void ProcORA(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::Accumulator = reg::Accumulator | operand;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);

}

void ProcPHA(AddressingMode addressingMode, uint8_t operands[])
{
	_push_onto_stack(reg::Accumulator);
}

void ProcPHP(AddressingMode addressingMode, uint8_t operands[])
{
	_push_onto_stack(reg::Status);
}

void ProcPLA(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Accumulator = _pull_from_stack();

	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);
}

void ProcPLP(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Status = _pull_from_stack();
}

void ProcROL(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "ROL ";
	PrintOperands(addressingMode, operands);
}

void ProcROR(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "ROR ";
	PrintOperands(addressingMode, operands);
}

void ProcRTI(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "RTI ";
	PrintOperands(addressingMode, operands);
}

void ProcRTS(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "RTS ";
	PrintOperands(addressingMode, operands);
}

void ProcSBC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "SBC ";
	PrintOperands(addressingMode, operands);
}

void ProcSEC(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagC(true);
}

void ProcSED(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagD(true);
}

void ProcSEI(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagI(true);
}

void ProcSTA(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	operand = reg::Accumulator;
}

void ProcSTX(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	operand = reg::X;
}

void ProcSTY(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	operand = reg::Y;
}

void ProcTAX(AddressingMode addressingMode, uint8_t operands[])
{
	reg::X = reg::Accumulator;
	SetFlagZ(reg::X == 0);
	SetFlagN((reg::X & (1 << 7)) != 0);
}

void ProcTAY(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Y = reg::Accumulator;
	SetFlagZ(reg::Y == 0);
	SetFlagN((reg::Y & (1 << 7)) != 0);
}

void ProcTSX(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "TSX ";
	PrintOperands(addressingMode, operands);
}

void ProcTXA(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Accumulator = reg::X;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);
}

void ProcTXS(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "TXS ";
	PrintOperands(addressingMode, operands);
}

void ProcTYA(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Accumulator = reg::Y;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);

}
<commit_msg>Implement JSR and RTS<commit_after>#pragma once
#include <cstdint>
#include <iostream>
#include <iomanip>

#include "instruction_procedures.h"
#include "decoder.h"
#include "memory.h"
#include "global_registers.h"
#include "register_procedures.h"

using namespace std;

void Format(AddressingMode addressingMode)
{
	switch (addressingMode)
	{
	case Immediate:
		cout << "#$" << setw(2) << setfill('0') << uppercase << hex;
		break;
	case ZeroPage:
	case ZeroPageX:
	case ZeroPageY:
	case Relative:
		cout << "$" << setw(2) << setfill('0') << uppercase << hex;
		break;
	case Absolute:
	case AbsoluteX:
	case AbsoluteY:
		cout << "$" << setw(4) << setfill('0') << uppercase << hex;
		break;
	case ZeroPageIndirectX:
	case ZeroPageIndirectY:
		cout << '(' << '$' << setw(4) << setfill('0') << uppercase << hex;
		break;
	}

	//Anything else does not need special formatting
}

void PrintOperands(AddressingMode addressingMode, uint8_t operands[])
{
	Format(addressingMode);

	uint16_t operand;
	switch (addressingMode)
	{
	case Immediate:
		cout << (int)operands[0];
		break;
	case ZeroPage:
		cout << (int)operands[0];
		break;
	case ZeroPageX:
		cout << (int)operands[0] << ",X";
		break;
	case ZeroPageY:
		cout << (int)operands[0] << ",Y";
	case Relative:
		cout << (int)operands[0];
		break;
	case Absolute:
		operand = (uint16_t)operands[1] << 8 | operands[0];
		cout << operand;
		break;
	case AbsoluteX:
		operand = (uint16_t)operands[1] << 8 | operands[0];
		cout << operand << ",X";
		break;
	case AbsoluteY:
		operand = (uint16_t)operands[1] << 8 | operands[0];
		cout << operand << ",Y";
		break;
	case ZeroPageIndirectX:
		cout << (int)operands[0] << ",X)";
		break;
	case ZeroPageIndirectY:
		cout << (int)operands[0] << "),Y";
		break;
	}

	cout << endl;

}

uint16_t _8_to_16(uint8_t high, uint8_t low)
{
	return (uint16_t)high << 8 | low;
}

uint16_t _calculate_address(AddressingMode addressingMode, uint8_t operands[])
{
	switch (addressingMode)
	{
	case Absolute:
		return _8_to_16(operands[1], operands[0]);
	case ZeroPage:
		return operands[0];
	case Relative:
		return _8_to_16(reg::PCH, reg::PCL) + (int8_t)operands[0];
	case AbsoluteX:
		return reg::X + (int16_t)_8_to_16(operands[1], operands[0]);
	case AbsoluteY:
		return reg::Y + (int16_t)_8_to_16(operands[1], operands[0]);
	case ZeroPageX:
		return (uint16_t)((reg::X + operands[0]) % 0xFF);
	case ZeroPageY:
		return (uint16_t)((reg::Y + operands[0]) % 0xFF);
	case ZeroPageIndirectX:
		return _8_to_16(mem[reg::X + operands[0] + 1], mem[reg::X + operands[0]]);
	case ZeroPageIndirectY:
		return _8_to_16(mem[reg::Y + operands[0] + 1], mem[reg::Y + operands[0]]);
	default:
		return 0;
	}
}

// Should not be used with addressing modes Accumulator and Implied.
uint8_t& _fetch_operand(AddressingMode addressingMode, uint8_t operands[])
{
	switch (addressingMode)
	{
	case Immediate:
		return operands[0];
	default:
		return mem[_calculate_address(addressingMode, operands)];
	}
}

void _push_onto_stack(uint8_t operand)
{
	mem[reg::SP + 0x100] = operand;
	reg::SP--;
}

uint8_t _pull_from_stack()
{
	return mem[++reg::SP];
}

void ProcADC(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	if (!GetFlagD())
	{
		bool bit7 = (reg::Accumulator & (1 << 7)) != 0;
		uint8_t oldAcc = reg::Accumulator;
		if (reg::Accumulator + operand > 255)
			SetFlagC(true);
		else
			SetFlagC(false);

		reg::Accumulator += operand;

		SetFlagN((reg::Accumulator & (1 << 7)) != 0); // Put bit 7 in S flag
		SetFlagZ(!reg::Accumulator);
		//TODO: Implement overflow flag setting
	}
}

void ProcAND(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::Accumulator = reg::Accumulator & operand;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);
}

void ProcASL(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = (addressingMode == Accumulator) ? reg::Accumulator : _fetch_operand(addressingMode, operands);

	SetFlagC((operand & (1 << 7)) != 0);
	SetFlagN((operand & (1 << 6)) != 0);

	operand <<= 1;

	SetFlagZ(operand == 0);
}

void ProcBCC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BCC ";
	PrintOperands(addressingMode, operands);
}

void ProcBCS(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BCS ";
	PrintOperands(addressingMode, operands);
}

void ProcBEQ(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BEQ ";
	PrintOperands(addressingMode, operands);
}

void ProcBIT(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BIT ";
	PrintOperands(addressingMode, operands);
}

void ProcBMI(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BMI ";
	PrintOperands(addressingMode, operands);
}

void ProcBNE(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BNE ";
	PrintOperands(addressingMode, operands);
}

void ProcBPL(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BPL ";
	PrintOperands(addressingMode, operands);
}

void ProcBRK(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BRK ";
	PrintOperands(addressingMode, operands);
}

void ProcBVC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BVC ";
	PrintOperands(addressingMode, operands);
}

void ProcBVS(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "BVS ";
	PrintOperands(addressingMode, operands);
}

void ProcCLC(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagC(false);
}

void ProcCLD(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagD(false);
}

void ProcCLI(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagI(false);
}

void ProcCLV(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagV(false);
}

void ProcCMP(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t &operand = _fetch_operand(addressingMode, operands);
	SetFlagZ(operand == reg::Accumulator);
	SetFlagN(reg::Accumulator < operand);
	SetFlagC(reg::Accumulator >= operand);
}

void ProcCPX(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "CPX ";
	PrintOperands(addressingMode, operands);
}

void ProcCPY(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "CPY ";
	PrintOperands(addressingMode, operands);
}

void ProcDEC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "DEC ";
	PrintOperands(addressingMode, operands);
}

void ProcDEX(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "DEX ";
	PrintOperands(addressingMode, operands);
}

void ProcDEY(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "DEY ";
	PrintOperands(addressingMode, operands);
}

void ProcEOR(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "EOR ";
	PrintOperands(addressingMode, operands);
}

void ProcINC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "INC ";
	PrintOperands(addressingMode, operands);
}

void ProcINX(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "INX ";
	PrintOperands(addressingMode, operands);
}

void ProcINY(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "INY ";
	PrintOperands(addressingMode, operands);
}

void ProcJMP(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "JMP ";
	PrintOperands(addressingMode, operands);
}

void ProcJSR(AddressingMode addressingMode, uint8_t operands[])
{
	IncrementPC();
	IncrementPC(); //PC + 2
	_push_onto_stack(reg::PCH);
	_push_onto_stack(reg::PCL);
	reg::PCH = _calculate_address(addressingMode, operands);
}

void ProcLDA(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::Accumulator = operand;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);
}

void ProcLDX(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::X = operand;
	SetFlagZ(reg::X == 0);
	SetFlagN((reg::X & (1 << 7)) != 0);
}

void ProcLDY(AddressingMode addressingMode, uint8_t operands[])
{
    uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::Y= operand;
	SetFlagN((reg::Y & (1 << 7)) != 0);
	SetFlagZ(reg::Y == 0);
}

void ProcLSR(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "LSR ";
	PrintOperands(addressingMode, operands);
}

void ProcNOP(AddressingMode addressingMode, uint8_t operands[])
{
}

void ProcORA(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	reg::Accumulator = reg::Accumulator | operand;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);

}

void ProcPHA(AddressingMode addressingMode, uint8_t operands[])
{
	_push_onto_stack(reg::Accumulator);
}

void ProcPHP(AddressingMode addressingMode, uint8_t operands[])
{
	_push_onto_stack(reg::Status);
}

void ProcPLA(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Accumulator = _pull_from_stack();

	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);
}

void ProcPLP(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Status = _pull_from_stack();
}

void ProcROL(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "ROL ";
	PrintOperands(addressingMode, operands);
}

void ProcROR(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "ROR ";
	PrintOperands(addressingMode, operands);
}

void ProcRTI(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "RTI ";
	PrintOperands(addressingMode, operands);
}

void ProcRTS(AddressingMode addressingMode, uint8_t operands[])
{
	reg::PCL = _pull_from_stack();
	reg::PCH = _pull_from_stack();
	IncrementPC();
}

void ProcSBC(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "SBC ";
	PrintOperands(addressingMode, operands);
}

void ProcSEC(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagC(true);
}

void ProcSED(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagD(true);
}

void ProcSEI(AddressingMode addressingMode, uint8_t operands[])
{
	SetFlagI(true);
}

void ProcSTA(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	operand = reg::Accumulator;
}

void ProcSTX(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	operand = reg::X;
}

void ProcSTY(AddressingMode addressingMode, uint8_t operands[])
{
	uint8_t& operand = _fetch_operand(addressingMode, operands);
	operand = reg::Y;
}

void ProcTAX(AddressingMode addressingMode, uint8_t operands[])
{
	reg::X = reg::Accumulator;
	SetFlagZ(reg::X == 0);
	SetFlagN((reg::X & (1 << 7)) != 0);
}

void ProcTAY(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Y = reg::Accumulator;
	SetFlagZ(reg::Y == 0);
	SetFlagN((reg::Y & (1 << 7)) != 0);
}

void ProcTSX(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "TSX ";
	PrintOperands(addressingMode, operands);
}

void ProcTXA(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Accumulator = reg::X;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);
}

void ProcTXS(AddressingMode addressingMode, uint8_t operands[])
{
	cout << "TXS ";
	PrintOperands(addressingMode, operands);
}

void ProcTYA(AddressingMode addressingMode, uint8_t operands[])
{
	reg::Accumulator = reg::Y;
	SetFlagZ(reg::Accumulator == 0);
	SetFlagN((reg::Accumulator & (1 << 7)) != 0);

}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include <string.h>
#include "stdsneezy.h"
#include "connect.h"

#define WIZ_KEY_FILE "/mud/prod/lib/IPC_Wiznet"
#define MAIN_PORT 7900
#define BUILD_PORT 8900
#define WIZNET_FORMAT "%s %s"
#define MAX_STRING_LENGTH 4096
#define MAX_INPUT_LENGTH 1024
#define MAX_MSGBUF_LENGTH 2048

int my_ipc_id, other_ipc_id;

key_t keyval;
int qid=-2;
struct mud_msgbuf
{
    long mtype;
    char mtext[MAX_MSGBUF_LENGTH+1];
};

int openQueue()
{
  int oldqid=qid;

  if (qid==-2) {
    extern int gamePort;
    if (gamePort==MAIN_PORT) {
      my_ipc_id = MAIN_PORT;
      other_ipc_id = BUILD_PORT;
    } else {
      my_ipc_id = BUILD_PORT;
      other_ipc_id = MAIN_PORT;
    }
    keyval = ftok(WIZ_KEY_FILE, 'm');
  }
  if ((qid = msgget(keyval, IPC_CREAT|0660)) == -1) {
    vlogf(LOG_BUG, "Unable to msgget keyval %d.", keyval);
    return -1;
  }
  if (oldqid!=qid) {
    vlogf(LOG_BUG, "msgget successful, qid: %d, keyval: %d", qid, keyval);
    oldqid = qid;
  }
  return 1;
}

void closeQueue()
{
    msgctl(qid, IPC_RMID, 0);
    vlogf(LOG_BUG, "closeQueue");
}

void mudSendMessage(int mtype, int ctype, const char *arg)
{
  struct mud_msgbuf qbuf;
  int ret;

  if (openQueue()<0)
    return;

  if (mtype<=0) {
    vlogf(LOG_BUG, "invalid mtype, must be > 0, setting to 1");
    mtype = 1;
  }
  snprintf(qbuf.mtext, MAX_MSGBUF_LENGTH, "%d %s", ctype, arg);
  qbuf.mtype = mtype;

  if ((ret = msgsnd(qid, (struct msgbuf *)&qbuf, strlen(qbuf.mtext)+1, 0)) == -1)
    vlogf(LOG_BUG, "mudSendMessage: errno: %d ret: %d", errno, ret);
}

void TBeing::mudMessage(TBeing *ch, int channel, const char *arg)
{
  char tbuf[MAX_MSGBUF_LENGTH+1];
  snprintf(tbuf, MAX_MSGBUF_LENGTH, "%s: %s", ch->getName(), arg);
  mudSendMessage(other_ipc_id, channel, tbuf);
}

void recvTextHandler(const char *str)
{
  Descriptor *d;
  char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH], chname[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH-1];
  int channel=-1, level=-1;

  str = one_argument(str, arg1);
  str = one_argument(str, arg2);
  str = one_argument(str, chname);
  channel = convertTo<int>(arg1);
  level = convertTo<int>(arg2);

  snprintf(buf, MAX_STRING_LENGTH, WIZNET_FORMAT, chname, str);

  for (d = descriptor_list; d; d = d->next) {
    TBeing *och;
    och = d->original ? d->original : d->character;
    if (!och)
      continue;
    if (och->hasWizPower(POWER_WIZNET)) {
      och->sendTo(buf);
    } else {
    }
  }
}

void mudRecvMessage()
{
  struct mud_msgbuf qbuf;
  int ret;

  if (openQueue() < 0)
    return;

  while ((ret = msgrcv(qid, (struct msgbuf *)&qbuf, MAX_MSGBUF_LENGTH, my_ipc_id, IPC_NOWAIT)) > 0)
    recvTextHandler(qbuf.mtext);

  if (ret==-1 && errno!=ENOMSG)
    vlogf(LOG_BUG, "mudRecvMessage: errno: %d ret: %d", errno, ret);
}

<commit_msg>commented out a couple of lines that didn't do anything but were trying to convert non-number strings to ints<commit_after>#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include <string.h>
#include "stdsneezy.h"
#include "connect.h"

#define WIZ_KEY_FILE "/mud/prod/lib/IPC_Wiznet"
#define MAIN_PORT 7900
#define BUILD_PORT 8900
#define WIZNET_FORMAT "%s %s"
#define MAX_STRING_LENGTH 4096
#define MAX_INPUT_LENGTH 1024
#define MAX_MSGBUF_LENGTH 2048

int my_ipc_id, other_ipc_id;

key_t keyval;
int qid=-2;
struct mud_msgbuf
{
    long mtype;
    char mtext[MAX_MSGBUF_LENGTH+1];
};

int openQueue()
{
  int oldqid=qid;

  if (qid==-2) {
    extern int gamePort;
    if (gamePort==MAIN_PORT) {
      my_ipc_id = MAIN_PORT;
      other_ipc_id = BUILD_PORT;
    } else {
      my_ipc_id = BUILD_PORT;
      other_ipc_id = MAIN_PORT;
    }
    keyval = ftok(WIZ_KEY_FILE, 'm');
  }
  if ((qid = msgget(keyval, IPC_CREAT|0660)) == -1) {
    vlogf(LOG_BUG, "Unable to msgget keyval %d.", keyval);
    return -1;
  }
  if (oldqid!=qid) {
    vlogf(LOG_BUG, "msgget successful, qid: %d, keyval: %d", qid, keyval);
    oldqid = qid;
  }
  return 1;
}

void closeQueue()
{
    msgctl(qid, IPC_RMID, 0);
    vlogf(LOG_BUG, "closeQueue");
}

void mudSendMessage(int mtype, int ctype, const char *arg)
{
  struct mud_msgbuf qbuf;
  int ret;

  if (openQueue()<0)
    return;

  if (mtype<=0) {
    vlogf(LOG_BUG, "invalid mtype, must be > 0, setting to 1");
    mtype = 1;
  }
  snprintf(qbuf.mtext, MAX_MSGBUF_LENGTH, "%d %s", ctype, arg);
  qbuf.mtype = mtype;

  if ((ret = msgsnd(qid, (struct msgbuf *)&qbuf, strlen(qbuf.mtext)+1, 0)) == -1)
    vlogf(LOG_BUG, "mudSendMessage: errno: %d ret: %d", errno, ret);
}

void TBeing::mudMessage(TBeing *ch, int channel, const char *arg)
{
  char tbuf[MAX_MSGBUF_LENGTH+1];
  snprintf(tbuf, MAX_MSGBUF_LENGTH, "%s: %s", ch->getName(), arg);
  mudSendMessage(other_ipc_id, channel, tbuf);
}

void recvTextHandler(const char *str)
{
  Descriptor *d;
  char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH], chname[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH-1];
  //  int channel=-1, level=-1;

  str = one_argument(str, arg1);
  str = one_argument(str, arg2);
  str = one_argument(str, chname);
  //  channel = convertTo<int>(arg1);
  //  level = convertTo<int>(arg2);

  snprintf(buf, MAX_STRING_LENGTH, WIZNET_FORMAT, chname, str);

  for (d = descriptor_list; d; d = d->next) {
    TBeing *och;
    och = d->original ? d->original : d->character;
    if (!och)
      continue;
    if (och->hasWizPower(POWER_WIZNET)) {
      och->sendTo(buf);
    } else {
    }
  }
}

void mudRecvMessage()
{
  struct mud_msgbuf qbuf;
  int ret;

  if (openQueue() < 0)
    return;

  while ((ret = msgrcv(qid, (struct msgbuf *)&qbuf, MAX_MSGBUF_LENGTH, my_ipc_id, IPC_NOWAIT)) > 0)
    recvTextHandler(qbuf.mtext);

  if (ret==-1 && errno!=ENOMSG)
    vlogf(LOG_BUG, "mudRecvMessage: errno: %d ret: %d", errno, ret);
}

<|endoftext|>


<commit_before>//  2006-2008 (c) Viva64.com Team
//  2008-2018 (c) OOO "Program Verification Systems"

#include "comments.h"
#include <cassert>

const std::vector<PvsStudioFreeComments::Comment> PvsStudioFreeComments::Comments = {
#include "comments_msg.h"
};

static bool beginsWithICase(const std::string &str, const std::string &prefix)
{
  if (str.length() < prefix.length())
  {
    return false;
  }

  for (size_t i = 0; i < prefix.length(); ++i)
  {
    if (tolower(str[i]) != tolower(prefix[i]))
    {
      return false;
    }
  }
  return true;
}

class CommentsParser
{
public:
  bool readFreeComment(const char* buf)
  {
    m_comment.trimmedText.clear();
    m_comment.lines = 0;
    m_skippedLines = 0;
    m_inMultiline = false;
    size_t prevLines = 0;
    while (buf != nullptr && *buf != '\0')
    {
      buf = readComment(buf);
      if (m_comment.lines != prevLines)
      {
        for (auto &comment : PvsStudioFreeComments::Comments)
        {
          if (comment.lines == m_comment.lines)
          {
            if (beginsWithICase(comment.trimmedText, m_comment.trimmedText))
              return true;
          }
        }
        prevLines = m_comment.lines;
      }
      else
      {
        ++m_skippedLines;
      }
    }
    return false;
  }

private:
  const char* readComment(const char* it)
  {
    while (isspace(*it) && m_skippedLines < MaxSkippedLines)
    {
      if (it[0] == '\n')
        ++m_skippedLines;
      ++it;
    }

    if (m_skippedLines >= MaxSkippedLines)
      return nullptr;

    if (m_inMultiline)
      return readMultilineComment(it);

    if (it[0] == '/' && it[1] == '/')
    {
      const char *begin = it + 2;
      const char *end = begin;
      while (*end != '\n' && *end != '\0')
        ++end;
      it = (*end == '\n') ? end + 1 : end;

      return m_comment.addLine(begin, end) ? it : nullptr;
    }
    if (it[0] == '/' && it[1] == '*')
    {
      m_inMultiline = true;
      return readMultilineComment(it + 2);
    }

    return nullptr;
  }

  const char* readMultilineComment(const char* it)
  {
    if (it[0] == '*' && it[1] != '/')
      ++it;

    const char *begin = it;
    const char *end = begin;
    while (*end != '\n' && *end != '\0' && (end[0] != '*' || end[1] != '/'))
      ++end;

    switch (*end)
    {
    case '\n':
      it = end + 1;
      break;
    case '\0':
      it = end;
      break;
    case '*':
      it = end + 2;
      m_inMultiline = false;
      break;
    default:
      assert(false);
    }

    return m_comment.addLine(begin, end) ? it : nullptr;
  }

  static constexpr size_t MaxSkippedLines = 10;

  PvsStudioFreeComments::Comment m_comment;
  size_t m_skippedLines;
  bool m_inMultiline;
};

bool PvsStudioFreeComments::HasAnyComment(const char* buf)
{
  CommentsParser parser;
  return parser.readFreeComment(buf);
}
<commit_msg>Comments for free version are not added into files which have been already commented<commit_after>//  2006-2008 (c) Viva64.com Team
//  2008-2018 (c) OOO "Program Verification Systems"

#include "comments.h"
#include <cassert>

const std::vector<PvsStudioFreeComments::Comment> PvsStudioFreeComments::Comments = {
#include "comments_msg.h"
};

class CommentsParser
{
public:
  bool readFreeComment(const char* buf)
  {
    m_comment.trimmedText.clear();
    m_comment.lines = 0;
    m_skippedLines = 0;
    m_inMultiline = false;
    size_t prevLines = 0;
    while (buf != nullptr && *buf != '\0')
    {
      buf = readComment(buf);
      if (m_comment.lines != prevLines)
      {
        for (auto &comment : PvsStudioFreeComments::Comments)
        {
          bool isCommentsEqual = std::equal(comment.trimmedText.begin(),   comment.trimmedText.end(),
                                            m_comment.trimmedText.begin(), m_comment.trimmedText.end(),
                                            [](auto a, auto b) { return tolower(a) == tolower(b); });
          if (isCommentsEqual)
          {
            return true;
          }
        }
        prevLines = m_comment.lines;
      }
      else
      {
        m_comment.trimmedText.clear();
        ++m_skippedLines;
      }
    }

    return false;
  }

private:
  const char* readComment(const char* it)
  {
    while (isspace(*it) && m_skippedLines < MaxSkippedLines)
    {
      if (it[0] == '\n')
        ++m_skippedLines;
      ++it;
    }

    if (m_skippedLines >= MaxSkippedLines)
      return nullptr;

    if (m_inMultiline)
      return readMultilineComment(it);

    if (it[0] == '/' && it[1] == '/')
    {
      const char *begin = it + 2;
      const char *end = begin;

      while (*end != '\n' && *end != '\r' && *end != '\0' )
      {
        ++end;
      }

      if (end[0] == '\r')
      {
        it = end[1] == '\n' ? end + 2 : end + 1;
      }
      else
      {
        it = end[0] == '\n' ? end + 1 : end;
      }

      return m_comment.addLine(begin, end) ? it : nullptr;
    }

    if (it[0] == '/' && it[1] == '*')
    {
      m_inMultiline = true;
      return readMultilineComment(it + 2);
    }

    return nullptr;
  }

  const char* readMultilineComment(const char* it)
  {
    if (it[0] == '*' && it[1] != '/')
      ++it;

    const char *begin = it;
    const char *end = begin;

    while (*end != '\n' && *end != '\r' && *end != '\0' && (end[0] != '*' || end[1] != '/'))
    {
      ++end;
    }

    if (*end == '*')
    {
      it = end + 2;
      m_inMultiline = false;
    }
    else if (*end == '\r')
    {
      it = end[1] == '\n' ? end + 2 : end + 1;
    }
    else
    {
      it = end[0] == '\n' ? end + 1 : end;
    }
    return m_comment.addLine(begin, end) ? it : nullptr;
  }

  static constexpr size_t MaxSkippedLines = 10;

  PvsStudioFreeComments::Comment m_comment;
  size_t m_skippedLines;
  bool m_inMultiline;
};

bool PvsStudioFreeComments::HasAnyComment(const char* buf)
{
  CommentsParser parser;
  return parser.readFreeComment(buf);
}
<|endoftext|>


<commit_before>/**************************************************************************
 *
 * Copyright 2017 VMware, Inc
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

#include "process_name.hpp"

#include <assert.h>

#if defined(__linux__)
#include <features.h>  // __GLIBC__
#endif

#include <iostream>

#include "os.hpp"
#include "os_symbols.hpp"

#if defined(__GLIBC__)

#include <dlfcn.h>
#include <string.h>
#include <unistd.h>

static std::string g_processName;

extern "C"  {

PUBLIC ssize_t readlink(const char *pathname, char *buf, size_t bufsiz)
{
    unsigned long pid = 0;
    if (strcmp(pathname, "/proc/self/exe") == 0 ||
        (sscanf(pathname, "/proc/%lu/exe", &pid) == 1 &&
         pid == getpid())) {
        if (0) {
            std::cerr << "readlink(\"" << pathname << "\") from " << getModuleFromAddress(ReturnAddress()) << "\n";
        }
        if (!g_processName.empty()) {
            size_t len = g_processName.length();
            if (len < bufsiz) {
                memcpy(buf, g_processName.data(), len);
                buf[len] = 0;
                return len;
            } else {
                memcpy(buf, g_processName.data(), bufsiz);
                return bufsiz;
            }
        } else {
            // FIXME: We need to defer retrace::setUp() until after the first trace is loaded.
            std::cerr << "warning: process name not yet set\n";
            return -1;
        }
    }

    typedef ssize_t (*p_readlink)(const char *pathname, char *buf, size_t bufsiz);
    p_readlink p = (p_readlink)dlsym(RTLD_NEXT, "readlink");
    assert(p != nullptr);
    return p(pathname, buf, bufsiz);
}

} /* extern C */

void
setProcessName(const char *processName)
{
    g_processName = processName;

    char **p__progname_full = (char **)dlsym(RTLD_DEFAULT, "__progname_full");
    if (p__progname_full == nullptr) {
        std::cerr << "error: failed to get address of __progname_full symbol" << std::endl;
        return;
    }

    char *progname_full = strdup(processName);
    assert(progname_full != nullptr);

    *p__progname_full = progname_full;

    char **p__progname = (char **)dlsym(RTLD_DEFAULT, "__progname");
    if (p__progname == nullptr) {
        std::cerr << "error: failed to get address of __progname symbol" << std::endl;
        return;
    }

    char *progname = strrchr(progname_full, '/');
    if (progname == nullptr) {
        progname = progname_full;
    } else {
        progname += 1;
    }

    *p__progname = progname;
}

#elif defined(_WIN32)

#include <windows.h>
#include "mhook.h"

typedef DWORD (WINAPI *PFNGETMODULEFILENAMEA)(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
static PFNGETMODULEFILENAMEA pfnGetModuleFileNameA = &GetModuleFileNameA;

static inline HMODULE
GetModuleFromAddress(PVOID pAddress)
{
    HMODULE hModule = nullptr;
    BOOL bRet = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
                                  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                                  (LPCTSTR)pAddress,
                                  &hModule);
    return bRet ? hModule : nullptr;
}

static std::string g_processName;

static DWORD WINAPI
MyGetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
{
    if (hModule == nullptr) {
        if (0) {
            void *pCallerAddr = ReturnAddress();
            HMODULE hCallerModule = GetModuleFromAddress(pCallerAddr);
            char szCaller[MAX_PATH];
            DWORD dwRet = pfnGetModuleFileNameA(hCallerModule, szCaller, sizeof szCaller);
            assert(dwRet > 0);

            std::cerr << "GetModuleFileNameA(" << hModule << ") from " << szCaller << "\n";
        }

        assert(!g_processName.empty());
        assert(nSize != 0);

        size_t len = g_processName.length();
        if (len < nSize) {
            memcpy(lpFilename, g_processName.data(), len);
            lpFilename[len] = 0;
            SetLastError(ERROR_SUCCESS);
            return len;
        } else {
            memcpy(lpFilename, g_processName.data(), nSize - 1);
            lpFilename[nSize - 1] = 0;
            SetLastError(ERROR_INSUFFICIENT_BUFFER);
            return nSize;
        }
    }

    return pfnGetModuleFileNameA(hModule, lpFilename, nSize);
}

void
setProcessName(const char *processName)
{
    g_processName = processName;

    static BOOL bHooked = FALSE;
    if (!bHooked) {
        bHooked = TRUE;

        LPVOID lpOrigAddress = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32"), "GetModuleFileNameA");
        if (lpOrigAddress) {
            LPVOID lpHookAddress = (LPVOID)&MyGetModuleFileNameA;
            LPVOID lpRealAddress = lpOrigAddress;
            if (!Mhook_SetHook(&lpRealAddress, lpHookAddress)) {
                std::cerr << "error: failed to GetModuleFileNameA\n";
            }
            pfnGetModuleFileNameA = (PFNGETMODULEFILENAMEA)lpRealAddress;
        }
    }
}

#else

void
setProcessName(const char *processName)
{
}

#endif
<commit_msg>retrace: Avoid std::cerr/cout in intercepted readlink.<commit_after>/**************************************************************************
 *
 * Copyright 2017 VMware, Inc
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

#include "process_name.hpp"

#include <assert.h>

#if defined(__linux__)
#include <features.h>  // __GLIBC__
#endif

#include <iostream>

#include "os.hpp"
#include "os_symbols.hpp"

#if defined(__GLIBC__)

#include <dlfcn.h>
#include <string.h>
#include <unistd.h>

static std::string g_processName;

extern "C"  {

PUBLIC ssize_t
readlink(const char *pathname, char *buf, size_t bufsiz)
{
    /*
     * NOTE: Best to avoid std::cerr/cout as this fuction might be called
     * before libstdc++ has initialized.
     */
    unsigned long pid = 0;
    if (strcmp(pathname, "/proc/self/exe") == 0 ||
        (sscanf(pathname, "/proc/%lu/exe", &pid) == 1 &&
         pid == getpid())) {
        if (0) {
            std::string callerModule(getModuleFromAddress(ReturnAddress()));
            fprintf(stderr, "readlink(\"%s\") from %s\n", pathname, callerModule.c_str());
        }
        if (!g_processName.empty()) {
            size_t len = g_processName.length();
            if (len < bufsiz) {
                memcpy(buf, g_processName.data(), len);
                buf[len] = 0;
                return len;
            } else {
                memcpy(buf, g_processName.data(), bufsiz);
                return bufsiz;
            }
        } else {
            // FIXME: We need to defer retrace::setUp() until after the first trace is loaded.
            fprintf(stderr, "warning: process name not yet set\n");
            return -1;
        }
    }

    typedef ssize_t (*p_readlink)(const char *pathname, char *buf, size_t bufsiz);
    p_readlink p = (p_readlink)dlsym(RTLD_NEXT, "readlink");
    assert(p != nullptr);
    return p(pathname, buf, bufsiz);
}

} /* extern C */

void
setProcessName(const char *processName)
{
    g_processName = processName;

    char **p__progname_full = (char **)dlsym(RTLD_DEFAULT, "__progname_full");
    if (p__progname_full == nullptr) {
        std::cerr << "error: failed to get address of __progname_full symbol" << std::endl;
        return;
    }

    char *progname_full = strdup(processName);
    assert(progname_full != nullptr);

    *p__progname_full = progname_full;

    char **p__progname = (char **)dlsym(RTLD_DEFAULT, "__progname");
    if (p__progname == nullptr) {
        std::cerr << "error: failed to get address of __progname symbol" << std::endl;
        return;
    }

    char *progname = strrchr(progname_full, '/');
    if (progname == nullptr) {
        progname = progname_full;
    } else {
        progname += 1;
    }

    *p__progname = progname;
}

#elif defined(_WIN32)

#include <windows.h>
#include "mhook.h"

typedef DWORD (WINAPI *PFNGETMODULEFILENAMEA)(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
static PFNGETMODULEFILENAMEA pfnGetModuleFileNameA = &GetModuleFileNameA;

static inline HMODULE
GetModuleFromAddress(PVOID pAddress)
{
    HMODULE hModule = nullptr;
    BOOL bRet = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
                                  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                                  (LPCTSTR)pAddress,
                                  &hModule);
    return bRet ? hModule : nullptr;
}

static std::string g_processName;

static DWORD WINAPI
MyGetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
{
    if (hModule == nullptr) {
        if (0) {
            void *pCallerAddr = ReturnAddress();
            HMODULE hCallerModule = GetModuleFromAddress(pCallerAddr);
            char szCaller[MAX_PATH];
            DWORD dwRet = pfnGetModuleFileNameA(hCallerModule, szCaller, sizeof szCaller);
            assert(dwRet > 0);

            std::cerr << "GetModuleFileNameA(" << hModule << ") from " << szCaller << "\n";
        }

        assert(!g_processName.empty());
        assert(nSize != 0);

        size_t len = g_processName.length();
        if (len < nSize) {
            memcpy(lpFilename, g_processName.data(), len);
            lpFilename[len] = 0;
            SetLastError(ERROR_SUCCESS);
            return len;
        } else {
            memcpy(lpFilename, g_processName.data(), nSize - 1);
            lpFilename[nSize - 1] = 0;
            SetLastError(ERROR_INSUFFICIENT_BUFFER);
            return nSize;
        }
    }

    return pfnGetModuleFileNameA(hModule, lpFilename, nSize);
}

void
setProcessName(const char *processName)
{
    g_processName = processName;

    static BOOL bHooked = FALSE;
    if (!bHooked) {
        bHooked = TRUE;

        LPVOID lpOrigAddress = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32"), "GetModuleFileNameA");
        if (lpOrigAddress) {
            LPVOID lpHookAddress = (LPVOID)&MyGetModuleFileNameA;
            LPVOID lpRealAddress = lpOrigAddress;
            if (!Mhook_SetHook(&lpRealAddress, lpHookAddress)) {
                std::cerr << "error: failed to GetModuleFileNameA\n";
            }
            pfnGetModuleFileNameA = (PFNGETMODULEFILENAMEA)lpRealAddress;
        }
    }
}

#else

void
setProcessName(const char *processName)
{
}

#endif
<|endoftext|>


<commit_before>#ifndef K3_RUNTIME_LITERALS_H
#define K3_RUNTIME_LITERALS_H

#include <map>
#include <string>

#include "boost/fusion/include/std_pair.hpp"
#include "boost/spirit/include/qi.hpp"

namespace K3 {
  namespace qi = boost::spirit::qi;

  using std::map;
  using std::pair;
  using std::string;

  template <class iterator>
  class literal: qi::grammar<iterator, map<string, string>()> {
   public:
    literal(): literal::base_type(start) {
      key = qi::char_("a-zA-Z0-9_");
      value = qi::char_("a-zA-Z0-9_");
      assignment = key >> ':' >> value;
      start = assignment % ';';
    }

   private:
    qi::rule<iterator, string()> key;
    qi::rule<iterator, string()> value;
    qi::rule<iterator, pair<string, string>()> assignment;
    qi::rule<iterator, map<string, string>()> start;
  };
}

#endif
<commit_msg>Fix inheritance access and separator tokens.<commit_after>#ifndef K3_RUNTIME_LITERALS_H
#define K3_RUNTIME_LITERALS_H

#include <map>
#include <string>

#include "boost/fusion/include/std_pair.hpp"
#include "boost/spirit/include/qi.hpp"

namespace K3 {
  namespace qi = boost::spirit::qi;

  using std::map;
  using std::pair;
  using std::string;

  template <class iterator>
  class literal: public qi::grammar<iterator, map<string, string>()> {
   public:
    literal(): literal::base_type(start) {
      key = +qi::char_("a-zA-Z0-9_");
      value = +qi::char_("a-zA-Z0-9_");
      assignment = key >> '=' >> value;
      start = assignment % ';';
    }

   private:
    qi::rule<iterator, string()> key;
    qi::rule<iterator, string()> value;
    qi::rule<iterator, pair<string, string>()> assignment;
    qi::rule<iterator, map<string, string>()> start;
  };
}

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: macro.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: ihi $ $Date: 2007-11-26 18:05:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _RTL_MACRO_HXX
#define _RTL_MACRO_HXX

#include <rtl/bootstrap.h>
#include <rtl/ustring.hxx>

#if defined WIN32
#define THIS_OS "Windows"
#elif defined OS2
#define THIS_OS "OS/2"
#elif defined SOLARIS
#define THIS_OS "Solaris"
#elif defined LINUX
#define THIS_OS "Linux"
#elif defined MACOSX
#define THIS_OS "MacOSX"
#elif defined NETBSD
#define THIS_OS "NetBSD"
#elif defined FREEBSD
#define THIS_OS "FreeBSD"
#elif defined IRIX
#define THIS_OS "Irix"
#endif

#if ! defined THIS_OS
#error "unknown OS -- insert your OS identifier above"
this is inserted for the case that the preprocessor ignores error
#endif

#if defined INTEL
#define THIS_ARCH "x86"
#elif defined POWERPC
#define THIS_ARCH "PowerPC"
#elif defined S390
#define THIS_ARCH "S390"
#elif defined SPARC
#define THIS_ARCH "SPARC"
#elif defined IRIX
#define THIS_ARCH "MIPS"
#elif defined X86_64
#define THIS_ARCH "X86_64"
#elif defined MIPS
#define THIS_ARCH "MIPS"
#elif defined ARM
#define THIS_ARCH "ARM"
#endif

#if ! defined THIS_ARCH
#error "unknown ARCH -- insert your ARCH identifier above"
this is inserted for the case that the preprocessor ignores error
#endif

/*
  Expand macros via rtl_bootstrap_get.
  see
    http://udk.openoffice.org/common/man/spec/uno_default_bootstrapping.html
  for details.
*/
::rtl::OUString SAL_CALL expandMacros(rtlBootstrapHandle handle, const ::rtl::OUString & argstr);

#endif

<commit_msg>INTEGRATION: CWS ia64port01_DEV300 (1.8.20); FILE MERGED 2008/01/04 19:04:40 cmc 1.8.20.1: #i84999# add ia64<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: macro.hxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: obo $ $Date: 2008-02-27 10:04:59 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _RTL_MACRO_HXX
#define _RTL_MACRO_HXX

#include <rtl/bootstrap.h>
#include <rtl/ustring.hxx>

#if defined WIN32
#define THIS_OS "Windows"
#elif defined OS2
#define THIS_OS "OS/2"
#elif defined SOLARIS
#define THIS_OS "Solaris"
#elif defined LINUX
#define THIS_OS "Linux"
#elif defined MACOSX
#define THIS_OS "MacOSX"
#elif defined NETBSD
#define THIS_OS "NetBSD"
#elif defined FREEBSD
#define THIS_OS "FreeBSD"
#elif defined IRIX
#define THIS_OS "Irix"
#endif

#if ! defined THIS_OS
#error "unknown OS -- insert your OS identifier above"
this is inserted for the case that the preprocessor ignores error
#endif

#if defined INTEL
#define THIS_ARCH "x86"
#elif defined POWERPC
#define THIS_ARCH "PowerPC"
#elif defined S390
#define THIS_ARCH "S390"
#elif defined SPARC
#define THIS_ARCH "SPARC"
#elif defined IRIX
#define THIS_ARCH "MIPS"
#elif defined X86_64
#define THIS_ARCH "X86_64"
#elif defined MIPS
#define THIS_ARCH "MIPS"
#elif defined ARM
#define THIS_ARCH "ARM"
#elif defined IA64
#define THIS_ARCH "IA64"
#endif

#if ! defined THIS_ARCH
#error "unknown ARCH -- insert your ARCH identifier above"
this is inserted for the case that the preprocessor ignores error
#endif

/*
  Expand macros via rtl_bootstrap_get.
  see
    http://udk.openoffice.org/common/man/spec/uno_default_bootstrapping.html
  for details.
*/
::rtl::OUString SAL_CALL expandMacros(rtlBootstrapHandle handle, const ::rtl::OUString & argstr);

#endif

<|endoftext|>


<commit_before>/*
  Copyright (c) 2014, Randolph Voorhies, Shane Grant
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
      * Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
      * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
      * Neither the name of cereal nor the
        names of its contributors may be used to endorse or promote products
        derived from this software without specific prior written permission.

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

#include <cereal/cereal.hpp>
#include <cereal/archives/binary.hpp>
#include <cereal/archives/json.hpp>

#include <cereal/types/string.hpp>
#include <cereal/types/utility.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/types/complex.hpp>
#include <cereal/types/base_class.hpp>
#include <cereal/types/array.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/map.hpp>

#include <sstream>
#include <fstream>
#include <cassert>
#include <complex>
#include <iostream>
#include <iomanip>
#include <string>

// ###################################
struct Test1
{
  int a;

  private:
    friend class cereal::access;
    template<class Archive>
    void serialize(Archive & ar)
    {
      ar(CEREAL_NVP(a));
    }
};

// ###################################
class Test2
{
  public:
    Test2() {}
    Test2( int x ) : a( x ) {}
    int a;

  private:
    friend class cereal::access;

    template<class Archive>
      void save(Archive & ar) const
      {
        ar(a);
      }

    template<class Archive>
      void load(Archive & ar)
      {
        ar(a);
      }
};

// ###################################
struct Test3
{
  int a;
};

template<class Archive>
void serialize(Archive & ar, Test3 & t)
{
  ar(CEREAL_NVP(t.a));
}

namespace test4
{
  // ###################################
  struct Test4
  {
    int a;
  };

  template<class Archive>
  void save(Archive & ar, Test4 const & t)
  {
    ar(CEREAL_NVP(t.a));
  }

  template<class Archive>
  void load(Archive & ar, Test4 & t)
  {
    ar(CEREAL_NVP(t.a));
  }
}

class Private
{
  public:
    Private() : a('z') {}

  private:
    char a;

    friend class cereal::access;

    template<class Archive>
      void serialize(Archive & ar)
      {
        ar(a);
      }
};

struct Everything
{
  int x;
  int y;
  Test1 t1;
  Test2 t2;
  Test3 t3;
  test4::Test4 t4;
  std::string s;

  template<class Archive>
  void serialize(Archive & ar)
  {
    ar(CEREAL_NVP(x));
    ar(CEREAL_NVP(y));
    ar(CEREAL_NVP(t1));
    ar(CEREAL_NVP(t2));
    ar(CEREAL_NVP(t3));
    ar(CEREAL_NVP(t4));
    ar(CEREAL_NVP(s));
  }

  bool operator==(Everything const & o)
  {
    return
      x == o.x &&
      y == o.y &&
      t1.a == o.t1.a &&
      t2.a == o.t2.a &&
      t3.a == o.t3.a &&
      t4.a == o.t4.a &&
      s == o.s;
  }
};

struct SubFixture
{
  SubFixture() : a( 3 ),
    b( 9999 ),
    c( 100.1f ),
    d( 2000.9 ),
    s( "hello, world!" )
  {}

  int a;
  uint64_t b;
  float c;
  double d;
  std::string s;

    template<class Archive>
      void serialize(Archive & ar)
      {
        ar( CEREAL_NVP(a),
            b,
            c,
            CEREAL_NVP(d),
            CEREAL_NVP(s) );
      }
    void change()
    {
      a = 4;
      b = 4;
      c = 4;
      d = 4;
      s = "4";
    }
};

struct Fixture
{
  SubFixture f1, f2, f3;
  int array[4];

  Fixture()
  {
    array[0] = 1;
    array[1] = 2;
    array[2] = 3;
    array[3] = 4;
  }

  template<class Archive>
  void save(Archive & ar) const
  {
    ar( f1,
        CEREAL_NVP(f2),
        f3 );
    ar.saveBinaryValue( array, sizeof(int)*4, "cool array man" );
  }

  template<class Archive>
  void load(Archive & ar)
  {
    ar( f1,
        CEREAL_NVP(f2),
        f3 );
    ar.loadBinaryValue( array, sizeof(int)*4 );
  }

    void change()
    {
      f1.change();
      f2.change();
      f3.change();
    }
};

struct AAA
{
  AAA() : one( 1 ), two( 2 ), three( { {1, 2, 3}, { 4, 5, 6 }, {} } ) {}
  int one, two;

  std::vector<std::vector<int>> three;

  template<class Archive>
    void serialize(Archive & ar)
    {
      ar( CEREAL_NVP(one), CEREAL_NVP(two) );
      //ar( CEREAL_NVP(three) );
    }
};

class Stuff
{
  public:
    Stuff() {}

    void fillData()
    {
      std::vector<std::complex<float>> t1{ {0, -1.0f},
                          { 0, -2.9932f },
                          { 0, -3.5f } };
      std::vector<std::complex<float>> t2{ {1.0f, 0},
                     { 2.2f, 0 },
                     { 3.3f, 0 } };
      data["imaginary"] = t1;
      data["real"] = t2;
    }

  private:
    std::map<std::string, std::vector<std::complex<float>>> data;

    friend class cereal::access;

    template <class Archive>
    void serialize( Archive & ar )
    {
      ar( CEREAL_NVP(data) );
    }
};

struct OOJson
{
  OOJson() = default;
  OOJson( int aa, int bb, bool cc, double dd ) :
    a( aa ), b( bb ), c{ cc, dd }
  {
    d[0] = 0; d[1] = 1; d[2] = 2;
  }

  int a;
  int b;
  std::pair<bool, double> c;
  float d[3];

  template <class Archive>
  void serialize( Archive & ar )
  {
    ar( CEREAL_NVP(c) );
    ar( CEREAL_NVP(a) );
    ar( b );
    ar( CEREAL_NVP(d) );
  }
};

enum Bla
{
  x,
  y
};

template <class Archive>
void save( Archive & ar, Bla const & b )
{
  ar( static_cast<const int &>(b) );
}

template <class Archive>
void load( Archive & ar, Bla & b )
{
  ar( static_cast<int&>(b) );
}

CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( Bla, cereal::specialization::non_member_load_save )

//namespace cereal
//{
//  //template <class Archive> struct specialize<Archive, Bla, cereal::specialization::non_member_load_save> {};
//}

// ######################################################################
int main()
{
  std::cout << std::boolalpha << std::endl;

  {
    std::ofstream os("file.json");
    cereal::JSONOutputArchive oar( os );

    //auto f = std::make_shared<Fixture>();
    //auto f2 = f;
    //oar( f );
    //oar( f2 );
    Stuff s; s.fillData();
    oar( cereal::make_nvp("best data ever", s) );
  }

  {
    std::ifstream is("file.json");
    std::string str((std::istreambuf_iterator<char>(is)), std::istreambuf_iterator<char>());
    std::cout << "---------------------" << std::endl << str << std::endl << "---------------------" << std::endl;
  }

  // playground
  {
    cereal::JSONOutputArchive archive( std::cout );
    bool arr[] = {true, false};
    std::vector<int> vec = {1, 2, 3, 4, 5};
    archive( CEREAL_NVP(vec),
        arr );
    auto f = std::make_shared<Fixture>();
    auto f2 = f;
    archive( f );
    archive( f2 );

    archive( Bla::x );
  }

  // test out of order
  std::stringstream oos;
  {
    cereal::JSONOutputArchive ar(oos);
    cereal::JSONOutputArchive ar2(std::cout,
        cereal::JSONOutputArchive::Options(2, cereal::JSONOutputArchive::Options::IndentChar::space, 2) );

    ar( cereal::make_nvp( "1", 1 ),
        cereal::make_nvp( "2", 2 ),
        3,
        0, // unused
        cereal::make_nvp( "4", 4 ),
        cereal::make_nvp( "5", 5 ) );

    int x = 33;
    ar.saveBinaryValue( &x, sizeof(int), "bla" );

    ar2( cereal::make_nvp( "1", 1 ),
         cereal::make_nvp( "2", 2 ),
         3,
         0, // unused
         cereal::make_nvp( "4", 4 ),
         cereal::make_nvp( "5", 5 ) );
    ar2.saveBinaryValue( &x, sizeof(int), "bla" );

    OOJson oo( 1, 2, true, 4.2 );
    ar( CEREAL_NVP(oo) );
    ar2( CEREAL_NVP(oo) );

    // boost stuff
    ar & cereal::make_nvp("usingop&", oo ) & 6;
    ar << 5 << 4 << 3;

    ar2 & cereal::make_nvp("usingop&", oo ) & 6;
    ar2 << 5 << 4 << 3;

    long double ld = std::numeric_limits<long double>::max();
    long long ll = std::numeric_limits<long long>::max();
    unsigned long long ull = std::numeric_limits<unsigned long long>::max();

    ar( CEREAL_NVP(ld),
        CEREAL_NVP(ll),
        CEREAL_NVP(ull) );

    ar2( CEREAL_NVP(ld),
         CEREAL_NVP(ll),
         CEREAL_NVP(ull) );
  }

  {
    cereal::JSONInputArchive ar(oos);
    int i1, i2, i3, i4, i5, x;

    ar( i1 );
    ar( cereal::make_nvp( "2", i2 ), i3 );

    ar( cereal::make_nvp( "4", i4 ),
        i5 );

    ar.loadBinaryValue( &x, sizeof(int) );

    OOJson ii;
    ar( cereal::make_nvp("oo", ii) );
    ar( cereal::make_nvp( "2", i2 ) );

    std::cout << i1 << " " << i2 << " " << i3 << " " << i4 << " " << i5 << std::endl;
    std::cout << x << std::endl;
    std::cout << ii.a << " " << ii.b << " " << ii.c.first << " " << ii.c.second << " ";
    for( auto z : ii.d )
      std::cout << z << " ";
    std::cout << std::endl;

    OOJson oo;
    ar >> cereal::make_nvp("usingop&", oo );
    std::cout << oo.a << " " << oo.b << " " << oo.c.first << " " << oo.c.second << " ";
    for( auto z : oo.d )
      std::cout << z << " ";

    int aa, a, b, c;
    ar & aa & a & b & c;
    std::cout << aa << " " << a << " " << b << " " << c << std::endl;

    long double ld;
    long long ll;
    unsigned long long ull;

    ar( CEREAL_NVP(ld),
        CEREAL_NVP(ll),
        CEREAL_NVP(ull) );

    std::cout << (ld  == std::numeric_limits<long double>::max()) << std::endl;
    std::cout << (ll  == std::numeric_limits<long long>::max()) << std::endl;
    std::cout << (ull == std::numeric_limits<unsigned long long>::max()) << std::endl;
  }

  return 0;
}
<commit_msg>remove old code from sandbox relates #363<commit_after>/*
  Copyright (c) 2014, Randolph Voorhies, Shane Grant
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
      * Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
      * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
      * Neither the name of cereal nor the
        names of its contributors may be used to endorse or promote products
        derived from this software without specific prior written permission.

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

#include <cereal/cereal.hpp>
#include <cereal/archives/binary.hpp>
#include <cereal/archives/json.hpp>

#include <cereal/types/string.hpp>
#include <cereal/types/utility.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/types/complex.hpp>
#include <cereal/types/base_class.hpp>
#include <cereal/types/array.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/map.hpp>

#include <sstream>
#include <fstream>
#include <cassert>
#include <complex>
#include <iostream>
#include <iomanip>
#include <string>

// ###################################
struct Test1
{
  int a;

  private:
    friend class cereal::access;
    template<class Archive>
    void serialize(Archive & ar)
    {
      ar(CEREAL_NVP(a));
    }
};

// ###################################
class Test2
{
  public:
    Test2() {}
    Test2( int x ) : a( x ) {}
    int a;

  private:
    friend class cereal::access;

    template<class Archive>
      void save(Archive & ar) const
      {
        ar(a);
      }

    template<class Archive>
      void load(Archive & ar)
      {
        ar(a);
      }
};

// ###################################
struct Test3
{
  int a;
};

template<class Archive>
void serialize(Archive & ar, Test3 & t)
{
  ar(CEREAL_NVP(t.a));
}

namespace test4
{
  // ###################################
  struct Test4
  {
    int a;
  };

  template<class Archive>
  void save(Archive & ar, Test4 const & t)
  {
    ar(CEREAL_NVP(t.a));
  }

  template<class Archive>
  void load(Archive & ar, Test4 & t)
  {
    ar(CEREAL_NVP(t.a));
  }
}

class Private
{
  public:
    Private() : a('z') {}

  private:
    char a;

    friend class cereal::access;

    template<class Archive>
      void serialize(Archive & ar)
      {
        ar(a);
      }
};

struct Everything
{
  int x;
  int y;
  Test1 t1;
  Test2 t2;
  Test3 t3;
  test4::Test4 t4;
  std::string s;

  template<class Archive>
  void serialize(Archive & ar)
  {
    ar(CEREAL_NVP(x));
    ar(CEREAL_NVP(y));
    ar(CEREAL_NVP(t1));
    ar(CEREAL_NVP(t2));
    ar(CEREAL_NVP(t3));
    ar(CEREAL_NVP(t4));
    ar(CEREAL_NVP(s));
  }

  bool operator==(Everything const & o)
  {
    return
      x == o.x &&
      y == o.y &&
      t1.a == o.t1.a &&
      t2.a == o.t2.a &&
      t3.a == o.t3.a &&
      t4.a == o.t4.a &&
      s == o.s;
  }
};

struct SubFixture
{
  SubFixture() : a( 3 ),
    b( 9999 ),
    c( 100.1f ),
    d( 2000.9 ),
    s( "hello, world!" )
  {}

  int a;
  uint64_t b;
  float c;
  double d;
  std::string s;

    template<class Archive>
      void serialize(Archive & ar)
      {
        ar( CEREAL_NVP(a),
            b,
            c,
            CEREAL_NVP(d),
            CEREAL_NVP(s) );
      }
    void change()
    {
      a = 4;
      b = 4;
      c = 4;
      d = 4;
      s = "4";
    }
};

struct Fixture
{
  SubFixture f1, f2, f3;
  int array[4];

  Fixture()
  {
    array[0] = 1;
    array[1] = 2;
    array[2] = 3;
    array[3] = 4;
  }

  template<class Archive>
  void save(Archive & ar) const
  {
    ar( f1,
        CEREAL_NVP(f2),
        f3 );
    ar.saveBinaryValue( array, sizeof(int)*4, "cool array man" );
  }

  template<class Archive>
  void load(Archive & ar)
  {
    ar( f1,
        CEREAL_NVP(f2),
        f3 );
    ar.loadBinaryValue( array, sizeof(int)*4 );
  }

    void change()
    {
      f1.change();
      f2.change();
      f3.change();
    }
};

struct AAA
{
  AAA() : one( 1 ), two( 2 ), three( { {1, 2, 3}, { 4, 5, 6 }, {} } ) {}
  int one, two;

  std::vector<std::vector<int>> three;

  template<class Archive>
    void serialize(Archive & ar)
    {
      ar( CEREAL_NVP(one), CEREAL_NVP(two) );
      //ar( CEREAL_NVP(three) );
    }
};

class Stuff
{
  public:
    Stuff() {}

    void fillData()
    {
      std::vector<std::complex<float>> t1{ {0, -1.0f},
                          { 0, -2.9932f },
                          { 0, -3.5f } };
      std::vector<std::complex<float>> t2{ {1.0f, 0},
                     { 2.2f, 0 },
                     { 3.3f, 0 } };
      data["imaginary"] = t1;
      data["real"] = t2;
    }

  private:
    std::map<std::string, std::vector<std::complex<float>>> data;

    friend class cereal::access;

    template <class Archive>
    void serialize( Archive & ar )
    {
      ar( CEREAL_NVP(data) );
    }
};

struct OOJson
{
  OOJson() = default;
  OOJson( int aa, int bb, bool cc, double dd ) :
    a( aa ), b( bb ), c{ cc, dd }
  {
    d[0] = 0; d[1] = 1; d[2] = 2;
  }

  int a;
  int b;
  std::pair<bool, double> c;
  float d[3];

  template <class Archive>
  void serialize( Archive & ar )
  {
    ar( CEREAL_NVP(c) );
    ar( CEREAL_NVP(a) );
    ar( b );
    ar( CEREAL_NVP(d) );
  }
};

// ######################################################################
int main()
{
  std::cout << std::boolalpha << std::endl;

  {
    std::ofstream os("file.json");
    cereal::JSONOutputArchive oar( os );

    //auto f = std::make_shared<Fixture>();
    //auto f2 = f;
    //oar( f );
    //oar( f2 );
    Stuff s; s.fillData();
    oar( cereal::make_nvp("best data ever", s) );
  }

  {
    std::ifstream is("file.json");
    std::string str((std::istreambuf_iterator<char>(is)), std::istreambuf_iterator<char>());
    std::cout << "---------------------" << std::endl << str << std::endl << "---------------------" << std::endl;
  }

  // playground
  {
    cereal::JSONOutputArchive archive( std::cout );
    bool arr[] = {true, false};
    std::vector<int> vec = {1, 2, 3, 4, 5};
    archive( CEREAL_NVP(vec),
        arr );
    auto f = std::make_shared<Fixture>();
    auto f2 = f;
    archive( f );
    archive( f2 );
  }

  // test out of order
  std::stringstream oos;
  {
    cereal::JSONOutputArchive ar(oos);
    cereal::JSONOutputArchive ar2(std::cout,
        cereal::JSONOutputArchive::Options(2, cereal::JSONOutputArchive::Options::IndentChar::space, 2) );

    ar( cereal::make_nvp( "1", 1 ),
        cereal::make_nvp( "2", 2 ),
        3,
        0, // unused
        cereal::make_nvp( "4", 4 ),
        cereal::make_nvp( "5", 5 ) );

    int x = 33;
    ar.saveBinaryValue( &x, sizeof(int), "bla" );

    ar2( cereal::make_nvp( "1", 1 ),
         cereal::make_nvp( "2", 2 ),
         3,
         0, // unused
         cereal::make_nvp( "4", 4 ),
         cereal::make_nvp( "5", 5 ) );
    ar2.saveBinaryValue( &x, sizeof(int), "bla" );

    OOJson oo( 1, 2, true, 4.2 );
    ar( CEREAL_NVP(oo) );
    ar2( CEREAL_NVP(oo) );

    // boost stuff
    ar & cereal::make_nvp("usingop&", oo ) & 6;
    ar << 5 << 4 << 3;

    ar2 & cereal::make_nvp("usingop&", oo ) & 6;
    ar2 << 5 << 4 << 3;

    long double ld = std::numeric_limits<long double>::max();
    long long ll = std::numeric_limits<long long>::max();
    unsigned long long ull = std::numeric_limits<unsigned long long>::max();

    ar( CEREAL_NVP(ld),
        CEREAL_NVP(ll),
        CEREAL_NVP(ull) );

    ar2( CEREAL_NVP(ld),
         CEREAL_NVP(ll),
         CEREAL_NVP(ull) );
  }

  {
    cereal::JSONInputArchive ar(oos);
    int i1, i2, i3, i4, i5, x;

    ar( i1 );
    ar( cereal::make_nvp( "2", i2 ), i3 );

    ar( cereal::make_nvp( "4", i4 ),
        i5 );

    ar.loadBinaryValue( &x, sizeof(int) );

    OOJson ii;
    ar( cereal::make_nvp("oo", ii) );
    ar( cereal::make_nvp( "2", i2 ) );

    std::cout << i1 << " " << i2 << " " << i3 << " " << i4 << " " << i5 << std::endl;
    std::cout << x << std::endl;
    std::cout << ii.a << " " << ii.b << " " << ii.c.first << " " << ii.c.second << " ";
    for( auto z : ii.d )
      std::cout << z << " ";
    std::cout << std::endl;

    OOJson oo;
    ar >> cereal::make_nvp("usingop&", oo );
    std::cout << oo.a << " " << oo.b << " " << oo.c.first << " " << oo.c.second << " ";
    for( auto z : oo.d )
      std::cout << z << " ";

    int aa, a, b, c;
    ar & aa & a & b & c;
    std::cout << aa << " " << a << " " << b << " " << c << std::endl;

    long double ld;
    long long ll;
    unsigned long long ull;

    ar( CEREAL_NVP(ld),
        CEREAL_NVP(ll),
        CEREAL_NVP(ull) );

    std::cout << (ld  == std::numeric_limits<long double>::max()) << std::endl;
    std::cout << (ll  == std::numeric_limits<long long>::max()) << std::endl;
    std::cout << (ull == std::numeric_limits<unsigned long long>::max()) << std::endl;
  }

  return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  skeleton_2d.cpp                                                      */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "skeleton_2d.h"

void Bone2D::_notification(int p_what) {

	if (p_what == NOTIFICATION_ENTER_TREE) {
		Node *parent = get_parent();
		parent_bone = Object::cast_to<Bone2D>(parent);
		skeleton = NULL;
		while (parent) {
			skeleton = Object::cast_to<Skeleton2D>(parent);
			if (skeleton)
				break;
			if (!Object::cast_to<Bone2D>(parent))
				break; //skeletons must be chained to Bone2Ds.

			parent = parent->get_parent();
		}

		if (skeleton) {
			Skeleton2D::Bone bone;
			bone.bone = this;
			skeleton->bones.push_back(bone);
			skeleton->_make_bone_setup_dirty();
		}
	}
	if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
		if (skeleton) {
			skeleton->_make_transform_dirty();
		}
	}
	if (p_what == NOTIFICATION_MOVED_IN_PARENT) {
		if (skeleton) {
			skeleton->_make_bone_setup_dirty();
		}
	}

	if (p_what == NOTIFICATION_EXIT_TREE) {
		if (skeleton) {
			for (int i = 0; i < skeleton->bones.size(); i++) {
				if (skeleton->bones[i].bone == this) {
					skeleton->bones.remove(i);
					break;
				}
			}
			skeleton->_make_bone_setup_dirty();
			skeleton = NULL;
		}
		parent_bone = NULL;
	}
}
void Bone2D::_bind_methods() {

	ClassDB::bind_method(D_METHOD("set_rest", "rest"), &Bone2D::set_rest);
	ClassDB::bind_method(D_METHOD("get_rest"), &Bone2D::get_rest);
	ClassDB::bind_method(D_METHOD("apply_rest"), &Bone2D::apply_rest);
	ClassDB::bind_method(D_METHOD("get_skeleton_rest"), &Bone2D::get_skeleton_rest);
	ClassDB::bind_method(D_METHOD("get_index_in_skeleton"), &Bone2D::get_index_in_skeleton);

	ClassDB::bind_method(D_METHOD("set_default_length", "default_length"), &Bone2D::set_default_length);
	ClassDB::bind_method(D_METHOD("get_default_length"), &Bone2D::get_default_length);

	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "rest"), "set_rest", "get_rest");
	ADD_PROPERTY(PropertyInfo(Variant::REAL, "default_length", PROPERTY_HINT_RANGE, "1,1024,1"), "set_default_length", "get_default_length");
}

void Bone2D::set_rest(const Transform2D &p_rest) {
	rest = p_rest;
	if (skeleton)
		skeleton->_make_bone_setup_dirty();

	update_configuration_warning();
}

Transform2D Bone2D::get_rest() const {
	return rest;
}

Transform2D Bone2D::get_skeleton_rest() const {

	if (parent_bone) {
		return parent_bone->get_skeleton_rest() * rest;
	} else {
		return rest;
	}
}

void Bone2D::apply_rest() {
	set_transform(rest);
}

void Bone2D::set_default_length(float p_length) {

	default_length = p_length;
}

float Bone2D::get_default_length() const {
	return default_length;
}

int Bone2D::get_index_in_skeleton() const {
	ERR_FAIL_COND_V(!skeleton, -1);
	skeleton->_update_bone_setup();
	return skeleton_index;
}
String Bone2D::get_configuration_warning() const {

	String warning = Node2D::get_configuration_warning();
	if (!skeleton) {
		if (warning != String()) {
			warning += "\n";
		}
		if (parent_bone) {
			warning += TTR("This Bone2D chain should end at a Skeleton2D node.");
		} else {
			warning += TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node.");
		}
	}

	if (rest == Transform2D(0, 0, 0, 0, 0, 0)) {
		if (warning != String()) {
			warning += "\n";
		}
		warning += TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one.");
	}

	return warning;
}

Bone2D::Bone2D() {
	skeleton = NULL;
	parent_bone = NULL;
	skeleton_index = -1;
	default_length = 16;
	set_notify_local_transform(true);
	//this is a clever hack so the bone knows no rest has been set yet, allowing to show an error.
	for (int i = 0; i < 3; i++) {
		rest[i] = Vector2(0, 0);
	}
}

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

void Skeleton2D::_make_bone_setup_dirty() {

	if (bone_setup_dirty)
		return;
	bone_setup_dirty = true;
	if (is_inside_tree()) {
		call_deferred("_update_bone_setup");
	}
}

void Skeleton2D::_update_bone_setup() {

	if (!bone_setup_dirty)
		return;

	bone_setup_dirty = false;
	VS::get_singleton()->skeleton_allocate(skeleton, bones.size(), true);

	bones.sort(); //sorty so they are always in the same order/index

	for (int i = 0; i < bones.size(); i++) {
		bones.write[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose
		bones.write[i].bone->skeleton_index = i;
		Bone2D *parent_bone = Object::cast_to<Bone2D>(bones[i].bone->get_parent());
		if (parent_bone) {
			bones.write[i].parent_index = parent_bone->skeleton_index;
		} else {
			bones.write[i].parent_index = -1;
		}
	}

	transform_dirty = true;
	_update_transform();
}

void Skeleton2D::_make_transform_dirty() {

	if (transform_dirty)
		return;
	transform_dirty = true;
	if (is_inside_tree()) {
		call_deferred("_update_transform");
	}
}

void Skeleton2D::_update_transform() {

	if (bone_setup_dirty) {
		_update_bone_setup();
		return; //above will update transform anyway
	}
	if (!transform_dirty)
		return;

	transform_dirty = false;

	for (int i = 0; i < bones.size(); i++) {

		ERR_CONTINUE(bones[i].parent_index >= i);
		if (bones[i].parent_index >= 0) {
			bones.write[i].accum_transform = bones[bones[i].parent_index].accum_transform * bones[i].bone->get_transform();
		} else {
			bones.write[i].accum_transform = bones[i].bone->get_transform();
		}
	}

	for (int i = 0; i < bones.size(); i++) {

		Transform2D final_xform = bones[i].accum_transform * bones[i].rest_inverse;
		VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, final_xform);
	}
}

int Skeleton2D::get_bone_count() const {

	ERR_FAIL_COND_V(!is_inside_tree(), 0);

	if (bone_setup_dirty) {
		const_cast<Skeleton2D *>(this)->_update_bone_setup();
	}

	return bones.size();
}

Bone2D *Skeleton2D::get_bone(int p_idx) {

	ERR_FAIL_COND_V(!is_inside_tree(), NULL);
	ERR_FAIL_INDEX_V(p_idx, bones.size(), NULL);

	return bones[p_idx].bone;
}

void Skeleton2D::_notification(int p_what) {

	if (p_what == NOTIFICATION_READY) {

		if (bone_setup_dirty)
			_update_bone_setup();
		if (transform_dirty)
			_update_transform();

		request_ready();
	}

	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
		VS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform());
	}
}

RID Skeleton2D::get_skeleton() const {
	return skeleton;
}
void Skeleton2D::_bind_methods() {

	ClassDB::bind_method(D_METHOD("_update_bone_setup"), &Skeleton2D::_update_bone_setup);
	ClassDB::bind_method(D_METHOD("_update_transform"), &Skeleton2D::_update_transform);

	ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton2D::get_bone_count);
	ClassDB::bind_method(D_METHOD("get_bone", "idx"), &Skeleton2D::get_bone);

	ClassDB::bind_method(D_METHOD("get_skeleton"), &Skeleton2D::get_skeleton);
}

Skeleton2D::Skeleton2D() {
	bone_setup_dirty = true;
	transform_dirty = true;

	skeleton = VS::get_singleton()->skeleton_create();
}

Skeleton2D::~Skeleton2D() {

	VS::get_singleton()->free(skeleton);
}
<commit_msg>Skeleton2D was missing transform notification, fixes #18719<commit_after>/*************************************************************************/
/*  skeleton_2d.cpp                                                      */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "skeleton_2d.h"

void Bone2D::_notification(int p_what) {

	if (p_what == NOTIFICATION_ENTER_TREE) {
		Node *parent = get_parent();
		parent_bone = Object::cast_to<Bone2D>(parent);
		skeleton = NULL;
		while (parent) {
			skeleton = Object::cast_to<Skeleton2D>(parent);
			if (skeleton)
				break;
			if (!Object::cast_to<Bone2D>(parent))
				break; //skeletons must be chained to Bone2Ds.

			parent = parent->get_parent();
		}

		if (skeleton) {
			Skeleton2D::Bone bone;
			bone.bone = this;
			skeleton->bones.push_back(bone);
			skeleton->_make_bone_setup_dirty();
		}
	}
	if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
		if (skeleton) {
			skeleton->_make_transform_dirty();
		}
	}
	if (p_what == NOTIFICATION_MOVED_IN_PARENT) {
		if (skeleton) {
			skeleton->_make_bone_setup_dirty();
		}
	}

	if (p_what == NOTIFICATION_EXIT_TREE) {
		if (skeleton) {
			for (int i = 0; i < skeleton->bones.size(); i++) {
				if (skeleton->bones[i].bone == this) {
					skeleton->bones.remove(i);
					break;
				}
			}
			skeleton->_make_bone_setup_dirty();
			skeleton = NULL;
		}
		parent_bone = NULL;
	}
}
void Bone2D::_bind_methods() {

	ClassDB::bind_method(D_METHOD("set_rest", "rest"), &Bone2D::set_rest);
	ClassDB::bind_method(D_METHOD("get_rest"), &Bone2D::get_rest);
	ClassDB::bind_method(D_METHOD("apply_rest"), &Bone2D::apply_rest);
	ClassDB::bind_method(D_METHOD("get_skeleton_rest"), &Bone2D::get_skeleton_rest);
	ClassDB::bind_method(D_METHOD("get_index_in_skeleton"), &Bone2D::get_index_in_skeleton);

	ClassDB::bind_method(D_METHOD("set_default_length", "default_length"), &Bone2D::set_default_length);
	ClassDB::bind_method(D_METHOD("get_default_length"), &Bone2D::get_default_length);

	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "rest"), "set_rest", "get_rest");
	ADD_PROPERTY(PropertyInfo(Variant::REAL, "default_length", PROPERTY_HINT_RANGE, "1,1024,1"), "set_default_length", "get_default_length");
}

void Bone2D::set_rest(const Transform2D &p_rest) {
	rest = p_rest;
	if (skeleton)
		skeleton->_make_bone_setup_dirty();

	update_configuration_warning();
}

Transform2D Bone2D::get_rest() const {
	return rest;
}

Transform2D Bone2D::get_skeleton_rest() const {

	if (parent_bone) {
		return parent_bone->get_skeleton_rest() * rest;
	} else {
		return rest;
	}
}

void Bone2D::apply_rest() {
	set_transform(rest);
}

void Bone2D::set_default_length(float p_length) {

	default_length = p_length;
}

float Bone2D::get_default_length() const {
	return default_length;
}

int Bone2D::get_index_in_skeleton() const {
	ERR_FAIL_COND_V(!skeleton, -1);
	skeleton->_update_bone_setup();
	return skeleton_index;
}
String Bone2D::get_configuration_warning() const {

	String warning = Node2D::get_configuration_warning();
	if (!skeleton) {
		if (warning != String()) {
			warning += "\n";
		}
		if (parent_bone) {
			warning += TTR("This Bone2D chain should end at a Skeleton2D node.");
		} else {
			warning += TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node.");
		}
	}

	if (rest == Transform2D(0, 0, 0, 0, 0, 0)) {
		if (warning != String()) {
			warning += "\n";
		}
		warning += TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one.");
	}

	return warning;
}

Bone2D::Bone2D() {
	skeleton = NULL;
	parent_bone = NULL;
	skeleton_index = -1;
	default_length = 16;
	set_notify_local_transform(true);
	//this is a clever hack so the bone knows no rest has been set yet, allowing to show an error.
	for (int i = 0; i < 3; i++) {
		rest[i] = Vector2(0, 0);
	}
}

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

void Skeleton2D::_make_bone_setup_dirty() {

	if (bone_setup_dirty)
		return;
	bone_setup_dirty = true;
	if (is_inside_tree()) {
		call_deferred("_update_bone_setup");
	}
}

void Skeleton2D::_update_bone_setup() {

	if (!bone_setup_dirty)
		return;

	bone_setup_dirty = false;
	VS::get_singleton()->skeleton_allocate(skeleton, bones.size(), true);

	bones.sort(); //sorty so they are always in the same order/index

	for (int i = 0; i < bones.size(); i++) {
		bones.write[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose
		bones.write[i].bone->skeleton_index = i;
		Bone2D *parent_bone = Object::cast_to<Bone2D>(bones[i].bone->get_parent());
		if (parent_bone) {
			bones.write[i].parent_index = parent_bone->skeleton_index;
		} else {
			bones.write[i].parent_index = -1;
		}
	}

	transform_dirty = true;
	_update_transform();
}

void Skeleton2D::_make_transform_dirty() {

	if (transform_dirty)
		return;
	transform_dirty = true;
	if (is_inside_tree()) {
		call_deferred("_update_transform");
	}
}

void Skeleton2D::_update_transform() {

	if (bone_setup_dirty) {
		_update_bone_setup();
		return; //above will update transform anyway
	}
	if (!transform_dirty)
		return;

	transform_dirty = false;

	for (int i = 0; i < bones.size(); i++) {

		ERR_CONTINUE(bones[i].parent_index >= i);
		if (bones[i].parent_index >= 0) {
			bones.write[i].accum_transform = bones[bones[i].parent_index].accum_transform * bones[i].bone->get_transform();
		} else {
			bones.write[i].accum_transform = bones[i].bone->get_transform();
		}
	}

	for (int i = 0; i < bones.size(); i++) {

		Transform2D final_xform = bones[i].accum_transform * bones[i].rest_inverse;
		VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, final_xform);
	}
}

int Skeleton2D::get_bone_count() const {

	ERR_FAIL_COND_V(!is_inside_tree(), 0);

	if (bone_setup_dirty) {
		const_cast<Skeleton2D *>(this)->_update_bone_setup();
	}

	return bones.size();
}

Bone2D *Skeleton2D::get_bone(int p_idx) {

	ERR_FAIL_COND_V(!is_inside_tree(), NULL);
	ERR_FAIL_INDEX_V(p_idx, bones.size(), NULL);

	return bones[p_idx].bone;
}

void Skeleton2D::_notification(int p_what) {

	if (p_what == NOTIFICATION_READY) {

		if (bone_setup_dirty)
			_update_bone_setup();
		if (transform_dirty)
			_update_transform();

		request_ready();
	}

	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
		VS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform());
	}
}

RID Skeleton2D::get_skeleton() const {
	return skeleton;
}
void Skeleton2D::_bind_methods() {

	ClassDB::bind_method(D_METHOD("_update_bone_setup"), &Skeleton2D::_update_bone_setup);
	ClassDB::bind_method(D_METHOD("_update_transform"), &Skeleton2D::_update_transform);

	ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton2D::get_bone_count);
	ClassDB::bind_method(D_METHOD("get_bone", "idx"), &Skeleton2D::get_bone);

	ClassDB::bind_method(D_METHOD("get_skeleton"), &Skeleton2D::get_skeleton);
}

Skeleton2D::Skeleton2D() {
	bone_setup_dirty = true;
	transform_dirty = true;

	skeleton = VS::get_singleton()->skeleton_create();
	set_notify_transform(true);
}

Skeleton2D::~Skeleton2D() {

	VS::get_singleton()->free(skeleton);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Author(s): Jeongseok Lee <jslee02@gmail.com>
 *
 * Georgia Tech Graphics Lab and Humanoid Robotics Lab
 *
 * Directed by Prof. C. Karen Liu and Prof. Mike Stilman
 * <karenliu@cc.gatech.edu> <mstilman@cc.gatech.edu>
 *
 * This file is provided under the following "BSD-style" License:
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 */

#include <gtest/gtest.h>

#include "dart/common/Timer.h"

using namespace dart::common;

//==============================================================================
TEST(Common, Timer)
{
  Timer timer1("Timer1");
  Timer timer2("Timer2");

  // Run for 2 seconds
  timer1.start();
  for (int i = 0; i < 1e+3; ++i)
  {
    timer2.start();
    usleep(2000);  // 2 microseconds
    timer2.stop();
  }
  timer1.stop();

  timer1.print();
  timer2.print();

  // Both timer should have counted more than 2 seconds
  EXPECT_GE(timer1.getTotalElapsedTime(), 2.0);
  EXPECT_GE(timer2.getTotalElapsedTime(), 2.0);
}

//==============================================================================
int main(int argc, char* argv[])
{
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

<commit_msg>Use Sleep() on Windows instead of usleep()<commit_after>/*
 * Copyright (c) 2014, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Author(s): Jeongseok Lee <jslee02@gmail.com>
 *
 * Georgia Tech Graphics Lab and Humanoid Robotics Lab
 *
 * Directed by Prof. C. Karen Liu and Prof. Mike Stilman
 * <karenliu@cc.gatech.edu> <mstilman@cc.gatech.edu>
 *
 * This file is provided under the following "BSD-style" License:
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 */

#include <gtest/gtest.h>

#include "dart/common/Timer.h"

using namespace dart::common;

//==============================================================================
TEST(Common, Timer)
{
  Timer timer1("Timer1");
  Timer timer2("Timer2");

  // Run for 2 seconds
  timer1.start();
  for (int i = 0; i < 1e+3; ++i)
  {
    timer2.start();
#ifdef WIN32
	Sleep(2);  // 2 milliseconds
#else
	usleep(2000);  // 2 milliseconds
#endif
    timer2.stop();
  }
  timer1.stop();

  timer1.print();
  timer2.print();

  // Both timer should have counted more than 2 seconds
#ifdef WIN32
  // On Windows, Sleep(2) takes less than exact 2 milliseconds..
  EXPECT_GE(timer1.getTotalElapsedTime(), 1.99);
  EXPECT_GE(timer2.getTotalElapsedTime(), 1.99);
#else
  EXPECT_GE(timer1.getTotalElapsedTime(), 2.0);
  EXPECT_GE(timer2.getTotalElapsedTime(), 2.0);
#endif
}

//==============================================================================
int main(int argc, char* argv[])
{
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

<|endoftext|>