<commit_before>/*
 * Copyright (c) 2009 Roy Wellington IV
 *
 * 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 <stack>
#include <cstdlib>
#include <climits>
#include <sstream>

#include "json.h"
#include "utf8_private.h"

/* Throw an exception if the passed stream is in an errored state.
 */
void check_stream(std::istream &s)
{
	if(!s)
	{
		if(s.eof())
			throw json::ParseException("Unexpected EOF in input stream.");
		else
			throw json::ParseException("I/O error in input.");
	}
}

/* Read a string from a stream.
 * If we can't read the passed string from the stream, throw an exception.
 */
void read_string(std::istream &s, const std::string &str)
{
	std::string::const_iterator i;
	char c;

	for(i = str.begin(); i != str.end(); ++i)
	{
		s.get(c);
		check_stream(s);
		if(c != *i)
			throw json::ParseException("Expected \"" + str + "\" input, but didn't find it.");
	}
}

/* Attempt to read a character from a stream.
 * Return true, and remove it from the stream if it is present.
 * Otherwise, return false.
 */
bool try_to_read(std::istream &s, char c_want)
{
	char c_have;

	c_have = s.peek();
	check_stream(s);

	if(c_have == c_want)
	{
		s.ignore();
		check_stream(s);
		return true;
	}
	return false;
}

/* Read digits from a stream, ie: [0-9]* or [0-9]+
 * If need_one is true, we must read at least one digit ([0-9]+)
 * Otherwise, no digits is acceptable ([0-9]*)
 * If need_one is true, and we can't read any digits, throw an exception.
 */
void read_digits_from_stream(std::istream &s, std::string &str, bool need_one)
{
	while(true)
	{
		char c = s.peek();
		check_stream(s);

		if(c >= '0' && c <= '9')
		{
			s.ignore();
			check_stream(s);
			str += c;
			need_one = false;
		}
		else
			break;
	}

	if(need_one)
	{
		// We needed a digit, but one didn't get read...
		throw json::ParseException();
	}
}

/* Read a numeric value, either integer or floating point, from the stream.
 * Return it as a json::Value -- this will be either a json::Double or a
 * json::Integer.
 */
json::Value *read_json_numeric(std::istream &s)
{
	std::string numeric_text;
	char c;

	if(try_to_read(s, '-'))
		numeric_text += '-';

	if(!try_to_read(s, '0'))
	{
		// Read in whole digits
		c = s.peek();
		check_stream(s);
		if(!(c >= '1' && c <= '9'))
		{
			throw json::ParseException();
		}

		numeric_text += c;
		s.ignore();
		check_stream(s);

		read_digits_from_stream(s, numeric_text, false);
	}
	else
	{
		// It was a 0.
		numeric_text += '0';
	}

	if(try_to_read(s, '.'))
	{
		// A decimal point.
		numeric_text += '.';

		// Read the digits!
		read_digits_from_stream(s, numeric_text, true);
	}

	c = s.peek();
	check_stream(s);
	if(c == 'e' || c == 'E')
	{
		s.ignore();
		check_stream(s);
		numeric_text += 'e';

		read_digits_from_stream(s, numeric_text, true);
	}

	long long ll;
	char *endptr;

	ll = strtoll(numeric_text.c_str(), &endptr, 10);
	if(endptr == numeric_text.c_str() + numeric_text.size())
	{
		// Yay, a number.
		if(ll <= INT_MAX && ll >= INT_MIN)
		{
			return new json::Integer(ll);
		}
		else return new json::Integer64(ll);
	}

	double d;

	d = strtod(numeric_text.c_str(), &endptr);
	if(endptr == numeric_text.c_str() + numeric_text.size())
	{
		return new json::Double(d);
	}

	throw json::ParseException();
}

/* Read a JSON string from a stream. This returns the actual string, and not
 * a json::String as it gets used to read keys in objects as well.
 * A JSON string is:
 *   "text... "
 * ie, an opening quote, characters, a closing quote. There are some escape
 * sequences for things like quotes or slashes.
 */
std::string read_json_string_basic(std::istream &s)
{
	char c;
	std::string text;

	// Read opening quote.
	c = s.get();
	if(!s || c != '\"')
		throw json::ParseException();

	while(true)
	{
		c = s.get();
		check_stream(s);

		if(c == '\"')
			break;

		// Characters below 0x20 must be escaped.
		if(c < 0x20)
			throw json::ParseException();

		if(c == '\\')
		{
			char escape_code = s.get();
			check_stream(s);

			if(escape_code == '\"')
				text += '\"';
			else if(escape_code == '\\')
				text += '\\';
			else if(escape_code == '/')
				text += '/';
			else if(escape_code == 'b')
				text += 0x08;
			else if(escape_code == 'f')
				text += 0x0C;
			else if(escape_code == 'n')
				text += '\n';
			else if(escape_code == 'r')
				text += '\r';
			else if(escape_code == 't')
				text += '\t';
			else if(escape_code == 'u')
			{
				char four_hex[5] = {0};
				for(int i = 0; i < 4; ++i)
				{
					four_hex[i] = s.get();
					check_stream(s);
					if(!((four_hex[i] >= '0' && four_hex[i] <= '9')
						|| (four_hex[i] >= 'A' && four_hex[i] <= 'F')
						|| (four_hex[i] >= 'a' && four_hex[i] <= 'f')))
					{
						throw json::ParseException();
					}
				}

				unsigned int code = strtoul(four_hex, NULL, 16);
				text += to_utf8(code);
			}
			else
				throw json::ParseException();
		}
		else
			text += c;
	}

	check_is_valid_utf8(text);
	return text;
}

/* Remove as much whitespace (tabs, newlines, carriage returns or spaces)
 * from the front of a string as possible.
 */
void eat_whitespace(std::istream &s)
{
	char c;

	while(true)
	{
		c = s.peek();
		check_stream(s);

		if(c == ' ' || c == '\t' || c == '\r' || c == '\n')
		{
			s.ignore();
			check_stream(s);
		}
		else
			break;
	}
}

json::Value *read_json_object_or_array(std::istream &s)
{
	char c;

	c = s.peek();
	check_stream(s);

	if(c == '[')
	{
		s.ignore();
		check_stream(s);
		eat_whitespace(s);
		return new json::Array();
	}
	else if(c == '{')
	{
		s.ignore();
		check_stream(s);
		eat_whitespace(s);
		return new json::Object();
	}
	else
		throw json::ParseException();
}

json::Value *read_json_value(std::istream &s)
{
	char c;
	c = s.peek();
	check_stream(s);

	if(c == 'n')
	{
		read_string(s, "null");
		return new json::Null();
	}
	else if(c == 't')
	{
		read_string(s, "true");
		return new json::Bool(true);
	}
	else if(c == 'f')
	{
		read_string(s, "false");
		return new json::Bool(false);
	}
	else if(c == '\"')
	{
		std::string str;
		str = read_json_string_basic(s);
		return new json::String(str);
	}
	else if(c == '-'
		|| (c >= '0' && c <= '9'))
	{
		return read_json_numeric(s);
	}
	else return read_json_object_or_array(s);
}

void parse_item(std::istream &s, std::stack<json::Value *> &struct_stack)
{
	// Get the object/array:
	json::Array *arr = NULL;
	json::Object *obj = NULL;
	if(struct_stack.top()->type() == json::TYPE_ARRAY)
		arr = dynamic_cast<json::Array *>(struct_stack.top());
	else
		obj = dynamic_cast<json::Object *>(struct_stack.top());

	// See if we've reached the end:
	char c = s.peek();
	check_stream(s);
	if((arr && c == ']')
		|| (obj && c == '}'))
	{
		s.ignore();
		check_stream(s);
		struct_stack.pop();

		if(!struct_stack.empty())
		{
			eat_whitespace(s);
		}

		return;
	}

	// Check for a comma:
	if((arr && !arr->empty())
		|| (obj && !obj->empty()))
	{
		if(c != ',')
			throw json::ParseException("Expected \',\' token.");

		s.ignore();
		check_stream(s);
		eat_whitespace(s);
	}

	// Read in a key if this is an object
	std::string key;
	if(obj)
	{
		key = read_json_string_basic(s);
		eat_whitespace(s);
		char colon = s.get();
		check_stream(s);
		if(colon != ':')
			throw json::ParseException("Expected \':\' token.");
		eat_whitespace(s);
	}

	// Read in the actual value:
	json::Value *v = NULL;
	try
	{
		v = read_json_value(s);
		if(arr)
			arr->pushBackTake(v);
		else
			obj->takeValue(key, v);
	}
	catch(...)
	{
		delete v;
		throw;
	}

	if(v->type() == json::TYPE_ARRAY
		|| v->type() == json::TYPE_OBJECT)
	{
		struct_stack.push(v);
	}

	eat_whitespace(s);
}

json::Value *json::parse(std::istream &s)
{
	std::stack<json::Value *> struct_stack;
	json::Value *base_object = NULL;

	eat_whitespace(s);
	try
	{
		struct_stack.push(base_object = read_json_object_or_array(s));

		while(!struct_stack.empty())
		{
			parse_item(s, struct_stack);
		}
	}
	catch(...)
	{
		delete base_object;
		throw;
	}
	return base_object;
}

json::Value *json::parse(const std::string &s)
{
	std::stringstream ss;

	ss.str(s);
	return json::parse(ss);
}
<commit_msg>More comments in source.<commit_after>/*
 * Copyright (c) 2009 Roy Wellington IV
 *
 * 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 <stack>
#include <cstdlib>
#include <climits>
#include <sstream>

#include "json.h"
#include "utf8_private.h"

/* Throw an exception if the passed stream is in an errored state.
 */
void check_stream(std::istream &s)
{
	if(!s)
	{
		if(s.eof())
			throw json::ParseException("Unexpected EOF in input stream.");
		else
			throw json::ParseException("I/O error in input.");
	}
}

/* Read a string from a stream.
 * If we can't read the passed string from the stream, throw an exception.
 */
void read_string(std::istream &s, const std::string &str)
{
	std::string::const_iterator i;
	char c;

	for(i = str.begin(); i != str.end(); ++i)
	{
		s.get(c);
		check_stream(s);
		if(c != *i)
			throw json::ParseException("Expected \"" + str + "\" input, but didn't find it.");
	}
}

/* Attempt to read a character from a stream.
 * Return true, and remove it from the stream if it is present.
 * Otherwise, return false.
 */
bool try_to_read(std::istream &s, char c_want)
{
	char c_have;

	c_have = s.peek();
	check_stream(s);

	if(c_have == c_want)
	{
		s.ignore();
		check_stream(s);
		return true;
	}
	return false;
}

/* Read digits from a stream, ie: [0-9]* or [0-9]+
 * If need_one is true, we must read at least one digit ([0-9]+)
 * Otherwise, no digits is acceptable ([0-9]*)
 * If need_one is true, and we can't read any digits, throw an exception.
 */
void read_digits_from_stream(std::istream &s, std::string &str, bool need_one)
{
	while(true)
	{
		char c = s.peek();
		check_stream(s);

		if(c >= '0' && c <= '9')
		{
			s.ignore();
			check_stream(s);
			str += c;
			need_one = false;
		}
		else
			break;
	}

	if(need_one)
	{
		// We needed a digit, but one didn't get read...
		throw json::ParseException();
	}
}

