From: Lukas Jiriste Date: Thu, 8 Aug 2024 13:40:35 +0000 (+0200) Subject: Add '*' and '?' wildcard support X-Git-Url: https://git.ljiriste.work/?a=commitdiff_plain;h=937de247eaa7f88cbbdb9dee39da05e1a0738c8a;p=42%2Fminishell.git Add '*' and '?' wildcard support --- diff --git a/Makefile b/Makefile index b57362a..b5ed745 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,7 @@ SOURCES := main.c \ env.c \ vars.c \ input_handling.c \ + wildcards.c \ tokenization.c \ parsing.c \ execution.c \ diff --git a/inc/minishell.h b/inc/minishell.h index 4dee16d..4fb3e46 100644 --- a/inc/minishell.h +++ b/inc/minishell.h @@ -6,7 +6,7 @@ /* By: ljiriste +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/02 13:22:57 by ljiriste #+# #+# */ -/* Updated: 2024/08/02 18:35:15 by ljiriste ### ########.fr */ +/* Updated: 2024/08/08 15:10:56 by ljiriste ### ########.fr */ /* */ /* ************************************************************************** */ @@ -34,6 +34,15 @@ typedef struct s_execution_env t_vars *vars; } t_execution_env; +typedef struct s_wildcard_info +{ + const char *to_expand; + const char *current_expand_char; + const char *entry; + const char *current_entry_char; + const char *path; +} t_wildcard_info; + typedef t_parse_tree_node t_tree; int init_env(t_execution_env *env, char **envp); @@ -45,6 +54,10 @@ void clean_env(t_execution_env *env); void handle_input(char **line, t_execution_env *env); +int add_conformant(t_vec *expanded, t_wildcard_info *info); +int expand_dir(t_vec *expanded, t_wildcard_info *info); + +int expand_wildcards(char **input, const t_execution_env *env); int tokenize(char **line, t_vec *tokens); int parse(t_vec *tokens, t_tree **parse_tree); int execute(t_tree *parse_tree, t_execution_env *env); @@ -54,4 +67,8 @@ void free_tree(t_tree *tree); void free_token(void *token); void free_str(void *str); +const char *get_env_var_value(const t_execution_env *env, const char *var_name); +char **quoted_split(const char *str); + + #endif // MINISHELL_H diff --git a/src/input_handling.c b/src/input_handling.c index 3eb44cd..9e98b55 100644 --- a/src/input_handling.c +++ b/src/input_handling.c @@ -6,7 +6,7 @@ /* By: ljiriste +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/03 09:00:00 by ljiriste #+# #+# */ -/* Updated: 2024/08/08 10:39:59 by ljiriste ### ########.fr */ +/* Updated: 2024/08/08 14:26:59 by ljiriste ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,8 @@ void handle_input(char **input, t_execution_env *env) ft_vec_init(&tokens, sizeof(t_token)); parse_tree = NULL; - res = tokenize(input, &tokens); + res = expand_wildcards(input, env); + res = res || tokenize(input, &tokens); if (tokens.size == 0 && res == 0) { ft_vec_free(&tokens, free_token); diff --git a/src/wildcards.c b/src/wildcards.c new file mode 100644 index 0000000..703608a --- /dev/null +++ b/src/wildcards.c @@ -0,0 +1,201 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* wildcards.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/08/08 10:50:26 by ljiriste #+# #+# */ +/* Updated: 2024/08/08 15:34:37 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" +#include "libft.h" +#include +#include +#include + +int add_entry(t_vec *expanded, t_wildcard_info *info) +{ + char *new_expanded; + + new_expanded = ft_strjoin(info->path, info->entry); + if (!new_expanded) + return (1); + if (ft_vec_append(expanded, &new_expanded) != success) + { + free(new_expanded); + return (1); + } + return (0); +} + +int branch_at_star(t_vec *expanded, t_wildcard_info *info) +{ + const size_t start_size = expanded->size; + + ++info->current_expand_char; + if (add_conformant(expanded, info)) + return (1); + if (start_size != expanded->size || *info->current_entry_char == '\0') + return (0); + --info->current_expand_char; + ++info->current_entry_char; + return (add_conformant(expanded, info)); +} + +int expand_further(t_vec *expanded, t_wildcard_info info) +{ + size_t path_len; + char *new_path; + int res; + + path_len = ft_strlen(info.path) + ft_strlen(info.entry); + new_path = malloc(path_len + 2); + if (!new_path) + return (1); + ft_strlcpy(new_path, info.path, path_len + 2); + ft_strlcat(new_path, info.entry, path_len + 2); + new_path[path_len] = '/'; + new_path[path_len + 1] = '\0'; + info.path = new_path; + info.to_expand = info.current_expand_char; + res = expand_dir(expanded, &info); + free(new_path); + return (res); +} + +int add_conformant(t_vec *expanded, t_wildcard_info *info) +{ + if (*info->current_expand_char == '\0' && *info->current_entry_char == '\0') + return (add_entry(expanded, info)); + if (*info->current_expand_char == '/' && *info->current_entry_char == '\0') + { + ++info->current_expand_char; + return (expand_further(expanded, *info)); + } + if ((*info->current_expand_char == '?' && *info->current_entry_char != '\0') + || *info->current_expand_char == *info->current_entry_char) + { + ++info->current_expand_char; + ++info->current_entry_char; + return (add_conformant(expanded, info)); + } + if (*info->current_expand_char == '*' && (*info->current_entry_char != '.' || info->current_entry_char != info->entry)) + return (branch_at_star(expanded, info)); + return (0); +} + +int expand_dir(t_vec *expanded, t_wildcard_info *info) +{ + DIR *dir; + struct dirent *dir_entry; + + dir = opendir(info->path); + if (!dir) + return (0); + dir_entry = readdir(dir); + while (dir_entry) + { + info->entry = dir_entry->d_name; + info->current_entry_char = info->entry; + info->current_expand_char = info->to_expand; + if (add_conformant(expanded, info)) + { + closedir(dir); + return (1); + } + dir_entry = readdir(dir); + } + closedir(dir); + return (0); +} + +// Adding one byte more to the str in case '\n' needs o be appended +int replace_str_by_joint_split(char **str, char **expanded_split) +{ + char *tmp; + size_t len; + size_t i; + + tmp = *str; + len = 0; + i = 0; + while (expanded_split[i]) + len += ft_strlen(expanded_split[i++]) + 1; + *str = malloc(len + 1 + 1); + str[0][0] = '\0'; + if (!str) + { + *str = tmp; + return (1); + } + i = 0; + while (expanded_split[i]) + { + ft_strlcat(*str, expanded_split[i++], len + 1 + 1); + ft_strlcat(*str, " ", len + 1 + 1); + } + free(tmp); + return (0); +} + +int expand_word(char **str, const t_execution_env *env) +{ + const char *nullptr = NULL; + t_vec matched; + t_wildcard_info info; + int res; + char last_char = str[0][ft_strlen(*str) - 1]; + + if (last_char == '\n') + str[0][ft_strlen(*str) - 1] = '\0'; + if (ft_vec_init(&matched, sizeof(char *)) != success) + return (1); + if (str[0][0] == '/') + info.path = ft_strdup("/"); + else if (str[0][0] == '~') + info.path = ft_strjoin(get_env_var_value(env, "HOME"), "/"); + else + info.path = ft_strdup("./"); + if (!info.path) + return (1); + info.to_expand = *str; + res = expand_dir(&matched, &info); + res = res || (ft_vec_append(&matched, &nullptr) != success); + res = res || replace_str_by_joint_split(str, matched.vec); + ft_vec_free(&matched, free_str); + free((char *)info.path); + if (last_char == '\n') + { + str[0][ft_strlen(*str) + 1] = '\0'; + str[0][ft_strlen(*str)] = '\n'; + } + return (res); +} + +int expand_wildcards(char **input, const t_execution_env *env) +{ + char **split; + size_t i; + int res; + + split = quoted_split(*input); + if (!split) + return (1); + i = 0; + while (split[i]) + { + if (split[i][0] != '"' && split[i][0] != '\'' && (ft_strchr(split[i], '*') != NULL || ft_strchr(split[i], '?') != NULL)) + if (expand_word(split + i, env)) + { + ft_free_split(split); + return (1); + } + ++i; + } + res = replace_str_by_joint_split(input, split); + ft_free_split(split); + return (res); +}