From 3e7dd56340535446f820a470ac5937b97b463952 Mon Sep 17 00:00:00 2001 From: Sergio Date: Mon, 4 Aug 2025 00:38:53 +0200 Subject: [PATCH] update: functions done: echo + echo -n, pwd, exit with and without arguments / parser appears to work, test with commands and local files (only tested with ls -l) --- Makefile | 24 +++- include/builtins.h | 60 ++++++++++ include/minishell.h | 37 ++++-- src/builtins/cd.c | 28 +++++ src/builtins/echo.c | 106 ++++++++++++++++++ src/builtins/env.c | 36 ++++++ src/builtins/exit.c | 62 ++++++++++ src/builtins/export.c | 0 src/builtins/pwd.c | 27 +++++ src/builtins/unset.c | 0 src/commands/exec.c | 20 ++++ src/commands/parse.c | 120 ++++++++++++++++++++ src/minishell.c | 236 +++++++++++++++++++++++++++------------ src/utils/get_hostname.c | 46 ++++++++ 14 files changed, 718 insertions(+), 84 deletions(-) create mode 100644 include/builtins.h create mode 100644 src/builtins/cd.c create mode 100644 src/builtins/echo.c create mode 100644 src/builtins/env.c create mode 100644 src/builtins/exit.c create mode 100644 src/builtins/export.c create mode 100644 src/builtins/pwd.c create mode 100644 src/builtins/unset.c create mode 100644 src/commands/exec.c create mode 100644 src/commands/parse.c create mode 100644 src/utils/get_hostname.c diff --git a/Makefile b/Makefile index cb676af..41ba8a6 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ # By: sede-san +# include + +typedef int (*t_builtin_func)(int argc, char const *argv[]); + +typedef struct s_builtin +{ + const char *name; + t_builtin_func function; +} t_builtin; + +// cd.c + +int cd_builtin(int argc, char const *argv[]); + +// echo.c + +typedef struct s_echo_flags +{ + int newline; // print newline after everything has been printed +} t_echo_flags; + +int echo_builtin(int argc, char const *argv[]); + +// env.c + +int env_builtin(int argc, char const *argv[]); + +// exit.c + +int exit_builtin(int argc, char const *argv[]); + +// export.c + +int export_builtin(int argc, char const *argv[]); + +// pwd.c + +int pwd_builtin(int argc, char const *argv[]); + +// unset.c + +int unset_builtin(int argc, char const *argv[]); + +#endif diff --git a/include/minishell.h b/include/minishell.h index e1a799a..167f454 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -6,33 +6,52 @@ /* By: sede-san # include # include # include # include -# define HISTORY_FILE "/.minishell_history" - -typedef struct s_env +typedef struct s_cmd { - char *home; - char **path; -} t_env; + int argc; + char **argv; + char **envp; +} t_cmd; + +# define HISTORY_FILE "/.minishell_history" typedef struct s_minishell { - char *prompt; char *history_file; - t_env env; + char **envp; } t_minishell; +/* ******************************* Commands ********************************* */ + +typedef int (*t_msh_cmdfunc)(char **args, char **env, t_minishell* minshell); + +// exec.c + +int exec_cmd(char *cmd, char **args, t_minishell *minishell); + +// parse.c + +t_cmd parse_cmd(char *line, t_minishell *minishell); + +/* ********************************* Utils ********************************** */ + +// get_hostname.c +char *get_hostname(void); + #endif diff --git a/src/builtins/cd.c b/src/builtins/cd.c new file mode 100644 index 0000000..3114e28 --- /dev/null +++ b/src/builtins/cd.c @@ -0,0 +1,28 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san newline = 1; +} diff --git a/src/builtins/env.c b/src/builtins/env.c new file mode 100644 index 0000000..1ba7775 --- /dev/null +++ b/src/builtins/env.c @@ -0,0 +1,36 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* env.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san 1) + { + if (!ft_isdigit(*argv[1]) || !ft_strisnum(argv[1])) + { + fprintf(stderr, "exit: %s: numeric argument required", argv[1]); + exit_code = 2; + } + else + { + fprintf(stderr, "exit: too many arguments"); + exit_code = -1; + } + } + else + exit_code = (unsigned int)((unsigned char)(ft_atol(argv[1]))); + return (exit_code); +} diff --git a/src/builtins/export.c b/src/builtins/export.c new file mode 100644 index 0000000..e69de29 diff --git a/src/builtins/pwd.c b/src/builtins/pwd.c new file mode 100644 index 0000000..3b79ae9 --- /dev/null +++ b/src/builtins/pwd.c @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* pwd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san "RESET; - minishell.env.home = getenv("HOME"); - minishell.history_file = ft_strjoin(minishell.env.home, HISTORY_FILE); - minishell.env.path = ft_split(getenv("PATH"), ':'); + minishell.history_file = ft_strjoin(getenv("HOME"), HISTORY_FILE); + // minishell.path = ft_split(getenv("PATH"), ':'); + minishell.envp = envp; return (minishell); } + +/** + * @brief Main loop for the minishell program. + * + * This function implements the main interactive loop of the minishell. It + * displays a dynamic prompt showing the user, hostname, and current working + * directory, reads user input, adds commands to the history, and executes + * commands by forking a new process. The loop continues until the user enters + * "exit" or EOF is encountered. + * + * @param minishell Pointer to the minishell state structure, containing at + * least the history file path. + * @param envp Environment variables to be passed to executed commands. + * + * The function performs the following steps: + * - Loads command history from the specified history file. + * - Constructs and displays a prompt with user, hostname, and current + * directory. + * - Reads a line of input from the user. + * - If the input is not empty: + * - Adds the command to the history and writes it to the history file. + * - If the command is "exit", breaks the loop and exits. + * - Otherwise, constructs the command path, forks a child process, and + * executes the command using execve. + * - Waits for the child process to finish. + * - Cleans up allocated memory and clears the history on exit. + */ +static void minishell(t_minishell *minishell, char **envp) +{ + char *line; + char *cmd; + char *args[2]; + pid_t pid; + + line = NULL; + read_history(minishell->history_file); + while (1) + { + if (line) + free(line); + char *prompt; + char *hostname = get_hostname(); + if (hostname) + { + prompt = ft_strjoin_mul(12, + BOLD, BLUE_TEXT, getenv("USER"), "@", hostname, + RESET, ":", + BOLD, GREEN_TEXT, getenv("PWD"), + RESET, "> "); + free(hostname); + } + if (prompt) + { + line = readline(prompt); + free(prompt); + } + else + line = readline("minishell> "); + if (!line && exit_builtin(1, NULL)) + break ; + if (*line) + { + add_history(line); + write_history(minishell->history_file); + + t_cmd cmd_parse = parse_cmd(line, minishell); + // exec_cmd(); + + // builtins + if (ft_strncmp("exit\0", line, 5) == 0 && exit_builtin(1, NULL) != -1) + break ; + else if (ft_strncmp("cd\0", line, 3) == 0) + cd_builtin(1, NULL); + else if (ft_strncmp("pwd\0", line, 4) == 0) + pwd_builtin(1, NULL); + else if (ft_strncmp("env\0", line, 4) == 0) + env_builtin(1, NULL); + else if (ft_strncmp("echo\0", line, 5) == 0) + echo_builtin(0, NULL); + // not builtins + else + { + // if string does not start with "./" + cmd = ft_strjoin("/usr/bin/", line); + args[0] = line; + args[1] = NULL; + pid = fork(); + if (pid == 0) + { + execve(cmd, args, envp); + exit(0); + } + waitpid(pid, NULL, 0); + free(cmd); + } + } + } + rl_clear_history(); + free(line); +} + +/** + * @brief Clears and frees resources associated with a t_minishell instance. + * + * This function performs the following actions: + * - Zeroes out the contents of the history_file string. + * - Frees the memory allocated for the history_file. + * - Frees the memory allocated for the path array using ft_free_split. + * - Zeroes out the entire t_minishell structure. + * + * @param minishell Pointer to the t_minishell structure to be cleared and + * freed. + */ +static void clear_minishell( + t_minishell *minishell +) +{ + ft_bzero(minishell->history_file, + ft_strlen(minishell->history_file) * sizeof(char)); + free(minishell->history_file); + // ft_free_split(minishell->path); + ft_bzero(minishell, sizeof(t_minishell)); +} diff --git a/src/utils/get_hostname.c b/src/utils/get_hostname.c new file mode 100644 index 0000000..74759f1 --- /dev/null +++ b/src/utils/get_hostname.c @@ -0,0 +1,46 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* get_hostname.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san