<commit_before>/*
 * Copyright (C) 2004-2015 ZNC, see the NOTICE file for details.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <znc/Message.h>
#include <znc/Utils.h>

CMessage::CMessage(const CString& sMessage)
{
	Parse(sMessage);
	InitTime();
}

CMessage::CMessage(const CNick& Nick, const CString& sCommand, const VCString& vsParams, const MCString& mssTags)
	: m_Nick(Nick), m_sCommand(sCommand), m_vsParams(vsParams), m_mssTags(mssTags)
{
	InitTime();
}

void CMessage::Clone(const CMessage& Message)
{
	if (&Message != this) {
		*this = Message;
	}
}

void CMessage::SetCommand(const CString& sCommand)
{
	m_sCommand = sCommand;
	InitType();
}

CString CMessage::GetParams(unsigned int uIdx, unsigned int uLen) const
{
	if (m_vsParams.empty() || uLen == 0) {
		return "";
	}
	if (uLen > m_vsParams.size() - uIdx - 1) {
		uLen = m_vsParams.size() - uIdx;
	}
	VCString vsParams;
	unsigned uParams = m_vsParams.size();
	for (unsigned int i = uIdx; i < uIdx + uLen; ++i) {
		CString sParam = m_vsParams[i];
		if (i == uParams - 1 && (m_bColon || sParam.empty() || sParam.StartsWith(":") || sParam.Contains(" "))) {
			sParam = ":" + sParam;
		}
		vsParams.push_back(sParam);
	}
	return CString(" ").Join(vsParams.begin(), vsParams.end());
}

void CMessage::SetParams(const VCString& vsParams)
{
	m_vsParams = vsParams;

	if (m_eType == Type::Text || m_eType == Type::Notice || m_eType == Type::Action || m_eType == Type::CTCP) {
		InitType();
	}
}

CString CMessage::GetParam(unsigned int uIdx) const
{
	if (uIdx >= m_vsParams.size()) {
		return "";
	}
	return m_vsParams[uIdx];
}

void CMessage::SetParam(unsigned int uIdx, const CString& sParam)
{
	if (uIdx >= m_vsParams.size()) {
		m_vsParams.resize(uIdx + 1);
	}
	m_vsParams[uIdx] = sParam;

	if (uIdx == 1 && (m_eType == Type::Text || m_eType == Type::Notice || m_eType == Type::Action || m_eType == Type::CTCP)) {
		InitType();
	}
}

CString CMessage::GetTag(const CString& sKey) const
{
	MCString::const_iterator it = m_mssTags.find(sKey);
	if (it != m_mssTags.end()) {
		return it->second;
	}
	return "";
}

void CMessage::SetTag(const CString& sKey, const CString& sValue)
{
	m_mssTags[sKey] = sValue;
}

CString CMessage::ToString(unsigned int uFlags) const
{
	CString sMessage;

	// <prefix>
	if (!(uFlags & ExcludePrefix)) {
		CString sPrefix = m_Nick.GetHostMask();
		if (!sPrefix.empty()) {
			sMessage += ":" + sPrefix;
		}
	}

	// <command>
	if (!m_sCommand.empty()) {
		if (!sMessage.empty()) {
			sMessage += " ";
		}
		sMessage += m_sCommand;
	}

	// <params>
	unsigned uParams = m_vsParams.size();
	for (unsigned int uIdx = 0; uIdx < uParams; ++uIdx) {
		const CString& sParam = m_vsParams[uIdx];
		sMessage += " ";
		if (uIdx == uParams - 1 && (m_bColon || sParam.empty() || sParam.StartsWith(":") || sParam.Contains(" "))) {
			sMessage += ":";
		}
		sMessage += sParam;
	}

	// <tags>
	if (!(uFlags & ExcludeTags)) {
		CUtils::SetMessageTags(sMessage, m_mssTags);
	}

	return sMessage;
}

void CMessage::Parse(CString sMessage)
{
	// <tags>
	if (sMessage.StartsWith("@")) {
		m_mssTags = CUtils::GetMessageTags(sMessage);
		sMessage = sMessage.Token(1, true);
	}

	//  <message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
	//  <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
	//  <command>  ::= <letter> { <letter> } | <number> <number> <number>
	//  <SPACE>    ::= ' ' { ' ' }
	//  <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
	//  <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
	//                 or NUL or CR or LF, the first of which may not be ':'>
	//  <trailing> ::= <Any, possibly *empty*, sequence of octets not including
	//                   NUL or CR or LF>

	// <prefix>
	if (sMessage.TrimPrefix(":")) {
		m_Nick.Parse(sMessage.Token(0));
		sMessage = sMessage.Token(1, true);
	}

	// <command>
	m_sCommand = sMessage.Token(0);
	sMessage = sMessage.Token(1, true);

	// <params>
	m_bColon = false;
	m_vsParams.clear();
	while (!sMessage.empty()) {
		m_bColon = sMessage.TrimPrefix(":");
		if (m_bColon) {
			m_vsParams.push_back(sMessage);
			sMessage.clear();
		} else {
			m_vsParams.push_back(sMessage.Token(0));
			sMessage = sMessage.Token(1, true);
		}
	}

	InitType();
}

void CMessage::InitTime()
{
	auto it = m_mssTags.find("time");
	if (it != m_mssTags.end()) {
		m_time = CUtils::ParseServerTime(it->second);
		return;
	}

#ifdef HAVE_CLOCK_GETTIME
	timespec ts;
	if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
		m_time.tv_sec = ts.tv_sec;
		m_time.tv_usec = ts.tv_nsec / 1000;
		return;
	}
#endif

	if (!gettimeofday(&m_time, nullptr)) {
		m_time.tv_sec = time(nullptr);
		m_time.tv_usec = 0;
	}
}

void CMessage::InitType()
{
	if (m_sCommand.length() == 3 && isdigit(m_sCommand[0]) && isdigit(m_sCommand[1]) && isdigit(m_sCommand[2])) {
		m_eType = Type::Numeric;
	} else if (m_sCommand.Equals("PRIVMSG")) {
		CString sParam = GetParam(1);
		if (sParam.TrimPrefix("\001") && sParam.EndsWith("\001")) {
			if (sParam.StartsWith("ACTION ")) {
				m_eType = Type::Action;
			} else {
				m_eType = Type::CTCP;
			}
		} else {
			m_eType = Type::Text;
		}
	} else if (m_sCommand.Equals("NOTICE")) {
		CString sParam = GetParam(1);
		if (sParam.StartsWith("\001") && sParam.EndsWith("\001")) {
			m_eType = Type::CTCP;
		} else {
			m_eType = Type::Notice;
		}
	} else {
		std::map<CString, Type> mTypes = {
			{"ACCOUNT", Type::Account},
			{"AWAY", Type::Away},
			{"CAP", Type::Capability},
			{"ERROR", Type::Error},
			{"INVITE", Type::Invite},
			{"JOIN", Type::Join},
			{"KICK", Type::Kick},
			{"MODE", Type::Mode},
			{"NICK", Type::Nick},
			{"PART", Type::Part},
			{"PING", Type::Ping},
			{"PONG", Type::Pong},
			{"QUIT", Type::Quit},
			{"TOPIC", Type::Topic},
			{"WALLOPS", Type::Wallops},
		};
		auto it = mTypes.find(m_sCommand.AsUpper());
		if (it != mTypes.end()) {
			m_eType = it->second;
		} else {
			m_eType = Type::Unknown;
		}
	}
}
<commit_msg>CMessage::SetParams(): forget the colon<commit_after>/*
 * Copyright (C) 2004-2015 ZNC, see the NOTICE file for details.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <znc/Message.h>
#include <znc/Utils.h>

CMessage::CMessage(const CString& sMessage)
{
	Parse(sMessage);
	InitTime();
}

CMessage::CMessage(const CNick& Nick, const CString& sCommand, const VCString& vsParams, const MCString& mssTags)
	: m_Nick(Nick), m_sCommand(sCommand), m_vsParams(vsParams), m_mssTags(mssTags)
{
	InitTime();
}

void CMessage::Clone(const CMessage& Message)
{
	if (&Message != this) {
		*this = Message;
	}
}

void CMessage::SetCommand(const CString& sCommand)
{
	m_sCommand = sCommand;
	InitType();
}

CString CMessage::GetParams(unsigned int uIdx, unsigned int uLen) const
{
	if (m_vsParams.empty() || uLen == 0) {
		return "";
	}
	if (uLen > m_vsParams.size() - uIdx - 1) {
		uLen = m_vsParams.size() - uIdx;
	}
	VCString vsParams;
	unsigned uParams = m_vsParams.size();
	for (unsigned int i = uIdx; i < uIdx + uLen; ++i) {
		CString sParam = m_vsParams[i];
		if (i == uParams - 1 && (m_bColon || sParam.empty() || sParam.StartsWith(":") || sParam.Contains(" "))) {
			sParam = ":" + sParam;
		}
		vsParams.push_back(sParam);
	}
	return CString(" ").Join(vsParams.begin(), vsParams.end());
}

void CMessage::SetParams(const VCString& vsParams)
{
	m_vsParams = vsParams;
	m_bColon = false;

	if (m_eType == Type::Text || m_eType == Type::Notice || m_eType == Type::Action || m_eType == Type::CTCP) {
		InitType();
	}
}

CString CMessage::GetParam(unsigned int uIdx) const
{
	if (uIdx >= m_vsParams.size()) {
		return "";
	}
	return m_vsParams[uIdx];
}

void CMessage::SetParam(unsigned int uIdx, const CString& sParam)
{
	if (uIdx >= m_vsParams.size()) {
		m_vsParams.resize(uIdx + 1);
	}
	m_vsParams[uIdx] = sParam;

	if (uIdx == 1 && (m_eType == Type::Text || m_eType == Type::Notice || m_eType == Type::Action || m_eType == Type::CTCP)) {
		InitType();
	}
}

CString CMessage::GetTag(const CString& sKey) const
{
	MCString::const_iterator it = m_mssTags.find(sKey);
	if (it != m_mssTags.end()) {
		return it->second;
	}
	return "";
}

void CMessage::SetTag(const CString& sKey, const CString& sValue)
{
	m_mssTags[sKey] = sValue;
}

CString CMessage::ToString(unsigned int uFlags) const
{
	CString sMessage;

	// <prefix>
	if (!(uFlags & ExcludePrefix)) {
		CString sPrefix = m_Nick.GetHostMask();
		if (!sPrefix.empty()) {
			sMessage += ":" + sPrefix;
		}
	}

	// <command>
	if (!m_sCommand.empty()) {
		if (!sMessage.empty()) {
			sMessage += " ";
		}
		sMessage += m_sCommand;
	}

	// <params>
	unsigned uParams = m_vsParams.size();
	for (unsigned int uIdx = 0; uIdx < uParams; ++uIdx) {
		const CString& sParam = m_vsParams[uIdx];
		sMessage += " ";
		if (uIdx == uParams - 1 && (m_bColon || sParam.empty() || sParam.StartsWith(":") || sParam.Contains(" "))) {
			sMessage += ":";
		}
		sMessage += sParam;
	}

	// <tags>
	if (!(uFlags & ExcludeTags)) {
		CUtils::SetMessageTags(sMessage, m_mssTags);
	}

	return sMessage;
}

void CMessage::Parse(CString sMessage)
{
	// <tags>
	if (sMessage.StartsWith("@")) {
		m_mssTags = CUtils::GetMessageTags(sMessage);
		sMessage = sMessage.Token(1, true);
	}

	//  <message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
	//  <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
	//  <command>  ::= <letter> { <letter> } | <number> <number> <number>
	//  <SPACE>    ::= ' ' { ' ' }
	//  <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
	//  <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
	//                 or NUL or CR or LF, the first of which may not be ':'>
	//  <trailing> ::= <Any, possibly *empty*, sequence of octets not including
	//                   NUL or CR or LF>

	// <prefix>
	if (sMessage.TrimPrefix(":")) {
		m_Nick.Parse(sMessage.Token(0));
		sMessage = sMessage.Token(1, true);
	}

	// <command>
	m_sCommand = sMessage.Token(0);
	sMessage = sMessage.Token(1, true);

	// <params>
	m_bColon = false;
	m_vsParams.clear();
	while (!sMessage.empty()) {
		m_bColon = sMessage.TrimPrefix(":");
		if (m_bColon) {
			m_vsParams.push_back(sMessage);
			sMessage.clear();
		} else {
			m_vsParams.push_back(sMessage.Token(0));
			sMessage = sMessage.Token(1, true);
		}
	}

	InitType();
}

void CMessage::InitTime()
{
	auto it = m_mssTags.find("time");
	if (it != m_mssTags.end()) {
		m_time = CUtils::ParseServerTime(it->second);
		return;
	}

#ifdef HAVE_CLOCK_GETTIME
	timespec ts;
	if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
		m_time.tv_sec = ts.tv_sec;
		m_time.tv_usec = ts.tv_nsec / 1000;
		return;
	}
#endif

	if (!gettimeofday(&m_time, nullptr)) {
		m_time.tv_sec = time(nullptr);
		m_time.tv_usec = 0;
	}
}

void CMessage::InitType()
{
	if (m_sCommand.length() == 3 && isdigit(m_sCommand[0]) && isdigit(m_sCommand[1]) && isdigit(m_sCommand[2])) {
		m_eType = Type::Numeric;
	} else if (m_sCommand.Equals("PRIVMSG")) {
		CString sParam = GetParam(1);
		if (sParam.TrimPrefix("\001") && sParam.EndsWith("\001")) {
			if (sParam.StartsWith("ACTION ")) {
				m_eType = Type::Action;
			} else {
				m_eType = Type::CTCP;
			}
		} else {
			m_eType = Type::Text;
		}
	} else if (m_sCommand.Equals("NOTICE")) {
		CString sParam = GetParam(1);
		if (sParam.StartsWith("\001") && sParam.EndsWith("\001")) {
			m_eType = Type::CTCP;
		} else {
			m_eType = Type::Notice;
		}
	} else {
		std::map<CString, Type> mTypes = {
			{"ACCOUNT", Type::Account},
			{"AWAY", Type::Away},
			{"CAP", Type::Capability},
			{"ERROR", Type::Error},
			{"INVITE", Type::Invite},
			{"JOIN", Type::Join},
			{"KICK", Type::Kick},
			{"MODE", Type::Mode},
			{"NICK", Type::Nick},
			{"PART", Type::Part},
			{"PING", Type::Ping},
			{"PONG", Type::Pong},
			{"QUIT", Type::Quit},
			{"TOPIC", Type::Topic},
			{"WALLOPS", Type::Wallops},
		};
		auto it = mTypes.find(m_sCommand.AsUpper());
		if (it != mTypes.end()) {
			m_eType = it->second;
		} else {
			m_eType = Type::Unknown;
		}
	}
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <cstdlib>
#include <fstream>
#include <vector>
#include <cmath>
#include <sstream>
#include <stdio.h>
#include <unistd.h>
#include <algorithm>
using namespace std;

#include "Processes.h"
#include "Base.h"
#include "Command.h"
#include "Andand.h"
#include "Oror.h"

//Simple constructor
Processes::Processes()
{
    currCmds.resize(0);
}
//Simple destructor
Processes::~Processes()
{
    for(unsigned i = 0; i < currCmds.size(); ++i)
    {
        delete currCmds.at(i);
    }
}
//This executes all objects within the object's currCmds vector
int Processes::execute()
{
    int temp = 0;
    for(unsigned i = 0; i < currCmds.size(); ++i)
    {
        temp = currCmds.at(i)->execute();
    }
    return temp;
}
//Processes parses the code to split it into separate command lines
//should there be any semicolons present.
void Processes::parse(string input)
{
    vector<string> currCs;
    istringstream inSS(input);
    string currString;
    //Main loop for parsing input that contains semicolons
    while(input.find(";") != string::npos)
    {
        bool hashtag = false;
        bool semicolon = false;
        currCs.resize(0);
        while(!semicolon)
        {
            inSS >> currString;
            input.erase(0, currString.size() + 1);
            //Tests for hashtag/semicolon presence
            if(currString.find("#") != string::npos)
            {
                hashtag = true;
            }
            if(currString.find(";") != string::npos)
            {
                semicolon = true;
            }
            currString.erase(remove(currString.begin(), currString.end(), '"'),
                currString.end());
            if(!hashtag)
            {
                if(!semicolon)
                {
                    currCs.push_back(currString);
                }
                else
                {
                    currString.erase(currString.size() - 1);
                    currCs.push_back(currString);
                }
            }
        }
        //Here, we detect the presence of connectors.
        bool detected = false;
        for(unsigned j = 0; j < currCs.size(); ++j)
        {
            if(currCs.at(j) == "||" || currCs.at(j) == "&&")
            {
                detected = true;
                break;
            }
        }
        //If it detects one, it sends the vector to a loop
        //that runs until the end of the current command string.
        //It stops at the next connector, looks at the previous connector,
        //and creates objects and links them correspondingly.
        if(detected)
        {
            string prevConnector;
            string nextConnector;
            vector<string> firstCommand;
            unsigned i = 0;
            while(currCs.at(i) != "&&" && currCs.at(i) != "||")
            {
                firstCommand.push_back(currCs.at(i));
                ++i;
            }
            prevConnector = currCs.at(i);
            Base *temp3 = new Command(firstCommand);
            currCmds.push_back(temp3);
            ++i;
            vector<string> currCommand;
            for(;i < currCs.size(); ++i)
            {
                currCommand.push_back(currCs.at(i));
                if(currCs.at(i) == "&&" || currCs.at(i) == "||")
                {
                    currCommand.pop_back();
                    Base *temp = new Command(currCommand);
                    nextConnector = currCs.at(i);
                    if(prevConnector == "&&")
                    {
                        Base *temp2 = new Andand(currCmds.at(
                            currCmds.size() - 1), temp);
                        currCmds.pop_back();
                        currCmds.push_back(temp2);
                        currCommand.resize(0);
                    }
                    else
                    {
                        Base * temp2 = new Oror(currCmds.at(
                            currCmds.size() - 1), temp);
                        currCmds.pop_back();
                        currCmds.push_back(temp2);
                        currCommand.resize(0);
                    }
                }
            }
        }
        //This runs if there no connectors left after semicolon detecting.
        else {
            vector<string> currCommand;
            for(unsigned k = 0; k < currCs.size(); ++k)
            {
                currCommand.push_back(currCs.at(k));
            }
            Base *temp = new Command(currCommand);
            currCmds.push_back(temp);
        }
    }
    //Second loop that parses the remaining part of the input
    //Also, if the input never contained any semicolons,
    //the parse will go straight to this part of the code.
    currCs.resize(0);
    while(inSS >> currString)
    {
        currString.erase(remove(currString.begin(), currString.end(), '"'),
                currString.end());
        if(currString.find("#") != string::npos)
        {
            break;
        }
        currCs.push_back(currString);
    }
    //Again, detects whether the string has connectors.
    bool detected = false;
    for(unsigned j = 0; j < currCs.size(); ++j)
    {
        if(currCs.at(j) == "&&" || currCs.at(j) == "||")
        {
            detected = true;
            break;
        }
    }
    //If it detects them, it sends them to be parsed,
    //where connector objects are created after the first command is created
    //and subsequently linked until the end of parsing.
    if(detected)
    {
        string prevConnector;
        string nextConnector;
        vector<string> firstCommand;
        unsigned i = 0;
        while(currCs.at(i) != "&&" && currCs.at(i) != "||")
        {
            firstCommand.push_back(currCs.at(i));
            ++i;
        }
        prevConnector = currCs.at(i);
        Base *temp3 = new Command(firstCommand);
        currCmds.push_back(temp3);
        ++i;
        vector<string> currCommand;
        for(; i < currCs.size(); ++i)
        {
            currCommand.push_back(currCs.at(i));
            if(currCs.at(i) == "&&" || currCs.at(i) == "||")
            {
                currCommand.pop_back();
                Base *temp = new Command(currCommand);
                nextConnector = currCs.at(i);
                if(prevConnector == "&&")
                {
                    Base *temp2 = new Andand(currCmds.at(currCmds.size() - 1),
                        temp);
                    currCmds.pop_back();
                    currCmds.push_back(temp2);
                    currCommand.resize(0);
                }
                else
                {
                    Base * temp2 = new Oror(currCmds.at(currCmds.size() - 1),
                        temp);
                    currCmds.pop_back();
                    currCmds.push_back(temp2);
                    currCommand.resize(0);
                }
            }
        }
        Base * temp = new Command(currCommand);
        if(prevConnector == "&&")
            {
                Base *temp2 = new Andand(currCmds.at(currCmds.size() - 1),
                    temp);
                currCmds.pop_back();
                currCmds.push_back(temp2);
                currCommand.resize(0);
            }
        else
        {
            Base * temp2 = new Oror(currCmds.at(currCmds.size() - 1), temp);
            currCmds.pop_back();
            currCmds.push_back(temp2);
        }
    }
    else {
        vector<string> currCommand;
        for(unsigned k = 0; k < currCs.size(); ++k)
        {
            currCommand.push_back(currCs.at(k));
        }
        Base *temp = new Command(currCommand);
        currCmds.push_back(temp);
    }
}
//This is used to clean up the Processes vector in order to gather further
//input from the user.
void Processes::reset()
{
    for(unsigned i = 0; i < currCmds.size(); ++i)
    {
        delete currCmds.at(i);
    }
    this->currCmds.resize(0);

}<commit_msg>handles comments correctly<commit_after>#include <iostream>
#include <string>
#include <cstdlib>
#include <fstream>
#include <vector>
#include <cmath>
#include <sstream>
#include <stdio.h>
#include <unistd.h>
#include <algorithm>
using namespace std;

#include "Processes.h"
#include "Base.h"
#include "Command.h"
#include "Andand.h"
#include "Oror.h"

//Simple constructor
Processes::Processes()
{
    currCmds.resize(0);
}
//Simple destructor
Processes::~Processes()
{
    for(unsigned i = 0; i < currCmds.size(); ++i)
    {
        delete currCmds.at(i);
    }
}
//This executes all objects within the object's currCmds vector
int Processes::execute()
{
    int temp = 0;
    for(unsigned i = 0; i < currCmds.size(); ++i)
    {
        temp = currCmds.at(i)->execute();
    }
    return temp;
}
//Processes parses the code to split it into separate command lines
//should there be any semicolons present.
void Processes::parse(string input)
{
    vector<string> currCs;
    istringstream inSS(input);
    string currString;
    //Main loop for parsing input that contains semicolons
    while(input.find(";") != string::npos)
    {
        bool hashtag = false;
        bool semicolon = false;
        bool first = false;
        currCs.resize(0);
        while(!semicolon)
        {
            inSS >> currString;
            input.erase(0, currString.size() + 1);
            //Tests for hashtag/semicolon presence
            if(currString.find("#") != string::npos)
            {
                hashtag = true;
                if(currString.find("#") != 0 && (!first))
                {
                    currCs.push_back(currString);
                    first = true;
                }
            }
            if(currString.find(";") != string::npos)
            {
                semicolon = true;
            }
            string temp = "";
            for(unsigned g = 0; g < currString.size(); ++g)
            {
                if(currString.at(g) == '"')
                {
                    if(g > 0 && currString.at(g - 1) == '\\')
                    {
                        temp += currString.at(g);
                    }
                }
                else if(currString.at(g) != '\\')
                {
                    temp += currString.at(g);
                }
            }
            currString = temp;
            if(!hashtag)
            {
                if(!semicolon)
                {
                    currCs.push_back(currString);
                }
                else
                {
                    currString.erase(currString.size() - 1, 1);
                    currCs.push_back(currString);
                }
            }
        }
        //Here, we detect the presence of connectors.
        bool detected = false;
        for(unsigned j = 0; j < currCs.size(); ++j)
        {
            if(currCs.at(j) == "||" || currCs.at(j) == "&&")
            {
                detected = true;
                break;
            }
        }
        //If it detects one, it sends the vector to a loop
        //that runs until the end of the current command string.
        //It stops at the next connector, looks at the previous connector,
        //and creates objects and links them correspondingly.
        if(detected)
        {
            string prevConnector;
            string nextConnector;
            vector<string> firstCommand;
            unsigned i = 0;
            while(currCs.at(i) != "&&" && currCs.at(i) != "||")
            {
                firstCommand.push_back(currCs.at(i));
                ++i;
            }
            prevConnector = currCs.at(i);
            Base *temp3 = new Command(firstCommand);
            currCmds.push_back(temp3);
            ++i;
            vector<string> currCommand;
            for(;i < currCs.size(); ++i)
            {
                currCommand.push_back(currCs.at(i));
                if(currCs.at(i) == "&&" || currCs.at(i) == "||")
                {
                    currCommand.pop_back();
                    Base *temp = new Command(currCommand);
                    nextConnector = currCs.at(i);
                    if(prevConnector == "&&")
                    {
                        Base *temp2 = new Andand(currCmds.at(
                            currCmds.size() - 1), temp);
                        currCmds.pop_back();
                        currCmds.push_back(temp2);
                        currCommand.resize(0);
                    }
                    else
                    {
                        Base * temp2 = new Oror(currCmds.at(
                            currCmds.size() - 1), temp);
                        currCmds.pop_back();
                        currCmds.push_back(temp2);
                        currCommand.resize(0);
                    }
                }
            }
        }
        //This runs if there no connectors left after semicolon detecting.
        else {
            vector<string> currCommand;
            for(unsigned k = 0; k < currCs.size(); ++k)
            {
                currCommand.push_back(currCs.at(k));
            }
            Base *temp = new Command(currCommand);
            currCmds.push_back(temp);
        }
    }
    //Second loop that parses the remaining part of the input
    //Also, if the input never contained any semicolons,
    //the parse will go straight to this part of the code.
    currCs.resize(0);
    while(inSS >> currString)
    {
        string temp = "";
        for(unsigned g = 0; g < currString.size(); ++g)
        {
            if(currString.at(g) == '"')
            {
                if(g > 0 && currString.at(g - 1) == '\\')
                {
                    temp += currString.at(g);
                }
            }
            else if(currString.at(g) != '\\')
            {
                temp += currString.at(g);
            }
        }
        currString = temp;
        if(currString.find("#") != string::npos)
        {
            if(currString.find("#") != 0)
            {
                currCs.push_back(currString);
            }
            break;
        }
        currCs.push_back(currString);
    }
    //Again, detects whether the string has connectors.
    bool detected = false;
    for(unsigned j = 0; j < currCs.size(); ++j)
    {
        if(currCs.at(j) == "&&" || currCs.at(j) == "||")
        {
            detected = true;
            break;
        }
    }
    //If it detects them, it sends them to be parsed,
    //where connector objects are created after the first command is created
    //and subsequently linked until the end of parsing.
    if(detected)
    {
        string prevConnector;
        string nextConnector;
        vector<string> firstCommand;
        unsigned i = 0;
        while(currCs.at(i) != "&&" && currCs.at(i) != "||")
        {
            firstCommand.push_back(currCs.at(i));
            ++i;
        }
        prevConnector = currCs.at(i);
        Base *temp3 = new Command(firstCommand);
        currCmds.push_back(temp3);
        ++i;
        vector<string> currCommand;
        for(; i < currCs.size(); ++i)
        {
            currCommand.push_back(currCs.at(i));
            if(currCs.at(i) == "&&" || currCs.at(i) == "||")
            {
                currCommand.pop_back();
                Base *temp = new Command(currCommand);
                nextConnector = currCs.at(i);
                if(prevConnector == "&&")
                {
                    Base *temp2 = new Andand(currCmds.at(currCmds.size() - 1),
                        temp);
                    currCmds.pop_back();
                    currCmds.push_back(temp2);
                    currCommand.resize(0);
                }
                else
                {
                    Base * temp2 = new Oror(currCmds.at(currCmds.size() - 1),
                        temp);
                    currCmds.pop_back();
                    currCmds.push_back(temp2);
                    currCommand.resize(0);
                }
            }
        }
        Base * temp = new Command(currCommand);
        if(prevConnector == "&&")
            {
                Base *temp2 = new Andand(currCmds.at(currCmds.size() - 1),
                    temp);
                currCmds.pop_back();
                currCmds.push_back(temp2);
                currCommand.resize(0);
            }
        else
        {
            Base * temp2 = new Oror(currCmds.at(currCmds.size() - 1), temp);
            currCmds.pop_back();
            currCmds.push_back(temp2);
        }
    }
    else {
        vector<string> currCommand;
        for(unsigned k = 0; k < currCs.size(); ++k)
        {
            currCommand.push_back(currCs.at(k));
        }
        Base *temp = new Command(currCommand);
        currCmds.push_back(temp);
    }
}
//This is used to clean up the Processes vector in order to gather further
//input from the user.
void Processes::reset()
{
    for(unsigned i = 0; i < currCmds.size(); ++i)
    {
        delete currCmds.at(i);
    }
    this->currCmds.resize(0);

}<|endoftext|>


<commit_before>// SciTE - Scintilla based Text Editor
// PropSet.cxx - a java style properties file module
// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

// Maintain a dictionary of properties

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

#include "Platform.h"

#include "PropSet.h"

bool EqualCaseInsensitive(const char *a, const char *b) {
#if PLAT_GTK
	return 0 == strcasecmp(a, b);
#elif PLAT_WIN
	return 0 == stricmp(a, b);
#elif PLAT_WX
	return 0 == wxStricmp(a, b);
#endif
}

// Get a line of input. If end of line escaped with '\\' then continue reading.
static bool GetFullLine(const char *&fpc, int &lenData, char *s, int len) {
	bool continuation = true;
	s[0] = '\0';
	while ((len > 1) && lenData > 0) {
		char ch = *fpc;
		fpc++;
		lenData--;
		if ((ch == '\r') || (ch == '\n')) {
			if (!continuation) {
				if ((lenData > 0) && (ch == '\r') && ((*fpc) == '\n')) {
					// munch the second half of a crlf
					fpc++;
					lenData--;
				}
				*s = '\0';
				return true;
			}
		} else if ((ch == '\\') && (lenData > 0) && ((*fpc == '\r') || (*fpc == '\n'))) {
			continuation = true;
		} else {
			continuation = false;
			*s++ = ch;
			*s = '\0';
			len--;
		}
	}
	return false;
}

PropSet::PropSet() {
	superPS = 0;
	size = 10;
	used = 0;
	vals = new char * [size];
}

PropSet::~PropSet() {
	superPS = 0;
	Clear();
	delete []vals;
}

void PropSet::EnsureCanAddEntry() {
	if (used >= size - 2) {
		int newsize = size + 10;
		char **newvals = new char * [newsize];

		for (int i = 0; i < used; i++) {
			newvals[i] = vals[i];
		}
		delete []vals;
		vals = newvals;
		size = newsize;
	}
}

void PropSet::Set(const char *key, const char *val) {
	EnsureCanAddEntry();
	for (int i = 0; i < used; i += 2) {
		if (EqualCaseInsensitive(vals[i], key)) {
			// Replace current value
			delete [](vals[i + 1]);
			vals[i + 1] = StringDup(val);
			return;
		}
	}
	// Not found
	vals[used++] = StringDup(key);
	vals[used++] = StringDup(val);
}

void PropSet::Set(char *keyval) {
	char *eqat = strchr(keyval, '=');
	if (eqat) {
		*eqat = '\0';
		Set(keyval, eqat + 1);
		*eqat = '=';
	}
}

SString PropSet::Get(const char *key) {
	for (int i = 0; i < used; i += 2) {
		if (EqualCaseInsensitive(vals[i], key)) {
			return vals[i + 1];
		}
	}
	if (superPS) {
		// Failed here, so try in base property set
		return superPS->Get(key);
	} else {
		return "";
	}
}

int PropSet::GetInt(const char *key, int defaultValue) {
	SString val = Get(key);
	if (val.length())
		return val.value();
	else
		return defaultValue;
}

bool isprefix(const char *target, const char *prefix) {
	while (*target && *prefix) {
		if (toupper(*target) != toupper(*prefix))
			return false;
		target++;
		prefix++;
	}
	if (*prefix)
		return false;
	else
		return true;
}

bool issuffix(const char *target, const char *suffix) {
	int lentarget = strlen(target);
	int lensuffix = strlen(suffix);
	if (lensuffix > lentarget)
		return false;
	for (int i = lensuffix - 1; i >= 0; i--) {
		if (toupper(target[i + lentarget - lensuffix]) != toupper(suffix[i]))
			return false;
	}
	return true;
}

SString PropSet::GetWild(const char *keybase, const char *filename) {
	for (int i = 0; i < used; i += 2) {
		if (isprefix(vals[i], keybase)) {
			char *orgkeyfile = vals[i] + strlen(keybase);
			char *keyfile = NULL;

			if (strstr(orgkeyfile, "$(") == orgkeyfile) {
				char *cpendvar = strchr(orgkeyfile, ')');
				if (cpendvar) {
					int lenvar = cpendvar - orgkeyfile - 2; 	// Subtract the $()
					char *var = static_cast<char *>(malloc(lenvar + 1));
					strncpy(var, orgkeyfile + 2, lenvar);
					var[lenvar] = '\0';
					SString s = Get(var);
					free(var);
					keyfile = strdup(s.c_str());
				}
			}
			char *keyptr = keyfile;

			if (keyfile == NULL)
				keyfile = orgkeyfile;

			for (; ; ) {
				char *del = strchr(keyfile, ';');
				if (del == NULL)
					del = keyfile + strlen(keyfile);
				char delchr = *del;
				*del = '\0';
				if (*keyfile == '*') {
					if (issuffix(filename, keyfile + 1)) {
						*del = delchr;
						free(keyptr);
						return vals[i + 1];
					}
				} else if (EqualCaseInsensitive(keyfile, filename)) {
					*del = delchr;
					free(keyptr);
					return vals[i + 1];
				}
				if (delchr == '\0')
					break;
				*del = delchr;
				keyfile = del + 1;
			}
			free(keyptr);

			if (EqualCaseInsensitive(vals[i], keybase)) {
				return vals[i + 1];
			}
		}
	}
	if (superPS) {
		// Failed here, so try in base property set
		return superPS->GetWild(keybase, filename);
	} else {
		return "";
	}
}

SString PropSet::GetNewExpand(const char *keybase, const char *filename) {
	char *base = StringDup(GetWild(keybase, filename).c_str());
	char *cpvar = strstr(base, "$(");
	while (cpvar) {
		char *cpendvar = strchr(cpvar, ')');
		if (cpendvar) {
			int lenvar = cpendvar - cpvar - 2;  	// Subtract the $()
			char *var = new char[lenvar + 1];
			strncpy(var, cpvar + 2, lenvar);
			var[lenvar] = '\0';
			SString val = GetWild(var, filename);
			int newlenbase = strlen(base) + val.length() - lenvar;
			char *newbase = new char[newlenbase];
			strncpy(newbase, base, cpvar - base);
			strcpy(newbase + (cpvar - base), val.c_str());
			strcpy(newbase + (cpvar - base) + val.length(), cpendvar + 1);
			delete []var;
			delete []base;
			base = newbase;
		}
		cpvar = strstr(base, "$(");
	}
	SString sret = base;
	delete []base;
	return sret;
}

void PropSet::Clear() {
	for (int i = 0; i < used; i++) {
		delete [](vals[i]);
		vals[i] = 0;
	}
	used = 0;
}

void PropSet::ReadFromMemory(const char *data, int len) {
	if (len > 0) {
		const char *pd = data;
		char linebuf[60000];
		while (GetFullLine(pd, len, linebuf, sizeof(linebuf))) {
			if (isalpha(linebuf[0]))
				Set(linebuf);
		}
		// If there is a final line:
		if (isalpha(linebuf[0]))
			Set(linebuf);
	}
}

void PropSet::Read(const char *filename) {
	//printf("Opening properties <%s>\n", filename);
	Clear();
	char propsData[60000];
	FILE *rcfile = fopen(filename, "rb");
	if (rcfile) {
		int lenFile = fread(propsData, 1, sizeof(propsData), rcfile);
		fclose(rcfile);
		ReadFromMemory(propsData, lenFile);
	} else {
		//printf("Could not open <%s>\n", filename);
	}
}

static bool iswordsep(char ch, bool onlyLineEnds) {
	if (!isspace(ch))
		return false;
	if (!onlyLineEnds)
		return true;
	return ch == '\r' || ch == '\n';
}

// Creates an array that points into each word in the string and puts \0 terminators
// after each word.
static char **ArrayFromWordList(char *wordlist, bool onlyLineEnds = false) {
	char prev = '\n';
	int words = 0;
	for (int j = 0; wordlist[j]; j++) {
		if (!iswordsep(wordlist[j], onlyLineEnds) && iswordsep(prev, onlyLineEnds))
			words++;
		prev = wordlist[j];
	}
	char **keywords = new char * [words + 1];
	if (keywords) {
		words = 0;
		prev = '\0';
		int len = strlen(wordlist);
		for (int k = 0; k < len; k++) {
			if (!iswordsep(wordlist[k], onlyLineEnds)) {
				if (!prev) {
					keywords[words] = &wordlist[k];
					words++;
				}
			} else {
				wordlist[k] = '\0';
			}
			prev = wordlist[k];
		}
		keywords[words] = &wordlist[len];
	}
	return keywords;
}

void WordList::Clear() {
	if (words) {
		delete []words;
		delete []list;
	}
	words = 0;
	list = 0;
	len = 0;
}

void WordList::Set(const char *s) {
	len = 0;
	list = StringDup(s);
	words = ArrayFromWordList(list, onlyLineEnds);
}

char *WordList::Allocate(int size) {
	list = new char[size + 1];
	list[size] = '\0';
	return list;
}

void WordList::SetFromAllocated() {
	len = 0;
	words = ArrayFromWordList(list, onlyLineEnds);
}

// Shell sort based upon public domain C implementation by Raymond Gardner 1991
// Used here because of problems with mingw qsort.
static void SortWordList(char **words, unsigned int len) {
	unsigned int gap = len / 2;

	while (gap > 0) {
		unsigned int i = gap;
		while (i < len) {
			unsigned int j = i;
			char **a = words + j;
			do {
				j -= gap;
				char **b = a;
				a -= gap;
				if (strcmp(*a, *b) > 0) {
					char *tmp = *a;
					*a = *b;
					*b = tmp;
				} else {
					break;
				}
			} while (j >= gap);
			i++;
		}
		gap = gap / 2;
	}
}

bool WordList::InList(const char *s) {
	if (0 == words)
		return false;
	if (len == 0) {
		for (int i = 0; words[i][0]; i++)
			len++;
		SortWordList(words, len);
		for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++)
			starts[k] = -1;
		for (int l = len - 1; l >= 0; l--) {
			unsigned char indexChar = words[l][0];
			starts[indexChar] = l;
		}
	}
	unsigned char firstChar = s[0];
	int j = starts[firstChar];
	if (j >= 0) {
		while (words[j][0] == firstChar) {
			if (s[1] == words[j][1]) {
				const char *a = words[j] + 1;
				const char *b = s + 1;
				while (*a && *a == *b) {
					a++;
					b++;
				}
				if (!*a && !*b)
					return true;
			}
			j++;
		}
	}
	return false;
}
<commit_msg>Property set keys are now case sensitive.<commit_after>// SciTE - Scintilla based Text Editor
// PropSet.cxx - a java style properties file module
// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

// Maintain a dictionary of properties

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

#include "Platform.h"

#include "PropSet.h"

bool EqualCaseInsensitive(const char *a, const char *b) {
#if PLAT_GTK
	return 0 == strcasecmp(a, b);
#elif PLAT_WIN
	return 0 == stricmp(a, b);
#elif PLAT_WX
	return 0 == wxStricmp(a, b);
#endif
}

// Get a line of input. If end of line escaped with '\\' then continue reading.
static bool GetFullLine(const char *&fpc, int &lenData, char *s, int len) {
	bool continuation = true;
	s[0] = '\0';
	while ((len > 1) && lenData > 0) {
		char ch = *fpc;
		fpc++;
		lenData--;
		if ((ch == '\r') || (ch == '\n')) {
			if (!continuation) {
				if ((lenData > 0) && (ch == '\r') && ((*fpc) == '\n')) {
					// munch the second half of a crlf
					fpc++;
					lenData--;
				}
				*s = '\0';
				return true;
			}
		} else if ((ch == '\\') && (lenData > 0) && ((*fpc == '\r') || (*fpc == '\n'))) {
			continuation = true;
		} else {
			continuation = false;
			*s++ = ch;
			*s = '\0';
			len--;
		}
	}
	return false;
}

PropSet::PropSet() {
	superPS = 0;
	size = 10;
	used = 0;
	vals = new char * [size];
}

PropSet::~PropSet() {
	superPS = 0;
	Clear();
	delete []vals;
}

void PropSet::EnsureCanAddEntry() {
	if (used >= size - 2) {
		int newsize = size + 10;
		char **newvals = new char * [newsize];

		for (int i = 0; i < used; i++) {
			newvals[i] = vals[i];
		}
		delete []vals;
		vals = newvals;
		size = newsize;
	}
}

void PropSet::Set(const char *key, const char *val) {
	EnsureCanAddEntry();
	for (int i = 0; i < used; i += 2) {
		if (0 == strcmp(vals[i], key)) {
			// Replace current value
			delete [](vals[i + 1]);
			vals[i + 1] = StringDup(val);
			return;
		}
	}
	// Not found
	vals[used++] = StringDup(key);
	vals[used++] = StringDup(val);
}

void PropSet::Set(char *keyval) {
	char *eqat = strchr(keyval, '=');
	if (eqat) {
		*eqat = '\0';
		Set(keyval, eqat + 1);
		*eqat = '=';
	}
}

SString PropSet::Get(const char *key) {
	for (int i = 0; i < used; i += 2) {
		if (0 == strcmp(vals[i], key)) {
			return vals[i + 1];
		}
	}
	if (superPS) {
		// Failed here, so try in base property set
		return superPS->Get(key);
	} else {
		return "";
	}
}

int PropSet::GetInt(const char *key, int defaultValue) {
	SString val = Get(key);
	if (val.length())
		return val.value();
	else
		return defaultValue;
}

bool isprefix(const char *target, const char *prefix) {
	while (*target && *prefix) {
		if (*target != *prefix)
			return false;
		target++;
		prefix++;
	}
	if (*prefix)
		return false;
	else
		return true;
}

bool issuffix(const char *target, const char *suffix) {
	int lentarget = strlen(target);
	int lensuffix = strlen(suffix);
	if (lensuffix > lentarget)
		return false;
	for (int i = lensuffix - 1; i >= 0; i--) {
		if (target[i + lentarget - lensuffix] != suffix[i])
			return false;
	}
	return true;
}

SString PropSet::GetWild(const char *keybase, const char *filename) {
	for (int i = 0; i < used; i += 2) {
		if (isprefix(vals[i], keybase)) {
			char *orgkeyfile = vals[i] + strlen(keybase);
			char *keyfile = NULL;

			if (strstr(orgkeyfile, "$(") == orgkeyfile) {
				char *cpendvar = strchr(orgkeyfile, ')');
				if (cpendvar) {
					*cpendvar = '\0';
					SString s = Get(orgkeyfile + 2);
					*cpendvar= ')';
					keyfile = strdup(s.c_str());
				}
			}
			char *keyptr = keyfile;

			if (keyfile == NULL)
				keyfile = orgkeyfile;

			for (; ; ) {
				char *del = strchr(keyfile, ';');
				if (del == NULL)
					del = keyfile + strlen(keyfile);
				char delchr = *del;
				*del = '\0';
				if (*keyfile == '*') {
					if (issuffix(filename, keyfile + 1)) {
						*del = delchr;
						free(keyptr);
						return vals[i + 1];
					}
				} else if (0 == strcmp(keyfile, filename)) {
					*del = delchr;
					free(keyptr);
					return vals[i + 1];
				}
				if (delchr == '\0')
					break;
				*del = delchr;
				keyfile = del + 1;
			}
			free(keyptr);

			if (0 == strcmp(vals[i], keybase)) {
				return vals[i + 1];
			}
		}
	}
	if (superPS) {
		// Failed here, so try in base property set
		return superPS->GetWild(keybase, filename);
	} else {
		return "";
	}
}

SString PropSet::GetNewExpand(const char *keybase, const char *filename) {
	char *base = StringDup(GetWild(keybase, filename).c_str());
	char *cpvar = strstr(base, "$(");
	while (cpvar) {
		char *cpendvar = strchr(cpvar, ')');
		if (cpendvar) {
			int lenvar = cpendvar - cpvar - 2;  	// Subtract the $()
			char *var = new char[lenvar + 1];
			strncpy(var, cpvar + 2, lenvar);
			var[lenvar] = '\0';
			SString val = GetWild(var, filename);
			int newlenbase = strlen(base) + val.length() - lenvar;
			char *newbase = new char[newlenbase];
			strncpy(newbase, base, cpvar - base);
			strcpy(newbase + (cpvar - base), val.c_str());
			strcpy(newbase + (cpvar - base) + val.length(), cpendvar + 1);
			delete []var;
			delete []base;
			base = newbase;
		}
		cpvar = strstr(base, "$(");
	}
	SString sret = base;
	delete []base;
	return sret;
}

void PropSet::Clear() {
	for (int i = 0; i < used; i++) {
		delete [](vals[i]);
		vals[i] = 0;
	}
	used = 0;
}

void PropSet::ReadFromMemory(const char *data, int len) {
	if (len > 0) {
		const char *pd = data;
		char linebuf[60000];
		while (GetFullLine(pd, len, linebuf, sizeof(linebuf))) {
			if (isalpha(linebuf[0]))
				Set(linebuf);
		}
		// If there is a final line:
		if (isalpha(linebuf[0]))
			Set(linebuf);
	}
}

void PropSet::Read(const char *filename) {
	//printf("Opening properties <%s>\n", filename);
	Clear();
	char propsData[60000];
	FILE *rcfile = fopen(filename, "rb");
	if (rcfile) {
		int lenFile = fread(propsData, 1, sizeof(propsData), rcfile);
		fclose(rcfile);
		ReadFromMemory(propsData, lenFile);
	} else {
		//printf("Could not open <%s>\n", filename);
	}
}

static bool iswordsep(char ch, bool onlyLineEnds) {
	if (!isspace(ch))
		return false;
	if (!onlyLineEnds)
		return true;
	return ch == '\r' || ch == '\n';
}

// Creates an array that points into each word in the string and puts \0 terminators
// after each word.
static char **ArrayFromWordList(char *wordlist, bool onlyLineEnds = false) {
	char prev = '\n';
	int words = 0;
	for (int j = 0; wordlist[j]; j++) {
		if (!iswordsep(wordlist[j], onlyLineEnds) && iswordsep(prev, onlyLineEnds))
			words++;
		prev = wordlist[j];
	}
	char **keywords = new char * [words + 1];
	if (keywords) {
		words = 0;
		prev = '\0';
		int len = strlen(wordlist);
		for (int k = 0; k < len; k++) {
			if (!iswordsep(wordlist[k], onlyLineEnds)) {
				if (!prev) {
					keywords[words] = &wordlist[k];
					words++;
				}
			} else {
				wordlist[k] = '\0';
			}
			prev = wordlist[k];
		}
		keywords[words] = &wordlist[len];
	}
	return keywords;
}

void WordList::Clear() {
	if (words) {
		delete []words;
		delete []list;
	}
	words = 0;
	list = 0;
	len = 0;
}

void WordList::Set(const char *s) {
	len = 0;
	list = StringDup(s);
	words = ArrayFromWordList(list, onlyLineEnds);
}

char *WordList::Allocate(int size) {
	list = new char[size + 1];
	list[size] = '\0';
	return list;
}

void WordList::SetFromAllocated() {
	len = 0;
	words = ArrayFromWordList(list, onlyLineEnds);
}

// Shell sort based upon public domain C implementation by Raymond Gardner 1991
// Used here because of problems with mingw qsort.
static void SortWordList(char **words, unsigned int len) {
	unsigned int gap = len / 2;

	while (gap > 0) {
		unsigned int i = gap;
		while (i < len) {
			unsigned int j = i;
			char **a = words + j;
			do {
				j -= gap;
				char **b = a;
				a -= gap;
				if (strcmp(*a, *b) > 0) {
					char *tmp = *a;
					*a = *b;
					*b = tmp;
				} else {
					break;
				}
			} while (j >= gap);
			i++;
		}
		gap = gap / 2;
	}
}

bool WordList::InList(const char *s) {
	if (0 == words)
		return false;
	if (len == 0) {
		for (int i = 0; words[i][0]; i++)
			len++;
		SortWordList(words, len);
		for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++)
			starts[k] = -1;
		for (int l = len - 1; l >= 0; l--) {
			unsigned char indexChar = words[l][0];
			starts[indexChar] = l;
		}
	}
	unsigned char firstChar = s[0];
	int j = starts[firstChar];
	if (j >= 0) {
		while (words[j][0] == firstChar) {
			if (s[1] == words[j][1]) {
				const char *a = words[j] + 1;
				const char *b = s + 1;
				while (*a && *a == *b) {
					a++;
					b++;
				}
				if (!*a && !*b)
					return true;
			}
			j++;
		}
	}
	return false;
}
<|endoftext|>


<commit_before>#include "RE_tree.h"

enum {
	Regex_symbol = 0, A_symbol, B_symbol, C_symbol, D_symbol, E_symbol, F_symbol, e_symbol, sign_symbol, eof_symbol
};

class Grammar_node
{
public:
	int symbol;
	char value;
	Grammar_node *prt_node;
	Grammar_node *lch_node;
	Grammar_node *bro_node;
	Grammar_node(int s, Grammar_node *p, char v = '\0', Grammar_node *l = NULL, Grammar_node *b = NULL);
};

Grammar_node::Grammar_node(int s, Grammar_node *p, char v, Grammar_node *l, Grammar_node *b)
{
	symbol = s;
	prt_node = p;
	lch_node = l;
	bro_node = b;
	value = v;
}
void insert_production_one_child(Grammar_node *p, char child_symbol, char num = '\0')
{
	Grammar_node *p_child = new Grammar_node(child_symbol, p, num);
	p->lch_node = p_child;
}
void insert_production_two_child(Grammar_node *p, char lchild_symbol, char rchild_symbol)
{
	Grammar_node *p_left = new Grammar_node(lchild_symbol, p);
	Grammar_node *p_right = new Grammar_node(rchild_symbol, p);
	p->lch_node = p_left;
	p_left->bro_node = p_right;
}
void insert_production_three_child(Grammar_node *p, char lchild_symbol, char mchild_symbol, char rchild_symbol)
{
	Grammar_node *p_left = new Grammar_node(lchild_symbol, p);
	Grammar_node *p_middle = new Grammar_node(mchild_symbol, p);
	Grammar_node *p_right = new Grammar_node(rchild_symbol, p);
	p->lch_node = p_left;
	p_left->bro_node = p_middle;
	p_middle->bro_node = p_right;
}
/*
      RegEx -> B A
*/
void insert_production_Regex(char symbol, Grammar_node *p, char num)
{
	insert_production_two_child(p, B_symbol, A_symbol);
}
/*
      A -> | B A
        -> eof
*/
void insert_production_A(char symbol, Grammar_node *p, char num)
{
	if(symbol =='|')
		insert_production_three_child(p, '|', B_symbol, A_symbol);
	else
		insert_production_one_child(p, eof_symbol);
}
/*
      B -> D C
*/
void insert_production_B(char symbol, Grammar_node *p, char num)
{
	insert_production_two_child(p, D_symbol, C_symbol);
}
/*
      C -> D C
        -> eof
*/
void insert_production_C(char symbol, Grammar_node *p, char num)
{
	if(symbol == '(' || symbol == e_symbol)
		insert_production_two_child(p, B_symbol, A_symbol);
	else
		insert_production_one_child(p, eof_symbol);
}
/*
      D -> E F
*/
void insert_production_D(char symbol, Grammar_node *p, char num)
{
	insert_production_two_child(p, E_symbol, F_symbol);
}
/*
      E -> ( RegEx )
        -> element
*/
void insert_production_E(char symbol, Grammar_node *p, char num)
{
	if(symbol == '(')
		insert_production_three_child(p, '(', Regex_symbol, ')');
	else
		insert_production_one_child(p, e_symbol, num);
}
/*
     F -> *
       -> eof
*/
void insert_production_F(char symbol, Grammar_node *p, char num)
{
	if(symbol == '*')
		insert_production_one_child(p, '*');
	else
		insert_production_one_child(p, eof_symbol);
}

