Expansion: fix: algo was wrong for wildcard

Hopefully, this is a proper fix. This commit serves mainly to save
advancement.
This commit is contained in:
Jérôme Guélen 2025-03-15 15:44:23 +01:00
parent 1766e8d1ba
commit fc12d8e057
No known key found for this signature in database
5 changed files with 129 additions and 81 deletions

View file

@ -50,6 +50,8 @@ srcs = \
src/parser/wordlist/wordlist_copy.c \
src/parser/wordlist/wordlist_debug.c \
src/parser/wordlist/wordlist_idx.c \
src/parser/wordlist/wordlist_quicksort.c \
src/parser/wordlist/wordlist_utils.c \
src/parser/wordsplit/rule_utils.c \
src/parser/wordsplit/tokenizing_1_5.c \
src/parser/wordsplit/tokenizing_6_10.c \
@ -59,10 +61,14 @@ srcs = \
src/postprocess/redirections/redirection_list.c \
src/postprocess/redirections/redirection_parsing.c \
src/postprocess/redirections/redirection_type.c \
src/subst/path_split.c \
src/subst/replace_substr.c \
src/subst/simple_filename_exp.c \
src/subst/variable_subst.c \
src/subst/variable_subst_utils.c \
src/subst/wildcard_exp.c \
src/subst/wildcard_exp_utils.c \
src/subst/wildcard_exp_utils2.c \
objs = $(srcs:.c=.o)
export objs

View file

