minishell

This commit is contained in:
2023-12-12 17:32:54 +01:00
commit 196e143285
92 changed files with 4905 additions and 0 deletions

78
parsing/herodoc.c Executable file
View File

@@ -0,0 +1,78 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* herodoc.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/01 15:49:41 by fgras-ca #+# #+# */
/* Updated: 2023/12/07 14:16:55 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
static void read_and_write_input(int write_end, const char *delimiter)
{
char buffer[1024];
ssize_t num_read;
char *newline;
while (1)
{
printf("> ");
fflush(stdout);
num_read = read(STDIN_FILENO, buffer, sizeof(buffer) - 1);
if (num_read <= 0)
break ;
buffer[num_read] = '\0';
if (ft_strncmp(buffer, delimiter, ft_strlen(delimiter)) == 0)
{
newline = ft_strchr(buffer, '\n');
if (newline != NULL && newline - buffer
== (ptrdiff_t)ft_strlen(delimiter))
break ;
}
write(write_end, buffer, num_read);
}
}
static void child_process(int *pipe_fds, const char *delimiter)
{
close(pipe_fds[0]);
read_and_write_input(pipe_fds[1], delimiter);
close(pipe_fds[1]);
exit(EXIT_SUCCESS);
}
static void parent_process(int *pipe_fds)
{
close(pipe_fds[1]);
dup2(pipe_fds[0], STDIN_FILENO);
close(pipe_fds[0]);
}
void heredoc_input(const char *delimiter)
{
int pipe_fds[2];
pid_t pid;
if (pipe(pipe_fds) == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0)
child_process(pipe_fds, delimiter);
else
{
parent_process(pipe_fds);
waitpid(pid, NULL, 0);
}
}

113
parsing/parse.c Executable file
View File

@@ -0,0 +1,113 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parse.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/11/29 21:03:27 by fgras-ca #+# #+# */
/* Updated: 2023/12/10 14:00:23 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
static void finalize_command(t_command **current_command, t_command_node **root)
{
t_command_node *new_node;
if (*current_command && (*current_command)->command)
{
new_node = create_command_node(*current_command);
add_node_to_tree(root, new_node);
}
else if (*current_command)
{
free_command(*current_command);
}
}
static bool handle_syntax_error_and_free(t_process_token_params *params,
t_minishell *shell)
{
char *current_token;
bool sb;
current_token = params->tokens[*params->token_index];
sb = shell->tokenizer->symbol;
if (sb && (is_pipe_token(current_token, shell)
|| is_redirection_token(current_token)))
{
if (check_syntax_error(params->tokens,
*params->token_index, shell->tokenizer->in_quotes, shell))
{
if (*(params->current_command) != NULL)
{
free_command(*(params->current_command));
*(params->current_command) = NULL;
}
return (true);
}
}
return (false);
}
static void process_single_token(t_process_token_params *params,
t_minishell *shell, int fd)
{
char *current_token;
current_token = params->tokens[*params->token_index];
if (shell->tokenizer->symbol && (is_pipe_token(current_token, shell)
|| is_redirection_token(current_token)))
{
handle_pipe_and_redirection(params, fd);
}
else
{
handle_variable_and_other_tokens(params);
}
}
static void process_tokens(t_process_token_params *params,
t_minishell *shell, int fd)
{
while (params->tokens[*params->token_index] != NULL)
{
if (handle_syntax_error_and_free(params, shell))
{
return ;
}
process_single_token(params, shell, fd);
(*params->token_index)++;
}
}
void parse_tokens(char **tokens, t_minishell *shell, int fd)
{
t_command_node *root;
t_command *current_command;
int token_index;
int error_detected;
t_process_token_params params;
token_index = 0;
current_command = NULL;
root = NULL;
error_detected = 0;
params.tokens = tokens;
params.token_index = &token_index;
params.current_command = &current_command;
params.root = &root;
params.shell = shell;
params.command_count = 1;
process_tokens(&params, shell, fd);
if (current_command && current_command->command)
{
finalize_command(&current_command, &root);
if (!error_detected)
execute_and_free_tree(root, shell, params.command_count, fd);
}
else if (current_command)
free_command(current_command);
}

45
parsing/parse_error.c Executable file
View File

@@ -0,0 +1,45 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parse_error.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/07 13:00:24 by fgras-ca #+# #+# */
/* Updated: 2023/12/09 19:25:39 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
void execute_and_free_tree(t_command_node *root,
t_minishell *shell, int command_count, int fd)
{
if (root)
{
execute_command_tree(root, shell, command_count, fd);
free_command_tree(root);
}
}
int check_syntax_error(char **tokens, int token_index,
bool in_quotes, t_minishell *shell)
{
if (in_quotes)
{
return (0);
}
if (is_redirection_token(tokens[token_index])
|| is_pipe_token(tokens[token_index], shell))
{
if (token_index == 0 || tokens[token_index + 1] == NULL)
{
write(2, RED"bash: erreur de syntaxe près du symbole inattendu "
RST, 58);
write(2, tokens[token_index], ft_strlen(tokens[token_index]));
write(2, "\n", 1);
return (1);
}
}
return (0);
}

87
parsing/parse_redirections.c Executable file
View File

@@ -0,0 +1,87 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parse_redirections.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/01 15:25:07 by fgras-ca #+# #+# */
/* Updated: 2023/12/10 13:55:02 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
void handle_pipe_and_redirection(t_process_token_params *params, int fd)
{
t_command_node *new_node;
if (is_pipe_token(params->tokens[*params->token_index], params->shell))
{
if (*params->current_command && (*params->current_command)->command)
{
new_node = create_command_node(*params->current_command);
add_node_to_tree(params->root, new_node);
*params->current_command = create_new_command();
params->command_count++;
}
}
else if (is_redirection_token(params->tokens[*params->token_index]))
{
if (*params->current_command && (*params->current_command)->command)
{
process_redirection
(params, *params->current_command, params->shell, fd);
}
}
}
void resolve_variable_and_add_to_command(t_process_token_params *params,
char *token)
{
char *resolved_value;
resolved_value = get_variable_value(token, params->shell);
add_token_to_command_wrapper(params->current_command, resolved_value);
free(resolved_value);
}
static void handle_variable_token(t_process_token_params *params)
{
char *token;
t_State current_state;
token = params->tokens[*params->token_index];
current_state = params->shell->tokenizer->state;
if (is_variable_resolvable(token, current_state))
{
resolve_variable_and_add_to_command(params, token);
}
else
{
add_token_to_command_wrapper(params->current_command, token);
}
}
static void handle_non_variable_token(t_process_token_params *params)
{
add_token_to_command_wrapper(params->current_command,
params->tokens[*params->token_index]);
}
void handle_variable_and_other_tokens(t_process_token_params *params)
{
char *current_token;
bool variable;
current_token = params->tokens[*params->token_index];
variable = params->shell->tokenizer->variable;
if (!variable && is_variable_token(current_token))
{
handle_variable_token(params);
}
else
{
handle_non_variable_token(params);
}
}

54
parsing/parse_utils.c Executable file
View File

@@ -0,0 +1,54 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parse_utils.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/07 09:58:11 by fgras-ca #+# #+# */
/* Updated: 2023/12/09 19:09:08 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
bool is_pipe_token(char *token, t_minishell *shell)
{
(void)shell;
return (strcmp(token, "|") == 0);
}
bool is_redirection_token(char *token)
{
static const char *redirections[] = {">", "<", ">>", "<<", NULL};
int i;
i = 0;
while (redirections[i] != NULL)
{
if (ft_strcmp(token, redirections[i]) == 0)
return (true);
i++;
}
return (false);
}
bool is_variable_token(char *token)
{
return (token[0] == '$' && token[1] != '\0');
}
void add_token_to_command_wrapper(t_command **command, char *token)
{
if (!*command)
{
*command = create_new_command();
}
add_token_to_command(*command, token);
}
int is_variable_resolvable(char *token, t_State current_state)
{
return ((current_state == DOUBLE_QUOTE || (token[0] == '$'))
&& (current_state != SINGLE_QUOTE));
}

92
parsing/pipe.c Executable file
View File

@@ -0,0 +1,92 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* pipe.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/11/28 19:21:38 by fgras-ca #+# #+# */
/* Updated: 2023/12/09 19:21:39 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
static void create_and_handle_processes(t_process_params *params)
{
int i;
pid_t pid;
t_child_process_params child_params;
i = 0;
while (i < params->command_count)
{
pid = fork();
if (pid == 0)
{
child_params = (t_child_process_params){i, params->pipe_fds,
params->command_count, params->fd,
params->commands, params->shell};
setup_child_process(&child_params);
}
else if (pid < 0)
{
perror("fork");
exit(EXIT_FAILURE);
}
i++;
}
}
static void initialize_pipes(int *pipe_fds, int command_count)
{
int i;
i = 0;
while (i < command_count - 1)
{
if (pipe(pipe_fds + i * 2) < 0)
{
perror("pipe");
exit(EXIT_FAILURE);
}
i++;
}
}
static void wait_for_all_processes(int command_count)
{
int i;
i = 0;
while (i < command_count)
{
wait(NULL);
i++;
}
}
void process_pipe(t_command **commands,
t_minishell *shell, int command_count, int fd)
{
int *pipe_fds;
t_process_params params;
if (command_count == 1)
{
execute_command(commands[0], shell, fd);
return ;
}
pipe_fds = malloc(2 * (command_count - 1) * sizeof(int));
if (!pipe_fds)
{
perror("malloc");
exit(EXIT_FAILURE);
}
initialize_pipes(pipe_fds, command_count);
params = (t_process_params){pipe_fds, commands, shell, command_count, fd};
create_and_handle_processes(&params);
close_all_pipes(pipe_fds, 2 * (command_count - 1));
wait_for_all_processes(command_count);
free(pipe_fds);
}

40
parsing/pipe_utils.c Executable file
View File

@@ -0,0 +1,40 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* pipe_utils.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/09 17:16:52 by fgras-ca #+# #+# */
/* Updated: 2023/12/09 18:45:08 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
void close_all_pipes(int *pipe_fds, int count)
{
int i;
i = 0;
while (i < count)
{
close(pipe_fds[i]);
i++;
}
}
void setup_child_process(t_child_process_params *params)
{
if (params->i != 0)
{
dup2(params->pipe_fds[(params->i - 1) * 2], STDIN_FILENO);
}
if (params->i != params->command_count - 1)
{
dup2(params->pipe_fds[params->i * 2 + 1], STDOUT_FILENO);
}
close_all_pipes(params->pipe_fds, 2 * (params->command_count - 1));
execute_command(params->commands[params->i], params->shell, params->fd);
exit(EXIT_SUCCESS);
}

82
parsing/redirection.c Executable file
View File

@@ -0,0 +1,82 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* redirection.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/11/28 18:42:58 by fgras-ca #+# #+# */
/* Updated: 2023/12/10 13:56:12 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
void configure_redirection(char *file, int mode)
{
int fd;
if (mode == REDIRECT_IN)
{
fd = open(file, O_RDONLY);
dup2(fd, STDIN_FILENO);
close(fd);
}
else if (mode == REDIRECT_OUT)
{
fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
dup2(fd, STDOUT_FILENO);
close(fd);
}
else if (mode == REDIRECT_APPEND)
{
fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0644);
dup2(fd, STDOUT_FILENO);
close(fd);
}
else if (mode == REDIRECT_HEREDOC)
{
heredoc_input(file);
}
}
static t_redirection_mode get_redirection_mode(char *token)
{
if (ft_strcmp(token, ">") == 0)
return (REDIRECT_OUT);
if (ft_strcmp(token, "<") == 0)
return (REDIRECT_IN);
if (ft_strcmp(token, ">>") == 0)
return (REDIRECT_APPEND);
if (ft_strcmp(token, "<<") == 0)
return (REDIRECT_HEREDOC);
perror(RED"Redirection non reconnue"RST);
return (REDIRECT_UNKNOWN);
}
static void handle_redirection(char *token, t_redirection_mode redirection_mode)
{
if (redirection_mode == REDIRECT_HEREDOC)
heredoc_input(token);
else
configure_redirection(token, redirection_mode);
}
void process_redirection(t_process_token_params *params, t_command *commands,
t_minishell*shell, int fd)
{
t_redirection redir;
t_redirection_mode redirection_mode;
save_standard_descriptors(&redir);
redirection_mode
= get_redirection_mode(params->tokens[*(params->token_index)]);
if (redirection_mode == REDIRECT_UNKNOWN)
return ;
(*(params->token_index))++;
handle_redirection
(params->tokens[*(params->token_index)], redirection_mode);
execute_command(commands, shell, fd);
restore_standard_descriptors(&redir);
reset_command(*params->current_command);
}

33
parsing/redirection_utils.c Executable file
View File

@@ -0,0 +1,33 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* redirection_utils.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/07 12:33:34 by fgras-ca #+# #+# */
/* Updated: 2023/12/10 13:29:36 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
void save_standard_descriptors(t_redirection *redir)
{
redir->stdin_backup = dup(STDIN_FILENO);
redir->stdout_backup = dup(STDOUT_FILENO);
}
void restore_standard_descriptors(t_redirection *redir)
{
if (redir->stdin_backup != -1)
{
dup2(redir->stdin_backup, STDIN_FILENO);
close(redir->stdin_backup);
}
if (redir->stdout_backup != -1)
{
dup2(redir->stdout_backup, STDOUT_FILENO);
close(redir->stdout_backup);
}
}

82
parsing/tree.c Executable file
View File

@@ -0,0 +1,82 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* tree.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/11/30 12:03:54 by fgras-ca #+# #+# */
/* Updated: 2023/12/10 13:56:39 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
t_command_node *create_command_node(t_command *command)
{
t_command_node *node;
node = malloc(sizeof(t_command_node));
if (node == NULL)
{
return (NULL);
}
node->command = command;
node->left = NULL;
node->right = NULL;
return (node);
}
void add_node_to_tree(t_command_node **root, t_command_node *new_node)
{
t_command_node *current;
if (*root == NULL)
{
*root = new_node;
}
else
{
current = *root;
while (current->right != NULL)
{
current = current->right;
}
current->right = new_node;
}
}
void execute_command_tree(t_command_node *node, t_minishell *shell,
int command_count, int fd)
{
t_command **commands_array;
t_command_node *current_node;
int i;
i = 0;
current_node = node;
commands_array = malloc(sizeof(t_command *) * command_count);
while (current_node != NULL && i < command_count)
{
commands_array[i] = current_node->command;
current_node = current_node->right;
i++;
}
process_pipe(commands_array, shell, command_count, fd);
free(commands_array);
}
void free_command_tree(t_command_node *node)
{
if (node == NULL)
{
return ;
}
free_command_tree(node->left);
free_command_tree(node->right);
if (node->command)
{
free(node->command);
}
free(node);
}

105
parsing/variable.c Executable file
View File

@@ -0,0 +1,105 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* variable.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/11/29 21:41:34 by fgras-ca #+# #+# */
/* Updated: 2023/12/07 14:10:45 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
static char *allocate_exit_status_str(void)
{
char *exit_status_str;
exit_status_str = malloc(sizeof(char) * 12);
if (exit_status_str == NULL)
{
perror("Erreur d'allocation mémoire $");
return (NULL);
}
return (exit_status_str);
}
static int num_to_str(int num, char *str, int base)
{
int i;
int rem;
i = 0;
if (num == 0)
{
str[i++] = '0';
}
else
{
while (num != 0)
{
rem = num % base;
if (rem > 9)
str[i++] = (rem - 10) + 'a';
else
str[i++] = rem + '0';
num /= base;
}
}
str[i] = '\0';
return (i);
}
static void int_to_str(int num, char *str, int base)
{
int isnegative;
int length;
isnegative = 0;
if (num == 0)
{
str[0] = '0';
str[1] = '\0';
return ;
}
if (num < 0 && base == 10)
{
isnegative = 1;
num = -num;
}
length = num_to_str(num, str, base);
if (isnegative)
{
str[length] = '-';
str[length + 1] = '\0';
length++;
}
reverse_str(str, length);
}
static char *get_exit_status_str(t_minishell *shell)
{
char *exit_status_str;
exit_status_str = allocate_exit_status_str();
if (exit_status_str == NULL)
return (NULL);
int_to_str(shell->last_exit_status, exit_status_str, 10);
return (exit_status_str);
}
char *get_variable_value(const char *variable_name, t_minishell *shell)
{
const char *name_to_search;
char *value;
name_to_search = skip_dollar(variable_name);
if (ft_strcmp(name_to_search, "?") == 0)
{
value = get_exit_status_str(shell);
return (value);
}
value = search_env_variable(name_to_search, shell);
return (value);
}

57
parsing/variable_utils.c Executable file
View File

@@ -0,0 +1,57 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* variable_utils.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/07 10:46:07 by fgras-ca #+# #+# */
/* Updated: 2023/12/07 14:11:44 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "../minishell.h"
const char *skip_dollar(const char *variable_name)
{
if (variable_name[0] == '$')
return (variable_name + 1);
return (variable_name);
}
void reverse_str(char *str, int length)
{
int start;
int end;
char temp;
start = 0;
end = length - 1;
while (start < end)
{
temp = str[start];
str[start] = str[end];
str[end] = temp;
start++;
end--;
}
}
char *search_env_variable(const char *name_to_search, t_minishell *shell)
{
int i;
char *env_entry;
size_t name_len;
name_len = ft_strlen(name_to_search);
i = 0;
while (shell->environ[i])
{
env_entry = shell->environ[i];
if (ft_strncmp(env_entry, name_to_search, name_len) == 0
&& env_entry[name_len] == '=')
return (ft_strdup(env_entry + name_len + 1));
i++;
}
return (ft_strdup(""));
}