Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] Implement builtin of exit #99

Merged
merged 12 commits into from
Jan 21, 2024
17 changes: 14 additions & 3 deletions include/builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,19 @@

# include "defines.h"

int ft_exec_env(t_shell *shell);
int ft_exec_echo(char **args);
int ft_exec_pwd(void);
typedef enum e_exit_args_error
{
NO_ARGS = -1,
NORM_ARGS = 0,
TOO_MANY_ARGS,
NOT_NUMERIC,
} t_exit_args_error;

int ft_exec_env(t_shell *shell);
int ft_exec_echo(char **args);
int ft_exec_pwd(void);
void exec_exit(t_shell *shell, t_final_cmd_table *final_cmd_table);

int get_args_error(char **args);

#endif
74 changes: 40 additions & 34 deletions include/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

# include <fcntl.h>
# include <linux/limits.h>
# include <limits.h>
# include <sysexits.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <unistd.h>
Expand All @@ -32,60 +34,60 @@
/* Error codes */
# define SUCCESS 0
# define EXIT_SUCCESS 0
# define GENERAL_ERROR 1

# define BAD_SUBSTITUTION 2
// # define EXPAND_ERROR 2
# define MISUSE_BUILTIN 2
# define CMD_EXEC_FAILED 126
# define CMD_NOT_FOUND 127
# define TERM_BY_SIGNAL 128
# define UNEXPECT_EXIT 128
# define TERM_BY_SIGNAL 128
# define EXIT_SIGTERM 130
# define PREPROCESS_ERROR 195
# define SUBSHELL_ERROR 196

/* Parsing Table */
# define PT_COL_SIZE 5
# define PT_ROW_SIZE 191
# define UNDEFINED_TYPE -99
# define UNDEFINED_STATE -1

# define STY_BLD "\e[1m"
# define STY_UND "\e[4m"
# define STY_RED "\e[31m"
# define STY_GRN "\e[32m"
# define STY_YEL "\e[33m"
# define STY_BLU "\e[34m"
# define STY_MAG "\e[35m"
# define STY_CYN "\e[36m"
# define STY_WHT "\e[37m"
# define STY_GRY "\e[90m"
# define STY_HWHT "\e[97m"
# define STY_BLKB "\e[41m"
# define STY_REDB "\e[41m"
# define STY_GRNB "\e[42m"
# define STY_YELB "\e[43m"
# define STY_BLUB "\e[44m"
# define STY_MAGB "\e[45m"
# define STY_CYNB "\e[46m"
# define STY_WHTB "\e[47m"
# define STY_GRYB "\e[100m"
# define STY_HWHTB "\e[107m"
# define STY_RES "\e[0m"

# define STY_BLD "\e[1m"
# define STY_UND "\e[4m"
# define STY_RED "\e[31m"
# define STY_GRN "\e[32m"
# define STY_YEL "\e[33m"
# define STY_BLU "\e[34m"
# define STY_MAG "\e[35m"
# define STY_CYN "\e[36m"
# define STY_WHT "\e[37m"
# define STY_GRY "\e[90m"
# define STY_HWHT "\e[97m"
# define STY_BLKB "\e[41m"
# define STY_REDB "\e[41m"
# define STY_GRNB "\e[42m"
# define STY_YELB "\e[43m"
# define STY_BLUB "\e[44m"
# define STY_MAGB "\e[45m"
# define STY_CYNB "\e[46m"
# define STY_WHTB "\e[47m"
# define STY_GRYB "\e[100m"
# define STY_HWHTB "\e[107m"
# define STY_RES "\e[0m"
// TODO: Remove the color codes from the prompt before the evaluations
# define PROMPT "\e[1;34m🌊rash$ \e[0m"
// # define PROMPT "\e[1;32mminishell$ \e[0m"
# define PROMPT "\e[1;34m🌊rash$ \e[0m"
// # define PROMPT "\e[1;32mminishell$ \e[0m"
# define HEREDOC_PROMPT "\e[1;37m> \e[0m"
// # define PROMPT "\001\033[1;32m\002minishell$ \001\033[0m\002"
// # define PROMPT "minishell$ "
// # define PROMPT "\001\033[1;32m\002minishell$ \001\033[0m\002"
// # define PROMPT "minishell$ "

/* Lexer */
# define QUOTES "'\""
# define TOK_SYMBOLS "<>|&()"
# define T_UNINITIALIZED -1 //TODO Replace with Lea's UNDEFINED_TYPE -99

/* Expander */
# define OPENING_BRACE '{'
# define CLOSING_BRACE '}'
# define OPENING_BRACE '{'
# define CLOSING_BRACE '}'

/* Error Messages */
// TODO Add minishell name in the front of messages
Expand All @@ -95,10 +97,14 @@
"%s: warning: here-document delimited by end-of-file (wanted `%s')\n"
# define ERROR_EXPANDER_BAD_SUBSTITUTION \
"%s: %s: bad substitution\n"
# define ERROR_EXIT_TOO_MANY_ARGS \
"%s: %s: too many arguments\n"
# define ERROR_EXIT_NUMERIC_ARG \
"%s: %s: %s: numeric argument required\n"

// TODO: Replace with OS error message
# define ERROR_REMOVE_FILE "%s: \
warning: failed to remove file `%s'\n"
# define ERROR_REMOVE_FILE \
"%s: warning: failed to remove file `%s'\n"

extern const int g_parsing_table[][PT_COL_SIZE];

Expand Down
9 changes: 5 additions & 4 deletions source/backend/executor/executor.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void handle_cmd_execution(t_shell *shell, t_list_d **cmd_table_node)
final_cmd_table = get_final_cmd_table(shell, (*cmd_table_node)->content);
if (!final_cmd_table)
ft_clean_and_exit_shell(
shell, GENERAL_ERROR, "final cmd table malloc failed");
shell, PREPROCESS_ERROR, "final cmd table malloc failed");
if (is_builtin(final_cmd_table->simple_cmd[0]) && \
!is_scmd_in_pipeline(*cmd_table_node))
{
Expand Down Expand Up @@ -54,15 +54,16 @@ void handle_process(t_shell *shell, t_list_d *cmd_table_node)
else if (cmd_table->type == C_SUBSHELL_START)
handle_pipeline(shell, &cmd_table_node);
else
ft_clean_and_exit_shell(
shell, GENERAL_ERROR, "handle process, unknown command type");
ft_clean_and_exit_shell(shell,
PREPROCESS_ERROR, "handle process, unknown command type");
}
}

// TODO: activate signal listener in the child process
void ft_executor(t_shell *shell)
{
if (!ft_heredoc(shell->cmd_table_list))
ft_clean_and_exit_shell(shell, GENERAL_ERROR, "heredoc malloc failed");
ft_clean_and_exit_shell(
shell, PREPROCESS_ERROR, "heredoc malloc failed");
handle_process(shell, shell->cmd_table_list);
}
2 changes: 1 addition & 1 deletion source/backend/executor/handle_builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ void exec_builtin_cmd(t_shell *shell, t_final_cmd_table *final_cmd_table)
else if (ft_strcmp(final_cmd_table->simple_cmd[0], "export") == 0)
shell->exit_code = 123;
else if (ft_strcmp(final_cmd_table->simple_cmd[0], "exit") == 0)
shell->exit_code = 123;
exec_exit(shell, final_cmd_table);
}

