diff --git a/.gitignore b/.gitignore index 1c5afbd..50c89a7 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ mallocfail_hashes bash.txt .cache/ compile_commands.json +.vscode diff --git a/src/minishell.h b/src/minishell.h index 01e2f51..4c32047 100644 --- a/src/minishell.h +++ b/src/minishell.h @@ -3,18 +3,19 @@ /* ::: :::::::: */ /* minishell.h :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: jguelen +#+ +:+ +#+ */ +/* By: jguelen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/24 12:51:21 by jguelen #+# #+# */ -/* Updated: 2025/02/24 13:04:32 by jguelen ### ########.fr */ +/* Updated: 2025/03/01 16:59:30 by jguelen ### ########.fr */ /* */ /* ************************************************************************** */ #ifndef MINISHELL_H # define MINISHELL_H -typedef struct s_minishell +typedef struct s_minishell { + t_env *env; int last_return_value; } t_minishell; diff --git a/src/parser/worddesc/worddesc.h b/src/parser/worddesc/worddesc.h index e3c4e2e..3cc67ad 100644 --- a/src/parser/worddesc/worddesc.h +++ b/src/parser/worddesc/worddesc.h @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* worddesc.h :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: khais +#+ +:+ +#+ */ +/* By: jguelen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ -/* Created: 2025/03/11 11:13/50 by khais #+# #+# */ -/* Updated: 2025/03/11 11:13:50 by khais ### ########.fr */ +/* Created: 2025/02/13 15:47:58 by khais #+# #+# */ +/* Updated: 2025/03/21 10:09:06 by jguelen ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/src/subst/subst.h b/src/subst/subst.h index e92130e..7e350b2 100644 --- a/src/subst/subst.h +++ b/src/subst/subst.h @@ -6,7 +6,7 @@ /* By: jguelen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/23 15:01:40 by jguelen #+# #+# */ -/* Updated: 2025/02/28 13:43:23 by jguelen ### ########.fr */ +/* Updated: 2025/03/01 17:00:52 by jguelen ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,7 +17,7 @@ # include "../parser/wordlist/wordlist.h" # include "../minishell.h" -int expand_question_mark(t_minishell *app); +int expand_question_mark(t_minishell *app); t_wordlist *wordlist_var_expansion(t_wordlist *list, t_env *env); t_wordlist *expand_star(char *file_pattern); diff --git a/src/subst/variable_subst.c b/src/subst/variable_subst.c index f3bfe66..9b844de 100644 --- a/src/subst/variable_subst.c +++ b/src/subst/variable_subst.c @@ -6,56 +6,72 @@ /* By: jguelen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/23 15:02:37 by jguelen #+# #+# */ -/* Updated: 2025/02/28 18:48:15 by jguelen ### ########.fr */ +/* 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" -/* -** @RETURN Returns a malloc-allocated string representing the return value of -** the last foreground executed pipeline. -*/ -char *expand_question_mark(t_minishell *app) +static char *word_update(t_worddesc *word, size_t i, size_t id_len, char *rep) { - return (ft_itoa(app->last_return_value)); -} + char *new_word; + size_t rep_len; + size_t digit; -/* -** Returns the longest possible substring present in str starting at the -** beginning that follows the definition of a valid bash identifier. -** NOTE(reminder): a valid bash identifier (name) is a non-empty string -** starting with a '_' or an alphabetic character and composed only of '_'s or -** alphanumerical characters. -** The returned string is malloc-allocated. -** In case of an allocation error, NULL is returned. -*/ -char *ft_get_longest_identifier(char *str) -{ - char *key; - size_t i; - - if (!str || (*str != '_' && !ft_isalpha(*str))) - return (ft_strdup("")); - i = 1; - while (str[i]) - { - if (!ft_isalpha(str[i]) && !ft_isdigit(str[i]) && str[i] != '_') - break ; - i++; - } - key = malloc((i + 1)* sizeof(char)); - if (!key) + 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); - ft_memcpy(key, str, i); - key[i] = '\0'; - return (key); + 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 @@ -66,50 +82,31 @@ char *ft_get_longest_identifier(char *str) ** 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. +** 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_env *env) +t_worddesc *word_var_expansion(t_worddesc *word, t_minishell *app) { size_t i; - char *id; - char *tmp; + size_t id_len; + size_t rep_len; char *rep; i = 0; - while (((*word)->word)[i]) + while (word->word[i] && word->word[i + 1]) { - if (word->flags[i] != '\'' && word->word[i] == '$') + if (word->mark_string[i] != '\'' && word->word[i] == '$') { - id = ft_get_longest_identifier((word->word) + i + 1); - if (!id) + rep = calculate_replacement(word, app, i, &id_len); + if (!rep) return (NULL); - id_len = ft_strlen(id); - if ((id_len == 0 && (word->word[i + 1] == '\0' - || word->word[i + 1] == '"' || word->word[i + 1] == '\'')) - || (id_len == 1 && ft_isdigit(*id))) - { - free(id); - if (word->word[i + 1] == '\0') - continue ; - tmp = replace_in_str(word->word, i, i, NULL); - free(word->word); - word->word = tmp; - /////flags update - continue ; - } - rep = env_get_val(env, id); - free(id); - tmp = replace_in_str(word->word, i, i + id_len, rep); - free(rep); - if (!tmp) + rep_len = ft_strlen(rep); + if (word_update(word, i, id_len, rep) == NULL) return (NULL); - free(word->word); - word->word = tmp; - ////flags update } - i++; + i += rep_len; } - return (*word); + return (word); } /* @@ -119,18 +116,15 @@ t_worddesc *word_var_expansion(t_worddesc *word, t_env *env) ** 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_env *env) +t_wordlist *wordlist_var_expansion(t_wordlist *list, t_minishell *app) { t_wordlist *tmp_list; - char *tmp_word; - ssize_t idx_start; - char *value; tmp_list = list; while (tmp_list) { if ((tmp_list->word->flags & W_HASDOLLAR) - && word_var_expansion(tmp_list->word, env) == NULL) + && word_var_expansion(tmp_list->word, app) == NULL) return (NULL); tmp_list = tmp_list->next; } diff --git a/src/subst/variable_subst_utils.c b/src/subst/variable_subst_utils.c new file mode 100644 index 0000000..2487060 --- /dev/null +++ b/src/subst/variable_subst_utils.c @@ -0,0 +1,73 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* variable_subst_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jguelen +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/03/01 13:04:27 by jguelen #+# #+# */ +/* Updated: 2025/03/01 17:02:27 by jguelen ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "subst.h" +#include "../minishell.h" +#include "replace_substr.h" +#include "../env/env.h" +#include "../env/env_manip.h" + +/* +** Returns a C-compliant malloc-allocated string of length len and complosed +** only of the character c except for the teerminating NULL-byte or NULL in +** case of an allocation error. +*/ +char *construct_repeting_char_string(char c, size_t len) +{ + char *new; + + new = ft_calloc(len + 1, sizeof(char)); + if (!new) + return (NULL); + ft_memset(new, c, len); + return (new); +} + +/* +** @RETURN Returns a malloc-allocated string representing the return value of +** the last foreground executed pipeline. +*/ +char *expand_question_mark(t_minishell *app) +{ + return (ft_itoa(app->last_return_value)); +} + +/* +** Returns the longest possible substring present in str starting at the +** beginning that follows the definition of a valid bash identifier. +** NOTE(reminder): a valid bash identifier (name) is a non-empty string +** starting with a '_' or an alphabetic character and composed only of '_'s or +** alphanumerical characters. +** The returned string is malloc-allocated. +** In case of an allocation error, NULL is returned. +*/ +char *ft_get_longest_identifier(char *str) +{ + char *key; + size_t i; + + if (!str || (*str != '_' && !ft_isalpha(*str))) + return (ft_strdup("")); + i = 1; + while (str[i]) + { + if (!ft_isalpha(str[i]) && !ft_isdigit(str[i]) && str[i] != '_') + break ; + i++; + } + key = malloc((i + 1) * sizeof(char)); + if (!key) + return (NULL); + ft_memcpy(key, str, i); + key[i] = '\0'; + return (key); +} diff --git a/tests/expansion.c b/tests/expansion.c index 0ea80fd..090951e 100644 --- a/tests/expansion.c +++ b/tests/expansion.c @@ -6,7 +6,7 @@ /* By: jguelen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/23 15:00:18 by jguelen #+# #+# */ -/* Updated: 2025/02/28 14:23:30 by jguelen ### ########.fr */ +/* Updated: 2025/03/01 11:07:17 by jguelen ### ########.fr */ /* */ /* ************************************************************************** */ @@ -43,6 +43,7 @@ static void test_insert_instr(void) free(line); } +//Test to be remade since structures changed in the function calls and returns. static void test_env_variable_expansion(void) { char *token;