-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathShellInterpreter.cpp
153 lines (121 loc) · 3.7 KB
/
ShellInterpreter.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* File: ShellInterpreter.cpp
* Author: debian
*
* Created on 24. April 2017, 10:51
*/
#include "ShellInterpreter.h"
#include <string.h>
#include <iterator>
#include <sstream>
#include <unistd.h>
#include <stdio.h>
#include <algorithm>
#include <sys/wait.h> // std::transform
ShellInterpreter::ShellInterpreter() {
this->isRunning = true;
this->shell_prompt = "$";
this->processWait = true;
}
ShellInterpreter::ShellInterpreter(const ShellInterpreter& orig) {
}
ShellInterpreter::~ShellInterpreter() {
}
/**
* @brief Mainloop of the shell
*/
void ShellInterpreter::update() {
// Loop until we should exit
while(this->isRunning) {
//Clean all input
this->cleanUp();
//Retrieve input
this->getUserInput();
//Validate input
if(this->formatInput()) {
//Execute input
this->executeProcess();
}
}
}
/**
* @brief Cleans all used var in this class for the next processing
*/
void ShellInterpreter::cleanUp(void) {
// Clear each char* with NULL to be safe
for(int i = 0; i < this->execBuffer.size();i++) {
this->execBuffer[i] = NULL;
}
this->execBuffer.clear(); // Clear the vector
this->buffer.clear(); // Clear the string
this->processWait = true; // Rest the wait to default
}
/**
* @brief Outputs the shell prompt and retrieve the user input
*/
void ShellInterpreter::getUserInput(void) {
std::cout << shell_prompt << " ";
getline(std::cin,this->buffer);
}
/**
* @brief Convert a string to an char*
* @param s string which should be converted
* @return returns an char* which contains the string
*/
static char *convert(const std::string & s)
{
char *pc = new char[s.size()+1];
strcpy(pc, s.c_str());
return pc;
}
/**
* @brief Converts the input which is formated as a string into an array of char* which can be passed to execvp
* @return returns if the input is valid or not
*/
bool ShellInterpreter::formatInput() {
// If the inputBuffer is empty we do not have to do anything
if(this->buffer.empty()) {
return false;
} else if(this->buffer == "logout") {
this->isRunning = false;
return false;
}
// Create a stringstream from a buffer and pass the string to the vector
std::stringstream ss(this->buffer);
std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::vector<std::string> vstrings(begin,end);
// Check for & sign to get process fork info
if(vstrings.at(vstrings.size()-1) == "&") {
vstrings.pop_back();
this->processWait = false;
}
// Transform string vector to char* vector
std::transform(vstrings.begin(),vstrings.end(),std::back_inserter(this->execBuffer),convert);
return true;
}
/**
* @brief Forks an process and wait for finish depending on wait flag set
*/
void ShellInterpreter::executeProcess(void) {
int pid;
// Try to fork a child process
if((pid = fork()) < 0) {
std::cout << "[ERROR] Forking process" << std::endl;
//Error while forking
exit(1);
} else if(pid == 0) { // If we are the child process try to run the command
// Try to execute the buffer
if(execvp(this->execBuffer[0],this->execBuffer.data()) < 0) {
std::cout << "[ERROR] Executing process" << std::endl;
// Error while running
exit(1);
}
}
// If we want to wait for an process to finish we need to call waitpid
if(this->processWait) {
waitpid(pid,NULL,0);
} else {
std::cout << "[PID] " << pid << std::endl;
}
}