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
Branches
No related tags found
No related merge requests found
File added
......@@ -9,6 +9,16 @@
#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) {
if (cmd_line == NULL || cmd_buff == NULL) {
return ERR_CMD_OR_ARGS_TOO_BIG;
......@@ -19,175 +29,194 @@ int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) {
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->_cmd_buffer = original_line;
char *saveptr1;
char *token = strtok_r(trimmed_line, " ", &saveptr1);
while (token != NULL && cmd_buff->argc < CMD_ARGV_MAX) {
if (token[0] == '"' || token[0] == '\'') {
char *end_quote = strchr(token + 1, token[0]);
if (end_quote != NULL) {
*end_quote = '\0';
cmd_buff->argv[cmd_buff->argc++] = token + 1;
token = strtok_r(NULL, " ", &saveptr1);
continue;
char *ptr = original_line;
char *arg_start = NULL;
bool in_quotes = false;//For quotes
char quote_char = '\0';
while (*ptr != '\0') {
if ((isspace((unsigned char)*ptr) && !in_quotes)) {
if (arg_start != NULL) {
*ptr = '\0';
cmd_buff->argv[cmd_buff->argc++] = arg_start;
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) {
int num_commands = cmd_list->num;
int pipefd[2];
int prev_pipe_read = -1;
pid_t pids[num_commands];
// Debugging output to verify parsing
// printf("Parsed command:\n");
// for (int i = 0; i < cmd_buff->argc; i++) {
// printf(" argv[%d]: %s\n", i, cmd_buff->argv[i]);
// }
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) {
if (prev_pipe_read != -1) {
dup2(prev_pipe_read, STDIN_FILENO);
close(prev_pipe_read);
return OK;
}
if (i < num_commands - 1) {
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
close(pipefd[0]);
}
char *trim_whitespace(char *str) { //Had to make a new function for readability
char *end;
if (prev_pipe_read != -1) {
close(prev_pipe_read);
}
while (isspace((unsigned char)*str)) str++;
cmd_buff_t *cmd = &cmd_list->commands[i];
if (*str == 0) // All spaces?
return str;
if (cmd->argv[0] == NULL) {
fprintf(stderr, "execvp error: command is NULL\n");
exit(ERR_EXEC_CMD);
}
// Trim trailing space
end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end)) end--;
execvp(cmd->argv[0], cmd->argv);
// new null terminator
*(end + 1) = '\0';
perror("execvp");
exit(ERR_EXEC_CMD);
} else {
if (prev_pipe_read != -1) {
close(prev_pipe_read);
return str;
}
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 buffer[1024];
ssize_t bytes_read;
while ((bytes_read = read(prev_pipe_read, buffer, sizeof(buffer) - 1)) > 0) {
buffer[bytes_read] = '\0';
printf("%s", buffer);
char *line_copy = strdup(cmd_line);
if (line_copy == NULL) {
return ERR_MEMORY;
}
if (bytes_read < 0) {
perror("read");
//Parsing using pipe.
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++) {
waitpid(pids[i], NULL, 0);
clist->num++;
command = strtok_r(NULL, "|", &saveptr);
}
free(line_copy);
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);
if (original_line == NULL) {
// Fork processes for each command
for (int i = 0; i < num_commands; i++) {
pids[i] = fork();
if (pids[i] == -1) {
perror("fork");
return ERR_MEMORY;
}
char *trimmed_line = original_line;
while (*trimmed_line == ' ') {
trimmed_line++;
if (pids[i] == 0) { // Child process
// if not first moves input
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;
char *saveptr1, *saveptr2;
char *command = strtok_r(trimmed_line, PIPE_STRING, &saveptr1);
// Redirect output if not the last command
if (i < num_commands - 1) {
if (dup2(pipefd[2 * i + 1], STDOUT_FILENO) == -1) {
perror("dup2 stdout");
exit(EXIT_FAILURE);
}
}
while (command != NULL && command_count < CMD_MAX) {
memset(&clist->commands[command_count], 0, sizeof(cmd_buff_t));
// Close all pipe file descriptors. Very important stuff
for (int j = 0; j < 2 * (num_commands - 1); j++) {
close(pipefd[j]);
}
char *token = strtok_r(command, " ", &saveptr2);
if (token != NULL) {
int arg_count = 0;
while (token != NULL && arg_count < CMD_ARGV_MAX - 1) {
clist->commands[command_count].argv[arg_count] = token;
arg_count++;
token = strtok_r(NULL, " ", &saveptr2);
// Execute the command
execvp(clist->commands[i].argv[0], clist->commands[i].argv);
perror("execvp");
exit(EXIT_FAILURE);
}
clist->commands[command_count].argv[arg_count] = NULL;
}
command_count++;
command = strtok_r(NULL, PIPE_STRING, &saveptr1);
// Closes all pipe
for (int i = 0; i < 2 * (num_commands - 1); i++) {
close(pipefd[i]);
}
if (command != NULL) {
free(original_line);
return ERR_TOO_MANY_COMMANDS;
// waitpid so everyhting is smooth
for (int i = 0; i < num_commands; i++) {
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;
}
int exec_local_cmd_loop() {
char cmd_buff[SH_CMD_MAX];
int rc = OK;
......@@ -216,11 +245,11 @@ int exec_local_cmd_loop() {
continue;
}
if (execute_pipeline(&cmd_list) != OK) {
fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
rc = ERR_MEMORY;
}
// Execute the pipeline
execute_pipeline(&cmd_list);
// Free memory for each command's buffer
for (int i = 0; i < cmd_list.num; i++) {
free(cmd_list.commands[i]._cmd_buffer);
}
......@@ -276,3 +305,4 @@ int exec_local_cmd_loop() {
return rc;
}
......@@ -4,11 +4,53 @@
#
# 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
ls
sleep 2 &
jobs
exit
EOF
# Assertions
[ "$status" -eq 0 ]
[[ "$output" == *"sleep 2 &"* ]]
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment