diff --git a/dshlib.c b/dshlib.c
new file mode 100644
index 0000000000000000000000000000000000000000..3ee5c6c47e4ae10d594c6d42b97ad4b896211dfc
--- /dev/null
+++ b/dshlib.c
@@ -0,0 +1,93 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "dshlib.h"
+
+/*
+ * trim: Removes leading and trailing whitespace from a string in-place.
+ * Returns a pointer to the first non-space character.
+ */
+static char *trim(char *str)
+{
+    /* Trim leading spaces */
+    while (isspace((unsigned char)*str))
+        str++;
+
+    if (*str == '\0')  /* All spaces? */
+        return str;
+
+    /* Trim trailing spaces */
+    char *end = str + strlen(str) - 1;
+    while (end > str && isspace((unsigned char)*end)) {
+        *end = '\0';
+        end--;
+    }
+    return str;
+}
+
+/*
+ * build_cmd_list:
+ *   - Splits the provided cmd_line into commands separated by '|'
+ *   - For each command it trims leading/trailing spaces and then splits the
+ *     command into tokens (using whitespace as the delimiter).
+ *   - The first token is stored in the exe field (if it is not too long).
+ *   - Any subsequent tokens are concatenated (with no intervening spaces)
+ *     and stored in the args field.
+ *
+ * Returns:
+ *   OK if the command was parsed successfully.
+ *   ERR_TOO_MANY_COMMANDS if more than CMD_MAX commands are specified.
+ *   ERR_CMD_OR_ARGS_TOO_BIG if the executable or argument string exceeds its size.
+ */
+int build_cmd_list(char *cmd_line, command_list_t *clist)
+{
+    clist->num = 0;
+    char *saveptr1;
+    /* Use strtok_r to split the command line by the pipe '|' character */
+    char *token = strtok_r(cmd_line, PIPE_STRING, &saveptr1);
+    while (token != NULL) {
+        char *trimmed = trim(token);
+        if (strlen(trimmed) == 0) {
+            token = strtok_r(NULL, PIPE_STRING, &saveptr1);
+            continue;
+        }
+
+        if (clist->num >= CMD_MAX) {
+            return ERR_TOO_MANY_COMMANDS;
+        }
+
+        char command_buffer[SH_CMD_MAX];
+        strncpy(command_buffer, trimmed, sizeof(command_buffer) - 1);
+        command_buffer[sizeof(command_buffer) - 1] = '\0';
+
+        char *saveptr2;
+        /* Use strtok_r to split the command_buffer by spaces */
+        char *arg = strtok_r(command_buffer, " ", &saveptr2);
+        if (arg == NULL) {
+            token = strtok_r(NULL, PIPE_STRING, &saveptr1);
+            continue;
+        }
+
+        if (strlen(arg) >= EXE_MAX) {
+            return ERR_CMD_OR_ARGS_TOO_BIG;
+        }
+        strcpy(clist->commands[clist->num].exe, arg);
+
+        /* Initialize the args string as empty */
+        clist->commands[clist->num].args[0] = '\0';
+
+        while ((arg = strtok_r(NULL, " ", &saveptr2)) != NULL) {
+            if (strlen(clist->commands[clist->num].args) + strlen(arg) >= ARG_MAX) {
+                return ERR_CMD_OR_ARGS_TOO_BIG;
+            }
+            strcat(clist->commands[clist->num].args, arg);
+        }
+
+        clist->num++;
+        token = strtok_r(NULL, PIPE_STRING, &saveptr1);
+    }
+
+    return OK;
+}
\ No newline at end of file