/* Read a numeric value, either integer or floating point, from the stream.
 * Return it as a json::Value -- this will be either a json::Double or a
 * json::Integer.
 */
json::Value *read_json_numeric(std::istream &s)
{
	std::string numeric_text;
	char c;

	if(try_to_read(s, '-'))
		numeric_text += '-';

	if(!try_to_read(s, '0'))
	{
		// Read in whole digits
		c = s.peek();
		check_stream(s);
		if(!(c >= '1' && c <= '9'))
		{
			throw json::ParseException();
		}

		numeric_text += c;
		s.ignore();
		check_stream(s);

		read_digits_from_stream(s, numeric_text, false);
	}
	else
	{
		// It was a 0.
		numeric_text += '0';
	}

	if(try_to_read(s, '.'))
	{
		// A decimal point.
		numeric_text += '.';

		// Read the digits!
		read_digits_from_stream(s, numeric_text, true);
	}

	c = s.peek();
	check_stream(s);
	if(c == 'e' || c == 'E')
	{
		s.ignore();
		check_stream(s);
		numeric_text += 'e';

		read_digits_from_stream(s, numeric_text, true);
	}

	long long ll;
	char *endptr;

	ll = strtoll(numeric_text.c_str(), &endptr, 10);
	if(endptr == numeric_text.c_str() + numeric_text.size())
	{
		// Yay, a number.
		if(ll <= INT_MAX && ll >= INT_MIN)
		{
			return new json::Integer(ll);
		}
		else return new json::Integer64(ll);
	}

	double d;

	d = strtod(numeric_text.c_str(), &endptr);
	if(endptr == numeric_text.c_str() + numeric_text.size())
	{
		return new json::Double(d);
	}

	throw json::ParseException();
}

/* Read a JSON string from a stream. This returns the actual string, and not
 * a json::String as it gets used to read keys in objects as well.
 * A JSON string is:
 *   "text... "
 * ie, an opening quote, characters, a closing quote. There are some escape
 * sequences for things like quotes or slashes.
 */
std::string read_json_string_basic(std::istream &s)
{
	char c;
	std::string text;

	// Read opening quote.
	c = s.get();
	if(!s || c != '\"')
		throw json::ParseException();

	while(true)
	{
		c = s.get();
		check_stream(s);

		if(c == '\"')
			break;

		// Characters below 0x20 must be escaped.
		if(c < 0x20)
			throw json::ParseException();

		if(c == '\\')
		{
			char escape_code = s.get();
			check_stream(s);

			if(escape_code == '\"')
				text += '\"';
			else if(escape_code == '\\')
				text += '\\';
			else if(escape_code == '/')
				text += '/';
			else if(escape_code == 'b')
				text += 0x08;
			else if(escape_code == 'f')
				text += 0x0C;
			else if(escape_code == 'n')
				text += '\n';
			else if(escape_code == 'r')
				text += '\r';
			else if(escape_code == 't')
				text += '\t';
			else if(escape_code == 'u')
			{
				char four_hex[5] = {0};
				for(int i = 0; i < 4; ++i)
				{
					four_hex[i] = s.get();
					check_stream(s);
					if(!((four_hex[i] >= '0' && four_hex[i] <= '9')
						|| (four_hex[i] >= 'A' && four_hex[i] <= 'F')
						|| (four_hex[i] >= 'a' && four_hex[i] <= 'f')))
					{
						throw json::ParseException();
					}
				}

				unsigned int code = strtoul(four_hex, NULL, 16);
				text += to_utf8(code);
			}
			else
				throw json::ParseException();
		}
		else
			text += c;
	}

	check_is_valid_utf8(text);
	return text;
}

/* Remove as much whitespace (tabs, newlines, carriage returns or spaces)
 * from the front of a string as possible.
 */
void eat_whitespace(std::istream &s)
{
	char c;

	while(true)
	{
		c = s.peek();
		check_stream(s);

		if(c == ' ' || c == '\t' || c == '\r' || c == '\n')
		{
			s.ignore();
			check_stream(s);
		}
		else
			break;
	}
}

/* Read in a JSON object or array start marker from the stream,
 * and create and return a JSON object/array to store it.
 */
json::Value *read_json_object_or_array(std::istream &s)
{
	char c;

	c = s.peek();
	check_stream(s);

	if(c == '[')
	{
		s.ignore();
		check_stream(s);
		eat_whitespace(s);
		return new json::Array();
	}
	else if(c == '{')
	{
		s.ignore();
		check_stream(s);
		eat_whitespace(s);
		return new json::Object();
	}
	else
		throw json::ParseException();
}

/* Read in a JSON value from the stream. We should be positioned right before
 * it.
 */
json::Value *read_json_value(std::istream &s)
{
	// Peek a character - this tells us what type we're looking at.
	// All the JSON primitives differ in their first character.
	char c;
	c = s.peek();
	check_stream(s);

	if(c == 'n')
	{
		read_string(s, "null");
		return new json::Null();
	}
	else if(c == 't')
	{
		read_string(s, "true");
		return new json::Bool(true);
	}
	else if(c == 'f')
	{
		read_string(s, "false");
		return new json::Bool(false);
	}
	else if(c == '\"')
	{
		std::string str;
		str = read_json_string_basic(s);
		return new json::String(str);
	}
	else if(c == '-'
		|| (c >= '0' && c <= '9'))
	{
		return read_json_numeric(s);
	}
	// By now, it should be an array or an object -- this function will throw
	// if it isn't.
	else return read_json_object_or_array(s);
}

void parse_item(std::istream &s, std::stack<json::Value *> &struct_stack)
{
	// Get the object/array:
	json::Array *arr = NULL;
	json::Object *obj = NULL;
	if(struct_stack.top()->type() == json::TYPE_ARRAY)
		arr = dynamic_cast<json::Array *>(struct_stack.top());
	else
		obj = dynamic_cast<json::Object *>(struct_stack.top());

	// See if we've reached the end:
	char c = s.peek();
	check_stream(s);
	if((arr && c == ']')
		|| (obj && c == '}'))
	{
		s.ignore();
		check_stream(s);
		struct_stack.pop();

		if(!struct_stack.empty())
		{
			eat_whitespace(s);
		}

		return;
	}

	// Check for a comma:
	if((arr && !arr->empty())
		|| (obj && !obj->empty()))
	{
		if(c != ',')
			throw json::ParseException("Expected \',\' token.");

		s.ignore();
		check_stream(s);
		eat_whitespace(s);
	}

	// Read in a key if this is an object
	std::string key;
	if(obj)
	{
		key = read_json_string_basic(s);
		eat_whitespace(s);
		char colon = s.get();
		check_stream(s);
		if(colon != ':')
			throw json::ParseException("Expected \':\' token.");
		eat_whitespace(s);
	}

	// Read in the actual value:
	json::Value *v = NULL;
	try
	{
		v = read_json_value(s);
		if(arr)
			arr->pushBackTake(v);
		else
			obj->takeValue(key, v);
	}
	catch(...)
	{
		delete v;
		throw;
	}

	if(v->type() == json::TYPE_ARRAY
		|| v->type() == json::TYPE_OBJECT)
	{
		struct_stack.push(v);
	}

	eat_whitespace(s);
}

json::Value *json::parse(std::istream &s)
{
	std::stack<json::Value *> struct_stack;
	json::Value *base_object = NULL;

	eat_whitespace(s);
	try
	{
		struct_stack.push(base_object = read_json_object_or_array(s));

		while(!struct_stack.empty())
		{
			parse_item(s, struct_stack);
		}
	}
	catch(...)
	{
		delete base_object;
		throw;
	}
	return base_object;
}

json::Value *json::parse(const std::string &s)
{
	std::stringstream ss;

	ss.str(s);
	return json::parse(ss);
}
<|endoftext|>


<commit_before>#include <stack>
#include <memory>

#define PARSER_H

#ifndef SCANNER_H
#include "scanner.hpp"
#endif

#include "util.hpp"

namespace CS {

        using std::pair;
        using std::string;
        using std::vector;
        using std::shared_ptr;

        class TokenNode;
        typedef TokenNode SyntaxTree;

        class TokenNode {
            public:
                /* constructors */
                TokenNode(const string& token_value, int token_type):
                    value_(token_value),
                    type_(token_type),
                    left_(nullptr),
                    right_(nullptr),
                    next_(nullptr) {
                    }

                TokenNode():
                    TokenNode("", 0) {
                    }

                TokenNode(const TokenPair& token):
                    TokenNode(token.first, token.second) {
                    }

                ~TokenNode() {
                    if (left_ != nullptr) {
                        left_->~TokenNode();
                        delete left_;
                    }
                    if (right_ != nullptr) {
                        right_->~TokenNode();
                        delete right_;
                    }
                    if (next_ != nullptr) {
                        next_->~TokenNode();
                        delete next_;
                    }
                }

                /* operations */
                void PushLeft(TokenNode* node) {
                    left_ = node;
                }

                void PushRight(TokenNode* node) {
                    right_ = node;
                }

                void PushNext(TokenNode* node) {
                    next_ = node;
                }

                void PushFront(TokenNode* node) {
                    if (this->next_ == nullptr) {
                        this->next_ = node;
                    } else {
                        node->next_ = this->next_;
                        this->next_ = node;
                    }
                }

                string value_;
                int type_;
                TokenNode* left_;
                TokenNode* right_;
                TokenNode* next_;
        };

        class Parser {

            public:
                // trivial constructor
                Parser():token_list_(nullptr), token_parsed_(0) {}

                SyntaxTree* Parse(TokenList& token_list) {
                    token_list_ = &token_list;
                    token_parsed_ = 0;
                    SyntaxTree root;
                    TokenNode* cursor = &root;

                    while (HasNext()) {
                        int position = Position();
                        if (IsStatement(position)) {
                            cursor->PushNext(Statement());
                        } else if (IsAssignment(position)) {
                            cursor->PushNext(Assignment());
                        } else {
                            cursor->PushNext(Expression());
                        }
                        SkipToken(";");
                        cursor = cursor->next_;
                    }
                    return root.next_;
                }

            private:
                // helper functions

                // does not need position, so these functions could be called through a single token without position
                inline bool IsOperator(int index) {
                    return IsOperator(GetToken(index));
                }

                inline bool IsOperator(const TokenPair& token) {
                    return Scanner::IsOperator(token.first);
                }

                inline bool IsOperator(const string& value) {
                    return Scanner::IsOperator(value);
                }

                inline bool IsBinaryOperator(int index) {
                    return IsBinaryOperator(GetToken(index));
                }

                inline bool IsBinaryOperator(const TokenPair& token) {
                    return IsOperator(token) &&
                        token.first != "\"" &&
                        token.first != ";";
                }

                inline bool IsBinaryOperator(const string& value) {
                    return Scanner::IsOperator(value) &&
                        value != "\"" &&
                        value != ";";
                }

                inline bool IsNumber(int index) {
                    return IsNumber(GetToken(index));
                }

                inline bool IsNumber(const TokenPair& token){
                    return token.second == GetId("int") ||
                        token.second == GetId("double");
                }

                inline bool IsIdentifier(int index) {
                    return IsIdentifier(GetToken(index));
                }

                inline bool IsIdentifier(const TokenPair& token) {
                    return token.second == 53;
                }
                // need the help of position
                bool IsStatement(int index) {
                    auto& token = GetToken(index);
                    return (token.second == 36 ||
                            token.second == 37) &&
                        HasNext(index) &&
                        IsIdentifier(index+1);
                }

