/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* wildcard_exp.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: jguelen +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/20 15:01:38 by jguelen #+# #+# */ /* Updated: 2025/04/25 18:54:06 by jguelen ### ########.fr */ /* */ /* ************************************************************************** */ #include "libft.h" #include "subst.h" #include "replace_substr.h" /******************************************************************************/ /* */ /* NOTE: The use of errno and the setting of it was OKed by Alexandru in this */ /* context. */ /* */ /******************************************************************************/ /* ** Returns a directory stream corresponding to the current directory. ** */ static DIR *open_current_dir(void) { 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); } /* ** 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. */ static t_wordlist *add_file_to_list(t_wordlist **list, char *filename) { t_worddesc *file_desc; char *copy; char *marker; copy = ft_strdup(filename); if (!copy) return (wordlist_destroy(*list), NULL); 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); if (!file_desc) { wordlist_destroy(*list); free(marker); return (NULL); } *list = wordlist_push(*list, file_desc); return (*list); } /* ** 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. ** @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) { 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); } new = readdir(current_dir); } closedir(current_dir); 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). ** 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); } t_wordlist *expand_star(t_worddesc *file_pattern) { t_worddesc *pattern_copy; t_wordlist *expanded; if (!file_pattern || !file_pattern->word) return (NULL); pattern_copy = deal_with_potential_pattern_marker(file_pattern); if (!ispattern(pattern_copy)) return (worddesc_destroy(pattern_copy), NULL); clean_pattern(pattern_copy); expanded = expand_star_core(pattern_copy); worddesc_destroy(pattern_copy); return (expanded); }