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)

This commit is contained in:
2025-08-04 00:38:53 +02:00
parent e89de4e20b
commit 3e7dd56340
14 changed files with 718 additions and 84 deletions

View File

@@ -6,98 +6,188 @@
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/07/31 03:42:25 by sede-san #+# #+# */
/* Updated: 2025/07/31 14:43:43 by sede-san ### ########.fr */
/* Updated: 2025/08/04 00:29:45 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "minishell.h"
static t_minishell init_minishell(void);
static t_minishell init_minishell(char **envp);
static void minishell(t_minishell *minishell, char **envp);
static void clear_minishell(t_minishell *minishell);
/**
* @brief Entry point for the minishell program.
*
* Validates the number of command-line arguments, initializes the minishell
* structure, starts the main shell loop, and performs necessary cleanup before
* exiting.
*
* @param argc Number of command-line arguments.
* @param argv Array of command-line argument strings.
* @param envp Array of environment variable strings.
*
* @return int Returns EXIT_SUCCESS if the program completes successfully, or
* an error code on failure.
*/
int main(
int argc,
char const *argv[],
char **envp
)
char **envp)
{
t_minishell minishell;
char *line;
t_minishell shell;
minishell = init_minishell();
line = NULL;
(void)argv;
(void)envp;
errno = 0;
if (argc != 1)
return (EXIT_FAILURE);
/* ====================================================================== */
char *cmd = "/usr/bin/whoami";
char *args[] = {"whoami", NULL};
__pid_t pid = fork(); // Creates a "secondary" process
if (pid == 0)
{
execve(cmd, args, envp);
exit(0);
}
waitpid(pid, NULL, 0); // Makes the "parent" process wait until the "child"
// has finished
/* ====================================================================== */
cmd = "/usr/bin/hostname";
args[0] = "hostname";
args[1] = NULL;
pid = fork();
if (pid == 0)
{
execve(cmd, args, envp);
exit(0);
}
waitpid(pid, NULL, 0);
read_history(minishell.history_file);
while (1)
{
if (line)
free(line);
line = readline(minishell.prompt);
if (!line)
break ;
if (*line)
{
add_history(line);
write_history(minishell.history_file);
if (!ft_strncmp("exit\0", line, 5))
break ;
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);
}
// ft_putendl(line);
}
rl_clear_history();
free(line);
free((char *)minishell.history_file);
ft_free_split(minishell.env.path);
return (errno = EINVAL, errno);
shell = init_minishell(envp);
minishell(&shell, envp);
clear_minishell(&shell);
return (EXIT_SUCCESS);
}
static t_minishell init_minishell(void)
/**
* @brief Initializes and returns a t_minishell structure with default values.
*
* This function zeroes out a t_minishell struct, sets up the history file path
* by joining the HOME environment variable with HISTORY_FILE, and splits the
* PATH environment variable into an array of strings using ':' as the
* delimiter.
*
* @return t_minishell The initialized minishell structure.
*/
static t_minishell init_minishell(
char **envp)
{
t_minishell minishell;
ft_bzero(&minishell, sizeof(t_minishell));
minishell.prompt = RED_TEXT"minishell> "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));
}