token_categorize.c \
token_finish.c \
parsing.c \
- execution.c \
+ \
+ execute.c \
+ add_word.c \
+ assignments.c \
+ exe_find.c \
+ exe_helpers.c \
+ exe_pipeline.c \
+ exe_prepare.c \
+ execute_builtin.c \
+ execute_cmd.c \
+ execute_raw.c \
+ expand.c \
+ expand_split.c \
+ redirection.c \
+ redir_file.c \
+ redir_here.c \
+ \
helpers.c \
vars_helpers.c \
- \
builtins/cd.c \
builtins/echo.c \
builtins/pwd.c \
/* By: ljiriste <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/02 17:40:19 by ljiriste #+# #+# */
-/* Updated: 2024/08/26 11:42:37 by ljiriste ### ########.fr */
+/* Updated: 2024/09/01 14:03:42 by lnikolov ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef EXECUTION_H
# define EXECUTION_H
+# include "minishell_structs.h"
+# include <signal.h>
+
+extern volatile sig_atomic_t g_last_signal;
+
+void free_split(char **fields);
+int set_quote(char *quote, char c);
+int is_token_type(const t_parse_tree_node *node, const char *type);
+
+int dup_pipes(const t_execution_env *env);
+int dup_redirections(const t_vec *redirections);
+
+char **quoted_split(const char *str);
+int unquote_field(char *field);
+int add_word(t_vec *exp_str, const char *word,
+ const t_execution_env *env, int enquote_result);
+char **expand(t_parse_tree_node *simple_command, const t_execution_env *env);
+
+char *find_exe(const char *exe_name, const t_execution_env *env);
+int prepare_env(t_execution_env *env,
+ const t_vec *redirections, t_vec *assignments);
+
+int ex_builtin(char **fields, __attribute__((unused))
+ t_vec *assignments, const t_vec *redirections, t_execution_env *env);
+int ex_fields(char **fields, t_vec *assignments,
+ const t_vec *redirections, t_execution_env *env);
+int ex_command(t_parse_tree_node *command, t_execution_env *env);
+int ex_pipeline(t_parse_tree_node *pipeline, t_execution_env *env, int depth);
+int ex_program(t_parse_tree_node *program, t_execution_env *env);
+
+char *get_word(const t_parse_tree_node *parent);
+int add_redirection_here(t_vec *redirections,
+ t_parse_tree_node *io_here, int fd, const t_execution_env *env);
+int add_redirection_file(t_vec *redirections,
+ t_parse_tree_node *io_file, int fd, t_execution_env *env);
+
+int save_redirections(t_vec *redirections,
+ t_parse_tree_node *simple_command, t_execution_env *env);
+int save_assignments(t_vec *assignments, t_parse_tree_node *simple_command,
+ const t_execution_env *env);
+
#endif // EXECUTION_H
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* add_word.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:51:31 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:24:55 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <stdlib.h>
+#include <sys/wait.h>
+
+static int is_expandable(const char *str)
+{
+ return (str[0] == '$'
+ && (ft_isalpha(str[1])
+ || str[1] == '_'
+ || str[1] == '?'));
+}
+
+static char *get_value(const char *word, size_t *i, const t_execution_env *env)
+{
+ char *var;
+ char *value;
+ const char *const_val;
+
+ if (word[*i] == '?')
+ {
+ ++*i;
+ value = ft_itoa(env->ret_val);
+ }
+ else
+ {
+ var = get_var_name(word + *i);
+ if (!var)
+ return (NULL);
+ *i += ft_strlen(var);
+ const_val = get_env_var_value(env, var);
+ free(var);
+ if (!const_val)
+ return (ft_strdup(""));
+ value = ft_strdup(const_val);
+ }
+ return (value);
+}
+
+static int append_value(t_vec *exp_str, const char *value, int enquote_result)
+{
+ int error;
+
+ if (!value)
+ return (1);
+ if (enquote_result)
+ {
+ error = ft_vec_append(exp_str, "'") != success;
+ error = error
+ || ft_vec_append_range(exp_str, value, ft_strlen(value)) != success;
+ error = error || ft_vec_append(exp_str, "'") != success;
+ return (error);
+ }
+ return (ft_vec_append_range(exp_str, value, ft_strlen(value)) != success);
+}
+
+int add_word(t_vec *exp_str, const char *word,
+ const t_execution_env *env, int enquote_result)
+{
+ size_t i;
+ char quote;
+ const char space = ' ';
+ char *value;
+
+ quote = '\0';
+ i = 0;
+ while (word[i])
+ {
+ set_quote("e, word[i]);
+ if (is_expandable(word + (i++)) && quote != '\'')
+ {
+ value = get_value(word, &i, env);
+ if (append_value(exp_str, value, enquote_result))
+ {
+ free(value);
+ return (1);
+ }
+ free(value);
+ }
+ else
+ if (ft_vec_append(exp_str, word + i - 1) != success)
+ return (1);
+ }
+ return (ft_vec_append(exp_str, &space) != success);
+}
\ No newline at end of file
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* assignments.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:19:00 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 14:00:36 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <stdlib.h>
+
+static void clear_old(t_vec *assignments, const char *new)
+{
+ size_t i;
+ char **assignment;
+
+ i = assignments->size;
+ while (i > 0)
+ {
+ --i;
+ assignment = ft_vec_access(assignments, i);
+ if (cmp_var_name(*assignment, new))
+ continue ;
+ ft_vec_erase(assignments, i, free);
+ }
+ return ;
+}
+
+static int add_assignment(t_vec *assignments, const char *assignment,
+ const t_execution_env *env)
+{
+ t_vec advanced_copy;
+ char *copy;
+
+ if (ft_vec_init(&advanced_copy, sizeof(char)) != success)
+ return (1);
+ if (add_word(&advanced_copy, assignment, env, 0))
+ return (1);
+ *(char *)ft_vec_access(&advanced_copy, advanced_copy.size - 1) = '\0';
+ copy = advanced_copy.vec;
+ unquote_field(copy);
+ clear_old(assignments, copy);
+ if (ft_vec_append(assignments, ©) == success)
+ return (0);
+ free(copy);
+ return (1);
+}
+
+static int save_assignments_prefix(t_vec *assignments, t_parse_tree_node *prefix,
+ const t_execution_env *env)
+{
+ size_t i;
+ t_parse_tree_node *subnode;
+
+ i = 0;
+ while (i < prefix->children.size)
+ {
+ subnode = ft_vec_access(&prefix->children, i);
+ if (is_token_type(subnode, "ASSIGNMENT_WORD"))
+ {
+ if (add_assignment(assignments, subnode->token.str, env))
+ return (1);
+ }
+ else if (is_token_type(subnode, "cmd_prefix"))
+ if (save_assignments_prefix(assignments, subnode, env))
+ return (1);
+ ++i;
+ }
+ return (0);
+}
+
+int save_assignments(t_vec *assignments, t_parse_tree_node *simple_command,
+ const t_execution_env *env)
+{
+ t_parse_tree_node *subnode;
+
+ if (ft_vec_init(assignments, sizeof(char *)) != success)
+ return (1);
+ subnode = ft_vec_access(&simple_command->children, 0);
+ if (is_token_type(subnode, "cmd_prefix"))
+ return (save_assignments_prefix(assignments, subnode, env));
+ return (0);
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* exe_find.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:53:28 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:23:51 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <dirent.h>
+
+int is_contained_in_dir(const char *exe_name, const char *dir_name)
+{
+ DIR *dir;
+ struct dirent *dir_entry;
+
+ dir = opendir(dir_name);
+ if (!dir)
+ return (0);
+ dir_entry = readdir(dir);
+ while (dir_entry)
+ {
+ if (!ft_strcmp(dir_entry->d_name, exe_name))
+ {
+ closedir(dir);
+ return (1);
+ }
+ dir_entry = readdir(dir);
+ }
+ closedir(dir);
+ return (0);
+}
+
+char *find_exe(const char *exe_name, const t_execution_env *env)
+{
+ const char *path;
+ char **paths;
+ size_t i;
+ char *res;
+
+ path = get_env_var_value(env, "PATH");
+ if (!path)
+ return (NULL);
+ paths = ft_split(path, ":");
+ if (!paths)
+ return (NULL);
+ res = NULL;
+ i = 0;
+ while (paths[i] && !res)
+ {
+ if (is_contained_in_dir(exe_name, paths[i]))
+ if (ft_strcat_alloc(&res, paths[i]))
+ if (ft_strcat_alloc(&res, "/"))
+ ft_strcat_alloc(&res, exe_name);
+ ++i;
+ }
+ free_split(paths);
+ return (res);
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* exe_helpers.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/07/21 08:57:54 by ljiriste #+# #+# */
+/* Updated: 2024/09/01 13:22:49 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "libft.h"
+#include <stdlib.h>
+
+// Returns 1 when quote is set (or unset)
+// and 0 when quote is left in current state
+int set_quote(char *quote, char c)
+{
+ if (c == '"' || c == '\'')
+ {
+ if (*quote == '\0')
+ *quote = c;
+ else if (*quote == c)
+ *quote = '\0';
+ else
+ return (0);
+ return (1);
+ }
+ return (0);
+}
+
+int is_token_type(const t_parse_tree_node *node, const char *type)
+{
+ return (!ft_strcmp(node->token.type, type));
+}
+
+// Returns 1 if any unquoting happened else returns 0
+int unquote_field(char *field)
+{
+ int res;
+ size_t i;
+ char quote;
+
+ res = 0;
+ quote = 0;
+ i = 0;
+ while (field && field[i])
+ {
+ if (field[i] == '"' || field[i] == '\'')
+ {
+ if (!set_quote("e, field[i]))
+ {
+ ++i;
+ continue ;
+ }
+ res = 1;
+ ft_memmove(field + i, field + i + 1, ft_strlen(field + i + 1) + 1);
+ }
+ else
+ ++i;
+ }
+ return (res);
+}
+
+void free_split(char **fields)
+{
+ size_t i;
+
+ if (!fields)
+ return ;
+ i = 0;
+ while (fields[i])
+ {
+ free(fields[i]);
+ ++i;
+ }
+ free(fields);
+ return ;
+}
\ No newline at end of file
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* exe_pipeline.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:52:56 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:43:51 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+static void killall(t_vec *child_pids, int sig_num)
+{
+ pid_t child_pid;
+ size_t i;
+
+ i = 0;
+ while (i < child_pids->size)
+ {
+ child_pid = *(pid_t *)ft_vec_access(child_pids, i);
+ kill(child_pid, sig_num);
+ ++i;
+ }
+ return ;
+}
+
+static void wait_for_all_to_end(t_vec *child_pids)
+{
+ size_t i;
+ pid_t pid;
+ int sig_num;
+
+ sig_num = 0;
+ i = child_pids->size;
+ while (i > 0)
+ {
+ --i;
+ pid = *(pid_t *)ft_vec_access(child_pids, i);
+ if (g_last_signal == 0)
+ waitpid(pid, NULL, 0);
+ if (g_last_signal)
+ {
+ sig_num = g_last_signal;
+ g_last_signal = 0;
+ killall(child_pids, g_last_signal);
+ i = child_pids->size;
+ }
+ ft_vec_forget(child_pids, i);
+ }
+ ft_vec_free(child_pids, NULL);
+ if (g_last_signal == 0)
+ g_last_signal = sig_num;
+ return ;
+}
+
+static void wait_for_return(t_execution_env *env)
+{
+ pid_t last_pid;
+ int status;
+
+ if (env->last_was_builtin)
+ env->ret_val = env->builtin_ret_val;
+ else
+ {
+ if (env->child_pids.size == 0)
+ return ;
+ last_pid = *(pid_t *)ft_vec_access(&env->child_pids,
+ env->child_pids.size - 1);
+ waitpid(last_pid, &status, 0);
+ if (g_last_signal == 0)
+ if (WIFEXITED(status))
+ env->ret_val = WEXITSTATUS(status);
+ }
+ wait_for_all_to_end(&env->child_pids);
+ return ;
+}
+
+static int advance_pipeline(t_parse_tree_node *pipeline,
+ t_execution_env *env, int depth)
+{
+ int pipe_fds[2];
+ int res;
+
+ if (pipe(pipe_fds))
+ return (1);
+ res = ft_vec_append(&env->fds_to_close, &pipe_fds[0]);
+ res = res || ft_vec_append(&env->fds_to_close, &env->stdout_fd);
+ ft_swap_int(&pipe_fds[1], &env->stdout_fd);
+ res = res
+ || ex_pipeline(ft_vec_access(&pipeline->children, 0), env, depth + 1);
+ ft_swap_int(&pipe_fds[1], &env->stdout_fd);
+ close(pipe_fds[1]);
+ if (res == 0)
+ {
+ ft_vec_forget(&env->fds_to_close, env->fds_to_close.size - 1);
+ ft_vec_forget(&env->fds_to_close, env->fds_to_close.size - 1);
+ }
+ ft_swap_int(&pipe_fds[0], &env->stdin_fd);
+ res = res || ex_command(ft_vec_access(&pipeline->children, 2), env);
+ ft_swap_int(&pipe_fds[0], &env->stdin_fd);
+ close(pipe_fds[0]);
+ return (res);
+}
+
+int ex_pipeline(t_parse_tree_node *pipeline, t_execution_env *env, int depth)
+{
+ if (g_last_signal != 0)
+ return (0);
+ if (pipeline->children.size == 1)
+ {
+ if (ex_command(ft_vec_access(&pipeline->children, 0), env))
+ return (1);
+ }
+ else
+ {
+ if (advance_pipeline(pipeline, env, depth))
+ {
+ killall(&env->child_pids, SIGTERM);
+ return (1);
+ }
+ }
+ if (depth == 0)
+ wait_for_return(env);
+ return (0);
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* exe_prepare.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:53:23 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:25:40 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <unistd.h>
+#include <fcntl.h>
+
+int dup_pipes(const t_execution_env *env)
+{
+ if (dup2(env->stdin_fd, STDIN_FILENO) == -1)
+ return (1);
+ if (dup2(env->stdout_fd, STDOUT_FILENO) == -1)
+ return (1);
+ if (env->stdin_fd != STDIN_FILENO)
+ close(env->stdin_fd);
+ if (env->stdout_fd != STDOUT_FILENO)
+ close(env->stdout_fd);
+ return (0);
+}
+
+int dup_redirections(const t_vec *redirections)
+{
+ size_t i;
+ const t_redirection *redir;
+
+ i = 0;
+ while (i < redirections->size)
+ {
+ redir = ft_vec_caccess(redirections, i);
+ dup2(redir->from_to_fds[1], redir->from_to_fds[0]);
+ close(redir->from_to_fds[1]);
+ ++i;
+ }
+ return (0);
+}
+
+static int add_exported(t_vec *assignments, const t_execution_env *env)
+{
+ size_t i;
+ char *var;
+ const t_vec *exported;
+
+ exported = &env->vars->exported;
+ i = 0;
+ while (i < exported->size)
+ {
+ var = ft_strdup(*(char *const *)ft_vec_caccess(exported, i));
+ if (ft_vec_append(assignments, &var) != success)
+ return (1);
+ ++i;
+ }
+ return (0);
+}
+
+static void close_fds(t_vec *fds_to_close)
+{
+ int fd;
+ size_t i;
+
+ i = 0;
+ while (i < fds_to_close->size)
+ {
+ fd = *(int *)ft_vec_access(fds_to_close, i);
+ close(fd);
+ ++i;
+ }
+ return ;
+}
+
+int prepare_env(t_execution_env *env,
+ const t_vec *redirections, t_vec *assignments)
+{
+ int res;
+
+ close_fds(&env->fds_to_close);
+ res = dup_pipes(env);
+ res = dup_redirections(redirections) || res;
+ res = add_exported(assignments, env) || res;
+ return (res);
+}
\ No newline at end of file
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* execute.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:52:49 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:29:51 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+
+int ex_program(t_parse_tree_node *program, t_execution_env *env)
+{
+ if (program->children.size == 1)
+ return (ex_pipeline(ft_vec_access(&program->children, 0), env, 0));
+ if (ex_program(ft_vec_access(&program->children, 0), env))
+ return (1);
+ if (is_token_type(ft_vec_caccess(&program->children, 1), "AND_IF"))
+ {
+ if (env->ret_val == 0)
+ return (ex_pipeline(ft_vec_access(&program->children, 2), env, 0));
+ }
+ else
+ {
+ if (env->ret_val != 0)
+ return (ex_pipeline(ft_vec_access(&program->children, 2), env, 0));
+ }
+ return (0);
+}
+
+int execute(t_tree *parse_tree, t_execution_env *env)
+{
+ int res;
+
+ res = ex_program(parse_tree, env);
+ if (g_last_signal != 0)
+ {
+ env->ret_val = 128 + g_last_signal;
+ g_last_signal = 0;
+ }
+ return (res);
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* execute_builtin.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:53:07 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:26:33 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "builtins.h"
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <unistd.h>
+#include <fcntl.h>
+
+static int save_std_filenos(int fds[3])
+{
+ fds[0] = dup(STDIN_FILENO);
+ if (fds[0] < 0)
+ return (1);
+ fds[1] = dup(STDOUT_FILENO);
+ if (fds[1] < 0)
+ {
+ close(fds[0]);
+ return (1);
+ }
+ fds[2] = dup(STDERR_FILENO);
+ if (fds[2] < 0)
+ {
+ close(fds[0]);
+ close(fds[1]);
+ return (1);
+ }
+ return (0);
+}
+
+static int restore_std_filenos(int fds[3])
+{
+ if (dup2(fds[0], STDIN_FILENO) == -1)
+ return (1);
+ if (dup2(fds[1], STDOUT_FILENO) == -1)
+ return (1);
+ if (dup2(fds[2], STDERR_FILENO) == -1)
+ return (1);
+ close(fds[0]);
+ close(fds[1]);
+ close(fds[2]);
+ return (0);
+}
+
+static void close_pipes(const t_execution_env *env)
+{
+ close(env->stdin_fd);
+ close(env->stdout_fd);
+ return ;
+}
+
+static size_t count_fields(char **fields)
+{
+ size_t i;
+
+ i = 0;
+ while (fields[i])
+ ++i;
+ return (i);
+}
+
+static void close_redirections(const t_vec *redirections)
+{
+ size_t i;
+ const t_redirection *redir;
+
+ i = 0;
+ while (i < redirections->size)
+ {
+ redir = ft_vec_caccess(redirections, i);
+ close(redir->from_to_fds[0]);
+ ++i;
+ }
+ return ;
+}
+
+int ex_builtin(char **fields, __attribute__((unused))
+ t_vec *assignments, const t_vec *redirections, t_execution_env *env)
+{
+ int fds[3];
+
+ save_std_filenos(fds);
+ dup_pipes(env);
+ dup_redirections(redirections);
+ if (!ft_strcmp(fields[0], "cd"))
+ env->builtin_ret_val = cd(count_fields(fields), fields, env);
+ else if (!ft_strcmp(fields[0], "echo"))
+ env->builtin_ret_val = echo(count_fields(fields), fields);
+ else if (!ft_strcmp(fields[0], "pwd"))
+ env->builtin_ret_val = pwd();
+ else if (!ft_strcmp(fields[0], "env"))
+ env->builtin_ret_val = ft_env(count_fields(fields), env);
+ else if (!ft_strcmp(fields[0], "export"))
+ env->builtin_ret_val = export(count_fields(fields), fields, env);
+ else if (!ft_strcmp(fields[0], "unset"))
+ env->builtin_ret_val = unset(count_fields(fields), fields, env);
+ else if (!ft_strcmp(fields[0], "exit"))
+ env->builtin_ret_val = execute_exit(count_fields(fields), fields, env);
+ else
+ return (1);
+ close_redirections(redirections);
+ close_pipes(env);
+ restore_std_filenos(fds);
+ return (0);
+}
\ No newline at end of file
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* execute_cmd.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:53:01 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 14:01:19 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+static void close_redirection(void *v_redir)
+{
+ t_redirection *redir;
+
+ redir = v_redir;
+ close(redir->from_to_fds[1]);
+ return ;
+}
+
+static int assignments_to_env(const t_vec *assignments, t_execution_env *env)
+{
+ size_t i;
+ const char *var_line;
+ char *var_name;
+
+ i = 0;
+ while (i < assignments->size)
+ {
+ var_line = *(char **)ft_vec_caccess(assignments, i);
+ var_name = get_var_name(var_line);
+ if (!var_name)
+ return (1);
+ if (set_env_var_value(env, var_name,
+ var_line + ft_strlen(var_name) + 1))
+ {
+ free(var_name);
+ return (1);
+ }
+ free(var_name);
+ ++i;
+ }
+ return (0);
+}
+
+static int ex_simple_command(t_parse_tree_node *simple_command, t_execution_env *env)
+{
+ t_vec redirections;
+ t_vec assignments;
+ char **fields;
+ int res;
+
+ res = save_redirections(&redirections, simple_command, env);
+ res = save_assignments(&assignments, simple_command, env) || res;
+ fields = NULL;
+ if (!res)
+ fields = expand(simple_command, env);
+ if (!fields || res)
+ res = 1;
+ else if (!*fields)
+ res = assignments_to_env(&assignments, env);
+ else
+ res = ex_fields(fields, &assignments, &redirections, env);
+ free_split(fields);
+ ft_vec_free(&redirections, close_redirection);
+ ft_vec_free(&assignments, free_str);
+ return (res);
+}
+
+static int subshell(t_parse_tree_node *program, t_execution_env *env)
+{
+ int res;
+ int status;
+ pid_t pid;
+
+ pid = fork();
+ if (pid == 0)
+ {
+ env->subshell = 1;
+ res = ex_program(program, env);
+ env->exit = 1;
+ return (res);
+ }
+ else if (pid < 0)
+ return (1);
+ waitpid(pid, &status, 0);
+ if (!WIFEXITED(status))
+ return (1);
+ env->ret_val = WEXITSTATUS(status);
+ return (0);
+}
+
+int ex_command(t_parse_tree_node *command, t_execution_env *env)
+{
+ t_parse_tree_node *comp_command;
+
+ if (env->exit)
+ return (0);
+ if (is_token_type(ft_vec_caccess(&command->children, 0), "simple_command"))
+ return (ex_simple_command(ft_vec_access(&command->children, 0), env));
+ else
+ {
+ comp_command = ft_vec_access(&command->children, 0);
+ return (subshell(ft_vec_access(&comp_command->children, 1), env));
+ }
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* execute_raw.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:53:16 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:29:27 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "builtins.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+static int is_builtin(const char *str)
+{
+ if (!ft_strcmp(str, "cd"))
+ return (1);
+ if (!ft_strcmp(str, "echo"))
+ return (1);
+ if (!ft_strcmp(str, "pwd"))
+ return (1);
+ if (!ft_strcmp(str, "env"))
+ return (1);
+ if (!ft_strcmp(str, "export"))
+ return (1);
+ if (!ft_strcmp(str, "unset"))
+ return (1);
+ if (!ft_strcmp(str, "exit"))
+ return (1);
+ return (0);
+}
+
+static int contains_path(const char *str)
+{
+ return (ft_strchr(str, '/') != NULL);
+}
+
+static int file_exists(const char *path)
+{
+ return (!access(path, F_OK));
+}
+
+static char *get_path(const char *cmd, t_execution_env *env)
+{
+ char *path;
+
+ path = NULL;
+ if (contains_path(cmd) && file_exists(cmd))
+ path = ft_strdup(cmd);
+ else if (!contains_path(cmd))
+ path = find_exe(cmd, env);
+ if (!path)
+ env->ret_val = 127;
+ return (path);
+}
+
+int ex_fields(char **fields, t_vec *assignments,
+ const t_vec *redirections, t_execution_env *env)
+{
+ pid_t pid;
+ char *path;
+
+ env->last_was_builtin = is_builtin(fields[0]);
+ if (env->last_was_builtin)
+ return (ex_builtin(fields, assignments, redirections, env));
+ path = get_path(fields[0], env);
+ if (!path)
+ return (1);
+ pid = fork();
+ if (pid == 0)
+ {
+ if (prepare_env(env, redirections, assignments) == 0)
+ execve(path, fields, assignments->vec);
+ exit(-1);
+ }
+ free(path);
+ if (pid < 0)
+ return (1);
+ if (ft_vec_append(&env->child_pids, &pid) != success)
+ {
+ kill(pid, SIGTERM);
+ return (1);
+ }
+ return (0);
+}
+++ /dev/null
-/* ************************************************************************** */
-/* */
-/* ::: :::::::: */
-/* execution.c :+: :+: :+: */
-/* +:+ +:+ +:+ */
-/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
-/* +#+#+#+#+#+ +#+ */
-/* Created: 2024/07/21 08:57:54 by ljiriste #+# #+# */
-/* Updated: 2024/09/01 10:19:33 by ljiriste ### ########.fr */
-/* */
-/* ************************************************************************** */
-
-#include "execution.h"
-#include "builtins.h"
-#include "minishell_structs.h"
-#include "minishell.h"
-#include "libft.h"
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include <sys/types.h>
-#include <dirent.h>
-#include <sys/wait.h>
-
-int is_token_type(const t_parse_tree_node *node, const char *type)
-{
- return (!ft_strcmp(node->token.type, type));
-}
-
-void clear_old(t_vec *assignments, const char *new)
-{
- size_t i;
- char **assignment;
-
- i = assignments->size;
- while (i > 0)
- {
- --i;
- assignment = ft_vec_access(assignments, i);
- if (cmp_var_name(*assignment, new))
- continue ;
- ft_vec_erase(assignments, i, free);
- }
- return ;
-}
-
-int add_word(t_vec *exp_str, const char *word,
- const t_execution_env *env, int quote);
-
-int add_assignment(t_vec *assignments, const char *assignment,
- const t_execution_env *env)
-{
- t_vec advanced_copy;
- char *copy;
-
- if (ft_vec_init(&advanced_copy, sizeof(char)) != success)
- return (1);
- if (add_word(&advanced_copy, assignment, env, 0))
- return (1);
- *(char *)ft_vec_access(&advanced_copy, advanced_copy.size - 1) = '\0';
- copy = advanced_copy.vec;
- unquote_field(copy);
- clear_old(assignments, copy);
- if (ft_vec_append(assignments, ©) == success)
- return (0);
- free(copy);
- return (1);
-}
-
-int save_assignments_prefix(t_vec *assignments, t_parse_tree_node *prefix,
- const t_execution_env *env)
-{
- size_t i;
- t_parse_tree_node *subnode;
-
- i = 0;
- while (i < prefix->children.size)
- {
- subnode = ft_vec_access(&prefix->children, i);
- if (is_token_type(subnode, "ASSIGNMENT_WORD"))
- {
- if (add_assignment(assignments, subnode->token.str, env))
- return (1);
- }
- else if (is_token_type(subnode, "cmd_prefix"))
- if (save_assignments_prefix(assignments, subnode, env))
- return (1);
- ++i;
- }
- return (0);
-}
-
-int save_assignments(t_vec *assignments, t_parse_tree_node *simple_command,
- const t_execution_env *env)
-{
- t_parse_tree_node *subnode;
-
- if (ft_vec_init(assignments, sizeof(char *)) != success)
- return (1);
- subnode = ft_vec_access(&simple_command->children, 0);
- if (is_token_type(subnode, "cmd_prefix"))
- return (save_assignments_prefix(assignments, subnode, env));
- return (0);
-}
-
-char *get_word(const t_parse_tree_node *parent)
-{
- char *res;
- const t_parse_tree_node *word = ft_vec_caccess(&parent->children, 0);
-
- res = ft_strdup(word->token.str);
- return (res);
-}
-
-int expand_filename(char **filename, const t_execution_env *env)
-{
- t_vec advanced_copy;
-
- if (ft_vec_init(&advanced_copy, sizeof(char)) != success)
- return (1);
- if (add_word(&advanced_copy, *filename, env, 0))
- {
- ft_vec_free(&advanced_copy, NULL);
- return (1);
- }
- free(*filename);
- *filename = advanced_copy.vec;
- filename[0][advanced_copy.size - 1] = '\0';
- unquote_field(*filename);
- return (0);
-}
-
-static void handle_fds(int *fd, int *sec_fd, const char *filename,
- const t_parse_tree_node *operator)
-{
- if (*fd < 0)
- {
- if (is_token_type(operator, "LESS"))
- *fd = STDIN_FILENO;
- else
- *fd = STDOUT_FILENO;
- }
- if (is_token_type(operator, "LESS"))
- *sec_fd = open(filename, O_RDONLY);
- else if (is_token_type(operator, "GREAT"))
- *sec_fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC,
- S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
- else
- *sec_fd = open(filename, O_CREAT | O_WRONLY | O_APPEND,
- S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
- return ;
-}
-
-int add_redirection_file(t_vec *redirections,
- t_parse_tree_node *io_file, int fd, t_execution_env *env)
-{
- t_redirection redir;
- const t_parse_tree_node *operator;
- char *filename;
- int sec_fd;
-
- filename = get_word(ft_vec_caccess(&io_file->children, 1));
- if (!filename)
- return (1);
- expand_filename(&filename, env);
- operator = ft_vec_caccess(&io_file->children, 0);
- handle_fds(&fd, &sec_fd, filename, operator);
- if (sec_fd < 0)
- {
- free(filename);
- env->ret_val = 1;
- return (1);
- }
- redir = (t_redirection){.from_to_fds[0] = fd, .from_to_fds[1] = sec_fd};
- free(filename);
- return (ft_vec_append(redirections, &redir) != success);
-}
-
-static int write_line_to_pipe(int pipe_fd, const char *line,
- const t_execution_env *env, int expand)
-{
- size_t i;
- char *var;
- const char *value;
-
- i = 0;
- while (line[i])
- {
- if (line[i] != '$' || !expand)
- {
- ft_dprintf(pipe_fd, "%c", line[i]);
- ++i;
- continue ;
- }
- ++i;
- var = get_var_name(line + i);
- if (!var)
- return (1);
- value = get_env_var_value(env, var);
- if (value)
- ft_dprintf(pipe_fd, "%s", value);
- i += ft_strlen(var);
- free(var);
- }
- return (0);
-}
-
-static char *here_file_getline(void)
-{
- ft_printf("> ");
- return (get_next_line(STDIN_FILENO));
-}
-
-// In case of an error the pipe_fd is repurposed to indicate the error.
-// This is done to save a few lines
-int here_file_to_pipe(int pipe_fd, char *delimiter,
- const t_execution_env *env)
-{
- int expand;
- char *line;
-
- expand = !unquote_field(delimiter);
- line = here_file_getline();
- while (line && ft_strncmp(line, delimiter, ft_strlen(line) - 1))
- {
- if (write_line_to_pipe(pipe_fd, line, env, expand))
- {
- pipe_fd = -1;
- break ;
- }
- free(line);
- line = here_file_getline();
- }
- if (!line)
- ft_printf
- ("minishell: warning: here-document delimited by EOF instead of %s\n",
- delimiter);
- get_next_line(-1);
- free(line);
- return (pipe_fd == -1);
-}
-
-int add_redirection_here(t_vec *redirections,
- t_parse_tree_node *io_here, int fd, const t_execution_env *env)
-{
- char *delimiter;
- int pipe_fds[2];
- int err;
- t_redirection redir;
-
- delimiter = get_word(ft_vec_caccess(&io_here->children, 1));
- if (!delimiter)
- return (1);
- if (fd == -1)
- fd = STDIN_FILENO;
- if (pipe(pipe_fds))
- {
- free(delimiter);
- return (1);
- }
- err = here_file_to_pipe(pipe_fds[1], delimiter, env);
- close(pipe_fds[1]);
- free(delimiter);
- if (err)
- return (1);
- redir = (t_redirection){.from_to_fds[0] = fd,
- .from_to_fds[1] = pipe_fds[0]};
- return (ft_vec_append(redirections, &redir) != success);
-}
-
-int add_redirection(t_vec *redirections,
- t_parse_tree_node *redirect, t_execution_env *env)
-{
- int fd;
- t_parse_tree_node *subnode;
-
- fd = -1;
- subnode = ft_vec_access(&redirect->children, 0);
- if (redirect->children.size == 2)
- {
- fd = ft_atoi(subnode->token.str);
- if (fd < 0)
- fd = -2;
- subnode = ft_vec_access(&redirect->children, 1);
- }
- if (is_token_type(subnode, "io_file"))
- return (add_redirection_file(redirections, subnode, fd, env));
- else
- return (add_redirection_here(redirections, subnode, fd, env));
-}
-
-int save_redirections_psfix(t_vec *redirections,
- t_parse_tree_node *node, t_execution_env *env)
-{
- size_t i;
- t_parse_tree_node *subnode;
-
- i = 0;
- while (i < node->children.size)
- {
- subnode = ft_vec_access(&node->children, i);
- if (is_token_type(subnode, "io_redirect"))
- {
- if (add_redirection(redirections, subnode, env))
- return (1);
- }
- else if (is_token_type(subnode, "cmd_suffix")
- || is_token_type(subnode, "cmd_prefix"))
- if (save_redirections_psfix(redirections, subnode, env))
- return (1);
- ++i;
- }
- return (0);
-}
-
-int save_redirections(t_vec *redirections,
- t_parse_tree_node *simple_command, t_execution_env *env)
-{
- t_parse_tree_node *subnode;
-
- if (ft_vec_init(redirections, sizeof(t_redirection)) != success)
- return (1);
- subnode = ft_vec_access(&simple_command->children, 0);
- if (is_token_type(subnode, "cmd_prefix"))
- if (save_redirections_psfix(redirections, subnode, env))
- return (1);
- subnode = ft_vec_access(&simple_command->children,
- simple_command->children.size - 1);
- if (is_token_type(subnode, "cmd_suffix"))
- if (save_redirections_psfix(redirections, subnode, env))
- return (1);
- return (0);
-}
-
-static char *get_value(const char *word, size_t *i, const t_execution_env *env)
-{
- char *var;
- char *value;
- const char *const_val;
-
- if (word[*i] == '?')
- {
- ++*i;
- value = ft_itoa(env->ret_val);
- }
- else
- {
- var = get_var_name(word + *i);
- if (!var)
- return (NULL);
- *i += ft_strlen(var);
- const_val = get_env_var_value(env, var);
- free(var);
- if (!const_val)
- return (ft_strdup(""));
- value = ft_strdup(const_val);
- }
- return (value);
-}
-
-static int append_value(t_vec *exp_str, const char *value, int enquote_result)
-{
- int error;
-
- if (!value)
- return (1);
- if (enquote_result)
- {
- error = ft_vec_append(exp_str, "'") != success;
- error = error
- || ft_vec_append_range(exp_str, value, ft_strlen(value)) != success;
- error = error || ft_vec_append(exp_str, "'") != success;
- return (error);
- }
- return (ft_vec_append_range(exp_str, value, ft_strlen(value)) != success);
-}
-
-// Returns 1 when quote is set (or unset)
-// and 0 when quote is left in current state
-int set_quote(char *quote, char c)
-{
- if (c == '"' || c == '\'')
- {
- if (*quote == '\0')
- *quote = c;
- else if (*quote == c)
- *quote = '\0';
- else
- return (0);
- return (1);
- }
- return (0);
-}
-
-int is_expandable(const char *str)
-{
- return (str[0] == '$'
- && (ft_isalpha(str[1])
- || str[1] == '_'
- || str[1] == '?'));
-}
-
-int add_word(t_vec *exp_str, const char *word,
- const t_execution_env *env, int enquote_result)
-{
- size_t i;
- char quote;
- const char space = ' ';
- char *value;
-
- quote = '\0';
- i = 0;
- while (word[i])
- {
- set_quote("e, word[i]);
- if (is_expandable(word + (i++)) && quote != '\'')
- {
- value = get_value(word, &i, env);
- if (append_value(exp_str, value, enquote_result))
- {
- free(value);
- return (1);
- }
- free(value);
- }
- else
- if (ft_vec_append(exp_str, word + i - 1) != success)
- return (1);
- }
- return (ft_vec_append(exp_str, &space) != success);
-}
-
-int expand_cmd(t_vec *exp_str,
- const t_parse_tree_node *node, const t_execution_env *env)
-{
- size_t i;
- const t_parse_tree_node *subnode;
-
- i = 0;
- while (i < node->children.size)
- {
- subnode = ft_vec_caccess(&node->children, i);
- if (is_token_type(subnode, "cmd_suffix"))
- {
- if (expand_cmd(exp_str, subnode, env))
- return (1);
- }
- else if (is_token_type(subnode, "WORD"))
- if (add_word(exp_str, subnode->token.str, env, 0))
- return (1);
- ++i;
- }
- return (0);
-}
-
-size_t get_next_word_size(const char *str)
-{
- size_t n;
- char quote;
-
- quote = 0;
- n = 0;
- while (str[n])
- {
- if (str[n] == ' ' && !quote)
- break ;
- set_quote("e, str[n]);
- ++n;
- }
- return (n);
-}
-
-// Returns 1 if any unquoting happened else returns 0
-int unquote_field(char *field)
-{
- int res;
- size_t i;
- char quote;
-
- res = 0;
- quote = 0;
- i = 0;
- while (field && field[i])
- {
- if (field[i] == '"' || field[i] == '\'')
- {
- if (!set_quote("e, field[i]))
- {
- ++i;
- continue ;
- }
- res = 1;
- ft_memmove(field + i, field + i + 1, ft_strlen(field + i + 1) + 1);
- }
- else
- ++i;
- }
- return (res);
-}
-
-void unquote(char **fields)
-{
- size_t i;
-
- i = 0;
- while (fields[i])
- {
- unquote_field(fields[i]);
- ++i;
- }
- return ;
-}
-
-int process_word(const char *str, t_vec *fields, size_t *i)
-{
- size_t n;
- char *new_str;
-
- while (str[*i] == ' ')
- ++*i;
- n = get_next_word_size(str + *i);
- if (n == 0)
- return (0);
- new_str = ft_strndup(str + *i, n);
- if (!new_str)
- return (1);
- if (ft_vec_append(fields, &new_str) != success)
- {
- free(new_str);
- return (1);
- }
- *i += n;
- return (0);
-}
-
-char **quoted_split(const char *str)
-{
- size_t i;
- t_vec fields;
- const void *g_nullptr = NULL;
-
- if (ft_vec_init(&fields, sizeof(char *)) != success)
- return (NULL);
- i = 0;
- while (str[i])
- {
- if (process_word(str, &fields, &i))
- {
- ft_vec_free(&fields, free);
- return (NULL);
- }
- }
- if (ft_vec_append(&fields, &g_nullptr) != success)
- {
- ft_vec_free(&fields, free);
- return (NULL);
- }
- return (fields.vec);
-}
-
-int expand_child(t_parse_tree_node *subnode,
- t_vec *expanded_str, const t_execution_env *env)
-{
- if ((is_token_type(subnode, "cmd_name")
- || is_token_type(subnode, "cmd_word")
- || is_token_type(subnode, "cmd_suffix"))
- && expand_cmd(expanded_str, subnode, env))
- return (1);
- return (0);
-}
-
-char **expand(t_parse_tree_node *simple_command, const t_execution_env *env)
-{
- const char g_null_char = '\0';
- size_t i;
- char **fields;
- t_vec expanded_str;
-
- ft_vec_init(&expanded_str, sizeof(char));
- i = 0;
- while (i < simple_command->children.size)
- {
- if (expand_child(ft_vec_access(&simple_command->children, i++),
- &expanded_str, env))
- {
- ft_vec_free(&expanded_str, NULL);
- return (NULL);
- }
- }
- if (ft_vec_append(&expanded_str, &g_null_char) != success)
- {
- ft_vec_free(&expanded_str, NULL);
- return (NULL);
- }
- fields = quoted_split(expanded_str.vec);
- ft_vec_free(&expanded_str, NULL);
- unquote(fields);
- return (fields);
-}
-
-int assignments_to_env(const t_vec *assignments, t_execution_env *env)
-{
- size_t i;
- const char *var_line;
- char *var_name;
-
- i = 0;
- while (i < assignments->size)
- {
- var_line = *(char **)ft_vec_caccess(assignments, i);
- var_name = get_var_name(var_line);
- if (!var_name)
- return (1);
- if (set_env_var_value(env, var_name,
- var_line + ft_strlen(var_name) + 1))
- {
- free(var_name);
- return (1);
- }
- free(var_name);
- ++i;
- }
- return (0);
-}
-
-void free_split(char **fields)
-{
- size_t i;
-
- if (!fields)
- return ;
- i = 0;
- while (fields[i])
- {
- free(fields[i]);
- ++i;
- }
- free(fields);
- return ;
-}
-
-int contains_path(const char *str)
-{
- return (ft_strchr(str, '/') != NULL);
-}
-
-int file_exists(const char *path)
-{
- return (!access(path, F_OK));
-}
-
-int is_contained_in_dir(const char *exe_name, const char *dir_name)
-{
- DIR *dir;
- struct dirent *dir_entry;
-
- dir = opendir(dir_name);
- if (!dir)
- return (0);
- dir_entry = readdir(dir);
- while (dir_entry)
- {
- if (!ft_strcmp(dir_entry->d_name, exe_name))
- {
- closedir(dir);
- return (1);
- }
- dir_entry = readdir(dir);
- }
- closedir(dir);
- return (0);
-}
-
-char *find_exe(const char *exe_name, const t_execution_env *env)
-{
- const char *path;
- char **paths;
- size_t i;
- char *res;
-
- path = get_env_var_value(env, "PATH");
- if (!path)
- return (NULL);
- paths = ft_split(path, ":");
- if (!paths)
- return (NULL);
- res = NULL;
- i = 0;
- while (paths[i] && !res)
- {
- if (is_contained_in_dir(exe_name, paths[i]))
- if (ft_strcat_alloc(&res, paths[i]))
- if (ft_strcat_alloc(&res, "/"))
- ft_strcat_alloc(&res, exe_name);
- ++i;
- }
- free_split(paths);
- return (res);
-}
-
-int dup_pipes(const t_execution_env *env)
-{
- if (dup2(env->stdin_fd, STDIN_FILENO) == -1)
- return (1);
- if (dup2(env->stdout_fd, STDOUT_FILENO) == -1)
- return (1);
- if (env->stdin_fd != STDIN_FILENO)
- close(env->stdin_fd);
- if (env->stdout_fd != STDOUT_FILENO)
- close(env->stdout_fd);
- return (0);
-}
-
-void close_pipes(const t_execution_env *env)
-{
- close(env->stdin_fd);
- close(env->stdout_fd);
- return ;
-}
-
-int dup_redirections(__attribute__((unused)) const t_vec *redirections)
-{
- size_t i;
- const t_redirection *redir;
-
- i = 0;
- while (i < redirections->size)
- {
- redir = ft_vec_caccess(redirections, i);
- dup2(redir->from_to_fds[1], redir->from_to_fds[0]);
- close(redir->from_to_fds[1]);
- ++i;
- }
- return (0);
-}
-
-void close_redirections(const t_vec *redirections)
-{
- size_t i;
- const t_redirection *redir;
-
- i = 0;
- while (i < redirections->size)
- {
- redir = ft_vec_caccess(redirections, i);
- close(redir->from_to_fds[0]);
- ++i;
- }
- return ;
-}
-
-int add_exported(t_vec *assignments, const t_execution_env *env)
-{
- size_t i;
- char *var;
- const t_vec *exported;
-
- exported = &env->vars->exported;
- i = 0;
- while (i < exported->size)
- {
- var = ft_strdup(*(char *const *)ft_vec_caccess(exported, i));
- if (ft_vec_append(assignments, &var) != success)
- return (1);
- ++i;
- }
- return (0);
-}
-
-int is_builtin(const char *str)
-{
- if (!ft_strcmp(str, "cd"))
- return (1);
- if (!ft_strcmp(str, "echo"))
- return (1);
- if (!ft_strcmp(str, "pwd"))
- return (1);
- if (!ft_strcmp(str, "env"))
- return (1);
- if (!ft_strcmp(str, "export"))
- return (1);
- if (!ft_strcmp(str, "unset"))
- return (1);
- if (!ft_strcmp(str, "exit"))
- return (1);
- return (0);
-}
-
-size_t count_fields(char **fields)
-{
- size_t i;
-
- i = 0;
- while (fields[i])
- ++i;
- return (i);
-}
-
-int save_std_filenos(int fds[3])
-{
- fds[0] = dup(STDIN_FILENO);
- if (fds[0] < 0)
- return (1);
- fds[1] = dup(STDOUT_FILENO);
- if (fds[1] < 0)
- {
- close(fds[0]);
- return (1);
- }
- fds[2] = dup(STDERR_FILENO);
- if (fds[2] < 0)
- {
- close(fds[0]);
- close(fds[1]);
- return (1);
- }
- return (0);
-}
-
-int restore_std_filenos(int fds[3])
-{
- if (dup2(fds[0], STDIN_FILENO) == -1)
- return (1);
- if (dup2(fds[1], STDOUT_FILENO) == -1)
- return (1);
- if (dup2(fds[2], STDERR_FILENO) == -1)
- return (1);
- close(fds[0]);
- close(fds[1]);
- close(fds[2]);
- return (0);
-}
-
-int ex_builtin(char **fields, __attribute__((unused))
- t_vec *assignments, __attribute__((unused)) const t_vec *redirections,
- t_execution_env *env)
-{
- int fds[3];
-
- save_std_filenos(fds);
- dup_pipes(env);
- dup_redirections(redirections);
- if (!ft_strcmp(fields[0], "cd"))
- env->builtin_ret_val = cd(count_fields(fields), fields, env);
- else if (!ft_strcmp(fields[0], "echo"))
- env->builtin_ret_val = echo(count_fields(fields), fields);
- else if (!ft_strcmp(fields[0], "pwd"))
- env->builtin_ret_val = pwd();
- else if (!ft_strcmp(fields[0], "env"))
- env->builtin_ret_val = ft_env(count_fields(fields), env);
- else if (!ft_strcmp(fields[0], "export"))
- env->builtin_ret_val = export(count_fields(fields), fields, env);
- else if (!ft_strcmp(fields[0], "unset"))
- env->builtin_ret_val = unset(count_fields(fields), fields, env);
- else if (!ft_strcmp(fields[0], "exit"))
- env->builtin_ret_val = execute_exit(count_fields(fields), fields, env);
- else
- return (1);
- close_redirections(redirections);
- close_pipes(env);
- restore_std_filenos(fds);
- return (0);
-}
-
-void close_fds(t_vec *fds_to_close)
-{
- int fd;
- size_t i;
-
- i = 0;
- while (i < fds_to_close->size)
- {
- fd = *(int *)ft_vec_access(fds_to_close, i);
- close(fd);
- ++i;
- }
- return ;
-}
-
-char *get_path(const char *cmd, t_execution_env *env)
-{
- char *path;
-
- path = NULL;
- if (contains_path(cmd) && file_exists(cmd))
- path = ft_strdup(cmd);
- else if (!contains_path(cmd))
- path = find_exe(cmd, env);
- if (!path)
- env->ret_val = 127;
- return (path);
-}
-
-int prepare_env(t_execution_env *env,
- const t_vec *redirections, t_vec *assignments)
-{
- int res;
-
- close_fds(&env->fds_to_close);
- res = dup_pipes(env);
- res = dup_redirections(redirections) || res;
- res = add_exported(assignments, env) || res;
- return (res);
-}
-
-int ex_fields(char **fields, t_vec *assignments,
- const t_vec *redirections, t_execution_env *env)
-{
- pid_t pid;
- char *path;
-
- env->last_was_builtin = is_builtin(fields[0]);
- if (env->last_was_builtin)
- return (ex_builtin(fields, assignments, redirections, env));
- path = get_path(fields[0], env);
- if (!path)
- return (1);
- pid = fork();
- if (pid == 0)
- {
- if (prepare_env(env, redirections, assignments) == 0)
- execve(path, fields, assignments->vec);
- exit(-1);
- }
- free(path);
- if (pid < 0)
- return (1);
- if (ft_vec_append(&env->child_pids, &pid) != success)
- {
- kill(pid, SIGTERM);
- return (1);
- }
- return (0);
-}
-
-void close_redirection(void *v_redir)
-{
- t_redirection *redir;
-
- redir = v_redir;
- close(redir->from_to_fds[1]);
- return ;
-}
-
-int ex_simple_command(t_parse_tree_node *simple_command, t_execution_env *env)
-{
- t_vec redirections;
- t_vec assignments;
- char **fields;
- int res;
-
- res = save_redirections(&redirections, simple_command, env);
- res = save_assignments(&assignments, simple_command, env) || res;
- fields = NULL;
- if (!res)
- fields = expand(simple_command, env);
- if (!fields || res)
- res = 1;
- else if (!*fields)
- res = assignments_to_env(&assignments, env);
- else
- res = ex_fields(fields, &assignments, &redirections, env);
- free_split(fields);
- ft_vec_free(&redirections, close_redirection);
- ft_vec_free(&assignments, free_str);
- return (res);
-}
-
-t_ft_stat v_strcopy(void *v_dest, const void *v_src)
-{
- char **dest;
- const char *const *src;
-
- dest = v_dest;
- src = v_src;
- if (!*src)
- {
- *dest = NULL;
- return (success);
- }
- *dest = ft_strdup(*src);
- if (!*dest)
- return (alloc_fail);
- return (success);
-}
-
-t_ft_stat v_copy_redir(void *v_dest, const void *v_src)
-{
- t_redirection *dest;
- const t_redirection *src;
-
- dest = v_dest;
- src = v_src;
- *dest = *src;
- return (success);
-}
-
-int ex_program(t_parse_tree_node *program, t_execution_env *env);
-
-int subshell(t_parse_tree_node *program, t_execution_env *env)
-{
- int res;
- int status;
- pid_t pid;
-
- pid = fork();
- if (pid == 0)
- {
- env->subshell = 1;
- res = ex_program(program, env);
- env->exit = 1;
- return (res);
- }
- else if (pid < 0)
- return (1);
- waitpid(pid, &status, 0);
- if (!WIFEXITED(status))
- return (1);
- env->ret_val = WEXITSTATUS(status);
- return (0);
-}
-
-int ex_command(t_parse_tree_node *command, t_execution_env *env)
-{
- t_parse_tree_node *comp_command;
-
- if (env->exit)
- return (0);
- if (is_token_type(ft_vec_caccess(&command->children, 0), "simple_command"))
- return (ex_simple_command(ft_vec_access(&command->children, 0), env));
- else
- {
- comp_command = ft_vec_access(&command->children, 0);
- return (subshell(ft_vec_access(&comp_command->children, 1), env));
- }
-}
-
-void killall(t_vec *child_pids, int sig_num)
-{
- pid_t child_pid;
- size_t i;
-
- i = 0;
- while (i < child_pids->size)
- {
- child_pid = *(pid_t *)ft_vec_access(child_pids, i);
- kill(child_pid, sig_num);
- ++i;
- }
- return ;
-}
-
-void wait_for_all_to_end(t_vec *child_pids)
-{
- size_t i;
- pid_t pid;
- int sig_num;
-
- sig_num = 0;
- i = child_pids->size;
- while (i > 0)
- {
- --i;
- pid = *(pid_t *)ft_vec_access(child_pids, i);
- if (g_last_signal == 0)
- waitpid(pid, NULL, 0);
- if (g_last_signal)
- {
- sig_num = g_last_signal;
- g_last_signal = 0;
- killall(child_pids, g_last_signal);
- i = child_pids->size;
- }
- ft_vec_forget(child_pids, i);
- }
- ft_vec_free(child_pids, NULL);
- if (g_last_signal == 0)
- g_last_signal = sig_num;
- return ;
-}
-
-void wait_for_return(t_execution_env *env)
-{
- pid_t last_pid;
- int status;
-
- if (env->last_was_builtin)
- env->ret_val = env->builtin_ret_val;
- else
- {
- if (env->child_pids.size == 0)
- return ;
- last_pid = *(pid_t *)ft_vec_access(&env->child_pids,
- env->child_pids.size - 1);
- waitpid(last_pid, &status, 0);
- if (g_last_signal == 0)
- if (WIFEXITED(status))
- env->ret_val = WEXITSTATUS(status);
- }
- wait_for_all_to_end(&env->child_pids);
- return ;
-}
-
-int ex_pipeline(t_parse_tree_node *pipeline, t_execution_env *env, int depth);
-
-int advance_pipeline(t_parse_tree_node *pipeline,
- t_execution_env *env, int depth)
-{
- int pipe_fds[2];
- int res;
-
- if (pipe(pipe_fds))
- return (1);
- res = ft_vec_append(&env->fds_to_close, &pipe_fds[0]);
- res = res || ft_vec_append(&env->fds_to_close, &env->stdout_fd);
- ft_swap_int(&pipe_fds[1], &env->stdout_fd);
- res = res
- || ex_pipeline(ft_vec_access(&pipeline->children, 0), env, depth + 1);
- ft_swap_int(&pipe_fds[1], &env->stdout_fd);
- close(pipe_fds[1]);
- if (res == 0)
- {
- ft_vec_forget(&env->fds_to_close, env->fds_to_close.size - 1);
- ft_vec_forget(&env->fds_to_close, env->fds_to_close.size - 1);
- }
- ft_swap_int(&pipe_fds[0], &env->stdin_fd);
- res = res || ex_command(ft_vec_access(&pipeline->children, 2), env);
- ft_swap_int(&pipe_fds[0], &env->stdin_fd);
- close(pipe_fds[0]);
- return (res);
-}
-
-int ex_pipeline(t_parse_tree_node *pipeline, t_execution_env *env, int depth)
-{
- if (g_last_signal != 0)
- return (0);
- if (pipeline->children.size == 1)
- {
- if (ex_command(ft_vec_access(&pipeline->children, 0), env))
- return (1);
- }
- else
- {
- if (advance_pipeline(pipeline, env, depth))
- {
- killall(&env->child_pids, SIGTERM);
- return (1);
- }
- }
- if (depth == 0)
- wait_for_return(env);
- return (0);
-}
-
-int ex_program(t_parse_tree_node *program, t_execution_env *env)
-{
- if (program->children.size == 1)
- return (ex_pipeline(ft_vec_access(&program->children, 0), env, 0));
- if (ex_program(ft_vec_access(&program->children, 0), env))
- return (1);
- if (is_token_type(ft_vec_caccess(&program->children, 1), "AND_IF"))
- {
- if (env->ret_val == 0)
- return (ex_pipeline(ft_vec_access(&program->children, 2), env, 0));
- }
- else
- {
- if (env->ret_val != 0)
- return (ex_pipeline(ft_vec_access(&program->children, 2), env, 0));
- }
- return (0);
-}
-
-int execute(t_tree *parse_tree, t_execution_env *env)
-{
- int res;
-
- res = ex_program(parse_tree, env);
- if (g_last_signal != 0)
- {
- env->ret_val = 128 + g_last_signal;
- g_last_signal = 0;
- }
- return (res);
-}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* expand.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:53:33 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:31:20 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+
+static void unquote(char **fields)
+{
+ size_t i;
+
+ i = 0;
+ while (fields[i])
+ {
+ unquote_field(fields[i]);
+ ++i;
+ }
+ return ;
+}
+
+static int expand_cmd(t_vec *exp_str,
+ const t_parse_tree_node *node, const t_execution_env *env)
+{
+ size_t i;
+ const t_parse_tree_node *subnode;
+
+ i = 0;
+ while (i < node->children.size)
+ {
+ subnode = ft_vec_caccess(&node->children, i);
+ if (is_token_type(subnode, "cmd_suffix"))
+ {
+ if (expand_cmd(exp_str, subnode, env))
+ return (1);
+ }
+ else if (is_token_type(subnode, "WORD"))
+ if (add_word(exp_str, subnode->token.str, env, 0))
+ return (1);
+ ++i;
+ }
+ return (0);
+}
+
+static int expand_child(t_parse_tree_node *subnode,
+ t_vec *expanded_str, const t_execution_env *env)
+{
+ if ((is_token_type(subnode, "cmd_name")
+ || is_token_type(subnode, "cmd_word")
+ || is_token_type(subnode, "cmd_suffix"))
+ && expand_cmd(expanded_str, subnode, env))
+ return (1);
+ return (0);
+}
+
+char **expand(t_parse_tree_node *simple_command, const t_execution_env *env)
+{
+ const char g_null_char = '\0';
+ size_t i;
+ char **fields;
+ t_vec expanded_str;
+
+ ft_vec_init(&expanded_str, sizeof(char));
+ i = 0;
+ while (i < simple_command->children.size)
+ {
+ if (expand_child(ft_vec_access(&simple_command->children, i++),
+ &expanded_str, env))
+ {
+ ft_vec_free(&expanded_str, NULL);
+ return (NULL);
+ }
+ }
+ if (ft_vec_append(&expanded_str, &g_null_char) != success)
+ {
+ ft_vec_free(&expanded_str, NULL);
+ return (NULL);
+ }
+ fields = quoted_split(expanded_str.vec);
+ ft_vec_free(&expanded_str, NULL);
+ unquote(fields);
+ return (fields);
+}
\ No newline at end of file
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* expand_split.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:51:34 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:30:17 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "libft.h"
+#include <stdlib.h>
+
+static size_t get_next_word_size(const char *str)
+{
+ size_t n;
+ char quote;
+
+ quote = 0;
+ n = 0;
+ while (str[n])
+ {
+ if (str[n] == ' ' && !quote)
+ break ;
+ set_quote("e, str[n]);
+ ++n;
+ }
+ return (n);
+}
+
+static int process_word(const char *str, t_vec *fields, size_t *i)
+{
+ size_t n;
+ char *new_str;
+
+ while (str[*i] == ' ')
+ ++*i;
+ n = get_next_word_size(str + *i);
+ if (n == 0)
+ return (0);
+ new_str = ft_strndup(str + *i, n);
+ if (!new_str)
+ return (1);
+ if (ft_vec_append(fields, &new_str) != success)
+ {
+ free(new_str);
+ return (1);
+ }
+ *i += n;
+ return (0);
+}
+
+char **quoted_split(const char *str)
+{
+ size_t i;
+ t_vec fields;
+ const void *g_nullptr = NULL;
+
+ if (ft_vec_init(&fields, sizeof(char *)) != success)
+ return (NULL);
+ i = 0;
+ while (str[i])
+ {
+ if (process_word(str, &fields, &i))
+ {
+ ft_vec_free(&fields, free);
+ return (NULL);
+ }
+ }
+ if (ft_vec_append(&fields, &g_nullptr) != success)
+ {
+ ft_vec_free(&fields, free);
+ return (NULL);
+ }
+ return (fields.vec);
+}
\ No newline at end of file
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* redir_file.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:23:57 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 14:02:22 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static void handle_fds(int *fd, int *sec_fd, const char *filename,
+ const t_parse_tree_node *operator)
+{
+ if (*fd < 0)
+ {
+ if (is_token_type(operator, "LESS"))
+ *fd = STDIN_FILENO;
+ else
+ *fd = STDOUT_FILENO;
+ }
+ if (is_token_type(operator, "LESS"))
+ *sec_fd = open(filename, O_RDONLY);
+ else if (is_token_type(operator, "GREAT"))
+ *sec_fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC,
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+ else
+ *sec_fd = open(filename, O_CREAT | O_WRONLY | O_APPEND,
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+ return ;
+}
+
+static int expand_filename(char **filename, const t_execution_env *env)
+{
+ t_vec advanced_copy;
+
+ if (ft_vec_init(&advanced_copy, sizeof(char)) != success)
+ return (1);
+ if (add_word(&advanced_copy, *filename, env, 0))
+ {
+ ft_vec_free(&advanced_copy, NULL);
+ return (1);
+ }
+ free(*filename);
+ *filename = advanced_copy.vec;
+ filename[0][advanced_copy.size - 1] = '\0';
+ unquote_field(*filename);
+ return (0);
+}
+
+int add_redirection_file(t_vec *redirections,
+ t_parse_tree_node *io_file, int fd, t_execution_env *env)
+{
+ t_redirection redir;
+ const t_parse_tree_node *operator;
+ char *filename;
+ int sec_fd;
+
+ filename = get_word(ft_vec_caccess(&io_file->children, 1));
+ if (!filename)
+ return (1);
+ expand_filename(&filename, env);
+ operator = ft_vec_caccess(&io_file->children, 0);
+ handle_fds(&fd, &sec_fd, filename, operator);
+ if (sec_fd < 0)
+ {
+ free(filename);
+ env->ret_val = 1;
+ return (1);
+ }
+ redir = (t_redirection){.from_to_fds[0] = fd, .from_to_fds[1] = sec_fd};
+ free(filename);
+ return (ft_vec_append(redirections, &redir) != success);
+}
+
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* redir_here.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:48:10 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 13:31:59 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+
+static char *here_file_getline(void)
+{
+ ft_printf("> ");
+ return (get_next_line(STDIN_FILENO));
+}
+
+static int write_line_to_pipe(int pipe_fd, const char *line,
+ const t_execution_env *env, int expand)
+{
+ size_t i;
+ char *var;
+ const char *value;
+
+ i = 0;
+ while (line[i])
+ {
+ if (line[i] != '$' || !expand)
+ {
+ ft_dprintf(pipe_fd, "%c", line[i]);
+ ++i;
+ continue ;
+ }
+ ++i;
+ var = get_var_name(line + i);
+ if (!var)
+ return (1);
+ value = get_env_var_value(env, var);
+ if (value)
+ ft_dprintf(pipe_fd, "%s", value);
+ i += ft_strlen(var);
+ free(var);
+ }
+ return (0);
+}
+
+// In case of an error the pipe_fd is repurposed to indicate the error.
+// This is done to save a few lines
+int here_file_to_pipe(int pipe_fd, char *delimiter,
+ const t_execution_env *env)
+{
+ int expand;
+ char *line;
+
+ expand = !unquote_field(delimiter);
+ line = here_file_getline();
+ while (line && ft_strncmp(line, delimiter, ft_strlen(line) - 1))
+ {
+ if (write_line_to_pipe(pipe_fd, line, env, expand))
+ {
+ pipe_fd = -1;
+ break ;
+ }
+ free(line);
+ line = here_file_getline();
+ }
+ if (!line)
+ ft_printf
+ ("minishell: warning: here-document delimited by EOF instead of %s\n",
+ delimiter);
+ get_next_line(-1);
+ free(line);
+ return (pipe_fd == -1);
+}
+
+int add_redirection_here(t_vec *redirections,
+ t_parse_tree_node *io_here, int fd, const t_execution_env *env)
+{
+ char *delimiter;
+ int pipe_fds[2];
+ int err;
+ t_redirection redir;
+
+ delimiter = get_word(ft_vec_caccess(&io_here->children, 1));
+ if (!delimiter)
+ return (1);
+ if (fd == -1)
+ fd = STDIN_FILENO;
+ if (pipe(pipe_fds))
+ {
+ free(delimiter);
+ return (1);
+ }
+ err = here_file_to_pipe(pipe_fds[1], delimiter, env);
+ close(pipe_fds[1]);
+ free(delimiter);
+ if (err)
+ return (1);
+ redir = (t_redirection){.from_to_fds[0] = fd,
+ .from_to_fds[1] = pipe_fds[0]};
+ return (ft_vec_append(redirections, &redir) != success);
+}
\ No newline at end of file
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* redirection.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: lnikolov <lnikolov@student.42prague.com +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/09/01 11:49:27 by lnikolov #+# #+# */
+/* Updated: 2024/09/01 14:02:49 by lnikolov ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "execution.h"
+#include "minishell_structs.h"
+#include "libft.h"
+
+
+char *get_word(const t_parse_tree_node *parent)
+{
+ char *res;
+ const t_parse_tree_node *word = ft_vec_caccess(&parent->children, 0);
+
+ res = ft_strdup(word->token.str);
+ return (res);
+}
+
+static int add_redirection(t_vec *redirections,
+ t_parse_tree_node *redirect, t_execution_env *env)
+{
+ int fd;
+ t_parse_tree_node *subnode;
+
+ fd = -1;
+ subnode = ft_vec_access(&redirect->children, 0);
+ if (redirect->children.size == 2)
+ {
+ fd = ft_atoi(subnode->token.str);
+ if (fd < 0)
+ fd = -2;
+ subnode = ft_vec_access(&redirect->children, 1);
+ }
+ if (is_token_type(subnode, "io_file"))
+ return (add_redirection_file(redirections, subnode, fd, env));
+ else
+ return (add_redirection_here(redirections, subnode, fd, env));
+}
+
+static int save_redirections_psfix(t_vec *redirections,
+ t_parse_tree_node *node, t_execution_env *env)
+{
+ size_t i;
+ t_parse_tree_node *subnode;
+
+ i = 0;
+ while (i < node->children.size)
+ {
+ subnode = ft_vec_access(&node->children, i);
+ if (is_token_type(subnode, "io_redirect"))
+ {
+ if (add_redirection(redirections, subnode, env))
+ return (1);
+ }
+ else if (is_token_type(subnode, "cmd_suffix")
+ || is_token_type(subnode, "cmd_prefix"))
+ if (save_redirections_psfix(redirections, subnode, env))
+ return (1);
+ ++i;
+ }
+ return (0);
+}
+
+int save_redirections(t_vec *redirections,
+ t_parse_tree_node *simple_command, t_execution_env *env)
+{
+ t_parse_tree_node *subnode;
+
+ if (ft_vec_init(redirections, sizeof(t_redirection)) != success)
+ return (1);
+ subnode = ft_vec_access(&simple_command->children, 0);
+ if (is_token_type(subnode, "cmd_prefix"))
+ if (save_redirections_psfix(redirections, subnode, env))
+ return (1);
+ subnode = ft_vec_access(&simple_command->children,
+ simple_command->children.size - 1);
+ if (is_token_type(subnode, "cmd_suffix"))
+ if (save_redirections_psfix(redirections, subnode, env))
+ return (1);
+ return (0);
+}