Skip to content
Snippets Groups Projects
Commit 97d2ba9b authored by hk835's avatar hk835
Browse files

Add new file

parent 35af2ca3
No related branches found
No related tags found
No related merge requests found
#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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment