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.