/*
    初始化终结符集合terminator,以及产生式数组insert
*/
RE_tree::RE_tree()
{
	terminator.insert('*');
	terminator.insert('|');
	terminator.insert('(');
	terminator.insert(')');
	terminator.insert(e_symbol);
	terminator.insert(eof_symbol);

	insert.push_back(insert_production_Regex);
	insert.push_back(insert_production_A);
	insert.push_back(insert_production_B);
	insert.push_back(insert_production_C);
	insert.push_back(insert_production_D);
	insert.push_back(insert_production_E);
	insert.push_back(insert_production_F);

	grammar_tree = new Grammar_node(Regex_symbol, NULL);

	regex_tree = new Regex_node;
}
/*
    析构函数,释放new表达式所分配的内存
*/
RE_tree::~RE_tree()
{
	delete_grammar_tree(grammar_tree);
	delete_regex_tree(regex_tree);
}
void RE_tree::delete_grammar_tree(Grammar_node *node)
{
	if(node == NULL)
		return;
	delete_grammar_tree(node->lch_node);
	delete_grammar_tree(node->bro_node);
	delete node;
}
void RE_tree::delete_regex_tree(Regex_node *node)
{
	if(node == NULL)
		return;
	delete_regex_tree(node->left);
	delete_regex_tree(node->right);
	delete node;
}
/*
    读入用户输入的正则表达式
*/
void RE_tree::input_regex()
{
	cout << "请输入正则表达式：" << endl;
	cin >> regex_string;
}
/*
    构建文法分析树
*/
void RE_tree::generate_tree()
{
	string::iterator pos_current = regex_string.begin();
	string::iterator pos_end = regex_string.end();
	Grammar_node * node = grammar_tree;
	char symbol_current = get_current_symbol(pos_current);
	while(true)
	{
		if(terminator.find(node->symbol) != terminator.end() && node->symbol == eof_symbol)
			node = get_next_node(node);
		else if(terminator.find(node->symbol) != terminator.end() && symbol_current == node->symbol)
		{
			node = get_next_node(node);
			pos_current++;	//这里不需要先判断是否pos_current != pos_end
			if(pos_current != pos_end)
				symbol_current = get_current_symbol(pos_current);
			else
				symbol_current = eof_symbol;

		}
		else if(terminator.find(node->symbol) == terminator.end())
		{
			insert[node->symbol](symbol_current, node, *pos_current);
			node = node->lch_node;
		}
		if(node == NULL && pos_current == pos_end)
			return;
	}
}
/*
    构建文法分析树辅助函数,获取下一个符号信息
*/
char RE_tree::get_current_symbol(string::iterator pos_current)
{
	if(terminator.find(*pos_current) != terminator.end())
		return *pos_current;
	else
		return e_symbol;
}
/*
    构建文法分析树辅助函数,获取下一个符号信息
*/
Grammar_node *RE_tree::get_next_node(Grammar_node *p)
{
	if(p == NULL)
		return NULL;
	if(p->bro_node != NULL)
		return p->bro_node;
	return get_next_node(p->prt_node);
}

