minishell/src/subst/variable_subst.c
Jérôme Guélen fa383c4f17
Expansion: variable substitution V1 attempt
Norm has been checked, test are not up to date. Wildcard management and
filename expansions still to be done.
2025-03-21 10:09:28 +01:00

132 lines
4 KiB
C

/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* variable_subst.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/23 15:02:37 by jguelen #+# #+# */
/* Updated: 2025/03/01 17:01:47 by jguelen ### ########.fr */
/* */
/* ************************************************************************** */
#include "subst.h"
#include "../minishell.h"
#include "replace_substr.h"
#include "../env/env.h"
#include "../env/env_manip.h"
static char *word_update(t_worddesc *word, size_t i, size_t id_len, char *rep)
{
char *new_word;
size_t rep_len;
size_t digit;
digit = ft_isdigit(word->word[i + 1]);
rep_len = ft_strlen(rep);
new_word = replace_in_str(word->word, i, i + id_len + digit, rep);
free(rep);
free(word->word);
word->word = new_word;
rep = construct_repeting_char_string('$', rep_len);
if (!rep)
return (NULL);
new_word = replace_in_str(word->mark_string, i, i + id_len + digit, rep);
free(rep);
if (!new_word)
return (NULL);
free(word->mark_string);
word->mark_string = new_word;
return (new_word);
}
static char *calculate_replacement(t_worddesc *word, t_minishell *app, size_t i,
size_t *id_len)
{
char *rep;
char *id;
id = ft_get_longest_identifier(word->word + i + 1);
if (!id)
return (NULL);
*id_len = ft_strlen(id);
if (*id_len == 0 && word->word[i + 1] == '?')
{
rep = expand_question_mark(app);
if (!rep)
return (NULL);
}
else
{
rep = env_get_val(app->env, id);
if (!rep)
rep = strdup("");
else
rep = strdup(rep);
if (!rep)
return (NULL);
}
free(id);
return (rep);
}
/*
** @Param word should NOT be NULL.
** Replace the word field of the t_worddesc pointer word with a new string
** corresponding to the replacement of the '$' followed by a valid bash
** identifier with the corresponding value if present in env or nothing if
** the corresponding identifier does not have an entry in env.
** Additionnally if the first character following is a digit both the '$'
** and digit are removed even though we do not deal with those type of bash
** parameters (we consider them to never hold a value).
** Similarly if the character following the '$' is neither '_' or
** alphanumerical the dollar is removed except for the appearance of a '\0'
** signaling the end of the word.
** Returns NULL in case of error, or the worddesc pointer word itself if
** everything went normally.
*/
t_worddesc *word_var_expansion(t_worddesc *word, t_minishell *app)
{
size_t i;
size_t id_len;
size_t rep_len;
char *rep;
i = 0;
while (word->word[i] && word->word[i + 1])
{
if (word->mark_string[i] != '\'' && word->word[i] == '$')
{
rep = calculate_replacement(word, app, i, &id_len);
if (!rep)
return (NULL);
rep_len = ft_strlen(rep);
if (word_update(word, i, id_len, rep) == NULL)
return (NULL);
}
i += rep_len;
}
return (word);
}
/*
** Returns the t_wordlist passed as a parameter where the words have been
** modified to contain string that represent the result of parameter expansion
** where the introductory '$' character was not single quoted.
** We do NOT take the '\' character into account as an escape character here
** under any circumstance per subject requirement.
*/
t_wordlist *wordlist_var_expansion(t_wordlist *list, t_minishell *app)
{
t_wordlist *tmp_list;
tmp_list = list;
while (tmp_list)
{
if ((tmp_list->word->flags & W_HASDOLLAR)
&& word_var_expansion(tmp_list->word, app) == NULL)
return (NULL);
tmp_list = tmp_list->next;
}
return (list);
}