diff options
| author | Charles <sircharlesaze@gmail.com> | 2020-04-01 15:55:57 +0200 |
|---|---|---|
| committer | Charles <sircharlesaze@gmail.com> | 2020-04-01 15:55:57 +0200 |
| commit | 2eb59ee61e49b60472f82c000dd4f3536bd1987c (patch) | |
| tree | 190ac7bc42051ee9fcc7c1d781be16afa4d43075 /src/eval | |
| parent | 551e668e1b7a030fdff236067963100c7d8747a5 (diff) | |
| download | minishell-2eb59ee61e49b60472f82c000dd4f3536bd1987c.tar.gz minishell-2eb59ee61e49b60472f82c000dd4f3536bd1987c.tar.bz2 minishell-2eb59ee61e49b60472f82c000dd4f3536bd1987c.zip | |
Added builtin support in command eval, Refactoring eval/builtin function, Added doc
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/eval.c | 85 | ||||
| -rw-r--r-- | src/eval/exec.c | 62 | ||||
| -rw-r--r-- | src/eval/pipe.c | 48 |
3 files changed, 143 insertions, 52 deletions
diff --git a/src/eval/eval.c b/src/eval/eval.c index 28cb386..d2fab39 100644 --- a/src/eval/eval.c +++ b/src/eval/eval.c @@ -5,89 +5,70 @@ #include "eval.h" +/** +** \brief Evaluate a line +** \param state State of the evaluation +** \param line Line to evaluate +** \return Last Executed command status or -1 on error +*/ + static int eval_line(t_eval_state *state, t_line *line) { int status; if (line->right == NULL) return (eval(state, line->left)); - status = eval(state, line->left); + if ((status = eval(state, line->left)) == -1) + return (-1); if ((line->sep == SEP_AND && status != 0) || (line->sep == SEP_OR && status == 0)) return (status); return (eval(state, line->right)); } -static bool is_exec_path(char *path_str) -{ - return (ft_strncmp(path_str, "../", 3) == 0 - || ft_strncmp(path_str, "./", 2) == 0 - || ft_strncmp(path_str, "/", 1) == 0); -} - -static bool is_valid_exec(char *exec_path) -{ - struct stat statbuf; - - if (stat(exec_path, &statbuf) != 0) - return (false); - if (!S_ISREG(statbuf.st_mode)) // also need to manage link - return (false); - // could test permission but probably handled by execve - return (true); -} - -static char *search_exec_path(t_path path, char *path_var, char *exec_name) -{ - char *exec_path; - - if (is_exec_path(exec_name)) - return (exec_name); - // try current first - if ((exec_path = ft_htget(path, exec_name)) == NULL) - { - if (path_update(path, path_var) == NULL) // optimise by not updating not changed path in ht - return (NULL); - if ((exec_path = ft_htget(path, exec_name)) == NULL) - return (NULL); - } - return (exec_path); -} +/** +** \brief Evaluate a command +** \param state Evaluation state +** \param cmd Command to evaluate +** \return Executable status or -1 on error +*/ static int eval_cmd(t_eval_state *state, t_cmd *cmd) { int child_pid; char *exec_path; + bool is_builtin; - if ((exec_path = search_exec_path(state->path, - ft_htget(state->env, "PATH"), cmd->argv[0])) == NULL) - return (-1); - if (cmd->in != NULL) + is_builtin = builtin_check_exec_name(cmd->argv[0]); + if (!is_builtin) { - if ((state->in_pipe[PIPE_WRITE] = open(cmd->in, O_RDONLY)) < 0) - return (-1); - } - if (cmd->out != NULL) - { - if ((state->out_pipe[PIPE_READ] = open(cmd->out, - (cmd->is_append ? O_WRONLY : O_APPEND) | O_CREAT)) < 0) + if ((exec_path = exec_search_path(state->path, + ft_htget(state->env, "PATH"), cmd->argv[0])) == NULL) return (-1); } + pipe_setup_parent(cmd, state->pipe_in, state->pipe_out); if ((child_pid = fork()) == -1) return (-1); if (child_pid == 0) { - if (state->in_pipe[PIPE_READ] != PIPE_CLOSED) - dup2(STDIN_FILENO, state->in_pipe[PIPE_READ]); - if (state->out_pipe[PIPE_WRITE] != PIPE_CLOSED) - dup2(STDOUT_FILENO, state->out_pipe[PIPE_WRITE]); - if (execve(exec_path, cmd->argv, NULL /*env_array*/) == -1) + pipe_setup_child(state->pipe_in, state->pipe_out); + if (is_builtin) + exit(builtin_dispatch_run(cmd->argv, state->env)); + else if (execve(exec_path, cmd->argv, NULL /*env_array*/) == -1) exit(EXIT_FAILURE); + exit(EXIT_SUCCESS); } wait(&child_pid); return (WEXITSTATUS(child_pid)); } +/** +** \brief Evaluate an AST +** \param state State of the evaluation +** \param ast Abstract syntax tree to evaluate +** \return Executable status or -1 on error +*/ + int eval(t_eval_state *state, t_ast *ast) { errno = 0; diff --git a/src/eval/exec.c b/src/eval/exec.c new file mode 100644 index 0000000..1ac9754 --- /dev/null +++ b/src/eval/exec.c @@ -0,0 +1,62 @@ +/** +** \file exec.c +** \brief Executable name and path +*/ + +#include "eval.h" + +/** +** \brief Check if executable name is already a path +** \param exec_name Executable name +** \return True if valid +*/ + +bool exec_is_path(char *exec_name) +{ + return (ft_strncmp(exec_name, "../", 3) == 0 + || ft_strncmp(exec_name, "./", 2) == 0 + || ft_strncmp(exec_name, "/", 1) == 0); +} + +/** +** \brief Check if executable path is valid +** \param exec_path Executable path +** \return True if valid +*/ + +bool exec_is_valid(char *exec_path) +{ + struct stat statbuf; + + if (stat(exec_path, &statbuf) != 0) + return (false); + if (!S_ISREG(statbuf.st_mode)) // also need to manage link + return (false); + // could test permission but probably handled by execve + return (true); +} + +/** +** \brief Search executable name in path +** \param path Path hash table +** \param path_var Path environment string in case we need to update path +** \param exec_name Executable name to search +** \return Executable path or NULL if not found or path update error +*/ + +char *exec_search_path(t_path path, char *path_var, char *exec_name) +{ + char *exec_path; + + if (exec_is_path(exec_name)) + return (exec_name); + // try current first + if ((exec_path = ft_htget(path, exec_name)) == NULL) + { + if (path_update(path, path_var) == NULL) // optimise by not updating not changed path in ht + return (NULL); + if ((exec_path = ft_htget(path, exec_name)) == NULL) + return (NULL); + } + return (exec_path); +} diff --git a/src/eval/pipe.c b/src/eval/pipe.c new file mode 100644 index 0000000..897a5f2 --- /dev/null +++ b/src/eval/pipe.c @@ -0,0 +1,48 @@ +/** +** \file pipe.c +** \brief Pipes setup +*/ + +#include "eval.h" + +/** +** \brief Setup STDIN and STDOUT pipe in the parent process +** \param cmd Command to setup +** \param pipe_in STDIN pipe +** \param pipe_out STDOUT pipe +** \return -1 on error, 0 otherwise +*/ + +int pipe_setup_parent(t_cmd *cmd, int pipe_in[2], int pipe_out[2]) +{ + if (cmd->in != NULL) + { + if ((pipe_in[PIPE_WRITE] = open(cmd->in, O_RDONLY)) < 0) + return (-1); + } + if (cmd->out != NULL) + { + if ((pipe_out[PIPE_READ] = open(cmd->out, + (cmd->is_append ? O_WRONLY : O_APPEND) | O_CREAT)) < 0) + return (-1); + } + return (0); +} + +/** +** \brief Setup STDIN and STDOUT pipe in the child process +** \param pipe_in STDIN pipe +** \param pipe_out STDOUT pipe +** \return -1 on error, 0 otherwise +*/ + +int pipe_setup_child(int pipe_in[2], int pipe_out[2]) +{ + if (pipe_in[PIPE_READ] != PIPE_CLOSED) + if (dup2(STDIN_FILENO, pipe_in[PIPE_READ]) == -1) + return (-1); + if (pipe_out[PIPE_WRITE] != PIPE_CLOSED) + if (dup2(STDOUT_FILENO, pipe_out[PIPE_WRITE]) == -1) + return (-1); + return (0); +} |
