<commit_before>
#include <libclientserver.h>

Buffer::Buffer()
{
	m_buffer_length = 8192;
	m_chunk_size = 65535;
	m_buffer_used = 0;
	m_buffer = NULL;
	m_max_size = 0;
}

Buffer::~Buffer()
{
	free(m_buffer);
}

/**
 * @Init
 *
 * One of the Init functions or overloads must be called before using any other function in the class
 */
int Buffer::Init()
{
	m_buffer = (char *) malloc(m_buffer_length * sizeof(m_buffer));
	if (!m_buffer)
		return -ENOMEM;
	return 0;
}

/**
 * @Init
 * @param[in] buflen This should be the initial size of memory allocated to the buffer
 *
 * One of the Init functions or overloads must be called before using any other function in the class
 */
int Buffer::Init(size_t buflen)
{
	m_buffer_length = buflen;
	return Init();
}

/**
 * @Read
 * @param[in] fd This should be the file descriptor to read from
 *
 * This function will attempt to read chunk size from the fd and populate the buffer contents with the data
 * If the buffer is going to exceed the max size it will return -ENOMEM
 * If the file has reached EOF -1 will be returned
 * If there is an error reading from the fd the approiate error code will be returned to indicte what the problem was.
 * In normal working cases without error's the length of the data read will be returned. This includes returning 0 if there was no data to read.
 */
int Buffer::Read(int fd)
{
	if (GetFreeSpace() < m_chunk_size)
	{
		if (ReSize(m_buffer_length + m_chunk_size) == false)
		{
			return -ENOMEM;
		}
	}

	int ret = read(fd, m_buffer + m_buffer_used, m_chunk_size);
	if (ret < 0)
	{
		switch(errno)
		{
			case EAGAIN:
			case EINTR:
				return 0;
			default:
				return -errno;
		}
	}
	if (ret == 0)
		return -1;
	m_buffer_used += ret;
	return ret;
}

/**
 * Write
 * @param[in] fd The file descriptor to write to
 *
 * This function will attempt to write as much of the buffer as possible to the fd.
 * If an error occurs it will will return the approate error code to indicate what the error was.
 * If the function was able to write any data it will return the amount of data that was written to the fd
 */
int Buffer::Write(int fd)
{
	if (m_buffer_used == 0)
		return 0;

	int ret = write(fd, m_buffer, m_buffer_used);
	if (ret > 0)
	{
		Shift(ret);
		return ret;
	}
	switch(errno)
	{
		case EAGAIN:
		case EINTR:
			return 0;
			break;
		default:
			return -errno;
			break;
	}
	return -1;
}

/**
 * WriteBuffered
 * @param[in] fd The file descriptor to write to
 * @param[in] buf The data to write
 * @param[in] length The amount of data to write from buf
 *
 * This functin will attempt to write as much data as it can to the file descriptor before it blocks.
 * Once it starts blocking it will then write the remaining part of the data to the buffer which can be written by calling Write(fd) later
 * If the initial write fails it will return the error that occured and will not attempt to write any data to either the fd or the buffer
 * If the buffers required more memory it is posisble for this function to file is there is a maximum buffer limit set. In which case it will fail with -NOBUFS
 * Under normal situations this function will always return the lgnth value passed
 */
int Buffer::WriteBuffered(int fd, const char *buf, size_t length)
{
	int ret = write(fd, buf, length);
	if (ret < 0)
	{
		switch(errno)
		{
			case EAGAIN:
			case EINTR:
				return PushData(buf, length);
			default:
				return -errno;
				break;
		}
	}
	size_t written = ret;

	if (written == length)
		return length;

	//Not all of it went to the socket to buffer it and say success to the caller
	ret = PushData(&buf[written], length - written);
	if (ret < 0)
		return ret;
	if ((size_t) ret != length - written)
		return -ENOBUFS;
	return length;
}

/**
 * PushData
 * @param[in] buf The buffer to append the to the buffer contents
 * @param[in] length The length of the data
 *
 * This function will append the data to the buffer
 * It is possible to fail with eother a memory allocation issue or if the maxmimum buffer size is going to be exceeded
 */
int Buffer::PushData(const char *buf, size_t length)
{
	if (GetFreeSpace() < length)
	{
		if (ReSize(m_buffer_length + length) == false)
		{
			return -ENOMEM;
		}
	}
	memcpy(&m_buffer[m_buffer_used], buf, length);
	m_buffer_used += length;
	return length;
}

/**
 * PullData
 * @param[in] buf This will be populated by the data
 * @param[in] length The size of the buffer buf
 *
 * This function will read data from the front of the buffer and populate as much as possible in buf
 * If the passed buf is larger than the data stored in the buffer then the return value will indicate how much data was copied ot buf
 */
int Buffer::PullData(char *buf, size_t length)
{
	int len = length;
	if (m_buffer_used < length)
		len = m_buffer_used;
	memcpy(buf, m_buffer, len);
	Shift(len);
	return len;
}

/**
 * Clear
 *
 * This function will mark the buffer as empty as if it has no data in it
 */
void Buffer::Clear()
{
	m_buffer_used = 0;
}

/*
 * GetLine
 * @param[in] str This will be modified to contain the next line found in the buffer
 *
 * This function will attempt to scan the buffer and return the first line of text found in the buffer
 * If it finds a line of text then true will be returned. It will return false if it the buffer does nto contain a full line
 */
bool Buffer::GetLine(std::string *str)
{
	return GetLine(str, '\n');
}

/*
 * GetLine
 * @param[in] str This will be modified to contain the next line found in the buffer
 * @param[in] term This will be used to specifiy the end of line marker to look for in the buffer
 *
 * This function will attempt to scan the buffer and return the first line of text found in the buffer
 * If it finds a line of text then true will be returned. It will return false if it the buffer does nto contain a full line
 */
bool Buffer::GetLine(std::string *str, const char term)
{
	if (GetDataLength() == 0)
		return false;

	char *lf = (char *) memchr(m_buffer, term, m_buffer_used);
	if (lf == NULL)
		return false;
	*lf = 0; //Add NULL Terminator

	*str = m_buffer;

	size_t Offset = lf - m_buffer + 1;
	Shift(Offset);
	return true;
}

/*
 * GetLine
 * @param[in] str This will be modified to contain the next line found in the buffer
 * @param[in] ending This will be used to specifiy the end of line marker to look for in the buffer
 *
 * This function will attempt to scan the buffer and return the first line of text found in the buffer
 * If it finds a line of text then true will be returned. It will return false if it the buffer does nto contain a full line
 */
bool Buffer::GetLine(std::string *str, const std::string &ending)
{
	return GetLine(str, ending.c_str());
}

/*
 * GetLine
 * @param[in] str This will be modified to contain the next line found in the buffer
 * @param[in] ending This will be used to specifiy the end of line marker to look for in the buffer
 *
 * This function will attempt to scan the buffer and return the first line of text found in the buffer
 * If it finds a line of text then true will be returned. It will return false if it the buffer does nto contain a full line
 */
bool Buffer::GetLine(std::string *str, const char *ending)
{
	if (GetDataLength() == 0)
		return false;

	char *lf = (char *) memmem(m_buffer, m_buffer_used, ending, strlen(ending));
	if (lf == NULL)
		return false;
	*lf = 0; //Add NULL Terminator

	*str = m_buffer;

	size_t Offset = lf - m_buffer + 1;
	Shift(Offset);
	return true;
}

/**
 * Shift
 * @param[in] size The amount of data to remove from the front of the buffer
 *
 * This will rmeove the size of bytes from the front of the buffer. If you attempt to remove more data that exists in the buffer abort will be called.
 */
void Buffer::Shift(size_t size)
{
	if (size == 0)
		return;
	if (m_buffer_used == 0)
		abort();
	if (size > m_buffer_used)
		abort();
	if (size == m_buffer_used)
	{
		m_buffer_used = 0;
		return;
	}
	memmove(m_buffer, m_buffer + size, m_buffer_used);
	m_buffer_used -= size;
}

/**
 * GetPtr
 *
 * This function return a raw value to a buffer. Beaware that calling other functions can invalidate this pointer as the memory block may be relocated to a different area.
 */
void *Buffer::GetPtr()
{
	return m_buffer;
}

/**
 * GetDataLength
 *
 * This function will return the number of bytes stored in the buffer
 */
size_t Buffer::GetDataLength()
{
	return m_buffer_used;
}

/**
 * GetFreeSpace
 *
 * This function will return the number of free bytes in the buffer before the buffer would need to be expanded to use more data
 */
size_t Buffer::GetFreeSpace()
{
	return m_buffer_length - m_buffer_used;
}

/**
 * GetTotalSpace
 *
 * This function returns the total space of the allocated buffer
 */
size_t Buffer::GetTotalSpace()
{
	return m_buffer_length;
}

/**
 * SetChunkSize
 * @param[in] size Value to store
 *
 * After setting this value it will be used to perform io on the Read function when attempting to read data
 */
void Buffer::SetChunkSize(size_t size)
{
	m_chunk_size = size;
}

/**
 * GetChunkSize
 *
 * Opposite of SetChunkSize
 */
size_t Buffer::GetChunkSize()
{
	return m_chunk_size;
}

/**
 * SetMaxSize
 * @param[in] size Set the maximum size of the buffer
 *
 * This will set the enforced limit of how big the buffer can grow.
 * This function can fail if a limit is placed but there is currently data in the buffer bigger than the new limit
 * Calling with a value of 0 will impose no limit on the buffer and no reallocation will be attempted
 */
int Buffer::SetMaxSize(size_t size)
{
	if (size == 0)
		m_max_size = 0;
	if (m_buffer_length > size)
	{
		if (Shrink() == false)
		{
			return -1;
		}
	}
	if (m_buffer_length > size)
	{
		return -1;
	}
	m_max_size = size;
	return 0;
}

/**
 * GetMaxSize
 *
 * This will return the maximum size the buffer can be.
 * 0 imposes no limit
 */
size_t Buffer::GetMaxSize()
{
	return m_max_size;
}

/**
 * Shrink
 *
 * Cause the allocated memory to be shrunk to use the minimum amount of memory
 */
bool Buffer::Shrink()
{
	return ReSize(m_buffer_used);
}

/**
 * ReSize
 * @param[in] size The new size for the block of allocated memory
 *
 * Cause the allocated buffer memory to be resized
 */