                bool IsAssignment(int index) {
                    auto& token = GetToken(index);
                    return IsIdentifier(index) &&
                        HasNext(index) &&
                        NextToken(index).first == "=";
                }

                bool IsCall(int index) {
                    auto& token = GetToken(index);
                    return IsIdentifier(index) &&
                        HasNext(index) &&
                        NextToken(index).first == "(";
                }

                bool IsValue(int index) {
                    auto& token = GetToken(index);
                    return (token.first == "(" &&
                            HasNext(index) &&
                            IsValue(index+1)) ||
                        IsNumber(index) ||
                        IsIdentifier(index) ||
                        IsCall(index);
                }

                // control the token list
                inline void Next() {
                    ++token_parsed_;
                }

                inline void Prev() {
                    --token_parsed_;
                }

                inline int Position() {
                    return token_parsed_;
                }

                inline pair<string, int>& NextToken() {
                    return (*token_list_)[token_parsed_+1];
                }

                inline pair<string, int>& NextToken(int index) {
                    return (*token_list_)[index+1];
                }

                inline pair<string, int>& Consume() {
                    return (*token_list_)[token_parsed_++];
                }

                inline pair<string, int>& GetToken() {
                    return (*token_list_)[token_parsed_];
                }

                inline pair<string, int>& GetToken(int index) {
                    return (*token_list_)[index];
                }

                inline bool HasNext() {
                    return token_parsed_ < token_list_->size();
                }

                inline bool HasNext(int index) {
                    return index < token_list_->size();
                }

                void SkipToken(const char* token) {
                    assert(Consume().first == token);
                }

                // operator priority

                int Priority(char ch) {
                    switch (ch) {
                        case '+':
                        case '-':
                            return 1;
                        case '*':
                        case '/':
                        case '%':
                            return 2;
                        case '(':
                            return 3;
                        default:
                            assert(false);
                    }
                }

                // main force

                SyntaxTree* Statement() {
                    SyntaxTree* type = new SyntaxTree(Consume());
                    TokenNode* id = new SyntaxTree(Consume());
                    type->PushLeft(id);
                    return type;
                }

                SyntaxTree* Assignment() {
                    SyntaxTree* id = new SyntaxTree(Consume());
                    TokenNode* equal = new SyntaxTree(Consume());
                    TokenNode* expr = Expression();
                    equal->PushLeft(id);
                    equal->PushRight(expr);
                    return equal;
                }

                TokenNode* Arguments() {
                    TokenNode* root = nullptr;
                    enum State { ZERO, ONE, TWO };
                    State state = ZERO;
                    while (HasNext() && state != TWO) {
                        int position = Position();
                        switch (state) {
                            case ZERO:
                                if (IsValue(position)) {
                                    if (root == nullptr)
                                        root = Value();
                                    else
                                        root->PushFront(Value());
                                    state = TWO;
                                } else {
                                    std::cerr << "not a value" << std::endl;
                                    exit(3);
                                }
                                break;
                            case ONE:
                                if (GetToken().first == ",") {
                                    SkipToken(",");
                                    state = ZERO;
                                } else {
                                    state = TWO;
                                }
                                break;
                            case TWO:
                                goto end;
                            default:
                                assert(false);
                        }
                    }
end:
                    return root;
                }

                TokenNode* Value() {
                    auto& token = GetToken();
                    TokenNode* node;
                    if (token.first == "(") {
                        SkipToken("(");
                        node = Value();
                        SkipToken(")");
                    } else {
                        if (IsNumber(Position())) {
                            node = new TokenNode(Consume());
                        } else if (IsCall(Position())) {
                            node = new TokenNode;
                            node->type_ = GetId("call_type");
                            // function identifier
                            node->PushLeft(new TokenNode(Consume()));
                            // '('
                            SkipToken("(");
                            // expr
                            node->PushRight(Arguments());
                            // ')'
                            SkipToken(")");
                        } else if (IsIdentifier(Position())) {
                            node = new TokenNode(Consume());
                        } else {
                            std::cerr << "not a value" << std::endl;
                            exit(3);
                        }
                    }
                    return node;
                }

                SyntaxTree* Expression() {
                    std::vector<TokenNode*> tokens;
                    enum State { ZERO, ONE, TWO};
                    State state = ZERO;
                    while (HasNext() && state != TWO) {
                        int position = Position();
                        switch (state) {
                            case ZERO:
                                if (IsValue(position)) {
                                    tokens.push_back(Value());
                                } else {
                                    std::cerr << "not a value:\t\'" << GetToken(position).first << "\'"<< std::endl;
                                    exit(2);
                                }
                                state = ONE;
                                break;
                            case ONE:
                                if (IsBinaryOperator(position)) {
                                    tokens.push_back(new TokenNode(Consume()));
                                    state = ZERO;
                                } else {
                                    state = TWO;
                                }
                                break;
                            case TWO:
                            default:
                                assert(false);
                        }
                    }
                    // convert it to postfix
                    std::vector<TokenNode*> postfix;
                    std::stack<TokenNode*> operators;
                    for (auto node : tokens) {
                        char ch = node->value_.front();
                        if (IsBinaryOperator(node->value_)) {
                            while (!operators.empty() && operators.top()->value_ != "(" &&
                                    Priority(ch) <= Priority(operators.top()->value_.front())) {
                                postfix.push_back(operators.top()), operators.pop();
                            }
                            operators.push(node);
                        } else {
                            postfix.push_back(node);
                        }
                    }
                    while (!operators.empty())
                        postfix.push_back(operators.top()), operators.pop();

                    // construct syntax tree from postfix expression
                    std::stack<TokenNode*> node_stack;
                    for (auto &node : postfix) {
                        if (IsOperator(node->value_)) {
                            TokenNode* rhs = node_stack.top();
                            node_stack.pop();
                            TokenNode* lhs = node_stack.top();
                            node_stack.pop();
                            node->PushLeft(lhs);
                            node->PushRight(rhs);
                            node_stack.push(node);
                        } else {
                            node_stack.push(node);
                        }
                    }
                    return node_stack.top();
                }

                TokenList* token_list_;
                int token_parsed_;
        };
}
<commit_msg>solve the memory leak problem<commit_after>#include <stack>
#include <memory>

#define PARSER_H

#ifndef SCANNER_H
#include "scanner.hpp"
#endif

#include "util.hpp"

namespace CS {

        using std::pair;
        using std::string;
        using std::vector;
        using std::shared_ptr;

        class TokenNode;
        typedef TokenNode SyntaxTree;

        class TokenNode {
            public:
                /* constructors */
                TokenNode(const string& token_value, int token_type):
                    value_(token_value),
                    type_(token_type),
                    left_(nullptr),
                    right_(nullptr),
                    next_(nullptr) {
                    }

                TokenNode():
                    TokenNode("", 0) {
                    }

                TokenNode(const TokenPair& token):
                    TokenNode(token.first, token.second) {
                    }

                ~TokenNode() {
                    if (left_) delete left_;
                    if (right_) delete right_;
                    if (next_) delete next_;
                }

                /* operations */
                void PushLeft(TokenNode* node) {
                    left_ = node;
                }

                void PushRight(TokenNode* node) {
                    right_ = node;
                }

                void PushNext(TokenNode* node) {
                    next_ = node;
                }

                void PushFront(TokenNode* node) {
                    if (this->next_ == nullptr) {
                        this->next_ = node;
                    } else {
                        node->next_ = this->next_;
                        this->next_ = node;
                    }
                }

                string value_;
                int type_;
                TokenNode* left_;
                TokenNode* right_;
                TokenNode* next_;
        };

        class Parser {

            public:
                // trivial constructor
                Parser():token_list_(nullptr), token_parsed_(0) {}

                SyntaxTree* Parse(TokenList& token_list) {
                    token_list_ = &token_list;
                    token_parsed_ = 0;
                    SyntaxTree guard;
                    TokenNode* cursor = &guard;

                    while (HasNext()) {
                        int position = Position();
                        if (IsStatement(position)) {
                            cursor->PushNext(Statement());
                        } else if (IsAssignment(position)) {
                            cursor->PushNext(Assignment());
                        } else {
                            cursor->PushNext(Expression());
                        }
                        SkipToken(";");
                        cursor = cursor->next_;
                    }

                    /* to protect the tree be destructed by the destruction of 'guard' */
                    TokenNode* res = guard.next_;
                    guard.next_ = nullptr;
                    return res;
                }

            private:
                // helper functions

                // does not need position, so these functions could be called through a single token without position
                inline bool IsOperator(int index) {
                    return IsOperator(GetToken(index));
                }

                inline bool IsOperator(const TokenPair& token) {
                    return Scanner::IsOperator(token.first);
                }

                inline bool IsOperator(const string& value) {
                    return Scanner::IsOperator(value);
                }

                inline bool IsBinaryOperator(int index) {
                    return IsBinaryOperator(GetToken(index));
                }

                inline bool IsBinaryOperator(const TokenPair& token) {
                    return IsOperator(token) &&
                        token.first != "\"" &&
                        token.first != ";";
                }

                inline bool IsBinaryOperator(const string& value) {
                    return Scanner::IsOperator(value) &&
                        value != "\"" &&
                        value != ";";
                }

                inline bool IsNumber(int index) {
                    return IsNumber(GetToken(index));
                }

                inline bool IsNumber(const TokenPair& token){
                    return token.second == GetId("int") ||
                        token.second == GetId("double");
                }

                inline bool IsIdentifier(int index) {
                    return IsIdentifier(GetToken(index));
                }

                inline bool IsIdentifier(const TokenPair& token) {
                    return token.second == 53;
                }
                // need the help of position
                bool IsStatement(int index) {
                    auto& token = GetToken(index);
                    return (token.second == 36 ||
                            token.second == 37) &&
                        HasNext(index) &&
                        IsIdentifier(index+1);
                }

                bool IsAssignment(int index) {
                    auto& token = GetToken(index);
                    return IsIdentifier(index) &&
                        HasNext(index) &&
                        NextToken(index).first == "=";
                }

                bool IsCall(int index) {
                    auto& token = GetToken(index);
                    return IsIdentifier(index) &&
                        HasNext(index) &&
                        NextToken(index).first == "(";
                }

                bool IsValue(int index) {
                    auto& token = GetToken(index);
                    return (token.first == "(" &&
                            HasNext(index) &&
                            IsValue(index+1)) ||
                        IsNumber(index) ||
                        IsIdentifier(index) ||
                        IsCall(index);
                }

                // control the token list
                inline void Next() {
                    ++token_parsed_;
                }

                inline void Prev() {
                    --token_parsed_;
                }

                inline int Position() {
                    return token_parsed_;
                }

                inline pair<string, int>& NextToken() {
                    return (*token_list_)[token_parsed_+1];
                }

                inline pair<string, int>& NextToken(int index) {
                    return (*token_list_)[index+1];
                }

                inline pair<string, int>& Consume() {
                    return (*token_list_)[token_parsed_++];
                }

                inline pair<string, int>& GetToken() {
                    return (*token_list_)[token_parsed_];
                }

                inline pair<string, int>& GetToken(int index) {
                    return (*token_list_)[index];
                }

                inline bool HasNext() {
                    return token_parsed_ < token_list_->size();
                }

                inline bool HasNext(int index) {
                    return index < token_list_->size();
                }

                void SkipToken(const char* token) {
                    assert(Consume().first == token);
                }

