<commit_before>#include<iostream>
#include<sys/stat.h>
#include<fcntl.h>
#include<pwd.h>
#include<sstream>
#include<stdio.h>
#include<boost/tokenizer.hpp>
#include<errno.h>
#include<string>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/unistd.h>

using namespace std;
using namespace boost;

typedef tokenizer<char_separator<char> > Tok;

char directory[1024];
string cwd = "";

void readCommands(string str);
int conjunct(int n, stringstream& ss, const Tok::iterator &it, bool didExtra = false);
void skipCommand(Tok::iterator &it, Tok &tokens);
void splitString(char** args, stringstream& ss, int n);
bool ioRedir(const Tok::iterator &it, bool inRedir, bool append);
void resetIO(int in0, int out1);
void pipeRedir(int fd[], int fdLoop[], bool pipeOut, bool isFirst, bool isLast, int n, stringstream& ss, const Tok::iterator &it, bool didRedir);
string findPath(string file);

int main(){
    cout << endl;
    string str = "";
    struct passwd *pass;

    bool hasDirectory = true;

    if((getcwd(directory, 1024)) == NULL){
        perror("getcwd");
        hasDirectory = false;
    }

    pass = getpwuid(getuid());
    if(pass == NULL){
        perror("getpwuid()");
    }

    char* usrname = pass->pw_name;
    char hostname[128];

    int success = gethostname(hostname, sizeof hostname);
    if(success == -1){
        perror("gethostname()");
    }

    string userinfo = "";
    string username = "";

    if(usrname != NULL && success == 0){
        username = usrname;
        userinfo = username + "@" + hostname;
    }

    if(hasDirectory){
        cwd = directory;
        cwd = ":" + cwd;
    }

    bool notExited = true;

    while(notExited){
        cout << userinfo << cwd << "$ ";
        getline(cin, str);
        readCommands(str);
    }

    return 0;
}

void readCommands(string str){

    char_separator<char> sep("\" ", ";#|&<>");

    Tok tokens(str, sep);
    stringstream ss;
    int in0;
    int out1;
    int fd[2];
    int fdLoop[2];
    bool pipeOut = false; bool isFirst = true;
    bool didRedir = false;
    bool didPipe = false; bool didExtra = false;
    int n = 0;

    if((in0 = dup(0)) == -1){
        perror("input-0");
        return;
    }

    if((out1 = dup(1)) == -1){
        perror("output-1");
        return;
    }

    if((pipe(fd)) == -1){
        perror("pipe");
        exit(-1);
    }

    for(Tok::iterator it = tokens.begin(); it != tokens.end(); it++){

        begin:

        if(*it == ";"){
            conjunct(n, ss, it);
            n = 0;
            it++;
            if(it == tokens.end()) break;
        }
        else if(*it ==  "&"){
            if(conjunct(n, ss, it) == -1){
                skipCommand(it, tokens);
            }
            n = 0;
            if(it == tokens.end()) break;
            it++;
            if(it == tokens.end()) break;
        }
        else if(*it == "|"){
            Tok::iterator copy = it;
            copy++;

            if(copy == tokens.end() || *copy == ";" || *copy == "&"){
                conjunct(0, ss, it);
                skipCommand(it, tokens);
                return;
            }

            if(*copy == "|"){
                copy++;
                if(copy == tokens.end() || *copy == ";" || *copy == "&"){
                    conjunct(0, ss, it);
                    skipCommand(it, tokens);
                    return;
                }

                if(conjunct(n, ss, it) != -1){
                    skipCommand(it, tokens);
                }
            }
            else{
//TODO piping
                didPipe = true;

                (!pipeOut) ? pipeOut = true : pipeOut = false;

                pipeRedir(fd, fdLoop, pipeOut, isFirst, false, n, ss, it, didRedir);
                isFirst = false;

                n = 0;
                continue;
            }

            n = 0;
            if(it == tokens.end()) break;
            it++;
        }
        else if(*it == "<" || *it == ">"){
            bool append = false;

another:
            Tok::iterator check = it;
            check++;
            bool inRedir = false;
            bool stringRedir = false;

            if(check != tokens.end() && *check == ">"){
                append = true;
                it++;
                goto here;
            }

            if(*it == "<"){
                inRedir = true;
                Tok::iterator copy = it;
                int i;
                for(i = 0; i < 2; i++){
                    copy++;
                    if(copy == tokens.end() || *copy != "<") break;
                }

                if(i == 2 && copy != tokens.end() && *copy != ";" && *copy != "|" && *copy != "&"){
                    stringRedir = true;
                }
            }

            if(stringRedir){
                didExtra = true;
                it++; it++; it++;
                string redirString = "";

                while(it != tokens.end() && *it != ";" && *it != "|" && *it != "&"){
                    redirString += (*it + " ");
                    it++;
                }

                if(write(0, (char*) redirString.c_str(), redirString.size() + 1) == -1){
                    perror("write to extra");
                    return;
                }

                if(it == tokens.end()){
                    break;
                }
                else{
                    goto begin;
                }

            }
here:
            it++;

            if(it == tokens.end()){
                cerr << "Bash: syntax error near unexpected token \'newline\'" << endl;
                exit(-1);
            }

            if(!ioRedir(it, inRedir, append)) return;

            didRedir = true;

            Tok::iterator copy = it;
            copy++;

            if(copy == tokens.end()) break;

            if(*copy == ">" || *copy == "<"){
                it++;
                goto another;
            }

            continue;
        }

        if(*it == "#"){
            if(didPipe){
                (!pipeOut) ? pipeOut = true : pipeOut = false;
                pipeRedir(fd, fdLoop, pipeOut, isFirst, true, n, ss, it, didRedir);
                return;
            }

            conjunct(n, ss, it);

            if(didRedir){
                resetIO(in0, out1);
            }
            return;
        }

        if(*it != "&" && *it != "|"){
            ss << *it;
            ss << " ";
            n++;
        }
    }
    //TODO piping
    if(n > 0){
        Tok::iterator it = tokens.begin();
        if(didPipe){
            (!pipeOut) ? pipeOut = true : pipeOut = false;
            pipeRedir(fd, fdLoop,  pipeOut, isFirst, true, n, ss, it, didRedir);
        }
        else{
            conjunct(n, ss, it, didExtra);
        }
    }

    if(didRedir){
        resetIO(in0, out1);
    }
}

int conjunct(int n, stringstream& ss, const Tok::iterator &it, bool didExtra){

    int status;

    if(n == 0 && *it != "#"){
        cerr << "Bash: syntax error near unexpected token \'" << *it << "\'" << endl;
        return -1;
    }
    else if(n == 0 && *it == "#") return 0;
    char** args = new char*[n + 1];

    splitString(args, ss, n);

    if(strcmp(args[0], "cd") == 0){
        if(n <= 1){

            string home;

            if((home = getenv("HOME")) == ""){
                perror("getenv");
            }

            if(chdir((char*) home.c_str()) == -1){
                perror("chdir");
                return -1;
            }

            if((getcwd(directory, 1024)) == NULL){
                perror("getcwd");
            }
            else{
                cwd = directory;
                cwd = ":" + cwd;
            }
        }
        else{
            if(chdir(args[1]) == -1){
                perror("chdir");
                return -1;
            }

            if((getcwd(directory, 1024)) == NULL){
                perror("getcwd");
            }
            else{
                cwd = directory;
                cwd = ":" + cwd;
            }
        }
    }
    else{

        int pid = fork();

        if(pid == -1){
            perror("There was an error with the fork().");
            exit(1);
        }
        else if(pid == 0){
            if(-1 == execv((const char*) args[0], (char* const*) args)){
                perror(args[0]);
                exit(3);
            }
        }
        else if(pid > 0){

            if(-1 == wait(&status)){
                perror("There was an error with wait().");
                return -1;
            }

            if(WIFEXITED(status)){
                if(WEXITSTATUS(status) == 3){
                    delete[] args;
                    return -1;
                }
            }
        }
    }

    delete[] args;

    return 0;
}

bool ioRedir(const Tok::iterator &it, bool inRedir, bool append){

    if(*it == "&" || *it == "|" || *it == ";"){
        cerr << "Bash: syntax error near unexpected token \'" << *it << "\'" << endl;
        return false;
    }

    if(inRedir){
        string input = *it;

        int fdi;

        if((fdi = open((char*) input.c_str(), O_RDONLY)) == -1){
            perror("open input");
            return false;
        }

        if(close(0) == -1){
            perror("close input");
            exit(-1);
        }

        if(dup(fdi) == -1){
            perror("dup input");
            exit(-1);
        }
        return true;
    }
    else{
        string output = *it;

        int fdo;
        mode_t readWrite = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;

        if(append){
            if((fdo = open((char*) output.c_str(), O_RDWR | O_CREAT | O_APPEND,  readWrite)) == -1){
                perror("open output");
                exit(-1);
            }
        }
        else{
            if((fdo = open((char*) output.c_str(), O_RDWR | O_CREAT | O_TRUNC,  readWrite)) == -1){
                perror("open output append");
                exit(-1);
            }
        }

        if(close(1) == -1){
            perror("close output");
            exit(-1);
        }

        if(dup(fdo) == -1){
            perror("dup output");
            exit(-1);
        }
    }

    return true;
}

void resetIO(int in0, int out1){

    if(dup2(in0, 0) == -1){
        perror("dup input - 0");
        exit(-1);
    }

    if(dup2(out1, 1) == -1){
        perror("dup output - 1");
        exit(-1);
    }
}

//TODO piping
void pipeRedir(int fd[], int fdLoop[], bool pipeOut, bool isFirst, bool isLast, int n, stringstream& ss, const Tok::iterator& it, bool didRedir){

    int status;

    if(n == 0 && *it != "#"){
        cerr << "Bash: syntax error near unexpected token \'" << *it << "\'" << endl;
        return;
    }
    else if(n == 0 && *it == "#") return;
    char** args = new char*[n + 1];

    splitString(args, ss, n);

    if(pipeOut){
        int pid;

        if(!isFirst){
            if(pipe(fd) == -1){
                perror("repipe fd in input");
                exit(-1);
            }
        }

        if((pid = fork()) == -1){
            perror("fork in pipe");
            exit(-1);
        }

        if(pid == 0){
            if(isFirst){
                if(close(fd[0]) == -1){
                    perror("close in pipe");
                    exit(-1);
                }
            }

            if(!isFirst){
                if(dup2(fdLoop[0], 0) == -1){
                    perror("dup2 fdLoop in input");
                    exit(-1);
                }
            }

            if(!isLast){
                if(dup2(fd[1], 1) == -1){
                    perror("dup2 in pipe");
                    exit(-1);
                }
            }
            //TODO execute command here

            if(-1 == execv((const char*) args[0], (char* const*) args)){
                perror("execv in pipe");
                exit(-1);
            }
        }
        else{
            if(wait(&status) == -1){
                perror("wait in pipe");
                exit(-1);
            }

            if(close(fd[1]) == -1){
                perror("close in pipe parent");
                exit(-1);
            }

            if(!isFirst){
                if(close(fdLoop[0]) == -1){
                    perror("close fdLoop in input");
                    exit(-1);
                }
            }

            if(WIFEXITED(status)){
                if(WEXITSTATUS(status) == 3){
                    exit(-1);
                }
            }

        }
    }
    else{
        int pid;
        if(!isLast){
            if(pipe(fdLoop) == -1){
                perror("fdLoop in output");
                exit(-1);
            }
        }

        if((pid = fork()) == -1){
            perror("fork#2 in pipe");
            exit(-1);
        }

        if(pid == 0){

            if(dup2(fd[0], 0) == -1){
                perror("dup2 #2 in pipe");
                exit(-1);
            }

            //TODO execute command here

            if(!isLast){
                if(dup2(fdLoop[1], 1) == -1){
                    perror("dup2 loop in output");
                    exit(-1);
                }
            }

            if(-1 == execv((const char*) args[0], (char* const*) args)){
                perror("execv in pipe");
                exit(-1);
            }

        }
        else{

            if(wait(&status) == -1){
                perror("wait #2 in pipe");
                exit(-1);
            }

            if(close(fd[0]) == -1){
                perror("close #2 in pipe parent");
                exit(-1);
            }

            if(!isLast){
                if(close(fdLoop[1]) == -1){
                    perror("close fdLoop in output");
                    exit(-1);
                }
            }
            if(WIFEXITED(status)){
                if(WEXITSTATUS(status) == 3){
                    exit(-1);
                }
            }
        }
    }
}

void skipCommand(Tok::iterator &it, Tok &tokens){
    while(it != tokens.end() && *it != ";"){
        it++;
    }
}

void splitString(char** args, stringstream& ss, int n){

    string *str = new string[n];

    for(int i = 0; i < n; i++){

        ss >> str[i];

        if(str[i] != "cd" && i == 0){
           str[i] = findPath(str[i]);
        }

        args[i] = (char*) str[i].c_str();
    }

    args[n] = NULL;

    char exitC[] = "exit";

    if(strcmp(args[0], exitC) == 0){
        cout << endl;
        exit(0);
    }

    delete[] str;
}

string findPath(string file){
    string env = "";

    if((env = getenv("PATH")) == ""){
        perror("getenv findPath");
        exit(-1);
    }

    string dir = "";
    string path = "";
    struct stat buf;

    int i;

    while((i = env.find(":")) != -1){
        dir = env.substr(0, i);

        env = env.substr(i + 1, env.size());

        if(stat((dir + "/" + file).c_str(), &buf) != -1){
            path = dir + "/" + file;
        }
    }

    return path;
}
<commit_msg>Finished requirements for assignment<commit_after>#include<iostream>
#include<sys/stat.h>
#include<fcntl.h>
#include<pwd.h>
#include<sstream>
#include<stdio.h>
#include<boost/tokenizer.hpp>
#include<errno.h>
#include<string>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/unistd.h>

using namespace std;
using namespace boost;

typedef tokenizer<char_separator<char> > Tok;

char directory[1024];
string cwd = "";
string userinfo = "";
bool mainPar = true;

void interrupt(int sig){

    if(mainPar){

        cout << endl;
        cout << userinfo << cwd << "$ " << flush;
    }
    else{
        cout << endl;
    }
}

void readCommands(string str);
int conjunct(int n, stringstream& ss, const Tok::iterator &it, bool didExtra = false);
void skipCommand(Tok::iterator &it, Tok &tokens);
void splitString(char** args, stringstream& ss, int n);
bool ioRedir(const Tok::iterator &it, bool inRedir, bool append);
void resetIO(int in0, int out1);
void pipeRedir(int fd[], int fdLoop[], bool pipeOut, bool isFirst, bool isLast, int n, stringstream& ss, const Tok::iterator &it, bool didRedir);
string findPath(string file);

int main(){
    cout << endl;
    string str = "";
    struct passwd *pass;

    if(signal(SIGINT, interrupt) == SIG_ERR){
        perror("signal");
        exit(-1);
    }

    bool hasDirectory = true;

    if((getcwd(directory, 1024)) == NULL){
        perror("getcwd");
        hasDirectory = false;
    }

    pass = getpwuid(getuid());
    if(pass == NULL){
        perror("getpwuid()");
    }

    char* usrname = pass->pw_name;
    char hostname[128];

    int success = gethostname(hostname, sizeof hostname);
    if(success == -1){
        perror("gethostname()");
    }

    string username = "";

    if(usrname != NULL && success == 0){
        username = usrname;
        userinfo = username + "@" + hostname;
    }

    if(hasDirectory){
        string home = "";
        cwd = directory;
        cwd = ":" + cwd;
        if((home = getenv("HOME")) != ""){
            cwd.replace(0, home.size() + 1, ":~");
        }
        else{
            perror("getenv");
        }
    }

    bool notExited = true;

    while(notExited){
        cout << userinfo << cwd << "$ ";
        getline(cin, str);
        readCommands(str);
        mainPar = true;
    }

    return 0;
}

void readCommands(string str){

    char_separator<char> sep("\" ", ";#|&<>");

    Tok tokens(str, sep);
    stringstream ss;
    int in0;
    int out1;
    int fd[2];
    int fdLoop[2];
    bool pipeOut = false; bool isFirst = true;
    bool didRedir = false;
    bool didPipe = false; bool didExtra = false;
    int n = 0;

    if((in0 = dup(0)) == -1){
        perror("input-0");
        return;
    }

    if((out1 = dup(1)) == -1){
        perror("output-1");
        return;
    }

    if((pipe(fd)) == -1){
        perror("pipe");
        exit(-1);
    }

    for(Tok::iterator it = tokens.begin(); it != tokens.end(); it++){
        mainPar = false;

begin:

        if(*it == ";"){
            conjunct(n, ss, it);
            n = 0;
            it++;
            if(it == tokens.end()) break;
        }
        else if(*it ==  "&"){
            if(conjunct(n, ss, it) == -1){
                skipCommand(it, tokens);
            }
            n = 0;
            if(it == tokens.end()) break;
            it++;
            if(it == tokens.end()) break;
        }
        else if(*it == "|"){
            Tok::iterator copy = it;
            copy++;

            if(copy == tokens.end() || *copy == ";" || *copy == "&"){
                conjunct(0, ss, it);
                skipCommand(it, tokens);
                return;
            }

            if(*copy == "|"){
                copy++;
                if(copy == tokens.end() || *copy == ";" || *copy == "&"){
                    conjunct(0, ss, it);
                    skipCommand(it, tokens);
                    return;
                }

                if(conjunct(n, ss, it) != -1){
                    skipCommand(it, tokens);
                }
            }
            else{
                //TODO piping
                didPipe = true;

                (!pipeOut) ? pipeOut = true : pipeOut = false;

                pipeRedir(fd, fdLoop, pipeOut, isFirst, false, n, ss, it, didRedir);
                isFirst = false;

                n = 0;
                continue;
            }

            n = 0;
            if(it == tokens.end()) break;
            it++;
        }
        else if(*it == "<" || *it == ">"){
            bool append = false;

another:
            Tok::iterator check = it;
            check++;
            bool inRedir = false;
            bool stringRedir = false;

            if(check != tokens.end() && *check == ">"){
                append = true;
                it++;
                goto here;
            }

            if(*it == "<"){
                inRedir = true;
                Tok::iterator copy = it;
                int i;
                for(i = 0; i < 2; i++){
                    copy++;
                    if(copy == tokens.end() || *copy != "<") break;
                }

                if(i == 2 && copy != tokens.end() && *copy != ";" && *copy != "|" && *copy != "&"){
                    stringRedir = true;
                }
            }

            if(stringRedir){
                didExtra = true;
                it++; it++; it++;
                string redirString = "";

                while(it != tokens.end() && *it != ";" && *it != "|" && *it != "&"){
                    redirString += (*it + " ");
                    it++;
                }

                if(write(0, (char*) redirString.c_str(), redirString.size() + 1) == -1){
                    perror("write to extra");
                    return;
                }

                if(it == tokens.end()){
                    break;
                }
                else{
                    goto begin;
                }

            }
here:
            it++;

            if(it == tokens.end()){
                cerr << "Bash: syntax error near unexpected token \'newline\'" << endl;
                exit(-1);
            }

            if(!ioRedir(it, inRedir, append)) return;

            didRedir = true;

            Tok::iterator copy = it;
            copy++;

            if(copy == tokens.end()) break;

            if(*copy == ">" || *copy == "<"){
                it++;
                goto another;
            }

            continue;
        }

        if(*it == "#"){
            if(didPipe){
                (!pipeOut) ? pipeOut = true : pipeOut = false;
                pipeRedir(fd, fdLoop, pipeOut, isFirst, true, n, ss, it, didRedir);
                return;
            }

            conjunct(n, ss, it);

            if(didRedir){
                resetIO(in0, out1);
            }
            return;
        }

        if(*it != "&" && *it != "|"){
            ss << *it;
            ss << " ";
            n++;
        }
    }
    //TODO piping
    if(n > 0){
        Tok::iterator it = tokens.begin();
        if(didPipe){
            (!pipeOut) ? pipeOut = true : pipeOut = false;
            pipeRedir(fd, fdLoop,  pipeOut, isFirst, true, n, ss, it, didRedir);
        }
        else{
            conjunct(n, ss, it, didExtra);
        }
    }

    if(didRedir){
        resetIO(in0, out1);
    }
}

