aboutsummaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/cmd.c98
-rw-r--r--src/eval/error.c56
-rw-r--r--src/eval/eval.c93
-rw-r--r--src/eval/redir.c80
4 files changed, 241 insertions, 86 deletions
diff --git a/src/eval/cmd.c b/src/eval/cmd.c
new file mode 100644
index 0000000..9468cb2
--- /dev/null
+++ b/src/eval/cmd.c
@@ -0,0 +1,98 @@
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* cmd.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2020/06/14 10:41:31 by charles #+# #+# */
+/* Updated: 2020/06/15 11:09:38 by charles ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "eval.h"
+
+/*
+** \brief Wrap a function in a fork
+** \param fd_in fork input file descriptor
+** \param fd_out fork output file descriptor
+** \param passed param of the wrapped function
+** \param wrapped function to wrap
+*/
+
+int fork_wrap(
+ int fd_in,
+ int fd_out,
+ void *passed,
+ int (*wrapped)(void *param))
+{
+ int status;
+ pid_t child_pid;
+
+ if ((child_pid = fork()) == -1)
+ return (-1);
+ if (child_pid == 0)
+ {
+ if ((fd_in != MS_NO_FD && dup2(fd_in, STDIN_FILENO) == -1) ||
+ (fd_out != MS_NO_FD && dup2(fd_out, STDOUT_FILENO) == -1))
+ exit(EXIT_FAILURE);
+ if ((status = wrapped(passed)) == -1)
+ exit(EXIT_FAILURE);
+ exit(status);
+ }
+ wait(&child_pid);
+ return (WEXITSTATUS(child_pid));
+}
+
+int forked_cmd(void *void_param)
+{
+ t_fork_param_cmd *param;
+
+ param = void_param;
+
+ if (param->builtin != NULL)
+ return (param->builtin(param->argv, param->env));
+ else
+ return (execve(param->exec_path, param->argv, (char**)param->env->data));
+}
+
+int eval_cmd(t_env env, t_path path, t_ast *ast)
+{
+ t_fork_param_cmd param;
+ int fd_in;
+ int fd_out;
+ char **argv;
+
+ fd_in = MS_NO_FD;
+ fd_out = MS_NO_FD;
+ if (!redir_extract(ast->redirs, env, &fd_in, &fd_out))
+ {
+ ast->redirs = NULL;
+ return (-1);
+ }
+ ast->redirs = NULL;
+
+ if ((argv = preprocess(&ast->cmd_argv, env)) == NULL)
+ {
+ ast->cmd_argv = NULL;
+ return (-1);
+ }
+
+ param.builtin = builtin_search_func(argv[0]);
+ if (param.builtin == NULL)
+ {
+ param.exec_path = exec_search_path(path, env_search(env, "PATH"), argv[0]);
+ if (param.exec_path == NULL)
+ {
+ error_eval_put(ERROR_CMD_NOT_FOUND, argv[0]);
+ ft_split_destroy(argv);
+ return (-1); // return error status
+ }
+ }
+
+ param.argv = argv;
+ param.env = env;
+ int ret = fork_wrap(fd_in, fd_out, &param, &forked_cmd);
+ ft_split_destroy(argv);
+ return (ret);
+}
diff --git a/src/eval/error.c b/src/eval/error.c
new file mode 100644
index 0000000..016a751
--- /dev/null
+++ b/src/eval/error.c
@@ -0,0 +1,56 @@
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* error.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2020/06/14 11:02:52 by charles #+# #+# */
+/* Updated: 2020/06/14 12:19:14 by charles ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "eval.h"
+
+static t_error g_errors[] =
+{
+ {ERROR_AMBIGUOUS_REDIR, 1, "ambiguous redirect"},
+ {ERROR_OPEN, 1, NULL},
+ {ERROR_CMD_NOT_FOUND, 127, "command not found"},
+ {ERROR_SYNTAX, 2, "syntax error near unexpected token "},
+};
+
+t_error *st_error_get(enum e_error id)
+{
+ size_t i;
+ t_error *match;
+
+ match = NULL;
+ i = 0;
+ while (i < sizeof(g_errors) / sizeof(t_error))
+ {
+ if (g_errors[i].id == id)
+ match = &g_errors[i];
+ i++;
+ }
+ return (match);
+}
+
+void error_eval_put(enum e_error id, char *unexpected)
+{
+ t_error *err;
+
+ err = st_error_get(id);
+ ft_putstr_fd("minishell: ", STDERR_FILENO);
+ ft_putstr_fd(unexpected, STDERR_FILENO);
+ ft_putstr_fd(": ", STDERR_FILENO);
+ if (err->msg == NULL)
+ ft_putendl_fd(strerror(errno), STDERR_FILENO);
+ else
+ ft_putendl_fd(err->msg, STDERR_FILENO);
+}
+
+int error_status(enum e_error id)
+{
+ return (st_error_get(id)->status);
+}
diff --git a/src/eval/eval.c b/src/eval/eval.c
index 1e0a8d7..c1b580f 100644
--- a/src/eval/eval.c
+++ b/src/eval/eval.c
@@ -6,96 +6,17 @@
/* By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2020/04/01 17:05:21 by charles #+# #+# */
-/* Updated: 2020/06/14 10:34:11 by charles ### ########.fr */
+/* Updated: 2020/06/14 10:42:37 by charles ### ########.fr */
/* */
/* ************************************************************************** */
-/* #<{(| */
-/* ** \file eval.c */
-/* ** \brief Evaluation of an AST */
-/* |)}># */
-/* */
+/*
+** \file eval.c
+** \brief Evaluation of an AST
+*/
+
/* #include "eval.h" */
-/* */
-/* #<{(| */
-/* ** \brief Wrap a function in a fork */
-/* ** \param fd_in fork input file descriptor */
-/* ** \param fd_out fork output file descriptor */
-/* ** \param passed param of the wrapped function */
-/* ** \param wrapped function to wrap */
-/* |)}># */
-/* */
-/* int fork_wrap( */
-/* int fd_in, */
-/* int fd_out, */
-/* void *passed, */
-/* int (*wrapped)(void *param)) */
-/* { */
-/* int status; */
-/* pid_t child_pid; */
-/* */
-/* if ((child_pid = fork()) == -1) */
-/* return (-1); */
-/* if (child_pid == 0) */
-/* { */
-/* if (dup2(STDIN_FILENO, fd_in) == -1 || */
-/* dup2(STDOUT_FILENO, fd_out) == -1) */
-/* exit(EXIT_FAILURE); */
-/* if ((status = wrapped(passed)) == -1) */
-/* exit(EXIT_FAILURE); */
-/* exit(status); */
-/* } */
-/* wait(&child_pid); */
-/* return (WEXITSTATUS(child_pid)); */
-/* } */
-/* */
-/* int run_builtin(t_eval_state *state, char **argv) */
-/* { */
-/* return (builtin_dispatch_run(argv, state->env)); */
-/* } */
-/* */
-/* #<{(| */
-/* ** \brief execve syscall wrapper passed it to fork_wrap */
-/* ** \param param function params */
-/* ** \return execve return value */
-/* |)}># */
-/* */
-/* int execve_wrapper(void *param) */
-/* { */
-/* return (execve( */
-/* ((t_fork_param_execve*)param)->exec_path, */
-/* ((t_fork_param_execve*)param)->argv, */
-/* ((t_fork_param_execve*)param)->envp */
-/* )); */
-/* } */
-/* */
-/* #<{(| */
-/* ** \brief Evaluate a command */
-/* ** \param state Evaluation state */
-/* ** \param cmd Command to evaluate */
-/* ** \return Executable status or -1 on error */
-/* |)}># */
-/* */
-/* static int eval_cmd(int fd_in, int fd_out, t_eval_state *state, t_cmd *cmd) */
-/* { */
-/* t_fork_param_execve param; */
-/* */
-/* if (builtin_check_exec_name(cmd->argv[0])) */
-/* return (run_builtin(state, cmd->argv)); */
-/* param.exec_path = exec_search_path( */
-/* state->path, env_search(state->env, "PATH"), cmd->argv[0]); */
-/* if (param.exec_path == NULL) */
-/* return (-1); */
-/* if (cmd->in != NULL && (fd_in = open(cmd->in, O_RDONLY)) == -1) */
-/* return (-1); */
-/* if (cmd->out != NULL && (fd_out = open(cmd->out, */
-/* (cmd->is_append ? O_APPEND : O_WRONLY) | O_CREAT)) == -1) */
-/* return (-1); */
-/* param.argv = cmd->argv; */
-/* param.envp = (char**)state->env->data; */
-/* return (fork_wrap(fd_in, fd_out, &param, &execve_wrapper)); */
-/* } */
-/* */
+
/* #<{(| */
/* ** \brief Evaluate a line */
/* ** \param state State of the evaluation */
diff --git a/src/eval/redir.c b/src/eval/redir.c
new file mode 100644
index 0000000..c6f98d4
--- /dev/null
+++ b/src/eval/redir.c
@@ -0,0 +1,80 @@
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* redir.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2020/06/15 11:05:34 by charles #+# #+# */
+/* Updated: 2020/06/15 11:44:38 by charles ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "eval.h"
+
+static enum e_token_tag st_lst_tag(t_ftlst *lst)
+{
+ return (((t_token*)lst->data)->tag);
+}
+
+static bool st_open_replace(int *fd, char *filename, int oflag)
+{
+ if (*fd != MS_NO_FD)
+ close(*fd);
+ if (oflag & O_CREAT)
+ *fd = open(filename, oflag, 0644);
+ else
+ *fd = open(filename, oflag);
+ if (*fd == -1)
+ {
+ error_eval_put(ERROR_OPEN, filename);
+ free(filename);
+ return (false);
+ }
+ return (true);
+}
+
+bool redir_extract(
+ t_ftlst *redirs,
+ t_env env,
+ int *fd_in,
+ int *fd_out)
+{
+ t_ftlst *after;
+ t_ftlst *curr;
+ char *filename;
+
+ if (redirs == NULL)
+ return (true);
+ if (!(st_lst_tag(redirs) & TAG_IS_REDIR) || redirs->next == NULL
+ || !(st_lst_tag(redirs->next) & TAG_IS_STR))
+ return (false);
+ curr = redirs->next;
+ while (curr != NULL && st_lst_tag(curr) & TAG_IS_STR)
+ {
+ if (curr->next == NULL || st_lst_tag(curr->next) & TAG_IS_REDIR)
+ {
+ after = curr->next;
+ curr->next = NULL;
+ }
+ curr = curr->next;
+ }
+ if ((filename = preprocess_filename(&redirs->next, env)) == NULL)
+ {
+ token_destroy_lst2(redirs, after);
+ return (false);
+ }
+ if ((st_lst_tag(redirs) == TAG_REDIR_IN
+ && !st_open_replace(fd_in, filename, O_RDONLY))
+ || (st_lst_tag(redirs) == TAG_REDIR_OUT
+ && !st_open_replace(fd_out, filename, O_WRONLY | O_CREAT | O_TRUNC))
+ || (st_lst_tag(redirs) == TAG_REDIR_APPEND
+ && !st_open_replace(fd_out, filename, O_WRONLY | O_CREAT | O_APPEND)))
+ {
+ token_destroy_lst2(redirs, after);
+ return (false);
+ }
+ token_destroy_lst(redirs);
+ free(filename);
+ return (redir_extract(after, env, fd_in, fd_out));
+}