bool Buffer::ReSize(size_t newsize)
{
	if (newsize < m_buffer_used)
		abort();
	if (m_max_size != 0 && newsize > m_max_size)
		return false;

	char *nbuf = (char *) realloc(m_buffer, newsize * sizeof(m_buffer));
	if (!nbuf)
		return false;
	m_buffer = nbuf;
	m_buffer_length = newsize;
	return true;
}

<commit_msg>Missing pointer de-reference<commit_after>
#include <libclientserver.h>

Buffer::Buffer()
{
	m_buffer_length = 8192;
	m_chunk_size = 65535;
	m_buffer_used = 0;
	m_buffer = NULL;
	m_max_size = 0;
}

Buffer::~Buffer()
{
	free(m_buffer);
}

/**
 * @Init
 *
 * One of the Init functions or overloads must be called before using any other function in the class
 */
int Buffer::Init()
{
	m_buffer = (char *) malloc(m_buffer_length * sizeof(*m_buffer));
	if (!m_buffer)
		return -ENOMEM;
	return 0;
}

/**
 * @Init
 * @param[in] buflen This should be the initial size of memory allocated to the buffer
 *
 * One of the Init functions or overloads must be called before using any other function in the class
 */
int Buffer::Init(size_t buflen)
{
	m_buffer_length = buflen;
	return Init();
}

/**
 * @Read
 * @param[in] fd This should be the file descriptor to read from
 *
 * This function will attempt to read chunk size from the fd and populate the buffer contents with the data
 * If the buffer is going to exceed the max size it will return -ENOMEM
 * If the file has reached EOF -1 will be returned
 * If there is an error reading from the fd the approiate error code will be returned to indicte what the problem was.
 * In normal working cases without error's the length of the data read will be returned. This includes returning 0 if there was no data to read.
 */
int Buffer::Read(int fd)
{
	if (GetFreeSpace() < m_chunk_size)
	{
		if (ReSize(m_buffer_length + m_chunk_size) == false)
		{
			return -ENOMEM;
		}
	}

	int ret = read(fd, m_buffer + m_buffer_used, m_chunk_size);
	if (ret < 0)
	{
		switch(errno)
		{
			case EAGAIN:
			case EINTR:
				return 0;
			default:
				return -errno;
		}
	}
	if (ret == 0)
		return -1;
	m_buffer_used += ret;
	return ret;
}

/**
 * Write
 * @param[in] fd The file descriptor to write to
 *
 * This function will attempt to write as much of the buffer as possible to the fd.
 * If an error occurs it will will return the approate error code to indicate what the error was.
 * If the function was able to write any data it will return the amount of data that was written to the fd
 */
int Buffer::Write(int fd)
{
	if (m_buffer_used == 0)
		return 0;

	int ret = write(fd, m_buffer, m_buffer_used);
	if (ret > 0)
	{
		Shift(ret);
		return ret;
	}
	switch(errno)
	{
		case EAGAIN:
		case EINTR:
			return 0;
			break;
		default:
			return -errno;
			break;
	}
	return -1;
}

/**
 * WriteBuffered
 * @param[in] fd The file descriptor to write to
 * @param[in] buf The data to write
 * @param[in] length The amount of data to write from buf
 *
 * This functin will attempt to write as much data as it can to the file descriptor before it blocks.
 * Once it starts blocking it will then write the remaining part of the data to the buffer which can be written by calling Write(fd) later
 * If the initial write fails it will return the error that occured and will not attempt to write any data to either the fd or the buffer
 * If the buffers required more memory it is posisble for this function to file is there is a maximum buffer limit set. In which case it will fail with -NOBUFS
 * Under normal situations this function will always return the lgnth value passed
 */
int Buffer::WriteBuffered(int fd, const char *buf, size_t length)
{
	int ret = write(fd, buf, length);
	if (ret < 0)
	{
		switch(errno)
		{
			case EAGAIN:
			case EINTR:
				return PushData(buf, length);
			default:
				return -errno;
				break;
		}
	}
	size_t written = ret;

	if (written == length)
		return length;

	//Not all of it went to the socket to buffer it and say success to the caller
	ret = PushData(&buf[written], length - written);
	if (ret < 0)
		return ret;
	if ((size_t) ret != length - written)
		return -ENOBUFS;
	return length;
}

/**
 * PushData
 * @param[in] buf The buffer to append the to the buffer contents
 * @param[in] length The length of the data
 *
 * This function will append the data to the buffer
 * It is possible to fail with eother a memory allocation issue or if the maxmimum buffer size is going to be exceeded
 */
int Buffer::PushData(const char *buf, size_t length)
{
	if (GetFreeSpace() < length)
	{
		if (ReSize(m_buffer_length + length) == false)
		{
			return -ENOMEM;
		}
	}
	memcpy(&m_buffer[m_buffer_used], buf, length);
	m_buffer_used += length;
	return length;
}

/**
 * PullData
 * @param[in] buf This will be populated by the data
 * @param[in] length The size of the buffer buf
 *
 * This function will read data from the front of the buffer and populate as much as possible in buf
 * If the passed buf is larger than the data stored in the buffer then the return value will indicate how much data was copied ot buf
 */
int Buffer::PullData(char *buf, size_t length)
{
	int len = length;
	if (m_buffer_used < length)
		len = m_buffer_used;
	memcpy(buf, m_buffer, len);
	Shift(len);
	return len;
}

/**
 * Clear
 *
 * This function will mark the buffer as empty as if it has no data in it
 */
void Buffer::Clear()
{
	m_buffer_used = 0;
}

/*
 * GetLine
 * @param[in] str This will be modified to contain the next line found in the buffer
 *
 * This function will attempt to scan the buffer and return the first line of text found in the buffer
 * If it finds a line of text then true will be returned. It will return false if it the buffer does nto contain a full line
 */
bool Buffer::GetLine(std::string *str)
{
	return GetLine(str, '\n');
}

/*
 * GetLine
 * @param[in] str This will be modified to contain the next line found in the buffer
 * @param[in] term This will be used to specifiy the end of line marker to look for in the buffer
 *
 * This function will attempt to scan the buffer and return the first line of text found in the buffer
 * If it finds a line of text then true will be returned. It will return false if it the buffer does nto contain a full line
 */
bool Buffer::GetLine(std::string *str, const char term)
{
	if (GetDataLength() == 0)
		return false;

	char *lf = (char *) memchr(m_buffer, term, m_buffer_used);
	if (lf == NULL)
		return false;
	*lf = 0; //Add NULL Terminator

	*str = m_buffer;

	size_t Offset = lf - m_buffer + 1;
	Shift(Offset);
	return true;
}

/*
 * GetLine
 * @param[in] str This will be modified to contain the next line found in the buffer
 * @param[in] ending This will be used to specifiy the end of line marker to look for in the buffer
 *
 * This function will attempt to scan the buffer and return the first line of text found in the buffer
 * If it finds a line of text then true will be returned. It will return false if it the buffer does nto contain a full line
 */
bool Buffer::GetLine(std::string *str, const std::string &ending)
{
	return GetLine(str, ending.c_str());
}

/*
 * GetLine
 * @param[in] str This will be modified to contain the next line found in the buffer
 * @param[in] ending This will be used to specifiy the end of line marker to look for in the buffer
 *
 * This function will attempt to scan the buffer and return the first line of text found in the buffer
 * If it finds a line of text then true will be returned. It will return false if it the buffer does nto contain a full line
 */
bool Buffer::GetLine(std::string *str, const char *ending)
{
	if (GetDataLength() == 0)
		return false;

	char *lf = (char *) memmem(m_buffer, m_buffer_used, ending, strlen(ending));
	if (lf == NULL)
		return false;
	*lf = 0; //Add NULL Terminator

	*str = m_buffer;

	size_t Offset = lf - m_buffer + 1;
	Shift(Offset);
	return true;
}

/**
 * Shift
 * @param[in] size The amount of data to remove from the front of the buffer
 *
 * This will rmeove the size of bytes from the front of the buffer. If you attempt to remove more data that exists in the buffer abort will be called.
 */
void Buffer::Shift(size_t size)
{
	if (size == 0)
		return;
	if (m_buffer_used == 0)
		abort();
	if (size > m_buffer_used)
		abort();
	if (size == m_buffer_used)
	{
		m_buffer_used = 0;
		return;
	}
	memmove(m_buffer, m_buffer + size, m_buffer_used);
	m_buffer_used -= size;
}

/**
 * GetPtr
 *
 * This function return a raw value to a buffer. Beaware that calling other functions can invalidate this pointer as the memory block may be relocated to a different area.
 */
void *Buffer::GetPtr()
{
	return m_buffer;
}

/**
 * GetDataLength
 *
 * This function will return the number of bytes stored in the buffer
 */
size_t Buffer::GetDataLength()
{
	return m_buffer_used;
}

/**
 * GetFreeSpace
 *
 * This function will return the number of free bytes in the buffer before the buffer would need to be expanded to use more data
 */
size_t Buffer::GetFreeSpace()
{
	return m_buffer_length - m_buffer_used;
}

/**
 * GetTotalSpace
 *
 * This function returns the total space of the allocated buffer
 */
size_t Buffer::GetTotalSpace()
{
	return m_buffer_length;
}

/**
 * SetChunkSize
 * @param[in] size Value to store
 *
 * After setting this value it will be used to perform io on the Read function when attempting to read data
 */
void Buffer::SetChunkSize(size_t size)
{
	m_chunk_size = size;
}

/**
 * GetChunkSize
 *
 * Opposite of SetChunkSize
 */
size_t Buffer::GetChunkSize()
{
	return m_chunk_size;
}

/**
 * SetMaxSize
 * @param[in] size Set the maximum size of the buffer
 *
 * This will set the enforced limit of how big the buffer can grow.
 * This function can fail if a limit is placed but there is currently data in the buffer bigger than the new limit
 * Calling with a value of 0 will impose no limit on the buffer and no reallocation will be attempted
 */
int Buffer::SetMaxSize(size_t size)
{
	if (size == 0)
		m_max_size = 0;
	if (m_buffer_length > size)
	{
		if (Shrink() == false)
		{
			return -1;
		}
	}
	if (m_buffer_length > size)
	{
		return -1;
	}
	m_max_size = size;
	return 0;
}

/**
 * GetMaxSize
 *
 * This will return the maximum size the buffer can be.
 * 0 imposes no limit
 */
size_t Buffer::GetMaxSize()
{
	return m_max_size;
}

/**
 * Shrink
 *
 * Cause the allocated memory to be shrunk to use the minimum amount of memory
 */
bool Buffer::Shrink()
{
	return ReSize(m_buffer_used);
}

/**
 * ReSize
 * @param[in] size The new size for the block of allocated memory
 *
 * Cause the allocated buffer memory to be resized
 */
bool Buffer::ReSize(size_t newsize)
{
	if (newsize < m_buffer_used)
		abort();
	if (m_max_size != 0 && newsize > m_max_size)
		return false;

	char *nbuf = (char *) realloc(m_buffer, newsize * sizeof(*m_buffer));
	if (!nbuf)
		return false;
	m_buffer = nbuf;
	m_buffer_length = newsize;
	return true;
}

<|endoftext|>


<commit_before>//
// MIT License
//
// Copyright 2018-2019
//
// 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.
//
#define BOOST_TEST_MODULE cpu_test

#include <boost/test/unit_test.hpp>
#include <variant>

#include "decode.hh"
#include "disassemble.hh"

namespace jde = jones::decode;
namespace jdi = jones::disassemble;

namespace {

void check_instruction_invalid(const jde::instruction &instruction) {
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::INVALID);
  BOOST_CHECK(instruction.decoded_opcode.value == 0);

  BOOST_CHECK(instruction.decoded_operand.type == operand_type::INVALID);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0x00));
}

void check_instruction_no_operand(const jde::instruction &instruction) {
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::NONE);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0x00));
}

} // namespace

BOOST_AUTO_TEST_CASE(cpu_test) { BOOST_CHECK(true); }

BOOST_AUTO_TEST_CASE(disasemble_test_and_immediate) {

  uint8_t and_immediate[] = {0x29, 0x2C};

  const auto instructions = jdi::disassemble(and_immediate, sizeof(and_immediate));
  BOOST_CHECK(instructions.instructions.size() == 1);

  const auto &first_instruction = instructions.instructions[0];
  BOOST_CHECK(first_instruction == "AND #$2C");
}

//
// Test: Decodes an instruction that is too small.  In this case, an empty instruction.
//
BOOST_AUTO_TEST_CASE(decode_invalid_instruction_too_small) {

  uint8_t empty_instruction[] = {};

  const auto instruction = jde::decode(empty_instruction, sizeof(empty_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x00.
//
BOOST_AUTO_TEST_CASE(decode_0x00_brk_instruction_valid) {

  uint8_t brk_instruction[] = {0x00};

  const auto instruction = jde::decode(brk_instruction, sizeof(brk_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::BRK);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x00);
  check_instruction_no_operand(instruction);
}

//
// Test: Decodes opcode value 0x01 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x01_ora_instruction_valid) {

  uint8_t ora_instruction[] = {0x01, 0xFF};

  const auto instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ORA);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x01);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x01 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x01_ora_instruction_invalid_too_small) {

  uint8_t ora_instruction[] = {0x01};

  const auto instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x02.
//
BOOST_AUTO_TEST_CASE(decode_0x02_stp_instruction_valid) {

  uint8_t stp_instruction[] = {0x02};

  const auto instruction = jde::decode(stp_instruction, sizeof(stp_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::STP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x02);
  check_instruction_no_operand(instruction);
}

//
// Test: Decodes opcode value 0x03 with operand value set to 0xFF.
//
BOOST_AUTO_TEST_CASE(decode_0x03_slo_instruction_valid) {

  uint8_t slo_instruction[] = {0x03, 0xFF};

  const auto instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::SLO);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x03);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x03 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x03_slo_instruction_invalid_too_small) {

  uint8_t slo_instruction[] = {0x03};

  const auto instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x04 with operand value set to 0xFF.
//
BOOST_AUTO_TEST_CASE(decode_0x04_nop_instruction_valid) {

  uint8_t nop_instruction[] = {0x04, 0xFF};

  const auto instruction = jde::decode(nop_instruction, sizeof(nop_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::NOP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x04);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x04 with missing operand type.
//
BOOST_AUTO_TEST_CASE(decode_0x04_nop_instruction_invalid_too_small) {

  uint8_t nop_instruction[] = {0x04};

  const auto instruction = jde::decode(nop_instruction, sizeof(nop_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x05 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x05_ora_instruction_valid) {

  uint8_t ora_instruction[] = {0x05, 0xFF};

  const auto instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ORA);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x05);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x05 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x05_ora_instruction_invalid_too_small) {

  uint8_t ora_instruction[] = {0x05};

  const auto instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  check_instruction_invalid(instruction);
}
<commit_msg>adding more unit tests<commit_after>//
// MIT License
//
// Copyright 2018-2019
//
// 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.
//
#define BOOST_TEST_MODULE cpu_test

#include <boost/test/unit_test.hpp>
#include <variant>

#include "decode.hh"
#include "disassemble.hh"

namespace jde = jones::decode;
namespace jdi = jones::disassemble;

namespace {

void check_instruction_invalid(const jde::instruction &instruction) {
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::INVALID);
  BOOST_CHECK(instruction.decoded_opcode.value == 0);

  BOOST_CHECK(instruction.decoded_operand.type == operand_type::INVALID);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0x00));
}

void check_instruction_no_operand(const jde::instruction &instruction) {
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::NONE);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0x00));
}

} // namespace

BOOST_AUTO_TEST_CASE(cpu_test) { BOOST_CHECK(true); }

BOOST_AUTO_TEST_CASE(disasemble_test_and_immediate) {

  uint8_t and_immediate[] = {0x29, 0x2C};

  const auto instructions = jdi::disassemble(and_immediate, sizeof(and_immediate));
  BOOST_CHECK(instructions.instructions.size() == 1);

  const auto &first_instruction = instructions.instructions[0];
  BOOST_CHECK(first_instruction == "AND #$2C");
}

