Fixed variable expansion errors

This commit is contained in:
marcnava-42cursus
2026-02-14 13:33:44 +01:00
parent dd6101edec
commit ba40670ace
11 changed files with 27965 additions and 7 deletions

View File

@@ -12,25 +12,81 @@
#include "parser_expand_internal.h"
static void command_clear_argv_expand(
t_command *command
)
{
int i;
i = 0;
while (i < command->argc)
{
free(command->argv[i]);
i++;
}
free(command->argv);
}
static bool command_set_expanded_argv(
t_command *command,
t_list *expanded_args,
t_minishell *minishell
)
{
char **argv;
t_list *current;
int argc;
int i;
argc = ft_lstsize(expanded_args);
argv = (char **)malloc(sizeof(char *) * (argc + 1));
if (argv == NULL)
return (ft_lstclear(&expanded_args, free),
parser_expand_malloc_error(minishell), false);
i = 0;
current = expanded_args;
while (current != NULL)
{
argv[i++] = (char *)current->content;
current = current->next;
}
argv[i] = NULL;
ft_lstclear_nodes(&expanded_args);
command_clear_argv_expand(command);
command->argc = argc;
command->argv = argv;
return (true);
}
static bool expand_argv(
t_command *command,
t_minishell *minishell
)
{
int i;
char *expanded;
t_list *expanded_args;
t_list *fields;
t_list *last;
i = 0;
expanded_args = NULL;
while (i < command->argc)
{
expanded = parser_expand_word(command->argv[i], minishell, true);
if (expanded == NULL)
return (false);
free(command->argv[i]);
command->argv[i] = expanded;
fields = NULL;
if (!parser_expand_word_fields(command->argv[i], minishell,
true, &fields))
return (ft_lstclear(&expanded_args, free), false);
if (expanded_args == NULL)
expanded_args = fields;
else
{
last = ft_lstlast(expanded_args);
if (last != NULL)
last->next = fields;
}
i++;
}
return (true);
return (command_set_expanded_argv(command, expanded_args, minishell));
}
static bool expand_redirections(

View File

@@ -0,0 +1,90 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parser_expand_fields.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/14 13:15:00 by sede-san #+# #+# */
/* Updated: 2026/02/14 13:15:00 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "parser_expand_internal.h"
static t_fields_ctx init_fields_ctx(
t_list **fields,
char **current,
t_field_state *state
)
{
t_fields_ctx ctx;
ctx.fields = fields;
ctx.current = current;
ctx.touched = &state->touched;
ctx.in_single_quote = &state->in_single_quote;
ctx.in_double_quote = &state->in_double_quote;
return (ctx);
}
static bool finish_word_fields(
t_fields_ctx ctx
)
{
if (*ctx.in_single_quote || *ctx.in_double_quote)
{
ft_lstclear(ctx.fields, free);
free(*ctx.current);
syntax_error_unexpected_token(NULL);
ctx.minishell->exit_status = 2;
return (false);
}
if ((*ctx.touched || (*ctx.current)[0] != '\0')
&& !parser_fields_push_field(ctx))
return (false);
free(*ctx.current);
return (true);
}
static bool process_word_fields(
const char *word,
t_fields_ctx ctx
)
{
size_t i;
i = 0;
while (word[i] != '\0')
{
if (!parser_fields_step(word, &i, ctx))
return (false);
}
return (true);
}
bool parser_expand_word_fields(
const char *word,
t_minishell *minishell,
bool expand_vars,
t_list **fields
)
{
char *current;
t_field_state state;
t_fields_ctx ctx;
*fields = NULL;
current = ft_strdup("");
if (current == NULL)
return (parser_expand_malloc_error(minishell), false);
state.touched = false;
state.in_single_quote = false;
state.in_double_quote = false;
ctx = init_fields_ctx(fields, &current, &state);
ctx.minishell = minishell;
ctx.expand_vars = expand_vars;
if (!process_word_fields(word, ctx))
return (ft_lstclear(fields, free), free(current), false);
return (finish_word_fields(ctx));
}

View File

@@ -0,0 +1,105 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parser_expand_fields_step.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/14 14:12:00 by sede-san #+# #+# */
/* Updated: 2026/02/14 14:12:00 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "parser_expand_internal.h"
static bool handle_quote_char(
const char *word,
size_t *i,
t_fields_ctx ctx
)
{
if (word[*i] == '\'' && !*ctx.in_double_quote)
{
*ctx.in_single_quote = !*ctx.in_single_quote;
*ctx.touched = true;
(*i)++;
return (true);
}
if (word[*i] == '\"' && !*ctx.in_single_quote)
{
*ctx.in_double_quote = !*ctx.in_double_quote;
*ctx.touched = true;
(*i)++;
return (true);
}
return (false);
}
static bool skip_dollar_quote_prefix(
const char *word,
size_t *i,
t_fields_ctx ctx
)
{
if (word[*i] == '$' && !*ctx.in_single_quote && !*ctx.in_double_quote
&& word[*i + 1] != '\0'
&& (word[*i + 1] == '\'' || word[*i + 1] == '\"'))
{
(*i)++;
return (true);
}
return (false);
}
static bool expand_dollar_token(
const char *word,
size_t *i,
t_fields_ctx ctx,
bool *handled
)
{
char *expanded;
*handled = false;
if (word[*i] != '$' || *ctx.in_single_quote || !ctx.expand_vars)
return (true);
*handled = true;
expanded = parser_expand_variable(word, i, ctx.minishell);
if (expanded == NULL)
return (false);
if (!*ctx.in_double_quote
&& !parser_fields_expand_unquoted_value(ctx, expanded))
return (free(expanded), false);
if (*ctx.in_double_quote && !parser_fields_append_text(ctx.current,
expanded, ctx.minishell))
return (free(expanded), false);
if (*ctx.in_double_quote && expanded[0] != '\0')
*ctx.touched = true;
free(expanded);
return (true);
}
bool parser_fields_step(
const char *word,
size_t *i,
t_fields_ctx ctx
)
{
char value[2];
bool handled;
if (handle_quote_char(word, i, ctx))
return (true);
if (skip_dollar_quote_prefix(word, i, ctx))
return (true);
if (!expand_dollar_token(word, i, ctx, &handled))
return (false);
if (handled)
return (true);
value[0] = word[(*i)++];
value[1] = '\0';
if (!parser_fields_append_text(ctx.current, value, ctx.minishell))
return (false);
*ctx.touched = true;
return (true);
}

View File

@@ -0,0 +1,100 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parser_expand_fields_utils.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/14 14:12:00 by sede-san #+# #+# */
/* Updated: 2026/02/14 14:12:00 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "parser_expand_internal.h"
bool parser_fields_append_text(
char **current,
const char *value,
t_minishell *minishell
)
{
char *joined;
joined = ft_strnjoin(2, *current, (char *)value);
if (joined == NULL)
{
free(*current);
*current = NULL;
return (parser_expand_malloc_error(minishell), false);
}
free(*current);
*current = joined;
return (true);
}
static bool is_ifs_char(
char c
)
{
return (c == ' ' || c == '\t' || c == '\n');
}
bool parser_fields_push_field(
t_fields_ctx ctx
)
{
t_list *node;
node = ft_lstnew(*ctx.current);
if (node == NULL)
{
free(*ctx.current);
*ctx.current = NULL;
return (parser_expand_malloc_error(ctx.minishell), false);
}
ft_lstadd_back(ctx.fields, node);
*ctx.current = ft_strdup("");
if (*ctx.current == NULL)
return (ft_lstclear(ctx.fields, free),
parser_expand_malloc_error(ctx.minishell), false);
*ctx.touched = false;
return (true);
}
static void skip_ifs(
const char *expanded,
size_t *i
)
{
while (expanded[*i] != '\0' && is_ifs_char(expanded[*i]))
(*i)++;
}
bool parser_fields_expand_unquoted_value(
t_fields_ctx ctx,
const char *expanded
)
{
size_t i;
char value[2];
i = 0;
while (expanded[i] != '\0')
{
if (is_ifs_char(expanded[i]))
{
if ((*ctx.touched || (*ctx.current)[0] != '\0')
&& !parser_fields_push_field(ctx))
return (false);
skip_ifs(expanded, &i);
continue ;
}
value[0] = expanded[i];
value[1] = '\0';
if (!parser_fields_append_text(ctx.current, value, ctx.minishell))
return (false);
*ctx.touched = true;
i++;
}
return (true);
}

View File

@@ -17,11 +17,21 @@
# include "errors.h"
# include "variables.h"
typedef struct s_fields_ctx t_fields_ctx;
void parser_expand_malloc_error(t_minishell *minishell);
char *parser_expand_variable(const char *word, size_t *i,
t_minishell *minishell);
char *parser_expand_word(const char *word, t_minishell *minishell,
bool expand_vars);
bool parser_expand_word_fields(const char *word, t_minishell *minishell,
bool expand_vars, t_list **fields);
bool parser_fields_append_text(char **current, const char *value,
t_minishell *minishell);
bool parser_fields_push_field(t_fields_ctx ctx);
bool parser_fields_expand_unquoted_value(t_fields_ctx ctx,
const char *expanded);
bool parser_fields_step(const char *word, size_t *i, t_fields_ctx ctx);
typedef struct s_word_ctx
{
@@ -32,4 +42,22 @@ typedef struct s_word_ctx
bool expand_vars;
} t_word_ctx;
typedef struct s_fields_ctx
{
t_list **fields;
char **current;
bool *touched;
bool *in_single_quote;
bool *in_double_quote;
t_minishell *minishell;
bool expand_vars;
} t_fields_ctx;
typedef struct s_field_state
{
bool touched;
bool in_single_quote;
bool in_double_quote;
} t_field_state;
#endif

View File

@@ -56,6 +56,10 @@ static bool word_step(
if (word_toggle_quotes(word[*i], ctx.in_single_quote, ctx.in_double_quote))
return ((*i)++, true);
if (word[*i] == '$' && word[*i + 1] != '\0'
&& !*ctx.in_single_quote && !*ctx.in_double_quote
&& (word[*i + 1] == '\'' || word[*i + 1] == '\"'))
return ((*i)++, true);
if (word[*i] == '$' && !*ctx.in_single_quote && ctx.expand_vars)
{
expanded = parser_expand_variable(word, i, ctx.minishell);