Skip to content

Commit 1baa988

Browse files
author
mgroot
committed
5.4: Pipes | 1. Simple shell pipe done
1 parent d108736 commit 1baa988

File tree

9 files changed

+518
-0
lines changed

9 files changed

+518
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
simple-shell-pipe
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
NAME := simple-shell-pipe
2+
3+
CC := g++
4+
CFLAGS := -std=c++17 -Wall -Wextra -Werror -g
5+
DEP_FLAGS := -MP -MMD
6+
7+
SRCS_DIRS := $(addprefix src, \
8+
/ \
9+
/Command \
10+
/Executor \
11+
/Env \
12+
)
13+
14+
15+
vpath %.cpp $(SRCS_DIRS)
16+
vpath %.hpp $(SRCS_DIRS)
17+
18+
19+
SRCS := main.cpp \
20+
Command/Command.cpp \
21+
Executor/Executor.cpp \
22+
Env/Env.cpp
23+
24+
25+
26+
27+
OBJS_DIR := .objects
28+
OBJS := $(addprefix $(OBJS_DIR)/, \
29+
$(patsubst %.cpp, %.o, $(SRCS)))
30+
31+
DEPS := $(addprefix $(OBJS_DIR)/, \
32+
$(patsubst %.cpp, %.d, $(SRCS)))
33+
34+
35+
all:
36+
@echo "$(FMT_BOLD)Creating/updating $(FMT_WHITE_B)'$(NAME)'$(FMT_BOLD):$(FMT_DEF)"
37+
@$(MAKE) --no-print-directory $(NAME)
38+
39+
$(NAME): $(OBJS) Makefile
40+
@echo "$(FMT_BOLD)Linking files...$(FMT_DEF)"
41+
@$(CC) $(OBJS) $(CFLAGS) -o $@
42+
@echo "$(FMT_WHITE_B)'$(NAME)'$(FMT_BOLD) has been created/updated.$(FMT_DEF)"
43+
44+
$(OBJS_DIR)/%.o: %.cpp | $(OBJS_DIR)
45+
@echo "Assembling $<..."
46+
@mkdir -p $(dir $@)
47+
@$(CC) $(CFLAGS) $(DEP_FLAGS) -c $< -o $@
48+
49+
$(OBJS_DIR):
50+
@mkdir -p $@
51+
@echo "$(FMT_BOLD)Directory '$(OBJS_DIR)' has been created.$(FMT_DEF)"
52+
53+
clean:
54+
@rm -rf $(OBJS) $(DEPS) $(OBJS_DIR)
55+
@echo "$(FMT_WHITE)$(NAME): $(FMT_BOLD)Object files have been cleaned.$(FMT_DEF)"
56+
57+
fclean: clean
58+
@rm -rf $(NAME)
59+
@echo "$(FMT_WHITE)'$(NAME)'$(FMT_BOLD) has been cleaned.$(FMT_DEF)"
60+
61+
re: fclean all
62+
63+
.PHONY: all clean fclean re
64+
65+
-include $(DEPS)
66+
67+
FMT_BOLD := \033[0;1m
68+
FMT_WHITE_B := \033[1;37m
69+
FMT_WHITE := \033[37m
70+
FMT_DEF := \033[0;39m
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#include "Command.hpp"
2+
3+
#include "../Env/Env.hpp"
4+
5+
#include <algorithm>
6+
7+
namespace PipeApp
8+
{
9+
10+
////////////////////
11+
// Command //
12+
////////////////////
13+
14+
Command::Command(const std::string::const_iterator& begin,
15+
const std::string::const_iterator& end)
16+
{
17+
// Get command
18+
auto begin_it = std::find_if(begin, end,
19+
[] (char c) { return !::isspace(c); });
20+
auto end_it = std::find_if(begin_it, end,
21+
[] (char c) { return ::isspace(c); });
22+
23+
{
24+
std::string temp_command = Env::getFromPath(std::string(begin_it, end_it));
25+
this->command_ = new char[temp_command.size() + 1];
26+
::memcpy(this->command_, temp_command.c_str(), temp_command.size() + 1);
27+
}
28+
29+
30+
// Get argv
31+
std::vector<std::string> argv;
32+
argv.push_back(std::string(begin_it, end_it));
33+
while (end_it != end)
34+
{
35+
begin_it = std::find_if(end_it, end,
36+
[] (char c) { return !::isspace(c); });
37+
end_it = std::find_if(begin_it, end,
38+
[] (char c) { return ::isspace(c); });
39+
40+
if (begin_it != end_it)
41+
argv.push_back(std::string(begin_it, end_it));
42+
}
43+
44+
this->argv_ = new char*[argv.size() + 1];
45+
for (size_t i = 0; i < argv.size(); ++i)
46+
{
47+
this->argv_[i] = new char[argv[i].size() + 1];
48+
::memcpy(this->argv_[i], argv[i].c_str(), argv[i].size() + 1);
49+
}
50+
this->argv_[argv.size()] = nullptr;
51+
}
52+
53+
Command::Command(const std::string& command)
54+
: Command(command.cbegin(), command.cend())
55+
{}
56+
57+
Command::Command(Command&& old)
58+
: command_(old.command_), argv_(old.argv_)
59+
{
60+
old.command_ = nullptr;
61+
old.argv_ = nullptr;
62+
}
63+
64+
Command& Command::operator=(Command&& old)
65+
{
66+
if (this == &old)
67+
return *this;
68+
69+
this->command_ = old.command_; old.command_ = nullptr;
70+
this->argv_ = old.argv_; old.argv_ = nullptr;
71+
return *this;
72+
}
73+
74+
Command::~Command()
75+
{
76+
delete[] this->command_;
77+
78+
if (this->argv_)
79+
{
80+
size_t i = 0;
81+
while (this->argv_[i])
82+
delete[] this->argv_[i++];
83+
delete[] this->argv_;
84+
}
85+
}
86+
87+
88+
const char* Command::getCommand() const
89+
{
90+
return this->command_;
91+
}
92+
93+
94+
char* const* Command::getArgv()
95+
{
96+
return this->argv_;
97+
}
98+
99+
100+
101+
////////////////////
102+
// Command List //
103+
////////////////////
104+
105+
CommandList::CommandList(const std::string& commandline)
106+
{
107+
// init iterators
108+
auto begin_it = commandline.cbegin();
109+
auto end_it = std::find(commandline.begin(), commandline.end(), '|');
110+
111+
// parse commands
112+
while (begin_it != commandline.cend())
113+
{
114+
this->container_.emplace_back(begin_it, end_it);
115+
begin_it = (end_it != commandline.end()) ? std::next(end_it) : end_it;
116+
end_it = std::find(begin_it, commandline.end(), '|');
117+
}
118+
}
119+
120+
CommandList::CommandList(CommandList&& old)
121+
: container_(std::move(old.container_))
122+
{}
123+
124+
CommandList& CommandList::operator=(CommandList&& old)
125+
{
126+
if (this == &old)
127+
return *this;
128+
129+
this->container_ = std::move(old.container_);
130+
return *this;
131+
}
132+
133+
CommandList::iterator CommandList::begin()
134+
{
135+
return this->container_.begin();
136+
}
137+
138+
CommandList::iterator CommandList::end()
139+
{
140+
return this->container_.end();
141+
}
142+
143+
} //!namespace PipeApp
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include <string>
5+
6+
namespace PipeApp
7+
{
8+
9+
class Command final
10+
{
11+
// Fields
12+
private:
13+
char* command_;
14+
char** argv_;
15+
16+
// Constructor and destructor
17+
public:
18+
Command(const std::string::const_iterator& begin,
19+
const std::string::const_iterator& end);
20+
Command(const std::string& command);
21+
22+
Command(Command&& old);
23+
Command& operator=(Command&& old);
24+
25+
Command(const Command& other) = delete;
26+
Command& operator=(const Command& other) = delete;
27+
28+
~Command();
29+
30+
// Logic
31+
const char* getCommand() const;
32+
char* const* getArgv();
33+
34+
}; //!class Command final
35+
36+
37+
38+
class CommandList final
39+
{
40+
// Fields
41+
public:
42+
using container = std::vector<Command>;
43+
using iterator = typename container::iterator;
44+
45+
private:
46+
std::vector<Command> container_;
47+
48+
// Constructor and destructor
49+
public:
50+
CommandList(const std::string& commandline);
51+
52+
CommandList(CommandList&& old);
53+
CommandList& operator=(CommandList&& old);
54+
55+
CommandList(const CommandList& other) = delete;
56+
CommandList& operator=(const CommandList& other) = delete;
57+
58+
~CommandList() = default;
59+
60+
// Logic
61+
iterator begin();
62+
iterator end();
63+
64+
}; //!class CommandList final
65+
66+
} //!namespace PipeApp
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include "Env.hpp"
2+
3+
#include <cstring>
4+
#include <string>
5+
#include <algorithm>
6+
7+
#include <sys/types.h>
8+
#include <sys/stat.h>
9+
10+
11+
namespace PipeApp::Env
12+
{
13+
14+
static bool isExecutable(const char *path)
15+
{
16+
struct stat sb;
17+
if (stat(path, &sb) != 0)
18+
return false;
19+
return sb.st_mode & S_IXUSR;
20+
}
21+
22+
23+
std::string getFromPath(const std::string& command)
24+
{
25+
size_t i = 0;
26+
for (; environ[i]; ++i)
27+
if (::strncmp(environ[i], "PATH=", 5) == 0)
28+
break;
29+
30+
// original
31+
if (!environ[i])
32+
return command;
33+
34+
// with path
35+
std::string path_value(environ[i] + 5);
36+
auto begin_it = path_value.begin();
37+
auto end_it = std::find(begin_it, path_value.end(), ':');
38+
39+
while (begin_it != path_value.end())
40+
{
41+
42+
std::string temp_path(begin_it, end_it);
43+
if (temp_path.back() != '/')
44+
temp_path.push_back('/');
45+
temp_path += command;
46+
47+
if (isExecutable(temp_path.c_str()))
48+
return temp_path;
49+
50+
begin_it = (end_it != path_value.end()) ? std::next(end_it) : end_it;
51+
end_it = std::find(begin_it, path_value.end(), ':');
52+
}
53+
return command;
54+
}
55+
56+
} //!namespace PipeApp::Env
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
6+
extern char * const *environ;
7+
8+
9+
namespace PipeApp::Env
10+
{
11+
12+
std::string getFromPath(const std::string& command);
13+
14+
} //!namespace PipeApp::Env

0 commit comments

Comments
 (0)