diff --git a/3-ShellPart1/dshlib.c b/3-ShellPart1/dshlib.c
new file mode 100644
index 0000000000000000000000000000000000000000..104caa21a49fab4d6ab786055e1cf2b6bd2f9511
--- /dev/null
+++ b/3-ShellPart1/dshlib.c
@@ -0,0 +1,144 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "dshlib.h"
+
+/*
+ *  build_cmd_list
+ *    cmd_line:     the command line from the user
+ *    clist *:      pointer to clist structure to be populated
+ *
+ *  This function builds the command_list_t structure passed by the caller
+ *  It does this by first splitting the cmd_line into commands by spltting
+ *  the string based on any pipe characters '|'.  It then traverses each
+ *  command.  For each command (a substring of cmd_line), it then parses
+ *  that command by taking the first token as the executable name, and
+ *  then the remaining tokens as the arguments.
+ *
+ *  NOTE your implementation should be able to handle properly removing
+ *  leading and trailing spaces!
+ *
+ *  errors returned:
+ *
+ *    OK:                      No Error
+ *    ERR_TOO_MANY_COMMANDS:   There is a limit of CMD_MAX (see dshlib.h)
+ *                             commands.
+ *    ERR_CMD_OR_ARGS_TOO_BIG: One of the commands provided by the user
+ *                             was larger than allowed, either the
+ *                             executable name, or the arg string.
+ *
+ *  Standard Library Functions You Might Want To Consider Using
+ *      memset(), strcmp(), strcpy(), strtok(), strlen(), strchr()
+ */
+
+ // Helper function to trim leading and trailing whitespace
+static char* trim(char* str) {
+    if (!str) return NULL;  // Return NULL if input is NULL
+    
+    // Move the pointer forward to skip leading whitespace
+    while(isspace((unsigned char)*str)) str++;
+    
+    // If the string is now empty, return it
+    if(*str == 0) return str;
+    
+    // Find the last non-whitespace character
+    char* end = str + strlen(str) - 1;
+    while(end > str && isspace((unsigned char)*end)) end--;
+    
+    // Null-terminate the trimmed string
+    end[1] = '\0';
+    
+    return str;  // Return the trimmed string
+}
+
+// Helper function to parse a single command and its arguments
+static int parse_command(char* cmd_str, command_t* cmd) {
+    if (!cmd_str || !cmd) return ERR_CMD_OR_ARGS_TOO_BIG; // Validate input
+    
+    // Clear the command structure to ensure no leftover data
+    memset(cmd->exe, 0, EXE_MAX);
+    memset(cmd->args, 0, ARG_MAX);
+    
+    // Trim whitespace around the command string
+    cmd_str = trim(cmd_str);
+    
+    // If the command string is empty after trimming, return OK
+    if (strlen(cmd_str) == 0) return OK;
+    
+    char* saveptr;  // Save pointer for strtok_r (reentrant version of strtok)
+    
+    // Extract the first token (command executable)
+    char* token = strtok_r(cmd_str, " \t", &saveptr);
+    if (!token) return OK; // If no token found, return OK
+    
+    // Ensure the command is not too large
+    if (strlen(token) >= EXE_MAX) return ERR_CMD_OR_ARGS_TOO_BIG;
+    
+    // Copy the command executable to the structure
+    strcpy(cmd->exe, token);
+    
+    // Extract the remaining part of the command as arguments
+    char* remaining = strtok_r(NULL, "", &saveptr);
+    if (remaining) {
+        remaining = trim(remaining); // Trim any extra whitespace
+        if (strlen(remaining) >= ARG_MAX) return ERR_CMD_OR_ARGS_TOO_BIG; // Check size
+        strcpy(cmd->args, remaining); // Store arguments in the structure
+    }
+    
+    return OK;  // Return success
+}
+
+// Function to parse a command line into a list of commands
+int build_cmd_list(char* cmd_line, command_list_t* clist) {
+    if (!cmd_line || !clist) return ERR_CMD_OR_ARGS_TOO_BIG; // Validate input
+    
+    // Initialize the command list structure to zero
+    memset(clist, 0, sizeof(command_list_t));
+    clist->num = 0;
+    
+    // Trim leading and trailing whitespace from the command line
+    cmd_line = trim(cmd_line);
+    
+    // If the command line is empty after trimming, return a warning
+    if (strlen(cmd_line) == 0) return WARN_NO_CMDS;
+    
+    // Create a copy of the command line for safe tokenization
+    char* cmd_copy = strdup(cmd_line);
+    if (!cmd_copy) return ERR_CMD_OR_ARGS_TOO_BIG; // Check memory allocation
+    
+    char* saveptr; // Save pointer for strtok_r
+    char* cmd_str = strtok_r(cmd_copy, "|", &saveptr); // Split commands by '|'
+    
+    while (cmd_str) {
+        // Ensure the command list does not exceed the limit
+        if (clist->num >= CMD_MAX) {
+            free(cmd_copy);
+            return ERR_TOO_MANY_COMMANDS;
+        }
+        
+        // Parse the command and its arguments
+        int status = parse_command(cmd_str, &clist->commands[clist->num]);
+        if (status != OK) {
+            free(cmd_copy);
+            return status;
+        }
+        
+        // Only add the command if it contains an executable
+        if (strlen(clist->commands[clist->num].exe) > 0) {
+            clist->num++; // Increment the command count
+        }
+        
+        // Get the next command in the pipeline
+        cmd_str = strtok_r(NULL, "|", &saveptr);
+    }
+    
+    free(cmd_copy); // Free the duplicated command line memory
+    return OK; // Return success
+}
+
+    
+    free(cmd_copy);
+    return (clist->num > 0) ? OK : WARN_NO_CMDS;
+}
\ No newline at end of file