0

The following is my approach for a program that simulates a bash terminal.

I have the following:

class Shell
{
    public:
        string currentDir;
        vector<string> cmdHistory;
        vector<pid_t> pidHistory;

    public:
    Shell(string dir)
    {
        this->currentDir = dir;
        this->cmdHistory.clear();
        this->pidHistory.clear();
    };

    // Get the current directory
    string getDir()
    {
        return this->currentDir;
    }

    void setDir(string dir)
    {
        this->currentDir = dir;
    }

    void appendDir(string dir)
    {
        this->currentDir.append(dir);
    }

    void recordCmd (string record)
    {
        cmdHistory.push_back(record);
    }

    void recordPID(pid_t record)
    {
        this->pidHistory.push_back(record);
    }

    void printCmdHistory()
    {
        int size = cmdHistory.size();

        if (size == 0)
            return;

        for (int i = 0; i < size; i++)
        {
            cout << cmdHistory[i] << "\n";
        }
    }

    void clearHistory()
    {
        cmdHistory.clear();
    }

    void clearPIDHistory()
    {
        pidHistory.clear();
    }

    int getPIDsize()
    {
        return this->pidHistory.size();
    }

    pid_t getCurrentPID()
    {
        return this->pidHistory.at(pidHistory.size() - 1);
    }

    pid_t getAtPID(int i)
    {
        return pidHistory.at(i);
    }
};

Which is my object type Shell. I then continue to call a new type of Shell object in main in an infinite loop and do the following:

    Shell newShell(currentDir);

    do
    {
        cout << "#";
        getline(cin, inputBuffer);
        newShell = processLine(newShell, inputBuffer);
        cout << endl;
        
    }while(inputBuffer.compare("byebye") != 0);

Similarly, I am doing the same inside the function processLine():

// #background:
        else if (args[0].compare("background") == 0)
        {
            if (args.size() > 1)
            {
                // CASE I: Full path
                if (args[1][0] == '/')
                {
                    // There's a parameter
                    if (args.size() > 2)
                    {
                        currentShell = backgroundProgramHelper(currentShell, args, true);
                    }
                    else
                    {
                        currentShell = backgroundProgramHelper(currentShell, args, false);
                    }
                }
                // CASE II: Relative path
                else
                {
                    // Append program to current directory address
                    args[1] = currentShell.getDir() + "/" + (args[1]);
                    // There's a parameter
                    if (args.size() > 2)
                    {
                        currentShell = backgroundProgramHelper(currentShell, args, true);
                    }
                    else
                    {
                        currentShell = backgroundProgramHelper(currentShell, args, false);
                    }
                }
            }

The function backgroundProgramHelper() does the following:

Shell backgroundProgramHelper(Shell currentShell, vector<string> args, bool flag)
{
    if (flag)
    {
        // Get rid of '-'
        string flag = args[2];
        string delimeter = "-";

        size_t pos = flag.find(delimeter);
        string token = flag.substr(0, pos);

        args[2] = flag.erase(0, pos + delimeter.length());

        // DMA a char * for the amount of parameters.
        // I made the assumption based on the example given
        // that the total amount of parameters passed would 2
        char * arguments[4];
        arguments[0] = (char*)args[1].c_str(); // program
        arguments[1] = (char*)args[2].c_str(); // flag
        arguments[2] = (char*)args[3].c_str(); // flag
        arguments[3] = NULL;

        pid_t pid = fork();
        
        // ERROR
        if (pid == -1)
            perror("ERROR: Failed to fork");
        // Child
        if (pid == 0)
        {
            cout << "child: " << pid << endl;
            if (execvp (arguments[0], arguments) == -1)
            {
                perror("exec");
            }
        }
        // Parent
        if (pid > 0)
        {
            wait(0);
            currentShell.recordPID(pid);
            cout << "\nparent: " << pid << endl;
        }
    }
    else
    {
        char * arguments[2];
        arguments[0] = (char*)args[1].c_str(); // program
        arguments[1] = NULL;

        pid_t pid = fork();
        
        // ERROR
        if (pid == -1)
            perror("ERROR: Failed to fork");
        // Child
        if (pid == 0)
        {
            cout << "child: " << pid << endl;
            if (execvp (arguments[0], arguments) == -1)
            {
                perror("exec");
            }
        }
        // Parent
        if (pid > 0)
        {
            wait(0);
            currentShell.recordPID(pid);
            cout << "\nparent: " << pid << endl;
        }
    }

    return currentShell;
}

It takes the currentSHell and then updates the history of PID with any program that was run. The problem is if I make backgroundProgramHelper type void and not return a Shell type variable to update the one I passed, then my object in main doesn't get updated with the PID history of the programs run. I think this is a fundamental problem in passing by values and passing by reference, but again, I am not sure why is it that I have to do currentSHell = backgroundProgramHelper(Shell currentShell, vector args, bool flag), in order for my PID history to get updated.

D.C.M.
  • 1
  • 2
  • You might want to distill this question to its essential parts. – Homer6 Sep 21 '20 at 19:43
  • BTW, you don't need to use the `this->` notation to access member variables or methods (see `Shell::recordCmd` as an example). Usually, more typing leads to greater chance of injecting defects. Less code to type == less chance of defects. – Thomas Matthews Sep 21 '20 at 20:16

0 Answers0