<commit_before>#include <iostream>
#include <vector>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <stack>
using namespace std;

#include "../header/Command.h"
#include "../header/Connector.h"
#include "../header/Command.h"
#include "../header/Andand.h"
#include "../header/Oror.h"
#include "../header/Semicolon.h"
#include "../header/Base.h"
#include "../header/Flag.h"

int main() {
    vector<Base*> commands;         //Vector to hold the commands
    vector<char> connectorTypes;    //Vector to hold the connectors
    stack<const char*> history;     //Stack to hold the history of cd inputs
    string input;                   //String to store user input
    int prevIndex = 0;              /* To keep track of where we are in
                                      commands and connectorTypes */

    //Used to check the input (mainly for the cd command)
    bool sharp = false;
    bool goHome = false;
    bool dash = false;
    bool slash = false;

    do {

    commands.resize(0);
    connectorTypes.resize(0);

    //Used to output current working directory
    cout << getenv("PWD") << " $ ";

    string input;
    cout << "$ ";
    getline(cin, input);
    prevIndex = 0;

    sharp = false;
    goHome = false;
    dash = false;
    slash = false;

    cout << getenv("PWD") << endl;

    cout << "Parsing commands: " << endl;

    //Loop to check the input for connectors and other indicators

    bool sharp = false;
    bool goHome = true;
    bool dash = false;
    bool slash = false;
    cout << "Parsing commands: " << endl;

    for (unsigned i = 0; i < input.size(); ++i) {

        //Is it a commented-out command?
        if (input.at(i) == '#') {
            Command* comm = new Command(input.substr(prevIndex, i - prevIndex));
            commands.push_back(comm);
            sharp = true;
            prevIndex = i + 1;
        }

        //Is it a regular command?
        if (input.at(i) == ';') {
            cout << input.substr(prevIndex, i - prevIndex) << endl;
            Command* comm = new Command(input.substr(prevIndex, i - prevIndex));
            commands.push_back(comm);
            connectorTypes.push_back(';');
            prevIndex = i + 1;
        }

        //Is it a command with an AND connector behind it?
        if (input.at(i) == '&') {
            if (i != input.size() - 1) {
                if (input.at(i + 1) == '&') {
                    cout << input.substr(prevIndex, i - prevIndex) << endl;
                    Command* comm = new Command(input.substr(prevIndex, i - prevIndex));
                    commands.push_back(comm);
                    connectorTypes.push_back('&');
                    prevIndex = i + 2;
                }
            }
        }

        //Is it a command with an OR connector behind it?
        if (input.at(i) == '|') {
            if (i != input.size() - 1) {
                if (input.at(i + 1) == '|') {
                    cout << input.substr(prevIndex, i - prevIndex) << endl;
                    Command* comm = new Command(input.substr(prevIndex, i - prevIndex));
                    commands.push_back(comm);
                    connectorTypes.push_back('|');
                    prevIndex = i + 2;
                }
            }
        }

        //Is it a command with a test? [isDir? isReg?]
        if (input.at(i) == ']') {
            cout << input.substr(input.find('[', prevIndex) + 1, i - input.find('[', prevIndex) - 1) << endl;
            Flag* fl = new Flag(input.substr(input.find('[', prevIndex) + 1, i - input.find('[', prevIndex) - 1));
            commands.push_back(fl);
            connectorTypes.push_back(']');
            prevIndex = i + 1;
        }

        //Same as above [the alternative way]

        if (input.at(i) == 't') {
            if((i + 3) < input.size()) {
                if((input.at(i + 1) == 'e') && (input.at(i + 2) == 's') && (input.at(i + 3) == 't')){
                    cout << "test";
                    prevIndex = i + 4;
                    int lastIndex;

                    while(i < input.size()) {
                        if (input.at(i) == '#') {
                            lastIndex = i;
                            cout << input.substr(prevIndex, lastIndex - prevIndex) << endl;
                            Flag* fl = new Flag(input.substr(prevIndex, lastIndex - prevIndex));
                            commands.push_back(fl);
                            sharp = true;
                            prevIndex = i + 1;
                            break;
                        }
                        if (input.at(i) == ';') {
                            lastIndex = i;
                            cout << input.substr(prevIndex, lastIndex - prevIndex) << endl;
                            Flag* fl = new Flag(input.substr(prevIndex, lastIndex - prevIndex));
                            commands.push_back(fl);
                            connectorTypes.push_back(';');
                            prevIndex = i + 1;
                            break;
                        }
                        if (input.at(i) == '&') {
                            if (i != input.size() - 1) {
                                if (input.at(i + 1) == '&') {
                                    lastIndex = i - 1;
                                    cout << input.substr(prevIndex, lastIndex - prevIndex) << endl;
                                    Flag* fl = new Flag(input.substr(prevIndex, lastIndex - prevIndex));
                                    commands.push_back(fl);
                                    connectorTypes.push_back('&');
                                    prevIndex = i + 2;
                                }
                            }
                            break;
                        }
                        if (input.at(i) == '|') {
                            if (i != input.size() - 1) {
                                if (input.at(i + 1) == '|') {
                                    lastIndex = i - 1;
                                    cout << input.substr(prevIndex, lastIndex - prevIndex) << endl;
                                    Flag* fl = new Flag(input.substr(prevIndex, lastIndex - prevIndex));
                                    commands.push_back(fl);
                                    connectorTypes.push_back('|');
                                    prevIndex = i + 2;
                                }
                            }
                            break;
                        }
                        ++i;
                    }
                    if(i == input.size()) {
                        cout << input.substr(prevIndex, input.size() - prevIndex) << endl;
                        Flag* fl = new Flag(input.substr(prevIndex, input.size() - prevIndex));
                        commands.push_back(fl);
                    }

                }
            }
        }

    //==========================================================================
    //BEGIN CORE OF ASSIGNMENT 4
    //==========================================================================

    //Is cd the only command inputted
    if (input.at(0) == 'c' && input.at(1) == 'd') {
        for (unsigned d = 3; d < input.size(); ++d) {
            //Do they want to go back to the previous directory?
            if (input.at(d) == '-') {
                goHome = false;
                dash = true;
            }
            //Did they want to go to a new directory/path?
            else {
                goHome = false;
                slash = true;
            }
        }
        if(input.size() < 3) {
            goHome = true;
        }
        //User only put "cd", meaning to go back home
        if (goHome) {
            char* oldEnv = getenv("PWD");
            history.push(oldEnv);
            if (oldEnv == NULL) {
                perror("getenv");
            }
            int newEnv = setenv("OLDPWD", oldEnv, 1); //set oldpwd to current environment
            if (newEnv == -1) {
                perror("setenv");
            }
            int dir = chdir(getenv("HOME"));
            if (dir == -1) {
                perror("chdir");
            }
            else {
                //Gets the home environment
                char* env = getenv("HOME");
                if (env == NULL) {
                    perror("getenv");
                }
                //Sets the environment to HOME
                int set = setenv("PWD", env, 1); //set pwd to home environment
                if (set == -1) {
                    perror("setenv");
                }
            }
            //cout << "AFTER RUNNING: " << getenv("PWD") << endl;
        }
        //User put "cd -", meaning to go back to the previous environment
        else if (dash) {
            char* oldEnv = getenv("PWD");
            if (oldEnv == NULL) {
                perror("getenv");
            }
            int setOldEnv = setenv("OLDPWD", oldEnv, 1); //set oldpwd to current environment
            if (setOldEnv == -1) {
                perror("setenv");
            }
            //Is it empty? If not, then continue
            if (history.size() > 0) {
                //cout << "Previous environment: " << history.top() << endl;
                int dir = chdir(history.top());
                if (dir == -1) {
                    perror("chdir");
                }
                else {
                    //Sets the environment to previous environment
                    if ( (setenv("PWD", history.top(), 1)) == -1) {
                        perror("setenv");
                    }
                }
                history.pop();
            }
            history.push(oldEnv);
        }
        //User put cd <PATH>, meaning go to the path specified by the input
        else if (slash) { //SUSPECT
            char* oldEnv = getenv("PWD");
            if (oldEnv == NULL) {
                perror("getenv");
            }
            int setOldEnv = setenv("OLDPWD", oldEnv, 1); //set oldpwd to current environment
            if (setOldEnv == -1) {
                perror("setenv");
            }

            //PWD = <PATH>; //Set PWD to PATH

            string path;
            // int temp = i + 2;
            path = input.substr(input.find(' ') + 1);
            // path = input.substr(' ', temp);
            int dir = chdir(path.c_str());
            if (dir == -1) {
                perror("chdir");
            }
            else { //SUSPECT
                //Gets the home environment
                char* env = getenv(path.c_str());
                if (env == NULL) {
                    perror("getenv");
                } else {
                    //Sets the environment to HOME
                    int set = setenv(path.c_str(), env, 0);
                    if (set == -1) {
                        perror("setenv");
                    }
                    //Is the current path not starting from the beginning? (In other words, did the user access previous directories before?)
                    // if (history.size() > 0) {
                    //     //Are we at the end of history? If so, then push_back
                    //     if (PWD == history.size() - 1) {
                    //         history.push_back(path.c_str());
                    //         OLDPWD = PWD;
                    //         ++PWD;
                    //     }
                    //     //If not, then that means we're somewhere in the middle
                    //     else {
                    //         history.at(PWD + 1) = path.c_str();
                    //         OLDPWD = PWD;
                    //         ++PWD;
                    //     }
                    // }
                    // //If here, then that means this is the first directory
                    // else {
                    //     history.push_back(path.c_str());
                    //     PWD = 0;
                    //     OLDPWD = 0;
                    // }
                }
            }
        }
    }

    //==========================================================================
    // END CORE OF ASSIGNMENT 4
    //==========================================================================

    //Checks to see if the command was actually commented out
    if(!sharp) {
        cout << input.substr(prevIndex, input.size() - prevIndex) << endl;
        Command* last = new Command(input.substr(prevIndex, input.size() - prevIndex));
        commands.push_back(last);
    }
    cout << endl;

    int prevResult;

    //Was it not one of the three?
    if(!(goHome || dash || slash)) {

        prevResult = commands.at(0)->execute();
        cout << endl;
        cout << "Exit status: " << prevResult << endl;

    }

    //Loop takes it's commands along with the connectors and runs execute()
    unsigned i = 0;
    while(i < connectorTypes.size()) {
        ++i;
        if(connectorTypes.at(i - 1) == ';') {
            Semicolon* semi = new Semicolon(commands.at(i), prevResult);
            prevResult = semi->execute();
        }
        else if(connectorTypes.at(i - 1) == '&') {
            Andand* amper = new Andand(commands.at(i), prevResult);
            prevResult = amper->execute();
        }
        else if(connectorTypes.at(i - 1) == '|') {
            Oror* bar = new Oror(commands.at(i), prevResult);
            prevResult = bar->execute();
        }
        cout << endl;
        cout << "Exit status: " << prevResult << endl;
    }

    /*cout << "Argument list:" << endl;
    for(unsigned i = 0; i < commands.size(); ++i) {
        //cout << commands.at(i)->command[0] << endl;
        for(unsigned j = 0; j < commands.at(i)->size; ++j) {
            printf ("%s \n", commands.at(i)->command[j]);
        }
    }
    cout << endl;
    cout << "Connector Type list:" << endl;
    for(unsigned i = 0; i < connectorTypes.size(); ++i) {
        cout << connectorTypes.at(i) << endl;
    }*/

    } while(true);
    return 0;
}
<commit_msg>finished assignment 4<commit_after>#include <iostream>
#include <vector>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <stack>
using namespace std;

#include "../header/Command.h"
#include "../header/Connector.h"
#include "../header/Command.h"
#include "../header/Andand.h"
#include "../header/Oror.h"
#include "../header/Semicolon.h"
#include "../header/Base.h"
#include "../header/Flag.h"

int main() {
    vector<Base*> commands;         //Vector to hold the commands
    vector<char> connectorTypes;    //Vector to hold the connectors
    stack<const char*> history;     //Stack to hold the history of cd inputs
    string input;                   //String to store user input
    int prevIndex = 0;              /* To keep track of where we are in
                                      commands and connectorTypes */

    //Used to check the input (mainly for the cd command)
    bool sharp = false;
    bool goHome = false;
    bool dash = false;
    bool slash = false;

    do {

    commands.resize(0);
    connectorTypes.resize(0);

    //Used to output current working directory
    cout << getenv("PWD") << " $ ";
    getline(cin, input);
    prevIndex = 0;

    sharp = false;
    goHome = false;
    dash = false;
    slash = false;

    cout << getenv("PWD") << endl;

    cout << "Parsing commands: " << endl;

    //Loop to check the input for connectors and other indicators
    for (unsigned i = 0; i < input.size(); ++i) {

        //Is it a commented-out command?
        if (input.at(i) == '#') {
            Command* comm = new Command(input.substr(prevIndex, i - prevIndex));
            commands.push_back(comm);
            sharp = true;
            prevIndex = i + 1;
        }

        //Is it a regular command?
        if (input.at(i) == ';') {
            cout << input.substr(prevIndex, i - prevIndex) << endl;
            Command* comm = new Command(input.substr(prevIndex, i - prevIndex));
            commands.push_back(comm);
            connectorTypes.push_back(';');
            prevIndex = i + 1;
        }

        //Is it a command with an AND connector behind it?
        if (input.at(i) == '&') {
            if (i != input.size() - 1) {
                if (input.at(i + 1) == '&') {
                    cout << input.substr(prevIndex, i - prevIndex) << endl;
                    Command* comm = new Command(input.substr(prevIndex, i - prevIndex));
                    commands.push_back(comm);
                    connectorTypes.push_back('&');
                    prevIndex = i + 2;
                }
            }
        }

        //Is it a command with an OR connector behind it?
        if (input.at(i) == '|') {
            if (i != input.size() - 1) {
                if (input.at(i + 1) == '|') {
                    cout << input.substr(prevIndex, i - prevIndex) << endl;
                    Command* comm = new Command(input.substr(prevIndex, i - prevIndex));
                    commands.push_back(comm);
                    connectorTypes.push_back('|');
                    prevIndex = i + 2;
                }
            }
        }

        //Is it a command with a test? [isDir? isReg?]
        if (input.at(i) == ']') {
            cout << input.substr(input.find('[', prevIndex) + 1, i - input.find('[', prevIndex) - 1) << endl;
            Flag* fl = new Flag(input.substr(input.find('[', prevIndex) + 1, i - input.find('[', prevIndex) - 1));
            commands.push_back(fl);
            connectorTypes.push_back(']');
            prevIndex = i + 1;
        }

        //Same as above [the alternative way]
        if (input.at(i) == 't') {
            if((i + 3) < input.size()) {
                if((input.at(i + 1) == 'e') && (input.at(i + 2) == 's') && (input.at(i + 3) == 't')){
                    cout << "test";
                    prevIndex = i + 4;
                    int lastIndex;

                    while(i < input.size()) {
                        if (input.at(i) == '#') {
                            lastIndex = i;
                            cout << input.substr(prevIndex, lastIndex - prevIndex) << endl;
                            Flag* fl = new Flag(input.substr(prevIndex, lastIndex - prevIndex));
                            commands.push_back(fl);
                            sharp = true;
                            prevIndex = i + 1;
                            break;
                        }
                        if (input.at(i) == ';') {
                            lastIndex = i;
                            cout << input.substr(prevIndex, lastIndex - prevIndex) << endl;
                            Flag* fl = new Flag(input.substr(prevIndex, lastIndex - prevIndex));
                            commands.push_back(fl);
                            connectorTypes.push_back(';');
                            prevIndex = i + 1;
                            break;
                        }
                        if (input.at(i) == '&') {
                            if (i != input.size() - 1) {
                                if (input.at(i + 1) == '&') {
                                    lastIndex = i - 1;
                                    cout << input.substr(prevIndex, lastIndex - prevIndex) << endl;
                                    Flag* fl = new Flag(input.substr(prevIndex, lastIndex - prevIndex));
                                    commands.push_back(fl);
                                    connectorTypes.push_back('&');
                                    prevIndex = i + 2;
                                }
                            }
                            break;
                        }
                        if (input.at(i) == '|') {
                            if (i != input.size() - 1) {
                                if (input.at(i + 1) == '|') {
                                    lastIndex = i - 1;
                                    cout << input.substr(prevIndex, lastIndex - prevIndex) << endl;
                                    Flag* fl = new Flag(input.substr(prevIndex, lastIndex - prevIndex));
                                    commands.push_back(fl);
                                    connectorTypes.push_back('|');
                                    prevIndex = i + 2;
                                }
                            }
                            break;
                        }
                        ++i;
                    }
                    if(i == input.size()) {
                        cout << input.substr(prevIndex, input.size() - prevIndex) << endl;
                        Flag* fl = new Flag(input.substr(prevIndex, input.size() - prevIndex));
                        commands.push_back(fl);
                    }

                }
            }
        }

    }

    //==========================================================================
    //BEGIN CORE OF ASSIGNMENT 4
    //==========================================================================

    //Is cd the only command inputted?
    if (input.at(0) == 'c' && input.at(1) == 'd') {
        for (unsigned d = 3; d < input.size(); ++d) {
            //Do they want to go back to the previous directory?
            if (input.at(d) == '-') {
                goHome = false;
                dash = true;
            }
            //Did they want to go to a new directory/path?
            else {
                goHome = false;
                slash = true;
            }
        }
        if(input.size() < 3) {
            goHome = true;
        }
        //User only put "cd", meaning to go back home
        if (goHome) {
            char* oldEnv = getenv("PWD");
            history.push(oldEnv);
            if (oldEnv == NULL) {
                perror("getenv");
            }
            int newEnv = setenv("OLDPWD", oldEnv, 1); //set oldpwd to current environment
            if (newEnv == -1) {
                perror("setenv");
            }
            int dir = chdir(getenv("HOME"));
            if (dir == -1) {
                perror("chdir");
            }
            else {
                //Gets the home environment
                char* env = getenv("HOME");
                if (env == NULL) {
                    perror("getenv");
                }
                //Sets the environment to HOME
                int set = setenv("PWD", env, 1); //set pwd to home environment
                if (set == -1) {
                    perror("setenv");
                }
            }
        }
        //User put "cd -", meaning to go back to the previous environment
        else if (dash) {
            char* oldEnv = getenv("PWD");
            if (oldEnv == NULL) {
                perror("getenv");
            }
            int setOldEnv = setenv("OLDPWD", oldEnv, 1); //set oldpwd to current environment
            if (setOldEnv == -1) {
                perror("setenv");
            }
            //Is it empty? If not, then continue
            if (history.size() > 0) {
                int dir = chdir(history.top());
                if (dir == -1) {
                    perror("chdir");
                }
                else {
                    //Sets the environment to previous environment
                    if ( (setenv("PWD", history.top(), 1)) == -1) {
                        perror("setenv");
                    }
                }
                history.pop();
            }
            history.push(oldEnv);
        }
        //User put cd <PATH>, meaning go to the path specified by the input
        else if (slash) {
            char* oldEnv = getenv("PWD");
            if (oldEnv == NULL) {
                perror("getenv");
            }
            int setOldEnv = setenv("OLDPWD", oldEnv, 1); //set oldpwd to current environment
            if (setOldEnv == -1) {
                perror("setenv");
            }
            history.push(oldEnv);

            //Next block of code is used to output current working directory
            string path;
            path = input.substr(input.find(' ') + 1);
            int dir = chdir(path.c_str());
            if (dir == -1) {
                perror("chdir");
            }
            else {
                string properPath;
                string oldPath(getenv("OLDPWD"));
                if(path.find(oldPath) != string::npos) { //check what case of path
                    path = path.substr(path.find(oldPath) + oldPath.size() + 1);
                    properPath.append(oldPath);
                    properPath.append("/");
                } else if (oldPath.find(path) != string::npos) {
                    //do nothing
                } else {
                    properPath.append(oldPath);
                    properPath.append("/");
                }
                properPath.append(path);
                int set = setenv("PWD", properPath.c_str(), 1);
                if (set == -1) {
                    perror("setenv");
                }

            }
        } else {
            cout << "ERROR: improper cd argument" << endl;
        }
    }

    //==========================================================================
    // END CORE OF ASSIGNMENT 4
    //==========================================================================

    //Checks to see if the command was actually commented out
    if(!sharp) {
        cout << input.substr(prevIndex, input.size() - prevIndex) << endl;
        Command* last = new Command(input.substr(prevIndex, input.size() - prevIndex));
        commands.push_back(last);
    }
    cout << endl;

    int prevResult;

    //Was it not one of the three?
    if(!(goHome || dash || slash)) {

        prevResult = commands.at(0)->execute();
        cout << endl;
        cout << "Exit status: " << prevResult << endl;

    }

    //Loop takes it's commands along with the connectors and runs execute()
    unsigned i = 0;
    while(i < connectorTypes.size()) {
        ++i;
        if(connectorTypes.at(i - 1) == ';') {
            Semicolon* semi = new Semicolon(commands.at(i), prevResult);
            prevResult = semi->execute();
        }
        else if(connectorTypes.at(i - 1) == '&') {
            Andand* amper = new Andand(commands.at(i), prevResult);
            prevResult = amper->execute();
        }
        else if(connectorTypes.at(i - 1) == '|') {
            Oror* bar = new Oror(commands.at(i), prevResult);
            prevResult = bar->execute();
        }
        cout << endl;
        cout << "Exit status: " << prevResult << endl;
    }

    /*cout << "Argument list:" << endl;
    for(unsigned i = 0; i < commands.size(); ++i) {
        //cout << commands.at(i)->command[0] << endl;
        for(unsigned j = 0; j < commands.at(i)->size; ++j) {
            printf ("%s \n", commands.at(i)->command[j]);
        }
    }
    cout << endl;
    cout << "Connector Type list:" << endl;
    for(unsigned i = 0; i < connectorTypes.size(); ++i) {
        cout << connectorTypes.at(i) << endl;
    }*/
    } while(true);
    return 0;
}<|endoftext|>


<commit_before>#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
#include <map>
#include <string>
#include <functional>
#include <stdio.h>

#include "gob_internal.hh"

using std::map;
using std::string;
using std::function;

void gob_trace(string path, map<gob::Address, gob::Symbol> symbols, function<void(gob::Symbol)> handler) {

    int pid = fork();
    if (pid < 0)
        throw gob::gob_exception("Couldn't start process with " + path);

    if (pid == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);

        char *argv[] = { const_cast<char*>(path.c_str()), NULL };
        char *envp[] = { NULL };

        execve(const_cast<char*>(path.c_str()), argv, envp);
    }

    int status = 0;

    wait(&status);

    if (!WIFSTOPPED(status))
        throw gob::gob_exception("Couldn't trace target process");

    map<int, long int> bps;
    for (auto i = symbols.begin(); i != symbols.end(); ++i) {
        printf("setting breakpoint for %s at 0x%lx\n", i->second.name.c_str(), i->first);
        // store the existing byte
        auto value = ptrace(PTRACE_PEEKTEXT, pid, i->first, 0);
        printf("overwriting ins 0x%lx\n", value);
        bps[i->first] = value;

        // and set a breakpoint
        ptrace(PTRACE_POKETEXT, pid, i->first, 0xCC);
    }

    ptrace(PTRACE_CONT, pid, 0, 0);

    while (1) {
        wait(&status);

        if (WIFEXITED(status)) {
            break;
        }

        if (WIFSTOPPED(status)) {
           struct user_regs_struct regs;
           ptrace(PTRACE_GETREGS, pid, NULL, &regs);

           printf("stopped at 0x%llx\n", regs.rip);

            // bp has just been executed so
            regs.rip -= 1;

           auto sym = symbols.find(regs.rip);
           if (sym != symbols.end()) {
                printf("replacing ins 0x%lx\n", bps[regs.rip]);
                // replace the value
                ptrace(PTRACE_POKETEXT, pid, regs.rip, bps[regs.rip]);
                // move the ins pointer
                ptrace(PTRACE_SETREGS, pid, 0, &regs);
                // invoke the handler
                handler(sym->second);
           }

           ptrace(PTRACE_GETREGS, pid, NULL, &regs);
           printf("continuing at 0x%llx\n", regs.rip);
           // and then carry on with the run
           ptrace(PTRACE_CONT, pid, NULL, NULL);
        }
    }
}
<commit_msg>Removed debug lines<commit_after>#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
#include <map>
#include <string>
#include <functional>

