mirror of
https://codeberg.org/la-chouette/minishell.git
synced 2025-12-06 07:28:09 +01:00
Subst: A norm NON-compliant and incomplete version
The code does not update flags yet and is to be refactored to conform to the norm. Tests required but needing a new version of the wordsplitting code.
This commit is contained in:
parent
2dd54e2827
commit
e348040ea4
10 changed files with 328 additions and 91 deletions
1
Makefile
1
Makefile
|
|
@ -59,6 +59,7 @@ srcs = \
|
|||
src/postprocess/redirections/redirection_list.c \
|
||||
src/postprocess/redirections/redirection_parsing.c \
|
||||
src/postprocess/redirections/redirection_type.c \
|
||||
src/subst/replace_substr.c \
|
||||
|
||||
objs = $(srcs:.c=.o)
|
||||
export objs
|
||||
|
|
|
|||
21
src/minishell.h
Normal file
21
src/minishell.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* minishell.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/24 12:51:21 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/24 13:04:32 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef MINISHELL_H
|
||||
# define MINISHELL_H
|
||||
|
||||
typedef struct s_minishell
|
||||
{
|
||||
int last_return_value;
|
||||
} t_minishell;
|
||||
|
||||
#endif
|
||||
|
|
@ -6,17 +6,18 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/19 18:21:55 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/21 15:26:59 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/02/26 12:26:56 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef SIG_H
|
||||
# define SIG_H
|
||||
|
||||
# define _POSIX_C_SOURCE 200809L
|
||||
|
||||
# include "libft.h"
|
||||
# include <signal.h>
|
||||
# include <stddef.h>
|
||||
# include <asm-generic/signal-defs.h>
|
||||
|
||||
# ifndef NSIG
|
||||
# define NSIG 64
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/25 13:02:59 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/26 10:55:00 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/02/26 13:30:07 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
|
@ -44,88 +44,3 @@ char *replace_in_str(const char *text, size_t index_start, size_t index_end,
|
|||
}
|
||||
return (ft_strdup(text));
|
||||
}
|
||||
|
||||
/*
|
||||
** word is presumed not to be NULL
|
||||
*/
|
||||
static int *better_prefix_array(char *word, size_t word_len)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int *better_prefix;
|
||||
|
||||
i = 0;
|
||||
better_prefix = ft_calloc(word_len + 1, sizeof(int));
|
||||
if (!better_prefix)
|
||||
return (NULL);
|
||||
better_prefix[0] = -1;
|
||||
j = 0;
|
||||
while (++j < word_len)
|
||||
{
|
||||
if (word[i] == word[j])
|
||||
better_prefix[j] = better_prefix[i];
|
||||
else
|
||||
{
|
||||
better_prefix[j] = i;
|
||||
i = better_prefix[i];
|
||||
while (i >= 0 && word[j] != word[i])
|
||||
i = better_prefix[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
better_prefix[word_len] = i;
|
||||
return (better_prefix);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the index at which the word needle begins in haystack if found,
|
||||
** -1 if needle is not to be found in haystack.
|
||||
*/
|
||||
ssize_t find_word_byprefix(const char *haystack, char *needle)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
size_t len_n;
|
||||
int *better_prefix;
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
len_n = ft_strlen(needle);
|
||||
better_prefix = better_prefix_array(needle, len_n);
|
||||
while (haystack[j])
|
||||
{
|
||||
while (i >= 0 && needle[i] != haystack[j])
|
||||
i = better_prefix[i];
|
||||
i++;
|
||||
if (i == len_n)
|
||||
return (free(better_prefix), j);
|
||||
i = better_prefix[i];
|
||||
j++;
|
||||
}
|
||||
free(better_prefix);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
** @RETURN Returns a new C-compliant malloc-allocated string corresponding to
|
||||
** the C-compliant string text where the first occurrence of the C-compliant
|
||||
** string to_replace (NULL-byte excluded) found in text is replaced by the
|
||||
** C-compliant string replacement.
|
||||
** Returns NULL if an allocation error occurred.
|
||||
*/
|
||||
char *replace_substr(const char *text, char *to_replace, char *replacement)
|
||||
{
|
||||
char *new;
|
||||
size_t start_index;
|
||||
size_t len_torep;
|
||||
|
||||
len_torep = ft_strlen(to_replace);
|
||||
if (len_torep)
|
||||
{
|
||||
start_index = find_word_index(text, to_replace);
|
||||
if (start_index != -1)
|
||||
return (replace_in_str(text, start_index,
|
||||
(size_t)start_index + len_torep - 1, replacement));
|
||||
}
|
||||
return (ft_strdup(text));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,11 @@
|
|||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/25 12:48:39 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/26 10:56:30 by jguelen ### ########.fr */
|
||||
/* Updated: 2025/02/26 13:30:18 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "libft.h"
|
||||
|
||||
ssize_t find_word_byprefix(const char *haystack, char *needle);
|
||||
char *replace_in_str(const char *text, size_t index_start, size_t index_end,
|
||||
char *replacement);
|
||||
char *replace_substr(const char *text, char *to_replace, char *replacement);
|
||||
|
|
|
|||
24
src/subst/subst.h
Normal file
24
src/subst/subst.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* subst.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/23 15:01:40 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/28 13:43:23 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef SUBST_H
|
||||
# define SUBST_H
|
||||
|
||||
# include <stdlib.h>
|
||||
# include "../parser/wordlist/wordlist.h"
|
||||
# include "../minishell.h"
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
138
src/subst/variable_subst.c
Normal file
138
src/subst/variable_subst.c
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* variable_subst.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/23 15:02:37 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/28 18:48:15 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "subst.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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
t_worddesc *word_var_expansion(t_worddesc *word, t_env *env)
|
||||
{
|
||||
size_t i;
|
||||
char *id;
|
||||
char *tmp;
|
||||
char *rep;
|
||||
|
||||
i = 0;
|
||||
while (((*word)->word)[i])
|
||||
{
|
||||
if (word->flags[i] != '\'' && word->word[i] == '$')
|
||||
{
|
||||
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] == '\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)
|
||||
return (NULL);
|
||||
free(word->word);
|
||||
word->word = tmp;
|
||||
////flags update
|
||||
}
|
||||
i++;
|
||||
}
|
||||
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_env *env)
|
||||
{
|
||||
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)
|
||||
return (NULL);
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
return (list);
|
||||
}
|
||||
29
src/subst/wildcard_exp.c
Normal file
29
src/subst/wildcard_exp.c
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* wildcard_exp.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/23 15:02:59 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/25 10:07:59 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "subst.h"
|
||||
|
||||
/*
|
||||
** TODO
|
||||
*/
|
||||
|
||||
/*
|
||||
** A function designed to present all possible * filename expansions for the
|
||||
** current directory.
|
||||
** Does not take into account any other wildcard and does only search the
|
||||
** current working directory.
|
||||
** @PARAM A C compliant character string representing a pattern for a filename.
|
||||
** @RETURN A NULL-terminated pointer to a wordlist
|
||||
*/
|
||||
t_wordlist *expand_star(char *file_pattern)
|
||||
{
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ rawtests = \
|
|||
test_redirection_parsing \
|
||||
quote_removal \
|
||||
cmdlist_use_after_free \
|
||||
expansion \
|
||||
metacharacters \
|
||||
parse_command_lists \
|
||||
parse_pipelines \
|
||||
|
|
|
|||
109
tests/expansion.c
Normal file
109
tests/expansion.c
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* expansion.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/02/23 15:00:18 by jguelen #+# #+# */
|
||||
/* Updated: 2025/02/28 14:23:30 by jguelen ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "testutil.h"
|
||||
#include "../src/subst/subst.h"
|
||||
#include "../src/subst/replace_substr.h"
|
||||
#include "../../env/env.h"
|
||||
#include "../../env/env_manip.h"
|
||||
|
||||
/*
|
||||
** Test file for the different expansion/substitution types of minishell.
|
||||
*/
|
||||
|
||||
static void test_insert_instr(void)
|
||||
{
|
||||
char *line;
|
||||
|
||||
line = replace_in_str("abcdefghijk", 1, 4, "souris");
|
||||
assert_strequal("asourisfghijk", line);
|
||||
free(line);
|
||||
line = replace_in_str("abcdefgh" , 2, 2, "non ce n'est pas ma faute");
|
||||
assert_strequal("abnon ce n'est pas ma fautedefgh", line);
|
||||
free(line);
|
||||
line = replace_in_str("le petit canari qui fait cuicui", 3, 8, "");
|
||||
assert_strequal("le canari qui fait cuicui", line);
|
||||
free(line);
|
||||
line = replace_in_str("le petit canari qui fait cuicui", 3, 8, NULL);
|
||||
assert_strequal("le canari qui fait cuicui", line);
|
||||
free(line);
|
||||
line = replace_in_str("le canari qui fait cuicui", 2, 2, " petit ");
|
||||
assert_strequal("le petit canari qui fait cuicui", line);
|
||||
free(line);
|
||||
}
|
||||
|
||||
static void test_env_variable_expansion(void)
|
||||
{
|
||||
char *token;
|
||||
char *tk;
|
||||
t_env *env;
|
||||
|
||||
token = ft_strdup("$USER");
|
||||
if (!token)
|
||||
assert("ft_strdup failed" && false);
|
||||
env = NULL;
|
||||
env = env_set_entry(&env, "USER", "jguelen");
|
||||
if (env == NULL)
|
||||
assert("malloc failed" && false);
|
||||
env = env_set_entry(&env, "_canard", "coing coing");
|
||||
if (!env)
|
||||
assert("malloc failed: slipped on a duck" && false);
|
||||
tk = word_var_expansion(&token, env);
|
||||
if (!tk)
|
||||
assert("internal word_var_expansion failure" && false);
|
||||
assert_strequal("jguelen", tk);
|
||||
free(token);
|
||||
token = ft_strdup("\"$_caneton\"");
|
||||
if (!token)
|
||||
assert("ft_strdup failed" && false);
|
||||
tk = word_var_expansion(&token, env);
|
||||
if (!tk)
|
||||
assert("internal word_var_expansion failure" && false);
|
||||
assert_strequal("\"\"", tk);
|
||||
free(token);
|
||||
token = ft_strdup("$_canard$USER$''$USER\"\"\"$_canard\"$");
|
||||
if (!token)
|
||||
assert("ft_strdup failed" && false);
|
||||
tk = word_var_expansion(token, env);
|
||||
if (!tk)
|
||||
assert("internal word_var_expansion failure" && false);
|
||||
assert_strequal("coing coingjguelen''jguelencoing coing$", tk);
|
||||
free(token);
|
||||
token = ft_strdup("$_can'a'rd");
|
||||
if (!token)
|
||||
assert("ft_strdup failed" && false);
|
||||
tk = word_var_expansion(token, env);
|
||||
if (!tk)
|
||||
assert("internal word_var_expansion failure" && false);
|
||||
assert_strequal("'a'rd", tk);
|
||||
free(token);
|
||||
env_destroy(env);
|
||||
}
|
||||
|
||||
static void test_filename_path_expansion(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void test_filename_star_expansion(void)
|
||||
{
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_insert_instr();
|
||||
test_env_variable_expansion();
|
||||
test_filename_path_expansion();
|
||||
test_filename_star_expansion();
|
||||
return (0);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue