diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ast.c | 40 | ||||
| -rw-r--r-- | src/builtin/builtin.c | 61 | ||||
| -rw-r--r-- | src/builtin/cd.c | 2 | ||||
| -rw-r--r-- | src/builtin/echo.c | 3 | ||||
| -rw-r--r-- | src/builtin/env.c | 3 | ||||
| -rw-r--r-- | src/builtin/exit.c | 9 | ||||
| -rw-r--r-- | src/builtin/export.c | 12 | ||||
| -rw-r--r-- | src/builtin/pwd.c | 4 | ||||
| -rw-r--r-- | src/builtin/unset.c | 2 | ||||
| -rw-r--r-- | src/eval/eval.c | 85 | ||||
| -rw-r--r-- | src/eval/exec.c | 62 | ||||
| -rw-r--r-- | src/eval/pipe.c | 48 | ||||
| -rw-r--r-- | src/main.c | 8 |
13 files changed, 260 insertions, 79 deletions
@@ -1,5 +1,18 @@ +/** +** \file ast.c +** \brief AST functions +*/ + #include "ast.h" +/** +** \brief Create a new AST node according to `tag` +** \param tag Tag of node +** \param data Pointer to node data (t_cmd or t_line) +** which will be copied in ast::data union +** \return Created node or NULL on error +*/ + t_ast *ast_new(t_ast_tag tag, void *data) { t_ast *ast; @@ -17,26 +30,25 @@ t_ast *ast_new(t_ast_tag tag, void *data) return (ast); } -static void cmd_destroy(t_cmd *cmd) -{ - ft_split_destroy(cmd->argv); - free(cmd->in); - free(cmd->out); -} - -static void line_destroy(t_line *line) -{ - ast_destroy(line->left); - ast_destroy(line->right); -} +/** +** \brief Destroy an AST node and all his child nodes +** \param ast AST to destroy +*/ void ast_destroy(t_ast *ast) { if (ast == NULL) return ; if (ast->tag == TAG_CMD) - cmd_destroy(&ast->data.cmd); + { + ft_split_destroy(ast->data.cmd.argv); + free(ast->data.cmd.in); + free(ast->data.cmd.out); + } else if (ast->tag == TAG_LINE) - line_destroy(&ast->data.line); + { + ast_destroy(ast->data.line.left); + ast_destroy(ast->data.line.right); + } free(ast); } diff --git a/src/builtin/builtin.c b/src/builtin/builtin.c new file mode 100644 index 0000000..4889f9c --- /dev/null +++ b/src/builtin/builtin.c @@ -0,0 +1,61 @@ +/** +** \file builtin.c +** \brief Builtin functions +*/ + +#include "minishell.h" + +/** +** \brief Array storing builtin executable name and associated functions +*/ + +static struct s_builtin_entry g_builtin_lookup[] = { + {"echo", builtin_echo}, + {"cd", builtin_cd}, + {"pwd", builtin_pwd}, + {"export", builtin_export}, + {"unset", builtin_unset}, + {"env", builtin_env}, + {"exit", builtin_exit}, +}; + +/** +** \brief Call builtin function associated with command name +** \param argv Arguments to the builtin 'main', with argv[0] being the executable name +** \param env Environment Vector +** \return Builtin main return status +*/ + +int builtin_dispatch_run(char **argv, t_env env) +{ + size_t i; + + i = 0; + while (i < sizeof(g_builtin_lookup) / sizeof(struct s_builtin_entry)) + { + if (ft_strcmp(g_builtin_lookup[i].name, argv[0]) == 0) + return (g_builtin_lookup[i].func(argv, env)); + i++; + } + return (BUILTIN_NOT_FOUND); +} + +/** +** \brief Check if executable name is a builtin +** \param exec_name Executable name +** \return True if executable name is a builtin +*/ + +bool builtin_check_exec_name(char *exec_name) +{ + size_t i; + + i = 0; + while (i < sizeof(g_builtin_lookup) / sizeof(struct s_builtin_entry)) + { + if (ft_strcmp(g_builtin_lookup[i].name, exec_name) == 0) + return (true); + i++; + } + return (false); +} diff --git a/src/builtin/cd.c b/src/builtin/cd.c index 14c38d2..db629b0 100644 --- a/src/builtin/cd.c +++ b/src/builtin/cd.c @@ -5,7 +5,7 @@ #include "minishell.h" -int builtin_cd(t_env env, char **argv) +int builtin_cd(char **argv, t_env env) { char *path; diff --git a/src/builtin/echo.c b/src/builtin/echo.c index b9f2e28..c9e8cc7 100644 --- a/src/builtin/echo.c +++ b/src/builtin/echo.c @@ -5,10 +5,11 @@ #include "minishell.h" -int builtin_echo(char **argv) +int builtin_echo(char **argv, t_env env) { bool newline; + (void)env; newline = ft_strcmp(argv[1], "-n") == 0; if (newline) argv++; diff --git a/src/builtin/env.c b/src/builtin/env.c index 3869ead..352e2c3 100644 --- a/src/builtin/env.c +++ b/src/builtin/env.c @@ -13,8 +13,9 @@ void st_print_env_variable(t_ftht_entry *entry) ft_putchar('\n'); } -int builtin_env(t_env env) +int builtin_env(char **argv, t_env env) { + (void)argv; ft_htiter(env, st_print_env_variable); return (0); } diff --git a/src/builtin/exit.c b/src/builtin/exit.c index f4cc4fd..bd41f0f 100644 --- a/src/builtin/exit.c +++ b/src/builtin/exit.c @@ -1,4 +1,13 @@ +#include "minishell.h" + /** ** \file exit.c ** \brief `exit` builtin */ + +int builtin_exit(char **argv, t_env env) +{ + (void)argv; + (void)env; + return (0); +} diff --git a/src/builtin/export.c b/src/builtin/export.c index c0839b9..1b148a9 100644 --- a/src/builtin/export.c +++ b/src/builtin/export.c @@ -5,7 +5,11 @@ #include "minishell.h" -/* int export(t_env env, char **argv) */ -/* { */ -/* return (0); */ -/* } */ +int builtin_export(char **argv, t_env env) +{ + (void)argv; + (void)env; + /* if (ft_htset(env, ) == NULL) */ + /* return (-1); */ + return (0); +} diff --git a/src/builtin/pwd.c b/src/builtin/pwd.c index 813c4c6..6e0971f 100644 --- a/src/builtin/pwd.c +++ b/src/builtin/pwd.c @@ -5,10 +5,12 @@ #include "minishell.h" -int builtin_pwd(void) +int builtin_pwd(char **argv, t_env env) { char buf[PATH_MAX]; + (void)argv; + (void)env; ft_bzero(buf, PATH_MAX); if (getcwd(buf, PATH_MAX) == NULL) return (1); diff --git a/src/builtin/unset.c b/src/builtin/unset.c index 64f25f4..1fc5ce1 100644 --- a/src/builtin/unset.c +++ b/src/builtin/unset.c @@ -5,7 +5,7 @@ #include "minishell.h" -int builtin_unset(t_env env, char **argv) +int builtin_unset(char **argv, t_env env) { if (argv[1] == NULL) return (1); 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); +} @@ -64,10 +64,10 @@ int main(int argc, char **argv, char **envp) /* printf("%s\n", ast->data.line.left->data.cmd.argv[0]); */ /* printf("%s\n", ast->data.line.left->data.cmd.argv[1]); */ - state.in_pipe[0] = -1; - state.in_pipe[1] = -1; - state.out_pipe[0] = -1; - state.out_pipe[1] = -1; + state.pipe_in[0] = -1; + state.pipe_in[1] = -1; + state.pipe_out[0] = -1; + state.pipe_out[1] = -1; state.path = path; state.env = env; eval(&state, ast); |