#include "gob_internal.hh"

using std::map;
using std::string;
using std::function;

void gob_trace(string path, map<gob::Address, gob::Symbol> symbols, function<void(gob::Symbol)> handler) {

    int pid = fork();
    if (pid < 0)
        throw gob::gob_exception("Couldn't start process with " + path);

    if (pid == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);

        char *argv[] = { const_cast<char*>(path.c_str()), NULL };
        char *envp[] = { NULL };

        execve(const_cast<char*>(path.c_str()), argv, envp);
    }

    int status = 0;

    wait(&status);

    if (!WIFSTOPPED(status))
        throw gob::gob_exception("Couldn't trace target process");

    map<int, long int> bps;
    for (auto i = symbols.begin(); i != symbols.end(); ++i) {
        // store the existing byte
        auto value = ptrace(PTRACE_PEEKTEXT, pid, i->first, 0);
        bps[i->first] = value;

        // and set a breakpoint
        ptrace(PTRACE_POKETEXT, pid, i->first, 0xCC);
    }

    ptrace(PTRACE_CONT, pid, 0, 0);

    while (1) {
        wait(&status);

        if (WIFEXITED(status)) {
            break;
        }

        if (WIFSTOPPED(status)) {
           struct user_regs_struct regs;
           ptrace(PTRACE_GETREGS, pid, NULL, &regs);

           // bp has just been executed so
           regs.rip -= 1;

           auto sym = symbols.find(regs.rip);
           if (sym != symbols.end()) {
                // replace the value
                ptrace(PTRACE_POKETEXT, pid, regs.rip, bps[regs.rip]);
                // move the ins pointer
                ptrace(PTRACE_SETREGS, pid, 0, &regs);
                // invoke the handler
                handler(sym->second);
           }

           // and then carry on with the run
           ptrace(PTRACE_CONT, pid, NULL, NULL);
        }
    }
}
<|endoftext|>