/*
    简化分析树作为输出,之后用该树来构造NFA
*/
void RE_tree::simplification(Grammar_node *root, Regex_node *node)
{
	if(root->symbol == B_symbol)
	{
		if(root->bro_node->lch_node->symbol == eof_symbol)
			simplification(root->lch_node, node);
		else
		{
			node->value = ALT;
			Regex_node *left = new Regex_node;
			Regex_node *right = new Regex_node;
			node->left = left;
			node->right = right;
			simplification(root->lch_node, left);
			simplification(root->bro_node->lch_node->bro_node, right);
		}
	}
	else if(root->symbol == D_symbol)
	{
		if(root->bro_node->lch_node->symbol == eof_symbol)
			simplification(root->lch_node, node);
		else
		{
			node->value = CONCAT;
			Regex_node *left = new Regex_node;
			Regex_node *right = new Regex_node;
			node->left = left;
			node->right = right;
			simplification(root->lch_node, left);
			simplification(root->bro_node->lch_node, right);
		}
	}
	else if(root->symbol == E_symbol)
	{
		if(root->bro_node->lch_node->symbol == eof_symbol)
			simplification(root->lch_node, node);
		else
		{
			node->value = CLOSURE;
			Regex_node *left = new Regex_node;
			node->left = left;
			node->right = NULL;
			simplification(root->lch_node, left);
		}
	}
	else if(root->symbol == '(')
		simplification(root->bro_node, node);
	else if(root->symbol == e_symbol)
	{
		node->value = root->value;
		node->left = node->right = NULL;
	}
	else
		simplification(root->lch_node, node);
}
/*
    打印RE树,检查是否得到正确结果
*/
void RE_tree::print_tree(Regex_node *node)
{
	if(node == NULL)
		cout<<"NULL ";
	else
	{
		cout<<(int)node->value<<" ";
		print_tree(node->left);
		print_tree(node->right);
	}
}
/*
    执行输入的正则表达式到RE树的转换
*/
Regex_node *RE_tree::get_re_tree()
{
	input_regex();
	generate_tree();
	simplification(grammar_tree, regex_tree);
//	print_tree(regex_tree);
	return regex_tree;
}

