Cpp Shell
Cppshell code is not much shorter than csimpleshell one (you may think it is longer, since many lines are split in two to make it more readable in HTML). Still it is much more readable. In fact parse_args is rewritten using C++ std::string class (a comment is made here) and a class Command is created to parse and execute commands.
You can see a more object oriented (and more complete) implementation with cppshell2.
In fact this shares lot of code with the csimpleshell, you can see this as a kind of small refactory. Nothing new under the hood.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cstdlib>
#include <cerrno>
#include <exception>
#include <unistd.h>
using std::string;
void
split_string(const std::string s,
const std::string sep,
std::vector<std::string> &components)
{
typedef std::pair<size_t, size_t> Range;
size_t pos, old_pos;
Range trange;
std::vector<Range> ranges;
trange.first = 0;
trange.second = s.find(sep, trange.first);
if (trange.second == string::npos){
trange.second = s.length();
}
ranges.push_back(trange);
while(trange.second < s.length()){
trange.first = trange.second + 1;
trange.second = s.find(sep, trange.first);
if (trange.second == string::npos){
trange.second = s.length();
}
ranges.push_back(trange);
}
for (int i = 0; i < ranges.size() ; ++i){
components.push_back(s.substr(ranges[i].first,
ranges[i].second - ranges[i].first) );
}
}
class InvalidCommandLine : public std::exception {
};
class Command {
private:
char *name;
char **arguments;
size_t arg_num;
bool has_run;
unsigned int pid;
int ret_status;
public:
Command(const std::string& line)
: has_run(false) { parse_line(line); };
~Command();
unsigned int sync_run();
private:
void parse_line(const std::string&);
};
Command::~Command(){
delete [] name;
}
void Command::parse_line(const std::string& s){
std::vector<std::string> args;
split_string(s, " ", args);
if (args.size() >0 ){
name = new char[args[0].size()];
std::copy(args[0].begin(), args[0].end(), name);
arg_num = args.size();
arguments = new char* [arg_num + 1];
for(int i = 0; i < arg_num; ++i){
arguments[i] = new char[args[i].size()];
std::copy(args[i].begin(),
args[i].end(),
arguments[i]);
}
arguments[arg_num] = 0;
} else {
throw InvalidCommandLine();
}
}
unsigned int Command::sync_run(){
pid = fork();
if (pid){
printf("Waiting for child (%d)\n", pid);
pid = wait(&ret_status);
printf("Child (%d) finished\n", pid);
} else {
if( execvp(args[0], args)) {
puts(strerror(errno));
exit(127);
} }
return ret_status;
}
int main(){
while(1){
std::cout << "$ ";
std::string line;
std::getline(std::cin, line);
Command c(line);
c.sync_run();
}
return 0;
}