diff --git a/include/core.h b/include/core.h index 25e5319..5c5c519 100644 --- a/include/core.h +++ b/include/core.h @@ -48,7 +48,10 @@ typedef enum e_redirection_type typedef struct s_redirection { t_token_type type; + int io_number; char *target; + bool heredoc_expand; + bool heredoc_ready; } t_redirection; /** @@ -129,6 +132,8 @@ extern void minishell_set_execution_signals(void); extern void minishell_set_child_signals(void); +extern void minishell_set_heredoc_signals(void); + extern bool minishell_consume_sigint(void); /* environment.c */ @@ -142,8 +147,7 @@ extern char **get_envp(t_minishell *msh); extern void free_envp(char **envp); -void handle_sigint_status(t_minishell *minishell); -bool handle_eof(char *line, t_minishell *minishell); - +extern void handle_sigint_status(t_minishell *minishell); +extern bool handle_eof(char *line, t_minishell *minishell); #endif /* CORE_H */ diff --git a/include/executor.h b/include/executor.h index d91de93..3e30d09 100644 --- a/include/executor.h +++ b/include/executor.h @@ -53,8 +53,12 @@ extern void executor_parent_cleanup(t_list *node, t_pipeline *pl); extern uint8_t executor_wait_for_children(pid_t last_child_pid); extern void executor_cmdfree(t_command *command); extern bool executor_apply_redirections(const t_command *command, - int *saved_stdin, int *saved_stdout); + int *saved_stdin, int *saved_stdout, int *saved_stderr); extern void executor_restore_redirections(int saved_stdin, - int saved_stdout); + int saved_stdout, int saved_stderr); +extern bool executor_prepare_heredocs(t_list *command_list, + t_minishell *minishell, uint8_t *exit_status); +extern char *executor_expand_heredoc_line(const char *line, + t_minishell *minishell); #endif /* EXECUTOR_H */ diff --git a/include/parser.h b/include/parser.h index 469a80f..dd69ca1 100644 --- a/include/parser.h +++ b/include/parser.h @@ -41,8 +41,10 @@ extern void command_clear(t_command *command); extern void command_add_tokens(t_command **command, t_list **tokens); extern bool is_pipe(t_token *token); extern bool is_redirection(t_token *token); -void redirection_add(t_list **tokens, t_token *token, - t_command **command); +bool parser_token_is_fd_prefix(t_list *token_node, + int *io_number); +void redirection_add_with_fd(t_list **tokens, t_token *token, + t_command **command, int io_number); void words_add(t_list **tokens, t_command **command); void expand(t_list **commands, t_minishell *minishell); diff --git a/src/builtins/env/env.c b/src/builtins/env/env.c index e79d06e..cc750fa 100644 --- a/src/builtins/env/env.c +++ b/src/builtins/env/env.c @@ -22,8 +22,9 @@ uint8_t builtin_env( { if (cmd.argc > 1) { - ft_eputendl("minishell: env: too many arguments"); - return (EXIT_FAILURE); + ft_eprintf("minishell: env: %s: No such file or directory\n", + cmd.argv[1]); + return (127); } print_env(msh); return (EXIT_SUCCESS); diff --git a/src/builtins/exit/exit.c b/src/builtins/exit/exit.c index 55622f9..a7340a7 100644 --- a/src/builtins/exit/exit.c +++ b/src/builtins/exit/exit.c @@ -16,6 +16,8 @@ static bool exit_arg_is_invalid(const char *arg) { if (arg == NULL) return (true); + if (arg[0] == '\0') + return (true); if ((*arg == '+' || *arg == '-') && arg[1] == '\0') return (true); if (!ft_strisnum(arg)) diff --git a/src/builtins/export/export.c b/src/builtins/export/export.c index 22cdac5..3781788 100644 --- a/src/builtins/export/export.c +++ b/src/builtins/export/export.c @@ -12,8 +12,18 @@ #include "builtins.h" -static uint8_t is_valid_identifier(const char *arg, size_t name_len); static uint8_t export_one(char *arg, t_minishell *msh); +static uint8_t print_exported(t_minishell *msh); +static void **entries_to_array(t_list *lst, size_t *count, + bool add_oldpwd); +static void sort_entries(t_map_entry **entries, size_t count); +bool export_is_valid_identifier(const char *arg, size_t name_len); +void export_parse_assignment(char *arg, char **eq_pos, + size_t *name_len, bool *append); +uint8_t export_set_assigned_value(const char *name, char *eq_pos, + bool append, t_minishell *msh); +bool export_print_declaration(const char *name, const char *value); +static t_map_entry g_oldpwd_entry = {"OLDPWD", NULL}; uint8_t builtin_export( t_command cmd, @@ -21,36 +31,24 @@ uint8_t builtin_export( ) { uint8_t status; + uint8_t result; size_t i; if (cmd.argc == 1) - return (builtin_env(cmd, msh)); + return (print_exported(msh)); status = EXIT_SUCCESS; i = 0; while (cmd.argv[++i] != NULL) - if (export_one(cmd.argv[i], msh) != EXIT_SUCCESS) + { + result = export_one(cmd.argv[i], msh); + if (result == 2) + return (2); + if (result != EXIT_SUCCESS) status = EXIT_FAILURE; + } return (status); } -static uint8_t is_valid_identifier( - const char *arg, - size_t name_len -) -{ - size_t i; - - if (name_len == 0 || arg == NULL) - return (0); - if (!ft_isalpha(arg[0]) && arg[0] != '_') - return (0); - i = 0; - while (++i < name_len) - if (!ft_isalnum(arg[i]) && arg[i] != '_') - return (0); - return (1); -} - static uint8_t export_one( char *arg, t_minishell *msh @@ -59,21 +57,111 @@ static uint8_t export_one( char *eq_pos; char *name; size_t name_len; + bool append; - eq_pos = ft_strchr(arg, '='); - name_len = ft_strlen(arg); - if (eq_pos != NULL) - name_len = (size_t)(eq_pos - arg); - if (!is_valid_identifier(arg, name_len)) - return (ft_eprintf("minishell: export: `%s': not a valid identifier\n", - arg), EXIT_FAILURE); + if (arg[0] == '-' && arg[1] != '\0') + return (ft_eprintf("minishell: export: %s: invalid option\n", arg), + ft_eputendl("export: usage: export [name[=value] ...]"), 2); + export_parse_assignment(arg, &eq_pos, &name_len, &append); + if (!export_is_valid_identifier(arg, name_len)) + return (ft_eprintf( + "minishell: export: `%s': not a valid identifier\n", arg), + EXIT_FAILURE); name = ft_substr(arg, 0, name_len); if (name == NULL) return (EXIT_FAILURE); - if (eq_pos != NULL) - set_var(name, eq_pos + 1, msh); - else - set_var(name, "", msh); + if (export_set_assigned_value(name, eq_pos, append, msh) != EXIT_SUCCESS) + return (free(name), EXIT_FAILURE); free(name); return (EXIT_SUCCESS); } + +static uint8_t print_exported( + t_minishell *msh +) +{ + t_list *entries; + t_map_entry **sorted_entries; + size_t count; + size_t i; + bool add_oldpwd; + + entries = ft_hashmap_entries(msh->variables.environment); + if (entries == NULL) + return (EXIT_SUCCESS); + add_oldpwd = !ft_hashmap_contains_key(msh->variables.environment, "OLDPWD"); + sorted_entries = (t_map_entry **)entries_to_array(entries, &count, + add_oldpwd); + ft_lstclear_nodes(&entries); + if (sorted_entries == NULL) + return (EXIT_FAILURE); + sort_entries(sorted_entries, count); + i = 0; + while (i < count) + { + if (!export_print_declaration((char *)sorted_entries[i]->key, + (char *)sorted_entries[i]->value)) + return (free(sorted_entries), EXIT_FAILURE); + i++; + } + free(sorted_entries); + return (EXIT_SUCCESS); +} + +static void **entries_to_array( + t_list *entries, + size_t *count, + bool add_oldpwd +) +{ + void **array; + t_list *node; + t_map_entry *entry; + size_t i; + + *count = (size_t)ft_lstsize(entries) + (size_t)add_oldpwd; + array = (void **)malloc(sizeof(void *) * (*count)); + if (array == NULL) + return (NULL); + i = 0; + node = entries; + while (node != NULL) + { + entry = (t_map_entry *)node->content; + if (entry != NULL && ft_strcmp((char *)entry->key, "_") != 0) + array[i++] = entry; + node = node->next; + } + if (add_oldpwd) + array[i++] = &g_oldpwd_entry; + *count = i; + return (array); +} + +static void sort_entries( + t_map_entry **entries, + size_t count +) +{ + size_t i; + size_t j; + t_map_entry *tmp; + + i = 0; + while (i < count) + { + j = i + 1; + while (j < count) + { + if (ft_strcmp((char *)entries[i]->key, + (char *)entries[j]->key) > 0) + { + tmp = entries[i]; + entries[i] = entries[j]; + entries[j] = tmp; + } + j++; + } + i++; + } +} diff --git a/src/builtins/export/export_utils.c b/src/builtins/export/export_utils.c new file mode 100644 index 0000000..068b153 --- /dev/null +++ b/src/builtins/export/export_utils.c @@ -0,0 +1,129 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* export_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san type == TOKEN_HEREDOC && redirection->heredoc_ready + && redirection->target != NULL) + unlink(redirection->target); free(redirection->target); free(redirection); } diff --git a/src/executor/executor.c b/src/executor/executor.c index 375e5a2..103ceca 100644 --- a/src/executor/executor.c +++ b/src/executor/executor.c @@ -48,13 +48,15 @@ static void run_command_in_parent( t_command *command; int saved_stdin; int saved_stdout; + int saved_stderr; command = state->current_command->content; - if (!executor_apply_redirections(command, &saved_stdin, &saved_stdout)) + if (!executor_apply_redirections(command, &saved_stdin, &saved_stdout, + &saved_stderr)) state->exit_status = EXIT_FAILURE; else state->exit_status = executor_execute_command(command, minishell); - executor_restore_redirections(saved_stdin, saved_stdout); + executor_restore_redirections(saved_stdin, saved_stdout, saved_stderr); } static bool run_current_command( @@ -89,6 +91,12 @@ uint8_t execute( t_exec_state state; init_exec_state(&state, command_list); + if (!executor_prepare_heredocs(command_list, minishell, &state.exit_status)) + { + minishell->exit_status = state.exit_status; + ft_lstclear(&command_list, (void (*)(void *))executor_cmdfree); + return (state.exit_status); + } minishell_set_execution_signals(); while (state.current_command) { diff --git a/src/executor/heredoc.c b/src/executor/heredoc.c new file mode 100644 index 0000000..6926cd4 --- /dev/null +++ b/src/executor/heredoc.c @@ -0,0 +1,65 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* heredoc.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san redirections; + while (redir_node != NULL) + { + rd = (t_redirection *)redir_node->content; + if (rd->type == TOKEN_HEREDOC + && !prepare_heredoc_redirection(rd, minishell, exit_status)) + return (false); + redir_node = redir_node->next; + } + return (true); +} + +bool executor_prepare_heredocs(t_list *command_list, t_minishell *minishell, + uint8_t *exit_status) +{ + t_command *command; + + *exit_status = EXIT_SUCCESS; + minishell_set_heredoc_signals(); + while (command_list != NULL) + { + command = (t_command *)command_list->content; + if (!process_command_heredocs(command, minishell, exit_status)) + return (minishell_set_interactive_signals(), false); + command_list = command_list->next; + } + minishell_set_interactive_signals(); + return (true); +} diff --git a/src/executor/heredoc_expand.c b/src/executor/heredoc_expand.c new file mode 100644 index 0000000..09850d4 --- /dev/null +++ b/src/executor/heredoc_expand.c @@ -0,0 +1,98 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* heredoc_expand.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san exit_status)); + if (line[*i] == '\0' || !is_var_char(line[*i])) + return (ft_strdup("$")); + start = *i; + while (line[*i] != '\0' && is_var_char(line[*i])) + (*i)++; + name = ft_substr(line, start, *i - start); + if (name == NULL) + return (NULL); + value = get_var(name, msh); + free(name); + if (value == NULL) + value = ""; + return (ft_strdup(value)); +} + +static char *expand_literal_char(const char *line, size_t *i) +{ + char value[2]; + + value[0] = line[*i]; + value[1] = '\0'; + (*i)++; + return (ft_strdup(value)); +} + +char *executor_expand_heredoc_line( + const char *line, + t_minishell *minishell +) +{ + char *result; + char *expanded; + size_t i; + + result = ft_strdup(""); + if (result == NULL) + return (malloc_error(), NULL); + i = 0; + while (line[i] != '\0') + { + if (line[i] == '$') + expanded = expand_variable(line, &i, minishell); + else + expanded = expand_literal_char(line, &i); + if (expanded == NULL) + return (free(result), malloc_error(), NULL); + if (!append_text(&result, expanded)) + return (free(expanded), malloc_error(), NULL); + free(expanded); + } + return (result); +} diff --git a/src/executor/heredoc_file.c b/src/executor/heredoc_file.c new file mode 100644 index 0000000..a4ae094 --- /dev/null +++ b/src/executor/heredoc_file.c @@ -0,0 +1,99 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* heredoc_file.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san +#include "variables.h" + +static char *build_tmp_path(unsigned int id) +{ + char *suffix; + char *path; + + suffix = ft_uitoa(id); + if (suffix == NULL) + return (errno = ENOMEM, NULL); + path = ft_strnjoin(2, "/tmp/minishell_heredoc_", suffix); + free(suffix); + if (path == NULL) + return (errno = ENOMEM, NULL); + return (path); +} + +int executor_heredoc_open_tmp(char **path_out) +{ + static unsigned int counter; + char *path; + unsigned int attempts; + int fd; + + attempts = 0; + while (attempts++ < 10000) + { + path = build_tmp_path(counter++); + if (path == NULL) + return (-1); + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600); + if (fd != -1) + return (*path_out = path, fd); + free(path); + if (errno != EEXIST) + return (-1); + } + errno = EEXIST; + return (-1); +} + +char *executor_heredoc_read_line(t_minishell *minishell) +{ + char *prompt; + char *line; + size_t len; + + if (!isatty(STDIN_FILENO)) + { + line = get_next_line(STDIN_FILENO); + if (line == NULL) + return (NULL); + len = ft_strlen(line); + if (len > 0 && line[len - 1] == '\n') + line[len - 1] = '\0'; + return (line); + } + prompt = get_var("PS2", minishell); + if (prompt == NULL) + prompt = DEFAULT_PS2; + return (readline(prompt)); +} + +void executor_heredoc_discard_tmp(int fd, char *path) +{ + if (fd >= 0) + close(fd); + if (path != NULL) + { + unlink(path); + free(path); + } +} + +bool executor_heredoc_finalize_tmp(t_redirection *rd, int fd, char *path, + uint8_t *exit_status) +{ + if (close(fd) == -1) + return (executor_heredoc_discard_tmp(-1, path), perror("close"), + *exit_status = EXIT_FAILURE, false); + free(rd->target); + rd->target = path; + rd->heredoc_ready = true; + return (true); +} diff --git a/src/executor/heredoc_input.c b/src/executor/heredoc_input.c new file mode 100644 index 0000000..c5ea36f --- /dev/null +++ b/src/executor/heredoc_input.c @@ -0,0 +1,80 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* heredoc_input.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san heredoc_expand) + { + expanded = executor_expand_heredoc_line(line, minishell); + free(line); + if (expanded == NULL) + return (false); + } + if (!write_heredoc_line(fd, expanded)) + return (free(expanded), perror("write"), false); + free(expanded); + return (true); +} + +bool executor_heredoc_fill_tmp(int fd, t_redirection *rd, + t_minishell *minishell, uint8_t *exit_status) +{ + char *line; + + while (1) + { + line = executor_heredoc_read_line(minishell); + if (minishell_consume_sigint()) + return (free(line), *exit_status = 130, false); + if (line == NULL) + { + if (!isatty(STDIN_FILENO)) + minishell->exit = true; + return (ft_eprintf("minishell: warning: here-document delimited by " + "end-of-file (wanted `%s')\n", rd->target), true); + } + if (ft_strcmp(line, rd->target) == 0) + return (free(line), true); + if (!handle_heredoc_line(fd, line, rd, minishell)) + return (*exit_status = EXIT_FAILURE, false); + } +} diff --git a/src/executor/heredoc_internal.h b/src/executor/heredoc_internal.h new file mode 100644 index 0000000..e556bbb --- /dev/null +++ b/src/executor/heredoc_internal.h @@ -0,0 +1,26 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* heredoc_internal.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san type == TOKEN_REDIRECT_IN) return (open(redirection->target, O_RDONLY)); + if (redirection->type == TOKEN_HEREDOC) + return (open(redirection->target, O_RDONLY)); if (redirection->type == TOKEN_REDIRECT_OUT) return (open(redirection->target, O_WRONLY | O_CREAT | O_TRUNC, 0644)); if (redirection->type == TOKEN_APPEND) @@ -27,73 +29,74 @@ static int open_redirection_target( return (-1); } -static bool backup_stream_if_needed( - const t_redirection *redirection, - int *saved_stdin, - int *saved_stdout +static bool backup_fd_if_needed( + int io_number, + int *saved_fd ) { - if (redirection->type == TOKEN_REDIRECT_IN && saved_stdin != NULL - && *saved_stdin == -1) - { - *saved_stdin = dup(STDIN_FILENO); - if (*saved_stdin == -1) - return (perror("dup"), false); - } - if ((redirection->type == TOKEN_REDIRECT_OUT - || redirection->type == TOKEN_APPEND) && saved_stdout != NULL - && *saved_stdout == -1) - { - *saved_stdout = dup(STDOUT_FILENO); - if (*saved_stdout == -1) - return (perror("dup"), false); - } + if (saved_fd == NULL || *saved_fd != -1) + return (true); + *saved_fd = dup(io_number); + if (*saved_fd == -1) + return (perror("dup"), false); return (true); } +static bool apply_redirection( + const t_redirection *redirection, + int *saved_stdin, + int *saved_stdout, + int *saved_stderr +) +{ + int fd; + + if (redirection == NULL || redirection->target == NULL) + return (false); + if ((redirection->io_number == STDIN_FILENO + && !backup_fd_if_needed(STDIN_FILENO, saved_stdin)) + || (redirection->io_number == STDOUT_FILENO + && !backup_fd_if_needed(STDOUT_FILENO, saved_stdout)) + || (redirection->io_number == STDERR_FILENO + && !backup_fd_if_needed(STDERR_FILENO, saved_stderr))) + return (false); + fd = open_redirection_target(redirection); + if (fd == -1) + return (perror(redirection->target), false); + if (dup2(fd, redirection->io_number) == -1) + return (close(fd), perror("dup2"), false); + return (close(fd), true); +} + bool executor_apply_redirections( const t_command *command, int *saved_stdin, - int *saved_stdout + int *saved_stdout, + int *saved_stderr ) { - t_list *node; - t_redirection *redirection; - int fd; + t_list *node; if (saved_stdin != NULL) *saved_stdin = -1; if (saved_stdout != NULL) *saved_stdout = -1; - if (command == NULL || command->redirections == NULL) + if (saved_stderr != NULL) + *saved_stderr = -1; + if (command == NULL) return (true); node = command->redirections; - while (node != NULL) - { - redirection = (t_redirection *)node->content; - if (redirection == NULL || redirection->target == NULL) - return (false); - if (!backup_stream_if_needed(redirection, saved_stdin, saved_stdout)) - return (false); - fd = open_redirection_target(redirection); - if (fd == -1) - return (perror(redirection->target), false); - if (redirection->type == TOKEN_REDIRECT_IN - && dup2(fd, STDIN_FILENO) == -1) - return (close(fd), perror("dup2"), false); - if ((redirection->type == TOKEN_REDIRECT_OUT - || redirection->type == TOKEN_APPEND) - && dup2(fd, STDOUT_FILENO) == -1) - return (close(fd), perror("dup2"), false); - close(fd); + while (node != NULL + && apply_redirection((t_redirection *)node->content, + saved_stdin, saved_stdout, saved_stderr)) node = node->next; - } - return (true); + return (node == NULL); } void executor_restore_redirections( int saved_stdin, - int saved_stdout + int saved_stdout, + int saved_stderr ) { if (saved_stdin != -1) @@ -108,4 +111,10 @@ void executor_restore_redirections( perror("dup2"); close(saved_stdout); } + if (saved_stderr != -1) + { + if (dup2(saved_stderr, STDERR_FILENO) == -1) + perror("dup2"); + close(saved_stderr); + } } diff --git a/src/parser/parser_command.c b/src/parser/parser_command.c index 66171db..c5e17bd 100644 --- a/src/parser/parser_command.c +++ b/src/parser/parser_command.c @@ -58,10 +58,18 @@ void command_add_tokens( ) { t_token *token; + int io_number; token = (t_token *)(*tokens)->content; + if (parser_token_is_fd_prefix(*tokens, &io_number)) + { + *tokens = (*tokens)->next; + token = (t_token *)(*tokens)->content; + redirection_add_with_fd(tokens, token, command, io_number); + return ; + } if (is_redirection(token)) - redirection_add(tokens, token, command); + redirection_add_with_fd(tokens, token, command, -1); else words_add(tokens, command); } diff --git a/src/parser/parser_command_fd.c b/src/parser/parser_command_fd.c new file mode 100644 index 0000000..2962b79 --- /dev/null +++ b/src/parser/parser_command_fd.c @@ -0,0 +1,54 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parser_command_fd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san + +static bool parse_io_number(const char *value, int *io_number) +{ + long number; + size_t i; + + if (value == NULL || value[0] == '\0') + return (false); + number = 0; + i = 0; + while (value[i] != '\0') + { + if (!ft_isdigit(value[i])) + return (false); + if (number > (INT_MAX - (value[i] - '0')) / 10) + return (false); + number = (number * 10) + (value[i] - '0'); + i++; + } + *io_number = (int)number; + return (true); +} + +bool parser_token_is_fd_prefix( + t_list *token_node, + int *io_number +) +{ + t_token *token; + t_token *next_token; + + if (token_node == NULL || token_node->next == NULL) + return (false); + token = (t_token *)token_node->content; + next_token = (t_token *)token_node->next->content; + if (token == NULL || next_token == NULL || token->type != TOKEN_WORD + || !is_redirection(next_token)) + return (false); + return (parse_io_number(token->value, io_number)); +} diff --git a/src/parser/parser_expand.c b/src/parser/parser_expand.c index 6b557ac..18357cc 100644 --- a/src/parser/parser_expand.c +++ b/src/parser/parser_expand.c @@ -91,16 +91,17 @@ static bool expand_argv( static bool expand_redirections( t_list *redirections, - t_minishell *minishell, - bool expand_vars + t_minishell *minishell ) { t_redirection *redirection; char *expanded; + bool expand_vars; while (redirections != NULL) { redirection = (t_redirection *)redirections->content; + expand_vars = (redirection->type != TOKEN_HEREDOC); expanded = parser_expand_word(redirection->target, minishell, expand_vars); if (expanded == NULL) @@ -127,8 +128,8 @@ void expand( { command = (t_command *)current->content; if (!expand_argv(command, minishell) - || !expand_redirections(command->redirections, minishell, true) - || !expand_redirections(command->heredocs, minishell, false)) + || !expand_redirections(command->redirections, minishell) + || !expand_redirections(command->heredocs, minishell)) { ft_lstclear(commands, (void (*)(void *))command_clear); *commands = NULL; diff --git a/src/parser/parser_expand_fields.c b/src/parser/parser_expand_fields.c index d9c6250..1526701 100644 --- a/src/parser/parser_expand_fields.c +++ b/src/parser/parser_expand_fields.c @@ -63,6 +63,20 @@ static bool process_word_fields( return (true); } +static bool set_empty_word_field( + t_list **fields, + t_minishell *minishell +) +{ + t_list *node; + + node = ft_lstnew(ft_strdup("")); + if (node == NULL || node->content == NULL) + return (free(node), parser_expand_malloc_error(minishell), false); + *fields = node; + return (true); +} + bool parser_expand_word_fields( const char *word, t_minishell *minishell, @@ -75,6 +89,8 @@ bool parser_expand_word_fields( t_fields_ctx ctx; *fields = NULL; + if (word[0] == '\0') + return (set_empty_word_field(fields, minishell)); current = ft_strdup(""); if (current == NULL) return (parser_expand_malloc_error(minishell), false); diff --git a/src/parser/parser_expand_fields_escape.c b/src/parser/parser_expand_fields_escape.c new file mode 100644 index 0000000..144e414 --- /dev/null +++ b/src/parser/parser_expand_fields_escape.c @@ -0,0 +1,85 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parser_expand_fields_escape.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san content; redirection->type = token->type; - *tokens = (*tokens)->next; - if (*tokens == NULL) - { - free(redirection); - return (syntax_error_unexpected_token(NULL), NULL); - } - token = (t_token *)(*tokens)->content; + redirection->heredoc_expand = true; + redirection->heredoc_ready = false; + if (io_number < 0) + redirection->io_number = STDOUT_FILENO; + else + redirection->io_number = io_number; + if (io_number < 0 && (token->type == TOKEN_REDIRECT_IN + || token->type == TOKEN_HEREDOC)) + redirection->io_number = STDIN_FILENO; + if (!redirection_read_target(redirection, tokens)) + return (free(redirection), NULL); + return (redirection); +} + +static bool redirection_read_target( + t_redirection *rd, + t_list **tk +) +{ + t_token *token; + + *tk = (*tk)->next; + if (*tk == NULL) + return (syntax_error_unexpected_token(NULL), false); + token = (t_token *)(*tk)->content; if (token->type != TOKEN_WORD) { - free(redirection); - while (*tokens != NULL) - *tokens = (*tokens)->next; - return (syntax_error_unexpected_token(token), NULL); + while (*tk != NULL) + *tk = (*tk)->next; + return (syntax_error_unexpected_token(token), false); } - redirection->target = ft_strdup(token->value); - if (redirection->target == NULL) + if (rd->type == TOKEN_HEREDOC && has_quote_char(token->value)) + rd->heredoc_expand = false; + rd->target = ft_strdup(token->value); + if (rd->target == NULL) + return (malloc_error(), false); + *tk = (*tk)->next; + return (true); +} + +static bool has_quote_char( + const char *value +) +{ + size_t i; + + if (value == NULL) + return (false); + i = 0; + while (value[i] != '\0') { - free(redirection); - return (malloc_error(), NULL); + if (value[i] == '\'' || value[i] == '\"') + return (true); + i++; } - *tokens = (*tokens)->next; - return (redirection); + return (false); } void redirection_clear( @@ -69,16 +106,17 @@ void redirection_clear( } } -void redirection_add( +void redirection_add_with_fd( t_list **tokens, t_token *token, - t_command **command + t_command **command, + int io_number ) { t_redirection *redirection; t_list *redirection_tokens; - redirection = redirection_new(tokens); + redirection = redirection_new(tokens, io_number); if (redirection == NULL) { command_clear(*command); @@ -91,8 +129,6 @@ void redirection_add( free(redirection); return (malloc_error()); } - if (token->type == TOKEN_HEREDOC) - ft_lstadd_back(&(*command)->heredocs, redirection_tokens); - else - ft_lstadd_back(&(*command)->redirections, redirection_tokens); + (void)token; + ft_lstadd_back(&(*command)->redirections, redirection_tokens); } diff --git a/src/parser/parser_words.c b/src/parser/parser_words.c index bff78e5..1e23b03 100644 --- a/src/parser/parser_words.c +++ b/src/parser/parser_words.c @@ -12,42 +12,57 @@ #include "parser.h" -char **args_to_array(t_list **args, size_t argc); void command_clear_argv(t_command *command); -/** - * @brief Converts a list of arguments into an array. - * - * @param args The list of arguments to convert. - * @param argc The number of arguments in the list. - * - * @return An array of arguments or `NULL` on error. - * - * @note The `args` list is cleared after the conversion and set to NULL. - */ -char **args_to_array( +static bool args_add_word( t_list **args, - size_t argc + const char *value +) +{ + t_list *node; + char *dup; + + dup = ft_strdup(value); + if (dup == NULL) + return (false); + node = ft_lstnew(dup); + if (node == NULL) + return (free(dup), false); + ft_lstadd_back(args, node); + return (true); +} + +static bool command_append_words( + t_command *command, + t_list **args, + int new_argc ) { char **argv; - t_list *arg; - size_t i; + t_list *current; + int i; - argv = (char **)malloc(sizeof(char *) * (argc + 1)); + argv = (char **)malloc(sizeof(char *) * (command->argc + new_argc + 1)); if (argv == NULL) - return (NULL); + return (false); i = 0; - arg = *args; - while (arg != NULL) + while (i < command->argc) { - argv[i] = (char *)arg->content; - arg = arg->next; + argv[i] = command->argv[i]; i++; } + current = *args; + while (current != NULL) + { + argv[i++] = (char *)current->content; + current = current->next; + } argv[i] = NULL; + free(command->argv); ft_lstclear_nodes(args); - return (argv); + command->argv = argv; + command->argc += new_argc; + return (true); } /** @@ -65,21 +80,41 @@ void words_add( t_list *args; t_list *arg; t_token *token; + t_token *next_token; + int new_argc; + size_t i; + bool is_fd_prefix; args = NULL; + new_argc = 0; arg = *tokens; token = (t_token *)arg->content; while (arg != NULL && token->type == TOKEN_WORD) { - ft_lstadd_back(&args, ft_lstnew(ft_strdup(token->value))); - (*command)->argc++; + is_fd_prefix = false; + if (arg->next != NULL && token->value != NULL + && token->value[0] != '\0') + { + next_token = (t_token *)arg->next->content; + i = 0; + while (token->value[i] != '\0' && ft_isdigit(token->value[i])) + i++; + is_fd_prefix = (token->value[i] == '\0' && is_redirection(next_token)); + } + if (is_fd_prefix) + break ; + if (!args_add_word(&args, token->value)) + return (ft_lstclear(&args, free), command_clear(*command), + *command = NULL, (void)0); + new_argc++; arg = arg->next; if (arg != NULL) token = (t_token *)arg->content; } *tokens = arg; - (*command)->argv = args_to_array(&args, (*command)->argc); - ft_lstclear_nodes(&args); + if (!command_append_words(*command, &args, new_argc)) + return (ft_lstclear(&args, free), command_clear(*command), + *command = NULL, (void)0); } void command_clear_argv( diff --git a/src/variables/environment/environment.c b/src/variables/environment/environment.c index 7482adf..b05369e 100644 --- a/src/variables/environment/environment.c +++ b/src/variables/environment/environment.c @@ -175,7 +175,12 @@ void set_envp( ) { t_hashmap **environment; - char **key_value; + char *equal; + char *key; + char *value; + char *new_shlvl; + int shlvl; + size_t key_len; if (minishell == NULL || envp == NULL) return ; @@ -185,9 +190,36 @@ void set_envp( return ; while (*envp != NULL) { - key_value = ft_split(*envp, '='); - set_env(key_value[0], key_value[1], minishell); - ft_free_split(key_value); + equal = ft_strchr(*envp, '='); + if (equal == NULL) + { + envp++; + continue ; + } + key_len = (size_t)(equal - *envp); + key = ft_substr(*envp, 0, key_len); + value = ft_strdup(equal + 1); + if (key == NULL || value == NULL) + { + free(key); + free(value); + minishell->exit = true; + return (malloc_error()); + } + set_env(key, value, minishell); + free(key); + free(value); envp++; } + value = get_env("SHLVL", minishell); + shlvl = 0; + if (value != NULL) + shlvl = ft_atoi(value); + if (shlvl < 0) + shlvl = 0; + new_shlvl = ft_itoa(shlvl + 1); + if (new_shlvl == NULL) + return (minishell->exit = true, malloc_error()); + set_env("SHLVL", new_shlvl, minishell); + free(new_shlvl); }