/*
int main()
{
	RE_tree re;
	re.get_re_tree();
}
*/
<commit_msg>update<commit_after>#include "RE_tree.h"

enum {
	Regex_symbol = 0, A_symbol, B_symbol, C_symbol, D_symbol, E_symbol, F_symbol, e_symbol, sign_symbol, eof_symbol
};

class Grammar_node
{
public:
	int symbol;
	char value;
	Grammar_node *prt_node;
	Grammar_node *lch_node;
	Grammar_node *bro_node;
	Grammar_node(int s, Grammar_node *p, char v = '\0', Grammar_node *l = NULL, Grammar_node *b = NULL);
};

Grammar_node::Grammar_node(int s, Grammar_node *p, char v, Grammar_node *l, Grammar_node *b)
{
	symbol = s;
	prt_node = p;
	lch_node = l;
	bro_node = b;
	value = v;
}
void insert_production_one_child(Grammar_node *p, char child_symbol, char num = '\0')
{
	Grammar_node *p_child = new Grammar_node(child_symbol, p, num);
	p->lch_node = p_child;
}
void insert_production_two_child(Grammar_node *p, char lchild_symbol, char rchild_symbol)
{
	Grammar_node *p_left = new Grammar_node(lchild_symbol, p);
	Grammar_node *p_right = new Grammar_node(rchild_symbol, p);
	p->lch_node = p_left;
	p_left->bro_node = p_right;
}
void insert_production_three_child(Grammar_node *p, char lchild_symbol, char mchild_symbol, char rchild_symbol)
{
	Grammar_node *p_left = new Grammar_node(lchild_symbol, p);
	Grammar_node *p_middle = new Grammar_node(mchild_symbol, p);
	Grammar_node *p_right = new Grammar_node(rchild_symbol, p);
	p->lch_node = p_left;
	p_left->bro_node = p_middle;
	p_middle->bro_node = p_right;
}
/*
      RegEx -> B A
*/
void insert_production_Regex(char symbol, Grammar_node *p, char num)
{
	insert_production_two_child(p, B_symbol, A_symbol);
}
/*
      A -> | B A
        -> eof
*/
void insert_production_A(char symbol, Grammar_node *p, char num)
{
	if(symbol =='|')
		insert_production_three_child(p, '|', B_symbol, A_symbol);
	else
		insert_production_one_child(p, eof_symbol);
}
/*
      B -> D C
*/
void insert_production_B(char symbol, Grammar_node *p, char num)
{
	insert_production_two_child(p, D_symbol, C_symbol);
}
/*
      C -> D C
        -> eof
*/
void insert_production_C(char symbol, Grammar_node *p, char num)
{
	if(symbol == '(' || symbol == e_symbol)
		insert_production_two_child(p, B_symbol, A_symbol);
	else
		insert_production_one_child(p, eof_symbol);
}
/*
      D -> E F
*/
void insert_production_D(char symbol, Grammar_node *p, char num)
{
	insert_production_two_child(p, E_symbol, F_symbol);
}
/*
      E -> ( RegEx )
        -> element
*/
void insert_production_E(char symbol, Grammar_node *p, char num)
{
	if(symbol == '(')
		insert_production_three_child(p, '(', Regex_symbol, ')');
	else
		insert_production_one_child(p, e_symbol, num);
}
/*
     F -> *
       -> eof
*/
void insert_production_F(char symbol, Grammar_node *p, char num)
{
	if(symbol == '*')
		insert_production_one_child(p, '*');
	else
		insert_production_one_child(p, eof_symbol);
}