//
// Test: Decodes an instruction that is too small.  In this case, an empty instruction.
//
BOOST_AUTO_TEST_CASE(decode_invalid_instruction_too_small) {

  uint8_t empty_instruction[] = {};

  const auto instruction = jde::decode(empty_instruction, sizeof(empty_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x00.
//
BOOST_AUTO_TEST_CASE(decode_0x00_brk_instruction_valid) {

  uint8_t brk_instruction[] = {0x00};

  const auto instruction = jde::decode(brk_instruction, sizeof(brk_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::BRK);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x00);
  check_instruction_no_operand(instruction);
}

//
// Test: Decodes opcode value 0x01 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x01_ora_instruction_valid) {

  uint8_t ora_instruction[] = {0x01, 0xFF};

  const auto instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ORA);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x01);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x01 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x01_ora_instruction_invalid_too_small) {

  uint8_t ora_instruction[] = {0x01};

  const auto instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x02.
//
BOOST_AUTO_TEST_CASE(decode_0x02_stp_instruction_valid) {

  uint8_t stp_instruction[] = {0x02};

  const auto instruction = jde::decode(stp_instruction, sizeof(stp_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::STP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x02);
  check_instruction_no_operand(instruction);
}

//
// Test: Decodes opcode value 0x03 with operand value set to 0xFF.
//
BOOST_AUTO_TEST_CASE(decode_0x03_slo_instruction_valid) {

  uint8_t slo_instruction[] = {0x03, 0xFF};

  const auto instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::SLO);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x03);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x03 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x03_slo_instruction_invalid_too_small) {

  uint8_t slo_instruction[] = {0x03};

  const auto instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x04 with operand value set to 0xFF.
//
BOOST_AUTO_TEST_CASE(decode_0x04_nop_instruction_valid) {

  uint8_t nop_instruction[] = {0x04, 0xFF};

  const auto instruction = jde::decode(nop_instruction, sizeof(nop_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::NOP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x04);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x04 with missing operand type.
//
BOOST_AUTO_TEST_CASE(decode_0x04_nop_instruction_invalid_too_small) {

  uint8_t nop_instruction[] = {0x04};

  const auto instruction = jde::decode(nop_instruction, sizeof(nop_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x05 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x05_ora_instruction_valid) {

  uint8_t ora_instruction[] = {0x05, 0xFF};

  const auto instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ORA);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x05);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x05 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x05_ora_instruction_invalid_too_small) {

  uint8_t ora_instruction[] = {0x05};

  const auto instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x06 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x06_asl_instruction_valid) {

  uint8_t asl_instruction[] = {0x06, 0xFF};

  const auto instruction = jde::decode(asl_instruction, sizeof(asl_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ASL);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x06);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x06 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x06_asl_instruction_invalid_too_small) {

  uint8_t asl_instruction[] = {0x06};

  const auto instruction = jde::decode(asl_instruction, sizeof(asl_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x07 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x07_slo_instruction_valid) {

  uint8_t slo_instruction[] = {0x07, 0xFF};

  const auto instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::SLO);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x07);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x07 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x07_slo_instruction_invalid_too_small) {

  uint8_t slo_instruction[] = {0x07};

  const auto instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x08.
//
BOOST_AUTO_TEST_CASE(decode_0x08_php_instruction_valid) {

  uint8_t php_instruction[] = {0x08, 0xFF};

  const auto instruction = jde::decode(php_instruction, sizeof(php_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::PHP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x08);
  check_instruction_no_operand(instruction);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011 Isaac W. Foraker, all rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the Author 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 AND DOCUMENTATION IS PROVIDED BY THE AUTHOR 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
 * AUTHOR 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 "c_duck_type/duck_type.h"
#include "c_duck_type/nil_class.h"
#include "c_duck_type/string.h"
#include "c_duck_type/integer.h"
#include "c_duck_type/real.h"
#include "c_duck_type/boolean.h"
#include <sstream>
#include <cstring>

namespace CDuckType {

DuckType::DuckType()
{
    value_ = &nil;
}

DuckType::DuckType(const DuckType &object)
{
}

DuckType::DuckType(const BaseType &object)
{
    value_ = object.dup();
}

DuckType::~DuckType()
{
    if (value_ && !value_->is_a<NilClass>())
        delete value_;
}

DuckType &DuckType::swap(DuckType &value)
{
    BaseType *v = value_;
    value_ = value.value_;
    value.value_ = v;
    return *this;
}

DuckType &DuckType::operator=(const DuckType &value)
{
    throw std::runtime_error("implement me");
    return *this;
}

DuckType &DuckType::operator=(const BaseType &value)
{
    throw std::runtime_error("implement me");
    return *this;
}

DuckType &DuckType::operator=(const char* value)
{
    if (value_ && value_->is_a<String>()) {
        static_cast<String*>(value_)->assign(value);
    }
    else if (value_ && value_->equals(nil)) {
        value_ = new String(value);
    }
    else {
        delete value_;
        value_ = new String(value);
    }
    return *this;
}

DuckType &DuckType::operator=(integer_type value)
{
    if (value_ && value_->is_a<Integer>()) {
        static_cast<Integer*>(value_)->assign(value);
    }
    else if (value_ && value_->equals(nil)) {
        value_ = new Integer(value);
    }
    else {
        delete value_;
        value_ = new Integer(value);
    }
    return *this;
}

DuckType &DuckType::operator=(real_type value)
{
    if (value_ && value_->is_a<Real>()) {
        static_cast<Real*>(value_)->assign(value);
    }
    else if (value_ && value_->equals(nil)) {
        value_ = new Real(value);
    }
    else {
        delete value_;
        value_ = new Real(value);
    }
    return *this;
}

DuckType &DuckType::operator=(bool value)
{
    if (value_ && value_->is_a<Boolean>()) {
        Boolean *b = static_cast<Boolean*>(value_);
        b->assign(value);
    }
    else if (value_ && value_->equals(nil)) {
        value_ = new Boolean(value);
    }
    else {
        delete value_;
        value_ = new Boolean(value);
    }
    return *this;
}

string_type DuckType::to_string() const
{
    return value_->to_string();
}

integer_type DuckType::to_integer() const
{
    return value_->to_integer();
}

real_type DuckType::to_real() const
{
    return value_->to_real();
}

bool DuckType::is_a(const DuckType &object) const
{
    if (value_)
        return value_->is_a(*object.value_);
    else
        return false;
}

bool DuckType::is_a(const BaseType &object) const
{
    if (value_)
        return value_->is_a(object);
    else
        return false;
}

} // CDuckType
<commit_msg>Implemented more DuckType constructors.<commit_after>/*
 * Copyright (c) 2011 Isaac W. Foraker, all rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the Author 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 AND DOCUMENTATION IS PROVIDED BY THE AUTHOR 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
 * AUTHOR 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 "c_duck_type/duck_type.h"
#include "c_duck_type/nil_class.h"
#include "c_duck_type/string.h"
#include "c_duck_type/integer.h"
#include "c_duck_type/real.h"
#include "c_duck_type/boolean.h"
#include <sstream>
#include <cstring>

namespace CDuckType {

DuckType::DuckType()
{
    value_ = &nil;
}

DuckType::DuckType(const DuckType &object)
{
    value_ = object.value_->dup();
}

DuckType::DuckType(const BaseType &object)
{
    value_ = object.dup();
}

DuckType::DuckType(const char *value)
{
    value_ = new String(value);
}

DuckType::DuckType(integer_type value)
{
    value_ = new Integer(value);
}

DuckType::DuckType(real_type value)
{
    value_ = new Real(value);
}

DuckType::DuckType(bool value)
{
    value_ = new Boolean(value);
}

DuckType::~DuckType()
{
    if (value_ && value_ != &nil)
        delete value_;
}

DuckType &DuckType::swap(DuckType &value)
{
    BaseType *v = value_;
    value_ = value.value_;
    value.value_ = v;
    return *this;
}

DuckType &DuckType::operator=(const DuckType &value)
{
    throw std::runtime_error("implement me");
    return *this;
}

DuckType &DuckType::operator=(const BaseType &value)
{
    throw std::runtime_error("implement me");
    return *this;
}

DuckType &DuckType::operator=(const char* value)
{
    if (value_ && value_->is_a<String>()) {
        static_cast<String*>(value_)->assign(value);
    }
    else if (value_ && value_->equals(nil)) {
        value_ = new String(value);
    }
    else {
        delete value_;
        value_ = new String(value);
    }
    return *this;
}

DuckType &DuckType::operator=(integer_type value)
{
    if (value_ && value_->is_a<Integer>()) {
        static_cast<Integer*>(value_)->assign(value);
    }
    else if (value_ && value_->equals(nil)) {
        value_ = new Integer(value);
    }
    else {
        delete value_;
        value_ = new Integer(value);
    }
    return *this;
}

DuckType &DuckType::operator=(real_type value)
{
    if (value_ && value_->is_a<Real>()) {
        static_cast<Real*>(value_)->assign(value);
    }
    else if (value_ && value_->equals(nil)) {
        value_ = new Real(value);
    }
    else {
        delete value_;
        value_ = new Real(value);
    }
    return *this;
}

DuckType &DuckType::operator=(bool value)
{
    if (value_ && value_->is_a<Boolean>()) {
        Boolean *b = static_cast<Boolean*>(value_);
        b->assign(value);
    }
    else if (value_ && value_->equals(nil)) {
        value_ = new Boolean(value);
    }
    else {
        delete value_;
        value_ = new Boolean(value);
    }
    return *this;
}

string_type DuckType::to_string() const
{
    return value_->to_string();
}

integer_type DuckType::to_integer() const
{
    return value_->to_integer();
}

real_type DuckType::to_real() const
{
    return value_->to_real();
}

bool DuckType::is_a(const DuckType &object) const
{
    if (value_)
        return value_->is_a(*object.value_);
    else
        return false;
}

bool DuckType::is_a(const BaseType &object) const
{
    if (value_)
        return value_->is_a(object);
    else
        return false;
}

} // CDuckType
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013 rajendrauppal

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 <iostream>

#include "Exceptions.h"
#include "GcdLcm.h"

using std::cout;
using std::cin;
using std::endl;

int GcdLcm::GCD_Euclidean_Iterative(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;

	while ( n ) {
		int temp = n;
		n = m % n;
		m = temp;
	}

	return m;
}

int GcdLcm::GCD_Euclidean_Recursive(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;

	return GCD_Euclidean_Recursive(n, m % n);
}

int GcdLcm::GCD_AlternateEuclidean_Iterative(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;

	while ( m != n ) {
		if ( m > n )
			m = m - n;
		else
			n = n - m;
	}

	return m;
}

int GcdLcm::GCD_AlternateEuclidean_Recursive(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;

	if ( m == n ) return m;
	if ( m > n )
		return GCD_AlternateEuclidean_Recursive(m - n, n);
	else
		return GCD_AlternateEuclidean_Recursive(m, n - m);
}

int GcdLcm::GCD_Binary_Iterative(int m, int n)
{
	return 0;
}

/* Binary GCD algorithm (Credit: en.wikipedia.org/wiki/Binary_GCD_algorithm)
-----------------------------------------------
m		n		gcd
-----------------------------------------------
even	even		2 * gcd( m/2, n/2 )
even	odd			gcd( m/2, n )
odd			even	gcd( m, n/2 )
odd			odd		m >= n then gcd( (m - n)/2, n )
				    m < n  then gcd( (n - m)/2, m )
-----------------------------------------------
*/
int GcdLcm::GCD_Binary_Recursive(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;
	if ( m == n ) return m;

	bool m_even = ~m & 1;
	bool n_even = ~n & 1;

	if ( m_even && n_even )
		return GCD_Binary_Recursive( m >> 1, n >> 1 ) << 1;

	if ( m_even && !n_even )
		return GCD_Binary_Recursive( m >> 1, n );

	if ( !m_even && n_even )
		return GCD_Binary_Recursive( m, n >> 1 );

	if ( m >= n )
		return GCD_Binary_Recursive( (m - n) >> 1, n );
	else
		return GCD_Binary_Recursive( (n - m) >> 1, m );
}

int GcdLcm::LCM_Iterative(int m, int n)
{
	return 0;
}

int GcdLcm::LCM_Recursive(int m, int n)
{
	return 0;
}

int GcdLcm::GCD_UsingLCM(int m, int n)
{
	return 0;
}

int main()
{
	GcdLcm gcdlcm;
	int nums[13][2] = {{0,1}, {1,0}, {0,0}, {1,1}, {-1,1}, {1,-1}, {-1,-1}, {1,1}, {2,3}, {10,10}, {121,11}, {24,60}, {36253652,183728732}};
	for ( size_t i = 0; i < 13; ++i ) {
		try
		{
			cout << gcdlcm.GCD_Euclidean_Iterative(nums[i][0], nums[i][1]) << endl;
			cout << gcdlcm.GCD_Euclidean_Recursive(nums[i][0], nums[i][1]) << endl;

			cout << gcdlcm.GCD_AlternateEuclidean_Iterative(nums[i][0], nums[i][1]) << endl;
			cout << gcdlcm.GCD_AlternateEuclidean_Recursive(nums[i][0], nums[i][1]) << endl;

			cout << gcdlcm.GCD_Binary_Recursive(nums[i][0], nums[i][1]) << endl;
		}
		catch (CPPExceptions& e)
		{
			cout << e.message() << endl;
		}
	}

	cout << "Press Enter to continue..." << endl;
	cin.get();
	return 0;
}<commit_msg>Implemented Binary GCD algorithm<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013 rajendrauppal

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 <iostream>

#include "Exceptions.h"
#include "GcdLcm.h"

using std::cout;
using std::cin;
using std::endl;

int GcdLcm::GCD_Euclidean_Iterative(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;

	while ( n ) {
		int temp = n;
		n = m % n;
		m = temp;
	}

	return m;
}

int GcdLcm::GCD_Euclidean_Recursive(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;

	return GCD_Euclidean_Recursive(n, m % n);
}

int GcdLcm::GCD_AlternateEuclidean_Iterative(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;

	while ( m != n ) {
		if ( m > n )
			m = m - n;
		else
			n = n - m;
	}

	return m;
}

int GcdLcm::GCD_AlternateEuclidean_Recursive(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;

	if ( m == n ) return m;
	if ( m > n )
		return GCD_AlternateEuclidean_Recursive(m - n, n);
	else
		return GCD_AlternateEuclidean_Recursive(m, n - m);
}

int GcdLcm::GCD_Binary_Iterative(int m, int n)
{
	return 0;
}

/* Binary GCD algorithm (Credit: en.wikipedia.org/wiki/Binary_GCD_algorithm)
-----------------------------------------------
m		n		gcd
-----------------------------------------------
even	even	2 * gcd( m/2, n/2 )
even	odd		gcd( m/2, n )
odd		even	gcd( m, n/2 )
odd		odd		m >= n then gcd( (m - n)/2, n )
				m < n  then gcd( (n - m)/2, m )
-----------------------------------------------
*/
int GcdLcm::GCD_Binary_Recursive(int m, int n)
{
	if ( (m < 0) || (n < 0) ) throw InvalidInputException();
	if ( !m && !n ) throw InvalidInputException();
	if ( m && !n ) return m;
	if ( !m && n ) return n;
	if ( m == n ) return m;

	bool m_even = ~m & 1;
	bool n_even = ~n & 1;

	if ( m_even && n_even )
		return GCD_Binary_Recursive( m >> 1, n >> 1 ) << 1;

	if ( m_even && !n_even )
		return GCD_Binary_Recursive( m >> 1, n );

	if ( !m_even && n_even )
		return GCD_Binary_Recursive( m, n >> 1 );

	if ( m >= n )
		return GCD_Binary_Recursive( (m - n) >> 1, n );
	else
		return GCD_Binary_Recursive( (n - m) >> 1, m );
}

int GcdLcm::LCM_Iterative(int m, int n)
{
	return 0;
}

int GcdLcm::LCM_Recursive(int m, int n)
{
	return 0;
}

int GcdLcm::GCD_UsingLCM(int m, int n)
{
	return 0;
}

int main()
{
	GcdLcm gcdlcm;
	int nums[13][2] = {{0,1}, {1,0}, {0,0}, {1,1}, {-1,1}, {1,-1}, {-1,-1}, {1,1}, {2,3}, {10,10}, {121,11}, {24,60}, {36253652,183728732}};
	for ( size_t i = 0; i < 13; ++i ) {
		try
		{
			cout << gcdlcm.GCD_Euclidean_Iterative(nums[i][0], nums[i][1]) << endl;
			cout << gcdlcm.GCD_Euclidean_Recursive(nums[i][0], nums[i][1]) << endl;

			cout << gcdlcm.GCD_AlternateEuclidean_Iterative(nums[i][0], nums[i][1]) << endl;
			cout << gcdlcm.GCD_AlternateEuclidean_Recursive(nums[i][0], nums[i][1]) << endl;

			cout << gcdlcm.GCD_Binary_Recursive(nums[i][0], nums[i][1]) << endl;
		}
		catch (CPPExceptions& e)
		{
			cout << e.message() << endl;
		}
	}

	cout << "Press Enter to continue..." << endl;
	cin.get();
	return 0;
}<|endoftext|>


<commit_before>// Scintilla source code edit control
// @file LexAU3.cxx
// Lexer for AutoIt3  http://www.hiddensoft.com/autoit3
// by Jos van der Zande, jvdzande@yahoo.com
//
// Changes:
//
// Copyright for Scintilla: 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
// Scintilla source code edit control

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static inline bool IsTypeCharacter(const int ch)
{
    return ch == '$';
}
static inline bool IsAWordChar(const int ch)
{
    return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '-');
}

static inline bool IsAWordStart(const int ch)
{
    return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '@' || ch == '#' || ch == '{' || ch == '+' || ch == '!' || ch == '#' || ch == '^');
}

static void ColouriseAU3Doc(unsigned int startPos,
							int length, int initStyle,
							WordList *keywordlists[],
							Accessor &styler) {

    WordList &keywords = *keywordlists[0];
    WordList &keywords2 = *keywordlists[1];
    WordList &keywords3 = *keywordlists[2];
    WordList &keywords4 = *keywordlists[3];
    styler.StartAt(startPos);

    StyleContext sc(startPos, length, initStyle, styler);
	char si,sk;
	si=0;
	sk=0;
    for (; sc.More(); sc.Forward()) {
		char s[100];
		sc.GetCurrentLowered(s, sizeof(s));
		switch (sc.state)
        {
            case SCE_AU3_COMMENTBLOCK:
            {
                if (sc.ch == '#') {sc.SetState(SCE_AU3_DEFAULT);}
				break;
			}
            case SCE_AU3_COMMENT:
            {
                if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
                break;
            }
            case SCE_AU3_OPERATOR:
            {
                sc.SetState(SCE_AU3_DEFAULT);
                break;
            }
            case SCE_AU3_KEYWORD:
            {
                if (!IsAWordChar(sc.ch))
                {
                    if (!IsTypeCharacter(sc.ch))
                    {
						if (strcmp(s, "#cs")==0 || strcmp(s, "#comments_start")==0)
						{
							sc.ChangeState(SCE_AU3_COMMENTBLOCK);
							sc.SetState(SCE_AU3_COMMENTBLOCK);
						}
						else if (strcmp(s, "#ce")==0 || strcmp(s, "#comments_end")==0)
						{
							sc.ChangeState(SCE_AU3_COMMENTBLOCK);
							sc.SetState(SCE_AU3_DEFAULT);
						}
						else if (keywords.InList(s)) {
							sc.ChangeState(SCE_AU3_KEYWORD);
							sc.SetState(SCE_AU3_DEFAULT);
							//sc.SetState(SCE_AU3_KEYWORD);
						}
						else if (keywords2.InList(s)) {
							sc.ChangeState(SCE_AU3_FUNCTION);
							sc.SetState(SCE_AU3_DEFAULT);
							//sc.SetState(SCE_AU3_FUNCTION);
						}
						else if (keywords3.InList(s)) {
							sc.ChangeState(SCE_AU3_MACRO);
							sc.SetState(SCE_AU3_DEFAULT);
						}
						else if (!IsAWordChar(sc.ch)) {
							sc.ChangeState(SCE_AU3_DEFAULT);
							sc.SetState(SCE_AU3_DEFAULT);
						}
					}
				}
                if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
                break;
            }
            case SCE_AU3_NUMBER:
            {
                if (!IsAWordChar(sc.ch)) {sc.SetState(SCE_AU3_DEFAULT);}
                break;
            }
            case SCE_AU3_VARIABLE:
            {
                if (!IsAWordChar(sc.ch)) {sc.SetState(SCE_AU3_DEFAULT);}
                break;
            }
            case SCE_AU3_STRING:
            {
				sk = 0;
				// check for " in and single qouted string
	            if (si == 1){
					if (sc.ch == '\"'){sc.ForwardSetState(SCE_AU3_DEFAULT);}}
				// check for ' in and double qouted string
                if (si == 2){
					if (sc.ch == '\''){sc.ForwardSetState(SCE_AU3_DEFAULT);}}
                if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
				// find Sendkeys in an STRING
				if (sc.ch == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '+' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '!' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '^' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '#' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				break;
            }

            case SCE_AU3_SENT:
            {
				// Sent key string ended
				if (sk == 1)
				{
					// set color to SENTKEY when valid sentkey .. else set to comment to show its wrong
					if (keywords4.InList(s))
					{
						sc.ChangeState(SCE_AU3_SENT);
					}
					else
					{
						sc.ChangeState(SCE_AU3_STRING);
					}
					sc.SetState(SCE_AU3_STRING);
					sk=0;
				}
				// check if next portion is again a sentkey
				if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
				if (sc.ch == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '+' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '!' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '^' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '#' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				// check to see if the string ended...
				// check for " in and single qouted string
	            if (si == 1){
					if (sc.ch == '\"'){sc.ForwardSetState(SCE_AU3_DEFAULT);}}
				// check for ' in and double qouted string
                if (si == 2){
					if (sc.ch == '\''){sc.ForwardSetState(SCE_AU3_DEFAULT);}}
				break;
            }
        }  //switch (sc.state)

        // Determine if a new state should be entered:
        if (sc.state == SCE_AU3_SENT)
        {
			if (sc.ch == '}' && sc.chNext != '}')
			{
				sk = 1;
			}
		}
		if (sc.state == SCE_AU3_DEFAULT)
        {
            if (sc.ch == ';') {sc.SetState(SCE_AU3_COMMENT);}
            else if (sc.ch == '#') {sc.SetState(SCE_AU3_KEYWORD);}
            else if (IsAWordStart(sc.ch)) {sc.SetState(SCE_AU3_KEYWORD);}
            else if (sc.ch == '@') {sc.SetState(SCE_AU3_KEYWORD);}
            else if (sc.ch == '\"') {
				sc.SetState(SCE_AU3_STRING);
				si = 1;	}
            else if (sc.ch == '\'') {
				sc.SetState(SCE_AU3_STRING);
				si = 2;	}
            else if (sc.ch == '$') {sc.SetState(SCE_AU3_VARIABLE);}
            else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {sc.SetState(SCE_AU3_NUMBER);}
            //else if (IsAWordStart(sc.ch)) {sc.SetState(SCE_AU3_KEYWORD);}
            else if (isoperator(static_cast<char>(sc.ch)) || (sc.ch == '\\')) {sc.SetState(SCE_AU3_OPERATOR);}
			else if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
        }
    }      //for (; sc.More(); sc.Forward())
    sc.Complete();
}

//

static const char * const AU3WordLists[] = {
    "#autoit keywords",
    "#autoit functions",
    "#autoit macros",
    "#autoit Sent keys",
    0
};
LexerModule lmAU3(SCLEX_AU3, ColouriseAU3Doc, "au3", NULL , AU3WordLists);
<commit_msg>Folder added by Jos.<commit_after>// Scintilla source code edit control
// @file LexAU3.cxx
// Lexer for AutoIt3  http://www.hiddensoft.com/autoit3
// by Jos van der Zande, jvdzande@yahoo.com
//
// Changes:
//
// Copyright for Scintilla: 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
// Scintilla source code edit control

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool IsAU3Comment(Accessor &styler, int pos, int len) {
	return len>0 && styler[pos]==';';
}

static inline bool IsTypeCharacter(const int ch)
{
    return ch == '$';
}
static inline bool IsAWordChar(const int ch)
{
    return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '-');
}

static inline bool IsAWordStart(const int ch)
{
    return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '@' || ch == '#' || ch == '{' || ch == '+' || ch == '!' || ch == '#' || ch == '^');
}

static void ColouriseAU3Doc(unsigned int startPos,
							int length, int initStyle,
							WordList *keywordlists[],
							Accessor &styler) {

    WordList &keywords = *keywordlists[0];
    WordList &keywords2 = *keywordlists[1];
    WordList &keywords3 = *keywordlists[2];
    WordList &keywords4 = *keywordlists[3];
    styler.StartAt(startPos);

    StyleContext sc(startPos, length, initStyle, styler);
	char si,sk;
	si=0;
	sk=0;
    for (; sc.More(); sc.Forward()) {
		char s[100];
		sc.GetCurrentLowered(s, sizeof(s));
		switch (sc.state)
        {
            case SCE_AU3_COMMENTBLOCK:
            {
                if (sc.ch == '#') {sc.SetState(SCE_AU3_DEFAULT);}
				break;
			}
            case SCE_AU3_COMMENT:
            {
                if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
                break;
            }
            case SCE_AU3_OPERATOR:
            {
                sc.SetState(SCE_AU3_DEFAULT);
                break;
            }
            case SCE_AU3_KEYWORD:
            {
                if (!IsAWordChar(sc.ch))
                {
                    if (!IsTypeCharacter(sc.ch))
                    {
						if (strcmp(s, "#cs")==0 || strcmp(s, "#comments_start")==0)
						{
							sc.ChangeState(SCE_AU3_COMMENTBLOCK);
							sc.SetState(SCE_AU3_COMMENTBLOCK);
						}
						else if (strcmp(s, "#ce")==0 || strcmp(s, "#comments_end")==0)
						{
							sc.ChangeState(SCE_AU3_COMMENTBLOCK);
							sc.SetState(SCE_AU3_DEFAULT);
						}
						else if (keywords.InList(s)) {
							sc.ChangeState(SCE_AU3_KEYWORD);
							sc.SetState(SCE_AU3_DEFAULT);
							//sc.SetState(SCE_AU3_KEYWORD);
						}
						else if (keywords2.InList(s)) {
							sc.ChangeState(SCE_AU3_FUNCTION);
							sc.SetState(SCE_AU3_DEFAULT);
							//sc.SetState(SCE_AU3_FUNCTION);
						}
						else if (keywords3.InList(s)) {
							sc.ChangeState(SCE_AU3_MACRO);
							sc.SetState(SCE_AU3_DEFAULT);
						}
						else if (!IsAWordChar(sc.ch)) {
							sc.ChangeState(SCE_AU3_DEFAULT);
							sc.SetState(SCE_AU3_DEFAULT);
						}
					}
				}
                if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
                break;
            }
            case SCE_AU3_NUMBER:
            {
                if (!IsAWordChar(sc.ch)) {sc.SetState(SCE_AU3_DEFAULT);}
                break;
            }
            case SCE_AU3_VARIABLE:
            {
                if (!IsAWordChar(sc.ch)) {sc.SetState(SCE_AU3_DEFAULT);}
                break;
            }
            case SCE_AU3_STRING:
            {
				sk = 0;
				// check for " in and single qouted string
	            if (si == 1){
					if (sc.ch == '\"'){sc.ForwardSetState(SCE_AU3_DEFAULT);}}
				// check for ' in and double qouted string
                if (si == 2){
					if (sc.ch == '\''){sc.ForwardSetState(SCE_AU3_DEFAULT);}}
                if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
				// find Sendkeys in an STRING
				if (sc.ch == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '+' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '!' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '^' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '#' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				break;
            }

            case SCE_AU3_SENT:
            {
				// Sent key string ended
				if (sk == 1)
				{
					// set color to SENTKEY when valid sentkey .. else set to comment to show its wrong
					if (keywords4.InList(s))
					{
						sc.ChangeState(SCE_AU3_SENT);
					}
					else
					{
						sc.ChangeState(SCE_AU3_STRING);
					}
					sc.SetState(SCE_AU3_STRING);
					sk=0;
				}
				// check if next portion is again a sentkey
				if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
				if (sc.ch == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '+' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '!' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '^' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				if (sc.ch == '#' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
				// check to see if the string ended...
				// check for " in and single qouted string
	            if (si == 1){
					if (sc.ch == '\"'){sc.ForwardSetState(SCE_AU3_DEFAULT);}}
				// check for ' in and double qouted string
                if (si == 2){
					if (sc.ch == '\''){sc.ForwardSetState(SCE_AU3_DEFAULT);}}
				break;
            }
        }  //switch (sc.state)

        // Determine if a new state should be entered:
        if (sc.state == SCE_AU3_SENT)
        {
			if (sc.ch == '}' && sc.chNext != '}')
			{
				sk = 1;
			}
		}
		if (sc.state == SCE_AU3_DEFAULT)
        {
            if (sc.ch == ';') {sc.SetState(SCE_AU3_COMMENT);}
            else if (sc.ch == '#') {sc.SetState(SCE_AU3_KEYWORD);}
            else if (IsAWordStart(sc.ch)) {sc.SetState(SCE_AU3_KEYWORD);}
            else if (sc.ch == '@') {sc.SetState(SCE_AU3_KEYWORD);}
            else if (sc.ch == '\"') {
				sc.SetState(SCE_AU3_STRING);
				si = 1;	}
            else if (sc.ch == '\'') {
				sc.SetState(SCE_AU3_STRING);
				si = 2;	}
            else if (sc.ch == '$') {sc.SetState(SCE_AU3_VARIABLE);}
            else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {sc.SetState(SCE_AU3_NUMBER);}
            //else if (IsAWordStart(sc.ch)) {sc.SetState(SCE_AU3_KEYWORD);}
            else if (isoperator(static_cast<char>(sc.ch)) || (sc.ch == '\\')) {sc.SetState(SCE_AU3_OPERATOR);}
			else if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
        }
    }      //for (; sc.More(); sc.Forward())
    sc.Complete();
}

//
//
static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Accessor &styler)
{
		int endPos = startPos + length;

	// Backtrack to previous line in case need to fix its fold status
	int lineCurrent = styler.GetLine(startPos);
	if (startPos > 0) {
		if (lineCurrent > 0) {
			lineCurrent--;
			startPos = styler.LineStart(lineCurrent);
		}
	}
	int spaceFlags = 0;
	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsAU3Comment);
	char chNext = styler[startPos];
	for (int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {
			int lev = indentCurrent;
			int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsAU3Comment);
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
					// Line after is blank so check the next - maybe should continue further?
					int spaceFlags2 = 0;
					int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsAU3Comment);
					if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
						lev |= SC_FOLDLEVELHEADERFLAG;
					}
				}
			}
			indentCurrent = indentNext;
			styler.SetLevel(lineCurrent, lev);
			lineCurrent++;
		}
	}

}

//

static const char * const AU3WordLists[] = {
    "#autoit keywords",
    "#autoit functions",
    "#autoit macros",
    "#autoit Sent keys",
    0
};
LexerModule lmAU3(SCLEX_AU3, ColouriseAU3Doc, "au3", FoldAU3Doc , AU3WordLists);
<|endoftext|>


<commit_before>/* -*- indent-tabs-mode: nil -*- */
#include "client/http_log_client.h"
#include "log/cert.h"
#include "proto/ct.pb.h"
#include "proto/serializer.h"
#include "util/json_wrapper.h"
#include "util/util.h"

#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
#include <glog/logging.h>
#include <sstream>

using std::string;
using std::ostringstream;

using ct::Cert;
using ct::CertChain;

void HTTPLogClient::BaseUrl(ostringstream *url) {
  *url << "http://" << server_ << "/ct/v1/";
}

static HTTPLogClient::Status SendRequest(ostringstream *response,
                                         curlpp::Easy *request,
                                         const ostringstream &url) {
  request->setOpt(new curlpp::options::Url(url.str()));
  try {
    *response << *request;
  } catch(curlpp::LibcurlRuntimeError &e) {
    if (e.what() == string("couldn't connect to host"))
      return HTTPLogClient::CONNECT_FAILED;
    LOG(ERROR) << "Caught curlpp::LibcurlRuntimeError: " << e.what();
    return HTTPLogClient::UNKNOWN_ERROR;
  }
  return HTTPLogClient::OK;
}

