From 6658ae04a8c36a0e36bd1fa4d54ffd8522311a8a Mon Sep 17 00:00:00 2001
From: Bao Mai <bgm47@drexel.edu>
Date: Thu, 20 Feb 2025 22:55:06 -0500
Subject: [PATCH] update assignment 4

---
 4-ShellP2/.DS_Store                | Bin 0 -> 6148 bytes
 4-ShellP2/bats/assignment_tests.sh | 118 ++++++++++++++
 4-ShellP2/bats/student_tests.sh    |  14 ++
 4-ShellP2/debug/launch.json        |  29 ++++
 4-ShellP2/debug/tasks.json         |  20 +++
 4-ShellP2/dragon.c                 |   6 +
 4-ShellP2/dsh                      | Bin 0 -> 78152 bytes
 4-ShellP2/dsh_cli.c                |  13 ++
 4-ShellP2/dshlib.c                 | 242 +++++++++++++++++++++++++++++
 4-ShellP2/dshlib.h                 | 122 +++++++++++++++
 4-ShellP2/gitignore.txt            |   1 +
 4-ShellP2/makefile                 |  31 ++++
 4-ShellP2/questions.md             |  41 +++++
 4-ShellP2/shell_roadmap.md         |  13 ++
 14 files changed, 650 insertions(+)
 create mode 100644 4-ShellP2/.DS_Store
 create mode 100644 4-ShellP2/bats/assignment_tests.sh
 create mode 100644 4-ShellP2/bats/student_tests.sh
 create mode 100644 4-ShellP2/debug/launch.json
 create mode 100644 4-ShellP2/debug/tasks.json
 create mode 100644 4-ShellP2/dragon.c
 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/gitignore.txt
 create mode 100644 4-ShellP2/makefile
 create mode 100644 4-ShellP2/questions.md
 create mode 100644 4-ShellP2/shell_roadmap.md

