<commit_before>#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include "rshell.h"

using namespace std;

//Function which finds all the connectors in a char string and puts
//them in a queue
queue<char> findConnectors(char cmdCharString[])
{
    queue<char> connectorQueue;

    //Create a pointer pointing to the first occurance of a connector
    char* connectorPointer = strpbrk(cmdCharString, "|;&#");
    //Create a bool for keeping track of doubles
    bool conDoubCatcher = false;
    bool hashCatcher = false;

    //Loop to find all connectors and put them in the queue
    while (connectorPointer != NULL && hashCatcher == false)
    {
        //Store the characters for each connector
        if (!conDoubCatcher)
        {
            //Push connector character into command queue
            if ((*connectorPointer == '&' || *connectorPointer == '|') &&
                (*connectorPointer == *(connectorPointer + 1)))
            {
                connectorQueue.push(*connectorPointer);
                conDoubCatcher = true;
            }
            //Do not store single & or | and throw error
            else if ((*connectorPointer == '&' || *connectorPointer == '|') &&
                (*connectorPointer != *(connectorPointer + 1)))
            {
                cout << "ERROR: Invalid connector: " << *connectorPointer
                    << endl;
                exit(1);
            }
            else if (*connectorPointer == '#' && *(connectorPointer - 1) == ' ')
            {
                connectorQueue.push(*connectorPointer);
                hashCatcher = true;
            }
            else if (*connectorPointer == ';')
                connectorQueue.push(*connectorPointer);

        }
        else
            conDoubCatcher = false;
        //Go to the next occurance of a connector character
        connectorPointer = strpbrk(connectorPointer + 1, "|;&#");
    }
    //return queue with all found connectors
    return connectorQueue;
}

//Read through input until first non whitespace char and if hash then return
//true else return false
bool firstCharHash(string cmdString)
{
    if (cmdString.find_first_not_of(" \t\r\n") != string::npos &&
        cmdString.at(cmdString.find_first_not_of(" \t\r\n")) == '#')
        return true;
    return false;
}

//Finds the commands and stores them in a queue for later use
queue<char*> findCommands(char cmdCharString[])
{
    queue<char*> commandQueue;

    //Create pointers for finding commands and connectors
    char* conPointer = strpbrk(cmdCharString, "|;&#");
    char* cmdCharPointer = NULL;

    //point at commands based on # placement
    if (conPointer != NULL && *conPointer == '#' && *(conPointer - 1) != ' ')
    {
        cmdCharPointer = strtok(cmdCharString, "|;&");
    }
    else
    {
        cmdCharPointer = strtok(cmdCharString, "|;&#");
    }

    //Go through command cString and find commands
    while (cmdCharPointer != NULL)
    {
        //Get rid of space in begining of command
        while (*cmdCharPointer == ' ')
            cmdCharPointer++;

        //Add the command to the queue
        commandQueue.push(cmdCharPointer);

        //Add commands based on # placement
        if (conPointer != NULL)
        {
            conPointer = strpbrk(conPointer + 1, "|;&#");

            if (conPointer != NULL)
            {
                if(*conPointer == '#' && *(conPointer - 1) != ' ')
                    cmdCharPointer = strtok(NULL, "|;&");
                else
                    cmdCharPointer = strtok(NULL, "|;&#");
            }
            else
                cmdCharPointer = strtok(NULL, "|;&#");
        }
        else
            cmdCharPointer = strtok(NULL, "|;&#");
    }

    return commandQueue;
}

//Checks for starting connector with no previous command
void checkForStartingConnectors(char cmdCharString[])
{
    char* cmdCharPointer = cmdCharString;
    while (*cmdCharPointer == ' ')
            cmdCharPointer++;

    if (cmdCharPointer != NULL && (cmdCharPointer + 1) != NULL &&
        ((*cmdCharPointer == '&' && *(cmdCharPointer + 1) == '&') ||
        (*cmdCharPointer == '|' && *(cmdCharPointer + 1) == '|')))
    {
        cout << "ERROR: syntax error near unexpected token \'"
            << *cmdCharPointer << *cmdCharPointer << "\'" << endl;
        exit(1);
    }
    if (cmdCharPointer != NULL && *cmdCharPointer == ';')
    {
        cout << "ERROR: syntax error near unexpected token \'"
            << *cmdCharPointer << "\'" << endl;
        exit(1);
    }
}

//Creates a queue with the seperate arguments for a command
queue<char*> seperateCommand(char command[])
{
    queue<char*> sepComQueue;

    char* cmdCharPointer = strtok(command, " ");
    while (cmdCharPointer != NULL)
    {
        sepComQueue.push(cmdCharPointer);
        cmdCharPointer = strtok(NULL, " ");
    }

    return sepComQueue;
}

//Fills the 2D array with all arguments for running the command
void fillArgsArray(char** args, queue<char*> sepComQueue)
{
    unsigned i;
    for (i = 0; !sepComQueue.empty(); i++)
    {
        args[i] = sepComQueue.front();
        sepComQueue.pop();
    }
    args[i] = NULL;
}

//Runs the command and returns true if success else return false
bool runCommand(char** args)
{
    //Create bool to store whether command execution was a success
    bool ynSuccess = true;

    pid_t pid;
    int status;

    //Run fork and get parent id
    //If an error while forking occurs then say so and exit
    if ((pid = fork()) < 0)
    {
        cout << "ERROR: forking child process failed" << endl;
        exit(1);
    }
    else if (pid == 0)
    {
        //Run the command
        if(execvp(*args, args) < 0)
            perror(NULL);
    }
    else
    {
        //Wait for completion
        while (wait(&status) != pid);

        //Tests if command executed properly and if not sets success to false
        if (WIFEXITED(status))
        {
            if (WEXITSTATUS(status) != 0)
            {
                ynSuccess = false;
            }
        }
        else
        {
            ynSuccess = false;
        }
    }

    return ynSuccess;
}

//Function to run the shell
void rshell()
{
    while(true)
    {
        //Output Command prompt
        cout << "$ ";

        //Take in command and store it in a c-string
        string cmdString;
        getline(cin, cmdString);
        char* cmdCharString = new char[cmdString.size() + 1];
        strcpy(cmdCharString, cmdString.c_str());

        //For making testing with files better looking
        cout << endl;

        //Check for bad starting connectors
        checkForStartingConnectors(cmdCharString);

        //Catches specific case for Connector followed by # with no command
        //in between
        char* findHash = strpbrk(cmdCharString, "#");
        if (findHash != NULL && findHash != cmdCharString)
        {
            findHash--;
            while (*findHash == ' ' && findHash != cmdCharString)
                findHash--;
            if (*findHash == '&' || *findHash == '|')
            {
                cout << "ERROR: Command string ends in " << *findHash << *findHash
                    << " and has no following command" << endl;
                exit(1);
            }
        }

        //Check for two connectors with no command inbetween
        char* findDoubleConnectors = strpbrk(cmdCharString, ";&|");
        while (findDoubleConnectors != NULL && findDoubleConnectors != cmdCharString)
        {
            bool skipChecking = false;
            char* temp = findDoubleConnectors;
            if(*temp == ';')
                temp--;
            else if((*temp == '|' || *temp == '&') && (*(temp - 1) == *temp))
                temp = temp - 2;
            else if((*temp == '|' || *temp == '&') && (*(temp - 1) != *temp))
                skipChecking = true;

            while (*temp == ' ' && temp != cmdCharString && !skipChecking)
                temp--;
            if ((*temp == '&' || *temp == '|') && !skipChecking)
            {
                cout << "Syntax error near unexpected token \'" << *temp << *temp
                    << "\'" << endl;
                exit(1);
            }
            else if(*temp == ';' && !skipChecking)
            {
                cout << "Syntax error near unexpected token \'" << *temp << "\'"
                    << endl;
                exit(1);
            }
            findDoubleConnectors = strpbrk(findDoubleConnectors + 1, ";&|");
        }

        //Create a queue filled with connectors in order using findConnectors()
        queue<char> connectorCharQueue = findConnectors(cmdCharString);

        //Create a queue filled with commands in order using findCommands()
        queue<char*> commandQueue = findCommands(cmdCharString);

        //Makes sure the string doesn't end in a '&&' or '||' connector
        if (commandQueue.size() <= connectorCharQueue.size()
            && (connectorCharQueue.back() == '|'
            || connectorCharQueue.back() == '&'))
        {
            cout << "ERROR: Command string ends in " << connectorCharQueue.back()
                << connectorCharQueue.back() << " and has no following command"
                << endl;
            exit(1);
        }

        //Create a queue of connector* based on the connectorCharQueue
        queue<connector*> connectorQueue;
        while (!connectorCharQueue.empty() && connectorCharQueue.front() != '#')
        {
            if (connectorCharQueue.front() == '&')
            {
                andConnector* p = new andConnector();
                connectorQueue.push(p);
            }
            else if (connectorCharQueue.front() == '|')
            {
                orConnector* p = new orConnector();
                connectorQueue.push(p);
            }
            else
            {
                semiColonConnector* p = new semiColonConnector();
                connectorQueue.push(p);
            }
            connectorCharQueue.pop();
        }

        //Create bool to store whether command execution was a success
        bool ynSuccess = true;

        //Create a bool for checking if the first non space character is a hash
        bool firstHash = firstCharHash(cmdString);

        //Run commands until we run out of commands to call
        //Don't run if first char is a hash
        while (!commandQueue.empty() && !firstHash)
        {
            //Creates a queue with the seperate arguments for a command
            queue<char*> sepComQueue = seperateCommand(commandQueue.front());

            //Take one out of the queue of commands which need to be run
            commandQueue.pop();

            //Create a 2D array and store all arguments for command
            unsigned argsSize = sepComQueue.size() + 1;
            char** args = new char*[argsSize];
            fillArgsArray(args, sepComQueue);

            //If command is exit then exit
            if(strcmp(*args, "exit") == 0)
                exit(0);

            //Run the command and store whether it was a success
            ynSuccess = runCommand(args);

            //Handles connectors
            if (!connectorQueue.empty())
            {
                while (!connectorQueue.empty() && !commandQueue.empty() &&
                    !(connectorQueue.front()->isGoodOrNot(ynSuccess)))
                {
                    commandQueue.pop();
                    connector* p = connectorQueue.front();
                    delete p;
                    connectorQueue.pop();
                }

                connector* p = connectorQueue.front();
                delete p;
                connectorQueue.pop();

                //Special case to check for semi colon followed by # with no command
                //in between and at the end of command string
                if (connectorQueue.empty() && connectorCharQueue.front() == '#')
                {
                    char* sCHashCatcherString = new char[cmdString.size() + 1];
                    strcpy(sCHashCatcherString, commandQueue.front());
                    char* semiColonHashCatcher = strtok(sCHashCatcherString, " ");
                    if (semiColonHashCatcher == NULL)
                    {
                        delete[] sCHashCatcherString;
                        exit(0);
                    }
                    delete[] sCHashCatcherString;
                }
            }
            else if (!connectorCharQueue.empty())
            {
                if (connectorCharQueue.front() == '#')
                    exit(0);
            }

            delete[] args;
        }
        delete[] cmdCharString;
    }
}<commit_msg>Fixed the spacing so the added loop doesn't ruin the 80 character line limit<commit_after>#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include "rshell.h"