                // operator priority

                int Priority(char ch) {
                    switch (ch) {
                        case '+':
                        case '-':
                            return 1;
                        case '*':
                        case '/':
                        case '%':
                            return 2;
                        case '(':
                            return 3;
                        default:
                            assert(false);
                    }
                }

                // main force

                SyntaxTree* Statement() {
                    SyntaxTree* type = new SyntaxTree(Consume());
                    TokenNode* id = new SyntaxTree(Consume());
                    type->PushLeft(id);
                    return type;
                }

                SyntaxTree* Assignment() {
                    SyntaxTree* id = new SyntaxTree(Consume());
                    TokenNode* equal = new SyntaxTree(Consume());
                    TokenNode* expr = Expression();
                    equal->PushLeft(id);
                    equal->PushRight(expr);
                    return equal;
                }

                TokenNode* Arguments() {
                    TokenNode* root = nullptr;
                    enum State { ZERO, ONE, TWO };
                    State state = ZERO;
                    while (HasNext() && state != TWO) {
                        int position = Position();
                        switch (state) {
                            case ZERO:
                                if (IsValue(position)) {
                                    if (root == nullptr)
                                        root = Value();
                                    else
                                        root->PushFront(Value());
                                    state = TWO;
                                } else {
                                    std::cerr << "not a value" << std::endl;
                                    exit(3);
                                }
                                break;
                            case ONE:
                                if (GetToken().first == ",") {
                                    SkipToken(",");
                                    state = ZERO;
                                } else {
                                    state = TWO;
                                }
                                break;
                            case TWO:
                                goto end;
                            default:
                                assert(false);
                        }
                    }
end:
                    return root;
                }

                TokenNode* Value() {
                    auto& token = GetToken();
                    TokenNode* node;
                    if (token.first == "(") {
                        SkipToken("(");
                        node = Value();
                        SkipToken(")");
                    } else {
                        if (IsNumber(Position())) {
                            node = new TokenNode(Consume());
                        } else if (IsCall(Position())) {
                            node = new TokenNode;
                            node->type_ = GetId("call_type");
                            // function identifier
                            node->PushLeft(new TokenNode(Consume()));
                            // '('
                            SkipToken("(");
                            // expr
                            node->PushRight(Arguments());
                            // ')'
                            SkipToken(")");
                        } else if (IsIdentifier(Position())) {
                            node = new TokenNode(Consume());
                        } else {
                            std::cerr << "not a value" << std::endl;
                            exit(3);
                        }
                    }
                    return node;
                }

                SyntaxTree* Expression() {
                    std::vector<TokenNode*> tokens;
                    enum State { ZERO, ONE, TWO};
                    State state = ZERO;
                    while (HasNext() && state != TWO) {
                        int position = Position();
                        switch (state) {
                            case ZERO:
                                if (IsValue(position)) {
                                    tokens.push_back(Value());
                                } else {
                                    std::cerr << "not a value:\t\'" << GetToken(position).first << "\'"<< std::endl;
                                    exit(2);
                                }
                                state = ONE;
                                break;
                            case ONE:
                                if (IsBinaryOperator(position)) {
                                    tokens.push_back(new TokenNode(Consume()));
                                    state = ZERO;
                                } else {
                                    state = TWO;
                                }
                                break;
                            case TWO:
                            default:
                                assert(false);
                        }
                    }
                    // convert it to postfix
                    std::vector<TokenNode*> postfix;
                    std::stack<TokenNode*> operators;
                    for (auto node : tokens) {
                        char ch = node->value_.front();
                        if (IsBinaryOperator(node->value_)) {
                            while (!operators.empty() && operators.top()->value_ != "(" &&
                                    Priority(ch) <= Priority(operators.top()->value_.front())) {
                                postfix.push_back(operators.top()), operators.pop();
                            }
                            operators.push(node);
                        } else {
                            postfix.push_back(node);
                        }
                    }
                    while (!operators.empty())
                        postfix.push_back(operators.top()), operators.pop();

                    // construct syntax tree from postfix expression
                    std::stack<TokenNode*> node_stack;
                    for (auto &node : postfix) {
                        if (IsOperator(node->value_)) {
                            TokenNode* rhs = node_stack.top();
                            node_stack.pop();
                            TokenNode* lhs = node_stack.top();
                            node_stack.pop();
                            node->PushLeft(lhs);
                            node->PushRight(rhs);
                            node_stack.push(node);
                        } else {
                            node_stack.push(node);
                        }
                    }
                    return node_stack.top();
                }

                TokenList* token_list_;
                int token_parsed_;
        };
}
<|endoftext|>


<commit_before>//Author: Julian Yi
//Date Created: 18 July 2017
//File Description: .cpp file for Pieces
#include <iostream>
#include <string>
#include "pieces.h"
#include "board.h"
#include "pawn.h"
#include "defs.h"

using namespace std;

Pieces::Pieces() : team(TeamColor::None), type(PieceType::None), position({0, 0}) { }

void Pieces::increaseMove()
{
	moveCounter++;
}

int Pieces::getMove()
{
	return moveCounter;
}

void Pieces::setPosition(coord newPos)
{
	position = newPos;
}

coord Pieces::getPosition() const
{
	return position;
}

TeamColor Pieces::getTeamColor() const
{
	return team;
}

PieceType Pieces::getPieceType() const
{
	return type;
}

coordList Pieces::calculateMoves(coord boundary, const squareGrid& square) const
{
	coordList moveList;
	return moveList;
}
<commit_msg>Changed Pieces initialization list order<commit_after>//Author: Julian Yi
//Date Created: 18 July 2017
//File Description: .cpp file for Pieces
#include <iostream>
#include <string>
#include "pieces.h"
#include "board.h"
#include "pawn.h"
#include "defs.h"

using namespace std;

Pieces::Pieces() : position({0, 0}), team(TeamColor::None), type(PieceType::None)  { }

void Pieces::increaseMove()
{
	moveCounter++;
}

int Pieces::getMove()
{
	return moveCounter;
}

void Pieces::setPosition(coord newPos)
{
	position = newPos;
}

coord Pieces::getPosition() const
{
	return position;
}

TeamColor Pieces::getTeamColor() const
{
	return team;
}

PieceType Pieces::getPieceType() const
{
	return type;
}

coordList Pieces::calculateMoves(coord boundary, const squareGrid& square) const
{
	coordList moveList;
	return moveList;
}
<|endoftext|>


<commit_before>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

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

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

    You should have received a copy of the GNU General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "world.hpp"

using namespace the_decomposition_of_the_world_into_blocks_impl;

namespace the_decomposition_of_the_world_into_blocks_impl {

  // Water that starts out in a worldblock starts out inactive (observing the rule "the landscape takes zero time to process").
  //
  // We would have to make special rules for worldblocks that start out with
  // active water in them, because it could invalidate iterators into the
  // active_water_tiles map, because worldblocks can be created essentially any time in the processing.
  //
  // If we try to use a level-X value from a worldblock while it's busy computing a realization
  // level less-than-or-equal-to X, then we justly receive get an assertion failure.
  // Realizing a worldblock at a given level must not require same-level information.
  worldblock& worldblock::ensure_realization(level_of_tile_realization_needed realineeded, world *w, vector3<tile_coordinate> global_position) {
    // This function gets called to do nothing a LOT more than it gets called to actually do something;
    // bail ASAP if we don't have to do anything.
    if (realineeded <= current_tile_realization_) return *this;

    caller_correct_if(realineeded >= COMPLETELY_IMAGINARY && realineeded <= FULL_REALIZATION, "Calling ensure_realization with an invalid realization level");

    if ((              realineeded >= CONTENTS_ONLY) &&
        (current_tile_realization_ <  CONTENTS_ONLY)) {

      caller_error_if(is_busy_realizing_, "Referring to a realization level currently being computed");
      is_busy_realizing_ = true;

      w_ = w;
      global_position_ = global_position;
      tile_bounding_box bounds(global_position_, vector3<tile_coordinate>(worldblock_dimension,worldblock_dimension,worldblock_dimension));
      w_->worldgen_function_(world_building_gun(w_, bounds), bounds);
      //std::cerr << "A worldblock has been created!\n";

      current_tile_realization_ = CONTENTS_ONLY;
      is_busy_realizing_ = false;
    }

    if ((              realineeded >= CONTENTS_AND_LOCAL_CACHES_ONLY) &&
        (current_tile_realization_ <  CONTENTS_AND_LOCAL_CACHES_ONLY)) {

      caller_error_if(is_busy_realizing_, "Referring to a realization level currently being computed");
      is_busy_realizing_ = true;

      for (tile_coordinate x = global_position.x; x < global_position.x + worldblock_dimension; ++x) {
        for (tile_coordinate y = global_position.y; y < global_position.y + worldblock_dimension; ++y) {
          for (tile_coordinate z = global_position.z; z < global_position.z + worldblock_dimension; ++z) {
            tile_location loc(vector3<tile_coordinate>(x,y,z), this);
            w_->initialize_tile_local_caches_(loc);
          }
        }
      }

      current_tile_realization_ = CONTENTS_AND_LOCAL_CACHES_ONLY;
      is_busy_realizing_ = false;
    }

    if ((              realineeded >= FULL_REALIZATION) &&
        (current_tile_realization_ <  FULL_REALIZATION)) {

      caller_error_if(is_busy_realizing_, "Referring to a realization level currently being computed");
      is_busy_realizing_ = true;

      for (tile_coordinate x = global_position.x; x < global_position.x + worldblock_dimension; ++x) {
        for (tile_coordinate y = global_position.y; y < global_position.y + worldblock_dimension; ++y) {
          for (tile_coordinate z = global_position.z; z < global_position.z + worldblock_dimension; ++z) {
            const vector3<tile_coordinate> coords(x,y,z);
            tile& here = this->get_tile(coords);
            // Checking contents() here: significant speed improvement.
            // (Some from the inlining, some from not having to construct a tile_location if not GROUPABLE_WATER,
            // I believe.) --Isaac
            if (here.contents() == GROUPABLE_WATER) {
              w_->initialize_tile_water_group_caches_(tile_location(coords, this));
            }
          }
        }
      }

      current_tile_realization_ = FULL_REALIZATION;
      is_busy_realizing_ = false;
    }

    return (*this);
  }

  template<> bool worldblock::crossed_boundary<xminus>(tile_coordinate new_coord) { return new_coord < global_position_.x; }
  template<> bool worldblock::crossed_boundary<yminus>(tile_coordinate new_coord) { return new_coord < global_position_.y; }
  template<> bool worldblock::crossed_boundary<zminus>(tile_coordinate new_coord) { return new_coord < global_position_.z; }
  template<> bool worldblock::crossed_boundary<xplus>(tile_coordinate new_coord) { return new_coord >= global_position_.x + worldblock_dimension; }
  template<> bool worldblock::crossed_boundary<yplus>(tile_coordinate new_coord) { return new_coord >= global_position_.y + worldblock_dimension; }
  template<> bool worldblock::crossed_boundary<zplus>(tile_coordinate new_coord) { return new_coord >= global_position_.z + worldblock_dimension; }