/*
    初始化终结符集合terminator,以及产生式数组insert
*/
RE_tree::RE_tree()
{
	terminator.insert('*');
	terminator.insert('|');
	terminator.insert('(');
	terminator.insert(')');
	terminator.insert(e_symbol);
	terminator.insert(eof_symbol);

	insert.resize(7, NULL);
	insert[0] = insert_production_Regex;
	insert[1] = insert_production_A;
	insert[2] = insert_production_B;
	insert[3] = insert_production_C;
	insert[4] = insert_production_D;
	insert[5] = insert_production_E;
	insert[6] = insert_production_F;

	grammar_tree = new Grammar_node(Regex_symbol, NULL);

	regex_tree = new Regex_node;
}
/*
    析构函数,释放new表达式所分配的内存
*/
RE_tree::~RE_tree()
{
	delete_grammar_tree(grammar_tree);
	delete_regex_tree(regex_tree);
}
void RE_tree::delete_grammar_tree(Grammar_node *node)
{
	if(node == NULL)
		return;
	delete_grammar_tree(node->lch_node);
	delete_grammar_tree(node->bro_node);
	delete node;
}
void RE_tree::delete_regex_tree(Regex_node *node)
{
	if(node == NULL)
		return;
	delete_regex_tree(node->left);
	delete_regex_tree(node->right);
	delete node;
}
/*
    读入用户输入的正则表达式
*/
void RE_tree::input_regex()
{
	cout << "请输入正则表达式：" << endl;
	cin >> regex_string;
}
/*
    构建文法分析树
*/
void RE_tree::generate_tree()
{
	string::iterator pos_current = regex_string.begin();
	string::iterator pos_end = regex_string.end();
	Grammar_node * node = grammar_tree;
	char symbol_current = get_current_symbol(pos_current);
	while(true)
	{
		if(terminator.find(node->symbol) != terminator.end() && node->symbol == eof_symbol)
			node = get_next_node(node);
		else if(terminator.find(node->symbol) != terminator.end() && symbol_current == node->symbol)
		{
			node = get_next_node(node);
			pos_current++;	//这里不需要先判断是否pos_current != pos_end
			if(pos_current != pos_end)
				symbol_current = get_current_symbol(pos_current);
			else
				symbol_current = eof_symbol;

		}
		else if(terminator.find(node->symbol) == terminator.end())
		{
			insert[node->symbol](symbol_current, node, *pos_current);
			node = node->lch_node;
		}
		if(node == NULL && pos_current == pos_end)
			return;
	}
}
/*
    构建文法分析树辅助函数,获取下一个符号信息
*/
char RE_tree::get_current_symbol(string::iterator pos_current)
{
	if(terminator.find(*pos_current) != terminator.end())
		return *pos_current;
	else
		return e_symbol;
}
/*
    构建文法分析树辅助函数,获取下一个符号信息
*/
Grammar_node *RE_tree::get_next_node(Grammar_node *p)
{
	if(p == NULL)
		return NULL;
	if(p->bro_node != NULL)
		return p->bro_node;
	return get_next_node(p->prt_node);
}

