From c41ea664c0dde1878ad84d849c76d04d76b00593 Mon Sep 17 00:00:00 2001 From: Quinten Mennen Date: Tue, 18 Mar 2025 14:41:11 +0100 Subject: [PATCH 1/4] refactor (heredoc): make norm compliant --- src/redirect/redirect_process_heredoc.c | 43 +++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/redirect/redirect_process_heredoc.c b/src/redirect/redirect_process_heredoc.c index 56c3789..f5799b1 100644 --- a/src/redirect/redirect_process_heredoc.c +++ b/src/redirect/redirect_process_heredoc.c @@ -6,7 +6,7 @@ /* By: qmennen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/26 16:46:32 by qmennen #+# #+# */ -/* Updated: 2025/03/18 14:32:19 by qmennen ### ########.fr */ +/* Updated: 2025/03/18 14:40:51 by qmennen ### ########.fr */ /* */ /* ************************************************************************** */ @@ -52,10 +52,31 @@ int fork_for_heredoc(t_minishell *msh, t_token *heredoc, t_token *delim) return (0); } +static int process_heredoc_line(t_minishell *msh, int fd, char *delim) +{ + char *line; + char *expand; + + line = readline(">"); + if (!line) + { + error_msg("warning: here-document delimited by end-of-file, wanted", + delim); + return (FAILURE); + } + if ((*line && ft_strcmp(line, delim) == 0)) + return (free(line), FAILURE); + if (!*line) + ft_strlcat(line, "\n", 1); + expand = expander_parse_string(line, msh); + ft_putendl_fd(expand, fd); + free_safe(msh, (void **)&expand); + free(line); + return (SUCCESS); +} + int process_heredoc(t_minishell *msh, t_token *heredoc, t_token *delim) { - char *line; - char *expand; const int fd = open(".ms_heredoc", O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) @@ -65,23 +86,11 @@ int process_heredoc(t_minishell *msh, t_token *heredoc, t_token *delim) } while (TRUE) { - line = readline(">"); - if (!line) - { - error_msg("warning: here-document delimited by end-of-file, wanted", delim->value); - break; - } - if ((*line && ft_strcmp(line, delim->value) == 0)) + if (! process_heredoc_line(msh, fd, delim->value)) break ; - if (!*line) - ft_strlcat(line, "\n", 1); - expand = expander_parse_string(line, msh); - ft_putendl_fd(expand, fd); - free_safe(msh, (void **)&expand); - free(line); } close(fd); heredoc->type = T_REDIRECT_IN; delim->value = ft_strdup_safe(msh, ".ms_heredoc"); - return (free(line), 1); + return (SUCCESS); } From df327180cbf9e340a7fa4e3d7e47ffbe45504d58 Mon Sep 17 00:00:00 2001 From: Quinten Mennen Date: Tue, 18 Mar 2025 16:00:03 +0100 Subject: [PATCH 2/4] chore (todo): update todo --- README.md | 46 +++------------------------------------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index eeca4a3..3f29449 100644 --- a/README.md +++ b/README.md @@ -25,49 +25,9 @@ A lot of amazing shell stuff ## TODO -- [ ] export without arguments -- [ ] ft_free_arr_safe in environment mess -- [ ] builtins not first in pipeline? wtf is happening HAHAHAHAHAH its not using builtin, but core-utils -- [ ] Remove -c option parsing as split can break -- [ ] Only `""` as input shows command not found, that invalid -- [ ] CTRL+\ during `sleep 5` should do nothing, but returns a new prompt -- [ ] echo "hello" > /root/protected.txt gives the error but still prints -- [ ] cat < filenoexit returns `minishell: minishell: unable to write to temp file: No such file or directory` but we're not writin -- [x] Find absolute path for command input ('/', './', 'cmd') -- [x]Add heredoc to tokenizer -- [x] Environment to `t_list` -- [x] Get environment array (export) -- [x] Set environment variable (export) -- [x] Simple builtin export -- [x] builtins -- [x] Preliminary signals -- [x] Define struct for commands, something like ( - ```c - typedef struct s_command - { - char *command; - char *path; - char **args; - int fd_in; - int fd_out; - } t_command; - ``` -) -- [x] Make the `executor`, run a command -- [x] Make a parser to create a command list -- [x] Add redirects, appends, pipe etc. File descriptor functions - a command can have multiple redirects but only the last is used for stdout - Redirects take precedence over pipes, but pipes are still created and managed. - should it close the unused pipe-end? - all redirects are opened and closed, but only last fd is used. - multiple HEREDOCs can be nested, only last is used. -- [x] Expand \$ vars & support \$ ~? - * [x] $var - * [x] $? - * [ ] ~ -- [x] export without arguments -- [ ] ft_free_arr_safe in environment mess -- [x] builtins not first in pipeline? wtf is happening HAHAHAHAHAH its not using builtin, but core-utils +- CTRL+C on input line results in exit code 130 in bash. -> this is signal global +- `cat | cat | ls` isn't blocking. (processes appear to be active while parent moves on) +- `echo $USER" $PWD` -> match quotes and throw error. - CB command to change banner - __Bonus:__ Command tree for &&, ||, * From 6b9e09fb55665d713a29829413f39100e704fd7b Mon Sep 17 00:00:00 2001 From: Quinten Mennen Date: Tue, 18 Mar 2025 16:22:03 +0100 Subject: [PATCH 3/4] feat (lexer): print syntax error --- inc/token.h | 3 ++- src/lexer/lexer_read_word.c | 27 +++++++++++++++++++++++++++ src/lexer/lexer_token_next.c | 16 +++++++--------- src/main.c | 24 ++++++++++++++++-------- src/token/token_validate_list.c | 30 ++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 18 deletions(-) create mode 100644 src/token/token_validate_list.c diff --git a/inc/token.h b/inc/token.h index 51c7a15..dae5a76 100644 --- a/inc/token.h +++ b/inc/token.h @@ -6,7 +6,7 @@ /* By: qmennen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/05 13:11:41 by qmennen #+# #+# */ -/* Updated: 2025/03/05 20:54:45 by qmennen ### ########.fr */ +/* Updated: 2025/03/18 16:14:51 by qmennen ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,5 +17,6 @@ t_token *token_from_list(t_list *list); t_list *token_list_index(t_list *tokens, int index); +t_token *token_validate_list(t_list *tokens); #endif diff --git a/src/lexer/lexer_read_word.c b/src/lexer/lexer_read_word.c index f1119a9..9b3ab0c 100644 --- a/src/lexer/lexer_read_word.c +++ b/src/lexer/lexer_read_word.c @@ -57,6 +57,31 @@ char *read_word(t_minishell *msh, t_lexer *lexer, int len) return (dest); } +int match_quotes(t_lexer *lexer) +{ + char c; + int i; + int sq; + int dq; + + sq = 0; + dq = 0; + i = lexer->pos; + c = lexer->current_char; + while (c && !ft_isspace(c) && !(c == '>' || c == '<' || c == '|')) + { + c = lexer->input[i]; + if (c == '\'') + sq++; + else if (c == '"') + dq++; + i++; + } + if (sq == 0 && dq == 0) + return (1); + return (dq % 2 == 0 && sq % 2 == 0); +} + char *lexer_readword(t_minishell *msh, t_lexer *lexer) { int len; @@ -68,6 +93,8 @@ char *lexer_readword(t_minishell *msh, t_lexer *lexer) qts = (c == '"' || c == '\''); if (qts) return (lexer_parse_quotes(msh, lexer)); + if (!match_quotes(lexer)) + return (NULL); len = calculate_word_len(lexer); word = read_word(msh, lexer, len); return (word); diff --git a/src/lexer/lexer_token_next.c b/src/lexer/lexer_token_next.c index 52deb97..53f24d6 100644 --- a/src/lexer/lexer_token_next.c +++ b/src/lexer/lexer_token_next.c @@ -1,12 +1,12 @@ /* ************************************************************************** */ /* */ -/* :::::::: */ -/* lexer_token_next.c :+: :+: */ -/* +:+ */ -/* By: qmennen +#+ */ -/* +#+ */ -/* Created: 2025/02/04 16:07:58 by qmennen #+# #+# */ -/* Updated: 2025/02/26 16:14:10 by whaffman ######## odam.nl */ +/* ::: :::::::: */ +/* lexer_token_next.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: qmennen +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/04 16:07:58 by qmennen #+# #+# */ +/* Updated: 2025/03/18 16:18:23 by qmennen ### ########.fr */ /* */ /* ************************************************************************** */ @@ -31,9 +31,7 @@ static t_token *process_word(t_minishell *msh, t_lexer *lexer, int pos) word_type = get_word_type(lexer->current_char); word = lexer_readword(msh, lexer); if (!word) - { return (token_new(msh, T_ERROR, &(lexer->current_char), pos)); - } token = token_new(msh, word_type, word, pos); free_safe(msh, (void **)&word); return (token); diff --git a/src/main.c b/src/main.c index e0220a6..6988c9d 100644 --- a/src/main.c +++ b/src/main.c @@ -1,20 +1,20 @@ /* ************************************************************************** */ /* */ -/* :::::::: */ -/* main.c :+: :+: */ -/* +:+ */ -/* By: qmennen +#+ */ -/* +#+ */ -/* Created: 2025/02/04 16:19:22 by whaffman #+# #+# */ -/* Updated: 2025/03/06 11:24:46 by whaffman ######## odam.nl */ +/* ::: :::::::: */ +/* main.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: qmennen +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/04 16:19:22 by whaffman #+# #+# */ +/* Updated: 2025/03/18 16:20:18 by qmennen ### ########.fr */ /* */ /* ************************************************************************** */ -#include "libft.h" #include "minishell.h" static void main_loop(t_minishell *msh) { + t_token *error_token; while (TRUE) { msh->line = ft_prompt(msh); @@ -22,6 +22,14 @@ static void main_loop(t_minishell *msh) break ; msh->lexer = ft_lexer_new(msh); msh->tokens = ft_parse_input(msh); + error_token = token_validate_list(msh->tokens); + if (error_token) + { + printf(BOLD RED"minishell"RESET": syntax error near position %i\n", + (error_token->position + 1)); + free_minishell_line(msh); + continue; + } ft_lstiter(msh->tokens, token_print); msh->commands = parser_get_commands(msh); executor_execute_pipeline(msh); diff --git a/src/token/token_validate_list.c b/src/token/token_validate_list.c new file mode 100644 index 0000000..f82d780 --- /dev/null +++ b/src/token/token_validate_list.c @@ -0,0 +1,30 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* token_validate_list.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: qmennen +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/03/18 16:08:44 by qmennen #+# #+# */ +/* Updated: 2025/03/18 16:13:41 by qmennen ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "token.h" + +t_token *token_validate_list(t_list *tokens) +{ + t_list *current; + t_token *token; + + current = tokens; + token = token_from_list(current); + while (current) + { + token = token_from_list(current); + if (token->type == T_ERROR) + return (token); + current = current->next; + } + return (NULL); +} From c8acd3d4f2ed5f3b8dc3b9df9b34b6051edfe135 Mon Sep 17 00:00:00 2001 From: Quinten Mennen Date: Tue, 18 Mar 2025 16:24:05 +0100 Subject: [PATCH 4/4] chore (format): make it norminette compliant once again --- inc/token.h | 4 ++-- src/lexer/lexer_read_word.c | 16 ++++++++-------- src/main.c | 5 +++-- src/token/token_validate_list.c | 4 ++-- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/inc/token.h b/inc/token.h index dae5a76..e149799 100644 --- a/inc/token.h +++ b/inc/token.h @@ -6,7 +6,7 @@ /* By: qmennen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/05 13:11:41 by qmennen #+# #+# */ -/* Updated: 2025/03/18 16:14:51 by qmennen ### ########.fr */ +/* Updated: 2025/03/18 16:22:39 by qmennen ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,6 +17,6 @@ t_token *token_from_list(t_list *list); t_list *token_list_index(t_list *tokens, int index); -t_token *token_validate_list(t_list *tokens); +t_token *token_validate_list(t_list *tokens); #endif diff --git a/src/lexer/lexer_read_word.c b/src/lexer/lexer_read_word.c index 9b3ab0c..0f6d697 100644 --- a/src/lexer/lexer_read_word.c +++ b/src/lexer/lexer_read_word.c @@ -1,12 +1,12 @@ /* ************************************************************************** */ /* */ -/* :::::::: */ -/* lexer_read_word.c :+: :+: */ -/* +:+ */ -/* By: qmennen +#+ */ -/* +#+ */ -/* Created: 2025/02/05 19:03:47 by qmennen #+# #+# */ -/* Updated: 2025/03/07 13:42:29 by whaffman ######## odam.nl */ +/* ::: :::::::: */ +/* lexer_read_word.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: qmennen +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/05 19:03:47 by qmennen #+# #+# */ +/* Updated: 2025/03/18 16:23:02 by qmennen ### ########.fr */ /* */ /* ************************************************************************** */ @@ -57,7 +57,7 @@ char *read_word(t_minishell *msh, t_lexer *lexer, int len) return (dest); } -int match_quotes(t_lexer *lexer) +int match_quotes(t_lexer *lexer) { char c; int i; diff --git a/src/main.c b/src/main.c index 6988c9d..5a58b17 100644 --- a/src/main.c +++ b/src/main.c @@ -6,7 +6,7 @@ /* By: qmennen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/04 16:19:22 by whaffman #+# #+# */ -/* Updated: 2025/03/18 16:20:18 by qmennen ### ########.fr */ +/* Updated: 2025/03/18 16:22:54 by qmennen ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,6 +15,7 @@ static void main_loop(t_minishell *msh) { t_token *error_token; + while (TRUE) { msh->line = ft_prompt(msh); @@ -28,7 +29,7 @@ static void main_loop(t_minishell *msh) printf(BOLD RED"minishell"RESET": syntax error near position %i\n", (error_token->position + 1)); free_minishell_line(msh); - continue; + continue ; } ft_lstiter(msh->tokens, token_print); msh->commands = parser_get_commands(msh); diff --git a/src/token/token_validate_list.c b/src/token/token_validate_list.c index f82d780..92272ea 100644 --- a/src/token/token_validate_list.c +++ b/src/token/token_validate_list.c @@ -6,13 +6,13 @@ /* By: qmennen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/18 16:08:44 by qmennen #+# #+# */ -/* Updated: 2025/03/18 16:13:41 by qmennen ### ########.fr */ +/* Updated: 2025/03/18 16:23:11 by qmennen ### ########.fr */ /* */ /* ************************************************************************** */ #include "token.h" -t_token *token_validate_list(t_list *tokens) +t_token *token_validate_list(t_list *tokens) { t_list *current; t_token *token;