  template<cardinal_direction Dir> tile_location worldblock::get_neighboring_loc(vector3<tile_coordinate> const& old_coords, level_of_tile_realization_needed realineeded) {
    ensure_realization(realineeded);
    vector3<tile_coordinate> new_coords = old_coords; cdir_info<Dir>::add_to(new_coords);
    if (crossed_boundary<Dir>(new_coords[cdir_info<Dir>::dimension])) return get_loc_across_boundary<Dir>(new_coords, realineeded);
    else return tile_location(new_coords, this);
  }

  template<cardinal_direction Dir> tile_location worldblock::get_loc_across_boundary(vector3<tile_coordinate> const& new_coords, level_of_tile_realization_needed realineeded) {
    if (worldblock* neighbor = neighbors_[Dir]) {
      neighbor->ensure_realization(realineeded);
      return tile_location(new_coords, neighbor);
    }
    else return tile_location(
      new_coords,
      (
        neighbors_[Dir] =
        w_->ensure_realization_of_and_get_worldblock_(
          global_position_ + vector3<worldblock_dimension_type>(cdir_info<Dir>::as_vector()) * worldblock_dimension,
          realineeded
        )
      )
    );
  }

  tile_location worldblock::get_loc_guaranteed_to_be_in_this_block(vector3<tile_coordinate> coords) {
    return tile_location(coords, this);
  }

}

tile_location tile_location::get_neighbor_by_variable(cardinal_direction dir, level_of_tile_realization_needed realineeded)const {
  switch(dir) {
    case xminus: return wb_->get_neighboring_loc<xminus>(v_, realineeded);
    case yminus: return wb_->get_neighboring_loc<yminus>(v_, realineeded);
    case zminus: return wb_->get_neighboring_loc<zminus>(v_, realineeded);
    case xplus: return wb_->get_neighboring_loc<xplus>(v_, realineeded);
    case yplus: return wb_->get_neighboring_loc<yplus>(v_, realineeded);
    case zplus: return wb_->get_neighboring_loc<zplus>(v_, realineeded);
    default: caller_error("calling get_neighbor_by_variable with an invalid direction");
  }
}

namespace { // anonymous
vector3<tile_coordinate> coordinates_of_containing_worldblock(vector3<tile_coordinate> const& coords) {
  return vector3<tile_coordinate>(
    coords.x & ~(worldblock_dimension-1),
    coords.y & ~(worldblock_dimension-1),
    coords.z & ~(worldblock_dimension-1)
  );
}
} // end anonymous namespace

tile_location world::make_tile_location(vector3<tile_coordinate> const& coords, level_of_tile_realization_needed realineeded) {
  return ensure_realization_of_and_get_worldblock_(coordinates_of_containing_worldblock(coords), realineeded)->get_loc_guaranteed_to_be_in_this_block(coords);
}

worldblock* world::ensure_realization_of_and_get_worldblock_(vector3<tile_coordinate> position, level_of_tile_realization_needed realineeded) {
  return &(blocks_[position].ensure_realization(realineeded, this, position));
}

void world::ensure_realization_of_space_(tile_bounding_box space, level_of_tile_realization_needed realineeded) {
  const worldblock_dimension_type wd = worldblock_dimension;
  for (tile_coordinate
       x =  space.min.x                            / wd;
       x < (space.min.x + space.size.x + (wd - 1)) / wd;
       ++x) {
    for (tile_coordinate
         y =  space.min.y                            / wd;
         y < (space.min.y + space.size.y + (wd - 1)) / wd;
         ++y) {
      for (tile_coordinate
           z =  space.min.z                            / wd;
           z < (space.min.z + space.size.z + (wd - 1)) / wd;
           ++z) {
        const vector3<tile_coordinate> worldblock_position(x*wd, y*wd, z*wd);
        ensure_realization_of_and_get_worldblock_(worldblock_position, realineeded);
      }
    }
  }
}

<commit_msg>fixed a bug Isaac introduced with the coding conventions<commit_after>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

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

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

    You should have received a copy of the GNU General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "world.hpp"

using namespace the_decomposition_of_the_world_into_blocks_impl;

namespace the_decomposition_of_the_world_into_blocks_impl {

  // Water that starts out in a worldblock starts out inactive (observing the rule "the landscape takes zero time to process").
  //
  // We would have to make special rules for worldblocks that start out with
  // active water in them, because it could invalidate iterators into the
  // active_water_tiles map, because worldblocks can be created essentially any time in the processing.
  //
  // If we try to use a level-X value from a worldblock while it's busy computing a realization
  // level less-than-or-equal-to X, then we justly receive get an assertion failure.
  // Realizing a worldblock at a given level must not require same-level information.
  worldblock& worldblock::ensure_realization(level_of_tile_realization_needed realineeded, world *w, vector3<tile_coordinate> global_position) {
    // This function gets called to do nothing a LOT more than it gets called to actually do something;
    // bail ASAP if we don't have to do anything.
    if (realineeded <= current_tile_realization_) return *this;

    caller_correct_if(realineeded >= COMPLETELY_IMAGINARY && realineeded <= FULL_REALIZATION, "Calling ensure_realization with an invalid realization level");

    if ((              realineeded >= CONTENTS_ONLY) &&
        (current_tile_realization_ <  CONTENTS_ONLY)) {

      caller_error_if(is_busy_realizing_, "Referring to a realization level currently being computed");
      is_busy_realizing_ = true;

      w_ = w;
      global_position_ = global_position;
      tile_bounding_box bounds(global_position_, vector3<tile_coordinate>(worldblock_dimension,worldblock_dimension,worldblock_dimension));
      w_->worldgen_function_(world_building_gun(w_, bounds), bounds);
      //std::cerr << "A worldblock has been created!\n";

      current_tile_realization_ = CONTENTS_ONLY;
      is_busy_realizing_ = false;
    }

    if ((              realineeded >= CONTENTS_AND_LOCAL_CACHES_ONLY) &&
        (current_tile_realization_ <  CONTENTS_AND_LOCAL_CACHES_ONLY)) {

      caller_error_if(is_busy_realizing_, "Referring to a realization level currently being computed");
      is_busy_realizing_ = true;

      for (tile_coordinate x = global_position_.x; x < global_position_.x + worldblock_dimension; ++x) {
        for (tile_coordinate y = global_position_.y; y < global_position_.y + worldblock_dimension; ++y) {
          for (tile_coordinate z = global_position_.z; z < global_position_.z + worldblock_dimension; ++z) {
            tile_location loc(vector3<tile_coordinate>(x,y,z), this);
            w_->initialize_tile_local_caches_(loc);
          }
        }
      }

      current_tile_realization_ = CONTENTS_AND_LOCAL_CACHES_ONLY;
      is_busy_realizing_ = false;
    }

    if ((              realineeded >= FULL_REALIZATION) &&
        (current_tile_realization_ <  FULL_REALIZATION)) {

      caller_error_if(is_busy_realizing_, "Referring to a realization level currently being computed");
      is_busy_realizing_ = true;

      for (tile_coordinate x = global_position_.x; x < global_position_.x + worldblock_dimension; ++x) {
        for (tile_coordinate y = global_position_.y; y < global_position_.y + worldblock_dimension; ++y) {
          for (tile_coordinate z = global_position_.z; z < global_position_.z + worldblock_dimension; ++z) {
            const vector3<tile_coordinate> coords(x,y,z);
            tile& here = this->get_tile(coords);
            // Checking contents() here: significant speed improvement.
            // (Some from the inlining, some from not having to construct a tile_location if not GROUPABLE_WATER,
            // I believe.) --Isaac
            if (here.contents() == GROUPABLE_WATER) {
              w_->initialize_tile_water_group_caches_(tile_location(coords, this));
            }
          }
        }
      }

      current_tile_realization_ = FULL_REALIZATION;
      is_busy_realizing_ = false;
    }

    return (*this);
  }

  template<> bool worldblock::crossed_boundary<xminus>(tile_coordinate new_coord) { return new_coord < global_position_.x; }
  template<> bool worldblock::crossed_boundary<yminus>(tile_coordinate new_coord) { return new_coord < global_position_.y; }
  template<> bool worldblock::crossed_boundary<zminus>(tile_coordinate new_coord) { return new_coord < global_position_.z; }
  template<> bool worldblock::crossed_boundary<xplus>(tile_coordinate new_coord) { return new_coord >= global_position_.x + worldblock_dimension; }
  template<> bool worldblock::crossed_boundary<yplus>(tile_coordinate new_coord) { return new_coord >= global_position_.y + worldblock_dimension; }
  template<> bool worldblock::crossed_boundary<zplus>(tile_coordinate new_coord) { return new_coord >= global_position_.z + worldblock_dimension; }

  template<cardinal_direction Dir> tile_location worldblock::get_neighboring_loc(vector3<tile_coordinate> const& old_coords, level_of_tile_realization_needed realineeded) {
    ensure_realization(realineeded);
    vector3<tile_coordinate> new_coords = old_coords; cdir_info<Dir>::add_to(new_coords);
    if (crossed_boundary<Dir>(new_coords[cdir_info<Dir>::dimension])) return get_loc_across_boundary<Dir>(new_coords, realineeded);
    else return tile_location(new_coords, this);
  }

  template<cardinal_direction Dir> tile_location worldblock::get_loc_across_boundary(vector3<tile_coordinate> const& new_coords, level_of_tile_realization_needed realineeded) {
    if (worldblock* neighbor = neighbors_[Dir]) {
      neighbor->ensure_realization(realineeded);
      return tile_location(new_coords, neighbor);
    }
    else return tile_location(
      new_coords,
      (
        neighbors_[Dir] =
        w_->ensure_realization_of_and_get_worldblock_(
          global_position_ + vector3<worldblock_dimension_type>(cdir_info<Dir>::as_vector()) * worldblock_dimension,
          realineeded
        )
      )
    );
  }

  tile_location worldblock::get_loc_guaranteed_to_be_in_this_block(vector3<tile_coordinate> coords) {
    return tile_location(coords, this);
  }

}

tile_location tile_location::get_neighbor_by_variable(cardinal_direction dir, level_of_tile_realization_needed realineeded)const {
  switch(dir) {
    case xminus: return wb_->get_neighboring_loc<xminus>(v_, realineeded);
    case yminus: return wb_->get_neighboring_loc<yminus>(v_, realineeded);
    case zminus: return wb_->get_neighboring_loc<zminus>(v_, realineeded);
    case xplus: return wb_->get_neighboring_loc<xplus>(v_, realineeded);
    case yplus: return wb_->get_neighboring_loc<yplus>(v_, realineeded);
    case zplus: return wb_->get_neighboring_loc<zplus>(v_, realineeded);
    default: caller_error("calling get_neighbor_by_variable with an invalid direction");
  }
}

namespace { // anonymous
vector3<tile_coordinate> coordinates_of_containing_worldblock(vector3<tile_coordinate> const& coords) {
  return vector3<tile_coordinate>(
    coords.x & ~(worldblock_dimension-1),
    coords.y & ~(worldblock_dimension-1),
    coords.z & ~(worldblock_dimension-1)
  );
}
} // end anonymous namespace

tile_location world::make_tile_location(vector3<tile_coordinate> const& coords, level_of_tile_realization_needed realineeded) {
  return ensure_realization_of_and_get_worldblock_(coordinates_of_containing_worldblock(coords), realineeded)->get_loc_guaranteed_to_be_in_this_block(coords);
}

worldblock* world::ensure_realization_of_and_get_worldblock_(vector3<tile_coordinate> position, level_of_tile_realization_needed realineeded) {
  return &(blocks_[position].ensure_realization(realineeded, this, position));
}