using namespace std;

//Function which finds all the connectors in a char string and puts
//them in a queue
queue<char> findConnectors(char cmdCharString[])
{
    queue<char> connectorQueue;

    //Create a pointer pointing to the first occurance of a connector
    char* connectorPointer = strpbrk(cmdCharString, "|;&#");
    //Create a bool for keeping track of doubles
    bool conDoubCatcher = false;
    bool hashCatcher = false;

    //Loop to find all connectors and put them in the queue
    while (connectorPointer != NULL && hashCatcher == false)
    {
        //Store the characters for each connector
        if (!conDoubCatcher)
        {
            //Push connector character into command queue
            if ((*connectorPointer == '&' || *connectorPointer == '|') &&
                (*connectorPointer == *(connectorPointer + 1)))
            {
                connectorQueue.push(*connectorPointer);
                conDoubCatcher = true;
            }
            //Do not store single & or | and throw error
            else if ((*connectorPointer == '&' || *connectorPointer == '|') &&
                (*connectorPointer != *(connectorPointer + 1)))
            {
                cout << "ERROR: Invalid connector: " << *connectorPointer
                    << endl;
                exit(1);
            }
            else if (*connectorPointer == '#' && *(connectorPointer - 1) == ' ')
            {
                connectorQueue.push(*connectorPointer);
                hashCatcher = true;
            }
            else if (*connectorPointer == ';')
                connectorQueue.push(*connectorPointer);

        }
        else
            conDoubCatcher = false;
        //Go to the next occurance of a connector character
        connectorPointer = strpbrk(connectorPointer + 1, "|;&#");
    }
    //return queue with all found connectors
    return connectorQueue;
}

//Read through input until first non whitespace char and if hash then return
//true else return false
bool firstCharHash(string cmdString)
{
    if (cmdString.find_first_not_of(" \t\r\n") != string::npos &&
        cmdString.at(cmdString.find_first_not_of(" \t\r\n")) == '#')
        return true;
    return false;
}

//Finds the commands and stores them in a queue for later use
queue<char*> findCommands(char cmdCharString[])
{
    queue<char*> commandQueue;

    //Create pointers for finding commands and connectors
    char* conPointer = strpbrk(cmdCharString, "|;&#");
    char* cmdCharPointer = NULL;

    //point at commands based on # placement
    if (conPointer != NULL && *conPointer == '#' && *(conPointer - 1) != ' ')
    {
        cmdCharPointer = strtok(cmdCharString, "|;&");
    }
    else
    {
        cmdCharPointer = strtok(cmdCharString, "|;&#");
    }

    //Go through command cString and find commands
    while (cmdCharPointer != NULL)
    {
        //Get rid of space in begining of command
        while (*cmdCharPointer == ' ')
            cmdCharPointer++;

        //Add the command to the queue
        commandQueue.push(cmdCharPointer);

        //Add commands based on # placement
        if (conPointer != NULL)
        {
            conPointer = strpbrk(conPointer + 1, "|;&#");

            if (conPointer != NULL)
            {
                if(*conPointer == '#' && *(conPointer - 1) != ' ')
                    cmdCharPointer = strtok(NULL, "|;&");
                else
                    cmdCharPointer = strtok(NULL, "|;&#");
            }
            else
                cmdCharPointer = strtok(NULL, "|;&#");
        }
        else
            cmdCharPointer = strtok(NULL, "|;&#");
    }

    return commandQueue;
}

//Checks for starting connector with no previous command
void checkForStartingConnectors(char cmdCharString[])
{
    char* cmdCharPointer = cmdCharString;
    while (*cmdCharPointer == ' ')
            cmdCharPointer++;

    if (cmdCharPointer != NULL && (cmdCharPointer + 1) != NULL &&
        ((*cmdCharPointer == '&' && *(cmdCharPointer + 1) == '&') ||
        (*cmdCharPointer == '|' && *(cmdCharPointer + 1) == '|')))
    {
        cout << "ERROR: syntax error near unexpected token \'"
            << *cmdCharPointer << *cmdCharPointer << "\'" << endl;
        exit(1);
    }
    if (cmdCharPointer != NULL && *cmdCharPointer == ';')
    {
        cout << "ERROR: syntax error near unexpected token \'"
            << *cmdCharPointer << "\'" << endl;
        exit(1);
    }
}

//Creates a queue with the seperate arguments for a command
queue<char*> seperateCommand(char command[])
{
    queue<char*> sepComQueue;

    char* cmdCharPointer = strtok(command, " ");
    while (cmdCharPointer != NULL)
    {
        sepComQueue.push(cmdCharPointer);
        cmdCharPointer = strtok(NULL, " ");
    }

    return sepComQueue;
}

//Fills the 2D array with all arguments for running the command
void fillArgsArray(char** args, queue<char*> sepComQueue)
{
    unsigned i;
    for (i = 0; !sepComQueue.empty(); i++)
    {
        args[i] = sepComQueue.front();
        sepComQueue.pop();
    }
    args[i] = NULL;
}

//Runs the command and returns true if success else return false
bool runCommand(char** args)
{
    //Create bool to store whether command execution was a success
    bool ynSuccess = true;

    pid_t pid;
    int status;

    //Run fork and get parent id
    //If an error while forking occurs then say so and exit
    if ((pid = fork()) < 0)
    {
        cout << "ERROR: forking child process failed" << endl;
        exit(1);
    }
    else if (pid == 0)
    {
        //Run the command
        if(execvp(*args, args) < 0)
            perror(NULL);
    }
    else
    {
        //Wait for completion
        while (wait(&status) != pid);

        //Tests if command executed properly and if not sets success to false
        if (WIFEXITED(status))
        {
            if (WEXITSTATUS(status) != 0)
            {
                ynSuccess = false;
            }
        }
        else
        {
            ynSuccess = false;
        }
    }

    return ynSuccess;
}

