-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
377 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Prerequisites | ||
*.d | ||
|
||
# Compiled Object files | ||
*.slo | ||
*.lo | ||
*.o | ||
*.obj | ||
|
||
# Precompiled Headers | ||
*.gch | ||
*.pch | ||
|
||
# Compiled Dynamic libraries | ||
*.so | ||
*.dylib | ||
*.dll | ||
|
||
# Fortran module files | ||
*.mod | ||
*.smod | ||
|
||
# Compiled Static libraries | ||
*.lai | ||
*.la | ||
*.a | ||
*.lib | ||
|
||
# Executables | ||
*.exe | ||
*.out | ||
*.app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
DEBUG=y | ||
|
||
CC=g++ | ||
CFLAGS= -Werror -Wall | ||
LDFLAGS= | ||
|
||
ifeq ($DEBUG), y) | ||
CFLAGS += -DDEBUG -g | ||
else | ||
CFLAGS += -O2 | ||
endif | ||
|
||
.PHONY: all clean | ||
|
||
all: bin/shell | ||
|
||
bin/shell: obj/shell.o obj/parser.o obj/main.o | ||
$(CC) $^ -o $@ | ||
|
||
obj/%.o: src/%.cpp | ||
$(CC) -c $(CFLAGS) $< -o $@ | ||
|
||
clean: | ||
$(RM) *~ src/*~ src/#* obj/*.o bin/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This is the bin directory. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This is the obj directory. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
int main() | ||
{ | ||
Shell::Run(); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
#include "parser.hpp" | ||
|
||
#include <stdlib.h> // EXIT_FAILURE | ||
#include <stdio.h> // printf() | ||
#include <string.h> // strlen() | ||
#include <ctype.h> // isspace(), | ||
#include <string.h> // strtok_r() | ||
#include <stdbool.h> | ||
|
||
bool Parser::Empty(char *str) | ||
{ | ||
while (*str) | ||
{ | ||
if (!isspace(*str++)) | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
char *Parser::LeftTrim(char *s) | ||
{ | ||
while (isspace((int)*s)) | ||
++s; | ||
return s; | ||
} | ||
|
||
char *Parser::RightTrim(char *str) | ||
{ | ||
if (*str == 0) | ||
return str; | ||
else | ||
{ | ||
char *back = str + strlen(str) - 1; | ||
|
||
while (isspace(*back)) | ||
back--; | ||
|
||
*(back + 1) = 0; | ||
|
||
return str; | ||
} | ||
} | ||
|
||
char *Parser::Trim(char *str) | ||
{ | ||
if (str != nullptr) | ||
return (LeftTrim(RightTrim(str))); | ||
else | ||
return nullptr; | ||
} | ||
|
||
void Parser::GetArgument(char *str, const char *delim, char *argv[]) | ||
{ | ||
|
||
char *token; | ||
int i = 0; | ||
|
||
token = strtok(str, delim); | ||
|
||
while (token != nullptr) | ||
{ | ||
argv[i] = token; | ||
token = strtok(NULL, delim); | ||
i++; | ||
} | ||
argv[i] = nullptr; | ||
} | ||
|
||
void Parser::PrintArgument(char *argv[]) | ||
{ | ||
int i = 0; | ||
char *s; | ||
|
||
while ((s = argv[i])) | ||
{ | ||
printf(" argv[%d] = %s\n", i, s); | ||
i++; | ||
} | ||
} | ||
|
||
void Parser::PrintArguments(char *argvs[MAX_COMMANDS][MAX_ARGV]) | ||
{ | ||
int i = 0; | ||
while (argvs[i][0]) | ||
{ | ||
printf("Command %d\n", i); | ||
PrintArgument(argvs[i]); | ||
i++; | ||
} | ||
} | ||
|
||
void Parser::ParseCommands(char *str, const char *delim, char *cmds[]) | ||
{ | ||
|
||
char *token; | ||
int i = 0; | ||
|
||
token = strtok(str, delim); | ||
|
||
while (token != NULL) | ||
{ | ||
if (Empty(token)) | ||
{ | ||
fprintf(stderr, "Parser error: EMPTY command!\n"); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
cmds[i] = Trim(token); | ||
token = strtok(nullptr, delim); | ||
i++; | ||
} | ||
cmds[i] = nullptr; | ||
} | ||
|
||
int Parser::Parse(char *str, char *argvs[MAX_COMMANDS][MAX_ARGV]) | ||
{ | ||
|
||
char *cmds[MAX_COMMANDS]; | ||
|
||
ParseCommands(str, "|", cmds); | ||
|
||
int i = 0; | ||
|
||
while (cmds[i]) | ||
{ | ||
GetArgument(cmds[i], " ", argvs[i]); | ||
i++; | ||
} | ||
|
||
argvs[i][0] = nullptr; | ||
return i; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#ifndef PARSER_HPP | ||
#define PARSER_HPP | ||
|
||
const int MAX_COMMANDS = 16; | ||
const int MAX_ARGV = 16; | ||
|
||
class Parser | ||
{ | ||
public: | ||
static int Parse(char *str, char *argvs[MAX_COMMANDS][MAX_ARGV]); | ||
static void PrintArguments(char *argvs[MAX_COMMANDS][MAX_ARGV]); | ||
|
||
private: | ||
static void PrintArgument(char *argv[]); | ||
static void ParseCommands(char *str, const char *delim, char *cmds[]); | ||
static bool Empty(char *str); | ||
static char *LeftTrim(char *s); | ||
static char *RightTrim(char *str); | ||
static char *Trim(char *str); | ||
static void GetArgument(char *str, const char *delim, char *argv[]); | ||
}; | ||
|
||
#endif // PARSER_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
#include "shell.hpp" | ||
|
||
bool DEBUG = false; | ||
|
||
void DebugPrint(const char *message) | ||
{ | ||
if (DEBUG) | ||
printf("%s\n", message); | ||
} | ||
|
||
void Shell::ForkError() | ||
{ | ||
perror("fork() failed)"); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
void Shell::CloseError() | ||
{ | ||
perror("Couldn't close file descriptor"); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
void Shell::Execute(char *argv[], int number_of_commands, int read_pipe[2], int write_pipe[2], int all_pipes[][2]) | ||
{ | ||
pid_t pid; | ||
|
||
switch (pid = fork()) | ||
{ | ||
case -1: | ||
ForkError(); | ||
case 0: | ||
// if read_pipe is not null | ||
// then duplicate read_pipe (e.g. dup2) for STDIN | ||
// if write_pipe is not null | ||
// then duplicate write_pipe (e.g. dup2) for STDOUT | ||
// Close pipes. | ||
|
||
execvp(argv[0], argv); | ||
perror("execvp"); | ||
exit(EXIT_FAILURE); | ||
|
||
default: | ||
char buffer[MAX_BUFFER]; | ||
sprintf(buffer, "Pid of %s: %d\n", argv[0], pid); | ||
DebugPrint(buffer); | ||
break; | ||
} | ||
} | ||
|
||
void Shell::ExecuteCommands(char *argvs[MAX_COMMANDS][MAX_ARGV], const size_t &number_of_commands, int all_pipes[][2]) | ||
{ | ||
// 1. Cases to cover in a loop; for i = 0 to number_of_commands | ||
// |------------------------------------------------------------------- | ||
// | COMMAND | READ PIPE | WRITE PIPE | | ||
// |------------------------------------------------------------------- | ||
// | Only 1 command | null | null | | ||
// |------------------------------------------------------------------- | ||
// | First command | null | current pipe | | ||
// |------------------------------------------------------------------- | ||
// | Last command | previous pipe | null | | ||
// |------------------------------------------------------------------- | ||
// | Middle command | previous pipe | current pipe | | ||
// -------------------------------------------------------------------- | ||
|
||
// 2. Close pipes. | ||
} | ||
|
||
void Shell::GetLine(char *buffer, size_t size) | ||
{ | ||
getline(&buffer, &size, stdin); | ||
buffer[strlen(buffer) - 1] = '\0'; | ||
} | ||
|
||
void Shell::WaitForAllCommands(const size_t &number_of_commands) | ||
{ | ||
// for i = 0 to number_of_commands | ||
// call wait() | ||
|
||
} | ||
|
||
void Shell::InitializePipes(int all_pipes[][2], const size_t &number_of_commands) | ||
{ | ||
// for i = 0 to number_of_commands | ||
// init all_pipes[i] | ||
} | ||
|
||
void Shell::ClosePipes(int all_pipes[][2], const size_t &number_of_commands) | ||
{ | ||
// for i = 0 to number_of_commands | ||
// close read and write ends for pipes | ||
} | ||
|
||
void Shell::Run() | ||
{ | ||
int number_of_commands = 0; | ||
char *argvs[MAX_COMMANDS][MAX_ARGV]; | ||
const size_t size = 128; | ||
char line[size]; | ||
|
||
while (true) | ||
{ | ||
printf(" >> "); | ||
|
||
Shell::GetLine(line, size); | ||
|
||
number_of_commands = Parser::Parse(line, argvs); | ||
|
||
char buffer[MAX_BUFFER]; | ||
sprintf(buffer, "%d commands parsed.\n", number_of_commands); | ||
DebugPrint(buffer); | ||
|
||
if (DEBUG) | ||
Parser::PrintArguments(argvs); | ||
|
||
int(*all_pipes)[2] = new int[number_of_commands][2]; | ||
Shell::InitializePipes(all_pipes, number_of_commands); | ||
|
||
ExecuteCommands(argvs, number_of_commands, all_pipes); | ||
Shell::WaitForAllCommands(number_of_commands); | ||
|
||
delete[] all_pipes; | ||
} | ||
|
||
exit(EXIT_SUCCESS); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#ifndef SHELL_HPP | ||
#define SHELL_HPP | ||
|
||
#include "parser.hpp" | ||
|
||
#include <sys/types.h> | ||
#include <unistd.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <errno.h> | ||
#include <stdlib.h> | ||
#include <stdbool.h> | ||
#include <sys/wait.h> | ||
|
||
const int READ = 0; | ||
const int WRITE = 1; | ||
const int MAX_BUFFER = 128; | ||
|
||
class Shell | ||
{ | ||
public: | ||
static void ForkError(); | ||
static void CloseError(); | ||
static void Execute(char *argv[], int number_of_commands, int read_pipe[2], int write_pipe[2], int all_pipes[][2]); | ||
static void ExecuteCommands(char *argvs[MAX_COMMANDS][MAX_ARGV], const size_t &number_of_commands, int all_pipes[][2]); | ||
static void GetLine(char *buffer, size_t size); | ||
static void WaitForAllCommands(const size_t& n); | ||
static void Run(); | ||
static void InitializePipes(int all_pipes[][2], const size_t &number_of_commands); | ||
static void ClosePipes(int all_pipes[][2], const size_t &number_of_commands); | ||
}; | ||
|
||
#endif |