diff --git a/Makefile b/Makefile index 25c8766..892938b 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,9 @@ CC = clang CFLAGS = -Wall -Wextra $(INCLUDES) -g # add -Werror, del -g VPATH = $(DIR_SRCS) -DIR_SRCS = srcs srcs/builtins srcs/lexing srcs/parsing +DIR_SRCS = srcs srcs/builtins srcs/lexing \ + srcs/parsing srcs/parsing/valid_syntax \ + srcs/parsing/expansions srcs/parsing/redirections INCLUDES = -I$(HEADERS_D) -I$(LIBFT_D) @@ -25,8 +27,12 @@ SRCS = main.c init.c free.c generic.c \ signals.c \ shell_loop.c shell_script.c \ lexing.c fill_token.c check_operators.c \ - parsing.c \ + parsing.c cmd_array.c \ valid_syntax.c valid_pipeline.c valid_command.c valid_io_redirect.c \ + words_expansions.c expand_token.c rejoin_after_expand.c new_token_for_each_field.c \ + ft_split_quotes.c ft_strdup_quotes.c \ + redirections.c here_doc.c \ + exec_cmd_line.c \ cd.c pwd.c export.c unset.c exit.c env.c echo.c DIR_OBJS = builds diff --git a/headers/minishell_prototypes.h b/headers/minishell_prototypes.h index d4ce5c5..064ffce 100644 --- a/headers/minishell_prototypes.h +++ b/headers/minishell_prototypes.h @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/08 02:59:58 by lperrey #+# #+# */ -/* Updated: 2021/11/15 19:23:23 by hulamy ### ########.fr */ +/* Updated: 2021/11/16 22:58:35 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,6 +15,10 @@ // Init int init(t_all *c, char *envp[]); +char **retrieve_path(char *envp[]); +int set_terminal_attributes(struct termios *ori_termios, + struct termios *interactive_termios, + int *termios_changed); // WIP, TEST, TEMP, PLACEHOLDER, NOT IMPORTANT, :) int set_signals_handling(struct sigaction *signal_behaviour); // Shell modes @@ -25,12 +29,19 @@ void shell_script(t_all *c); t_token *input_to_tokens(char *input); // Parser -t_cmd **parsing(t_token *token_list, char **envp); +t_cmd **parsing(t_token *token_list); int valid_syntax(t_token *token_list); int valid_token(t_token **token_list, enum e_token_id token_id); int valid_command_separator(const t_token *token_list); -t_cmd **fill_cmd(t_token *token, char **envp); -void cmd_expansion(t_cmd **cmd_arr, char **envp); +size_t count_pipes(t_token *token_list); +t_cmd **cmd_array_alloc(size_t cmd_nbr); +int cmd_array_fill_argv(t_token *token_list, t_cmd **cmd_arr); +int words_expansions(t_token *token_list); +int token_expansions(t_token **t); +int redirections(t_token *token_list, t_cmd **cmd_arr); + +// Exec +int exec_cmd_line(t_all *c); // Builtins int builtin_cd(int argc, char *argv[], t_all *c); @@ -44,6 +55,9 @@ int getenv_position(char **envp, char *name); // Free int free_exit(t_all *c, int exit_status); +void free_pipeline(t_cmd **pipeline_ptr[]); +void close_pipeline_fd(t_cmd *pipeline[]); +typedef void (*t_free_f)(void *); // generic // Generic char *ft_strjoinfree(char *s1, char *s2); @@ -56,9 +70,16 @@ char **ft_dup_2d_char_arr(char **ptr); void *ft_resize_2d_arr(void *ptr, size_t add_nbr); void print_matrix(char **matrix, char *sep); t_list *ft_lstbeforelast(t_list *lst); +t_list *ft_lstnew_generic(size_t lst_sizse, size_t content_size); +typedef void *(*t_dup_f)(void *); +void *ft_dup_2d_arr(void *ptr, void *(*dup_func)(void *)); +void ft_perror_io(char *err_str, char *io_file); +int ft_reti_perror_io(int ret, char *err_str, char *io_file); + +char **ft_split_quotes(char const *s, char c); +char *ft_strdup_quotes(const char *s); // signals.c -void sigint_handler_interactiv(int signum); -void sigint_handler_execution(int signum); +void sigint_handler_interactive(int signum); #endif diff --git a/headers/minishell_structs.h b/headers/minishell_structs.h index fd641af..7ac5831 100644 --- a/headers/minishell_structs.h +++ b/headers/minishell_structs.h @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/08 02:35:52 by lperrey #+# #+# */ -/* Updated: 2021/11/10 17:33:37 by hulamy ### ########.fr */ +/* Updated: 2021/11/16 21:38:28 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -23,7 +23,8 @@ enum e_token_id T_PIPE = '|', T_DLESS, T_DGREAT, - T_WORD + T_WORD, + T_REDIRECTION_WORD }; // T_DLESS == '<<' // T_DGREAT == '>>' @@ -35,21 +36,24 @@ typedef struct s_token enum e_token_id id; } t_token; -typedef int t_builtin_ptr(int,char **,struct s_all *); +typedef int (*t_builtin_f)(int,char **,struct s_all *); typedef struct s_cmd { - char **argv; - pid_t pid; - t_builtin_ptr *builtin_command; - int fd_in; - int fd_out; + char **argv; + char *path; + t_builtin_f builtin_func; + int fd_in; + int fd_out; + pid_t pid; + int error; } t_cmd; typedef struct s_all { t_cmd **cmd_arr; char **envp; + char **path; char *prompt_base; char *prompt; t_token *token_list; diff --git a/srcs/builtins/exit.c b/srcs/builtins/exit.c index 71e09f7..e6f6ca5 100644 --- a/srcs/builtins/exit.c +++ b/srcs/builtins/exit.c @@ -36,7 +36,7 @@ int builtin_exit(int argc, char *argv[], t_all *c) // WIP return (ft_reti_print(2, " numeric argument required\n", 2)); } } - status = ft_atoi(argv[1]); + status = ft_atoi(argv[1]); } return (free_exit(c, status)); } diff --git a/srcs/exec_cmd_line.c b/srcs/exec_cmd_line.c new file mode 100644 index 0000000..49c1796 --- /dev/null +++ b/srcs/exec_cmd_line.c @@ -0,0 +1,183 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exec_cmd_line.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/16 01:57:38 by lperrey #+# #+# */ +/* Updated: 2021/11/17 01:08:38 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01_01 +// Bien penser à mettre les ptr à NULL aprés free en cas d'erreur (pour ne pas double free si appel à free_exit()) + +int pipeline(t_all *c); +int open_pipes(t_cmd *pipeline[]); +int pipeline_access_cmd(t_cmd *pipeline[], char *path[]); +pid_t pipeline_exec(t_cmd *pipeline[], t_all *c); +int cmd_exec_in_subshell(t_cmd *cmd, t_all *c); +int simple_cmd_builtin(t_cmd *cmd, t_all *c); +void wait_subshell(pid_t last_cmd_pid, int *last_exit_status); + +int exec_cmd_line(t_all *c) +{ + if (!pipeline(c)) + { + free_pipeline(&c->cmd_arr); + return (0); + } + return (1); +} + +int pipeline(t_all *c) +{ + if (!open_pipes(c->cmd_arr)) + return (0); + if (!pipeline_access_cmd(c->cmd_arr, c->path)) + return (0); + if (ft_2d_arrlen(pipeline) == 1 && c->cmd_arr[0]->builtin_func) + { + simple_cmd_builtin(c->cmd_arr[0], c); + free_pipeline(&c->cmd_arr); + } + else + { + wait_subshell(pipeline_exec(c->cmd_arr, c), &c->last_exit_status); + free_pipeline(&c->cmd_arr); + } + return (1); +} + +int open_pipes(t_cmd *pipeline[]) +{ + int i; + int pipes[2]; + + i = 0; + while (pipeline[i] && pipeline[i + 1]) + { + if (pipe(pipes) == -1) + return (ft_reti_perror(0, "pipe()")); + if (pipeline[i]->fd_out == STDOUT_FILENO) + pipeline[i]->fd_out = pipes[STDOUT_FILENO]; + else + if (close(pipes[STDOUT_FILENO]) == -1) + perror("close()"); + if (pipeline[i]->fd_in == STDIN_FILENO) + pipeline[i + 1]->fd_in = pipes[STDIN_FILENO]; + else + if (close(pipes[STDIN_FILENO]) == -1) + perror("close()"); + i++; + } + return (1); +} + +int pipeline_access_cmd(t_cmd *pipeline[], char *path[]) +{ + // TODO + // Penser à : path = strdup(argv[0]); + // et non : path = argv[0]; + // pour ne pas double free + + return (1); +} + +int simple_cmd_builtin(t_cmd *cmd, t_all *c) +{ + // TODO + return (1); +} + +// TODO : Change exit status as in documentation : +// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08_02 +pid_t pipeline_exec(t_cmd *pipeline[], t_all *c) +{ + int i; + int ret; + + i = 0; + while (pipeline[i]) + { + if (!pipeline[i]->error) + { + ret = cmd_exec_in_subshell(pipeline[i], c); + if (ret != EXIT_SUCCESS) + free_exit(c, ret); + } + i++; + } + close_pipeline_fd(c->cmd_arr); + i -= 1; + if (pipeline[i]->error) + c->last_exit_status = pipeline[i]->error; + return (pipeline[i]->pid); +} + +int handle_wait_error(void) +{ + if (errno == ECHILD) + return (-1); + else if (errno == EINTR) + return (0); + else + perror("wait()"); + return (-1); +} + +void wait_subshell(pid_t last_cmd_pid, int *last_exit_status) +{ + int wstatus; + int ret; + + //wstatus = 0; + if (last_cmd_pid > 0) + { + if (waitpid(last_cmd_pid, &wstatus, 0) == -1) + perror("waitpid()"); + if (WIFEXITED(wstatus)) + *last_exit_status = WEXITSTATUS(wstatus); + } + ret = 0; + while (ret != -1) + { + ret = wait(&wstatus); + if (ret == -1) + ret = handle_wait_error(); + } + if (WIFSIGNALED(wstatus)) + { + write(STDIN_FILENO, "\n", 1); + *last_exit_status = 128 + WTERMSIG(wstatus); + } +} + +int cmd_exec_in_subshell(t_cmd *cmd, t_all *c) +{ + cmd->pid = fork(); + if (cmd->pid == -1) + perror("fork()"); + if (cmd->pid == 0) + { + c->signal_behaviour.sa_handler = SIG_DFL; + sigaction(SIGINT, &c->signal_behaviour, NULL); + if (cmd->fd_in != STDIN_FILENO) + if (dup2(cmd->fd_in, STDIN_FILENO) == -1) + return (ft_reti_perror(EXIT_FAILURE, "dup2()")); + if (cmd->fd_out != STDOUT_FILENO) + if (dup2(cmd->fd_out, STDOUT_FILENO) == -1) + return (ft_reti_perror(EXIT_FAILURE, "dup2()")); + close_pipeline_fd(c->cmd_arr); + if (cmd->builtin_func) + free_exit(c, cmd->builtin_func(ft_2d_arrlen(cmd->argv), cmd->argv,c)); + else if (execve("/bin/echo", cmd->argv, c->envp) == -1) // WIP, TEST + return (ft_reti_perror_io(EXIT_FAILURE, "execve() ", cmd->argv[0])); + //else if (execve(cmd->path, cmd->argv, c->envp) == -1) + // return (ft_reti_perror_io(EXIT_FAILURE, "execve() ", cmd->argv[0])); + } + return (EXIT_SUCCESS); +} diff --git a/srcs/free.c b/srcs/free.c index e0ca7e8..b933fc4 100644 --- a/srcs/free.c +++ b/srcs/free.c @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/10 23:53:17 by lperrey #+# #+# */ -/* Updated: 2021/11/10 17:15:44 by hulamy ### ########.fr */ +/* Updated: 2021/11/17 01:25:35 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,8 +18,55 @@ int free_exit(t_all *c, int exit_status) free(c->prompt); ft_lstclear((t_list **)&c->token_list, free); // a voir avec Hugo, il y a un truc qui me semble superflu dans la fonction ft_free_2d_arr(c->envp); -// if (c->termios_changed) -// tcsetattr(STDIN_FILENO, TCSANOW, &c->ori_termios); + ft_free_2d_arr(c->path); + free_pipeline(&c->cmd_arr); + //if (c->termios_changed) + // tcsetattr(STDIN_FILENO, TCSANOW, &c->ori_termios); rl_clear_history(); exit(exit_status); } + +void free_pipeline(t_cmd **pipeline_ptr[]) +{ + int i; + t_cmd **pipeline; + + pipeline = *pipeline_ptr; + if (!pipeline) + return ; + close_pipeline_fd(pipeline); + i = 0; + while (pipeline[i]) + { + ft_free_2d_arr(pipeline[i]->argv); + free(pipeline[i]->path); + i++; + } + ft_free_2d_arr(pipeline); + *pipeline_ptr = NULL; +} + +void close_pipeline_fd(t_cmd *pipeline[]) +{ + int i; + + if (!pipeline) + return ; + i = 0; + while (pipeline[i]) + { + if (pipeline[i]->fd_in != STDIN_FILENO && pipeline[i]->fd_in > 0) + { + if (close(pipeline[i]->fd_in) == -1) + perror("close()"); + pipeline[i]->fd_in = 0; + } + if (pipeline[i]->fd_out != STDOUT_FILENO && pipeline[i]->fd_out > 0) + { + if (close(pipeline[i]->fd_out) == -1) + perror("close()"); + pipeline[i]->fd_out = 0; + } + i++; + } +} diff --git a/srcs/generic.c b/srcs/generic.c index 9426b83..002eec3 100644 --- a/srcs/generic.c +++ b/srcs/generic.c @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/08 09:25:35 by lperrey #+# #+# */ -/* Updated: 2021/11/02 13:52:23 by hulamy ### ########.fr */ +/* Updated: 2021/11/14 08:27:40 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -85,7 +85,7 @@ size_t ft_2d_arrlen(void *ptr) // Replace ft_arrlen() return (len); } -char **ft_dup_2d_char_arr(char **ptr) +char **ft_dup_2d_char_arr(char **ptr) // Superflu si ft_dup_2d_arr() fonctionne { unsigned int i; char **arr; @@ -107,6 +107,29 @@ char **ft_dup_2d_char_arr(char **ptr) return (new_arr); } +// Test generic. Pas certain que ça fonctionne bien avec le pointeur sur fonction +void *ft_dup_2d_arr(void *ptr, void *(*dup_func)(void *)) +{ + unsigned int i; + char **arr; + char **new_arr; + + new_arr = malloc((ft_2d_arrlen(ptr) + 1) * sizeof (void *)); + if (!new_arr) + return (NULL); + arr = (char **)ptr; + i = 0; + while (arr[i]) + { + new_arr[i] = dup_func(arr[i]); + if (!new_arr[i]) + return (ft_retp_free(NULL, new_arr, ft_free_2d_arr)); + i++; + } + new_arr[i] = NULL; + return (new_arr); +} + void *ft_resize_2d_arr(void *ptr, size_t add_nbr) { unsigned int i; @@ -150,3 +173,40 @@ t_list *ft_lstbeforelast(t_list *lst) lst = lst->next; return (lst); } + +t_list *ft_lstnew_generic(size_t lst_size, size_t content_size) +{ + t_list *elem; + void *content; + + if (content_size == 0) + content = NULL; + else + { + content = ft_calloc(content_size, 1); + if (!content) + return (NULL); + } + elem = ft_calloc(1, lst_size); + if (!elem) + { + free(content); + return (NULL); + } + elem->content = content; + elem->next = NULL; + return (elem); +} + +void ft_perror_io(char *err_str, char *io_file) +{ + ft_putstr_fd(err_str, 2); + perror(io_file); +} + +int ft_reti_perror_io(int ret, char *err_str, char *io_file) +{ + ft_putstr_fd(err_str, 2); + perror(io_file); + return (ret); +} diff --git a/srcs/init.c b/srcs/init.c index 814ec56..d42bf8f 100644 --- a/srcs/init.c +++ b/srcs/init.c @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/08 09:22:12 by lperrey #+# #+# */ -/* Updated: 2021/11/10 13:43:59 by hulamy ### ########.fr */ +/* Updated: 2021/11/16 21:06:18 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -19,9 +19,11 @@ int init(t_all *c, char *envp[]) { g_all = c; ft_bzero(c, sizeof (*c)); - c->envp = ft_dup_2d_char_arr(envp); + c->envp = ft_dup_2d_arr(envp, (t_dup_f)ft_strdup); // TEST WIP if (!c->envp) return (ft_reti_perror(0, "ft_dup_2d_char_arr(envp) error")); + //print_matrix(c->envp, "\n --- \n"); // TEST WIP + c->path = retrieve_path(c->envp); // No return check. Its intended. PATH is optional c->prompt_base = init_prompt_base(); if (!c->prompt_base) return (ft_reti_perror(0, "init_prompt_base() error")); @@ -32,7 +34,24 @@ int init(t_all *c, char *envp[]) return (1); } -static char *init_prompt_base(void) +// TODO : Un appel à builtin_export() modifiant $PATH doit aussi entrainer un appel à "c->path = retrieve_path()" +char **retrieve_path(char *envp[]) +{ + char *path; + char **path_split; + + (void)envp; + //path = search_env_var(envp, "PATH"); // A reprendre du projet pipex si besoin de remplacer getenv() + path = getenv("PATH"); + if (!path) + return (ft_retp_print(NULL, "minishell: Warning, $PATH not set\n", 2)); + path_split = ft_split(path, ':'); + if (!path_split) + return (ft_retp_perror(NULL, "retrieve_path()")); + return (path_split); +} + +static char *init_prompt_base(void) // WIP, error return TODO { char *prompt_base; char *tmp; @@ -52,7 +71,7 @@ static char *init_prompt_base(void) return (prompt_base); } -static char *init_prompt(char *prompt_base) +static char *init_prompt(char *prompt_base) // WIP, error return TODO { char *prompt; diff --git a/srcs/lexing/lexing.c b/srcs/lexing/lexing.c index 33ebd56..920e277 100644 --- a/srcs/lexing/lexing.c +++ b/srcs/lexing/lexing.c @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/19 08:38:55 by lperrey #+# #+# */ -/* Updated: 2021/10/30 22:37:48 by lperrey ### ########.fr */ +/* Updated: 2021/11/07 03:18:38 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,7 +14,7 @@ int fill_token(t_token *t, char *input, int *i, int *t_i); -static t_token *alloc_token(size_t content_len); +static t_token *alloc_token(size_t content_len); // TODO, a remplacer par ft_lstnew_generic() static int tokenize_input(t_token *t, char *input, size_t input_len); t_token *input_to_tokens(char *input) @@ -30,7 +30,7 @@ t_token *input_to_tokens(char *input) if (!tokenize_input(t_head, input, input_len)) return (ft_lstclear((t_list **)&t_head, free)); t_tmp = (t_token *)ft_lstbeforelast((t_list *)t_head); - if (t_tmp && !t_tmp->next->id) + if (t_tmp && t_tmp->next && !t_tmp->next->id) { ft_lstdelone((t_list *)t_tmp->next, free); t_tmp->next = NULL; diff --git a/srcs/main.c b/srcs/main.c index 6227695..b423b02 100644 --- a/srcs/main.c +++ b/srcs/main.c @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/04 05:59:26 by lperrey #+# #+# */ -/* Updated: 2021/11/02 14:03:31 by hulamy ### ########.fr */ +/* Updated: 2021/11/08 04:05:41 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -20,9 +20,10 @@ int main(int argc, char *argv[], char *envp[]) (void)argv; if (!init(&c, envp)) free_exit(&c, EXIT_FAILURE); - if (isatty(STDIN_FILENO)) - shell_loop(&c); - else - shell_script(&c); + putenv("VAR=W1 W2 W3"); // TEMP TEST + //if (isatty(STDIN_FILENO)) + shell_loop(&c); + //else + // shell_script(&c); return (0); } diff --git a/srcs/parsing/HUGO_WIP.c b/srcs/parsing/HUGO_WIP.c new file mode 100644 index 0000000..9865c25 --- /dev/null +++ b/srcs/parsing/HUGO_WIP.c @@ -0,0 +1,189 @@ + +#include "minishell.h" + +int is_redirection(enum e_token_id id) +{ + if (id == T_LESS) // < + return (1); + else if (id == T_GREAT) // > + return (1); + else if (id == T_DLESS) // << + return (1); + else if (id == T_DGREAT) // >> + return (1); + else + return (0); +} + +// count nbr word in cmd, minus redirection and heredoc +int next_cmd(t_token *token) +{ + int i; + + i = 0; + while (token && token->id != T_PIPE) + { + if (is_redirection(token->id)) + i--; + else + i++; + token = token->next; + } + if (token && token->id == T_PIPE) + token = token->next; + return (i); +} + +void handle_argv(t_token *token, t_cmd **cmd, size_t cmd_nbr) +{ + int argc; + int j; + int i; + int redirection; + + i = 0; + while (cmd_nbr) + { + argc = next_cmd(token); + cmd[i]->argv = calloc(argc + 1, sizeof(char *)); + cmd[i]->argv[argc] = NULL; + j = 0; + redirection = is_redirection(token->id); + while (token && token->id != T_PIPE) + { + if (!redirection && token->id == T_WORD) + { + cmd[i]->argv[j] = ft_strdup(token->content); + j++; + } + redirection = is_redirection(token->id); + token = token->next; + } + if (token && token->id == T_PIPE) + token = token->next; + cmd_nbr--; + i++; + } +} + +int fill_builtin(t_cmd *cmd, int (*builtin)(int, char **, t_all *)) +{ + cmd->builtin_command = &builtin; + return (1); +} + +int handle_builtin(t_cmd *cmd) +{ // Il faut penser à comparer un char de plus (\0 inclus) + if (!ft_strncmp(cmd->argv[0], "echo", 4)) + return (fill_builtin(cmd, &builtin_echo)); +// else if (!ft_strncmp(cmd->argv[0], "cd", 2)) +// return (fill_builtin(cmd, &builtin_cd)); +// else if (!ft_strncmp(cmd->argv[0], "pwd", 3)) +// return (fill_builtin(cmd, &builtin_pwd)); +// else if (!ft_strncmp(cmd->argv[0], "export", 6)) +// return (fill_builtin(cmd, &builtin_export)); +// else if (!ft_strncmp(cmd->argv[0], "unset", 5)) +// return (fill_builtin(cmd, &builtin_unset)); + else if (!ft_strncmp(cmd->argv[0], "env", 3)) + return (fill_builtin(cmd, &builtin_env)); + else if (!ft_strncmp(cmd->argv[0], "exit", 4)) + return (fill_builtin(cmd, &builtin_exit)); + return (0); +} + +void find_path(char **argv, char **envp) +{ + int i; + char **path; + char *cmd; + + i = 0; + while (envp[i] && ft_strncmp(envp[i], "PATH=", 5)) + i++; + path = ft_split(envp[i] + 5, ':'); // 5 = lentgh of "PATH=" + i = -1; + while (*path && i != 0) + { + cmd = ft_strjoin(path[0], "/"); + cmd = ft_strjoin(cmd, argv[0]); + i = access(cmd, X_OK); + path++; + } + if (!(*path)) + exit(0); // gerer erreur + argv[0] = cmd; +} + +void handle_path(t_cmd **cmd_arr, char **envp) +{ + int i; + + i = 0; + while (cmd_arr[i]) + { + if (!handle_builtin(cmd_arr[i])) + find_path(cmd_arr[i]->argv, envp); + i++; + } +} + +void fd_redirection(t_token *token, t_cmd *cmd) +{ + int flag; + + if (token->id == T_LESS) // '<' + { + flag = O_RDONLY | O_CREAT; // O_CREAT ? Pourquoi donc ? + if (cmd->fd_in != 0) + close(cmd->fd_in); + cmd->fd_in = open(token->next->content, flag); + } + else if (token->id == T_GREAT) // '>' + { + flag = O_WRONLY | O_CREAT | O_TRUNC; + cmd->fd_out = open(token->next->content, flag, S_IRWXU); + } + else if (token->id == T_DGREAT) // '>>' + { + flag = O_WRONLY | O_CREAT | O_APPEND; + cmd->fd_out = open(token->next->content, flag, S_IRWXU); + } +} + +void fd_heredoc(t_token *token, t_cmd *cmd) +{ + (void)token; + (void)cmd; +} + +void handle_fd(t_token *token, t_cmd **cmd_arr) +{ + int *pipes_fd; + int i; + + i = 0; + while (cmd_arr[i]) + { + cmd_arr[i]->fd_out = 1; + while (token && token->id != T_PIPE) + { + if (token->id == T_DGREAT) // '<<' + fd_heredoc(token, cmd_arr[i]); + else + fd_redirection(token, cmd_arr[i]); + token = token->next; + } + if (token && token->id == T_PIPE) + { + token = token->next; + pipes_fd = calloc(2, sizeof(int)); + pipe(pipes_fd); + if (cmd_arr[i]->fd_out == 1) + cmd_arr[i]->fd_out = pipes_fd[1]; + else + close(pipes_fd[1]); + cmd_arr[i + 1]->fd_in = pipes_fd[0]; + } + i++; + } +} diff --git a/srcs/parsing/cmd_array.c b/srcs/parsing/cmd_array.c new file mode 100644 index 0000000..b57386c --- /dev/null +++ b/srcs/parsing/cmd_array.c @@ -0,0 +1,95 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cmd_array.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/02 22:46:23 by lperrey #+# #+# */ +/* Updated: 2021/11/14 12:24:39 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static size_t cmd_words_count(t_token *t); + +size_t count_pipes(t_token *t) +{ + size_t count; + + count = 0; + while (t) + { + if (t->id == T_PIPE) + count++; + t = t->next; + } + return (count); +} + +t_cmd **cmd_array_alloc(size_t cmd_nbr) +{ + t_cmd **cmd_arr; + size_t i; + + cmd_arr = ft_calloc(cmd_nbr + 1, sizeof (void *)); + if (!cmd_arr) + return (ft_retp_perror(NULL, "cmd_array_alloc()")); + i = 0; + while (i < cmd_nbr) + { + cmd_arr[i] = ft_calloc(1, sizeof (*cmd_arr[i])); + if (!cmd_arr[i]) + { + ft_free_2d_arr(cmd_arr); + return (ft_retp_perror(NULL, "cmd_array_alloc()")); + } + cmd_arr[i]->fd_in = STDIN_FILENO; + cmd_arr[i]->fd_out = STDOUT_FILENO; + i++; + } + return (cmd_arr); +} + +int cmd_array_fill_argv(t_token *t, t_cmd **cmd_arr) +{ + size_t i; + size_t arg_i; + + i = 0; + while (cmd_arr[i]) + { + cmd_arr[i]->argv = ft_calloc(cmd_words_count(t) + 1, sizeof (char *)); + if (!cmd_arr[i]->argv) + return (ft_reti_perror(0, "cmd_array_fill_argv()")); + arg_i = 0; + while (t && t->id != '|') + { + if (t->id == T_WORD) + { + cmd_arr[i]->argv[arg_i++] = t->content; + t->content = NULL; + } + t = t->next; + } + if (t && t->id == '|') + t = t->next; + i++; + } + return (1); +} + +static size_t cmd_words_count(t_token *t) +{ + size_t count; + + count = 0; + while (t && t->id != '|') + { + if (t->id == T_WORD) + count++; + t = t->next; + } + return (count); +} diff --git a/srcs/parsing/expansions/expand_token.c b/srcs/parsing/expansions/expand_token.c new file mode 100644 index 0000000..7885052 --- /dev/null +++ b/srcs/parsing/expansions/expand_token.c @@ -0,0 +1,116 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* expand_token.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/07 02:01:33 by lperrey #+# #+# */ +/* Updated: 2021/11/11 21:04:41 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +t_list *ft_lstnew_generic(size_t lst_sizse, size_t content_size); + +enum e_in_quote_state +{ + NOT_IN = 0, + IN_QUOTES = '\'', + IN_DQUOTES = '\"' +}; + +static t_list *ret_parameter_expansion(char *content, int *i); + +t_list *expand_token(char *content) +{ + int in_quotes; + int i; + int i_exp; + t_list head; + t_list *expand; + + in_quotes = 0; + i = 0; + head.next = NULL; + expand = &head; + while (content[i]) + { + if (content[i] == '$') + { + expand->next = ret_parameter_expansion(content, &i); + expand = expand->next; + if (!expand) + {//todo wrap + perror("expand_token() error"); + return (ft_lstclear(&head.next, free)); + } + } + else + { + expand->next = ft_lstnew_generic(sizeof(t_list), ft_strlen(&content[i]) + 1); + expand = expand->next; + i_exp = 0; + if (!expand) + {//todo wrap + perror("expand_token() error"); + return (ft_lstclear(&head.next, free)); + } + while (content[i] && (content[i] != '$' || in_quotes == IN_QUOTES)) + { + // quoting + if (content[i] == '\'' && in_quotes != IN_DQUOTES) + { + if (in_quotes == IN_QUOTES) + in_quotes = 0; + else + in_quotes = IN_QUOTES; + } + ((char *)expand->content)[i_exp++] = content[i++]; + } + } + } + return (head.next); +} + +// a voir si je retourne pas plutot un "char *". +// Malloc la lst dans la fonction est peut-être un peu superflu et pas super clair. +static t_list *ret_parameter_expansion(char *content, int *i) +{ + t_list *expand; + char *tmp; + int i_tmp; + + tmp = ft_calloc(ft_strlen(&content[*i]) + 1, 1); + if (!tmp) + return (NULL); + expand = ft_lstnew(NULL); + if (!expand) + return (ft_retp_free(NULL, tmp, free)); + (*i)++; // skip '$' + if (content[*i] == '?') + { + (*i)++; + expand->content = ft_itoa(g_all->last_exit_status); + return (ft_retp_free(expand, tmp, free)); + } + else if (content[*i] != '_' && !ft_isalpha(content[*i])) + { + tmp[0] = '$'; + expand->content = tmp; + return (expand); + } + i_tmp = 0; + while (content[*i] == '_' || ft_isalnum(content[*i])) + tmp[i_tmp++] = content[(*i)++]; + expand->content = getenv(tmp); + free(tmp); + if (expand->content) + expand->content = ft_strdup(expand->content); + else + expand->content = ft_calloc(1, 1); + if (!expand->content) + return (ft_retp_free(NULL, expand, free)); + return (expand); +} diff --git a/srcs/parsing/expansions/ft_split_MODIF.c b/srcs/parsing/expansions/ft_split_MODIF.c new file mode 100644 index 0000000..e60f6e4 --- /dev/null +++ b/srcs/parsing/expansions/ft_split_MODIF.c @@ -0,0 +1,106 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_split_MODIF.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/13 07:08:40 by lperrey #+# #+# */ +/* Updated: 2021/11/13 20:24:33 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +// FT_SPLIT LEGEREMENT REMANIER. +// A REMPLACER DANS LA LIBFT +#include "libft.h" + +static size_t count_word(char const *s, char c); +static char **alloc_words(char const *s, char c, char **str_arr, + size_t words_count); +static void fill_arr(char const *s, char c, char **str_arr); + +char **ft_split(char const *s, char c) +{ + char **str_arr; + size_t words_count; + + if (s == NULL) + return (NULL); + words_count = count_word(s, c); + str_arr = ft_calloc(words_count + 1, sizeof(char *)); + if (!str_arr) + return (NULL); + if (!(alloc_words(s, c, str_arr, words_count))) + { + ft_free_2d_arr(str_arr); + return (NULL); + } + fill_arr(s, c, str_arr); + return (str_arr); +} + +static size_t count_word(char const *s, char c) +{ + unsigned int i; + size_t count; + + count = 0; + i = 0; + while (s[i]) + { + while (s[i] == c) + i++; + if (s[i]) + count++; + while (s[i] && s[i] != c) + i++; + } + return (count); +} + +static char **alloc_words(char const *s, char c, char **str_arr, + size_t words_count) +{ + unsigned int i; + size_t len; + unsigned int arr_i; + + i = 0; + arr_i = 0; + while (arr_i < words_count) + { + len = 0; + while (s[i] == c) + i++; + while (s[i] && s[i] != c) + { + len++; + i++; + } + str_arr[arr_i] = malloc(len + 1); + if (!str_arr[arr_i]) + return (NULL); + arr_i++; + } + return (str_arr); +} + +static void fill_arr(char const *s, char c, char **str_arr) +{ + unsigned int i; + unsigned int arr_i; + unsigned int char_i; + + i = 0; + arr_i = 0; + while (str_arr[arr_i]) + { + while (s[i] == c) + i++; + char_i = 0; + while (s[i] && s[i] != c) + str_arr[arr_i][char_i++] = s[i++]; + str_arr[arr_i][char_i] = '\0'; + arr_i++; + } +} diff --git a/srcs/parsing/expansions/ft_split_quotes.c b/srcs/parsing/expansions/ft_split_quotes.c new file mode 100644 index 0000000..83ccb22 --- /dev/null +++ b/srcs/parsing/expansions/ft_split_quotes.c @@ -0,0 +1,186 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_split_quotes.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/13 07:08:40 by lperrey #+# #+# */ +/* Updated: 2021/11/13 22:35:34 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +enum e_in_quote_state +{ + NOT_IN = 0, + IN_QUOTES = '\'', + IN_DQUOTES = '\"' +}; + +static size_t count_word(char const *s, char c); +static char **alloc_words(char const *s, char c, char **str_arr, + size_t words_count); +static void fill_arr(char const *s, char c, char **str_arr); +static int quote_state_change(int *quote_state, const char *s); + +char **ft_split_quotes(char const *s, char c) +{ + char **str_arr; + size_t words_count; + + if (s == NULL) + return (NULL); + words_count = count_word(s, c); + str_arr = ft_calloc(words_count + 1, sizeof(char *)); + if (!str_arr) + return (NULL); + if (!(alloc_words(s, c, str_arr, words_count))) + { + ft_free_2d_arr(str_arr); + return (NULL); + } + fill_arr(s, c, str_arr); + return (str_arr); +} + +static size_t count_word(char const *s, char c) +{ + unsigned int i; + size_t count; + int quote_state; + + i = 0; + count = 0; + quote_state = 0; + while (s[i]) + { + while (s[i] == c) + i++; + if (s[i]) + count++; + while (s[i] && (s[i] != c || quote_state)) + { + while (quote_state_change("e_state, &s[i])) + i++; + if (s[i] && (s[i] != c || quote_state)) + i++; + } + } + return (count); +} + +static char **alloc_words(char const *s, char c, char **str_arr, + size_t words_count) +{ + unsigned int i; + size_t len; + unsigned int arr_i; + int quote_state; + + i = 0; + arr_i = 0; + quote_state = 0; + while (arr_i < words_count) + { + len = 0; + while (s[i] == c) + i++; + while (s[i + len] + && (quote_state_change("e_state, &s[i + len]) + || (s[i + len] != c || quote_state))) + len++; + i = i + len; + str_arr[arr_i] = ft_calloc(len + 1, 1); + if (!str_arr[arr_i]) + return (NULL); + arr_i++; + } + return (str_arr); +} + +// Plus clair, plus de 25 lignes :( +/* static char **alloc_words(char const *s, char c, char **str_arr, + size_t words_count) +{ + unsigned int i; + size_t len; + unsigned int arr_i; + int quote_state; + + i = 0; + arr_i = 0; + quote_state = 0; + while (arr_i < words_count) + { + len = 0; + while (s[i] == c) + i++; + while (s[i + len] && (s[i + len] != c || quote_state)) + { + while (quote_state_change("e_state, &s[i + len])) + len++; + if (s[i + len] != c || quote_state) + len++; + } + i = i + len; + str_arr[arr_i] = ft_calloc(len + 1, 1); + if (!str_arr[arr_i]) + return (NULL); + arr_i++; + } + return (str_arr); +} */ + +static void fill_arr(char const *s, char c, char **str_arr) +{ + unsigned int i; + unsigned int arr_i; + unsigned int char_i; + int quote_state; + + i = 0; + arr_i = 0; + quote_state = 0; + while (str_arr[arr_i]) + { + while (s[i] == c) + i++; + char_i = 0; + while (s[i] && (s[i] != c || quote_state)) + { + while (quote_state_change("e_state, &s[i])) + str_arr[arr_i][char_i++] = s[i++]; + if (s[i] && (s[i] != c || quote_state)) + str_arr[arr_i][char_i++] = s[i++]; + } + str_arr[arr_i][char_i] = '\0'; //superflu si ft_calloc + arr_i++; + } +} + +static int quote_state_change(int *quote_state, const char *s) +{ + if (s[0] == '\'' && *quote_state != IN_DQUOTES) + { + if (*quote_state == IN_QUOTES) + *quote_state = 0; + else if (ft_strchr(&s[1], '\'')) // if closed quotes + *quote_state = IN_QUOTES; + else + return (0); + return (1); + } + else if (s[0] == '\"' && *quote_state != IN_QUOTES) + { + if (*quote_state == IN_DQUOTES) + *quote_state = 0; + else if (ft_strchr(&s[1], '\"')) // if closed quotes + *quote_state = IN_DQUOTES; + else + return (0); + return (1); + } + return (0); +} diff --git a/srcs/parsing/expansions/ft_strdup_quotes.c b/srcs/parsing/expansions/ft_strdup_quotes.c new file mode 100644 index 0000000..1b4525f --- /dev/null +++ b/srcs/parsing/expansions/ft_strdup_quotes.c @@ -0,0 +1,70 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strdup_quotes.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/13 04:35:06 by lperrey #+# #+# */ +/* Updated: 2021/11/14 06:01:45 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +enum e_in_quote_state +{ + NOT_IN = 0, + IN_QUOTES = '\'', + IN_DQUOTES = '\"' +}; +static int quote_state_change(int *quote_state, const char *s); + +/* Duplicate a string minus the quoting characters ['] and ["]*/ +char *ft_strdup_quotes(const char *s) +{ + unsigned int i; + unsigned int i_dup; + char *dup; + int quote_state; + + dup = ft_calloc(ft_strlen(s) + 1, 1); + if (!dup) + return (NULL); + i = 0; + i_dup = 0; + quote_state = 0; + while (s[i]) + { + while (quote_state_change("e_state, &s[i])) + i++; + if (s[i]) + dup[i_dup++] = s[i++]; + } + return (dup); +} + +static int quote_state_change(int *quote_state, const char *s) +{ + if (s[0] == '\'' && *quote_state != IN_DQUOTES) + { + if (*quote_state == IN_QUOTES) + *quote_state = 0; + else if (ft_strchr(&s[1], '\'')) // if closed quotes + *quote_state = IN_QUOTES; + else + return (0); + return (1); + } + else if (s[0] == '\"' && *quote_state != IN_QUOTES) + { + if (*quote_state == IN_DQUOTES) + *quote_state = 0; + else if (ft_strchr(&s[1], '\"')) // if closed quotes + *quote_state = IN_DQUOTES; + else + return (0); + return (1); + } + return (0); +} diff --git a/srcs/parsing/expansions/new_token_for_each_field.c b/srcs/parsing/expansions/new_token_for_each_field.c new file mode 100644 index 0000000..38298b9 --- /dev/null +++ b/srcs/parsing/expansions/new_token_for_each_field.c @@ -0,0 +1,69 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* new_token_for_each_field.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/07 02:01:33 by lperrey #+# #+# */ +/* Updated: 2021/11/07 04:33:04 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +t_list *ft_lstnew_generic(size_t lst_sizse, size_t content_size); + +static t_token *insert_tokens(t_token *t, t_token *insert_lst); + +int new_token_for_each_field(char **fields, t_token **t) +{ + t_token head; + t_token *insert_lst; + int i; + + head.next = NULL; + insert_lst = &head; + i = 0; + while (fields[i]) + { + if (fields[i][0]) + { + insert_lst->next = (t_token *)ft_lstnew_generic(sizeof(t_token), 0); + insert_lst = insert_lst->next; + if (!insert_lst) + {//todo wrap + perror("insert_token_for_each_field() error"); + ft_free_2d_arr(fields); + return ((int)ft_lstclear((t_list **)&head.next, NULL)); + } + insert_lst->content = fields[i]; + insert_lst->id = T_WORD; + } + else + free(fields[i]); + i++; + } + free(fields); + *t = insert_tokens(*t, head.next); + return (1); +} + +static t_token *insert_tokens(t_token *t, t_token *insert_lst) +{ + t_token *tmp; + t_token *insert_lst_last; + + t->id = 0; + free(t->content); + t->content = NULL; + if (!insert_lst) + return (t); + + tmp = t->next; + t->next = insert_lst; + insert_lst_last = (t_token *)ft_lstlast((t_list *)insert_lst); + insert_lst_last->next = tmp; + + return (insert_lst_last); +} diff --git a/srcs/parsing/expansions/rejoin_after_expand.c b/srcs/parsing/expansions/rejoin_after_expand.c new file mode 100644 index 0000000..c56c98b --- /dev/null +++ b/srcs/parsing/expansions/rejoin_after_expand.c @@ -0,0 +1,39 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* rejoin_after_expand.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/07 02:01:33 by lperrey #+# #+# */ +/* Updated: 2021/11/07 04:03:02 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +char *rejoin_after_expand(t_list *expand_lst) +{ + t_list *head; + char *result; + + head = expand_lst; + result = ft_calloc(1, 1); + if (!result) + {//todo wrap + perror("rejoin_after_expand() error"); + return (ft_lstclear(&head, free)); + } + while (expand_lst) + { + result = ft_strjoinfree_s1(result, expand_lst->content); + if (!result) + {//todo wrap + perror("rejoin_after_expand() error"); + return (ft_lstclear(&head, free)); + } + expand_lst = expand_lst->next; + } + ft_lstclear(&head, free); + return (result); +} diff --git a/srcs/parsing/expansions/words_expansions.c b/srcs/parsing/expansions/words_expansions.c new file mode 100644 index 0000000..a802bee --- /dev/null +++ b/srcs/parsing/expansions/words_expansions.c @@ -0,0 +1,75 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* words_expansions.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/07 02:01:33 by lperrey #+# #+# */ +/* Updated: 2021/11/16 03:45:15 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +enum e_in_quote_state +{ + NOT_IN = 0, + IN_QUOTES = '\'', + IN_DQUOTES = '\"' +}; + +t_list *ft_lstnew_generic(size_t lst_sizse, size_t content_size); +t_list *expand_token(char *content); +char *rejoin_after_expand(t_list *expand_lst); +int new_token_for_each_field(char **fields, t_token **t); + +// 1 - chaque bout dans un element d'une t_list +// (telle quelle si non expand, ou VARIABLE de env) +// 2 - strjoin() le tout +// 3 - split avec un ft_strplit() modifié (ne splitant pas dans les quotes) +// 4 - quotes removal, ft_strdup_quotes() le tableau split +// 5 - creer un token T_WORD pour chaque *string du **split_arr +// (ft_lstadd_front() sur le token original, puis set le token orignal à : +// t->id = 0 ; free(t->content) ; t->content = NULL ; pour qu'il soit ignoré sur la suite du parsing) + +int words_expansions(t_token *token_list) +{ + while (token_list) + { + if (token_list->id == T_WORD) + token_expansions(&token_list); + token_list = token_list->next; + } + return (1); +} + +int token_expansions(t_token **t) +{ + void *tmp; + char **tmp_split; + + // 1 + tmp = expand_token((*t)->content); + if (!tmp) + return (0); + // 2 + tmp = rejoin_after_expand(tmp); + if (!tmp) + return (0); + // 3 + tmp_split = ft_split_quotes(tmp, ' '); + free(tmp); + if (!tmp_split) + return (0); + // 4 + tmp = ft_dup_2d_arr(tmp_split, (t_dup_f)ft_strdup_quotes); + ft_free_2d_arr(tmp_split); + tmp_split = tmp; + if (!tmp_split) + return (0); + // 5 + if (!new_token_for_each_field(tmp_split, t)) + return (0); + return (1); +} diff --git a/srcs/parsing/parsing.c b/srcs/parsing/parsing.c index d8823a7..8028768 100644 --- a/srcs/parsing/parsing.c +++ b/srcs/parsing/parsing.c @@ -6,261 +6,92 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/24 10:52:40 by lperrey #+# #+# */ -/* Updated: 2021/11/11 13:11:55 by hulamy ### ########.fr */ +/* Updated: 2021/11/16 21:18:27 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ #include "minishell.h" -size_t count_pipes(t_token *token); -t_cmd **create_cmd(t_token *token_list, size_t cmd_nbr); -void handle_argv(t_token *token, t_cmd **cmd, size_t cmd_nbr); +// HUGO WIP void handle_path(t_cmd **cmd_arr, char **envp); -void handle_fd(t_token *token, t_cmd **cmd_arr); -void fd_heredoc(t_token *token, t_cmd *cmd); -void fd_redirection(t_token *token, t_cmd *cmd); void find_path(char **argv, char **envp); int handle_builtin(t_cmd *cmd); int fill_builtin(t_cmd *cmd, int (*builtin)(int, char **, t_all *)); -int next_cmd(t_token *token); -int is_redirection(enum e_token_id id); +// HUGO WIP -t_cmd **parsing(t_token *token_list, char **envp) +void save_redirections_words(t_token *t) +{ + while (t) + { + if (t->id == '>' || t->id == T_DGREAT + || t->id == '<' || t->id == T_DLESS) + { + t = t->next; + t->id = T_REDIRECTION_WORD; + } + t = t->next; + } +} + +void print_cmd_array(t_cmd **cmd_arr) +{ + int i; + + i = 0; + while (cmd_arr[i]) + { + printf("CMD %i, fd_in=%i, fd_out=%i\n", i, cmd_arr[i]->fd_in, cmd_arr[i]->fd_out); + ft_putstr_fd(" |", 1); + print_matrix(cmd_arr[i]->argv, "|\n |"); + i++; + if (cmd_arr[i]) + ft_putstr_fd("----------------\n", 1); + } +} + +t_cmd **parsing(t_token *token_list) { t_cmd **cmd_arr; - size_t cmd_nbr; if (!valid_syntax(token_list)) return (NULL); - cmd_nbr = count_pipes(token_list); - cmd_arr = create_cmd(token_list, cmd_nbr); -// cmd_expansion(cmd_arr, envp); - handle_argv(token_list, cmd_arr, cmd_nbr); - handle_path(cmd_arr, envp); - handle_fd(token_list, cmd_arr); + + // 2.9.1 - 1) Save Words + save_redirections_words(token_list); + + // 2.9.1 - 2) Expansion + // TEST TOKENS PRINT + //ft_putstr_fd("TOKENS LIST :\n-----------\n", 1); + //ft_lstprint((t_list *)token_list, 1); + // + // getenv() ne va pas fonctionner avec le changement d'environnement prévu jusqu'ici. + // TODO : Revoir le changement d'environnement (avec extern char **environ ?) + // OU Integrer un equivalent perso comme dans pipex + if (!words_expansions(token_list)) + return (NULL); + // + //ft_putstr_fd("TOKENS LIST EXPANDED :\n-----------\n", 1); + //ft_lstprint((t_list *)token_list, 1); + + // Struct CMD alloc + cmd_arr = cmd_array_alloc(1 + count_pipes(token_list)); + if (!cmd_arr) + return (NULL); + + // 2.9.1 - 3) Redirection + if (!redirections(token_list, cmd_arr)) + return (ft_retp_free(NULL, &cmd_arr, (t_free_f)free_pipeline)); + + // Struct CMD fill + if (!cmd_array_fill_argv(token_list, cmd_arr)) + return (ft_retp_free(NULL, &cmd_arr, (t_free_f)free_pipeline)); + print_cmd_array(cmd_arr); + + // HUGO WIP +// handle_path(cmd_arr, envp); return (cmd_arr); } -size_t count_pipes(t_token *token) -{ - size_t nb; - - nb = 0; - while (token) - { - if (token->id == T_PIPE) - nb++; - token = token->next; - } - return (nb + 1); -} - -t_cmd **create_cmd(t_token *token_list, size_t cmd_nbr) -{ - t_cmd **cmd_arr; - size_t i; - - (void)token_list; - cmd_arr = ft_calloc(cmd_nbr + 1, sizeof(t_cmd *)); - cmd_arr[cmd_nbr] = NULL; - i = 0; - while (i < cmd_nbr) - { - cmd_arr[i] = ft_calloc(1, sizeof(t_cmd)); - ft_bzero(cmd_arr[i], sizeof(t_cmd)); - i++; - } - return (cmd_arr); -} - -int is_redirection(enum e_token_id id) -{ - if (id == T_LESS) // < - return (1); - else if (id == T_GREAT) // > - return (1); - else if (id == T_DLESS) // << - return (1); - else if (id == T_DGREAT) // >> - return (1); - else - return (0); -} - -// count nbr word in cmd, minus redirection and heredoc -int next_cmd(t_token *token) -{ - int i; - - i = 0; - while (token && token->id != T_PIPE) - { - if (is_redirection(token->id)) - i--; - else - i++; - token = token->next; - } - if (token && token->id == T_PIPE) - token = token->next; - return (i); -} - -void handle_argv(t_token *token, t_cmd **cmd, size_t cmd_nbr) -{ - int argc; - int j; - int i; - int redirection; - - i = 0; - while (cmd_nbr) - { - argc = next_cmd(token); - cmd[i]->argv = calloc(argc + 1, sizeof(char *)); - cmd[i]->argv[argc] = NULL; - j = 0; - redirection = is_redirection(token->id); - while (token && token->id != T_PIPE) - { - if (!redirection && token->id == T_WORD) - { - cmd[i]->argv[j] = ft_strdup(token->content); - j++; - } - redirection = is_redirection(token->id); - token = token->next; - } - if (token && token->id == T_PIPE) - token = token->next; - cmd_nbr--; - i++; - } -} - -int fill_builtin(t_cmd *cmd, int (*builtin)(int, char **, t_all *)) -{ - cmd->builtin_command = builtin; - return (1); -} - -int handle_builtin(t_cmd *cmd) -{ - if (!ft_strncmp(cmd->argv[0], "echo", 4)) - return (fill_builtin(cmd, builtin_echo)); - else if (!ft_strncmp(cmd->argv[0], "cd", 2)) - return (fill_builtin(cmd, &builtin_cd)); - else if (!ft_strncmp(cmd->argv[0], "pwd", 3)) - return (fill_builtin(cmd, builtin_pwd)); - else if (!ft_strncmp(cmd->argv[0], "export", 6)) - return (fill_builtin(cmd, &builtin_export)); - else if (!ft_strncmp(cmd->argv[0], "unset", 5)) - return (fill_builtin(cmd, &builtin_unset)); - else if (!ft_strncmp(cmd->argv[0], "env", 3)) - return (fill_builtin(cmd, builtin_env)); - else if (!ft_strncmp(cmd->argv[0], "exit", 4)) - return (fill_builtin(cmd, builtin_exit)); - return (0); -} - -void find_path(char **argv, char **envp) -{ - int i; - char **path; - char *cmd; - - i = 0; - while (envp[i] && ft_strncmp(envp[i], "PATH=", 5)) - i++; - path = ft_split(envp[i] + 5, ':'); // 5 = lentgh of "PATH=" - i = -1; - while (*path && i != 0) - { - cmd = ft_strjoin(path[0], "/"); - cmd = ft_strjoin(cmd, argv[0]); - i = access(cmd, X_OK); - path++; - } - if (!(*path)) - exit(0); // gerer erreur - argv[0] = cmd; -} - -void handle_path(t_cmd **cmd_arr, char **envp) -{ - int i; - - i = 0; - while (cmd_arr[i]) - { - if (!handle_builtin(cmd_arr[i])) - find_path(cmd_arr[i]->argv, envp); - i++; - } -} - -void fd_redirection(t_token *token, t_cmd *cmd) -{ - int flag; - - if (token->id == T_LESS) // '<' - { - flag = O_RDONLY | O_CREAT; - if (cmd->fd_in != 0) - close(cmd->fd_in); - cmd->fd_in = open(token->next->content, flag); - } - else if (token->id == T_GREAT) // '>' - { - flag = O_WRONLY | O_CREAT | O_TRUNC; - cmd->fd_out = open(token->next->content, flag, S_IRWXU); - } - else if (token->id == T_DGREAT) // '>>' - { - flag = O_WRONLY | O_CREAT | O_APPEND; - cmd->fd_out = open(token->next->content, flag, S_IRWXU); - } -} - -void fd_heredoc(t_token *token, t_cmd *cmd) -{ - (void)token; - (void)cmd; -} - -void handle_fd(t_token *token, t_cmd **cmd_arr) -{ - int *pipes_fd; - int i; - - i = 0; - while (cmd_arr[i]) - { - cmd_arr[i]->fd_out = 1; - while (token && token->id != T_PIPE) - { - if (token->id == T_DGREAT) // '<<' - fd_heredoc(token, cmd_arr[i]); - else - fd_redirection(token, cmd_arr[i]); - token = token->next; - } - if (token && token->id == T_PIPE) - { - token = token->next; - pipes_fd = calloc(2, sizeof(int)); - pipe(pipes_fd); - if (cmd_arr[i]->fd_out == 1) - cmd_arr[i]->fd_out = pipes_fd[1]; - else - close(pipes_fd[1]); - cmd_arr[i + 1]->fd_in = pipes_fd[0]; - } - i++; - } -} - - /* ------------------------------------------------------- The grammar symbols ------------------------------------------------------- */ diff --git a/srcs/parsing/redirections/here_doc.c b/srcs/parsing/redirections/here_doc.c new file mode 100644 index 0000000..8fe3dee --- /dev/null +++ b/srcs/parsing/redirections/here_doc.c @@ -0,0 +1,114 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* here_doc.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/11 18:46:43 by lperrey #+# #+# */ +/* Updated: 2021/11/16 22:29:01 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +#define TMP_HERE_DOC "/tmp/minishell_here_doc" + +static int here_doc_write(char *delimiter, int doc_fd); + +int here_doc(char *delimiter) +{ + // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04 + // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 + /* If any part of word is quoted, + the delimiter shall be formed by performing quote removal on word, + and the here-document lines shall not be expanded. + Otherwise, the delimiter shall be the word itself. */ + // TODO : A voir si on fait les expansions de variables dans le here_doc. + // implementer une gestion des signaux pour here_doc (verifier comportement bash et doc POSIX). + // Peut-être remplacer gnl() par readline() pour avoir une gestion correct + // du terminal (actuellement l'affichage lors du changement de ligne est foireux). + int here_doc; + + here_doc = open(TMP_HERE_DOC, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); + if (here_doc == -1) + return (ft_reti_perror_io(-1, "open() ", TMP_HERE_DOC)); + delimiter = ft_strdup_quotes(delimiter); + if (!delimiter) + return (ft_reti_perror(-1, "ft_strdup_quotes()")); + if (!here_doc_write(delimiter, here_doc)) + { + free(delimiter); + return (0); + } + free(delimiter); + if (close(here_doc) == -1) + ft_perror_io("close() ", TMP_HERE_DOC); + here_doc = open(TMP_HERE_DOC, O_RDONLY); + if (here_doc == -1) + ft_perror_io("open() ", TMP_HERE_DOC); + if (unlink(TMP_HERE_DOC) == -1) + return (ft_reti_perror_io(-1, "unlink() ", TMP_HERE_DOC)); + return (here_doc); +} + +static int here_doc_write(char *delimiter, int doc_fd) +{ + char *line; + size_t line_count; + + line_count = 0; + while (1) + { + line_count++; + line = NULL; + line = readline("> "); + if (!line) + { // TODO : error print wrapper + ft_putstr_fd("minishell: ", 2); + ft_putstr_fd("warning: here-document at line ", 2); + ft_putnbr_fd(line_count, 2); + ft_putstr_fd(" delimited by end-of-file (wanted `", 2); + ft_putstr_fd(delimiter, 2); + ft_putstr_fd("')\n", 2); + return (0); + } + if (ft_strncmp(line, delimiter, ft_strlen(line) + 1) == 0) // Ou ft_strlen(delimiter) + 1 ? Ça devrais être identique et ça peux se calculer une seul fois. + break ; + if (write(doc_fd, line, ft_strlen(line)) == -1) + return (ft_reti_perror_free(0, line, free, "write() "TMP_HERE_DOC)); + if (write(doc_fd, "\n", 1) == -1) + return (ft_reti_perror_free(0, line, free, "write() "TMP_HERE_DOC)); + free(line); + } + free(line); + return (1); +} + +/* +static int here_doc_write(char *delimiter, int doc_fd) +{ + char *line; + int ret; + + line = NULL; + ret = 1; + while (ret) + { + ret = gnl(STDIN_FILENO, &line, 0); + if (ret == -1) + return (ft_reti_perror_free(0, line, free, "gnl() STDIN")); + if (ft_strncmp(line, delimiter, ft_strlen(line) + 1) == 0) // Ou ft_strlen(delimiter) + 1 ? Ça devrais être identique et ça peux se calculer une seul fois. + break ; + if (write(doc_fd, line, ft_strlen(line)) == -1) + return (ft_reti_perror_free(0, line, free, "write() "TMP_HERE_DOC)); + if (write(doc_fd, "\n", 1) == -1) + return (ft_reti_perror_free(0, line, free, "write() "TMP_HERE_DOC)); + free(line); + line = NULL; + } + free(line); + gnl(STDIN_FILENO, NULL, 1); + return (1); +} + */ diff --git a/srcs/parsing/redirections/redirections.c b/srcs/parsing/redirections/redirections.c new file mode 100644 index 0000000..2855c9e --- /dev/null +++ b/srcs/parsing/redirections/redirections.c @@ -0,0 +1,99 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* redirections.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/11 18:46:43 by lperrey #+# #+# */ +/* Updated: 2021/11/16 22:29:52 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +int here_doc(char *delimiter); + +static int redirect_cmd_input(t_token *t, t_cmd *cmd); +static int redirect_cmd_output(t_token *t, t_cmd *cmd); + +int redirections(t_token *t, t_cmd **cmd_arr) +{ + int i; + + i = 0; + while (t) + { + if (!cmd_arr[i]->error) + { + if (t->id == '<' || t->id == T_DLESS) + { + if (!redirect_cmd_input(t, cmd_arr[i])) + return (0); + } + else if (t->id == '>' || t->id == T_DGREAT) + { + if (!redirect_cmd_output(t, cmd_arr[i])) + return (0); + } + } + else if (t->id == '|') + i++; + t = t->next; + } + return (1); +} + +static int redirect_cmd_input(t_token *t, t_cmd *cmd) +{ + if (cmd->fd_in != STDIN_FILENO) + if (close(cmd->fd_in) == -1) + perror("close()"); + if (t->id == '<') + { + // TODO : Expansion + quote removal sur le word t->next->content. + // si plus d'un champ ou aucun champ aprés expansion, + // message d'erreur comme bash "bash: $VAR: ambiguous redirect" + // OU prise en compte seulement du premier champ. + //EXPAND_AND_QUOTE_REMOVAL_PLACEHOLDER(); + cmd->fd_in = open(t->next->content, O_RDONLY); + if (cmd->fd_in == -1) + { + ft_perror_io("open() ", t->next->content); // todo error + cmd->error = 42; // WIP error status + } + } + else if (t->id == T_DLESS) + { + cmd->fd_in = here_doc(t->next->content); + if (cmd->fd_in == -1) + return (ft_reti_print(0, "minishell: heredoc error\n", 2)); + } + return (1); +} + +static int redirect_cmd_output(t_token *t, t_cmd *cmd) +{ + int flags; + + if (cmd->fd_out != STDOUT_FILENO) + if (close(cmd->fd_out) == -1) + perror("close()"); + // TODO : Expansion + quote removal sur le word t->next->content. + // si plus d'un champ ou aucun champ aprés expansion, + // message d'erreur comme bash "bash: $VAR: ambiguous redirect" + // OU prise en compte seulement du premier champ. + //EXPAND_AND_QUOTE_REMOVAL_PLACEHOLDER(); + flags = O_WRONLY | O_CREAT; + if (t->id == '>') + flags = flags | O_TRUNC; + else if (t->id == T_DGREAT) + flags = flags | O_APPEND; + cmd->fd_out = open(t->next->content, flags, S_IRWXU); + if (cmd->fd_out == -1) + { + ft_perror_io("open() ", t->next->content); + cmd->error = 42; // WIP error status + } + return (1); +} diff --git a/srcs/parsing/valid_command.c b/srcs/parsing/valid_syntax/valid_command.c similarity index 100% rename from srcs/parsing/valid_command.c rename to srcs/parsing/valid_syntax/valid_command.c diff --git a/srcs/parsing/valid_io_redirect.c b/srcs/parsing/valid_syntax/valid_io_redirect.c similarity index 100% rename from srcs/parsing/valid_io_redirect.c rename to srcs/parsing/valid_syntax/valid_io_redirect.c diff --git a/srcs/parsing/valid_pipeline.c b/srcs/parsing/valid_syntax/valid_pipeline.c similarity index 100% rename from srcs/parsing/valid_pipeline.c rename to srcs/parsing/valid_syntax/valid_pipeline.c diff --git a/srcs/parsing/valid_syntax.c b/srcs/parsing/valid_syntax/valid_syntax.c similarity index 100% rename from srcs/parsing/valid_syntax.c rename to srcs/parsing/valid_syntax/valid_syntax.c diff --git a/srcs/shell_loop.c b/srcs/shell_loop.c index 5e37a5b..f60c5b0 100644 --- a/srcs/shell_loop.c +++ b/srcs/shell_loop.c @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/04 05:59:26 by lperrey #+# #+# */ -/* Updated: 2021/11/16 13:12:52 by hulamy ### ########.fr */ +/* Updated: 2021/11/17 01:30:27 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -24,82 +24,30 @@ void shell_loop(t_all *c) { if (line_input) free(line_input); + c->signal_behaviour.sa_handler = sigint_handler_interactive; + sigaction(SIGINT, &c->signal_behaviour, NULL); line_input = readline(c->prompt); if (line_input && *line_input) { + c->signal_behaviour.sa_handler = SIG_IGN; + sigaction(SIGINT, &c->signal_behaviour, NULL); add_history(line_input); + // Lexing c->token_list = input_to_tokens(line_input); - c->cmd_arr = parsing(c->token_list, c->envp); - execute_cmd(c->envp, c->cmd_arr, c); + if (!c->token_list) + continue ; + // Parsing + c->cmd_arr = parsing(c->token_list); ft_lstclear((t_list **)&c->token_list, free); + if (!c->cmd_arr) + continue ; + // Exec Pipeline + exec_cmd_line(c); } else if (!line_input) { write(1, "exit\n", 5); - exit(0); + free_exit(c, c->last_exit_status); } } } - -void close_fd(t_cmd *cmd) -{ - if (cmd->fd_in != 0) - close(cmd->fd_in); - if (cmd->fd_out != 1) - close(cmd->fd_out); -} - -void execute_cmd(char **envp, t_cmd **cmd_arr, t_all *c) -{ - pid_t pid; - pid_t wpid; - int wstatus; - int i; - int argc; - - // put signal handling for SIGINT to ignore so parent process will not activate signal_handling_executiv while childs are in process - c->signal_behaviour.sa_handler = SIG_IGN; - sigaction(SIGINT, &c->signal_behaviour, NULL); - i = 0; - while(cmd_arr[i]) - { - pid = fork(); - if (pid == 0) - { - // activate singal handling for execution mode - c->signal_behaviour.sa_handler = sigint_handler_execution; - sigaction(SIGINT, &c->signal_behaviour, NULL); - if (cmd_arr[i]->fd_in != 0) - dup2(cmd_arr[i]->fd_in, STDIN_FILENO); - if (cmd_arr[i]->fd_out != 1) - dup2(cmd_arr[i]->fd_out, STDOUT_FILENO); - close_fd(cmd_arr[i]); - if (cmd_arr[i]->builtin_command) - { - argc = 0; - while (cmd_arr[i]->argv[argc]) - argc++; - cmd_arr[i]->builtin_command(argc, cmd_arr[i]->argv, c); - exit(0); - } - else - { - write(1, "1", 1); - execve(cmd_arr[i]->argv[0], cmd_arr[i]->argv, envp); - } - } - else - close_fd(cmd_arr[i]); - i++; - } - // waitpid pour la derniere commande (pour '$?') - wpid = 1; - while (wpid > 0) - wpid = wait(&wstatus); - // to print a \n after execve was terminated by a signal - if (WIFSIGNALED(wstatus)) - write(1, "\n", 1); - // put signal handling for sigint back to the signal handler for interactiv mode - c->signal_behaviour.sa_handler = sigint_handler_interactiv; - sigaction(SIGINT, &c->signal_behaviour, NULL); -} diff --git a/srcs/signals.c b/srcs/signals.c index 35b7d43..b04dfc0 100644 --- a/srcs/signals.c +++ b/srcs/signals.c @@ -6,31 +6,24 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/23 18:56:53 by lperrey #+# #+# */ -/* Updated: 2021/11/15 20:08:26 by hulamy ### ########.fr */ +/* Updated: 2021/11/16 22:58:29 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ #include "minishell.h" -void sigint_handler_interactiv(int signum) +void sigint_handler_interactive(int signum) { (void)signum; write(1, "\n", 1); - rl_replace_line("", 1); rl_on_new_line(); + rl_replace_line("", 1); rl_redisplay(); } -void sigint_handler_execution(int signum) -{ - (void)signum; - write(1, "\n", 1); -// exit(0); -} - int set_signals_handling(struct sigaction *signal_behaviour) { - signal_behaviour->sa_handler = sigint_handler_interactiv; + signal_behaviour->sa_handler = sigint_handler_interactive; sigaction(SIGINT, signal_behaviour, NULL); signal_behaviour->sa_handler = SIG_IGN; sigaction(SIGQUIT, signal_behaviour, NULL); diff --git a/test_rl_base.c b/test_rl_base.c deleted file mode 100644 index 02d291f..0000000 --- a/test_rl_base.c +++ /dev/null @@ -1,29 +0,0 @@ -# include -# include -# include - -int main(int argc, char *argv[], char *envp[]) -{ - (void)argc; - (void)argv; - char *line_input; - char *prompt; - - line_input = NULL; - prompt = strdup("\e[0;31mtest>\e[0m "); - while (1) - { - if (line_input) - free(line_input); - line_input = readline(prompt); - if (line_input && *line_input) - { - write(1, line_input, strlen(line_input)); - write(1, "\n", 1); - } - else if (!line_input) - write(1, "\n", 1); - } - - return (0); -} diff --git a/test_rl_modif.c b/test_rl_modif.c deleted file mode 100644 index a043aa7..0000000 --- a/test_rl_modif.c +++ /dev/null @@ -1,98 +0,0 @@ -# include -# include -# include -# include -# include - -void handler_sigint(int id) -{ - (void)id; - write(1, "\n", 1); - rl_replace_line("", 1); - rl_on_new_line(); - rl_redisplay(); -} - -void handler_sigint_execution(int id) -{ - (void)id; - write(1, "\n", 1); - exit(0); -} - -int main(int argc, char *argv[], char *envp[]) -{ - (void)argc; - (void)argv; - char *line_input; - char *prompt; - pid_t pid; - char **argvtmp; - int wstatus; - - signal(SIGINT, handler_sigint); // signal handling for SINGINT while interactive mode - line_input = NULL; - prompt = strdup("\e[0;31m>\e[0m "); - while (1) - { - if (line_input) - free(line_input); - line_input = readline(prompt); - if (line_input && *line_input) - { - signal(SIGINT, SIG_IGN); // stop signal handling for SIGINT because end of interactive mode - pid = fork(); - if (pid == 0) - { - signal(SIGINT, handler_sigint_execution); // start signal handling for SIGINT in child process - if (!strncmp("sleep", line_input, 5)) - { - argvtmp = malloc(sizeof(char*) * 3); - argvtmp[0] = strdup("sleep"); - argvtmp[1] = strdup("2"); - argvtmp[2] = NULL; - execve("/bin/sleep", argvtmp, envp); - } - else if (!strncmp("echo", line_input, 4)) - { - write(1, "3", 2); - sleep(1); - write(1, "\b2", 2); - sleep(1); - write(1, "\b1", 2); - sleep(1); - write(1, "\b0\n", 3); - execve("/bin/echo", argv, envp); - } - else - { - write(1, line_input, strlen(line_input)); - write(1, " 3", 2); - sleep(1); - write(1, "\b2", 2); - sleep(1); - write(1, "\b1", 2); - sleep(1); - write(1, "\b0\n", 3); - exit(0); - } - } - else - { - wait(&wstatus); - if (WIFEXITED(wstatus)) - write(1, "the child terminated normally\n", 30); - if (WIFSIGNALED(wstatus)) - write(1, "the child was terminated by a signal\n", 37); - } - signal(SIGINT, handler_sigint); // restart signal handling for SIGINT because re-entring in interactive mode - } - else if (!line_input) - { - write(1, "exit\n", 5); - exit(0); - } - } - - return (0); -}