Fixed all norme from lexer, parser. minishell and builtins
This commit is contained in:
@@ -72,7 +72,6 @@ typedef struct s_prompt
|
|||||||
const char *ps2; // secondary prompt string for multiline input
|
const char *ps2; // secondary prompt string for multiline input
|
||||||
} t_prompt;
|
} t_prompt;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Main minishell structure containing global state information
|
* @brief Main minishell structure containing global state information
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# include "core.h"
|
# include "core.h"
|
||||||
# include "parser.h"
|
# include "parser.h"
|
||||||
|
|
||||||
extern void syntax_error_unexpected_token(t_token *token);
|
extern void syntax_error_unexpected_token(t_token *token);
|
||||||
extern void malloc_error(void);
|
extern void malloc_error(void);
|
||||||
|
|
||||||
#endif /* ERRORS_H */
|
#endif /* ERRORS_H */
|
||||||
@@ -42,4 +42,7 @@
|
|||||||
# include <term.h> // tgetent(3), tgetflag(3), tgetnum(3),
|
# include <term.h> // tgetent(3), tgetflag(3), tgetnum(3),
|
||||||
// tgetstr(3), tgoto(3), tputs(3)
|
// tgetstr(3), tgoto(3), tputs(3)
|
||||||
|
|
||||||
|
void handle_sigint_status(t_minishell *minishell);
|
||||||
|
bool handle_eof(char *line, t_minishell *minishell);
|
||||||
|
|
||||||
#endif /* MINISHELL_H */
|
#endif /* MINISHELL_H */
|
||||||
|
|||||||
@@ -23,19 +23,29 @@
|
|||||||
|
|
||||||
// parser.c
|
// parser.c
|
||||||
|
|
||||||
extern t_list *parse(char *line, t_minishell *minishell);
|
extern t_list *parse(char *line, t_minishell *minishell);
|
||||||
|
|
||||||
// lexer.c
|
// lexer.c
|
||||||
|
|
||||||
extern t_list *lex(const char *line);
|
t_token_type get_token_type(const char *str);
|
||||||
|
t_token *token_new(t_token_type type, char *text);
|
||||||
|
t_token *read_token(t_token_type type, const char *line,
|
||||||
|
size_t *i);
|
||||||
|
t_token *read_word(const char *line, size_t *i);
|
||||||
|
|
||||||
extern void token_clear(t_token *token);
|
extern t_list *lex(const char *line);
|
||||||
|
|
||||||
|
extern void token_clear(t_token *token);
|
||||||
extern t_command *command_new(t_list **tokens);
|
extern t_command *command_new(t_list **tokens);
|
||||||
extern void command_clear(t_command *command);
|
extern void command_clear(t_command *command);
|
||||||
extern void command_add_tokens(t_command **command, t_list **tokens);
|
extern void command_add_tokens(t_command **command, t_list **tokens);
|
||||||
extern bool is_pipe(t_token *token);
|
extern bool is_pipe(t_token *token);
|
||||||
extern bool is_redirection(t_token *token);
|
extern bool is_redirection(t_token *token);
|
||||||
void redirection_add(t_list **tokens, t_token *token, t_command **command);
|
void redirection_add(t_list **tokens, t_token *token,
|
||||||
void words_add(t_list **tokens, t_command **command);
|
t_command **command);
|
||||||
|
void words_add(t_list **tokens, t_command **command);
|
||||||
|
|
||||||
|
void expand(t_list **commands, t_minishell *minishell);
|
||||||
|
void redirection_clear(t_redirection *redirection);
|
||||||
|
|
||||||
#endif /* PARSER_H */
|
#endif /* PARSER_H */
|
||||||
|
|||||||
@@ -9,4 +9,3 @@
|
|||||||
/* Updated: 2026/02/09 18:40:04 by sede-san ### ########.fr */
|
/* Updated: 2026/02/09 18:40:04 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
|||||||
@@ -28,4 +28,4 @@ void syntax_error_unexpected_token(
|
|||||||
void malloc_error(void)
|
void malloc_error(void)
|
||||||
{
|
{
|
||||||
ft_eprintf("minishell: %s\n", strerror(ENOMEM));
|
ft_eprintf("minishell: %s\n", strerror(ENOMEM));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,28 +15,6 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "executor.h"
|
#include "executor.h"
|
||||||
|
|
||||||
static void handle_sigint_status(
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (!minishell_consume_sigint())
|
|
||||||
return ;
|
|
||||||
minishell->exit_status = 130;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool handle_eof(
|
|
||||||
char *line,
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (line != NULL)
|
|
||||||
return (false);
|
|
||||||
if (isatty(STDIN_FILENO))
|
|
||||||
ft_putendl("exit");
|
|
||||||
minishell->exit = true;
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_prompts(
|
static void set_prompts(
|
||||||
t_minishell *minishell
|
t_minishell *minishell
|
||||||
)
|
)
|
||||||
|
|||||||
36
src/minishell_helpers.c
Normal file
36
src/minishell_helpers.c
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* minishell_helpers.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:09:23 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:09:23 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "minishell.h"
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
void handle_sigint_status(
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!minishell_consume_sigint())
|
||||||
|
return ;
|
||||||
|
minishell->exit_status = 130;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_eof(
|
||||||
|
char *line,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (line != NULL)
|
||||||
|
return (false);
|
||||||
|
if (isatty(STDIN_FILENO))
|
||||||
|
ft_putendl("exit");
|
||||||
|
minishell->exit = true;
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
@@ -13,26 +13,20 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
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 *token_new(t_token_type type, char *text);
|
|
||||||
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_word(const char *line, size_t *i);
|
|
||||||
static inline bool is_meta(char c);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts a command line string into a list of tokens.
|
* @brief Converts a command line string into a list of tokens.
|
||||||
*
|
*
|
||||||
* @return A list of tokens or NULL on error.
|
* @return A list of tokens or NULL on error.
|
||||||
*/
|
*/
|
||||||
t_list *lex(
|
t_list *lex(
|
||||||
const char *line
|
const char *line
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
t_list *tokens;
|
t_list *tokens;
|
||||||
t_token *token;
|
t_token *token;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
tokens = NULL;
|
tokens = NULL;
|
||||||
i = 0;
|
i = 0;
|
||||||
@@ -56,13 +50,13 @@ t_list *lex(
|
|||||||
/**
|
/**
|
||||||
* @return A new token or NULL on error.
|
* @return A new token or NULL on error.
|
||||||
*/
|
*/
|
||||||
static t_token *tokenize(
|
static t_token *tokenize(
|
||||||
const char *line,
|
const char *line,
|
||||||
size_t *start
|
size_t *start
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
t_token *token;
|
t_token *token;
|
||||||
t_token_type type;
|
t_token_type type;
|
||||||
|
|
||||||
if (line == NULL || line[*start] == '\0')
|
if (line == NULL || line[*start] == '\0')
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -73,106 +67,3 @@ static t_token *tokenize(
|
|||||||
token = read_word(line, start);
|
token = read_word(line, start);
|
||||||
return (token);
|
return (token);
|
||||||
}
|
}
|
||||||
|
|
||||||
static t_token_type get_token_type(
|
|
||||||
const char *str
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (str == NULL || str[0] == '\0')
|
|
||||||
return (TOKEN_WORD);
|
|
||||||
if (str[0] == '|')
|
|
||||||
return (TOKEN_PIPE);
|
|
||||||
if (str[0] == '<')
|
|
||||||
{
|
|
||||||
if (str[1] == '<')
|
|
||||||
return (TOKEN_HEREDOC);
|
|
||||||
return (TOKEN_REDIRECT_IN);
|
|
||||||
}
|
|
||||||
if (str[0] == '>')
|
|
||||||
{
|
|
||||||
if (str[1] == '>')
|
|
||||||
return (TOKEN_APPEND);
|
|
||||||
return (TOKEN_REDIRECT_OUT);
|
|
||||||
}
|
|
||||||
return (TOKEN_WORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
static t_token *token_new(
|
|
||||||
t_token_type type,
|
|
||||||
char *text
|
|
||||||
)
|
|
||||||
{
|
|
||||||
t_token *token;
|
|
||||||
|
|
||||||
token = (t_token *)malloc(sizeof(t_token));
|
|
||||||
if (token == NULL)
|
|
||||||
return (NULL);
|
|
||||||
token->type = type;
|
|
||||||
token->value = text;
|
|
||||||
if (token->type == TOKEN_WORD && token->value == NULL)
|
|
||||||
{
|
|
||||||
free(token);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
return (token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void token_clear(
|
|
||||||
t_token *token
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (token != NULL)
|
|
||||||
{
|
|
||||||
free(token->value);
|
|
||||||
free(token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static t_token *read_token(
|
|
||||||
t_token_type type,
|
|
||||||
const char *line,
|
|
||||||
size_t *i
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const size_t start = *i;
|
|
||||||
size_t end;
|
|
||||||
|
|
||||||
while (is_meta(line[*i]))
|
|
||||||
(*i)++;
|
|
||||||
end = *i;
|
|
||||||
while (ft_isspace(line[*i]))
|
|
||||||
(*i)++;
|
|
||||||
return (token_new(type, ft_substr(line, start, end - start)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static t_token *read_word(
|
|
||||||
const char *line,
|
|
||||||
size_t *i
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const size_t start = *i;
|
|
||||||
bool in_single_quote;
|
|
||||||
bool in_double_quote;
|
|
||||||
|
|
||||||
in_single_quote = false;
|
|
||||||
in_double_quote = false;
|
|
||||||
while (line[*i] != '\0')
|
|
||||||
{
|
|
||||||
if (line[*i] == '\'' && !in_double_quote)
|
|
||||||
in_single_quote = !in_single_quote;
|
|
||||||
else if (line[*i] == '"' && !in_single_quote)
|
|
||||||
in_double_quote = !in_double_quote;
|
|
||||||
else if (!in_single_quote && !in_double_quote
|
|
||||||
&& (isspace(line[*i]) || is_meta(line[*i])))
|
|
||||||
break;
|
|
||||||
(*i)++;
|
|
||||||
}
|
|
||||||
return (token_new(TOKEN_WORD, ft_substr(line, start, *i - start)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool is_meta(
|
|
||||||
char c
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return (c == '|' || c == '<' || c == '>');
|
|
||||||
}
|
|
||||||
|
|||||||
64
src/parser/lexer_reader.c
Normal file
64
src/parser/lexer_reader.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* lexer_reader.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:13:23 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:13:23 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
static inline bool is_meta(char c);
|
||||||
|
|
||||||
|
t_token *read_token(
|
||||||
|
t_token_type type,
|
||||||
|
const char *line,
|
||||||
|
size_t *i
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const size_t start = *i;
|
||||||
|
size_t end;
|
||||||
|
|
||||||
|
while (is_meta(line[*i]))
|
||||||
|
(*i)++;
|
||||||
|
end = *i;
|
||||||
|
while (ft_isspace(line[*i]))
|
||||||
|
(*i)++;
|
||||||
|
return (token_new(type, ft_substr(line, start, end - start)));
|
||||||
|
}
|
||||||
|
|
||||||
|
t_token *read_word(
|
||||||
|
const char *line,
|
||||||
|
size_t *i
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const size_t start = *i;
|
||||||
|
bool in_single_quote;
|
||||||
|
bool in_double_quote;
|
||||||
|
|
||||||
|
in_single_quote = false;
|
||||||
|
in_double_quote = false;
|
||||||
|
while (line[*i] != '\0')
|
||||||
|
{
|
||||||
|
if (line[*i] == '\'' && !in_double_quote)
|
||||||
|
in_single_quote = !in_single_quote;
|
||||||
|
else if (line[*i] == '"' && !in_single_quote)
|
||||||
|
in_double_quote = !in_double_quote;
|
||||||
|
else if (!in_single_quote && !in_double_quote
|
||||||
|
&& (isspace(line[*i]) || is_meta(line[*i])))
|
||||||
|
break ;
|
||||||
|
(*i)++;
|
||||||
|
}
|
||||||
|
return (token_new(TOKEN_WORD, ft_substr(line, start, *i - start)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_meta(
|
||||||
|
char c
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return (c == '|' || c == '<' || c == '>');
|
||||||
|
}
|
||||||
67
src/parser/lexer_token.c
Normal file
67
src/parser/lexer_token.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* lexer_token.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:12:49 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:12:49 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
t_token_type get_token_type(
|
||||||
|
const char *str
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (str == NULL || str[0] == '\0')
|
||||||
|
return (TOKEN_WORD);
|
||||||
|
if (str[0] == '|')
|
||||||
|
return (TOKEN_PIPE);
|
||||||
|
if (str[0] == '<')
|
||||||
|
{
|
||||||
|
if (str[1] == '<')
|
||||||
|
return (TOKEN_HEREDOC);
|
||||||
|
return (TOKEN_REDIRECT_IN);
|
||||||
|
}
|
||||||
|
if (str[0] == '>')
|
||||||
|
{
|
||||||
|
if (str[1] == '>')
|
||||||
|
return (TOKEN_APPEND);
|
||||||
|
return (TOKEN_REDIRECT_OUT);
|
||||||
|
}
|
||||||
|
return (TOKEN_WORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_token *token_new(
|
||||||
|
t_token_type type,
|
||||||
|
char *text
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_token *token;
|
||||||
|
|
||||||
|
token = (t_token *)malloc(sizeof(t_token));
|
||||||
|
if (token == NULL)
|
||||||
|
return (NULL);
|
||||||
|
token->type = type;
|
||||||
|
token->value = text;
|
||||||
|
if (token->type == TOKEN_WORD && token->value == NULL)
|
||||||
|
{
|
||||||
|
free(token);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
return (token);
|
||||||
|
}
|
||||||
|
|
||||||
|
void token_clear(
|
||||||
|
t_token *token
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (token != NULL)
|
||||||
|
{
|
||||||
|
free(token->value);
|
||||||
|
free(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,33 +6,14 @@
|
|||||||
/* 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/13 18:17:00 by sede-san ### ########.fr */
|
/* Updated: 2026/02/13 21:22:06 by sede-san ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
|
|
||||||
static t_list *parse_tokens(
|
static t_list *parse_tokens(t_list *tokens);
|
||||||
t_list *tokens
|
|
||||||
);
|
|
||||||
|
|
||||||
static t_list *ft_lstfind(
|
|
||||||
t_list *lst,
|
|
||||||
bool (*pre)(void *)
|
|
||||||
);
|
|
||||||
|
|
||||||
static void expand_variable(
|
|
||||||
char **argument,
|
|
||||||
int *i,
|
|
||||||
t_minishell *minishell
|
|
||||||
);
|
|
||||||
|
|
||||||
static void expand(
|
|
||||||
t_list **commands,
|
|
||||||
t_minishell *minishell
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts a command line string into a list of commands.
|
* @brief Converts a command line string into a list of commands.
|
||||||
@@ -42,13 +23,13 @@ static void expand(
|
|||||||
*
|
*
|
||||||
* @return A list of commands or `NULL` on error.
|
* @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;
|
||||||
|
|
||||||
if (line == NULL)
|
if (line == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -63,11 +44,10 @@ t_list *parse(
|
|||||||
* @brief Converts a list of tokens into a list of commands.
|
* @brief Converts a list of tokens into a list of commands.
|
||||||
*
|
*
|
||||||
* @param tokens The list of tokens to parse.
|
* @param tokens The list of tokens to parse.
|
||||||
* @param minishell The minishell instance.
|
|
||||||
*
|
*
|
||||||
* @return A list of commands or `NULL` on error.
|
* @return A list of commands or `NULL` on error.
|
||||||
*/
|
*/
|
||||||
static t_list *parse_tokens(
|
static t_list *parse_tokens(
|
||||||
t_list *tokens
|
t_list *tokens
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -81,7 +61,8 @@ static t_list *parse_tokens(
|
|||||||
commands = NULL;
|
commands = NULL;
|
||||||
current_token = tokens;
|
current_token = tokens;
|
||||||
if (((t_token *)current_token->content)->type == TOKEN_PIPE)
|
if (((t_token *)current_token->content)->type == TOKEN_PIPE)
|
||||||
return (syntax_error_unexpected_token((t_token *)current_token->content), NULL);
|
return (syntax_error_unexpected_token(
|
||||||
|
(t_token *)current_token->content), NULL);
|
||||||
while (current_token != NULL)
|
while (current_token != NULL)
|
||||||
{
|
{
|
||||||
command = command_new(¤t_token);
|
command = command_new(¤t_token);
|
||||||
@@ -103,404 +84,11 @@ static t_list *parse_tokens(
|
|||||||
if (current_token->next == NULL)
|
if (current_token->next == NULL)
|
||||||
{
|
{
|
||||||
ft_lstclear(&commands, (void (*)(void *))command_clear);
|
ft_lstclear(&commands, (void (*)(void *))command_clear);
|
||||||
return (syntax_error_unexpected_token((t_token *)current_token->content), NULL);
|
return (syntax_error_unexpected_token(
|
||||||
|
(t_token *)current_token->content), NULL);
|
||||||
}
|
}
|
||||||
current_token = current_token->next;
|
current_token = current_token->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (commands);
|
return (commands);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *replace_value(
|
|
||||||
char *original,
|
|
||||||
char *value,
|
|
||||||
int start,
|
|
||||||
int end
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const char *before = ft_substr(original, 0, start);
|
|
||||||
const char *after = ft_substr(original, end, ft_strlen(original) - end);
|
|
||||||
const char *expanded = ft_strnjoin(3, before, value, after);
|
|
||||||
|
|
||||||
free((char *)before);
|
|
||||||
free((char *)after);
|
|
||||||
return ((char *)expanded);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void expand_variable(
|
|
||||||
char **argument,
|
|
||||||
int *i,
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
char *expanded;
|
|
||||||
char *variable_name;
|
|
||||||
char *variable_value;
|
|
||||||
const int start = *i + 1;
|
|
||||||
int end;
|
|
||||||
|
|
||||||
end = start;
|
|
||||||
while (ft_isalnum((*argument)[end]) || (*argument)[end] == '_')
|
|
||||||
end++;
|
|
||||||
variable_name = ft_substr(*argument, start, end - start);
|
|
||||||
if (variable_name == NULL)
|
|
||||||
return (minishell->exit = true, malloc_error());
|
|
||||||
variable_value = get_env(variable_name, minishell);
|
|
||||||
free(variable_name);
|
|
||||||
if (variable_value == NULL)
|
|
||||||
variable_value = "";
|
|
||||||
expanded = replace_value(*argument, variable_value, start - 1, end);
|
|
||||||
if (expanded == NULL)
|
|
||||||
return (minishell->exit = true, malloc_error());
|
|
||||||
*i += ft_strlen(variable_value);
|
|
||||||
free(*argument);
|
|
||||||
*argument = expanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void expand_argument(
|
|
||||||
char **argument,
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
bool in_single_quote;
|
|
||||||
bool in_double_quote;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
in_single_quote = false;
|
|
||||||
in_double_quote = false;
|
|
||||||
i = 0;
|
|
||||||
while ((*argument)[i] != '\0')
|
|
||||||
{
|
|
||||||
if ((*argument)[i] == '$' && !in_single_quote)
|
|
||||||
{
|
|
||||||
expand_variable(argument, &i, minishell);
|
|
||||||
if (*argument == NULL)
|
|
||||||
return (minishell->exit = true, malloc_error());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((*argument)[i] == '\'' && !in_double_quote)
|
|
||||||
in_single_quote = !in_single_quote;
|
|
||||||
else if ((*argument)[i] == '"' && !in_single_quote)
|
|
||||||
in_double_quote = !in_double_quote;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void expand(
|
|
||||||
t_list **commands,
|
|
||||||
t_minishell *minishell
|
|
||||||
)
|
|
||||||
{
|
|
||||||
t_list *current_command;
|
|
||||||
t_command *command;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
current_command = *commands;
|
|
||||||
while (current_command != NULL)
|
|
||||||
{
|
|
||||||
command = (t_command *)current_command->content;
|
|
||||||
i = 0;
|
|
||||||
while (i < command->argc)
|
|
||||||
{
|
|
||||||
expand_argument(&command->argv[i], minishell);
|
|
||||||
if (command->argv[i] == NULL)
|
|
||||||
ft_lstclear(commands, (void (*)(void *))command_clear);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (command == NULL)
|
|
||||||
return (ft_lstclear(commands, (void (*)(void *))command_clear));
|
|
||||||
current_command = current_command->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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(NULL), 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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(
|
|
||||||
t_list **args,
|
|
||||||
size_t argc
|
|
||||||
)
|
|
||||||
{
|
|
||||||
char **argv;
|
|
||||||
t_list *arg;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
argv = (char **)malloc(sizeof(char *) * (argc + 1));
|
|
||||||
if (argv == NULL)
|
|
||||||
return (NULL);
|
|
||||||
i = 0;
|
|
||||||
arg = *args;
|
|
||||||
while (arg != NULL)
|
|
||||||
{
|
|
||||||
argv[i] = (char *)arg->content;
|
|
||||||
arg = arg->next;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
argv[i] = NULL;
|
|
||||||
ft_lstclear_nodes(args);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
command_clear(*command);
|
|
||||||
*command = 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);
|
|
||||||
}
|
|
||||||
|
|||||||
120
src/parser/parser_command.c
Normal file
120
src/parser/parser_command.c
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* parser_command.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:26:42 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:26:42 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
static t_list *ft_lstfind(t_list *lst, bool (*pre)(void *));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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`.
|
||||||
|
*/
|
||||||
|
static t_list *ft_lstfind(
|
||||||
|
t_list *lst,
|
||||||
|
bool (*pre)(void *))
|
||||||
|
{
|
||||||
|
while (lst != NULL)
|
||||||
|
{
|
||||||
|
if (pre(lst->content))
|
||||||
|
return (lst);
|
||||||
|
lst = lst->next;
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
122
src/parser/parser_expand.c
Normal file
122
src/parser/parser_expand.c
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* parser_expand.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:24:45 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:24:45 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
#include "errors.h"
|
||||||
|
|
||||||
|
static char *replace_value(char *original, char *value, int start, int end);
|
||||||
|
static void expand_variable(char **argument, int *i, t_minishell *minishell);
|
||||||
|
static void expand_argument(char **argument, t_minishell *minishell);
|
||||||
|
|
||||||
|
static char *replace_value(
|
||||||
|
char *original,
|
||||||
|
char *value,
|
||||||
|
int start,
|
||||||
|
int end
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const char *before = ft_substr(original, 0, start);
|
||||||
|
const char *after = ft_substr(original, end, ft_strlen(original) - end);
|
||||||
|
const char *expanded = ft_strnjoin(3, before, value, after);
|
||||||
|
|
||||||
|
free((char *)before);
|
||||||
|
free((char *)after);
|
||||||
|
return ((char *)expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expand_variable(
|
||||||
|
char **argument,
|
||||||
|
int *i,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char *expanded;
|
||||||
|
char *variable_name;
|
||||||
|
char *variable_value;
|
||||||
|
const int start = *i + 1;
|
||||||
|
int end;
|
||||||
|
|
||||||
|
end = start;
|
||||||
|
while (ft_isalnum((*argument)[end]) || (*argument)[end] == '_')
|
||||||
|
end++;
|
||||||
|
variable_name = ft_substr(*argument, start, end - start);
|
||||||
|
if (variable_name == NULL)
|
||||||
|
return (minishell->exit = true, malloc_error());
|
||||||
|
variable_value = get_env(variable_name, minishell);
|
||||||
|
free(variable_name);
|
||||||
|
if (variable_value == NULL)
|
||||||
|
variable_value = "";
|
||||||
|
expanded = replace_value(*argument, variable_value, start - 1, end);
|
||||||
|
if (expanded == NULL)
|
||||||
|
return (minishell->exit = true, malloc_error());
|
||||||
|
*i += ft_strlen(variable_value);
|
||||||
|
free(*argument);
|
||||||
|
*argument = expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expand_argument(
|
||||||
|
char **argument,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
bool in_single_quote;
|
||||||
|
bool in_double_quote;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
in_single_quote = false;
|
||||||
|
in_double_quote = false;
|
||||||
|
i = 0;
|
||||||
|
while ((*argument)[i] != '\0')
|
||||||
|
{
|
||||||
|
if ((*argument)[i] == '$' && !in_single_quote)
|
||||||
|
{
|
||||||
|
expand_variable(argument, &i, minishell);
|
||||||
|
if (*argument == NULL)
|
||||||
|
return (minishell->exit = true, malloc_error());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((*argument)[i] == '\'' && !in_double_quote)
|
||||||
|
in_single_quote = !in_single_quote;
|
||||||
|
else if ((*argument)[i] == '"' && !in_single_quote)
|
||||||
|
in_double_quote = !in_double_quote;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void expand(
|
||||||
|
t_list **commands,
|
||||||
|
t_minishell *minishell
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t_list *current_command;
|
||||||
|
t_command *command;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
current_command = *commands;
|
||||||
|
while (current_command != NULL)
|
||||||
|
{
|
||||||
|
command = (t_command *)current_command->content;
|
||||||
|
i = 0;
|
||||||
|
while (i < command->argc)
|
||||||
|
{
|
||||||
|
expand_argument(&command->argv[i], minishell);
|
||||||
|
if (command->argv[i] == NULL)
|
||||||
|
ft_lstclear(commands, (void (*)(void *))command_clear);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (command == NULL)
|
||||||
|
return (ft_lstclear(commands, (void (*)(void *))command_clear));
|
||||||
|
current_command = current_command->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
98
src/parser/parser_redirection.c
Normal file
98
src/parser/parser_redirection.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* parser_redirection.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:28:35 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:28:35 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
#include "errors.h"
|
||||||
|
|
||||||
|
static t_redirection *redirection_new(t_list **tokens);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
static 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(NULL), 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
command_clear(*command);
|
||||||
|
*command = 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);
|
||||||
|
}
|
||||||
121
src/parser/parser_words.c
Normal file
121
src/parser/parser_words.c
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* parser_words.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2026/02/13 21:29:44 by sede-san #+# #+# */
|
||||||
|
/* Updated: 2026/02/13 21:29:44 by sede-san ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#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(
|
||||||
|
t_list **args,
|
||||||
|
size_t argc
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char **argv;
|
||||||
|
t_list *arg;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
argv = (char **)malloc(sizeof(char *) * (argc + 1));
|
||||||
|
if (argv == NULL)
|
||||||
|
return (NULL);
|
||||||
|
i = 0;
|
||||||
|
arg = *args;
|
||||||
|
while (arg != NULL)
|
||||||
|
{
|
||||||
|
argv[i] = (char *)arg->content;
|
||||||
|
arg = arg->next;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
argv[i] = NULL;
|
||||||
|
ft_lstclear_nodes(args);
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user