<commit_before>/***
DEVSIM
Copyright 2013 Devsim LLC

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 "Fermi.hh"
#include "BoostConstants.hh"
#ifdef DEVSIM_EXTENDED_PRECISION
#include "Float128.hh"
#endif
#include <cmath>
using std::abs;
#include <cstdlib>
namespace
{
// TODO: "These coefficients only worked out for amd64 in current configuration"
const double breakpoint = 8.46296036621705;
const double offset = -0.0137050034663995;

template <typename T>
T Joyce(T r)
{
    //static const T sqrt1_8 = 1.0/sqrt(8.);
    static const T sqrt1_8 = 0.5 * boost::math::constants::one_div_root_pi<T>();
    static const T c1 = -4.9500897298752622e-3;
    static const T c2 =  1.4838577128872821e-4;
    static const T c3 = -4.4256301190009895e-6;

    T R = r;
    T sum = log(r);
    sum += sqrt1_8 * R;
    R *= r;
    sum += c1 * R;
    R *= r;
    sum += c2 * R;
    R *= r;
    sum += c3 * R;

    return sum;
}

template <typename T>
T dJoycedx(T r)
{
    //static const double sqrt1_8 = 1.0/sqrt(8.);
    static const T sqrt1_8 = 0.5 * boost::math::constants::one_div_root_pi<T>();
    static const T c1 = -2.0*4.9500897298752622e-3;
    static const T c2 =  3.0*1.4838577128872821e-4;
    static const T c3 = -4.0*4.4256301190009895e-6;

    T sum = 1/r;
    T R = r;
    sum += sqrt1_8;
    sum += c1 * R;
    R *= r;
    sum += c2 * R;
    R *= r;
    sum += c3 * R;

    return sum;
}

template <typename T>
T Expansion(T r)
{
    /// M_PI_4 = pi/4
    // static const T d1 = 3./4.* sqrt(M_PI);
    static const T d1 = boost::math::constants::three_quarters_pi<T>();
    //static const T d2 = 4./3.;
    static const T d2 = static_cast<T>(4.)/static_cast<T>(3.);
    //static const T d3 = - M_PI * M_PI/6;
    static const T d3 = - boost::math::constants::pi_sqr_div_six<T>();
    //static const double d1 = 3./4.* sqrt(M_PI);
    //static const double d2 = 4./3.;
    //static const double d3 = - M_PI * M_PI/6;
    T sum = pow(d1*r, d2);
    sum += d3;
    sum = sqrt(sum);

    sum += offset;
    return sum;
}

template <typename T>
T dExpansiondx(T r)
{

        //static const double d0 = sqrt(M_PI)/2.0;
        //static const T d0 = sqrt(M_PI)/2.0;
        static const T d0 = 0.5 * boost::math::constants::root_pi<T>();
        //static const T d1 = 3./4.* sqrt(M_PI);
        static const T d1 = 3./4. * boost::math::constants::root_pi<T>();
        //static const double d2 = 1.0/3.0;
        static const T d2 = boost::math::constants::third<T>();
        T sum = d0 * pow(d1 * r, d2) / Expansion(r);
        return sum;
}

template <typename T>
T good_relerror()
{
}

template <>
double good_relerror()
{
  return 1e-12;
}

#ifdef DEVSIM_EXTENDED_PRECISION
template <>
float128 good_relerror()
{
  return 1e-31;
}
#endif
}

template <typename T>
T InvFermi(T r)
{
    if (r < breakpoint)
    {
        return Joyce(r);
    }
    else
    {
        return Expansion(r);
    }
}

template <typename T>
T dInvFermidx(T r)
{
    if (r < breakpoint)
    {
        return dJoycedx(r);
    }
    else
    {
        return dExpansiondx(r);
    }
}

//// Need some way to calculate a function and its derivative simultaneously
//#include <iostream>
template <typename T>
T Fermi(T Eta)
{
    //// initial guess
    T r = exp(Eta);
//    std::cerr << "Init: " << Eta << " " << r << std::endl;
    T rerr = 0.0;
    size_t i = 0;
    do
    {
        const T f = InvFermi(r) - Eta;
        const T fp = dInvFermidx(r);
        T upd = -f/fp;
        while ((upd + r) <= 0.0)
        {
            upd *= 0.5;
        }
        r += upd;
        //// eta would be -infinity for r to go to 0
        rerr = abs(upd)/(abs(r)+good_relerror<T>());
//      std::cerr << "try " << i << " " << r <<  " " << f << " " << fp << " " << upd << " " << rerr << std::endl;
//      TODO: consider second order newton
        ++i;
    } while ((rerr > good_relerror<T>()) && (i < 20) ) ;
    ///// Arbitrary relative error
    return r;

}
///// define dFermidx as g'(x) = 1.0 / (f'(g(x)));
///// This is inefficient so be sure to program special node model depending on ferm result
template <typename T>
T dFermidx(T Eta)
{
    return 1.0/dInvFermidx(Fermi(Eta));
}

template double InvFermi<double>(double);
template double dInvFermidx<double>(double);
template double Fermi<double>(double);
template double dFermidx<double>(double);
#ifdef DEVSIM_EXTENDED_PRECISION
template float128 InvFermi<float128>(float128);
template float128 dInvFermidx<float128>(float128);
template float128 Fermi<float128>(float128);
template float128 dFermidx<float128>(float128);
#endif

#ifdef DEVSIM_UNIT_TEST
#include <iostream>
#include <iomanip>
template <typename T>
T pdiff(T x1, T x2)
{
    return 2.0*(x1-x2)/(x1+x2);
}
template <typename T>
void unit()
{
    std::cout << std::setprecision(std::numeric_limits<T>::max_digits10);
    for (T x = 8.46296036621705; x < 8.46296036621707; x += 0.0000001)
    {
        std::cout
            << x << " "
            << InvFermi(x) << " "
            << Joyce(x) << " "
            << Expansion(x) << " "
            << dJoycedx(x) << " "
            << dExpansiondx(x) <<" "
            << pdiff(dJoycedx(x), dExpansiondx(x)) << " " << Expansion(x)-Joyce(x) <<"\n";
    }
    for (T x = 4.8; x < 4.9; x += 0.001)
    {
        std::cout << x << " " << Fermi(x) << " " << dFermidx(x) << "\n";
    }
}

int main()
{
  unit<double>();
#ifdef DEVSIM_EXTENDED_PRECISION
  unit<float128>();
#endif
}
#endif

<commit_msg>update reference<commit_after>/***
DEVSIM
Copyright 2013 Devsim LLC

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.
***/

