Skip to content

Instantly share code, notes, and snippets.

@SungjinYoo
Created November 13, 2014 12:06
Show Gist options
  • Save SungjinYoo/e8c75be281268d0d32ee to your computer and use it in GitHub Desktop.
Save SungjinYoo/e8c75be281268d0d32ee to your computer and use it in GitHub Desktop.
//
// 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;
}
//
// 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;
}
//
// 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