├── .gitmodules ├── .gitignore ├── .ignore_readline_leaks.supp ├── libft ├── ft_putchar_fd.c ├── ft_strcmp.c ├── ft_isdigit.c ├── ft_isprint.c ├── ft_isalpha.c ├── ft_isascii.c ├── ft_isalnum.c ├── ft_isspace.c ├── ft_putstr_fd.c ├── ft_putendl_fd.c ├── ft_bzero.c ├── ft_strlen.c ├── ft_tolower.c ├── ft_toupper.c ├── ft_lstlast.c ├── ft_lstiter.c ├── ft_lstdelone.c ├── ft_lstsize.c ├── ft_striteri.c ├── ft_lstadd_front.c ├── ft_lstadd_back.c ├── ft_calloc.c ├── ft_lstnew.c ├── ft_memset.c ├── ft_strdup.c ├── ft_lstclear.c ├── ft_putnbr_fd.c ├── ft_strchr.c ├── ft_strrchr.c ├── ft_strncmp.c ├── ft_atoi.c ├── ft_memchr.c ├── ft_memcpy.c ├── ft_strjoin.c ├── ft_strmapi.c ├── ft_memcmp.c ├── ft_strlcpy.c ├── ft_substr.c ├── ft_memmove.c ├── ft_strnstr.c ├── ft_strlcat.c ├── ft_strtrim.c ├── ft_lstmap.c ├── ft_itoa.c ├── Makefile ├── ft_split.c └── libft.h ├── sources ├── parser │ ├── parse_pipe.c │ ├── cmd_lst_utils_cleanup.c │ ├── cmd_lst_utils.c │ ├── create_commands.c │ ├── parse_word.c │ ├── parse_append.c │ ├── fill_args_echo.c │ ├── parse_trunc.c │ ├── parse_heredoc.c │ ├── parse_input.c │ ├── parse_heredoc_utils.c │ ├── fill_args_echo_utils.c │ └── fill_args_default.c ├── utils │ ├── exit.c │ ├── cleanup.c │ ├── error.c │ └── init_data.c ├── builtins │ ├── env_builtin.c │ ├── pwd_builtin.c │ ├── unset_builtin.c │ ├── export_builtin.c │ ├── echo_builtin.c │ ├── cd_builtin.c │ └── exit_builtin.c ├── lexer │ ├── check_if_var.c │ ├── token_lst_utils_2.c │ ├── parse_user_input.c │ ├── lexer_grammar.c │ ├── tokenization.c │ ├── token_lst_utils.c │ └── tokenization_utils.c ├── expansion │ ├── var_expander_utils.c │ ├── identify_var.c │ ├── recover_value.c │ ├── quotes_handler.c │ ├── quotes_remover.c │ ├── var_expander.c │ └── replace_var.c ├── execution │ ├── execute_utils.c │ ├── parse_path.c │ ├── execute.c │ └── execute_cmd.c ├── signals │ └── signal.c ├── redirections │ ├── pipe.c │ └── file_io.c ├── env │ ├── env_set.c │ └── env.c ├── debug │ └── debug.c └── main.c ├── Makefile └── README.md /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "minitester"] 2 | path = minitester 3 | url = https://github.com/mcombeau/minitester-minishell-tester.git 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | */*.o 2 | /objects/ 3 | .vscode 4 | .vscode/ 5 | /libft/libft.a 6 | minishell 7 | /testing/o_tests 8 | /testing/old_exec_tests 9 | /testing/todo_tests.md 10 | minishell_test.log 11 | .idea/ -------------------------------------------------------------------------------- /.ignore_readline_leaks.supp: -------------------------------------------------------------------------------- 1 | { 2 | ignore_readline_leaks 3 | Memcheck:Leak 4 | ... 5 | fun:readline 6 | } 7 | { 8 | ignore_rl_history_leaks 9 | Memcheck:Leak 10 | ... 11 | fun:add_history 12 | } -------------------------------------------------------------------------------- /libft/ft_putchar_fd.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_putchar_fd.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/28 05:38:33 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 15:40:12 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_putchar_fd writes the given character to the given 18 | file descriptor. 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_putchar_fd(char c, int fd) 25 | { 26 | write(fd, &c, 1); 27 | } 28 | -------------------------------------------------------------------------------- /libft/ft_strcmp.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strcmp.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 19:08:27 by mcombeau #+# #+# */ 9 | /* Updated: 2022/09/17 19:08:28 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | int ft_strcmp(const char *s1, const char *s2) 16 | { 17 | size_t i; 18 | 19 | i = 0; 20 | if (!s1 || !s2) 21 | return (1); 22 | while (s1[i] && s2[i] && (s1[i] == s2[i])) 23 | i++; 24 | return ((unsigned char)s1[i] - (unsigned char)s2[i]); 25 | } 26 | -------------------------------------------------------------------------------- /libft/ft_isdigit.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_isdigit.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:53:06 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 14:40:52 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | /* 14 | DESCRIPTION : 15 | The function ft_isdigit checks whether c is a digit character or not. 16 | 17 | RETURN VALUE: 18 | Non-zero if c is a digit, zero if not. 19 | */ 20 | 21 | int ft_isdigit(int c) 22 | { 23 | if (c >= '0' && c <= '9') 24 | return (c); 25 | return (0); 26 | } 27 | -------------------------------------------------------------------------------- /libft/ft_isprint.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_isprint.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:50:49 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 14:42:17 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | /* 14 | DESCRIPTION : 15 | The function ft_isprint checks whether c is a printable character or not. 16 | 17 | RETURN VALUE : 18 | Non-zero if c is printable, zero if not. 19 | */ 20 | 21 | int ft_isprint(int c) 22 | { 23 | if (c >= ' ' && c <= '~') 24 | return (c); 25 | return (0); 26 | } 27 | -------------------------------------------------------------------------------- /sources/parser/parse_pipe.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* parse_pipe.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:22:49 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:22:52 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | void parse_pipe(t_command **cmd, t_token **token_lst) 16 | { 17 | t_command *last_cmd; 18 | 19 | last_cmd = lst_last_cmd(*cmd); 20 | last_cmd->pipe_output = true; 21 | lst_add_back_cmd(&last_cmd, lst_new_cmd(false)); 22 | *token_lst = (*token_lst)->next; 23 | } 24 | -------------------------------------------------------------------------------- /libft/ft_isalpha.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_isalpha.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:50:28 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 14:36:38 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | /* 14 | DESCRIPTION : 15 | The function ft_isalpha checks whether c is alphabetic or not. 16 | 17 | RETURN VALUE : 18 | Non-zero if c is alphabetic, zero if not. 19 | */ 20 | 21 | int ft_isalpha(int c) 22 | { 23 | if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) 24 | return (c); 25 | return (0); 26 | } 27 | -------------------------------------------------------------------------------- /libft/ft_isascii.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_isascii.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:48:51 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 14:38:16 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | /* 14 | DESCRIPTION : 15 | The function ft_isascii checks whether c is an ascii character or not. 16 | 17 | RESULT VALUE : 18 | Non-zero if c is ascii, zero if not. 19 | */ 20 | 21 | int ft_isascii(int c) 22 | { 23 | if (c == 0) 24 | return (1); 25 | if (c > 0 && c <= 127) 26 | return (c); 27 | return (0); 28 | } 29 | -------------------------------------------------------------------------------- /libft/ft_isalnum.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_isalnum.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:52:40 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:49:56 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_isalnum checks whether the value of c is alphanumeric. 18 | 19 | RETURN VALUE : 20 | Non-zero if c is alphanumeric, zero if not. 21 | */ 22 | 23 | int ft_isalnum(int c) 24 | { 25 | if (ft_isalpha(c) || ft_isdigit(c)) 26 | return (c); 27 | return (0); 28 | } 29 | -------------------------------------------------------------------------------- /libft/ft_isspace.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_isspace.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:53:06 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/10 00:57:38 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | /* 14 | DESCRIPTION : 15 | The function ft_isspace checks whether c is a space character or not. 16 | 17 | RETURN VALUE: 18 | Non-zero if c is a space, zero if not. 19 | */ 20 | 21 | int ft_isspace(int c) 22 | { 23 | if (c == ' ' || c == '\t' || c == '\n' || c == '\r' 24 | || c == '\v' || c == '\f') 25 | return (c); 26 | return (0); 27 | } 28 | -------------------------------------------------------------------------------- /libft/ft_putstr_fd.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_putstr_fd.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/28 05:42:28 by mcombeau #+# #+# */ 9 | /* Updated: 2022/07/20 17:08:27 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_putstr_fd writes the given string to the given 18 | file descriptor. 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_putstr_fd(char *s, int fd) 25 | { 26 | int len; 27 | 28 | if (!s) 29 | return ; 30 | len = ft_strlen(s); 31 | write (fd, s, len); 32 | } 33 | -------------------------------------------------------------------------------- /libft/ft_putendl_fd.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_putendl_fd.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/28 06:13:20 by mcombeau #+# #+# */ 9 | /* Updated: 2022/07/20 17:10:10 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_putendl_fd writes the given string to the given 18 | file descriptor followed by a new line. 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_putendl_fd(char *s, int fd) 25 | { 26 | char *tmp; 27 | 28 | tmp = ft_strjoin(s, "\n"); 29 | ft_putstr_fd(tmp, fd); 30 | free(tmp); 31 | } 32 | -------------------------------------------------------------------------------- /sources/utils/exit.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* exit.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 19:06:38 by mcombeau #+# #+# */ 9 | /* Updated: 2022/09/17 19:06:40 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* exit_shell: 16 | * Cleanly exits the minishell program by closing all opened 17 | * fds and freeing all allocated memory. 18 | */ 19 | void exit_shell(t_data *data, int exno) 20 | { 21 | if (data) 22 | { 23 | if (data->cmd && data->cmd->io_fds) 24 | close_fds(data->cmd, true); 25 | free_data(data, true); 26 | } 27 | exit(exno); 28 | } 29 | -------------------------------------------------------------------------------- /libft/ft_bzero.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_bzero.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/23 14:22:49 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 14:21:37 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_bzero erases data in the n bytes of memory starting 18 | at location s by writing '\0's. 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_bzero(void *s, size_t n) 25 | { 26 | unsigned char *p; 27 | 28 | p = (unsigned char *)s; 29 | while (n != 0) 30 | { 31 | *p = '\0'; 32 | p++; 33 | n--; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /libft/ft_strlen.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strlen.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:51:11 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:17:56 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strlen measures the length of the given string str, 18 | excluding the terminating \0 character. 19 | 20 | RETURN VALUE : 21 | The number of bytes in the string str. 22 | */ 23 | 24 | size_t ft_strlen(const char *str) 25 | { 26 | size_t i; 27 | 28 | i = 0; 29 | while (str[i] != '\0') 30 | i++; 31 | return (i); 32 | } 33 | -------------------------------------------------------------------------------- /libft/ft_tolower.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_tolower.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:52:04 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/06 15:42:20 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_tolower converts a given uppercase letter c to its 18 | lowercase equivalent. 19 | 20 | RETURN VALUE : 21 | The lowercase equivalent letter. 22 | The original character c if c is not an uppercase letter. 23 | */ 24 | 25 | int ft_tolower(int c) 26 | { 27 | if (c >= 'A' && c <= 'Z') 28 | c += 32; 29 | return (c); 30 | } 31 | -------------------------------------------------------------------------------- /libft/ft_toupper.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_toupper.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:53:56 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/06 15:41:08 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_toupper converts a given lowercase letter c to its 18 | uppercase equivalent. 19 | 20 | RETURN VALUE : 21 | The uppercase equivalent letter. 22 | The original character c if c is not a lowercase letter. 23 | */ 24 | 25 | int ft_toupper(int c) 26 | { 27 | if (c >= 'a' && c <= 'z') 28 | c -= 32; 29 | return (c); 30 | } 31 | -------------------------------------------------------------------------------- /libft/ft_lstlast.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_lstlast.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/12/01 19:48:52 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:51:11 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_lstlast finds the last node in a given list. 18 | 19 | RETURN VALUE : 20 | The last node of a list. 21 | [.]->[.]->[.]->[LAST]->[NULL] 22 | */ 23 | 24 | t_list *ft_lstlast(t_list *lst) 25 | { 26 | if (!lst) 27 | return (NULL); 28 | while (lst != NULL && lst->next != NULL) 29 | lst = lst->next; 30 | return (lst); 31 | } 32 | -------------------------------------------------------------------------------- /libft/ft_lstiter.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_lstiter.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/12/01 20:26:30 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:50:47 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_lstiter applies the function f passed as parameter 18 | to the content of each node of a given list. 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_lstiter(t_list *lst, void (*f)(void *)) 25 | { 26 | if (!f || !lst) 27 | return ; 28 | while (lst) 29 | { 30 | f(lst->content); 31 | lst = lst->next; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /libft/ft_lstdelone.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_lstdelone.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/12/01 20:05:57 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/05 13:10:41 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_lstdelone deletes the content of a list node with the 18 | function passed as parameter before freeing the memory of the node. 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_lstdelone(t_list *lst, void (*del)(void *)) 25 | { 26 | if (!lst) 27 | return ; 28 | if (del) 29 | (del)(lst->content); 30 | free(lst); 31 | } 32 | -------------------------------------------------------------------------------- /libft/ft_lstsize.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_lstsize.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/12/01 19:44:21 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 15:15:06 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_lstsize measures the size of a given list by counting 18 | the number of nodes in it. 19 | 20 | RETURN VALUE : 21 | The integer number of nodes in the given list. 22 | */ 23 | 24 | int ft_lstsize(t_list *lst) 25 | { 26 | int i; 27 | 28 | i = 0; 29 | while (lst) 30 | { 31 | lst = lst->next; 32 | i++; 33 | } 34 | return (i); 35 | } 36 | -------------------------------------------------------------------------------- /libft/ft_striteri.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_striteri.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/28 05:10:58 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:00:25 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_striteri applies the given function f to each 18 | character in the given string s. 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_striteri(char *s, void (*f)(unsigned int, char*)) 25 | { 26 | int i; 27 | 28 | if (!s || !f) 29 | return ; 30 | i = 0; 31 | while (s[i]) 32 | { 33 | (*f)(i, &s[i]); 34 | i++; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /libft/ft_lstadd_front.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_lstadd_front.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/30 22:10:05 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/07 12:13:58 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_lstadd_front adds a new node to the front of a list: 18 | [NEW]->[.]->[.]->[.]->[NULL] 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_lstadd_front(t_list **alst, t_list *new) 25 | { 26 | if (!new) 27 | return ; 28 | if (!*alst) 29 | { 30 | *alst = new; 31 | return ; 32 | } 33 | new->next = *alst; 34 | *alst = new; 35 | } 36 | -------------------------------------------------------------------------------- /libft/ft_lstadd_back.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_lstadd_back.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/12/01 19:56:07 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/08 12:22:04 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_lstadd_back adds a new node to the back of a list: 18 | [.]->[.]->[.]->[NEW]->[NULL] 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_lstadd_back(t_list **alst, t_list *new) 25 | { 26 | t_list *tmp; 27 | 28 | if (!new) 29 | return ; 30 | if (!*alst) 31 | { 32 | *alst = new; 33 | return ; 34 | } 35 | tmp = ft_lstlast(*alst); 36 | tmp->next = new; 37 | } 38 | -------------------------------------------------------------------------------- /sources/builtins/env_builtin.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* env_builtin.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 18:55:54 by mcombeau #+# #+# */ 9 | /* Updated: 2022/09/19 15:41:22 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* env_builtin: 16 | * Executes the builtin env command: Prints the environment variables. 17 | */ 18 | int env_builtin(t_data *data, char **args) 19 | { 20 | int i; 21 | 22 | if (args && args[1]) 23 | return (errmsg_cmd("env", NULL, "too many arguments", 2)); 24 | i = 0; 25 | if (!data->env) 26 | return (EXIT_FAILURE); 27 | while (data->env[i]) 28 | ft_putendl_fd(data->env[i++], STDOUT_FILENO); 29 | return (EXIT_SUCCESS); 30 | } 31 | -------------------------------------------------------------------------------- /libft/ft_calloc.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_calloc.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/26 15:28:22 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:49:19 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_calloc allocates memory for an array of count elements 18 | of size bytes each and sets the memory to zero. 19 | 20 | RETURN VALUE : 21 | The pointer to the allocated memory. NULL if the memory allocation fails. 22 | */ 23 | 24 | void *ft_calloc(size_t count, size_t size) 25 | { 26 | void *r; 27 | 28 | r = malloc(count * size); 29 | if (!r) 30 | return (NULL); 31 | ft_bzero(r, size * count); 32 | return (r); 33 | } 34 | -------------------------------------------------------------------------------- /libft/ft_lstnew.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_lstnew.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/30 17:28:58 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 15:13:17 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_lstnew allocates memory for a new list node and 18 | initializes its content to the value passed as parameter, before 19 | setting its next node to NULL. 20 | 21 | RESULT VALUE : 22 | The new list ode. 23 | */ 24 | 25 | t_list *ft_lstnew(void *content) 26 | { 27 | t_list *list; 28 | 29 | list = malloc(sizeof(t_list)); 30 | if (!list) 31 | return (NULL); 32 | list->content = content; 33 | list->next = NULL; 34 | return (list); 35 | } 36 | -------------------------------------------------------------------------------- /libft/ft_memset.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_memset.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:48:14 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/03 12:05:11 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_memset fills the first len bytes of the memory area 18 | pointed to by b with the byte c. Both b and c are interpreted as 19 | unsigned char. 20 | 21 | RETURN VALUE : 22 | A pointer to memory area s. 23 | */ 24 | 25 | void *ft_memset(void *b, int c, size_t len) 26 | { 27 | unsigned char *p; 28 | unsigned char ch; 29 | 30 | p = (unsigned char *)b; 31 | ch = c; 32 | while (len--) 33 | { 34 | *p = ch; 35 | p++; 36 | } 37 | return (b); 38 | } 39 | -------------------------------------------------------------------------------- /libft/ft_strdup.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strdup.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/26 16:03:27 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 15:58:22 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strdup duplicates the given string s1 by allocating 18 | memory and performing a copy of the given string. 19 | 20 | RETURN VALUE : 21 | A pointer to the new string. NULL if the memory allocation fails. 22 | */ 23 | 24 | char *ft_strdup(const char *s1) 25 | { 26 | char *s2; 27 | size_t len; 28 | 29 | len = ft_strlen(s1) + 1; 30 | s2 = malloc(len * sizeof(char)); 31 | if (!s2) 32 | return (NULL); 33 | ft_strlcpy(s2, s1, len); 34 | return (s2); 35 | } 36 | -------------------------------------------------------------------------------- /libft/ft_lstclear.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_lstclear.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/12/01 20:11:58 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/05 13:09:17 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_lstclear deletes each node of a list with the function 18 | passed as parameter. It also frees the memory of each node and finally 19 | sets the list pointer to NULL. 20 | 21 | RETURN VALUE : 22 | None. 23 | */ 24 | 25 | void ft_lstclear(t_list **lst, void (*del)(void *)) 26 | { 27 | t_list *tmp; 28 | 29 | if (!lst) 30 | return ; 31 | while (*lst) 32 | { 33 | tmp = (*lst)->next; 34 | ft_lstdelone(*lst, del); 35 | *lst = tmp; 36 | } 37 | *lst = NULL; 38 | } 39 | -------------------------------------------------------------------------------- /libft/ft_putnbr_fd.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_putnbr_fd.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/28 06:22:02 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 15:44:08 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_putnbr_fd writes the given integer n on the given 18 | file descriptor by converting it into char. 19 | 20 | RETURN VALUE : 21 | None. 22 | */ 23 | 24 | void ft_putnbr_fd(int n, int fd) 25 | { 26 | long nbr; 27 | 28 | nbr = n; 29 | if (nbr < 0) 30 | { 31 | ft_putchar_fd('-', fd); 32 | nbr = -nbr; 33 | } 34 | if (nbr >= 10) 35 | { 36 | ft_putnbr_fd(nbr / 10, fd); 37 | ft_putchar_fd((nbr % 10) + '0', fd); 38 | } 39 | else 40 | ft_putchar_fd(nbr + '0', fd); 41 | } 42 | -------------------------------------------------------------------------------- /sources/parser/cmd_lst_utils_cleanup.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* cmd_lst_utils_cleanup.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:21:24 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:21:27 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | void lst_delone_cmd(t_command *lst, void (*del)(void *)) 16 | { 17 | if (lst->command) 18 | (*del)(lst->command); 19 | if (lst->args) 20 | free_str_tab(lst->args); 21 | if (lst->pipe_fd) 22 | (*del)(lst->pipe_fd); 23 | if (lst->io_fds) 24 | free_io(lst->io_fds); 25 | (*del)(lst); 26 | } 27 | 28 | void lst_clear_cmd(t_command **lst, void (*del)(void *)) 29 | { 30 | t_command *temp; 31 | 32 | temp = NULL; 33 | while (*lst != NULL) 34 | { 35 | temp = (*lst)->next; 36 | lst_delone_cmd(*lst, del); 37 | *lst = temp; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /libft/ft_strchr.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strchr.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:53:33 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/05 15:35:48 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strchr finds the first occurence of character c in 18 | string str. 19 | 20 | RETURN VALUE : 21 | A pointer to the first occurence of c in str. 22 | NULL if c is not found. 23 | */ 24 | 25 | char *ft_strchr(const char *str, int c) 26 | { 27 | int i; 28 | unsigned char ch; 29 | 30 | i = 0; 31 | ch = c; 32 | if (ch == '\0') 33 | { 34 | i = ft_strlen(str); 35 | return ((char *)str + i++); 36 | } 37 | while (str[i]) 38 | { 39 | if (str[i] == ch) 40 | return ((char *)str + i); 41 | i++; 42 | } 43 | return (NULL); 44 | } 45 | -------------------------------------------------------------------------------- /libft/ft_strrchr.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strrchr.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/24 15:50:46 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/05 15:37:01 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strrchr finds the last occurrence of character c in 18 | string str. 19 | 20 | RETURN VALUE : 21 | A pointer to the last occurrence of c in str. 22 | NULL if c is not found. 23 | */ 24 | 25 | char *ft_strrchr(const char *str, int c) 26 | { 27 | char *p; 28 | unsigned char ch; 29 | size_t offset; 30 | 31 | ch = c; 32 | offset = ft_strlen(str); 33 | p = (char *)str + offset; 34 | if (ch == '\0') 35 | return (p++); 36 | while (p >= str) 37 | { 38 | if (*p == ch) 39 | return (p); 40 | p--; 41 | } 42 | p = NULL; 43 | return (p); 44 | } 45 | -------------------------------------------------------------------------------- /libft/ft_strncmp.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strncmp.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/24 17:09:14 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/06 15:15:37 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strncmp compares the first n bytes of the given strings 18 | s1 and s2. 19 | 20 | RETURN VALUE : 21 | An integer less than, equal to, or greater than zero if one of the first 22 | n bytes of s1 is found to be less than, to match, or to be greater than 23 | s2. 24 | */ 25 | 26 | int ft_strncmp(const char *s1, const char *s2, size_t n) 27 | { 28 | size_t i; 29 | 30 | i = 0; 31 | if (n == 0) 32 | return (0); 33 | while ((s1[i] != '\0' && s2[i] != '\0') 34 | && (i < n - 1) && s1[i] == s2[i]) 35 | i++; 36 | return ((unsigned char)s1[i] - (unsigned char)s2[i]); 37 | } 38 | -------------------------------------------------------------------------------- /sources/builtins/pwd_builtin.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* pwd_builtin.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 18:30:28 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/05 12:17:15 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* pwd_builtin: 16 | * Executes the builtin pwd command and displays the 17 | * current working directory path. 18 | * Returns 0 if successful, 1 if an error occured. 19 | */ 20 | int pwd_builtin(t_data *data, char **args) 21 | { 22 | char buf[PATH_MAX]; 23 | char *cwd; 24 | 25 | (void)args; 26 | if (data->working_dir) 27 | { 28 | ft_putendl_fd(data->working_dir, STDOUT_FILENO); 29 | return (EXIT_SUCCESS); 30 | } 31 | cwd = getcwd(buf, PATH_MAX); 32 | if (cwd) 33 | { 34 | ft_putendl_fd(cwd, STDOUT_FILENO); 35 | return (EXIT_SUCCESS); 36 | } 37 | errmsg_cmd("pwd", NULL, strerror(errno), errno); 38 | return (EXIT_FAILURE); 39 | } 40 | -------------------------------------------------------------------------------- /libft/ft_atoi.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_atoi.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/24 18:06:58 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:48:58 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_atoi converts a string into an int. 18 | 19 | RETURN VALUE : 20 | The converted int. 21 | */ 22 | 23 | int ft_atoi(const char *str) 24 | { 25 | int num; 26 | int isneg; 27 | int i; 28 | 29 | num = 0; 30 | isneg = 1; 31 | i = 0; 32 | while (str[i] && (str[i] == ' ' || str[i] == '\t' 33 | || str[i] == '\n' || str[i] == '\r' 34 | || str[i] == '\v' || str[i] == '\f')) 35 | i++; 36 | if (str[i] == '+') 37 | i++; 38 | else if (str[i] == '-') 39 | { 40 | isneg *= -1; 41 | i++; 42 | } 43 | while (ft_isdigit(str[i])) 44 | { 45 | num = (num * 10) + (str[i] - '0'); 46 | i++; 47 | } 48 | return (num * isneg); 49 | } 50 | -------------------------------------------------------------------------------- /libft/ft_memchr.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_memchr.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/25 21:57:14 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/03 16:31:15 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_memchr searches n bytes of the memory area pointed to 18 | by s for the first occurence of c. Both c and the bytes of s are 19 | interpreted as unsigned char. 20 | 21 | RETURN VALUE: 22 | A pointer to the matching byte. NULL if the character does not occur 23 | in the given memory area. 24 | */ 25 | 26 | void *ft_memchr(const void *s, int c, size_t n) 27 | { 28 | size_t i; 29 | unsigned char ch; 30 | const unsigned char *str; 31 | 32 | ch = c; 33 | str = (const unsigned char *)s; 34 | i = 0; 35 | while (i < n) 36 | { 37 | if (str[i] == ch) 38 | return ((void *)s + i); 39 | i++; 40 | } 41 | return (0); 42 | } 43 | -------------------------------------------------------------------------------- /libft/ft_memcpy.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_memcpy.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/23 15:02:13 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 15:26:40 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_memcpy copies n bytes from memory area src to memory 18 | area dst. 19 | Does not account for memory overlaps. Use ft_memmove if the memory areas 20 | overlap or might overlap. 21 | 22 | RETURN VALUE : 23 | A pointer to dst. NULL if src and dst are both NULL. 24 | */ 25 | 26 | void *ft_memcpy(void *dst, const void *src, size_t n) 27 | { 28 | char *dp; 29 | const char *sp; 30 | 31 | if (!dst && !src) 32 | return (0); 33 | if (n == 0 || (dst == src)) 34 | return (dst); 35 | dp = (char *)dst; 36 | sp = (const char *)src; 37 | while (n != 0) 38 | { 39 | if (*dp != *sp) 40 | *dp = *sp; 41 | dp++; 42 | sp++; 43 | n--; 44 | } 45 | return (dst); 46 | } 47 | -------------------------------------------------------------------------------- /libft/ft_strjoin.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strjoin.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/26 18:18:15 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/06 15:09:40 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strjoin concatenates the given strings s1 and s2 18 | and allocates sufficient memory for the newly created string. 19 | 20 | RETURN VALUE : 21 | A pointer to the new concatenated string. 22 | NULL if the memory allocation fails. 23 | */ 24 | 25 | char *ft_strjoin(char const *s1, char const *s2) 26 | { 27 | char *s; 28 | size_t len; 29 | int i; 30 | 31 | len = ft_strlen(s1) + ft_strlen(s2); 32 | s = ft_calloc(len + 1, sizeof(char)); 33 | if (!s) 34 | return (NULL); 35 | len = 0; 36 | while (s1[len]) 37 | { 38 | s[len] = s1[len]; 39 | len++; 40 | } 41 | i = 0; 42 | while (s2[i]) 43 | { 44 | s[len + i] = s2[i]; 45 | i++; 46 | } 47 | return (s); 48 | } 49 | -------------------------------------------------------------------------------- /libft/ft_strmapi.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strmapi.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/28 04:35:39 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:21:12 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESRIPTION : 17 | The function ft_strmapi applies the given function f to each character 18 | in the given string s and allocates sufficient memory to store the 19 | resulting new string. 20 | 21 | RETURN VALUE : 22 | A pointer to the newly created string. NULL if the memory allocation 23 | fails. 24 | */ 25 | 26 | char *ft_strmapi(char const *s, char (*f)(unsigned int, char)) 27 | { 28 | char *str; 29 | unsigned int i; 30 | 31 | if (!s || (!s && !f)) 32 | return (ft_strdup("")); 33 | else if (!f) 34 | return (ft_strdup(s)); 35 | str = ft_strdup(s); 36 | if (!str) 37 | return (NULL); 38 | i = 0; 39 | while (s[i]) 40 | { 41 | str[i] = (*f)(i, s[i]); 42 | i++; 43 | } 44 | return (str); 45 | } 46 | -------------------------------------------------------------------------------- /libft/ft_memcmp.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_memcmp.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/25 22:41:23 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:51:42 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_memcmp compares the first n bytes of the memory areas 18 | s1 and s2. The bytes are interpreted as unsigned char. 19 | 20 | RETURN VALUE : 21 | An integer less than, equal to, or greater than zero if the first 22 | n bytes of s1 is found to be less than, equal to, or greater than the 23 | first n bytes of s2. Zero if n is equal to zero. 24 | */ 25 | 26 | int ft_memcmp(const void *s1, const void *s2, size_t n) 27 | { 28 | const char *str1; 29 | const char *str2; 30 | size_t i; 31 | 32 | if (n == 0) 33 | return (0); 34 | str1 = (const char *)s1; 35 | str2 = (const char *)s2; 36 | i = 0; 37 | while ((i < n - 1) && str1[i] == str2[i]) 38 | i++; 39 | return ((unsigned char)str1[i] - (unsigned char)str2[i]); 40 | } 41 | -------------------------------------------------------------------------------- /libft/ft_strlcpy.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strlcpy.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/24 14:16:24 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/03 16:32:30 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strlcpy copies up to size - 1 characters from the given 18 | string src to the given string dst, nul-terminating the result. 19 | 20 | Note : space for the terminating \0 character must be included in dstsize. 21 | 22 | RETURN VALUE : 23 | The total length of the string that it tried to create : the length of 24 | src, with the goal to facilitate truncaction detection. 25 | */ 26 | 27 | size_t ft_strlcpy(char *dst, const char *src, size_t dstsize) 28 | { 29 | size_t i; 30 | size_t srclen; 31 | 32 | srclen = ft_strlen(src); 33 | if (dstsize == 0) 34 | return (srclen); 35 | i = 0; 36 | while (i < (dstsize - 1) && src[i] != '\0') 37 | { 38 | dst[i] = src[i]; 39 | i++; 40 | } 41 | dst[i] = '\0'; 42 | return (srclen); 43 | } 44 | -------------------------------------------------------------------------------- /sources/lexer/check_if_var.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* check_if_var.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/15 23:40:24 by alexa #+# #+# */ 9 | /* Updated: 2022/09/23 15:20:27 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static void variable_check(t_token **token_node) 16 | { 17 | int i; 18 | 19 | i = 0; 20 | while ((*token_node)->str[i]) 21 | { 22 | if ((*token_node)->str[i] == '$') 23 | { 24 | if ((*token_node)->prev && (*token_node)->prev->type == HEREDOC) 25 | break ; 26 | (*token_node)->type = VAR; 27 | return ; 28 | } 29 | i++; 30 | } 31 | } 32 | 33 | int check_if_var(t_token **token_lst) 34 | { 35 | t_token *temp; 36 | 37 | temp = *token_lst; 38 | if (temp->type == PIPE) 39 | { 40 | errmsg("syntax error near unexpected token", temp->str, true); 41 | return (FAILURE); 42 | } 43 | while (temp) 44 | { 45 | variable_check(&temp); 46 | if (check_consecutives(&temp) == FAILURE) 47 | return (FAILURE); 48 | temp = temp->next; 49 | } 50 | return (SUCCESS); 51 | } 52 | -------------------------------------------------------------------------------- /libft/ft_substr.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_substr.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/26 16:50:44 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:53:34 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_substr extracts a substring from the given string by 18 | allocating sufficient memory for the new string starting at index start 19 | and ending at len characters. 20 | 21 | RETURN VALUE : 22 | A pointer to the new string. 23 | NULL if the memory allocation fails. 24 | */ 25 | 26 | char *ft_substr(char const *s, unsigned int start, size_t len) 27 | { 28 | char *res; 29 | char *src; 30 | size_t reslen; 31 | 32 | if (!s) 33 | return (NULL); 34 | if (ft_strlen(s) < (size_t)start) 35 | return (ft_strdup("")); 36 | src = (char *)s + start; 37 | if (ft_strlen(src) < len) 38 | reslen = ft_strlen(src) + 1; 39 | else 40 | reslen = len + 1; 41 | res = malloc(reslen * sizeof(char)); 42 | if (!res) 43 | return (NULL); 44 | ft_strlcpy(res, src, reslen); 45 | return (res); 46 | } 47 | -------------------------------------------------------------------------------- /sources/expansion/var_expander_utils.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* var_expander_utils.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:52:09 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:52:18 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | void copy_var_value(char *new_str, char *var_value, int *j) 16 | { 17 | int k; 18 | 19 | k = 0; 20 | while (var_value[k]) 21 | { 22 | new_str[*j] = var_value[k]; 23 | k++; 24 | (*j)++; 25 | } 26 | } 27 | 28 | char *get_new_token_string(char *oldstr, char *var_value, 29 | int newstr_size, int index) 30 | { 31 | int i; 32 | int j; 33 | char *new_str; 34 | 35 | i = 0; 36 | j = 0; 37 | new_str = malloc(sizeof(char) * newstr_size); 38 | if (!new_str) 39 | return (NULL); 40 | while (oldstr[i]) 41 | { 42 | if (oldstr[i] == '$' && i == index) 43 | { 44 | copy_var_value(new_str, var_value, &j); 45 | i = i + var_length(oldstr + index) + 1; 46 | if (oldstr[i] == '\0') 47 | break ; 48 | } 49 | new_str[j++] = oldstr[i++]; 50 | } 51 | new_str[j] = '\0'; 52 | return (new_str); 53 | } 54 | -------------------------------------------------------------------------------- /sources/lexer/token_lst_utils_2.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* token_lst_utils_2.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/16 00:10:55 by alexa #+# #+# */ 9 | /* Updated: 2022/10/06 14:44:13 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static void link_extremities(t_token *to_del, t_token *temp, t_token *insert) 16 | { 17 | while (temp != to_del) 18 | temp = temp->next; 19 | insert->prev = temp->prev; 20 | temp->prev->next = insert; 21 | while (insert->next) 22 | insert = insert->next; 23 | temp->next->prev = insert; 24 | insert->next = temp->next; 25 | } 26 | 27 | t_token *insert_lst_between(t_token **head, t_token *to_del, t_token *insert) 28 | { 29 | t_token *temp; 30 | 31 | temp = *head; 32 | if (temp == NULL) 33 | *head = insert; 34 | else if (temp == to_del) 35 | { 36 | *head = insert; 37 | insert->next = temp->next; 38 | if (temp->next != NULL) 39 | temp->next->prev = insert; 40 | } 41 | else 42 | link_extremities(to_del, temp, insert); 43 | free_ptr(to_del->str); 44 | free_ptr(to_del); 45 | return (insert); 46 | } 47 | -------------------------------------------------------------------------------- /sources/builtins/unset_builtin.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* unset_builtin.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 18:29:52 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/05 12:17:21 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* unset_builtin: 16 | * Removes the environment variables with the given keys 17 | * after checking if they are valid keys. 18 | * Does nothing if the key is not in the environment. 19 | * Returns 0 if all args were successfully unset, or 1 if 20 | * one or more args could not be unset. 21 | */ 22 | int unset_builtin(t_data *data, char **args) 23 | { 24 | int i; 25 | int idx; 26 | int ret; 27 | 28 | ret = EXIT_SUCCESS; 29 | i = 1; 30 | while (args[i]) 31 | { 32 | if (!is_valid_env_var_key(args[i]) || ft_strchr(args[i], '=') != NULL) 33 | { 34 | errmsg_cmd("unset", args[i], "not a valid identifier", false); 35 | ret = EXIT_FAILURE; 36 | } 37 | else 38 | { 39 | idx = get_env_var_index(data->env, args[i]); 40 | if (idx != -1) 41 | remove_env_var(data, idx); 42 | } 43 | i++; 44 | } 45 | return (ret); 46 | } 47 | -------------------------------------------------------------------------------- /libft/ft_memmove.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_memmove.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/23 15:57:19 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:48:38 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_memmove copies n bytes from memory area src to memory 18 | area dst. The memory areas may overlap: if the dst pointer is found 19 | to be between the src pointer and the index n, copying will be done 20 | back to front to prevent data being modified before being copied. 21 | Otherwise it will be done front to back to preserve data. 22 | 23 | RETURN VALUE : 24 | A pointer to dst. 25 | */ 26 | 27 | void *ft_memmove(void *dst, const void *src, size_t len) 28 | { 29 | char *dp; 30 | const char *sp; 31 | 32 | if (src == dst) 33 | return (dst); 34 | dp = (char *)dst; 35 | sp = (const char *)src; 36 | if (sp < dp && sp + len > dp) 37 | while (len--) 38 | *(dp + len) = *(sp + len); 39 | else 40 | { 41 | while (len--) 42 | { 43 | *dp = *sp; 44 | sp++; 45 | dp++; 46 | } 47 | } 48 | return (dst); 49 | } 50 | -------------------------------------------------------------------------------- /libft/ft_strnstr.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strnstr.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/25 23:07:33 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/03 16:33:24 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strnstr searches the first n bytes of the given string 18 | s1 for the first occurence of the full string s2. 19 | Characters that appear after \0 are not searched. 20 | 21 | RETURN VALUE : 22 | A pointer to the first character of the first occurrence of s2. 23 | A pointer to s1 if s2 is empty. 24 | NULL if s2 occurs nowhere in s1. 25 | */ 26 | 27 | char *ft_strnstr(const char *s1, const char *s2, size_t n) 28 | { 29 | size_t s2len; 30 | size_t i; 31 | size_t j; 32 | 33 | s2len = ft_strlen(s2); 34 | if (s1 == s2 || s2len == 0) 35 | return ((char *)s1); 36 | i = 0; 37 | while (i < n && s1[i] != '\0') 38 | { 39 | j = 0; 40 | while (s1[i + j] != '\0' && s2[j] != '\0' 41 | && (i + j) < n && s1[i + j] == s2[j]) 42 | { 43 | j++; 44 | if ((j == n && j == s2len) || j == s2len) 45 | return ((char *)(s1 + i)); 46 | } 47 | i++; 48 | } 49 | return (0); 50 | } 51 | -------------------------------------------------------------------------------- /libft/ft_strlcat.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strlcat.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/24 15:14:19 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/02 16:13:28 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strlcat appends the given string src to the end of 18 | dst. It will append at most dstsize - ft_strlen(dst) - 1 and 19 | nul-terminate the result. 20 | 21 | Note : space for the terminating \0 character must be included in dstsize. 22 | 23 | RETURN VALUE : 24 | The total length of the string that it tried to create : the initial 25 | length of dst + the length of src, with the goal to facilitate 26 | truncaction detection. 27 | */ 28 | 29 | size_t ft_strlcat(char *dst, const char *src, size_t dstsize) 30 | { 31 | size_t i; 32 | size_t j; 33 | size_t d_size; 34 | size_t s_size; 35 | 36 | d_size = ft_strlen(dst); 37 | s_size = ft_strlen(src); 38 | if (dstsize <= d_size) 39 | return (dstsize + s_size); 40 | i = d_size; 41 | j = 0; 42 | while ((i + j) < (dstsize - 1) && src[j] != '\0') 43 | { 44 | dst[i + j] = src[j]; 45 | j++; 46 | } 47 | dst[i + j] = '\0'; 48 | return (d_size + s_size); 49 | } 50 | -------------------------------------------------------------------------------- /libft/ft_strtrim.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_strtrim.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/27 16:51:42 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/03 16:21:52 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_strtrim removes any characters of the given set from 18 | the beginning and end of the given string s1, and allocates sufficient 19 | memory to store the trimmed copy of the string. 20 | 21 | RETURN VALUE : 22 | A pointer to the trimmed copy of the string. 23 | NULL if the memory allocation fails. 24 | */ 25 | 26 | static int is_set(char c, char const *set) 27 | { 28 | int i; 29 | 30 | i = 0; 31 | while (set[i]) 32 | { 33 | if (set[i] == c) 34 | return (1); 35 | i++; 36 | } 37 | return (0); 38 | } 39 | 40 | char *ft_strtrim(char const *s1, char const *set) 41 | { 42 | size_t start; 43 | size_t end; 44 | 45 | if (!s1) 46 | return (ft_strdup("")); 47 | if (!set) 48 | return (ft_strdup(s1)); 49 | start = 0; 50 | end = ft_strlen(s1); 51 | while (is_set(s1[start], set)) 52 | start++; 53 | if (start == end) 54 | return (ft_strdup("")); 55 | while (is_set(s1[end - 1], set)) 56 | end--; 57 | return (ft_substr(s1, start, end - start)); 58 | } 59 | -------------------------------------------------------------------------------- /sources/lexer/parse_user_input.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* parse_user_input.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:01:18 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:01:22 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static bool input_is_space(char *input) 16 | { 17 | int i; 18 | 19 | i = 0; 20 | while (input[i]) 21 | { 22 | if (!ft_isspace(input[i])) 23 | return (false); 24 | i++; 25 | } 26 | return (true); 27 | } 28 | 29 | /* parse_user_input: 30 | * Tokenizes and parses user input into a structure for execution. 31 | * Returns true if successful, false in case of error. 32 | */ 33 | bool parse_user_input(t_data *data) 34 | { 35 | if (data->user_input == NULL) 36 | exit_builtin(data, NULL); 37 | else if (ft_strcmp(data->user_input, "\0") == 0) 38 | return (false); 39 | else if (input_is_space(data->user_input)) 40 | return (true); 41 | add_history(data->user_input); 42 | if (tokenization(data, data->user_input) == FAILURE) 43 | return (false); 44 | if (data->token->type == END) 45 | return (false); 46 | if (check_if_var(&data->token) == FAILURE) 47 | return (false); 48 | var_expander(data, &data->token); 49 | handle_quotes(data); 50 | create_commands(data, data->token); 51 | return (true); 52 | } 53 | -------------------------------------------------------------------------------- /sources/expansion/identify_var.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* identify_var.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/20 15:14:08 by alexa #+# #+# */ 9 | /* Updated: 2022/11/04 12:32:48 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | bool is_var_compliant(char c) 16 | { 17 | if (ft_isalnum(c) == 0 && c != '_') 18 | return (false); 19 | else 20 | return (true); 21 | } 22 | 23 | int var_length(char *str) 24 | { 25 | int i; 26 | int count; 27 | 28 | count = 0; 29 | i = 0; 30 | while (str[i] != '$') 31 | i++; 32 | i++; 33 | if ((str[i] >= '0' && str[i] <= '9') || str[i] == '?') 34 | return (count + 1); 35 | while (str[i]) 36 | { 37 | if (is_var_compliant(str[i]) == false) 38 | break ; 39 | count++; 40 | i++; 41 | } 42 | return (count); 43 | } 44 | 45 | char *identify_var(char *str) 46 | { 47 | char *var; 48 | char *tmp; 49 | int start; 50 | int len; 51 | int i; 52 | 53 | i = 0; 54 | start = 0; 55 | while (str[i]) 56 | { 57 | if (str[i] == '$') 58 | { 59 | start = i + 1; 60 | break ; 61 | } 62 | i++; 63 | } 64 | len = var_length(str); 65 | var = ft_substr(str, start, len); 66 | if (!var) 67 | return (NULL); 68 | tmp = ft_strjoin(var, "="); 69 | free_ptr(var); 70 | var = tmp; 71 | return (var); 72 | } 73 | -------------------------------------------------------------------------------- /sources/lexer/lexer_grammar.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* lexer_grammar.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/15 23:45:35 by alexa #+# #+# */ 9 | /* Updated: 2022/09/23 15:20:47 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static bool consecutive_ops(t_token *token_node) 16 | { 17 | if (token_node->prev) 18 | { 19 | if (token_node->type == PIPE && token_node->prev->type == PIPE) 20 | return (true); 21 | if (token_node->type > PIPE && token_node->prev->type > PIPE) 22 | return (true); 23 | if (token_node->type == END && token_node->prev->type >= PIPE) 24 | return (true); 25 | } 26 | return (false); 27 | } 28 | 29 | int check_consecutives(t_token **token_lst) 30 | { 31 | t_token *temp; 32 | 33 | temp = *token_lst; 34 | while (temp) 35 | { 36 | if (consecutive_ops(temp) == true) 37 | { 38 | if (temp->type == END && temp->prev && temp->prev->type > PIPE) 39 | errmsg("syntax error near unexpected token", "newline", true); 40 | else if (temp->type == END && temp->prev) 41 | errmsg("syntax error near unexpected token", 42 | temp->prev->str, true); 43 | else 44 | errmsg("syntax error near unexpected token", temp->str, true); 45 | return (FAILURE); 46 | } 47 | temp = temp->next; 48 | } 49 | return (SUCCESS); 50 | } 51 | -------------------------------------------------------------------------------- /libft/ft_lstmap.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_lstmap.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/12/01 20:34:19 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/04 13:13:40 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_lstmap creates a new list from a given list by 18 | applying the function passed as parameter to the original list. If 19 | the memory allocation fails for any node in the new list, the new list 20 | will be deleted with the function passed as parameter and its memory 21 | will be freed. 22 | 23 | RETURN VALUE : 24 | The new list containing the new values if a functon was provided. 25 | A new copy of the list if no function was provided. 26 | NULL if the memory allocation failed. 27 | */ 28 | 29 | t_list *ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *)) 30 | { 31 | t_list *newlst; 32 | t_list *node; 33 | 34 | if (!lst) 35 | return (NULL); 36 | newlst = NULL; 37 | node = NULL; 38 | while (lst) 39 | { 40 | if (!f) 41 | node = ft_lstnew(lst->content); 42 | else 43 | node = ft_lstnew(f(lst->content)); 44 | if (!node) 45 | { 46 | ft_lstclear(&newlst, del); 47 | return (NULL); 48 | } 49 | ft_lstadd_back(&newlst, node); 50 | lst = lst->next; 51 | } 52 | return (newlst); 53 | } 54 | -------------------------------------------------------------------------------- /sources/expansion/recover_value.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* recover_value.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/07 16:26:14 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/07 16:26:15 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static int var_exists(t_data *data, char *var) 16 | { 17 | int i; 18 | int len; 19 | 20 | i = 0; 21 | len = ft_strlen(var); 22 | while (data->env[i]) 23 | { 24 | if (ft_strncmp(data->env[i], var, len) == 0) 25 | return (0); 26 | i++; 27 | } 28 | return (1); 29 | } 30 | 31 | static char *search_env_var(t_data *data, char *var) 32 | { 33 | char *str; 34 | int i; 35 | int len; 36 | 37 | i = 0; 38 | len = ft_strlen(var); 39 | while (data->env[i]) 40 | { 41 | if (ft_strncmp(data->env[i], var, len) == 0) 42 | break ; 43 | i++; 44 | } 45 | str = ft_strdup(data->env[i] + len); 46 | return (str); 47 | } 48 | 49 | char *recover_val(t_token *token, char *str, t_data *data) 50 | { 51 | char *value; 52 | char *var; 53 | 54 | var = identify_var(str); 55 | if (var && var_exists(data, var) == 0) 56 | { 57 | if (token != NULL) 58 | token->var_exists = true; 59 | value = search_env_var(data, var); 60 | } 61 | else if (var && var[0] == '?' && var[1] == '=') 62 | value = ft_itoa(g_last_exit_code); 63 | else 64 | value = NULL; 65 | free_ptr(var); 66 | return (value); 67 | } 68 | -------------------------------------------------------------------------------- /sources/parser/cmd_lst_utils.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* cmd_lst_utils.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:22:15 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:22:18 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static void initialize_cmd(t_command **cmd) 16 | { 17 | (*cmd)->command = NULL; 18 | (*cmd)->path = NULL; 19 | (*cmd)->args = NULL; 20 | (*cmd)->pipe_output = false; 21 | (*cmd)->pipe_fd = 0; 22 | (*cmd)->prev = NULL; 23 | (*cmd)->next = NULL; 24 | } 25 | 26 | t_command *lst_new_cmd(bool value) 27 | { 28 | t_command *new_node; 29 | 30 | new_node = (t_command *)malloc(sizeof(t_command)); 31 | if (!(new_node)) 32 | return (NULL); 33 | ft_memset(new_node, 0, sizeof(t_command)); 34 | new_node->pipe_output = value; 35 | initialize_cmd(&new_node); 36 | return (new_node); 37 | } 38 | 39 | void lst_add_back_cmd(t_command **alst, t_command *new_node) 40 | { 41 | t_command *start; 42 | 43 | start = *alst; 44 | if (start == NULL) 45 | { 46 | *alst = new_node; 47 | return ; 48 | } 49 | if (alst && *alst && new_node) 50 | { 51 | while (start->next != NULL) 52 | start = start->next; 53 | start->next = new_node; 54 | new_node->prev = start; 55 | } 56 | } 57 | 58 | t_command *lst_last_cmd(t_command *cmd) 59 | { 60 | while (cmd->next != NULL) 61 | cmd = cmd->next; 62 | return (cmd); 63 | } 64 | -------------------------------------------------------------------------------- /sources/expansion/quotes_handler.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* quotes_handler.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/20 14:39:40 by alexa #+# #+# */ 9 | /* Updated: 2022/11/05 13:15:10 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | int count_len(char *str, int count, int i) 16 | { 17 | int status; 18 | 19 | status = 0; 20 | while (str[i]) 21 | { 22 | if ((str[i] == '\'' || str[i] == '\"') && status == DEFAULT) 23 | { 24 | if (str[i] == '\'') 25 | status = SQUOTE; 26 | if (str[i] == '\"') 27 | status = DQUOTE; 28 | i++; 29 | continue ; 30 | } 31 | else if ((str[i] == '\'' && status == SQUOTE) 32 | || (str[i] == '\"' && status == DQUOTE)) 33 | { 34 | status = DEFAULT; 35 | i++; 36 | continue ; 37 | } 38 | count++; 39 | i++; 40 | } 41 | return (count + 1); 42 | } 43 | 44 | bool quotes_in_string(char *str) 45 | { 46 | int i; 47 | 48 | i = 0; 49 | while (str[i]) 50 | { 51 | if (str[i] == '\'' || str[i] == '\"') 52 | return (true); 53 | i++; 54 | } 55 | return (false); 56 | } 57 | 58 | int handle_quotes(t_data *data) 59 | { 60 | t_token *temp; 61 | 62 | temp = data->token; 63 | while (temp) 64 | { 65 | if (quotes_in_string(temp->str) == true 66 | && (!temp->prev || (temp->prev && temp->prev->type != HEREDOC))) 67 | remove_quotes(&temp); 68 | temp = temp->next; 69 | } 70 | return (0); 71 | } 72 | -------------------------------------------------------------------------------- /libft/ft_itoa.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_itoa.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/27 18:04:16 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/08 12:12:23 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_itoa converts the integer n into a string of characters. 18 | 19 | RESULT VALUE : 20 | The string of the converted integer. 21 | */ 22 | 23 | static size_t ft_itoa_len(long num) 24 | { 25 | size_t len; 26 | 27 | len = 0; 28 | if (num == 0) 29 | return (1); 30 | if (num < 0) 31 | { 32 | len++; 33 | num = -num; 34 | } 35 | while (num >= 1) 36 | { 37 | len++; 38 | num /= 10; 39 | } 40 | return (len); 41 | } 42 | 43 | static char *ft_num_to_str(long num, char *str, size_t len) 44 | { 45 | str = ft_calloc(len + 1, sizeof(char)); 46 | if (str == NULL) 47 | return (NULL); 48 | if (num < 0) 49 | { 50 | str[0] = '-'; 51 | num = -num; 52 | } 53 | len--; 54 | while (len) 55 | { 56 | str[len] = (num % 10) + '0'; 57 | num /= 10; 58 | len--; 59 | } 60 | if (str[0] != '-') 61 | str[0] = (num % 10) + '0'; 62 | return (str); 63 | } 64 | 65 | char *ft_itoa(int n) 66 | { 67 | long num; 68 | size_t len; 69 | char *str; 70 | 71 | num = n; 72 | len = ft_itoa_len(num); 73 | str = 0; 74 | str = ft_num_to_str(num, str, len); 75 | if (!str) 76 | return (NULL); 77 | return (str); 78 | } 79 | -------------------------------------------------------------------------------- /sources/parser/create_commands.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* create_commands.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:16:58 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:17:32 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static void prep_no_arg_commands(t_data *data) 16 | { 17 | t_command *cmd; 18 | 19 | if (!data || !data->cmd) 20 | return ; 21 | cmd = data->cmd; 22 | while (cmd && cmd->command) 23 | { 24 | if (!cmd->args) 25 | { 26 | cmd->args = malloc(sizeof * cmd->args * 2); 27 | cmd->args[0] = ft_strdup(cmd->command); 28 | cmd->args[1] = NULL; 29 | } 30 | cmd = cmd->next; 31 | } 32 | cmd = lst_last_cmd(data->cmd); 33 | } 34 | 35 | void create_commands(t_data *data, t_token *token) 36 | { 37 | t_token *temp; 38 | 39 | temp = token; 40 | if (temp->type == END) 41 | return ; 42 | while (temp->next != NULL) 43 | { 44 | if (temp == token) 45 | lst_add_back_cmd(&data->cmd, lst_new_cmd(false)); 46 | if (temp->type == WORD || temp->type == VAR) 47 | parse_word(&data->cmd, &temp); 48 | else if (temp->type == INPUT) 49 | parse_input(&data->cmd, &temp); 50 | else if (temp->type == TRUNC) 51 | parse_trunc(&data->cmd, &temp); 52 | else if (temp->type == HEREDOC) 53 | parse_heredoc(data, &data->cmd, &temp); 54 | else if (temp->type == APPEND) 55 | parse_append(&data->cmd, &temp); 56 | else if (temp->type == PIPE) 57 | parse_pipe(&data->cmd, &temp); 58 | else if (temp->type == END) 59 | break ; 60 | } 61 | prep_no_arg_commands(data); 62 | } 63 | -------------------------------------------------------------------------------- /sources/execution/execute_utils.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* execute_utils.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/20 17:28:59 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/04 17:27:57 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* cmd_is_dir: 16 | * Checks if the command is a directory rather than an executable. 17 | * Returns true if the command is a directory, false if not. 18 | */ 19 | bool cmd_is_dir(char *cmd) 20 | { 21 | struct stat cmd_stat; 22 | 23 | ft_memset(&cmd_stat, 0, sizeof(cmd_stat)); 24 | stat(cmd, &cmd_stat); 25 | return (S_ISDIR(cmd_stat.st_mode)); 26 | } 27 | 28 | /* check_command_not_found: 29 | * Searches for the reason a command was not found in the system binaries. 30 | * Returns an error message and status if the command is invalid, 31 | * returns EXIT_SUCCESS if the command is valid and should be executed 32 | * as a local executable. 33 | */ 34 | int check_command_not_found(t_data *data, t_command *cmd) 35 | { 36 | if (ft_strchr(cmd->command, '/') == NULL 37 | && get_env_var_index(data->env, "PATH") != -1) 38 | return (errmsg_cmd(cmd->command, NULL, "command not found", 39 | CMD_NOT_FOUND)); 40 | if (access(cmd->command, F_OK) != 0) 41 | return (errmsg_cmd(cmd->command, NULL, strerror(errno), CMD_NOT_FOUND)); 42 | else if (cmd_is_dir(cmd->command)) 43 | return (errmsg_cmd(cmd->command, NULL, "Is a directory", 44 | CMD_NOT_EXECUTABLE)); 45 | else if (access(cmd->command, F_OK | X_OK) != 0) 46 | return (errmsg_cmd(cmd->command, NULL, strerror(errno), 47 | CMD_NOT_EXECUTABLE)); 48 | return (EXIT_SUCCESS); 49 | } 50 | -------------------------------------------------------------------------------- /libft/Makefile: -------------------------------------------------------------------------------- 1 | # **************************************************************************** # 2 | # # 3 | # ::: :::::::: # 4 | # Makefile :+: :+: :+: # 5 | # +:+ +:+ +:+ # 6 | # By: mcombeau +#+ +:+ +#+ # 7 | # +#+#+#+#+#+ +#+ # 8 | # Created: 2021/11/22 13:48:30 by mcombeau #+# #+# # 9 | # Updated: 2022/09/25 14:50:00 by mcombeau ### ########.fr # 10 | # # 11 | # **************************************************************************** # 12 | 13 | NAME = libft.a 14 | CC = gcc 15 | CFLAGS = -Wall -Werror -Wextra -g3 16 | AR = ar rcs 17 | SRC = ft_isalpha \ 18 | ft_isdigit \ 19 | ft_isalnum \ 20 | ft_isascii \ 21 | ft_isprint \ 22 | ft_isspace \ 23 | ft_strlen \ 24 | ft_memset \ 25 | ft_bzero \ 26 | ft_memcpy \ 27 | ft_memmove \ 28 | ft_strlcpy \ 29 | ft_strlcat \ 30 | ft_toupper \ 31 | ft_tolower \ 32 | ft_strchr \ 33 | ft_strrchr \ 34 | ft_strncmp \ 35 | ft_strcmp \ 36 | ft_memchr \ 37 | ft_memcmp \ 38 | ft_strnstr \ 39 | ft_atoi \ 40 | ft_calloc \ 41 | ft_strdup \ 42 | ft_substr \ 43 | ft_strjoin \ 44 | ft_strtrim \ 45 | ft_split \ 46 | ft_itoa \ 47 | ft_strmapi \ 48 | ft_striteri \ 49 | ft_putchar_fd \ 50 | ft_putstr_fd \ 51 | ft_putendl_fd \ 52 | ft_putnbr_fd 53 | BONUS_SRC = ft_lstnew \ 54 | ft_lstadd_front \ 55 | ft_lstsize \ 56 | ft_lstlast \ 57 | ft_lstadd_back \ 58 | ft_lstdelone \ 59 | ft_lstclear \ 60 | ft_lstiter \ 61 | ft_lstmap 62 | 63 | SRCS = $(addsuffix .c, $(SRC)) 64 | OBJS = $(addsuffix .o, $(SRC)) 65 | BONUS_SRCS = $(addsuffix .c, $(BONUS_SRC)) 66 | BONUS_OBJS = $(addsuffix .o, $(BONUS_SRC)) 67 | 68 | .c.o: $(SRCS) $(BONUS_SRCS) 69 | $(CC) $(CFLAGS) -c -o $@ $< 70 | 71 | $(NAME): $(OBJS) 72 | $(AR) $@ $^ 73 | 74 | bonus: $(OBJS) $(BONUS_OBJS) 75 | $(AR) $(NAME) $^ 76 | 77 | all: $(NAME) 78 | 79 | clean: 80 | rm -f *.o 81 | 82 | fclean: clean 83 | rm -f $(NAME) 84 | 85 | re: clean all 86 | 87 | .PHONY: all clean fclean re bonus 88 | -------------------------------------------------------------------------------- /sources/lexer/tokenization.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* tokenization.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/20 12:31:15 by alexa #+# #+# */ 9 | /* Updated: 2022/09/20 12:31:43 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* 16 | * This function divides the given string (user input) into two 17 | * types of tokens : words or separators (pipes, heredoc , etc) 18 | * It checks each char of the string and defines if it is a separator or 19 | * a word and then saves the token in a linked list. 20 | * Also checks if there is an unclosed quote error and defines which 21 | * separators will be evaluated following the single or double quoting rules: 22 | * 23 | * -Without quotes, bash tries to evaluate all special characters 24 | * -Single quotes (') prevent all evaluation 25 | * -Double quotes (") prevent most evaluation, 26 | * but notably not the evaluation of variables 27 | * 28 | */ 29 | 30 | int tokenization(t_data *data, char *str) 31 | { 32 | int i; 33 | int end; 34 | int start; 35 | int status; 36 | 37 | i = -1; 38 | start = 0; 39 | end = ft_strlen(str); 40 | status = DEFAULT; 41 | while (++i <= end) 42 | { 43 | status = set_status(status, str, i); 44 | if (status == DEFAULT) 45 | start = save_word_or_sep(&i, str, start, data); 46 | } 47 | if (status != DEFAULT) 48 | { 49 | if (status == DQUOTE) 50 | errmsg("unexpected EOF while looking for matching", "\"", true); 51 | else if (status == SQUOTE) 52 | errmsg("unexpected EOF while looking for matching", "\'", true); 53 | errmsg("syntax error", "unexpected end of file", false); 54 | return (1); 55 | } 56 | return (0); 57 | } 58 | -------------------------------------------------------------------------------- /sources/builtins/export_builtin.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* export_builtin.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 18:30:41 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/05 12:17:12 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* get_key_value_pair: 16 | * Separates the given argument into a key-value pair 17 | * for the environment variable. 18 | * Returns an array of 2 strings containing the key and the 19 | * value of the new environment variable. 20 | * Returns NULL in case of error. 21 | */ 22 | static char **get_key_value_pair(char *arg) 23 | { 24 | char **tmp; 25 | char *eq_pos; 26 | 27 | eq_pos = ft_strchr(arg, '='); 28 | tmp = malloc(sizeof * tmp * (2 + 1)); 29 | tmp[0] = ft_substr(arg, 0, eq_pos - arg); 30 | tmp[1] = ft_substr(eq_pos, 1, ft_strlen(eq_pos)); 31 | tmp[2] = NULL; 32 | return (tmp); 33 | } 34 | 35 | /* export_builtin: 36 | * Adds the given variables to the environment variables. 37 | * Returns 0 if all args were successfully added to env, 38 | * or 1 if one or more args were not added to env. 39 | */ 40 | int export_builtin(t_data *data, char **args) 41 | { 42 | int i; 43 | char **tmp; 44 | int ret; 45 | 46 | ret = EXIT_SUCCESS; 47 | i = 1; 48 | if (!args[i]) 49 | return (env_builtin(data, NULL)); 50 | while (args[i]) 51 | { 52 | if (!is_valid_env_var_key(args[i])) 53 | { 54 | errmsg_cmd("export", args[i], "not a valid identifier", false); 55 | ret = EXIT_FAILURE; 56 | } 57 | else if (ft_strchr(args[i], '=') != NULL) 58 | { 59 | tmp = get_key_value_pair(args[i]); 60 | set_env_var(data, tmp[0], tmp[1]); 61 | free_str_tab(tmp); 62 | } 63 | i++; 64 | } 65 | return (ret); 66 | } 67 | -------------------------------------------------------------------------------- /sources/lexer/token_lst_utils.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* token_lst_utils.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/15 23:50:28 by alexa #+# #+# */ 9 | /* Updated: 2022/11/07 14:49:40 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | t_token *lst_new_token(char *str, char *str_backup, int type, int status) 16 | { 17 | t_token *new_node; 18 | 19 | new_node = malloc(sizeof(t_token) * 1); 20 | if (!(new_node)) 21 | return (NULL); 22 | new_node->str = str; 23 | new_node->str_backup = str_backup; 24 | new_node->var_exists = false; 25 | new_node->type = type; 26 | new_node->status = status; 27 | new_node->join = false; 28 | new_node->prev = NULL; 29 | new_node->next = NULL; 30 | return (new_node); 31 | } 32 | 33 | void lst_add_back_token(t_token **alst, t_token *new_node) 34 | { 35 | t_token *start; 36 | 37 | start = *alst; 38 | if (start == NULL) 39 | { 40 | *alst = new_node; 41 | return ; 42 | } 43 | if (alst && *alst && new_node) 44 | { 45 | while (start->next != NULL) 46 | start = start->next; 47 | start->next = new_node; 48 | new_node->prev = start; 49 | } 50 | } 51 | 52 | void lstdelone_token(t_token *lst, void (*del)(void *)) 53 | { 54 | if (del && lst && lst->str) 55 | { 56 | (*del)(lst->str); 57 | lst->str = NULL; 58 | } 59 | if (del && lst && lst->str_backup) 60 | { 61 | (*del)(lst->str_backup); 62 | lst->str_backup = NULL; 63 | } 64 | if (lst->prev) 65 | lst->prev->next = lst->next; 66 | if (lst->next) 67 | lst->next->prev = lst->prev; 68 | free_ptr(lst); 69 | } 70 | 71 | void lstclear_token(t_token **lst, void (*del)(void *)) 72 | { 73 | t_token *tmp; 74 | 75 | tmp = NULL; 76 | while (*lst != NULL) 77 | { 78 | tmp = (*lst)->next; 79 | lstdelone_token(*lst, del); 80 | *lst = tmp; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /sources/builtins/echo_builtin.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* echo_builtin.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 18:55:59 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/03 15:48:44 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* is_n_flag: 16 | * Checks whether an arg is an -n option flag. 17 | * Returns true if the arg is some variation of -n, -nnnn, -nn, etc. 18 | * Returns false if it contains anything other than - and n (ex. --n -nnnm -n1234) 19 | */ 20 | static bool is_n_flag(char *arg) 21 | { 22 | int i; 23 | bool n_flag; 24 | 25 | n_flag = false; 26 | i = 0; 27 | if (arg[i] != '-') 28 | return (n_flag); 29 | i++; 30 | while (arg[i] && arg[i] == 'n') 31 | i++; 32 | if (arg[i] == '\0') 33 | n_flag = true; 34 | return (n_flag); 35 | } 36 | 37 | /* echo_print_args: 38 | * Prints the given array of aruments to STDOUT. 39 | */ 40 | static void echo_print_args(char **args, bool n_flag, int i) 41 | { 42 | if (!args[i]) 43 | { 44 | if (!n_flag) 45 | ft_putchar_fd('\n', STDOUT_FILENO); 46 | return ; 47 | } 48 | while (args[i]) 49 | { 50 | ft_putstr_fd(args[i], STDOUT_FILENO); 51 | if (args[i + 1]) 52 | ft_putchar_fd(' ', STDOUT_FILENO); 53 | else if (!args[i + 1] && !n_flag) 54 | ft_putchar_fd('\n', STDOUT_FILENO); 55 | i++; 56 | } 57 | } 58 | 59 | /* echo_builtin: 60 | * Executes the echo builtin command: prints the given strings 61 | * and adds a \n character or not depending on the -n option. 62 | * Returns 1 on completion. 63 | */ 64 | int echo_builtin(t_data *data, char **args) 65 | { 66 | int i; 67 | bool n_flag; 68 | 69 | (void)data; 70 | n_flag = false; 71 | i = 1; 72 | while (args[i] && is_n_flag(args[i])) 73 | { 74 | n_flag = true; 75 | i++; 76 | } 77 | echo_print_args(args, n_flag, i); 78 | return (EXIT_SUCCESS); 79 | } 80 | -------------------------------------------------------------------------------- /sources/expansion/quotes_remover.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* quotes_remover.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/20 14:42:10 by alexa #+# #+# */ 9 | /* Updated: 2022/10/06 14:43:22 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static void change_status_to_quote(t_token **token_node, int *i) 16 | { 17 | if ((*token_node)->str[*i] == '\'') 18 | (*token_node)->status = SQUOTE; 19 | if ((*token_node)->str[*i] == '\"') 20 | (*token_node)->status = DQUOTE; 21 | (*i)++; 22 | } 23 | 24 | static bool if_quotes_and_default(t_token **token_node, int i) 25 | { 26 | if (((*token_node)->str[i] == '\'' || (*token_node)->str[i] == '\"') 27 | && (*token_node)->status == DEFAULT) 28 | return (true); 29 | else 30 | return (false); 31 | } 32 | 33 | static bool change_back_to_default(t_token **token_node, int *i) 34 | { 35 | if (((*token_node)->str[*i] == '\'' && (*token_node)->status == SQUOTE) 36 | || ((*token_node)->str[*i] == '\"' && (*token_node)->status == DQUOTE)) 37 | { 38 | (*token_node)->status = DEFAULT; 39 | (*i)++; 40 | return (true); 41 | } 42 | else 43 | return (false); 44 | } 45 | 46 | int remove_quotes(t_token **token_node) 47 | { 48 | char *new_line; 49 | int i; 50 | int j; 51 | 52 | i = 0; 53 | j = 0; 54 | new_line = malloc(sizeof(char) * count_len((*token_node)->str, i, i)); 55 | if (!new_line) 56 | return (1); 57 | while ((*token_node)->str[i]) 58 | { 59 | if (if_quotes_and_default(token_node, i) == true) 60 | { 61 | change_status_to_quote(token_node, &i); 62 | continue ; 63 | } 64 | else if (change_back_to_default(token_node, &i) == true) 65 | continue ; 66 | new_line[j++] = (*token_node)->str[i++]; 67 | } 68 | new_line[j] = '\0'; 69 | free_ptr((*token_node)->str); 70 | (*token_node)->str = new_line; 71 | (*token_node)->join = true; 72 | return (0); 73 | } 74 | -------------------------------------------------------------------------------- /sources/parser/parse_word.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* parse_word.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:21:47 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:22:01 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static bool contains_space(char *str) 16 | { 17 | int i; 18 | 19 | i = 0; 20 | while (str[i]) 21 | { 22 | if (str[i] == ' ') 23 | return (true); 24 | i++; 25 | } 26 | return (false); 27 | } 28 | 29 | static void split_var_cmd_token(t_command *last_cmd, char *cmd_str) 30 | { 31 | t_token *new_tokens; 32 | t_token *tmp; 33 | char **strs; 34 | int i; 35 | 36 | new_tokens = NULL; 37 | strs = ft_split(cmd_str, ' '); 38 | if (!strs) 39 | return ; 40 | last_cmd->command = ft_strdup(strs[0]); 41 | if (strs[1]) 42 | new_tokens = lst_new_token(ft_strdup(strs[1]), NULL, WORD, DEFAULT); 43 | tmp = new_tokens; 44 | i = 1; 45 | while (strs[++i]) 46 | lst_add_back_token(&new_tokens, 47 | lst_new_token(ft_strdup(strs[i]), NULL, WORD, DEFAULT)); 48 | lst_add_back_token(&new_tokens, 49 | lst_new_token(NULL, NULL, END, DEFAULT)); 50 | fill_args(&new_tokens, last_cmd); 51 | lstclear_token(&tmp, &free_ptr); 52 | free_str_tab(strs); 53 | } 54 | 55 | void parse_word(t_command **cmd, t_token **token_lst) 56 | { 57 | t_token *temp; 58 | t_command *last_cmd; 59 | 60 | temp = *token_lst; 61 | while (temp->type == WORD || temp->type == VAR) 62 | { 63 | last_cmd = lst_last_cmd(*cmd); 64 | if (temp->prev == NULL || (temp->prev && temp->prev->type == PIPE) 65 | || last_cmd->command == NULL) 66 | { 67 | if (temp->type == VAR && contains_space(temp->str)) 68 | split_var_cmd_token(last_cmd, temp->str); 69 | else 70 | last_cmd->command = ft_strdup(temp->str); 71 | temp = temp->next; 72 | } 73 | else 74 | fill_args(&temp, last_cmd); 75 | } 76 | *token_lst = temp; 77 | } 78 | -------------------------------------------------------------------------------- /sources/parser/parse_append.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* parse_append.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:06:46 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:08:37 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* 16 | ***APPEND*** 17 | Redirection of output in append mode causes the file whose name results 18 | from the expansion of word to be opened for appending on file descriptor n, 19 | or the standard output (fd 1) if n is not specified. 20 | If the file does not exist it is created. 21 | 22 | The general format for appending output is: [n]>>word. 23 | 24 | */ 25 | 26 | /* open_outfile_append: 27 | * Opens an outfile in append mode. If an outfile was already set, frees it 28 | * and overwrites it. If a previous infile or outfile open failed (file does 29 | * not exist or permission denied), does not open any further output file. 30 | * 31 | * Ex.: 32 | * echo hello > forbidden_file >> test 33 | * echo hello >> forbidden_file >> test 34 | * < forbidden_file cat >> test 35 | * In these 3 cases, the test file should not be opened or created. 36 | */ 37 | static void open_outfile_append(t_io_fds *io, char *file, char *var_filename) 38 | { 39 | if (!remove_old_file_ref(io, false)) 40 | return ; 41 | io->outfile = ft_strdup(file); 42 | if (io->outfile && io->outfile[0] == '\0' && var_filename) 43 | { 44 | errmsg_cmd(var_filename, NULL, "ambiguous redirect", false); 45 | return ; 46 | } 47 | io->fd_out = open(io->outfile, O_WRONLY | O_CREAT | O_APPEND, 0664); 48 | if (io->fd_out == -1) 49 | errmsg_cmd(io->outfile, NULL, strerror(errno), false); 50 | } 51 | 52 | void parse_append(t_command **last_cmd, t_token **token_lst) 53 | { 54 | t_token *temp; 55 | t_command *cmd; 56 | 57 | temp = *token_lst; 58 | cmd = lst_last_cmd(*last_cmd); 59 | init_io(cmd); 60 | open_outfile_append(cmd->io_fds, temp->next->str, temp->next->str_backup); 61 | if (temp->next->next) 62 | temp = temp->next->next; 63 | else 64 | temp = temp->next; 65 | *token_lst = temp; 66 | } 67 | -------------------------------------------------------------------------------- /sources/signals/signal.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* signal.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 18:06:43 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/04 17:22:11 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* signal_reset_prompt: 16 | * Resets the readline user input prompt for interactive signal handling. 17 | */ 18 | void signal_reset_prompt(int signo) 19 | { 20 | (void)signo; 21 | write(1, "\n", 1); 22 | rl_on_new_line(); 23 | rl_replace_line("", 0); 24 | rl_redisplay(); 25 | } 26 | 27 | /* set_signals_interactive: 28 | * Sets the behavior in response to SIGINT (ctrl-c) and SIGQUIT (ctrl-\). 29 | * SIGINT resets the user input prompt to a new blank line. 30 | * SIGQUIT is ignored. 31 | * Used when minishell is in interactive mode, meaning it is awaiting 32 | * user input. 33 | */ 34 | void set_signals_interactive(void) 35 | { 36 | struct sigaction act; 37 | 38 | ignore_sigquit(); 39 | ft_memset(&act, 0, sizeof(act)); 40 | act.sa_handler = &signal_reset_prompt; 41 | sigaction(SIGINT, &act, NULL); 42 | } 43 | 44 | /* signal_print_newline: 45 | * Prints a newline for noninteractive signal handling. 46 | */ 47 | void signal_print_newline(int signal) 48 | { 49 | (void)signal; 50 | rl_on_new_line(); 51 | } 52 | 53 | /* set_signals_noninteractive: 54 | * Sets the behavior in response to SIGINT (ctrl -c) and SIGQUIT (ctrl -\). 55 | * Used when minishell is in noninteractive mode, meaning it is not awaiting 56 | * user input. For example, when a command is running (i.e. cat), minishell 57 | * should not react to SIGINT and SIGQUIT because only the running process (cat) 58 | * needs to react to those signals. 59 | */ 60 | void set_signals_noninteractive(void) 61 | { 62 | struct sigaction act; 63 | 64 | ft_memset(&act, 0, sizeof(act)); 65 | act.sa_handler = &signal_print_newline; 66 | sigaction(SIGINT, &act, NULL); 67 | sigaction(SIGQUIT, &act, NULL); 68 | } 69 | 70 | /* ignore_sigquit: 71 | * Replaces SIGQUIT signals (ctrl-\) with SIG_IGN to ignore 72 | * the signal. 73 | */ 74 | void ignore_sigquit(void) 75 | { 76 | struct sigaction act; 77 | 78 | ft_memset(&act, 0, sizeof(act)); 79 | act.sa_handler = SIG_IGN; 80 | sigaction(SIGQUIT, &act, NULL); 81 | } 82 | -------------------------------------------------------------------------------- /sources/parser/fill_args_echo.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* fill_args_echo.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:02:55 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:03:12 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* 16 | ** This function deals with the specific case when the command is "echo" 17 | ** - It allocates the array of arguments thanks to the count_args function 18 | ** - It loops through the tokens list while the nodes are of type 19 | ** VAR or WORD: 20 | ** * If "bool join = true" in the token structure is true : we join all 21 | ** the tokens of type VAR that have the setting "join = true" 22 | ** * if "join = false" we just fill the last_cmd_>args[i] 23 | ** with the current token. 24 | */ 25 | int create_args_echo_mode(t_token **token_node, t_command *last_cmd) 26 | { 27 | int nb_args; 28 | t_token *temp; 29 | int i; 30 | 31 | remove_empty_var_args(token_node); 32 | temp = *token_node; 33 | nb_args = count_args(temp); 34 | last_cmd->args = malloc(sizeof(char *) * (nb_args + 2)); 35 | if (!last_cmd->args) 36 | return (FAILURE); 37 | i = 0; 38 | last_cmd->args[i] = ft_strdup(last_cmd->command); 39 | i++; 40 | while (temp->type == WORD || temp->type == VAR) 41 | { 42 | if (temp->join == true) 43 | last_cmd->args[i] = join_vars(&temp); 44 | else 45 | last_cmd->args[i] = ft_strdup(temp->str); 46 | i++; 47 | temp = temp->next; 48 | } 49 | last_cmd->args[i] = NULL; 50 | *token_node = temp; 51 | return (SUCCESS); 52 | } 53 | 54 | int add_args_echo_mode(t_token **token_node, t_command *last_cmd) 55 | { 56 | int len; 57 | int nb_args; 58 | char **new_tab; 59 | t_token *temp; 60 | 61 | remove_empty_var_args(token_node); 62 | temp = *token_node; 63 | nb_args = count_args(temp); 64 | len = 0; 65 | while (last_cmd->args[len]) 66 | len++; 67 | new_tab = malloc(sizeof(char *) * (nb_args + len + 1)); 68 | if (!new_tab) 69 | return (FAILURE); 70 | new_tab = copy_in_new_tab(len, new_tab, last_cmd, temp); 71 | free(last_cmd->args); 72 | last_cmd->args = new_tab; 73 | while (temp->type == WORD || temp->type == VAR) 74 | temp = temp->next; 75 | *token_node = temp; 76 | return (SUCCESS); 77 | } 78 | -------------------------------------------------------------------------------- /sources/redirections/pipe.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* pipe.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 18:06:24 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/04 17:21:47 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* close_pipe_fds: 16 | * Closes the pipe fds of all commands. A pointer to a command to skip 17 | * can be specified to skip closing that command's pipe fds: 18 | * - The parent will specify NULL for the skip command while closing 19 | * all pipe fds. 20 | * - The child will specify its own command as skip command while 21 | * closing all pipe fds so as to not accidentally close its own 22 | * pipe fds. 23 | */ 24 | void close_pipe_fds(t_command *cmds, t_command *skip_cmd) 25 | { 26 | while (cmds) 27 | { 28 | if (cmds != skip_cmd && cmds->pipe_fd) 29 | { 30 | close(cmds->pipe_fd[0]); 31 | close(cmds->pipe_fd[1]); 32 | } 33 | cmds = cmds->next; 34 | } 35 | } 36 | 37 | /* create_pipes: 38 | * Creates a set of pipes for each piped command in the list 39 | * of commands. 40 | * Returns 1 if successful, 0 in case of failure. 41 | */ 42 | bool create_pipes(t_data *data) 43 | { 44 | int *fd; 45 | t_command *tmp; 46 | 47 | tmp = data->cmd; 48 | while (tmp) 49 | { 50 | if (tmp->pipe_output || (tmp->prev && tmp->prev->pipe_output)) 51 | { 52 | fd = malloc(sizeof * fd * 2); 53 | if (!fd || pipe(fd) != 0) 54 | { 55 | free_data(data, false); 56 | return (false); 57 | } 58 | tmp->pipe_fd = fd; 59 | } 60 | tmp = tmp->next; 61 | } 62 | return (true); 63 | } 64 | 65 | /* set_pipe_fds: 66 | * Sets the pipe fds for this command. If the previous command 67 | * was piped to this one, sets the input as the read end of 68 | * the previous command. If this command is piped to the 69 | * next, sets the output ad the write end of the pipe. 70 | * pipe_fd[0] = read end of pipe. 71 | * pipe_fd[1] = write end of pipe. 72 | * Returns true when the pipe file descriptors are set. 73 | */ 74 | bool set_pipe_fds(t_command *cmds, t_command *c) 75 | { 76 | if (!c) 77 | return (false); 78 | if (c->prev && c->prev->pipe_output) 79 | dup2(c->prev->pipe_fd[0], STDIN_FILENO); 80 | if (c->pipe_output) 81 | dup2(c->pipe_fd[1], STDOUT_FILENO); 82 | close_pipe_fds(cmds, c); 83 | return (true); 84 | } 85 | -------------------------------------------------------------------------------- /sources/execution/parse_path.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* parse_path.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 17:46:45 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/04 13:06:33 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* find_valid_cmd_path: 16 | * Checks access and permissions for each possible command path to find 17 | * a valid path to binay files for a command. 18 | * Returns the valid path to a command binary, or NULL if no valid path is 19 | * found. 20 | */ 21 | static char *find_valid_cmd_path(char *cmd, char **paths) 22 | { 23 | int i; 24 | char *cmd_path; 25 | 26 | cmd_path = NULL; 27 | i = 0; 28 | while (paths[i]) 29 | { 30 | cmd_path = ft_strjoin(paths[i], cmd); 31 | if (!cmd_path) 32 | { 33 | errmsg_cmd("malloc", NULL, 34 | "an unexpected error occured", EXIT_FAILURE); 35 | return (NULL); 36 | } 37 | if (access(cmd_path, F_OK | X_OK) == 0) 38 | return (cmd_path); 39 | free_ptr(cmd_path); 40 | i++; 41 | } 42 | return (NULL); 43 | } 44 | 45 | /* get_paths_from_env: 46 | * Attempts to extract paths from the PATH environment variable. 47 | * Returns an array of paths on success. On failure, returns NULL. 48 | */ 49 | static char **get_paths_from_env(t_data *data) 50 | { 51 | char **env_paths; 52 | 53 | if (get_env_var_index(data->env, "PATH") == -1) 54 | return (NULL); 55 | env_paths = ft_split(get_env_var_value(data->env, "PATH"), ':'); 56 | if (!env_paths) 57 | return (NULL); 58 | return (env_paths); 59 | } 60 | 61 | /* get_cmd_path: 62 | * Searches the PATH environment variable for the location of the given 63 | * command's binary file. 64 | * Returns the path to the command binary file. NULL if no valid path 65 | * is found. 66 | */ 67 | char *get_cmd_path(t_data *data, char *name) 68 | { 69 | char **env_paths; 70 | char *cmd; 71 | char *cmd_path; 72 | 73 | if (!name) 74 | return (NULL); 75 | env_paths = get_paths_from_env(data); 76 | if (!env_paths) 77 | return (NULL); 78 | cmd = ft_strjoin("/", name); 79 | if (!cmd) 80 | { 81 | free_str_tab(env_paths); 82 | return (NULL); 83 | } 84 | cmd_path = find_valid_cmd_path(cmd, env_paths); 85 | if (!cmd_path) 86 | { 87 | free_ptr(cmd); 88 | free_str_tab(env_paths); 89 | return (NULL); 90 | } 91 | return (cmd_path); 92 | } 93 | -------------------------------------------------------------------------------- /sources/parser/parse_trunc.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* parse_trunc.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:16:18 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:16:26 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* 16 | TRUNC -> Redirection of output. 17 | The file whose name results from the expansion of word has to be opened 18 | in writing mode on fd n or the standard output (fd 1) if n is not specified. 19 | If the file does not exist it is created; 20 | if it does exist it is truncated to 0 size. 21 | 22 | The general format for redirecting output is: [n]>[|]word 23 | */ 24 | 25 | char *get_relative_path(char *file_to_open) 26 | { 27 | char *path; 28 | char *ret; 29 | 30 | if (file_to_open[0] == '/') 31 | return (ft_strdup(file_to_open)); 32 | path = ft_strdup("./"); 33 | ret = ft_strjoin(path, file_to_open); 34 | printf("PARSING - Get_rel_path function return : %s\n", ret); 35 | return (ret); 36 | } 37 | 38 | /* open_outfile_trunc: 39 | * Opens an outfile in truncated mode. If an outfile was already set, frees it 40 | * and overwrites it. If a previous infile or outfile open failed (file does 41 | * not exist or permission denied), does not open any further output file. 42 | * 43 | * Ex.: 44 | * echo hello > forbidden_file > test 45 | * echo hello >> forbidden_file > test 46 | * < forbidden_file cat > test 47 | * In these 3 cases, the test file should not be opened or created. 48 | */ 49 | static void open_outfile_trunc(t_io_fds *io, char *file, char *var_filename) 50 | { 51 | if (!remove_old_file_ref(io, false)) 52 | return ; 53 | io->outfile = ft_strdup(file); 54 | if (io->outfile && io->outfile[0] == '\0') 55 | { 56 | errmsg_cmd(var_filename, NULL, "ambiguous redirect", false); 57 | return ; 58 | } 59 | io->fd_out = open(io->outfile, O_WRONLY | O_CREAT | O_TRUNC, 0664); 60 | if (io->fd_out == -1) 61 | errmsg_cmd(io->outfile, NULL, strerror(errno), false); 62 | } 63 | 64 | void parse_trunc(t_command **last_cmd, t_token **token_lst) 65 | { 66 | t_token *temp; 67 | t_command *cmd; 68 | 69 | temp = *token_lst; 70 | cmd = lst_last_cmd(*last_cmd); 71 | init_io(cmd); 72 | open_outfile_trunc(cmd->io_fds, temp->next->str, temp->next->str_backup); 73 | if (temp->next->next) 74 | temp = temp->next->next; 75 | else 76 | temp = temp->next; 77 | *token_lst = temp; 78 | } 79 | -------------------------------------------------------------------------------- /sources/parser/parse_heredoc.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* parse_heredoc.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:09:01 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:09:19 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* get_heredoc: 16 | * Opens a heredoc awaiting user input. 17 | * Translates any given variables into their environment values. 18 | * Returns false in case of error, true if successful. 19 | */ 20 | bool get_heredoc(t_data *data, t_io_fds *io) 21 | { 22 | int tmp_fd; 23 | bool ret; 24 | 25 | ret = true; 26 | tmp_fd = open(io->infile, O_CREAT | O_WRONLY | O_TRUNC, 0644); 27 | ret = fill_heredoc(data, io, tmp_fd); 28 | close(tmp_fd); 29 | return (ret); 30 | } 31 | 32 | /* get_heredoc_name: 33 | * Generates a unique name for the current heredoc. 34 | * Returns the new heredoc name. 35 | */ 36 | static char *get_heredoc_name(void) 37 | { 38 | static int i; 39 | char *name; 40 | char *number; 41 | 42 | number = ft_itoa(i); 43 | if (!number) 44 | return (NULL); 45 | name = ft_strjoin(HEREDOC_NAME, number); 46 | free(number); 47 | i++; 48 | return (name); 49 | } 50 | 51 | /* get_delim: 52 | * Returns the heredoc delimiter. Quotes are removed if present 53 | * around the delimiter, and the quotes boolean is set to true. 54 | */ 55 | static char *get_delim(char *delim, bool *quotes) 56 | { 57 | int len; 58 | 59 | len = ft_strlen(delim) - 1; 60 | if ((delim[0] == '\"' && delim[len] == '\"') 61 | || (delim[0] == '\'' && delim[len] == '\'')) 62 | { 63 | *quotes = true; 64 | return (ft_strtrim(delim, "\'\"")); 65 | } 66 | return (ft_strdup(delim)); 67 | } 68 | 69 | /* parse_heredoc: 70 | * Creates a temporary heredoc file which will be filled with 71 | * user input. 72 | */ 73 | void parse_heredoc(t_data *data, t_command **last_cmd, t_token **token_lst) 74 | { 75 | t_token *temp; 76 | t_command *cmd; 77 | t_io_fds *io; 78 | 79 | temp = *token_lst; 80 | cmd = lst_last_cmd(*last_cmd); 81 | init_io(cmd); 82 | io = cmd->io_fds; 83 | if (!remove_old_file_ref(io, true)) 84 | return ; 85 | io->infile = get_heredoc_name(); 86 | io->heredoc_delimiter = get_delim(temp->next->str, &(io->heredoc_quotes)); 87 | if (get_heredoc(data, io)) 88 | io->fd_in = open(io->infile, O_RDONLY); 89 | else 90 | io->fd_in = -1; 91 | if (temp->next->next) 92 | temp = temp->next->next; 93 | else 94 | temp = temp->next; 95 | *token_lst = temp; 96 | } 97 | -------------------------------------------------------------------------------- /sources/redirections/file_io.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* file_io.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 17:51:46 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/04 17:21:42 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* restore_io: 16 | * Restores the original standard input and standard output 17 | * to their original fds of 0 and 1. Used to clear the input/output 18 | * fds after execution, in preparation for the next set of user commands. 19 | * Returns 1 if the duplication was successful, 0 if not. 20 | */ 21 | bool restore_io(t_io_fds *io) 22 | { 23 | int ret; 24 | 25 | ret = true; 26 | if (!io) 27 | return (ret); 28 | if (io->stdin_backup != -1) 29 | { 30 | if (dup2(io->stdin_backup, STDIN_FILENO) == -1) 31 | ret = false; 32 | close(io->stdin_backup); 33 | io->stdin_backup = -1; 34 | } 35 | if (io->stdout_backup != -1) 36 | { 37 | if (dup2(io->stdout_backup, STDOUT_FILENO) == -1) 38 | ret = false; 39 | close(io->stdout_backup); 40 | io->stdout_backup = -1; 41 | } 42 | return (ret); 43 | } 44 | 45 | /* redirect_io: 46 | * Duplicates the input and output fds to the standard input and output. 47 | * Backs up the standard input and output before replacing them in order 48 | * to restore them after execution. 49 | * Returns 1 for success, 0 in case of error. 50 | */ 51 | bool redirect_io(t_io_fds *io) 52 | { 53 | int ret; 54 | 55 | ret = true; 56 | if (!io) 57 | return (ret); 58 | io->stdin_backup = dup(STDIN_FILENO); 59 | if (io->stdin_backup == -1) 60 | ret = errmsg_cmd("dup", "stdin backup", strerror(errno), false); 61 | io->stdout_backup = dup(STDOUT_FILENO); 62 | if (io->stdout_backup == -1) 63 | ret = errmsg_cmd("dup", "stdout backup", strerror(errno), false); 64 | if (io->fd_in != -1) 65 | if (dup2(io->fd_in, STDIN_FILENO) == -1) 66 | ret = errmsg_cmd("dup2", io->infile, strerror(errno), false); 67 | if (io->fd_out != -1) 68 | if (dup2(io->fd_out, STDOUT_FILENO) == -1) 69 | ret = errmsg_cmd("dup2", io->outfile, strerror(errno), false); 70 | return (ret); 71 | } 72 | 73 | /* check_infile_outfile: 74 | * Checks if the infile and outfile are set correctly. 75 | * Returns 1 on success, 0 on failure. 76 | */ 77 | bool check_infile_outfile(t_io_fds *io) 78 | { 79 | if (!io || (!io->infile && !io->outfile)) 80 | return (true); 81 | if ((io->infile && io->fd_in == -1) 82 | || (io->outfile && io->fd_out == -1)) 83 | return (false); 84 | return (true); 85 | } 86 | -------------------------------------------------------------------------------- /sources/parser/parse_input.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* parse_input.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:20:39 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:20:42 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* INPUT -> REDIR_IN (<) 16 | Redirection of input causes the file whose name results from the expansion 17 | of word to be opened for reading on file descriptor n, or the standard input 18 | (file descriptor 0) if n is not specified. 19 | 20 | The general format for redirecting input is: [n]infile) 26 | { 27 | if (io->fd_in == -1 || (io->outfile && io->fd_out == -1)) 28 | return (false); 29 | if (io->heredoc_delimiter != NULL) 30 | { 31 | free_ptr(io->heredoc_delimiter); 32 | io->heredoc_delimiter = NULL; 33 | unlink(io->infile); 34 | } 35 | free_ptr(io->infile); 36 | close(io->fd_in); 37 | } 38 | else if (infile == false && io->outfile) 39 | { 40 | if (io->fd_out == -1 || (io->infile && io->fd_in == -1)) 41 | return (false); 42 | free_ptr(io->outfile); 43 | close(io->fd_out); 44 | } 45 | return (true); 46 | } 47 | 48 | /* open_infile: 49 | * Opens an infile. If an infile was already set, frees it 50 | * and overwrites it. If a previous infile open failed (file does 51 | * not exist or permission denied), does not open any further input file. 52 | * Ex.: 53 | * < Makefile test 54 | * Uses contents of README as input (ignores Makefile) 55 | * < forbidden test 56 | * Permission denied (no README cat) 57 | */ 58 | static void open_infile(t_io_fds *io, char *file, char *original_filename) 59 | { 60 | if (!remove_old_file_ref(io, true)) 61 | return ; 62 | io->infile = ft_strdup(file); 63 | if (io->infile && io->infile[0] == '\0') 64 | { 65 | errmsg_cmd(original_filename, NULL, "ambiguous redirect", false); 66 | return ; 67 | } 68 | io->fd_in = open(io->infile, O_RDONLY); 69 | if (io->fd_in == -1) 70 | errmsg_cmd(io->infile, NULL, strerror(errno), false); 71 | } 72 | 73 | void parse_input(t_command **last_cmd, t_token **token_lst) 74 | { 75 | t_token *temp; 76 | t_command *cmd; 77 | 78 | temp = *token_lst; 79 | cmd = lst_last_cmd(*last_cmd); 80 | init_io(cmd); 81 | open_infile(cmd->io_fds, temp->next->str, temp->next->str_backup); 82 | if (temp->next->next) 83 | temp = temp->next->next; 84 | else 85 | temp = temp->next; 86 | *token_lst = temp; 87 | } 88 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Program file name 2 | NAME = minishell 3 | 4 | # Compiler and compilation flags 5 | CC = clang 6 | CFLAGS = -Werror -Wextra -Wall -gdwarf-4 -g 7 | 8 | # Build files and directories 9 | SRC_PATH = ./sources/ 10 | OBJ_PATH = ./objects/ 11 | INC_PATH = ./includes/ 12 | SRC = main.c \ 13 | utils/init_data.c \ 14 | env/env.c \ 15 | env/env_set.c \ 16 | lexer/parse_user_input.c \ 17 | lexer/tokenization.c \ 18 | lexer/tokenization_utils.c \ 19 | lexer/check_if_var.c \ 20 | lexer/lexer_grammar.c \ 21 | lexer/token_lst_utils.c \ 22 | lexer/token_lst_utils_2.c \ 23 | expansion/var_expander.c \ 24 | expansion/var_expander_utils.c \ 25 | expansion/identify_var.c \ 26 | expansion/quotes_handler.c \ 27 | expansion/quotes_remover.c \ 28 | expansion/recover_value.c \ 29 | expansion/replace_var.c \ 30 | parser/create_commands.c \ 31 | parser/parse_word.c \ 32 | parser/fill_args_echo.c \ 33 | parser/fill_args_echo_utils.c \ 34 | parser/fill_args_default.c \ 35 | parser/parse_input.c \ 36 | parser/parse_trunc.c \ 37 | parser/parse_append.c \ 38 | parser/parse_heredoc.c \ 39 | parser/parse_heredoc_utils.c \ 40 | parser/parse_pipe.c \ 41 | parser/cmd_lst_utils.c \ 42 | parser/cmd_lst_utils_cleanup.c \ 43 | builtins/export_builtin.c \ 44 | builtins/unset_builtin.c \ 45 | builtins/cd_builtin.c \ 46 | builtins/env_builtin.c \ 47 | builtins/pwd_builtin.c \ 48 | builtins/echo_builtin.c \ 49 | builtins/exit_builtin.c \ 50 | execution/execute.c \ 51 | execution/execute_cmd.c \ 52 | execution/execute_utils.c \ 53 | execution/parse_path.c \ 54 | redirections/pipe.c \ 55 | redirections/file_io.c \ 56 | utils/exit.c \ 57 | utils/error.c \ 58 | utils/cleanup.c \ 59 | signals/signal.c \ 60 | debug/debug.c 61 | SRCS = $(addprefix $(SRC_PATH), $(SRC)) 62 | OBJ = $(SRC:.c=.o) 63 | OBJS = $(addprefix $(OBJ_PATH), $(OBJ)) 64 | INC = -I $(INC_PATH) -I $(LIBFT_PATH) 65 | 66 | # Libft files and directories 67 | LIBFT_PATH = ./libft/ 68 | LIBFT = ./libft/libft.a 69 | 70 | # Main rule 71 | all: $(OBJ_PATH) $(LIBFT) $(NAME) 72 | 73 | # Objects directory rule 74 | $(OBJ_PATH): 75 | mkdir -p $(OBJ_PATH) 76 | mkdir -p $(OBJ_PATH)/builtins 77 | mkdir -p $(OBJ_PATH)/lexer 78 | mkdir -p $(OBJ_PATH)/expansion 79 | mkdir -p $(OBJ_PATH)/parser 80 | mkdir -p $(OBJ_PATH)/testing 81 | mkdir -p $(OBJ_PATH)/env 82 | mkdir -p $(OBJ_PATH)/execution 83 | mkdir -p $(OBJ_PATH)/utils 84 | mkdir -p $(OBJ_PATH)/redirections 85 | mkdir -p $(OBJ_PATH)/signals 86 | mkdir -p $(OBJ_PATH)/debug 87 | 88 | # Objects rule 89 | $(OBJ_PATH)%.o: $(SRC_PATH)%.c 90 | $(CC) $(CFLAGS) -c $< -o $@ $(INC) 91 | 92 | # Project file rule 93 | $(NAME): $(OBJS) 94 | $(CC) $(CFLAGS) $(OBJS) -o $@ $(INC) $(LIBFT) -l readline 95 | 96 | # Libft rule 97 | $(LIBFT): 98 | make -C $(LIBFT_PATH) 99 | 100 | # Clean up build files rule 101 | clean: 102 | rm -rf $(OBJ_PATH) 103 | make -C $(LIBFT_PATH) clean 104 | 105 | # Remove program executable 106 | fclean: clean 107 | rm -f $(NAME) 108 | make -C $(LIBFT_PATH) fclean 109 | 110 | # Clean + remove executable 111 | re: fclean all 112 | 113 | .PHONY: all re clean fclean -------------------------------------------------------------------------------- /sources/env/env_set.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* env_set.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 17:51:06 by mcombeau #+# #+# */ 9 | /* Updated: 2022/10/06 14:45:10 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* realloc_env_vars: 16 | * Reallocates memory for the global variable g_env_vars. 17 | * 18 | * Returns a pointer to the new environment variables 19 | * or NULL in case of a memory allocation error. 20 | */ 21 | static char **realloc_env_vars(t_data *data, int size) 22 | { 23 | char **new_env; 24 | int i; 25 | 26 | new_env = ft_calloc(size + 1, sizeof * new_env); 27 | if (!new_env) 28 | return (NULL); 29 | i = 0; 30 | while (data->env[i] && i < size) 31 | { 32 | new_env[i] = ft_strdup(data->env[i]); 33 | free_ptr(data->env[i]); 34 | i++; 35 | } 36 | free(data->env); 37 | return (new_env); 38 | } 39 | 40 | /* set_env_var: 41 | * Adds an environment variable with the given key 42 | * corresponding to the given value. If the key already 43 | * exists in the environment variables, the value will 44 | * be overwritten. If not, it creates a new entry. 45 | * 46 | * Returns 1 if the operation was successful, or 0 if 47 | * in case of error. 48 | */ 49 | bool set_env_var(t_data *data, char *key, char *value) 50 | { 51 | int idx; 52 | char *tmp; 53 | 54 | idx = get_env_var_index(data->env, key); 55 | if (value == NULL) 56 | value = ""; 57 | tmp = ft_strjoin("=", value); 58 | if (!tmp) 59 | return (false); 60 | if (idx != -1 && data->env[idx]) 61 | { 62 | free_ptr(data->env[idx]); 63 | data->env[idx] = ft_strjoin(key, tmp); 64 | } 65 | else 66 | { 67 | idx = env_var_count(data->env); 68 | data->env = realloc_env_vars(data, idx + 1); 69 | if (!data->env) 70 | return (false); 71 | data->env[idx] = ft_strjoin(key, tmp); 72 | } 73 | free_ptr(tmp); 74 | return (true); 75 | } 76 | 77 | /* remove_env_var: 78 | * Removes the variable at the given index from the 79 | * environment variables. 80 | * 81 | * Returns 1 if the removal was successful, 0 if case 82 | * of an invalid index or a memory allocation error. 83 | */ 84 | bool remove_env_var(t_data *data, int idx) 85 | { 86 | int i; 87 | int count; 88 | 89 | if (idx > env_var_count(data->env)) 90 | return (false); 91 | free_ptr(data->env[idx]); 92 | i = idx; 93 | count = idx; 94 | while (data->env[i + 1]) 95 | { 96 | data->env[i] = ft_strdup(data->env[i + 1]); 97 | free_ptr(data->env[i + 1]); 98 | count++; 99 | i++; 100 | } 101 | data->env = realloc_env_vars(data, count); 102 | if (!data->env) 103 | return (false); 104 | return (true); 105 | } 106 | -------------------------------------------------------------------------------- /sources/env/env.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* env.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 17:50:51 by mcombeau #+# #+# */ 9 | /* Updated: 2022/10/06 14:43:22 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* env_var_count: 16 | * Counts how many original environment variables there are. 17 | * Returns the number of environment variables. 18 | */ 19 | int env_var_count(char **env) 20 | { 21 | int i; 22 | 23 | i = 0; 24 | while (env && env[i]) 25 | i++; 26 | return (i); 27 | } 28 | 29 | /* get_env_var_index: 30 | * Searches for the given variable in the environment variables. 31 | * 32 | * Returns the index of the variable in the environment 33 | * matching the given string. Partial variable names are not 34 | * supported: the given string must be a full variable name. 35 | * Returns -1 if the string cannot be found in the environment. 36 | */ 37 | int get_env_var_index(char **env, char *var) 38 | { 39 | int i; 40 | char *tmp; 41 | 42 | tmp = ft_strjoin(var, "="); 43 | if (!tmp) 44 | return (-1); 45 | i = 0; 46 | while (env[i]) 47 | { 48 | if (ft_strncmp(tmp, env[i], ft_strlen(tmp)) == 0) 49 | { 50 | free_ptr(tmp); 51 | return (i); 52 | } 53 | i++; 54 | } 55 | free_ptr(tmp); 56 | return (-1); 57 | } 58 | 59 | /* get_env_var_value: 60 | * Searches for the given variable in the environment variables. 61 | * 62 | * Returns a pointer to the value of the variable in the environment 63 | * matching the given string. Partial variable names are not 64 | * supported: the given string must be a full variable name. 65 | * Returns NULL if the string cannot be found in the environment. 66 | */ 67 | char *get_env_var_value(char **env, char *var) 68 | { 69 | int i; 70 | char *tmp; 71 | 72 | tmp = ft_strjoin(var, "="); 73 | if (!tmp) 74 | return (NULL); 75 | i = 0; 76 | while (env[i]) 77 | { 78 | if (ft_strncmp(tmp, env[i], ft_strlen(tmp)) == 0) 79 | { 80 | free_ptr(tmp); 81 | return (ft_strchr(env[i], '=') + 1); 82 | } 83 | i++; 84 | } 85 | free_ptr(tmp); 86 | return (NULL); 87 | } 88 | 89 | /* is_valid_env_var_key: 90 | * Checks if the key is a valid name for an evironment 91 | * variable. 92 | * Returns true if the key contains only alphanumeric chars 93 | * or '_', or false if not. 94 | */ 95 | bool is_valid_env_var_key(char *var) 96 | { 97 | int i; 98 | 99 | i = 0; 100 | if (ft_isalpha(var[i]) == 0 && var[i] != '_') 101 | return (false); 102 | i++; 103 | while (var[i] && var[i] != '=') 104 | { 105 | if (ft_isalnum(var[i]) == 0 && var[i] != '_') 106 | return (false); 107 | i++; 108 | } 109 | return (true); 110 | } 111 | -------------------------------------------------------------------------------- /libft/ft_split.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* ft_split.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/27 17:56:03 by mcombeau #+# #+# */ 9 | /* Updated: 2021/12/08 12:14:01 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "libft.h" 14 | 15 | /* 16 | DESCRIPTION : 17 | The function ft_split allocates and copies an array of strings by 18 | splitting the given string s using the given separator c. 19 | 20 | RETURN VALUE : 21 | An array of strings resulting from the split. NULL if the memory 22 | allocation fails. 23 | */ 24 | 25 | static int ft_count_words(const char *s, char c) 26 | { 27 | int words; 28 | int i; 29 | 30 | words = 0; 31 | i = 0; 32 | while (s[i]) 33 | { 34 | if (i == 0 && s[i] != c) 35 | words++; 36 | if (i > 0 && s[i] != c && s[i - 1] == c) 37 | words++; 38 | i++; 39 | } 40 | return (words); 41 | } 42 | 43 | static char **ft_malloc_strs(char **strs, const char *s, char c) 44 | { 45 | int count; 46 | int i; 47 | int x; 48 | 49 | count = 0; 50 | i = 0; 51 | x = 0; 52 | while (s[i]) 53 | { 54 | if (s[i] != c) 55 | count++; 56 | if ((s[i] == c && i > 0 && s[i - 1] != c) 57 | || (s[i] != c && s[i + 1] == '\0')) 58 | { 59 | strs[x] = malloc(sizeof(char) * (count + 1)); 60 | if (!strs[x]) 61 | return (NULL); 62 | count = 0; 63 | x++; 64 | } 65 | i++; 66 | } 67 | return (strs); 68 | } 69 | 70 | static char **ft_cpy_strs(char **strs, const char *s, char c) 71 | { 72 | int i; 73 | int x; 74 | int y; 75 | 76 | i = 0; 77 | x = 0; 78 | y = 0; 79 | while (s[i]) 80 | { 81 | if (s[i] != c) 82 | strs[x][y++] = s[i]; 83 | if (s[i] != c && s[i + 1] == '\0') 84 | strs[x][y] = '\0'; 85 | if (s[i] == c && i > 0 && s[i - 1] != c) 86 | { 87 | strs[x][y] = '\0'; 88 | x++; 89 | y = 0; 90 | } 91 | i++; 92 | } 93 | return (strs); 94 | } 95 | 96 | static char **ft_merror(char **strs) 97 | { 98 | int i; 99 | 100 | i = 0; 101 | while (strs[i]) 102 | { 103 | free(strs[i]); 104 | strs[i] = NULL; 105 | i++; 106 | } 107 | free(strs); 108 | return (NULL); 109 | } 110 | 111 | char **ft_split(char const *s, char c) 112 | { 113 | char **strs; 114 | int wordcount; 115 | 116 | if (!s) 117 | { 118 | strs = malloc(sizeof(char) * 1); 119 | if (!strs) 120 | return (NULL); 121 | *strs = NULL; 122 | return (strs); 123 | } 124 | wordcount = ft_count_words(s, c); 125 | strs = malloc(sizeof(*strs) * (wordcount + 1)); 126 | if (!strs) 127 | return (NULL); 128 | if (ft_malloc_strs(strs, s, c)) 129 | { 130 | ft_cpy_strs(strs, s, c); 131 | strs[wordcount] = NULL; 132 | } 133 | else 134 | strs = ft_merror(strs); 135 | return (strs); 136 | } 137 | -------------------------------------------------------------------------------- /sources/utils/cleanup.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* cleanup.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 19:05:55 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/04 17:24:24 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* free_data: 16 | * Frees all of the data used to run a command. If clear_history is true, 17 | * frees the environment and the command history before returning. 18 | */ 19 | void free_data(t_data *data, bool clear_history) 20 | { 21 | if (data && data->user_input) 22 | { 23 | free_ptr(data->user_input); 24 | data->user_input = NULL; 25 | } 26 | if (data && data->token) 27 | lstclear_token(&data->token, &free_ptr); 28 | if (data && data->cmd) 29 | lst_clear_cmd(&data->cmd, &free_ptr); 30 | if (clear_history == true) 31 | { 32 | if (data && data->working_dir) 33 | free_ptr(data->working_dir); 34 | if (data && data->old_working_dir) 35 | free_ptr(data->old_working_dir); 36 | if (data && data->env) 37 | free_str_tab(data->env); 38 | rl_clear_history(); 39 | } 40 | } 41 | 42 | /* close_fds: 43 | * Closes opened file descriptors, including pipes and input and 44 | * output fds. If close_backups is set to true, it also closes 45 | * backup STDIN and STDOUT file descriptors. 46 | */ 47 | void close_fds(t_command *cmds, bool close_backups) 48 | { 49 | if (cmds->io_fds) 50 | { 51 | if (cmds->io_fds->fd_in != -1) 52 | close(cmds->io_fds->fd_in); 53 | if (cmds->io_fds->fd_out != -1) 54 | close(cmds->io_fds->fd_out); 55 | if (close_backups) 56 | restore_io(cmds->io_fds); 57 | } 58 | close_pipe_fds(cmds, NULL); 59 | } 60 | 61 | /* free_io: 62 | * Frees the input/output fd structure. 63 | */ 64 | void free_io(t_io_fds *io) 65 | { 66 | if (!io) 67 | return ; 68 | restore_io(io); 69 | if (io->heredoc_delimiter) 70 | { 71 | unlink(io->infile); 72 | free_ptr(io->heredoc_delimiter); 73 | } 74 | if (io->infile) 75 | free_ptr(io->infile); 76 | if (io->outfile) 77 | free_ptr(io->outfile); 78 | if (io) 79 | free_ptr(io); 80 | } 81 | 82 | /* free_str_tab: 83 | * Frees an array of strings. 84 | */ 85 | void free_str_tab(char **tab) 86 | { 87 | int i; 88 | 89 | i = 0; 90 | if (tab) 91 | { 92 | while (tab[i]) 93 | { 94 | if (tab[i]) 95 | { 96 | free_ptr(tab[i]); 97 | tab[i] = NULL; 98 | } 99 | i++; 100 | } 101 | free(tab); 102 | tab = NULL; 103 | } 104 | } 105 | 106 | /* free_ptr: 107 | * Frees a pointer of any type if it is not NULL and sets it to NULL. 108 | * This avoids accidental double-frees. 109 | */ 110 | void free_ptr(void *ptr) 111 | { 112 | if (ptr != NULL) 113 | { 114 | free(ptr); 115 | ptr = NULL; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /sources/expansion/var_expander.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* var_expander.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/22 02:35:14 by alexa #+# #+# */ 9 | /* Updated: 2022/11/07 17:03:43 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* 16 | * After splitting the user's input into tokens, we have to expand 17 | * the variables. After the expansion is done, quote characters are 18 | * removed from the original word unless they are between quotes. 19 | */ 20 | 21 | static void update_status(t_token **token_node, char c) 22 | { 23 | if (c == '\'' && (*token_node)->status == DEFAULT) 24 | (*token_node)->status = SQUOTE; 25 | else if (c == '\"' && (*token_node)->status == DEFAULT) 26 | (*token_node)->status = DQUOTE; 27 | else if (c == '\'' && (*token_node)->status == SQUOTE) 28 | (*token_node)->status = DEFAULT; 29 | else if (c == '\"' && (*token_node)->status == DQUOTE) 30 | (*token_node)->status = DEFAULT; 31 | } 32 | 33 | static bool is_next_char_a_sep(char c) 34 | { 35 | if (c == '$' || c == ' ' || c == '=' || c == '\0') 36 | return (true); 37 | else 38 | return (false); 39 | } 40 | 41 | static bool var_between_quotes(char *str, int i) 42 | { 43 | if (i > 0) 44 | { 45 | if (str[i - 1] == '\"' && str[i + 1] == '\"') 46 | return (true); 47 | else 48 | return (false); 49 | } 50 | return (false); 51 | } 52 | 53 | int var_expander(t_data *data, t_token **token_lst) 54 | { 55 | t_token *temp; 56 | int i; 57 | 58 | temp = *token_lst; 59 | while (temp) 60 | { 61 | if (temp->type == VAR) 62 | { 63 | i = 0; 64 | while (temp->str[i]) 65 | { 66 | update_status(&temp, temp->str[i]); 67 | if (temp->str[i] == '$' 68 | && is_next_char_a_sep(temp->str[i + 1]) == false 69 | && var_between_quotes(temp->str, i) == false 70 | && (temp->status == DEFAULT || temp->status == DQUOTE)) 71 | replace_var(&temp, 72 | recover_val(temp, temp->str + i, data), i); 73 | else 74 | i++; 75 | } 76 | } 77 | temp = temp->next; 78 | } 79 | return (0); 80 | } 81 | 82 | /* var_expander_heredoc: 83 | * Heredoc variant of var_expander. Replaces a string containing an 84 | * environment variable, like $USER with its corresponding value. 85 | * Returns the replaced string. May return NULL on error. 86 | */ 87 | char *var_expander_heredoc(t_data *data, char *str) 88 | { 89 | int i; 90 | 91 | i = 0; 92 | while (str[i]) 93 | { 94 | if (str[i] == '$' 95 | && is_next_char_a_sep(str[i + 1]) == false 96 | && var_between_quotes(str, i) == false) 97 | str = replace_str_heredoc(str, recover_val(NULL, str + i, data), i); 98 | else 99 | i++; 100 | } 101 | return (str); 102 | } 103 | -------------------------------------------------------------------------------- /sources/expansion/replace_var.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* replace_var.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:51:45 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:51:47 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static int erase_var(t_token **token_node, char *str, int index) 16 | { 17 | int i; 18 | int j; 19 | int len; 20 | char *new_str; 21 | 22 | i = 0; 23 | j = 0; 24 | len = ft_strlen(str) - var_length(str + index); 25 | new_str = (char *)malloc(sizeof(char) * len + 1); 26 | if (!new_str) 27 | return (1); 28 | while (str[i]) 29 | { 30 | if (str[i] == '$' && i == index) 31 | { 32 | i = i + var_length(str + index) + 1; 33 | if (str[i] == '\0') 34 | break ; 35 | } 36 | new_str[j++] = str[i++]; 37 | } 38 | new_str[j] = '\0'; 39 | free_ptr((*token_node)->str); 40 | (*token_node)->str = new_str; 41 | return (0); 42 | } 43 | 44 | // Changed return type from int to char * to adapt the function 45 | // to work for heredoc variable expansion. Heredoc has no tokens 46 | // so token_node becomes optional. 47 | // Heredoc variant replace_str_heredoc calls this function with 48 | // token_node == NULL! 49 | 50 | static char *erase_and_replace(t_token **token_node, char *str, 51 | char *var_value, int index) 52 | { 53 | char *newstr; 54 | int newstr_size; 55 | 56 | newstr_size = (ft_strlen(str) - var_length(str + index) 57 | + ft_strlen(var_value)); 58 | newstr = get_new_token_string(str, var_value, newstr_size, index); 59 | if (token_node && *token_node) 60 | { 61 | free_ptr((*token_node)->str); 62 | (*token_node)->str = newstr; 63 | } 64 | return (newstr); 65 | } 66 | 67 | int replace_var(t_token **token_node, char *var_value, int index) 68 | { 69 | if (var_value == NULL) 70 | { 71 | if (erase_var(token_node, (*token_node)->str, index) == 1) 72 | { 73 | free_ptr(var_value); 74 | return (1); 75 | } 76 | } 77 | else 78 | { 79 | if (erase_and_replace(token_node, (*token_node)->str, \ 80 | var_value, index) == NULL) 81 | { 82 | free_ptr(var_value); 83 | return (1); 84 | } 85 | } 86 | free_ptr(var_value); 87 | return (0); 88 | } 89 | 90 | /* replace_str_heredoc: 91 | * Heredoc variant of replace_var, replaces an environment variable 92 | * by its value. Ex. $USER -> username. 93 | * Returns the replaced string. 94 | */ 95 | 96 | char *replace_str_heredoc(char *str, char *var_value, int index) 97 | { 98 | char *tmp; 99 | 100 | tmp = NULL; 101 | if (var_value == NULL) 102 | *str = '\0'; 103 | else 104 | { 105 | tmp = str; 106 | str = erase_and_replace(NULL, str, var_value, index); 107 | free_ptr(tmp); 108 | } 109 | free_ptr(var_value); 110 | return (str); 111 | } 112 | -------------------------------------------------------------------------------- /libft/libft.h: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* libft.h :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/11/22 13:54:20 by mcombeau #+# #+# */ 9 | /* Updated: 2022/09/25 14:51:46 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #ifndef LIBFT_H 14 | # define LIBFT_H 15 | 16 | # include 17 | # include 18 | # include 19 | 20 | /* --------------- LISTS --------------- */ 21 | typedef struct s_list 22 | { 23 | void *content; 24 | struct s_list *next; 25 | } t_list; 26 | 27 | t_list *ft_lstnew(void *content); 28 | void ft_lstadd_front(t_list **alst, t_list *new); 29 | int ft_lstsize(t_list *lst); 30 | t_list *ft_lstlast(t_list *lst); 31 | void ft_lstadd_back(t_list **alst, t_list *new); 32 | void ft_lstdelone(t_list *lst, void (*del)(void *)); 33 | void ft_lstclear(t_list **lst, void (*del)(void *)); 34 | void ft_lstiter(t_list *lst, void (*f)(void *)); 35 | t_list *ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *)); 36 | 37 | /* --------------- CHARS --------------- */ 38 | int ft_isalpha(int c); 39 | int ft_isdigit(int c); 40 | int ft_isalnum(int c); 41 | int ft_isascii(int c); 42 | int ft_isprint(int c); 43 | int ft_isspace(int c); 44 | int ft_toupper(int c); 45 | int ft_tolower(int c); 46 | 47 | /* --------------- STRINGS --------------- */ 48 | size_t ft_strlen(const char *str); 49 | char *ft_strchr(const char *str, int c); 50 | char *ft_strrchr(const char *str, int c); 51 | size_t ft_strlcpy(char *dst, const char *src, size_t dstsize); 52 | size_t ft_strlcat(char *dst, const char *src, size_t dstsize); 53 | int ft_strncmp(const char *s1, const char *s2, size_t n); 54 | int ft_strcmp(const char *s1, const char *s2); 55 | char *ft_strnstr(const char *s1, const char *s2, size_t n); 56 | char *ft_strdup(const char *s1); 57 | char *ft_substr(char const *s, unsigned int start, size_t len); 58 | char *ft_strjoin(char const *s1, char const *s2); 59 | char *ft_strtrim(char const *s1, char const *set); 60 | char **ft_split(char const *s, char c); 61 | char *ft_strmapi(char const *s, char (*f)(unsigned int, char)); 62 | void ft_striteri(char *s, void (*f)(unsigned int, char*)); 63 | 64 | /* --------------- FILE DESCRIPTORS --------------- */ 65 | void ft_putchar_fd(char c, int fd); 66 | void ft_putstr_fd(char *s, int fd); 67 | void ft_putendl_fd(char *s, int fd); 68 | void ft_putnbr_fd(int n, int fd); 69 | 70 | /* --------------- MEMORY --------------- */ 71 | void *ft_memset(void *b, int c, size_t len); 72 | void ft_bzero(void *s, size_t n); 73 | void *ft_memcpy(void *dst, const void *src, size_t n); 74 | void *ft_memmove(void *dst, const void *src, size_t len); 75 | void *ft_memchr(const void *s, int c, size_t n); 76 | int ft_memcmp(const void *s1, const void *s2, size_t n); 77 | void *ft_calloc(size_t count, size_t size); 78 | 79 | /* --------------- NUMBERS --------------- */ 80 | int ft_atoi(const char *str); 81 | char *ft_itoa(int n); 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /sources/utils/error.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* error.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 19:06:15 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/05 12:35:50 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* join_strs: 16 | * Joins two strings together, freeing the previous string. 17 | * Returns the new concatenated string. Or NULL if an error occured. 18 | */ 19 | char *join_strs(char *str, char *add) 20 | { 21 | char *tmp; 22 | 23 | if (!add) 24 | return (str); 25 | if (!str) 26 | return (ft_strdup(add)); 27 | tmp = str; 28 | str = ft_strjoin(tmp, add); 29 | free_ptr(tmp); 30 | return (str); 31 | } 32 | 33 | /* add_detail_quotes: 34 | * Checks whether to add quotes around the error detail: 35 | * i.e. "unset: `@': not a valid identifier" 36 | * Returns true if the command is export or unset, 37 | * false if not. 38 | */ 39 | static bool add_detail_quotes(char *command) 40 | { 41 | if (ft_strncmp(command, "export", 7) == 0 42 | || ft_strncmp(command, "unset", 6) == 0) 43 | return (true); 44 | return (false); 45 | } 46 | 47 | /* errmsg_cmd: 48 | * Prints an error message to the standard error, prefixed with the 49 | * program name. 50 | * Returns with the specified error number. 51 | */ 52 | int errmsg_cmd(char *command, char *detail, char *error_message, int error_nb) 53 | { 54 | char *msg; 55 | bool detail_quotes; 56 | 57 | detail_quotes = add_detail_quotes(command); 58 | msg = ft_strdup("minishell: "); 59 | if (command != NULL) 60 | { 61 | msg = join_strs(msg, command); 62 | msg = join_strs(msg, ": "); 63 | } 64 | if (detail != NULL) 65 | { 66 | if (detail_quotes) 67 | msg = join_strs(msg, "`"); 68 | msg = join_strs(msg, detail); 69 | if (detail_quotes) 70 | msg = join_strs(msg, "'"); 71 | msg = join_strs(msg, ": "); 72 | } 73 | msg = join_strs(msg, error_message); 74 | ft_putendl_fd(msg, STDERR_FILENO); 75 | free_ptr(msg); 76 | return (error_nb); 77 | } 78 | 79 | /* errmsg: 80 | * Prints an error message that is unrelated to a specific command. 81 | * Used in parsing phase for syntax errors. 82 | */ 83 | void errmsg(char *errmsg, char *detail, int quotes) 84 | { 85 | char *msg; 86 | 87 | msg = ft_strdup("minishell: "); 88 | msg = join_strs(msg, errmsg); 89 | if (quotes) 90 | msg = join_strs(msg, " `"); 91 | else 92 | msg = join_strs(msg, ": "); 93 | msg = join_strs(msg, detail); 94 | if (quotes) 95 | msg = join_strs(msg, "'"); 96 | ft_putendl_fd(msg, STDERR_FILENO); 97 | free_ptr(msg); 98 | } 99 | 100 | /* usage_message: 101 | * Prints a usage message. Used if start-up arguments are invalid. 102 | */ 103 | bool usage_message(bool return_val) 104 | { 105 | ft_putendl_fd("Usage: ./minishell", 2); 106 | ft_putendl_fd("Usage: ./minishell -c \"input line\"", 2); 107 | return (return_val); 108 | } 109 | -------------------------------------------------------------------------------- /sources/lexer/tokenization_utils.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* tokenization_utils.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/20 12:34:40 by alexa #+# #+# */ 9 | /* Updated: 2022/09/20 12:35:02 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | int save_separator(t_token **token_lst, char *str, int index, int type) 16 | { 17 | int i; 18 | char *sep; 19 | 20 | i = 0; 21 | if (type == APPEND || type == HEREDOC) 22 | { 23 | sep = malloc(sizeof(char) * 3); 24 | if (!sep) 25 | return (1); 26 | while (i < 2) 27 | sep[i++] = str[index++]; 28 | sep[i] = '\0'; 29 | lst_add_back_token(token_lst, lst_new_token(sep, NULL, type, DEFAULT)); 30 | } 31 | else 32 | { 33 | sep = malloc(sizeof(char) * 2); 34 | if (!sep) 35 | return (1); 36 | while (i < 1) 37 | sep[i++] = str[index++]; 38 | sep[i] = '\0'; 39 | lst_add_back_token(token_lst, lst_new_token(sep, NULL, type, DEFAULT)); 40 | } 41 | return (0); 42 | } 43 | 44 | int save_word(t_token **token_lst, char *str, int index, int start) 45 | { 46 | int i; 47 | char *word; 48 | 49 | i = 0; 50 | word = malloc(sizeof(char) * (index - start + 1)); 51 | if (!word) 52 | return (1); 53 | while (start < index) 54 | { 55 | word[i] = str[start]; 56 | start++; 57 | i++; 58 | } 59 | word[i] = '\0'; 60 | lst_add_back_token(token_lst, \ 61 | lst_new_token(word, ft_strdup(word), WORD, DEFAULT)); 62 | return (0); 63 | } 64 | 65 | int is_separator(char *str, int i) 66 | { 67 | if (((str[i] > 8 && str[i] < 14) || str[i] == 32)) 68 | return (SPACES); 69 | else if (str[i] == '|') 70 | return (PIPE); 71 | else if (str[i] == '<' && str[i + 1] == '<') 72 | return (HEREDOC); 73 | else if (str[i] == '>' && str[i + 1] == '>') 74 | return (APPEND); 75 | else if (str[i] == '<') 76 | return (INPUT); 77 | else if (str[i] == '>') 78 | return (TRUNC); 79 | else if (str[i] == '\0') 80 | return (END); 81 | else 82 | return (0); 83 | } 84 | 85 | int set_status(int status, char *str, int i) 86 | { 87 | if (str[i] == '\'' && status == DEFAULT) 88 | status = SQUOTE; 89 | else if (str[i] == '\"' && status == DEFAULT) 90 | status = DQUOTE; 91 | else if (str[i] == '\'' && status == SQUOTE) 92 | status = DEFAULT; 93 | else if (str[i] == '\"' && status == DQUOTE) 94 | status = DEFAULT; 95 | return (status); 96 | } 97 | 98 | int save_word_or_sep(int *i, char *str, int start, t_data *data) 99 | { 100 | int type; 101 | 102 | type = is_separator(str, (*i)); 103 | if (type) 104 | { 105 | if ((*i) != 0 && is_separator(str, (*i) - 1) == 0) 106 | save_word(&data->token, str, (*i), start); 107 | if (type == APPEND || type == HEREDOC || type == PIPE 108 | || type == INPUT || type == TRUNC || type == END) 109 | { 110 | save_separator(&data->token, str, (*i), type); 111 | if (type == APPEND || type == HEREDOC) 112 | (*i)++; 113 | } 114 | start = (*i) + 1; 115 | } 116 | return (start); 117 | } 118 | -------------------------------------------------------------------------------- /sources/utils/init_data.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* init_data.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 17:09:12 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/05 13:11:22 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* init_env: 16 | * Initializes a data variable with the contents of the environment 17 | * variables inherited from the original shell. 18 | * Returns 0 on failure, 1 on success. 19 | */ 20 | static bool init_env(t_data *data, char **env) 21 | { 22 | int i; 23 | 24 | data->env = ft_calloc(env_var_count(env) + 1, sizeof * data->env); 25 | if (!data->env) 26 | return (false); 27 | i = 0; 28 | while (env[i]) 29 | { 30 | data->env[i] = ft_strdup(env[i]); 31 | if (!data->env[i]) 32 | return (false); 33 | i++; 34 | } 35 | return (true); 36 | } 37 | 38 | /* init_wds: 39 | * Initializes working directory variables as a safeguard against 40 | * environment PWD and OLDPWD being unset or otherwise not present 41 | * in the environment. Used for cd builtin. 42 | * Returns true if successful, false in case of error. 43 | */ 44 | static bool init_wds(t_data *data) 45 | { 46 | char buff[PATH_MAX]; 47 | char *wd; 48 | 49 | wd = getcwd(buff, PATH_MAX); 50 | data->working_dir = ft_strdup(wd); 51 | if (!data->working_dir) 52 | return (false); 53 | if (get_env_var_index(data->env, "OLDPWD") != -1) 54 | { 55 | data->old_working_dir = ft_strdup(get_env_var_value(data->env, 56 | "OLDPWD")); 57 | if (!data->old_working_dir) 58 | return (false); 59 | } 60 | else 61 | { 62 | data->old_working_dir = ft_strdup(wd); 63 | if (!data->old_working_dir) 64 | return (false); 65 | } 66 | return (true); 67 | } 68 | 69 | /* init_data: 70 | * Initializes the data structure used in parsing and executing user input. 71 | * Returns true if successful, false in case of error. 72 | */ 73 | bool init_data(t_data *data, char **env) 74 | { 75 | if (!init_env(data, env)) 76 | { 77 | errmsg_cmd("Fatal", NULL, "Could not initialize environment", 1); 78 | return (false); 79 | } 80 | if (!init_wds(data)) 81 | { 82 | errmsg_cmd("Fatal", NULL, "Could not initialize working directories", 83 | 1); 84 | return (false); 85 | } 86 | data->token = NULL; 87 | data->user_input = NULL; 88 | data->cmd = NULL; 89 | data->pid = -1; 90 | g_last_exit_code = 0; 91 | return (true); 92 | } 93 | 94 | /* init_io: 95 | * Initializes a structure with default values to contain 96 | * infile and outfile information for a command. 97 | */ 98 | void init_io(t_command *cmd) 99 | { 100 | if (!cmd->io_fds) 101 | { 102 | cmd->io_fds = malloc(sizeof * cmd->io_fds); 103 | if (!cmd->io_fds) 104 | return ; 105 | cmd->io_fds->infile = NULL; 106 | cmd->io_fds->outfile = NULL; 107 | cmd->io_fds->heredoc_delimiter = NULL; 108 | cmd->io_fds->heredoc_quotes = false; 109 | cmd->io_fds->fd_in = -1; 110 | cmd->io_fds->fd_out = -1; 111 | cmd->io_fds->stdin_backup = -1; 112 | cmd->io_fds->stdout_backup = -1; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /sources/debug/debug.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* debug.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/05 12:17:42 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/07 16:25:21 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | static void print_cmd_args(t_command *cmd) 16 | { 17 | int i; 18 | 19 | if (!cmd->args) 20 | return ; 21 | i = 0; 22 | while (cmd->args[i]) 23 | { 24 | printf("\tArgs[%d] = %s\n", i, cmd->args[i]); 25 | i++; 26 | } 27 | } 28 | 29 | static void print_cmd_io(t_command *cmd) 30 | { 31 | if (!cmd->io_fds) 32 | return ; 33 | if (cmd->io_fds->infile) 34 | { 35 | printf("\tInfile: %s\n", cmd->io_fds->infile); 36 | printf("\t\tfd_in: %d\n", cmd->io_fds->fd_in); 37 | } 38 | if (cmd->io_fds->heredoc_delimiter) 39 | printf("\tHeredoc delimiter: %s\n", cmd->io_fds->heredoc_delimiter); 40 | if (cmd->io_fds->outfile) 41 | { 42 | printf("\tOutfile: %s\n", cmd->io_fds->outfile); 43 | printf("\t\tfd_in: %d\n", cmd->io_fds->fd_out); 44 | } 45 | } 46 | 47 | void print_cmd_list(t_data *data) 48 | { 49 | t_command *cmd; 50 | 51 | cmd = data->cmd; 52 | printf("\n---- COMMAND LIST\n"); 53 | while (cmd) 54 | { 55 | printf("--- Command = %s\n", cmd->command); 56 | print_cmd_args(cmd); 57 | printf("\tPipe_output = %d\n", cmd->pipe_output); 58 | print_cmd_io(cmd); 59 | if (cmd->prev == NULL) 60 | printf("\tprev = NULL\n"); 61 | else 62 | printf("\tprev = %s\n", cmd->prev->command); 63 | if (cmd->next == NULL) 64 | printf("\tnext = NULL\n"); 65 | else 66 | printf("\tnext = %s\n", cmd->next->command); 67 | printf("\n"); 68 | cmd = cmd->next; 69 | } 70 | printf("\n"); 71 | } 72 | 73 | void print_token_type(t_token *token, char *prefix) 74 | { 75 | printf("%s", prefix); 76 | if (token->type == SPACES) 77 | printf("SPACES\n"); 78 | else if (token->type == WORD) 79 | printf("WORD\n"); 80 | else if (token->type == VAR) 81 | printf("VAR\n"); 82 | else if (token->type == PIPE) 83 | printf("PIPE\n"); 84 | else if (token->type == INPUT) 85 | printf("INPUT\n"); 86 | else if (token->type == TRUNC) 87 | printf("TRUNC\n"); 88 | else if (token->type == HEREDOC) 89 | printf("HEREDOC\n"); 90 | else if (token->type == APPEND) 91 | printf("APPEND\n"); 92 | else if (token->type == END) 93 | printf("END\n"); 94 | } 95 | 96 | void print_token_list(t_token **tokens) 97 | { 98 | t_token *lst; 99 | int i; 100 | 101 | lst = *tokens; 102 | printf("\n---- TOKEN LIST\n"); 103 | i = 0; 104 | while (lst) 105 | { 106 | printf("--- Token [%d] [%p]\n", i, lst); 107 | printf("\tString = [%s]\n", lst->str); 108 | printf("\tStr backup = [%s]\n", lst->str_backup); 109 | print_token_type(lst, "\tType = "); 110 | printf("\tStatus = %d\n", lst->status); 111 | if (lst->prev) 112 | printf("\tPrev = [%p]\n", lst->prev); 113 | else 114 | printf("\tPrev = NULL\n"); 115 | if (lst->next) 116 | printf("\tNext = [%p]\n", lst->next); 117 | else 118 | printf("\tNext = NULL\n"); 119 | i++; 120 | lst = lst->next; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /sources/main.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* main.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 17:08:47 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/11 13:57:52 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* start_check: 16 | * Checks the arguments at program start up. Minishell can start either: 17 | * * when no arguments are supplied. 18 | * * when the -c option is supplied followed by one argument. 19 | * Returns true if minishell can begin, false with a usage message if not. 20 | */ 21 | static bool start_check(t_data *data, int ac, char **av) 22 | { 23 | if (ac != 1 && ac != 3) 24 | return (usage_message(false)); 25 | if (ac == 3) 26 | { 27 | data->interactive = false; 28 | if (!av[1] || (av[1] && ft_strcmp(av[1], "-c") != 0)) 29 | return (usage_message(false)); 30 | else if (!av[2] || (av[2] && av[2][0] == '\0')) 31 | return (usage_message(false)); 32 | } 33 | else 34 | data->interactive = true; 35 | return (true); 36 | } 37 | 38 | /* minishell_interactive: 39 | * Runs parsing and execution in interactive mode, i.e. when minishell 40 | * is started without arguments and provides a prompt for user input. 41 | */ 42 | void minishell_interactive(t_data *data) 43 | { 44 | while (1) 45 | { 46 | set_signals_interactive(); 47 | data->user_input = readline(PROMPT); 48 | set_signals_noninteractive(); 49 | if (parse_user_input(data) == true) 50 | g_last_exit_code = execute(data); 51 | else 52 | g_last_exit_code = 1; 53 | free_data(data, false); 54 | } 55 | } 56 | 57 | /* minishell_noninteractive: 58 | * Runs parsing and execution in noninteractive mode, i.e. when 59 | * minishell is started with the -c option followed by an argument 60 | * containing the commands to be executed: 61 | * ./minishell -c "echo hello | wc -c" 62 | * Commands in this mode can be separated by a semicolon, ';' to 63 | * indicate sequential execution: 64 | * ./minishell -c "echo hello; ls" 65 | * -> echo hello is the first command run 66 | * -> ls is the second 67 | */ 68 | void minishell_noninteractive(t_data *data, char *arg) 69 | { 70 | char **user_inputs; 71 | int i; 72 | 73 | user_inputs = ft_split(arg, ';'); 74 | if (!user_inputs) 75 | exit_shell(data, EXIT_FAILURE); 76 | i = 0; 77 | while (user_inputs[i]) 78 | { 79 | data->user_input = ft_strdup(user_inputs[i]); 80 | if (parse_user_input(data) == true) 81 | g_last_exit_code = execute(data); 82 | else 83 | g_last_exit_code = 1; 84 | i++; 85 | free_data(data, false); 86 | } 87 | free_str_tab(user_inputs); 88 | } 89 | 90 | /* main: 91 | * Begins minishell. Checks input and determines if 92 | * minishell should be run interactively or not. 93 | * Exits the shell with the exit status or the last command. 94 | */ 95 | int main(int ac, char **av, char **env) 96 | { 97 | t_data data; 98 | 99 | ft_memset(&data, 0, sizeof(t_data)); 100 | if (!start_check(&data, ac, av) || !init_data(&data, env)) 101 | exit_shell(NULL, EXIT_FAILURE); 102 | if (data.interactive) 103 | minishell_interactive(&data); 104 | else 105 | minishell_noninteractive(&data, av[2]); 106 | exit_shell(&data, g_last_exit_code); 107 | return (0); 108 | } 109 | -------------------------------------------------------------------------------- /sources/builtins/cd_builtin.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* cd_builtin.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 19:03:08 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/11 14:22:23 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* update_wds: 16 | * Updates the PWD and OLDPWD in the environment after a directory change. 17 | * A copy of the paths are stored internally for use in case the environment 18 | * variables are unset. 19 | */ 20 | static void update_wds(t_data *data, char *wd) 21 | { 22 | set_env_var(data, "OLDPWD", get_env_var_value(data->env, "PWD")); 23 | set_env_var(data, "PWD", wd); 24 | if (data->old_working_dir) 25 | { 26 | free_ptr(data->old_working_dir); 27 | data->old_working_dir = ft_strdup(data->working_dir); 28 | } 29 | if (data->working_dir) 30 | { 31 | free_ptr(data->working_dir); 32 | data->working_dir = ft_strdup(wd); 33 | } 34 | free_ptr(wd); 35 | } 36 | 37 | /* chdir_errno_mod: 38 | * chdir can sometimes set errno to ESTALE ("Stale file handle") 39 | * when a parent directory is removed on some systems. This is due 40 | * to the inode table entry being recycled. This is a fix to display 41 | * "no such file or directory" error instead. 42 | */ 43 | static bool chdir_errno_mod(char *path) 44 | { 45 | if (errno == ESTALE) 46 | errno = ENOENT; 47 | errmsg_cmd("cd", path, strerror(errno), errno); 48 | return (false); 49 | } 50 | 51 | /* change_dir: 52 | * Changes the current working directory and updates the 53 | * OLDPWD environment variable. 54 | * Returns 1 on success, 0 on failure. 55 | */ 56 | static bool change_dir(t_data *data, char *path) 57 | { 58 | char *ret; 59 | char *tmp; 60 | char cwd[PATH_MAX]; 61 | 62 | ret = NULL; 63 | if (chdir(path) != 0) 64 | return (chdir_errno_mod(path)); 65 | ret = getcwd(cwd, PATH_MAX); 66 | if (!ret) 67 | { 68 | errmsg_cmd("cd: error retrieving current directory", 69 | "getcwd: cannot access parent directories", 70 | strerror(errno), errno); 71 | ret = ft_strjoin(data->working_dir, "/"); 72 | tmp = ret; 73 | ret = ft_strjoin(tmp, path); 74 | free_ptr(tmp); 75 | } 76 | else 77 | ret = ft_strdup(cwd); 78 | update_wds(data, ret); 79 | return (true); 80 | } 81 | 82 | /* cd_builtin: 83 | * Executes the builtin cd command by changing the working directory. 84 | * Returns 0 on success, 1 on failure. 85 | */ 86 | int cd_builtin(t_data *data, char **args) 87 | { 88 | char *path; 89 | 90 | if (!args || !args[1] || ft_isspace(args[1][0]) 91 | || args[1][0] == '\0' || ft_strncmp(args[1], "--", 3) == 0) 92 | { 93 | path = get_env_var_value(data->env, "HOME"); 94 | if (!path || *path == '\0' || ft_isspace(*path)) 95 | return (errmsg_cmd("cd", NULL, "HOME not set", EXIT_FAILURE)); 96 | return (!change_dir(data, path)); 97 | } 98 | if (args[2]) 99 | return (errmsg_cmd("cd", NULL, "too many arguments", EXIT_FAILURE)); 100 | if (ft_strncmp(args[1], "-", 2) == 0) 101 | { 102 | path = get_env_var_value(data->env, "OLDPWD"); 103 | if (!path) 104 | return (errmsg_cmd("cd", NULL, "OLDPWD not set", EXIT_FAILURE)); 105 | return (!change_dir(data, path)); 106 | } 107 | return (!change_dir(data, args[1])); 108 | } 109 | -------------------------------------------------------------------------------- /sources/parser/parse_heredoc_utils.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* parse_heredoc_utils.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:09:37 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:09:40 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* make_str_from_tab: 16 | * Creates a single string from an array of strings by 17 | * joining a string to the next. 18 | * Returns the string. 19 | */ 20 | static char *make_str_from_tab(char **tab) 21 | { 22 | char *str; 23 | char *tmp; 24 | int i; 25 | 26 | i = -1; 27 | while (tab[++i]) 28 | { 29 | tmp = str; 30 | if (i == 0) 31 | str = ft_strdup(tab[0]); 32 | else 33 | { 34 | str = ft_strjoin(tmp, tab[i]); 35 | free_ptr(tmp); 36 | } 37 | if (tab[i + 1]) 38 | { 39 | tmp = str; 40 | str = ft_strjoin(tmp, " "); 41 | free_ptr(tmp); 42 | } 43 | } 44 | free_str_tab(tab); 45 | return (str); 46 | } 47 | 48 | /* get_exoanded_var_line: 49 | * Prepares a line containing '$' for environment variable expansion. 50 | * Splits the line into words to avoid issues with inexistent 51 | * environment variables. 52 | * ex. $USER uses $LANGUAGE -> username uses en_US:en 53 | * Returns a new line with expanded variables. 54 | */ 55 | static char *get_expanded_var_line(t_data *data, char *line) 56 | { 57 | char **words; 58 | int i; 59 | 60 | words = ft_split(line, ' '); 61 | if (!words) 62 | return (NULL); 63 | i = 0; 64 | while (words[i]) 65 | { 66 | if (ft_strchr(words[i], '$')) 67 | { 68 | words[i] = var_expander_heredoc(data, words[i]); 69 | if (!words[i]) 70 | return (NULL); 71 | } 72 | i++; 73 | } 74 | return (make_str_from_tab(words)); 75 | } 76 | 77 | /* evaluate_heredoc_line: 78 | * Checks whether the read line should be written to heredoc file. 79 | * If the line is NULL or the same as the given delimiter, returns false 80 | * to signify that we should stop reading with readline. Otherwise, returns 81 | * true. 82 | */ 83 | static bool evaluate_heredoc_line(t_data *data, char **line, 84 | t_io_fds *io, bool *ret) 85 | { 86 | if (*line == NULL) 87 | { 88 | errmsg_cmd("warning", "here-document delimited by end-of-file: wanted", 89 | io->heredoc_delimiter, true); 90 | *ret = true; 91 | return (false); 92 | } 93 | if (ft_strcmp(*line, io->heredoc_delimiter) == 0) 94 | { 95 | *ret = true; 96 | return (false); 97 | } 98 | if (io->heredoc_quotes == false && ft_strchr(*line, '$')) 99 | { 100 | *line = get_expanded_var_line(data, *line); 101 | if (!(*line)) 102 | { 103 | free_ptr(*line); 104 | *ret = false; 105 | return (false); 106 | } 107 | } 108 | return (true); 109 | } 110 | 111 | /* fill_heredoc: 112 | * Copies user input into a temporary file. If user inputs an environment variable 113 | * like $USER, expands the variable before writing to the heredoc. 114 | * Returns true on success, false on failure. 115 | */ 116 | bool fill_heredoc(t_data *data, t_io_fds *io, int fd) 117 | { 118 | char *line; 119 | bool ret; 120 | 121 | ret = false; 122 | line = NULL; 123 | while (1) 124 | { 125 | set_signals_interactive(); 126 | line = readline(">"); 127 | set_signals_noninteractive(); 128 | if (!evaluate_heredoc_line(data, &line, io, &ret)) 129 | break ; 130 | ft_putendl_fd(line, fd); 131 | free_ptr(line); 132 | } 133 | free_ptr(line); 134 | return (ret); 135 | } 136 | -------------------------------------------------------------------------------- /sources/parser/fill_args_echo_utils.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* fill_args_echo_utils.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:10:11 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:11:41 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* 16 | ** This function joins all the tokens of a quoted sentence 17 | ** (ex " Hello $user") that was previously split. 18 | ** To join them, the tokens have to be of type VAR and the join 19 | ** setting must be set to true (the quotes are implied) 20 | ** The function is only used when the command is "echo". 21 | ** 22 | ** ex: The strings -> "Hello" " " "world" 23 | ** become "Hello world" 24 | */ 25 | 26 | char *join_vars(t_token **token_node) 27 | { 28 | t_token *temp; 29 | char *str; 30 | 31 | temp = *token_node; 32 | str = ft_strdup(temp->str); 33 | while (temp->type == VAR && temp->next->type == VAR 34 | && temp->next->join == true) 35 | { 36 | str = ft_strjoin(str, temp->next->str); 37 | temp = temp->next; 38 | } 39 | *token_node = temp; 40 | return (str); 41 | } 42 | 43 | /* 44 | ** This function counts the number of arguments in the list of tokens 45 | ** To consider a token or multiple tokens as an argument they must be either 46 | ** a WORD or a VAR and if they temp = *token_node; 47 | are a VAR that has to be joined, we have 48 | ** to loop through all the tokens that check these conditions 49 | ** (type == VAR and join == true) before counting them as one argument 50 | */ 51 | 52 | int count_args(t_token *temp) 53 | { 54 | int i; 55 | 56 | i = 0; 57 | while (temp && (temp->type == WORD || temp->type == VAR)) 58 | { 59 | if (temp->type == VAR && temp->join == true) 60 | { 61 | while (temp->type == VAR && temp->join == true) 62 | temp = temp->next; 63 | i++; 64 | } 65 | else 66 | { 67 | i++; 68 | temp = temp->next; 69 | } 70 | } 71 | return (i); 72 | } 73 | 74 | char **copy_in_new_tab(int len, char **new_tab, 75 | t_command *last_cmd, t_token *tmp) 76 | { 77 | int i; 78 | 79 | i = 0; 80 | while (i < len) 81 | { 82 | new_tab[i] = last_cmd->args[i]; 83 | i++; 84 | } 85 | while (tmp->type == WORD || tmp->type == VAR) 86 | { 87 | if (tmp->join == true) 88 | new_tab[i] = join_vars(&tmp); 89 | else 90 | new_tab[i] = ft_strdup(tmp->str); 91 | i++; 92 | tmp = tmp->next; 93 | } 94 | new_tab[i] = NULL; 95 | return (new_tab); 96 | } 97 | 98 | /* remove_empty_var_args: 99 | ** If a variable does not exist in the environment, the token string 100 | ** will contain "\0". In this case, echo should not print the variable 101 | ** or any spaces before/after it. Therefore the token must be 102 | ** removed before creating/adding echo args. 103 | ** i.e., if variable X does not exist in environment, 104 | ** 'echo $X $X $X $USER' should print: 105 | ** 'username' (not ' username') 106 | ** However, if the variable exists but its value is empty, the token 107 | ** should not be removed. 108 | */ 109 | void remove_empty_var_args(t_token **tokens) 110 | { 111 | t_token *temp; 112 | 113 | temp = *tokens; 114 | while (temp->type == WORD || temp->type == VAR) 115 | { 116 | if (temp->type == VAR && temp->str[0] == '\0' 117 | && temp->var_exists == false) 118 | { 119 | temp = temp->next; 120 | if (temp == (*tokens)->next) 121 | (*tokens) = (*tokens)->next; 122 | lstdelone_token(temp->prev, free_ptr); 123 | } 124 | else 125 | temp = temp->next; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /sources/parser/fill_args_default.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* fill_args_default.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alexa +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/11/10 00:05:49 by alexa #+# #+# */ 9 | /* Updated: 2022/11/10 00:45:21 by alexa ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | int count_arguments(t_token *temp) 16 | { 17 | int i; 18 | 19 | i = 0; 20 | while (temp && (temp->type == WORD || temp->type == VAR)) 21 | { 22 | i++; 23 | temp = temp->next; 24 | } 25 | return (i); 26 | } 27 | 28 | /* 29 | ** This function fills the array of arguments of the last_cmd by default mode: 30 | ** - It allocates the array of arguments thanks to the count_args function 31 | ** - It loops through the tokens list while the nodes are of type 32 | ** VAR or WORD, and fills last_cmd->args[i] with the current token 33 | */ 34 | 35 | int create_args_default_mode(t_token **token_node, t_command *last_cmd) 36 | { 37 | int i; 38 | int nb_args; 39 | t_token *temp; 40 | 41 | i = 0; 42 | temp = *token_node; 43 | nb_args = count_arguments(temp); 44 | last_cmd->args = malloc(sizeof(char *) * (nb_args + 2)); 45 | if (!last_cmd->args) 46 | return (FAILURE); 47 | temp = *token_node; 48 | i = 0; 49 | last_cmd->args[i] = ft_strdup(last_cmd->command); 50 | i++; 51 | while (temp->type == WORD || temp->type == VAR) 52 | { 53 | last_cmd->args[i] = ft_strdup(temp->str); 54 | i++; 55 | temp = temp->next; 56 | } 57 | last_cmd->args[i] = NULL; 58 | *token_node = temp; 59 | return (SUCCESS); 60 | } 61 | 62 | static char **copy_default_in_new_tab( 63 | int len, char **new_tab, t_command *last_cmd, t_token **tk_node) 64 | { 65 | int i; 66 | t_token *temp; 67 | 68 | i = 0; 69 | temp = *tk_node; 70 | while (i < len) 71 | { 72 | new_tab[i] = last_cmd->args[i]; 73 | i++; 74 | } 75 | while (temp->type == WORD || temp->type == VAR) 76 | { 77 | new_tab[i] = ft_strdup(temp->str); 78 | i++; 79 | temp = temp->next; 80 | } 81 | new_tab[i] = NULL; 82 | return (new_tab); 83 | } 84 | 85 | int add_args_default_mode(t_token **token_node, t_command *last_cmd) 86 | { 87 | int i; 88 | int len; 89 | char **new_tab; 90 | t_token *temp; 91 | 92 | i = 0; 93 | temp = *token_node; 94 | while (temp->type == WORD || temp->type == VAR) 95 | { 96 | i++; 97 | temp = temp->next; 98 | } 99 | len = 0; 100 | while (last_cmd->args[len]) 101 | len++; 102 | new_tab = malloc(sizeof(char *) * (i + len + 1)); 103 | if (!new_tab) 104 | return (FAILURE); 105 | new_tab = copy_default_in_new_tab(len, new_tab, last_cmd, token_node); 106 | free(last_cmd->args); 107 | last_cmd->args = new_tab; 108 | *token_node = temp; 109 | return (SUCCESS); 110 | } 111 | 112 | /* 113 | ** This function fills the arguments in the command structure (command->args) 114 | ** It has two modes: 115 | ** - The "echo mode" if the command is the builtin "echo" 116 | ** - The default mode for all the other cases 117 | */ 118 | 119 | int fill_args(t_token **token_node, t_command *last_cmd) 120 | { 121 | if (!ft_strcmp(last_cmd->command, "echo")) 122 | { 123 | if (!(last_cmd->args)) 124 | return (create_args_echo_mode(token_node, last_cmd)); 125 | else 126 | return (add_args_echo_mode(token_node, last_cmd)); 127 | } 128 | else 129 | { 130 | if (last_cmd && !(last_cmd->args)) 131 | return (create_args_default_mode(token_node, last_cmd)); 132 | else 133 | return (add_args_default_mode(token_node, last_cmd)); 134 | } 135 | return (SUCCESS); 136 | } 137 | -------------------------------------------------------------------------------- /sources/execution/execute.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* execute.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 17:09:49 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/07 16:10:23 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | int g_last_exit_code; 16 | 17 | /* get_children: 18 | * Waits for children to terminate after cleaning up fds and the command 19 | * list. 20 | * Returns a child's exit status as bash does: 21 | * "The return status (see Exit Status) of a simple command is its 22 | * exit status as provided by the POSIX 1003.1 waitpid function, or 23 | * 128+n if the command was terminated by signal n." 24 | * If there are multiple commands in a pipeline: 25 | * "The exit status of a pipeline is the exit status of the last command 26 | * in the pipeline" 27 | */ 28 | static int get_children(t_data *data) 29 | { 30 | pid_t wpid; 31 | int status; 32 | int save_status; 33 | 34 | close_fds(data->cmd, false); 35 | save_status = 0; 36 | wpid = 0; 37 | while (wpid != -1 || errno != ECHILD) 38 | { 39 | wpid = waitpid(-1, &status, 0); 40 | if (wpid == data->pid) 41 | save_status = status; 42 | continue ; 43 | } 44 | if (WIFSIGNALED(save_status)) 45 | status = 128 + WTERMSIG(save_status); 46 | else if (WIFEXITED(save_status)) 47 | status = WEXITSTATUS(save_status); 48 | else 49 | status = save_status; 50 | return (status); 51 | } 52 | 53 | /* create_children: 54 | * Creates a child process for each command to execute, except in the 55 | * case of a builtin command that is not piped, which executes in the 56 | * main process (no children created in this case). 57 | * Returns true when a process was created for each command or when a 58 | * builtin was executed alone. 59 | * Returns false if there was a fork error. 60 | */ 61 | static int create_children(t_data *data) 62 | { 63 | t_command *cmd; 64 | 65 | cmd = data->cmd; 66 | while (data->pid != 0 && cmd) 67 | { 68 | data->pid = fork(); 69 | if (data->pid == -1) 70 | return (errmsg_cmd("fork", NULL, strerror(errno), EXIT_FAILURE)); 71 | else if (data->pid == 0) 72 | execute_command(data, cmd); 73 | cmd = cmd->next; 74 | } 75 | return (get_children(data)); 76 | } 77 | 78 | /* prep_for_exec: 79 | * Prepares the command list for execution, creates pipes 80 | * and checks the input and output files. 81 | * Returns false in case of error, true if all is ready to 82 | * execute. 83 | */ 84 | static int prep_for_exec(t_data *data) 85 | { 86 | if (!data || !data->cmd) 87 | return (EXIT_SUCCESS); 88 | if (!data->cmd->command) 89 | { 90 | if (data->cmd->io_fds 91 | && !check_infile_outfile(data->cmd->io_fds)) 92 | return (EXIT_FAILURE); 93 | return (EXIT_SUCCESS); 94 | } 95 | if (!create_pipes(data)) 96 | return (EXIT_FAILURE); 97 | return (CMD_NOT_FOUND); 98 | } 99 | 100 | /* execute: 101 | * Executes the given commands by creating children processes 102 | * and waiting for them to terminate. 103 | * Returns the exit code of the last child to terminate. Or 104 | * exit code 1 in case of failure in the child creation process. 105 | */ 106 | int execute(t_data *data) 107 | { 108 | int ret; 109 | 110 | ret = prep_for_exec(data); 111 | if (ret != CMD_NOT_FOUND) 112 | return (ret); 113 | if (!data->cmd->pipe_output && !data->cmd->prev 114 | && check_infile_outfile(data->cmd->io_fds)) 115 | { 116 | redirect_io(data->cmd->io_fds); 117 | ret = execute_builtin(data, data->cmd); 118 | restore_io(data->cmd->io_fds); 119 | } 120 | if (ret != CMD_NOT_FOUND) 121 | return (ret); 122 | return (create_children(data)); 123 | } 124 | -------------------------------------------------------------------------------- /sources/builtins/exit_builtin.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* exit_builtin.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 18:32:33 by mcombeau #+# #+# */ 9 | /* Updated: 2022/11/05 12:17:05 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* check_out_of_range: 16 | * Checks if the number goes over LONG_MAX or LONG_MIN. 17 | * Sets an error boolean to true if the number is out of range, false if not. 18 | */ 19 | static bool check_out_of_range(int neg, unsigned long long num, bool *error) 20 | { 21 | if ((neg == 1 && num > LONG_MAX) 22 | || (neg == -1 && num > -(unsigned long)LONG_MIN)) 23 | *error = true; 24 | return (*error); 25 | } 26 | 27 | /* ft_atoi_long: 28 | * Transforms a string comprised of digits into a long integer. 29 | * Returns the long integer. In case of error, sets an error boolean 30 | * to true. 31 | */ 32 | static int ft_atoi_long(const char *str, bool *error) 33 | { 34 | unsigned long long num; 35 | int neg; 36 | int i; 37 | 38 | num = 0; 39 | neg = 1; 40 | i = 0; 41 | while (str[i] && ft_isspace(str[i])) 42 | i++; 43 | if (str[i] == '+') 44 | i++; 45 | else if (str[i] == '-') 46 | { 47 | neg *= -1; 48 | i++; 49 | } 50 | while (str[i] && ft_isdigit(str[i])) 51 | { 52 | num = (num * 10) + (str[i] - '0'); 53 | if (check_out_of_range(neg, num, error)) 54 | break ; 55 | i++; 56 | } 57 | return (num * neg); 58 | } 59 | 60 | /* get_exit_code: 61 | * Gets the exit code from the arguments given to the exit builtin. 62 | * Returns 0 if no arguments were provided. 63 | * Returns 2 in case argument is not digits. 64 | * Returns the numeric exit code on success. 65 | */ 66 | static int get_exit_code(char *arg, bool *error) 67 | { 68 | unsigned long long i; 69 | 70 | if (!arg) 71 | return (g_last_exit_code); 72 | i = 0; 73 | while (ft_isspace(arg[i])) 74 | i++; 75 | if (arg[i] == '\0') 76 | *error = true; 77 | if (arg[i] == '-' || arg[i] == '+') 78 | i++; 79 | if (!ft_isdigit(arg[i])) 80 | *error = true; 81 | while (arg[i]) 82 | { 83 | if (!isdigit(arg[i]) && !ft_isspace(arg[i])) 84 | *error = true; 85 | i++; 86 | } 87 | i = ft_atoi_long(arg, error); 88 | return (i % 256); 89 | } 90 | 91 | /* is_quiet_mode: 92 | * If exit is not called alone, it should not print "exit". 93 | * Returns true if exit should not be printed. False if exit was called 94 | * alone and the "exit" message should be printed. 95 | */ 96 | static bool is_quiet_mode(t_data *data) 97 | { 98 | t_command *cmd; 99 | 100 | cmd = data->cmd; 101 | if (!cmd) 102 | return (false); 103 | if (cmd->next != NULL || cmd->prev != NULL) 104 | return (true); 105 | return (false); 106 | } 107 | 108 | /* exit_builtin: 109 | * Executes the exit builtin. 110 | * If alone, prints exit and exits the shell with the provided exit code, or 0. 111 | * If piped, exits the child process with the provided exit code and does not exit 112 | * minishell. 113 | * In case of failure due to invalid arguments, does not exit the shell 114 | * and returns an error exit code (1 or 2) instead. 115 | */ 116 | int exit_builtin(t_data *data, char **args) 117 | { 118 | int exit_code; 119 | bool error; 120 | bool quiet; 121 | 122 | quiet = is_quiet_mode(data); 123 | error = false; 124 | if (!quiet && data->interactive) 125 | ft_putendl_fd("exit", 2); 126 | if (!args || !args[1]) 127 | exit_code = g_last_exit_code; 128 | else 129 | { 130 | exit_code = get_exit_code(args[1], &error); 131 | if (error) 132 | exit_code = errmsg_cmd("exit", args[1], 133 | "numeric argument required", 2); 134 | else if (args[2]) 135 | return (errmsg_cmd("exit", NULL, "too many arguments", 1)); 136 | } 137 | exit_shell(data, exit_code); 138 | return (2); 139 | } 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # minishell 2 | 3 |

4 | Minishell 42 project badge 5 |

6 | 7 | Minishell is a 42 school team project to create a basic shell program in C. It implements redirections and pipes, as well as environment variable expansions and the `cd`, `echo`, `env`, `exit`, `export`, `pwd` and `unset` builtin commands. 8 | 9 | > This project has been archived in the state it was in at the time of evaluation. 10 | 11 | ## Status 12 | 13 | Validated 11/11/2022. Grade: 99%. 14 | 15 | ## Usage 16 | 17 | Clone the repository with the [minitester](https://github.com/mcombeau/minitester-minishell-tester) submodule: 18 | ``` 19 | git clone --recurse-submodules git@github.com:mcombeau/minishell.git 20 | ``` 21 | 22 | To compile: 23 | 24 | ```shell 25 | cd minishell && make 26 | ``` 27 | 28 | To run the program: 29 | 30 | ```shell 31 | ./minishell 32 | ``` 33 | 34 | A prompt will appear. You may enter your commands to be executed. 35 | 36 | To run the included tester: 37 | ```shell 38 | cd minitester/ && bash minitester.sh 39 | ``` 40 | 41 | ## Supported Features 42 | 43 | Minishell is a miniature shell program based on Bash. Minishell supports: 44 | * Prompt display 45 | * Command history (up and down arrows) 46 | * System executables available from the environment (`ls`, `cat`, `grep`, etc.) 47 | * Local executables (`./minishell`) 48 | * Builtin commands : 49 | * `echo` (and option `-n`) 50 | * `cd` (with only a relative or absolute path) 51 | * `pwd` (no options) 52 | * `export` (no options) 53 | * `unset` (no options) 54 | * `env` (no options or arguments) 55 | * `exit` (with exit number but no other options) 56 | * Pipes `|` which redirect output from one command to input for the next 57 | * Redirections: 58 | * `>` redirects output 59 | * `>>` redirects output in append mode 60 | * `<` redirects input 61 | * `<< DELIMITER` displays a new prompt, reads user input until reaching `DELIMITER`, redirects user input to command input (does not update history) 62 | * Environment variables (i.e. `$USER` or `$VAR`) that expand to their values. 63 | * `$?` expands to the exit status of the most recently executed foreground pipeline. 64 | * User keyboard signals: 65 | * `ctrl-c` displays a new prompt line. 66 | * `ctrl-d` exits minishell 67 | * `ctrl-\` does nothing 68 | 69 | However, Minishell does not support `\`, `;`, `&&`, `||`, or wildcards. 70 | 71 | --- 72 | ### Useful Resources for the Minishell Project 73 | 74 | :us: Articles in English about the concepts tackled in this project: 75 | 76 | * [Creating and Killing Child Processes in C](https://www.codequoi.com/en/creating-and-killing-child-processes-in-c/) 77 | * [Pipe: an Inter-Process Communication Method](https://www.codequoi.com/en/pipe-an-inter-process-communication-method/) 78 | * [Sending and Intercepting a Signal in C](https://www.codequoi.com/en/sending-and-intercepting-a-signal-in-c/) 79 | * [Handling a File by its Descriptor in C](https://www.codequoi.com/en/handling-a-file-by-its-descriptor-in-c/) 80 | * [Errno and Error Management in C](https://www.codequoi.com/en/errno-and-error-management-in-c/) 81 | 82 | :fr: Articles en français sur les concepts abordés dans ce projet : 83 | 84 | * [Créer et tuer des processus fils en C](https://www.codequoi.com/creer-et-tuer-des-processus-fils-en-c/) 85 | * [Pipe : une méthode de communication inter-processus](https://www.codequoi.com/pipe-une-methode-de-communication-inter-processus/) 86 | * [Envoyer et intercepter un signal en C](https://www.codequoi.com/envoyer-et-intercepter-un-signal-en-c/) 87 | * [Manipuler un fichier à l’aide de son descripteur en C](https://www.codequoi.com/manipuler-un-fichier-a-laide-de-son-descripteur-en-c/) 88 | * [Errno et la gestion d’erreur en C](https://www.codequoi.com/errno-et-la-gestion-derreur-en-c/) 89 | 90 | Other useful links: 91 | 92 | * [Bash reference manual](https://www.gnu.org/software/bash/manual/bash.html) 93 | * Introduction to Systems Programming: a Hands-on Approach, [Chapter 5. Writing Your Own Shell](https://www.cs.purdue.edu/homes/grr/SystemsProgrammingBook/Book/Chapter5-WritingYourOwnShell.pdf) 94 | * [Stephen Brennan's Tutorial - Write a Shell in C](https://brennan.io/2015/01/16/write-a-shell-in-c/) 95 | * The Open Group Base Specifications, [Shell Command Language](https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html) 96 | * [A Guide to Unix Shell Quoting](https://rg1-teaching.mpi-inf.mpg.de/unixffb-ss98/quoting-guide.html) 97 | * [Austin Tripp's Quick Tutorial on Bash Quotes](https://www.austintripp.ca/blog/2019/07/18/bash-quotes) 98 | 99 | --- 100 | Made by aquesada and mcombeau 101 | -------------------------------------------------------------------------------- /sources/execution/execute_cmd.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* execute_cmd.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: mcombeau +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2022/09/17 17:12:08 by mcombeau #+# #+# */ 9 | /* Updated: 2022/10/07 15:49:07 by mcombeau ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "minishell.h" 14 | 15 | /* execute_builtin: 16 | * Executes the given command if it is a builtin command. 17 | * Returns -1 if the command is not a builtin command. 18 | * Returns 0 or 1 if the builtin command succeeded or failed. 19 | */ 20 | int execute_builtin(t_data *data, t_command *cmd) 21 | { 22 | int ret; 23 | 24 | ret = CMD_NOT_FOUND; 25 | if (ft_strncmp(cmd->command, "cd", 3) == 0) 26 | ret = cd_builtin(data, cmd->args); 27 | else if (ft_strncmp(cmd->command, "echo", 5) == 0) 28 | ret = echo_builtin(data, cmd->args); 29 | else if (ft_strncmp(cmd->command, "env", 4) == 0) 30 | ret = env_builtin(data, cmd->args); 31 | else if (ft_strncmp(cmd->command, "export", 7) == 0) 32 | ret = export_builtin(data, cmd->args); 33 | else if (ft_strncmp(cmd->command, "pwd", 4) == 0) 34 | ret = pwd_builtin(data, cmd->args); 35 | else if (ft_strncmp(cmd->command, "unset", 6) == 0) 36 | ret = unset_builtin(data, cmd->args); 37 | else if (ft_strncmp(cmd->command, "exit", 5) == 0) 38 | ret = exit_builtin(data, cmd->args); 39 | return (ret); 40 | } 41 | 42 | /* execute_sys_bin: 43 | * Executes the command's system binary file if it can be found 44 | * among the environment executable paths. 45 | * Returns CMD_NOT_FOUND if a path to the executable bin file cannot be 46 | * found. Returns 1 in case of failure to run existing, executable 47 | * file. 48 | */ 49 | static int execute_sys_bin(t_data *data, t_command *cmd) 50 | { 51 | if (!cmd->command || cmd->command[0] == '\0') 52 | return (CMD_NOT_FOUND); 53 | if (cmd_is_dir(cmd->command)) 54 | return (CMD_NOT_FOUND); 55 | cmd->path = get_cmd_path(data, cmd->command); 56 | if (!cmd->path) 57 | return (CMD_NOT_FOUND); 58 | if (execve(cmd->path, cmd->args, data->env) == -1) 59 | errmsg_cmd("execve", NULL, strerror(errno), errno); 60 | return (EXIT_FAILURE); 61 | } 62 | 63 | /* execute_local_bin: 64 | * Attempts to execute the given command as is, in case 65 | * it is a local directory file or already contains the 66 | * path to bin. 67 | * Returns CMD_NOT_FOUND if the command is not an existing executable 68 | * file. Returns 1 in case of failure to launch executable. 69 | */ 70 | static int execute_local_bin(t_data *data, t_command *cmd) 71 | { 72 | int ret; 73 | 74 | ret = check_command_not_found(data, cmd); 75 | if (ret != 0) 76 | return (ret); 77 | if (execve(cmd->command, cmd->args, data->env) == -1) 78 | return (errmsg_cmd("execve", NULL, strerror(errno), errno)); 79 | return (EXIT_FAILURE); 80 | } 81 | 82 | /* execute_command: 83 | * Child process tries to execute the given command by setting 84 | * its input/output fds and searching for an executable. 85 | * Searching for executable in this order: 86 | * 1. Execute builtin command 87 | * 2. Execute system binaries for command. 88 | * 3. Execute given command name directly (local bin) 89 | * If it cannot find a matching builtin or executable, 90 | * prints an error message. 91 | * Child exits with it's executed program's exit code, or 1 if 92 | * it could not find one. 93 | */ 94 | int execute_command(t_data *data, t_command *cmd) 95 | { 96 | int ret; 97 | 98 | if (!cmd || !cmd->command) 99 | exit_shell(data, errmsg_cmd("child", NULL, 100 | "parsing error: no command to execute!", EXIT_FAILURE)); 101 | if (!check_infile_outfile(cmd->io_fds)) 102 | exit_shell(data, EXIT_FAILURE); 103 | set_pipe_fds(data->cmd, cmd); 104 | redirect_io(cmd->io_fds); 105 | close_fds(data->cmd, false); 106 | if (ft_strchr(cmd->command, '/') == NULL) 107 | { 108 | ret = execute_builtin(data, cmd); 109 | if (ret != CMD_NOT_FOUND) 110 | exit_shell(data, ret); 111 | ret = execute_sys_bin(data, cmd); 112 | if (ret != CMD_NOT_FOUND) 113 | exit_shell(data, ret); 114 | } 115 | ret = execute_local_bin(data, cmd); 116 | exit_shell(data, ret); 117 | return (ret); 118 | } 119 | --------------------------------------------------------------------------------