From 804b8c1e57d4073c5e06a32116a170f3ebdfbdb6 Mon Sep 17 00:00:00 2001 From: Lukas Jiriste Date: Fri, 2 Aug 2024 18:43:10 +0200 Subject: [PATCH] Implement the change directory (cd) builtin It supports the $PWD variable and ~/nothign for home dir. --- Makefile | 2 ++ inc/execution.h | 22 ++++++++++++ inc/minishell.h | 3 +- src/builtins/cd.c | 48 ++++++++++++++++++++++++++ src/execution.c | 88 ++++++++++++++++++++++++++++++++++++++++++++--- src/vars.c | 4 +-- 6 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 inc/execution.h create mode 100644 src/builtins/cd.c diff --git a/Makefile b/Makefile index 0d8d3ef..b57362a 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,8 @@ SOURCES := main.c \ parsing.c \ execution.c \ helpers.c \ + \ + builtins/cd.c \ SOURCES := $(addprefix $(SRCDIR)/, $(SOURCES)) diff --git a/inc/execution.h b/inc/execution.h new file mode 100644 index 0000000..b413c7b --- /dev/null +++ b/inc/execution.h @@ -0,0 +1,22 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* execution.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/08/02 17:40:19 by ljiriste #+# #+# */ +/* Updated: 2024/08/02 17:42:18 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef EXECUTION_H +# define EXECUTION_H + +const char *get_env_var_value(const t_execution_env *env, + const char *var_name); +int set_env_var_value(t_execution_env *env, const char *var_name, + const char *new_value); +int cd(int argc, char **argv, t_execution_env *env); + +#endif // EXECUTION_H diff --git a/inc/minishell.h b/inc/minishell.h index 2320422..4dee16d 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/01 15:47:47 by ljiriste ### ########.fr */ +/* Updated: 2024/08/02 18:35:15 by ljiriste ### ########.fr */ /* */ /* ************************************************************************** */ @@ -52,5 +52,6 @@ int execute(t_tree *parse_tree, t_execution_env *env); int init_tree(t_tree *tree); void free_tree(t_tree *tree); void free_token(void *token); +void free_str(void *str); #endif // MINISHELL_H diff --git a/src/builtins/cd.c b/src/builtins/cd.c new file mode 100644 index 0000000..3d6c35f --- /dev/null +++ b/src/builtins/cd.c @@ -0,0 +1,48 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/08/02 16:37:48 by ljiriste #+# #+# */ +/* Updated: 2024/08/02 18:37:45 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" +#include "execution.h" +#include +#include + +int chdir_wrapper(const char *path, t_execution_env *env) +{ + char *cwd; + + if (!ft_strcmp(path, "~")) + path = get_env_var_value(env, "HOME"); + if (!path || path[0] == '\0') + return (0); + if (chdir(path)) + return (3); + cwd = getcwd(NULL, 0); + if (!cwd) + return (1); + if (set_env_var_value(env, "PWD", cwd)) + { + chdir(get_env_var_value(env, "PWD")); + free(cwd); + return (2); + } + free(cwd); + return (0); +} + +int cd(int argc, char **argv, t_execution_env *env) +{ + if (argc == 1) + return (chdir_wrapper("~", env)); + if (argc == 2) + return (chdir_wrapper(argv[1], env)); + return (1); +} diff --git a/src/execution.c b/src/execution.c index c8bcd83..819fcf1 100644 --- a/src/execution.c +++ b/src/execution.c @@ -6,11 +6,12 @@ /* By: ljiriste +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/07/21 08:57:54 by ljiriste #+# #+# */ -/* Updated: 2024/08/01 16:07:38 by ljiriste ### ########.fr */ +/* Updated: 2024/08/02 18:35:53 by ljiriste ### ########.fr */ /* */ /* ************************************************************************** */ #include "minishell.h" +#include "execution.h" #include "libft.h" #include #include @@ -174,23 +175,39 @@ char *get_var_name(const char *line) return (ft_strndup(line, i)); } -const char *get_var_value(const t_vec *vars, const char *var_name) +ssize_t get_var_index(const t_vec *vars, const char *var_name) { size_t len; - size_t i; + ssize_t i; const char *const *line; len = ft_strlen(var_name); i = 0; - while (i < vars->size) + while ((size_t)i < vars->size) { line = ft_vec_caccess(vars, i); if (!*line) break ; if (!ft_strncmp(*line, var_name, len) && (*line)[len] == '=') - return (*line + len + 1); + return (i); ++i; } + return (-1); +} + +const char *get_var_value(const t_vec *vars, const char *var_name) +{ + size_t len; + ssize_t i; + const char *const *line; + + len = ft_strlen(var_name); + i = get_var_index(vars, var_name); + if (i >= 0) + { + line = ft_vec_caccess(vars, i); + return (*line + len + 1); + } return (NULL); } @@ -584,6 +601,39 @@ char **expand(t_parse_tree_node *simple_command, const t_execution_env *env) return (fields); } +int set_var_value(t_vec *vars, const char *name, const char *value) +{ + ssize_t i; + char *new_entry; + + i = get_var_index(vars, name); + new_entry = malloc(ft_strlen(name) + 1 + ft_strlen(value) + 1); + if (!new_entry) + return (1); + ft_memcpy(new_entry, name, ft_strlen(name)); + new_entry[ft_strlen(name)] = '='; + ft_memcpy(new_entry + ft_strlen(name) + 1, value, ft_strlen(value) + 1); + if (add_var_line(vars, new_entry)) + { + free(new_entry); + return (1); + } + if (i >= 0) + ft_vec_erase(vars, i, free_str); + free(new_entry); + return (0); +} + +int set_env_var_value(t_execution_env *env, const char *name, const char *value) +{ + if (get_var_value(&env->vars->other, name)) + return (set_var_value(&env->vars->other, name, value)); + else if (get_var_value(&env->vars->exported, name)) + return (set_var_value(&env->vars->exported, name, value)); + else + return (set_var_value(&env->vars->other, name, value)); +} + int assignments_to_env(const t_vec *assignments, t_execution_env *env) { return (ft_vec_insert_range(&env->vars->other, assignments->vec, assignments->size, 0) == success); @@ -705,12 +755,40 @@ int add_exported(__attribute__((unused)) t_vec *assignments, __attribute__((unus return (0); } +int is_builtin(const char *str) +{ + if (!ft_strcmp(str, "cd")) + return (1); + return (0); +} + +size_t count_fields(char **fields) +{ + size_t i; + + i = 0; + while (fields[i]) + ++i; + return (i); +} + +int ex_builtin(char **fields, __attribute__((unused)) t_vec *assignments, __attribute__((unused)) const t_vec *redirections, t_execution_env *env) +{ + if (!ft_strcmp(fields[0], "cd")) + env->ret_val = cd(count_fields(fields), fields, env); + else + return (-1); + return (0); +} + int ex_fields(char **fields, t_vec *assignments, const t_vec *redirections, t_execution_env *env) { pid_t pid; int status; char *path; + if (is_builtin(fields[0])) + return (ex_builtin(fields, assignments, redirections, env)); path = NULL; if (contains_path(fields[0]) && file_exists(fields[0])) path = ft_strdup(fields[0]); diff --git a/src/vars.c b/src/vars.c index 8b11d6d..3a11e63 100644 --- a/src/vars.c +++ b/src/vars.c @@ -6,7 +6,7 @@ /* By: ljiriste +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/02 13:21:32 by ljiriste #+# #+# */ -/* Updated: 2024/05/02 13:24:39 by ljiriste ### ########.fr */ +/* Updated: 2024/08/02 18:34:58 by ljiriste ### ########.fr */ /* */ /* ************************************************************************** */ @@ -71,7 +71,7 @@ int init_vars(t_vars *vars, char **envp) return (0); } -static void free_str(void *str) +void free_str(void *str) { free(*(char **)str); return ; -- 2.30.2