void world::ensure_realization_of_space_(tile_bounding_box space, level_of_tile_realization_needed realineeded) {
  const worldblock_dimension_type wd = worldblock_dimension;
  for (tile_coordinate
       x =  space.min.x                            / wd;
       x < (space.min.x + space.size.x + (wd - 1)) / wd;
       ++x) {
    for (tile_coordinate
         y =  space.min.y                            / wd;
         y < (space.min.y + space.size.y + (wd - 1)) / wd;
         ++y) {
      for (tile_coordinate
           z =  space.min.z                            / wd;
           z < (space.min.z + space.size.z + (wd - 1)) / wd;
           ++z) {
        const vector3<tile_coordinate> worldblock_position(x*wd, y*wd, z*wd);
        ensure_realization_of_and_get_worldblock_(worldblock_position, realineeded);
      }
    }
  }
}

<|endoftext|>


<commit_before>// This file is part of playd.
// playd is licensed under the MIT licence: see LICENSE.txt.

/**
 * @file
 * Declaration of the Player class, and associated types.
 * @see player.cpp
 */

#ifndef PLAYD_PLAYER_HPP
#define PLAYD_PLAYER_HPP

#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "audio/audio_system.hpp"
#include "audio/audio.hpp"
#include "response.hpp"
#include "cmd_result.hpp"

/**
 * A Player contains a loaded audio file and a command API for manipulating it.
 * @see Audio
 * @see AudioSystem
 */
class Player
{
private:
	AudioSystem &audio;          ///< The system used for loading audio.
	std::unique_ptr<Audio> file; ///< The currently loaded Audio.
	bool is_running;             ///< Whether the Player is running.
	const ResponseSink *sink;    ///< The sink for audio responses.

	/// The set of features playd implements.
	const static std::vector<std::string> FEATURES;

public:
	/**
	 * Constructs a Player.
	 * @param audio The AudioSystem to be used by the player.
	 */
	Player(AudioSystem &audio);

	/// Deleted copy constructor.
	Player(const Player &) = delete;

	/// Deleted copy-assignment constructor.
	Player &operator=(const Player &) = delete;

	/**
	 * Sets the sink to which this Player shall send responses.
	 * @param sink The response sink.
	 */
	void SetSink(ResponseSink &sink);

	//
	// Commands
	//

	/**
	 * Handles a command line.
	 * @param cmd A reference to the list of words in the command.
	 * @return Whether the command succeeded.
	 */
	CommandResult RunCommand(const std::vector<std::string> &words);

	//
	// Other methods
	//

	/**
	 * Instructs the Player to perform a cycle of work.
	 * This includes decoding the next frame and responding to commands.
	 * @return Whether the player has more cycles of work to do.
	 */
	bool Update();

	/**
	 * Sends welcome/current status information to a new client.
	 * @param id The ID of the new client inside the IO system.
	 */
	void WelcomeClient(size_t id) const;

private:
	//
	// Commands
	//

	/**
	 * Runs a nullary (0-argument) command.
	 * @param word The command word.
	 * @return True if the command was successfully found and executed;
	 *   false otherwise.
	 */
	CommandResult RunNullaryCommand(const std::string &word);

	/**
	 * Runs a unary (1-argument) command.
	 * @param word The command word.
	 * @param arg The argument to the command.
	 * @return True if the command was successfully found and executed;
	 *   false otherwise.
	 */
	CommandResult RunUnaryCommand(const std::string &word,
	                              const std::string &arg);

	//
	// Playback control
	//

	/**
	 * Tells the audio file to start or stop playing.
	 * @param playing True if playing; false otherwise.
	 * @see Play
	 * @see Stop
	 */
	CommandResult SetPlaying(bool playing);

	/**
	 * Ejects the current loaded song, if any.
	 * @return Whether the ejection succeeded.
	 */
	CommandResult Eject();

	/**
	 * Loads a track.
	 * @param path The absolute path to a track to load.
	 * @return Whether the load succeeded.
	 */
	CommandResult Load(const std::string &path);

	/// Handles ending a file (stopping and rewinding).
	void End();

	//
	// Seeking
	//

	/**
	 * Seeks to a given position in the current track.
	 * @param time_str A string containing a timestamp, followed by the
	 *   shorthand for the units of time in which the timestamp is measured
	 *   relative to the start of the track.  If the latter is omitted,
	 *   microseconds are assumed.
	 * @return Whether the seek succeeded.
	 */
	CommandResult Seek(const std::string &time_str);

	/**
	 * Parses time_str as a seek timestamp.
	 * @param time_str The time string to be parsed.
	 * @return The parsed time.
	 * @exception std::out_of_range
	 *   See http://www.cplusplus.com/reference/string/stoull/#exceptions
	 * @exception std::invalid_argument
	 *   See http://www.cplusplus.com/reference/string/stoull/#exceptions
	 * @exception SeekError
	 *   Raised if checks beyond those done by stoull fail.
	 */
	static std::uint64_t SeekParse(const std::string &time_str);

	/**
	 * Performs an actual seek.
	 * This does not do any EOF handling.
	 * @param pos The new position, in microseconds.
	 * @exception SeekError
	 *   Raised if the seek is out of range (usually EOF).
	 * @see Player::Seek
	 */
	void SeekRaw(std::uint64_t pos);

	//
	// Other
	//

	/**
	 * Quits playd.
	 * @return Whether the quit succeeded.
	 */
	CommandResult Quit();

	/**
	 * Asks the current file to dump all of its state to the connection
	 * with the given ID.
	 * @param id The ID of the connection to receive the dump.
	 * @note This is a pointer, not a reference, so as to allow nullptr
	 *   (which means no sink is assigned).  When `optional` becomes
	 *   standard, perhaps use that.
	 */
	void EmitAllAudioState(size_t id) const;
};

#endif // PLAYD_PLAYER_HPP
<commit_msg>Clean up public methods of Player.<commit_after>// This file is part of playd.
// playd is licensed under the MIT licence: see LICENSE.txt.

/**
 * @file
 * Declaration of the Player class, and associated types.
 * @see player.cpp
 */

#ifndef PLAYD_PLAYER_HPP
#define PLAYD_PLAYER_HPP

#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "audio/audio_system.hpp"
#include "audio/audio.hpp"
#include "response.hpp"
#include "cmd_result.hpp"

/**
 * A Player contains a loaded audio file and a command API for manipulating it.
 * @see Audio
 * @see AudioSystem
 */
class Player
{
public:
	/**
	 * Constructs a Player.
	 * @param audio The AudioSystem to be used by the player.
	 */
	Player(AudioSystem &audio);

	/// Deleted copy constructor.
	Player(const Player &) = delete;

	/// Deleted copy-assignment constructor.
	Player &operator=(const Player &) = delete;

	/**
	 * Handles a command line.
	 * @param cmd A reference to the list of words in the command.
	 * @return Whether the command succeeded.
	 */
	CommandResult RunCommand(const std::vector<std::string> &words);

	/**
	 * Sets the sink to which this Player shall send responses.
	 * This sink shall be the target for WelcomeClient, as well as
	 * any responses generated by RunCommand or Update.
	 * @param sink The response sink.
	 */
	void SetSink(ResponseSink &sink);

	/**
	 * Instructs the Player to perform a cycle of work.
	 * This includes decoding the next frame and responding to commands.
	 * @return Whether the player has more cycles of work to do.
	 */
	bool Update();

	/**
	 * Sends welcome/current status information to a new client.
	 * @param id The ID of the new client inside the IO system.
	 */
	void WelcomeClient(size_t id) const;

private:
	AudioSystem &audio;          ///< The system used for loading audio.
	std::unique_ptr<Audio> file; ///< The currently loaded audio file.
	bool is_running;             ///< Whether the Player is running.
	const ResponseSink *sink;    ///< The sink for audio responses.

	/// The set of features playd implements.
	const static std::vector<std::string> FEATURES;

	//
	// Commands
	//

	/**
	 * Runs a nullary (0-argument) command.
	 * @param word The command word.
	 * @return True if the command was successfully found and executed;
	 *   false otherwise.
	 */
	CommandResult RunNullaryCommand(const std::string &word);

	/**
	 * Runs a unary (1-argument) command.
	 * @param word The command word.
	 * @param arg The argument to the command.
	 * @return True if the command was successfully found and executed;
	 *   false otherwise.
	 */
	CommandResult RunUnaryCommand(const std::string &word,
	                              const std::string &arg);

	//
	// Playback control
	//

	/**
	 * Tells the audio file to start or stop playing.
	 * @param playing True if playing; false otherwise.
	 * @see Play
	 * @see Stop
	 */
	CommandResult SetPlaying(bool playing);

	/**
	 * Ejects the current loaded song, if any.
	 * @return Whether the ejection succeeded.
	 */
	CommandResult Eject();

	/**
	 * Loads a track.
	 * @param path The absolute path to a track to load.
	 * @return Whether the load succeeded.
	 */
	CommandResult Load(const std::string &path);

	/// Handles ending a file (stopping and rewinding).
	void End();

	//
	// Seeking
	//

	/**
	 * Seeks to a given position in the current track.
	 * @param time_str A string containing a timestamp, followed by the
	 *   shorthand for the units of time in which the timestamp is measured
	 *   relative to the start of the track.  If the latter is omitted,
	 *   microseconds are assumed.
	 * @return Whether the seek succeeded.
	 */
	CommandResult Seek(const std::string &time_str);

	/**
	 * Parses time_str as a seek timestamp.
	 * @param time_str The time string to be parsed.
	 * @return The parsed time.
	 * @exception std::out_of_range
	 *   See http://www.cplusplus.com/reference/string/stoull/#exceptions
	 * @exception std::invalid_argument
	 *   See http://www.cplusplus.com/reference/string/stoull/#exceptions
	 * @exception SeekError
	 *   Raised if checks beyond those done by stoull fail.
	 */
	static std::uint64_t SeekParse(const std::string &time_str);

	/**
	 * Performs an actual seek.
	 * This does not do any EOF handling.
	 * @param pos The new position, in microseconds.
	 * @exception SeekError
	 *   Raised if the seek is out of range (usually EOF).
	 * @see Player::Seek
	 */
	void SeekRaw(std::uint64_t pos);

	//
	// Other
	//

	/**
	 * Quits playd.
	 * @return Whether the quit succeeded.
	 */
	CommandResult Quit();

	/**
	 * Asks the current file to dump all of its state to the connection
	 * with the given ID.
	 * @param id The ID of the connection to receive the dump.
	 * @note This is a pointer, not a reference, so as to allow nullptr
	 *   (which means no sink is assigned).  When `optional` becomes
	 *   standard, perhaps use that.
	 */
	void EmitAllAudioState(size_t id) const;
};

#endif // PLAYD_PLAYER_HPP
<|endoftext|>


<commit_before>#include "core.hpp"
#include "output.hpp"
#include <cmath>
#include "input-manager.hpp"

bool wayfire_grab_interface_t::grab()
{
    if (grabbed)
        return true;

    if (!output->is_plugin_active(name))
        return false;

    grabbed = true;

    /* unset modifiers, otherwise clients may not receive
     * the release event for them, as the release usually happens in a grab */
    auto kbd = weston_seat_get_keyboard(core->get_current_seat());
    if (kbd)
    {
        weston_keyboard_send_modifiers(kbd,
                                       wl_display_get_serial(core->ec->wl_display),
                                       0, 0, 0, 0);
    }

    return core->input->grab_input(this);
}

