update: parser now uses tokens from lexer

fixes pending:
 - some functions are longer than norminette allows
 - find solution to a list of commands being returned, even though a
syntax error is found when processing tokens (maybe delegate some work
to the lexer and return only a syntax-valid list?)
This commit is contained in:
2026-02-11 02:51:30 +01:00
parent 1715f2dd40
commit c493979a18
7 changed files with 475 additions and 289 deletions

View File

@@ -6,7 +6,7 @@
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */ /* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2025/10/22 19:10:13 by sede-san #+# #+# */ /* Created: 2025/10/22 19:10:13 by sede-san #+# #+# */
/* Updated: 2026/02/09 18:45:41 by sede-san ### ########.fr */ /* Updated: 2026/02/10 23:21:35 by sede-san ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -19,9 +19,37 @@
/* Structures & Data Types */ /* Structures & Data Types */
/******************************************************************************/ /******************************************************************************/
typedef struct s_minishell t_minishell; # define TOKENS_COUNT 5
typedef struct s_variables t_variables;
typedef struct s_command t_command; typedef enum e_token_type
{
TOKEN_WORD,
TOKEN_PIPE,
TOKEN_REDIRECT_IN,
TOKEN_REDIRECT_OUT,
TOKEN_APPEND,
TOKEN_HEREDOC
} t_token_type;
typedef struct s_token
{
t_token_type type;
char *value;
} t_token;
typedef enum e_redirection_type
{
REDIRECT_IN,
REDIRECT_OUT,
APPEND,
HEREDOC
} t_redirection_type;
typedef struct s_redirection
{
t_token_type type;
char *target;
} t_redirection;
/** /**
* @brief Structure that holds both environment and internal variables * @brief Structure that holds both environment and internal variables
@@ -54,6 +82,12 @@ typedef struct s_minishell
bool exit; bool exit;
} t_minishell; } t_minishell;
typedef struct s_redirection
{
t_token_type type;
char *target;
} t_redirection;
/** /**
* @brief Structure representing a single command in the shell * @brief Structure representing a single command in the shell
* *
@@ -70,6 +104,7 @@ typedef struct s_command
char **argv; char **argv;
char *path; char *path;
t_list *redirections; t_list *redirections;
t_list *heredocs;
} t_command; } t_command;
/** /**

23
include/errors.h Normal file
View File

@@ -0,0 +1,23 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* errors.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/10 22:28:01 by sede-san #+# #+# */
/* Updated: 2026/02/10 23:24:16 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef ERRORS_H
# define ERRORS_H
# include "minishell.h"
# include "core.h"
# include "parser.h"
extern void syntax_error_unexpected_token(t_token *token);
extern void malloc_error(void);
#endif /* ERRORS_H */

View File

@@ -6,7 +6,7 @@
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */ /* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2025/10/20 16:35:10 by sede-san #+# #+# */ /* Created: 2025/10/20 16:35:10 by sede-san #+# #+# */
/* Updated: 2026/02/09 18:38:16 by sede-san ### ########.fr */ /* Updated: 2026/02/10 22:12:58 by sede-san ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -18,6 +18,7 @@
# include "chardefs.h" # include "chardefs.h"
# include <stdbool.h> # include <stdbool.h>
# include <stdint.h> # include <stdint.h>
# include <errno.h>
# include <readline/readline.h> // readline(3), rl_clear_history(), # include <readline/readline.h> // readline(3), rl_clear_history(),
// rl_on_new_line(), rl_replace_line(), // rl_on_new_line(), rl_replace_line(),
// rl_redisplay() // rl_redisplay()

View File

@@ -6,7 +6,7 @@
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */ /* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2025/10/22 19:03:51 by sede-san #+# #+# */ /* Created: 2025/10/22 19:03:51 by sede-san #+# #+# */
/* Updated: 2026/02/09 21:19:02 by sede-san ### ########.fr */ /* Updated: 2026/02/11 00:35:08 by sede-san ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -17,38 +17,6 @@
# include "core.h" # include "core.h"
# include "builtins.h" # include "builtins.h"
# define TOKENS_COUNT 5
typedef enum e_token_type
{
TOKEN_WORD,
TOKEN_PIPE,
TOKEN_REDIRECT_IN,
TOKEN_REDIRECT_OUT,
TOKEN_APPEND,
TOKEN_HEREDOC
} t_token_type;
typedef struct s_token
{
t_token_type type;
char *value;
} t_token;
typedef enum e_redirection_type
{
REDIRECT_IN,
REDIRECT_OUT,
APPEND,
HEREDOC
} t_redirection_type;
typedef struct s_redirection
{
t_redirection_type type;
char *target;
} t_redirection;
/******************************************************************************/ /******************************************************************************/
/* Functions */ /* Functions */
/******************************************************************************/ /******************************************************************************/
@@ -57,4 +25,16 @@ typedef struct s_redirection
extern t_list *parse(char *line, t_minishell *minishell); extern t_list *parse(char *line, t_minishell *minishell);
// lexer.c
extern t_list *lex(const char *line);
extern void token_clear(t_token *token);
extern t_command *command_new(t_list **tokens);
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);
void words_add(t_list **tokens, t_command *command);
#endif /* PARSER_H */ #endif /* PARSER_H */