/*
    简化分析树作为输出,之后用该树来构造NFA
*/
void RE_tree::simplification(Grammar_node *root, Regex_node *node)
{
	if(root->symbol == B_symbol)
	{
		if(root->bro_node->lch_node->symbol == eof_symbol)
			simplification(root->lch_node, node);
		else
		{
			node->value = ALT;
			Regex_node *left = new Regex_node;
			Regex_node *right = new Regex_node;
			node->left = left;
			node->right = right;
			simplification(root->lch_node, left);
			simplification(root->bro_node->lch_node->bro_node, right);
		}
	}
	else if(root->symbol == D_symbol)
	{
		if(root->bro_node->lch_node->symbol == eof_symbol)
			simplification(root->lch_node, node);
		else
		{
			node->value = CONCAT;
			Regex_node *left = new Regex_node;
			Regex_node *right = new Regex_node;
			node->left = left;
			node->right = right;
			simplification(root->lch_node, left);
			simplification(root->bro_node->lch_node, right);
		}
	}
	else if(root->symbol == E_symbol)
	{
		if(root->bro_node->lch_node->symbol == eof_symbol)
			simplification(root->lch_node, node);
		else
		{
			node->value = CLOSURE;
			Regex_node *left = new Regex_node;
			node->left = left;
			node->right = NULL;
			simplification(root->lch_node, left);
		}
	}
	else if(root->symbol == '(')
		simplification(root->bro_node, node);
	else if(root->symbol == e_symbol)
	{
		node->value = root->value;
		node->left = node->right = NULL;
	}
	else
		simplification(root->lch_node, node);
}
/*
    打印RE树,检查是否得到正确结果
*/
void RE_tree::print_tree(Regex_node *node)
{
	if(node == NULL)
		cout<<"NULL ";
	else
	{
		cout<<(int)node->value<<" ";
		print_tree(node->left);
		print_tree(node->right);
	}
}
/*
    执行输入的正则表达式到RE树的转换
*/
Regex_node *RE_tree::get_re_tree()
{
	input_regex();
	generate_tree();
	simplification(grammar_tree, regex_tree);
//	print_tree(regex_tree);
	return regex_tree;
}

/*
int main()
{
	RE_tree re;
	re.get_re_tree();
}
*/
<|endoftext|>


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

#include "rpcserver.h"
#include "rpcclient.h"

#include "base58.h"
#include "netbase.h"

#include "test/test_eternity.h"

#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>

#include <univalue.h>

using namespace std;

UniValue createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
{
    UniValue result(UniValue::VARR);
    result.push_back(nRequired);
    UniValue addresses(UniValue::VARR);
    if (address1) addresses.push_back(address1);
    if (address2) addresses.push_back(address2);
    result.push_back(addresses);
    return result;
}

UniValue CallRPC(string args)
{
    vector<string> vArgs;
    boost::split(vArgs, args, boost::is_any_of(" \t"));
    string strMethod = vArgs[0];
    vArgs.erase(vArgs.begin());
    UniValue params = RPCConvertValues(strMethod, vArgs);

    rpcfn_type method = tableRPC[strMethod]->actor;
    try {
        UniValue result = (*method)(params, false);
        return result;
    }
    catch (const UniValue& objError) {
        throw runtime_error(find_value(objError, "message").get_str());
    }
}

BOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup)

BOOST_AUTO_TEST_CASE(rpc_rawparams)
{
    // Test raw transaction API argument handling
    UniValue r;

    BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error);

    BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), runtime_error);
    BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [] {}"));
    BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), runtime_error);

    BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error);
    string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
    BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx));
    BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193);
    BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1);
    BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0);
    BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error);

    BOOST_CHECK_THROW(CallRPC("signrawtransaction"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error);
    BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx));
    BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY"));
    BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY"));
    BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null badenum"), runtime_error);

    // Only check failure cases for sendrawtransaction, there's no network to send to...
    BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), runtime_error);
    BOOST_CHECK_THROW(CallRPC(string("sendrawtransaction ")+rawtx+" extra"), runtime_error);
}

BOOST_AUTO_TEST_CASE(rpc_rawsign)
{
    UniValue r;
    // input is a 1-of-2 multisig (so is output):
    string prevout =
      "[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\","
      "\"vout\":1,\"scriptPubKey\":\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\","
      "\"redeemScript\":\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f9216ecefca5b94d6df834e77e108f68e66f126044c052ae\"}]";
    r = CallRPC(string("createrawtransaction ")+prevout+" "+
      "{\"7iYoULd4BAqRsRt1UbD5qqna88JvKRU3SL\":11}");
    string notsigned = r.get_str();
    string privkey1 = "\"XEwTRsCX3CiWSQf8YmKMTeb84KyTbibkUv9mDTZHQ5MwuKG2ZzES\"";
    string privkey2 = "\"XDmZ7LjGd94Q81eUBjb2h6uV5Y14s7fmeXWEGYabfBJP8RVpprBu\"";
    r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]");
    BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false);
    r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]");
    BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true);
}

BOOST_AUTO_TEST_CASE(rpc_createraw_op_return)
{
    BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\"}"));

    // Allow more than one data transaction output
    BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\",\"data\":\"68656c6c6f776f726c64\"}"));

    // Key not "data" (bad address)
    BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), runtime_error);

    // Bad hex encoding of data output
    BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345\"}"), runtime_error);
    BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345g\"}"), runtime_error);

    // Data 81 bytes long
    BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081\"}"));
}

BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
{
    BOOST_CHECK(ValueFromAmount(0LL).write() == "0.00000000");
    BOOST_CHECK(ValueFromAmount(1LL).write() == "0.00000001");
    BOOST_CHECK(ValueFromAmount(17622195LL).write() == "0.17622195");
    BOOST_CHECK(ValueFromAmount(50000000LL).write() == "0.50000000");
    BOOST_CHECK(ValueFromAmount(89898989LL).write() == "0.89898989");
    BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
    BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
    BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");

    BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), "0.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount((COIN/10000)*123456789).write(), "12345.67890000");
    BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), "-1.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(-COIN/10).write(), "-0.10000000");

    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000000).write(), "100000000.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000000).write(), "10000000.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000000).write(), "1000000.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000).write(), "100000.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000).write(), "10000.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000).write(), "1000.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100).write(), "100.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10).write(), "10.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), "1.00000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10).write(), "0.10000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100).write(), "0.01000000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000).write(), "0.00100000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000).write(), "0.00010000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000).write(), "0.00001000");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000000).write(), "0.00000100");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000000).write(), "0.00000010");
    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000000).write(), "0.00000001");
}

static UniValue ValueFromString(const std::string &str)
{
    UniValue value;
    BOOST_CHECK(value.setNumStr(str));
    return value;
}

BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
{
    BOOST_CHECK_THROW(AmountFromValue(ValueFromString("-0.00000001")), UniValue);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0")), 0LL);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000000")), 0LL);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.50000000")), 50000000LL);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.89898989")), 89898989LL);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1.00000000")), 100000000LL);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.9999999")), 2099999999999990LL);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL);

    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1e-8")), COIN/100000000);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.1e-7")), COIN/100000000);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.01e-6")), COIN/100000000);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.0000000000000000000000000000000000000000000000000000000000000000000000000001e+68")), COIN/100000000);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("10000000000000000000000000000000000000000000000000000000000000000e-64")), COIN);
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000e64")), COIN);

    BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e-9")), UniValue); //should fail
    BOOST_CHECK_THROW(AmountFromValue(ValueFromString("0.000000019")), UniValue); //should fail
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001000000")), 1LL); //should pass, cut trailing 0
    BOOST_CHECK_THROW(AmountFromValue(ValueFromString("19e-9")), UniValue); //should fail
    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.19e-6")), 19); //should pass, leading 0 is present

    BOOST_CHECK_THROW(AmountFromValue(ValueFromString("92233720368.54775808")), UniValue); //overflow error
    BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e+11")), UniValue); //overflow error
    BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e11")), UniValue); //overflow error signless
    BOOST_CHECK_THROW(AmountFromValue(ValueFromString("93e+9")), UniValue); //overflow error
}

BOOST_AUTO_TEST_CASE(json_parse_errors)
{
    // Valid
    BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0);
    // Valid, with leading or trailing whitespace
    BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0);
    BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0);

    BOOST_CHECK_THROW(AmountFromValue(ParseNonRFCJSONValue(".19e-6")), std::runtime_error); //should fail, missing leading 0, therefore invalid JSON
    BOOST_CHECK_EQUAL(AmountFromValue(ParseNonRFCJSONValue("0.00000000000000000000000000000000000001e+30 ")), 1);
    // Invalid, initial garbage
    BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error);
    BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error);
    // Invalid, trailing garbage
    BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error);
    BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error);
    // BTC addresses should fail parsing
    BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error);
    BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error);
}