HTTPLogClient::Status
HTTPLogClient::UploadSubmission(const std::string &submission, bool pre,
                                ct::SignedCertificateTimestamp *sct) {

  CertChain chain(submission);

  if (!chain.IsLoaded())
    return INVALID_INPUT;

  JsonArray jchain;
  for (size_t n = 0; n < chain.Length(); ++n) {
    string cert;
    CHECK_EQ(Cert::TRUE, chain.CertAt(n)->DerEncoding(&cert));
    jchain.Add(json_object_new_string(ToBase64(cert).c_str()));
  }
  json_object *jsend = json_object_new_object();
  json_object_object_add(jsend, "chain", jchain.Extract());

  const char *jsoned = json_object_to_json_string(jsend);

  ostringstream url;
  BaseUrl(&url);
  url << "add-";
  if (pre)
    url << "pre-";
  url << "chain";

  curlpp::Easy request;
  request.setOpt(new curlpp::options::PostFields(jsoned));

  std::ostringstream response;
  Status ret = SendRequest(&response, &request, url);
  LOG(INFO) << "request = " << url.str();
  LOG(INFO) << "body = " << jsoned;
  LOG(INFO) << "response = " << response.str();
  json_object_put(jsend);
  if (ret != OK)
    return ret;

  JsonObject jresponse(json_tokener_parse(response.str().c_str()));

  jsoned = jresponse.ToJson();

  if (!jresponse.IsType(json_type_object)) {
    LOG(ERROR) << "Expected a JSON object, got: " << response.str();
    return BAD_RESPONSE;
  }

  JsonString id(jresponse, "id");
  if (!id.Ok())
    return BAD_RESPONSE;
  sct->mutable_id()->set_key_id(id.FromBase64());

  JsonInt timestamp(jresponse, "timestamp");
  if (!timestamp.Ok())
    return BAD_RESPONSE;
  sct->set_timestamp(timestamp.Value());

  JsonString extensions(jresponse, "extensions");
  if (!extensions.Ok())
    return BAD_RESPONSE;
  sct->set_extension(extensions.FromBase64());

  JsonString signature(jresponse, "signature");
  if (!signature.Ok())
    return BAD_RESPONSE;
  if (Deserializer::DeserializeDigitallySigned(signature.FromBase64(),
                                               sct->mutable_signature())
      != Deserializer::OK)
    return BAD_RESPONSE;

  sct->set_version(ct::V1);

  return OK;
}

