Add '*' and '?' wildcard support
authorLukas Jiriste <ljiriste@student.42prague.com>
Thu, 8 Aug 2024 13:40:35 +0000 (15:40 +0200)
committerLukas Jiriste <ljiriste@student.42prague.com>
Thu, 8 Aug 2024 13:40:35 +0000 (15:40 +0200)
Makefile
inc/minishell.h
src/input_handling.c
src/wildcards.c [new file with mode: 0644]

index b57362ad9de7c23834b0cfe6c02f2669e2dbe92e..b5ed7458364461cac9b15c752dbc68786cb65705 100644 (file)
--- 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                     \
index 4dee16d2c0ad0c878f205801d0c172eb25331502..4fb3e4684b820f8cb44ad83bbead729c44748ec4 100644 (file)
@@ -6,7 +6,7 @@
 /*   By: ljiriste <marvin@42.fr>                    +#+  +:+       +#+        */
 /*                                                +#+#+#+#+#+   +#+           */
 /*   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
index 3eb44cd31bf19d316f1122c372b7f093000cca38..9e98b552df814240ca9a6ffe114657e261c78ef5 100644 (file)
@@ -6,7 +6,7 @@
 /*   By: ljiriste <marvin@42.fr>                    +#+  +:+       +#+        */
 /*                                                +#+#+#+#+#+   +#+           */
 /*   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 (file)
index 0000000..703608a
--- /dev/null
@@ -0,0 +1,201 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   wildcards.c                                        :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: ljiriste <marvin@42.fr>                    +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   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 <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+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);
+}