minishell/src/subst/wildcard_exp.c

174 lines
5.8 KiB
C
Raw Normal View History

/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* wildcard_exp.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: khais <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/20 15:01:38 by jguelen #+# #+# */
/* Updated: 2025/04/08 16:31:46 by khais ### ########.fr */
/* */
/* ************************************************************************** */
2025-03-20 14:52:12 +01:00
#include "libft.h"
#include "subst.h"
#include "replace_substr.h"
2025-03-06 17:37:08 +01:00
/******************************************************************************/
/* */
2025-03-08 17:32:47 +01:00
/* NOTE: The use of errno and the setting of it was OKed by Alexandru in this */
2025-03-06 17:37:08 +01:00
/* context. */
/* */
2025-03-06 17:37:08 +01:00
/******************************************************************************/
/*
2025-03-06 17:37:08 +01:00
** Returns a directory stream corresponding to the current directory.
**
*/
static DIR *open_current_dir(void)
2025-03-06 17:37:08 +01:00
{
char *cur_dir_path;
size_t size;
DIR *dir;
size = PATH_SIZE_INIT;
cur_dir_path = malloc(size * sizeof(char));
if (!cur_dir_path)
return (NULL);
while (getcwd(cur_dir_path, size) == NULL)
{
if (errno != ERANGE)
return (NULL);
free(cur_dir_path);
size *= 2;
cur_dir_path = malloc(size * sizeof(char));
if (!cur_dir_path)
return (NULL);
}
errno = 0;
dir = opendir(cur_dir_path);
free(cur_dir_path);
return (dir);
}
2025-03-21 18:54:10 +01:00
/*
** Adds filename to the end of the wordlist *list by creating a worddesc whose
** word is filename and marker makes filename be considered fully single
** quoted.
** NOTE: In case of error, this function destroys *list in a similar fashion
** as worddesc_create destroys its first parameter in case of failure.
*/
2025-03-06 17:37:08 +01:00
static t_wordlist *add_file_to_list(t_wordlist **list, char *filename)
{
t_worddesc *file_desc;
char *copy;
2025-03-21 18:54:10 +01:00
char *marker;
2025-03-06 17:37:08 +01:00
copy = ft_strdup(filename);
if (!copy)
return (wordlist_destroy(*list), NULL);
2025-03-21 18:54:10 +01:00
marker = construct_repeting_char_string('\'', ft_strlen(copy));
if (!marker)
return (wordlist_destroy(*list), free(copy), NULL);
file_desc = worddesc_create(copy, '\0', marker, WORD_TOKEN);
2025-03-06 17:37:08 +01:00
if (!file_desc)
{
wordlist_destroy(*list);
2025-03-21 18:54:10 +01:00
free(marker);
2025-03-06 17:37:08 +01:00
return (NULL);
}
*list = wordlist_push(*list, file_desc);
return (*list);
}
2025-03-06 17:37:08 +01:00
/*
** A function designed to present all possible * or ? filename expansions
** for the current directory. (? is not asked by the subject).
** 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.
2025-03-08 17:32:47 +01:00
** @RETURN Returns a wordlist for which each entry corresponds to a filename
** that matches pattern->word if any file matches in the current directory.
** Otherwise return file_pattern itself if nothing matches the perceived
** pattern. This list should be alphabetically sorted.
** Can return NULL only in case of error.
** NOTE: this function never becomes the owner of file_pattern to maintain
** coherency of use.
*/
static t_wordlist *expand_star_core(t_worddesc *file_pattern)
{
2025-03-06 17:37:08 +01:00
struct dirent *new;
DIR *current_dir;
t_wordlist *file_wordlist;
current_dir = open_current_dir();
if (current_dir == NULL)
return (NULL);
file_wordlist = NULL;
new = readdir(current_dir);
while (new)
{
if (fits_pattern(new->d_name, file_pattern))
{
if (add_file_to_list(&file_wordlist, new->d_name) == NULL)
return (closedir(current_dir), NULL);
2025-03-06 17:37:08 +01:00
}
new = readdir(current_dir);
}
closedir(current_dir);
2025-03-06 17:37:08 +01:00
if (!file_wordlist)
file_wordlist = wordlist_independant_create(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).
2025-03-21 18:54:10 +01:00
** Similarly, '/' is never to be matched except if given explicitly as per
** bash requirement. This is a note in case of future expansion as in our case
** here we do not have to deal with that since we concern ourselves only with
** the current working directory.
*/
char fits_pattern(char *str, t_worddesc *pattern)
{
char **pattern_check;
size_t str_len;
size_t pattern_len;
size_t i;
char ret;
if (str && str[0] == '.' && pattern->word[0] != '.')
return (0);
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), -1);
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);
}
/*
** Returns NULL in case of error.
** NOTE: This phase of pre-processing relies partly on processing done before
** it therefore checks more loosely (and quote removal still seems not to be
** done on string comming from a variable expansion) <-----TO RE-CHECK
*/
t_wordlist *expand_star(t_worddesc *file_pattern)
{
2025-03-21 18:54:10 +01:00
clean_pattern(file_pattern);
return (expand_star_core(file_pattern));
}