diff --git a/Makefile b/Makefile index 15c39f6..9098e9f 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ SRCS = $(SRC_DIR)/main.c \ $(SRC_DIR)/exec/execute_utils.c \ $(SRC_DIR)/parser/create_default_pipeline_node.c \ $(SRC_DIR)/parser/parser.c \ - $(SRC_DIR)/parser/remove_cmd_arg.c \ + $(SRC_DIR)/parser/parser_utils.c \ $(SRC_DIR)/parser/replace_vars.c \ $(SRC_DIR)/parser/replace_wildcards.c \ $(SRC_DIR)/parser/set_redirections.c \ @@ -54,6 +54,7 @@ OBJS = $(SRCS:.c=.o) # Include files INCS = $(INC_DIR)/environment.h \ $(INC_DIR)/execute.h \ + $(INC_DIR)/messages.h \ $(INC_DIR)/minishell.h \ $(INC_DIR)/parser.h \ $(INC_DIR)/signals.h \ diff --git a/include/messages.h b/include/messages.h new file mode 100644 index 0000000..94437e2 --- /dev/null +++ b/include/messages.h @@ -0,0 +1,47 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* messages.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 10:21:05 by sehosaf #+# #+# */ +/* Updated: 2024/07/18 21:05:21 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef MESSAGES_H +# define MESSAGES_H + +# define PROMPT "\033[0;36mminishell\033[0m \033[0;32m> \033[0m" + +// ** Error messages ** +# define ERR_GENERIC "\033[0;31mError: \033[0m" +# define ERR_MALLOC "minishell: malloc failed" +# define ERR_PERM "Permission denied" + +// ** Syntax error messages ** +# define ERR_SNX_TOKEN "minishell: syntax error near unexpected token `" +# define ERR_SNX_EOF "minishell: syntax error: unexpected end of file " + +// ** Built-in commands messages ** +# define ERR_NO_HOME "minishell: cd: HOME not set " +# define ERR_NO_CD "minishell: cd: can't cd to " +# define ERR_RET_CWD "minishell: cd: error retrieving current directory " +# define ERR_MANY_ARGS "minishell: exit: too many arguments " +# define ERR_PWD "minishell: pwd: error " + +// ** Execution messages ** +# define ERR_IS_DIR "minishell: is a directory: " +# define ERR_FORK "minishell: fork failed " +# define ERR_EXEC "minishell: execve failed " +# define ERR_ENV "minishell: environment list is empty " +# define ERR_INPUT_FILE "minishell: input file error: " +# define ERR_OUTPUT_FILE "minishell: output file error: " +# define ERR_PIPE "minishell: pipe error: " + +// ** Signals messages ** +# define ERR_SIGINT "minishell: sigaction: SIGINT " +# define ERR_SIGQUIT "minishell: sigaction: SIGQUIT " + +#endif diff --git a/include/minishell.h b/include/minishell.h index 5c51f02..05d0f4e 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -6,7 +6,7 @@ /* By: dmoroz +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/11 20:37:44 by sehosaf #+# #+# */ -/* Updated: 2024/07/10 15:51:34 by dmoroz ### ########.fr */ +/* Updated: 2024/07/17 14:23:21 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -29,6 +29,7 @@ # include # include # include "libft.h" +# include "messages.h" /* t_command struct represent command which has to be executed @@ -59,12 +60,12 @@ typedef enum e_connection typedef struct s_command { char **args; - t_connection connection_type; + t_connection conn_type; int is_heredoc; char *limiter; char *infile; char *outfile; - int outfile_append_mode; + int ap_mode; } t_command; typedef struct s_pipeline @@ -106,6 +107,4 @@ void free_pipeline(t_pipeline *p); void interactive_signal_handlers(void); void non_interactive_signal_handlers(void); -# define PROMPT "\033[0;36mminishell\033[0m \033[0;32m> \033[0m" - #endif diff --git a/include/parser.h b/include/parser.h index 2ba2884..b0b674d 100644 --- a/include/parser.h +++ b/include/parser.h @@ -1,3 +1,15 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parser.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 09:26:08 by sehosaf #+# #+# */ +/* Updated: 2024/07/18 17:19:48 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #ifndef PARSER_H # define PARSER_H @@ -7,9 +19,11 @@ char **split_line(char *line); void split_tokens_per_command(t_pipeline *start, char **tokens); t_pipeline *create_default_pipeline_node(void); -void set_redirections(t_pipeline *node); +int set_redirections(t_pipeline *node); void remove_cmd_arg(t_pipeline *node, int ind); void replace_vars(t_pipeline *node, t_shell *shell); void replace_wildcards(t_pipeline *node); +char *get_var_name(char *dollar); +char *get_var_value(const char *name, t_shell *shell); #endif diff --git a/libft/libft/libft.h b/libft/libft/libft.h index fbba8c3..19e76e4 100644 --- a/libft/libft/libft.h +++ b/libft/libft/libft.h @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/02/26 18:53:52 by dmoroz #+# #+# */ -/* Updated: 2024/06/12 10:32:48 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 20:42:46 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -42,8 +42,8 @@ size_t ft_strlcat(char *dst, const char *src, size_t size); char *ft_strchr(const char *s, int c); char *ft_strrchr(const char *s, int c); char *ft_strnstr(const char *str, const char *sub, size_t len); -int ft_strcmp(const char *s1, const char *s2); -int ft_strncmp(const char *s1, const char *s2, size_t n); +int ft_strcmp(const char *s1, const char *s2); +int ft_strncmp(const char *s1, const char *s2, size_t n); int ft_atoi(const char *str); size_t ft_strlcpy(char *dst, const char *src, size_t size); char *ft_substr(char const *s, unsigned int start, size_t len); diff --git a/src/builtin/cmd_cd.c b/src/builtin/cmd_cd.c index 924454d..f7b1f0c 100644 --- a/src/builtin/cmd_cd.c +++ b/src/builtin/cmd_cd.c @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/10 20:37:41 by sehosaf #+# #+# */ -/* Updated: 2024/06/19 21:03:35 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 11:30:10 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -31,7 +31,7 @@ int cmd_cd(t_shell *shell, char **args) change_to = get_env_val(shell->env, "HOME"); if (change_to == NULL) { - ft_putendl_fd("minishell: cd: HOME not set", 2); + ft_putendl_fd(ERR_NO_HOME, 2); return (EXIT_FAILURE); } } @@ -43,7 +43,7 @@ int cmd_cd(t_shell *shell, char **args) old_pwd = getcwd(NULL, 0); if (chdir(change_to) != 0) { - ft_putstr_fd("minishell: cd: can't cd to ", 2); + ft_putstr_fd(ERR_NO_CD, 2); ft_putendl_fd(change_to, 2); return (free(old_pwd), EXIT_FAILURE); } @@ -52,7 +52,7 @@ int cmd_cd(t_shell *shell, char **args) static bool is_home_keyword(const char *arg) { - if (arg[0] == '~' && (arg[1] == '\0')) + if (arg[0] == '~' && arg[1] == '\0') return (true); else if (ft_strcmp(arg, "--") == 0) return (true); @@ -70,7 +70,7 @@ static int update_pwd_env(t_shell *shell, char *old_pwd) new_pwd = getcwd(NULL, 0); if (new_pwd == NULL) { - ft_putendl_fd("minishell: cd: error retrieving current directory", 2); + ft_putendl_fd(ERR_RET_CWD, 2); return (free(old_pwd), EXIT_FAILURE); } if (set_env_var(shell->env, "OLDPWD", old_pwd) == EXIT_FAILURE) diff --git a/src/builtin/cmd_exit.c b/src/builtin/cmd_exit.c index 78786c6..ff5e982 100644 --- a/src/builtin/cmd_exit.c +++ b/src/builtin/cmd_exit.c @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/09 19:04:21 by sehosaf #+# #+# */ -/* Updated: 2024/06/24 21:06:54 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 11:32:13 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -24,11 +24,11 @@ int cmd_exit(t_shell *shell, char **args, t_connection ct) shell->exit_status = EXIT_SUCCESS; else if (args[2]) { - ft_putendl_fd("minishell: exit: too many arguments", STDERR_FILENO); + ft_putendl_fd(ERR_MANY_ARGS, STDERR_FILENO); return (EXIT_FAILURE); } if (is_number(args[1])) - shell->exit_status = ft_atol(args[1]); + shell->exit_status = (signed int)ft_atol(args[1]); else if (args[1] && !is_number(args[1])) { ft_putstr_fd("minishell: exit: ", STDERR_FILENO); diff --git a/src/builtin/cmd_pwd.c b/src/builtin/cmd_pwd.c index c05f201..8ad9d16 100644 --- a/src/builtin/cmd_pwd.c +++ b/src/builtin/cmd_pwd.c @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/02 14:08:08 by sehosaf #+# #+# */ -/* Updated: 2024/06/19 20:53:20 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 11:33:39 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,7 @@ int cmd_pwd(void) if (getcwd(cwd, PATH_MAX) == NULL) { - ft_putendl_fd("minishell: pwd: error", STDERR_FILENO); + ft_putendl_fd(ERR_PWD, STDERR_FILENO); return (EXIT_FAILURE); } return (ft_putendl_fd(cwd, STDOUT_FILENO), EXIT_SUCCESS); diff --git a/src/env/env_init.c b/src/env/env_init.c index ee3fcc7..7e4c2f4 100644 --- a/src/env/env_init.c +++ b/src/env/env_init.c @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* env_init.c :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: dmoroz +#+ +:+ +#+ */ +/* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/03 21:34:34 by sehosaf #+# #+# */ -/* Updated: 2024/07/08 16:12:38 by dmoroz ### ########.fr */ +/* Updated: 2024/07/18 15:07:15 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -28,25 +28,22 @@ int init_environment(t_shell *shell) t_env *last_node; int i; - if (shell && shell->env == NULL) + shell->env = NULL; + i = 0; + while (environ[i]) { - i = 0; - while (environ[i]) - { - key_value = split_key_value(environ[i], '='); - new_node = create_env_node(key_value); - if (handle_errors(new_node, key_value) == EXIT_FAILURE) - return (EXIT_FAILURE); - if (i == 0) - shell->env = new_node; - else - last_node->next = new_node; - last_node = new_node; - i++; - } - return (EXIT_SUCCESS); + key_value = split_key_value(environ[i], '='); + new_node = create_env_node(key_value); + if (handle_errors(new_node, key_value) == EXIT_FAILURE) + return (EXIT_FAILURE); + if (i == 0) + shell->env = new_node; + else + last_node->next = new_node; + last_node = new_node; + i++; } - return (EXIT_FAILURE); + return (EXIT_SUCCESS); } static int handle_errors(t_env *new_node, char **key_value) @@ -61,7 +58,7 @@ static int handle_errors(t_env *new_node, char **key_value) } if (new_node == NULL) { - perror("malloc"); + perror(ERR_MALLOC); ret = EXIT_FAILURE; } if (key_value) diff --git a/src/env/env_utils.c b/src/env/env_utils.c index 04ee644..251afb9 100644 --- a/src/env/env_utils.c +++ b/src/env/env_utils.c @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/04 12:42:49 by sehosaf #+# #+# */ -/* Updated: 2024/06/19 21:14:07 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 11:35:00 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -57,7 +57,7 @@ char **split_key_value(const char *str, char c) result = (char **)malloc(sizeof(char *) * 3); if (!result) - return (perror("malloc"), NULL); + return (perror(ERR_MALLOC), NULL); index = ft_strchr(str, c); if (index) { diff --git a/src/exec/execute.c b/src/exec/execute.c index d078ce8..5d90e08 100644 --- a/src/exec/execute.c +++ b/src/exec/execute.c @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/17 21:04:06 by sehosaf #+# #+# */ -/* Updated: 2024/06/24 21:46:51 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 12:32:00 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -39,7 +39,7 @@ void execute(t_pipeline *pipeline, t_shell *shell) while (cur != NULL) { if (!async - && !should_execute(cur->cmd.connection_type, shell->exit_status)) + && !should_execute(cur->cmd.conn_type, shell->exit_status)) break ; cmds[i] = find_type(shell, pipeline, cur); if (!async) @@ -77,13 +77,13 @@ static pid_t absolute_path(t_shell *shell, t_pipeline *p, t_pipeline *cur) if (stat(cur->cmd.args[0], &st) == -1) { - perror("minishell: "); + perror(ERR_GENERIC); shell->exit_status = 127; return (EXIT_FAILURE); } if (S_ISDIR(st.st_mode)) { - ft_putendl_fd("minishell: is a directory", 2); + ft_putendl_fd(ERR_IS_DIR, 2); shell->exit_status = 126; return (EXIT_FAILURE); } diff --git a/src/exec/execute_builtin.c b/src/exec/execute_builtin.c index 28d690d..2815011 100644 --- a/src/exec/execute_builtin.c +++ b/src/exec/execute_builtin.c @@ -47,7 +47,7 @@ int execute_builtin(t_command command, t_shell *shell) t_connection connection_type; ret = EXIT_SUCCESS; - connection_type = command.connection_type; + connection_type = command.conn_type; cmd_name = command.args[0]; if (ft_strcmp(cmd_name, "cd") == 0) ret = cmd_cd(shell, command.args); diff --git a/src/exec/execute_cmd.c b/src/exec/execute_cmd.c index 5bd8ced..0f44548 100644 --- a/src/exec/execute_cmd.c +++ b/src/exec/execute_cmd.c @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/19 21:28:19 by sehosaf #+# #+# */ -/* Updated: 2024/06/24 21:40:23 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 14:18:33 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -38,13 +38,13 @@ int exec_command(t_shell *shell, t_pipeline *p, t_pipeline *cur, pid_t pid) env_array = env_list_to_array(shell->env); if (env_array == NULL) { - ft_putendl_fd("minishell: environment list is empty", 2); + ft_putendl_fd(ERR_ENV, 2); return (EXIT_FAILURE); } if (execve(cur->cmd.args[0], cur->cmd.args, env_array) == -1) { free_split(env_array); - return (perror("minishell: "), EXIT_FAILURE); + return (perror(ERR_EXEC), EXIT_FAILURE); } free_split(env_array); return (EXIT_SUCCESS); @@ -63,12 +63,12 @@ static void handle_input(t_command *cmd) in = open(cmd->infile, O_RDONLY); if (in < 0) { - perror("minishell: input file error: "); + perror(ERR_INPUT_FILE); exit(EXIT_FAILURE); } if (dup2(in, STDIN_FILENO) < 0) { - perror("minishell: input file error: "); + perror(ERR_INPUT_FILE); close(in); exit(EXIT_FAILURE); } @@ -87,18 +87,18 @@ static void handle_output(t_command *cmd) if (cmd->outfile != NULL) { - if (cmd->outfile_append_mode) + if (cmd->ap_mode) out = open(cmd->outfile, O_WRONLY | O_CREAT | O_APPEND, 0644); else out = open(cmd->outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (out < 0) { - perror("minishell: output file error: "); + perror(ERR_OUTPUT_FILE); exit(EXIT_FAILURE); } if (dup2(out, STDOUT_FILENO) < 0) { - perror("minishell: output file error: "); + perror(ERR_OUTPUT_FILE); close(out); exit(EXIT_FAILURE); } diff --git a/src/exec/execute_proc.c b/src/exec/execute_proc.c index 5d989cc..a10ed89 100644 --- a/src/exec/execute_proc.c +++ b/src/exec/execute_proc.c @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/19 21:29:30 by sehosaf #+# #+# */ -/* Updated: 2024/06/24 21:42:11 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 12:41:16 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -26,7 +26,7 @@ pid_t create_child(t_shell *shell, t_pipeline *p, t_pipeline *cur) pid = fork(); if (pid < 0) { - perror("minishell: Fork failed: "); + perror(ERR_FORK); return (EXIT_FAILURE); } if (pid == 0) @@ -80,8 +80,8 @@ bool is_async(t_pipeline *pipeline) current = pipeline; while (current) { - if (current->cmd.connection_type == CON_OR - || current->cmd.connection_type == CON_AND) + if (current->cmd.conn_type == CON_OR + || current->cmd.conn_type == CON_AND) return (false); current = current->next; } diff --git a/src/exec/execute_utils.c b/src/exec/execute_utils.c index 087a357..efda2fc 100644 --- a/src/exec/execute_utils.c +++ b/src/exec/execute_utils.c @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/19 21:25:20 by sehosaf #+# #+# */ -/* Updated: 2024/06/23 21:31:23 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 12:44:41 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -81,7 +81,7 @@ char *find_sys_cmd(char *cmd, t_env *env) } } free_split(path_dirs); - printf("minishell: %s: not found\n", cmd); + printf("%s%s: not found\n", ERR_GENERIC, cmd); return (NULL); } @@ -113,7 +113,7 @@ static char *check_file(char *file) if (access(file, X_OK) == 0) return (ft_strdup(file)); else - printf("minishell: %d: %s: Permission denied\n", errno, file); + printf("%s%d: %s: %s\n", ERR_GENERIC, errno, file, ERR_PERM); } return (NULL); } diff --git a/src/main.c b/src/main.c index b58b07b..a89c034 100644 --- a/src/main.c +++ b/src/main.c @@ -1,29 +1,42 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* main.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 09:35:57 by sehosaf #+# #+# */ +/* Updated: 2024/07/18 16:41:09 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "minishell.h" -int main(void) +int main(void) { - char * line; - t_pipeline *p; - t_shell shell; + char *line; + t_pipeline *p; + t_shell shell; - init_environment(&shell); - while (1) - { + if (init_environment(&shell) == EXIT_FAILURE) + exit(EXIT_FAILURE); + while (1) + { interactive_signal_handlers(); - line = readline(PROMPT); + line = readline(PROMPT); non_interactive_signal_handlers(); - if (!line) - exit(EXIT_SUCCESS); - if (!*line) - { - free(line); - continue ; - } - add_history(line); - p = parse(line, &shell); - free(line); - if (validate_pipeline(p) == EXIT_SUCCESS) - execute(p, &shell); - free_pipeline(p); - } -} \ No newline at end of file + if (!line) + exit(EXIT_SUCCESS); + if (!*line) + { + free(line); + continue ; + } + add_history(line); + p = parse(line, &shell); + free(line); + if (p && validate_pipeline(p) == EXIT_SUCCESS) + execute(p, &shell); + free_pipeline(p); + } +} diff --git a/src/parser/create_default_pipeline_node.c b/src/parser/create_default_pipeline_node.c index 22aaec8..938ce35 100644 --- a/src/parser/create_default_pipeline_node.c +++ b/src/parser/create_default_pipeline_node.c @@ -1,22 +1,34 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* create_default_pipeline_node.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 09:29:11 by sehosaf #+# #+# */ +/* Updated: 2024/07/17 09:29:18 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "parser.h" -t_pipeline *create_default_pipeline_node(void) +t_pipeline *create_default_pipeline_node(void) { - t_pipeline *res; + t_pipeline *res; - res = malloc(sizeof(t_pipeline)); - if (!res) - return (NULL); - res->next = NULL; + res = malloc(sizeof(t_pipeline)); + if (!res) + return (NULL); + res->next = NULL; res->prev = NULL; res->fd_in = 0; res->fd_out = 1; - res->cmd.args = NULL; - res->cmd.connection_type = CON_NONE; - res->cmd.is_heredoc = 0; - res->cmd.limiter = NULL; - res->cmd.infile = NULL; - res->cmd.outfile = NULL; - res->cmd.outfile_append_mode = 0; - return (res); -} \ No newline at end of file + res->cmd.args = NULL; + res->cmd.conn_type = CON_NONE; + res->cmd.is_heredoc = 0; + res->cmd.limiter = NULL; + res->cmd.infile = NULL; + res->cmd.outfile = NULL; + res->cmd.ap_mode = 0; + return (res); +} diff --git a/src/parser/parser.c b/src/parser/parser.c index 7c0b6a8..c9b27f0 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1,31 +1,44 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parser.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 09:15:45 by sehosaf #+# #+# */ +/* Updated: 2024/07/18 17:20:24 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "parser.h" -static void set_pipeline_parameters(t_pipeline *node, t_shell *shell); -static void set_connection_type(t_pipeline *node); -static void drop_outside_quotation(t_pipeline *node); +static int set_pipeline_parameters(t_pipeline *node, t_shell *shell); +static void set_connection_type(t_pipeline *node); +static void drop_outside_quotation(t_pipeline *node); /* -Main API for parsing part of the programm -Arg: - line (char *) - prompt text - env (t_env *) - structure which represent env vars -Return: - Commands pipeline - structure which describes what should be executet + Main API for parsing part of the programm + Arg: + line (char *) - prompt text + env (t_env *) - structure which represent env vars + Return: + Commands pipeline - structure which describes what should be executet -1) Split string into tokens -2) Interpret tokens and devide them by |, && and || operators to commands -3) iterrate through commands: - 3.1) redirections - 3.2) variables - 3.3) wildcard - 3.4) drop quotation markss + 1) Split string into tokens + 2) Interpret tokens and devide them by |, && and || operators to commands + 3) iterrate through commands: + 3.1) redirections + 3.2) variables + 3.3) wildcard + 3.4) drop quotation markss -Undefined behavior: -- multiple redirections to the same command, eg. `cmd >1.out >>2.out` or `cmd <1.txt <1.out >>2.out` + or `cmd <1.txt <prev = tmp; if (!node->cmd.args || !node->cmd.args[0]) - break; + break ; set_connection_type(node); - set_redirections(node); + if (set_redirections(node)) + return (1); replace_vars(node, shell); replace_wildcards(node); drop_outside_quotation(node); tmp = node; node = node->next; } + return (0); } -static void set_connection_type(t_pipeline *node) +static void set_connection_type(t_pipeline *node) { if (!ft_memcmp(node->cmd.args[0], "|", 2)) { - node->cmd.connection_type = CON_PIPE; - if (node->prev && node->prev->cmd.connection_type == CON_NONE) - node->prev->cmd.connection_type = CON_PIPE; + node->cmd.conn_type = CON_PIPE; + if (node->prev && node->prev->cmd.conn_type == CON_NONE) + node->prev->cmd.conn_type = CON_PIPE; } else if (!ft_memcmp(node->cmd.args[0], "||", 3)) - node->cmd.connection_type = CON_OR; + node->cmd.conn_type = CON_OR; else if (!ft_memcmp(node->cmd.args[0], "&&", 3)) - node->cmd.connection_type = CON_AND; + node->cmd.conn_type = CON_AND; else return ; remove_cmd_arg(node, 0); } -static void drop_outside_quotation(t_pipeline *node) +static void drop_outside_quotation(t_pipeline *node) { - int i; - int j; - char *end; - char *tmp; + int i; + int j; + char *end; + char *tmp; i = 0; while (node->cmd.args[i]) @@ -96,7 +115,7 @@ static void drop_outside_quotation(t_pipeline *node) break ; ft_memmove(tmp, tmp + 1, end - tmp - 1); ft_memmove(end - 1, end + 1, ft_strlen(end + 1) + 1); - j = (end - node->cmd.args[i]) - 2; + j = (int)((end - node->cmd.args[i]) - 2); } j++; } diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c new file mode 100644 index 0000000..1076e02 --- /dev/null +++ b/src/parser/parser_utils.c @@ -0,0 +1,59 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* remove_cmd_arg.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/10 20:28:38 by sehosaf #+# #+# */ +/* Updated: 2024/07/18 10:27:36 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "parser.h" +#include "environment.h" + +void remove_cmd_arg(t_pipeline *node, int ind) +{ + free(node->cmd.args[ind]); + while (node->cmd.args[ind]) + { + node->cmd.args[ind] = node->cmd.args[ind + 1]; + ind++; + } +} + +/* + Returns variable name. Result is dynamically allocated and should be freed. + Input - pointer on `$` (char before variable name) +*/ +char *get_var_name(char *dollar) +{ + char *res; + int i; + + if (dollar[1] == '?') + i = 2; + else + { + i = 1; + while (ft_isalpha(dollar[i])) + i++; + } + res = malloc(i); + if (!res) + return (NULL); + ft_memcpy(res, dollar + 1, i - 1); + res[i - 1] = 0; + return (res); +} + +char *get_var_value(const char *name, t_shell *shell) +{ + char *var_value; + + if (ft_memcmp(name, "?", 2) == 0) + return (ft_itoa(shell->exit_status)); + var_value = get_env_val(shell->env, name); + return (ft_strdup(var_value)); +} diff --git a/src/parser/remove_cmd_arg.c b/src/parser/remove_cmd_arg.c deleted file mode 100644 index b24d8bd..0000000 --- a/src/parser/remove_cmd_arg.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "parser.h" - -void remove_cmd_arg(t_pipeline *node, int ind) -{ - free(node->cmd.args[ind]); - while (node->cmd.args[ind]) - { - node->cmd.args[ind] = node->cmd.args[ind + 1]; - ind++; - } -} diff --git a/src/parser/replace_vars.c b/src/parser/replace_vars.c index e8b8974..bd05165 100644 --- a/src/parser/replace_vars.c +++ b/src/parser/replace_vars.c @@ -1,22 +1,31 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* replace_vars.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 09:32:14 by sehosaf #+# #+# */ +/* Updated: 2024/07/18 14:01:25 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "parser.h" -#include "environment.h" -static int validate_var_expansion(char *arg, char *dollar); -static char *get_var_name(char *dollar); -static char *get_var_value(const char *name, t_shell *shell); +static int validate_var_expansion(char *arg, const char *dollar); +static void handle_expanded(t_pipeline *node, int i, char *start, t_shell *sh); +static void *alloc_expanded(const t_pipeline *node, int i, const char *value, + const char *name); /* -Only 2 types of variable names are accepted: -- $? -- $ + Only 2 types of variable names are accepted: + - $? + - $ */ -void replace_vars(t_pipeline *node, t_shell *shell) +void replace_vars(t_pipeline *node, t_shell *shell) { - int i; - char *start; - char *var_value; - char *var_name; - char *expanded; + int i; + char *start; i = 0; start = NULL; @@ -31,91 +40,77 @@ void replace_vars(t_pipeline *node, t_shell *shell) if (!start || !validate_var_expansion(node->cmd.args[i], start) || !(ft_isalpha(start[1]) || start[1] == '?')) continue ; - var_name = get_var_name(start); - if (!var_name) - continue ; - var_value = get_var_value(var_name, shell); - expanded = NULL; - if (var_value) - expanded = malloc(ft_strlen(node->cmd.args[i]) - ft_strlen(var_name) - 1 + ft_strlen(var_value) + 1); - if (expanded) - { - ft_memcpy(expanded, node->cmd.args[i], start - node->cmd.args[i]); - ft_memcpy(expanded + (start - node->cmd.args[i]), var_value, ft_strlen(var_value)); - ft_memcpy(expanded + (start - node->cmd.args[i]) + ft_strlen(var_value), start + strlen(var_name) + 1, ft_strlen(node->cmd.args[i]) - ft_strlen(var_name) - (start - node->cmd.args[i]) - 1); - expanded[ft_strlen(node->cmd.args[i]) - ft_strlen(var_name) + ft_strlen(var_value) - 1] = 0; - free(node->cmd.args[i]); - node->cmd.args[i] = expanded; - start = NULL; - } - free(var_name); - free(var_value); + handle_expanded(node, i, start, shell); + start = NULL; } } -/* -Validates, whether variable should be replaced by it's value. -If var is in single quotes - invalid. -*/ -static int validate_var_expansion(char *arg, char *dollar) +static void *alloc_expanded(const t_pipeline *node, int i, const char *value, + const char *name) { - char *dq; - char *sq; + if (value == NULL) + return (NULL); + return (malloc(ft_strlen(node->cmd.args[i]) + - ft_strlen(name) - 1 + ft_strlen(value) + 1)); +} - while (arg && arg < dollar) +static void handle_expanded(t_pipeline *node, int i, char *start, t_shell *sh) +{ + char *exp; + char *value; + char *name; + unsigned long loc; + + exp = NULL; + name = get_var_name(start); + if (!name) + return ; + value = get_var_value(name, sh); + exp = alloc_expanded(node, i, value, name); + if (exp) { - dq = ft_strchr(arg, '"'); - sq = ft_strchr(arg, '\''); - if (sq && sq < dollar) - { - if (dq && dq < sq) - arg = ft_strchr(dq + 1, '"'); - else - { - arg = ft_strchr(sq + 1, '\''); - if (arg && arg > dollar) - return (0); - } - if (arg) - arg++; - } - else - break ; + loc = start - node->cmd.args[i]; + ft_memcpy(exp, node->cmd.args[i], start - node->cmd.args[i]); + ft_memcpy(exp + loc, value, ft_strlen(value)); + ft_memcpy(exp + loc + ft_strlen(value), start + strlen(name) + + 1, ft_strlen(node->cmd.args[i]) - ft_strlen(name) - loc - 1); + exp[ft_strlen(node->cmd.args[i]) - ft_strlen(name) + + ft_strlen(value) - 1] = 0; + free(node->cmd.args[i]); + node->cmd.args[i] = exp; + free(name); + free(value); } - return (1); } /* -Returns variable name. Result is dynamicly allocated and should be freed. -Input - pointer on `$` (char before variable name) + Validates, whether variable should be replaced by its value. + If var is in single quotes - invalid. */ -static char *get_var_name(char *dollar) +static int validate_var_expansion(char *arg, const char *dollar) { - char *res; - int i; + char *dq; + char *sq; - if (dollar[1] == '?') - i = 2; - else + while (arg && arg < dollar) { - i = 1; - while (ft_isalpha(dollar[i])) - i++; + dq = ft_strchr(arg, '"'); + sq = ft_strchr(arg, '\''); + if (sq && sq < dollar) + { + if (dq && dq < sq) + arg = ft_strchr(dq + 1, '"'); + else + { + arg = ft_strchr(sq + 1, '\''); + if (arg && arg > dollar) + return (0); + } + if (arg) + arg++; + } + else + break ; } - res = malloc(i); - if (!res) - return (NULL); - ft_memcpy(res, dollar + 1, i - 1); - res[i - 1] = 0; - return (res); -} - -static char *get_var_value(const char *name, t_shell *shell) -{ - char *var_value; - - if (ft_memcmp(name, "?", 2) == 0) - return ft_itoa(shell->exit_status); - var_value = get_env_val(shell->env, name); - return (ft_strdup(var_value)); + return (1); } diff --git a/src/parser/replace_wildcards.c b/src/parser/replace_wildcards.c index 5ccd764..a079638 100644 --- a/src/parser/replace_wildcards.c +++ b/src/parser/replace_wildcards.c @@ -1,19 +1,31 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* replace_wildcards.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 10:06:56 by sehosaf #+# #+# */ +/* Updated: 2024/07/17 14:26:55 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "parser.h" -static int validate_asterisk(char *arg, char *asterisk); -static t_list *get_args_list(char *arg, char *asterisk); -static void fill_ast_args(char **ast_args, t_list *args_list); -static void replace_asterisk(char ***old_args_p, int ast_pos, char **ast_args); +static int validate_asterisk(const char *arg, const char *asterisk); +static t_list *get_args_list(char *arg, char *astr); +static void fill_ast_args(char **ast_args, t_list *args_list); +static void replace_asterisk(char ***old_args_p, int pos, char **args); -void replace_wildcards(t_pipeline *node) +void replace_wildcards(t_pipeline *node) { - int i; - char *asterisk; - t_list *args_list; - char **ast_args; + int i; + char *asterisk; + t_list *args_list; + char **ast_args; - i = 0; - while (node->cmd.args[i]) + i = -1; + while (node->cmd.args[++i]) { asterisk = ft_strchr(node->cmd.args[i], '*'); if (asterisk && validate_asterisk(node->cmd.args[i], asterisk)) @@ -31,19 +43,18 @@ void replace_wildcards(t_pipeline *node) } ft_lstclear(&args_list, free); } - i++; } } /* -Simple validation of asterisk. -Valid only if out of any type of quotes. + Simple validation of asterisk. + Valid only if out of any type of quotes. */ -static int validate_asterisk(char *arg, char *asterisk) +static int validate_asterisk(const char *arg, const char *asterisk) { - int sq; - int dq; - int i; + int sq; + int dq; + int i; i = 0; sq = 0; @@ -61,12 +72,12 @@ static int validate_asterisk(char *arg, char *asterisk) return (1); } -static t_list *get_args_list(char *arg, char *asterisk) +static t_list *get_args_list(char *arg, char *astr) { - t_list *res; - char *dirname; - DIR *dirstream; - struct dirent *_dirent; + t_list *res; + char *dirname; + DIR *dirstream; + struct dirent *_dirent; res = NULL; dirname = getcwd(NULL, 0); @@ -77,10 +88,11 @@ static t_list *get_args_list(char *arg, char *asterisk) _dirent = readdir(dirstream); while (_dirent) { - if ((size_t)(asterisk - arg) <= ft_strlen(_dirent->d_name) - && !ft_memcmp(_dirent->d_name, arg, asterisk - arg) - && ft_strlen(asterisk + 1) <= ft_strlen(_dirent->d_name) - && !ft_memcmp(_dirent->d_name + ft_strlen(_dirent->d_name) - ft_strlen(asterisk + 1), asterisk + 1, ft_strlen(asterisk + 1))) + if ((size_t)(astr - arg) <= ft_strlen(_dirent->d_name) + && !ft_memcmp(_dirent->d_name, arg, astr - arg) + && ft_strlen(astr + 1) <= ft_strlen(_dirent->d_name) + && !ft_memcmp(_dirent->d_name + ft_strlen(_dirent->d_name) + - ft_strlen(astr + 1), astr + 1, ft_strlen(astr + 1))) ft_lstadd_back(&res, ft_lstnew(ft_strdup(_dirent->d_name))); _dirent = readdir(dirstream); } @@ -88,9 +100,9 @@ static t_list *get_args_list(char *arg, char *asterisk) return (res); } -static void fill_ast_args(char **ast_args, t_list *args_list) +static void fill_ast_args(char **ast_args, t_list *args_list) { - int i; + int i; i = 0; while (args_list) @@ -102,26 +114,27 @@ static void fill_ast_args(char **ast_args, t_list *args_list) ast_args[i] = NULL; } -static void replace_asterisk(char ***old_args_p, int ast_pos, char **ast_args) +static void replace_asterisk(char ***old_args_p, int pos, char **args) { - char **old_args; - char **new_args; - int s_old; - int s_ast; + char **old_args; + char **new_args; + int s_old; + int s_ast; - old_args = *old_args_p; + old_args = *old_args_p; s_old = get_split_size(old_args); - s_ast = get_split_size(ast_args); + s_ast = get_split_size(args); new_args = malloc(sizeof(char *) * (s_old + s_ast)); if (new_args) { - ft_memcpy(new_args, old_args, sizeof(char *) * ast_pos); - ft_memcpy(new_args + ast_pos, ast_args, sizeof(char *) * s_ast); - ft_memcpy(new_args + ast_pos + s_ast, old_args + ast_pos + 1, sizeof(char *) * (s_old - ast_pos - 1)); + ft_memcpy(new_args, old_args, sizeof(char *) * pos); + ft_memcpy(new_args + pos, args, sizeof(char *) * s_ast); + ft_memcpy(new_args + pos + s_ast, old_args + pos + + 1, sizeof(char *) * (s_old - pos - 1)); new_args[s_old + s_ast - 1] = NULL; - free(old_args[ast_pos]); + free(old_args[pos]); free(old_args); *old_args_p = new_args; } - free(ast_args); + free(args); } diff --git a/src/parser/set_redirections.c b/src/parser/set_redirections.c index 2d03b58..62ee364 100644 --- a/src/parser/set_redirections.c +++ b/src/parser/set_redirections.c @@ -1,50 +1,73 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* set_redirections.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/10 20:28:38 by sehosaf #+# #+# */ +/* Updated: 2024/07/18 21:39:45 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "parser.h" -static void set_redirection_field(t_pipeline *node, int i, char **str_field, int checked_char); +static int set_redir(t_pipeline *nd, int i, char **s_field, int ck_char); /* -Finds tokens which define redirection, set respective t_command values and drop such tokens. -Designed to work with cases where there is only one type of in and out redirections. + Finds tokens which define redirection, set respective t_command values + and drop such tokens. Designed to work with cases where there is only + one type of in and out redirections. */ -void set_redirections(t_pipeline *node) +int set_redirections(t_pipeline *node) { - int i; + int i; + int res; i = 0; + res = 0; while (node->cmd.args[i]) { if (node->cmd.args[i][0] == '<') { if (node->cmd.args[i][1] == '<') - { - node->cmd.is_heredoc = 1; - set_redirection_field(node, i, &node->cmd.limiter, 2); - } + res = set_redir(node, i, &node->cmd.limiter, 2); else - set_redirection_field(node, i, &node->cmd.infile, 1); + res = set_redir(node, i, &node->cmd.infile, 1); } else if (node->cmd.args[i][0] == '>') - { - if (node->cmd.args[i][1] == '>') - node->cmd.outfile_append_mode = 1; - set_redirection_field(node, i, &node->cmd.outfile, 1 + node->cmd.outfile_append_mode); - } + res = set_redir(node, i, &node->cmd.outfile, 1 + node->cmd.ap_mode); else i++; + if (res) + return (res); } + return (res); } -static void set_redirection_field(t_pipeline *node, int i, char **str_field, int checked_char) +static int set_redir(t_pipeline *nd, int i, char **s_field, int ck_char) { - char *arg; + char *arg; - arg = node->cmd.args[i]; - if (arg[checked_char] == 0) + if (!nd->cmd.args[i + 1]) + { + ft_putstr_fd(ERR_SNX_TOKEN, STDERR_FILENO); + ft_putstr_fd(nd->cmd.args[i], STDERR_FILENO); + ft_putendl_fd("`", STDERR_FILENO); + return (1); + } + if (nd->cmd.args[i][1] == '<') + nd->cmd.is_heredoc = 1; + if (nd->cmd.args[i][1] == '>') + nd->cmd.ap_mode = 1; + arg = nd->cmd.args[i]; + if (arg[ck_char] == 0) { - *str_field = ft_strdup(node->cmd.args[i + 1]); - remove_cmd_arg(node, i + 1); + *s_field = ft_strdup(nd->cmd.args[i + 1]); + remove_cmd_arg(nd, i + 1); } else - *str_field = ft_substr(arg, checked_char, ft_strlen(arg)); - remove_cmd_arg(node, i); + *s_field = ft_substr(arg, ck_char, ft_strlen(arg)); + remove_cmd_arg(nd, i); + return (0); } diff --git a/src/parser/split_line.c b/src/parser/split_line.c index 382db30..54b8c56 100644 --- a/src/parser/split_line.c +++ b/src/parser/split_line.c @@ -1,103 +1,115 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* split_line.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 10:11:47 by sehosaf #+# #+# */ +/* Updated: 2024/07/17 10:13:05 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "parser.h" -static int count_tokens(char *line); -static char *get_end(char *start); -static char *search_token_end(char *start); +static int count_tokens(char *line); +static char *get_end(char *line); +static char *search_token_end(char *start); /* -Similar to `ft_split` function but with original split logic -For more details check `char *search_token_end(char *start)` + Similar to `ft_split` function but with original split logic + For more details check `char *search_token_end(char *start)` */ -char **split_line(char *line) +char **split_line(char *line) { - int w; - char **res; - char *end; - int n_tokens; + int w; + char **res; + char *end; + int n_tokens; - n_tokens = count_tokens(line); - if (!n_tokens) - return (NULL); - res = malloc((n_tokens + 1) * sizeof(char *)); - if (!res) - return (NULL); - w = 0; - while (*line) - { - while (ft_isspace(*line)) - line++; - if (!*line) - break; - end = get_end(line); - res[w++] = ft_substr(line, 0, end - line); - line = end; - } - res[w] = NULL; - return (res); + n_tokens = count_tokens(line); + if (!n_tokens) + return (NULL); + res = malloc((n_tokens + 1) * sizeof(char *)); + if (!res) + return (NULL); + w = 0; + while (*line) + { + while (ft_isspace(*line)) + line++; + if (!*line) + break ; + end = get_end(line); + res[w++] = ft_substr(line, 0, end - line); + line = end; + } + res[w] = NULL; + return (res); } -static int count_tokens(char *line) +static int count_tokens(char *line) { - int counter; + int counter; - counter = 0; - while (*line) - { - while (ft_isspace(*line)) - line++; - if (!*line) - break; - line = get_end(line); - counter++; - } - return (counter); + counter = 0; + while (*line) + { + while (ft_isspace(*line)) + line++; + if (!*line) + break ; + line = get_end(line); + counter++; + } + return (counter); } -static char *get_end(char *line) +static char *get_end(char *line) { - char *end; + char *end; - if (*line == '|') - { - end = line + 1; - if (line[1] == '|') - end = line + 2; - } - else if (!ft_memcmp(line, "&&", 2)) - end = line + 2; - else - end = search_token_end(line); - return (end); + if (*line == '|') + { + end = line + 1; + if (line[1] == '|') + end = line + 2; + } + else if (!ft_memcmp(line, "&&", 2)) + end = line + 2; + else + end = search_token_end(line); + return (end); } /* -Searches for token end. -Returns character next after token end. -Designed to cope with cases like: -- 'file name'.txt -- file."$EXTENSION" -- ls|grep + Searches for token end. + Returns character next after token end. + Designed to cope with cases like: + - 'file name'.txt + - file."$EXTENSION" + - ls|grep */ -static char *search_token_end(char *start) +static char *search_token_end(char *start) { - char *end; + char *end; - if (*start == '\'') - { - end = ft_strchr(start + 1, '\''); - if (end) - return (search_token_end(end + 1)); - return ft_strchr(start + 1, '\0'); - } - if (*start == '"') - { - end = ft_strchr(start + 1, '"'); - if (end) - return (search_token_end(end + 1)); - return ft_strchr(start + 1, '\0'); - } - if (ft_isspace(*start) || *start == '\0' || *start == '|' - || !ft_memcmp(start, "&&", 2)) - return start; - return (search_token_end(start + 1)); + if (*start == '\'') + { + end = ft_strchr(start + 1, '\''); + if (end) + return (search_token_end(end + 1)); + return (ft_strchr(start + 1, '\0')); + } + if (*start == '"') + { + end = ft_strchr(start + 1, '"'); + if (end) + return (search_token_end(end + 1)); + return (ft_strchr(start + 1, '\0')); + } + if (ft_isspace(*start) || *start == '\0' || *start == '|' + || !ft_memcmp(start, "&&", 2)) + return (start); + return (search_token_end(start + 1)); } diff --git a/src/parser/split_tokens_per_command.c b/src/parser/split_tokens_per_command.c index 8ca980d..b23c86a 100644 --- a/src/parser/split_tokens_per_command.c +++ b/src/parser/split_tokens_per_command.c @@ -1,45 +1,57 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* split_tokens_per_command.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 10:13:37 by sehosaf #+# #+# */ +/* Updated: 2024/07/17 10:15:28 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "parser.h" -static void fill_node_with_tokens(t_pipeline *start, char **tokens, int first, int curr); +static void fill_w_tokens(t_pipeline *start, char **tokens, int first, int cur); /* -Creates node for each command and fills it args with relevand tokens. + Creates node for each command and fills it args with relevant tokens. */ -void split_tokens_per_command(t_pipeline *start, char **tokens) +void split_tokens_per_command(t_pipeline *start, char **tokens) { - int first; - int curr; + int first; + int curr; - first = 0; - curr = 0; - while (tokens[curr]) - { - if (!ft_memcmp(tokens[curr], "|", 2) - || !ft_memcmp(tokens[curr], "||", 3) - || !ft_memcmp(tokens[curr], "&&", 3)) - { - fill_node_with_tokens(start, tokens, first, curr); - start->next = create_default_pipeline_node(); - start = start->next; - first = curr; - } - curr++; - } - fill_node_with_tokens(start, tokens, first, curr); + first = 0; + curr = 0; + while (tokens[curr]) + { + if (!ft_memcmp(tokens[curr], "|", 2) + || !ft_memcmp(tokens[curr], "||", 3) + || !ft_memcmp(tokens[curr], "&&", 3)) + { + fill_w_tokens(start, tokens, first, curr); + start->next = create_default_pipeline_node(); + start = start->next; + first = curr; + } + curr++; + } + fill_w_tokens(start, tokens, first, curr); } -static void fill_node_with_tokens(t_pipeline *start, char **tokens, int first, int curr) +static void fill_w_tokens(t_pipeline *start, char **tokens, int first, int cur) { - int i; + int i; - start->cmd.args = malloc((curr - first + 1) * sizeof(char *)); - if (!start->cmd.args) - return ; - i = 0; - while (i < curr - first) - { - start->cmd.args[i] = ft_strdup(tokens[first + i]); - i++; - } - start->cmd.args[curr - first] = NULL; + start->cmd.args = malloc((cur - first + 1) * sizeof(char *)); + if (!start->cmd.args) + return ; + i = 0; + while (i < cur - first) + { + start->cmd.args[i] = ft_strdup(tokens[first + i]); + i++; + } + start->cmd.args[cur - first] = NULL; } diff --git a/src/parser/test_parser.c b/src/parser/test_parser.c deleted file mode 100644 index 2c24adb..0000000 --- a/src/parser/test_parser.c +++ /dev/null @@ -1,157 +0,0 @@ -#include "parser.h" - -// helper functions -int my_strcmp(char *s1, char *s2) -{ - if (s1 == NULL && s2 == NULL) - return 0; - if (s1 == NULL || s2 == NULL) - return 1; - return strcmp(s1, s2); -} - -void cmdcmp(t_command c1, t_command c2, int n) -{ - int i = 0; - while (c1.args[i] || c2.args[i]) - { - if (my_strcmp(c1.args[i], c2.args[i])){ - printf("E %d.1\n", n); - break; - } - i++; - } - if (c1.connection_type != c2.connection_type) - printf("E %d.2\n", n); - if (c1.is_heredoc != c2.is_heredoc - || my_strcmp(c1.limiter, c2.limiter) - || my_strcmp(c1.infile, c2.infile) - || my_strcmp(c1.outfile, c2.outfile) - || c1.outfile_append_mode != c2.outfile_append_mode) - printf("E %d.3\n", n); - free_split(c1.args); - free(c1.limiter); - free(c1.infile); - free(c1.outfile); -} - -void set_next(t_pipeline **node) -{ - t_pipeline *tmp = *node; - *node = tmp->next; - free(tmp); -} - -/* -** Test cases -*/ -// Base case -void test_case_1() -{ - char *line = "ls -l | grep -e .c | wc -l"; - t_pipeline *res = parse(line, NULL); - // 0 - char *cmd0_args[] = {"ls", "-l", NULL}; - t_command cmd0 = {cmd0_args, CON_NONE, 0, NULL, NULL, NULL, 0}; - cmdcmp(res->cmd, cmd0, 0); - // 1 - set_next(&res); - if (!res){ - printf("E 1.0\n"); exit(1);} - char *cmd1_args[] = {"grep", "-e", ".c", NULL}; - t_command cmd1 = {cmd1_args, CON_PIPE, 0, NULL, NULL, NULL, 0}; - cmdcmp(res->cmd, cmd1, 1); - // 2 - set_next(&res); - if (!res){ - printf("E 3.0\n"); exit(1);} - char *cmd2_args[] = {"wc", "-l", NULL}; - t_command cmd2 = {cmd2_args, CON_PIPE, 0, NULL, NULL, NULL, 0}; - cmdcmp(res->cmd, cmd2, 0); - // 3 - set_next(&res); - if (res){ - printf("E 4.0\n"); exit(1);} -} - -// Redirections and connection types -void test_case_2() -{ - char *line = "outfile || << LIM >> outfile wc -l"; - t_pipeline *res = parse(line, NULL); - // 0 - char *cmd0_args[] = {"ls", NULL}; - t_command cmd0 = {cmd0_args, CON_NONE, 0, NULL, "infile", NULL, 0}; - cmdcmp(res->cmd, cmd0, 0); - // 1 - set_next(&res); - if (!res){ - printf("E 1.0\n"); exit(1);} - char *cmd1_args[] = {"grep", "1", NULL}; - t_command cmd1 = {cmd1_args, CON_AND, 0, NULL, NULL, "outfile", 0}; - cmdcmp(res->cmd, cmd1, 1); - // 2 - set_next(&res); - if (!res){ - printf("E 3.0\n"); exit(1);} - char *cmd2_args[] = {"wc", "-l", NULL}; - t_command cmd2 = {cmd2_args, CON_OR, 1, "LIM", NULL, "outfile", 1}; - cmdcmp(res->cmd, cmd2, 0); - // 3 - set_next(&res); - if (res){ - printf("E 4.0\n"); exit(1);} -} - -// variables -void test_case_3() -{ - char *line = "echo $VAR $? \"$?\" '$?' '\"$?\"' \"'$VAR'\""; - t_env *env1 = malloc(sizeof(t_env)); - t_env *env2 = malloc(sizeof(t_env)); - env1->key = "?"; - env1->value = "my_var_val"; - env1->next = env2; - env2->key = "VAR"; - env2->value = "my_var_val"; - env2->next = NULL; - t_pipeline *res = parse(line, env1); - // 0 - char *cmd0_args[] = {"echo", "my_var_val", "my_var_val", "my_var_val", "$?", "\"$?\"", "'my_var_val'", NULL}; - t_command cmd0 = {cmd0_args, CON_NONE, 0, NULL, NULL, NULL, 0}; - cmdcmp(res->cmd, cmd0, 0); - // 1 - set_next(&res); - if (res){ - printf("E 1.0\n"); exit(1);} -} - -// wildcards -// expected order of objects in readdir: https://stackoverflow.com/a/8984803 -// order of files is changing if you modify the files, so if you face Error message double check the expected order with `ls -f` -void test_case_4() -{ - char *line = "echo replace* SEP *parser.c SEP split*.c"; - t_pipeline *res = parse(line, NULL); - // 0 - char *cmd0_args[] = {"echo", "replace_vars.c", "replace_wildcards.c", "SEP", "parser.c", "test_parser.c", "SEP", "split_line.c", "split_tokens_per_command.c", NULL}; - t_command cmd0 = {cmd0_args, CON_NONE, 0, NULL, NULL, NULL, 0}; - cmdcmp(res->cmd, cmd0, 0); - // 1 - set_next(&res); - if (res){ - printf("E 1.0\n"); exit(1);} -} - - -int main() -{ - printf("Runnung test 1...\n"); - test_case_1(); - printf("Runnung test 2...\n"); - test_case_2(); - printf("Runnung test 3...\n"); - test_case_3(); - printf("Runnung test 4...\n"); - test_case_4(); -} diff --git a/src/parser/tests_makefile b/src/parser/tests_makefile deleted file mode 100644 index ee73b0b..0000000 --- a/src/parser/tests_makefile +++ /dev/null @@ -1,63 +0,0 @@ -CC = gcc -CFLAGS = -Wall -Wextra -Werror -C_PRECOMPILE_FLAGS = -c -C_DEBUG_FLAG = -g - -LIBFT_DIR = ../../libft -LIBFT_NAME = libdmoroz.a -LIBFT = $(addprefix $(LIBFT_DIR)/, $(LIBFT_NAME)) - -INC_DIR = ../../include - -NAME = run_parser_tests -SRCS = test_parser.c \ - create_default_pipeline_node.c \ - parser.c \ - remove_cmd_arg.c \ - replace_vars.c \ - replace_wildcards.c \ - set_redirections.c \ - split_line.c \ - split_tokens_per_command.c \ - ../utils/free_split.c \ - ../utils/ft_isspace.c \ - ../utils/get_split_size.c \ - ../env/env_modify.c -OBJS = $(SRCS:.c=.o) -INCS = $(INC_DIR)/minishell.h \ - $(INC_DIR)/parser.h \ - $(LIBFT_DIR)/libft/libft.h \ - $(LIBFT_DIR)/ftprintf/ft_printf.h \ - $(LIBFT_DIR)/ftgnl/get_next_line.h -INCS_DIR = $(dir $(INCS)) -INC_FLAGS = $(addprefix -I, $(INCS_DIR)) - -LIB_FLAGS = -L$(LIBFT_DIR)/ -ldmoroz - -all: $(NAME) - -%.o: %.c $(INCS) - $(CC) $(CFLAGS) $(C_PRECOMPILE_FLAGS) $(INC_FLAGS) $(LIB_FLAGS) $< -o $@ - -$(NAME): $(LIBFT) $(OBJS) - $(CC) $(CFLAGS) $(INC_FLAGS) $(OBJS) $(LIB_FLAGS) -o $(NAME) - -debug: $(LIBFT) - $(CC) $(C_DEBUG_FLAG) $(INC_FLAGS) $(SRCS) $(LIB_FLAGS) -o $(NAME) - -clean: - $(MAKE) clean -C $(LIBFT_DIR) - rm -f $(OBJS) - rm -f $(BONUS_OBJS) - -fclean: clean - $(MAKE) fclean -C $(LIBFT_DIR) - rm -f $(NAME) - rm -f $(BONUS_NAME) - -re: fclean all - -$(LIBFT): - $(MAKE) all bonus clean -C $(LIBFT_DIR) - -.PHONY: all clean fclean re bonus \ No newline at end of file diff --git a/src/pipe/pipe.c b/src/pipe/pipe.c index f7362cc..0e0f5b8 100644 --- a/src/pipe/pipe.c +++ b/src/pipe/pipe.c @@ -6,7 +6,7 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/07/12 16:56:55 by sehosaf #+# #+# */ -/* Updated: 2024/07/12 16:56:56 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 12:50:07 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ @@ -29,10 +29,10 @@ int create_pipes(t_pipeline *pipeline) i = 0; while (current) { - if (current->cmd.connection_type == CON_PIPE) + if (current->cmd.conn_type == CON_PIPE) { if (pipe(pipefd[i]) == -1) - return (perror("minishell: pipe error: "), EXIT_FAILURE); + return (perror(ERR_PIPE), EXIT_FAILURE); current->fd_in = pipefd[i][0]; current->fd_out = pipefd[i][1]; i++; @@ -47,14 +47,14 @@ int create_pipes(t_pipeline *pipeline) * as argument * @param p The pipeline to close the file descriptors for */ -void close_pipes(t_pipeline *p) +void close_pipes(t_pipeline *p) { t_pipeline *current; current = p; while (current) { - if (current->cmd.connection_type == CON_PIPE) + if (current->cmd.conn_type == CON_PIPE) { close(current->fd_in); close(current->fd_out); diff --git a/src/signal/signal.c b/src/signal/signal.c index 9aa61b8..ef4a300 100644 --- a/src/signal/signal.c +++ b/src/signal/signal.c @@ -30,9 +30,9 @@ void non_interactive_signal_handlers(void) sa_int.sa_flags = 0; sa_quit.sa_flags = 0; if (sigaction(SIGINT, &sa_int, NULL)) - perror("minishell: sigaction: SIGINT "); + perror(ERR_SIGINT); if (sigaction(SIGQUIT, &sa_quit, NULL)) - perror("minishell: sigaction: SIGQUIT "); + perror(ERR_SIGQUIT); } /** @@ -53,9 +53,9 @@ void interactive_signal_handlers(void) sa_int.sa_flags = 0; sa_quit.sa_flags = 0; if (sigaction(SIGINT, &sa_int, NULL)) - perror("minishell: sigaction: SIGINT "); + perror(ERR_SIGINT); if (sigaction(SIGQUIT, &sa_quit, NULL)) - perror("minishell: sigaction: SIGQUIT "); + perror(ERR_SIGQUIT); } /** diff --git a/src/utils/free_pipeline.c b/src/utils/free_pipeline.c index a34cbdf..79d62dd 100644 --- a/src/utils/free_pipeline.c +++ b/src/utils/free_pipeline.c @@ -1,17 +1,33 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* free_pipeline.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 09:32:25 by sehosaf #+# #+# */ +/* Updated: 2024/07/18 13:56:59 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "minishell.h" -void free_pipeline(t_pipeline * p) +void free_pipeline(t_pipeline *p) { - t_pipeline * tmp; + t_pipeline *tmp; - while (p) - { - free_split(p->cmd.args); - free(p->cmd.limiter); - free(p->cmd.outfile); - free(p->cmd.infile); - tmp = p; - p = p->next; - free(tmp); - } + while (p != NULL) + { + tmp = p; + p = p->next; + free_split(tmp->cmd.args); + free(tmp->cmd.limiter); + free(tmp->cmd.outfile); + free(tmp->cmd.infile); + if (tmp->fd_in > 2) + close(tmp->fd_in); + if (tmp->fd_out > 2) + close(tmp->fd_out); + free(tmp); + } } diff --git a/src/utils/free_shell.c b/src/utils/free_shell.c index 210b98d..673f789 100644 --- a/src/utils/free_shell.c +++ b/src/utils/free_shell.c @@ -6,14 +6,13 @@ /* By: sehosaf +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/09 19:16:31 by sehosaf #+# #+# */ -/* Updated: 2024/06/24 20:02:09 by sehosaf ### ########.fr */ +/* Updated: 2024/07/17 09:32:39 by sehosaf ### ########.fr */ /* */ /* ************************************************************************** */ #include "minishell.h" #include "environment.h" -// TODO: Add further functions to handle the allocated memory for a clean exit /** * @brief Frees the shell structure and exits the shell with the exit status. * @param shell The shell structure to free diff --git a/src/utils/free_split.c b/src/utils/free_split.c index 590b9d2..2803a81 100644 --- a/src/utils/free_split.c +++ b/src/utils/free_split.c @@ -1,16 +1,28 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* free_split.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 09:32:48 by sehosaf #+# #+# */ +/* Updated: 2024/07/17 10:17:35 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "minishell.h" -void free_split(char **split) +void free_split(char **split) { - int i; + int i; - if (!split) - return ; - i = 0; - while (split[i]) - { - free(split[i]); - i++; - } - free(split); + if (!split) + return ; + i = 0; + while (split[i]) + { + free(split[i]); + i++; + } + free(split); } diff --git a/src/utils/ft_isspace.c b/src/utils/ft_isspace.c index 566a4ed..9d1632e 100644 --- a/src/utils/ft_isspace.c +++ b/src/utils/ft_isspace.c @@ -1,8 +1,18 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_isspace.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/10 20:28:38 by sehosaf #+# #+# */ +/* Updated: 2024/07/17 14:16:58 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + int ft_isspace(int c) { - if (c >= 9 && c <= 13) - return (1); - else if (c == ' ') + if ((c >= 9 && c <= 13) || c == ' ') return (1); return (0); } diff --git a/src/utils/get_split_size.c b/src/utils/get_split_size.c index 88cfc8a..2dee5dd 100644 --- a/src/utils/get_split_size.c +++ b/src/utils/get_split_size.c @@ -1,6 +1,18 @@ -int get_split_size(char **split) +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* get_split_size.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/10 20:28:38 by sehosaf #+# #+# */ +/* Updated: 2024/07/17 10:17:00 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + +int get_split_size(char **split) { - int i; + int i; if (!split) return (0); diff --git a/src/utils/validate_pipeline.c b/src/utils/validate_pipeline.c index 0cd3fcd..a6e01f2 100644 --- a/src/utils/validate_pipeline.c +++ b/src/utils/validate_pipeline.c @@ -1,39 +1,53 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* validate_pipeline.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sehosaf +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/17 09:35:43 by sehosaf #+# #+# */ +/* Updated: 2024/07/17 11:22:33 by sehosaf ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "minishell.h" -char *get_conn_type_name(t_connection c); +char *get_con_type(t_connection c); -int validate_pipeline(t_pipeline *p) +int validate_pipeline(t_pipeline *p) { - t_pipeline *current; - t_command *cmd; - - current = p; - while (current) { - cmd = ¤t->cmd; - if (!cmd->args || !cmd->args[0]) - { - if (current->next) - { - ft_putendl_fd("minishell: syntax error near unexpected token `", STDERR_FILENO); - ft_putendl_fd(get_conn_type_name(current->next->cmd.connection_type), STDERR_FILENO); - ft_putendl_fd("'", STDERR_FILENO); - } - else - ft_putendl_fd("minishell: syntax error: unexpected end of file", STDERR_FILENO); - return (EXIT_FAILURE); - } - current = current->next; - } - return (EXIT_SUCCESS); + t_pipeline *current; + t_command *cmd; + + current = p; + while (current) + { + cmd = ¤t->cmd; + if (!cmd->args || !cmd->args[0]) + { + if (current->next) + { + ft_putendl_fd(ERR_SNX_TOKEN, STDERR_FILENO); + ft_putendl_fd( + get_con_type(current->next->cmd.conn_type), STDERR_FILENO); + ft_putendl_fd("'", STDERR_FILENO); + } + else + ft_putendl_fd(ERR_SNX_EOF, STDERR_FILENO); + return (EXIT_FAILURE); + } + current = current->next; + } + return (EXIT_SUCCESS); } -char *get_conn_type_name(t_connection c) +char *get_con_type(t_connection c) { - if (c == CON_PIPE) - return ("|"); - if (c == CON_OR) - return ("||"); - if (c == CON_AND) - return ("&&"); - return ("NONE"); + if (c == CON_PIPE) + return ("|"); + if (c == CON_OR) + return ("||"); + if (c == CON_AND) + return ("&&"); + return ("NONE"); } diff --git a/tests/builtin/test_builtins.c b/tests/builtin/test_builtins.c deleted file mode 100644 index a8863c4..0000000 --- a/tests/builtin/test_builtins.c +++ /dev/null @@ -1,183 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* test_builtins.c :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: sehosaf +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/06/02 15:12:16 by sehosaf #+# #+# */ -/* Updated: 2024/06/19 21:30:54 by sehosaf ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "CUnit/Basic.h" -#include -#include -#include -#include "minishell.h" -#include "execute.h" - -static void test_cmd_pwd(void) -{ - char buffer[PATH_MAX + 2]; - int fd; - ssize_t num_read; - char *newline; - int saved_stdout; - char expected_output[PATH_MAX]; - t_shell *shell; - - shell = (t_shell *)malloc(sizeof(t_shell)); - saved_stdout = dup(STDOUT_FILENO); - fd = open("test_output", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd == -1) - { - perror("open"); - free(shell); - return ; - } - dup2(fd, STDOUT_FILENO); - CU_ASSERT_EQUAL(cmd_pwd(), EXIT_SUCCESS); - dup2(saved_stdout, STDOUT_FILENO); - close(saved_stdout); - close(fd); - free(shell); - fd = open("test_output", O_RDONLY); - if (fd == -1) - { - perror("open"); - return ; - } - num_read = read(fd, buffer, sizeof(buffer)); - if (num_read == -1) - { - perror("read"); - close(fd); - return ; - } - buffer[num_read] = '\0'; - close(fd); - newline = strchr(buffer, '\n'); - if (newline) - *newline = '\0'; - getcwd(expected_output, sizeof(expected_output)); - printf("\nExpected cwd: %s\n", expected_output); - printf("Actual cwd: %s\n", buffer); - CU_ASSERT_STRING_EQUAL(buffer, expected_output); - remove("test_output"); -} - -static void test_cmd_echo(void) -{ - const char *args1[] = {"echo", "Hello,", "World!", NULL}; - const char *args2[] = {"echo", "-n", "Hello,", "World!", NULL}; - const char *args3[] = {"echo", NULL}; - const char *args4[] = {NULL}; - - CU_ASSERT_EQUAL(cmd_echo(args1), EXIT_SUCCESS); - CU_ASSERT_EQUAL(cmd_echo(args2), EXIT_SUCCESS); - CU_ASSERT_EQUAL(cmd_echo(args3), EXIT_SUCCESS); - CU_ASSERT_EQUAL(cmd_echo(args4), EXIT_FAILURE); -} - -static void test_cmd_unset(void) -{ - t_shell *shell = (t_shell *)malloc(sizeof(t_shell)); - shell->env = NULL; - init_environment(shell); - cmd_unset(shell, "PATH"); - t_env *env = shell->env; - while (env != NULL) - { - CU_ASSERT_STRING_NOT_EQUAL(env->key, "PATH"); - env = env->next; - } - free_env(shell->env); - free(shell); -} - -static void test_cmd_env(void) -{ - t_shell *shell = (t_shell *)malloc(sizeof(t_shell)); - shell->env = NULL; - init_environment(shell); - int saved_stdout = dup(STDOUT_FILENO); - int fd = open("test_output", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd == -1) - { - perror("open"); - free_env(shell->env); - free(shell); - return; - } - dup2(fd, STDOUT_FILENO); - cmd_env(shell); - free_env(shell->env); - free(shell); - dup2(saved_stdout, STDOUT_FILENO); - close(saved_stdout); - close(fd); - fd = open("test_output", O_RDONLY); - if (fd == -1) - { - perror("open"); - return; - } - char buffer[1024]; - ssize_t num_read = read(fd, buffer, 1024); - if (num_read == -1) - { - perror("read"); - return; - } - buffer[num_read] = '\0'; - close(fd); - CU_ASSERT_PTR_NOT_NULL(strstr(buffer, "HOME=")); - CU_ASSERT_PTR_NOT_NULL(strstr(buffer, "USER=")); - remove("test_output"); -} - -static void test_cmd_export(void) -{ - t_shell *shell = (t_shell *)malloc(sizeof(t_shell)); - shell->env = NULL; - init_environment(shell); - char *new_var = "NEW_VAR=new_value"; - cmd_export(shell, new_var); - t_env *env_node = get_env_node(shell->env, "NEW_VAR"); - CU_ASSERT_PTR_NOT_NULL(env_node); - if (env_node != NULL) - CU_ASSERT_STRING_EQUAL(env_node->value, "new_value"); - char *overwrite_var = "HOME=new_home"; - cmd_export(shell, overwrite_var); - env_node = get_env_node(shell->env, "HOME"); - CU_ASSERT_PTR_NOT_NULL(env_node); - if (env_node != NULL) - CU_ASSERT_STRING_EQUAL(env_node->value, "new_home"); - free_env(shell->env); - free(shell); -} - -int main(void) -{ - CU_pSuite pSuite; - - pSuite = NULL; - if (CUE_SUCCESS != CU_initialize_registry()) - return (CU_get_error()); - pSuite = CU_add_suite("test_builtins", NULL, NULL); - if (NULL == pSuite) - { - CU_cleanup_registry(); - return (CU_get_error()); - } - CU_add_test(pSuite, "test_cmd_echo", test_cmd_echo); - CU_add_test(pSuite, "test_cmd_pwd", test_cmd_pwd); - CU_add_test(pSuite, "test_cmd_env", test_cmd_env); - CU_add_test(pSuite, "test_cmd_unset", test_cmd_unset); - CU_add_test(pSuite, "test_cmd_export", test_cmd_export); - CU_basic_set_mode(CU_BRM_VERBOSE); - CU_basic_run_tests(); - CU_cleanup_registry(); - return (CU_get_error()); -}