@ -6,7 +6,7 @@
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/02 13:40:10 by jguelen #+# #+# */
/* Updated: 2025/03/14 18:46:41 by jguelen ### ########.fr */
/* Updated: 2025/03/15 11:30:56 by jguelen ### ########.fr */
/* */
/* ************************************************************************** */
@ -83,7 +83,7 @@ char *filepath_from_env(char *filename, t_minishell *app)
while (path[i])
{
if (!path[i][0])
alloc_path(".", filename);
filepath = alloc_path(".", filename);
else
filepath = alloc_path(path[i], filename);
ret = stat(filepath, &file_stat); // Deal with possible failure of stat

View file

@ -6,7 +6,7 @@
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/23 15:02:59 by jguelen #+# #+# */
/* Updated: 2025/03/14 14:30:30 by jguelen ### ########.fr */
/* Updated: 2025/03/15 14:45:11 by jguelen ### ########.fr */
/* */
/* ************************************************************************** */
@ -128,6 +128,41 @@ static t_wordlist *expand_star_core(t_worddesc *file_pattern)
return (wordlist_quicksort_full(file_wordlist));
}
/*
** Returns 1 if and only if filename is recognized by pattern, 0
** otherwise or -1 in case of error.
** Takes only into account the * wildcard or ?, those characters
** NOTE: for a pattern to accept '.' as the first character of a filename
** it must be explicitly matched (only for the first character though).
** Similarly, '/' is never to be matched except if given explicitly.
*/
char fits_pattern(char *str, t_worddesc *pattern)
{
char **pattern_check;
size_t str_len;
size_t pattern_len;
size_t i;
char ret;
pattern_len = ft_strlen(pattern->word);
str_len = ft_strlen(str);
pattern_check = ft_calloc(str_len + 1, sizeof(char *));
if (!pattern_check)
return (-1);
i = 0;
while (i <= str_len)
{
pattern_check[i] = ft_calloc(pattern_len + 1, sizeof(char));
if (!pattern_check[i])
return (destroy_pattern_check(pattern_check, str_len + 1), NULL);
i++;
}
build_pattern_checks(str, pattern, pattern_check);
ret = pattern_check[str_len][pattern_len];
destroy_pattern_check(pattern_check, str_len + 1);
return (ret);
}
/*
** TODO
** Pre-processes file_pattern to give it a proper marker chain and remove

View file

@ -6,7 +6,7 @@
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/07 17:10:01 by jguelen #+# #+# */
/* Updated: 2025/03/14 15:09:36 by jguelen ### ########.fr */
/* Updated: 2025/03/15 15:33:07 by jguelen ### ########.fr */
/* */
/* ************************************************************************** */
@ -42,12 +42,45 @@ static void destroy_pattern_check(char **pattern_check, size_t len)
static int same_character_or_one_char_wild(char *str, t_worddesc *pattern,
size_t i, size_t j)
{
return (str[i] == pattern->word[j]
|| (pattern->word[j] == '?'
&& pattern->marker[j] != '\''
&& pattern->marker != '"'
&& pattern->marker != '&'
&& !(i == 1 && pattern->word[i] == '.')));
return (str[i - 1] == pattern->word[j - 1]
|| (pattern->word[j - 1] == '?'
&& pattern->marker[j - 1] != '\''
&& pattern->marker[j - 1] != '"'
&& pattern->marker[j - 1] != '&'
&& !(i == 1 && str[i - 1] == '.')));
}
/*
** Condition to know if the wildcard '*' can catch something.
*/
static int at_star_in_pattern(char *str, t_worddesc *pattern,
size_t i, size_t j)
{
return (pattern->word[j - 1] == '*'
&& pattern->marker[j - 1] != '\''
&& pattern->marker[j - 1] != '"'
&& pattern->marker[j - 1] != '&'
&& !(i == 1 && str[i - 1] == '.'));
}
/*
** Sets true where the pattern would match an empty string (the most basic
** prefix of str).
*/
static void init_pattern_checker(t_worddesc *pattern, char **checker)
{
size_t i;
checker[0][0] = 1;
i = 0;
while (pattern->word[i] == '*'
&& pattern->marker[i] != '\''
&& pattern->marker[i] != '"'
&& pattern->marker[i] != '&')
{
checker[0][i + 1] = 1;
i++;
}
}
/*
@ -58,11 +91,9 @@ static int same_character_or_one_char_wild(char *str, t_worddesc *pattern,
** to be matched explicitely. We do however consider the case where the '.'
** character cannot be matched unless explicitely when in first position
** in str.
** The algorithm is extremely similar to the one presented here:
** https://www.youtube.com/watch?v=3ZDZ-N0EPV0
*/
void build_pattern_checks(char *str, t_worddesc *pattern,
char **pattern_check)
char **checker)
{
size_t i;
size_t j;
@ -72,81 +103,19 @@ void build_pattern_checks(char *str, t_worddesc *pattern,
i = 1;
str_len = ft_strlen(str);
pattern_len = ft_strlen(pattern->word);
pattern_check[0][0] = 1;
init_pattern_checker(pattern, checker);
while (i <= str_len)
{
j = 1;
while (j <= pattern_len)
{
if (same_character_or_one_char_wild(str, pattern->word, i, j))
pattern_check[i][j] = pattern_check[i - 1][j - 1];
else if (pattern->word[j] == '*' && pattern->marker[j] != '\''
&& pattern->marker[j] != '"' && pattern->marker[j] != '&'
&& !(i == 1 && pattern->word[i] == '.'))
pattern_check[i][j] = !!(pattern_check[i - 1][j]
+ pattern_check[i][j - 1]);
if (same_character_or_one_char_wild(str, pattern, i, j))
checker[i][j] = checker[i - 1][j - 1];
else if (at_star_in_pattern(str, pattern, i, j))
checker[i][j] = !!(checker[i - 1][j] + checker[i][j - 1]
+ checker[i - 1][j - 1]);
j++;
}
i++;
}
}
/*
** Returns 1 if and only if filename is recognized by pattern, 0
** otherwise or -1 in case of error.
** Takes only into account the * wildcard or ?, those characters
** NOTE: for a pattern to accept '.' as the first character of a filename
** it must be explicitly matched (only for the first character though).
** Similarly, '/' is never to be matched except if given explicitly.
*/
char fits_pattern(char *str, t_worddesc *pattern)
{
char **pattern_check;
size_t str_len;
size_t pattern_len;
size_t i;
char ret;
pattern_len = ft_strlen(pattern->word);
str_len = ft_strlen(str);
pattern_check = ft_calloc(str_len + 1, sizeof(char *));
if (!pattern_check)
return (-1);
i = 0;
while (i <= str_len)
{
pattern_check[i] = ft_calloc(pattern_len + 1, sizeof(char));
if (!pattern_check[i])
return (destroy_pattern_check(pattern_check, str_len + 1), NULL);
i++;
}
build_pattern_checks(str, pattern, pattern_check);
ret = pattern_check[str_len][pattern_len];
destroy_pattern_check(pattern_check, str_len + 1);
return (ret);
}
/*
** Checks if a worddesc is to be considered a pattern as bash would in a
** reduced capacity, to wit if it contains at least one unquoted '?' or '*'
** character.
** Returns 1 if the worddesc pointed to by desc is to be considered a pattern,
** 0 otherwise.
*/
int ispattern(t_worddesc *desc)
{
size_t i;
if (!desc)
return (0);
i = 0;
while (desc->word[i])
{
if ((desc->word[i] == '*' || desc->word[i] == '?')
&& (desc->marker[i] != '\'' && desc->marker[i] != '"'
&& desc->marker[i] != '&'))
return (1);
i++;
}
return (0);
}

View file

@ -0,0 +1,38 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* wildcard_exp_utils2.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jguelen <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/15 15:09:56 by jguelen #+# #+# */
/* Updated: 2025/03/15 15:10:30 by jguelen ### ########.fr */
/* */
/* ************************************************************************** */
#include "subst.h"
/*
** Checks if a worddesc is to be considered a pattern as bash would in a
** reduced capacity, to wit if it contains at least one unquoted '?' or '*'
** character.
** Returns 1 if the worddesc pointed to by desc is to be considered a pattern,
** 0 otherwise.
*/
int ispattern(t_worddesc *desc)
{
size_t i;
if (!desc)
return (0);
i = 0;
while (desc->word[i])
{
if ((desc->word[i] == '*' || desc->word[i] == '?')
&& (desc->marker[i] != '\'' && desc->marker[i] != '"'
&& desc->marker[i] != '&'))
return (1);
i++;
}
return (0);
}