/*
@article{doi:10.1063/1.89697,
author = {Joyce,W. B.  and Dixon,R. W. },
title = {Analytic approximations for the Fermi energy of an ideal Fermi gas},
journal = {Applied Physics Letters},
volume = {31},
number = {5},
pages = {354-356},
year = {1977},
doi = {10.1063/1.89697},
URL = { https://doi.org/10.1063/1.89697 },
eprint = { https://doi.org/10.1063/1.89697 }
}

*/

#include "Fermi.hh"
#include "BoostConstants.hh"
#ifdef DEVSIM_EXTENDED_PRECISION
#include "Float128.hh"
#endif
#include <cmath>
using std::abs;
#include <cstdlib>
namespace
{
// TODO: "These coefficients only worked out for amd64 in current configuration"
const double breakpoint = 8.46296036621705;
const double offset = -0.0137050034663995;

template <typename T>
T Joyce(T r)
{
    //static const T sqrt1_8 = 1.0/sqrt(8.);
    static const T sqrt1_8 = 0.5 * boost::math::constants::one_div_root_pi<T>();
    static const T c1 = -4.9500897298752622e-3;
    static const T c2 =  1.4838577128872821e-4;
    static const T c3 = -4.4256301190009895e-6;

    T R = r;
    T sum = log(r);
    sum += sqrt1_8 * R;
    R *= r;
    sum += c1 * R;
    R *= r;
    sum += c2 * R;
    R *= r;
    sum += c3 * R;

    return sum;
}

template <typename T>
T dJoycedx(T r)
{
    //static const double sqrt1_8 = 1.0/sqrt(8.);
    static const T sqrt1_8 = 0.5 * boost::math::constants::one_div_root_pi<T>();
    static const T c1 = -2.0*4.9500897298752622e-3;
    static const T c2 =  3.0*1.4838577128872821e-4;
    static const T c3 = -4.0*4.4256301190009895e-6;

    T sum = 1/r;
    T R = r;
    sum += sqrt1_8;
    sum += c1 * R;
    R *= r;
    sum += c2 * R;
    R *= r;
    sum += c3 * R;

    return sum;
}

template <typename T>
T Expansion(T r)
{
    /// M_PI_4 = pi/4
    // static const T d1 = 3./4.* sqrt(M_PI);
    static const T d1 = boost::math::constants::three_quarters_pi<T>();
    //static const T d2 = 4./3.;
    static const T d2 = static_cast<T>(4.)/static_cast<T>(3.);
    //static const T d3 = - M_PI * M_PI/6;
    static const T d3 = - boost::math::constants::pi_sqr_div_six<T>();
    //static const double d1 = 3./4.* sqrt(M_PI);
    //static const double d2 = 4./3.;
    //static const double d3 = - M_PI * M_PI/6;
    T sum = pow(d1*r, d2);
    sum += d3;
    sum = sqrt(sum);

    sum += offset;
    return sum;
}

template <typename T>
T dExpansiondx(T r)
{

        //static const double d0 = sqrt(M_PI)/2.0;
        //static const T d0 = sqrt(M_PI)/2.0;
        static const T d0 = 0.5 * boost::math::constants::root_pi<T>();
        //static const T d1 = 3./4.* sqrt(M_PI);
        static const T d1 = 3./4. * boost::math::constants::root_pi<T>();
        //static const double d2 = 1.0/3.0;
        static const T d2 = boost::math::constants::third<T>();
        T sum = d0 * pow(d1 * r, d2) / Expansion(r);
        return sum;
}

template <typename T>
T good_relerror()
{
}

template <>
double good_relerror()
{
  return 1e-12;
}

#ifdef DEVSIM_EXTENDED_PRECISION
template <>
float128 good_relerror()
{
  return 1e-31;
}
#endif
}

template <typename T>
T InvFermi(T r)
{
    if (r < breakpoint)
    {
        return Joyce(r);
    }
    else
    {
        return Expansion(r);
    }
}

template <typename T>
T dInvFermidx(T r)
{
    if (r < breakpoint)
    {
        return dJoycedx(r);
    }
    else
    {
        return dExpansiondx(r);
    }
}

