diff --git a/.clang-format b/.clang-format index 1dd4b436..73efec44 100644 --- a/.clang-format +++ b/.clang-format @@ -1,6 +1,6 @@ BasedOnStyle: Microsoft IndentWidth: 4 -ColumnLimit: 140 +ColumnLimit: 800 UseTab: Always SortIncludes: CaseInsensitive IndentPPDirectives: AfterHash diff --git a/exec/Filelist.exec.mk b/exec/Filelist.exec.mk index 5fd1c36b..d4fd6874 100644 --- a/exec/Filelist.exec.mk +++ b/exec/Filelist.exec.mk @@ -13,5 +13,19 @@ run_arithmetic/_to_ast_node \ run_arithmetic/arithmetic \ run_arithmetic/arithmetic_operation \ run_arithmetic/operator_bis \ -run_ast \ +run_ast/_ast_into_str \ +run_ast/_ast_into_str2 \ +run_ast/_run_exit_code \ +run_ast/_run_exp_operators \ +run_ast/_spawn_cmd \ +run_ast/run_builtins \ +run_ast/run_cmd_sub \ +run_ast/run_command \ +run_ast/run_expansion \ +run_ast/run_expansion_builtin \ +run_ast/run_list \ +run_ast/run_pipeline \ +run_ast/run_program \ +run_ast/run_subshell \ +run_ast/run_words \ diff --git a/exec/include/exec/_run_ast.h b/exec/include/exec/_run_ast.h index f483ecdf..39e8c8c9 100644 --- a/exec/include/exec/_run_ast.h +++ b/exec/include/exec/_run_ast.h @@ -6,7 +6,7 @@ /* By: rparodi +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/08/14 17:57:57 by rparodi #+# #+# */ -/* Updated: 2024/08/30 18:05:23 by rparodi ### ########.fr */ +/* Updated: 2024/09/14 12:22:23 by maiboyer ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,6 +14,7 @@ # define _RUN_AST_H # include "app/state.h" +# include "exec/_run_arith.h" # include "ast/ast.h" # include "me/fs/fs.h" # include "me/os/os.h" @@ -86,61 +87,99 @@ struct s_subshell_result t_fd *stderr; }; -t_error run_arithmetic_expansion(\ -t_ast_arithmetic_expansion *arithmetic_expansion, t_state *state, t_i64 *out); +struct s_ffree_state +{ + t_state *state; + t_cmd_pipe cmd_pipe; +}; + +struct s_subshell_info +{ + t_fd *stdin; + t_fd *stderr; + t_fd *stdout; + t_fd *ret_stdout; +}; + +bool _is_builtin(\ + t_const_str argv0); +bool _is_special_var(\ + t_ast_expansion *self); +t_error _arith_into_str(\ + t_ast_node self, t_state *state, t_vec_str *append); +t_error _ast_get_str(\ + t_ast_node elem, t_word_iterator *state, t_vec_estr *out); +t_error _ast_get_str__arimethic_expansion(\ + t_ast_node elem, t_word_iterator *state, t_vec_estr *out); +t_error _ast_get_str__command_substitution(\ + t_ast_node elem, t_word_iterator *state, t_vec_estr *out); +t_error _ast_get_str__expansion(\ + t_ast_node elem, t_word_iterator *state, t_vec_estr *out); +t_error _ast_get_str__raw(\ + t_ast_node elem, t_word_iterator *state, t_vec_estr *out); +t_error _ast_get_str__raw__double_quote(\ + t_ast_node elem, t_word_iterator *state, t_vec_estr *out); +t_error _ast_get_str__raw__no_quote(\ + t_ast_node elem, t_word_iterator *state, t_vec_estr *out); +t_error _ast_get_str__raw__single_quote(\ + t_ast_node elem, t_word_iterator *state, t_vec_estr *out); +t_error _ast_get_str__word(\ + t_ast_node elem, t_word_iterator *state, t_vec_estr *out); +t_error _ast_into_str(\ + t_ast_node self, t_state *state, t_vec_str *append); +t_error _cmd_into_str(\ + t_ast_node self, t_state *state, t_vec_str *append); +t_error _exp_into_str(\ + t_ast_node self, t_state *state, t_vec_str *append); +t_error _get_expansion_value(\ + t_ast_expansion *self, t_state *state, t_expansion_result *out); +t_error _get_op_func(\ + t_ast_expansion *self, t_error (**op_func)(t_ast_expansion *self, \ + t_state *state, t_expansion_result *value)); +t_error _handle_builtin(\ + t_spawn_info info, t_state *state, t_cmd_pipe cmd_pipe, \ + t_command_result *out); +t_error _handle_expansion_operator(\ + t_ast_expansion *self, t_state *state, t_expansion_result *value); +t_error _handle_len_operator(\ + t_ast_expansion *self, t_state *state, t_expansion_result *value); +t_error _handle_no_operator(\ + t_ast_expansion *self, t_state *state, t_expansion_result *value); +t_error _raw_str_into_str(\ + t_ast_node self, t_state *state, t_vec_str *append); +t_error _run_expansion_special_var(\ + t_ast_expansion *self, t_state *state, t_expansion_result *out); +t_error _run_get_exit_code(\ + t_ast_node self, t_state *state, int *out); +t_error _spawn_cmd_and_run(\ + t_vec_str args, t_vec_ast redirection, t_state *state, \ + t_cmd_pipe cmd_pipe, t_command_result *out); +t_error _word_into_str(\ + t_ast_node self, t_state *state, t_vec_str *append); t_error run_command(\ -t_ast_command *command, t_state *state, t_cmd_pipe cmd_pipe, \ -t_command_result *out); + t_ast_command *command, t_state *state, t_cmd_pipe cmd_pipe, \ + t_command_result *out); +t_error run_command_substitution(\ + t_ast_command_substitution *self, t_state *state, void *out); t_error run_expansion(\ t_ast_expansion *self, t_state *state, t_expansion_result *out); -t_error run_word(\ - t_ast_word *word, t_state *state, t_word_result *out); -t_error run_program(\ - t_ast_program *program, t_state *state, t_program_result *out); -t_error run_pipeline(\ - t_ast_pipeline *pipeline, t_state *state, t_pipeline_result *out); t_error run_list(\ t_ast_list *list, t_state *state, t_list_result *out); +t_error run_pipeline(\ + t_ast_pipeline *pipeline, t_state *state, t_pipeline_result *out); +t_error run_program(\ + t_ast_program *self, t_state *state, t_program_result *out); t_error run_subshell(\ t_ast_subshell *subshell, t_state *state, t_cmd_pipe cmd_pipe, \ t_subshell_result *out); -t_error run_case_(\ - t_ast_case *case_, t_state *state, void *out); -t_error run_case_item(\ - t_ast_case_item *case_item, t_state *state, void *out); -t_error run_command_substitution(\ -t_ast_command_substitution *command_substitution, t_state *state, void *out); -t_error run_compound_statement(\ - t_ast_compound_statement *compound_statement, t_state *state, void *out); -t_error run_elif(\ - t_ast_elif *elif, t_state *state, void *out); -t_error run_else_(\ - t_ast_else *else_, t_state *state, void *out); -t_error run_extglob(\ - t_ast_extglob *extglob, t_state *state, void *out); -t_error run_for_(\ - t_ast_for *for_, t_state *state, void *out); -t_error run_function_definition(\ - t_ast_function_definition *function_definition, t_state *state, void *out); -t_error run_if_(\ - t_ast_if *if_, t_state *state, void *out); -t_error run_regex(\ - t_ast_regex *regex, t_state *state, void *out); -t_error run_until(\ - t_ast_until *until, t_state *state, void *out); -t_error run_variable_assignment(\ -t_ast_variable_assignment *variable_assignment, t_state *state, \ -bool is_temporary, void *out); -t_error run_while_(\ - t_ast_while *while_, t_state *state, void *out); +t_error run_word(\ + t_ast_word *word, t_state *state, t_word_result *out); +t_str _get_ifs_value(\ + t_state *state); +void _ffree_func(\ + struct s_ffree_state *state); +void _run_word_into_str(\ + t_usize idx, t_ast_node *elem, t_word_iterator *state); -t_error run_heredoc_redirection(\ - t_ast_heredoc_redirection *heredoc_redirection, t_state *state, void *out); -t_error run_file_redirection(\ - t_ast_file_redirection *file_redirection, t_state *state, void *out); -t_error run_empty(\ - t_ast_empty *empty, t_state *state, void *out); -t_error run_raw_string(\ - t_ast_raw_string *raw_string, t_state *state, void *out); #endif diff --git a/exec/src/run_ast.c b/exec/src/run_ast.c deleted file mode 100644 index 64aaf166..00000000 --- a/exec/src/run_ast.c +++ /dev/null @@ -1,1207 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* run_ast.c :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: maiboyer +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/07/11 17:22:29 by maiboyer #+# #+# */ -/* Updated: 2024/09/11 18:34:27 by maiboyer ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "app/env.h" -#include "app/state.h" -#include "ast/ast.h" -#include "exec/_run_ast.h" -#include "exec/builtins.h" -#include "exec/run.h" -#include "me/convert/numbers_to_str.h" -#include "me/fs/fs.h" -#include "me/hashmap/hashmap_env.h" -#include "me/mem/mem.h" -#include "me/os/os.h" -#include "me/str/str.h" -#include "me/string/string.h" -#include "me/types.h" -#include "me/vec/vec_ast.h" -#include "me/vec/vec_estr.h" -#include "me/vec/vec_pid.h" -#include "me/vec/vec_str.h" -#include "unistd.h" -#include -#include -#include - -#include - -#define NOT_DONE \ - { \ - printf("function `%s` isn't done !\n", __func__); \ - return (ERROR); \ - } - -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunknown-pragmas" -#pragma GCC diagnostic ignored "-Wempty-body" -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#pragma clang diagnostic ignored "-Wunused-parameter" -#pragma clang diagnostic ignored "-Wunused-variable" - -bool _is_special_var(t_ast_expansion *self) -{ - char name; - - if (self == NULL) - return (true); - if (self->var_name == NULL) - return (true); - if (str_len(self->var_name) != 1) - return (false); - name = self->var_name[0]; - if (name == '*' || name == '@' || name == '?' || name == '!' || name == '#' || name == '-' || name == '$' || name == '0') - return (true); - return (false); -} - -t_error _run_expansion_special_var(t_ast_expansion *self, t_state *state, t_expansion_result *out) -{ - char name; - - if (self == NULL || state == NULL || out == NULL) - return (ERROR); - name = self->var_name[0]; - *out = (t_expansion_result){.exists = false, .value = NULL}; - if (name == '*') - ; // return all args with argv[0] - if (name == '@') - ; // return all args without argv[0] - if (name == '?') - ; // return exit code of last run program - if (name == '!') - ; // return pid of last run program - if (name == '#') - ; // return `argc - 1` bc we don't care about argv[0] - if (name == '$') - ; // return pid of self (the shell) - if (name == '-') - ; // return the option string - - printf("PLEASE MAKE SURE TO FINISH THE SPECIAL VAR HANDLING !"); - return (ERROR); -} - -t_error _get_expansion_value(t_ast_expansion *self, t_state *state, t_expansion_result *out) -{ - t_str *hmap_ret; - t_expansion_result ret; - - if (self == NULL || state == NULL || out == NULL) - return (ERROR); - hmap_ret = hmap_env_get(state->tmp_var, &self->var_name); - if (hmap_ret == NULL) - hmap_ret = hmap_env_get(state->env, &self->var_name); - ret = (t_expansion_result){.exists = (hmap_ret != NULL), .value = NULL}; - if (ret.exists) - ret.value = *hmap_ret; - return (*out = ret, NO_ERROR); -} - -t_error _handle_len_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) -{ - t_str len_str; - t_usize len; - - if (value->exists && value->value != NULL) - len = str_len(value->value); - else - len = 0; - if (u64_to_str(len, &len_str)) - return (ERROR); - mem_free(value->value); - value->exists = true; - value->value = len_str; - return (NO_ERROR); -}; - -t_error _handle_no_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) -{ - t_str *val; - - if (self == NULL || state == NULL || value == NULL) - return (ERROR); - val = hmap_env_get(state->tmp_var, &self->var_name); - if (val == NULL) - val = hmap_env_get(state->env, &self->var_name); - if (val == NULL) - return (value->exists = false, NO_ERROR); - value->exists = true; - value->value = str_clone(*val); - return (NO_ERROR); -}; - -t_error _exp_assign_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_assign_colon_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_alternate_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_alternate_colon_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_default_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_default_colon_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_error_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_error_colon_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; - -t_error _exp_suffix_pattern_smallest_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_suffix_pattern_largest_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_prefix_pattern_smallest_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; -t_error _exp_prefix_pattern_largest_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) NOT_DONE; - -t_error _get_op_func(t_ast_expansion *self, t_error (**op_func)(t_ast_expansion *self, t_state *state, t_expansion_result *value)) -{ - if (self == NULL || op_func == NULL) - return (ERROR); - if (self->kind == E_OP_NONE) - return (*op_func = _handle_no_operator, NO_ERROR); - if (self->kind == E_OP_ERROR) - return (*op_func = _exp_error_operator, NO_ERROR); - if (self->kind == E_OP_ERROR_COLON) - return (*op_func = _exp_error_colon_operator, NO_ERROR); - if (self->kind == E_OP_ASSIGN_DEFAULT) - return (*op_func = _exp_assign_operator, NO_ERROR); - if (self->kind == E_OP_ASSIGN_DEFAULT_COLON) - return (*op_func = _exp_assign_colon_operator, NO_ERROR); - if (self->kind == E_OP_DEFAULT) - return (*op_func = _exp_default_operator, NO_ERROR); - if (self->kind == E_OP_DEFAULT_COLON) - return (*op_func = _exp_default_colon_operator, NO_ERROR); - if (self->kind == E_OP_ALTERNATE) - return (*op_func = _exp_alternate_operator, NO_ERROR); - if (self->kind == E_OP_ALTERNATE_COLON) - return (*op_func = _exp_alternate_colon_operator, NO_ERROR); - if (self->kind == E_OP_LARGEST_PREFIX) - return (*op_func = _exp_prefix_pattern_largest_operator, NO_ERROR); - if (self->kind == E_OP_SMALLEST_PREFIX) - return (*op_func = _exp_prefix_pattern_smallest_operator, NO_ERROR); - if (self->kind == E_OP_LARGEST_SUFFIX) - return (*op_func = _exp_suffix_pattern_largest_operator, NO_ERROR); - if (self->kind == E_OP_SMALLEST_SUFFIX) - return (*op_func = _exp_suffix_pattern_smallest_operator, NO_ERROR); - return (ERROR); -} - -t_error _handle_expansion_operator(t_ast_expansion *self, t_state *state, t_expansion_result *value) -{ - t_error (*op_func)(t_ast_expansion *self, t_state *state, t_expansion_result *value); - - if (self == NULL || state == NULL || value == NULL) - return (ERROR); - if (_get_op_func(self, &op_func)) - return (ERROR); - if (op_func(self, state, value)) - return (ERROR); - return (NO_ERROR); -} - -t_error _ast_get_str__raw__no_quote(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) -{ - bool last_backslash; - t_string ret; - t_usize i; - - if (elem == NULL || state == NULL || out == NULL || elem->kind != AST_RAW_STRING || elem->data.raw_string.kind != AST_WORD_NO_QUOTE) - return (ERROR); - i = 0; - ret = string_new(elem->data.raw_string.len); - last_backslash = false; - while (elem->data.raw_string.str[i]) - { - if (elem->data.raw_string.str[i] != '\\' || last_backslash) - string_push_char(&ret, elem->data.raw_string.str[i]); - last_backslash = false; - if (elem->data.raw_string.str[i] == '\\' && !last_backslash) - last_backslash = true; - i++; - } - return (vec_estr_push(out, (t_expandable_str){.do_expand = false, .value = ret.buf}), NO_ERROR); -} - -t_error _ast_get_str__raw__single_quote(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) -{ - t_string ret; - t_usize i; - - if (elem == NULL || state == NULL || out == NULL || elem->kind != AST_RAW_STRING || elem->data.raw_string.kind != AST_WORD_SINGLE_QUOTE) - return (ERROR); - i = 1; - ret = string_new(elem->data.raw_string.len); - while (elem->data.raw_string.str[i]) - string_push_char(&ret, elem->data.raw_string.str[i++]); - string_pop(&ret); - return (vec_estr_push(out, (t_expandable_str){.do_expand = false, .value = ret.buf}), NO_ERROR); -} - -t_error _ast_get_str__raw__double_quote(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) -{ - bool last_backslash; - t_string ret; - t_usize i; - - if (elem == NULL || state == NULL || out == NULL || elem->kind != AST_RAW_STRING || elem->data.raw_string.kind != AST_WORD_DOUBLE_QUOTE) - return (ERROR); - i = 0; - ret = string_new(elem->data.raw_string.len); - last_backslash = false; - while (elem->data.raw_string.str[i]) - { - if (elem->data.raw_string.str[i] != '\\' || last_backslash) - string_push_char(&ret, elem->data.raw_string.str[i]); - last_backslash = false; - if (elem->data.raw_string.str[i] == '\\' && !last_backslash) - last_backslash = true; - i++; - } - return (vec_estr_push(out, (t_expandable_str){.do_expand = false, .value = ret.buf}), NO_ERROR); -} - -t_error _ast_get_str__raw(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) -{ - if (elem == NULL || state == NULL || out == NULL || elem->kind != AST_RAW_STRING) - return (ERROR); - if (elem->data.raw_string.kind == AST_WORD_NO_QUOTE) - return (_ast_get_str__raw__no_quote(elem, state, out)); - if (elem->data.raw_string.kind == AST_WORD_SINGLE_QUOTE) - return (_ast_get_str__raw__single_quote(elem, state, out)); - if (elem->data.raw_string.kind == AST_WORD_DOUBLE_QUOTE) - return (_ast_get_str__raw__double_quote(elem, state, out)); - return (ERROR); -} - -t_str _get_ifs_value(t_state *state) -{ - t_str ifs; - t_str *ifs_entry; - t_str ifs_key; - - ifs_key = "IFS"; - ifs = NULL; - ifs_entry = hmap_env_get(state->tmp_var, (t_str *)&ifs_key); - if (ifs_entry != NULL) - ifs_entry = hmap_env_get(state->env, (t_str *)&ifs_key); - if (ifs_entry != NULL) - ifs = *ifs_entry; - if (ifs == NULL) - ifs = " \t\n"; - return (ifs); -} - -t_error _ast_get_str__expansion(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) -{ - t_expansion_result exp_ret; - t_vec_str words; - - if (elem == NULL || state == NULL || out == NULL || elem->kind != AST_EXPANSION) - return (ERROR); - if (run_expansion(&elem->data.expansion, state->state, &exp_ret)) - return (ERROR); - return (vec_estr_push(out, (t_expandable_str){.do_expand = state->res.kind == AST_WORD_NO_QUOTE, .value = exp_ret.value}), NO_ERROR); -} - -t_error _ast_get_str__arimethic_expansion(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) -{ - t_str out_str; - t_i64 out_num; - - if (elem == NULL || state == NULL || out == NULL || elem->kind != AST_ARITHMETIC_EXPANSION) - return (ERROR); - if (run_arithmetic_expansion(&elem->data.arithmetic_expansion, state->state, &out_num)) - return (ERROR); - if (i64_to_str(out_num, &out_str)) - return (ERROR); - vec_estr_push(out, (t_expandable_str){.do_expand = state->res.kind == AST_WORD_NO_QUOTE, .value = out_str}); - return (NO_ERROR); -} - -t_error _ast_get_str__command_substitution(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) -{ - if (elem == NULL || state == NULL || out == NULL || elem->kind != AST_COMMAND_SUBSTITUTION) - return (ERROR); - // vec_estr_push(out, (t_expandable_str){.do_expand = state->res.kind == AST_WORD_NO_QUOTE, .value = str_clone(exp_out.value)}); - return (ERROR); -} -t_error _ast_get_str(t_ast_node elem, t_word_iterator *state, t_vec_estr *out); -t_error _ast_into_str(t_ast_node self, t_state *state, t_vec_str *append); - -t_error _ast_get_str__word(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) -{ - t_usize i; - t_vec_str res; - t_str tmp; - - if (elem == NULL || state == NULL || out == NULL || elem->kind != AST_WORD) - return (ERROR); - res = vec_str_new(16, str_free); - if (_ast_into_str(elem, state->state, &res)) - return (vec_str_free(res), ERROR); - while (!vec_str_pop_front(&res, &tmp)) - vec_estr_push(out, (t_expandable_str){.do_expand = false, .value = tmp}); - vec_str_free(res); - return (NO_ERROR); -} - -t_error _ast_get_str(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) -{ - if (elem == NULL || state == NULL || out == NULL) - return (ERROR); - if (elem->kind == AST_RAW_STRING) - return (_ast_get_str__raw(elem, state, out)); - if (elem->kind == AST_EXPANSION) - return (_ast_get_str__expansion(elem, state, out)); - if (elem->kind == AST_ARITHMETIC_EXPANSION) - return (_ast_get_str__arimethic_expansion(elem, state, out)); - if (elem->kind == AST_COMMAND_SUBSTITUTION) - return (_ast_get_str__command_substitution(elem, state, out)); - if (elem->kind == AST_WORD) - return (_ast_get_str__word(elem, state, out)); - return (ERROR); -} - -void _run_word_into_str(t_usize idx, t_ast_node *elem, t_word_iterator *state) -{ - t_vec_str val; - - (void)(idx); - if (elem == NULL || *elem == NULL || state == NULL) - return; - if (_ast_get_str(*elem, state, &state->res.value)) - return; -} - -t_error _exp_into_str(t_ast_node self, t_state *state, t_vec_str *append) -{ - t_expansion_result res; - t_vec_str splitted; - t_str tmp; - - if (self == NULL || state == NULL || append == NULL || self->kind != AST_EXPANSION) - return (ERROR); - if (run_expansion(&self->data.expansion, state, &res)) - return (ERROR); - if (res.value == NULL) - return (NO_ERROR); - if (str_split(res.value, _get_ifs_value(state), &splitted)) - return (ERROR); - while (!vec_str_pop_front(&splitted, &tmp)) - vec_str_push(append, tmp); - vec_str_free(splitted); - return (NO_ERROR); -} - -t_error _arith_into_str(t_ast_node self, t_state *state, t_vec_str *append) -{ - if (self == NULL || state == NULL || append == NULL || self->kind != AST_ARITHMETIC_EXPANSION) - return (ERROR); - return (NO_ERROR); -} - -t_error _cmd_into_str(t_ast_node self, t_state *state, t_vec_str *append) -{ - if (self == NULL || state == NULL || append == NULL || self->kind != AST_COMMAND_SUBSTITUTION) - return (ERROR); - /* - if (str_split(res.value, _get_ifs_value(state), &splitted)) - return (ERROR); - while (!vec_str_pop_front(&splitted, &tmp)) - vec_str_push(append, tmp); - vec_str_free(splitted); - */ - return (ERROR); -} - -t_error _word_into_str(t_ast_node self, t_state *state, t_vec_str *append) -{ - t_word_result res; - t_vec_str splitted; - t_string tmp; - t_usize i; - t_usize j; - t_usize len; - t_str ifs; - t_str tmp_str; - - if (self == NULL || state == NULL || append == NULL || self->kind != AST_WORD) - return (ERROR); - if (run_word(&self->data.word, state, &res)) - return (ERROR); - if (res.kind == AST_WORD_NO_QUOTE) - { - tmp = string_new(64); - i = 0; - while (i < res.value.len) - { - if (!res.value.buffer[i].do_expand) - string_push(&tmp, res.value.buffer[i].value); - else - { - ifs = _get_ifs_value(state); - while (ifs != NULL && *ifs != '\0' && str_find_chr(res.value.buffer[i].value, *ifs) == NULL) - ifs++; - if (ifs == NULL || *ifs == '\0') - string_push(&tmp, res.value.buffer[i].value); - else - { - ifs = _get_ifs_value(state); - if (str_split(res.value.buffer[i].value, ifs, &splitted)) - return (vec_estr_free(res.value), ERROR); - if (!vec_str_pop_front(&splitted, &tmp_str)) - { - if (str_find_chr(ifs, res.value.buffer[i].value[0]) == NULL) - { - string_push(&tmp, tmp_str), str_free(tmp_str); - } - else - { - vec_str_push(append, tmp.buf); - tmp = string_new(64); - string_push(&tmp, tmp_str); - str_free(tmp_str); - } - j = 0; - while (j + 1 < splitted.len) - { - if (vec_str_pop_front(&splitted, &tmp_str)) - return (vec_estr_free(res.value), ERROR); - vec_str_push(append, tmp_str); - j++; - } - len = str_len(res.value.buffer[i].value); - if (len != 0 && str_find_chr(ifs, res.value.buffer[i].value[len - 1]) == NULL) - string_push(&tmp, tmp_str), str_free(tmp_str); - else - vec_str_push(append, tmp_str); - } - } - } - i++; - } - vec_str_push(append, tmp.buf); - } - else - { - tmp = string_new(64); - i = 0; - while (i < res.value.len) - { - string_push(&tmp, res.value.buffer[i++].value); - } - vec_str_push(append, tmp.buf); - } - vec_estr_free(res.value); - return (NO_ERROR); -} - -t_error _raw_str_into_str(t_ast_node self, t_state *state, t_vec_str *append) -{ - if (self == NULL || state == NULL || append == NULL || self->kind != AST_RAW_STRING) - return (ERROR); - vec_str_push(append, str_clone(self->data.raw_string.str)); - return (NO_ERROR); -} - -t_error _ast_into_str(t_ast_node self, t_state *state, t_vec_str *append) -{ - if (self == NULL || state == NULL || append == NULL) - return (ERROR); - if (self->kind == AST_EXPANSION) - return (_exp_into_str(self, state, append)); - if (self->kind == AST_ARITHMETIC_EXPANSION) - return (_arith_into_str(self, state, append)); - if (self->kind == AST_COMMAND_SUBSTITUTION) - return (_cmd_into_str(self, state, append)); - if (self->kind == AST_WORD) - return (_word_into_str(self, state, append)); - if (self->kind == AST_RAW_STRING) - return (_raw_str_into_str(self, state, append)); - printf("unknown Kind = %#04x\n", self->kind); - return (ERROR); -} - -// End Internals funcs - -// These are done externally -// t_error run_file_redirection(t_ast_file_redirection *file_redirection, t_state *state, void *out) NOT_DONE; -// t_error run_heredoc_redirection(t_ast_heredoc_redirection *heredoc_redirection, t_state *state, void *out) NOT_DONE; -// t_error run_raw_string(t_ast_raw_string *raw_string, t_state *state, void *out) NOT_DONE; - -t_error run_case_(t_ast_case *case_, t_state *state, void *out) NOT_DONE; -t_error run_case_item(t_ast_case_item *case_item, t_state *state, void *out) NOT_DONE; -t_error run_command_substitution(t_ast_command_substitution *command_substitution, t_state *state, void *out) NOT_DONE; -t_error run_compound_statement(t_ast_compound_statement *compound_statement, t_state *state, void *out) NOT_DONE; -t_error run_elif(t_ast_elif *elif, t_state *state, void *out) NOT_DONE; -t_error run_else_(t_ast_else *else_, t_state *state, void *out) NOT_DONE; -t_error run_empty(t_ast_empty *empty, t_state *state, void *out) NOT_DONE; -t_error run_extglob(t_ast_extglob *extglob, t_state *state, void *out) NOT_DONE; -t_error run_for_(t_ast_for *for_, t_state *state, void *out) NOT_DONE; -t_error run_function_definition(t_ast_function_definition *function_definition, t_state *state, void *out) NOT_DONE; -t_error run_if_(t_ast_if *if_, t_state *state, void *out) NOT_DONE; -t_error run_regex(t_ast_regex *regex, t_state *state, void *out) NOT_DONE; -t_error run_until(t_ast_until *until, t_state *state, void *out) NOT_DONE; -t_error run_variable_assignment(t_ast_variable_assignment *variable_assignment, t_state *state, bool is_temporary, void *out) NOT_DONE; -t_error run_while_(t_ast_while *while_, t_state *state, void *out) NOT_DONE; - -void mem_free(void *free); - -struct s_subshell_info -{ - t_fd *stdin; - t_fd *stderr; - t_fd *stdout; - t_fd *ret_stdout; -}; - -t_error _run_get_exit_code(t_ast_node self, t_state *state, int *out) -{ - t_command_result cmd_res; - t_pipeline_result pipe_res; - t_list_result list_res; - t_subshell_result subshell_res; - - if (self->kind == AST_COMMAND) - { - if (run_command(&self->data.command, state, (t_cmd_pipe){NULL, false}, &cmd_res)) - return (ERROR); - if (cmd_res.process.stdin != NULL) - close_fd(cmd_res.process.stdin); - if (cmd_res.process.stdout != NULL) - close_fd(cmd_res.process.stdout); - if (cmd_res.process.stderr != NULL) - close_fd(cmd_res.process.stderr); - *out = cmd_res.exit; - } - if (self->kind == AST_PIPELINE) - { - if (run_pipeline(&self->data.pipeline, state, &pipe_res)) - return (ERROR); - *out = pipe_res.exit; - } - if (self->kind == AST_LIST) - { - if (run_list(&self->data.list, state, &list_res)) - return (ERROR); - *out = list_res.exit; - } - if (self->kind == AST_SUBSHELL) - { - if (run_subshell(&self->data.subshell, state, (t_cmd_pipe){NULL, false}, &subshell_res)) - return (ERROR); - *out = subshell_res.exit; - } - return (NO_ERROR); -} - -t_error run_subshell(t_ast_subshell *subshell, t_state *state, t_cmd_pipe cmd_pipe, t_subshell_result *out) -{ - struct s_subshell_info info; - t_pipe spipe; - t_usize i; - t_vec_str filename_args; - t_ast_node red; - t_vec_ast redirection; - t_fd *red_fd; - - if (subshell == NULL || state == NULL || out == NULL) - return (ERROR); - - mem_set_zero(&info, sizeof(info)); - info.stdin = cmd_pipe.input; - if (cmd_pipe.create_output) - { - if (create_pipe(&spipe)) - return (ERROR); - info.stdout = spipe.write; - info.ret_stdout = spipe.read; - } - i = 0; - filename_args = vec_str_new(16, str_free); - redirection = subshell->suffixes_redirections; - while (i < redirection.len) - { - red = redirection.buffer[i]; - if (red == NULL) - continue; - vec_str_free(filename_args); - filename_args = vec_str_new(16, str_free); - if (red->kind == AST_FILE_REDIRECTION) - { - if (red->data.file_redirection.op == AST_REDIR_INPUT) - { - if (info.stdin != NULL) - close_fd(info.stdin); - info.stdin = NULL; - if (_ast_into_str(red->data.file_redirection.output, state, &filename_args)) - return (ERROR); - if (filename_args.len != 1) - return (vec_str_free(filename_args), ERROR); - red_fd = open_fd(filename_args.buffer[i], FD_READ, O_CLOEXEC, 0); - if (red_fd == NULL) - return (vec_str_free(filename_args), ERROR); - info.stdin = red_fd; - }; - if (red->data.file_redirection.op == AST_REDIR_OUTPUT) - { - if (info.stdout != NULL) - close_fd(info.stdout); - info.stdout = NULL; - if (_ast_into_str(red->data.file_redirection.output, state, &filename_args)) - return (ERROR); - if (filename_args.len != 1) - return (vec_str_free(filename_args), ERROR); - red_fd = open_fd(filename_args.buffer[i], FD_WRITE, O_TRUNC | O_CREAT | O_CLOEXEC, FP_ALL_READ | FP_ALL_WRITE); - if (red_fd == NULL) - return (vec_str_free(filename_args), ERROR); - info.stdout = red_fd; - }; - if (red->data.file_redirection.op == AST_REDIR_APPEND) - { - if (info.stdout != NULL) - close_fd(info.stdout); - info.stdout = NULL; - if (_ast_into_str(red->data.file_redirection.output, state, &filename_args)) - return (ERROR); - if (filename_args.len != 1) - return (vec_str_free(filename_args), ERROR); - red_fd = open_fd(filename_args.buffer[i], FD_WRITE, O_TRUNC | O_CREAT | O_CLOEXEC, FP_ALL_READ | FP_ALL_WRITE); - if (red_fd == NULL) - return (vec_str_free(filename_args), ERROR); - info.stdout = red_fd; - }; - if (red->data.file_redirection.op == AST_REDIR_DUP_INPUT || red->data.file_redirection.op == AST_REDIR_DUP_OUTPUT || - red->data.file_redirection.op == AST_REDIR_CLOSE_INPUT || red->data.file_redirection.op == AST_REDIR_CLOSE_OUTPUT || - red->data.file_redirection.op == AST_REDIR_INPUT_OUTPUT || red->data.file_redirection.op == AST_REDIR_OUTPUT_CLOBBER) - return (ERROR); - } - if (red->kind == AST_HEREDOC_REDIRECTION) - { - if (red->data.heredoc_redirection.op == AST_REDIR_HEREDOC) - { - t_pipe heredoc_pipe; - - if (info.stdout != NULL) - close_fd(info.stdout); - info.stdout = NULL; - if (create_pipe(&heredoc_pipe)) - return (ERROR); - put_string_fd(heredoc_pipe.write, red->data.heredoc_redirection.content); - close_fd(heredoc_pipe.write); - info.stdin = heredoc_pipe.read; - } - if (red->data.heredoc_redirection.op == AST_REDIR_HEREDOC_INDENT) - return (ERROR); - } - - i++; - } - vec_str_free(filename_args); - - t_pid forked; - forked = fork(); - if (forked == 0) - { - int code; - - if (info.ret_stdout != NULL) - close_fd(info.ret_stdout); - if (info.stdin != NULL) - (dup2(info.stdin->fd, 0), close_fd(info.stdin)); - if (info.stdout != NULL) - (dup2(info.stdout->fd, 1), close_fd(info.stdout)); - if (info.stderr != NULL) - (dup2(info.stderr->fd, 2), close_fd(info.stderr)); - i = 0; - code = 0; - while (i < subshell->body.len) - { - if (_run_get_exit_code(subshell->body.buffer[i], state, &code)) - me_exit(127); - i++; - } - me_exit(code); - } - if (forked == -1) - return (ERROR); - out->exit = -1; - out->pid = forked; - if (info.stdin != NULL) - (dup2(info.stdin->fd, 0), close_fd(info.stdin)); - if (info.stdout != NULL) - (dup2(info.stdout->fd, 1), close_fd(info.stdout)); - if (info.stderr != NULL) - (dup2(info.stderr->fd, 2), close_fd(info.stderr)); - if (cmd_pipe.create_output || cmd_pipe.input != NULL) - return (out->stdout = info.ret_stdout, NO_ERROR); - int status; - if (waitpid(forked, &status, 0) == -1) - return (ERROR); - if (WIFEXITED(status)) - out->exit = WEXITSTATUS(status); - if (WIFSIGNALED(status)) - out->exit = WTERMSIG(status); - return (NO_ERROR); -} - -t_error run_list(t_ast_list *list, t_state *state, t_list_result *out) -{ - t_ast_node tmp; - t_vec_ast *append; - int left; - int right; - if (list == NULL || state == NULL || out == NULL) - return (ERROR); - append = NULL; - if (list->right->kind == AST_COMMAND) - append = &list->right->data.command.suffixes_redirections; - if (list->right->kind == AST_PIPELINE) - append = &list->right->data.pipeline.suffixes_redirections; - if (list->right->kind == AST_LIST) - append = &list->right->data.list.suffixes_redirections; - if (list->right->kind == AST_SUBSHELL) - append = &list->right->data.subshell.suffixes_redirections; - if (append != NULL) - { - while (!vec_ast_pop_front(&list->suffixes_redirections, &tmp)) - vec_ast_push(append, tmp); - } - left = -1; - right = -1; - if (_run_get_exit_code(list->left, state, &left)) - return (ERROR); - if ((list->op == AST_LIST_OR && left != 0) || (list->op == AST_LIST_AND && left == 0)) - { - if (_run_get_exit_code(list->right, state, &right)) - return (ERROR); - out->exit = right; - } - else - out->exit = left; - return (NO_ERROR); -}; - -t_error run_pipeline(t_ast_pipeline *pipeline, t_state *state, t_pipeline_result *out) -{ - t_usize i; - t_cmd_pipe cmd_pipe; - t_ast_node child; - t_error ret; - t_command_result cmd_result; - t_ast_node tmp_ast; - t_vec_pid pids; - int waitpid_status; - - if (pipeline == NULL || state == NULL || out == NULL) - return (ERROR); - i = 0; - ret = NO_ERROR; - cmd_pipe.input = NULL; - cmd_pipe.create_output = true; - out->exit = 127; - pids = vec_pid_new(32, NULL); - while (i < pipeline->statements.len - 1) - { - child = pipeline->statements.buffer[i]; - if (child->kind == AST_COMMAND) - { - if (run_command(&child->data.command, state, cmd_pipe, &cmd_result)) - { - cmd_pipe.input = NULL; - ret = ERROR; - } - else - { - vec_pid_push(&pids, cmd_result.process.pid); - close_fd(cmd_pipe.input); - if (cmd_result.process.stdout != NULL) - cmd_pipe.input = cmd_result.process.stdout; - if (cmd_result.process.stdin != NULL) - close_fd(cmd_result.process.stdin); - if (cmd_result.process.stderr != NULL) - close_fd(cmd_result.process.stderr); - } - } - i++; - } - { - cmd_pipe.create_output = false; - child = pipeline->statements.buffer[i]; - if (child->kind == AST_COMMAND) - { - while (!vec_ast_pop_front(&pipeline->suffixes_redirections, &tmp_ast)) - vec_ast_push(&child->data.command.suffixes_redirections, tmp_ast); - if (run_command(&child->data.command, state, cmd_pipe, &cmd_result)) - { - ret = ERROR; - } - else - { - vec_pid_push(&pids, cmd_result.process.pid); - close_fd(cmd_pipe.input); - if (cmd_result.process.stdout != NULL) - close_fd(cmd_result.process.stdout); - if (cmd_result.process.stdin != NULL) - close_fd(cmd_result.process.stdin); - if (cmd_result.process.stderr != NULL) - close_fd(cmd_result.process.stderr); - } - } - } - if (pids.len != 0) - { - if (!(kill(pids.buffer[pids.len - 1], 0) == -1 && errno == ESRCH)) - while (waitpid(pids.buffer[pids.len - 1], &waitpid_status, 0) < 0) - ; - while (waitpid(-1, NULL, 0) != -1) - ; - if (WIFEXITED(waitpid_status)) - out->exit = WEXITSTATUS(waitpid_status); - if (WIFSIGNALED(waitpid_status)) - out->exit = WTERMSIG(waitpid_status); - } - else - out->exit = 127; - vec_pid_free(pids); - return (ret); -} - -t_error run_program(t_ast_program *self, t_state *state, t_program_result *out) -{ - t_usize i; - - if (self == NULL || state == NULL || out == NULL) - return (ERROR); - i = 0; - while (i < self->body.len) - { - if (_run_get_exit_code(self->body.buffer[i], state, &out->exit)) - return (ERROR); - i++; - } - - return (NO_ERROR); -} - -/// this functons returns different things depending on the operator and/or the state of the shell -/// NULL != empty string for example -t_error run_expansion(t_ast_expansion *self, t_state *state, t_expansion_result *out) -{ - t_expansion_result ret; - bool is_special_var; - - is_special_var = _is_special_var(self); - if (is_special_var && _run_expansion_special_var(self, state, &ret)) - return (ERROR); - if (!is_special_var && _get_expansion_value(self, state, &ret)) - return (ERROR); - if (_handle_expansion_operator(self, state, &ret)) - return (ERROR); - if (self->len_operator && _handle_len_operator(self, state, &ret)) - return (ERROR); - return (*out = ret, NO_ERROR); -} - -struct s_ffree_state -{ - t_state *state; - t_cmd_pipe cmd_pipe; -}; - -void _ffree_func(struct s_ffree_state *state) -{ - if (state == NULL) - return; - hmap_env_free(state->state->env); - hmap_env_free(state->state->tmp_var); - close_fd(state->cmd_pipe.input); -} - -bool _is_builtin(t_const_str argv0) -{ - t_usize i; - const t_str value[] = {"cd", "echo", "env", "exit", "export", "pwd", "unset", "_debug", NULL}; - - i = 0; - if (argv0 == NULL) - return (false); - while (value[i] != NULL) - if (str_compare(argv0, value[i++])) - return (true); - return (false); -} - -t_error _handle_builtin(t_spawn_info info, t_state *state, t_cmd_pipe cmd_pipe, t_command_result *out) -{ - t_usize i; - const t_const_str argv0 = info.binary_path; - const t_str value[] = {"cd", "echo", "env", "exit", "export", "pwd", "unset", "_debug", NULL}; - const t_builtin_func funcs[] = {builtin_cd____, builtin_echo__, builtin_env___, - builtin_exit__, builtin_export, builtin_pwd___, - builtin_unset_, builtin_debug_, NULL}; - t_builtin_func actual_func; - - i = 0; - if (argv0 == NULL) - return (ERROR); - actual_func = NULL; - while (value[i] != NULL) - { - if (str_compare(argv0, value[i])) - { - actual_func = funcs[i]; - break; - } - i++; - } - if (actual_func == NULL) - return (me_abort("Builtin found but no function found..."), ERROR); - t_builtin_spawn_info binfo; - mem_set_zero(out, sizeof(*out)); - if (info.stdin.tag == R_FD) - binfo.stdin = info.stdin.fd.fd; - if (info.stdin.tag == R_INHERITED) - binfo.stdin = dup_fd(get_stdin()); - if (info.stderr.tag == R_FD) - binfo.stderr = info.stderr.fd.fd; - if (info.stderr.tag == R_INHERITED) - binfo.stderr = dup_fd(get_stderr()); - if (info.stdout.tag == R_FD) - binfo.stdout = info.stdout.fd.fd; - if (info.stdout.tag == R_INHERITED) - binfo.stdout = dup_fd(get_stdout()); - if (info.stdout.tag == R_PIPED) - { - t_pipe pipe_fd; - if (create_pipe(&pipe_fd)) - return (ERROR); - out->process.stdout = pipe_fd.read; - binfo.stdout = pipe_fd.write; - } - binfo.args = info.arguments; - bool do_fork = cmd_pipe.input != NULL || cmd_pipe.create_output; - t_i32 exit_code; - if (do_fork) - { - out->process.pid = fork(); - if (out->process.pid == 0) - { - if (actual_func(state, binfo, &exit_code)) - me_exit(127); - me_exit(exit_code); - } - if (out->process.pid == -1) - out->exit = 126; - else - out->exit = -1; - } - else - { - if (actual_func(state, binfo, &exit_code)) - out->exit = 126; - else - out->exit = exit_code; - } - if (binfo.stdin) - close_fd(binfo.stdin); - if (binfo.stdout) - close_fd(binfo.stdout); - if (binfo.stderr) - close_fd(binfo.stderr); - vec_str_free(info.arguments); - str_free(info.binary_path); - return (NO_ERROR); -} - -t_error _spawn_cmd_and_run(t_vec_str args, t_vec_ast redirection, t_state *state, t_cmd_pipe cmd_pipe, t_command_result *out) -{ - t_spawn_info info; - t_usize i; - t_ast_node red; - t_vec_str filename_args; - t_fd *red_fd; - struct s_ffree_state ffree; - - info = (t_spawn_info){}; - if (cmd_pipe.input != NULL) - info.stdin = fd(cmd_pipe.input); - if (cmd_pipe.create_output) - info.stdout = piped(); - i = 0; - filename_args = vec_str_new(16, str_free); - while (i < redirection.len) - { - red = redirection.buffer[i]; - if (red == NULL) - continue; - vec_str_free(filename_args); - filename_args = vec_str_new(16, str_free); - if (red->kind == AST_FILE_REDIRECTION) - { - if (red->data.file_redirection.op == AST_REDIR_INPUT) - { - if (info.stdin.tag == R_FD) - close_fd(info.stdin.fd.fd); - info.stdin.tag = R_INHERITED; - if (_ast_into_str(red->data.file_redirection.output, state, &filename_args)) - return (ERROR); - if (filename_args.len != 1) - return (vec_str_free(filename_args), ERROR); - red_fd = open_fd(filename_args.buffer[i], FD_READ, O_CLOEXEC, 0); - if (red_fd == NULL) - return (vec_str_free(filename_args), ERROR); - info.stdin = fd(red_fd); - }; - if (red->data.file_redirection.op == AST_REDIR_OUTPUT) - { - if (info.stdout.tag == R_FD) - close_fd(info.stdout.fd.fd); - info.stdout.tag = R_INHERITED; - if (_ast_into_str(red->data.file_redirection.output, state, &filename_args)) - return (ERROR); - if (filename_args.len != 1) - return (vec_str_free(filename_args), ERROR); - red_fd = open_fd(filename_args.buffer[i], FD_WRITE, O_TRUNC | O_CREAT | O_CLOEXEC, FP_ALL_READ | FP_ALL_WRITE); - if (red_fd == NULL) - return (vec_str_free(filename_args), ERROR); - info.stdout = fd(red_fd); - }; - if (red->data.file_redirection.op == AST_REDIR_APPEND) - { - if (info.stdout.tag == R_FD) - close_fd(info.stdout.fd.fd); - info.stdout.tag = R_INHERITED; - if (_ast_into_str(red->data.file_redirection.output, state, &filename_args)) - return (ERROR); - if (filename_args.len != 1) - return (vec_str_free(filename_args), ERROR); - red_fd = open_fd(filename_args.buffer[i], FD_WRITE, O_TRUNC | O_CREAT | O_CLOEXEC, FP_ALL_READ | FP_ALL_WRITE); - if (red_fd == NULL) - return (vec_str_free(filename_args), ERROR); - info.stdout = fd(red_fd); - }; - if (red->data.file_redirection.op == AST_REDIR_DUP_INPUT || red->data.file_redirection.op == AST_REDIR_DUP_OUTPUT || - red->data.file_redirection.op == AST_REDIR_CLOSE_INPUT || red->data.file_redirection.op == AST_REDIR_CLOSE_OUTPUT || - red->data.file_redirection.op == AST_REDIR_INPUT_OUTPUT || red->data.file_redirection.op == AST_REDIR_OUTPUT_CLOBBER) - return (ERROR); - } - if (red->kind == AST_HEREDOC_REDIRECTION) - { - if (red->data.heredoc_redirection.op == AST_REDIR_HEREDOC) - { - t_pipe heredoc_pipe; - - if (info.stdout.tag == R_FD) - close_fd(info.stdout.fd.fd); - info.stdout.tag = R_INHERITED; - if (create_pipe(&heredoc_pipe)) - return (ERROR); - put_string_fd(heredoc_pipe.write, red->data.heredoc_redirection.content); - close_fd(heredoc_pipe.write); - info.stdin = fd(heredoc_pipe.read); - } - if (red->data.heredoc_redirection.op == AST_REDIR_HEREDOC_INDENT) - return (ERROR); - } - - i++; - } - ffree = (struct s_ffree_state){.state = state, .cmd_pipe = cmd_pipe}; - redirection.len = 0; - vec_ast_free(redirection); - vec_str_free(filename_args); - info.arguments = args; - if (args.len == 0) - return (vec_str_free(args), ERROR); - info.binary_path = str_clone(info.arguments.buffer[0]); - if (_is_builtin(info.binary_path)) - return (_handle_builtin(info, state, cmd_pipe, out)); - if (build_envp(state->env, state->tmp_var, &info.environement)) - return (str_free(info.binary_path), ERROR); - info.forked_free_args = &ffree; - info.forked_free = (void (*)(void *))_ffree_func; - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - if (spawn_process(info, &out->process)) - return (close_fd(cmd_pipe.input), out->exit = 127, ERROR); - if (cmd_pipe.create_output || cmd_pipe.input != NULL) - return (out->exit = -1, NO_ERROR); - int status; - if (waitpid(out->process.pid, &status, 0) == -1) - return (ERROR); - if (WIFEXITED(status)) - out->exit = WEXITSTATUS(status); - if (WIFSIGNALED(status)) - out->exit = WTERMSIG(status); - return (NO_ERROR); -} - -t_error run_command(t_ast_command *command, t_state *state, t_cmd_pipe cmd_pipe, t_command_result *out) -{ - t_vec_str args; - t_vec_str split; - t_vec_ast redirection; - t_usize i; - t_hashmap_env *env_bck; - t_ast_node tmp; - t_str tmp_str; - - if (command == NULL || state == NULL || out == NULL) - return (ERROR); - hmap_env_clear(state->tmp_var); - args = vec_str_new(command->cmd_word.len, str_free); - redirection = vec_ast_new(command->suffixes_redirections.len, ast_free); - i = 0; - while (i < command->prefixes.len) - { - tmp = command->prefixes.buffer[i]; - if (tmp->kind == AST_FILE_REDIRECTION || tmp->kind == AST_HEREDOC_REDIRECTION) - vec_ast_push(&redirection, tmp); - if (tmp->kind == AST_VARIABLE_ASSIGNMENT) - { - if (run_variable_assignment(&tmp->data.variable_assignment, state, true, NULL)) - return (vec_str_free(args), vec_ast_free(redirection), ERROR); - } - i++; - } - i = 0; - while (i < command->cmd_word.len) - { - if (_ast_into_str(command->cmd_word.buffer[i], state, &args)) - return (vec_str_free(args), vec_ast_free(redirection), ERROR); - i++; - } - i = 0; - while (i < command->suffixes_redirections.len) - { - tmp = command->suffixes_redirections.buffer[i]; - if (tmp->kind == AST_FILE_REDIRECTION || tmp->kind == AST_HEREDOC_REDIRECTION) - vec_ast_push(&redirection, tmp); - i++; - } - if (_spawn_cmd_and_run(args, redirection, state, cmd_pipe, out)) - return (ERROR); - return (NO_ERROR); -} - -t_error run_word(t_ast_word *word, t_state *state, t_word_result *out) -{ - t_word_iterator iter_state; - t_vec_str tmp; - t_str tmp_str; - t_expandable_str s; - - if (word == NULL || state == NULL || out == NULL) - return (ERROR); - iter_state.res.value = vec_estr_new(64, free_expandable_str); - iter_state.res.has_error = false; - iter_state.res.kind = word->kind; - iter_state.state = state; - vec_ast_iter(&word->inner, (void (*)())_run_word_into_str, &iter_state); - if (iter_state.res.has_error) - return (vec_estr_free(iter_state.res.value), ERROR); - return (*out = iter_state.res, NO_ERROR); -} diff --git a/exec/src/run_ast/_ast_into_str.c b/exec/src/run_ast/_ast_into_str.c new file mode 100644 index 00000000..6152ece8 --- /dev/null +++ b/exec/src/run_ast/_ast_into_str.c @@ -0,0 +1,127 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* _ast_into_str.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:26:51 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:46:11 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "me/string/string.h" +#include "me/str/str.h" +#include "me/convert/numbers_to_str.h" + +t_error _word_into_str(t_ast_node self, t_state *state, t_vec_str *append) +{ + t_word_result res; + t_vec_str splitted; + t_string tmp; + t_usize i; + t_usize j; + t_usize len; + t_str ifs; + t_str tmp_str; + + if (self == NULL || state == NULL || append == NULL + || self->kind != AST_WORD) + return (ERROR); + if (run_word(&self->data.word, state, &res)) + return (ERROR); + if (res.kind == AST_WORD_NO_QUOTE) + { + tmp = string_new(64); + i = 0; + while (i < res.value.len) + { + if (!res.value.buffer[i].do_expand) + string_push(&tmp, res.value.buffer[i].value); + else + { + ifs = _get_ifs_value(state); + while (ifs != NULL && *ifs != '\0' + && str_find_chr(res.value.buffer[i].value, *ifs) == NULL) + ifs++; + if (ifs == NULL || *ifs == '\0') + string_push(&tmp, res.value.buffer[i].value); + else + { + ifs = _get_ifs_value(state); + if (str_split(res.value.buffer[i].value, ifs, &splitted)) + return (vec_estr_free(res.value), ERROR); + if (!vec_str_pop_front(&splitted, &tmp_str)) + { + if (str_find_chr(ifs, + res.value.buffer[i].value[0]) == NULL) + (string_push(&tmp, tmp_str), str_free(tmp_str)); + else + { + vec_str_push(append, tmp.buf); + tmp = string_new(64); + string_push(&tmp, tmp_str); + str_free(tmp_str); + } + j = 0; + while (j + 1 < splitted.len) + { + if (vec_str_pop_front(&splitted, &tmp_str)) + return (vec_estr_free(res.value), ERROR); + vec_str_push(append, tmp_str); + j++; + } + len = str_len(res.value.buffer[i].value); + if (len != 0 && str_find_chr(ifs, + res.value.buffer[i].value[len - 1]) == NULL) + (string_push(&tmp, tmp_str), str_free(tmp_str)); + else + vec_str_push(append, tmp_str); + } + } + } + i++; + } + vec_str_push(append, tmp.buf); + } + else + { + tmp = string_new(64); + i = 0; + while (i < res.value.len) + { + string_push(&tmp, res.value.buffer[i++].value); + } + vec_str_push(append, tmp.buf); + } + vec_estr_free(res.value); + return (NO_ERROR); +} + +t_error _raw_str_into_str(t_ast_node self, t_state *state, t_vec_str *append) +{ + if (self == NULL || state == NULL || append == NULL + || self->kind != AST_RAW_STRING) + return (ERROR); + vec_str_push(append, str_clone(self->data.raw_string.str)); + return (NO_ERROR); +} + +t_error _ast_into_str(t_ast_node self, t_state *state, t_vec_str *append) +{ + if (self == NULL || state == NULL || append == NULL) + return (ERROR); + if (self->kind == AST_EXPANSION) + return (_exp_into_str(self, state, append)); + if (self->kind == AST_ARITHMETIC_EXPANSION) + return (_arith_into_str(self, state, append)); + if (self->kind == AST_COMMAND_SUBSTITUTION) + return (_cmd_into_str(self, state, append)); + if (self->kind == AST_WORD) + return (_word_into_str(self, state, append)); + if (self->kind == AST_RAW_STRING) + return (_raw_str_into_str(self, state, append)); + printf("unknown Kind = %#04x\n", self->kind); + return (ERROR); +} diff --git a/exec/src/run_ast/_ast_into_str2.c b/exec/src/run_ast/_ast_into_str2.c new file mode 100644 index 00000000..80a519e2 --- /dev/null +++ b/exec/src/run_ast/_ast_into_str2.c @@ -0,0 +1,122 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* _ast_into_str2.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:26:51 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:43:56 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "me/string/string.h" +#include "me/str/str.h" +#include "me/convert/numbers_to_str.h" + +t_error _ast_get_str__raw__no_quote(t_ast_node elem, t_word_iterator *state, + t_vec_estr *out) +{ + bool last_backslash; + t_string ret; + t_usize i; + + if (elem == NULL || state == NULL || out == NULL + || elem->kind != AST_RAW_STRING + || elem->data.raw_string.kind != AST_WORD_NO_QUOTE) + return (ERROR); + i = 0; + ret = string_new(elem->data.raw_string.len); + last_backslash = false; + while (elem->data.raw_string.str[i]) + { + if (elem->data.raw_string.str[i] != '\\' || last_backslash) + string_push_char(&ret, elem->data.raw_string.str[i]); + last_backslash = false; + if (elem->data.raw_string.str[i] == '\\' && !last_backslash) + last_backslash = true; + i++; + } + return (vec_estr_push(out, (t_expandable_str){.do_expand = false, + .value = ret.buf}), NO_ERROR); +} + +t_error _ast_get_str__raw__single_quote(t_ast_node elem, t_word_iterator *state, + t_vec_estr *out) +{ + t_string ret; + t_usize i; + + if (elem == NULL || state == NULL || out == NULL + || elem->kind != AST_RAW_STRING + || elem->data.raw_string.kind != AST_WORD_SINGLE_QUOTE) + return (ERROR); + i = 1; + ret = string_new(elem->data.raw_string.len); + while (elem->data.raw_string.str[i]) + string_push_char(&ret, elem->data.raw_string.str[i++]); + string_pop(&ret); + return (vec_estr_push(out, (t_expandable_str){.do_expand = false, + .value = ret.buf}), NO_ERROR); +} + +t_error _ast_get_str__raw__double_quote(t_ast_node elem, t_word_iterator *state, + t_vec_estr *out) +{ + bool last_backslash; + t_string ret; + t_usize i; + + if (elem == NULL || state == NULL || out == NULL + || elem->kind != AST_RAW_STRING + || elem->data.raw_string.kind != AST_WORD_DOUBLE_QUOTE) + return (ERROR); + i = 0; + ret = string_new(elem->data.raw_string.len); + last_backslash = false; + while (elem->data.raw_string.str[i]) + { + if (elem->data.raw_string.str[i] != '\\' || last_backslash) + string_push_char(&ret, elem->data.raw_string.str[i]); + last_backslash = false; + if (elem->data.raw_string.str[i] == '\\' && !last_backslash) + last_backslash = true; + i++; + } + return (vec_estr_push(out, (t_expandable_str){.do_expand = false, + .value = ret.buf}), NO_ERROR); +} + +t_error _ast_get_str__raw(t_ast_node elem, t_word_iterator *state, + t_vec_estr *out) +{ + if (elem == NULL || state == NULL || out == NULL + || elem->kind != AST_RAW_STRING) + return (ERROR); + if (elem->data.raw_string.kind == AST_WORD_NO_QUOTE) + return (_ast_get_str__raw__no_quote(elem, state, out)); + if (elem->data.raw_string.kind == AST_WORD_SINGLE_QUOTE) + return (_ast_get_str__raw__single_quote(elem, state, out)); + if (elem->data.raw_string.kind == AST_WORD_DOUBLE_QUOTE) + return (_ast_get_str__raw__double_quote(elem, state, out)); + return (ERROR); +} + +t_str _get_ifs_value(t_state *state) +{ + t_str ifs; + t_str *ifs_entry; + t_str ifs_key; + + ifs_key = "IFS"; + ifs = NULL; + ifs_entry = hmap_env_get(state->tmp_var, (t_str *)&ifs_key); + if (ifs_entry != NULL) + ifs_entry = hmap_env_get(state->env, (t_str *)&ifs_key); + if (ifs_entry != NULL) + ifs = *ifs_entry; + if (ifs == NULL) + ifs = " \t\n"; + return (ifs); +} diff --git a/exec/src/run_ast/_ast_into_str3.c b/exec/src/run_ast/_ast_into_str3.c new file mode 100644 index 00000000..5cf017b0 --- /dev/null +++ b/exec/src/run_ast/_ast_into_str3.c @@ -0,0 +1,99 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* _ast_into_str3.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:26:51 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:45:31 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "me/string/string.h" +#include "me/str/str.h" +#include "me/convert/numbers_to_str.h" + +t_error _ast_get_str__expansion(t_ast_node elem, t_word_iterator *state, + t_vec_estr *out) +{ + t_expansion_result exp_ret; + + if (elem == NULL || state == NULL || out == NULL + || elem->kind != AST_EXPANSION) + return (ERROR); + if (run_expansion(&elem->data.expansion, state->state, &exp_ret)) + return (ERROR); + return (vec_estr_push(out, + (t_expandable_str){.do_expand = \ + state->res.kind == AST_WORD_NO_QUOTE, .value = \ + exp_ret.value}), NO_ERROR); +} + +t_error _ast_get_str__arimethic_expansion(t_ast_node elem, + t_word_iterator *state, t_vec_estr *out) +{ + t_str out_str; + t_i64 out_num; + + if (elem == NULL || state == NULL || out == NULL + || elem->kind != AST_ARITHMETIC_EXPANSION) + return (ERROR); + if (run_arithmetic_expansion(&elem->data.arithmetic_expansion, state->state, + &out_num)) + return (ERROR); + if (i64_to_str(out_num, &out_str)) + return (ERROR); + vec_estr_push(out, + (t_expandable_str){.do_expand = state->res.kind == AST_WORD_NO_QUOTE, + .value = out_str}); + return (NO_ERROR); +} + +// vec_estr_push(out, (t_expandable_str){.do_expand = +// state->res.kind == AST_WORD_NO_QUOTE, .value = +// str_clone(exp_out.value)}); +t_error _ast_get_str__command_substitution(t_ast_node elem, + t_word_iterator *state, t_vec_estr *out) +{ + if (elem == NULL || state == NULL || out == NULL + || elem->kind != AST_COMMAND_SUBSTITUTION) + return (ERROR); + return (ERROR); +} + +t_error _ast_get_str__word(t_ast_node elem, t_word_iterator *state, + t_vec_estr *out) +{ + t_vec_str res; + t_str tmp; + + if (elem == NULL || state == NULL || out == NULL || elem->kind != AST_WORD) + return (ERROR); + res = vec_str_new(16, str_free); + if (_ast_into_str(elem, state->state, &res)) + return (vec_str_free(res), ERROR); + while (!vec_str_pop_front(&res, &tmp)) + vec_estr_push(out, (t_expandable_str){.do_expand = false, + .value = tmp}); + vec_str_free(res); + return (NO_ERROR); +} + +t_error _ast_get_str(t_ast_node elem, t_word_iterator *state, t_vec_estr *out) +{ + if (elem == NULL || state == NULL || out == NULL) + return (ERROR); + if (elem->kind == AST_RAW_STRING) + return (_ast_get_str__raw(elem, state, out)); + if (elem->kind == AST_EXPANSION) + return (_ast_get_str__expansion(elem, state, out)); + if (elem->kind == AST_ARITHMETIC_EXPANSION) + return (_ast_get_str__arimethic_expansion(elem, state, out)); + if (elem->kind == AST_COMMAND_SUBSTITUTION) + return (_ast_get_str__command_substitution(elem, state, out)); + if (elem->kind == AST_WORD) + return (_ast_get_str__word(elem, state, out)); + return (ERROR); +} diff --git a/exec/src/run_ast/_ast_into_str4.c b/exec/src/run_ast/_ast_into_str4.c new file mode 100644 index 00000000..a0a87ed1 --- /dev/null +++ b/exec/src/run_ast/_ast_into_str4.c @@ -0,0 +1,55 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* _ast_into_str4.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:26:51 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:46:00 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "me/string/string.h" +#include "me/str/str.h" +#include "me/convert/numbers_to_str.h" + +void _run_word_into_str(t_usize idx, t_ast_node *elem, + t_word_iterator *state) +{ + (void)(idx); + if (elem == NULL || *elem == NULL || state == NULL) + return ; + if (_ast_get_str(*elem, state, &state->res.value)) + return ; +} + +t_error _exp_into_str(t_ast_node self, t_state *state, t_vec_str *append) +{ + t_expansion_result res; + t_vec_str splitted; + t_str tmp; + + if (self == NULL || state == NULL || append == NULL + || self->kind != AST_EXPANSION) + return (ERROR); + if (run_expansion(&self->data.expansion, state, &res)) + return (ERROR); + if (res.value == NULL) + return (NO_ERROR); + if (str_split(res.value, _get_ifs_value(state), &splitted)) + return (ERROR); + while (!vec_str_pop_front(&splitted, &tmp)) + vec_str_push(append, tmp); + vec_str_free(splitted); + return (NO_ERROR); +} + +t_error _arith_into_str(t_ast_node self, t_state *state, t_vec_str *append) +{ + if (self == NULL || state == NULL || append == NULL + || self->kind != AST_ARITHMETIC_EXPANSION) + return (ERROR); + return (NO_ERROR); +} diff --git a/exec/src/run_ast/_run_exit_code.c b/exec/src/run_ast/_run_exit_code.c new file mode 100644 index 00000000..9f2eb908 --- /dev/null +++ b/exec/src/run_ast/_run_exit_code.c @@ -0,0 +1,55 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* _run_exit_code.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:31:28 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:31:47 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" + +t_error _run_get_exit_code(t_ast_node self, t_state *state, int *out) +{ + t_command_result cmd_res; + t_pipeline_result pipe_res; + t_list_result list_res; + t_subshell_result subshell_res; + + if (self->kind == AST_COMMAND) + { + if (run_command(\ + &self->data.command, state, (t_cmd_pipe){NULL, false}, &cmd_res)) + return (ERROR); + if (cmd_res.process.stdin != NULL) + close_fd(cmd_res.process.stdin); + if (cmd_res.process.stdout != NULL) + close_fd(cmd_res.process.stdout); + if (cmd_res.process.stderr != NULL) + close_fd(cmd_res.process.stderr); + *out = cmd_res.exit; + } + if (self->kind == AST_PIPELINE) + { + if (run_pipeline(&self->data.pipeline, state, &pipe_res)) + return (ERROR); + *out = pipe_res.exit; + } + if (self->kind == AST_LIST) + { + if (run_list(&self->data.list, state, &list_res)) + return (ERROR); + *out = list_res.exit; + } + if (self->kind == AST_SUBSHELL) + { + if (run_subshell(\ + &self->data.subshell, state, (t_cmd_pipe){NULL, false}, &subshell_res)) + return (ERROR); + *out = subshell_res.exit; + } + return (NO_ERROR); +} diff --git a/exec/src/run_ast/_run_exp_operators.c b/exec/src/run_ast/_run_exp_operators.c new file mode 100644 index 00000000..d2e76aa6 --- /dev/null +++ b/exec/src/run_ast/_run_exp_operators.c @@ -0,0 +1,79 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* _run_exp_operators.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:40:01 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:40:44 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "me/mem/mem.h" +#include "me/str/str.h" +#include "me/convert/numbers_to_str.h" + +t_error _handle_len_operator(t_ast_expansion *self, t_state *state, + t_expansion_result *value) +{ + t_str len_str; + t_usize len; + + (void)(self); + (void)(state); + (void)(value); + if (value->exists && value->value != NULL) + len = str_len(value->value); + else + len = 0; + if (u64_to_str(len, &len_str)) + return (ERROR); + mem_free(value->value); + value->exists = true; + value->value = len_str; + return (NO_ERROR); +} + +t_error _handle_no_operator(t_ast_expansion *self, t_state *state, + t_expansion_result *value) +{ + t_str *val; + + if (self == NULL || state == NULL || value == NULL) + return (ERROR); + val = hmap_env_get(state->tmp_var, &self->var_name); + if (val == NULL) + val = hmap_env_get(state->env, &self->var_name); + if (val == NULL) + return (value->exists = false, NO_ERROR); + value->exists = true; + value->value = str_clone(*val); + return (NO_ERROR); +} + +t_error _get_op_func(t_ast_expansion *self, + t_error (**op_func)(t_ast_expansion *self, t_state *state, + t_expansion_result *value)) +{ + if (self == NULL || op_func == NULL) + return (ERROR); + if (self->kind == E_OP_NONE) + return (*op_func = _handle_no_operator, NO_ERROR); + return (ERROR); +} + +t_error _handle_expansion_operator(t_ast_expansion *self, t_state *state, + t_expansion_result *value) +{ + t_error (*op_func)(t_ast_expansion * self, t_state * state, \ + t_expansion_result * value); + if (self == NULL || state == NULL || value == NULL) + return (ERROR); + if (_get_op_func(self, &op_func)) + return (ERROR); + if (op_func(self, state, value)) + return (ERROR); + return (NO_ERROR); +} diff --git a/exec/src/run_ast/_spawn_cmd.c b/exec/src/run_ast/_spawn_cmd.c new file mode 100644 index 00000000..1f8563b7 --- /dev/null +++ b/exec/src/run_ast/_spawn_cmd.c @@ -0,0 +1,151 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* _spawn_cmd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:30:09 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:31:00 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "app/env.h" +#include "exec/_run_ast.h" +#include "me/str/str.h" +#include +#include + +t_error _spawn_cmd_and_run(t_vec_str args, t_vec_ast redirection, + t_state *state, t_cmd_pipe cmd_pipe, t_command_result *out) +{ + t_spawn_info info; + t_usize i; + t_ast_node red; + t_vec_str filename_args; + t_fd *red_fd; + struct s_ffree_state ffree; + t_pipe heredoc_pipe; + int status; + + info = (t_spawn_info){}; + if (cmd_pipe.input != NULL) + info.stdin = fd(cmd_pipe.input); + if (cmd_pipe.create_output) + info.stdout = piped(); + i = 0; + filename_args = vec_str_new(16, str_free); + while (i < redirection.len) + { + red = redirection.buffer[i]; + if (red == NULL) + continue ; + vec_str_free(filename_args); + filename_args = vec_str_new(16, str_free); + if (red->kind == AST_FILE_REDIRECTION) + { + if (red->data.file_redirection.op == AST_REDIR_INPUT) + { + if (info.stdin.tag == R_FD) + close_fd(info.stdin.fd.fd); + info.stdin.tag = R_INHERITED; + if (_ast_into_str(red->data.file_redirection.output, state, + &filename_args)) + return (ERROR); + if (filename_args.len != 1) + return (vec_str_free(filename_args), ERROR); + red_fd = open_fd(filename_args.buffer[i], FD_READ, O_CLOEXEC, + 0); + if (red_fd == NULL) + return (vec_str_free(filename_args), ERROR); + info.stdin = fd(red_fd); + } + if (red->data.file_redirection.op == AST_REDIR_OUTPUT) + { + if (info.stdout.tag == R_FD) + close_fd(info.stdout.fd.fd); + info.stdout.tag = R_INHERITED; + if (_ast_into_str(red->data.file_redirection.output, state, + &filename_args)) + return (ERROR); + if (filename_args.len != 1) + return (vec_str_free(filename_args), ERROR); + red_fd = open_fd(filename_args.buffer[i], FD_WRITE, + O_TRUNC | O_CREAT | O_CLOEXEC, + FP_ALL_READ | FP_ALL_WRITE); + if (red_fd == NULL) + return (vec_str_free(filename_args), ERROR); + info.stdout = fd(red_fd); + } + if (red->data.file_redirection.op == AST_REDIR_APPEND) + { + if (info.stdout.tag == R_FD) + close_fd(info.stdout.fd.fd); + info.stdout.tag = R_INHERITED; + if (_ast_into_str(red->data.file_redirection.output, state, + &filename_args)) + return (ERROR); + if (filename_args.len != 1) + return (vec_str_free(filename_args), ERROR); + red_fd = open_fd(filename_args.buffer[i], FD_WRITE, + O_TRUNC | O_CREAT | O_CLOEXEC, + FP_ALL_READ | FP_ALL_WRITE); + if (red_fd == NULL) + return (vec_str_free(filename_args), ERROR); + info.stdout = fd(red_fd); + } + if (red->data.file_redirection.op == AST_REDIR_DUP_INPUT + || red->data.file_redirection.op == AST_REDIR_DUP_OUTPUT + || red->data.file_redirection.op == AST_REDIR_CLOSE_INPUT + || red->data.file_redirection.op == AST_REDIR_CLOSE_OUTPUT + || red->data.file_redirection.op == AST_REDIR_INPUT_OUTPUT + || red->data.file_redirection.op == AST_REDIR_OUTPUT_CLOBBER) + return (ERROR); + } + if (red->kind == AST_HEREDOC_REDIRECTION) + { + if (red->data.heredoc_redirection.op == AST_REDIR_HEREDOC) + { + if (info.stdout.tag == R_FD) + close_fd(info.stdout.fd.fd); + info.stdout.tag = R_INHERITED; + if (create_pipe(&heredoc_pipe)) + return (ERROR); + put_string_fd(heredoc_pipe.write, + red->data.heredoc_redirection.content); + close_fd(heredoc_pipe.write); + info.stdin = fd(heredoc_pipe.read); + } + if (red->data.heredoc_redirection.op == AST_REDIR_HEREDOC_INDENT) + return (ERROR); + } + i++; + } + ffree = (struct s_ffree_state){.state = state, .cmd_pipe = cmd_pipe}; + redirection.len = 0; + vec_ast_free(redirection); + vec_str_free(filename_args); + info.arguments = args; + if (args.len == 0) + return (vec_str_free(args), ERROR); + info.binary_path = str_clone(info.arguments.buffer[0]); + if (_is_builtin(info.binary_path)) + return (_handle_builtin(info, state, cmd_pipe, out)); + if (build_envp(state->env, state->tmp_var, &info.environement)) + return (str_free(info.binary_path), ERROR); + info.forked_free_args = &ffree; + info.forked_free = (void (*)(void *))_ffree_func; + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + if (spawn_process(info, &out->process)) + return (close_fd(cmd_pipe.input), out->exit = 127, ERROR); + if (cmd_pipe.create_output || cmd_pipe.input != NULL) + return (out->exit = -1, NO_ERROR); + if (waitpid(out->process.pid, &status, 0) == -1) + return (ERROR); + if (WIFEXITED(status)) + out->exit = WEXITSTATUS(status); + if (WIFSIGNALED(status)) + out->exit = WTERMSIG(status); + return (NO_ERROR); +} diff --git a/exec/src/run_ast/run_builtins.c b/exec/src/run_ast/run_builtins.c new file mode 100644 index 00000000..491f8990 --- /dev/null +++ b/exec/src/run_ast/run_builtins.c @@ -0,0 +1,125 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_builtins.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:24:49 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:25:48 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "exec/builtins.h" +#include "me/mem/mem.h" +#include "me/str/str.h" + +void _ffree_func(struct s_ffree_state *state) +{ + if (state == NULL) + return ; + hmap_env_free(state->state->env); + hmap_env_free(state->state->tmp_var); + close_fd(state->cmd_pipe.input); +} + +bool _is_builtin(t_const_str argv0) +{ + t_usize i; + const t_str value[] = {"cd", "echo", "env", "exit", "export", "pwd", \ + "unset", "_debug", NULL}; + + i = 0; + if (argv0 == NULL) + return (false); + while (value[i] != NULL) + if (str_compare(argv0, value[i++])) + return (true); + return (false); +} + +t_error _handle_builtin(t_spawn_info info, t_state *state, t_cmd_pipe cmd_pipe, + t_command_result *out) +{ + t_usize i; + const t_const_str argv0 = info.binary_path; + const t_str value[] = {"cd", "echo", "env", "exit", "export", \ + "pwd", "unset", "_debug", NULL}; + const t_builtin_func funcs[] = {builtin_cd____, builtin_echo__, \ + builtin_env___, builtin_exit__, builtin_export, builtin_pwd___, \ + builtin_unset_, builtin_debug_, NULL}; + t_builtin_func actual_func; + t_builtin_spawn_info binfo; + t_pipe pipe_fd; + bool do_fork; + t_i32 exit_code; + + i = 0; + if (argv0 == NULL) + return (ERROR); + actual_func = NULL; + while (value[i] != NULL) + { + if (str_compare(argv0, value[i])) + { + actual_func = funcs[i]; + break ; + } + i++; + } + if (actual_func == NULL) + return (me_abort("Builtin found but no function found..."), ERROR); + mem_set_zero(out, sizeof(*out)); + if (info.stdin.tag == R_FD) + binfo.stdin = info.stdin.fd.fd; + if (info.stdin.tag == R_INHERITED) + binfo.stdin = dup_fd(get_stdin()); + if (info.stderr.tag == R_FD) + binfo.stderr = info.stderr.fd.fd; + if (info.stderr.tag == R_INHERITED) + binfo.stderr = dup_fd(get_stderr()); + if (info.stdout.tag == R_FD) + binfo.stdout = info.stdout.fd.fd; + if (info.stdout.tag == R_INHERITED) + binfo.stdout = dup_fd(get_stdout()); + if (info.stdout.tag == R_PIPED) + { + if (create_pipe(&pipe_fd)) + return (ERROR); + out->process.stdout = pipe_fd.read; + binfo.stdout = pipe_fd.write; + } + binfo.args = info.arguments; + do_fork = cmd_pipe.input != NULL || cmd_pipe.create_output; + if (do_fork) + { + out->process.pid = fork(); + if (out->process.pid == 0) + { + if (actual_func(state, binfo, &exit_code)) + me_exit(127); + me_exit(exit_code); + } + if (out->process.pid == -1) + out->exit = 126; + else + out->exit = -1; + } + else + { + if (actual_func(state, binfo, &exit_code)) + out->exit = 126; + else + out->exit = exit_code; + } + if (binfo.stdin) + close_fd(binfo.stdin); + if (binfo.stdout) + close_fd(binfo.stdout); + if (binfo.stderr) + close_fd(binfo.stderr); + vec_str_free(info.arguments); + str_free(info.binary_path); + return (NO_ERROR); +} diff --git a/exec/src/run_ast/run_cmd_sub.c b/exec/src/run_ast/run_cmd_sub.c new file mode 100644 index 00000000..0f8527aa --- /dev/null +++ b/exec/src/run_ast/run_cmd_sub.c @@ -0,0 +1,22 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_cmd_sub.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:36:15 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:36:25 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" + +t_error run_command_substitution(t_ast_command_substitution *self, + t_state *state, void *out) +{ + (void)(self); + (void)(state); + (void)(out); + return (ERROR); +} diff --git a/exec/src/run_ast/run_command.c b/exec/src/run_ast/run_command.c new file mode 100644 index 00000000..659de47e --- /dev/null +++ b/exec/src/run_ast/run_command.c @@ -0,0 +1,63 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_command.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:23:53 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:24:24 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "me/str/str.h" + +// if +// (run_variable_assignment(&tmp->data.variable_assignment, +// state, true, NULL)) return (vec_str_free(args), +// vec_ast_free(redirection), ERROR); +t_error run_command(t_ast_command *command, t_state *state, t_cmd_pipe cmd_pipe, + t_command_result *out) +{ + t_vec_str args; + t_vec_ast redirection; + t_usize i; + t_ast_node tmp; + + if (command == NULL || state == NULL || out == NULL) + return (ERROR); + hmap_env_clear(state->tmp_var); + args = vec_str_new(command->cmd_word.len, str_free); + redirection = vec_ast_new(command->suffixes_redirections.len, ast_free); + i = 0; + while (i < command->prefixes.len) + { + tmp = command->prefixes.buffer[i]; + if (tmp->kind == AST_FILE_REDIRECTION + || tmp->kind == AST_HEREDOC_REDIRECTION) + vec_ast_push(&redirection, tmp); + if (tmp->kind == AST_VARIABLE_ASSIGNMENT) + return (printf("Variable assignment aren't supported !\n"), ERROR); + i++; + } + i = 0; + while (i < command->cmd_word.len) + { + if (_ast_into_str(command->cmd_word.buffer[i], state, &args)) + return (vec_str_free(args), vec_ast_free(redirection), ERROR); + i++; + } + i = 0; + while (i < command->suffixes_redirections.len) + { + tmp = command->suffixes_redirections.buffer[i]; + if (tmp->kind == AST_FILE_REDIRECTION + || tmp->kind == AST_HEREDOC_REDIRECTION) + vec_ast_push(&redirection, tmp); + i++; + } + if (_spawn_cmd_and_run(args, redirection, state, cmd_pipe, out)) + return (ERROR); + return (NO_ERROR); +} diff --git a/exec/src/run_ast/run_expansion.c b/exec/src/run_ast/run_expansion.c new file mode 100644 index 00000000..7b7067d7 --- /dev/null +++ b/exec/src/run_ast/run_expansion.c @@ -0,0 +1,51 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_expansion.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:41:23 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:41:28 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" + +t_error _get_expansion_value(t_ast_expansion *self, t_state *state, + t_expansion_result *out) +{ + t_str *hmap_ret; + t_expansion_result ret; + + if (self == NULL || state == NULL || out == NULL) + return (ERROR); + hmap_ret = hmap_env_get(state->tmp_var, &self->var_name); + if (hmap_ret == NULL) + hmap_ret = hmap_env_get(state->env, &self->var_name); + ret = (t_expansion_result){.exists = (hmap_ret != NULL), .value = NULL}; + if (ret.exists) + ret.value = *hmap_ret; + return (*out = ret, NO_ERROR); +} + +/// this functons returns different things depending on the +/// operator and/or the state of the shell NULL != empty +/// string for example +t_error run_expansion(t_ast_expansion *self, t_state *state, + t_expansion_result *out) +{ + t_expansion_result ret; + bool is_special_var; + + is_special_var = _is_special_var(self); + if (is_special_var && _run_expansion_special_var(self, state, &ret)) + return (ERROR); + if (!is_special_var && _get_expansion_value(self, state, &ret)) + return (ERROR); + if (_handle_expansion_operator(self, state, &ret)) + return (ERROR); + if (self->len_operator && _handle_len_operator(self, state, &ret)) + return (ERROR); + return (*out = ret, NO_ERROR); +} diff --git a/exec/src/run_ast/run_expansion_builtin.c b/exec/src/run_ast/run_expansion_builtin.c new file mode 100644 index 00000000..01f407c3 --- /dev/null +++ b/exec/src/run_ast/run_expansion_builtin.c @@ -0,0 +1,56 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_expansion_builtin.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:38:38 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:42:53 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "me/mem/mem.h" +#include "me/str/str.h" +#include "me/convert/numbers_to_str.h" + +bool _is_special_var(t_ast_expansion *self) +{ + char name; + + if (self == NULL) + return (true); + if (self->var_name == NULL) + return (true); + if (str_len(self->var_name) != 1) + return (false); + name = self->var_name[0]; + if (name == '*' || name == '@' || name == '?' || name == '!' || name == '#' + || name == '-' || name == '$' || name == '0') + return (true); + return (false); +} + +// return pid of last run program +// return `argc - 1` bc we don't care about argv[0] +// return pid of self (the shell) +// return the option string +// return all args without argv[0] +// return all args with argv[0] +// return exit code of last run program +t_error _run_expansion_special_var(t_ast_expansion *self, t_state *state, + t_expansion_result *out) +{ + char name; + + if (self == NULL || state == NULL || out == NULL) + return (ERROR); + name = self->var_name[0]; + *out = (t_expansion_result){.exists = false, .value = NULL}; + if (name == '?') + { + printf("PLEASE MAKE SURE TO FINISH THE SPECIAL VAR HANDLING !"); + } + return (NO_ERROR); +} diff --git a/exec/src/run_ast/run_list.c b/exec/src/run_ast/run_list.c new file mode 100644 index 00000000..25f32fcb --- /dev/null +++ b/exec/src/run_ast/run_list.c @@ -0,0 +1,52 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_list.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:34:33 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:34:39 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" + +t_error run_list(t_ast_list *list, t_state *state, t_list_result *out) +{ + int left; + int right; + t_ast_node tmp; + t_vec_ast *append; + + if (list == NULL || state == NULL || out == NULL) + return (ERROR); + append = NULL; + if (list->right->kind == AST_COMMAND) + append = &list->right->data.command.suffixes_redirections; + if (list->right->kind == AST_PIPELINE) + append = &list->right->data.pipeline.suffixes_redirections; + if (list->right->kind == AST_LIST) + append = &list->right->data.list.suffixes_redirections; + if (list->right->kind == AST_SUBSHELL) + append = &list->right->data.subshell.suffixes_redirections; + if (append != NULL) + { + while (!vec_ast_pop_front(&list->suffixes_redirections, &tmp)) + vec_ast_push(append, tmp); + } + left = -1; + right = -1; + if (_run_get_exit_code(list->left, state, &left)) + return (ERROR); + if ((list->op == AST_LIST_OR && left != 0) || (list->op == AST_LIST_AND + && left == 0)) + { + if (_run_get_exit_code(list->right, state, &right)) + return (ERROR); + out->exit = right; + } + else + out->exit = left; + return (NO_ERROR); +} diff --git a/exec/src/run_ast/run_pipeline.c b/exec/src/run_ast/run_pipeline.c new file mode 100644 index 00000000..6364e96d --- /dev/null +++ b/exec/src/run_ast/run_pipeline.c @@ -0,0 +1,104 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_pipeline.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:32:37 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:33:09 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "me/vec/vec_pid.h" +#include +#include + +t_error run_pipeline(t_ast_pipeline *pipeline, t_state *state, + t_pipeline_result *out) +{ + int waitpid_status; + t_ast_node child; + t_ast_node tmp_ast; + t_cmd_pipe cmd_pipe; + t_command_result cmd_result; + t_error ret; + t_usize i; + t_vec_pid pids; + + if (pipeline == NULL || state == NULL || out == NULL) + return (ERROR); + i = 0; + ret = NO_ERROR; + cmd_pipe.input = NULL; + cmd_pipe.create_output = true; + out->exit = 127; + pids = vec_pid_new(32, NULL); + while (i < pipeline->statements.len - 1) + { + child = pipeline->statements.buffer[i]; + if (child->kind == AST_COMMAND) + { + if (run_command(&child->data.command, state, cmd_pipe, &cmd_result)) + { + cmd_pipe.input = NULL; + ret = ERROR; + } + else + { + vec_pid_push(&pids, cmd_result.process.pid); + close_fd(cmd_pipe.input); + if (cmd_result.process.stdout != NULL) + cmd_pipe.input = cmd_result.process.stdout; + if (cmd_result.process.stdin != NULL) + close_fd(cmd_result.process.stdin); + if (cmd_result.process.stderr != NULL) + close_fd(cmd_result.process.stderr); + } + } + i++; + } + { + cmd_pipe.create_output = false; + child = pipeline->statements.buffer[i]; + if (child->kind == AST_COMMAND) + { + while (!vec_ast_pop_front(&pipeline->suffixes_redirections, + &tmp_ast)) + vec_ast_push(&child->data.command.suffixes_redirections, + tmp_ast); + if (run_command(&child->data.command, state, cmd_pipe, &cmd_result)) + { + ret = ERROR; + } + else + { + vec_pid_push(&pids, cmd_result.process.pid); + close_fd(cmd_pipe.input); + if (cmd_result.process.stdout != NULL) + close_fd(cmd_result.process.stdout); + if (cmd_result.process.stdin != NULL) + close_fd(cmd_result.process.stdin); + if (cmd_result.process.stderr != NULL) + close_fd(cmd_result.process.stderr); + } + } + } + if (pids.len != 0) + { + if (!(kill(pids.buffer[pids.len - 1], 0) == -1 && errno == ESRCH)) + while (waitpid(pids.buffer[pids.len - 1], &waitpid_status, 0) < 0) + ; + while (waitpid(-1, NULL, 0) != -1) + ; + if (WIFEXITED(waitpid_status)) + out->exit = WEXITSTATUS(waitpid_status); + if (WIFSIGNALED(waitpid_status)) + out->exit = WTERMSIG(waitpid_status); + } + else + out->exit = 127; + vec_pid_free(pids); + return (ret); +} diff --git a/exec/src/run_ast/run_program.c b/exec/src/run_ast/run_program.c new file mode 100644 index 00000000..2298ec69 --- /dev/null +++ b/exec/src/run_ast/run_program.c @@ -0,0 +1,29 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_program.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:32:04 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:32:20 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" + +t_error run_program(t_ast_program *self, t_state *state, t_program_result *out) +{ + t_usize i; + + if (self == NULL || state == NULL || out == NULL) + return (ERROR); + i = 0; + while (i < self->body.len) + { + if (_run_get_exit_code(self->body.buffer[i], state, &out->exit)) + return (ERROR); + i++; + } + return (NO_ERROR); +} diff --git a/exec/src/run_ast/run_subshell.c b/exec/src/run_ast/run_subshell.c new file mode 100644 index 00000000..bf9f78e0 --- /dev/null +++ b/exec/src/run_ast/run_subshell.c @@ -0,0 +1,175 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_subshell.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:35:02 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:35:58 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" +#include "me/mem/mem.h" +#include "me/str/str.h" +#include +#include + +t_error run_subshell(t_ast_subshell *subshell, t_state *state, + t_cmd_pipe cmd_pipe, t_subshell_result *out) +{ + struct s_subshell_info info; + t_pipe spipe; + t_usize i; + t_vec_str filename_args; + t_ast_node red; + t_vec_ast redirection; + t_fd *red_fd; + t_pipe heredoc_pipe; + t_pid forked; + int code; + int status; + + if (subshell == NULL || state == NULL || out == NULL) + return (ERROR); + mem_set_zero(&info, sizeof(info)); + info.stdin = cmd_pipe.input; + if (cmd_pipe.create_output) + { + if (create_pipe(&spipe)) + return (ERROR); + info.stdout = spipe.write; + info.ret_stdout = spipe.read; + } + i = 0; + filename_args = vec_str_new(16, str_free); + redirection = subshell->suffixes_redirections; + while (i < redirection.len) + { + red = redirection.buffer[i]; + if (red == NULL) + continue ; + vec_str_free(filename_args); + filename_args = vec_str_new(16, str_free); + if (red->kind == AST_FILE_REDIRECTION) + { + if (red->data.file_redirection.op == AST_REDIR_INPUT) + { + if (info.stdin != NULL) + close_fd(info.stdin); + info.stdin = NULL; + if (_ast_into_str(red->data.file_redirection.output, state, + &filename_args)) + return (ERROR); + if (filename_args.len != 1) + return (vec_str_free(filename_args), ERROR); + red_fd = open_fd(filename_args.buffer[i], FD_READ, O_CLOEXEC, + 0); + if (red_fd == NULL) + return (vec_str_free(filename_args), ERROR); + info.stdin = red_fd; + } + if (red->data.file_redirection.op == AST_REDIR_OUTPUT) + { + if (info.stdout != NULL) + close_fd(info.stdout); + info.stdout = NULL; + if (_ast_into_str(red->data.file_redirection.output, state, + &filename_args)) + return (ERROR); + if (filename_args.len != 1) + return (vec_str_free(filename_args), ERROR); + red_fd = open_fd(filename_args.buffer[i], FD_WRITE, + O_TRUNC | O_CREAT | O_CLOEXEC, + FP_ALL_READ | FP_ALL_WRITE); + if (red_fd == NULL) + return (vec_str_free(filename_args), ERROR); + info.stdout = red_fd; + } + if (red->data.file_redirection.op == AST_REDIR_APPEND) + { + if (info.stdout != NULL) + close_fd(info.stdout); + info.stdout = NULL; + if (_ast_into_str(red->data.file_redirection.output, state, + &filename_args)) + return (ERROR); + if (filename_args.len != 1) + return (vec_str_free(filename_args), ERROR); + red_fd = open_fd(filename_args.buffer[i], FD_WRITE, + O_TRUNC | O_CREAT | O_CLOEXEC, + FP_ALL_READ | FP_ALL_WRITE); + if (red_fd == NULL) + return (vec_str_free(filename_args), ERROR); + info.stdout = red_fd; + } + if (red->data.file_redirection.op == AST_REDIR_DUP_INPUT + || red->data.file_redirection.op == AST_REDIR_DUP_OUTPUT + || red->data.file_redirection.op == AST_REDIR_CLOSE_INPUT + || red->data.file_redirection.op == AST_REDIR_CLOSE_OUTPUT + || red->data.file_redirection.op == AST_REDIR_INPUT_OUTPUT + || red->data.file_redirection.op == AST_REDIR_OUTPUT_CLOBBER) + return (ERROR); + } + if (red->kind == AST_HEREDOC_REDIRECTION) + { + if (red->data.heredoc_redirection.op == AST_REDIR_HEREDOC) + { + if (info.stdout != NULL) + close_fd(info.stdout); + info.stdout = NULL; + if (create_pipe(&heredoc_pipe)) + return (ERROR); + put_string_fd(heredoc_pipe.write, + red->data.heredoc_redirection.content); + close_fd(heredoc_pipe.write); + info.stdin = heredoc_pipe.read; + } + if (red->data.heredoc_redirection.op == AST_REDIR_HEREDOC_INDENT) + return (ERROR); + } + i++; + } + vec_str_free(filename_args); + forked = fork(); + if (forked == 0) + { + if (info.ret_stdout != NULL) + close_fd(info.ret_stdout); + if (info.stdin != NULL) + (dup2(info.stdin->fd, 0), close_fd(info.stdin)); + if (info.stdout != NULL) + (dup2(info.stdout->fd, 1), close_fd(info.stdout)); + if (info.stderr != NULL) + (dup2(info.stderr->fd, 2), close_fd(info.stderr)); + i = 0; + code = 0; + while (i < subshell->body.len) + { + if (_run_get_exit_code(subshell->body.buffer[i], state, &code)) + me_exit(127); + i++; + } + me_exit(code); + } + if (forked == -1) + return (ERROR); + out->exit = -1; + out->pid = forked; + if (info.stdin != NULL) + (dup2(info.stdin->fd, 0), close_fd(info.stdin)); + if (info.stdout != NULL) + (dup2(info.stdout->fd, 1), close_fd(info.stdout)); + if (info.stderr != NULL) + (dup2(info.stderr->fd, 2), close_fd(info.stderr)); + if (cmd_pipe.create_output || cmd_pipe.input != NULL) + return (out->stdout = info.ret_stdout, NO_ERROR); + if (waitpid(forked, &status, 0) == -1) + return (ERROR); + if (WIFEXITED(status)) + out->exit = WEXITSTATUS(status); + if (WIFSIGNALED(status)) + out->exit = WTERMSIG(status); + return (NO_ERROR); +} diff --git a/exec/src/run_ast/run_words.c b/exec/src/run_ast/run_words.c new file mode 100644 index 00000000..0819cdc1 --- /dev/null +++ b/exec/src/run_ast/run_words.c @@ -0,0 +1,29 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* run_words.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/09/14 12:11:48 by maiboyer #+# #+# */ +/* Updated: 2024/09/14 12:23:38 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/_run_ast.h" + +t_error run_word(t_ast_word *word, t_state *state, t_word_result *out) +{ + t_word_iterator iter_state; + + if (word == NULL || state == NULL || out == NULL) + return (ERROR); + iter_state.res.value = vec_estr_new(64, free_expandable_str); + iter_state.res.has_error = false; + iter_state.res.kind = word->kind; + iter_state.state = state; + vec_ast_iter(&word->inner, (void (*)())_run_word_into_str, &iter_state); + if (iter_state.res.has_error) + return (vec_estr_free(iter_state.res.value), ERROR); + return (*out = iter_state.res, NO_ERROR); +} diff --git a/flake.nix b/flake.nix index c2afc839..b9fc8105 100644 --- a/flake.nix +++ b/flake.nix @@ -30,6 +30,7 @@ coreutils generic_c.packages.${system}.default python312 + tree ] ++ ( if system == "x86_64-linux"