30
src/errors/errors.c Normal file
View File

@@ -0,0 +1,30 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* errors.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/10 22:22:06 by sede-san #+# #+# */
/* Updated: 2026/02/11 02:30:32 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "errors.h"
void syntax_error_unexpected_token(
t_token *token
)
{
char *cause;
cause = token->value;
if (token == NULL)
cause = "newline";
ft_eprintf("minishell: syntax error near unexpected token `%s'\n", cause);
}
void malloc_error(void)
{
ft_eprintf("minishell: %s\n", strerror(ENOMEM));
}

View File

@@ -6,7 +6,7 @@
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */ /* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/09 18:56:41 by sede-san #+# #+# */ /* Created: 2026/02/09 18:56:41 by sede-san #+# #+# */
/* Updated: 2026/02/10 12:33:55 by sede-san ### ########.fr */ /* Updated: 2026/02/11 02:06:36 by sede-san ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -16,7 +16,7 @@
static t_token *tokenize(const char *line, size_t *start); static t_token *tokenize(const char *line, size_t *start);
static t_token_type get_token_type(const char *str); static t_token_type get_token_type(const char *str);
static t_token *token_new(t_token_type type, char *text); static t_token *token_new(t_token_type type, char *text);
static void token_clear(t_token *token); void token_clear(t_token *token);
static t_token *read_token(t_token_type type, const char *line, size_t *i); static t_token *read_token(t_token_type type, const char *line, size_t *i);
static t_token *read_word(const char *line, size_t *i); static t_token *read_word(const char *line, size_t *i);
static inline bool is_meta(char c); static inline bool is_meta(char c);
@@ -117,7 +117,7 @@ static t_token *token_new(
return (token); return (token);
} }
static void token_clear( void token_clear(
t_token *token t_token *token
) )
{ {
@@ -158,8 +158,6 @@ static t_token *read_word(
in_double_quote = false; in_double_quote = false;
while (line[*i] != '\0') while (line[*i] != '\0')
{ {
char c = line[*i];
(void)c;
if (line[*i] == '\'' && !in_double_quote) if (line[*i] == '\'' && !in_double_quote)
in_single_quote = !in_single_quote; in_single_quote = !in_single_quote;
else if (line[*i] == '"' && !in_single_quote) else if (line[*i] == '"' && !in_single_quote)

View File

@@ -6,295 +6,414 @@
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */ /* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2025/10/22 18:37:38 by sede-san #+# #+# */ /* Created: 2025/10/22 18:37:38 by sede-san #+# #+# */
/* Updated: 2026/02/09 18:50:43 by sede-san ### ########.fr */ /* Updated: 2026/02/11 02:42:52 by sede-san ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "parser.h" #include "parser.h"
#include "errors.h"
// parse exclusive static t_list *parse_tokens(
static char *extract_next_command(char *line, size_t *index); t_list *tokens
static char *trim_whitespaces(char *line, size_t *start, size_t *end); );
// static void set_pipes(t_list *commands);
// common static t_list *ft_lstfind(
static void find_boundary(char *line, size_t *index, char bound_char); t_list *lst,
bool (*pre)(void *)
// command exclusive );
static t_command *cmdnew(char *line, t_minishell *minishell);
static void set_argv(t_command *command, char *line, t_minishell *minishell);
static void expand_envs(char *arg, t_minishell *minishell);
static char **lst_to_argv(t_list *argv_list);
static void set_argc(t_command *command);
static void set_infile(t_command *command);
static void set_outfile(t_command *command);
static void set_path(t_command *command, t_minishell *minishell);
static u_int8_t path_is_solved(char *cmd_name, t_minishell *msh);
static char *solve_path(char *command_name, t_minishell *minishell);
/**
* @brief Converts a command line string into a list of commands.
*
* @param line The command line string to parse.
* @param minishell The minishell instance.
*
* @return A list of commands or `NULL` on error.
*/
t_list *parse( t_list *parse(
char *line, char *line,
t_minishell *minishell t_minishell *minishell
) { )
{
t_list *commands; t_list *commands;
t_list *tokens; t_list *tokens;
t_command *command;
char *command_str;
size_t i;
if (line == NULL) if (line == NULL)
return (NULL); return (NULL);
commands = NULL; tokens = lex(line);
i = 0; commands = parse_tokens(tokens);
while (line[i] != '\0') (void)minishell;
{ // expand_variables(commands, minishell);
tokens = tokenize(); ft_lstclear(&tokens, (void (*)(void *))token_clear);
command_str = extract_next_command(line, &i);
if (command_str != NULL)
{
command = cmdnew(command_str, minishell);
free(command_str);
if (command != NULL)
ft_lstadd_back(&commands, ft_lstnew(command));
}
}
// set_pipes(commands);
return (commands); return (commands);
} }
// static void set_pipes( /**
// t_list *commands * @brief Converts a list of tokens into a list of commands.
// ) { *
// t_list *current_command; * @param tokens The list of tokens to parse.
// t_list *previous_command; * @param minishell The minishell instance.
// t_list *next_command; *
// t_command *command; * @return A list of commands or `NULL` on error.
*/
// previous_command = NULL; static t_list *parse_tokens(
// current_command = commands; t_list *tokens
// while (current_command != NULL) )
// {
// command = (t_command *)current_command->content;
// if (previous_command != NULL)
// command->piped_from = (t_command *)previous_command->content;
// next_command = current_command->next;
// if (next_command != NULL)
// command->piped_to = (t_command *)next_command->content;
// previous_command = current_command;
// current_command = current_command->next;
// }
// }
static char *extract_next_command(
char *line,
size_t *index
) {
char *command_str;
size_t start;
size_t end;
start = *index;
find_boundary(line, index, '|');
end = *index;
command_str = trim_whitespaces(line, &start, &end);
while (line[*index] == '|' || ft_isspace(line[*index]))
(*index)++;
return (command_str);
}
static void find_boundary(
char *line,
size_t *index,
char bound_char
) {
bool in_single_quote;
bool in_double_quote;
in_single_quote = false;
in_double_quote = false;
while (line[*index] != '\0')
{ {
if (line[*index] == '\'' && !in_double_quote) t_list *commands;
in_single_quote = !in_single_quote; t_command *command;
else if (line[*index] == '"' && !in_single_quote) t_list *current_token;
in_double_quote = !in_double_quote; t_list *new_command;
if (line[*index] == bound_char && !in_single_quote && !in_double_quote)
break ;
(*index)++;
}
}
static char *trim_whitespaces( if (tokens == NULL)
char *line, return (NULL);
size_t *start, commands = NULL;
size_t *end current_token = tokens;
) { while (current_token != NULL)
while (*start < *end && ft_isspace(line[*start])) {
(*start)++; command = command_new(&current_token);
while (*end > *start && ft_isspace(line[*end - 1])) if (command == NULL)
(*end)--; {
if (*end > *start) ft_lstclear(&commands, (void (*)(void *))command_clear);
return (ft_substr(line, *start, *end - *start));
return (NULL); return (NULL);
} }
new_command = ft_lstnew(command);
if (new_command == NULL)
{
command_clear(command);
ft_lstclear(&commands, (void (*)(void *))command_clear);
return (malloc_error(), NULL);
}
ft_lstadd_back(&commands, new_command);
if (current_token != NULL)
{
if (current_token->next == NULL)
syntax_error_unexpected_token((t_token *)current_token->content);
current_token = current_token->next;
}
}
return (commands);
}
static t_command *cmdnew( /**
char *line, * @brief Creates a new command from a list of tokens.
t_minishell *minishell *
) { * @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_command *command;
t_list *current_token;
t_list *delimiter_token;
command = (t_command *)ft_calloc(1, sizeof(t_command)); command = (t_command *)ft_calloc(1, sizeof(t_command));
if (!command) if (command == NULL)
return (NULL); return (NULL);
// resolve_heredoc current_token = *tokens;
set_argv(command, line, minishell); delimiter_token = ft_lstfind(current_token, (bool (*)(void *))is_pipe);
if (!command->argv) while (command != NULL && current_token != delimiter_token)
{ {
free(command); command_add_tokens(command, &current_token);
return (NULL);
} }
set_argc(command); *tokens = current_token;
set_infile(command);
set_outfile(command);
set_path(command, minishell);
return (command); return (command);
} }
static void set_argv( /**
t_command *command, * @brief Creates a new redirection from a list of tokens.
char *line, *
t_minishell *minishell * @param tokens The list of tokens to create the redirection from.
) { *
t_list *argv_list; * @return A new redirection or `NULL` on error.
char *arg; */
size_t i; t_redirection *redirection_new(
size_t start; t_list **tokens
size_t end; )
if (line == NULL)
return ;
i = 0;
argv_list = NULL;
while (line[i] != '\0')
{ {
start = i; t_redirection *redirection;
find_boundary(line, &i, ' '); t_token *token;
end = i;
arg = trim_whitespaces(line, &start, &end); redirection = (t_redirection *)malloc(sizeof(t_redirection));
expand_envs(arg, minishell); if (redirection == NULL)
if (arg != NULL) return (malloc_error(), NULL);
ft_lstadd_back(&argv_list, ft_lstnew(arg)); token = (t_token *)(*tokens)->content;
while (ft_isspace(line[i])) redirection->type = token->type;
i++; *tokens = (*tokens)->next;
if (*tokens == NULL)
{
free(redirection);
return (syntax_error_unexpected_token(NULL), NULL);
} }
command->argv = lst_to_argv(argv_list); token = (t_token *)(*tokens)->content;
ft_lstclear(&argv_list, free); if (token->type != TOKEN_WORD)
{
free(redirection);
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);
} }
static void expand_envs( void redirection_clear(
char *arg, t_redirection *redirection
t_minishell *minishell )
) { {
// TODO if (redirection != NULL)
(void)arg; {
(void)minishell; free(redirection->target);
free(redirection);
}
} }
static char **lst_to_argv( /**
t_list *argv_list * @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; char **argv;
t_list *current_arg;
size_t i; size_t i;
argv = (char **)ft_calloc(ft_lstsize(argv_list) + 1, sizeof(char *)); argv = (char **)malloc(sizeof(char *) * (argc + 1));
if (!argv) if (argv == NULL)
return (NULL); return (NULL);
i = 0; i = 0;
current_arg = argv_list; while (args != NULL)
while (current_arg != NULL)
{ {
argv[i] = ft_strdup((char *)current_arg->content); argv[i] = (char *)args->content;
args = args->next;
i++; i++;
current_arg = current_arg->next;
} }
argv[i] = NULL;
return (argv); return (argv);
} }
static void set_argc( /**
* @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_command *command
) { )
int argc; {
t_list *args;
t_list *arg;
t_token *token;
argc = 0; args = NULL;
while (command->argv[argc] != NULL) arg = *tokens;
argc++; token = (t_token *)arg->content;
command->argc = argc; 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);
} }
static void set_infile( void redirection_add(
t_list **tokens,
t_token *token,
t_command *command t_command *command
) { )
// test_infile {
command->infile = -1; 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)
static void set_outfile( ft_lstadd_back(&command->heredocs, redirection_tokens);
t_command *command
) {
// test_outfile
command->outfile = STDOUT_FILENO;
}
static void set_path(
t_command *command,
t_minishell *minishell
) {
char *command_path;
char *command_name;
command_name = command->argv[0];
if (!path_is_solved(command_name, minishell))
command_path = solve_path(command_name, minishell);
else else
command_path = ft_strdup(command_name); ft_lstadd_back(&command->redirections, redirection_tokens);
command->path = command_path;
} }
static char *solve_path( /**
char *command_name, * @brief Checks if a token is a redirection token.
t_minishell *minishell *
){ * @param token The token to check.
char *command_path; *
char **path_env; * @return `true` if the token is a redirection token, `false` otherwise.
size_t i; */
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);
}
path_env = ft_split(get_env("PATH", minishell), ':'); void command_clear_argv(
if (!path_env) 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); return (NULL);
command_path = NULL;
i = -1;
while (!command_path && path_env[++i])
{
command_path = ft_strnjoin(3, path_env[i], "/", command_name);
if (command_path != NULL && access(command_path, F_OK) != EXIT_SUCCESS)
{
free(command_path);
command_path = NULL;
}
}
ft_free_split(path_env);
return (command_path);
} }
static u_int8_t path_is_solved( void print_command_info(
char *command_name, t_command *command
t_minishell *minishell )
){ {
return (ft_strncmp(command_name, "/", 1) == 0 printf("Command:\n");
|| (command_name[1] && ft_strncmp(command_name, "./", 2) == 0) printf(" argc: %d\n", command->argc);
|| (command_name[2] && ft_strncmp(command_name, "../", 3) == 0) printf(" argv: [");
|| is_builtin(command_name, minishell) 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;
} }