|
#include "kernel/types.h" |
|
#include "user/user.h" |
|
#include "kernel/fcntl.h" |
|
|
|
#define false 0 |
|
#define true 1 |
|
#define STDOUT_FILENO 0 |
|
#define STDIN_FILENO 1 |
|
|
|
typedef enum{ |
|
WRITE = 1, |
|
APPEND, |
|
READ |
|
} redirect; |
|
|
|
struct cmd { |
|
char** argv; |
|
int argc; |
|
}; |
|
|
|
// Will return a string representing the part until the sep |
|
char* get_left(char *initial_string, char sep) { |
|
int i = 0; |
|
while(initial_string[i] != sep && initial_string[i] != '\0') |
|
i++; |
|
|
|
char *first_word = (char*) malloc((i + 1) * sizeof(char)); |
|
|
|
i = 0; |
|
while(initial_string[i] != sep && initial_string[i] != '\0'){ |
|
first_word[i] = initial_string[i]; |
|
i++; |
|
} |
|
first_word[i] = '\0'; |
|
|
|
return first_word; |
|
} // get_left |
|
|
|
// Will return a string representing the part after the sep |
|
char* get_right(char *initial_string, char sep) { |
|
int start = 0; |
|
int i; |
|
|
|
while (initial_string[start] != sep && initial_string[start] != '\0') |
|
start++; |
|
i = start + 1; |
|
while (i < strlen(initial_string) && initial_string[i] != '\0') |
|
i++; |
|
|
|
char *first_word = (char*) malloc((i - start + 1) * sizeof(char)); |
|
|
|
i = 0; |
|
while (i + start + 1 < strlen(initial_string) && initial_string[i + start + 1] != '\0'){ |
|
first_word[i] = initial_string[i + start + 1]; |
|
i++; |
|
} |
|
first_word[i] = '\0'; |
|
|
|
return first_word; |
|
} // get_right |
|
|
|
// This functuon will return an enum value representing what kind of |
|
// redirection we have to process |
|
int is_redirection(char *string){ |
|
int higher = 0; |
|
int smaller = 0; |
|
|
|
for(int i = 0; i < strlen(string); i++){ |
|
if (string[i] == '<') |
|
smaller++; |
|
else if(string[i] == '>') |
|
higher++; |
|
} |
|
|
|
if(smaller == 0 && higher == 1) |
|
return WRITE; |
|
else if(smaller == 0 && higher == 2) |
|
return APPEND; |
|
else if(smaller == 1 && higher == 0) |
|
return READ; |
|
|
|
return 0; |
|
} // is_redirection |
|
|
|
// This function will return the number of times a chr is in a string |
|
int number_of_chr(char *string, char chr){ |
|
int s = 0; |
|
for(int i = 0; i < strlen(string); i++) |
|
if (string[i] == chr) |
|
s++; |
|
return s; |
|
} // number_of_chr |
|
|
|
// This function will return the first part of a redirection |
|
char* get_first_redirection(char *string){ |
|
int i = 0; |
|
|
|
while(string[i] != '<' && string[i] != '>') |
|
i++; |
|
|
|
char *new_string = (char*) malloc((i + 1) * sizeof(char)); |
|
|
|
i = 0; |
|
while(string[i] != '<' && string[i] != '>'){ |
|
new_string[i] = string[i]; |
|
i++; |
|
} |
|
new_string[i] = '\0'; |
|
|
|
return new_string; |
|
} // get_first_redirection |
|
|
|
// This function will return the second part of a redirection |
|
char* get_last_redirection(char *string){ |
|
int i = 0; |
|
int start = 0; |
|
|
|
while(string[start] != '<' && string[start] != '>') |
|
start++; |
|
|
|
// In case we have to append |
|
if(string[start + 1] == '>') |
|
start++; |
|
|
|
// In case we have a spaces after the redirection character |
|
while (string[start + 1] == ' ') |
|
start++; |
|
|
|
i = start + 1; |
|
|
|
while (string[i] != '\0') |
|
i++; |
|
|
|
char *new_string = (char*) malloc((i - start + 1) * sizeof(char)); |
|
|
|
i = 0; |
|
while (string[i + start + 1] != '\0'){ |
|
new_string[i] = string[i + start + 1]; |
|
i++; |
|
} |
|
|
|
new_string[i] = '\0'; |
|
return new_string; |
|
} // get_last_redirection |
|
|
|
// This function will make a cmd struct out of a string |
|
struct cmd parse_command(char *string) { |
|
struct cmd command; |
|
|
|
// Eliminate the spaces at the end of the string |
|
int i = strlen(string) - 1; |
|
while(string[i] == ' ') |
|
i--; |
|
string[i + 1] = '\0'; |
|
|
|
// Elininate the spaces at the start of the string |
|
i = 0; |
|
while(string[i++] == ' ') |
|
string++; |
|
|
|
if(strlen(get_right(string, ' ')) > 0){ |
|
command.argv = (char**) malloc(3 * sizeof(char*)); |
|
command.argc = 2; |
|
command.argv[0] = get_left(string, ' '); |
|
command.argv[1] = get_right(string, ' '); |
|
i = 0;// Eliminate the spaces at the start of the arguments |
|
while(string[i++] == ' ') |
|
command.argv[1]++; |
|
command.argv[2] = 0; |
|
} |
|
else{ |
|
command.argv = (char**) malloc(2 * sizeof(char*)); |
|
command.argc = 1; |
|
command.argv[0] = get_left(string, ' '); |
|
command.argv[1] = 0; |
|
} |
|
|
|
return command; |
|
} // parse_command |
|
|
|
// This function will make a list of lipes into an array of struct cmds |
|
struct cmd* parse_more_pipes(char *string) { |
|
int i; |
|
int n = number_of_chr(string, '|') + 1; |
|
struct cmd *command = (struct cmd*) malloc(n * sizeof(struct cmd)); |
|
|
|
for(i = 0; i < n - 1; i++) { |
|
command[i] = parse_command(get_left(string, '|')); |
|
string = get_right(string, '|'); |
|
} |
|
command[i] = parse_command(string); |
|
|
|
return command; |
|
} // parse_more_pipes |
|
|
|
// This function will process a simple command |
|
void process_command(char *string) { |
|
struct cmd command = parse_command(string); |
|
|
|
if (strcmp(command.argv[0], "cd") == 0){ |
|
chdir(command.argv[1]); |
|
} |
|
else if (strcmp(command.argv[0], "exit") == 0){ |
|
exit(0); |
|
} |
|
else if (strlen(command.argv[0]) > 0){ |
|
if (fork() == 0) { |
|
exec(command.argv[0], command.argv); |
|
} |
|
else { |
|
wait(0); |
|
} |
|
} |
|
|
|
for (int i = 0; i < command.argc; i++) |
|
free(command.argv[i]); |
|
free(command.argv); |
|
} // process_command |
|
|
|
// This function will exec a command with pipes |
|
void make_pipe(int *in, int *out, struct cmd *command) { |
|
if (fork() == 0) { |
|
if (*in != STDOUT_FILENO) { |
|
close(STDOUT_FILENO); |
|
dup(*in); |
|
close (*in); |
|
} |
|
if (*out != STDIN_FILENO) { |
|
close(STDIN_FILENO); |
|
dup(*out); |
|
close (*out); |
|
} |
|
|
|
exec(command->argv[0], command->argv); |
|
} |
|
} // make_pipe |
|
|
|
// This function will process more pipe processes |
|
void process_pipes(char *string) { |
|
int in; |
|
int p[2]; |
|
int i; |
|
int j; |
|
int n = number_of_chr(string, '|') + 1; // when we have 3 '|', |
|
// the function will return 2, therefore we have 2 + 1 pipes |
|
|
|
struct cmd *command = parse_more_pipes(string); |
|
in = STDOUT_FILENO; |
|
|
|
for (i = 0; i < n - 1; ++i){ |
|
pipe(p); |
|
|
|
make_pipe(&in, &p[1], &command[i]); |
|
|
|
close(p[1]); |
|
|
|
in = p[0]; |
|
} |
|
|
|
if (in != STDOUT_FILENO) { |
|
close(STDOUT_FILENO); |
|
dup(in); |
|
} |
|
|
|
exec(command[i].argv[0], command[i].argv); |
|
|
|
// Free the data |
|
for (i = 0; i < n ; i++){ |
|
for (j = 0; j < command[i].argc; j++) |
|
free(command[i].argv[j]); |
|
free(command[i].argv); |
|
} |
|
free(command); |
|
} // process_pipes |
|
|
|
// This function will process a redirection process |
|
void process_redirection(char *string){ |
|
char *left = get_first_redirection(string); |
|
char *file_name = get_last_redirection(string); |
|
struct cmd command = parse_command(left); |
|
int i; |
|
|
|
switch(is_redirection(string)){ |
|
case WRITE: |
|
if (fork() == 0){ |
|
close(1); |
|
open(file_name, O_WRONLY|O_CREATE|O_TRUNC); |
|
exec(command.argv[0], command.argv); |
|
} |
|
else{ |
|
wait(0); |
|
} |
|
break; |
|
|
|
case READ: |
|
if (fork() == 0) { |
|
close(0); |
|
open(file_name, O_RDONLY); |
|
exec(command.argv[0], command.argv); |
|
} |
|
else { |
|
wait(0); |
|
} |
|
break; |
|
|
|
default: |
|
free(left); |
|
free(file_name); |
|
for(i = 0; i < command.argc; i++) |
|
free(command.argv[i]); |
|
free(command.argv); |
|
break; |
|
} |
|
} // process_redirection |
|
|
|
// This function will process pipes and redirections |
|
void process_pipe_and_redirection(char *string) { |
|
int i = 0, j; |
|
int p[2]; |
|
int in; |
|
int n = number_of_chr(string, '|') + 1; |
|
struct cmd *command; |
|
|
|
char *left = 0; |
|
char *right = 0; |
|
|
|
left = get_first_redirection(string); |
|
right = get_last_redirection(string); |
|
|
|
command = parse_more_pipes(left); |
|
|
|
in = STDIN_FILENO; |
|
|
|
for (i = 0; i < n - 1; ++i){ |
|
pipe(p); |
|
|
|
make_pipe(&in, &p[1], &command[i]); |
|
|
|
close(p[1]); |
|
|
|
in = p[0]; |
|
} |
|
|
|
if (in != STDOUT_FILENO) { |
|
close(STDOUT_FILENO); |
|
dup(in); |
|
} |
|
|
|
close(STDIN_FILENO); |
|
open(right, O_WRONLY|O_CREATE|O_TRUNC); |
|
exec(command[n - 1].argv[0], command[n -1].argv); |
|
|
|
// Free the data |
|
for (i = 0; i < n ; i++){ |
|
for (j = 0; j < command[i].argc; j++) |
|
free(command[i].argv[j]); |
|
free(command[i].argv); |
|
} |
|
free(command); |
|
free(left); |
|
free(right); |
|
} // process_pipe_and_redirection |
|
|
|
int main(int argc, char *argv[]) { |
|
char *command = (char*) malloc(300 * sizeof(char)); |
|
char *small_command; |
|
int n; |
|
|
|
while (true) { |
|
printf(">>>"); |
|
gets (command, 300); |
|
command[strlen(command) - 1] = '\0'; |
|
|
|
// Will go through all the commands that are parsed by ';' |
|
n = number_of_chr(command, ';'); |
|
for (int i = 0 ; i <= n; i++){ |
|
small_command = get_left(command, ';'); |
|
command = get_right(command, ';'); |
|
|
|
if ((number_of_chr(small_command, '>') || number_of_chr(small_command, '<')) |
|
&& number_of_chr(small_command, '|')) { |
|
if(fork() == 0) { |
|
process_pipe_and_redirection(small_command); |
|
} |
|
else { |
|
wait(0); |
|
} |
|
} |
|
else if (is_redirection(small_command)){ |
|
process_redirection(small_command); |
|
} |
|
else if (number_of_chr(small_command, '|') > 0) { |
|
if (fork() == 0){ |
|
process_pipes(small_command); |
|
} |
|
else { |
|
wait(0); |
|
} |
|
} |
|
else{ |
|
process_command(small_command); |
|
} |
|
|
|
free(small_command); |
|
} |
|
free(command); |
|
} // while |
|
|
|
exit(0); |
|
} // main |