//// Need some way to calculate a function and its derivative simultaneously
//#include <iostream>
template <typename T>
T Fermi(T Eta)
{
    //// initial guess
    T r = exp(Eta);
//    std::cerr << "Init: " << Eta << " " << r << std::endl;
    T rerr = 0.0;
    size_t i = 0;
    do
    {
        const T f = InvFermi(r) - Eta;
        const T fp = dInvFermidx(r);
        T upd = -f/fp;
        while ((upd + r) <= 0.0)
        {
            upd *= 0.5;
        }
        r += upd;
        //// eta would be -infinity for r to go to 0
        rerr = abs(upd)/(abs(r)+good_relerror<T>());
//      std::cerr << "try " << i << " " << r <<  " " << f << " " << fp << " " << upd << " " << rerr << std::endl;
//      TODO: consider second order newton
        ++i;
    } while ((rerr > good_relerror<T>()) && (i < 20) ) ;
    ///// Arbitrary relative error
    return r;

}
///// define dFermidx as g'(x) = 1.0 / (f'(g(x)));
///// This is inefficient so be sure to program special node model depending on ferm result
template <typename T>
T dFermidx(T Eta)
{
    return 1.0/dInvFermidx(Fermi(Eta));
}

template double InvFermi<double>(double);
template double dInvFermidx<double>(double);
template double Fermi<double>(double);
template double dFermidx<double>(double);
#ifdef DEVSIM_EXTENDED_PRECISION
template float128 InvFermi<float128>(float128);
template float128 dInvFermidx<float128>(float128);
template float128 Fermi<float128>(float128);
template float128 dFermidx<float128>(float128);
#endif

#ifdef DEVSIM_UNIT_TEST
#include <iostream>
#include <iomanip>
template <typename T>
T pdiff(T x1, T x2)
{
    return 2.0*(x1-x2)/(x1+x2);
}
template <typename T>
void unit()
{
    std::cout << std::setprecision(std::numeric_limits<T>::max_digits10);
    for (T x = 8.46296036621705; x < 8.46296036621707; x += 0.0000001)
    {
        std::cout
            << x << " "
            << InvFermi(x) << " "
            << Joyce(x) << " "
            << Expansion(x) << " "
            << dJoycedx(x) << " "
            << dExpansiondx(x) <<" "
            << pdiff(dJoycedx(x), dExpansiondx(x)) << " " << Expansion(x)-Joyce(x) <<"\n";
    }
    for (T x = 4.8; x < 4.9; x += 0.001)
    {
        std::cout << x << " " << Fermi(x) << " " << dFermidx(x) << "\n";
    }
}

int main()
{
  unit<double>();
#ifdef DEVSIM_EXTENDED_PRECISION
  unit<float128>();
#endif
}
#endif

<|endoftext|>


<commit_before>/*
   Copyright (c) 2011, The Mineserver Project
   All rights reserved.

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

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

#ifdef WIN32
    #include <stdlib.h>
    #include <conio.h>
    #include <winsock2.h>
    typedef  int socklen_t;
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#include <errno.h>
#include <iostream>
#include <fstream>
#include <deque>
#include <vector>
#include <ctime>
#include <event.h>
#include <sys/stat.h>
#include <zlib.h>

#include "tools.h"

#include "logger.h"
#include "constants.h"
#include "user.h"
#include "map.h"
#include "chat.h"
#include "nbt.h"
#include "mineserver.h"

#include "packets.h"
#include <algorithm>

extern int setnonblock(int fd);

#ifndef WIN32
#define SOCKET_ERROR -1
#endif

void client_callback(int fd,
                     short ev,
                     void *arg)
{
  User *user = (User *)arg;
  /*
  std::vector<User *>::const_iterator it = std::find (Mineserver::get()->users().begin(),
                                                      Mineserver::get()->users().end(), user);
  if(it == Mineserver::get()->users().end())
  {
    Mineserver::get()->logger()->log(LogType::LOG_INFO, "Sockets", "Using dead player!!!");
    return;
  }
  */
  if(ev & EV_READ)
  {

    int read   = 1;

    uint8_t *buf = new uint8_t[2048];

    read = recv(fd, (char*)buf, 2048, 0);
    if(read == 0)
    {
      Mineserver::get()->logger()->log(LogType::LOG_INFO, "Sockets", "Socket closed properly");

      delete user;
      user = (User *)1;
      delete[] buf;
      return;
    }

    if(read == SOCKET_ERROR)
    {
      Mineserver::get()->logger()->log(LogType::LOG_INFO, "Sockets", "Socket had no data to read");

      delete user;
      user = (User *)2;
      delete[] buf;
      return;
    }

    user->lastData = time(NULL);

    user->buffer.addToRead(buf, read);

    delete[] buf;

    user->buffer.reset();

    while(user->buffer >> (int8_t&)user->action)
    {
      //Variable len package
      if(Mineserver::get()->packetHandler()->packets[user->action].len == PACKET_VARIABLE_LEN)
      {
        //Call specific function
        int (PacketHandler::*function)(User *) =
          Mineserver::get()->packetHandler()->packets[user->action].function;
        bool disconnecting = user->action == 0xFF;
        int curpos = (Mineserver::get()->packetHandler()->*function)(user);
        if(curpos == PACKET_NEED_MORE_DATA)
        {
          user->waitForData = true;
          event_set(user->GetEvent(), fd, EV_READ, client_callback, user);
          event_add(user->GetEvent(), NULL);
          return;
        }

        if(disconnecting) // disconnect -- player gone
        {
          delete user;
          user = (User *)4;
          return;
        }
      }
      else if(Mineserver::get()->packetHandler()->packets[user->action].len == PACKET_DOES_NOT_EXIST)
      {
        printf("Unknown action: 0x%x\n", user->action);

        delete user;
        user = (User *)3;
        return;
      }
      else
      {
        if(!user->buffer.haveData(Mineserver::get()->packetHandler()->packets[user->action].len))
        {
          user->waitForData = true;
          event_set(user->GetEvent(), fd, EV_READ, client_callback, user);
          event_add(user->GetEvent(), NULL);
          return;
        }

        //Call specific function
        int (PacketHandler::*function)(User *) = Mineserver::get()->packetHandler()->packets[user->action].function;
        (Mineserver::get()->packetHandler()->*function)(user);
      }
    } //End while
  }

  int writeLen = user->buffer.getWriteLen();
  if(writeLen)
  {
    int written = send(fd, (char*)user->buffer.getWrite(), writeLen, 0);
    if(written == SOCKET_ERROR)
    {
      #ifdef WIN32
      #define ERROR_NUMBER WSAGetLastError()
      if((errno != WSATRY_AGAIN && errno != WSAEINTR))
      #else
      #define ERROR_NUMBER errno
      if((errno != EAGAIN && errno != EINTR))
      #endif
      {
        Mineserver::get()->logger()->log(LogType::LOG_ERROR, "Socket", "Error writing to client, tried to write " + dtos(writeLen) + " bytes, code: " + dtos(ERROR_NUMBER));

        delete user;
        user = (User *)5;
        return;
      }
      else
      {
        //user->write_err_count++;
      }

    }
    else
    {
      user->buffer.clearWrite(written);
      //user->write_err_count=0;
    }

    if(user->buffer.getWriteLen())
    {
      event_set(user->GetEvent(), fd, EV_WRITE|EV_READ, client_callback, user);
      event_add(user->GetEvent(), NULL);
      return;
    }
  }

  event_set(user->GetEvent(), fd, EV_READ, client_callback, user);
  event_add(user->GetEvent(), NULL);
}

void accept_callback(int fd,
                     short ev,
                     void *arg)
{
  int client_fd;
  struct sockaddr_in client_addr;
  socklen_t client_len = sizeof(client_addr);

  client_fd = accept(fd,
                     (struct sockaddr *)&client_addr,
                     &client_len);
  if(client_fd < 0)
  {
    LOGLF("Client: accept() failed");
    return;
  }
  User *client = new User(client_fd, generateEID());
  setnonblock(client_fd);

  event_set(client->GetEvent(), client_fd,EV_WRITE|EV_READ, client_callback, client);
  event_add(client->GetEvent(), NULL);

}
<commit_msg>windows sockets fix<commit_after>/*
   Copyright (c) 2011, The Mineserver Project
   All rights reserved.

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

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

#ifdef WIN32
    #include <stdlib.h>
    #include <conio.h>
    #include <winsock2.h>
    typedef  int socklen_t;
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#include <errno.h>
#include <iostream>
#include <fstream>
#include <deque>
#include <vector>
#include <ctime>
#include <event.h>
#include <sys/stat.h>
#include <zlib.h>

#include "tools.h"

#include "logger.h"
#include "constants.h"
#include "user.h"
#include "map.h"
#include "chat.h"
#include "nbt.h"
#include "mineserver.h"

#include "packets.h"
#include <algorithm>

extern int setnonblock(int fd);

#ifndef WIN32
#define SOCKET_ERROR -1
#endif

void client_callback(int fd,
                     short ev,
                     void *arg)
{
  User *user = (User *)arg;
  /*
  std::vector<User *>::const_iterator it = std::find (Mineserver::get()->users().begin(),
                                                      Mineserver::get()->users().end(), user);
  if(it == Mineserver::get()->users().end())
  {
    Mineserver::get()->logger()->log(LogType::LOG_INFO, "Sockets", "Using dead player!!!");
    return;
  }
  */
  if(ev & EV_READ)
  {

    int read   = 1;

    uint8_t *buf = new uint8_t[2048];

    read = recv(fd, (char*)buf, 2048, 0);
    if(read == 0)
    {
      Mineserver::get()->logger()->log(LogType::LOG_INFO, "Sockets", "Socket closed properly");

      delete user;
      user = (User *)1;
      delete[] buf;
      return;
    }

    if(read == SOCKET_ERROR)
    {
      Mineserver::get()->logger()->log(LogType::LOG_INFO, "Sockets", "Socket had no data to read");

      delete user;
      user = (User *)2;
      delete[] buf;
      return;
    }

    user->lastData = time(NULL);

    user->buffer.addToRead(buf, read);

    delete[] buf;

    user->buffer.reset();

    while(user->buffer >> (int8_t&)user->action)
    {
      //Variable len package
      if(Mineserver::get()->packetHandler()->packets[user->action].len == PACKET_VARIABLE_LEN)
      {
        //Call specific function
        int (PacketHandler::*function)(User *) =
          Mineserver::get()->packetHandler()->packets[user->action].function;
        bool disconnecting = user->action == 0xFF;
        int curpos = (Mineserver::get()->packetHandler()->*function)(user);
        if(curpos == PACKET_NEED_MORE_DATA)
        {
          user->waitForData = true;
          event_set(user->GetEvent(), fd, EV_READ, client_callback, user);
          event_add(user->GetEvent(), NULL);
          return;
        }

        if(disconnecting) // disconnect -- player gone
        {
          delete user;
          user = (User *)4;
          return;
        }
      }
      else if(Mineserver::get()->packetHandler()->packets[user->action].len == PACKET_DOES_NOT_EXIST)
      {
        printf("Unknown action: 0x%x\n", user->action);

        delete user;
        user = (User *)3;
        return;
      }
      else
      {
        if(!user->buffer.haveData(Mineserver::get()->packetHandler()->packets[user->action].len))
        {
          user->waitForData = true;
          event_set(user->GetEvent(), fd, EV_READ, client_callback, user);
          event_add(user->GetEvent(), NULL);
          return;
        }

        //Call specific function
        int (PacketHandler::*function)(User *) = Mineserver::get()->packetHandler()->packets[user->action].function;
        (Mineserver::get()->packetHandler()->*function)(user);
      }
    } //End while
  }

  int writeLen = user->buffer.getWriteLen();
  if(writeLen)
  {
    int written = send(fd, (char*)user->buffer.getWrite(), writeLen, 0);
    if(written == SOCKET_ERROR)
    {
      #ifdef WIN32
      #define ERROR_NUMBER WSAGetLastError()
      if((ERROR_NUMBER != WSATRY_AGAIN && ERROR_NUMBER != WSAEINTR && ERROR_NUMBER != WSAEWOULDBLOCK))
      #else
      #define ERROR_NUMBER errno
      if((errno != EAGAIN && errno != EINTR))
      #endif
      {
        Mineserver::get()->logger()->log(LogType::LOG_ERROR, "Socket", "Error writing to client, tried to write " + dtos(writeLen) + " bytes, code: " + dtos(ERROR_NUMBER));

        delete user;
        user = (User *)5;
        return;
      }
      else
      {
        //user->write_err_count++;
      }

    }
    else
    {
      user->buffer.clearWrite(written);
      //user->write_err_count=0;
    }

    if(user->buffer.getWriteLen())
    {
      event_set(user->GetEvent(), fd, EV_WRITE|EV_READ, client_callback, user);
      event_add(user->GetEvent(), NULL);
      return;
    }
  }

  event_set(user->GetEvent(), fd, EV_READ, client_callback, user);
  event_add(user->GetEvent(), NULL);
}

void accept_callback(int fd,
                     short ev,
                     void *arg)
{
  int client_fd;
  struct sockaddr_in client_addr;
  socklen_t client_len = sizeof(client_addr);

  client_fd = accept(fd,
                     (struct sockaddr *)&client_addr,
                     &client_len);
  if(client_fd < 0)
  {
    LOGLF("Client: accept() failed");
    return;
  }
  User *client = new User(client_fd, generateEID());
  setnonblock(client_fd);

  event_set(client->GetEvent(), client_fd,EV_WRITE|EV_READ, client_callback, client);
  event_add(client->GetEvent(), NULL);

}
<|endoftext|>


<commit_before>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "Enderman.h"
#include "../Entities/Player.h"
#include "../Tracer.h"

////////////////////////////////////////////////////////////////////////////////
// cPlayerLookCheck
class cPlayerLookCheck :
	public cPlayerListCallback
{
public:
	cPlayerLookCheck(Vector3d a_EndermanPos, int a_SightDistance) :
		m_Player(NULL),
		m_EndermanPos(a_EndermanPos),
		m_SightDistance(a_SightDistance)
	{
	}

	virtual bool Item(cPlayer * a_Player) override
	{
		// Don't check players who are in creative gamemode
		if (a_Player->IsGameModeCreative())
		{
			return false;
		}

		Vector3d Direction = m_EndermanPos - a_Player->GetPosition();

		// Don't check players who are more then SightDistance (64) blocks away
		if (Direction.Length() > m_SightDistance)
		{
			return false;
		}

		// Don't check if the player has a pumpkin on his head
		if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN)
		{
			return false;
		}

		Vector3d LookVector = a_Player->GetLookVector();
		double dot = Direction.Dot(LookVector);

		// 0.09 rad ~ 5 degrees
		// If the player's crosshair is within 5 degrees of the enderman, it counts as looking
		if (dot <= cos(0.09))
		{
			return false;
		}

		cTracer LineOfSight(a_Player->GetWorld());
		if (LineOfSight.Trace(m_EndermanPos, Direction, (int)Direction.Length()))
		{
			// No direct line of sight
			return false;
		}

		m_Player = a_Player;
		return true;
	}

	cPlayer * GetPlayer(void) const { return m_Player; }

protected:
	cPlayer * m_Player;
	Vector3d m_EndermanPos;
	int m_SightDistance;
} ;

cEnderman::cEnderman(void) :
	super("Enderman", mtEnderman, "mob.endermen.hit", "mob.endermen.death", 0.5, 2.9),
	m_bIsScreaming(false),
	CarriedBlock(E_BLOCK_AIR),
	CarriedMeta(0)
{
}

void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
	int LootingLevel = 0;
	if (a_Killer != NULL)
	{
		LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
	}
	AddRandomDropItem(a_Drops, 0, 1 + LootingLevel, E_ITEM_ENDER_PEARL);
}

void cEnderman::CheckEventSeePlayer()
{
	if (m_Target != NULL)
	{
		return;
	}

	cPlayerLookCheck Callback(GetPosition(), m_SightDistance);
	if (m_World->ForEachPlayer(Callback))
	{
		return;
	}

	ASSERT(Callback.GetPlayer() != NULL);

	if (!CheckLight())
	{
		// Insufficient light for enderman to become aggravated
		// TODO: Teleport to a suitable location
		return;
	}

	if (!Callback.GetPlayer()->IsGameModeCreative())
	{
		super::EventSeePlayer(Callback.GetPlayer());
		m_EMState = CHASING;
		m_bIsScreaming = true;
		GetWorld()->BroadcastEntityMetadata(*this);
	}
}

void cEnderman::CheckEventLostPlayer(void)
{
	super::CheckEventLostPlayer();
	if (!CheckLight())
	{
		EventLosePlayer();
	}
}

void cEnderman::EventLosePlayer()
{
	super::EventLosePlayer();
	m_bIsScreaming = false;
	GetWorld()->BroadcastEntityMetadata(*this);
}

bool cEnderman::CheckLight()
{
	int ChunkX, ChunkZ;
	cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ);

	// Check if the chunk the enderman is in is lit
	if (!m_World->IsChunkLighted(ChunkX, ChunkZ))
	{
		m_World->QueueLightChunk(ChunkX, ChunkZ);
		return true;
	}

	// Enderman only attack if the skylight is lower or equal to 8
	if (m_World->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) - GetWorld()->GetSkyDarkness() > 8)
	{
		return false;
	}

	return true;
}

void cEnderman::Tick(float a_Dt, cChunk & a_Chunk)
{
	super::Tick(a_Dt, a_Chunk);

	//TODO take damage in rain

	//Take damage when touching water, drowning damage seems to be most appropriate
	if (IsSwimming())
	{
		EventLosePlayer();
		TakeDamage(dtDrowning, NULL, 1, 0);
		//TODO teleport to a safe location
	}

}
<commit_msg>Fix comments<commit_after>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "Enderman.h"
#include "../Entities/Player.h"
#include "../Tracer.h"

////////////////////////////////////////////////////////////////////////////////
// cPlayerLookCheck
class cPlayerLookCheck :
	public cPlayerListCallback
{
public:
	cPlayerLookCheck(Vector3d a_EndermanPos, int a_SightDistance) :
		m_Player(NULL),
		m_EndermanPos(a_EndermanPos),
		m_SightDistance(a_SightDistance)
	{
	}

	virtual bool Item(cPlayer * a_Player) override
	{
		// Don't check players who are in creative gamemode
		if (a_Player->IsGameModeCreative())
		{
			return false;
		}

		Vector3d Direction = m_EndermanPos - a_Player->GetPosition();

		// Don't check players who are more then SightDistance (64) blocks away
		if (Direction.Length() > m_SightDistance)
		{
			return false;
		}

		// Don't check if the player has a pumpkin on his head
		if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN)
		{
			return false;
		}

		Vector3d LookVector = a_Player->GetLookVector();
		double dot = Direction.Dot(LookVector);

		// 0.09 rad ~ 5 degrees
		// If the player's crosshair is within 5 degrees of the enderman, it counts as looking
		if (dot <= cos(0.09))
		{
			return false;
		}

		cTracer LineOfSight(a_Player->GetWorld());
		if (LineOfSight.Trace(m_EndermanPos, Direction, (int)Direction.Length()))
		{
			// No direct line of sight
			return false;
		}

		m_Player = a_Player;
		return true;
	}

	cPlayer * GetPlayer(void) const { return m_Player; }

protected:
	cPlayer * m_Player;
	Vector3d m_EndermanPos;
	int m_SightDistance;
} ;

cEnderman::cEnderman(void) :
	super("Enderman", mtEnderman, "mob.endermen.hit", "mob.endermen.death", 0.5, 2.9),
	m_bIsScreaming(false),
	CarriedBlock(E_BLOCK_AIR),
	CarriedMeta(0)
{
}

void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
	int LootingLevel = 0;
	if (a_Killer != NULL)
	{
		LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
	}
	AddRandomDropItem(a_Drops, 0, 1 + LootingLevel, E_ITEM_ENDER_PEARL);
}

void cEnderman::CheckEventSeePlayer()
{
	if (m_Target != NULL)
	{
		return;
	}

	cPlayerLookCheck Callback(GetPosition(), m_SightDistance);
	if (m_World->ForEachPlayer(Callback))
	{
		return;
	}

	ASSERT(Callback.GetPlayer() != NULL);

	if (!CheckLight())
	{
		// Insufficient light for enderman to become aggravated
		// TODO: Teleport to a suitable location
		return;
	}

	if (!Callback.GetPlayer()->IsGameModeCreative())
	{
		super::EventSeePlayer(Callback.GetPlayer());
		m_EMState = CHASING;
		m_bIsScreaming = true;
		GetWorld()->BroadcastEntityMetadata(*this);
	}
}

void cEnderman::CheckEventLostPlayer(void)
{
	super::CheckEventLostPlayer();
	if (!CheckLight())
	{
		EventLosePlayer();
	}
}

void cEnderman::EventLosePlayer()
{
	super::EventLosePlayer();
	m_bIsScreaming = false;
	GetWorld()->BroadcastEntityMetadata(*this);
}

bool cEnderman::CheckLight()
{
	int ChunkX, ChunkZ;
	cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ);

	// Check if the chunk the enderman is in is lit
	if (!m_World->IsChunkLighted(ChunkX, ChunkZ))
	{
		m_World->QueueLightChunk(ChunkX, ChunkZ);
		return true;
	}

	// Enderman only attack if the skylight is lower or equal to 8
	if (m_World->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) - GetWorld()->GetSkyDarkness() > 8)
	{
		return false;
	}

	return true;
}

void cEnderman::Tick(float a_Dt, cChunk & a_Chunk)
{
	super::Tick(a_Dt, a_Chunk);

	// TODO take damage in rain

	// Take damage when touching water, drowning damage seems to be most appropriate
	if (IsSwimming())
	{
		EventLosePlayer();
		TakeDamage(dtDrowning, NULL, 1, 0);
		//TODO teleport to a safe location
	}

}
<|endoftext|>


<commit_before><?hh //strict

