Created
November 13, 2014 12:06
-
-
Save SungjinYoo/e8c75be281268d0d32ee to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// | |
// command.c | |
// minishell | |
// | |
// Created by SungJinYoo on 11/10/14. | |
// Copyright (c) 2014 SungJinYoo. All rights reserved. | |
// | |
#include "command.h" | |
#include <string.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
struct SimpleCommand* parse_simple_command(const char* simple_command_string) | |
{ | |
char* input_string = NULL; | |
char* param_string = NULL; | |
char* param_list[128]; | |
int param_count = 0; | |
int i = 0; | |
struct SimpleCommand* simple_command = NULL; | |
if(simple_command_string == NULL) return NULL; | |
input_string = strdup(simple_command_string); | |
while((param_string = strsep(&input_string, " ")) != NULL){ | |
char* newline_pos = NULL; | |
if(strcmp(param_string, "") == 0 || strcmp(param_string, "\n") == 0) continue; | |
newline_pos = strrchr(param_string, '\n');// trim last \n | |
if(newline_pos != NULL) newline_pos[0] = '\0'; | |
param_list[param_count++] = param_string; | |
} | |
simple_command = malloc(sizeof(struct SimpleCommand)); | |
simple_command->param_list = malloc(sizeof(char*) * (param_count + 1)); | |
for(i = 0; i < param_count; i++){ | |
simple_command->param_list[i] = strdup(param_list[i]); | |
} | |
simple_command->param_list[param_count] = NULL; | |
simple_command->param_count = param_count; | |
return simple_command; | |
} | |
struct Queue* parse_input_string(const char* input_string) | |
{ | |
char* input_string_dup = NULL; | |
char* command_string = NULL; | |
struct Queue* command_queue = queue_create(); | |
input_string_dup = strdup(input_string); | |
while((command_string = strsep(&input_string_dup, ";")) != NULL){ | |
if(strcmp(command_string, "") == 0 || strcmp(command_string, "\n") == 0) continue; | |
struct Command* command = malloc(sizeof(struct Command)); | |
command->pipeline = parse_pipeline(command_string); | |
queue_enqueue(command_queue, command); | |
} | |
return command_queue; | |
} | |
struct Pipeline* parse_pipeline(const char* pipeline_string) | |
{ | |
char* input_string = NULL; | |
char* command_string = NULL; | |
char* amp_found_point = NULL; | |
struct Pipeline* pipeline = malloc(sizeof(struct Pipeline)); | |
pipeline->run_in_background = FALSE; | |
pipeline->redirection_list = queue_create(); | |
amp_found_point = strrchr(pipeline_string, '&'); | |
if(amp_found_point){ | |
pipeline->run_in_background = TRUE; | |
amp_found_point[0] = '\0'; | |
} | |
input_string = strndup(pipeline_string, strlen(pipeline_string)); | |
while ((command_string = strsep(&input_string, "|")) != NULL){ | |
queue_enqueue(pipeline->redirection_list, parse_redirection(command_string)); | |
} | |
return pipeline; | |
} | |
struct Redirection* parse_redirection(const char* redirection_string) | |
{ | |
char* input_string = NULL; | |
char* found_string_position = NULL; | |
char* src = NULL; | |
char* dest = NULL; | |
struct Redirection* redirection = malloc(sizeof(struct Redirection)); | |
redirection->is_write = TRUE; | |
redirection->check_exists = FALSE; | |
redirection->override = FALSE; | |
input_string = strdup(redirection_string); | |
if((found_string_position = strchr(input_string, '>')) != NULL){ | |
if(strlen(found_string_position) > 2 && found_string_position[1] == '!'){ // >! | |
src = strsep(&input_string, ">!"); // get rid of > and get src command | |
strsep(&input_string, ">!"); // get rid of ! | |
dest = input_string; // get dest filename | |
redirection->check_exists = TRUE; | |
} | |
else if(strlen(found_string_position) > 2 && found_string_position[1] == '>'){ // >> | |
src = strsep(&input_string, ">"); // get rid of > and get src command | |
strsep(&input_string, ">>"); // get rid of another > | |
dest = input_string; // get dest filename | |
} | |
else{ // > | |
src = strsep(&input_string, ">"); | |
dest = strsep(&input_string, ">"); | |
redirection->override = TRUE; | |
} | |
} | |
else if((found_string_position = strrchr(input_string, '<')) != NULL){ // < | |
dest = strsep(&input_string, "<"); | |
src = strsep(&input_string, "<"); | |
redirection->override = TRUE; | |
redirection->is_write = FALSE; | |
} | |
else{ | |
dest = input_string; | |
} | |
redirection->src = parse_simple_command(src); | |
redirection->dest = parse_simple_command(dest); | |
return redirection; | |
} |
This file contains hidden or 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
// | |
// list.c | |
// minishell | |
// | |
// Created by SungJinYoo on 11/8/14. | |
// Copyright (c) 2014 SungJinYoo. All rights reserved. | |
// | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include "list.h" | |
struct List* list_create() | |
{ | |
struct List* list = malloc(sizeof(struct List)); | |
list->length = 0; | |
return list; | |
} | |
void list_push_front(struct List* list, void* item) | |
{ | |
struct Node* node = malloc(sizeof(struct Node)); | |
node->item = item; | |
if(list->head == NULL){ | |
list->head = node; | |
list->tail = node; | |
} | |
else{ | |
node->next = list->head; | |
node->next->prev = node; | |
list->head = node; | |
} | |
list->length++; | |
} | |
struct Node* list_pop_front(struct List* list) | |
{ | |
if(list_is_empty(list)) return NULL; | |
struct Node* origin_head = list->head; | |
struct Node* new_head = origin_head->next; | |
if(new_head != NULL){ | |
new_head->prev = NULL; | |
} | |
list->head = new_head; | |
if(new_head == NULL){ | |
list->tail = NULL; | |
} | |
list->length--; | |
return origin_head; | |
} | |
void list_push_back(struct List* list, void* item) | |
{ | |
struct Node* node = malloc(sizeof(struct Node)); | |
node->item = item; | |
if(list->tail == NULL){ | |
list->head = node; | |
list->tail = node; | |
} | |
else{ | |
node->prev = list->tail; | |
node->prev->next = node; | |
list->tail = node; | |
} | |
list->length++; | |
} | |
struct Node* list_pop_back(struct List* list) | |
{ | |
if(list_is_empty(list)) return NULL; | |
struct Node* origin_tail = list->tail; | |
struct Node* new_tail = origin_tail->prev; | |
if(new_tail != NULL){ | |
new_tail->next = NULL; | |
} | |
list->tail = new_tail; | |
if(new_tail == NULL){ | |
list->head = NULL; | |
} | |
list->length--; | |
return origin_tail; | |
} | |
void list_delete(struct List* list) | |
{ | |
struct Node* node = list->head; | |
while(node != NULL){ | |
struct Node* next_node = node->next; | |
free(node->item); | |
free(node); | |
node = next_node; | |
} | |
free(list); | |
} | |
void list_node_delete(struct Node* node) | |
{ | |
free(node->item); | |
free(node); | |
} | |
void list_for_each(struct List* list, void function(struct Node*, int)) | |
{ | |
struct Node* node = list->head; | |
int node_index = 0; | |
while(node != NULL){ | |
struct Node* next_node = node->next; | |
function(node, node_index++); | |
node = next_node; | |
} | |
} | |
void queue_enqueue(struct Queue* queue, void* item) | |
{ | |
list_push_front(queue, item); | |
} | |
struct Node* queue_dequeue(struct Queue* queue) | |
{ | |
return list_pop_back(queue); | |
} | |
void queue_for_each(struct Queue* queue, void function(struct Node*, int)) | |
{ | |
struct Node* node = queue->tail; | |
int node_index = 0; | |
while(node != NULL){ | |
struct Node* next_node = node->prev; | |
function(node, node_index++); | |
node = next_node; | |
} | |
} | |
bool list_is_empty(struct List* list) | |
{ | |
return list->head == NULL; | |
} |
This file contains hidden or 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
// | |
// main.c | |
// minishell | |
// | |
// Created by SungJinYoo on 11/7/14. | |
// Copyright (c) 2014 SungJinYoo. All rights reserved. | |
// | |
#include <libgen.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include "types.h" | |
#include "list.h" | |
#include "command.h" | |
const size_t BUFFER_SIZE = 256; | |
struct Queue* _history_queue = NULL; | |
struct Queue* get_history_queue() | |
{ | |
if(_history_queue == NULL) | |
_history_queue = queue_create(); | |
return _history_queue; | |
} | |
void for_each_history_node(struct Node* history_node, int node_index) | |
{ | |
printf("%d: %s\n", node_index, (char*)history_node->item); | |
} | |
void append_history(char* history) | |
{ | |
struct Queue* history_queue = get_history_queue(); | |
queue_enqueue(history_queue, history); | |
} | |
void print_history() | |
{ | |
struct Queue* history_queue = get_history_queue(); | |
queue_for_each(history_queue, for_each_history_node); | |
} | |
void execute_simple_command(struct SimpleCommand* command) | |
{ | |
/* handle command history */ | |
if(strcmp(command->param_list[0], "history") == 0){ | |
print_history(); | |
} | |
/* handle command cd */ | |
else if(strcmp(command->param_list[0], "cd") == 0){ | |
if(command->param_count < 2){ | |
fprintf(stderr, "cd error\n"); | |
} | |
else{ | |
chdir(command->param_list[1]); | |
} | |
} | |
else{ | |
if(execvp(command->param_list[0], command->param_list) < 0) | |
fprintf(stderr, "execvp error\n"); | |
} | |
} | |
void execute_redirection(struct Redirection* redirection) | |
{ | |
struct SimpleCommand* command = redirection->dest; | |
if(redirection->src != NULL){ | |
if(redirection->is_write){ | |
int option = O_WRONLY|O_CREAT; | |
int fd = -1; | |
if(!redirection->override) option |= O_APPEND; | |
if(!redirection->check_exists) option |= O_CREAT; | |
if(redirection->check_exists && access(redirection->dest->param_list[0], F_OK ) != -1 ) { // check for file existence | |
// behavior of >! is if the file does not exists make a redirection | |
return; | |
} | |
fd = open(redirection->dest->param_list[0], option, 0644); | |
if(fd < 0){ | |
fprintf(stderr, "no such file : %s\n", redirection->dest->param_list[0]); | |
} | |
close(STDOUT_FILENO); | |
dup(fd); | |
command = redirection->src; | |
} | |
else{ | |
int fd = open(redirection->src->param_list[0], O_RDONLY, 0644); | |
close(STDIN_FILENO); | |
dup(fd); | |
command = redirection->dest; | |
} | |
} | |
execute_simple_command(command); | |
} | |
void for_each_command_node(struct Node* node, int node_index) | |
{ | |
int status; | |
struct Command* command = (struct Command*)node->item; | |
struct Pipeline* pipeline = command->pipeline; | |
pid_t pid; | |
if((pid = fork()) == 0) | |
{ | |
if(pipeline->redirection_list->length > 1) // use pipe | |
{ | |
int redirection_node_index = 0; | |
struct Node* redirection_node = pipeline->redirection_list->tail; | |
while(redirection_node_index < pipeline->redirection_list->length - 1) | |
{ | |
int pipe_fd[2]; | |
struct Node* next_node = redirection_node->prev; | |
if(pipe(pipe_fd) < 0) | |
{ | |
perror("pipe error\n"); | |
break; | |
} | |
if(fork() == 0) | |
{ | |
close(pipe_fd[0]); | |
close(STDOUT_FILENO); | |
dup(pipe_fd[1]); | |
execute_redirection((struct Redirection*)redirection_node->item); | |
} | |
close(pipe_fd[1]); | |
close(STDIN_FILENO); | |
dup(pipe_fd[0]); | |
redirection_node_index++; | |
redirection_node = next_node; | |
if(redirection_node_index == pipeline->redirection_list->length - 1){ | |
execute_redirection((struct Redirection*)redirection_node->item); | |
} | |
} | |
} | |
execute_redirection((struct Redirection*)pipeline->redirection_list->head->item); | |
} | |
if(!pipeline->run_in_background){ | |
waitpid(pid, &status, 0); | |
} | |
} | |
void print_shell_info() | |
{ | |
printf("System Programming minishell\n"); | |
} | |
void print_cwdir() | |
{ | |
char cwdir[BUFFER_SIZE]; | |
char* to_print = NULL; | |
getcwd(cwdir, BUFFER_SIZE); | |
to_print = strcat(basename(cwdir), "$ "); | |
write(STDOUT_FILENO, to_print, strlen(to_print)); | |
} | |
int main(int argc, const char * argv[]) | |
{ | |
char* input_buffer=(char*)malloc(BUFFER_SIZE); | |
ssize_t bytes_read = 0; | |
print_shell_info(); | |
print_cwdir(); | |
while((bytes_read = read(STDIN_FILENO, input_buffer, BUFFER_SIZE))) | |
{ | |
char* input_string = NULL; | |
struct Queue* command_queue = NULL; | |
struct Queue* history_queue = NULL; | |
if(bytes_read < 0) continue; | |
input_string = strndup(input_buffer, strlen(input_buffer) - 1); | |
if(strcmp(input_string, "exit") == 0) exit(EXIT_SUCCESS); | |
history_queue = get_history_queue(); | |
append_history(input_string); | |
command_queue = parse_input_string(input_string); | |
queue_for_each(command_queue, &for_each_command_node); | |
queue_delete(command_queue); | |
memset(input_buffer, 0, BUFFER_SIZE); | |
free(input_string); | |
fflush(stdin); | |
print_cwdir(); | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment