Skip to content
Snippets Groups Projects
Commit 49576172 authored by luishernandez's avatar luishernandez
Browse files

4-Shellp2

parent 34e22d42
Branches
No related tags found
No related merge requests found
#include "dshlib.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/wait.h>
//---------------------------------------------------------------------
// Helper: trim_whitespace
// Removes leading and trailing whitespace from a string.
static char *trim_whitespace(char *str) {
while (isspace((unsigned char)*str))
str++;
if (*str == '\0')
return str;
char *end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end))
end--;
*(end + 1) = '\0';
return str;
}
//---------------------------------------------------------------------
// Helper: parse_cmd_buff
//
// Parses the input command line stored in buf into tokens placed into
// the cmd_buff_t structure. It follows these rules:
// - All leading and trailing spaces are removed.
// - Duplicate spaces are eliminated outside quoted strings.
// - Quoted strings (using double quotes) are treated as a single token,
// preserving any spaces within them.
//
// This function modifies the input buffer by inserting '\0' terminators.
// Returns 0 on success and -1 on error.
static int parse_cmd_buff(char *buf, cmd_buff_t *cb) {
cb->argc = 0;
char *p = buf;
while (*p != '\0') {
// Skip any spaces.
while (*p && isspace((unsigned char)*p))
p++;
if (*p == '\0')
break;
char *token;
if (*p == '\"') { // Quoted token.
p++; // Skip the opening quote.
token = p;
// Advance until closing quote or end-of-string.
while (*p && *p != '\"')
p++;
if (*p == '\"') {
*p = '\0'; // Terminate token.
p++; // Skip the closing quote.
}
} else { // Non-quoted token.
token = p;
while (*p && !isspace((unsigned char)*p))
p++;
if (*p != '\0') {
*p = '\0';
p++;
}
}
// Store the token if we haven’t exceeded the maximum.
if (cb->argc < CMD_ARGV_MAX)
cb->argv[cb->argc++] = token;
else {
fprintf(stderr, "Error: Too many arguments\n");
return -1;
}
}
return 0;
}
//---------------------------------------------------------------------
// Function: exec_local_cmd_loop
//
// Implements the shell’s main loop. It:
// - Prompts the user with SH_PROMPT.
// - Reads a line of input using fgets().
// - Trims all leading/trailing spaces.
// - Parses the line into arguments (handling duplicate spaces and quoted strings).
// - If the command is EXIT_CMD, the loop exits.
// - If the command is "cd", it calls the built-in cd command logic.
// - Otherwise, it forks a child process that executes the command using execvp().
// - The parent waits for the child process to finish.
int exec_local_cmd_loop(void) {
char input[SH_CMD_MAX];
cmd_buff_t cb;
// Allocate memory for the raw command buffer.
cb._cmd_buffer = malloc(SH_CMD_MAX);
if (!cb._cmd_buffer) {
perror("malloc");
return -1;
}
while (1) {
printf("%s", SH_PROMPT);
if (fgets(input, sizeof(input), stdin) == NULL) {
printf("\n");
break;
}
// Remove trailing newline.
input[strcspn(input, "\n")] = '\0';
// Trim the input.
char *trimmed = trim_whitespace(input);
if (strcmp(trimmed, EXIT_CMD) == 0)
break;
// Copy the trimmed input into our command buffer.
strncpy(cb._cmd_buffer, trimmed, SH_CMD_MAX);
cb._cmd_buffer[SH_CMD_MAX - 1] = '\0';
// Parse the command buffer into tokens.
if (parse_cmd_buff(cb._cmd_buffer, &cb) != 0) {
fprintf(stderr, "Error parsing command\n");
continue;
}
// If no command was entered, print a warning and prompt again.
if (cb.argc == 0) {
printf("%s", CMD_WARN_NO_CMD);
continue;
}
// Built-in cd command:
if (strcmp(cb.argv[0], "cd") == 0) {
// If no argument, do nothing.
if (cb.argc < 2) {
/* do nothing */
} else if (cb.argc == 2) {
if (chdir(cb.argv[1]) != 0)
perror("cd");
} else {
fprintf(stderr, "cd: too many arguments\n");
}
continue;
}
// Fork and execute an external command.
pid_t pid = fork();
if (pid < 0) {
perror("fork");
continue;
}
if (pid == 0) { // Child process.
cb.argv[cb.argc] = NULL; // NULL-terminate the argument list.
execvp(cb.argv[0], cb.argv);
perror("execvp");
exit(1);
} else { // Parent process.
int status;
waitpid(pid, &status, 0);
}
}
free(cb._cmd_buffer);
return 0;
}
\ 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