void handle_builtin(t_shell *shell,
Expand Down
2 changes: 1 addition & 1 deletion source/backend/executor/handle_pipeline.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void handle_pipeline(t_shell *shell, t_list_d **cmd_table_node)
shell->subshell_pid = fork();
if (shell->subshell_pid == -1)
ft_clean_and_exit_shell(
shell, GENERAL_ERROR, "handle_pipeline, fork failed");
shell, SUBSHELL_ERROR, "handle_pipeline, fork failed");
else if (shell->subshell_pid == 0)
{
shell->subshell_level += 1;
Expand Down
4 changes: 2 additions & 2 deletions source/backend/executor/handle_simple_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ void exec_simple_cmd(t_shell *shell, t_list_d **cmd_table_node)
final_cmd_table = get_final_cmd_table(shell, cmd_table);
if (!final_cmd_table)
ft_clean_and_exit_shell(
shell, GENERAL_ERROR, "get_final_cmd_table failed");
shell, SUBSHELL_ERROR, "get_final_cmd_table failed");
print_final_cmd_table(final_cmd_table);
if (final_cmd_table->simple_cmd[0] == NULL)
printf("\n");
Expand All @@ -59,7 +59,7 @@ void handle_simple_cmd(t_shell *shell, t_list_d **cmd_table_node)
shell->subshell_pid = fork();
if (shell->subshell_pid == -1)
ft_clean_and_exit_shell(
shell, GENERAL_ERROR, "handle_simple_cmd, fork failed");
shell, SUBSHELL_ERROR, "handle_simple_cmd, fork failed");
else if (shell->subshell_pid == 0)
{
shell->subshell_level += 1;
Expand Down
2 changes: 1 addition & 1 deletion source/backend/executor/handle_subshell.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void handle_subshell(t_shell *shell, t_list_d **cmd_table_node)
{
shell->subshell_pid = fork();
if (shell->subshell_pid == -1)
ft_clean_and_exit_shell(shell, GENERAL_ERROR, "subshell fork failed");
ft_clean_and_exit_shell(shell, SUBSHELL_ERROR, "subshell fork failed");
else if (shell->subshell_pid == 0)
{
shell->subshell_level += 1;
Expand Down
37 changes: 37 additions & 0 deletions source/builtins/exit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "builtins.h"
#include "utils.h"
#include "clean.h"

void handle_exit(
t_shell *shell, t_final_cmd_table *final_cmd_table, int args_error)
{
if (shell->subshell_level == 0)
printf("exit\n");
if (args_error == TOO_MANY_ARGS)
{
ft_dprintf(2, ERROR_EXIT_TOO_MANY_ARGS, PROGRAM_NAME, "exit");
if (shell->subshell_level == 0)
return ;
}
else if (args_error == NOT_NUMERIC)
ft_dprintf(2, ERROR_EXIT_NUMERIC_ARG,
PROGRAM_NAME, "exit", final_cmd_table->simple_cmd[1]);
free_final_cmd_table(&final_cmd_table);
ft_clean_and_exit_shell(shell, shell->exit_code, NULL);
}

void exec_exit(t_shell *shell, t_final_cmd_table *final_cmd_table)
{
int args_error;
char **args;

args = &final_cmd_table->simple_cmd[1];
args_error = get_args_error(args);
if (args_error == NO_ARGS)
shell->exit_code = SUCCESS;
else if (args_error == NORM_ARGS)
shell->exit_code = (ft_atol(args[0])) % 256;
else
shell->exit_code = args_error;
handle_exit(shell, final_cmd_table, args_error);
}
76 changes: 76 additions & 0 deletions source/builtins/exit_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include "defines.h"
#include "utils.h"
#include "builtins.h"

bool is_sign(char c)
{
if (c == '+' || c == '-')
return (true);
return (false);
}

bool valid_number(char *str)
{
int i;

if (!str)
return (false);
i = 0;
if (ft_strlen(str) > 1 && is_sign(str[i]))
i++;
while (str[i])
{
if (ft_isdigit(str[i]))
i++;
itislu marked this conversation as resolved.
Show resolved Hide resolved
else
return (false);
}
return (true);
}

bool is_atol_overflow(char *str)
{
int i;
char *long_max;

i = 0;
if (str[i] == '-')
long_max = "9223372036854775808";
else
long_max = "9223372036854775807";
if (is_sign(str[i]))
i++;
while (str[i] == '0')
i++;
if (ft_strlen(&str[i]) < ft_strlen(long_max) || \
ft_strcmp(&str[i], long_max) <= 0)
return (false);
return (true);
}

int get_args_error(char **args)
{
int type;
// int i;

if (!*args)
return (NO_ARGS);
type = NORM_ARGS;
if (!valid_number(args[0]) || is_atol_overflow(args[0]))
type = NOT_NUMERIC;
else if (get_array_len(args) > 1)
{
type = TOO_MANY_ARGS;
// i = 1;
// while (args[i])
// {
// if (!valid_number(args[i]) || is_overflow(args[i]))
// {
// type = NOT_NUMERIC;
// break ;
// }
// i++;
// }
}
return (type);
}
2 changes: 1 addition & 1 deletion source/debug/print_expanded_cmd_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ bool expand_and_print(char *str, t_shell *shell)

expanded_list = NULL;
ret = ft_expander(str, &expanded_list, shell);
if (ret == GENERAL_ERROR)
if (ret == SUBSHELL_ERROR)
return (printf("malloc failed in expander"), false);
if (ret == BAD_SUBSTITUTION)
printf(STY_RED "Bad substitution." STY_RES);
Expand Down
8 changes: 4 additions & 4 deletions source/frontend/expander/expander.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,16 @@ int ft_expander(char *str, t_list **lst, t_shell *shell)
return (BAD_SUBSTITUTION);
dup = ft_strdup(str);
if (!dup)
return (GENERAL_ERROR);
return (SUBSHELL_ERROR);
if (!parameter_expansion(&dup, shell))
return (free(dup), GENERAL_ERROR);
return (free(dup), SUBSHELL_ERROR);
if (!*dup)
return (free(dup), SUCCESS);
if (!quote_removal(&dup))
return (free(dup), GENERAL_ERROR);
return (free(dup), SUBSHELL_ERROR);
// TODO: Potentially split into multiple nodes by whitespace here.
// The keyword in the bash manual is "Word Splitting".
if (!ft_lstnew_back(lst, dup))
return (free(dup), GENERAL_ERROR);
return (free(dup), SUBSHELL_ERROR);
return (SUCCESS);
}
6 changes: 3 additions & 3 deletions source/frontend/lexer/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ bool ft_lexer(t_shell *shell)
if (!create_token_data_list(&token_data_list, shell->input_line))
{
ft_lstclear(&token_data_list, free);
ft_clean_and_exit_shell(shell, GENERAL_ERROR, "lexer malloc failed");
ft_clean_and_exit_shell(shell, PREPROCESS_ERROR, "lexer malloc failed");
}
if (!token_data_list)
return (false);
if (!create_token_list(&shell->token_list, &token_data_list))
{
ft_lstclear(&token_data_list, free);
ft_clean_and_exit_shell(shell, GENERAL_ERROR, "lexer malloc failed");
ft_clean_and_exit_shell(shell, PREPROCESS_ERROR, "lexer malloc failed");
}
set_token_type(shell->token_list);
finetune_token_list(shell->token_list);
if (!add_end_node(&shell->token_list))
ft_clean_and_exit_shell(shell, GENERAL_ERROR, "lexer malloc failed");
ft_clean_and_exit_shell(shell, PREPROCESS_ERROR, "lexer malloc failed");
return (true);
}
Loading
Loading