/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* parser.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: sede-san next == NULL) syntax_error_unexpected_token((t_token *)current_token->content); current_token = current_token->next; } } return (commands); } /** * @brief Creates a new command from a list of tokens. * * @param tokens The list of tokens to create the command from. * * @return A new command or NULL on error. * * @note The `tokens` pointer is moved to the next command's tokens. */ t_command *command_new( t_list **tokens ) { t_command *command; t_list *current_token; t_list *delimiter_token; command = (t_command *)ft_calloc(1, sizeof(t_command)); if (command == NULL) return (NULL); current_token = *tokens; delimiter_token = ft_lstfind(current_token, (bool (*)(void *))is_pipe); while (command != NULL && current_token != delimiter_token) { command_add_tokens(command, ¤t_token); } *tokens = current_token; return (command); } /** * @brief Creates a new redirection from a list of tokens. * * @param tokens The list of tokens to create the redirection from. * * @return A new redirection or `NULL` on error. */ t_redirection *redirection_new( t_list **tokens ) { t_redirection *redirection; t_token *token; redirection = (t_redirection *)malloc(sizeof(t_redirection)); if (redirection == NULL) return (malloc_error(), NULL); token = (t_token *)(*tokens)->content; redirection->type = token->type; *tokens = (*tokens)->next; if (*tokens == NULL) { free(redirection); return (syntax_error_unexpected_token(token), NULL); } token = (t_token *)(*tokens)->content; if (token->type != TOKEN_WORD) { free(redirection); while (*tokens != NULL) *tokens = (*tokens)->next; return (syntax_error_unexpected_token(token), NULL); } redirection->target = ft_strdup(token->value); if (redirection->target == NULL) { free(redirection); return (malloc_error(), NULL); } *tokens = (*tokens)->next; return (redirection); } void redirection_clear( t_redirection *redirection ) { if (redirection != NULL) { free(redirection->target); free(redirection); } } /** * @brief Adds a token to a command, updating the command's arguments and * redirections as necessary. * * @param command The command to add the token to. * @param tokens The list of tokens to add to the command. * * @note The `command` pointer can be free'd if there is an error while adding * the token. */ void command_add_tokens( t_command *command, t_list **tokens ) { t_token *token; token = (t_token *)(*tokens)->content; if (is_redirection(token)) redirection_add(tokens, token, command); else words_add(tokens, command); } char **args_to_array( t_list *args, size_t argc ) { char **argv; size_t i; argv = (char **)malloc(sizeof(char *) * (argc + 1)); if (argv == NULL) return (NULL); i = 0; while (args != NULL) { argv[i] = (char *)args->content; args = args->next; i++; } argv[i] = NULL; return (argv); } /** * @brief Adds all consecutive word tokens to a command's argv and updates its * argc accordingly. * * @param command The command to add the word tokens to. * @param tokens The list of tokens to add to the command. */ void words_add( t_list **tokens, t_command *command ) { t_list *args; t_list *arg; t_token *token; args = NULL; 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++; 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); } void redirection_add( t_list **tokens, t_token *token, t_command *command ) { t_redirection *redirection; t_list *redirection_tokens; redirection = redirection_new(tokens); if (redirection == NULL) return ; redirection_tokens = ft_lstnew(redirection); if (redirection_tokens == NULL) { 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); } /** * @brief Checks if a token is a redirection token. * * @param token The token to check. * * @return `true` if the token is a redirection token, `false` otherwise. */ bool is_redirection( t_token *token ) { return (token->type == TOKEN_REDIRECT_IN || token->type == TOKEN_REDIRECT_OUT || token->type == TOKEN_APPEND || token->type == TOKEN_HEREDOC); } void command_clear_argv( t_command *command ) { int i; if (command->argv != NULL) { i = 0; while (i < command->argc) { free(command->argv[i]); i++; } free(command->argv); command->argv = NULL; } } /** * @brief Clears a command, freeing all associated memory. * * @param command The command to clear. */ void command_clear( t_command *command ) { if (command != NULL) { command_clear_argv(command); ft_lstclear(&command->redirections, (void (*)(void *))redirection_clear); ft_lstclear(&command->heredocs, (void (*)(void *))redirection_clear); free(command); } } /** * @brief Checks if a token is a pipe token. * * @param token The token to check. * * @return `true` if the token is a pipe token, `false` otherwise. */ bool is_pipe( t_token *token) { return (token->type == TOKEN_PIPE); } /** * @brief Finds a node in a linked list that satisfies a given predicate. * * @param lst The linked list to search through. * @param pre The predicate function to apply to each node's content. * * @returns The first node that satisfies the predicate or `NULL` if no such * node exists or if the list is `NULL`. */ t_list *ft_lstfind( t_list *lst, bool (*pre)(void *)) { while (lst != NULL) { if (pre(lst->content)) return (lst); lst = lst->next; } return (NULL); } void print_command_info( t_command *command ) { printf("Command:\n"); printf(" argc: %d\n", command->argc); printf(" argv: ["); for (int i = 0; i < command->argc; i++) { printf("%s", command->argv[i]); if (i < command->argc - 1) printf(", "); } printf("]\n"); printf(" path: %s\n", command->path); printf(" redirections:\n"); t_list *redirection_node = command->redirections; while (redirection_node != NULL) { t_redirection *redirection = (t_redirection *)redirection_node->content; printf(" type: %d, target: %s\n", redirection->type, redirection->target); redirection_node = redirection_node->next; } printf(" heredocs:\n"); t_list *heredoc_node = command->heredocs; while (heredoc_node != NULL) { t_redirection *heredoc = (t_redirection *)heredoc_node->content; printf(" type: %d, target: %s\n", heredoc->type, heredoc->target); heredoc_node = heredoc_node->next; } } int main(int argc, char const *argv[]) { t_list *commands; char *line; if (argc != 2) return (EXIT_FAILURE); line = ft_strdup(argv[1]); commands = parse(line, NULL); ft_lstiter(commands, (void (*)(void *))print_command_info); if (line != NULL) free(line); if (commands != NULL) ft_lstclear(&commands, (void (*)(void *))command_clear); return 0; }