From ea9272dce3d0c9cf05610c4587feac2dde990aa9 Mon Sep 17 00:00:00 2001 From: cxb23 <cxb23@tux1.cci.drexel.edu> Date: Fri, 21 Feb 2025 23:55:10 -0500 Subject: [PATCH] finished assignment 4 --- 4-ShellP2/.dshlib.c.swp | Bin 0 -> 24576 bytes 4-ShellP2/bats/assignment_test.sh | 118 +++++++++++++ 4-ShellP2/bats/student_test.sh | 14 ++ 4-ShellP2/dragon.c | 37 ++++ 4-ShellP2/dragon.txt | 38 +++++ 4-ShellP2/dsh | Bin 0 -> 24968 bytes 4-ShellP2/dsh_cli.c | 13 ++ 4-ShellP2/dshlib.c | 275 ++++++++++++++++++++++++++++++ 4-ShellP2/dshlib.h | 85 +++++++++ 4-ShellP2/makefile | 31 ++++ 10 files changed, 611 insertions(+) create mode 100644 4-ShellP2/.dshlib.c.swp create mode 100644 4-ShellP2/bats/assignment_test.sh create mode 100644 4-ShellP2/bats/student_test.sh create mode 100644 4-ShellP2/dragon.c create mode 100644 4-ShellP2/dragon.txt create mode 100755 4-ShellP2/dsh create mode 100644 4-ShellP2/dsh_cli.c create mode 100644 4-ShellP2/dshlib.c create mode 100644 4-ShellP2/dshlib.h create mode 100644 4-ShellP2/makefile diff --git a/4-ShellP2/.dshlib.c.swp b/4-ShellP2/.dshlib.c.swp new file mode 100644 index 0000000000000000000000000000000000000000..7b1c66f6e023becd69f71d5ed390e4de36e131a8 GIT binary patch literal 24576 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 literal 0 HcmV?d00001 diff --git a/4-ShellP2/bats/assignment_test.sh b/4-ShellP2/bats/assignment_test.sh new file mode 100644 index 0000000..30b12ec --- /dev/null +++ b/4-ShellP2/bats/assignment_test.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bats + +############################ DO NOT EDIT THIS FILE ##################################### +# File: assignement_tests.sh +# +# DO NOT EDIT THIS FILE +# +# Add/Edit Student tests in student_tests.sh +# +# All tests in this file must pass - it is used as part of grading! +######################################################################################## + +@test "Change directory" { + current=$(pwd) + + cd /tmp + mkdir -p dsh-test + + run "${current}/dsh" <<EOF +cd dsh-test +pwd +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="/tmp/dsh-testdsh2>dsh2>dsh2>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + +@test "Change directory - no args" { + current=$(pwd) + + cd /tmp + mkdir -p dsh-test + + run "${current}/dsh" <<EOF +cd +pwd +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="/tmpdsh2>dsh2>dsh2>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + + +@test "Which which ... which?" { + run "./dsh" <<EOF +which which +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="/usr/bin/whichdsh2>dsh2>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] +} + +@test "It handles quoted spaces" { + run "./dsh" <<EOF + echo " hello world " +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '\t\n\r\f\v') + + # Expected output with all whitespace removed for easier matching + expected_output=" hello world dsh2> dsh2> cmd loop returned 0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] +} diff --git a/4-ShellP2/bats/student_test.sh b/4-ShellP2/bats/student_test.sh new file mode 100644 index 0000000..638bc34 --- /dev/null +++ b/4-ShellP2/bats/student_test.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bats + +# File: student_tests.sh +# +# Create your unit tests suit in this file + +@test "Example: check ls runs without errors" { + run ./dsh <<EOF +ls +EOF + + # Assertions + [ "$status" -eq 0 ] +} diff --git a/4-ShellP2/dragon.c b/4-ShellP2/dragon.c new file mode 100644 index 0000000..b5ac87f --- /dev/null +++ b/4-ShellP2/dragon.c @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdlib.h> +#include "dshlib.h" + +// EXTRA CREDIT - print the drexel dragon from the readme.md +extern void print_dragon(){ + // TODO implement + FILE *dragon = fopen("dragon.txt", "r"); + if (dragon == NULL) { + return; + } + + char *s = NULL; + size_t nbyte; + ssize_t nchar; + + while (1) { + nchar = getline(&s, &nbyte, dragon); + if (nchar == -1) { // end of file reached + break; + } + if (nchar == 0) { + continue; + } + if (s == NULL) { // out of memory + exit(1); + } + if (s[nchar - 1] == '\n') { + s[nchar - 1] = '\0'; // remove newline + nchar--; // newline removed + } + + printf("%s\n", s); + } + free(s); + fclose(dragon); +} diff --git a/4-ShellP2/dragon.txt b/4-ShellP2/dragon.txt new file mode 100644 index 0000000..a9177fd --- /dev/null +++ b/4-ShellP2/dragon.txt @@ -0,0 +1,38 @@ + @%%%% + %%%%%% + %%%%%% + % %%%%%%% @ + %%%%%%%%%% %%%%%%% + %%%%%%% %%%%@ %%%%%%%%%%%%@ %%%%%% @%%%% + %%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%% %%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%% %%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%@ @%%%%%%%%%%%%%%%%%% %% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%@ + %%%%%%%%@ %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%% %% + %%%%%%%%%%%%% %%@%%%%%%%%%%%% %%%%%%%%%%% %%%%%%%%%%%% @% + %%%%%%%%%% %%% %%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%% % %%%%%%%%%%%%% %%%%%%%%%%%%@%%%%%%%%%%% +%%%%%%%%%@ % %%%%%%%%%%%%% @%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%@ %%@%%%%%%%%%%%% @%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%@ %%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% +%%%%%%%%%@ @%%%%%%%%%%%%%% %%%%%%%%%%%%@ %%%% %%%%%%%%%%%%%%%%% %%%%%%%% +%%%%%%%%%% %%%%%%%%%%%%%%%%% %%%%%%%%%%%%% %%%%%%%%%%%%%%%%%% %%%%%%%%% +%%%%%%%%%@%%@ %%%%%%%%%%%%%%%%@ %%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%% %% + %%%%%%%%%% % %%%%%%%%%%%%%%@ %%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%% %% + %%%%%%%%%%%% @ %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% + %%%%%%%%%%%%% %% % %@ %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% + %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%% @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% + @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%% %%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%% @%%%%%%%%% + %%%%%%%%%%%%%%%%%%%% @%@% @%%%%%%%%%%%%%%%%%% %%% + %%%%%%%%%%%%%%% %%%%%%%%%% %%%%%%%%%%%%%%% % + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%% %%%% %%% %%%%%%%%%% %%%@ + %%%%%%%%%%%%%%%%%%% %%%%%% %% %%%%%%%%%%%%%@ + %%%%%%%@ diff --git a/4-ShellP2/dsh b/4-ShellP2/dsh new file mode 100755 index 0000000000000000000000000000000000000000..bc71f23f06921448398c90d8c8ef9609de2dbfd4 GIT binary patch literal 24968 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 Qfhh*iN_PkgLZa&j0IxVzO8@`> literal 0 HcmV?d00001 diff --git a/4-ShellP2/dsh_cli.c b/4-ShellP2/dsh_cli.c new file mode 100644 index 0000000..ef8029b --- /dev/null +++ b/4-ShellP2/dsh_cli.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "dshlib.h" + +/* DO NOT EDIT + * main() logic moved to exec_local_cmd_loop() in dshlib.c +*/ +int main(){ + int rc = exec_local_cmd_loop(); + printf("cmd loop returned %d\n", rc); +} diff --git a/4-ShellP2/dshlib.c b/4-ShellP2/dshlib.c new file mode 100644 index 0000000..c168f6d --- /dev/null +++ b/4-ShellP2/dshlib.c @@ -0,0 +1,275 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdbool.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/wait.h> +#include <errno.h> +#include "dshlib.h" + +int numInstanceOf(char *str, const char c) { + int count = 0; + while (*str != '\0') { + if (*str == c) count++; + str++; + } + return count; +} + +int alloc_cmd_buff(cmd_buff_t *cmd_buff) { + if (cmd_buff == NULL) { + return ERR_MEMORY; + } + cmd_buff->argc = 0; + + cmd_buff->argv = (char**)malloc(CMD_ARGV_MAX * sizeof(char *)); + if (cmd_buff->argv == NULL) { + free(cmd_buff); + return ERR_MEMORY; + } + + for (int i = 0; i < CMD_ARGV_MAX; i++) { + cmd_buff->argv[i] = (char *)malloc(ARG_MAX); + if (cmd_buff->argv[i] == NULL) { + for (int j = 0; j < i; j++) { + free(cmd_buff->argv[j]); + } + free(cmd_buff->argv); + return ERR_MEMORY; + } + } + + cmd_buff->_cmd_buffer = (char *)malloc(SH_CMD_MAX); + if (cmd_buff->_cmd_buffer == NULL) { + free(cmd_buff->_cmd_buffer); + for (int i = 0; i < CMD_ARGV_MAX; i++) { + free(cmd_buff->argv[i]); + } + free(cmd_buff->argv); + return ERR_MEMORY; + } + + + return OK_EXIT; +} + +int free_cmd_buff(cmd_buff_t *cmd_buff) { + free(cmd_buff->_cmd_buffer); + + for (int i = 0; i < CMD_ARGV_MAX - 1; i++) free(cmd_buff->argv[i]); + free(cmd_buff); + return OK_EXIT; +} + +int clear_cmd_buff(cmd_buff_t *cmd_buff) { + cmd_buff->argc = 0; + free(cmd_buff->_cmd_buffer); + + for (int i = 0; i < CMD_ARGV_MAX; i++) cmd_buff->argv[i] = NULL; + return OK_EXIT; +} + +char* trim_whitespace(char *str) { + int start = 0; + while (isspace((unsigned char)str[start])) { + start++; + } + + int end = strlen(str) - 1; + while (end > start && isspace((unsigned char)str[end])) { + end--; + } + + int j = 0; + for (int i = start; i <= end; i++) { + str[j++] = str[i]; + } + str[j] = '\0'; + + return str; +} + +int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) { + if ((int)strlen(cmd_line) > SH_CMD_MAX) return ERR_CMD_OR_ARGS_TOO_BIG; + + if ((int)strlen(cmd_line) == 0) return WARN_NO_CMDS; + + cmd_buff->_cmd_buffer = strdup(trim_whitespace(cmd_line)); + if (cmd_buff->_cmd_buffer == NULL) { + free(cmd_buff); + return ERR_MEMORY; + } + + char *token = cmd_buff->_cmd_buffer; + bool quotes = false; + char *p = NULL; + + while (*token) { + if (*token == DOUBLE_QUOTE_CHAR) { + quotes = !quotes; + if (quotes) p = token + 1; + else *token = '\0'; + } else if (!quotes && (*token == SPACE_CHAR || *token == '\t')) { + *token = '\0'; + + if (p != NULL) { + cmd_buff->argv[cmd_buff->argc++] = p; + p = NULL; + } + } else if (p == NULL) { + p = token; + } + token++; + } + + if (p != NULL) cmd_buff->argv[cmd_buff->argc++] = p; + + cmd_buff->argv[cmd_buff->argc] = NULL; + return OK_EXIT; +} +/* + * Implement your exec_local_cmd_loop function by building a loop that prompts the + * user for input. Use the SH_PROMPT constant from dshlib.h and then + * use fgets to accept user input. + * + * while(1){ + * printf("%s", SH_PROMPT); + * if (fgets(cmd_buff, ARG_MAX, stdin) == NULL){ + * printf("\n"); + * break; + * } + * //remove the trailing \n from cmd_buff + * cmd_buff[strcspn(cmd_buff,"\n")] = '\0'; + * + * //IMPLEMENT THE REST OF THE REQUIREMENTS + * } + * + * Also, use the constants in the dshlib.h in this code. + * SH_CMD_MAX maximum buffer size for user input + * EXIT_CMD constant that terminates the dsh program + * SH_PROMPT the shell prompt + * OK the command was parsed properly + * WARN_NO_CMDS the user command was empty + * ERR_TOO_MANY_COMMANDS too many pipes used + * ERR_MEMORY dynamic memory management failure + * + * errors returned + * OK No error + * ERR_MEMORY Dynamic memory management failure + * WARN_NO_CMDS No commands parsed + * ERR_TOO_MANY_COMMANDS too many pipes used + * + * console messages + * CMD_WARN_NO_CMD print on WARN_NO_CMDS + * CMD_ERR_PIPE_LIMIT print on ERR_TOO_MANY_COMMANDS + * CMD_ERR_EXECUTE print on execution failure of external command + * + * Standard Library Functions You Might Want To Consider Using (assignment 1+) + * malloc(), free(), strlen(), fgets(), strcspn(), printf() + * + * Standard Library Functions You Might Want To Consider Using (assignment 2+) + * fork(), execvp(), exit(), chdir() + */ +int exec_local_cmd_loop() +{ + char *cmd_buff = malloc(ARG_MAX * sizeof(char)); + int rc = 0; + cmd_buff_t *cmd = malloc(CMD_ARGV_MAX * sizeof(char *)); + + if ((rc = alloc_cmd_buff(cmd)) != OK_EXIT) exit(rc); + + // TODO IMPLEMENT MAIN LOOP + while(1){ + printf("%s", SH_PROMPT); + if (fgets(cmd_buff, ARG_MAX, stdin) == NULL){ + printf("\n"); + break; + } + //remove the trailing \n from cmd_buff + cmd_buff[strcspn(cmd_buff,"\n")] = '\0'; + + //IMPLEMENT THE REST OF THE REQUIREMENTS + if (strcmp(cmd_buff, EXIT_CMD) == 0) { + exit(rc); + } + + if (strcmp(cmd_buff, "rc") == 0) { + printf("%d\n", rc); + if ((rc = clear_cmd_buff(cmd)) != OK_EXIT) exit(rc); + continue; + } + + if (strcmp(cmd_buff, "\0") == 0) { + rc = WARN_NO_CMDS; + printf(CMD_WARN_NO_CMD); + //if ((rc = clear_cmd_buff(cmd)) != OK_EXIT) exit(rc); + continue; + } + + // TODO IMPLEMENT parsing input to cmd_buff_t *cmd_buff + if ((rc = build_cmd_buff(cmd_buff, cmd)) != OK_EXIT) { + exit(rc); + rc = 0; + } + /* + if (strcmp(cmd->argv[0], "echo") == 0) { + for (int i = 1; i < CMD_ARGV_MAX; i++) { + printf("%s ", cmd->argv[i]); + } + printf("\n"); + if ((rc = clear_cmd_buff(cmd)) != OK_EXIT) exit(rc); + continue; + }*/ + + // TODO IMPLEMENT if built-in command, execute builtin logic for exit, cd (extra credit: dragon) + if (strcmp(cmd_buff, "dragon") == 0) { + print_dragon(); + if ((rc = clear_cmd_buff(cmd)) != OK_EXIT) exit(rc); + rc = 0; + continue; + } + + // the cd command should chdir to the provided directory; if no directory is provided, do nothing + if (strcmp(cmd->argv[0], "cd") == 0) { + if (cmd->argc < 2) { + if ((rc = clear_cmd_buff(cmd)) != OK_EXIT) exit(rc); + rc = 0; + continue; + } + if (chdir(cmd->argv[1]) != 0) { + perror("chdir failed"); + rc = 1; + } + if ((rc = clear_cmd_buff(cmd)) != OK_EXIT) exit(rc); + rc = 0; + continue; + } + + // TODO IMPLEMENT if not built-in command, fork/exec as an external command + // for example, if the user input is "ls -l", you would fork/exec the command "ls" with the arg "-l" + pid_t pid = fork(); + if (pid < 0) { + printf("fork failed"); + if ((rc = clear_cmd_buff(cmd)) != OK_EXIT) exit(rc); + continue; + } else if (pid == 0) { + execvp(cmd->argv[0], cmd->argv); + perror(CMD_ERR_EXECUTE); + exit(1); + } else { + int status; + waitpid(pid, &status, 0); + if (WIFEXITED(status)) { + rc = WEXITSTATUS(status); + } else { + rc = 1; + } + } + if ((rc = clear_cmd_buff(cmd)) != OK_EXIT) exit(rc); + } + free(cmd_buff); + free_cmd_buff(cmd); + return OK; +} diff --git a/4-ShellP2/dshlib.h b/4-ShellP2/dshlib.h new file mode 100644 index 0000000..df2f9a4 --- /dev/null +++ b/4-ShellP2/dshlib.h @@ -0,0 +1,85 @@ +#ifndef __DSHLIB_H__ + #define __DSHLIB_H__ + + +//Constants for command structure sizes +#define EXE_MAX 64 +#define ARG_MAX 256 +#define CMD_MAX 8 +#define CMD_ARGV_MAX (CMD_MAX + 1) +// Longest command that can be read from the shell +#define SH_CMD_MAX EXE_MAX + ARG_MAX + +typedef struct cmd_buff +{ + int argc; + char **argv; + char *_cmd_buffer; +} cmd_buff_t; + +/* WIP - Move to next assignment +#define N_ARG_MAX 15 //MAX number of args for a command +typedef struct command{ + char exe [EXE_MAX]; + char args[ARG_MAX]; + int argc; + char *argv[N_ARG_MAX + 1]; //last argv[LAST] must be \0 +}command_t; +*/ + + +//Special character #defines +#define SPACE_CHAR ' ' +#define SPACE_STRING " " +#define PIPE_CHAR '|' +#define PIPE_STRING "|" +#define DOUBLE_QUOTE_CHAR '"' + +#define SH_PROMPT "dsh2> " +#define EXIT_CMD "exit" + +//Standard Return Codes +#define OK 0 +#define WARN_NO_CMDS -1 +#define ERR_TOO_MANY_COMMANDS -2 +#define ERR_CMD_OR_ARGS_TOO_BIG -3 +#define ERR_CMD_ARGS_BAD -4 //for extra credit +#define ERR_MEMORY -5 +#define ERR_EXEC_CMD -6 +#define OK_EXIT -7 + +//prototypes +int alloc_cmd_buff(); +int free_cmd_buff(cmd_buff_t *); +int clear_cmd_buff(cmd_buff_t *); +int build_cmd_buff(char *, cmd_buff_t *); +void exeCD(char *path); +void execFork(char *); +extern void print_dragon(); + +//built in command stuff +typedef enum { + BI_CMD_EXIT, + BI_CMD_DRAGON, + BI_CMD_CD, + BI_NOT_BI, + BI_EXECUTED, + BI_RC, +} Built_In_Cmds; +Built_In_Cmds match_command(const char *input); +Built_In_Cmds exec_built_in_cmd(cmd_buff_t *cmd); + +//main execution context +int exec_local_cmd_loop(); +int exec_cmd(cmd_buff_t *cmd); + + + + +//output constants +#define CMD_OK_HEADER "PARSED COMMAND LINE - TOTAL COMMANDS %d\n" +#define CMD_WARN_NO_CMD "warning: no commands provided\n" +#define CMD_ERR_PIPE_LIMIT "error: piping limited to %d commands\n" +#define CMD_ERR_EXECUTE "Command not found in PATH\n" + +#endif diff --git a/4-ShellP2/makefile b/4-ShellP2/makefile new file mode 100644 index 0000000..a079ef4 --- /dev/null +++ b/4-ShellP2/makefile @@ -0,0 +1,31 @@ +# Compiler settings +CC = gcc +CFLAGS = -Wall -Wextra -g + +# Target executable name +TARGET = dsh + +# Find all source and header files +SRCS = $(wildcard *.c) +HDRS = $(wildcard *.h) + +# Default target +all: $(TARGET) + +# Compile source to executable +$(TARGET): $(SRCS) $(HDRS) + $(CC) $(CFLAGS) -o $(TARGET) $(SRCS) + +# Clean up build files +clean: + rm -f $(TARGET) + +test: + bats $(wildcard ./bats/*.sh) + +valgrind: + echo "pwd\nexit" | valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 ./$(TARGET) + echo "pwd\nexit" | valgrind --tool=helgrind --error-exitcode=1 ./$(TARGET) + +# Phony targets +.PHONY: all clean test -- GitLab