/**
 * This file is part of hhpack/migrate.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace HHPack\Migrate\Application;

use HHPack\Getopt as cli;
use HHPack\Getopt\Parser\{ OptionParser };
use HHPack\Migrate\{ File, Output, Logger };
use HHPack\Migrate\Logger\{ PlainLogger, ColoredLogger };

final class MigrateApplication
{

    const PROGRAM_NAME = 'migrate';
    const PROGRAM_VERSION = '1.0.0';
    const PROGRAM_LICENCE = 'The MIT Licence';

    private bool $help = false;
    private bool $version = false;
    private bool $outputColor = true;
    private string $configurationPath = 'config/database.json';
    private OptionParser $optionParser;
    private ImmMap<string, Command> $commands;

    public function __construct(
        private Output $output
    )
    {
        $this->optionParser = cli\optparser([
            cli\take_on(['-c', '--config'], 'FILE', 'Path of configuration file', ($path) ==> {
                $this->configurationPath = $path;
            }),
            cli\on(['--no-color'], 'If specified, color output will not be performed', () ==> {
                $this->outputColor = false;
            }),
            cli\on(['-h', '--help'], 'Display help message', () ==> {
                $this->help = true;
            }),
            cli\on(['-v', '--version'], 'Display version', () ==> {
                $this->version = true;
            })
        ]);

        $this->commands = ImmMap {
            "up" => new UpCommand(),
            "down" => new DownCommand()
        };
    }

    public function run(Traversable<string> $argv): void
    {
        $cliArgv = Vector::fromItems($argv)->skip(1);
        $remainArgv = Vector::fromItems($this->optionParser->parse($cliArgv));

        if ($this->help || !$remainArgv->containsKey(0)) {
            $this->displayHelp();
        } else if ($this->version) {
            $this->displayVersion();
        } else {
            $commandName = $remainArgv->at(0);
            $this->runCommand($commandName, $argv);
        }
    }

    private function runCommand(string $name, Traversable<string> $argv): void
    {
        if (!$this->commands->contains($name)) {
            $this->displayHelp();
        } else {
            $loader = new ConfigurationLoader(File\absolutePath(getcwd() . $this->configurationPath));
            $env = getenv('HHVM_ENV') ? getenv('HHVM_ENV') : 'development';
            $configuration = $loader->load($env);

            $context = new MigrateContext($argv, $configuration, $this->outputLogger());

            $command = $this->commands->at($name);
            $command->run($context);
        }
    }

    private function outputLogger(): Logger {
        if ($this->outputColor) {
            return new ColoredLogger($this->output);
        } else {
            return new PlainLogger($this->output);
        }
    }

    private function displayHelp(): void
    {
        $this->output->write("Migration tool for database.\n");
        $this->output->write("https://github.com/hhpack/migrate");
        $this->output->write(sprintf("\n\n  %s %s %s\n\n",
            static::PROGRAM_NAME,
            "[OPTIONS]", "[COMMAND]"));

        $this->output->write("Commands:\n");
        $this->displayCommands();
        $this->output->write("\n");

        $this->optionParser->displayHelp();
    }

    private function displayCommands(): void
    {
        $keys = $this->commands->keys()->toValuesArray();
        $maxLength = (int) array_reduce($keys, (int $max, string $key) ==> {
            return ($max < strlen($key)) ? strlen($key) : $max;
        }, 0);

        foreach ($this->commands->lazy() as $name => $command) {
            $this->output->write(sprintf("  %s   %s\n", str_pad($name, $maxLength), $command->description()));
        }
    }

    private function displayVersion(): void
    {
        $this->output->write(sprintf("%s %s\n", static::PROGRAM_NAME, static::PROGRAM_VERSION));
    }

}
<commit_msg>fix --version option<commit_after><?hh //strict

/**
 * This file is part of hhpack/migrate.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace HHPack\Migrate\Application;

use HHPack\Getopt as cli;
use HHPack\Getopt\Parser\{ OptionParser };
use HHPack\Migrate\{ File, Output, Logger };
use HHPack\Migrate\Logger\{ PlainLogger, ColoredLogger };

final class MigrateApplication
{

    const PROGRAM_NAME = 'migrate';
    const PROGRAM_VERSION = '1.0.0';
    const PROGRAM_LICENCE = 'The MIT Licence';

    private bool $help = false;
    private bool $version = false;
    private bool $outputColor = true;
    private string $configurationPath = 'config/database.json';
    private OptionParser $optionParser;
    private ImmMap<string, Command> $commands;

    public function __construct(
        private Output $output
    )
    {
        $this->optionParser = cli\optparser([
            cli\take_on(['-c', '--config'], 'FILE', 'Path of configuration file', ($path) ==> {
                $this->configurationPath = $path;
            }),
            cli\on(['--no-color'], 'If specified, color output will not be performed', () ==> {
                $this->outputColor = false;
            }),
            cli\on(['-h', '--help'], 'Display help message', () ==> {
                $this->help = true;
            }),
            cli\on(['-v', '--version'], 'Display version', () ==> {
                $this->version = true;
            })
        ]);

        $this->commands = ImmMap {
            "up" => new UpCommand(),
            "down" => new DownCommand()
        };
    }

    public function run(Traversable<string> $argv): void
    {
        $cliArgv = Vector::fromItems($argv)->skip(1);
        $remainArgv = Vector::fromItems($this->optionParser->parse($cliArgv));

        if ($this->help) {
            $this->displayHelp();
        } else if ($this->version) {
            $this->displayVersion();
        } else if (!$remainArgv->containsKey(0)) {
            $this->displayHelp();
        } else {
            $commandName = $remainArgv->at(0);
            $this->runCommand($commandName, $argv);
        }
    }

    private function runCommand(string $name, Traversable<string> $argv): void
    {
        if (!$this->commands->contains($name)) {
            $this->displayHelp();
        } else {
            $loader = new ConfigurationLoader(File\absolutePath(getcwd() . $this->configurationPath));
            $env = getenv('HHVM_ENV') ? getenv('HHVM_ENV') : 'development';
            $configuration = $loader->load($env);

            $context = new MigrateContext($argv, $configuration, $this->outputLogger());

            $command = $this->commands->at($name);
            $command->run($context);
        }
    }

    private function outputLogger(): Logger {
        if ($this->outputColor) {
            return new ColoredLogger($this->output);
        } else {
            return new PlainLogger($this->output);
        }
    }

    private function displayHelp(): void
    {
        $this->output->write("Migration tool for database.\n");
        $this->output->write("https://github.com/hhpack/migrate");
        $this->output->write(sprintf("\n\n  %s %s %s\n\n",
            static::PROGRAM_NAME,
            "[OPTIONS]", "[COMMAND]"));

        $this->output->write("Commands:\n");
        $this->displayCommands();
        $this->output->write("\n");

        $this->optionParser->displayHelp();
    }

    private function displayCommands(): void
    {
        $keys = $this->commands->keys()->toValuesArray();
        $maxLength = (int) array_reduce($keys, (int $max, string $key) ==> {
            return ($max < strlen($key)) ? strlen($key) : $max;
        }, 0);

        foreach ($this->commands->lazy() as $name => $command) {
            $this->output->write(sprintf("  %s   %s\n", str_pad($name, $maxLength), $command->description()));
        }
    }

    private function displayVersion(): void
    {
        $this->output->write(sprintf("%s %s\n", static::PROGRAM_NAME, static::PROGRAM_VERSION));
    }

}
<|endoftext|>


<commit_before>#ifndef ITER_COMPRESS_H_
#define ITER_COMPRESS_H_

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of Compressed and compress
    template <typename Container, typename Selector>
    class Compressed;

    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(Container&&, Selector&&);

    template <typename T, typename Selector>
    Compressed<std::initializer_list<T>, Selector> compress(
            std::initializer_list<T>, Selector&&);

    template <typename Container, typename T>
    Compressed<Container, std::initializer_list<T>> compress(
            Container&&, std::initializer_list<T>);

    template <typename T, typename U>
    Compressed<std::initializer_list<T>, std::initializer_list<U>> compress(
            std::initializer_list<T>, std::initializer_list<U>);

    template <typename Container, typename Selector>
    class Compressed  {
        private:
            Container container;
            Selector selectors;

            // The only thing allowed to directly instantiate an Compressed is
            // the compress function
            friend Compressed compress<Container, Selector>(
                    Container&&, Selector&&);

            template <typename T, typename Sel>
            friend Compressed<std::initializer_list<T>, Sel> compress(
                    std::initializer_list<T>, Sel&&);

            template <typename Con, typename T>
            friend Compressed<Con, std::initializer_list<T>> compress(
                    Con&&, std::initializer_list<T>);

            template <typename T, typename U>
            friend Compressed<std::initializer_list<T>,
                   std::initializer_list<U>> compress(
                    std::initializer_list<T>, std::initializer_list<U>);

            // Selector::Iterator type
            using selector_iter_type = decltype(std::begin(selectors));

            // Value constructor for use only in the compress function
            Compressed(Container&& container, Selector&& selectors)
                : container(std::forward<Container>(container)),
                selectors(std::forward<Selector>(selectors))
            { }

        public:

            class Iterator
                : public std::iterator<std::input_iterator_tag,
                        iterator_traits_deref<Container>>
            {
                private:
                    iterator_type<Container> sub_iter;
                    iterator_type<Container> sub_end;

                    selector_iter_type selector_iter;
                    selector_iter_type selector_end;

                    void increment_iterators() {
                        ++this->sub_iter;
                        ++this->selector_iter;
                    }

                    void skip_failures() {
                        while (this->sub_iter != this->sub_end
                               && this->selector_iter != this->selector_end
                                && !*this->selector_iter) {
                            this->increment_iterators();
                        }
                    }

                public:
                    Iterator(iterator_type<Container> cont_iter,
                            iterator_type<Container> cont_end,
                            selector_iter_type sel_iter,
                            selector_iter_type sel_end)
                        : sub_iter{cont_iter},
                        sub_end{cont_end},
                        selector_iter{sel_iter},
                        selector_end{sel_end}
                    {
                        this->skip_failures();
                    }

                    iterator_deref<Container> operator*() {
                        return *this->sub_iter;
                    }

                    Iterator& operator++() {
                        this->increment_iterators();
                        this->skip_failures();
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter
                            && this->selector_iter != other.selector_iter;
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }
            };

            Iterator begin() {
                return {std::begin(this->container), std::end(this->container),
                    std::begin(this->selectors), std::end(this->selectors)};
            }

            Iterator end() {
                return {std::end(this->container), std::end(this->container),
                        std::end(this->selectors), std::end(this->selectors)};
            }

    };

    // Helper function to instantiate an Compressed
    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(
            Container&& container, Selector&& selectors) {
        return {std::forward<Container>(container),
                std::forward<Selector>(selectors)};
    }

    template <typename T, typename Selector>
    Compressed<std::initializer_list<T>, Selector> compress(
            std::initializer_list<T> data, Selector&& selectors) {
        return {std::move(data),
                std::forward<Selector>(selectors)};
    }

    template <typename Container, typename T>
    Compressed<Container, std::initializer_list<T>> compress(
            Container&& container, std::initializer_list<T> selectors) {
        return {std::forward<Container>(container),
                std::move(selectors)};
    }

    template <typename T, typename U>
    Compressed<std::initializer_list<T>, std::initializer_list<U>> compress(
            std::initializer_list<T> data,
            std::initializer_list<U> selectors) {
        return {std::move(data),
                std::move(selectors)};
    }
}

#endif
<commit_msg>moves iterators rather than copies<commit_after>#ifndef ITER_COMPRESS_H_
#define ITER_COMPRESS_H_

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of Compressed and compress
    template <typename Container, typename Selector>
    class Compressed;

    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(Container&&, Selector&&);

    template <typename T, typename Selector>
    Compressed<std::initializer_list<T>, Selector> compress(
            std::initializer_list<T>, Selector&&);

    template <typename Container, typename T>
    Compressed<Container, std::initializer_list<T>> compress(
            Container&&, std::initializer_list<T>);

    template <typename T, typename U>
    Compressed<std::initializer_list<T>, std::initializer_list<U>> compress(
            std::initializer_list<T>, std::initializer_list<U>);

    template <typename Container, typename Selector>
    class Compressed  {
        private:
            Container container;
            Selector selectors;

            // The only thing allowed to directly instantiate an Compressed is
            // the compress function
            friend Compressed compress<Container, Selector>(
                    Container&&, Selector&&);

            template <typename T, typename Sel>
            friend Compressed<std::initializer_list<T>, Sel> compress(
                    std::initializer_list<T>, Sel&&);

            template <typename Con, typename T>
            friend Compressed<Con, std::initializer_list<T>> compress(
                    Con&&, std::initializer_list<T>);

            template <typename T, typename U>
            friend Compressed<std::initializer_list<T>,
                   std::initializer_list<U>> compress(
                    std::initializer_list<T>, std::initializer_list<U>);

            // Selector::Iterator type
            using selector_iter_type = decltype(std::begin(selectors));

            // Value constructor for use only in the compress function
            Compressed(Container&& container, Selector&& selectors)
                : container(std::forward<Container>(container)),
                selectors(std::forward<Selector>(selectors))
            { }

        public:

            class Iterator
                : public std::iterator<std::input_iterator_tag,
                        iterator_traits_deref<Container>>
            {
                private:
                    iterator_type<Container> sub_iter;
                    iterator_type<Container> sub_end;

                    selector_iter_type selector_iter;
                    selector_iter_type selector_end;

                    void increment_iterators() {
                        ++this->sub_iter;
                        ++this->selector_iter;
                    }

                    void skip_failures() {
                        while (this->sub_iter != this->sub_end
                               && this->selector_iter != this->selector_end
                                && !*this->selector_iter) {
                            this->increment_iterators();
                        }
                    }

                public:
                    Iterator(iterator_type<Container>&& cont_iter,
                            iterator_type<Container>&& cont_end,
                            selector_iter_type&& sel_iter,
                            selector_iter_type&& sel_end)
                        : sub_iter{std::move(cont_iter)},
                        sub_end{std::move(cont_end)},
                        selector_iter{std::move(sel_iter)},
                        selector_end{std::move(sel_end)}
                    {
                        this->skip_failures();
                    }

                    iterator_deref<Container> operator*() {
                        return *this->sub_iter;
                    }

                    Iterator& operator++() {
                        this->increment_iterators();
                        this->skip_failures();
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter
                            && this->selector_iter != other.selector_iter;
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }
            };

            Iterator begin() {
                return {std::begin(this->container), std::end(this->container),
                    std::begin(this->selectors), std::end(this->selectors)};
            }

            Iterator end() {
                return {std::end(this->container), std::end(this->container),
                        std::end(this->selectors), std::end(this->selectors)};
            }

    };

    // Helper function to instantiate an Compressed
    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(
            Container&& container, Selector&& selectors) {
        return {std::forward<Container>(container),
                std::forward<Selector>(selectors)};
    }

    template <typename T, typename Selector>
    Compressed<std::initializer_list<T>, Selector> compress(
            std::initializer_list<T> data, Selector&& selectors) {
        return {std::move(data),
                std::forward<Selector>(selectors)};
    }

    template <typename Container, typename T>
    Compressed<Container, std::initializer_list<T>> compress(
            Container&& container, std::initializer_list<T> selectors) {
        return {std::forward<Container>(container),
                std::move(selectors)};
    }

    template <typename T, typename U>
    Compressed<std::initializer_list<T>, std::initializer_list<U>> compress(
            std::initializer_list<T> data,
            std::initializer_list<U> selectors) {
        return {std::move(data),
                std::move(selectors)};
    }
}

#endif
<|endoftext|>