diff --git a/4-ShellP2/.DS_Store b/4-ShellP2/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..7899819c089041c78a1a01f3754c09624f3aceae
GIT binary patch
literal 6148
zcmZQzU|@7AO)+F(5MW?n;9!8zEL;p&0Z1N%F(jFwBElf^z-FW~<T2zjq%!0&ltAT1
zsnHM^4S~TM0-(Gr%#g@X%uvjb$$*@H;~7dAQW=UFN*Ib6^cad6GCXtglaq4tlc2?g
zBLf42-hVIvdyj=7i6IfBIw##QI5|JJ04&PDJClKd0WO!D@8SYAgX6%0xpu{ykAciV
zl23ul+h(=cpvxCzAe*fKvVxT%g&~z8iJ_Ds9o1&m6b1$cBw1v;pZwAdhMJ9{0%1FL
z6<F-&U`SyoVn}32XUJ#BW6)zrMhmC)XyL@kkOB%#hIoc#h8%`WOdX7}XgWYP6f<Oi
zRVQIl-%UV0TFf#2L{rbpkj{|FPy&tre1;;1R0chU5{3$f5>&r1rK9QOX2@YkWGH3G
zV@PJmV9;a8VkicM0;(<sPz<jDCzSu72xH)2$Yn@m$Yw}oNMp!k$YDrDQx6I;Wc32z
z@JeOKVaQ>KXDDLGXGmm70h>|4pvREQkb<fo9DeBfOBhPQ=>$|W5lGpLpzuW2&&5yz
z&LP?0oPgDj;4nqj1NP`3Cm12_<KTwSqvU7^jE2By2*5)CR6c;JSP<<1Y2!0AKxmK<
z10w?ixC_7ts^Foz7{UDj29O*`D~JYZ1<@d_42&Qa*bJ~%21W)JuuevBHw2^))FlDY
zVC@Wy3}EdHj9{A?7#P7eGcYhhv@<Y5v@<Y5dnk+$?F@_%?F@_%?O;1biO~=k4FN<5
zFhiIEp!(mHfdN<lAEIiM91Vfd5Ezyrz{uhf?BWEjl(G8{RM&#)(*&qAs163z=8T|v
s8ln%R1T4!08Bmk}b0Bgct)OZjTop4iKx*>Qh5#&tM(NQIpnnJe0FdwK#{d8T

literal 0
HcmV?d00001

diff --git a/4-ShellP2/bats/assignment_tests.sh b/4-ShellP2/bats/assignment_tests.sh
new file mode 100644
index 0000000..794b5d8
--- /dev/null
+++ b/4-ShellP2/bats/assignment_tests.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" ]
+}
\ No newline at end of file
diff --git a/4-ShellP2/bats/student_tests.sh b/4-ShellP2/bats/student_tests.sh
new file mode 100644
index 0000000..638bc34
--- /dev/null
+++ b/4-ShellP2/bats/student_tests.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/debug/launch.json b/4-ShellP2/debug/launch.json
new file mode 100644
index 0000000..aedc1ef
--- /dev/null
+++ b/4-ShellP2/debug/launch.json
@@ -0,0 +1,29 @@
+{
+    "configurations": [
+        {
+            "name": "(gdb) 4-ShellP2",
+            "type": "cppdbg",
+            "request": "launch",
+            "program": "${workspaceFolder}/4-ShellP2/starter/dsh",
+            "args": [""],
+            "stopAtEntry": false,
+            "cwd": "${workspaceFolder}/4-ShellP2/starter",
+            "environment": [],
+            "externalConsole": false,
+            "MIMode": "gdb",
+            "setupCommands": [
+                {
+                    "description": "Enable pretty-printing for gdb",
+                    "text": "-enable-pretty-printing",
+                    "ignoreFailures": true
+                },
+                {
+                    "description": "Set Disassembly Flavor to Intel",
+                    "text": "-gdb-set disassembly-flavor intel",
+                    "ignoreFailures": true
+                }
+            ],
+            "preLaunchTask": "Build 4-ShellP2"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/4-ShellP2/debug/tasks.json b/4-ShellP2/debug/tasks.json
new file mode 100644
index 0000000..71013e3
--- /dev/null
+++ b/4-ShellP2/debug/tasks.json
@@ -0,0 +1,20 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+      {
+        "label": "Build 4-ShellP2",
+        "type": "shell",
+        "command": "make",
+        "group": {
+          "kind": "build",
+          "isDefault": true
+        },
+        "options": {
+          "cwd": "${workspaceFolder}/4-ShellP2/starter"
+      },
+        "problemMatcher": ["$gcc"],
+        "detail": "Runs the 'make' command to build the project."
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/4-ShellP2/dragon.c b/4-ShellP2/dragon.c
new file mode 100644
index 0000000..581408b
--- /dev/null
+++ b/4-ShellP2/dragon.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+#include "dshlib.h"
+// EXTRA CREDIT - print the drexel dragon from the readme.md
+extern void print_dragon(){
+  printf("%s\n", DRAGON_ASCII);
+}
diff --git a/4-ShellP2/dsh b/4-ShellP2/dsh
new file mode 100755
index 0000000000000000000000000000000000000000..ead4f253f37269bd40ef405a63ee5d2f880c9952
GIT binary patch
literal 78152
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
DOJ%xU

literal 0
HcmV?d00001

diff --git a/4-ShellP2/dsh_cli.c b/4-ShellP2/dsh_cli.c
new file mode 100644
index 0000000..9262cf4
--- /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);
+}
\ No newline at end of file
diff --git a/4-ShellP2/dshlib.c b/4-ShellP2/dshlib.c
new file mode 100644
index 0000000..0edc75e
--- /dev/null
+++ b/4-ShellP2/dshlib.c
@@ -0,0 +1,242 @@
+#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 "dshlib.h"
+#include <errno.h>
+
+/*
+ * 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 last_rc = 0;  // Global variable to store the return code
+
+int exec_local_cmd_loop() {
+    cmd_buff_t cmd;
+    int rc;
+
+    rc = alloc_cmd_buff(&cmd);
+    if (rc != OK) {
+        fprintf(stderr, "Error: Unable to allocate command buffer.\n");
+        return ERR_MEMORY;
+    }
+
+    while (1) {
+        printf("%s", SH_PROMPT);
+
+        if (!fgets(cmd._cmd_buffer, SH_CMD_MAX, stdin)) {
+            printf("\n");
+            break;
+        }
+        cmd._cmd_buffer[strcspn(cmd._cmd_buffer, "\n")] = '\0';
+
+        if (cmd._cmd_buffer[0] == '\0') {
+            printf("%s\n", CMD_WARN_NO_CMD);
+            continue;
+        }
+        char *input = cmd._cmd_buffer;
+        while (isspace((unsigned char)*input)) {
+            input++;
+        }
+        if (*input == '\0') {
+            printf("%s\n", CMD_WARN_NO_CMD);
+            continue;
+        }
+
+        if (strcmp(input, EXIT_CMD) == 0) {
+            break;
+        }
+        if (strcmp(input, "dragon") == 0) {
+            print_dragon();
+            continue;
+        }
+        if (strcmp(input, "rc") == 0) {
+            printf("%d\n", last_rc);
+            continue;
+        }
+
+        rc = build_cmd_buff(cmd._cmd_buffer, &cmd);
+        if (rc != OK) {
+            fprintf(stderr, "Error: Failed to parse command.\n");
+            continue;
+        }
+
+        if (strcmp(cmd.argv[0], "cd") == 0) {
+            handle_cd(cmd.argv[1]);
+            continue;
+        }
+
+        pid_t pid = fork();
+        if (pid < 0) {
+            if (errno == EAGAIN) {
+                fprintf(stderr, "Error: System process limit reached (EAGAIN).\n");
+            } else if (errno == ENOMEM) {
+                fprintf(stderr, "Error: Insufficient memory (ENOMEM).\n");
+            } else {
+                perror("fork");
+            }
+            continue;
+        }
+
+        if (pid == 0) {
+            execvp(cmd.argv[0], cmd.argv);
+
+            int err = errno;
+            switch (err) {
+                case ENOENT:
+                    fprintf(stderr, "Error: Command not found.\n");
+                    break;
+                case EACCES:
+                    fprintf(stderr, "Error: Permission denied.\n");
+                    break;
+                default:
+                    fprintf(stderr, "Error: %s\n", strerror(err));
+                    break;
+            }
+            exit(err);
+        } else {
+            int status;
+            waitpid(pid, &status, 0);
+            last_rc = WEXITSTATUS(status);
+        }
+    }
+
+    free_cmd_buff(&cmd);
+    return OK;
+}
+
+int handle_cd(char *path) {
+    if (path) {
+        if (chdir(path) == -1) {
+            perror("cd");
+            return -1;
+        }
+    }
+    return 0;
+}
+
+int alloc_cmd_buff(cmd_buff_t *cmd) {
+    if (!cmd) {
+        return ERR_MEMORY;
+    }
+    cmd->_cmd_buffer = malloc(SH_CMD_MAX + 1);
+    if (!cmd->_cmd_buffer) {
+        return ERR_MEMORY;
+    }
+
+    return OK;
+}
+
+int free_cmd_buff(cmd_buff_t *cmd) {
+    if (!cmd) {
+        return ERR_MEMORY;
+    }
+    if (cmd->_cmd_buffer) {
+        free(cmd->_cmd_buffer);
+        cmd->_cmd_buffer = NULL;
+    }
+
+    return OK;
+}
+
+int clear_cmd_buff(cmd_buff_t *cmd) {
+    if (!cmd) {
+        return ERR_MEMORY;
+    }
+    cmd->argc = 0;
+    for (int i = 0; i < CMD_ARGV_MAX; i++) {
+        cmd->argv[i] = NULL;
+    }
+
+    return OK;
+}
+
+
+int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd) {
+    if (!cmd_line || !cmd) {
+        return ERR_MEMORY;
+    }
+    clear_cmd_buff(cmd);
+    int count = 0;
+    char *p = cmd_line;
+    while (*p) {
+    while (isspace((unsigned char)*p)) {
+        p++;
+    }
+    if (!*p) {
+        break;
+    }
+
+    char *start = p;
+    if (*p == '"' || *p == '\'') {
+        char quote = *p++;
+        start = p;
+
+        while (*p && *p != quote) {
+            p++;
+        }
+        if (*p == quote) {
+            *p++ = '\0';
+        }
+    } 
+    else {
+        while (*p && !isspace((unsigned char)*p)) {
+            p++;
+        }
+        if (*p) {
+            *p++ = '\0';
+        }
+    }
+    cmd->argv[count++] = start;
+    if (count >= CMD_ARGV_MAX - 1) {
+        break;
+    }
+}
+
+    cmd->argv[count] = NULL;
+    cmd->argc = count;
+    return count ? OK : WARN_NO_CMDS;
+}
diff --git a/4-ShellP2/dshlib.h b/4-ShellP2/dshlib.h
new file mode 100644
index 0000000..cc1d878
--- /dev/null
+++ b/4-ShellP2/dshlib.h
@@ -0,0 +1,122 @@
+#ifndef __DSHLIB_H__
+    #define __DSHLIB_H__
+
+
+//Constants for command structure sizes
+#define DRAGON_ASCII "\
+                                                                        @%%%%                       \n\
+                                                                     %%%%%%                         \n\
+                                                                    %%%%%%                          \n\
+                                                                 % %%%%%%%           @              \n\
+                                                                %%%%%%%%%%        %%%%%%%           \n\
+                                       %%%%%%%  %%%%@         %%%%%%%%%%%%@    %%%%%%  @%%%%        \n\
+                                  %%%%%%%%%%%%%%%%%%%%%%      %%%%%%%%%%%%%%%%%%%%%%%%%%%%          \n\
+                                %%%%%%%%%%%%%%%%%%%%%%%%%%   %%%%%%%%%%%% %%%%%%%%%%%%%%%           \n\
+                               %%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%     %%%            \n\
+                             %%%%%%%%%%%%%%%%%%%%%%%%%%%%@ @%%%%%%%%%%%%%%%%%%        %%            \n\
+                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%                \n\
+                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              \n\
+                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%@              \n\
+      %%%%%%%%@           %%%%%%%%%%%%%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%      %%                \n\
+    %%%%%%%%%%%%%         %%@%%%%%%%%%%%%           %%%%%%%%%%% %%%%%%%%%%%%      @%                \n\
+  %%%%%%%%%%   %%%        %%%%%%%%%%%%%%            %%%%%%%%%%%%%%%%%%%%%%%%                        \n\
+ %%%%%%%%%       %         %%%%%%%%%%%%%             %%%%%%%%%%%%@%%%%%%%%%%%                       \n\
+%%%%%%%%%@                % %%%%%%%%%%%%%            @%%%%%%%%%%%%%%%%%%%%%%%%%                     \n\
+%%%%%%%%@                 %%@%%%%%%%%%%%%            @%%%%%%%%%%%%%%%%%%%%%%%%%%%%                  \n\
+%%%%%%%@                   %%%%%%%%%%%%%%%           %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              \n\
+%%%%%%%%%%                  %%%%%%%%%%%%%%%          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%      %%%%  \n\
+%%%%%%%%%@                   @%%%%%%%%%%%%%%         %%%%%%%%%%%%@ %%%% %%%%%%%%%%%%%%%%%   %%%%%%%%\n\
+%%%%%%%%%%                  %%%%%%%%%%%%%%%%%        %%%%%%%%%%%%%      %%%%%%%%%%%%%%%%%% %%%%%%%%%\n\
+%%%%%%%%%@%%@                %%%%%%%%%%%%%%%%@       %%%%%%%%%%%%%%     %%%%%%%%%%%%%%%%%%%%%%%%  %%\n\
+ %%%%%%%%%%                  % %%%%%%%%%%%%%%@        %%%%%%%%%%%%%%   %%%%%%%%%%%%%%%%%%%%%%%%%% %%\n\
+  %%%%%%%%%%%%  @           %%%%%%%%%%%%%%%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%% \n\
+   %%%%%%%%%%%%% %%  %  %@ %%%%%%%%%%%%%%%%%%          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    %%% \n\
+    %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%           @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    %%%%%%% \n\
+     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              %%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%   \n\
+      @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                  %%%%%%%%%%%%%%%%%%%%%%%%%               \n\
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                      %%%%%%%%%%%%%%%%%%%  %%%%%%%          \n\
+           %%%%%%%%%%%%%%%%%%%%%%%%%%                           %%%%%%%%%%%%%%%  @%%%%%%%%%         \n\
+              %%%%%%%%%%%%%%%%%%%%           @%@%                  @%%%%%%%%%%%%%%%%%%   %%%        \n\
+                  %%%%%%%%%%%%%%%        %%%%%%%%%%                    %%%%%%%%%%%%%%%    %         \n\
+                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                      %%%%%%%%%%%%%%            \n\
+                %%%%%%%%%%%%%%%%%%%%%%%%%%  %%%% %%%                      %%%%%%%%%%  %%%@          \n\
+                     %%%%%%%%%%%%%%%%%%% %%%%%% %%                          %%%%%%%%%%%%%@          \n\
+                                                                                 %%%%%%%@        \n"
+
+#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[CMD_ARGV_MAX];
+    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 PIPE_CHAR   '|'
+#define PIPE_STRING "|"
+
+#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(cmd_buff_t *cmd_buff);
+int free_cmd_buff(cmd_buff_t *cmd_buff);
+int clear_cmd_buff(cmd_buff_t *cmd_buff);
+int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff);
+int handle_cd(char *path);
+void print_dragon(void);
+
+
+//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"
+
+#endif
\ No newline at end of file
diff --git a/4-ShellP2/gitignore.txt b/4-ShellP2/gitignore.txt
new file mode 100644
index 0000000..eb47a8e
--- /dev/null
+++ b/4-ShellP2/gitignore.txt
@@ -0,0 +1 @@
+dsh
\ No newline at end of file
diff --git a/4-ShellP2/makefile b/4-ShellP2/makefile
new file mode 100644
index 0000000..b14b072
--- /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
\ No newline at end of file
diff --git a/4-ShellP2/questions.md b/4-ShellP2/questions.md
new file mode 100644
index 0000000..d2798e5
--- /dev/null
+++ b/4-ShellP2/questions.md
@@ -0,0 +1,41 @@
+1. Can you think of why we use `fork/execvp` instead of just calling `execvp` directly? What value do you think the `fork` provides?
+
+    > **Answer**:  We need to use fork() since execvp() completely replaces the current process. If we just ran execvp(), our shell would be replaced with the command and then exited. We use fork() to create a copy of our shell process first, allowing the child process to run the command while the parent shell process continues to take commands. This also allows us to execute many commands and wait for them to complete.
+
+2. What happens if the fork() system call fails? How does your implementation handle this scenario?
+
+    > **Answer**:  Fork() sets errno to indicate the error and returns -1 if it fails. Our implementation would terminate the program and print an error message.
+
+3. How does execvp() find the command to execute? What system environment variable plays a role in this process?
+
+    > **Answer**:  In the directories specified in the PATH environment variable, execvp() looks for the command.
+
+4. What is the purpose of calling wait() in the parent process after forking? What would happen if we didn’t call it?
+
+    > **Answer**:  After a fork, the parent process calls wait() to wait for the child process to finish and obtain its exit state. This enables the parent process to manage the errors or output of the child process. The parent process would proceed right away after forking without waiting for the child process to finish if wait() wasn't used.
+
+5. In the referenced demo code we used WEXITSTATUS(). What information does this provide, and why is it important?
+
+    > **Answer**:  The child process's exit status is provided by WEXITSTATUS(). It's crucial since it enables the parent process to determine if the child process ended successfully or unsuccessfully.
+
+6. Describe how your implementation of build_cmd_buff() handles quoted arguments. Why is this necessary?
+
+    > **Answer**:  I use it for execvp() after copying every character in an argument—aside from the quote marks—to a new string.  Prior to that, all leading and trailing spaces are eliminated.  This is required because one argument with white spaces between it is regarded as several arguments if quotation marks are not removed by excecvp().
+
+7. What changes did you make to your parsing logic compared to the previous assignment? Were there any unexpected challenges in refactoring your old code?
+
+    > **Answer**:  In this implementation, I employed a straightforward parsing technique that uses strtok() to divide the command line into the executable name and parameters.  The command name is the first token, while the remaining tokens are the arguments.  The primary difficulty was ensuring that the argv array was correctly NULL-terminated for execvp() to function.
+
+8. For this quesiton, you need to do some research on Linux signals. You can use [this google search](https://www.google.com/search?q=Linux+signals+overview+site%3Aman7.org+OR+site%3Alinux.die.net+OR+site%3Atldp.org&oq=Linux+signals+overview+site%3Aman7.org+OR+site%3Alinux.die.net+OR+site%3Atldp.org&gs_lcrp=EgZjaHJvbWUyBggAEEUYOdIBBzc2MGowajeoAgCwAgA&sourceid=chrome&ie=UTF-8) to get started.
+
+- What is the purpose of signals in a Linux system, and how do they differ from other forms of interprocess communication (IPC)?
+
+    > **Answer**:  In a Linux system, signals are used to facilitate communication between processes.  Signals are asynchronous and unidirectional, which sets them apart from other types of IPC like pipes or sockets.
+
+- Find and describe three commonly used signals (e.g., SIGKILL, SIGTERM, SIGINT). What are their typical use cases?
+
+    > **Answer**:  Identify and explain three frequently used signals (such as SIGKILL, SIGTERM, and SIGINT). Which usage cases are normal for them?
+
+- What happens when a process receives SIGSTOP? Can it be caught or ignored like SIGINT? Why or why not?
+
+    > **Answer**:  A process instantly freezes (suspends) upon receiving SIGSTOP. Since SIGSTOP is meant to always return control to the user, it cannot be intercepted or disregarded like SIGINT. This is crucial for process management and debugging since you need a dependable method of stopping a process. With SIGCONT, the procedure can be continued at a later time.
diff --git a/4-ShellP2/shell_roadmap.md b/4-ShellP2/shell_roadmap.md
new file mode 100644
index 0000000..9af1434
--- /dev/null
+++ b/4-ShellP2/shell_roadmap.md
@@ -0,0 +1,13 @@
+## Proposed Shell Roadmap
+
+Week 5:  Shell CLI Parser Due
+
+Week 6:  Execute Basic Commands
+
+Week 7:  Add support for pipes (extra-credit for file redirection)
+
+Week 8:  Basic socket assignment
+
+Week 9:  Remote Shell Extension
+
+Week 11: Add support for something like `nsenter` to enter a namespace
\ No newline at end of file
-- 
GitLab