//Function to run the shell
void rshell()
{
    while(true)
    {
        //Output Command prompt
        cout << "$ ";

        //Take in command and store it in a c-string
        string cmdString;
        getline(cin, cmdString);
        char* cmdCharString = new char[cmdString.size() + 1];
        strcpy(cmdCharString, cmdString.c_str());

        //For making testing with files better looking
        cout << endl;

        //Check for bad starting connectors
        checkForStartingConnectors(cmdCharString);

        //Catches specific case for Connector followed by # with no command
        //in between
        char* findHash = strpbrk(cmdCharString, "#");
        if (findHash != NULL && findHash != cmdCharString)
        {
            findHash--;
            while (*findHash == ' ' && findHash != cmdCharString)
                findHash--;
            if (*findHash == '&' || *findHash == '|')
            {
                cout << "ERROR: Command string ends in " << *findHash
                    << *findHash << " and has no following command" << endl;
                exit(1);
            }
        }

        //Check for two connectors with no command inbetween
        char* findDoubleConnectors = strpbrk(cmdCharString, ";&|");
        while (findDoubleConnectors != NULL
            && findDoubleConnectors != cmdCharString)
        {
            bool skipChecking = false;
            char* temp = findDoubleConnectors;
            if(*temp == ';')
                temp--;
            else if((*temp == '|' || *temp == '&') && (*(temp - 1) == *temp))
                temp = temp - 2;
            else if((*temp == '|' || *temp == '&') && (*(temp - 1) != *temp))
                skipChecking = true;

            while (*temp == ' ' && temp != cmdCharString && !skipChecking)
                temp--;
            if ((*temp == '&' || *temp == '|') && !skipChecking)
            {
                cout << "Syntax error near unexpected token \'" << *temp
                    << *temp << "\'" << endl;
                exit(1);
            }
            else if(*temp == ';' && !skipChecking)
            {
                cout << "Syntax error near unexpected token \'" << *temp << "\'"
                    << endl;
                exit(1);
            }
            findDoubleConnectors = strpbrk(findDoubleConnectors + 1, ";&|");
        }

        //Create a queue filled with connectors in order using findConnectors()
        queue<char> connectorCharQueue = findConnectors(cmdCharString);

        //Create a queue filled with commands in order using findCommands()
        queue<char*> commandQueue = findCommands(cmdCharString);

        //Makes sure the string doesn't end in a '&&' or '||' connector
        if (commandQueue.size() <= connectorCharQueue.size()
            && (connectorCharQueue.back() == '|'
            || connectorCharQueue.back() == '&'))
        {
            cout << "ERROR: Command string ends in "
                << connectorCharQueue.back() << connectorCharQueue.back()
                << " and has no following command" << endl;
            exit(1);
        }

        //Create a queue of connector* based on the connectorCharQueue
        queue<connector*> connectorQueue;
        while (!connectorCharQueue.empty() && connectorCharQueue.front() != '#')
        {
            if (connectorCharQueue.front() == '&')
            {
                andConnector* p = new andConnector();
                connectorQueue.push(p);
            }
            else if (connectorCharQueue.front() == '|')
            {
                orConnector* p = new orConnector();
                connectorQueue.push(p);
            }
            else
            {
                semiColonConnector* p = new semiColonConnector();
                connectorQueue.push(p);
            }
            connectorCharQueue.pop();
        }

        //Create bool to store whether command execution was a success
        bool ynSuccess = true;

        //Create a bool for checking if the first non space character is a hash
        bool firstHash = firstCharHash(cmdString);

        //Run commands until we run out of commands to call
        //Don't run if first char is a hash
        while (!commandQueue.empty() && !firstHash)
        {
            //Creates a queue with the seperate arguments for a command
            queue<char*> sepComQueue = seperateCommand(commandQueue.front());

            //Take one out of the queue of commands which need to be run
            commandQueue.pop();

            //Create a 2D array and store all arguments for command
            unsigned argsSize = sepComQueue.size() + 1;
            char** args = new char*[argsSize];
            fillArgsArray(args, sepComQueue);

            //If command is exit then exit
            if(strcmp(*args, "exit") == 0)
                exit(0);

            //Run the command and store whether it was a success
            ynSuccess = runCommand(args);

            //Handles connectors
            if (!connectorQueue.empty())
            {
                while (!connectorQueue.empty() && !commandQueue.empty() &&
                    !(connectorQueue.front()->isGoodOrNot(ynSuccess)))
                {
                    commandQueue.pop();
                    connector* p = connectorQueue.front();
                    delete p;
                    connectorQueue.pop();
                }

                connector* p = connectorQueue.front();
                delete p;
                connectorQueue.pop();

                //Special case to check for semi colon followed by # with
                //no command in between and at the end of command string
                if (connectorQueue.empty() && connectorCharQueue.front() == '#')
                {
                    char* sCHashCatcherString = new char[cmdString.size() + 1];
                    strcpy(sCHashCatcherString, commandQueue.front());
                    char* semiColonHashCatcher
                        = strtok(sCHashCatcherString, " ");
                    if (semiColonHashCatcher == NULL)
                    {
                        delete[] sCHashCatcherString;
                        exit(0);
                    }
                    delete[] sCHashCatcherString;
                }
            }
            else if (!connectorCharQueue.empty())
            {
                if (connectorCharQueue.front() == '#')
                    exit(0);
            }

            delete[] args;
        }
        delete[] cmdCharString;
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// 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.

#ifndef IOX_DDS_INTERNAL_GATEWAY_CHANNEL_INL
#define IOX_DDS_INTERNAL_GATEWAY_CHANNEL_INL

namespace iox
{
namespace dds
{
// Typedefs
template <typename IceoryxTerminal>
using IceoryxTerminalPool = iox::cxx::ObjectPool<IceoryxTerminal, MAX_CHANNEL_NUMBER>;
template <typename DDSTerminal>
using DDSTerminalPool = iox::cxx::ObjectPool<DDSTerminal, MAX_CHANNEL_NUMBER>;

// Statics
template <typename IceoryxTerminal, typename DDSTerminal>
IceoryxTerminalPool<IceoryxTerminal> Channel<IceoryxTerminal, DDSTerminal>::s_iceoryxTerminals = IceoryxTerminalPool();
template <typename IceoryxTerminal, typename DDSTerminal>
DDSTerminalPool<DDSTerminal> Channel<IceoryxTerminal, DDSTerminal>::s_ddsTerminals = DDSTerminalPool();

template <typename IceoryxTerminal, typename DDSTerminal>
inline Channel<IceoryxTerminal, DDSTerminal>::Channel(const iox::capro::ServiceDescription& service,
                                                      const IceoryxTerminalPtr iceoryxTerminal,
                                                      const DDSTerminalPtr ddsTerminal) noexcept
    : m_service(service)
    , m_iceoryxTerminal(iceoryxTerminal)
    , m_ddsTerminal(ddsTerminal)
    , m_dataSize(0u)
{
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline Channel<IceoryxTerminal, DDSTerminal>::Channel(const iox::capro::ServiceDescription& service,
                                                      const IceoryxTerminalPtr iceoryxTerminal,
                                                      const DDSTerminalPtr ddsTerminal,
                                                      const uint64_t& dataSize) noexcept
    : m_service(service)
    , m_iceoryxTerminal(iceoryxTerminal)
    , m_ddsTerminal(ddsTerminal)
    , m_dataSize(dataSize)
{
}

template <typename IceoryxTerminal, typename DDSTerminal>
constexpr inline bool
Channel<IceoryxTerminal, DDSTerminal>::operator==(const Channel<IceoryxTerminal, DDSTerminal>& rhs) const noexcept
{
    return m_service == rhs.getService();
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline iox::cxx::expected<Channel<IceoryxTerminal, DDSTerminal>, ChannelError>
Channel<IceoryxTerminal, DDSTerminal>::create(const iox::capro::ServiceDescription& service) noexcept
{
    return create(service);
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline iox::cxx::expected<Channel<IceoryxTerminal, DDSTerminal>, ChannelError>
Channel<IceoryxTerminal, DDSTerminal>::create(const iox::capro::ServiceDescription& service,
                                              const uint64_t& dataSize) noexcept
{
    // Create objects in the pool.
    auto rawIceoryxTerminalPtr = s_iceoryxTerminals.create(std::forward<const iox::capro::ServiceDescription>(service));
    if (rawIceoryxTerminalPtr == nullptr)
    {
        return iox::cxx::error<ChannelError>(ChannelError::OBJECT_POOL_FULL);
    }
    auto rawDDSTerminalPtr =
        s_ddsTerminals.create(service.getServiceIDString(), service.getInstanceIDString(), service.getEventIDString());
    if (rawDDSTerminalPtr == nullptr)
    {
        return iox::cxx::error<ChannelError>(ChannelError::OBJECT_POOL_FULL);
    }

    // Wrap in smart pointer with custom deleter to ensure automatic cleanup.
    auto iceoryxTerminalPtr =
        IceoryxTerminalPtr(rawIceoryxTerminalPtr, [](IceoryxTerminal* const p) { s_iceoryxTerminals.free(p); });
    auto ddsTerminalPtr = DDSTerminalPtr(rawDDSTerminalPtr, [](DDSTerminal* const p) { s_ddsTerminals.free(p); });

    return iox::cxx::success<Channel>(Channel(service, iceoryxTerminalPtr, ddsTerminalPtr, dataSize));
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline iox::capro::ServiceDescription Channel<IceoryxTerminal, DDSTerminal>::getServiceDescription() const noexcept
{
    return m_service;
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline std::shared_ptr<IceoryxTerminal> Channel<IceoryxTerminal, DDSTerminal>::getIceoryxTerminal() const noexcept
{
    return m_iceoryxTerminal;
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline std::shared_ptr<DDSTerminal> Channel<IceoryxTerminal, DDSTerminal>::getDDSTerminal() const noexcept
{
    return m_ddsTerminal;
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline iox::cxx::optional<uint64_t> Channel<IceoryxTerminal, DDSTerminal>::getDataSize() const noexcept
{
    if (m_dataSize > 0)
    {
        return iox::cxx::make_optional<uint64_t>(m_dataSize);
    }
    else
    {
        return iox::cxx::nullopt_t();
    }
}

} // namespace dds
} // namespace iox

#endif
<commit_msg>iox-#65 Fix error from merge.<commit_after>// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// 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.

#ifndef IOX_DDS_INTERNAL_GATEWAY_CHANNEL_INL
#define IOX_DDS_INTERNAL_GATEWAY_CHANNEL_INL

namespace iox
{
namespace dds
{
// Typedefs
template <typename IceoryxTerminal>
using IceoryxTerminalPool = iox::cxx::ObjectPool<IceoryxTerminal, MAX_CHANNEL_NUMBER>;
template <typename DDSTerminal>
using DDSTerminalPool = iox::cxx::ObjectPool<DDSTerminal, MAX_CHANNEL_NUMBER>;

// Statics
template <typename IceoryxTerminal, typename DDSTerminal>
IceoryxTerminalPool<IceoryxTerminal> Channel<IceoryxTerminal, DDSTerminal>::s_iceoryxTerminals = IceoryxTerminalPool();
template <typename IceoryxTerminal, typename DDSTerminal>
DDSTerminalPool<DDSTerminal> Channel<IceoryxTerminal, DDSTerminal>::s_ddsTerminals = DDSTerminalPool();

template <typename IceoryxTerminal, typename DDSTerminal>
inline Channel<IceoryxTerminal, DDSTerminal>::Channel(const iox::capro::ServiceDescription& service,
                                                      const IceoryxTerminalPtr iceoryxTerminal,
                                                      const DDSTerminalPtr ddsTerminal) noexcept
    : m_service(service)
    , m_iceoryxTerminal(iceoryxTerminal)
    , m_ddsTerminal(ddsTerminal)
    , m_dataSize(0u)
{
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline Channel<IceoryxTerminal, DDSTerminal>::Channel(const iox::capro::ServiceDescription& service,
                                                      const IceoryxTerminalPtr iceoryxTerminal,
                                                      const DDSTerminalPtr ddsTerminal,
                                                      const uint64_t& dataSize) noexcept
    : m_service(service)
    , m_iceoryxTerminal(iceoryxTerminal)
    , m_ddsTerminal(ddsTerminal)
    , m_dataSize(dataSize)
{
}

template <typename IceoryxTerminal, typename DDSTerminal>
constexpr inline bool
Channel<IceoryxTerminal, DDSTerminal>::operator==(const Channel<IceoryxTerminal, DDSTerminal>& rhs) const noexcept
{
    return m_service == rhs.getService();
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline iox::cxx::expected<Channel<IceoryxTerminal, DDSTerminal>, ChannelError>
Channel<IceoryxTerminal, DDSTerminal>::create(const iox::capro::ServiceDescription& service) noexcept
{
    return create(service, 0u);
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline iox::cxx::expected<Channel<IceoryxTerminal, DDSTerminal>, ChannelError>
Channel<IceoryxTerminal, DDSTerminal>::create(const iox::capro::ServiceDescription& service,
                                              const uint64_t& dataSize) noexcept
{
    // Create objects in the pool.
    auto rawIceoryxTerminalPtr = s_iceoryxTerminals.create(std::forward<const iox::capro::ServiceDescription>(service));
    if (rawIceoryxTerminalPtr == nullptr)
    {
        return iox::cxx::error<ChannelError>(ChannelError::OBJECT_POOL_FULL);
    }
    auto rawDDSTerminalPtr =
        s_ddsTerminals.create(service.getServiceIDString(), service.getInstanceIDString(), service.getEventIDString());
    if (rawDDSTerminalPtr == nullptr)
    {
        return iox::cxx::error<ChannelError>(ChannelError::OBJECT_POOL_FULL);
    }

    // Wrap in smart pointer with custom deleter to ensure automatic cleanup.
    auto iceoryxTerminalPtr =
        IceoryxTerminalPtr(rawIceoryxTerminalPtr, [](IceoryxTerminal* const p) { s_iceoryxTerminals.free(p); });
    auto ddsTerminalPtr = DDSTerminalPtr(rawDDSTerminalPtr, [](DDSTerminal* const p) { s_ddsTerminals.free(p); });

    return iox::cxx::success<Channel>(Channel(service, iceoryxTerminalPtr, ddsTerminalPtr, dataSize));
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline iox::capro::ServiceDescription Channel<IceoryxTerminal, DDSTerminal>::getServiceDescription() const noexcept
{
    return m_service;
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline std::shared_ptr<IceoryxTerminal> Channel<IceoryxTerminal, DDSTerminal>::getIceoryxTerminal() const noexcept
{
    return m_iceoryxTerminal;
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline std::shared_ptr<DDSTerminal> Channel<IceoryxTerminal, DDSTerminal>::getDDSTerminal() const noexcept
{
    return m_ddsTerminal;
}

template <typename IceoryxTerminal, typename DDSTerminal>
inline iox::cxx::optional<uint64_t> Channel<IceoryxTerminal, DDSTerminal>::getDataSize() const noexcept
{
    if (m_dataSize > 0)
    {
        return iox::cxx::make_optional<uint64_t>(m_dataSize);
    }
    else
    {
        return iox::cxx::nullopt_t();
    }
}

} // namespace dds
} // namespace iox

#endif
<|endoftext|>


<commit_before>#include <bitcoin/script.hpp>

#include <stack>

#include <bitcoin/messages.hpp>
#include <bitcoin/transaction.hpp>
#include <bitcoin/util/elliptic_curve_key.hpp>
#include <bitcoin/util/assert.hpp>
#include <bitcoin/util/logger.hpp>
#include <bitcoin/util/ripemd.hpp>
#include <bitcoin/util/sha256.hpp>

namespace libbitcoin {

void script::join(const script& other)
{
    operations_.insert(operations_.end(),
        other.operations_.begin(), other.operations_.end());
}

void script::push_operation(operation oper)
{
    operations_.push_back(oper);
}

const operation_stack& script::operations() const
{
    return operations_;
}

bool script::run(script input_script,
    const message::transaction& parent_tx, uint32_t input_index)
{
    stack_.clear();
    input_script.stack_.clear();
    if (!input_script.run(parent_tx, input_index))
        return false;
    stack_ = input_script.stack_;
    if (!run(parent_tx, input_index))
        return false;
    if (stack_.size() != 0)
    {
        // TODO: OP_CHECKSIG actually leaves stuff on stack
        log_error() << "Script left junk on top of the stack";
        return false;
    }
    return true;
}

bool script::run(const message::transaction& parent_tx, uint32_t input_index)
{
    for (const operation oper: operations_)
    {
        //log_debug() << "Run: " << opcode_to_string(oper.code);
        if (!run_operation(oper, parent_tx, input_index))
            return false;
        if (oper.data.size() > 0)
        {
            BITCOIN_ASSERT(oper.code == opcode::special ||
                oper.code == opcode::pushdata1 ||
                oper.code == opcode::pushdata2 ||
                oper.code == opcode::pushdata4);
            stack_.push_back(oper.data);
        }
    }
    return true;
}

data_chunk script::pop_stack()
{
    data_chunk value = stack_.back();
    stack_.pop_back();
    return value;
}

bool script::op_dup()
{
    if (stack_.size() < 1)
        return false;
    stack_.push_back(stack_.back());
    return true;
}

bool script::op_hash160()
{
    if (stack_.size() < 1)
        return false;
    data_chunk data = pop_stack();
    short_hash hash = generate_ripemd_hash(data);
    data_chunk raw_hash(hash.begin(), hash.end());
    stack_.push_back(raw_hash);
    return true;
}

bool script::op_equalverify()
{
    if (stack_.size() < 2)
        return false;
    return pop_stack() == pop_stack();
}

inline void nullify_input_sequences(
    message::transaction_input_list& inputs, uint32_t except_input)
{
    for (size_t i = 0; i < inputs.size(); ++i)
        if (i != except_input)
            inputs[i].sequence = 0;
}

bool script::op_checksig(message::transaction parent_tx, uint32_t input_index)
{
    BITCOIN_ASSERT(input_index < parent_tx.inputs.size());
    if (stack_.size() < 2)
        return false;
    data_chunk pubkey = pop_stack(), signature = pop_stack();

    script script_code;
    for (operation op: operations_)
    {
        if (op.data == signature || op.code == opcode::codeseparator)
            continue;
        script_code.push_operation(op);
    }

    elliptic_curve_key key;
    key.set_public_key(pubkey);

    uint32_t hash_type = 0;
    hash_type = signature.back();
    signature.pop_back();

    if ((hash_type & 0x1f) == sighash::none)
    {
        parent_tx.outputs.clear();
        nullify_input_sequences(parent_tx.inputs, input_index);
    }
    else if ((hash_type & 0x1f) == sighash::single)
    {
        uint32_t output_index = input_index;
        if (output_index >= parent_tx.outputs.size())
        {
            log_error() << "sighash::single the output_index is out of range";
            return false;
        }
        parent_tx.outputs.resize(output_index + 1);
        for (message::transaction_output& output: parent_tx.outputs)
        {
            output.value = ~0;
            output.output_script = script();
        }
        nullify_input_sequences(parent_tx.inputs, input_index);
    }

    if (hash_type & sighash::anyone_can_pay)
    {
        parent_tx.inputs[0] = parent_tx.inputs[input_index];
        parent_tx.inputs.resize(1);
    }

    if (input_index >= parent_tx.inputs.size())
    {
        log_fatal() << "script::op_checksig() : input_index " << input_index
                << " is out of range.";
        return false;
    }

    message::transaction tx_tmp = parent_tx;
    // Blank all other inputs' signatures
    for (message::transaction_input& input: tx_tmp.inputs)
        input.input_script = script();
    tx_tmp.inputs[input_index].input_script = script_code;

    hash_digest tx_hash = hash_transaction(tx_tmp, hash_type);
    return key.verify(tx_hash, signature);
}

bool script::run_operation(operation op,
        const message::transaction& parent_tx, uint32_t input_index)
{
    switch (op.code)
    {
        case opcode::special:
            return true;

        case opcode::pushdata1:
            BITCOIN_ASSERT(op.data.size() == static_cast<size_t>(op.code));
            return true;

        case opcode::pushdata2:
            BITCOIN_ASSERT(op.data.size() == static_cast<size_t>(op.code));
            return true;

        case opcode::pushdata4:
            BITCOIN_ASSERT(op.data.size() == static_cast<size_t>(op.code));
            return true;

        case opcode::nop:
            return true;

        case opcode::dup:
            return op_dup();

        case opcode::hash160:
            return op_hash160();

        case opcode::equalverify:
            return op_equalverify();

        case opcode::checksig:
            return op_checksig(parent_tx, input_index);

        default:
            log_fatal() << "Umimplemented operation <none "
                << static_cast<int>(op.code) << ">";
            break;
    }
    return false;
}

transaction_type script::type() const
{
    return transaction_type::normal;
}

bool script::matches_template(operation_stack templ) const
{
    return templ.size() == 0;
}

std::string script::pretty() const
{
    std::ostringstream ss;
    for (auto it = operations_.begin(); it != operations_.end(); ++it)
    {
        if (it != operations_.begin())
            ss << " ";
        const operation& op = *it;
        if (op.data.size() == 0)
            ss << opcode_to_string(op.code);
        else
        {
            ss << "[ " << pretty_hex(op.data) << " ]";
        }
    }
    return ss.str();
}

std::string opcode_to_string(opcode code)
{
    switch (code)
    {
        case opcode::special:
            return "special";
        case opcode::pushdata1:
            return "pushdata1";
        case opcode::pushdata2:
            return "pushdata2";
        case opcode::pushdata4:
            return "pushdata4";
        case opcode::nop:
            return "nop";
        case opcode::dup:
            return "dup";
        case opcode::hash160:
            return "hash160";
        case opcode::equalverify:
            return "equalverify";
        case opcode::checksig:
            return "checksig";
        default:
        {
            std::ostringstream ss;
            ss << "<none " << static_cast<int>(code) << ">";
            return ss.str();
        }
    }
}
opcode string_to_opcode(std::string code_repr)
{
    if (code_repr == "special")
        return opcode::special;
    else if (code_repr == "pushdata1")
        return opcode::pushdata1;
    else if (code_repr == "pushdata2")
        return opcode::pushdata2;
    else if (code_repr == "pushdata4")
        return opcode::pushdata4;
    else if (code_repr == "nop")
        return opcode::nop;
    else if (code_repr == "dup")
        return opcode::dup;
    else if (code_repr == "hash160")
        return opcode::hash160;
    else if (code_repr == "equalverify")
        return opcode::equalverify;
    else if (code_repr == "checksig")
        return opcode::checksig;
    // ERROR: unknown...
    return opcode::bad_operation;
}

size_t number_of_bytes_from_opcode(opcode code, byte raw_byte)
{
    if (code == opcode::special)
        return raw_byte;
    else if (code == opcode::pushdata1 || code == opcode::pushdata2
            || code == opcode::pushdata4)
        return static_cast<size_t>(code);
    else
        return 0;
}

script parse_script(const data_chunk& raw_script)
{
    script script_object;
    for (auto it = raw_script.begin(); it != raw_script.end(); ++it)
    {
        byte raw_byte = *it;
        operation op;
        op.code = static_cast<opcode>(raw_byte);
        // raw_byte is unsigned so it's always >= 0
        if (raw_byte <= 75)
            op.code = opcode::special;
        size_t read_n_bytes = number_of_bytes_from_opcode(op.code, raw_byte);

        for (size_t byte_count = 0; byte_count < read_n_bytes; ++byte_count)
        {
            ++it;
            if (it == raw_script.cend())
            {
                log_warning() << "Premature end of script.";
                return script();
            }
            op.data.push_back(*it);
        }

        script_object.push_operation(op);

    }
    return script_object;
}

data_chunk save_script(const script& scr)
{
    data_chunk raw_script;
    for (operation op: scr.operations())
    {
        byte raw_byte = static_cast<byte>(op.code);
        if (op.code == opcode::special)
            raw_byte = op.data.size();
        raw_script.push_back(raw_byte);
        extend_data(raw_script, op.data);
    }
    return raw_script;
}

script script_from_pretty(const std::string& pretty_script)
{
    script script_object;
    std::stringstream splitter;
    splitter << pretty_script;
    std::string token;
    while (splitter >> token)
    {
        operation op;
        if (token == "[")
        {
            while ((splitter >> token) && token != "]")
            {
                std::istringstream to_int(token);
                int value;
                to_int >> std::hex >> value;
                op.data.push_back(value);
            }
            if (token != "]")
            {
                log_warning() << "Premature end of script.";
                return script();
            }
            op.code = opcode::special;
        }
        else
        {
            op.code = string_to_opcode(token);
        }
        script_object.push_operation(op);
    }
    return script_object;
}

} // libbitcoin

<commit_msg>pushdata1/2/4<commit_after>#include <bitcoin/script.hpp>

#include <stack>

#include <bitcoin/messages.hpp>
#include <bitcoin/transaction.hpp>
#include <bitcoin/util/elliptic_curve_key.hpp>
#include <bitcoin/util/assert.hpp>
#include <bitcoin/util/logger.hpp>
#include <bitcoin/util/ripemd.hpp>
#include <bitcoin/util/sha256.hpp>

namespace libbitcoin {

void script::join(const script& other)
{
    operations_.insert(operations_.end(),
        other.operations_.begin(), other.operations_.end());
}

void script::push_operation(operation oper)
{
    operations_.push_back(oper);
}

const operation_stack& script::operations() const
{
    return operations_;
}

bool script::run(script input_script,
    const message::transaction& parent_tx, uint32_t input_index)
{
    stack_.clear();
    input_script.stack_.clear();
    if (!input_script.run(parent_tx, input_index))
        return false;
    stack_ = input_script.stack_;
    if (!run(parent_tx, input_index))
        return false;
    if (stack_.size() != 0)
    {
        // TODO: OP_CHECKSIG actually leaves stuff on stack
        log_error() << "Script left junk on top of the stack";
        return false;
    }
    return true;
}

bool script::run(const message::transaction& parent_tx, uint32_t input_index)
{
    for (const operation oper: operations_)
    {
        //log_debug() << "Run: " << opcode_to_string(oper.code);
        if (!run_operation(oper, parent_tx, input_index))
            return false;
        if (oper.data.size() > 0)
        {
            BITCOIN_ASSERT(oper.code == opcode::special ||
                oper.code == opcode::pushdata1 ||
                oper.code == opcode::pushdata2 ||
                oper.code == opcode::pushdata4);
            stack_.push_back(oper.data);
        }
    }
    return true;
}

data_chunk script::pop_stack()
{
    data_chunk value = stack_.back();
    stack_.pop_back();
    return value;
}

bool script::op_dup()
{
    if (stack_.size() < 1)
        return false;
    stack_.push_back(stack_.back());
    return true;
}

bool script::op_hash160()
{
    if (stack_.size() < 1)
        return false;
    data_chunk data = pop_stack();
    short_hash hash = generate_ripemd_hash(data);
    data_chunk raw_hash(hash.begin(), hash.end());
    stack_.push_back(raw_hash);
    return true;
}

bool script::op_equalverify()
{
    if (stack_.size() < 2)
        return false;
    return pop_stack() == pop_stack();
}

inline void nullify_input_sequences(
    message::transaction_input_list& inputs, uint32_t except_input)
{
    for (size_t i = 0; i < inputs.size(); ++i)
        if (i != except_input)
            inputs[i].sequence = 0;
}

bool script::op_checksig(message::transaction parent_tx, uint32_t input_index)
{
    BITCOIN_ASSERT(input_index < parent_tx.inputs.size());
    if (stack_.size() < 2)
        return false;
    data_chunk pubkey = pop_stack(), signature = pop_stack();

    script script_code;
    for (operation op: operations_)
    {
        if (op.data == signature || op.code == opcode::codeseparator)
            continue;
        script_code.push_operation(op);
    }

    elliptic_curve_key key;
    key.set_public_key(pubkey);

    uint32_t hash_type = 0;
    hash_type = signature.back();
    signature.pop_back();

    if ((hash_type & 0x1f) == sighash::none)
    {
        parent_tx.outputs.clear();
        nullify_input_sequences(parent_tx.inputs, input_index);
    }
    else if ((hash_type & 0x1f) == sighash::single)
    {
        uint32_t output_index = input_index;
        if (output_index >= parent_tx.outputs.size())
        {
            log_error() << "sighash::single the output_index is out of range";
            return false;
        }
        parent_tx.outputs.resize(output_index + 1);
        for (message::transaction_output& output: parent_tx.outputs)
        {
            output.value = ~0;
            output.output_script = script();
        }
        nullify_input_sequences(parent_tx.inputs, input_index);
    }

    if (hash_type & sighash::anyone_can_pay)
    {
        parent_tx.inputs[0] = parent_tx.inputs[input_index];
        parent_tx.inputs.resize(1);
    }

    if (input_index >= parent_tx.inputs.size())
    {
        log_fatal() << "script::op_checksig() : input_index " << input_index
                << " is out of range.";
        return false;
    }

    message::transaction tx_tmp = parent_tx;
    // Blank all other inputs' signatures
    for (message::transaction_input& input: tx_tmp.inputs)
        input.input_script = script();
    tx_tmp.inputs[input_index].input_script = script_code;

    hash_digest tx_hash = hash_transaction(tx_tmp, hash_type);
    return key.verify(tx_hash, signature);
}

bool script::run_operation(operation op,
        const message::transaction& parent_tx, uint32_t input_index)
{
    switch (op.code)
    {
        case opcode::special:
        case opcode::pushdata1:
        case opcode::pushdata2:
        case opcode::pushdata4:
            return true;

        case opcode::nop:
            return true;

        case opcode::dup:
            return op_dup();

        case opcode::hash160:
            return op_hash160();

        case opcode::equalverify:
            return op_equalverify();

        case opcode::checksig:
            return op_checksig(parent_tx, input_index);

        default:
            log_fatal() << "Unimplemented operation <none "
                << static_cast<int>(op.code) << ">";
            break;
    }
    return false;
}

transaction_type script::type() const
{
    return transaction_type::normal;
}

bool script::matches_template(operation_stack templ) const
{
    return templ.size() == 0;
}

std::string script::pretty() const
{
    std::ostringstream ss;
    for (auto it = operations_.begin(); it != operations_.end(); ++it)
    {
        if (it != operations_.begin())
            ss << " ";
        const operation& op = *it;
        if (op.data.size() == 0)
            ss << opcode_to_string(op.code);
        else
        {
            ss << "[ " << pretty_hex(op.data) << " ]";
        }
    }
    return ss.str();
}

std::string opcode_to_string(opcode code)
{
    switch (code)
    {
        case opcode::special:
            return "special";
        case opcode::pushdata1:
            return "pushdata1";
        case opcode::pushdata2:
            return "pushdata2";
        case opcode::pushdata4:
            return "pushdata4";
        case opcode::nop:
            return "nop";
        case opcode::dup:
            return "dup";
        case opcode::hash160:
            return "hash160";
        case opcode::equalverify:
            return "equalverify";
        case opcode::checksig:
            return "checksig";
        default:
        {
            std::ostringstream ss;
            ss << "<none " << static_cast<int>(code) << ">";
            return ss.str();
        }
    }
}
opcode string_to_opcode(std::string code_repr)
{
    if (code_repr == "special")
        return opcode::special;
    else if (code_repr == "pushdata1")
        return opcode::pushdata1;
    else if (code_repr == "pushdata2")
        return opcode::pushdata2;
    else if (code_repr == "pushdata4")
        return opcode::pushdata4;
    else if (code_repr == "nop")
        return opcode::nop;
    else if (code_repr == "dup")
        return opcode::dup;
    else if (code_repr == "hash160")
        return opcode::hash160;
    else if (code_repr == "equalverify")
        return opcode::equalverify;
    else if (code_repr == "checksig")
        return opcode::checksig;
    // ERROR: unknown...
    return opcode::bad_operation;
}

// Read next n bytes while advancing iterator
// Used for seeing length of data to push to stack with pushdata2/4
template <typename Iterator>
inline data_chunk read_back_from_iterator(Iterator& it, size_t total)
{
    data_chunk number_bytes;
    for (size_t i = 0; i < total; ++i)
    {
        ++it;
        number_bytes.push_back(*it);
    }
    return number_bytes;
}

template <typename Iterator>
size_t number_of_bytes_from_opcode(opcode code, byte raw_byte, Iterator& it)
{
    switch (code)
    {
        case opcode::special:
            return raw_byte;
        case opcode::pushdata1:
            ++it;
            return static_cast<uint8_t>(*it);
        case opcode::pushdata2:
            return cast_chunk<uint16_t>(read_back_from_iterator(it, 2));
        case opcode::pushdata4:
            return cast_chunk<uint32_t>(read_back_from_iterator(it, 4));
        default:
            return 0;
    }
}

script parse_script(const data_chunk& raw_script)
{
    script script_object;
    for (auto it = raw_script.begin(); it != raw_script.end(); ++it)
    {
        byte raw_byte = *it;
        operation op;
        op.code = static_cast<opcode>(raw_byte);
        // raw_byte is unsigned so it's always >= 0
        if (raw_byte <= 75)
            op.code = opcode::special;
        size_t read_n_bytes =
            number_of_bytes_from_opcode(op.code, raw_byte, it);

        for (size_t byte_count = 0; byte_count < read_n_bytes; ++byte_count)
        {
            ++it;
            if (it == raw_script.cend())
            {
                log_warning() << "Premature end of script.";
                return script();
            }
            op.data.push_back(*it);
        }

        script_object.push_operation(op);

    }
    return script_object;
}

inline data_chunk operation_metadata(const opcode code, size_t data_size)
{
    switch (code)
    {
        case opcode::pushdata1:
            return uncast_type<uint8_t>(data_size);
        case opcode::pushdata2:
            return uncast_type<uint16_t>(data_size);
        case opcode::pushdata4:
            return uncast_type<uint32_t>(data_size);
        default:
            return data_chunk();
    }
}
data_chunk save_script(const script& scr)
{
    data_chunk raw_script;
    for (operation op: scr.operations())
    {
        byte raw_byte = static_cast<byte>(op.code);
        if (op.code == opcode::special)
            raw_byte = op.data.size();
        raw_script.push_back(raw_byte);
        extend_data(raw_script, operation_metadata(op.code, op.data.size()));
        extend_data(raw_script, op.data);
    }
    return raw_script;
}

script script_from_pretty(const std::string& pretty_script)
{
    script script_object;
    std::stringstream splitter;
    splitter << pretty_script;
    std::string token;
    while (splitter >> token)
    {
        operation op;
        if (token == "[")
        {
            while ((splitter >> token) && token != "]")
            {
                std::istringstream to_int(token);
                int value;
                to_int >> std::hex >> value;
                op.data.push_back(value);
            }
            if (token != "]")
            {
                log_warning() << "Premature end of script.";
                return script();
            }
            op.code = opcode::special;
        }
        else
        {
            op.code = string_to_opcode(token);
        }
        script_object.push_operation(op);
    }
    return script_object;
}

} // libbitcoin

<|endoftext|>


<commit_before>#include <util/PlatformUtils.hpp>

#include <XalanTransformer/XalanTransformer.hpp>

#include <cstdio>

#if defined(XALAN_OLD_STREAM_HEADERS)
#include <iostream.h>
#else
#include <iostream>
#endif

// This is a simple class that illustrates how XalanTransformer's "callback" API
// is used.  This example just abstracts writing data to a FILE*, but other
// actions are possible.
class CallbackHandler
{
public:

	CallbackHandler(FILE*	theFile) :
		m_file(theFile)
	{
		assert(m_file != 0);
	}

	unsigned long
	write(
			const char*		theData,
			unsigned long	theLength)
	{
		return fwrite(theData, sizeof(char), theLength, m_file);
	}

	void
	flush()
	{
		fflush(m_file);
	}

private:

	FILE* const		m_file;
};

// These functions need to have C linkage, so surround them with an extern C block...
extern "C"
{

// This is the write callback function, which casts the handle
// to the appropriate type, then calls the write() member function
// on the CallbackHandler class.
unsigned long
writeCallback(
			const char*		theData,
			unsigned long	theLength,
			void*			theHandle)
{
#if defined(XALAN_OLD_STYLE_CASTS)
	return ((CallbackHandler*)theHandle)->write(theData, theLength);
#else
	return reinterpret_cast<CallbackHandler*>(theHandle)->write(theData, theLength);
#endif
}

// This is the flush callback function, which casts the handle
// to the appropriate type, then calls the flush() member function
// on the CallbackHandler class.
void
flushCallback(void*	theHandle)
{
#if defined(XALAN_OLD_STYLE_CASTS)
	((CallbackHandler*)theHandle)->flush();
#else
	reinterpret_cast<CallbackHandler*>(theHandle)->flush();
#endif
}

};

int
doTransform(
			const char*		theXMLFile,
			const char*		theXSLFile,
			FILE*			theOutputFile)
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
    using std::endl;
#endif

    // Create a XalanTransformer...
	XalanTransformer	theXalanTransformer;

	// Create an instance of the class we wrote to handle
	// the callbacks...
	CallbackHandler		theHandler(theOutputFile);

	// Do the transform...
	const int	theResult = theXalanTransformer.transform(
					theXMLFile,
					theXSLFile,
					&theHandler,
					writeCallback,
					flushCallback);

	if(theResult != 0)
	{
		cerr << "XalanError: " << theXalanTransformer.getLastError() << endl;
	}

	return theResult;
}

int
main(
			int				 argc,
			const char*		 argv[])
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
    using std::endl;
#endif

    if (argc < 3 || argc > 4)
	{
		cerr << "Usage: XalanTransformerCallback XMLFileName XSLFileName [OutFileName]" << endl;

		return -1;
	}

	// Call the static initializer for Xerces.
	XMLPlatformUtils::Initialize();

    // Initialize Xalan.
    XalanTransformer::initialize();

    int				theResult = 0;

    if (argc == 3)
	{
		// No output file, so use stdout...
		theResult = doTransform(argv[1], argv[2], stdout);
    }
    else
    {
		// Ooutput file specified, so try to open it...
		FILE* const	theOutputFile = fopen(argv[3], "w");

		if (theOutputFile == 0)
		{
			cerr << "Error: " << "Unable to open output file " << argv[3] << endl;
		}
		else
		{
			theResult = doTransform(argv[1], argv[2], theOutputFile);

			fclose(theOutputFile);
		}
    }

    // Terminate Xalan.
	XalanTransformer::terminate();

	// Call the static terminator for Xerces.
	XMLPlatformUtils::Terminate();

	return theResult;
}
<commit_msg>32/64-bit fixes.<commit_after>#include <util/PlatformUtils.hpp>

#include <XalanTransformer/XalanTransformer.hpp>

#include <cstdio>

#if defined(XALAN_OLD_STREAM_HEADERS)
#include <iostream.h>
#else
#include <iostream>
#endif

// This is a simple class that illustrates how XalanTransformer's "callback" API
// is used.  This example just abstracts writing data to a FILE*, but other
// actions are possible.
class CallbackHandler
{
public:

	CallbackHandler(FILE*	theFile) :
		m_file(theFile)
	{
		assert(m_file != 0);
	}

	CallbackSizeType
	write(
			const char*			theData,
			CallbackSizeType	theLength)
	{
		return fwrite(theData, sizeof(char), theLength, m_file);
	}

	void
	flush()
	{
		fflush(m_file);
	}

private:

	FILE* const		m_file;
};

// These functions need to have C linkage, so surround them with an extern C block...
extern "C"
{

// This is the write callback function, which casts the handle
// to the appropriate type, then calls the write() member function
// on the CallbackHandler class.
CallbackSizeType
writeCallback(
			const char*			theData,
			CallbackSizeType	theLength,
			void*				theHandle)
{
#if defined(XALAN_OLD_STYLE_CASTS)
	return ((CallbackHandler*)theHandle)->write(theData, theLength);
#else
	return reinterpret_cast<CallbackHandler*>(theHandle)->write(theData, theLength);
#endif
}

// This is the flush callback function, which casts the handle
// to the appropriate type, then calls the flush() member function
// on the CallbackHandler class.
void
flushCallback(void*	theHandle)
{
#if defined(XALAN_OLD_STYLE_CASTS)
	((CallbackHandler*)theHandle)->flush();
#else
	reinterpret_cast<CallbackHandler*>(theHandle)->flush();
#endif
}

};

int
doTransform(
			const char*		theXMLFile,
			const char*		theXSLFile,
			FILE*			theOutputFile)
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
    using std::endl;
#endif

    // Create a XalanTransformer...
	XalanTransformer	theXalanTransformer;

	// Create an instance of the class we wrote to handle
	// the callbacks...
	CallbackHandler		theHandler(theOutputFile);

	// Do the transform...
	const int	theResult = theXalanTransformer.transform(
					theXMLFile,
					theXSLFile,
					&theHandler,
					writeCallback,
					flushCallback);

	if(theResult != 0)
	{
		cerr << "XalanError: " << theXalanTransformer.getLastError() << endl;
	}

	return theResult;
}

int
main(
			int				 argc,
			const char*		 argv[])
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
    using std::endl;
#endif

    if (argc < 3 || argc > 4)
	{
		cerr << "Usage: XalanTransformerCallback XMLFileName XSLFileName [OutFileName]" << endl;

		return -1;
	}

	// Call the static initializer for Xerces.
	XMLPlatformUtils::Initialize();

    // Initialize Xalan.
    XalanTransformer::initialize();

    int				theResult = 0;

    if (argc == 3)
	{
		// No output file, so use stdout...
		theResult = doTransform(argv[1], argv[2], stdout);
    }
    else
    {
		// Ooutput file specified, so try to open it...
		FILE* const	theOutputFile = fopen(argv[3], "w");

		if (theOutputFile == 0)
		{
			cerr << "Error: " << "Unable to open output file " << argv[3] << endl;
		}
		else
		{
			theResult = doTransform(argv[1], argv[2], theOutputFile);

			fclose(theOutputFile);
		}
    }

    // Terminate Xalan.
	XalanTransformer::terminate();

	// Call the static terminator for Xerces.
	XMLPlatformUtils::Terminate();

	return theResult;
}
<|endoftext|>


<commit_before>/**
 * \file null_block_allocator.hpp
 *
 * \brief todo: fill in documentation
 *
 * \author Matthew Rodusek (matthew.rodusek@gmail.com)
 */

#ifndef BIT_MEMORY_BLOCK_ALLOCATORS_NULL_BLOCK_ALLOCATOR_HPP
#define BIT_MEMORY_BLOCK_ALLOCATORS_NULL_BLOCK_ALLOCATOR_HPP

#include "../memory.hpp"
#include "../memory_block.hpp"
#include "cached_block_allocator.hpp"

#include <type_traits> // std::integral_constant, std::true_false
#include <cstddef>     // std::max_align_t

namespace bit {
  namespace memory {

    //////////////////////////////////////////////////////////////////////////
    /// \brief A block allocator that only distributes null blocks
    ///
    /// \satisfies BlockAllocator
    //////////////////////////////////////////////////////////////////////////
    class null_block_allocator
    {
      //----------------------------------------------------------------------
      // Public Member Types
      //----------------------------------------------------------------------
    public:

      using is_always_equal = std::true_type;
      using is_stateless    = std::true_type;
      using block_alignment = std::integral_constant<std::size_t,1>;

      //-----------------------------------------------------------------------
      // Constructor / Assignment
      //-----------------------------------------------------------------------
    public:

      /// \brief Default-constructs a null_block_allocator
      null_block_allocator() = default;

      /// \brief Move-constructs a null_block_allocator from another allocator
      ///
      /// \param other the other null_block_allocator to move
      null_block_allocator( null_block_allocator&& other ) noexcept = default;

      // Deleted copy constructor
      null_block_allocator( const null_block_allocator& other ) = delete;

      //-----------------------------------------------------------------------

      // Deleted move assignment
      null_block_allocator& operator=( null_block_allocator&& other ) = delete;

      // Deleted copy assignment
      null_block_allocator& operator=( const null_block_allocator& other ) = delete;

      //----------------------------------------------------------------------
      // Block Allocations
      //----------------------------------------------------------------------
    public:

      /// \brief Allocates a null memory_block
      ///
      /// \return a null memory_block
      owner<memory_block> allocate_block() noexcept;

      /// \brief Deallocates a memory_block
      ///
      /// \param block the block to deallocate
      void deallocate_block( owner<memory_block> block ) noexcept;
    };

    //-------------------------------------------------------------------------
    // Comparisons
    //-------------------------------------------------------------------------

    bool operator==( const null_block_allocator& lhs,
                     const null_block_allocator& rhs ) noexcept;
    bool operator!=( const null_block_allocator& lhs,
                     const null_block_allocator& rhs ) noexcept;

    //-------------------------------------------------------------------------
    // Utilities
    //-------------------------------------------------------------------------

    using cached_null_block_allocator = cached_block_allocator<null_block_allocator>;

  } // namespace memory
} // namespace bit

#include "detail/null_block_allocator.inl"

#endif /* BIT_MEMORY_BLOCK_ALLOCATORS_NULL_BLOCK_ALLOCATOR_HPP */
<commit_msg>Updated 'null_block_allocator' to be stateless<commit_after>/**
 * \file null_block_allocator.hpp
 *
 * \brief todo: fill in documentation
 *
 * \author Matthew Rodusek (matthew.rodusek@gmail.com)
 */

#ifndef BIT_MEMORY_BLOCK_ALLOCATORS_NULL_BLOCK_ALLOCATOR_HPP
#define BIT_MEMORY_BLOCK_ALLOCATORS_NULL_BLOCK_ALLOCATOR_HPP

#include "../memory.hpp"
#include "../memory_block.hpp"
#include "cached_block_allocator.hpp"

#include <type_traits> // std::integral_constant, std::true_false
#include <cstddef>     // std::max_align_t

namespace bit {
  namespace memory {

    //////////////////////////////////////////////////////////////////////////
    /// \brief A block allocator that only distributes null blocks
    ///
    /// \satisfies BlockAllocator
    /// \satisfies Stateless
    //////////////////////////////////////////////////////////////////////////
    class null_block_allocator
    {
      //----------------------------------------------------------------------
      // Public Member Types
      //----------------------------------------------------------------------
    public:

      using is_stateless    = std::true_type;
      using block_alignment = std::integral_constant<std::size_t,1>;

      //-----------------------------------------------------------------------
      // Constructor / Assignment
      //-----------------------------------------------------------------------
    public:

      /// \brief Default-constructs a null_block_allocator
      null_block_allocator() = default;

      /// \brief Move-constructs a null_block_allocator from another allocator
      ///
      /// \param other the other null_block_allocator to move
      null_block_allocator( null_block_allocator&& other ) noexcept = default;

      /// \brief Copy-constructs a null_block_allocator from another allocator
      ///
      /// \param other the other null_block_allocator to copy
      null_block_allocator( const null_block_allocator& other ) noexcept = default;

      //-----------------------------------------------------------------------

      /// \brief Move-assigns a null_block_allocator from another allocator
      ///
      /// \param other the other null_block_allocator to move
      /// \return reference to \c (*this)
      null_block_allocator& operator=( null_block_allocator&& other ) noexcept = default;

      /// \brief Copy-assigns a null_block_allocator from another allocator
      ///
      /// \param other the other null_block_allocator to copy\
      /// \return reference to \c (*this)
      null_block_allocator& operator=( const null_block_allocator& other ) noexcept = default;

      //----------------------------------------------------------------------
      // Block Allocations
      //----------------------------------------------------------------------
    public:

      /// \brief Allocates a null memory_block
      ///
      /// \return a null memory_block
      owner<memory_block> allocate_block() noexcept;

      /// \brief Deallocates a memory_block
      ///
      /// \param block the block to deallocate
      void deallocate_block( owner<memory_block> block ) noexcept;
    };

    //-------------------------------------------------------------------------
    // Comparisons
    //-------------------------------------------------------------------------

    bool operator==( const null_block_allocator& lhs,
                     const null_block_allocator& rhs ) noexcept;
    bool operator!=( const null_block_allocator& lhs,
                     const null_block_allocator& rhs ) noexcept;

    //-------------------------------------------------------------------------
    // Utilities
    //-------------------------------------------------------------------------

    using cached_null_block_allocator = cached_block_allocator<null_block_allocator>;

  } // namespace memory
} // namespace bit

#include "detail/null_block_allocator.inl"

#endif /* BIT_MEMORY_BLOCK_ALLOCATORS_NULL_BLOCK_ALLOCATOR_HPP */
<|endoftext|>


<commit_before>#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif

#include <fstream>

#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Lex/Lexer.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

#include "search.hpp"

using namespace clang;
using namespace clang::tooling;
using namespace clang::ast_matchers;

namespace {

std::string get_line_from_offset(StringRef buffer, std::size_t offset) {
    assert(buffer.size() > offset);

    auto line_start = buffer.find_last_of("\r\n", offset) + 1;
    auto line_end = buffer.find_first_of("\r\n", offset);
    return std::string(buffer.begin() + line_start, buffer.begin() + line_end);
}

///  Adapted from clang CIndex.cpp
///
/// Clang internally represents ranges where the end location points to the
/// start of the token at the end. However, for external clients it is more
/// useful to have a CXSourceRange be a proper half-open interval. This
/// routine does the appropriate translation.
SourceRange translateSourceRange(const ASTContext* context,
                                 const SourceManager* sm,
                                 const SourceRange& range) {
    // We want the last character in this location, so we will adjust the
    // location accordingly.
    auto R = CharSourceRange::getTokenRange(range);
    auto& LangOpts = context->getLangOpts();
    SourceLocation EndLoc = R.getEnd();
    if (EndLoc.isValid() && EndLoc.isMacroID() &&
        !sm->isMacroArgExpansion(EndLoc))
        EndLoc = sm->getExpansionRange(EndLoc).second;
    if (R.isTokenRange() && EndLoc.isValid()) {
        unsigned Length = Lexer::MeasureTokenLength(sm->getSpellingLoc(EndLoc),
                                                    *sm, LangOpts);
        EndLoc = EndLoc.getLocWithOffset(Length - 1);
    }
    SourceRange Result = {R.getBegin(), EndLoc};
    return Result;
}

template <typename U>
void print_node(const ASTContext* context, const SourceManager* sm,
                const U* node) {
    auto range = node->getSourceRange();
    range = translateSourceRange(context, sm, range);

    if (!range.isValid())
        return;

    auto start_loc = sm->getExpansionLoc(range.getBegin());
    auto end_loc = sm->getExpansionLoc(range.getEnd());

    auto start_row = sm->getExpansionLineNumber(start_loc);
    auto start_column = sm->getExpansionColumnNumber(start_loc);
    auto end_row = sm->getExpansionLineNumber(end_loc);
    auto end_column = sm->getExpansionColumnNumber(end_loc);

    auto file_id = sm->getFileID(start_loc);
    auto buffer = sm->getBufferData(file_id);
    auto offset = sm->getDecomposedLoc(start_loc).second;

    std::cout << start_row << ":" << start_column << ":"
              << get_line_from_offset(buffer, offset) << std::endl;
}

AST_MATCHER_P(NamedDecl, matchesUnqualifiedName, std::string, RegExp) {
    assert(!RegExp.empty());
    std::string FullNameString = Node.getNameAsString();
    llvm::Regex RE(RegExp);
    return RE.match(FullNameString);
}

AST_MATCHER_P(QualType, matchesType, std::string, RegExp) {
    assert(!RegExp.empty());
    llvm::Regex RE(RegExp);
    return RE.match(Node.getAsString());
}

AST_MATCHER_P(ParmVarDecl, matchesParameter, ExplicitParameter, param) {
    auto matcher = parmVarDecl(allOf(matchesUnqualifiedName(param.name),
                                     hasType(matchesType(param.type)),
                                     unless(isImplicit())));
    return matcher.matches(Node, Finder, Builder);
}

AST_MATCHER_P(FunctionDecl, matchesParameters, std::vector<FunctionParameter>,
              parameters) {
    bool ellipses_active = false;
    auto iter = Node.param_begin();
    for (const auto& p : parameters) {
        if (p.which() == 1) {
            ellipses_active = true;
            continue;
        }
        if (iter == Node.param_end()) {
            return false;
        }

        auto matcher = matchesParameter(boost::get<ExplicitParameter>(p));
        if (!matcher.matches(**iter, Finder, Builder)) {
            if (!ellipses_active) {
                return false;
            } else {
                ++iter;
            }
        } else {
            ++iter;
            ellipses_active = false;
        }
    }
    if (iter != Node.param_end() && !ellipses_active) {
        return false;
    }
    return true;
}

AST_MATCHER_P(NamespaceDecl, matchesNamespace, Namespace, ns) {
    llvm::Regex RE(ns.name);
    return RE.match(Node.getNameAsString());
}

AST_MATCHER_P(RecordDecl, matchesClass, Class, cls) {
    llvm::Regex RE(cls.name);
    return RE.match(Node.getNameAsString());
}

AST_MATCHER_P(NamedDecl, matchesQualifiers, std::vector<Qualifier>,
              qualifiers) {
    auto context = Node.getDeclContext();

    std::vector<const DeclContext*> contexts;

    while (context && isa<NamedDecl>(context)) {
        contexts.push_back(context);
        context = context->getParent();
    }

    if (qualifiers.size() > contexts.size()) {
        return false;
    }

    for (std::size_t i = 0; i < qualifiers.size(); ++i) {
        const auto& qual = qualifiers[qualifiers.size() - 1 - i];
        if (qual.which() == 0) {
            if (const auto* ND = dyn_cast<NamespaceDecl>(contexts[i])) {
                auto ns = boost::get<Namespace>(qual);
                auto matcher = matchesNamespace(ns);
                if (!matcher.matches(*ND, Finder, Builder)) {
                    return false;
                }
            } else {
                return false;
            }
        } else if (qual.which() == 1) {
            if (const auto* RD = dyn_cast<RecordDecl>(contexts[i])) {
                auto cls = boost::get<Class>(qual);
                auto matcher = matchesClass(cls);
                if (!matcher.matches(*RD, Finder, Builder)) {
                    return false;
                }
            } else {
                return false;
            }
        }
    }
    return true;
}
}

template <typename T>
class Printer;

template <>
class Printer<Variable> : public MatchFinder::MatchCallback {
public:
    virtual void run(const MatchFinder::MatchResult& Result) {
        auto d = Result.Nodes.getNodeAs<VarDecl>("varDecl");
        print_node(Result.Context, Result.SourceManager, d);
    }
};

template <>
class Printer<Function> : public MatchFinder::MatchCallback {
public:
    virtual void run(const MatchFinder::MatchResult& Result) {
        if (auto d = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl")) {
            print_node(Result.Context, Result.SourceManager, d);
        }
        if (auto e = Result.Nodes.getNodeAs<CallExpr>("funcCall")) {
            print_node(Result.Context, Result.SourceManager, e);
        }
    }
};

void addMatchersForTerm(const Variable& v, MatchFinder& finder,
                        Printer<Variable>* printer) {

    auto varDeclMatcher =
        varDecl(allOf(matchesUnqualifiedName(v.name),
                      hasType(matchesType(v.type)),
                      matchesQualifiers(v.qualifiers), unless(isImplicit())))
            .bind("varDecl");

    finder.addMatcher(varDeclMatcher, printer);
}

void addMatchersForTerm(const Function& f, MatchFinder& finder,
                        Printer<Function>* printer) {

    auto declMatcher = functionDecl(allOf(matchesUnqualifiedName(f.name),
                                          returns(matchesType(f.return_type)),
                                          unless(isImplicit()),
                                          matchesQualifiers(f.qualifiers),
                                          matchesParameters(f.parameters)));

    auto funcDeclMatcher = declMatcher.bind("funcDecl");

    auto funcCallMatcher =
        callExpr(hasDeclaration(declMatcher)).bind("funcCall");

    finder.addMatcher(funcDeclMatcher, printer);
    finder.addMatcher(funcCallMatcher, printer);
}

template <typename T>
void findTermIn(std::string path, const T& term) {
    std::ifstream file{path};
    std::stringstream buffer;
    buffer << file.rdbuf();

    Printer<T> Printer;
    MatchFinder Finder;
    addMatchersForTerm(term, Finder, &Printer);

    auto action_factory = newFrontendActionFactory(&Finder);
    auto action = action_factory->create();

    runToolOnCodeWithArgs(action, buffer.str(),
                          {"-w", "-std=c++14",
                           "-I/usr/lib/clang/3.7.1/include"});
}

void search_file(const char* file, Term& term,
                 const po::variables_map& config) {
    auto p = boost::filesystem::path(file);
    auto extension = boost::filesystem::extension(p);
    if (!config.count("search-all-extensions") && extension != ".cpp" &&
        extension != ".c" && extension != ".h" && extension != ".hpp") {
        return;
    }

    boost::apply_visitor(TermSearchVisitor(file, config), term);
}

void TermSearchVisitor::operator()(Function& f) const {
    findTermIn(this->m_root_filename, f);
}

void TermSearchVisitor::operator()(Variable& v) const {
    findTermIn(this->m_root_filename, v);
}
<commit_msg>Exclude declarations from include files<commit_after>#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif

#include <fstream>

#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Lex/Lexer.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

#include "search.hpp"

using namespace clang;
using namespace clang::tooling;
using namespace clang::ast_matchers;

namespace {

std::string get_line_from_offset(StringRef buffer, std::size_t offset) {
    assert(buffer.size() > offset);

    auto line_start = buffer.find_last_of("\r\n", offset) + 1;
    auto line_end = buffer.find_first_of("\r\n", offset);
    return std::string(buffer.begin() + line_start, buffer.begin() + line_end);
}

///  Adapted from clang CIndex.cpp
///
/// Clang internally represents ranges where the end location points to the
/// start of the token at the end. However, for external clients it is more
/// useful to have a CXSourceRange be a proper half-open interval. This
/// routine does the appropriate translation.
SourceRange translateSourceRange(const ASTContext* context,
                                 const SourceManager* sm,
                                 const SourceRange& range) {
    // We want the last character in this location, so we will adjust the
    // location accordingly.
    auto R = CharSourceRange::getTokenRange(range);
    auto& LangOpts = context->getLangOpts();
    SourceLocation EndLoc = R.getEnd();
    if (EndLoc.isValid() && EndLoc.isMacroID() &&
        !sm->isMacroArgExpansion(EndLoc))
        EndLoc = sm->getExpansionRange(EndLoc).second;
    if (R.isTokenRange() && EndLoc.isValid()) {
        unsigned Length = Lexer::MeasureTokenLength(sm->getSpellingLoc(EndLoc),
                                                    *sm, LangOpts);
        EndLoc = EndLoc.getLocWithOffset(Length - 1);
    }
    SourceRange Result = {R.getBegin(), EndLoc};
    return Result;
}

template <typename U>
void print_node(const ASTContext* context, const SourceManager* sm,
                const U* node) {
    auto range = node->getSourceRange();
    range = translateSourceRange(context, sm, range);

    if (!range.isValid())
        return;

    auto start_loc = sm->getExpansionLoc(range.getBegin());
    auto end_loc = sm->getExpansionLoc(range.getEnd());

    auto start_row = sm->getExpansionLineNumber(start_loc);
    auto start_column = sm->getExpansionColumnNumber(start_loc);
    auto end_row = sm->getExpansionLineNumber(end_loc);
    auto end_column = sm->getExpansionColumnNumber(end_loc);

    auto file_id = sm->getFileID(start_loc);
    auto buffer = sm->getBufferData(file_id);
    auto offset = sm->getDecomposedLoc(start_loc).second;

    std::cout << start_row << ":" << start_column << ":"
              << get_line_from_offset(buffer, offset) << std::endl;
}

AST_MATCHER_P(NamedDecl, matchesUnqualifiedName, std::string, RegExp) {
    assert(!RegExp.empty());
    std::string FullNameString = Node.getNameAsString();
    llvm::Regex RE(RegExp);
    return RE.match(FullNameString);
}

AST_MATCHER_P(QualType, matchesType, std::string, RegExp) {
    assert(!RegExp.empty());
    llvm::Regex RE(RegExp);
    return RE.match(Node.getAsString());
}

AST_MATCHER_P(ParmVarDecl, matchesParameter, ExplicitParameter, param) {
    auto matcher = parmVarDecl(allOf(matchesUnqualifiedName(param.name),
                                     hasType(matchesType(param.type)),
                                     unless(isImplicit())));
    return matcher.matches(Node, Finder, Builder);
}

AST_MATCHER_P(FunctionDecl, matchesParameters, std::vector<FunctionParameter>,
              parameters) {
    bool ellipses_active = false;
    auto iter = Node.param_begin();
    for (const auto& p : parameters) {
        if (p.which() == 1) {
            ellipses_active = true;
            continue;
        }
        if (iter == Node.param_end()) {
            return false;
        }

        auto matcher = matchesParameter(boost::get<ExplicitParameter>(p));
        if (!matcher.matches(**iter, Finder, Builder)) {
            if (!ellipses_active) {
                return false;
            } else {
                ++iter;
            }
        } else {
            ++iter;
            ellipses_active = false;
        }
    }
    if (iter != Node.param_end() && !ellipses_active) {
        return false;
    }
    return true;
}

AST_MATCHER_P(NamespaceDecl, matchesNamespace, Namespace, ns) {
    llvm::Regex RE(ns.name);
    return RE.match(Node.getNameAsString());
}

AST_MATCHER_P(RecordDecl, matchesClass, Class, cls) {
    llvm::Regex RE(cls.name);
    return RE.match(Node.getNameAsString());
}

AST_MATCHER_P(NamedDecl, matchesQualifiers, std::vector<Qualifier>,
              qualifiers) {
    auto context = Node.getDeclContext();

    std::vector<const DeclContext*> contexts;

    while (context && isa<NamedDecl>(context)) {
        contexts.push_back(context);
        context = context->getParent();
    }

    if (qualifiers.size() > contexts.size()) {
        return false;
    }

    for (std::size_t i = 0; i < qualifiers.size(); ++i) {
        const auto& qual = qualifiers[qualifiers.size() - 1 - i];
        if (qual.which() == 0) {
            if (const auto* ND = dyn_cast<NamespaceDecl>(contexts[i])) {
                auto ns = boost::get<Namespace>(qual);
                auto matcher = matchesNamespace(ns);
                if (!matcher.matches(*ND, Finder, Builder)) {
                    return false;
                }
            } else {
                return false;
            }
        } else if (qual.which() == 1) {
            if (const auto* RD = dyn_cast<RecordDecl>(contexts[i])) {
                auto cls = boost::get<Class>(qual);
                auto matcher = matchesClass(cls);
                if (!matcher.matches(*RD, Finder, Builder)) {
                    return false;
                }
            } else {
                return false;
            }
        }
    }
    return true;
}
}

template <typename T>
class Printer;

template <>
class Printer<Variable> : public MatchFinder::MatchCallback {
public:
    virtual void run(const MatchFinder::MatchResult& Result) {
        auto d = Result.Nodes.getNodeAs<VarDecl>("varDecl");
        print_node(Result.Context, Result.SourceManager, d);
    }
};

template <>
class Printer<Function> : public MatchFinder::MatchCallback {
public:
    virtual void run(const MatchFinder::MatchResult& Result) {
        if (auto d = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl")) {
            print_node(Result.Context, Result.SourceManager, d);
        }
        if (auto e = Result.Nodes.getNodeAs<CallExpr>("funcCall")) {
            print_node(Result.Context, Result.SourceManager, e);
        }
    }
};

void addMatchersForTerm(const Variable& v, MatchFinder& finder,
                        Printer<Variable>* printer) {

    auto varDeclMatcher =
        varDecl(allOf(isExpansionInMainFile(), matchesUnqualifiedName(v.name),
                      hasType(matchesType(v.type)),
                      matchesQualifiers(v.qualifiers), unless(isImplicit())))
            .bind("varDecl");

    finder.addMatcher(varDeclMatcher, printer);
}

void addMatchersForTerm(const Function& f, MatchFinder& finder,
                        Printer<Function>* printer) {

    auto declMatcher = functionDecl(
        allOf(isExpansionInMainFile(), matchesUnqualifiedName(f.name),
              returns(matchesType(f.return_type)), unless(isImplicit()),
              matchesQualifiers(f.qualifiers),
              matchesParameters(f.parameters)));

    auto funcDeclMatcher = declMatcher.bind("funcDecl");

    auto funcCallMatcher =
        callExpr(hasDeclaration(declMatcher)).bind("funcCall");

    finder.addMatcher(funcDeclMatcher, printer);
    finder.addMatcher(funcCallMatcher, printer);
}

template <typename T>
void findTermIn(std::string path, const T& term) {
    std::ifstream file{path};
    std::stringstream buffer;
    buffer << file.rdbuf();

    Printer<T> Printer;
    MatchFinder Finder;
    addMatchersForTerm(term, Finder, &Printer);

    auto action_factory = newFrontendActionFactory(&Finder);
    auto action = action_factory->create();

    runToolOnCodeWithArgs(action, buffer.str(),
                          {"-w", "-std=c++14",
                           "-I/usr/lib/clang/3.7.1/include"});
}

void search_file(const char* file, Term& term,
                 const po::variables_map& config) {
    auto p = boost::filesystem::path(file);
    auto extension = boost::filesystem::extension(p);
    if (!config.count("search-all-extensions") && extension != ".cpp" &&
        extension != ".c" && extension != ".h" && extension != ".hpp") {
        return;
    }

    boost::apply_visitor(TermSearchVisitor(file, config), term);
}

void TermSearchVisitor::operator()(Function& f) const {
    findTermIn(this->m_root_filename, f);
}

void TermSearchVisitor::operator()(Variable& v) const {
    findTermIn(this->m_root_filename, v);
}
<|endoftext|>