BOOST_AUTO_TEST_CASE(rpc_ban)
{
    BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));

    UniValue r;
    BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add")));
    BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); //portnumber for setban not allowed
    BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
    UniValue ar = r.get_array();
    UniValue o1 = ar[0].get_obj();
    UniValue adr = find_value(o1, "address");
    BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32");
    BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove")));;
    BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
    ar = r.get_array();
    BOOST_CHECK_EQUAL(ar.size(), 0);

    BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 1607731200 true")));
    BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
    ar = r.get_array();
    o1 = ar[0].get_obj();
    adr = find_value(o1, "address");
    UniValue banned_until = find_value(o1, "banned_until");
    BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
    BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check

    BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));

    BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 200")));
    BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
    ar = r.get_array();
    o1 = ar[0].get_obj();
    adr = find_value(o1, "address");
    banned_until = find_value(o1, "banned_until");
    BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
    int64_t now = GetTime();
    BOOST_CHECK(banned_until.get_int64() > now);
    BOOST_CHECK(banned_until.get_int64()-now <= 200);

    // must throw an exception because 127.0.0.1 is in already banned suubnet range
    BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.1 add")), runtime_error);

    BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0/24 remove")));;
    BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
    ar = r.get_array();
    BOOST_CHECK_EQUAL(ar.size(), 0);

    BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/255.255.0.0 add")));
    BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.1.1 add")), runtime_error);

    BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
    BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
    ar = r.get_array();
    BOOST_CHECK_EQUAL(ar.size(), 0);

    BOOST_CHECK_THROW(r = CallRPC(string("setban test add")), runtime_error); //invalid IP

    //IPv6 tests
    BOOST_CHECK_NO_THROW(r = CallRPC(string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add")));
    BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
    ar = r.get_array();
    o1 = ar[0].get_obj();
    adr = find_value(o1, "address");
    BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/128");

    BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
    BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add")));
    BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
    ar = r.get_array();
    o1 = ar[0].get_obj();
    adr = find_value(o1, "address");
    BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/30");

    BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
    BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add")));
    BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
    ar = r.get_array();
    o1 = ar[0].get_obj();
    adr = find_value(o1, "address");
    BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128");
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Delete rpc_tests.cpp<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2009-2011 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "condor_common.h"

// local includes
#include "ODSMongodbOps.h"
#include "ODSPoolUtils.h"

// seems boost meddles with assert defs
#include "assert.h"
#include "condor_config.h"
#include "../condor_collector.V6/CollectorPlugin.h"
#include "hashkey.h"
#include "../condor_collector.V6/collector.h"
#include "../condor_daemon_core.V6/condor_daemon_core.h"

using namespace std;
using namespace mongo;
using namespace plumage::etl;

struct ODSCollectorPlugin : public Service, CollectorPlugin
{
private:
	string m_name;
	string m_ip;

public:
	void
	initialize()
	{

		dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Initializing...\n");

		m_name = getPoolName();
		m_ip = my_ip_string();
	}

	void
	shutdown()
	{

		dprintf(D_FULLDEBUG, "ODSCollectorPlugin: shutting down...\n");

	}

	void
	update(int command, const ClassAd &ad)
	{
		MyString name;
		AdNameHashKey hashKey;

		// TODO: const hack for make*HashKey and dPrint
		ClassAd* _ad = const_cast<ClassAd *> (&ad);

		switch (command) {
		case UPDATE_STARTD_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_STARTD_AD\n");
			if (param_boolean("ODS_IGNORE_UPDATE_STARTD_AD", FALSE)) {
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Configured to ignore UPDATE_STARTD_AD\n");
				break;
			}

			if (!makeStartdAdHashKey(hashKey, _ad, NULL)) {
				dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
			}

			_ad->dPrint(D_FULLDEBUG|D_NOHEADER);

			break;
		case UPDATE_NEGOTIATOR_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_NEGOTIATOR_AD\n");
			if (param_boolean("ODS_IGNORE_UPDATE_NEGOTIATOR_AD", FALSE)) {
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Configured to ignore UPDATE_NEGOTIATOR_AD\n");
				break;
			}

			if (!makeNegotiatorAdHashKey(hashKey, _ad, NULL)) {
				dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
			}

			_ad->dPrint(D_FULLDEBUG|D_NOHEADER);

			break;
		case UPDATE_SCHEDD_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_SCHEDD_AD\n");
			if (param_boolean("ODS_IGNORE_UPDATE_SCHEDD_AD", FALSE)) {
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Configured to ignore UPDATE_SCHEDD_AD\n");
				break;
			}

			if (!makeScheddAdHashKey(hashKey, _ad, NULL)) {
				dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
			}

			_ad->dPrint(D_FULLDEBUG|D_NOHEADER);

			break;
		case UPDATE_GRID_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_GRID_AD\n");

			if (!makeGridAdHashKey(hashKey, _ad, NULL)) {
				dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
			}

			_ad->dPrint(D_FULLDEBUG|D_NOHEADER);

			break;
		case UPDATE_COLLECTOR_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_COLLECTOR_AD\n");
				// We could receive collector ads from many
				// collectors, but we only maintain our own. So,
				// ignore all others.
			char *str;
			if (ad.LookupString(ATTR_MY_ADDRESS, &str)) {
				string public_addr(str);
				free(str);

				if (public_addr != m_ip) {
					_ad->dPrint(D_FULLDEBUG|D_NOHEADER);
				}
			}
			break;
		default:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Unsupported command: %s\n",
					getCollectorCommandString(command));
		}
	}

	void
	invalidate(int command, const ClassAd &ad)
	{
		AdNameHashKey hashKey;

		switch (command) {
			case INVALIDATE_STARTD_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_STARTD_ADS\n");
				if (!makeStartdAdHashKey(hashKey, ((ClassAd *) &ad), NULL)) {
					dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
					return;
				}
				else {
					dprintf(D_FULLDEBUG, "'%'s startd key invalidated\n",HashString(hashKey).Value());
				}
			break;
			case INVALIDATE_NEGOTIATOR_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_NEGOTIATOR_ADS\n");
				if (!makeNegotiatorAdHashKey(hashKey, ((ClassAd *) &ad), NULL)) {
					dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
					return;
				}
				else {
					dprintf(D_FULLDEBUG, "%s negotiator key invalidated\n",HashString(hashKey).Value());
				}
			break;
			case INVALIDATE_SCHEDD_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_SCHEDD_ADS\n");
				if (!makeScheddAdHashKey(hashKey, ((ClassAd *) &ad), NULL)) {
					dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
					return;
				}
				else {
					dprintf(D_FULLDEBUG, "%s scheduler key invalidated\n",HashString(hashKey).Value());
				}
			break;
			case INVALIDATE_GRID_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_GRID_ADS\n");
				if (!makeGridAdHashKey(hashKey, ((ClassAd *) &ad), NULL)) {
					dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
					return;
				}
				else {
					dprintf(D_FULLDEBUG, "%s grid key invalidated\n",HashString(hashKey).Value());
				}
			break;
			case INVALIDATE_COLLECTOR_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_COLLECTOR_ADS\n");
			break;
			default:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Unsupported command: %s\n",
					getCollectorCommandString(command));
		}
	}

};

static ODSCollectorPlugin instance;
<commit_msg>Added initial db writer calls in collector plugin for ODS<commit_after>/*
 * Copyright 2009-2011 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "condor_common.h"

// local includes
#include "ODSMongodbOps.h"
#include "ODSPoolUtils.h"

// seems boost meddles with assert defs
#include "assert.h"
#include "condor_config.h"
#include "../condor_collector.V6/CollectorPlugin.h"
#include "hashkey.h"
#include "../condor_collector.V6/collector.h"
#include "../condor_daemon_core.V6/condor_daemon_core.h"

using namespace std;
using namespace mongo;
using namespace plumage::etl;

struct ODSCollectorPlugin : public Service, CollectorPlugin
{
	string m_name;
	string m_ip;
	ODSMongodbOps* m_writer;

	// TODO: figure out our update/inavlidation strategy
// 	typedef HashTable<AdNameHashKey, SlotObject *> SlotHashTable;
// 	SlotHashTable *startdAds;
// 	typedef HashTable<AdNameHashKey, NegotiatorObject *> NegotiatorHashTable;
// 	NegotiatorHashTable *negotiatorAds;
// 	typedef HashTable<AdNameHashKey, SchedulerObject *> SchedulerHashTable;
// 	SchedulerHashTable *schedulerAds;
// 	typedef HashTable<AdNameHashKey, GridObject *> GridHashTable;
// 	GridHashTable *gridAds;

	void
	initialize()
	{

		dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Initializing...\n");

		m_name = getPoolName();
		m_ip = my_ip_string();

		m_writer = new ODSMongodbOps("condor.collector");
		m_writer->init("localhost");
	}

	void
	shutdown()
	{

		dprintf(D_FULLDEBUG, "ODSCollectorPlugin: shutting down...\n");
		delete m_writer;

	}

	void
	update(int command, const ClassAd &ad)
	{
		MyString name;
		AdNameHashKey hashKey;

		// TODO: const hack for make*HashKey and dPrint
		ClassAd* _ad = const_cast<ClassAd *> (&ad);
		BSONObjBuilder key;
		key.append("k",m_name+"#"+time_t_to_String());

		switch (command) {
		case UPDATE_STARTD_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_STARTD_AD\n");
			if (param_boolean("ODS_IGNORE_UPDATE_STARTD_AD", FALSE)) {
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Configured to ignore UPDATE_STARTD_AD\n");
				break;
			}

			if (!makeStartdAdHashKey(hashKey, _ad, NULL)) {
				dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
			}

			m_writer->updateAd(key,_ad);

			break;
		case UPDATE_NEGOTIATOR_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_NEGOTIATOR_AD\n");
			if (param_boolean("ODS_IGNORE_UPDATE_NEGOTIATOR_AD", FALSE)) {
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Configured to ignore UPDATE_NEGOTIATOR_AD\n");
				break;
			}

			if (!makeNegotiatorAdHashKey(hashKey, _ad, NULL)) {
				dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
			}

			m_writer->updateAd(key,_ad);

			break;
		case UPDATE_SCHEDD_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_SCHEDD_AD\n");
			if (param_boolean("ODS_IGNORE_UPDATE_SCHEDD_AD", FALSE)) {
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Configured to ignore UPDATE_SCHEDD_AD\n");
				break;
			}

			if (!makeScheddAdHashKey(hashKey, _ad, NULL)) {
				dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
			}

			m_writer->updateAd(key,_ad);

			break;
		case UPDATE_GRID_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_GRID_AD\n");

			if (!makeGridAdHashKey(hashKey, _ad, NULL)) {
				dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
			}

			m_writer->updateAd(key,_ad);

			break;
		case UPDATE_COLLECTOR_AD:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received UPDATE_COLLECTOR_AD\n");
				// We could receive collector ads from many
				// collectors, but we only maintain our own. So,
				// ignore all others.
			char *str;
			if (ad.LookupString(ATTR_MY_ADDRESS, &str)) {
				string public_addr(str);
				free(str);

				if (public_addr != m_ip) {
					m_writer->updateAd(key,_ad);
				}
			}
			break;
		default:
			dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Unsupported command: %s\n",
					getCollectorCommandString(command));
		}
	}

	void
	invalidate(int command, const ClassAd &ad)
	{
		AdNameHashKey hashKey;

		// TODO: const hack for make*HashKey
		ClassAd* _ad = const_cast<ClassAd *> (&ad);

		switch (command) {
			case INVALIDATE_STARTD_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_STARTD_ADS\n");
				if (!makeStartdAdHashKey(hashKey, _ad, NULL)) {
					dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
					return;
				}
				else {
					dprintf(D_FULLDEBUG, "'%s' startd key invalidated\n",HashString(hashKey).Value());
				}
			break;
			case INVALIDATE_NEGOTIATOR_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_NEGOTIATOR_ADS\n");
				if (!makeNegotiatorAdHashKey(hashKey, _ad, NULL)) {
					dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
					return;
				}
				else {
					dprintf(D_FULLDEBUG, "%s negotiator key invalidated\n",HashString(hashKey).Value());
				}
			break;
			case INVALIDATE_SCHEDD_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_SCHEDD_ADS\n");
				if (!makeScheddAdHashKey(hashKey, _ad, NULL)) {
					dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
					return;
				}
				else {
					dprintf(D_FULLDEBUG, "%s scheduler key invalidated\n",HashString(hashKey).Value());
				}
			break;
			case INVALIDATE_GRID_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_GRID_ADS\n");
				if (!makeGridAdHashKey(hashKey, _ad, NULL)) {
					dprintf(D_FULLDEBUG, "Could not make hashkey -- ignoring ad\n");
					return;
				}
				else {
					dprintf(D_FULLDEBUG, "%s grid key invalidated\n",HashString(hashKey).Value());
				}
			break;
			case INVALIDATE_COLLECTOR_ADS:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Received INVALIDATE_COLLECTOR_ADS\n");
			break;
			default:
				dprintf(D_FULLDEBUG, "ODSCollectorPlugin: Unsupported command: %s\n",
					getCollectorCommandString(command));
		}
	}

};

static ODSCollectorPlugin instance;
<|endoftext|>