HTTPLogClient::Status
HTTPLogClient::QueryAuditProof(const string &merkle_leaf_hash,
                               ct::MerkleAuditProof *proof) {
  ostringstream url;
  BaseUrl(&url);
  url << "get-sth";

  curlpp::Easy request;

  std::ostringstream response;
  Status ret = SendRequest(&response, &request, url);
  LOG(INFO) << "request = " << url.str();
  LOG(INFO) << "response = " << response.str();
  if (ret != OK)
    return ret;

  JsonObject jresponse(response);

  JsonInt tree_size(jresponse, "tree_size");
  if (!tree_size.Ok())
    return BAD_RESPONSE;
  proof->set_tree_size(tree_size.Value());

  JsonInt timestamp(jresponse, "timestamp");
  if (!timestamp.Ok())
    return BAD_RESPONSE;
  proof->set_timestamp(timestamp.Value());

  JsonString tree_head_signature(jresponse, "tree_head_signature");
  if (!tree_head_signature.Ok())
    return BAD_RESPONSE;
  string decoded = tree_head_signature.FromBase64();
  if (Deserializer::DeserializeDigitallySigned(decoded,
          proof->mutable_tree_head_signature()) != Deserializer::OK)
    return BAD_RESPONSE;

  ostringstream url2;
  BaseUrl(&url2);
  url2 << "get-proof-by-hash?hash="
       << curlpp::escape(ToBase64(merkle_leaf_hash))
       << "&tree_size=" << tree_size.Value();
  curlpp::Easy request2;
  std::ostringstream response2;
  ret = SendRequest(&response2, &request2, url2);
  LOG(INFO) << "request = " << url2.str();
  LOG(INFO) << "response = " << response2.str();
  if (ret != OK)
    return ret;

  JsonObject jresponse2(response2);

  JsonInt leaf_index(jresponse2, "leaf_index");
  if (!leaf_index.Ok())
    return BAD_RESPONSE;
  proof->set_leaf_index(leaf_index.Value());

  JsonArray audit_path(jresponse2, "audit_path");
  if (!audit_path.Ok())
    return BAD_RESPONSE;

  for (int n = 0; n < audit_path.Length(); ++n) {
    JsonString path_node(audit_path, n);
    CHECK(path_node.Ok());
    proof->add_path_node(path_node.FromBase64());
  }

  proof->set_version(ct::V1);

  return OK;
}

HTTPLogClient::Status HTTPLogClient::GetEntries(int first, int last,
                                               std::vector<LogEntry> *entries) {
  ostringstream url;
  BaseUrl(&url);
  url << "get-entries?start=" << first << "&end=" << last;

  curlpp::Easy request;

  std::ostringstream response;
  Status ret = SendRequest(&response, &request, url);
  LOG(INFO) << "request = " << url.str();
  LOG(INFO) << "response = " << response.str();
  if (ret != OK)
    return ret;

  JsonObject jresponse(response);
  if (!jresponse.Ok())
    return BAD_RESPONSE;

  JsonArray jentries(jresponse, "entries");
  if (!jentries.Ok())
    return BAD_RESPONSE;

  for (int n = 0; n < jentries.Length(); ++n) {
    JsonObject entry(jentries, n);
    if (!entry.Ok())
      return BAD_RESPONSE;

    JsonString leaf_input(entry, "leaf_input");
    if (!leaf_input.Ok())
      return BAD_RESPONSE;

    LogEntry log_entry;
    if (Deserializer::DeserializeMerkleTreeLeaf(leaf_input.FromBase64(),
                                                &log_entry.leaf)
        != Deserializer::OK)
      return BAD_RESPONSE;

    JsonString extra_data(entry, "extra_data");
    if (!extra_data.Ok())
      return BAD_RESPONSE;

    if (log_entry.leaf.timestamped_entry().entry_type() == ct::X509_ENTRY)
      Deserializer::DeserializeX509Chain(extra_data.FromBase64(),
                                         log_entry.entry.mutable_x509_entry());
    else if (log_entry.leaf.timestamped_entry().entry_type()
            == ct::PRECERT_ENTRY)
      Deserializer::DeserializePrecertChainEntry(extra_data.FromBase64(),
          log_entry.entry.mutable_precert_entry());
    else
      LOG(FATAL) << "Don't understand entry type: "
                 << log_entry.leaf.timestamped_entry().entry_type();

    entries->push_back(log_entry);
  }

  return OK;
}
<commit_msg>Remove unnecessary call to ToJson.<commit_after>/* -*- indent-tabs-mode: nil -*- */
#include "client/http_log_client.h"
#include "log/cert.h"
#include "proto/ct.pb.h"
#include "proto/serializer.h"
#include "util/json_wrapper.h"
#include "util/util.h"

#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
#include <glog/logging.h>
#include <sstream>

using std::string;
using std::ostringstream;

using ct::Cert;
using ct::CertChain;

void HTTPLogClient::BaseUrl(ostringstream *url) {
  *url << "http://" << server_ << "/ct/v1/";
}

static HTTPLogClient::Status SendRequest(ostringstream *response,
                                         curlpp::Easy *request,
                                         const ostringstream &url) {
  request->setOpt(new curlpp::options::Url(url.str()));
  try {
    *response << *request;
  } catch(curlpp::LibcurlRuntimeError &e) {
    if (e.what() == string("couldn't connect to host"))
      return HTTPLogClient::CONNECT_FAILED;
    LOG(ERROR) << "Caught curlpp::LibcurlRuntimeError: " << e.what();
    return HTTPLogClient::UNKNOWN_ERROR;
  }
  return HTTPLogClient::OK;
}

HTTPLogClient::Status
HTTPLogClient::UploadSubmission(const std::string &submission, bool pre,
                                ct::SignedCertificateTimestamp *sct) {

  CertChain chain(submission);

  if (!chain.IsLoaded())
    return INVALID_INPUT;

  JsonArray jchain;
  for (size_t n = 0; n < chain.Length(); ++n) {
    string cert;
    CHECK_EQ(Cert::TRUE, chain.CertAt(n)->DerEncoding(&cert));
    jchain.Add(json_object_new_string(ToBase64(cert).c_str()));
  }
  json_object *jsend = json_object_new_object();
  json_object_object_add(jsend, "chain", jchain.Extract());

  const char *jsoned = json_object_to_json_string(jsend);

  ostringstream url;
  BaseUrl(&url);
  url << "add-";
  if (pre)
    url << "pre-";
  url << "chain";

  curlpp::Easy request;
  request.setOpt(new curlpp::options::PostFields(jsoned));

  std::ostringstream response;
  Status ret = SendRequest(&response, &request, url);
  LOG(INFO) << "request = " << url.str();
  LOG(INFO) << "body = " << jsoned;
  LOG(INFO) << "response = " << response.str();
  json_object_put(jsend);
  if (ret != OK)
    return ret;

  JsonObject jresponse(json_tokener_parse(response.str().c_str()));

  if (!jresponse.IsType(json_type_object)) {
    LOG(ERROR) << "Expected a JSON object, got: " << response.str();
    return BAD_RESPONSE;
  }

  JsonString id(jresponse, "id");
  if (!id.Ok())
    return BAD_RESPONSE;
  sct->mutable_id()->set_key_id(id.FromBase64());

  JsonInt timestamp(jresponse, "timestamp");
  if (!timestamp.Ok())
    return BAD_RESPONSE;
  sct->set_timestamp(timestamp.Value());

  JsonString extensions(jresponse, "extensions");
  if (!extensions.Ok())
    return BAD_RESPONSE;
  sct->set_extension(extensions.FromBase64());

  JsonString signature(jresponse, "signature");
  if (!signature.Ok())
    return BAD_RESPONSE;
  if (Deserializer::DeserializeDigitallySigned(signature.FromBase64(),
                                               sct->mutable_signature())
      != Deserializer::OK)
    return BAD_RESPONSE;

  sct->set_version(ct::V1);

  return OK;
}

HTTPLogClient::Status
HTTPLogClient::QueryAuditProof(const string &merkle_leaf_hash,
                               ct::MerkleAuditProof *proof) {
  ostringstream url;
  BaseUrl(&url);
  url << "get-sth";

  curlpp::Easy request;

  std::ostringstream response;
  Status ret = SendRequest(&response, &request, url);
  LOG(INFO) << "request = " << url.str();
  LOG(INFO) << "response = " << response.str();
  if (ret != OK)
    return ret;

  JsonObject jresponse(response);

  JsonInt tree_size(jresponse, "tree_size");
  if (!tree_size.Ok())
    return BAD_RESPONSE;
  proof->set_tree_size(tree_size.Value());

  JsonInt timestamp(jresponse, "timestamp");
  if (!timestamp.Ok())
    return BAD_RESPONSE;
  proof->set_timestamp(timestamp.Value());

  JsonString tree_head_signature(jresponse, "tree_head_signature");
  if (!tree_head_signature.Ok())
    return BAD_RESPONSE;
  string decoded = tree_head_signature.FromBase64();
  if (Deserializer::DeserializeDigitallySigned(decoded,
          proof->mutable_tree_head_signature()) != Deserializer::OK)
    return BAD_RESPONSE;

  ostringstream url2;
  BaseUrl(&url2);
  url2 << "get-proof-by-hash?hash="
       << curlpp::escape(ToBase64(merkle_leaf_hash))
       << "&tree_size=" << tree_size.Value();
  curlpp::Easy request2;
  std::ostringstream response2;
  ret = SendRequest(&response2, &request2, url2);
  LOG(INFO) << "request = " << url2.str();
  LOG(INFO) << "response = " << response2.str();
  if (ret != OK)
    return ret;

  JsonObject jresponse2(response2);

  JsonInt leaf_index(jresponse2, "leaf_index");
  if (!leaf_index.Ok())
    return BAD_RESPONSE;
  proof->set_leaf_index(leaf_index.Value());

  JsonArray audit_path(jresponse2, "audit_path");
  if (!audit_path.Ok())
    return BAD_RESPONSE;

  for (int n = 0; n < audit_path.Length(); ++n) {
    JsonString path_node(audit_path, n);
    CHECK(path_node.Ok());
    proof->add_path_node(path_node.FromBase64());
  }

  proof->set_version(ct::V1);

  return OK;
}