void wayfire_grab_interface_t::ungrab()
{
    if (!grabbed)
        return;

    grabbed = false;
    core->input->ungrab_input();
}

bool wayfire_grab_interface_t::is_grabbed()
{
    return grabbed;
}

void wayfire_plugin_t::fini() {}

const float MPI = 3.1415926535;

float GetProgress(float start, float end, float current_step, float max_steps)
{
    if (max_steps <= 1e-4)
        return end;

    float c = current_step / max_steps;
    float prog = (std::sin(1.5 * MPI + MPI * c) + 1) / 2.0;
    return prog * end + (1 - prog) * start;
}
<commit_msg>plugin: change animation easing function<commit_after>#include "core.hpp"
#include "output.hpp"
#include <cmath>
#include "input-manager.hpp"

bool wayfire_grab_interface_t::grab()
{
    if (grabbed)
        return true;

    if (!output->is_plugin_active(name))
        return false;

    grabbed = true;

    /* unset modifiers, otherwise clients may not receive
     * the release event for them, as the release usually happens in a grab */
    auto kbd = weston_seat_get_keyboard(core->get_current_seat());
    if (kbd)
    {
        weston_keyboard_send_modifiers(kbd,
                                       wl_display_get_serial(core->ec->wl_display),
                                       0, 0, 0, 0);
    }

    return core->input->grab_input(this);
}

void wayfire_grab_interface_t::ungrab()
{
    if (!grabbed)
        return;

    grabbed = false;
    core->input->ungrab_input();
}

bool wayfire_grab_interface_t::is_grabbed()
{
    return grabbed;
}

void wayfire_plugin_t::fini() {}

const float MPI = 3.1415926535;

float GetProgress(float start, float end, float current_step, float max_steps)
{
    if (max_steps <= 1e-4)
        return end;

    float c = current_step / max_steps;
    float prog = std::sqrt(2 * c - c * c);
    return prog * end + (1 - prog) * start;
}
<|endoftext|>


<commit_before>#include <cstring>

#include <boost/filesystem.hpp>

#include "about_window.h"
#include "viewer_window.h"
#include "find_datarefs_in_files.h"

#include "datarefs.h"

#include "prefs.h"

#include "XPWidgets.h"
#include "XPLMMenus.h"
#include "XPLMDisplay.h"
#include "XPLMUtilities.h"
#include "XPLMPlugin.h"
#include "XPLMProcessing.h"
#include "XPLMPlanes.h"

boost::filesystem::path prefs_path;

void loadAircraftDatarefs() {
	//get path
	char filename[256] = {0};
	char path[512] = {0};
	XPLMGetNthAircraftModel(0, filename, path);
	std::vector<std::string> aircraft_datarefs = getDatarefsFromAircraft(path);

	int loaded_ok = addUserDatarefs(aircraft_datarefs);
	const std::string message = std::string("DRT: Found ") + std::to_string(aircraft_datarefs.size()) + std::string(" possible datarefs from aircraft files; " + std::to_string(loaded_ok) + " loaded OK.\n");
	XPLMDebugString(message.c_str());
}

//callback so we can load new aircraft datarefs when the aircraft is reloaded
float load_acf_dr_callback(float, float, int, void *) {
	loadAircraftDatarefs();

	updateViewerResults();
	updateSearchResults();

	return 0;
}

float load_dr_callback(float, float, int, void *) {
	if(false == loadDatarefsFile()) {
		XPLMDebugString("DRT: Couldn't load datarefs from file.");
		return 0;
	}

	loadAircraftDatarefs();

	//load plugins
	int num_plugins = XPLMCountPlugins();
	XPLMPluginID my_id = XPLMGetMyID();

	std::vector<std::string> all_plugin_datarefs;

	for(int i = 0; i < num_plugins; i++) {
		XPLMPluginID id = XPLMGetNthPlugin(i);
		if(id == my_id) {
			continue;
		}

		char filename[256] = {0};
		char path[512] = {0};
		XPLMGetPluginInfo(id, filename, path, nullptr, nullptr);

		std::vector<std::string> this_plugin_datarefs = getDatarefsFromFile(path);
		all_plugin_datarefs.insert(all_plugin_datarefs.end(), this_plugin_datarefs.begin(), this_plugin_datarefs.end());
	}

	removeVectorUniques(all_plugin_datarefs);

	int loaded_ok = addUserDatarefs(all_plugin_datarefs);
	const std::string message = std::string("DRT: Found ") + std::to_string(all_plugin_datarefs.size()) + std::string(" possible datarefs from plugin files; " + std::to_string(loaded_ok) + " loaded OK.\n");
	XPLMDebugString(message.c_str());

	updateViewerResults();
	updateSearchResults();

	return 0;
}

void reloadAircraft() {
	char acf_path[2048], acf_filename[1024];
	XPLMGetNthAircraftModel(0, acf_filename, acf_path);
	XPLMSetUsersAircraft(acf_path);
}

void plugin_menu_handler(void *, void * inItemRef)
{
	switch ( intptr_t(inItemRef) )
	{
		case 0: showViewerWindow(); break;
		//case 1: showCommandWindow(); break;
		case 2:
			XPLMSetFlightLoopCallbackInterval(load_dr_callback, -1, 1, nullptr);
			break;
		case 3:
			XPLMDebugString("DRT: reloaded aircraft\n");
			reloadAircraft();
			break;
		case 4:
			XPLMDebugString("DRT: reloaded plugins\n");
			XPLMReloadPlugins();
			break;
		case 5:
			XPLMDebugString("DRT: reloaded scenery\n");
			XPLMReloadScenery();
			break;
		case 6:
			showAboutWindow();
			break;
		default:
			break;
	}
}

XPLMCommandRef reload_aircraft_command = nullptr;
XPLMCommandRef reload_plugins_command = nullptr;
XPLMCommandRef reload_scenery_command = nullptr;
XPLMCommandRef show_datarefs_command = nullptr;

int command_handler(XPLMCommandRef command, XPLMCommandPhase phase, void * ) {
	if(xplm_CommandBegin == phase) {
		if(command == reload_aircraft_command) {
				reloadAircraft();
		} else if(command == reload_plugins_command) {
				XPLMReloadPlugins();
		} else if(command == reload_scenery_command) {
				XPLMReloadScenery();
		} else if(command == show_datarefs_command) {
				showViewerWindow();
		}
	}
	return 1;
}

PLUGIN_API int XPluginStart(char * outName, char * outSig, char * outDesc) {
	strcpy(outName, "DataRef Tool");
	strcpy(outSig, "com.leecbaker.datareftool");
	strcpy(outDesc, "View and edit X-Plane Datarefs");
	XPLMEnableFeature("XPLM_USE_NATIVE_PATHS", 1);

	char prefs_dir_c[512];
	XPLMGetPrefsPath(prefs_dir_c);
	prefs_path = boost::filesystem::path(prefs_dir_c).parent_path() / "datareftool.json";
    if(loadPrefs(prefs_path)) {
        std::stringstream ss;
        ss << "DRT prefs loaded from " << prefs_path.native();
        XPLMDebugString(ss.str().c_str());
    }

	XPLMRegisterFlightLoopCallback(load_dr_callback, -1, nullptr);

	int plugin_submenu = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "DataRefTool", nullptr, 1);
	XPLMMenuID plugin_menu = XPLMCreateMenu("DataRefTool", XPLMFindPluginsMenu(), plugin_submenu, plugin_menu_handler, nullptr);

	XPLMAppendMenuItem(plugin_menu, "View Datarefs", (void *)0, 1);
	XPLMAppendMenuItem(plugin_menu, "View Commands", (void *)1, 1);
	XPLMAppendMenuSeparator(plugin_menu);
	XPLMAppendMenuItem(plugin_menu, "Rescan for datarefs", (void *)2, 1);
	XPLMAppendMenuSeparator(plugin_menu);
	XPLMAppendMenuItem(plugin_menu, "Reload aircraft", (void *)3, 1);
	XPLMAppendMenuItem(plugin_menu, "Reload plugins", (void *)4, 1);
	XPLMAppendMenuItem(plugin_menu, "Reload scenery", (void *)5, 1);
	XPLMAppendMenuSeparator(plugin_menu);
	XPLMAppendMenuItem(plugin_menu, "About DataRefTool", (void *)6, 1);

	XPLMEnableMenuItem(plugin_menu, 0, 1);
	XPLMEnableMenuItem(plugin_menu, 1, 0);
	XPLMEnableMenuItem(plugin_menu, 2, 1);	//sep
	XPLMEnableMenuItem(plugin_menu, 3, 1);
	XPLMEnableMenuItem(plugin_menu, 4, 1);	//sep
	XPLMEnableMenuItem(plugin_menu, 5, 1);
	XPLMEnableMenuItem(plugin_menu, 6, 1);
	XPLMEnableMenuItem(plugin_menu, 7, 1);
	XPLMEnableMenuItem(plugin_menu, 8, 1);	//sep
	XPLMEnableMenuItem(plugin_menu, 9, 1);

	//commands
	reload_aircraft_command = XPLMCreateCommand("datareftool/reload_aircraft", "Reload the current aircraft");
	reload_plugins_command = XPLMCreateCommand("datareftool/reload_plugins", "Reload all plugins");
	reload_scenery_command = XPLMCreateCommand("datareftool/reload_scenery", "Reload the scenery");
	show_datarefs_command = XPLMCreateCommand("datareftool/show_datarefs", "Show the dataref search window");

	XPLMRegisterCommandHandler(reload_aircraft_command, command_handler, 0, nullptr);
	XPLMRegisterCommandHandler(reload_plugins_command, command_handler, 0, nullptr);
	XPLMRegisterCommandHandler(reload_scenery_command, command_handler, 0, nullptr);
	XPLMRegisterCommandHandler(show_datarefs_command, command_handler, 0, nullptr);

	return 1;
}

PLUGIN_API void	XPluginStop(void) {
    if(savePrefs(prefs_path)) {
        std::stringstream ss;
        ss << "DRT prefs saved to " << prefs_path.native();
        XPLMDebugString(ss.str().c_str());
    }
	//closeCommandWindows();
	closeAboutWindow();
	closeViewerWindows();
	cleanupDatarefs();
	XPLMUnregisterFlightLoopCallback(load_dr_callback, nullptr);
	XPLMUnregisterFlightLoopCallback(load_acf_dr_callback, nullptr);
}

PLUGIN_API void XPluginDisable(void) {
}

PLUGIN_API int XPluginEnable(void) {
	return 1;
}

const intptr_t MSG_ADD_DATAREF = 0x01000000;
const intptr_t MSG_ADD_COMMANDREF = 0x01000099;