int conjunct(int n, stringstream& ss, const Tok::iterator &it, bool didExtra){

    int status;

    if(n == 0 && *it != "#"){
        cerr << "Bash: syntax error near unexpected token \'" << *it << "\'" << endl;
        return -1;
    }
    else if(n == 0 && *it == "#") return 0;
    char** args = new char*[n + 1];

    splitString(args, ss, n);

    if(strcmp(args[0], "cd") == 0){
        if(n <= 1){

            string home;

            if((home = getenv("HOME")) == ""){
                perror("getenv");
            }

            if(chdir((char*) home.c_str()) == -1){
                perror("chdir");
                return -1;
            }

            if((getcwd(directory, 1024)) == NULL){
                perror("getcwd");
            }
            else{
                cwd = directory;
                cwd = ":" + cwd;
                cwd.replace(0, home.size() + 1, ":~");
            }
        }
        else{
            if(chdir(args[1]) == -1){
                perror("chdir");
                return -1;
            }

            if((getcwd(directory, 1024)) == NULL){
                perror("getcwd");
            }
            else{
                string home = "";
                cwd = directory;
                cwd = ":" + cwd;
                if((home = getenv("HOME")) != ""){
                    cwd.replace(0, home.size() + 1, ":~");
                }
                else{
                    perror("getenv conjunct");
                }

            }
        }
    }
    else{

        int pid = fork();

        if(pid == -1){
            perror("There was an error with the fork().");
            exit(1);
        }
        else if(pid == 0){
            if(-1 == execv((const char*) args[0], (char* const*) args)){
                perror(args[0]);
                exit(3);
            }
        }
        else if(pid > 0){

            if(-1 == wait(&status)){
                perror("There was an error with wait().");
                return -1;
            }

            if(WIFEXITED(status)){
                if(WEXITSTATUS(status) == 3){
                    delete[] args;
                    return -1;
                }
            }
        }
    }

    delete[] args;

    return 0;
}

bool ioRedir(const Tok::iterator &it, bool inRedir, bool append){

    if(*it == "&" || *it == "|" || *it == ";"){
        cerr << "Bash: syntax error near unexpected token \'" << *it << "\'" << endl;
        return false;
    }

    if(inRedir){
        string input = *it;

        int fdi;

        if((fdi = open((char*) input.c_str(), O_RDONLY)) == -1){
            perror("open input");
            return false;
        }

        if(close(0) == -1){
            perror("close input");
            exit(-1);
        }

        if(dup(fdi) == -1){
            perror("dup input");
            exit(-1);
        }
        return true;
    }
    else{
        string output = *it;

        int fdo;
        mode_t readWrite = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;

        if(append){
            if((fdo = open((char*) output.c_str(), O_RDWR | O_CREAT | O_APPEND,  readWrite)) == -1){
                perror("open output");
                exit(-1);
            }
        }
        else{
            if((fdo = open((char*) output.c_str(), O_RDWR | O_CREAT | O_TRUNC,  readWrite)) == -1){
                perror("open output append");
                exit(-1);
            }
        }

        if(close(1) == -1){
            perror("close output");
            exit(-1);
        }

        if(dup(fdo) == -1){
            perror("dup output");
            exit(-1);
        }
    }

    return true;
}

void resetIO(int in0, int out1){

    if(dup2(in0, 0) == -1){
        perror("dup input - 0");
        exit(-1);
    }

    if(dup2(out1, 1) == -1){
        perror("dup output - 1");
        exit(-1);
    }
}

//TODO piping
void pipeRedir(int fd[], int fdLoop[], bool pipeOut, bool isFirst, bool isLast, int n, stringstream& ss, const Tok::iterator& it, bool didRedir){

    int status;

    if(n == 0 && *it != "#"){
        cerr << "Bash: syntax error near unexpected token \'" << *it << "\'" << endl;
        return;
    }
    else if(n == 0 && *it == "#") return;
    char** args = new char*[n + 1];

    splitString(args, ss, n);

    if(pipeOut){
        int pid;

        if(!isFirst){
            if(pipe(fd) == -1){
                perror("repipe fd in input");
                exit(-1);
            }
        }

        if((pid = fork()) == -1){
            perror("fork in pipe");
            exit(-1);
        }

        if(pid == 0){
            if(isFirst){
                if(close(fd[0]) == -1){
                    perror("close in pipe");
                    exit(-1);
                }
            }

            if(!isFirst){
                if(dup2(fdLoop[0], 0) == -1){
                    perror("dup2 fdLoop in input");
                    exit(-1);
                }
            }

            if(!isLast){
                if(dup2(fd[1], 1) == -1){
                    perror("dup2 in pipe");
                    exit(-1);
                }
            }
            //TODO execute command here

            if(-1 == execv((const char*) args[0], (char* const*) args)){
                perror("execv in pipe");
                exit(-1);
            }
        }
        else{
            if(wait(&status) == -1){
                perror("wait in pipe");
                exit(-1);
            }

            if(close(fd[1]) == -1){
                perror("close in pipe parent");
                exit(-1);
            }

            if(!isFirst){
                if(close(fdLoop[0]) == -1){
                    perror("close fdLoop in input");
                    exit(-1);
                }
            }

            if(WIFEXITED(status)){
                if(WEXITSTATUS(status) == 3){
                    exit(-1);
                }
            }

        }
    }
    else{
        int pid;
        if(!isLast){
            if(pipe(fdLoop) == -1){
                perror("fdLoop in output");
                exit(-1);
            }
        }

        if((pid = fork()) == -1){
            perror("fork#2 in pipe");
            exit(-1);
        }

        if(pid == 0){

            if(dup2(fd[0], 0) == -1){
                perror("dup2 #2 in pipe");
                exit(-1);
            }

            //TODO execute command here

            if(!isLast){
                if(dup2(fdLoop[1], 1) == -1){
                    perror("dup2 loop in output");
                    exit(-1);
                }
            }

            if(-1 == execv((const char*) args[0], (char* const*) args)){
                perror("execv in pipe");
                exit(-1);
            }

        }
        else{

            if(wait(&status) == -1){
                perror("wait #2 in pipe");
                exit(-1);
            }

            if(close(fd[0]) == -1){
                perror("close #2 in pipe parent");
                exit(-1);
            }

            if(!isLast){
                if(close(fdLoop[1]) == -1){
                    perror("close fdLoop in output");
                    exit(-1);
                }
            }
            if(WIFEXITED(status)){
                if(WEXITSTATUS(status) == 3){
                    exit(-1);
                }
            }
        }
    }
}

void skipCommand(Tok::iterator &it, Tok &tokens){
    while(it != tokens.end() && *it != ";"){
        it++;
    }
}

void splitString(char** args, stringstream& ss, int n){

    string *str = new string[n];

    for(int i = 0; i < n; i++){

        ss >> str[i];

        if(str[i] != "cd" && i == 0 && str[i] != "exit"){
            str[i] = findPath(str[i]);
        }

        args[i] = (char*) str[i].c_str();
    }

    args[n] = NULL;

    char exitC[] = "exit";

    if(strcmp(args[0], exitC) == 0){
        cout << endl;
        exit(0);
    }

    delete[] str;
}

string findPath(string file){
    string env = "";

    if((env = getenv("PATH")) == ""){
        perror("getenv findPath");
        exit(-1);
    }

    string dir = "";
    string path = "";
    struct stat buf;

    int i;

    while((i = env.find(":")) != -1){
        dir = env.substr(0, i);

        env = env.substr(i + 1, env.size());

        if(stat((dir + "/" + file).c_str(), &buf) != -1){
            path = dir + "/" + file;
        }
        else{
            continue;
            perror("stat, this shouldn't show");
        }
    }

    return path;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <vector>
#include <stdlib.h>
#include <fcntl.h>

using namespace std;

void parse(char * line, vector<string> & input) {

    char * pch;
	pch = strtok (line, " \n");
	while (pch!= NULL) {

	    // Ignore after comments
	    if (*pch == '#')
		break;

	    // Check for && and ||
	    // Break input up
	    char * a = strstr(pch, "&&");
	    char * b = strstr(pch, "||");
	    char * c = strstr(pch, ";");
        char * d = strstr(pch, "<");
        char * e = strstr(pch, ">");
        char * f = strstr(pch, "|");

	    // If there are connectors, break up the string
	    // into parts and add them individually to the vector
	    if (a!=NULL || b!=NULL || c!=NULL || d!=NULL || e!=NULL || f!=NULL) {
		while (strlen(pch) != 0 ) {

		    // Checks for && and ||
		    if ((pch[0] == '&' && pch[1] == '&') ||
			(pch[0] == '|' && pch[1] == '|')) {

			    string tmp;
			    tmp += *pch;
			    tmp += *(pch+1);
			    tmp[2] = '\0';

			    input.push_back(tmp);
			    memmove(pch, pch+2, strlen(pch) - 2);
			    pch[strlen(pch)-2] = '\0';
		    }
		    // Check for semicolons
		    else if (*pch == ';') {
			    input.push_back(";");
			    memmove(pch, pch+1, strlen(pch) -1);
			    pch[strlen(pch)-1] = '\0';
		    }
            // Check for input/output redirectors
            else if (*pch == '<') {
                input.push_back("<");
                memmove(pch, pch+1, strlen(pch) -1);
                pch[strlen(pch)-1] = '\0';
            }
            else if (*pch == '>') {
                if (*(pch+1) == '>') {
                    input.push_back(">>");
                    memmove(pch, pch+2, strlen(pch) -2);
                    pch[strlen(pch)-2] = '\0';
                }
                else {
                    input.push_back(">");
                    memmove(pch, pch+1, strlen(pch) -1);
                    pch[strlen(pch)-1] = '\0';
                }
            }
            else if (*pch == '|') {
                input.push_back("|");
                memmove(pch, pch+1, strlen(pch) -1);
                pch[strlen(pch) -1] = '\0';
            }
		    else {
			string word;
			int numletters = 0;

			char *z = pch;
			while (z!=a && z!=b && z!=c && z!=d && z!=e && z!=f) {
			    if (*z == '\0')
				break;
			    word += *z;
			    numletters++;
			    z++;
			}
			input.push_back(word);
			memmove(pch, pch+numletters, strlen(pch) -numletters);
			pch[strlen(pch)-numletters] = '\0';
		    }

		    a = strstr(pch, "&&");
		    b = strstr(pch, "||");
		    c = strstr(pch, ";");
            d = strstr(pch, "<");
            e = strstr(pch, ">");
            f = strstr(pch, "|");
		}
	    }

	    // If no connectors, just add to vector
	    if (*pch != '\0' && *pch != '\n' && *pch != '#')
		input.push_back(pch);
	    pch = strtok (NULL, " \n");
	}
}

void execute(vector<string> & input, int start, int end) {

    //Call execvp, based on which elements in the string vector to use
    char * argv[5];

	    int i = 0;

	    for (i = 0; i <= (end - start); i++) {
		argv[i] = new char[5];
	    }

        cerr << "execvp sent:\n";

	    for (i = 0; i < (end-start); i++) {
        cerr << input[i+start] << endl;
		strcpy(argv[i], input[i+start].c_str());
	    }

	    argv[i] = NULL;

	    int status = execvp(argv[0], argv);
	    if (status == -1)
		perror("execvp");
		exit(1);
}

int main() {

    vector<string> input;
    int status=0;

    int savestdin;
    if ((savestdin = dup(0)) == -1)
        perror("dup");

    int savestdout;
    if ((savestdout = dup(1)) == -1)
        perror("dup");

    // Get username
    char * usrname = getlogin();
    if (usrname == NULL){
	perror ("getlogin");
	exit(1);
    }

    // Get hostname
    char hostname[20];

    if (gethostname(hostname, sizeof hostname) ==-1) {
	perror("gethostname");
	exit(1);
    }

    // Main loop
    while (1) {

   	 //Restore stdin and stdout
        if ((dup2(savestdin,0)) == -1)
            perror("dup2");

        if ((dup2(savestdout,0)) == -1)
            perror("dup2");

	status = 0;

	if (input.size() != 0)
	    input.clear();

	cout << usrname << "@" << hostname <<"$ ";

	string string1;
	getline(cin, string1);
	char * line = new char [string1.length() + 1];
	strcpy(line, string1.c_str());

	parse(line, input);

	delete line;

	if (input.size() == 0)
	    continue;

    for (int i = 0; i < input.size(); i++) {
	    if (strcmp(input[i].c_str(), "exit") == 0) exit(0);

        //cout << input[i] << endl;
    }

	int pid=fork();
    if (pid == -1)
        perror ("fork");
	int pid2;
	if (pid == 0) {

	    int start = 0;
	    int end = input.size();
	    unsigned i;

loop:

	    end = input.size();

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

            //input output redirection
            if (input[i] == ">" || input[i] == ">>" || input[i]=="<" || input[i] == "|") {

                if (input[i] == ">") {

                        int fdo = open(input[i+1].c_str(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
                        if (fdo==-1)
                            perror("open");

                        status = close(STDOUT_FILENO);
                        if (status == -1)
                            perror("close");

                        if ((dup(fdo)) == -1)
                            perror("dup");

                        if ((close(fdo)) == -1)
                            perror("close");

                        end = i;
                        break;
                    }

                else if (input[i] == ">>") {

                        int fdo = open(input[i+1].c_str(), O_CREAT | O_WRONLY | O_APPEND,
                                     S_IRUSR | S_IWUSR);
                        if (fdo==-1)
                            perror("open");

                        status = close(STDOUT_FILENO);
                        if (status == -1)
                            perror("close");

                        if ((dup(fdo)) == -1)
                            perror("dup");

                        if ((close(fdo)) == -1)
                            perror("close");

                        end = i;
                        break;
                }

                else if (input[i] == "<") {

                        int fdi = open(input[i+1].c_str(), O_RDONLY, 0);
                        if (fdi==-1)
                            perror("open");

                        status = close(STDIN_FILENO);
                        if (status == -1)
                            perror("close");

                        if ((dup(fdi)) == -1)
                            perror("dup");

                        if ((close(fdi)) == -1)
                            perror("close");

                        end = i;
                        break;
                }

                else if (input[i] == "|") {
                    int pfd[2];

                    if ((pipe(pfd)) == -1)
                        perror("pipe");

                    int pid3 = fork();
                    if (pid3 == -1) {
                        perror("fork");
                        exit(1);
                    }
                    if (pid3==0) {
                        cout << "This is the child process";

                        if ((dup2(pfd[1], 1)) == -1)
                            perror("dup2");

                        if ((close(pfd[0])) == -1)
                            perror("close");

                        end = i;
                        break;

                    }
                    else {
                        close(STDIN_FILENO);
                        dup2(pfd[0], 0);
                        close(pfd[1]);

                        if (-1 == wait(0))
                            perror("wait");

                        start = i+1;
                        goto loop;

                    }

                }
            }

            else if (input[i] == ";" || input[i] == "&&" || input[i] == "||") {
		        string connector = input[i];

		        pid2 = fork();
		        if (pid2 == -1) {
			        perror("fork");
			        exit(1);
		        }
		        if (pid2!=0) {
			        if (-1 == wait(&status))
			            perror("wait");

			        if (connector == "&&" && status != 0)
			            exit(1);

			        if (connector == "||" && status == 0)
			            exit(0);

			        start = i + 1;
			        goto loop;

		        }
		        else {
			        end = i;
			        break;
		        }
		    }
	    }

	    execute(input, start, end);

	}
	else {
	    status = wait(NULL);
	    if (status == -1)
		perror("wait");
	}
    }

    return 0;
}
<commit_msg>enabled linking pipes together<commit_after>#include <iostream>
#include <unistd.h>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <vector>
#include <stdlib.h>
#include <fcntl.h>

using namespace std;

void parse(char * line, vector<string> & input) {

    char * pch;
	pch = strtok (line, " \n");
	while (pch!= NULL) {

	    // Ignore after comments
	    if (*pch == '#')
		break;

	    // Check for && and ||
	    // Break input up
	    char * a = strstr(pch, "&&");
	    char * b = strstr(pch, "||");
	    char * c = strstr(pch, ";");
        char * d = strstr(pch, "<");
        char * e = strstr(pch, ">");
        char * f = strstr(pch, "|");

	    // If there are connectors, break up the string
	    // into parts and add them individually to the vector
	    if (a!=NULL || b!=NULL || c!=NULL || d!=NULL || e!=NULL || f!=NULL) {
		while (strlen(pch) != 0 ) {

		    // Checks for && and ||
		    if ((pch[0] == '&' && pch[1] == '&') ||
			(pch[0] == '|' && pch[1] == '|')) {

			    string tmp;
			    tmp += *pch;
			    tmp += *(pch+1);
			    tmp[2] = '\0';

			    input.push_back(tmp);
			    memmove(pch, pch+2, strlen(pch) - 2);
			    pch[strlen(pch)-2] = '\0';
		    }
		    // Check for semicolons
		    else if (*pch == ';') {
			    input.push_back(";");
			    memmove(pch, pch+1, strlen(pch) -1);
			    pch[strlen(pch)-1] = '\0';
		    }
            // Check for input/output redirectors
            else if (*pch == '<') {
                input.push_back("<");
                memmove(pch, pch+1, strlen(pch) -1);
                pch[strlen(pch)-1] = '\0';
            }
            else if (*pch == '>') {
                if (*(pch+1) == '>') {
                    input.push_back(">>");
                    memmove(pch, pch+2, strlen(pch) -2);
                    pch[strlen(pch)-2] = '\0';
                }
                else {
                    input.push_back(">");
                    memmove(pch, pch+1, strlen(pch) -1);
                    pch[strlen(pch)-1] = '\0';
                }
            }
            else if (*pch == '|') {
                input.push_back("|");
                memmove(pch, pch+1, strlen(pch) -1);
                pch[strlen(pch) -1] = '\0';
            }
		    else {
			string word;
			int numletters = 0;

			char *z = pch;
			while (z!=a && z!=b && z!=c && z!=d && z!=e && z!=f) {
			    if (*z == '\0')
				break;
			    word += *z;
			    numletters++;
			    z++;
			}
			input.push_back(word);
			memmove(pch, pch+numletters, strlen(pch) -numletters);
			pch[strlen(pch)-numletters] = '\0';
		    }

		    a = strstr(pch, "&&");
		    b = strstr(pch, "||");
		    c = strstr(pch, ";");
            d = strstr(pch, "<");
            e = strstr(pch, ">");
            f = strstr(pch, "|");
		}
	    }

	    // If no connectors, just add to vector
	    if (*pch != '\0' && *pch != '\n' && *pch != '#')
		input.push_back(pch);
	    pch = strtok (NULL, " \n");
	}
}

void execute(const vector<string> & input, int start, int end) {

    //Call execvp, based on which elements in the string vector to use
    char * argv[5];

	    int i = 0;

	    for (i = 0; i <= (end - start); i++) {
		argv[i] = new char[5];
	    }

        //debug
        //cerr << "sent to execvp:\n";

	    for (i = 0; i < (end-start); i++) {
		strcpy(argv[i], input[i+start].c_str());
	    //cerr << input[i+start] << endl;
        }

        //debug
        //cerr << endl;

	    argv[i] = NULL;

	    int status = execvp(argv[0], argv);
	    if (status == -1)
		perror("execvp");
		exit(1);
}

int main() {

    vector<string> input;
    int status=0;

    int savestdin;
    if ((savestdin = dup(0)) == -1)
        perror("dup");

    int savestdout;
    if ((savestdout = dup(1)) == -1)
        perror("dup");

    // Get username
    char * usrname = getlogin();
    if (usrname == NULL){
	perror ("getlogin");
	exit(1);
    }

    // Get hostname
    char hostname[20];

    if (gethostname(hostname, sizeof hostname) ==-1) {
	perror("gethostname");
	exit(1);
    }

    // Main loop
    while (1) {

   	 //Restore stdin and stdout
        if ((dup2(savestdin,0)) == -1)
            perror("dup2");

        if ((dup2(savestdout,0)) == -1)
            perror("dup2");

	status = 0;

	if (input.size() != 0)
	    input.clear();

	cout << usrname << "@" << hostname <<"$ ";

	string string1;
	getline(cin, string1);
	char * line = new char [string1.length() + 1];
	strcpy(line, string1.c_str());

	parse(line, input);

	delete line;

	if (input.size() == 0)
	    continue;

    for (int i = 0; i < input.size(); i++) {
	    if (strcmp(input[i].c_str(), "exit") == 0) exit(0);
    }

	int pid=fork();
    if (pid == -1)
        perror ("fork");
	int pid2;
	if (pid == 0) {

	    int start = 0;
	    int end = input.size();
	    unsigned i;

loop:
	    end = input.size();

        for (i = start; i < input.size(); ) {
            //input output redirection
            if (input[i] == ">" || input[i] == ">>" || input[i]=="<" || input[i] == "|") {

                if (input[i] == ">") {

                        int fdo = open(input[i+1].c_str(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
                        if (fdo==-1)
                            perror("open");

                        status = close(STDOUT_FILENO);
                        if (status == -1)
                            perror("close");

                        if ((dup(fdo)) == -1)
                            perror("dup");

                        if ((close(fdo)) == -1)
                            perror("close");

                        input.erase(input.begin() + i);

                        input.erase(input.begin() + i);

                        if (input[i] == ">" || input[i] == ">>" ||
                                        input[i+2]=="<" || input[i+2] == "|")
                            continue;

                        end = i;
                        break;
                    }

                else if (input[i] == ">>") {

                        int fdo = open(input[i+1].c_str(), O_CREAT | O_WRONLY | O_APPEND,
                                     S_IRUSR | S_IWUSR);
                        if (fdo==-1)
                            perror("open");

                        status = close(STDOUT_FILENO);
                        if (status == -1)
                            perror("close");

                        if ((dup(fdo)) == -1)
                            perror("dup");

                        if ((close(fdo)) == -1)
                            perror("close");

                        input.erase(input.begin() + i);

                        input.erase(input.begin() + i);

                        if (input[i] == ">" || input[i] == ">>" ||
                                        input[i+2]=="<" || input[i+2] == "|")
                            continue;

                        end = i;
                        break;
                }

                else if (input[i] == "<") {

                        int fdi = open(input[i+1].c_str(), O_RDONLY, 0);
                        if (fdi==-1)
                            perror("open");

                        status = close(STDIN_FILENO);
                        if (status == -1)
                            perror("close");

                        if ((dup(fdi)) == -1)
                            perror("dup");

                        if ((close(fdi)) == -1)
                            perror("close");

                        input.erase(input.begin() + i);

                        input.erase(input.begin() + i);

                        if (input[i] == ">" || input[i] == ">>" ||
                                        input[i+2]=="<" || input[i+2] == "|")
                            continue;

                        end = i;
                        break;
                }

                else if (input[i] == "|") {
                    int pfd[2];

                    if ((pipe(pfd)) == -1)
                        perror("pipe");

                    int pid3 = fork();
                    if (pid3 == -1) {
                        perror("fork");
                        exit(1);
                    }
                    if (pid3==0) {
                        cout << "This is the child process";

                        if ((dup2(pfd[1], 1)) == -1)
                            perror("dup2");

                        if ((close(pfd[0])) == -1)
                            perror("close");

                        end = i;
                        break;

                    }
                    else {
                        close(STDIN_FILENO);
                        dup2(pfd[0], 0);
                        close(pfd[1]);

                        if (-1 == wait(0))
                            perror("wait");

                        start = i+1;
                        goto loop;

                    }

                }
            }

            else if (input[i] == ";" || input[i] == "&&" || input[i] == "||") {
		        string connector = input[i];

		        pid2 = fork();
		        if (pid2 == -1) {
			        perror("fork");
			        exit(1);
		        }
		        if (pid2!=0) {
			        if (-1 == wait(&status))
			            perror("wait");

			        if (connector == "&&" && status != 0)
			            exit(1);

			        if (connector == "||" && status == 0)
			            exit(0);

			        start = i + 1;
			        goto loop;

		        }
		        else {
			        end = i;
			        break;
		        }
		    }
	    i++;
        }

	    execute(input, start, end);

	}
	else {
	    status = wait(NULL);
	    if (status == -1)
		perror("wait");
	}
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <stdlib.h>
#include <string>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
#include <vector>

using namespace std;

int main()
{
	while(true)
	{
		string commands;//Receive command line
		cout << "$";
		getline(cin,commands);
		const int y = commands.size() + 1;
		char* stuff = new char[y];//Stores command line as c strings
		strcpy(stuff,commands.c_str());
		char** cmd= new char*[y];//Stores the parsed command line
		int x = 0;
		char* tok = strtok(stuff, " ;\n\t\r");//Parses the c_strings
		while(tok != NULL)//Adding tokens into storage
		{
			if(strcmp(tok, "exit") == 0)//if an argument is exit
						    //it will exit
			{
				exit(0);
			}
			cmd[x] = tok;
			tok = strtok(NULL," ;\n\t\r");
			//cout << cmd[x] << " ";
			++x;
		}
		//cout << x << " " << x+1 << endl;
		cmd[x+1] = NULL;//Makes last argument the null character
		int pid = fork();
		if(pid == 0)
		{
			//cout << "This is the child" << endl;
			if(-1 == execvp(cmd[0], cmd))
			perror("execvp");
			exit(1);
		}
		else if (pid == -1)//If fork fails
		{
			perror("fork");
		}
		else
		{
			if(-1 == wait(0))
			{
				perror("wait");
			}
			//cout << "This is the parent" << endl;
		}

	}

	return 0;
}
<commit_msg>fixed seg faults/badd address<commit_after>#include <iostream>
#include <stdlib.h>
#include <string>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
#include <vector>

using namespace std;

int main()
{
	while(true)
	{
		string commands;//Receive command line
		cout << "$";
		getline(cin,commands);
		const int y = commands.size() + 1;
		char* stuff = new char[y];//Stores command line as c strings
		strcpy(stuff,commands.c_str());
		char** cmd= new char*[y];//Stores the parsed command line
		int x = 0;
		char* tok = strtok(stuff, " ;\n\t\r");//Parses the c_strings
		while(tok != NULL)//Adding tokens into storage
		{
			if(strcmp(tok, "exit") == 0)//if an argument is exit
						    //it will exit
			{
				exit(0);
			}
			cmd[x] = tok;
			tok = strtok(NULL," ;\n\t\r");
			//cout << cmd[x] << " ";
			++x;
		}

		cout << x << " " << x+1 << endl;
		cmd[x] = NULL;//Makes last argument the null character
		int pid = fork();
		if(pid == 0)
		{
			//cout << "This is the child" << endl;
			if(-1 == execvp(cmd[0], cmd))
			perror("execvp");
			exit(1);
		}
		else if (pid == -1)//If fork fails
		{
			perror("fork");
		}
		else
		{
			if(-1 == wait(0))
			{
				perror("wait");
			}
			//cout << "This is the parent" << endl;
		}

	}

	return 0;
}
<|endoftext|>


<commit_before>/************************************
 * file enc : ASCII
 * author   : wuyanyi09@gmail.com
 ************************************/
#ifndef CPPJIEBA_MPSEGMENT_H
#define CPPJIEBA_MPSEGMENT_H

#include <algorithm>
#include <set>
#include <cassert>
#include "Limonp/logger.hpp"
#include "Trie.hpp"
#include "Trie.hpp"
#include "ISegment.hpp"
#include "SegmentBase.hpp"

namespace CppJieba
{

    struct SegmentChar
    {
        uint16_t uniCh;
        DagType dag;
        const TrieNodeInfo * pInfo;
        double weight;

        SegmentChar(uint16_t uni):uniCh(uni), pInfo(NULL), weight(0.0)
        {}
    };
    typedef vector<SegmentChar> SegmentContext;

    class MPSegment: public SegmentBase
    {
        protected:
            Trie _trie;

        public:
            MPSegment(){_setInitFlag(false);};
            explicit MPSegment(const string& dictPath)
            {
                _setInitFlag(init(dictPath));
            };
            virtual ~MPSegment(){};
        public:
            bool init(const string& dictPath)
            {
                if(_getInitFlag())
                {
                    LogError("already inited before now.");
                    return false;
                }
                _trie.init(dictPath);
                assert(_trie);
                LogInfo("MPSegment init(%s) ok", dictPath.c_str());
                return _setInitFlag(true);
            }
        public:
            using SegmentBase::cut;
            virtual bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const
            {
                assert(_getInitFlag());
                if(begin == end)
                {
                    return false;
                }

                vector<Unicode> words;
                if(!cut(begin, end, words))
                {
                    return false;
                }
                string word;
                for(size_t i = 0; i < words.size(); i++)
                {
                    if(TransCode::encode(words[i], word))
                    {
                        res.push_back(word);
                    }
                    else
                    {
                        LogError("encode failed.");
                    }
                }
                return true;
            }

            bool cut(Unicode::const_iterator begin , Unicode::const_iterator end, vector<Unicode>& res) const
            {
                if(!_getInitFlag())
                {
                    LogError("not inited.");
                    return false;
                }
                SegmentContext segContext;
                //calc DAG
                if(!_calcDAG(begin, end, segContext))
                {
                    LogError("_calcDAG failed.");
                    return false;
                }

                if(!_calcDP(segContext))
                {
                    LogError("_calcDP failed.");
                    return false;
                }

                if(!_cut(segContext, res))
                {
                    LogError("_cut failed.");
                    return false;
                }

                return true;
            }

        private:
            bool _calcDAG(Unicode::const_iterator begin, Unicode::const_iterator end, SegmentContext& segContext) const
            {
                for(Unicode::const_iterator it = begin; it != end; it++)
                {
                    SegmentChar schar(*it);
                    size_t i = it - begin;
                    _trie.find(it, end, schar.dag, i);
                    //DagType::iterator dagIter;
                    if(schar.dag.end() ==  schar.dag.find(i))
                    {
                        schar.dag[i] = NULL;
                    }
                    segContext.push_back(schar);
                }
                return true;
            }
            bool _calcDP(SegmentContext& segContext)const
            {
                if(segContext.empty())
                {
                    LogError("segContext empty");
                    return false;
                }

                for(int i = segContext.size() - 1; i >= 0; i--)
                {
                    segContext[i].pInfo = NULL;
                    segContext[i].weight = MIN_DOUBLE;
                    for(DagType::const_iterator it = segContext[i].dag.begin(); it != segContext[i].dag.end(); it++)
                    {
                        size_t nextPos = it->first;
                        const TrieNodeInfo* p = it->second;
                        double val = 0.0;
                        if(nextPos + 1 < segContext.size())
                        {
                            val += segContext[nextPos + 1].weight;
                        }

                        if(p)
                        {
                            val += p->logFreq;
                        }
                        else
                        {
                            val += _trie.getMinLogFreq();
                        }
                        if(val > segContext[i].weight)
                        {
                            segContext[i].pInfo = p;
                            segContext[i].weight = val;
                        }
                    }
                }
                return true;

            }
            bool _cut(SegmentContext& segContext, vector<Unicode>& res)const
            {
                size_t i = 0;
                while(i < segContext.size())
                {
                    const TrieNodeInfo* p = segContext[i].pInfo;
                    if(p)
                    {
                        res.push_back(p->word);
                        i += p->word.size();
                    }
                    else//single chinese word
                    {
                        res.push_back(Unicode(1, segContext[i].uniCh));
                        i++;
                    }
                }
                return true;
            }

    };
}

#endif
<commit_msg>little modify MPSegment<commit_after>/************************************
 * file enc : ASCII
 * author   : wuyanyi09@gmail.com
 ************************************/
#ifndef CPPJIEBA_MPSEGMENT_H
#define CPPJIEBA_MPSEGMENT_H

#include <algorithm>
#include <set>
#include <cassert>
#include "Limonp/logger.hpp"
#include "Trie.hpp"
#include "Trie.hpp"
#include "ISegment.hpp"
#include "SegmentBase.hpp"

namespace CppJieba
{

    struct SegmentChar
    {
        uint16_t uniCh;
        DagType dag;
        const TrieNodeInfo * pInfo;
        double weight;

        SegmentChar():uniCh(0), pInfo(NULL), weight(0.0)
        {}
    };
    typedef vector<SegmentChar> SegmentContext;

    class MPSegment: public SegmentBase
    {
        protected:
            Trie _trie;

        public:
            MPSegment(){_setInitFlag(false);};
            explicit MPSegment(const string& dictPath)
            {
                _setInitFlag(init(dictPath));
            };
            virtual ~MPSegment(){};
        public:
            bool init(const string& dictPath)
            {
                if(_getInitFlag())
                {
                    LogError("already inited before now.");
                    return false;
                }
                _trie.init(dictPath);
                assert(_trie);
                LogInfo("MPSegment init(%s) ok", dictPath.c_str());
                return _setInitFlag(true);
            }
        public:
            using SegmentBase::cut;
            virtual bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const
            {
                assert(_getInitFlag());
                if(begin == end)
                {
                    return false;
                }

                vector<Unicode> words;
                if(!cut(begin, end, words))
                {
                    return false;
                }
                string word;
                for(size_t i = 0; i < words.size(); i++)
                {
                    if(TransCode::encode(words[i], word))
                    {
                        res.push_back(word);
                    }
                    else
                    {
                        LogError("encode failed.");
                    }
                }
                return true;
            }

            bool cut(Unicode::const_iterator begin , Unicode::const_iterator end, vector<Unicode>& res) const
            {
                if(!_getInitFlag())
                {
                    LogError("not inited.");
                    return false;
                }
                SegmentContext segContext;
                //calc DAG
                if(!_calcDAG(begin, end, segContext))
                {
                    LogError("_calcDAG failed.");
                    return false;
                }

                if(!_calcDP(segContext))
                {
                    LogError("_calcDP failed.");
                    return false;
                }

                if(!_cut(segContext, res))
                {
                    LogError("_cut failed.");
                    return false;
                }

                return true;
            }

        private:
            bool _calcDAG(Unicode::const_iterator begin, Unicode::const_iterator end, SegmentContext& segContext) const
            {
                SegmentChar schar;
                size_t offset;
                for(Unicode::const_iterator it = begin; it != end; it++)
                {
                    schar.uniCh = *it;
                    offset = it - begin;
                    schar.dag.clear();
                    _trie.find(it, end, schar.dag, offset);
                    if(!isIn(schar.dag, offset))
                    {
                        schar.dag[offset] = NULL;
                    }
                    segContext.push_back(schar);
                }
                return true;
            }
            bool _calcDP(SegmentContext& segContext)const
            {
                if(segContext.empty())
                {
                    LogError("segContext empty");
                    return false;
                }

                size_t nextPos;
                const TrieNodeInfo* p;
                double val;

                for(int i = segContext.size() - 1; i >= 0; i--)
                {
                    segContext[i].pInfo = NULL;
                    segContext[i].weight = MIN_DOUBLE;
                    for(DagType::const_iterator it = segContext[i].dag.begin(); it != segContext[i].dag.end(); it++)
                    {
                        nextPos = it->first;
                        p = it->second;
                        val = 0.0;
                        if(nextPos + 1 < segContext.size())
                        {
                            val += segContext[nextPos + 1].weight;
                        }

                        if(p)
                        {
                            val += p->logFreq;
                        }
                        else
                        {
                            val += _trie.getMinLogFreq();
                        }
                        if(val > segContext[i].weight)
                        {
                            segContext[i].pInfo = p;
                            segContext[i].weight = val;
                        }
                    }
                }
                return true;

            }
            bool _cut(SegmentContext& segContext, vector<Unicode>& res)const
            {
                size_t i = 0;
                while(i < segContext.size())
                {
                    const TrieNodeInfo* p = segContext[i].pInfo;
                    if(p)
                    {
                        res.push_back(p->word);
                        i += p->word.size();
                    }
                    else//single chinese word
                    {
                        res.push_back(Unicode(1, segContext[i].uniCh));
                        i++;
                    }
                }
                return true;
            }

    };
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <algorithm>

#include "skia/ext/convolver.h"

namespace skia {

namespace {

// Converts the argument to an 8-bit unsigned value by clamping to the range
// 0-255.
inline unsigned int ClampTo8(int a) {
  if (static_cast<int>(a) < 256)
    return a;  // Avoid the extra check in the common case.
  if (a < 0)
    return 0;
  return 255;
}

// Stores a list of rows in a circular buffer. The usage is you write into it
// by calling AdvanceRow. It will keep track of which row in the buffer it
// should use next, and the total number of rows added.
class CircularRowBuffer {
 public:
  // The number of pixels in each row is given in |source_row_pixel_width|.
  // The maximum number of rows needed in the buffer is |max_y_filter_size|
  // (we only need to store enough rows for the biggest filter).
  //
  // We use the |first_input_row| to compute the coordinates of all of the
  // following rows returned by Advance().
  CircularRowBuffer(int dest_row_pixel_width, int max_y_filter_size,
                    int first_input_row)
      : row_byte_width_(dest_row_pixel_width * 4),
        num_rows_(max_y_filter_size),
        next_row_(0),
        next_row_coordinate_(first_input_row) {
    buffer_.resize(row_byte_width_ * max_y_filter_size);
    row_addresses_.resize(num_rows_);
  }

  // Moves to the next row in the buffer, returning a pointer to the beginning
  // of it.
  unsigned char* AdvanceRow() {
    unsigned char* row = &buffer_[next_row_ * row_byte_width_];
    next_row_coordinate_++;

    // Set the pointer to the next row to use, wrapping around if necessary.
    next_row_++;
    if (next_row_ == num_rows_)
      next_row_ = 0;
    return row;
  }

  // Returns a pointer to an "unrolled" array of rows. These rows will start
  // at the y coordinate placed into |*first_row_index| and will continue in
  // order for the maximum number of rows in this circular buffer.
  //
  // The |first_row_index_| may be negative. This means the circular buffer
  // starts before the top of the image (it hasn't been filled yet).
  unsigned char* const* GetRowAddresses(int* first_row_index) {
    // Example for a 4-element circular buffer holding coords 6-9.
    //   Row 0   Coord 8
    //   Row 1   Coord 9
    //   Row 2   Coord 6  <- next_row_ = 2, next_row_coordinate_ = 10.
    //   Row 3   Coord 7
    //
    // The "next" row is also the first (lowest) coordinate. This computation
    // may yield a negative value, but that's OK, the math will work out
    // since the user of this buffer will compute the offset relative
    // to the first_row_index and the negative rows will never be used.
    *first_row_index = next_row_coordinate_ - num_rows_;

    int cur_row = next_row_;
    for (int i = 0; i < num_rows_; i++) {
      row_addresses_[i] = &buffer_[cur_row * row_byte_width_];

      // Advance to the next row, wrapping if necessary.
      cur_row++;
      if (cur_row == num_rows_)
        cur_row = 0;
    }
    return &row_addresses_[0];
  }

 private:
  // The buffer storing the rows. They are packed, each one row_byte_width_.
  std::vector<unsigned char> buffer_;

  // Number of bytes per row in the |buffer_|.
  int row_byte_width_;

  // The number of rows available in the buffer.
  int num_rows_;

  // The next row index we should write into. This wraps around as the
  // circular buffer is used.
  int next_row_;

  // The y coordinate of the |next_row_|. This is incremented each time a
  // new row is appended and does not wrap.
  int next_row_coordinate_;

  // Buffer used by GetRowAddresses().
  std::vector<unsigned char*> row_addresses_;
};

// Convolves horizontally along a single row. The row data is given in
// |src_data| and continues for the num_values() of the filter.
template<bool has_alpha>
void ConvolveHorizontally(const unsigned char* src_data,
                          const ConvolusionFilter1D& filter,
                          unsigned char* out_row) {
  // Loop over each pixel on this row in the output image.
  int num_values = filter.num_values();
  for (int out_x = 0; out_x < num_values; out_x++) {
    // Get the filter that determines the current output pixel.
    int filter_offset, filter_length;
    const short* filter_values =
        filter.FilterForValue(out_x, &filter_offset, &filter_length);

    // Compute the first pixel in this row that the filter affects. It will
    // touch |filter_length| pixels (4 bytes each) after this.
    const unsigned char* row_to_filter = &src_data[filter_offset * 4];

    // Apply the filter to the row to get the destination pixel in |accum|.
    int accum[4] = {0};
    for (int filter_x = 0; filter_x < filter_length; filter_x++) {
      short cur_filter = filter_values[filter_x];
      accum[0] += cur_filter * row_to_filter[filter_x * 4 + 0];
      accum[1] += cur_filter * row_to_filter[filter_x * 4 + 1];
      accum[2] += cur_filter * row_to_filter[filter_x * 4 + 2];
      if (has_alpha)
        accum[3] += cur_filter * row_to_filter[filter_x * 4 + 3];
    }

    // Bring this value back in range. All of the filter scaling factors
    // are in fixed point with kShiftBits bits of fractional part.
    accum[0] >>= ConvolusionFilter1D::kShiftBits;
    accum[1] >>= ConvolusionFilter1D::kShiftBits;
    accum[2] >>= ConvolusionFilter1D::kShiftBits;
    if (has_alpha)
      accum[3] >>= ConvolusionFilter1D::kShiftBits;

    // Store the new pixel.
    out_row[out_x * 4 + 0] = ClampTo8(accum[0]);
    out_row[out_x * 4 + 1] = ClampTo8(accum[1]);
    out_row[out_x * 4 + 2] = ClampTo8(accum[2]);
    if (has_alpha)
      out_row[out_x * 4 + 3] = ClampTo8(accum[3]);
  }
}

// Does vertical convolusion to produce one output row. The filter values and
// length are given in the first two parameters. These are applied to each
// of the rows pointed to in the |source_data_rows| array, with each row
// being |pixel_width| wide.
//
// The output must have room for |pixel_width * 4| bytes.
template<bool has_alpha>
void ConvolveVertically(const short* filter_values,
                        int filter_length,
                        unsigned char* const* source_data_rows,
                        int pixel_width,
                        unsigned char* out_row) {
  // We go through each column in the output and do a vertical convolusion,
  // generating one output pixel each time.
  for (int out_x = 0; out_x < pixel_width; out_x++) {
    // Compute the number of bytes over in each row that the current column
    // we're convolving starts at. The pixel will cover the next 4 bytes.
    int byte_offset = out_x * 4;

    // Apply the filter to one column of pixels.
    int accum[4] = {0};
    for (int filter_y = 0; filter_y < filter_length; filter_y++) {
      short cur_filter = filter_values[filter_y];
      accum[0] += cur_filter * source_data_rows[filter_y][byte_offset + 0];
      accum[1] += cur_filter * source_data_rows[filter_y][byte_offset + 1];
      accum[2] += cur_filter * source_data_rows[filter_y][byte_offset + 2];
      if (has_alpha)
        accum[3] += cur_filter * source_data_rows[filter_y][byte_offset + 3];
    }

    // Bring this value back in range. All of the filter scaling factors
    // are in fixed point with kShiftBits bits of precision.
    accum[0] >>= ConvolusionFilter1D::kShiftBits;
    accum[1] >>= ConvolusionFilter1D::kShiftBits;
    accum[2] >>= ConvolusionFilter1D::kShiftBits;
    if (has_alpha)
      accum[3] >>= ConvolusionFilter1D::kShiftBits;

    // Store the new pixel.
    out_row[byte_offset + 0] = ClampTo8(accum[0]);
    out_row[byte_offset + 1] = ClampTo8(accum[1]);
    out_row[byte_offset + 2] = ClampTo8(accum[2]);
    if (has_alpha) {
      unsigned char alpha = ClampTo8(accum[3]);

      // Make sure the alpha channel doesn't come out larger than any of the
      // color channels. We use premultipled alpha channels, so this should
      // never happen, but rounding errors will cause this from time to time.
      // These "impossible" colors will cause overflows (and hence random pixel
      // values) when the resulting bitmap is drawn to the screen.
      //
      // We only need to do this when generating the final output row (here).
      int max_color_channel = std::max(out_row[byte_offset + 0],
          std::max(out_row[byte_offset + 1], out_row[byte_offset + 2]));
      if (alpha < max_color_channel)
        out_row[byte_offset + 3] = max_color_channel;
      else
        out_row[byte_offset + 3] = alpha;
    } else {
      // No alpha channel, the image is opaque.
      out_row[byte_offset + 3] = 0xff;
    }
  }
}

}  // namespace

// ConvolusionFilter1D ---------------------------------------------------------

void ConvolusionFilter1D::AddFilter(int filter_offset,
                                    const float* filter_values,
                                    int filter_length) {
  FilterInstance instance;
  instance.data_location = static_cast<int>(filter_values_.size());
  instance.offset = filter_offset;
  instance.length = filter_length;
  filters_.push_back(instance);

  SkASSERT(filter_length > 0);
  for (int i = 0; i < filter_length; i++)
    filter_values_.push_back(FloatToFixed(filter_values[i]));

  max_filter_ = std::max(max_filter_, filter_length);
}

void ConvolusionFilter1D::AddFilter(int filter_offset,
                                    const short* filter_values,
                                    int filter_length) {
  FilterInstance instance;
  instance.data_location = static_cast<int>(filter_values_.size());
  instance.offset = filter_offset;
  instance.length = filter_length;
  filters_.push_back(instance);

  SkASSERT(filter_length > 0);
  for (int i = 0; i < filter_length; i++)
    filter_values_.push_back(filter_values[i]);

  max_filter_ = std::max(max_filter_, filter_length);
}

// BGRAConvolve2D -------------------------------------------------------------

void BGRAConvolve2D(const unsigned char* source_data,
                    int source_byte_row_stride,
                    bool source_has_alpha,
                    const ConvolusionFilter1D& filter_x,
                    const ConvolusionFilter1D& filter_y,
                    unsigned char* output) {
  int max_y_filter_size = filter_y.max_filter();

  // The next row in the input that we will generate a horizontally
  // convolved row for. If the filter doesn't start at the beginning of the
  // image (this is the case when we are only resizing a subset), then we
  // don't want to generate any output rows before that. Compute the starting
  // row for convolusion as the first pixel for the first vertical filter.
  int filter_offset, filter_length;
  const short* filter_values =
      filter_y.FilterForValue(0, &filter_offset, &filter_length);
  int next_x_row = filter_offset;

  // We loop over each row in the input doing a horizontal convolusion. This
  // will result in a horizontally convolved image. We write the results into
  // a circular buffer of convolved rows and do vertical convolusion as rows
  // are available. This prevents us from having to store the entire
  // intermediate image and helps cache coherency.
  CircularRowBuffer row_buffer(filter_x.num_values(), max_y_filter_size,
                               filter_offset);

  // Loop over every possible output row, processing just enough horizontal
  // convolusions to run each subsequent vertical convolusion.
  int output_row_byte_width = filter_x.num_values() * 4;
  int num_output_rows = filter_y.num_values();
  for (int out_y = 0; out_y < num_output_rows; out_y++) {
    filter_values = filter_y.FilterForValue(out_y,
                                            &filter_offset, &filter_length);

    // Generate output rows until we have enough to run the current filter.
    while (next_x_row < filter_offset + filter_length) {
      if (source_has_alpha) {
        ConvolveHorizontally<true>(
            &source_data[next_x_row * source_byte_row_stride],
            filter_x, row_buffer.AdvanceRow());
      } else {
        ConvolveHorizontally<false>(
            &source_data[next_x_row * source_byte_row_stride],
            filter_x, row_buffer.AdvanceRow());
      }
      next_x_row++;
    }

    // Compute where in the output image this row of final data will go.
    unsigned char* cur_output_row = &output[out_y * output_row_byte_width];

    // Get the list of rows that the circular buffer has, in order.
    int first_row_in_circular_buffer;
    unsigned char* const* rows_to_convolve =
        row_buffer.GetRowAddresses(&first_row_in_circular_buffer);

    // Now compute the start of the subset of those rows that the filter
    // needs.
    unsigned char* const* first_row_for_filter =
        &rows_to_convolve[filter_offset - first_row_in_circular_buffer];

    if (source_has_alpha) {
      ConvolveVertically<true>(filter_values, filter_length,
                               first_row_for_filter,
                               filter_x.num_values(), cur_output_row);
    } else {
      ConvolveVertically<false>(filter_values, filter_length,
                                first_row_for_filter,
                                filter_x.num_values(), cur_output_row);
    }
  }
}

}  // namespace gfx

<commit_msg>Add an additional include to get skASSERT.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <algorithm>

#include "skia/ext/convolver.h"
#include "SkTypes.h"

namespace skia {

namespace {

// Converts the argument to an 8-bit unsigned value by clamping to the range
// 0-255.
inline unsigned int ClampTo8(int a) {
  if (static_cast<int>(a) < 256)
    return a;  // Avoid the extra check in the common case.
  if (a < 0)
    return 0;
  return 255;
}

// Stores a list of rows in a circular buffer. The usage is you write into it
// by calling AdvanceRow. It will keep track of which row in the buffer it
// should use next, and the total number of rows added.
class CircularRowBuffer {
 public:
  // The number of pixels in each row is given in |source_row_pixel_width|.
  // The maximum number of rows needed in the buffer is |max_y_filter_size|
  // (we only need to store enough rows for the biggest filter).
  //
  // We use the |first_input_row| to compute the coordinates of all of the
  // following rows returned by Advance().
  CircularRowBuffer(int dest_row_pixel_width, int max_y_filter_size,
                    int first_input_row)
      : row_byte_width_(dest_row_pixel_width * 4),
        num_rows_(max_y_filter_size),
        next_row_(0),
        next_row_coordinate_(first_input_row) {
    buffer_.resize(row_byte_width_ * max_y_filter_size);
    row_addresses_.resize(num_rows_);
  }

  // Moves to the next row in the buffer, returning a pointer to the beginning
  // of it.
  unsigned char* AdvanceRow() {
    unsigned char* row = &buffer_[next_row_ * row_byte_width_];
    next_row_coordinate_++;

    // Set the pointer to the next row to use, wrapping around if necessary.
    next_row_++;
    if (next_row_ == num_rows_)
      next_row_ = 0;
    return row;
  }

  // Returns a pointer to an "unrolled" array of rows. These rows will start
  // at the y coordinate placed into |*first_row_index| and will continue in
  // order for the maximum number of rows in this circular buffer.
  //
  // The |first_row_index_| may be negative. This means the circular buffer
  // starts before the top of the image (it hasn't been filled yet).
  unsigned char* const* GetRowAddresses(int* first_row_index) {
    // Example for a 4-element circular buffer holding coords 6-9.
    //   Row 0   Coord 8
    //   Row 1   Coord 9
    //   Row 2   Coord 6  <- next_row_ = 2, next_row_coordinate_ = 10.
    //   Row 3   Coord 7
    //
    // The "next" row is also the first (lowest) coordinate. This computation
    // may yield a negative value, but that's OK, the math will work out
    // since the user of this buffer will compute the offset relative
    // to the first_row_index and the negative rows will never be used.
    *first_row_index = next_row_coordinate_ - num_rows_;

    int cur_row = next_row_;
    for (int i = 0; i < num_rows_; i++) {
      row_addresses_[i] = &buffer_[cur_row * row_byte_width_];

      // Advance to the next row, wrapping if necessary.
      cur_row++;
      if (cur_row == num_rows_)
        cur_row = 0;
    }
    return &row_addresses_[0];
  }

 private:
  // The buffer storing the rows. They are packed, each one row_byte_width_.
  std::vector<unsigned char> buffer_;

  // Number of bytes per row in the |buffer_|.
  int row_byte_width_;

  // The number of rows available in the buffer.
  int num_rows_;

  // The next row index we should write into. This wraps around as the
  // circular buffer is used.
  int next_row_;

  // The y coordinate of the |next_row_|. This is incremented each time a
  // new row is appended and does not wrap.
  int next_row_coordinate_;

  // Buffer used by GetRowAddresses().
  std::vector<unsigned char*> row_addresses_;
};

// Convolves horizontally along a single row. The row data is given in
// |src_data| and continues for the num_values() of the filter.
template<bool has_alpha>
void ConvolveHorizontally(const unsigned char* src_data,
                          const ConvolusionFilter1D& filter,
                          unsigned char* out_row) {
  // Loop over each pixel on this row in the output image.
  int num_values = filter.num_values();
  for (int out_x = 0; out_x < num_values; out_x++) {
    // Get the filter that determines the current output pixel.
    int filter_offset, filter_length;
    const short* filter_values =
        filter.FilterForValue(out_x, &filter_offset, &filter_length);

    // Compute the first pixel in this row that the filter affects. It will
    // touch |filter_length| pixels (4 bytes each) after this.
    const unsigned char* row_to_filter = &src_data[filter_offset * 4];

    // Apply the filter to the row to get the destination pixel in |accum|.
    int accum[4] = {0};
    for (int filter_x = 0; filter_x < filter_length; filter_x++) {
      short cur_filter = filter_values[filter_x];
      accum[0] += cur_filter * row_to_filter[filter_x * 4 + 0];
      accum[1] += cur_filter * row_to_filter[filter_x * 4 + 1];
      accum[2] += cur_filter * row_to_filter[filter_x * 4 + 2];
      if (has_alpha)
        accum[3] += cur_filter * row_to_filter[filter_x * 4 + 3];
    }

    // Bring this value back in range. All of the filter scaling factors
    // are in fixed point with kShiftBits bits of fractional part.
    accum[0] >>= ConvolusionFilter1D::kShiftBits;
    accum[1] >>= ConvolusionFilter1D::kShiftBits;
    accum[2] >>= ConvolusionFilter1D::kShiftBits;
    if (has_alpha)
      accum[3] >>= ConvolusionFilter1D::kShiftBits;

    // Store the new pixel.
    out_row[out_x * 4 + 0] = ClampTo8(accum[0]);
    out_row[out_x * 4 + 1] = ClampTo8(accum[1]);
    out_row[out_x * 4 + 2] = ClampTo8(accum[2]);
    if (has_alpha)
      out_row[out_x * 4 + 3] = ClampTo8(accum[3]);
  }
}

// Does vertical convolusion to produce one output row. The filter values and
// length are given in the first two parameters. These are applied to each
// of the rows pointed to in the |source_data_rows| array, with each row
// being |pixel_width| wide.
//
// The output must have room for |pixel_width * 4| bytes.
template<bool has_alpha>
void ConvolveVertically(const short* filter_values,
                        int filter_length,
                        unsigned char* const* source_data_rows,
                        int pixel_width,
                        unsigned char* out_row) {
  // We go through each column in the output and do a vertical convolusion,
  // generating one output pixel each time.
  for (int out_x = 0; out_x < pixel_width; out_x++) {
    // Compute the number of bytes over in each row that the current column
    // we're convolving starts at. The pixel will cover the next 4 bytes.
    int byte_offset = out_x * 4;

    // Apply the filter to one column of pixels.
    int accum[4] = {0};
    for (int filter_y = 0; filter_y < filter_length; filter_y++) {
      short cur_filter = filter_values[filter_y];
      accum[0] += cur_filter * source_data_rows[filter_y][byte_offset + 0];
      accum[1] += cur_filter * source_data_rows[filter_y][byte_offset + 1];
      accum[2] += cur_filter * source_data_rows[filter_y][byte_offset + 2];
      if (has_alpha)
        accum[3] += cur_filter * source_data_rows[filter_y][byte_offset + 3];
    }

    // Bring this value back in range. All of the filter scaling factors
    // are in fixed point with kShiftBits bits of precision.
    accum[0] >>= ConvolusionFilter1D::kShiftBits;
    accum[1] >>= ConvolusionFilter1D::kShiftBits;
    accum[2] >>= ConvolusionFilter1D::kShiftBits;
    if (has_alpha)
      accum[3] >>= ConvolusionFilter1D::kShiftBits;

    // Store the new pixel.
    out_row[byte_offset + 0] = ClampTo8(accum[0]);
    out_row[byte_offset + 1] = ClampTo8(accum[1]);
    out_row[byte_offset + 2] = ClampTo8(accum[2]);
    if (has_alpha) {
      unsigned char alpha = ClampTo8(accum[3]);

      // Make sure the alpha channel doesn't come out larger than any of the
      // color channels. We use premultipled alpha channels, so this should
      // never happen, but rounding errors will cause this from time to time.
      // These "impossible" colors will cause overflows (and hence random pixel
      // values) when the resulting bitmap is drawn to the screen.
      //
      // We only need to do this when generating the final output row (here).
      int max_color_channel = std::max(out_row[byte_offset + 0],
          std::max(out_row[byte_offset + 1], out_row[byte_offset + 2]));
      if (alpha < max_color_channel)
        out_row[byte_offset + 3] = max_color_channel;
      else
        out_row[byte_offset + 3] = alpha;
    } else {
      // No alpha channel, the image is opaque.
      out_row[byte_offset + 3] = 0xff;
    }
  }
}

}  // namespace

// ConvolusionFilter1D ---------------------------------------------------------

void ConvolusionFilter1D::AddFilter(int filter_offset,
                                    const float* filter_values,
                                    int filter_length) {
  FilterInstance instance;
  instance.data_location = static_cast<int>(filter_values_.size());
  instance.offset = filter_offset;
  instance.length = filter_length;
  filters_.push_back(instance);

  SkASSERT(filter_length > 0);
  for (int i = 0; i < filter_length; i++)
    filter_values_.push_back(FloatToFixed(filter_values[i]));

  max_filter_ = std::max(max_filter_, filter_length);
}

void ConvolusionFilter1D::AddFilter(int filter_offset,
                                    const short* filter_values,
                                    int filter_length) {
  FilterInstance instance;
  instance.data_location = static_cast<int>(filter_values_.size());
  instance.offset = filter_offset;
  instance.length = filter_length;
  filters_.push_back(instance);

  SkASSERT(filter_length > 0);
  for (int i = 0; i < filter_length; i++)
    filter_values_.push_back(filter_values[i]);

  max_filter_ = std::max(max_filter_, filter_length);
}

// BGRAConvolve2D -------------------------------------------------------------

void BGRAConvolve2D(const unsigned char* source_data,
                    int source_byte_row_stride,
                    bool source_has_alpha,
                    const ConvolusionFilter1D& filter_x,
                    const ConvolusionFilter1D& filter_y,
                    unsigned char* output) {
  int max_y_filter_size = filter_y.max_filter();

  // The next row in the input that we will generate a horizontally
  // convolved row for. If the filter doesn't start at the beginning of the
  // image (this is the case when we are only resizing a subset), then we
  // don't want to generate any output rows before that. Compute the starting
  // row for convolusion as the first pixel for the first vertical filter.
  int filter_offset, filter_length;
  const short* filter_values =
      filter_y.FilterForValue(0, &filter_offset, &filter_length);
  int next_x_row = filter_offset;

  // We loop over each row in the input doing a horizontal convolusion. This
  // will result in a horizontally convolved image. We write the results into
  // a circular buffer of convolved rows and do vertical convolusion as rows
  // are available. This prevents us from having to store the entire
  // intermediate image and helps cache coherency.
  CircularRowBuffer row_buffer(filter_x.num_values(), max_y_filter_size,
                               filter_offset);

  // Loop over every possible output row, processing just enough horizontal
  // convolusions to run each subsequent vertical convolusion.
  int output_row_byte_width = filter_x.num_values() * 4;
  int num_output_rows = filter_y.num_values();
  for (int out_y = 0; out_y < num_output_rows; out_y++) {
    filter_values = filter_y.FilterForValue(out_y,
                                            &filter_offset, &filter_length);

    // Generate output rows until we have enough to run the current filter.
    while (next_x_row < filter_offset + filter_length) {
      if (source_has_alpha) {
        ConvolveHorizontally<true>(
            &source_data[next_x_row * source_byte_row_stride],
            filter_x, row_buffer.AdvanceRow());
      } else {
        ConvolveHorizontally<false>(
            &source_data[next_x_row * source_byte_row_stride],
            filter_x, row_buffer.AdvanceRow());
      }
      next_x_row++;
    }

    // Compute where in the output image this row of final data will go.
    unsigned char* cur_output_row = &output[out_y * output_row_byte_width];

    // Get the list of rows that the circular buffer has, in order.
    int first_row_in_circular_buffer;
    unsigned char* const* rows_to_convolve =
        row_buffer.GetRowAddresses(&first_row_in_circular_buffer);

    // Now compute the start of the subset of those rows that the filter
    // needs.
    unsigned char* const* first_row_for_filter =
        &rows_to_convolve[filter_offset - first_row_in_circular_buffer];

    if (source_has_alpha) {
      ConvolveVertically<true>(filter_values, filter_length,
                               first_row_for_filter,
                               filter_x.num_values(), cur_output_row);
    } else {
      ConvolveVertically<false>(filter_values, filter_length,
                                first_row_for_filter,
                                filter_x.num_values(), cur_output_row);
    }
  }
}

}  // namespace gfx

<|endoftext|>