save commit
This commit is contained in:
@@ -6,28 +6,29 @@
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/12/01 17:04:57 by sede-san #+# #+# */
|
||||
/* Updated: 2025/12/01 17:54:26 by sede-san ### ########.fr */
|
||||
/* Updated: 2026/02/08 19:51:38 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "minishell.h"
|
||||
#include "builtins.h"
|
||||
|
||||
u_int8_t set_builtins(
|
||||
t_minishell *msh
|
||||
t_minishell *minishell
|
||||
) {
|
||||
msh->builtins = ft_hashmap_new(4, ft_hashmap_hashstr, ft_hashmap_strcmp);
|
||||
if (msh->builtins == NULL)
|
||||
minishell->builtins
|
||||
= ft_hashmap_new(4, ft_hashmap_hashstr, ft_hashmap_strcmp);
|
||||
if (minishell->builtins == NULL)
|
||||
return (0);
|
||||
ft_hashmap_put(msh->builtins, ft_strdup("cd"), builtin_cd);
|
||||
ft_hashmap_put(msh->builtins, ft_strdup("echo"), builtin_echo);
|
||||
ft_hashmap_put(msh->builtins, ft_strdup("exit"), builtin_exit);
|
||||
ft_hashmap_put(msh->builtins, ft_strdup("pwd"), builtin_pwd);
|
||||
ft_hashmap_put(minishell->builtins, ft_strdup("cd"), builtin_cd);
|
||||
ft_hashmap_put(minishell->builtins, ft_strdup("echo"), builtin_echo);
|
||||
ft_hashmap_put(minishell->builtins, ft_strdup("exit"), builtin_exit);
|
||||
ft_hashmap_put(minishell->builtins, ft_strdup("pwd"), builtin_pwd);
|
||||
return (1);
|
||||
}
|
||||
|
||||
u_int8_t is_builtin(
|
||||
const char *command_name,
|
||||
t_minishell *msh
|
||||
t_minishell *minishell
|
||||
) {
|
||||
return (ft_hashmap_contains_key(msh->builtins, command_name));
|
||||
return (ft_hashmap_contains_key(minishell->builtins, command_name));
|
||||
}
|
||||
|
||||
@@ -6,28 +6,28 @@
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/10/30 01:20:48 by sede-san #+# #+# */
|
||||
/* Updated: 2025/12/01 19:15:08 by sede-san ### ########.fr */
|
||||
/* Updated: 2026/02/08 21:16:18 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "builtins.h"
|
||||
#include <stdint.h>
|
||||
|
||||
u_int8_t builtin_exit(
|
||||
uint8_t builtin_exit(
|
||||
t_command cmd,
|
||||
t_minishell *msh
|
||||
){
|
||||
)
|
||||
{
|
||||
uint8_t exit_status;
|
||||
|
||||
ft_eputendl("exit");
|
||||
if (cmd.argc == 1)
|
||||
{
|
||||
msh->exit = 1;
|
||||
// return the last exit_status, if none 0 is returned
|
||||
return (msh->exit_status);
|
||||
}
|
||||
exit_status = msh->exit_status;
|
||||
else if (!ft_strisnum(cmd.argv[1]))
|
||||
{
|
||||
ft_eputstr("exit: ");
|
||||
ft_eputendl(cmd.argv[1]);
|
||||
ft_eputendl(": numeric argument required");
|
||||
ft_eprintf(
|
||||
"minishell: exit: %s: numeric argument required\n",
|
||||
cmd.argv[1]);
|
||||
return (2);
|
||||
}
|
||||
else if (cmd.argc > 2)
|
||||
@@ -36,9 +36,11 @@ u_int8_t builtin_exit(
|
||||
return (2);
|
||||
}
|
||||
else
|
||||
{
|
||||
msh->exit = 1;
|
||||
// cast to u_int8_t causes to return a value between 0 and 255
|
||||
return ((u_int8_t)ft_atol(cmd.argv[1]));
|
||||
}
|
||||
exit_status = (uint8_t)ft_atol(cmd.argv[1]);
|
||||
|
||||
printf("builtin_exit: exit_status=%d\n", exit_status); // Debug print
|
||||
|
||||
msh->exit = 1;
|
||||
msh->exit_status = exit_status;
|
||||
return (exit_status);
|
||||
}
|
||||
|
||||
12
src/core/command/command.c
Normal file
12
src/core/command/command.c
Normal file
@@ -0,0 +1,12 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* command.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/09 18:40:03 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/09 18:40:04 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -5,133 +5,226 @@
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/10/28 13:03:44 by sede-san #+# #+# */
|
||||
/* Updated: 2025/12/02 09:07:28 by sede-san ### ########.fr */
|
||||
/* Created: 2026/02/08 19:10:47 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/08 21:32:03 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "executor.h"
|
||||
#include "builtins.h"
|
||||
|
||||
static char *solve_path(char *cmd_name, t_minishell *msh);
|
||||
static u_int8_t path_is_solved(char *cmd_name, t_minishell *msh);
|
||||
static void handle_child(t_command *cmd, t_minishell *msh);
|
||||
static void handle_parent(pid_t child_pid, t_command *cmd, t_minishell *msh);
|
||||
static inline uint8_t execute_builtin(
|
||||
const t_command *command,
|
||||
t_minishell *minishell
|
||||
)
|
||||
{
|
||||
const t_builtin_func builtin
|
||||
= ft_hashmap_get(minishell->builtins, command->path);
|
||||
|
||||
u_int8_t execute(
|
||||
t_command cmd,
|
||||
t_minishell *msh
|
||||
) {
|
||||
pid_t child_pid;
|
||||
|
||||
cmd.path = solve_path(cmd.argv[0], msh);
|
||||
if (!cmd.path)
|
||||
{
|
||||
ft_eprintf("minishell: %s: command not found\n", cmd.argv[0]);
|
||||
return (msh->exit_status = 127, msh->exit_status);
|
||||
}
|
||||
if (!is_builtin(cmd.path, msh) && access(cmd.path, X_OK) != EXIT_SUCCESS)
|
||||
{
|
||||
ft_eputstr("minishell: ");
|
||||
perror(cmd.path);
|
||||
return (msh->exit_status = 126, msh->exit_status);
|
||||
}
|
||||
child_pid = 0;
|
||||
if (!is_builtin(cmd.path, msh))
|
||||
child_pid = fork();
|
||||
if (child_pid == -1)
|
||||
perror("minishell");
|
||||
else if (child_pid == 0)
|
||||
handle_child(&cmd, msh);
|
||||
else
|
||||
handle_parent(child_pid, &cmd, msh);
|
||||
return (msh->exit_status);
|
||||
return (builtin(*command, minishell));
|
||||
}
|
||||
|
||||
static char *solve_path(
|
||||
char *cmd_name,
|
||||
t_minishell *msh
|
||||
){
|
||||
char *cmd_path;
|
||||
char **path;
|
||||
static void handle_execve_error(
|
||||
const t_command *command,
|
||||
char **envp
|
||||
)
|
||||
{
|
||||
free_envp(envp);
|
||||
perror(command->path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void execute_external_command(
|
||||
const t_command *command,
|
||||
t_minishell *minishell
|
||||
)
|
||||
{
|
||||
char **envp;
|
||||
|
||||
envp = get_envp(minishell);
|
||||
if (envp == NULL)
|
||||
{
|
||||
perror("get_envp");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
execve(command->path, command->argv, envp);
|
||||
handle_execve_error(command, envp);
|
||||
}
|
||||
|
||||
static uint8_t execute_command(
|
||||
const t_command *command,
|
||||
t_minishell *minishell
|
||||
)
|
||||
{
|
||||
if (is_builtin(command->path, minishell))
|
||||
return (execute_builtin(command, minishell));
|
||||
else
|
||||
{
|
||||
execute_external_command(command, minishell);
|
||||
return (EXIT_FAILURE); //! should never reach here
|
||||
}
|
||||
}
|
||||
|
||||
static void cmdfree_argv(
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (path_is_solved(cmd_name, msh))
|
||||
// return a copy to avoid double free on parent
|
||||
return (ft_strdup(cmd_name));
|
||||
path = ft_split(get_env("PATH", msh), COLON);
|
||||
if (!path)
|
||||
return (NULL);
|
||||
cmd_path = NULL;
|
||||
i = -1;
|
||||
while (!cmd_path && path[++i])
|
||||
if (argv == NULL)
|
||||
return ;
|
||||
i = 0;
|
||||
while (argv[i] != NULL)
|
||||
{
|
||||
cmd_path = ft_strnjoin(3, path[i], "/", cmd_name);
|
||||
if (!cmd_path)
|
||||
return (NULL);
|
||||
/**
|
||||
* If a command exists but user has no execution permission
|
||||
* the command is shown as non existant instead of showing the
|
||||
* last ocurrence found
|
||||
*
|
||||
* TLDR: bash shows 'Permission denied'
|
||||
* and minishell 'command not found'
|
||||
*
|
||||
* TEST: execute an existing command without permission to do so
|
||||
*/
|
||||
if (access(cmd_path, X_OK) != EXIT_SUCCESS)
|
||||
ft_free((void **)&cmd_path);
|
||||
free(argv[i]);
|
||||
i++;
|
||||
}
|
||||
ft_free_split((char **)path);
|
||||
if (!cmd_path)
|
||||
return (NULL);
|
||||
return (cmd_path);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
static u_int8_t path_is_solved(
|
||||
char *cmd_name,
|
||||
t_minishell *msh
|
||||
){
|
||||
return (ft_strncmp(cmd_name, "/", 1) == 0
|
||||
|| (cmd_name[1] && ft_strncmp(cmd_name, "./", 2) == 0)
|
||||
|| (cmd_name[2] && ft_strncmp(cmd_name, "../", 3) == 0)
|
||||
|| is_builtin(cmd_name, msh)
|
||||
);
|
||||
static void cmdfree(
|
||||
t_command *command
|
||||
)
|
||||
{
|
||||
if (command == NULL)
|
||||
return ;
|
||||
cmdfree_argv(command->argv);
|
||||
free(command->path);
|
||||
free(command);
|
||||
}
|
||||
|
||||
static void handle_child(
|
||||
t_command *cmd,
|
||||
t_minishell *msh
|
||||
){
|
||||
char **envp;
|
||||
t_builtin_func builtin;
|
||||
static int create_pipe_if_needed(
|
||||
t_list *current_command,
|
||||
t_pipeline *pipeline
|
||||
)
|
||||
{
|
||||
if (!current_command->next)
|
||||
return (0);
|
||||
if (pipe(pipeline->pipefd) == PIPE_ERROR)
|
||||
return (perror("pipe"), PIPE_ERROR);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (is_builtin(cmd->argv[0], msh))
|
||||
static bool is_fork_required(
|
||||
t_list *current_command,
|
||||
t_minishell *minishell
|
||||
) {
|
||||
const t_command *command = current_command->content;
|
||||
|
||||
return (current_command->next != NULL
|
||||
|| !is_builtin(command->path, minishell));
|
||||
}
|
||||
|
||||
static pid_t fork_process(
|
||||
t_list *current_command,
|
||||
t_minishell *minishell
|
||||
)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = 0;
|
||||
if (is_fork_required(current_command, minishell))
|
||||
pid = fork();
|
||||
if (pid == FORK_ERROR)
|
||||
perror("fork");
|
||||
return (pid);
|
||||
}
|
||||
|
||||
static void setup_child_input(
|
||||
t_pipeline *pipeline
|
||||
)
|
||||
{
|
||||
if (pipeline->prev_read_fd != -1)
|
||||
{
|
||||
builtin = ft_hashmap_get(msh->builtins, cmd->argv[0]);
|
||||
builtin(*cmd, msh);
|
||||
dup2(pipeline->prev_read_fd, STDIN_FILENO);
|
||||
close(pipeline->prev_read_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_child_output(
|
||||
t_list *current_command,
|
||||
t_pipeline *pipeline
|
||||
)
|
||||
{
|
||||
if (current_command->next)
|
||||
{
|
||||
dup2(pipeline->pipefd[WRITE_PIPE], STDOUT_FILENO);
|
||||
close(pipeline->pipefd[READ_PIPE]);
|
||||
close(pipeline->pipefd[WRITE_PIPE]);
|
||||
}
|
||||
}
|
||||
|
||||
static void child_process(
|
||||
t_list *current_command,
|
||||
t_pipeline *pipeline,
|
||||
t_minishell *minishell
|
||||
)
|
||||
{
|
||||
uint8_t exit_status;
|
||||
const t_command *command = current_command->content;
|
||||
|
||||
setup_child_input(pipeline);
|
||||
setup_child_output(current_command, pipeline);
|
||||
exit_status = execute_command(command, minishell);
|
||||
if (is_fork_required(current_command, minishell))
|
||||
exit(exit_status);
|
||||
}
|
||||
|
||||
static void parent_cleanup(
|
||||
t_list *current_command,
|
||||
t_pipeline *pipeline
|
||||
)
|
||||
{
|
||||
if (pipeline->prev_read_fd != -1)
|
||||
close(pipeline->prev_read_fd);
|
||||
if (current_command->next)
|
||||
{
|
||||
close(pipeline->pipefd[WRITE_PIPE]);
|
||||
pipeline->prev_read_fd = pipeline->pipefd[READ_PIPE];
|
||||
}
|
||||
else
|
||||
{
|
||||
envp = get_envp(msh);
|
||||
execve(cmd->path, cmd->argv, envp);
|
||||
free_envp(envp);
|
||||
}
|
||||
pipeline->prev_read_fd = -1;
|
||||
}
|
||||
|
||||
static void handle_parent(
|
||||
pid_t child_pid,
|
||||
t_command *cmd,
|
||||
t_minishell *msh
|
||||
){
|
||||
if (waitpid(child_pid, (int *)&msh->exit_status, 0) == EXIT_SUCCESS)
|
||||
static uint8_t wait_for_children(void)
|
||||
{
|
||||
uint8_t exit_status;
|
||||
int status;
|
||||
|
||||
exit_status = EXIT_SUCCESS;
|
||||
while (wait(&status) > 0)
|
||||
{
|
||||
// handle success
|
||||
if (WIFEXITED(status))
|
||||
exit_status = WEXITSTATUS(status);
|
||||
}
|
||||
else
|
||||
{
|
||||
// handle error
|
||||
}
|
||||
ft_free((void **)&cmd->path);
|
||||
ft_free_split(cmd->argv);
|
||||
return (exit_status);
|
||||
}
|
||||
|
||||
uint8_t execute(
|
||||
t_list *command_list,
|
||||
t_minishell *minishell
|
||||
)
|
||||
{
|
||||
uint8_t exit_status;
|
||||
t_pipeline pipeline;
|
||||
t_list *current_command;
|
||||
pid_t pid;
|
||||
|
||||
pipeline.prev_read_fd = -1;
|
||||
current_command = command_list;
|
||||
while (current_command)
|
||||
{
|
||||
if (create_pipe_if_needed(current_command, &pipeline) == PIPE_ERROR)
|
||||
break ;
|
||||
pid = fork_process(current_command, minishell);
|
||||
if (pid == FORK_ERROR)
|
||||
break ;
|
||||
if (pid == 0)
|
||||
child_process(current_command, &pipeline, minishell);
|
||||
parent_cleanup(current_command, &pipeline);
|
||||
current_command = current_command->next;
|
||||
}
|
||||
exit_status = wait_for_children();
|
||||
ft_lstclear(&command_list, (void (*)(void *))cmdfree);
|
||||
return (exit_status);
|
||||
}
|
||||
|
||||
16
src/main.c
16
src/main.c
@@ -3,14 +3,15 @@
|
||||
/* ::: :::::::: */
|
||||
/* main.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: padan-pe <padan-pe@student.42.fr> +#+ +:+ +#+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/10/20 16:34:42 by sede-san #+# #+# */
|
||||
/* Updated: 2025/10/23 17:10:17 by padan-pe ### ########.fr */
|
||||
/* Updated: 2026/02/09 18:46:21 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "minishell.h"
|
||||
#include "core.h"
|
||||
|
||||
int main(
|
||||
int argc,
|
||||
@@ -18,19 +19,14 @@ int main(
|
||||
char **envp
|
||||
){
|
||||
t_minishell minishell;
|
||||
u_int8_t exit_status;
|
||||
|
||||
if (argc != 1 || argv[1] || !envp)
|
||||
{
|
||||
printf("Usage: ./minishell\n");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
if (!minishell_init(&minishell, envp))
|
||||
{
|
||||
printf("Error: %s\n", "failed to initialize minishell");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
exit_status = minishell_run(&minishell);
|
||||
minishell_init(&minishell, envp);
|
||||
minishell_run(&minishell);
|
||||
minishell_clear(&minishell);
|
||||
return (exit_status);
|
||||
return (minishell.exit_status);
|
||||
}
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/10/20 20:51:33 by sede-san #+# #+# */
|
||||
/* Updated: 2025/12/01 19:02:18 by sede-san ### ########.fr */
|
||||
/* Updated: 2026/02/09 18:48:34 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "minishell.h"
|
||||
#include "core.h"
|
||||
#include "parser.h"
|
||||
#include "executor.h"
|
||||
|
||||
int minishell_init(
|
||||
void minishell_init(
|
||||
t_minishell *minishell,
|
||||
char **envp
|
||||
){
|
||||
@@ -20,32 +23,34 @@ int minishell_init(
|
||||
set_envp(envp, minishell);
|
||||
set_builtins(minishell);
|
||||
if (minishell->variables.environment == NULL || minishell->builtins == NULL)
|
||||
{
|
||||
minishell_clear(minishell);
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
u_int8_t minishell_run(
|
||||
void minishell_run(
|
||||
t_minishell *minishell
|
||||
){
|
||||
char *line;
|
||||
t_command command;
|
||||
char *line;
|
||||
t_list *commands;
|
||||
|
||||
line = NULL;
|
||||
while (minishell->exit == 0)
|
||||
if (minishell == NULL)
|
||||
{
|
||||
line = readline("minishell > ");
|
||||
if (*line)
|
||||
{
|
||||
add_history(line);
|
||||
command = parse(line, minishell);
|
||||
execute(command, minishell);
|
||||
}
|
||||
ft_free((void **)&line);
|
||||
minishell->exit_status = EXIT_FAILURE;
|
||||
return ;
|
||||
}
|
||||
while (!minishell->exit)
|
||||
{
|
||||
line = readline(DEFAULT_PS1);
|
||||
if (line != NULL)
|
||||
{
|
||||
if (*line != '\0')
|
||||
{
|
||||
add_history(line);
|
||||
commands = parse(line, minishell);
|
||||
execute(commands, minishell);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
}
|
||||
return (minishell->exit_status);
|
||||
}
|
||||
|
||||
void minishell_clear(
|
||||
@@ -56,5 +61,4 @@ void minishell_clear(
|
||||
ft_hashmap_clear(&minishell->variables.environment, free);
|
||||
if (minishell->builtins != NULL)
|
||||
ft_hashmap_clear_keys(&minishell->builtins);
|
||||
ft_bzero(minishell, sizeof(t_minishell));
|
||||
}
|
||||
|
||||
79
src/parser/lexer.c
Normal file
79
src/parser/lexer.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* lexer.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/02/09 18:56:41 by sede-san #+# #+# */
|
||||
/* Updated: 2026/02/09 20:42:50 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "core.h"
|
||||
#include "parser.h"
|
||||
|
||||
static t_token *tokenize(const char *line, size_t *start);
|
||||
static t_token_type get_token_type(const char *str);
|
||||
|
||||
t_list *lex(
|
||||
const char *line
|
||||
) {
|
||||
t_list *tokens;
|
||||
t_token *token;
|
||||
size_t i;
|
||||
|
||||
tokens = NULL;
|
||||
i = 0;
|
||||
while (line[i] != '\0')
|
||||
{
|
||||
// ignore spaces
|
||||
while (ft_isspace(line[i]))
|
||||
i++;
|
||||
// create token
|
||||
token = tokenize(line, &i);
|
||||
// add token to list
|
||||
if (token != NULL)
|
||||
ft_lstadd_back(&tokens, ft_lstnew(token));
|
||||
}
|
||||
return (tokens);
|
||||
}
|
||||
|
||||
static t_token *tokenize(const char *line, size_t *start) {
|
||||
t_token *token;
|
||||
t_token_type type;
|
||||
|
||||
token = NULL;
|
||||
if (line == NULL || line[*start] == '\0')
|
||||
return (NULL);
|
||||
type = get_token_type(line + *start);
|
||||
(void)type;
|
||||
// if (type != TOKEN_WORD)
|
||||
// token = token_new(type, NULL);
|
||||
// else
|
||||
// token = read_word(line, start);
|
||||
// if (token == NULL)
|
||||
// (*start) += ft_strlen(token->value);
|
||||
return (token);
|
||||
}
|
||||
|
||||
static t_token_type get_token_type(const char *str)
|
||||
{
|
||||
size_t i;
|
||||
static const t_map_entry tokens[TOKENS_COUNT] = {
|
||||
{PIPE_STR, (void *)TOKEN_PIPE},
|
||||
{REDIRECT_IN_STR, (void *)TOKEN_REDIRECT_IN},
|
||||
{REDIRECT_OUT_STR, (void *)TOKEN_REDIRECT_OUT},
|
||||
{APPEND_STR, (void *)TOKEN_APPEND},
|
||||
{HEREDOC_STR, (void *)TOKEN_HEREDOC}
|
||||
};
|
||||
|
||||
i = 0;
|
||||
while (i < TOKENS_COUNT)
|
||||
{
|
||||
if (ft_strcmp(str, tokens[i].key) == 0)
|
||||
return ((t_token_type)tokens[i].value);
|
||||
i++;
|
||||
}
|
||||
return (TOKEN_WORD);
|
||||
}
|
||||
@@ -6,73 +6,295 @@
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/10/22 18:37:38 by sede-san #+# #+# */
|
||||
/* Updated: 2025/10/23 22:53:35 by sede-san ### ########.fr */
|
||||
/* Updated: 2026/02/09 18:50:43 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "minishell.h"
|
||||
#include "parser.h"
|
||||
|
||||
static char **expand_envs(char **argv);
|
||||
static int count_argv(char **argv);
|
||||
// parse exclusive
|
||||
static char *extract_next_command(char *line, size_t *index);
|
||||
static char *trim_whitespaces(char *line, size_t *start, size_t *end);
|
||||
// static void set_pipes(t_list *commands);
|
||||
|
||||
char *parse(
|
||||
// common
|
||||
static void find_boundary(char *line, size_t *index, char bound_char);
|
||||
|
||||
// command exclusive
|
||||
static t_command *cmdnew(char *line, t_minishell *minishell);
|
||||
static void set_argv(t_command *command, char *line, t_minishell *minishell);
|
||||
static void expand_envs(char *arg, t_minishell *minishell);
|
||||
static char **lst_to_argv(t_list *argv_list);
|
||||
static void set_argc(t_command *command);
|
||||
static void set_infile(t_command *command);
|
||||
static void set_outfile(t_command *command);
|
||||
static void set_path(t_command *command, t_minishell *minishell);
|
||||
static u_int8_t path_is_solved(char *cmd_name, t_minishell *msh);
|
||||
static char *solve_path(char *command_name, t_minishell *minishell);
|
||||
|
||||
t_list *parse(
|
||||
char *line,
|
||||
t_minishell *minishell
|
||||
){
|
||||
t_command command;
|
||||
) {
|
||||
t_list *commands;
|
||||
t_list *tokens;
|
||||
t_command *command;
|
||||
char *command_str;
|
||||
size_t i;
|
||||
|
||||
if (!line || !*line)
|
||||
if (line == NULL)
|
||||
return (NULL);
|
||||
(void)minishell;
|
||||
command.argv = expand_envs(ft_split(line, SPACE));
|
||||
command.argc = count_argv(command.argv);
|
||||
if (!command.argc)
|
||||
return (NULL);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//* DEBUG
|
||||
// int i = -1;
|
||||
// while (command.argv[++i])
|
||||
// printf("argv[%i]: %s\n", i, command.argv[i]);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
commands = NULL;
|
||||
i = 0;
|
||||
while (line[i] != '\0')
|
||||
{
|
||||
tokens = tokenize();
|
||||
command_str = extract_next_command(line, &i);
|
||||
if (command_str != NULL)
|
||||
{
|
||||
command = cmdnew(command_str, minishell);
|
||||
free(command_str);
|
||||
if (command != NULL)
|
||||
ft_lstadd_back(&commands, ft_lstnew(command));
|
||||
}
|
||||
}
|
||||
// set_pipes(commands);
|
||||
return (commands);
|
||||
}
|
||||
|
||||
// static void set_pipes(
|
||||
// t_list *commands
|
||||
// ) {
|
||||
// t_list *current_command;
|
||||
// t_list *previous_command;
|
||||
// t_list *next_command;
|
||||
// t_command *command;
|
||||
|
||||
// previous_command = NULL;
|
||||
// current_command = commands;
|
||||
// while (current_command != NULL)
|
||||
// {
|
||||
// command = (t_command *)current_command->content;
|
||||
// if (previous_command != NULL)
|
||||
// command->piped_from = (t_command *)previous_command->content;
|
||||
// next_command = current_command->next;
|
||||
// if (next_command != NULL)
|
||||
// command->piped_to = (t_command *)next_command->content;
|
||||
// previous_command = current_command;
|
||||
// current_command = current_command->next;
|
||||
// }
|
||||
// }
|
||||
|
||||
static char *extract_next_command(
|
||||
char *line,
|
||||
size_t *index
|
||||
) {
|
||||
char *command_str;
|
||||
size_t start;
|
||||
size_t end;
|
||||
|
||||
start = *index;
|
||||
find_boundary(line, index, '|');
|
||||
end = *index;
|
||||
command_str = trim_whitespaces(line, &start, &end);
|
||||
while (line[*index] == '|' || ft_isspace(line[*index]))
|
||||
(*index)++;
|
||||
return (command_str);
|
||||
}
|
||||
|
||||
static void find_boundary(
|
||||
char *line,
|
||||
size_t *index,
|
||||
char bound_char
|
||||
) {
|
||||
bool in_single_quote;
|
||||
bool in_double_quote;
|
||||
|
||||
in_single_quote = false;
|
||||
in_double_quote = false;
|
||||
while (line[*index] != '\0')
|
||||
{
|
||||
if (line[*index] == '\'' && !in_double_quote)
|
||||
in_single_quote = !in_single_quote;
|
||||
else if (line[*index] == '"' && !in_single_quote)
|
||||
in_double_quote = !in_double_quote;
|
||||
if (line[*index] == bound_char && !in_single_quote && !in_double_quote)
|
||||
break ;
|
||||
(*index)++;
|
||||
}
|
||||
}
|
||||
|
||||
static char *trim_whitespaces(
|
||||
char *line,
|
||||
size_t *start,
|
||||
size_t *end
|
||||
) {
|
||||
while (*start < *end && ft_isspace(line[*start]))
|
||||
(*start)++;
|
||||
while (*end > *start && ft_isspace(line[*end - 1]))
|
||||
(*end)--;
|
||||
if (*end > *start)
|
||||
return (ft_substr(line, *start, *end - *start));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static char **expand_envs(
|
||||
char **argv
|
||||
){
|
||||
int i;
|
||||
char *env;
|
||||
static t_command *cmdnew(
|
||||
char *line,
|
||||
t_minishell *minishell
|
||||
) {
|
||||
t_command *command;
|
||||
|
||||
if (!argv)
|
||||
command = (t_command *)ft_calloc(1, sizeof(t_command));
|
||||
if (!command)
|
||||
return (NULL);
|
||||
else if (!*argv) // check if ft_split returned and empty matrix
|
||||
// resolve_heredoc
|
||||
set_argv(command, line, minishell);
|
||||
if (!command->argv)
|
||||
{
|
||||
ft_free_split(argv);
|
||||
free(command);
|
||||
return (NULL);
|
||||
}
|
||||
i = -1;
|
||||
while (argv[++i])
|
||||
set_argc(command);
|
||||
set_infile(command);
|
||||
set_outfile(command);
|
||||
set_path(command, minishell);
|
||||
return (command);
|
||||
}
|
||||
|
||||
static void set_argv(
|
||||
t_command *command,
|
||||
char *line,
|
||||
t_minishell *minishell
|
||||
) {
|
||||
t_list *argv_list;
|
||||
char *arg;
|
||||
size_t i;
|
||||
size_t start;
|
||||
size_t end;
|
||||
|
||||
if (line == NULL)
|
||||
return ;
|
||||
i = 0;
|
||||
argv_list = NULL;
|
||||
while (line[i] != '\0')
|
||||
{
|
||||
if (!ft_strchr(argv[i], DOLLAR)
|
||||
|| (ft_strchr(argv[i], DOLLAR) && ft_strchr(argv[i], SINGLE_QUOTE) && ft_strchr(argv[i] + (ft_strchr(argv[i], SINGLE_QUOTE) + 1 - argv[i]), SINGLE_QUOTE))) // env is surrounded by single quote
|
||||
continue ;
|
||||
env = getenv(ft_strchr(argv[i], DOLLAR) + 1);
|
||||
free(argv[i]);
|
||||
if (env)
|
||||
argv[i] = ft_strdup(env);
|
||||
else
|
||||
argv[i] = ft_strdup("");
|
||||
start = i;
|
||||
find_boundary(line, &i, ' ');
|
||||
end = i;
|
||||
arg = trim_whitespaces(line, &start, &end);
|
||||
expand_envs(arg, minishell);
|
||||
if (arg != NULL)
|
||||
ft_lstadd_back(&argv_list, ft_lstnew(arg));
|
||||
while (ft_isspace(line[i]))
|
||||
i++;
|
||||
}
|
||||
command->argv = lst_to_argv(argv_list);
|
||||
ft_lstclear(&argv_list, free);
|
||||
}
|
||||
|
||||
static void expand_envs(
|
||||
char *arg,
|
||||
t_minishell *minishell
|
||||
) {
|
||||
// TODO
|
||||
(void)arg;
|
||||
(void)minishell;
|
||||
}
|
||||
|
||||
static char **lst_to_argv(
|
||||
t_list *argv_list
|
||||
) {
|
||||
char **argv;
|
||||
t_list *current_arg;
|
||||
size_t i;
|
||||
|
||||
argv = (char **)ft_calloc(ft_lstsize(argv_list) + 1, sizeof(char *));
|
||||
if (!argv)
|
||||
return (NULL);
|
||||
i = 0;
|
||||
current_arg = argv_list;
|
||||
while (current_arg != NULL)
|
||||
{
|
||||
argv[i] = ft_strdup((char *)current_arg->content);
|
||||
i++;
|
||||
current_arg = current_arg->next;
|
||||
}
|
||||
return (argv);
|
||||
}
|
||||
|
||||
static int count_argv(
|
||||
char **argv
|
||||
){
|
||||
int i;
|
||||
static void set_argc(
|
||||
t_command *command
|
||||
) {
|
||||
int argc;
|
||||
|
||||
i = 0;
|
||||
while (argv[i])
|
||||
i++;
|
||||
return (i);
|
||||
argc = 0;
|
||||
while (command->argv[argc] != NULL)
|
||||
argc++;
|
||||
command->argc = argc;
|
||||
}
|
||||
|
||||
static void set_infile(
|
||||
t_command *command
|
||||
) {
|
||||
// test_infile
|
||||
command->infile = -1;
|
||||
}
|
||||
|
||||
static void set_outfile(
|
||||
t_command *command
|
||||
) {
|
||||
// test_outfile
|
||||
command->outfile = STDOUT_FILENO;
|
||||
}
|
||||
|
||||
static void set_path(
|
||||
t_command *command,
|
||||
t_minishell *minishell
|
||||
) {
|
||||
char *command_path;
|
||||
char *command_name;
|
||||
|
||||
command_name = command->argv[0];
|
||||
if (!path_is_solved(command_name, minishell))
|
||||
command_path = solve_path(command_name, minishell);
|
||||
else
|
||||
command_path = ft_strdup(command_name);
|
||||
command->path = command_path;
|
||||
}
|
||||
|
||||
static char *solve_path(
|
||||
char *command_name,
|
||||
t_minishell *minishell
|
||||
){
|
||||
char *command_path;
|
||||
char **path_env;
|
||||
size_t i;
|
||||
|
||||
path_env = ft_split(get_env("PATH", minishell), ':');
|
||||
if (!path_env)
|
||||
return (NULL);
|
||||
command_path = NULL;
|
||||
i = -1;
|
||||
while (!command_path && path_env[++i])
|
||||
{
|
||||
command_path = ft_strnjoin(3, path_env[i], "/", command_name);
|
||||
if (command_path != NULL && access(command_path, F_OK) != EXIT_SUCCESS)
|
||||
{
|
||||
free(command_path);
|
||||
command_path = NULL;
|
||||
}
|
||||
}
|
||||
ft_free_split(path_env);
|
||||
return (command_path);
|
||||
}
|
||||
|
||||
static u_int8_t path_is_solved(
|
||||
char *command_name,
|
||||
t_minishell *minishell
|
||||
){
|
||||
return (ft_strncmp(command_name, "/", 1) == 0
|
||||
|| (command_name[1] && ft_strncmp(command_name, "./", 2) == 0)
|
||||
|| (command_name[2] && ft_strncmp(command_name, "../", 3) == 0)
|
||||
|| is_builtin(command_name, minishell)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2025/12/01 09:12:39 by sede-san #+# #+# */
|
||||
/* Updated: 2025/12/01 17:27:57 by sede-san ### ########.fr */
|
||||
/* Updated: 2026/02/08 19:44:15 by sede-san ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "minishell.h"
|
||||
#include "core.h"
|
||||
|
||||
/**
|
||||
* @brief Parses and stores environment variables from envp array into a hashmap
|
||||
@@ -117,8 +118,7 @@ char **get_envp(
|
||||
size_t i;
|
||||
|
||||
env_list = ft_hashmap_entries(msh->variables.environment);
|
||||
envp = (char **)malloc(
|
||||
(msh->variables.environment->size + 1) * sizeof(char *));
|
||||
envp = (char **)malloc((msh->variables.environment->size + 1) * sizeof(char *));
|
||||
if (envp != NULL)
|
||||
{
|
||||
i = 0;
|
||||
|
||||
Reference in New Issue
Block a user