PLUGIN_API void XPluginReceiveMessage(XPLMPluginID, intptr_t inMessage, void * inParam) {
	switch(inMessage) {
		// Add custom datarefs in the style of DRE:
		// http://www.xsquawkbox.net/xpsdk/mediawiki/Register_Custom_DataRef_in_DRE
		case MSG_ADD_DATAREF: {
			char * dataref_name = (char *) inParam;
			bool added_ok = addUserDataref(dataref_name);
			if(added_ok) {
				updateViewerResults();
			} else {
				const std::string message = std::string("DRT: Couldn't load dataref from message: ") + dataref_name + std::string("\n");
				XPLMDebugString(message.c_str());
			}
			break;
		}
		case MSG_ADD_COMMANDREF: {
			char * commandref_name = (char *) inParam;
			bool added_ok = true;//addUserCommandref(commandref_name);
			if(added_ok) {
				//updateCommandWindows();
			} else {
				const std::string message = std::string("DRT: Couldn't load commandref from message: ") + commandref_name + std::string("\n");
				XPLMDebugString(message.c_str());
			}
			break;
		}

		case XPLM_MSG_PLANE_LOADED: {
			int64_t plane_num = int64_t(inParam);
			const std::string message = std::string("DRT: Plane loaded #: ") + std::to_string(plane_num) + std::string("\n");
			XPLMDebugString(message.c_str());
			if(0 == plane_num) {	//user's plane
				XPLMRegisterFlightLoopCallback(load_acf_dr_callback, -1, nullptr);
			}
			break;
		}

		case XPLM_MSG_WILL_WRITE_PREFS: {
			break;
		}
	}
}
<commit_msg>Added line feed to the prefs statements in the Log.txt file<commit_after>#include <cstring>

#include <boost/filesystem.hpp>

#include "about_window.h"
#include "viewer_window.h"
#include "find_datarefs_in_files.h"

#include "datarefs.h"

#include "prefs.h"

#include "XPWidgets.h"
#include "XPLMMenus.h"
#include "XPLMDisplay.h"
#include "XPLMUtilities.h"
#include "XPLMPlugin.h"
#include "XPLMProcessing.h"
#include "XPLMPlanes.h"

boost::filesystem::path prefs_path;

void loadAircraftDatarefs() {
	//get path
	char filename[256] = {0};
	char path[512] = {0};
	XPLMGetNthAircraftModel(0, filename, path);
	std::vector<std::string> aircraft_datarefs = getDatarefsFromAircraft(path);

	int loaded_ok = addUserDatarefs(aircraft_datarefs);
	const std::string message = std::string("DRT: Found ") + std::to_string(aircraft_datarefs.size()) + std::string(" possible datarefs from aircraft files; " + std::to_string(loaded_ok) + " loaded OK.\n");
	XPLMDebugString(message.c_str());
}

//callback so we can load new aircraft datarefs when the aircraft is reloaded
float load_acf_dr_callback(float, float, int, void *) {
	loadAircraftDatarefs();

	updateViewerResults();
	updateSearchResults();

	return 0;
}

float load_dr_callback(float, float, int, void *) {
	if(false == loadDatarefsFile()) {
		XPLMDebugString("DRT: Couldn't load datarefs from file.");
		return 0;
	}

	loadAircraftDatarefs();

	//load plugins
	int num_plugins = XPLMCountPlugins();
	XPLMPluginID my_id = XPLMGetMyID();

	std::vector<std::string> all_plugin_datarefs;

	for(int i = 0; i < num_plugins; i++) {
		XPLMPluginID id = XPLMGetNthPlugin(i);
		if(id == my_id) {
			continue;
		}

		char filename[256] = {0};
		char path[512] = {0};
		XPLMGetPluginInfo(id, filename, path, nullptr, nullptr);

		std::vector<std::string> this_plugin_datarefs = getDatarefsFromFile(path);
		all_plugin_datarefs.insert(all_plugin_datarefs.end(), this_plugin_datarefs.begin(), this_plugin_datarefs.end());
	}

	removeVectorUniques(all_plugin_datarefs);

	int loaded_ok = addUserDatarefs(all_plugin_datarefs);
	const std::string message = std::string("DRT: Found ") + std::to_string(all_plugin_datarefs.size()) + std::string(" possible datarefs from plugin files; " + std::to_string(loaded_ok) + " loaded OK.\n");
	XPLMDebugString(message.c_str());

	updateViewerResults();
	updateSearchResults();

	return 0;
}

void reloadAircraft() {
	char acf_path[2048], acf_filename[1024];
	XPLMGetNthAircraftModel(0, acf_filename, acf_path);
	XPLMSetUsersAircraft(acf_path);
}

void plugin_menu_handler(void *, void * inItemRef)
{
	switch ( intptr_t(inItemRef) )
	{
		case 0: showViewerWindow(); break;
		//case 1: showCommandWindow(); break;
		case 2:
			XPLMSetFlightLoopCallbackInterval(load_dr_callback, -1, 1, nullptr);
			break;
		case 3:
			XPLMDebugString("DRT: reloaded aircraft\n");
			reloadAircraft();
			break;
		case 4:
			XPLMDebugString("DRT: reloaded plugins\n");
			XPLMReloadPlugins();
			break;
		case 5:
			XPLMDebugString("DRT: reloaded scenery\n");
			XPLMReloadScenery();
			break;
		case 6:
			showAboutWindow();
			break;
		default:
			break;
	}
}

XPLMCommandRef reload_aircraft_command = nullptr;
XPLMCommandRef reload_plugins_command = nullptr;
XPLMCommandRef reload_scenery_command = nullptr;
XPLMCommandRef show_datarefs_command = nullptr;

int command_handler(XPLMCommandRef command, XPLMCommandPhase phase, void * ) {
	if(xplm_CommandBegin == phase) {
		if(command == reload_aircraft_command) {
				reloadAircraft();
		} else if(command == reload_plugins_command) {
				XPLMReloadPlugins();
		} else if(command == reload_scenery_command) {
				XPLMReloadScenery();
		} else if(command == show_datarefs_command) {
				showViewerWindow();
		}
	}
	return 1;
}

PLUGIN_API int XPluginStart(char * outName, char * outSig, char * outDesc) {
	strcpy(outName, "DataRef Tool");
	strcpy(outSig, "com.leecbaker.datareftool");
	strcpy(outDesc, "View and edit X-Plane Datarefs");
	XPLMEnableFeature("XPLM_USE_NATIVE_PATHS", 1);

	char prefs_dir_c[512];
	XPLMGetPrefsPath(prefs_dir_c);
	prefs_path = boost::filesystem::path(prefs_dir_c).parent_path() / "datareftool.json";
    if(loadPrefs(prefs_path)) {
        std::stringstream ss;
        ss << "DRT: prefs loaded from " << prefs_path.native() << "\n";
        XPLMDebugString(ss.str().c_str());
    }

	XPLMRegisterFlightLoopCallback(load_dr_callback, -1, nullptr);

	int plugin_submenu = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "DataRefTool", nullptr, 1);
	XPLMMenuID plugin_menu = XPLMCreateMenu("DataRefTool", XPLMFindPluginsMenu(), plugin_submenu, plugin_menu_handler, nullptr);

	XPLMAppendMenuItem(plugin_menu, "View Datarefs", (void *)0, 1);
	XPLMAppendMenuItem(plugin_menu, "View Commands", (void *)1, 1);
	XPLMAppendMenuSeparator(plugin_menu);
	XPLMAppendMenuItem(plugin_menu, "Rescan for datarefs", (void *)2, 1);
	XPLMAppendMenuSeparator(plugin_menu);
	XPLMAppendMenuItem(plugin_menu, "Reload aircraft", (void *)3, 1);
	XPLMAppendMenuItem(plugin_menu, "Reload plugins", (void *)4, 1);
	XPLMAppendMenuItem(plugin_menu, "Reload scenery", (void *)5, 1);
	XPLMAppendMenuSeparator(plugin_menu);
	XPLMAppendMenuItem(plugin_menu, "About DataRefTool", (void *)6, 1);

	XPLMEnableMenuItem(plugin_menu, 0, 1);
	XPLMEnableMenuItem(plugin_menu, 1, 0);
	XPLMEnableMenuItem(plugin_menu, 2, 1);	//sep
	XPLMEnableMenuItem(plugin_menu, 3, 1);
	XPLMEnableMenuItem(plugin_menu, 4, 1);	//sep
	XPLMEnableMenuItem(plugin_menu, 5, 1);
	XPLMEnableMenuItem(plugin_menu, 6, 1);
	XPLMEnableMenuItem(plugin_menu, 7, 1);
	XPLMEnableMenuItem(plugin_menu, 8, 1);	//sep
	XPLMEnableMenuItem(plugin_menu, 9, 1);

	//commands
	reload_aircraft_command = XPLMCreateCommand("datareftool/reload_aircraft", "Reload the current aircraft");
	reload_plugins_command = XPLMCreateCommand("datareftool/reload_plugins", "Reload all plugins");
	reload_scenery_command = XPLMCreateCommand("datareftool/reload_scenery", "Reload the scenery");
	show_datarefs_command = XPLMCreateCommand("datareftool/show_datarefs", "Show the dataref search window");

	XPLMRegisterCommandHandler(reload_aircraft_command, command_handler, 0, nullptr);
	XPLMRegisterCommandHandler(reload_plugins_command, command_handler, 0, nullptr);
	XPLMRegisterCommandHandler(reload_scenery_command, command_handler, 0, nullptr);
	XPLMRegisterCommandHandler(show_datarefs_command, command_handler, 0, nullptr);

	return 1;
}

PLUGIN_API void	XPluginStop(void) {
    if(savePrefs(prefs_path)) {
        std::stringstream ss;
        ss << "DRT: prefs saved to " << prefs_path.native() << "\n";
        XPLMDebugString(ss.str().c_str());
    }
	//closeCommandWindows();
	closeAboutWindow();
	closeViewerWindows();
	cleanupDatarefs();
	XPLMUnregisterFlightLoopCallback(load_dr_callback, nullptr);
	XPLMUnregisterFlightLoopCallback(load_acf_dr_callback, nullptr);
}

PLUGIN_API void XPluginDisable(void) {
}

PLUGIN_API int XPluginEnable(void) {
	return 1;
}

const intptr_t MSG_ADD_DATAREF = 0x01000000;
const intptr_t MSG_ADD_COMMANDREF = 0x01000099;

PLUGIN_API void XPluginReceiveMessage(XPLMPluginID, intptr_t inMessage, void * inParam) {
	switch(inMessage) {
		// Add custom datarefs in the style of DRE:
		// http://www.xsquawkbox.net/xpsdk/mediawiki/Register_Custom_DataRef_in_DRE
		case MSG_ADD_DATAREF: {
			char * dataref_name = (char *) inParam;
			bool added_ok = addUserDataref(dataref_name);
			if(added_ok) {
				updateViewerResults();
			} else {
				const std::string message = std::string("DRT: Couldn't load dataref from message: ") + dataref_name + std::string("\n");
				XPLMDebugString(message.c_str());
			}
			break;
		}
		case MSG_ADD_COMMANDREF: {
			char * commandref_name = (char *) inParam;
			bool added_ok = true;//addUserCommandref(commandref_name);
			if(added_ok) {
				//updateCommandWindows();
			} else {
				const std::string message = std::string("DRT: Couldn't load commandref from message: ") + commandref_name + std::string("\n");
				XPLMDebugString(message.c_str());
			}
			break;
		}

		case XPLM_MSG_PLANE_LOADED: {
			int64_t plane_num = int64_t(inParam);
			const std::string message = std::string("DRT: Plane loaded #: ") + std::to_string(plane_num) + std::string("\n");
			XPLMDebugString(message.c_str());
			if(0 == plane_num) {	//user's plane
				XPLMRegisterFlightLoopCallback(load_acf_dr_callback, -1, nullptr);
			}
			break;
		}

		case XPLM_MSG_WILL_WRITE_PREFS: {
			break;
		}
	}
}
<|endoftext|>