HTTPLogClient::Status HTTPLogClient::GetEntries(int first, int last,
                                               std::vector<LogEntry> *entries) {
  ostringstream url;
  BaseUrl(&url);
  url << "get-entries?start=" << first << "&end=" << last;

  curlpp::Easy request;

  std::ostringstream response;
  Status ret = SendRequest(&response, &request, url);
  LOG(INFO) << "request = " << url.str();
  LOG(INFO) << "response = " << response.str();
  if (ret != OK)
    return ret;

  JsonObject jresponse(response);
  if (!jresponse.Ok())
    return BAD_RESPONSE;

  JsonArray jentries(jresponse, "entries");
  if (!jentries.Ok())
    return BAD_RESPONSE;

  for (int n = 0; n < jentries.Length(); ++n) {
    JsonObject entry(jentries, n);
    if (!entry.Ok())
      return BAD_RESPONSE;

    JsonString leaf_input(entry, "leaf_input");
    if (!leaf_input.Ok())
      return BAD_RESPONSE;

    LogEntry log_entry;
    if (Deserializer::DeserializeMerkleTreeLeaf(leaf_input.FromBase64(),
                                                &log_entry.leaf)
        != Deserializer::OK)
      return BAD_RESPONSE;

    JsonString extra_data(entry, "extra_data");
    if (!extra_data.Ok())
      return BAD_RESPONSE;

    if (log_entry.leaf.timestamped_entry().entry_type() == ct::X509_ENTRY)
      Deserializer::DeserializeX509Chain(extra_data.FromBase64(),
                                         log_entry.entry.mutable_x509_entry());
    else if (log_entry.leaf.timestamped_entry().entry_type()
            == ct::PRECERT_ENTRY)
      Deserializer::DeserializePrecertChainEntry(extra_data.FromBase64(),
          log_entry.entry.mutable_precert_entry());
    else
      LOG(FATAL) << "Don't understand entry type: "
                 << log_entry.leaf.timestamped_entry().entry_type();

    entries->push_back(log_entry);
  }

  return OK;
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "CommandManager.h"

/* system implementation headers */
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <string>

/* common implementation headers */
#include "TextUtils.h"

// initialize the singleton
template <>
CommandManager* Singleton<CommandManager>::_instance = (CommandManager*)0;

CommandManager::CommandManager()
{
  // do nothing
}

CommandManager::~CommandManager()
{
  // do nothing
}

void				CommandManager::add(const std::string& name,
						    CommandFunction func,
						    const std::string& help)
{
  commands.erase(name);
  CmdInfo info;
  info.func = func;
  info.help = help;
  commands.insert(std::make_pair(name, info));
}

void				CommandManager::remove(const std::string& name)
{
  commands.erase(name);
}

std::string			CommandManager::getHelp(const std::string& name) const
{
  // look up command
  Commands::const_iterator index = commands.find(name);
  if (index == commands.end())
    return "";

  // return help string
  return index->second.help;
}

std::string			CommandManager::run(const std::string& name,
							    const ArgList& args, bool* ret) const
{
  // look up command
  Commands::const_iterator index = commands.find(name);
  if (index == commands.end()) {
    if (ret)
      *ret = false;
    return TextUtils::format("Command %s not found", name.c_str());
  }
  if (ret)
    *ret = true;
  // run it
  return (*index->second.func)(name, args,ret);
}

std::string			CommandManager::run(const std::string& cmd,bool *ret) const
{
  std::string result;
  const char* scan = cmd.c_str();

  scan = skipWhitespace(scan);
  while (scan != NULL && *scan != '\0') {
    std::string name;
    ArgList args;

    // parse command name
    scan = skipWhitespace(scan);
    scan = readValue(scan, &name);
    if (scan != NULL)
      scan = skipWhitespace(scan);

    // parse arguments
    while (scan != NULL && *scan != '\0' && *scan != ';') {
      std::string value;
      scan = readValue(scan, &value);
      if (scan != NULL) {
	scan = skipWhitespace(scan);
	args.push_back(value);
      }
    }

    // run it or report error
    if (scan == NULL) {
      if (ret)
  	*ret = false;
      return std::string("Error parsing command");
    } else if (name[0] != '#') {
      result = run(name, args, ret);
    }

    // discard ; and empty commands
    while (scan != NULL && *scan == ';') {
      ++scan;
      scan = skipWhitespace(scan);
    }
  }

  // return result of last command only
  return result;
}

void				CommandManager::iterate(Callback callback,
							void* userData) const
{
  assert(callback != NULL);

  for (Commands::const_iterator index = commands.begin();
       index != commands.end(); ++index)
    (*callback)(index->first, userData);
}

const char*			CommandManager::readValue(const char* string,
							  std::string* value)
{
  if (*string == '\"')
    return readQuoted(string + 1, value);
  else if (*string != '\0')
    return readUnquoted(string, value);
  else
    return string;
}

const char*			CommandManager::readUnquoted(const char* string,
							     std::string* value)
{
  // read up to next whitespace.  escapes are not interpreted.
  const char* start = string;
  while (*string != '\0' && !isspace(*string) && *string != ';')
    ++string;
  *value = std::string(start, string - start);
  return string;
}

const char*			CommandManager::readQuoted(const char* string,
							   std::string* value)
{
  *value = "";
  bool escaped = false;
  for (; *string != '\0'; ++string) {
    if (escaped) {
      switch (*string) {
	case 't': value->append("\t", 1); break;
	case 'n': value->append("\n", 1); break;
	case 'r': value->append("\r", 1); break;
	case '\\': value->append("\\", 1); break;
	case '\"': value->append("\"", 1); break;
	default: value->append(string, 1); break;
      }
      escaped = false;
    } else if (*string == '\\') {
      escaped = true;
    } else if (*string == '\"') {
      return string + 1;
    } else {
      value->append(string, 1);
    }
  }
  // closing quote is missing.  if escaped is true the called may have
  // wanted to continue the line but we don't allow that.
  return NULL;
}

const char*			CommandManager::skipWhitespace(const char* string)
{
  while (*string != '\0' && isspace(*string))
    ++string;
  return string;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>make windows not choke on UTF8 sequences in the client config file.  since we aren't actually doing anything with the characters this routine doesn't actually need to be multibyte-aware.<commit_after>/* bzflag
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "CommandManager.h"

/* system implementation headers */
#include <ctype.h>
#include <wctype.h>
#include <stdio.h>
#include <assert.h>
#include <string>

/* common implementation headers */
#include "TextUtils.h"

// initialize the singleton
template <>
CommandManager* Singleton<CommandManager>::_instance = (CommandManager*)0;

CommandManager::CommandManager()
{
  // do nothing
}

CommandManager::~CommandManager()
{
  // do nothing
}

void				CommandManager::add(const std::string& name,
						    CommandFunction func,
						    const std::string& help)
{
  commands.erase(name);
  CmdInfo info;
  info.func = func;
  info.help = help;
  commands.insert(std::make_pair(name, info));
}

void				CommandManager::remove(const std::string& name)
{
  commands.erase(name);
}

std::string			CommandManager::getHelp(const std::string& name) const
{
  // look up command
  Commands::const_iterator index = commands.find(name);
  if (index == commands.end())
    return "";

  // return help string
  return index->second.help;
}

std::string			CommandManager::run(const std::string& name,
							    const ArgList& args, bool* ret) const
{
  // look up command
  Commands::const_iterator index = commands.find(name);
  if (index == commands.end()) {
    if (ret)
      *ret = false;
    return TextUtils::format("Command %s not found", name.c_str());
  }
  if (ret)
    *ret = true;
  // run it
  return (*index->second.func)(name, args,ret);
}

std::string			CommandManager::run(const std::string& cmd,bool *ret) const
{
  std::string result;
  const char* scan = cmd.c_str();

  scan = skipWhitespace(scan);
  while (scan != NULL && *scan != '\0') {
    std::string name;
    ArgList args;

    // parse command name
    scan = skipWhitespace(scan);
    scan = readValue(scan, &name);
    if (scan != NULL)
      scan = skipWhitespace(scan);

    // parse arguments
    while (scan != NULL && *scan != '\0' && *scan != ';') {
      std::string value;
      scan = readValue(scan, &value);
      if (scan != NULL) {
	scan = skipWhitespace(scan);
	args.push_back(value);
      }
    }

    // run it or report error
    if (scan == NULL) {
      if (ret)
  	*ret = false;
      return std::string("Error parsing command");
    } else if (name[0] != '#') {
      result = run(name, args, ret);
    }

    // discard ; and empty commands
    while (scan != NULL && *scan == ';') {
      ++scan;
      scan = skipWhitespace(scan);
    }
  }

  // return result of last command only
  return result;
}

void				CommandManager::iterate(Callback callback,
							void* userData) const
{
  assert(callback != NULL);

  for (Commands::const_iterator index = commands.begin();
       index != commands.end(); ++index)
    (*callback)(index->first, userData);
}

const char*			CommandManager::readValue(const char* string,
							  std::string* value)
{
  if (*string == '\"')
    return readQuoted(string + 1, value);
  else if (*string != '\0')
    return readUnquoted(string, value);
  else
    return string;
}

const char*			CommandManager::readUnquoted(const char* string,
							     std::string* value)
{
  // read up to next whitespace.  escapes are not interpreted.
  const char* start = string;
  while (*string != '\0' && !iswspace(*string) && *string != ';')
    ++string;
  *value = std::string(start, string - start);
  return string;
}

const char*			CommandManager::readQuoted(const char* string,
							   std::string* value)
{
  *value = "";
  bool escaped = false;
  for (; *string != '\0'; ++string) {
    if (escaped) {
      switch (*string) {
	case 't': value->append("\t", 1); break;
	case 'n': value->append("\n", 1); break;
	case 'r': value->append("\r", 1); break;
	case '\\': value->append("\\", 1); break;
	case '\"': value->append("\"", 1); break;
	default: value->append(string, 1); break;
      }
      escaped = false;
    } else if (*string == '\\') {
      escaped = true;
    } else if (*string == '\"') {
      return string + 1;
    } else {
      value->append(string, 1);
    }
  }
  // closing quote is missing.  if escaped is true the called may have
  // wanted to continue the line but we don't allow that.
  return NULL;
}

const char*			CommandManager::skipWhitespace(const char* string)
{
  while (*string != '\0' && isspace(*string))
    ++string;
  return string;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>