Merge branch 'fix/variable_expansion' into solo
This commit is contained in:
@@ -48,7 +48,10 @@ typedef enum e_redirection_type
|
||||
typedef struct s_redirection
|
||||
{
|
||||
t_token_type type;
|
||||
int io_number;
|
||||
char *target;
|
||||
bool heredoc_expand;
|
||||
bool heredoc_ready;
|
||||
} t_redirection;
|
||||
|
||||
/**
|
||||
@@ -129,6 +132,8 @@ extern void minishell_set_execution_signals(void);
|
||||
|
||||
extern void minishell_set_child_signals(void);
|
||||
|
||||
extern void minishell_set_heredoc_signals(void);
|
||||
|
||||
extern bool minishell_consume_sigint(void);
|
||||
|
||||
/* environment.c */
|
||||
@@ -142,8 +147,7 @@ extern char **get_envp(t_minishell *msh);
|
||||
|
||||
extern void free_envp(char **envp);
|
||||
|
||||
void handle_sigint_status(t_minishell *minishell);
|
||||
bool handle_eof(char *line, t_minishell *minishell);
|
||||
|
||||
extern void handle_sigint_status(t_minishell *minishell);
|
||||
extern bool handle_eof(char *line, t_minishell *minishell);
|
||||
|
||||
#endif /* CORE_H */
|
||||
|
||||
@@ -53,8 +53,12 @@ extern void executor_parent_cleanup(t_list *node, t_pipeline *pl);
|
||||
extern uint8_t executor_wait_for_children(pid_t last_child_pid);
|
||||
extern void executor_cmdfree(t_command *command);
|
||||
extern bool executor_apply_redirections(const t_command *command,
|
||||
int *saved_stdin, int *saved_stdout);
|
||||
int *saved_stdin, int *saved_stdout, int *saved_stderr);
|
||||
extern void executor_restore_redirections(int saved_stdin,
|
||||
int saved_stdout);
|
||||
int saved_stdout, int saved_stderr);
|
||||
extern bool executor_prepare_heredocs(t_list *command_list,
|
||||
t_minishell *minishell, uint8_t *exit_status);
|
||||
extern char *executor_expand_heredoc_line(const char *line,
|
||||
t_minishell *minishell);
|
||||
|
||||
#endif /* EXECUTOR_H */
|
||||
|
||||
@@ -41,8 +41,10 @@ extern void command_clear(t_command *command);
|
||||
extern void command_add_tokens(t_command **command, t_list **tokens);
|
||||
extern bool is_pipe(t_token *token);
|
||||
extern bool is_redirection(t_token *token);
|
||||
void redirection_add(t_list **tokens, t_token *token,
|
||||
t_command **command);
|
||||
bool parser_token_is_fd_prefix(t_list *token_node,
|
||||
int *io_number);
|
||||
void redirection_add_with_fd(t_list **tokens, t_token *token,
|
||||
t_command **command, int io_number);
|
||||
void words_add(t_list **tokens, t_command **command);
|
||||
|
||||
void expand(t_list **commands, t_minishell *minishell);
|
||||
|
||||
5
src/builtins/env/env.c
vendored
5
src/builtins/env/env.c
vendored
@@ -22,8 +22,9 @@ uint8_t builtin_env(
|
||||
{
|
||||
if (cmd.argc > 1)
|
||||
{
|
||||
ft_eputendl("minishell: env: too many arguments");
|
||||
return (EXIT_FAILURE);
|
||||
ft_eprintf("minishell: env: %s: No such file or directory\n",
|
||||
cmd.argv[1]);
|
||||
return (127);
|
||||
}
|
||||
print_env(msh);
|
||||
return (EXIT_SUCCESS);
|
||||
|
||||
@@ -16,6 +16,8 @@ static bool exit_arg_is_invalid(const char *arg)
|
||||
{
|
||||
if (arg == NULL)
|
||||
return (true);
|
||||
if (arg[0] == '\0')
|
||||
return (true);
|
||||
if ((*arg == '+' || *arg == '-') && arg[1] == '\0')
|
||||
return (true);
|
||||
if (!ft_strisnum(arg))
|
||||
|
||||
@@ -12,8 +12,18 @@
|
||||
|
||||
#include "builtins.h"
|
||||
|
||||
static uint8_t is_valid_identifier(const char *arg, size_t name_len);
|
||||
static uint8_t export_one(char *arg, t_minishell *msh);
|
||||
static uint8_t print_exported(t_minishell *msh);
|
||||
static void **entries_to_array(t_list *lst, size_t *count,
|
||||
bool add_oldpwd);
|
||||
static void sort_entries(t_map_entry **entries, size_t count);
|
||||
bool export_is_valid_identifier(const char *arg, size_t name_len);
|
||||
void export_parse_assignment(char *arg, char **eq_pos,
|
||||
size_t *name_len, bool *append);
|
||||
uint8_t export_set_assigned_value(const char *name, char *eq_pos,
|
||||
bool append, t_minishell *msh);
|
||||
bool export_print_declaration(const char *name, const char *value);
|
||||
static t_map_entry g_oldpwd_entry = {"OLDPWD", NULL};
|
||||
|
||||
uint8_t builtin_export(
|
||||
t_command cmd,
|
||||
@@ -21,34 +31,22 @@ uint8_t builtin_export(
|
||||
)
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t result;
|
||||
size_t i;
|
||||
|
||||
if (cmd.argc == 1)
|
||||
return (builtin_env(cmd, msh));
|
||||
return (print_exported(msh));
|
||||
status = EXIT_SUCCESS;
|
||||
i = 0;
|
||||
while (cmd.argv[++i] != NULL)
|
||||
if (export_one(cmd.argv[i], msh) != EXIT_SUCCESS)
|
||||
status = EXIT_FAILURE;
|
||||
return (status);
|
||||
}
|
||||
|
||||
static uint8_t is_valid_identifier(
|
||||
const char *arg,
|
||||
size_t name_len
|
||||
)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (name_len == 0 || arg == NULL)
|
||||
return (0);
|
||||
if (!ft_isalpha(arg[0]) && arg[0] != '_')
|
||||
return (0);
|
||||
i = 0;
|
||||
while (++i < name_len)
|
||||
if (!ft_isalnum(arg[i]) && arg[i] != '_')
|
||||
return (0);
|
||||
return (1);
|
||||
result = export_one(cmd.argv[i], msh);
|
||||
if (result == 2)
|
||||
return (2);
|
||||
if (result != EXIT_SUCCESS)
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
return (status);
|
||||
}
|
||||
|
||||
static uint8_t export_one(
|
||||
@@ -59,21 +57,111 @@ static uint8_t export_one(
|
||||
char *eq_pos;
|
||||
char *name;
|
||||
size_t name_len;
|
||||
bool append;
|
||||
|
||||
eq_pos = ft_strchr(arg, '=');
|
||||
name_len = ft_strlen(arg);
|
||||
if (eq_pos != NULL)
|
||||
name_len = (size_t)(eq_pos - arg);
|
||||
if (!is_valid_identifier(arg, name_len))
|
||||
return (ft_eprintf("minishell: export: `%s': not a valid identifier\n",
|
||||
arg), EXIT_FAILURE);
|
||||
if (arg[0] == '-' && arg[1] != '\0')
|
||||
return (ft_eprintf("minishell: export: %s: invalid option\n", arg),
|
||||
ft_eputendl("export: usage: export [name[=value] ...]"), 2);
|
||||
export_parse_assignment(arg, &eq_pos, &name_len, &append);
|
||||
if (!export_is_valid_identifier(arg, name_len))
|
||||
return (ft_eprintf(
|
||||
"minishell: export: `%s': not a valid identifier\n", arg),
|
||||
EXIT_FAILURE);
|
||||
name = ft_substr(arg, 0, name_len);
|
||||
if (name == NULL)
|
||||
return (EXIT_FAILURE);
|
||||
if (eq_pos != NULL)
|
||||
set_var(name, eq_pos + 1, msh);
|
||||
else
|
||||
set_var(name, "", msh);
|
||||
if (export_set_assigned_value(name, eq_pos, append, msh) != EXIT_SUCCESS)
|
||||
return (free(name), EXIT_FAILURE);
|
||||
free(name);
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static uint8_t print_exported(
|
||||
t_minishell *msh
|
||||
)
|
||||
{
|
||||
t_list *entries;
|
||||
t_map_entry **sorted_entries;
|
||||
size_t count;
|
||||
size_t i;
|
||||
bool add_oldpwd;
|
||||
|
||||
entries = ft_hashmap_entries(msh->variables.environment);
|
||||
if (entries == NULL)
|
||||
return (EXIT_SUCCESS);
|
||||
add_oldpwd = !ft_hashmap_contains_key(msh->variables.environment, "OLDPWD");
|
||||
sorted_entries = (t_map_entry **)entries_to_array(entries, &count,
|
||||
add_oldpwd);
|
||||
ft_lstclear_nodes(&entries);
|
||||
if (sorted_entries == NULL)
|
||||
return (EXIT_FAILURE);
|
||||
sort_entries(sorted_entries, count);
|
||||
i = 0;
|
||||
while (i < count)
|
||||
{
|
||||
if (!export_print_declaration((char *)sorted_entries[i]->key,
|
||||
(char *)sorted_entries[i]->value))
|
||||
return (free(sorted_entries), EXIT_FAILURE);
|
||||
i++;
|
||||
}
|
||||
free(sorted_entries);
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void **entries_to_array(
|
||||
t_list *entries,
|
||||
size_t *count,
|
||||
bool add_oldpwd
|
||||
)
|
||||
{
|
||||
void **array;
|
||||
t_list *node;
|
||||
t_map_entry *entry;
|
||||
size_t i;
|
||||
|
||||
*count = (size_t)ft_lstsize(entries) + (size_t)add_oldpwd;
|
||||
array = (void **)malloc(sizeof(void *) * (*count));
|
||||
if (array == NULL)
|
||||
return (NULL);
|
||||
i = 0;
|
||||
node = entries;
|
||||
while (node != NULL)
|
||||
{
|
||||
entry = (t_map_entry *)node->content;
|
||||
if (entry != NULL && ft_strcmp((char *)entry->key, "_") != 0)
|
||||
array[i++] = entry;
|
||||
node = node->next;
|
||||
}
|
||||
if (add_oldpwd)
|
||||
array[i++] = &g_oldpwd_entry;
|
||||
*count = i;
|
||||
return (array);
|
||||
}
|
||||
|
||||
static void sort_entries(
|
||||
t_map_entry **entries,
|
||||
size_t count
|
||||
)
|
||||
{
|
||||
size_t i;
|
||||
size_t j;
|
||||
t_map_entry *tmp;
|
||||
|
||||
i = 0;
|
||||
while (i < count)
|
||||
{
|
||||
j = i + 1;
|
||||
while (j < count)
|
||||
{
|
||||
if (ft_strcmp((char *)entries[i]->key,
|
||||
(char *)entries[j]->key) > 0)
|
||||
{
|
||||
tmp = entries[i];
|
||||
entries[i] = entries[j];
|
||||
entries[j] = tmp;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
129
src/builtins/export/export_utils.c
Normal file
129
src/builtins/export/export_utils.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* export_utils.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/14 15:20:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/14 15:20:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "builtins.h"
|
||||
|
||||
bool export_is_valid_identifier(
|
||||
const char *arg,
|
||||
size_t name_len
|
||||
)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (name_len == 0 || arg == NULL)
|
||||
return (false);
|
||||
if (!ft_isalpha(arg[0]) && arg[0] != '_')
|
||||
return (false);
|
||||
i = 0;
|
||||
while (++i < name_len)
|
||||
if (!ft_isalnum(arg[i]) && arg[i] != '_')
|
||||
return (false);
|
||||
return (true);
|
||||
}
|
||||
|
||||
void export_parse_assignment(
|
||||
char *arg,
|
||||
char **eq_pos,
|
||||
size_t *name_len,
|
||||
bool *append
|
||||
)
|
||||
{
|
||||
char *plus_eq;
|
||||
|
||||
*append = false;
|
||||
*eq_pos = ft_strchr(arg, '=');
|
||||
*name_len = ft_strlen(arg);
|
||||
plus_eq = ft_strnstr(arg, "+=", *name_len);
|
||||
if (plus_eq != NULL)
|
||||
{
|
||||
*append = true;
|
||||
*name_len = (size_t)(plus_eq - arg);
|
||||
*eq_pos = plus_eq + 1;
|
||||
}
|
||||
else if (*eq_pos != NULL)
|
||||
*name_len = (size_t)(*eq_pos - arg);
|
||||
}
|
||||
|
||||
uint8_t export_set_assigned_value(
|
||||
const char *name,
|
||||
char *eq_pos,
|
||||
bool append,
|
||||
t_minishell *msh
|
||||
)
|
||||
{
|
||||
char *current;
|
||||
char *joined;
|
||||
|
||||
if (append)
|
||||
{
|
||||
current = get_var((char *)name, msh);
|
||||
if (current == NULL)
|
||||
current = "";
|
||||
joined = ft_strnjoin(2, current, eq_pos + 1);
|
||||
if (joined == NULL)
|
||||
return (EXIT_FAILURE);
|
||||
set_var(name, joined, msh);
|
||||
free(joined);
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
if (eq_pos != NULL)
|
||||
set_var(name, eq_pos + 1, msh);
|
||||
else
|
||||
set_var(name, "", msh);
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
char *export_escape_value(
|
||||
const char *value
|
||||
)
|
||||
{
|
||||
char *escaped;
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
escaped = (char *)malloc((ft_strlen(value) * 2) + 1);
|
||||
if (escaped == NULL)
|
||||
return (NULL);
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (value[i] != '\0')
|
||||
{
|
||||
if (value[i] == '\\' || value[i] == '\"' || value[i] == '$')
|
||||
escaped[j++] = '\\';
|
||||
escaped[j++] = value[i++];
|
||||
}
|
||||
escaped[j] = '\0';
|
||||
return (escaped);
|
||||
}
|
||||
|
||||
bool export_print_declaration(
|
||||
const char *name,
|
||||
const char *value
|
||||
)
|
||||
{
|
||||
char *escaped;
|
||||
|
||||
ft_putstr("declare -x ");
|
||||
ft_putstr((char *)name);
|
||||
if (value != NULL)
|
||||
{
|
||||
escaped = export_escape_value(value);
|
||||
if (escaped == NULL)
|
||||
return (false);
|
||||
ft_putstr("=\"");
|
||||
ft_putstr(escaped);
|
||||
ft_putstr("\"");
|
||||
free(escaped);
|
||||
}
|
||||
ft_putchar('\n');
|
||||
return (true);
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
static uint8_t is_valid_identifier(const char *arg);
|
||||
static uint8_t unset_one(char *arg, t_minishell *msh);
|
||||
static bool is_option(const char *arg);
|
||||
|
||||
uint8_t builtin_unset(
|
||||
t_command cmd,
|
||||
@@ -21,13 +22,19 @@ uint8_t builtin_unset(
|
||||
)
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t result;
|
||||
size_t i;
|
||||
|
||||
status = EXIT_SUCCESS;
|
||||
i = 0;
|
||||
while (cmd.argv[++i] != NULL)
|
||||
if (unset_one(cmd.argv[i], msh) != EXIT_SUCCESS)
|
||||
{
|
||||
result = unset_one(cmd.argv[i], msh);
|
||||
if (result == 2)
|
||||
return (2);
|
||||
if (result != EXIT_SUCCESS)
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
return (status);
|
||||
}
|
||||
|
||||
@@ -53,9 +60,21 @@ static uint8_t unset_one(
|
||||
t_minishell *msh
|
||||
)
|
||||
{
|
||||
if (is_option(arg))
|
||||
{
|
||||
ft_eprintf("minishell: unset: %s: invalid option\n", arg);
|
||||
ft_eputendl("unset: usage: unset [name ...]");
|
||||
return (2);
|
||||
}
|
||||
if (!is_valid_identifier(arg))
|
||||
return (ft_eprintf("minishell: unset: `%s': not a valid identifier\n",
|
||||
arg), EXIT_FAILURE);
|
||||
return (EXIT_SUCCESS);
|
||||
unset_env(arg, msh);
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static bool is_option(
|
||||
const char *arg
|
||||
)
|
||||
{
|
||||
return (arg != NULL && arg[0] == '-' && arg[1] != '\0');
|
||||
}
|
||||
|
||||
@@ -13,11 +13,19 @@
|
||||
#include "core.h"
|
||||
|
||||
static int g_signal = 0;
|
||||
static bool g_heredoc_mode = false;
|
||||
|
||||
static void sigint_handler(int signal)
|
||||
{
|
||||
g_signal = signal;
|
||||
write(STDOUT_FILENO, "\n", 1);
|
||||
if (g_heredoc_mode)
|
||||
{
|
||||
rl_on_new_line();
|
||||
rl_replace_line("", 0);
|
||||
rl_done = 1;
|
||||
return ;
|
||||
}
|
||||
rl_on_new_line();
|
||||
rl_replace_line("", 0);
|
||||
rl_redisplay();
|
||||
@@ -28,6 +36,7 @@ void minishell_set_interactive_signals(void)
|
||||
struct sigaction action;
|
||||
|
||||
ft_bzero(&action, sizeof(action));
|
||||
g_heredoc_mode = false;
|
||||
action.sa_handler = sigint_handler;
|
||||
sigemptyset(&action.sa_mask);
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
@@ -40,20 +49,23 @@ void minishell_set_execution_signals(void)
|
||||
struct sigaction action;
|
||||
|
||||
ft_bzero(&action, sizeof(action));
|
||||
g_heredoc_mode = false;
|
||||
action.sa_handler = SIG_IGN;
|
||||
sigemptyset(&action.sa_mask);
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
sigaction(SIGQUIT, &action, NULL);
|
||||
}
|
||||
|
||||
void minishell_set_child_signals(void)
|
||||
void minishell_set_heredoc_signals(void)
|
||||
{
|
||||
struct sigaction action;
|
||||
|
||||
ft_bzero(&action, sizeof(action));
|
||||
action.sa_handler = SIG_DFL;
|
||||
g_heredoc_mode = true;
|
||||
action.sa_handler = sigint_handler;
|
||||
sigemptyset(&action.sa_mask);
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
action.sa_handler = SIG_IGN;
|
||||
sigaction(SIGQUIT, &action, NULL);
|
||||
}
|
||||
|
||||
|
||||
24
src/core/signals_child.c
Normal file
24
src/core/signals_child.c
Normal file
@@ -0,0 +1,24 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* signals_child.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/14 18:20:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/14 18:20:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "core.h"
|
||||
|
||||
void minishell_set_child_signals(void)
|
||||
{
|
||||
struct sigaction action;
|
||||
|
||||
ft_bzero(&action, sizeof(action));
|
||||
action.sa_handler = SIG_DFL;
|
||||
sigemptyset(&action.sa_mask);
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
sigaction(SIGQUIT, &action, NULL);
|
||||
}
|
||||
@@ -35,6 +35,9 @@ static void cmdfree_redirection(
|
||||
{
|
||||
if (redirection == NULL)
|
||||
return ;
|
||||
if (redirection->type == TOKEN_HEREDOC && redirection->heredoc_ready
|
||||
&& redirection->target != NULL)
|
||||
unlink(redirection->target);
|
||||
free(redirection->target);
|
||||
free(redirection);
|
||||
}
|
||||
|
||||
@@ -48,13 +48,15 @@ static void run_command_in_parent(
|
||||
t_command *command;
|
||||
int saved_stdin;
|
||||
int saved_stdout;
|
||||
int saved_stderr;
|
||||
|
||||
command = state->current_command->content;
|
||||
if (!executor_apply_redirections(command, &saved_stdin, &saved_stdout))
|
||||
if (!executor_apply_redirections(command, &saved_stdin, &saved_stdout,
|
||||
&saved_stderr))
|
||||
state->exit_status = EXIT_FAILURE;
|
||||
else
|
||||
state->exit_status = executor_execute_command(command, minishell);
|
||||
executor_restore_redirections(saved_stdin, saved_stdout);
|
||||
executor_restore_redirections(saved_stdin, saved_stdout, saved_stderr);
|
||||
}
|
||||
|
||||
static bool run_current_command(
|
||||
@@ -89,6 +91,12 @@ uint8_t execute(
|
||||
t_exec_state state;
|
||||
|
||||
init_exec_state(&state, command_list);
|
||||
if (!executor_prepare_heredocs(command_list, minishell, &state.exit_status))
|
||||
{
|
||||
minishell->exit_status = state.exit_status;
|
||||
ft_lstclear(&command_list, (void (*)(void *))executor_cmdfree);
|
||||
return (state.exit_status);
|
||||
}
|
||||
minishell_set_execution_signals();
|
||||
while (state.current_command)
|
||||
{
|
||||
|
||||
65
src/executor/heredoc.c
Normal file
65
src/executor/heredoc.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* heredoc.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/14 17:50:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/14 17:50:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "heredoc_internal.h"
|
||||
#include "errors.h"
|
||||
|
||||
static bool prepare_heredoc_redirection(t_redirection *rd,
|
||||
t_minishell *minishell, uint8_t *exit_status)
|
||||
{
|
||||
char *path;
|
||||
int fd;
|
||||
|
||||
path = NULL;
|
||||
fd = executor_heredoc_open_tmp(&path);
|
||||
if (fd == -1)
|
||||
return (perror("open"), *exit_status = EXIT_FAILURE, false);
|
||||
if (!executor_heredoc_fill_tmp(fd, rd, minishell, exit_status))
|
||||
return (executor_heredoc_discard_tmp(fd, path), false);
|
||||
return (executor_heredoc_finalize_tmp(rd, fd, path, exit_status));
|
||||
}
|
||||
|
||||
static bool process_command_heredocs(t_command *command, t_minishell *minishell,
|
||||
uint8_t *exit_status)
|
||||
{
|
||||
t_list *redir_node;
|
||||
t_redirection *rd;
|
||||
|
||||
redir_node = command->redirections;
|
||||
while (redir_node != NULL)
|
||||
{
|
||||
rd = (t_redirection *)redir_node->content;
|
||||
if (rd->type == TOKEN_HEREDOC
|
||||
&& !prepare_heredoc_redirection(rd, minishell, exit_status))
|
||||
return (false);
|
||||
redir_node = redir_node->next;
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool executor_prepare_heredocs(t_list *command_list, t_minishell *minishell,
|
||||
uint8_t *exit_status)
|
||||
{
|
||||
t_command *command;
|
||||
|
||||
*exit_status = EXIT_SUCCESS;
|
||||
minishell_set_heredoc_signals();
|
||||
while (command_list != NULL)
|
||||
{
|
||||
command = (t_command *)command_list->content;
|
||||
if (!process_command_heredocs(command, minishell, exit_status))
|
||||
return (minishell_set_interactive_signals(), false);
|
||||
command_list = command_list->next;
|
||||
}
|
||||
minishell_set_interactive_signals();
|
||||
return (true);
|
||||
}
|
||||
98
src/executor/heredoc_expand.c
Normal file
98
src/executor/heredoc_expand.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* heredoc_expand.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/14 17:30:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/14 17:30:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "executor.h"
|
||||
#include "variables.h"
|
||||
#include "errors.h"
|
||||
|
||||
static bool is_var_char(char c)
|
||||
{
|
||||
return (ft_isalnum(c) || c == '_');
|
||||
}
|
||||
|
||||
static bool append_text(char **result, const char *value)
|
||||
{
|
||||
char *joined;
|
||||
|
||||
joined = ft_strnjoin(2, *result, (char *)value);
|
||||
if (joined == NULL)
|
||||
{
|
||||
free(*result);
|
||||
*result = NULL;
|
||||
return (false);
|
||||
}
|
||||
free(*result);
|
||||
*result = joined;
|
||||
return (true);
|
||||
}
|
||||
|
||||
static char *expand_variable(const char *line, size_t *i, t_minishell *msh)
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
size_t start;
|
||||
|
||||
(*i)++;
|
||||
if (line[*i] == '?')
|
||||
return ((*i)++, ft_itoa(msh->exit_status));
|
||||
if (line[*i] == '\0' || !is_var_char(line[*i]))
|
||||
return (ft_strdup("$"));
|
||||
start = *i;
|
||||
while (line[*i] != '\0' && is_var_char(line[*i]))
|
||||
(*i)++;
|
||||
name = ft_substr(line, start, *i - start);
|
||||
if (name == NULL)
|
||||
return (NULL);
|
||||
value = get_var(name, msh);
|
||||
free(name);
|
||||
if (value == NULL)
|
||||
value = "";
|
||||
return (ft_strdup(value));
|
||||
}
|
||||
|
||||
static char *expand_literal_char(const char *line, size_t *i)
|
||||
{
|
||||
char value[2];
|
||||
|
||||
value[0] = line[*i];
|
||||
value[1] = '\0';
|
||||
(*i)++;
|
||||
return (ft_strdup(value));
|
||||
}
|
||||
|
||||
char *executor_expand_heredoc_line(
|
||||
const char *line,
|
||||
t_minishell *minishell
|
||||
)
|
||||
{
|
||||
char *result;
|
||||
char *expanded;
|
||||
size_t i;
|
||||
|
||||
result = ft_strdup("");
|
||||
if (result == NULL)
|
||||
return (malloc_error(), NULL);
|
||||
i = 0;
|
||||
while (line[i] != '\0')
|
||||
{
|
||||
if (line[i] == '$')
|
||||
expanded = expand_variable(line, &i, minishell);
|
||||
else
|
||||
expanded = expand_literal_char(line, &i);
|
||||
if (expanded == NULL)
|
||||
return (free(result), malloc_error(), NULL);
|
||||
if (!append_text(&result, expanded))
|
||||
return (free(expanded), malloc_error(), NULL);
|
||||
free(expanded);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
99
src/executor/heredoc_file.c
Normal file
99
src/executor/heredoc_file.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* heredoc_file.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/14 17:50:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/14 17:50:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "heredoc_internal.h"
|
||||
#include <errno.h>
|
||||
#include "variables.h"
|
||||
|
||||
static char *build_tmp_path(unsigned int id)
|
||||
{
|
||||
char *suffix;
|
||||
char *path;
|
||||
|
||||
suffix = ft_uitoa(id);
|
||||
if (suffix == NULL)
|
||||
return (errno = ENOMEM, NULL);
|
||||
path = ft_strnjoin(2, "/tmp/minishell_heredoc_", suffix);
|
||||
free(suffix);
|
||||
if (path == NULL)
|
||||
return (errno = ENOMEM, NULL);
|
||||
return (path);
|
||||
}
|
||||
|
||||
int executor_heredoc_open_tmp(char **path_out)
|
||||
{
|
||||
static unsigned int counter;
|
||||
char *path;
|
||||
unsigned int attempts;
|
||||
int fd;
|
||||
|
||||
attempts = 0;
|
||||
while (attempts++ < 10000)
|
||||
{
|
||||
path = build_tmp_path(counter++);
|
||||
if (path == NULL)
|
||||
return (-1);
|
||||
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600);
|
||||
if (fd != -1)
|
||||
return (*path_out = path, fd);
|
||||
free(path);
|
||||
if (errno != EEXIST)
|
||||
return (-1);
|
||||
}
|
||||
errno = EEXIST;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
char *executor_heredoc_read_line(t_minishell *minishell)
|
||||
{
|
||||
char *prompt;
|
||||
char *line;
|
||||
size_t len;
|
||||
|
||||
if (!isatty(STDIN_FILENO))
|
||||
{
|
||||
line = get_next_line(STDIN_FILENO);
|
||||
if (line == NULL)
|
||||
return (NULL);
|
||||
len = ft_strlen(line);
|
||||
if (len > 0 && line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
return (line);
|
||||
}
|
||||
prompt = get_var("PS2", minishell);
|
||||
if (prompt == NULL)
|
||||
prompt = DEFAULT_PS2;
|
||||
return (readline(prompt));
|
||||
}
|
||||
|
||||
void executor_heredoc_discard_tmp(int fd, char *path)
|
||||
{
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (path != NULL)
|
||||
{
|
||||
unlink(path);
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
bool executor_heredoc_finalize_tmp(t_redirection *rd, int fd, char *path,
|
||||
uint8_t *exit_status)
|
||||
{
|
||||
if (close(fd) == -1)
|
||||
return (executor_heredoc_discard_tmp(-1, path), perror("close"),
|
||||
*exit_status = EXIT_FAILURE, false);
|
||||
free(rd->target);
|
||||
rd->target = path;
|
||||
rd->heredoc_ready = true;
|
||||
return (true);
|
||||
}
|
||||
80
src/executor/heredoc_input.c
Normal file
80
src/executor/heredoc_input.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* heredoc_input.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/14 17:50:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/14 17:50:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "heredoc_internal.h"
|
||||
#include "errors.h"
|
||||
|
||||
static bool write_all(int fd, const char *buffer, size_t len)
|
||||
{
|
||||
size_t total;
|
||||
ssize_t written;
|
||||
|
||||
total = 0;
|
||||
while (total < len)
|
||||
{
|
||||
written = write(fd, buffer + total, len - total);
|
||||
if (written <= 0)
|
||||
return (false);
|
||||
total += written;
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
static bool write_heredoc_line(int fd, const char *line)
|
||||
{
|
||||
if (!write_all(fd, line, ft_strlen(line)))
|
||||
return (false);
|
||||
return (write_all(fd, "\n", 1));
|
||||
}
|
||||
|
||||
static bool handle_heredoc_line(int fd, char *line, t_redirection *rd,
|
||||
t_minishell *minishell)
|
||||
{
|
||||
char *expanded;
|
||||
|
||||
expanded = line;
|
||||
if (rd->heredoc_expand)
|
||||
{
|
||||
expanded = executor_expand_heredoc_line(line, minishell);
|
||||
free(line);
|
||||
if (expanded == NULL)
|
||||
return (false);
|
||||
}
|
||||
if (!write_heredoc_line(fd, expanded))
|
||||
return (free(expanded), perror("write"), false);
|
||||
free(expanded);
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool executor_heredoc_fill_tmp(int fd, t_redirection *rd,
|
||||
t_minishell *minishell, uint8_t *exit_status)
|
||||
{
|
||||
char *line;
|
||||
|
||||
while (1)
|
||||
{
|
||||
line = executor_heredoc_read_line(minishell);
|
||||
if (minishell_consume_sigint())
|
||||
return (free(line), *exit_status = 130, false);
|
||||
if (line == NULL)
|
||||
{
|
||||
if (!isatty(STDIN_FILENO))
|
||||
minishell->exit = true;
|
||||
return (ft_eprintf("minishell: warning: here-document delimited by "
|
||||
"end-of-file (wanted `%s')\n", rd->target), true);
|
||||
}
|
||||
if (ft_strcmp(line, rd->target) == 0)
|
||||
return (free(line), true);
|
||||
if (!handle_heredoc_line(fd, line, rd, minishell))
|
||||
return (*exit_status = EXIT_FAILURE, false);
|
||||
}
|
||||
}
|
||||
26
src/executor/heredoc_internal.h
Normal file
26
src/executor/heredoc_internal.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* heredoc_internal.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/14 17:50:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/14 17:50:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef HEREDOC_INTERNAL_H
|
||||
# define HEREDOC_INTERNAL_H
|
||||
|
||||
# include "executor.h"
|
||||
|
||||
char *executor_heredoc_read_line(t_minishell *minishell);
|
||||
int executor_heredoc_open_tmp(char **path_out);
|
||||
void executor_heredoc_discard_tmp(int fd, char *path);
|
||||
bool executor_heredoc_finalize_tmp(t_redirection *rd, int fd, char *path,
|
||||
uint8_t *exit_status);
|
||||
bool executor_heredoc_fill_tmp(int fd, t_redirection *rd,
|
||||
t_minishell *minishell, uint8_t *exit_status);
|
||||
|
||||
#endif
|
||||
@@ -53,7 +53,7 @@ void executor_child_process(
|
||||
minishell_set_child_signals();
|
||||
executor_setup_child_input(pipeline);
|
||||
executor_setup_child_output(current_command, pipeline);
|
||||
if (!executor_apply_redirections(command, NULL, NULL))
|
||||
if (!executor_apply_redirections(command, NULL, NULL, NULL))
|
||||
exit(EXIT_FAILURE);
|
||||
exit_status = executor_execute_command(command, minishell);
|
||||
exit(exit_status);
|
||||
|
||||
@@ -19,6 +19,8 @@ static int open_redirection_target(
|
||||
{
|
||||
if (redirection->type == TOKEN_REDIRECT_IN)
|
||||
return (open(redirection->target, O_RDONLY));
|
||||
if (redirection->type == TOKEN_HEREDOC)
|
||||
return (open(redirection->target, O_RDONLY));
|
||||
if (redirection->type == TOKEN_REDIRECT_OUT)
|
||||
return (open(redirection->target, O_WRONLY | O_CREAT | O_TRUNC, 0644));
|
||||
if (redirection->type == TOKEN_APPEND)
|
||||
@@ -27,73 +29,74 @@ static int open_redirection_target(
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static bool backup_stream_if_needed(
|
||||
const t_redirection *redirection,
|
||||
int *saved_stdin,
|
||||
int *saved_stdout
|
||||
static bool backup_fd_if_needed(
|
||||
int io_number,
|
||||
int *saved_fd
|
||||
)
|
||||
{
|
||||
if (redirection->type == TOKEN_REDIRECT_IN && saved_stdin != NULL
|
||||
&& *saved_stdin == -1)
|
||||
{
|
||||
*saved_stdin = dup(STDIN_FILENO);
|
||||
if (*saved_stdin == -1)
|
||||
return (perror("dup"), false);
|
||||
}
|
||||
if ((redirection->type == TOKEN_REDIRECT_OUT
|
||||
|| redirection->type == TOKEN_APPEND) && saved_stdout != NULL
|
||||
&& *saved_stdout == -1)
|
||||
{
|
||||
*saved_stdout = dup(STDOUT_FILENO);
|
||||
if (*saved_stdout == -1)
|
||||
return (perror("dup"), false);
|
||||
}
|
||||
if (saved_fd == NULL || *saved_fd != -1)
|
||||
return (true);
|
||||
*saved_fd = dup(io_number);
|
||||
if (*saved_fd == -1)
|
||||
return (perror("dup"), false);
|
||||
return (true);
|
||||
}
|
||||
|
||||
static bool apply_redirection(
|
||||
const t_redirection *redirection,
|
||||
int *saved_stdin,
|
||||
int *saved_stdout,
|
||||
int *saved_stderr
|
||||
)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (redirection == NULL || redirection->target == NULL)
|
||||
return (false);
|
||||
if ((redirection->io_number == STDIN_FILENO
|
||||
&& !backup_fd_if_needed(STDIN_FILENO, saved_stdin))
|
||||
|| (redirection->io_number == STDOUT_FILENO
|
||||
&& !backup_fd_if_needed(STDOUT_FILENO, saved_stdout))
|
||||
|| (redirection->io_number == STDERR_FILENO
|
||||
&& !backup_fd_if_needed(STDERR_FILENO, saved_stderr)))
|
||||
return (false);
|
||||
fd = open_redirection_target(redirection);
|
||||
if (fd == -1)
|
||||
return (perror(redirection->target), false);
|
||||
if (dup2(fd, redirection->io_number) == -1)
|
||||
return (close(fd), perror("dup2"), false);
|
||||
return (close(fd), true);
|
||||
}
|
||||
|
||||
bool executor_apply_redirections(
|
||||
const t_command *command,
|
||||
int *saved_stdin,
|
||||
int *saved_stdout
|
||||
int *saved_stdout,
|
||||
int *saved_stderr
|
||||
)
|
||||
{
|
||||
t_list *node;
|
||||
t_redirection *redirection;
|
||||
int fd;
|
||||
|
||||
if (saved_stdin != NULL)
|
||||
*saved_stdin = -1;
|
||||
if (saved_stdout != NULL)
|
||||
*saved_stdout = -1;
|
||||
if (command == NULL || command->redirections == NULL)
|
||||
if (saved_stderr != NULL)
|
||||
*saved_stderr = -1;
|
||||
if (command == NULL)
|
||||
return (true);
|
||||
node = command->redirections;
|
||||
while (node != NULL)
|
||||
{
|
||||
redirection = (t_redirection *)node->content;
|
||||
if (redirection == NULL || redirection->target == NULL)
|
||||
return (false);
|
||||
if (!backup_stream_if_needed(redirection, saved_stdin, saved_stdout))
|
||||
return (false);
|
||||
fd = open_redirection_target(redirection);
|
||||
if (fd == -1)
|
||||
return (perror(redirection->target), false);
|
||||
if (redirection->type == TOKEN_REDIRECT_IN
|
||||
&& dup2(fd, STDIN_FILENO) == -1)
|
||||
return (close(fd), perror("dup2"), false);
|
||||
if ((redirection->type == TOKEN_REDIRECT_OUT
|
||||
|| redirection->type == TOKEN_APPEND)
|
||||
&& dup2(fd, STDOUT_FILENO) == -1)
|
||||
return (close(fd), perror("dup2"), false);
|
||||
close(fd);
|
||||
while (node != NULL
|
||||
&& apply_redirection((t_redirection *)node->content,
|
||||
saved_stdin, saved_stdout, saved_stderr))
|
||||
node = node->next;
|
||||
}
|
||||
return (true);
|
||||
return (node == NULL);
|
||||
}
|
||||
|
||||
void executor_restore_redirections(
|
||||
int saved_stdin,
|
||||
int saved_stdout
|
||||
int saved_stdout,
|
||||
int saved_stderr
|
||||
)
|
||||
{
|
||||
if (saved_stdin != -1)
|
||||
@@ -108,4 +111,10 @@ void executor_restore_redirections(
|
||||
perror("dup2");
|
||||
close(saved_stdout);
|
||||
}
|
||||
if (saved_stderr != -1)
|
||||
{
|
||||
if (dup2(saved_stderr, STDERR_FILENO) == -1)
|
||||
perror("dup2");
|
||||
close(saved_stderr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +58,18 @@ void command_add_tokens(
|
||||
)
|
||||
{
|
||||
t_token *token;
|
||||
int io_number;
|
||||
|
||||
token = (t_token *)(*tokens)->content;
|
||||
if (parser_token_is_fd_prefix(*tokens, &io_number))
|
||||
{
|
||||
*tokens = (*tokens)->next;
|
||||
token = (t_token *)(*tokens)->content;
|
||||
redirection_add_with_fd(tokens, token, command, io_number);
|
||||
return ;
|
||||
}
|
||||
if (is_redirection(token))
|
||||
redirection_add(tokens, token, command);
|
||||
redirection_add_with_fd(tokens, token, command, -1);
|
||||
else
|
||||
words_add(tokens, command);
|
||||
}
|
||||
|
||||
54
src/parser/parser_command_fd.c
Normal file
54
src/parser/parser_command_fd.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* parser_command_fd.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/14 16:40:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/14 16:40:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "parser.h"
|
||||
#include <limits.h>
|
||||
|
||||
static bool parse_io_number(const char *value, int *io_number)
|
||||
{
|
||||
long number;
|
||||
size_t i;
|
||||
|
||||
if (value == NULL || value[0] == '\0')
|
||||
return (false);
|
||||
number = 0;
|
||||
i = 0;
|
||||
while (value[i] != '\0')
|
||||
{
|
||||
if (!ft_isdigit(value[i]))
|
||||
return (false);
|
||||
if (number > (INT_MAX - (value[i] - '0')) / 10)
|
||||
return (false);
|
||||
number = (number * 10) + (value[i] - '0');
|
||||
i++;
|
||||
}
|
||||
*io_number = (int)number;
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool parser_token_is_fd_prefix(
|
||||
t_list *token_node,
|
||||
int *io_number
|
||||
)
|
||||
{
|
||||
t_token *token;
|
||||
t_token *next_token;
|
||||
|
||||
if (token_node == NULL || token_node->next == NULL)
|
||||
return (false);
|
||||
token = (t_token *)token_node->content;
|
||||
next_token = (t_token *)token_node->next->content;
|
||||
if (token == NULL || next_token == NULL || token->type != TOKEN_WORD
|
||||
|| !is_redirection(next_token))
|
||||
return (false);
|
||||
return (parse_io_number(token->value, io_number));
|
||||
}
|
||||
@@ -91,16 +91,17 @@ static bool expand_argv(
|
||||
|
||||
static bool expand_redirections(
|
||||
t_list *redirections,
|
||||
t_minishell *minishell,
|
||||
bool expand_vars
|
||||
t_minishell *minishell
|
||||
)
|
||||
{
|
||||
t_redirection *redirection;
|
||||
char *expanded;
|
||||
bool expand_vars;
|
||||
|
||||
while (redirections != NULL)
|
||||
{
|
||||
redirection = (t_redirection *)redirections->content;
|
||||
expand_vars = (redirection->type != TOKEN_HEREDOC);
|
||||
expanded = parser_expand_word(redirection->target, minishell,
|
||||
expand_vars);
|
||||
if (expanded == NULL)
|
||||
@@ -127,8 +128,8 @@ void expand(
|
||||
{
|
||||
command = (t_command *)current->content;
|
||||
if (!expand_argv(command, minishell)
|
||||
|| !expand_redirections(command->redirections, minishell, true)
|
||||
|| !expand_redirections(command->heredocs, minishell, false))
|
||||
|| !expand_redirections(command->redirections, minishell)
|
||||
|| !expand_redirections(command->heredocs, minishell))
|
||||
{
|
||||
ft_lstclear(commands, (void (*)(void *))command_clear);
|
||||
*commands = NULL;
|
||||
|
||||
@@ -63,6 +63,20 @@ static bool process_word_fields(
|
||||
return (true);
|
||||
}
|
||||
|
||||
static bool set_empty_word_field(
|
||||
t_list **fields,
|
||||
t_minishell *minishell
|
||||
)
|
||||
{
|
||||
t_list *node;
|
||||
|
||||
node = ft_lstnew(ft_strdup(""));
|
||||
if (node == NULL || node->content == NULL)
|
||||
return (free(node), parser_expand_malloc_error(minishell), false);
|
||||
*fields = node;
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool parser_expand_word_fields(
|
||||
const char *word,
|
||||
t_minishell *minishell,
|
||||
@@ -75,6 +89,8 @@ bool parser_expand_word_fields(
|
||||
t_fields_ctx ctx;
|
||||
|
||||
*fields = NULL;
|
||||
if (word[0] == '\0')
|
||||
return (set_empty_word_field(fields, minishell));
|
||||
current = ft_strdup("");
|
||||
if (current == NULL)
|
||||
return (parser_expand_malloc_error(minishell), false);
|
||||
|
||||
85
src/parser/parser_expand_fields_escape.c
Normal file
85
src/parser/parser_expand_fields_escape.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* parser_expand_fields_escape.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/14 16:40:00 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/14 16:40:00 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "parser_expand_internal.h"
|
||||
|
||||
static bool is_backslash_escaped_in_double_quote(
|
||||
char c
|
||||
)
|
||||
{
|
||||
return (c == '$' || c == '\"' || c == '\\');
|
||||
}
|
||||
|
||||
static char get_escaped_char(
|
||||
const char *word,
|
||||
size_t *i
|
||||
)
|
||||
{
|
||||
char value;
|
||||
|
||||
if (word[*i + 1] == '\0')
|
||||
value = word[(*i)++];
|
||||
else
|
||||
{
|
||||
value = word[*i + 1];
|
||||
*i += 2;
|
||||
}
|
||||
return (value);
|
||||
}
|
||||
|
||||
bool parser_fields_handle_backslash(
|
||||
const char *word,
|
||||
size_t *i,
|
||||
t_fields_ctx ctx,
|
||||
bool *handled
|
||||
)
|
||||
{
|
||||
char value[2];
|
||||
|
||||
*handled = false;
|
||||
if (word[*i] != '\\' || *ctx.in_single_quote)
|
||||
return (true);
|
||||
if (*ctx.in_double_quote
|
||||
&& !is_backslash_escaped_in_double_quote(word[*i + 1]))
|
||||
return (true);
|
||||
*handled = true;
|
||||
value[0] = get_escaped_char(word, i);
|
||||
value[1] = '\0';
|
||||
if (!parser_fields_append_text(ctx.current, value, ctx.minishell))
|
||||
return (false);
|
||||
*ctx.touched = true;
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool parser_fields_expand_tilde(
|
||||
const char *word,
|
||||
size_t *i,
|
||||
t_fields_ctx ctx,
|
||||
bool *handled
|
||||
)
|
||||
{
|
||||
char *home;
|
||||
|
||||
*handled = false;
|
||||
if (word[*i] != '~' || *ctx.in_single_quote || *ctx.in_double_quote
|
||||
|| *i != 0 || (word[*i + 1] != '\0' && word[*i + 1] != '/'))
|
||||
return (true);
|
||||
home = get_var("HOME", ctx.minishell);
|
||||
if (home == NULL)
|
||||
return (true);
|
||||
*handled = true;
|
||||
(*i)++;
|
||||
if (!parser_fields_append_text(ctx.current, home, ctx.minishell))
|
||||
return (false);
|
||||
*ctx.touched = true;
|
||||
return (true);
|
||||
}
|
||||
@@ -90,6 +90,14 @@ bool parser_fields_step(
|
||||
|
||||
if (handle_quote_char(word, i, ctx))
|
||||
return (true);
|
||||
if (!parser_fields_handle_backslash(word, i, ctx, &handled))
|
||||
return (false);
|
||||
if (handled)
|
||||
return (true);
|
||||
if (!parser_fields_expand_tilde(word, i, ctx, &handled))
|
||||
return (false);
|
||||
if (handled)
|
||||
return (true);
|
||||
if (skip_dollar_quote_prefix(word, i, ctx))
|
||||
return (true);
|
||||
if (!expand_dollar_token(word, i, ctx, &handled))
|
||||
|
||||
@@ -32,6 +32,10 @@ bool parser_fields_push_field(t_fields_ctx ctx);
|
||||
bool parser_fields_expand_unquoted_value(t_fields_ctx ctx,
|
||||
const char *expanded);
|
||||
bool parser_fields_step(const char *word, size_t *i, t_fields_ctx ctx);
|
||||
bool parser_fields_handle_backslash(const char *word, size_t *i,
|
||||
t_fields_ctx ctx, bool *handled);
|
||||
bool parser_fields_expand_tilde(const char *word, size_t *i,
|
||||
t_fields_ctx ctx, bool *handled);
|
||||
|
||||
typedef struct s_word_ctx
|
||||
{
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#include "parser.h"
|
||||
#include "errors.h"
|
||||
|
||||
static t_redirection *redirection_new(t_list **tokens);
|
||||
static t_redirection *redirection_new(t_list **tokens, int io_number);
|
||||
static bool redirection_read_target(t_redirection *rd, t_list **tk);
|
||||
static bool has_quote_char(const char *value);
|
||||
|
||||
/**
|
||||
* @brief Creates a new redirection from a list of tokens.
|
||||
@@ -23,7 +25,8 @@ static t_redirection *redirection_new(t_list **tokens);
|
||||
* @return A new redirection or `NULL` on error.
|
||||
*/
|
||||
static t_redirection *redirection_new(
|
||||
t_list **tokens
|
||||
t_list **tokens,
|
||||
int io_number
|
||||
)
|
||||
{
|
||||
t_redirection *redirection;
|
||||
@@ -34,28 +37,62 @@ static t_redirection *redirection_new(
|
||||
return (malloc_error(), NULL);
|
||||
token = (t_token *)(*tokens)->content;
|
||||
redirection->type = token->type;
|
||||
*tokens = (*tokens)->next;
|
||||
if (*tokens == NULL)
|
||||
{
|
||||
free(redirection);
|
||||
return (syntax_error_unexpected_token(NULL), NULL);
|
||||
redirection->heredoc_expand = true;
|
||||
redirection->heredoc_ready = false;
|
||||
if (io_number < 0)
|
||||
redirection->io_number = STDOUT_FILENO;
|
||||
else
|
||||
redirection->io_number = io_number;
|
||||
if (io_number < 0 && (token->type == TOKEN_REDIRECT_IN
|
||||
|| token->type == TOKEN_HEREDOC))
|
||||
redirection->io_number = STDIN_FILENO;
|
||||
if (!redirection_read_target(redirection, tokens))
|
||||
return (free(redirection), NULL);
|
||||
return (redirection);
|
||||
}
|
||||
token = (t_token *)(*tokens)->content;
|
||||
|
||||
static bool redirection_read_target(
|
||||
t_redirection *rd,
|
||||
t_list **tk
|
||||
)
|
||||
{
|
||||
t_token *token;
|
||||
|
||||
*tk = (*tk)->next;
|
||||
if (*tk == NULL)
|
||||
return (syntax_error_unexpected_token(NULL), false);
|
||||
token = (t_token *)(*tk)->content;
|
||||
if (token->type != TOKEN_WORD)
|
||||
{
|
||||
free(redirection);
|
||||
while (*tokens != NULL)
|
||||
*tokens = (*tokens)->next;
|
||||
return (syntax_error_unexpected_token(token), NULL);
|
||||
while (*tk != NULL)
|
||||
*tk = (*tk)->next;
|
||||
return (syntax_error_unexpected_token(token), false);
|
||||
}
|
||||
redirection->target = ft_strdup(token->value);
|
||||
if (redirection->target == NULL)
|
||||
if (rd->type == TOKEN_HEREDOC && has_quote_char(token->value))
|
||||
rd->heredoc_expand = false;
|
||||
rd->target = ft_strdup(token->value);
|
||||
if (rd->target == NULL)
|
||||
return (malloc_error(), false);
|
||||
*tk = (*tk)->next;
|
||||
return (true);
|
||||
}
|
||||
|
||||
static bool has_quote_char(
|
||||
const char *value
|
||||
)
|
||||
{
|
||||
free(redirection);
|
||||
return (malloc_error(), NULL);
|
||||
size_t i;
|
||||
|
||||
if (value == NULL)
|
||||
return (false);
|
||||
i = 0;
|
||||
while (value[i] != '\0')
|
||||
{
|
||||
if (value[i] == '\'' || value[i] == '\"')
|
||||
return (true);
|
||||
i++;
|
||||
}
|
||||
*tokens = (*tokens)->next;
|
||||
return (redirection);
|
||||
return (false);
|
||||
}
|
||||
|
||||
void redirection_clear(
|
||||
@@ -69,16 +106,17 @@ void redirection_clear(
|
||||
}
|
||||
}
|
||||
|
||||
void redirection_add(
|
||||
void redirection_add_with_fd(
|
||||
t_list **tokens,
|
||||
t_token *token,
|
||||
t_command **command
|
||||
t_command **command,
|
||||
int io_number
|
||||
)
|
||||
{
|
||||
t_redirection *redirection;
|
||||
t_list *redirection_tokens;
|
||||
|
||||
redirection = redirection_new(tokens);
|
||||
redirection = redirection_new(tokens, io_number);
|
||||
if (redirection == NULL)
|
||||
{
|
||||
command_clear(*command);
|
||||
@@ -91,8 +129,6 @@ void redirection_add(
|
||||
free(redirection);
|
||||
return (malloc_error());
|
||||
}
|
||||
if (token->type == TOKEN_HEREDOC)
|
||||
ft_lstadd_back(&(*command)->heredocs, redirection_tokens);
|
||||
else
|
||||
(void)token;
|
||||
ft_lstadd_back(&(*command)->redirections, redirection_tokens);
|
||||
}
|
||||
|
||||
@@ -12,42 +12,57 @@
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
char **args_to_array(t_list **args, size_t argc);
|
||||
void command_clear_argv(t_command *command);
|
||||
|
||||
/**
|
||||
* @brief Converts a list of arguments into an array.
|
||||
*
|
||||
* @param args The list of arguments to convert.
|
||||
* @param argc The number of arguments in the list.
|
||||
*
|
||||
* @return An array of arguments or `NULL` on error.
|
||||
*
|
||||
* @note The `args` list is cleared after the conversion and set to NULL.
|
||||
*/
|
||||
char **args_to_array(
|
||||
static bool args_add_word(
|
||||
t_list **args,
|
||||
size_t argc
|
||||
const char *value
|
||||
)
|
||||
{
|
||||
t_list *node;
|
||||
char *dup;
|
||||
|
||||
dup = ft_strdup(value);
|
||||
if (dup == NULL)
|
||||
return (false);
|
||||
node = ft_lstnew(dup);
|
||||
if (node == NULL)
|
||||
return (free(dup), false);
|
||||
ft_lstadd_back(args, node);
|
||||
return (true);
|
||||
}
|
||||
|
||||
static bool command_append_words(
|
||||
t_command *command,
|
||||
t_list **args,
|
||||
int new_argc
|
||||
)
|
||||
{
|
||||
char **argv;
|
||||
t_list *arg;
|
||||
size_t i;
|
||||
t_list *current;
|
||||
int i;
|
||||
|
||||
argv = (char **)malloc(sizeof(char *) * (argc + 1));
|
||||
argv = (char **)malloc(sizeof(char *) * (command->argc + new_argc + 1));
|
||||
if (argv == NULL)
|
||||
return (NULL);
|
||||
return (false);
|
||||
i = 0;
|
||||
arg = *args;
|
||||
while (arg != NULL)
|
||||
while (i < command->argc)
|
||||
{
|
||||
argv[i] = (char *)arg->content;
|
||||
arg = arg->next;
|
||||
argv[i] = command->argv[i];
|
||||
i++;
|
||||
}
|
||||
current = *args;
|
||||
while (current != NULL)
|
||||
{
|
||||
argv[i++] = (char *)current->content;
|
||||
current = current->next;
|
||||
}
|
||||
argv[i] = NULL;
|
||||
free(command->argv);
|
||||
ft_lstclear_nodes(args);
|
||||
return (argv);
|
||||
command->argv = argv;
|
||||
command->argc += new_argc;
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,21 +80,41 @@ void words_add(
|
||||
t_list *args;
|
||||
t_list *arg;
|
||||
t_token *token;
|
||||
t_token *next_token;
|
||||
int new_argc;
|
||||
size_t i;
|
||||
bool is_fd_prefix;
|
||||
|
||||
args = NULL;
|
||||
new_argc = 0;
|
||||
arg = *tokens;
|
||||
token = (t_token *)arg->content;
|
||||
while (arg != NULL && token->type == TOKEN_WORD)
|
||||
{
|
||||
ft_lstadd_back(&args, ft_lstnew(ft_strdup(token->value)));
|
||||
(*command)->argc++;
|
||||
is_fd_prefix = false;
|
||||
if (arg->next != NULL && token->value != NULL
|
||||
&& token->value[0] != '\0')
|
||||
{
|
||||
next_token = (t_token *)arg->next->content;
|
||||
i = 0;
|
||||
while (token->value[i] != '\0' && ft_isdigit(token->value[i]))
|
||||
i++;
|
||||
is_fd_prefix = (token->value[i] == '\0' && is_redirection(next_token));
|
||||
}
|
||||
if (is_fd_prefix)
|
||||
break ;
|
||||
if (!args_add_word(&args, token->value))
|
||||
return (ft_lstclear(&args, free), command_clear(*command),
|
||||
*command = NULL, (void)0);
|
||||
new_argc++;
|
||||
arg = arg->next;
|
||||
if (arg != NULL)
|
||||
token = (t_token *)arg->content;
|
||||
}
|
||||
*tokens = arg;
|
||||
(*command)->argv = args_to_array(&args, (*command)->argc);
|
||||
ft_lstclear_nodes(&args);
|
||||
if (!command_append_words(*command, &args, new_argc))
|
||||
return (ft_lstclear(&args, free), command_clear(*command),
|
||||
*command = NULL, (void)0);
|
||||
}
|
||||
|
||||
void command_clear_argv(
|
||||
|
||||
@@ -175,7 +175,12 @@ void set_envp(
|
||||
)
|
||||
{
|
||||
t_hashmap **environment;
|
||||
char **key_value;
|
||||
char *equal;
|
||||
char *key;
|
||||
char *value;
|
||||
char *new_shlvl;
|
||||
int shlvl;
|
||||
size_t key_len;
|
||||
|
||||
if (minishell == NULL || envp == NULL)
|
||||
return ;
|
||||
@@ -185,9 +190,36 @@ void set_envp(
|
||||
return ;
|
||||
while (*envp != NULL)
|
||||
{
|
||||
key_value = ft_split(*envp, '=');
|
||||
set_env(key_value[0], key_value[1], minishell);
|
||||
ft_free_split(key_value);
|
||||
equal = ft_strchr(*envp, '=');
|
||||
if (equal == NULL)
|
||||
{
|
||||
envp++;
|
||||
continue ;
|
||||
}
|
||||
key_len = (size_t)(equal - *envp);
|
||||
key = ft_substr(*envp, 0, key_len);
|
||||
value = ft_strdup(equal + 1);
|
||||
if (key == NULL || value == NULL)
|
||||
{
|
||||
free(key);
|
||||
free(value);
|
||||
minishell->exit = true;
|
||||
return (malloc_error());
|
||||
}
|
||||
set_env(key, value, minishell);
|
||||
free(key);
|
||||
free(value);
|
||||
envp++;
|
||||
}
|
||||
value = get_env("SHLVL", minishell);
|
||||
shlvl = 0;
|
||||
if (value != NULL)
|
||||
shlvl = ft_atoi(value);
|
||||
if (shlvl < 0)
|
||||
shlvl = 0;
|
||||
new_shlvl = ft_itoa(shlvl + 1);
|
||||
if (new_shlvl == NULL)
|
||||
return (minishell->exit = true, malloc_error());
|
||||
set_env("SHLVL", new_shlvl, minishell);
|
||||
free(new_shlvl);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user