Skip to content
Snippets Groups Projects
Commit 033c3c13 authored by jl4589's avatar jl4589
Browse files

Fixed error and made the first assignment_test work

parent 04501785
No related branches found
No related tags found
No related merge requests found
File added
...@@ -9,6 +9,16 @@ ...@@ -9,6 +9,16 @@
#include "dshlib.h" #include "dshlib.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <unistd.h>
#include "dshlib.h"
//
int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) { int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) {
if (cmd_line == NULL || cmd_buff == NULL) { if (cmd_line == NULL || cmd_buff == NULL) {
return ERR_CMD_OR_ARGS_TOO_BIG; return ERR_CMD_OR_ARGS_TOO_BIG;
...@@ -19,175 +29,194 @@ int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) { ...@@ -19,175 +29,194 @@ int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) {
return ERR_MEMORY; return ERR_MEMORY;
} }
char *trimmed_line = original_line;
while (*trimmed_line == ' ') {
trimmed_line++;
}
size_t len = strlen(trimmed_line);
while (len > 0 && trimmed_line[len - 1] == ' ') {
trimmed_line[--len] = '\0';
}
cmd_buff->argc = 0; cmd_buff->argc = 0;
cmd_buff->_cmd_buffer = original_line; cmd_buff->_cmd_buffer = original_line;
char *saveptr1; char *ptr = original_line;
char *token = strtok_r(trimmed_line, " ", &saveptr1); char *arg_start = NULL;
bool in_quotes = false;//For quotes
while (token != NULL && cmd_buff->argc < CMD_ARGV_MAX) { char quote_char = '\0';
if (token[0] == '"' || token[0] == '\'') {
char *end_quote = strchr(token + 1, token[0]); while (*ptr != '\0') {
if (end_quote != NULL) { if ((isspace((unsigned char)*ptr) && !in_quotes)) {
*end_quote = '\0'; if (arg_start != NULL) {
cmd_buff->argv[cmd_buff->argc++] = token + 1; *ptr = '\0';
token = strtok_r(NULL, " ", &saveptr1); cmd_buff->argv[cmd_buff->argc++] = arg_start;
continue; arg_start = NULL;
}
} else if (*ptr == '"' || *ptr == '\'') {
if (in_quotes && *ptr == quote_char) {
in_quotes = false;
quote_char = '\0';
*ptr = '\0'; // End the argument at the closing quote
} else if (!in_quotes) {
in_quotes = true;
quote_char = *ptr;
arg_start = ptr + 1; // Start the argument after the opening quote
} }
} else {
if (arg_start == NULL) {
arg_start = ptr;
} }
cmd_buff->argv[cmd_buff->argc++] = token;
token = strtok_r(NULL, " ", &saveptr1);
} }
cmd_buff->argv[cmd_buff->argc] = NULL; ptr++;
}
return OK; if (arg_start != NULL) {
cmd_buff->argv[cmd_buff->argc++] = arg_start;
} }
cmd_buff->argv[cmd_buff->argc] = NULL;
int execute_pipeline(command_list_t *cmd_list) { // Debugging output to verify parsing
int num_commands = cmd_list->num; // printf("Parsed command:\n");
int pipefd[2]; // for (int i = 0; i < cmd_buff->argc; i++) {
int prev_pipe_read = -1; // printf(" argv[%d]: %s\n", i, cmd_buff->argv[i]);
pid_t pids[num_commands]; // }
for (int i = 0; i < num_commands; i++) {
if (i < num_commands - 1) {
if (pipe(pipefd) == -1) {
perror("pipe");
return ERR_MEMORY;
}
}
pids[i] = fork();
if (pids[i] == -1) {
perror("fork");
return ERR_MEMORY;
}
if (pids[i] == 0) { return OK;
if (prev_pipe_read != -1) {
dup2(prev_pipe_read, STDIN_FILENO);
close(prev_pipe_read);
} }
if (i < num_commands - 1) { char *trim_whitespace(char *str) { //Had to make a new function for readability
dup2(pipefd[1], STDOUT_FILENO); char *end;
close(pipefd[1]);
close(pipefd[0]);
}
if (prev_pipe_read != -1) { while (isspace((unsigned char)*str)) str++;
close(prev_pipe_read);
}
cmd_buff_t *cmd = &cmd_list->commands[i]; if (*str == 0) // All spaces?
return str;
if (cmd->argv[0] == NULL) { // Trim trailing space
fprintf(stderr, "execvp error: command is NULL\n"); end = str + strlen(str) - 1;
exit(ERR_EXEC_CMD); while (end > str && isspace((unsigned char)*end)) end--;
}
execvp(cmd->argv[0], cmd->argv); // new null terminator
*(end + 1) = '\0';
perror("execvp"); return str;
exit(ERR_EXEC_CMD);
} else {
if (prev_pipe_read != -1) {
close(prev_pipe_read);
} }
if (i < num_commands - 1) {
prev_pipe_read = pipefd[0];
close(pipefd[1]);
} int parse_pipeline(const char *cmd_line, command_list_t *clist) {
} if (cmd_line == NULL || clist == NULL) {
return ERR_CMD_OR_ARGS_TOO_BIG;
} }
if (prev_pipe_read != -1) { char *line_copy = strdup(cmd_line);
char buffer[1024]; if (line_copy == NULL) {
ssize_t bytes_read; return ERR_MEMORY;
while ((bytes_read = read(prev_pipe_read, buffer, sizeof(buffer) - 1)) > 0) {
buffer[bytes_read] = '\0';
printf("%s", buffer);
} }
if (bytes_read < 0) { //Parsing using pipe.
perror("read"); clist->num = 0;
char *saveptr;
char *command = strtok_r(line_copy, "|", &saveptr);
while (command != NULL) {
if (clist->num >= CMD_MAX) {
free(line_copy);
return ERR_TOO_MANY_COMMANDS;
} }
close(prev_pipe_read);
cmd_buff_t *cmd_buff = &clist->commands[clist->num];
int result = build_cmd_buff(command, cmd_buff);
if (result != OK) {
free(line_copy);
return result;
} }
for (int i = 0; i < num_commands; i++) { clist->num++;
waitpid(pids[i], NULL, 0); command = strtok_r(NULL, "|", &saveptr);
} }
free(line_copy);
return OK; return OK;
} }
int execute_pipeline(command_list_t *clist) {
int num_commands = clist->num;
int pipefd[2 * (num_commands - 1)];
pid_t pids[num_commands];
// for (int i = 0; i < clist->num; i++) {
// printf("Command %d:\n", i);
// for (int j = 0; clist->commands[i].argv[j] != NULL; j++) {
// printf(" argv[%d]: %s\n", j, clist->commands[i].argv[j]);
// }
// }
int parse_pipeline(char *cmd_line, command_list_t *clist) {
if (cmd_line == NULL || clist == NULL) {
return ERR_CMD_OR_ARGS_TOO_BIG;
for (int i = 0; i < num_commands - 1; i++) {
if (pipe(pipefd + 2 * i) == -1) {
perror("pipe");
return ERR_MEMORY;
}
} }
char *original_line = strdup(cmd_line); // Fork processes for each command
if (original_line == NULL) { for (int i = 0; i < num_commands; i++) {
pids[i] = fork();
if (pids[i] == -1) {
perror("fork");
return ERR_MEMORY; return ERR_MEMORY;
} }
char *trimmed_line = original_line; if (pids[i] == 0) { // Child process
while (*trimmed_line == ' ') { // if not first moves input
trimmed_line++; if (i > 0) {
if (dup2(pipefd[2 * (i - 1)], STDIN_FILENO) == -1) {
perror("dup2 stdin");
exit(EXIT_FAILURE);
} }
size_t len = strlen(trimmed_line);
while (len > 0 && trimmed_line[len - 1] == ' ') {
trimmed_line[--len] = '\0';
} }
int command_count = 0; // Redirect output if not the last command
char *saveptr1, *saveptr2; if (i < num_commands - 1) {
char *command = strtok_r(trimmed_line, PIPE_STRING, &saveptr1); if (dup2(pipefd[2 * i + 1], STDOUT_FILENO) == -1) {
perror("dup2 stdout");
exit(EXIT_FAILURE);
}
}
while (command != NULL && command_count < CMD_MAX) { // Close all pipe file descriptors. Very important stuff
memset(&clist->commands[command_count], 0, sizeof(cmd_buff_t)); for (int j = 0; j < 2 * (num_commands - 1); j++) {
close(pipefd[j]);
}
char *token = strtok_r(command, " ", &saveptr2); // Execute the command
if (token != NULL) { execvp(clist->commands[i].argv[0], clist->commands[i].argv);
int arg_count = 0; perror("execvp");
while (token != NULL && arg_count < CMD_ARGV_MAX - 1) { exit(EXIT_FAILURE);
clist->commands[command_count].argv[arg_count] = token;
arg_count++;
token = strtok_r(NULL, " ", &saveptr2);
} }
clist->commands[command_count].argv[arg_count] = NULL;
} }
command_count++; // Closes all pipe
command = strtok_r(NULL, PIPE_STRING, &saveptr1); for (int i = 0; i < 2 * (num_commands - 1); i++) {
close(pipefd[i]);
} }
if (command != NULL) { // waitpid so everyhting is smooth
free(original_line); for (int i = 0; i < num_commands; i++) {
return ERR_TOO_MANY_COMMANDS; int status;
waitpid(pids[i], &status, 0);
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
fprintf(stderr, "Command %d exited with status %d\n", i, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "Command %d terminated by signal %d\n", i, WTERMSIG(status));
}
} }
clist->num = command_count;
free(original_line);
return OK; return OK;
} }
int exec_local_cmd_loop() { int exec_local_cmd_loop() {
char cmd_buff[SH_CMD_MAX]; char cmd_buff[SH_CMD_MAX];
int rc = OK; int rc = OK;
...@@ -216,11 +245,11 @@ int exec_local_cmd_loop() { ...@@ -216,11 +245,11 @@ int exec_local_cmd_loop() {
continue; continue;
} }
if (execute_pipeline(&cmd_list) != OK) { // Execute the pipeline
fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
rc = ERR_MEMORY;
}
execute_pipeline(&cmd_list);
// Free memory for each command's buffer
for (int i = 0; i < cmd_list.num; i++) { for (int i = 0; i < cmd_list.num; i++) {
free(cmd_list.commands[i]._cmd_buffer); free(cmd_list.commands[i]._cmd_buffer);
} }
...@@ -276,3 +305,4 @@ int exec_local_cmd_loop() { ...@@ -276,3 +305,4 @@ int exec_local_cmd_loop() {
return rc; return rc;
} }
...@@ -4,11 +4,53 @@ ...@@ -4,11 +4,53 @@
# #
# Create your unit tests suit in this file # Create your unit tests suit in this file
@test "Example: check ls runs without errors" {
# Test pipeline: 'echo' output piped to 'grep'
@test "Test echo output piped to grep" {
run ./dsh <<EOF
echo "Hello World" | grep "World"
exit
EOF
# Assertions
[ "$status" -eq 0 ]
[[ "$output" == *"Hello World"* ]]
}
# Test pipeline with multiple commands: 'ls' piped to 'grep' and then to 'wc -l'
@test "Test ls piped to grep and wc -l" {
run ./dsh <<EOF
ls | grep "student_tests.sh" | wc -l
exit
EOF
# Assertions
[ "$status" -eq 0 ]
[[ "$output" -eq 1 ]]
}
# Test redirection: output of 'echo' redirected to a file
@test "Test output redirection to a file" {
run ./dsh <<EOF
echo "Test Output" > test_output.txt
cat test_output.txt
exit
EOF
# Assertions
[ "$status" -eq 0 ]
[[ "$output" == *"Test Output"* ]]
}
# Test background execution: 'sleep' command in the background
@test "Test background execution of sleep command" {
run ./dsh <<EOF run ./dsh <<EOF
ls sleep 2 &
jobs
exit
EOF EOF
# Assertions # Assertions
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
[[ "$output" == *"sleep 2 &"* ]]
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment