commit 03b080ed9246d13112ad247597c3f25eb84abfd1 Author: root Date: Sat Nov 15 22:28:42 2025 +0000 intra to gitea diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..d9cf0b0 --- /dev/null +++ b/Makefile @@ -0,0 +1,143 @@ +# **************************************************************************** # +# # +# ::: :::::::: # +# Makefile :+: :+: :+: # +# +:+ +:+ +:+ # +# By: tordner +#+ +:+ +#+ # +# +#+#+#+#+#+ +#+ # +# Created: 2025/01/29 17:32:15 by thorgal #+# #+# # +# Updated: 2025/06/03 04:09:04 by tordner ### ########.fr # +# # +# **************************************************************************** # + +NAME = minishell + +CC = cc + +CFLAGS = -pthread -Iincludes -Wall -Wextra -Wextra + +SRCDIR = src +LIBFT = libft.a +OBJDIR = obj + +INCDIR = includes + +SRCS = $(SRCDIR)/main/main.c \ + $(SRCDIR)/main/shell.c \ + $(SRCDIR)/main/signals.c \ + $(SRCDIR)/main/signals_utils.c \ + $(SRCDIR)/utils/utils.c \ + $(SRCDIR)/main/prompt.c \ + $(SRCDIR)/exec/execute_pipeline.c \ + $(SRCDIR)/utils/free.c \ + $(SRCDIR)/utils/get_env_value.c \ + $(SRCDIR)/main/input.c \ + $(SRCDIR)/tokens/tokens.c \ + $(SRCDIR)/tokens/handle_quoted_count.c \ + $(SRCDIR)/tokens/extract_quoted_content.c \ + $(SRCDIR)/tokens/tokens_utils.c \ + $(SRCDIR)/tokens/syntax.c \ + $(SRCDIR)/tokens/check_pipes.c \ + $(SRCDIR)/tokens/check_redirections.c \ + $(SRCDIR)/tokens/token_list.c \ + $(SRCDIR)/builtins/echo.c \ + $(SRCDIR)/builtins/cd.c \ + $(SRCDIR)/builtins/cd_utils.c \ + $(SRCDIR)/builtins/pwd.c \ + $(SRCDIR)/builtins/env.c \ + $(SRCDIR)/builtins/export.c \ + $(SRCDIR)/builtins/unset.c \ + $(SRCDIR)/exec/exec.c \ + $(SRCDIR)/exec/file_handler.c \ + $(SRCDIR)/exec/get_env.c \ + $(SRCDIR)/exec/heredoc.c \ + $(SRCDIR)/exec/pipe.c \ + $(SRCDIR)/tokens/tokens_list2.c \ + $(SRCDIR)/tokens/tokens_utils2.c \ + $(SRCDIR)/tokens/tokenize_command.c \ + $(SRCDIR)/tokens/extract_token_len.c \ + $(SRCDIR)/builtins/export_utils.c \ + $(SRCDIR)/builtins/export_utils2.c \ + $(SRCDIR)/builtins/exit.c \ + $(SRCDIR)/exec/exec_utils.c \ + $(SRCDIR)/exec/setup_files.c \ + $(SRCDIR)/exec/execute_ve.c \ + $(SRCDIR)/exec/ft_exec.c \ + $(SRCDIR)/exec/setup_output_redirections.c \ + $(SRCDIR)/tokens/expander.c \ + $(SRCDIR)/builtins/exit_utils.c \ + $(SRCDIR)/builtins/export_utils_3.c + +OBJS = $(SRCS:$(SRCDIR)/%.c=$(OBJDIR)/%.o) + +OBJSUBDIRS = $(sort $(dir $(OBJS))) + +GREEN = \033[0;32m +YELLOW = \033[0;33m +CYAN = \033[0;36m +RESET = \033[0m +BOLD = \033[1m +WHITE = \033[0;97m +BLUE = \033[0;34m + +LOADING_CHARS = ⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏ + +define MINISHELL_ART + + ███▄ ▄███▓ ██▓ ███▄ █ ██▓ ██████ ██░ ██ ▓█████ ██▓ ██▓ +▓██▒▀█▀ ██▒▓██▒ ██ ▀█ █ ▓██▒▒██ ▒ ▓██░ ██▒▓█ ▀ ▓██▒ ▓██▒ +▓██ ▓██░▒██▒▓██ ▀█ ██▒▒██▒░ ▓██▄ ▒██▀▀██░▒███ ▒██░ ▒██░ +▒██ ▒██ ░██░▓██▒ ▐▌██▒░██░ ▒ ██▒░▓█ ░██ ▒▓█ ▄ ▒██░ ▒██░ +▒██▒ ░██▒░██░▒██░ ▓██░░██░▒██████▒▒░▓█▒░██▓░▒████▒░██████▒░██████▒ +░ ▒░ ░ ░░▓ ░ ▒░ ▒ ▒ ░▓ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒░░ ▒░ ░░ ▒░▓ ░░ ▒░▓ ░ +░ ░ ░ ▒ ░░ ░░ ░ ▒░ ▒ ░░ ░▒ ░ ░ ▒ ░▒░ ░ ░ ░ ░░ ░ ▒ ░░ ░ ▒ ░ +░ ░ ▒ ░ ░ ░ ░ ▒ ░░ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ░ + ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ + +endef +export MINISHELL_ART + +all: print_art $(NAME) + +print_art: + @printf "$(CYAN)%s$(RESET)\n" "$$MINISHELL_ART" + +$(NAME): $(OBJS) + @$(MAKE) -s -C libft + @printf "$(BOLD)$(WHITE)Welcome to the $(BLUE)Minishell$(WHITE) compilation process.\nPlease hold on as we prepare your program.\n\n$(RESET)" + @printf "$(YELLOW)Compiling Minishell, Please wait...$(RESET)" + @for char in $(LOADING_CHARS); do \ + printf "\r$(YELLOW)Compiling Minishell, Please wait... $$char$(RESET)"; \ + sleep 0.1; \ + done + @$(CC) $(CFLAGS) $(OBJS) -o $(NAME) -g3 -lreadline libft/$(LIBFT) + @printf "\r$(GREEN)Nice ! $(WHITE)Minishell compiled successfully ! $(RESET)\n\n" + @printf "$(BOLD)$(WHITE)Compilation complete !\n$(BLUE)Minishell$(WHITE) is ready to use !\n$(RESET)" + +# Règle pour créer les fichiers objets +$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJSUBDIRS) + @$(CC) $(CFLAGS) -I $(INCDIR) -c $< -o $@ + +# Règle pour créer les sous-répertoires +$(OBJSUBDIRS): + @mkdir -p $@ + +clean: + @make clean -s -C libft + @rm -rf $(OBJDIR) + @printf "$(WHITE)Clean process completed for $(BLUE)Minishell.$(RESET)\n" + +clean1: + @rm -rf $(OBJDIR) + +fclean: clean1 + @make fclean -s -C libft + @rm -f $(NAME) + @printf "$(WHITE)Full clean process completed for $(BLUE)Minishell.$(RESET)\n" + +re: fclean all + +.PHONY: all clean fclean re clean1 print_art + +norminette: + norminette src/* includes/* | grep "Error" \ No newline at end of file diff --git a/includes/messages.h b/includes/messages.h new file mode 100644 index 0000000..554fb54 --- /dev/null +++ b/includes/messages.h @@ -0,0 +1,35 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* messages.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/11/21 15:38:19 by lfirmin #+# #+# */ +/* Updated: 2025/06/02 00:35:25 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef MESSAGES_H +# define MESSAGES_H + +# include "minishell.h" + +# define RED "\001\033[1;31m\002" +# define GREEN "\001\033[1;32m\002" +# define YELLOW "\001\033[1;33m\002" +# define BLUE "\001\033[1;34m\002" +# define MAGENTA "\001\033[1;35m\002" +# define CYAN "\001\033[1;36m\002" +# define RESET "\001\033[0m\002" + +# define WELCOME_MESS "Welcome to our MiniShell.\n" +# define ERROR_TOKEN "Error: Tokenization failed\n" +# define ERROR_NOT_FOUND "Command not found: %s\n" +# define PROMPT_GIT "➜\001\033[0m\002 \001\033[1;36m\002%s\001\033[0\ +m\002 \001\033[1;32m\002git:(\001\033[1;31m\002%s\001\033[1;\ +32m\002)\001\033[0m\002 ❯ " +# define PROMPT_STD "➜\001\033[0m\002 \001\033[1;36m\002%s\001\033[0m\002 ❯ " + +void debug_tokens(char **tokens); +#endif diff --git a/includes/minishell.h b/includes/minishell.h new file mode 100644 index 0000000..554bb40 --- /dev/null +++ b/includes/minishell.h @@ -0,0 +1,335 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* minishell.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/05 15:00:11 by thorgal #+# #+# */ +/* Updated: 2025/06/03 04:11:40 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef MINISHELL_H +# define MINISHELL_H + +//////////////////////////////////////////////////////////////// +////////////////////////////INCLUDES//////////////////////////// +//////////////////////////////////////////////////////////////// +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include "../libft/include/libft.h" +# include +# include +# include "messages.h" + +//////////////////////////////////////////////////////////////// +////////////////////////////GLOBALS///////////////////////////// +//////////////////////////////////////////////////////////////// +extern int g_signal; + +//////////////////////////////////////////////////////////////// +////////////////////////////ENUM//////////////////////////////// +//////////////////////////////////////////////////////////////// +typedef enum e_token_type +{ + TOKEN_WORD, + TOKEN_REDIRECTION_IN, + TOKEN_REDIRECTION_OUT, + TOKEN_APPEND, + TOKEN_HEREDOC, + TOKEN_PIPE +} t_token_type; + +//////////////////////////////////////////////////////////////// +////////////////////////////DATA//////////////////////////////// +//////////////////////////////////////////////////////////////// +typedef struct s_escape_handler +{ + char *input; + char *content; + int i; + int j; +} t_escape_handler; + +typedef struct s_redirection +{ + int type; + char *file; + struct s_redirection *next; +} t_redirection; + +typedef struct s_cmd +{ + char **args; + t_redirection *redir; + struct s_cmd *next; +} t_cmd; + +typedef struct s_shell +{ + char **env; + int exit_status; + int running; + int signaled; + int child_running; + int single_quoted_token; +} t_shell; + +//////////////////////////////////////////////////////////////// +////////////////////////////MAIN//////////////////////////////// +//////////////////////////////////////////////////////////////// + +//////////////////// +///////main.c/////// +//////////////////// +void initialize_shell(t_shell *shell, char **envp); +int execute_command(t_cmd *cmd, t_shell *shell); +int execute_builtin(t_cmd *cmd, t_shell *shell); +int is_builtin(char *cmd); +int main(void); + +//////////////////// +///////input.c////// +//////////////////// +char **parse_input(char *input, t_shell *shell); +void process_input(char *input, t_shell *shell); + +///////////////////// +///////shell.c/////// +///////////////////// +void minishell_loop(t_shell *shell); +void handle_input(char *input, t_shell *shell); +char *generate_prompt(t_shell *shell); +char *create_git_prompt(char *dir_name, int exit_status); +char *create_standard_prompt(char *dir_name, int exit_status); + +///////////////////// +///////signals.c///// +///////////////////// +void check_if_signal(t_shell *shell); +void handle_signal_parent(int num); +int sig_event(void); +void if_sigint(int sig); +void set_status_if_signal(t_shell *shell); +void set_signal_child(void); +void set_signal_parent_exec(void); +void set_signal_parent(void); + +///////////////////////////////////////////////////////////////// +////////////////////////////UTILS//////////////////////////////// +///////////////////////////////////////////////////////////////// + +//////////////////// +///////utils.c////// +//////////////////// +char *get_current_dir_name(void); +char *ft_get_env_var(char **env, char *var); +char **copy_env(char **envp); +int is_git_repository(void); +char *get_git_branch(void); + +//////////////////// +///////free.c/////// +//////////////////// +void *free_tokens(char **tokens, int count); + +///////////////////////////////////////////////////////////////// +////////////////////////////BULTINS////////////////////////////// +///////////////////////////////////////////////////////////////// + +/////////////////// +///////pwd.c/////// +/////////////////// +int ft_pwd(void); + +////////////////// +///////cd.c/////// +////////////////// +int handle_home_directory(t_shell *shell); +int handle_previous_directory(t_shell *shell); +int update_pwd_env(t_shell *shell); +char *resolve_env_variables(char *path, t_shell *shell); +char *expand_tilde(char *path, t_shell *shell); +int validate_cd_args(t_cmd *cmd, t_shell *shell); +char *resolve_cd_path(char *path, t_shell *shell); +int execute_cd_change(char *resolved_path); +int ft_cd(t_cmd *cmd, t_shell *shell); + +////////////////// +///////env.c////// +////////////////// +int ft_env(t_shell *shell, t_cmd *cmd); + +////////////////// +///////export.c/// +////////////////// +int ft_export(t_shell *shell, t_cmd *cmd); +int process_export_args(t_shell *shell, char **args, int i); +int update_env_var(char **env, char *var); +char **add_env_var(char **env, char *new_var); +int is_valid_identifier(char *str); + +////////////////// +///////unset.c//// +////////////////// +int delete_line(char **array, int index); +int find_env_var(char **env, char *var); +int ft_unset(t_shell *shell, t_cmd *cmd); + +////////////////// +///////echo.c///// +////////////////// +void print_echo_args(char **args, int i, int first); +int ft_echo(t_cmd *cmd, t_shell *shell); + +///////////////////////// +///////export_utils.c//// +///////////////////////// +int handle_env_var(t_shell *shell, char *arg); +char *handle_quotes_in_env_var(char *arg); +char *process_single_var(char *result, \ + char *var_start, char *var_end, char **env); +char *expand_env_variables(char *str, char **env); + +void handle_quote_char(char *var_value, \ + int *i, int *in_quotes, char *quote_type); +char *process_quotes(char *var_value, char *clean_value); + +///////////////////////// +///////export_utils2.c//// +///////////////////////// +char *find_next_var(char *result, char **var_start, char **var_end); +char *build_expanded_string(char *result, char *var_start, \ + char *var_end, char *var_value); +char *extract_var_name(char *result, char *var_start, char *var_end); +char *get_env_value_for_expansion(char **env, char *var_name); + +///////////////////////////////////////////////////////////////// +////////////////////////////TOKENS/////////////////////////////// +///////////////////////////////////////////////////////////////// + +/////////////////////////// +///////check_pipes.c/////// +/////////////////////////// +int check_before_pipe(char **tokens); +int pipe_sequence_invalid(char **tokens); +int validate_pipes(char **tokens); + +////////////////////////////////// +///////check_redirections.c/////// +////////////////////////////////// +int is_redirection(char *token); +int check_further_redirections(char **tokens, int i); +int validate_redirections(char **tokens); + +////////////////////// +///////syntax.c/////// +////////////////////// +t_token_type classify_token(char *token); +int validate_syntax(char **tokens); + +////////////////////////// +///////token_list.c/////// +////////////////////////// +void free_cmd_node(t_cmd *cmd); +t_cmd *create_command_node(void); +t_redirection *create_redirection_node(int type, char *file); +int add_argument(t_cmd *cmd, char *arg); +void add_redirection(t_cmd *cmd, t_redirection *redir); + +/////////////////////////// +///////token_list2.c/////// +/////////////////////////// +int handle_redirection(t_cmd *cmd, char **tokens, int *i); +t_cmd *init_cmd_segment(t_cmd **cmd_list, char **tokens, int *i); +int add_token_to_cmd(t_cmd *current, char **tokens, int *i); +t_cmd *parse_tokens_to_list(char **tokens); +void free_cmd_list(t_cmd *cmd_list); + +/////////////////////////// +///////token_utils.c/////// +/////////////////////////// +int count_tokens(char *str); +int handle_quoted_token(char *input, int *index, int *start); +int handle_special_token(char *input, int *index); +void handle_quoted_count(char *str, int *i, char quote); +void handle_special_count(char *str, int *i); + +//////////////////// +///////token.c////// +//////////////////// +int extract_quoted_token(char *input, int *index, char quote_char); +int is_delimiter(char c); +int is_special(char c); +void skip_delimiters(char *str, int *i); +char *extract_quoted_content(char *input, int start, \ + int len, char quote_char); + +/////////////////////////// +///////token_utils2.c////// +/////////////////////////// +int extract_token_len(char *input, int *index, int *start); +char *extract_token(char *input, int *index, t_shell *shell); +int check_quotes(char *input); +char **tokenize_command(char *input, t_shell *shell); +void handle_word_count(char *str, int *i); + +// Exec + +int open_file(char *file, int flags, int mode); +int setup_files(t_redirection *redir); +int setup_input_redirections(t_redirection *redir); +int setup_output_redirections(t_redirection *redir); +int has_input_redirection(t_redirection *redir); +void close_files(int infile, int outfile); +char *find_command(char **paths, char *cmd); +char *get_path_env(char **envp); +int ft_exec(t_cmd *cmd, char **envp, t_shell *shell); +int execute_ve(t_cmd *cmd, char **envp); +int loop_open_files(t_cmd *cmd); +int handle_heredoc(char *delim); +int execute_pipeline(t_cmd *cmd_list, t_shell *shell); +char *execute_ve_2(t_cmd *cmd, char *path_env, char *full_path); +int ft_exit(t_cmd *cmd, t_shell *shell); +int setup_pipe(int pipefd[2]); +int is_valid_number(char *str); +int check_positive_overflow(long long result, char digit); +int check_negative_overflow(long long result, char digit); +// expand.c + +char *expand_variables(char *str, t_shell *shell); +char *get_env_value(char *var, t_shell *shell); +void handle_child(t_cmd *cmd, int infile, int pipefd[2], \ + t_shell *shell); +int wait_for_children(pid_t last_pid); + +// pipe.c + +void restore_fds(int saved_stdin, int saved_stdout); +int spawn_pipeline(t_cmd *cmd, t_shell *shell); + +// setup_files.c + +int setup_files(t_redirection *redir); + +// setup_output_redirections.c +int setup_output_redirections(t_redirection *redir); + +// execute_ve.c +int execute_ve(t_cmd *cmd, char **envp); +int file_exists(const char *path); +void run_child_process(t_cmd *cmd, char **envp); + +#endif \ No newline at end of file diff --git a/libft/Makefile b/libft/Makefile new file mode 100644 index 0000000..dc17dcc --- /dev/null +++ b/libft/Makefile @@ -0,0 +1,68 @@ +# **************************************************************************** # +# # +# ::: :::::::: # +# Makefile :+: :+: :+: # +# +:+ +:+ +:+ # +# By: lfirmin +#+ +:+ +#+ # +# +#+#+#+#+#+ +#+ # +# Created: 2024/05/19 12:59:31 by lfirmin #+# #+# # +# Updated: 2025/04/19 11:53:48 by lfirmin ### ########.fr # +# # +# **************************************************************************** # + +NAME = libft.a +HEADER = ./include +SRCS_DIR = ./srcs/ +SRC = ft_isalnum.c ft_isprint.c ft_memcmp.c ft_putchar_fd.c ft_split.c \ + ft_strlcat.c ft_strncmp.c ft_substr.c ft_atoi.c ft_isalpha.c \ + ft_itoa.c ft_memcpy.c ft_putendl_fd.c ft_strchr.c ft_strlcpy.c \ + ft_strnstr.c ft_tolower.c ft_bzero.c ft_isascii.c ft_strtrim.c \ + ft_memmove.c ft_putnbr_fd.c ft_strdup.c ft_strlen.c ft_strrchr.c \ + ft_toupper.c ft_calloc.c ft_isdigit.c ft_memchr.c ft_memset.c \ + ft_putstr_fd.c ft_strjoin.c ft_strmapi.c ft_striteri.c \ + ft_lstnew_bonus.c ft_lstadd_front_bonus.c ft_lstsize_bonus.c \ + ft_lstlast_bonus.c ft_lstadd_back_bonus.c ft_lstdelone_bonus.c \ + ft_lstclear_bonus.c ft_lstiter_bonus.c ft_lstmap_bonus.c ft_strcmp.c \ + ft_atoll.c ft_straddchar.c ft_strcpy.c + +SRCS = $(addprefix $(SRCS_DIR), $(SRC)) +CC = cc +CFLAGS = -Wall -Wextra -Werror -g3 +INCLUDE = -I $(HEADER) +OBJ_DIR = obj/ +OBJ = $(addprefix $(OBJ_DIR), $(SRC:.c=.o)) + +GREEN = \033[0;32m +YELLOW = \033[0;33m +RESET = \033[0m +WHITE = \033[0;97m + +LOADING_CHARS = ⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏ + +all: $(NAME) + +$(NAME): $(OBJ) + @printf "$(YELLOW)Compiling libft, Please wait...$(RESET)" + @for char in $(LOADING_CHARS); do \ + printf "\r$(YELLOW)Compiling libft, Please wait... $$char$(RESET)"; \ + sleep 0.1; \ + done + @ar rc $(NAME) $(OBJ) + @ranlib $(NAME) + @printf "\r$(GREEN)Great news ! $(WHITE)Libft compiled successfully ! $(RESET)\n" + +$(OBJ_DIR)%.o: $(SRCS_DIR)%.c + @mkdir -p $(OBJ_DIR) + @$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +clean: + @rm -rf $(OBJ_DIR) + @printf "$(WHITE)Clean process completed for $(GREEN)Libft.$(RESET)\n" + +fclean: clean + @rm -f $(NAME) + @printf "$(WHITE)Full clean process completed for $(GREEN)Libft.$(RESET)\n" + +re: fclean all + +.PHONY: all clean fclean re \ No newline at end of file diff --git a/libft/Readme.md b/libft/Readme.md new file mode 100644 index 0000000..ef5f375 --- /dev/null +++ b/libft/Readme.md @@ -0,0 +1,55 @@ +# Libft - 42 Project + +## Description +Libft is the first project at 42 school. The aim is to recreate various standard C library functions, as well as additional functions that will be useful throughout the cursus. This library will be used in most of the future 42 projects. + +## Functions + +### Libc Functions +`ft_isalpha` • `ft_isdigit` • `ft_isalnum` • `ft_isascii` • `ft_isprint` • `ft_strlen` • `ft_memset` • `ft_bzero` • `ft_memcpy` • `ft_memmove` • `ft_strlcpy` • `ft_strlcat` • `ft_toupper` • `ft_tolower` • `ft_strchr` • `ft_strrchr` • `ft_strncmp` • `ft_memchr` • `ft_memcmp` • `ft_strnstr` • `ft_atoi` • `ft_calloc` • `ft_strdup` + +### Additional Functions +`ft_substr` • `ft_strjoin` • `ft_strtrim` • `ft_split` • `ft_itoa` • `ft_strmapi` • `ft_striteri` • `ft_putchar_fd` • `ft_putstr_fd` • `ft_putendl_fd` • `ft_putnbr_fd` + +### Bonus Functions +`ft_lstnew` • `ft_lstadd_front` • `ft_lstsize` • `ft_lstlast` • `ft_lstadd_back` • `ft_lstdelone` • `ft_lstclear` • `ft_lstiter` • `ft_lstmap` + +## Getting Started + +### Prerequisites +- GCC compiler +- Make + +### Usage +1. Include the header in your source file: +```c +#include "libft.h" +``` + +### Compilation +1. Compilation: +```bash +make +``` + +## Cleaning +- Remove object files: +```bash +make clean +``` + +- Remove object files and library: +```bash +make fclean +``` + +- Recompile everything: +```bash +make re +``` + +## Testing +This project doesn't come with unit tests, but you can use external testers: +- [libft-unit-test](https://github.com/alelievr/libft-unit-test) +- [libft-war-machine](https://github.com/ska42/libft-war-machine) +- [Tripouille/libfTester](https://github.com/Tripouille/libftTester) diff --git a/libft/include/libft.h b/libft/include/libft.h new file mode 100644 index 0000000..caf9d9c --- /dev/null +++ b/libft/include/libft.h @@ -0,0 +1,92 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* libft.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 11:19:08 by lfirmin #+# #+# */ +/* Updated: 2025/04/19 11:56:03 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef LIBFT_H +# define LIBFT_H + +# include +# include +# include +# include +# include +# include + +typedef struct v +{ + char **array; + int i; + int j; + int start; + int end; +} t_split_struct; + +typedef struct s_list +{ + void *content; + struct s_list *next; +} t_list; + +int ft_isalnum(int c); +int ft_isalpha(int c); +int ft_isascii(int c); +int ft_isdigit(int c); +int ft_isprint(int c); +int ft_atoi(const char *str); +int ft_memcmp(const void *ptr1, const void *ptr2, size_t num); +int ft_strncmp(const char *s1, const char *s2, unsigned int n); +int ft_toupper(int c); +int ft_tolower(int c); +int ft_lstsize(t_list *lst); +int ft_strcmp(char *s1, char *s2); +long long ft_atoll(const char *str); + +size_t ft_strlen(const char *s); +size_t ft_strlcat(char *dst, const char *src, size_t size); +size_t ft_strlcpy(char *dst, const char *src, size_t dsts); + +void *ft_bzero(void *s, size_t n); +void *ft_calloc(size_t count, size_t n); +void *ft_memchr(const void *s, int c, size_t n); +void *ft_memcpy(void *dest, const void *src, size_t len); +void *ft_memset(void *b, int c, size_t len); +void *ft_memmove(void *s1, const void *s2, size_t len); +void *ft_memset(void *str, int c, size_t n); +void ft_putchar_fd(char c, int fd); +void ft_putstr_fd(char *s, int fd); +void ft_putendl_fd(char *s, int fd); +void ft_putnbr_fd(int n, int fd); +void ft_striteri(char *s, void (*f)(unsigned int, char*)); +void ft_lstadd_front(t_list **lst, t_list *new); +void ft_lstadd_back(t_list **lst, t_list *new); +void ft_lstdelone(t_list *lst, void (*del)(void*)); +void ft_lstclear(t_list **lst, void (*del)(void*)); +void ft_lstiter(t_list *lst, void (*f)(void *)); + +char *ft_strchr(char const *str, int c); +char *ft_strdup(const char *src); +char *ft_strjoin(const char *s1, const char *s2); +char *ft_strnstr(const char *hay, const char *need, size_t len); +char *ft_strrchr(const char *str, int c); +char *ft_strtrim(char const *s1, char const *set); +char *ft_substr(char const *s, unsigned int start, size_t len); +char **ft_split(char const *s, char c); +char *ft_strmapi(char const *s, char (*f)(unsigned int, char)); +char *ft_itoa(int n); +char *ft_straddchar(char *str, char c); +char *ft_strcpy(char *dest, char *src); + +t_list *ft_lstnew(void *content); +t_list *ft_lstlast(t_list *lst); +t_list *ft_lstmap(t_list *lst, void *(*f)(void *), \ + void (*del)(void *)); + +#endif \ No newline at end of file diff --git a/libft/srcs/ft_atoi.c b/libft/srcs/ft_atoi.c new file mode 100644 index 0000000..a05a597 --- /dev/null +++ b/libft/srcs/ft_atoi.c @@ -0,0 +1,40 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_atoi.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 10:09:46 by lfirmin #+# #+# */ +/* Updated: 2024/06/03 21:02:02 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_atoi(const char *str) +{ + int i; + int s; + int m; + + i = 0; + s = 0; + m = 0; + while ((str[i] <= 13 && str[i] >= 9) || str[i] == 32) + i++; + while (str[i] == '-' || str[i] == '+') + { + s++; + if (s >= 2) + return (0); + if (str[i] == '-') + m++; + i++; + } + s = 0; + while (str[i] >= 48 && str[i] <= 57) + s = s * 10 + (str[i++] - 48); + if (m % 2 == 1) + s = s * -1; + return (s); +} diff --git a/libft/srcs/ft_atoll.c b/libft/srcs/ft_atoll.c new file mode 100644 index 0000000..34fd5a5 --- /dev/null +++ b/libft/srcs/ft_atoll.c @@ -0,0 +1,38 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_atoll.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/11/03 17:25:06 by lfirmin #+# #+# */ +/* Updated: 2024/11/03 17:25:33 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "libft.h" + +long long ft_atoll(const char *str) +{ + long long result; + int sign; + + result = 0; + sign = 1; + while (*str == ' ' || (*str >= 9 && *str <= 13)) + str++; + if (*str == '-' || *str == '+') + { + if (*str == '-') + sign = -1; + str++; + } + while (*str >= '0' && *str <= '9') + { + if (result > INT_MAX || result < INT_MIN) + return (2147483648); + result = result * 10 + (*str - '0'); + str++; + } + return (result * sign); +} diff --git a/libft/srcs/ft_bzero.c b/libft/srcs/ft_bzero.c new file mode 100644 index 0000000..507f22d --- /dev/null +++ b/libft/srcs/ft_bzero.c @@ -0,0 +1,24 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_bzero.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 00:20:00 by lfirmin #+# #+# */ +/* Updated: 2024/05/30 19:49:23 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void *ft_bzero(void *b, size_t len) +{ + size_t i; + unsigned char *r; + + r = (unsigned char *)b; + i = 0; + while (i < len) + r[i++] = '\0'; + return (b); +} diff --git a/libft/srcs/ft_calloc.c b/libft/srcs/ft_calloc.c new file mode 100644 index 0000000..b42206a --- /dev/null +++ b/libft/srcs/ft_calloc.c @@ -0,0 +1,31 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_calloc.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 11:14:02 by lfirmin #+# #+# */ +/* Updated: 2024/06/03 18:15:05 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void *ft_calloc(size_t c, size_t s) +{ + void *ptr; + long long int tmp1; + long long int tmp2; + + tmp1 = (long long int)c; + tmp2 = (long long int)s; + if ((c > 4294967295 || s > 4294967295) && (tmp1 < 0 && tmp2 < 0)) + return (NULL); + if (tmp1 * tmp2 < 0) + return (NULL); + ptr = malloc(c * s); + if (!ptr) + return (NULL); + ft_bzero(ptr, c * s); + return (ptr); +} diff --git a/libft/srcs/ft_isalnum.c b/libft/srcs/ft_isalnum.c new file mode 100644 index 0000000..0fd48a2 --- /dev/null +++ b/libft/srcs/ft_isalnum.c @@ -0,0 +1,19 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_isalnum.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/20 02:29:49 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_isalnum(int c) +{ + if ((c >= 97 && c <= 122) || (c >= 48 && c <= 57) || (c >= 65 && c <= 90)) + return (1); + return (0); +} diff --git a/libft/srcs/ft_isalpha.c b/libft/srcs/ft_isalpha.c new file mode 100644 index 0000000..3382c40 --- /dev/null +++ b/libft/srcs/ft_isalpha.c @@ -0,0 +1,19 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_isalpha.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/20 01:55:52 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_isalpha(int c) +{ + if ((c >= 97 && c <= 122) || (c >= 65 && c <= 90)) + return (1); + return (0); +} diff --git a/libft/srcs/ft_isascii.c b/libft/srcs/ft_isascii.c new file mode 100644 index 0000000..c5d9e0b --- /dev/null +++ b/libft/srcs/ft_isascii.c @@ -0,0 +1,19 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_isascii.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/20 02:36:17 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_isascii(int c) +{ + if (c >= 0 && c <= 127) + return (1); + return (0); +} diff --git a/libft/srcs/ft_isdigit.c b/libft/srcs/ft_isdigit.c new file mode 100644 index 0000000..78f90b9 --- /dev/null +++ b/libft/srcs/ft_isdigit.c @@ -0,0 +1,19 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_isdigit.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/20 02:31:51 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_isdigit(int c) +{ + if (c >= 48 && c <= 57) + return (1); + return (0); +} diff --git a/libft/srcs/ft_isprint.c b/libft/srcs/ft_isprint.c new file mode 100644 index 0000000..2a09bb2 --- /dev/null +++ b/libft/srcs/ft_isprint.c @@ -0,0 +1,19 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_isprint.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/20 02:38:24 by lfirmin #+# #+# */ +/* Updated: 2024/05/23 06:21:54 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_isprint(int c) +{ + if (((c >= 0 && c <= 31) || c >= 127 || c == EOF)) + return (0); + return (1); +} diff --git a/libft/srcs/ft_itoa.c b/libft/srcs/ft_itoa.c new file mode 100644 index 0000000..eade559 --- /dev/null +++ b/libft/srcs/ft_itoa.c @@ -0,0 +1,51 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_itoa.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/24 12:59:00 by lfirmin #+# #+# */ +/* Updated: 2024/05/29 10:31:36 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +static size_t ft_count(long int n) +{ + size_t c; + + c = 0; + if (n <= 0) + c = 1; + while (n != 0) + { + n = n / 10; + c++; + } + return (c); +} + +char *ft_itoa(int n) +{ + char *str; + size_t size; + long int num; + + num = n; + size = ft_count(num); + str = (char *)malloc(size + 1); + if (!str) + return (NULL); + str[size] = '\0'; + if (num < 0) + num = -num; + while (size--) + { + str[size] = num % 10 + '0'; + num = num / 10; + if (n < 0 && size == 0) + str[size] = '-'; + } + return (str); +} diff --git a/libft/srcs/ft_lstadd_back_bonus.c b/libft/srcs/ft_lstadd_back_bonus.c new file mode 100644 index 0000000..2bfdfc7 --- /dev/null +++ b/libft/srcs/ft_lstadd_back_bonus.c @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_lstadd_back.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/01 02:01:18 by lfirmin #+# #+# */ +/* Updated: 2024/06/03 15:59:33 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_lstadd_back(t_list **lst, t_list *new) +{ + t_list *last; + + if (!new) + return ; + if (!lst || !*lst) + { + *lst = new; + return ; + } + last = ft_lstlast(*lst); + last->next = new; +} diff --git a/libft/srcs/ft_lstadd_front_bonus.c b/libft/srcs/ft_lstadd_front_bonus.c new file mode 100644 index 0000000..b784622 --- /dev/null +++ b/libft/srcs/ft_lstadd_front_bonus.c @@ -0,0 +1,21 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_lstadd_front.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/31 20:34:57 by lfirmin #+# #+# */ +/* Updated: 2024/05/31 20:41:34 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_lstadd_front(t_list **lst, t_list *new) +{ + if (lst && new) + { + new->next = *lst; + *lst = new; + } +} diff --git a/libft/srcs/ft_lstclear_bonus.c b/libft/srcs/ft_lstclear_bonus.c new file mode 100644 index 0000000..54479d1 --- /dev/null +++ b/libft/srcs/ft_lstclear_bonus.c @@ -0,0 +1,28 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_lstclear.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/01 20:46:07 by lfirmin #+# #+# */ +/* Updated: 2024/06/01 20:51:07 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_lstclear(t_list **lst, void (*del)(void*)) +{ + t_list *t; + + if (lst) + { + while (*lst) + { + t = (*lst)->next; + ft_lstdelone(*lst, del); + (*lst) = t; + } + (*lst) = NULL; + } +} diff --git a/libft/srcs/ft_lstdelone_bonus.c b/libft/srcs/ft_lstdelone_bonus.c new file mode 100644 index 0000000..94ae5ab --- /dev/null +++ b/libft/srcs/ft_lstdelone_bonus.c @@ -0,0 +1,20 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_lstdelone.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/01 20:32:56 by lfirmin #+# #+# */ +/* Updated: 2024/06/01 20:32:56 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_lstdelone(t_list *lst, void (*del)(void*)) +{ + if (!lst || !del) + return ; + del(lst->content); + free(lst); +} diff --git a/libft/srcs/ft_lstiter_bonus.c b/libft/srcs/ft_lstiter_bonus.c new file mode 100644 index 0000000..8870692 --- /dev/null +++ b/libft/srcs/ft_lstiter_bonus.c @@ -0,0 +1,23 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_lstiter.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/01 21:05:12 by lfirmin #+# #+# */ +/* Updated: 2024/06/01 21:05:12 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_lstiter(t_list *lst, void (*f)(void *)) +{ + if (!lst || !f) + return ; + while (lst) + { + f(lst->content); + lst = lst->next; + } +} diff --git a/libft/srcs/ft_lstlast_bonus.c b/libft/srcs/ft_lstlast_bonus.c new file mode 100644 index 0000000..c00582b --- /dev/null +++ b/libft/srcs/ft_lstlast_bonus.c @@ -0,0 +1,23 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_lstlast.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/01 01:52:09 by lfirmin #+# #+# */ +/* Updated: 2024/06/01 01:57:22 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +t_list *ft_lstlast(t_list *lst) +{ + while (lst) + { + if (!lst->next) + return (lst); + lst = lst->next; + } + return (lst); +} diff --git a/libft/srcs/ft_lstmap_bonus.c b/libft/srcs/ft_lstmap_bonus.c new file mode 100644 index 0000000..7efc366 --- /dev/null +++ b/libft/srcs/ft_lstmap_bonus.c @@ -0,0 +1,41 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_lstmap.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/02 18:21:09 by lfirmin #+# #+# */ +/* Updated: 2024/06/03 15:53:13 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +t_list *ft_lstmap(t_list *lst, void *(*f)(void *), void (*del)(void *)) +{ + t_list *new; + t_list *save; + + if (!lst || !del || !f) + return (NULL); + new = ft_lstnew(lst->content); + if (!new) + return (NULL); + new->content = f(new->content); + save = new; + lst = lst->next; + while (lst) + { + new->next = ft_lstnew(lst->content); + if (!new->next) + { + ft_lstclear(&save, del); + return (NULL); + } + new->next->content = f(new->next->content); + new = new->next; + lst = lst->next; + } + new->next = NULL; + return (save); +} diff --git a/libft/srcs/ft_lstnew_bonus.c b/libft/srcs/ft_lstnew_bonus.c new file mode 100644 index 0000000..d9a9ba7 --- /dev/null +++ b/libft/srcs/ft_lstnew_bonus.c @@ -0,0 +1,24 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_lstnew.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/31 18:41:23 by lfirmin #+# #+# */ +/* Updated: 2024/05/31 20:33:26 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +t_list *ft_lstnew(void *content) +{ + t_list *new; + + new = (t_list *)malloc(sizeof(*new)); + if (!new) + return (NULL); + new->content = content; + new->next = NULL; + return (new); +} diff --git a/libft/srcs/ft_lstsize_bonus.c b/libft/srcs/ft_lstsize_bonus.c new file mode 100644 index 0000000..d68e15d --- /dev/null +++ b/libft/srcs/ft_lstsize_bonus.c @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_lstsize.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/31 22:00:49 by lfirmin #+# #+# */ +/* Updated: 2024/05/31 22:12:17 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_lstsize(t_list *lst) +{ + int i; + t_list *count; + + count = lst; + i = 0; + while (count) + { + count = count->next; + i++; + } + return (i); +} diff --git a/libft/srcs/ft_memchr.c b/libft/srcs/ft_memchr.c new file mode 100644 index 0000000..4272249 --- /dev/null +++ b/libft/srcs/ft_memchr.c @@ -0,0 +1,26 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_memchr.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 07:40:39 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void *ft_memchr(const void *s, int c, size_t n) +{ + unsigned char *str; + + str = (unsigned char *)s; + while (n--) + { + if (*str == (unsigned char)c) + return (str); + str++; + } + return (NULL); +} diff --git a/libft/srcs/ft_memcmp.c b/libft/srcs/ft_memcmp.c new file mode 100644 index 0000000..fc9d739 --- /dev/null +++ b/libft/srcs/ft_memcmp.c @@ -0,0 +1,30 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_memcmp.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 07:57:58 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 11:34:35 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_memcmp(const void *ptr1, const void *ptr2, size_t num) +{ + unsigned char *pt1; + unsigned char *pt2; + size_t i; + + pt1 = (unsigned char *)ptr1; + pt2 = (unsigned char *)ptr2; + i = 0; + while (i < num) + { + if (pt1[i] != pt2[i]) + return (pt1[i] - pt2[i]); + i++; + } + return (0); +} diff --git a/libft/srcs/ft_memcpy.c b/libft/srcs/ft_memcpy.c new file mode 100644 index 0000000..7f3d5a2 --- /dev/null +++ b/libft/srcs/ft_memcpy.c @@ -0,0 +1,32 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_memcpy.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 01:08:31 by lfirmin #+# #+# */ +/* Updated: 2025/06/02 00:40:39 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "libft.h" + +void *ft_memcpy(void *dest, const void *src, size_t len) +{ + size_t i; + unsigned char *r; + unsigned char *s; + + i = 0; + r = (unsigned char *)dest; + s = (unsigned char *)src; + if (dest == (void *)0 && src == (void *)0) + return (dest); + while (i < len) + { + r[i] = s[i]; + i++; + } + return (dest); +} diff --git a/libft/srcs/ft_memmove.c b/libft/srcs/ft_memmove.c new file mode 100644 index 0000000..8920c37 --- /dev/null +++ b/libft/srcs/ft_memmove.c @@ -0,0 +1,39 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_memmov.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 01:26:13 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void *ft_memmove(void *s1, const void *s2, size_t len) +{ + unsigned char *dest; + unsigned char *src; + unsigned int i; + + dest = (unsigned char *)s1; + src = (unsigned char *)s2; + i = 0; + if (dest == NULL && src == NULL) + return (NULL); + if (dest < src) + { + while (i < len) + { + dest[i] = src[i]; + i++; + } + } + else + { + while (0 < len--) + dest[len] = src[len]; + } + return (dest); +} diff --git a/libft/srcs/ft_memset.c b/libft/srcs/ft_memset.c new file mode 100644 index 0000000..d4ecdb0 --- /dev/null +++ b/libft/srcs/ft_memset.c @@ -0,0 +1,24 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_memset.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/20 02:42:40 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void *ft_memset(void *b, int c, size_t len) +{ + size_t i; + unsigned char *r; + + i = 0; + r = (unsigned char *)b; + while (i < len) + r[i++] = (unsigned char)c; + return (b); +} diff --git a/libft/srcs/ft_putchar_fd.c b/libft/srcs/ft_putchar_fd.c new file mode 100644 index 0000000..8a930f9 --- /dev/null +++ b/libft/srcs/ft_putchar_fd.c @@ -0,0 +1,17 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_putchar_fd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/29 11:17:45 by lfirmin #+# #+# */ +/* Updated: 2024/05/29 11:20:42 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_putchar_fd(char c, int fd) +{ + write(fd, &c, 1); +} diff --git a/libft/srcs/ft_putendl_fd.c b/libft/srcs/ft_putendl_fd.c new file mode 100644 index 0000000..c2e3e97 --- /dev/null +++ b/libft/srcs/ft_putendl_fd.c @@ -0,0 +1,18 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_putendl_fd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/29 11:35:44 by lfirmin #+# #+# */ +/* Updated: 2024/05/29 11:38:36 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_putendl_fd(char *s, int fd) +{ + ft_putstr_fd(s, fd); + ft_putchar_fd('\n', fd); +} diff --git a/libft/srcs/ft_putnbr_fd.c b/libft/srcs/ft_putnbr_fd.c new file mode 100644 index 0000000..0b02ab1 --- /dev/null +++ b/libft/srcs/ft_putnbr_fd.c @@ -0,0 +1,31 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_putnbr_fd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/29 11:42:38 by lfirmin #+# #+# */ +/* Updated: 2024/05/29 11:56:04 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_putnbr_fd(int n, int fd) +{ + long int nb; + + nb = n; + if (nb < 0) + { + nb = -nb; + ft_putchar_fd('-', fd); + } + if (nb >= 10) + { + ft_putnbr_fd(nb / 10, fd); + ft_putnbr_fd(nb % 10, fd); + } + else + ft_putchar_fd(nb + '0', fd); +} diff --git a/libft/srcs/ft_putstr_fd.c b/libft/srcs/ft_putstr_fd.c new file mode 100644 index 0000000..ecdc0ef --- /dev/null +++ b/libft/srcs/ft_putstr_fd.c @@ -0,0 +1,24 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_putstr_fd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/29 11:27:05 by lfirmin #+# #+# */ +/* Updated: 2024/05/29 11:33:18 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_putstr_fd(char *s, int fd) +{ + int i; + + i = 0; + while (s[i]) + { + ft_putchar_fd(s[i], fd); + i++; + } +} diff --git a/libft/srcs/ft_split.c b/libft/srcs/ft_split.c new file mode 100644 index 0000000..9650577 --- /dev/null +++ b/libft/srcs/ft_split.c @@ -0,0 +1,95 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_split.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/22 05:56:37 by lfirmin #+# #+# */ +/* Updated: 2024/06/04 12:08:51 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +static int ft_c(char const *s, char c) +{ + int i; + int count; + + count = 0; + i = 0; + while (s[i]) + { + if (s[i] != c && (i == 0 || s[i - 1] == c)) + count++; + i++; + } + return (count); +} + +void init_split_struct(t_split_struct *v, char const *s, char c) +{ + if (!s) + return ; + v->array = (char **)malloc((ft_c(s, c) + 1) * sizeof(char *)); + if (!s || !v->array) + return ; + v->i = 0; + v->j = 0; +} + +static char *ft_strncpy(char *dest, const char *src, unsigned int n) +{ + unsigned int i; + + i = 0; + while (src[i] != '\0' && i < n) + { + dest[i] = src[i]; + ++i; + } + while (i < n) + { + dest[i] = '\0'; + i++; + } + return (dest); +} + +char **free_split(char **array, size_t j) +{ + while (j > 0) + { + free(array[--j]); + } + free(array); + return (NULL); +} + +char **ft_split(char const *s, char c) +{ + t_split_struct v; + + init_split_struct(&v, s, c); + if (!s || !v.array) + return (NULL); + while (s[v.i]) + { + while (s[v.i] == c && s[v.i]) + v.i++; + v.start = v.i; + while (s[v.i] != c && s[v.i]) + v.i++; + if (v.i > v.start) + { + v.array[v.j] = (char *)malloc(v.i - v.start + 1); + if (!v.array[v.j]) + return (free_split(v.array, v.j)); + ft_strncpy(v.array[v.j], &s[v.start], v.i - v.start); + v.array[v.j][v.i - v.start] = '\0'; + v.j++; + } + } + v.array[v.j] = NULL; + return (v.array); +} diff --git a/libft/srcs/ft_straddchar.c b/libft/srcs/ft_straddchar.c new file mode 100644 index 0000000..bf83573 --- /dev/null +++ b/libft/srcs/ft_straddchar.c @@ -0,0 +1,37 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_straddchar.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/11/08 06:02:17 by lfirmin #+# #+# */ +/* Updated: 2024/11/08 06:02:17 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "libft.h" + +char *ft_straddchar(char *str, char c) +{ + int i; + char *res; + + if (!str) + return (NULL); + i = 0; + while (str[i]) + i++; + res = (char *)malloc(sizeof(char) * (i + 2)); + if (!res) + return (NULL); + i = 0; + while (str[i]) + { + res[i] = str[i]; + i++; + } + res[i] = c; + res[i + 1] = '\0'; + return (res); +} diff --git a/libft/srcs/ft_strchr.c b/libft/srcs/ft_strchr.c new file mode 100644 index 0000000..11f57be --- /dev/null +++ b/libft/srcs/ft_strchr.c @@ -0,0 +1,26 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strchr.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 06:46:40 by lfirmin #+# #+# */ +/* Updated: 2024/05/24 08:51:25 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +char *ft_strchr(char const *str, int c) +{ + while (*str) + { + if (*str == (char)c) + return ((char *)str); + str++; + } + if (*str == (char)c) + return ((char *)str); + else + return (NULL); +} diff --git a/libft/srcs/ft_strcmp.c b/libft/srcs/ft_strcmp.c new file mode 100644 index 0000000..e3d21ba --- /dev/null +++ b/libft/srcs/ft_strcmp.c @@ -0,0 +1,22 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strcmp.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/10/19 21:01:26 by lfirmin #+# #+# */ +/* Updated: 2024/10/19 21:01:26 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_strcmp(char *s1, char *s2) +{ + int i; + + i = 0; + while (s1[i] == s2[i] && s1[i] != '\0' && s2[i] != '\0') + i++; + return (s1[i] - s2[i]); +} diff --git a/libft/srcs/ft_strcpy.c b/libft/srcs/ft_strcpy.c new file mode 100644 index 0000000..c72313d --- /dev/null +++ b/libft/srcs/ft_strcpy.c @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strcpy.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/19 11:53:24 by lfirmin #+# #+# */ +/* Updated: 2025/04/19 11:58:04 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "libft.h" + +char *ft_strcpy(char *dest, char *src) +{ + size_t i; + + i = 0; + while (src[i] != '\0') + { + dest[i] = src[i]; + i++; + } + dest[i] = '\0'; + return (dest); +} diff --git a/libft/srcs/ft_strdup.c b/libft/srcs/ft_strdup.c new file mode 100644 index 0000000..7df78c5 --- /dev/null +++ b/libft/srcs/ft_strdup.c @@ -0,0 +1,34 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strdup.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/15 05:28:24 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +char *ft_strdup(const char *src) +{ + char *dest; + int i; + int size; + + size = 0; + while (src[size] != '\0') + size++; + dest = malloc(sizeof(char) * (size + 1)); + if (dest == NULL) + return (NULL); + i = 0; + while (i != size) + { + dest[i] = src[i]; + i++; + } + dest[i] = '\0'; + return (dest); +} diff --git a/libft/srcs/ft_striteri.c b/libft/srcs/ft_striteri.c new file mode 100644 index 0000000..bd32dda --- /dev/null +++ b/libft/srcs/ft_striteri.c @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_striteri.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/29 10:54:40 by lfirmin #+# #+# */ +/* Updated: 2024/05/29 11:12:05 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +void ft_striteri(char *s, void (*f)(unsigned int, char*)) +{ + int i; + + i = 0; + if (s) + { + while (s[i]) + { + f(i, &s[i]); + ++i; + } + } +} diff --git a/libft/srcs/ft_strjoin.c b/libft/srcs/ft_strjoin.c new file mode 100644 index 0000000..aed8eb4 --- /dev/null +++ b/libft/srcs/ft_strjoin.c @@ -0,0 +1,34 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strjoin.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/22 01:00:14 by lfirmin #+# #+# */ +/* Updated: 2024/05/24 08:49:06 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +char *ft_strjoin(const char *s1, const char *s2) +{ + char *res; + int i; + int j; + + i = 0; + j = 0; + if (s1 == NULL && s2 == NULL) + return (NULL); + res = (char *) malloc((ft_strlen(s1) + ft_strlen(s2) + 1) * sizeof(char)); + if (!res) + return (NULL); + while (s1[i]) + res[j++] = s1[i++]; + i = 0; + while (s2[i]) + res[j++] = s2[i++]; + res[j] = 0; + return (res); +} diff --git a/libft/srcs/ft_strlcat.c b/libft/srcs/ft_strlcat.c new file mode 100644 index 0000000..b691378 --- /dev/null +++ b/libft/srcs/ft_strlcat.c @@ -0,0 +1,32 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strlcat.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 03:55:25 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +size_t ft_strlcat(char *dst, const char *src, size_t size) +{ + size_t i; + size_t r; + size_t s; + + i = 0; + r = ft_strlen(dst); + s = ft_strlen(src); + if (size <= r) + return (s + size); + while (r + i < size - 1 && src[i] != '\0') + { + dst[r + i] = src[i]; + i++; + } + dst[r + i] = '\0'; + return (r + s); +} diff --git a/libft/srcs/ft_strlcpy.c b/libft/srcs/ft_strlcpy.c new file mode 100644 index 0000000..9721995 --- /dev/null +++ b/libft/srcs/ft_strlcpy.c @@ -0,0 +1,34 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strlcpy.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 02:18:17 by lfirmin #+# #+# */ +/* Updated: 2024/05/30 18:36:18 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +size_t ft_strlcpy(char *dst, const char *src, size_t dsts) +{ + size_t srcs; + size_t i; + + ft_strlen(src); + if (!src || !dst) + return (0); + srcs = ft_strlen(src); + i = 0; + if (dsts != 0) + { + while (src[i] != '\0' && i < (dsts - 1)) + { + dst[i] = src[i]; + i++; + } + dst[i] = '\0'; + } + return (srcs); +} diff --git a/libft/srcs/ft_strlen.c b/libft/srcs/ft_strlen.c new file mode 100644 index 0000000..c8a5c83 --- /dev/null +++ b/libft/srcs/ft_strlen.c @@ -0,0 +1,22 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strlen.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/19 23:16:45 by lfirmin #+# #+# */ +/* Updated: 2024/05/23 07:36:59 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +size_t ft_strlen(const char *s) +{ + int i; + + i = 0; + while (s[i]) + i++; + return ((size_t)i); +} diff --git a/libft/srcs/ft_strmapi.c b/libft/srcs/ft_strmapi.c new file mode 100644 index 0000000..9197596 --- /dev/null +++ b/libft/srcs/ft_strmapi.c @@ -0,0 +1,32 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strmapi.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/28 15:10:42 by lfirmin #+# #+# */ +/* Updated: 2024/05/28 17:00:27 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +char *ft_strmapi(char const *s, char (*f)(unsigned int, char)) +{ + char *str; + int i; + + if (!s) + return (NULL); + str = (char *)malloc(ft_strlen(s) + 1); + if (!str) + return (NULL); + i = 0; + while (s[i]) + { + str[i] = f(i, s[i]); + ++i; + } + str[i] = '\0'; + return (str); +} diff --git a/libft/srcs/ft_strncmp.c b/libft/srcs/ft_strncmp.c new file mode 100644 index 0000000..7fcfec4 --- /dev/null +++ b/libft/srcs/ft_strncmp.c @@ -0,0 +1,32 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strncmp.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 06:55:09 by lfirmin #+# #+# */ +/* Updated: 2024/05/24 08:47:59 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_strncmp(const char *s1, const char *s2, unsigned int n) +{ + unsigned int i; + unsigned char c1; + unsigned char c2; + + i = 0; + if (n == 0) + return (0); + while (i < n) + { + c1 = (unsigned char)s1[i]; + c2 = (unsigned char)s2[i]; + if (c1 != c2 || c1 == '\0' || c2 == '\0') + return (c1 - c2); + i++; + } + return (0); +} diff --git a/libft/srcs/ft_strnstr.c b/libft/srcs/ft_strnstr.c new file mode 100644 index 0000000..4f5acca --- /dev/null +++ b/libft/srcs/ft_strnstr.c @@ -0,0 +1,36 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strnstr.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 08:22:59 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +char *ft_strnstr(const char *hay, const char *need, size_t len) +{ + size_t i; + size_t n; + + i = 0; + if (need[0] == '\0') + return ((char *)hay); + while (hay[i] != '\0') + { + n = 0; + while (hay[i + n] == need[n] && (i + n) < len) + { + if (hay[i + n] == '\0' && need[n] == '\0') + return ((char *)&hay[i]); + n++; + } + if (need[n] == '\0') + return ((char *)hay + i); + i++; + } + return (0); +} diff --git a/libft/srcs/ft_strrchr.c b/libft/srcs/ft_strrchr.c new file mode 100644 index 0000000..c7fc977 --- /dev/null +++ b/libft/srcs/ft_strrchr.c @@ -0,0 +1,35 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strrchr.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 06:42:38 by lfirmin #+# #+# */ +/* Updated: 2024/05/30 18:30:00 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +char *ft_strrchr(const char *str, int c) +{ + int i; + int last_occurrence; + + ft_strlen(str); + i = 0; + last_occurrence = -1; + if (str == NULL) + return (NULL); + while (str[i]) + { + if (str[i] == (char)c) + last_occurrence = i; + i++; + } + if ((char)c == '\0') + return ((char *)&str[i]); + if (last_occurrence != -1) + return ((char *)&str[last_occurrence]); + return (NULL); +} diff --git a/libft/srcs/ft_strtrim.c b/libft/srcs/ft_strtrim.c new file mode 100644 index 0000000..abbf77f --- /dev/null +++ b/libft/srcs/ft_strtrim.c @@ -0,0 +1,68 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_strtrim.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/23 21:32:01 by lfirmin #+# #+# */ +/* Updated: 2024/05/31 02:04:11 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "libft.h" + +static int is_in_set(char c, const char *set) +{ + while (*set) + { + if (c == *set) + { + return (1); + } + set++; + } + return (0); +} + +static char *ft_strncpy(char *dest, const char *src, unsigned int n) +{ + unsigned int i; + + i = 0; + while (src[i] != '\0' && i < n) + { + dest[i] = src[i]; + ++i; + } + while (i < n) + { + dest[i] = '\0'; + i++; + } + return (dest); +} + +char *ft_strtrim(const char *s1, const char *set) +{ + size_t s; + size_t e; + size_t len; + char *str; + + if (!s1 || !set) + return (NULL); + s = 0; + while (s1[s] && is_in_set(s1[s], set)) + s++; + e = ft_strlen(s1); + while (e > s && is_in_set(s1[e - 1], set)) + e--; + len = e - s; + str = (char *)malloc(sizeof(char) * (len + 1)); + if (!str) + return (NULL); + ft_strncpy(str, s1 + s, len); + str[len] = '\0'; + return (str); +} diff --git a/libft/srcs/ft_substr.c b/libft/srcs/ft_substr.c new file mode 100644 index 0000000..8e73142 --- /dev/null +++ b/libft/srcs/ft_substr.c @@ -0,0 +1,34 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_substr.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/22 00:15:54 by lfirmin #+# #+# */ +/* Updated: 2024/05/24 08:28:01 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +char *ft_substr(char const *s, unsigned int start, size_t len) +{ + char *sub; + size_t i; + + if ((ft_strlen(s) - start) < len) + len = ft_strlen(s) - start; + if (ft_strlen(s) < start) + return (ft_strdup("")); + i = 0; + sub = (char *) malloc(len + 1); + if (!sub) + return (NULL); + while (len > 0) + { + sub[i++] = s[start++]; + len--; + } + sub[i] = '\0'; + return (sub); +} diff --git a/libft/srcs/ft_tolower.c b/libft/srcs/ft_tolower.c new file mode 100644 index 0000000..288a27a --- /dev/null +++ b/libft/srcs/ft_tolower.c @@ -0,0 +1,19 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_tolower.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 04:50:40 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 11:09:36 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_tolower(int c) +{ + if (c >= 65 && c <= 90) + return (c + 32); + return (c); +} diff --git a/libft/srcs/ft_toupper.c b/libft/srcs/ft_toupper.c new file mode 100644 index 0000000..d563003 --- /dev/null +++ b/libft/srcs/ft_toupper.c @@ -0,0 +1,19 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_toupper.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/21 04:50:40 by lfirmin #+# #+# */ +/* Updated: 2024/05/22 09:59:44 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ +#include "libft.h" + +int ft_toupper(int c) +{ + if (c >= 97 && c <= 122) + return (c - 32); + return (c); +} diff --git a/src/builtins/cd.c b/src/builtins/cd.c new file mode 100644 index 0000000..0f0dad0 --- /dev/null +++ b/src/builtins/cd.c @@ -0,0 +1,127 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/23 11:41:05 by lfirmin #+# #+# */ +/* Updated: 2025/06/01 21:35:36 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int update_pwd_env(t_shell *shell) +{ + char cwd[PATH_MAX]; + char *old_pwd; + char *new_pwd; + + old_pwd = ft_get_env_var(shell->env, "PWD"); + if (old_pwd) + { + new_pwd = ft_strjoin("OLDPWD=", old_pwd); + if (new_pwd) + { + update_env_var(shell->env, new_pwd); + free(new_pwd); + } + } + if (getcwd(cwd, PATH_MAX) != NULL) + { + new_pwd = ft_strjoin("PWD=", cwd); + if (new_pwd) + { + update_env_var(shell->env, new_pwd); + free(new_pwd); + } + return (0); + } + return (1); +} + +char *resolve_env_variables(char *path, t_shell *shell) +{ + char *env_value; + char *var_name; + int i; + int start; + + if (!path || !path[0] || !shell) + return (ft_strdup(path)); + if (path[0] != '$') + return (ft_strdup(path)); + start = 1; + i = start; + while (path[i] && path[i] != '/' && path[i] != ' ') + i++; + var_name = ft_substr(path, start, i - start); + if (!var_name) + return (NULL); + env_value = ft_get_env_var(shell->env, var_name); + free(var_name); + if (!env_value) + return (ft_strdup("")); + if (path[i]) + return (ft_strjoin(env_value, &path[i])); + return (ft_strdup(env_value)); +} + +char *expand_tilde(char *path, t_shell *shell) +{ + char *home; + char *result; + + if (!path || path[0] != '~') + return (ft_strdup(path)); + home = ft_get_env_var(shell->env, "HOME"); + if (!home) + return (ft_strdup(path)); + if (path[1] == '\0') + return (ft_strdup(home)); + if (path[1] == '/') + { + result = ft_strjoin(home, path + 1); + return (result); + } + return (ft_strdup(path)); +} + +int validate_cd_args(t_cmd *cmd, t_shell *shell) +{ + if (!cmd || !cmd->args) + return (1); + if (!cmd->args[1] || ft_strlen(cmd->args[1]) == 0) + return (handle_home_directory(shell)); + if (ft_strcmp(cmd->args[1], "-") == 0) + return (handle_previous_directory(shell)); + if (ft_strcmp(cmd->args[1], "~") == 0) + return (handle_home_directory(shell)); + if (cmd->args[1] && cmd->args[2]) + { + ft_putendl_fd("cd: too many arguments", STDERR_FILENO); + return (1); + } + return (0); +} + +int ft_cd(t_cmd *cmd, t_shell *shell) +{ + char *path; + char *resolved_path; + int validation_result; + int status; + + validation_result = validate_cd_args(cmd, shell); + if (validation_result != 0) + return (validation_result); + path = cmd->args[1]; + resolved_path = resolve_cd_path(path, shell); + if (!resolved_path) + return (1); + if (execute_cd_change(resolved_path) != 0) + return (1); + status = update_pwd_env(shell); + return (status); +} diff --git a/src/builtins/cd_utils.c b/src/builtins/cd_utils.c new file mode 100644 index 0000000..ec782ab --- /dev/null +++ b/src/builtins/cd_utils.c @@ -0,0 +1,130 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cd_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/01 21:31:25 by tordner #+# #+# */ +/* Updated: 2025/06/01 21:35:44 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int handle_home_directory(t_shell *shell) +{ + char *home; + + home = ft_get_env_var(shell->env, "HOME"); + if (home == NULL) + { + ft_putendl_fd("cd: HOME not set", STDERR_FILENO); + return (1); + } + if (chdir(home) == -1) + { + ft_putstr_fd("cd: ", STDERR_FILENO); + ft_putstr_fd(home, STDERR_FILENO); + ft_putstr_fd(": ", STDERR_FILENO); + perror(""); + return (1); + } + return (0); +} + +int handle_previous_directory(t_shell *shell) +{ + char *oldpwd; + + oldpwd = ft_get_env_var(shell->env, "OLDPWD"); + if (oldpwd == NULL) + { + ft_putendl_fd("cd: OLDPWD not set", STDERR_FILENO); + return (1); + } + ft_putendl_fd(oldpwd, STDOUT_FILENO); + if (chdir(oldpwd) == -1) + { + ft_putstr_fd("cd: ", STDERR_FILENO); + ft_putstr_fd(oldpwd, STDERR_FILENO); + ft_putstr_fd(": ", STDERR_FILENO); + perror(""); + return (1); + } + return (0); +} + +// char *resolve_cd_path(char *path, t_shell *shell) +// { +// char *resolved_path; + +// if (path && path[0] == '~') +// resolved_path = expand_tilde(path, shell); +// else if (path && path[0] == '$') +// { +// resolved_path = resolve_env_variables(path, shell); +// if (!resolved_path || ft_strlen(resolved_path) == 0) +// { +// ft_putstr_fd("cd: ", STDERR_FILENO); +// ft_putstr_fd(path, STDERR_FILENO); +// ft_putendl_fd(": No such file or directory", STDERR_FILENO); +// if (resolved_path) +// free(resolved_path); +// return (NULL); +// } +// } +// else +// resolved_path = ft_strdup(path); +// return (resolved_path); +// } + +char *resolve_cd_path(char *path, t_shell *shell) +{ + char *resolved_path; + char *home; + + if (!path) + { + home = get_env_value("HOME", shell); + if (!home) + { + ft_putendl_fd("minishell: cd: HOME not set", STDERR_FILENO); + return (NULL); + } + return (ft_strdup(home)); + } + if (path[0] == '~') + resolved_path = expand_tilde(path, shell); + else if (path[0] == '$') + { + resolved_path = resolve_env_variables(path, shell); + if (!resolved_path || ft_strlen(resolved_path) == 0) + { + ft_putstr_fd("cd: ", STDERR_FILENO); + ft_putstr_fd(path, STDERR_FILENO); + ft_putendl_fd(": No such file or directory", STDERR_FILENO); + if (resolved_path) + free(resolved_path); + return (NULL); + } + } + else + resolved_path = ft_strdup(path); + return (resolved_path); +} + +int execute_cd_change(char *resolved_path) +{ + if (chdir(resolved_path) == -1) + { + ft_putstr_fd("cd: ", STDERR_FILENO); + ft_putstr_fd(resolved_path, STDERR_FILENO); + ft_putstr_fd(": ", STDERR_FILENO); + perror(""); + free(resolved_path); + return (1); + } + free(resolved_path); + return (0); +} diff --git a/src/builtins/echo.c b/src/builtins/echo.c new file mode 100644 index 0000000..d05b52e --- /dev/null +++ b/src/builtins/echo.c @@ -0,0 +1,73 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* echo.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/30 17:17:08 by thorgal #+# #+# */ +/* Updated: 2025/06/02 00:22:51 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int is_valid_n_option(char *str) +{ + int i; + + if (!str || str[0] != '-' || str[1] != 'n') + return (0); + i = 2; + while (str[i]) + { + if (str[i] != 'n') + return (0); + i++; + } + return (1); +} + +void print_echo_args(char **args, int i, int first) +{ + if (!args) + return ; + while (args[i]) + { + if (!args[i]) + i++; + else + { + if (!first) + printf(" "); + printf("%s", args[i]); + first = 0; + i++; + } + } +} + +int ft_echo(t_cmd *cmd, t_shell *shell) +{ + int print_newline; + int i; + char **args; + int first; + + (void)shell; + if (!cmd || !cmd->args) + return (1); + i = 1; + print_newline = 1; + args = cmd->args; + while (args[i] && is_valid_n_option(args[i])) + { + print_newline = 0; + i++; + } + first = 1; + print_echo_args(args, i, first); + if (print_newline) + printf("\n"); + return (0); +} diff --git a/src/builtins/env.c b/src/builtins/env.c new file mode 100644 index 0000000..ed53212 --- /dev/null +++ b/src/builtins/env.c @@ -0,0 +1,35 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* env.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/04 15:49:05 by thorgal #+# #+# */ +/* Updated: 2025/06/01 21:28:22 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int ft_env(t_shell *shell, t_cmd *cmd) +{ + int i; + + i = 0; + if (!shell->env) + return (1); + if (cmd && cmd->args && cmd->args[1]) + { + ft_putstr_fd("env: '", 2); + ft_putstr_fd(cmd->args[1], 2); + ft_putstr_fd("': No such file or directory\n", 2); + return (127); + } + while (shell->env[i]) + { + printf("%s\n", shell->env[i]); + i++; + } + return (0); +} diff --git a/src/builtins/exit.c b/src/builtins/exit.c new file mode 100644 index 0000000..a29304a --- /dev/null +++ b/src/builtins/exit.c @@ -0,0 +1,110 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exit.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/19 10:00:00 by lfirmin #+# #+# */ +/* Updated: 2025/06/01 21:30:31 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" +#include +#include + +static long long parse_digits(char *str, int *i, int sign, int *overflow) +{ + long long result; + + result = 0; + while (str[*i] >= '0' && str[*i] <= '9') + { + if (sign == 1 && check_positive_overflow(result, str[*i])) + { + *overflow = 1; + return (LLONG_MAX); + } + if (sign == -1 && check_negative_overflow(result, str[*i])) + { + *overflow = 1; + return (LLONG_MIN); + } + result = result * 10 + (str[*i] - '0'); + (*i)++; + } + return (result); +} + +static long long safe_atoll(char *str, int *overflow) +{ + long long result; + int sign; + int i; + + result = 0; + sign = 1; + i = 0; + *overflow = 0; + if (str[i] == '-' || str[i] == '+') + { + if (str[i] == '-') + sign = -1; + i++; + } + result = parse_digits(str, &i, sign, overflow); + return (result * sign); +} + +static void print_numeric_error(char *arg, t_shell *shell) +{ + ft_putstr_fd("minishell: exit: ", 2); + ft_putstr_fd(arg, 2); + ft_putstr_fd(": numeric argument required\n", 2); + shell->exit_status = 2; + shell->running = 0; +} + +static int handle_exit_argument(t_cmd *cmd, t_shell *shell, int *exit_code) +{ + long long num; + int overflow; + + if (!is_valid_number(cmd->args[1])) + { + print_numeric_error(cmd->args[1], shell); + return (2); + } + num = safe_atoll(cmd->args[1], &overflow); + if (overflow) + { + print_numeric_error(cmd->args[1], shell); + return (2); + } + *exit_code = (unsigned char)(num % 256); + if (cmd->args[2]) + { + ft_putstr_fd("minishell: exit: too many arguments\n", 2); + return (1); + } + return (0); +} + +int ft_exit(t_cmd *cmd, t_shell *shell) +{ + int exit_code; + int result; + + printf("exit\n"); + exit_code = shell->exit_status; + if (cmd->args[1]) + { + result = handle_exit_argument(cmd, shell, &exit_code); + if (result != 0) + return (result); + } + shell->exit_status = exit_code; + shell->running = 0; + return (exit_code); +} diff --git a/src/builtins/exit_utils.c b/src/builtins/exit_utils.c new file mode 100644 index 0000000..bcd5fae --- /dev/null +++ b/src/builtins/exit_utils.c @@ -0,0 +1,47 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exit_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/23 11:41:05 by lfirmin #+# #+# */ +/* Updated: 2025/06/01 21:35:36 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int is_valid_number(char *str) +{ + int i; + + i = 0; + if (!str || !str[0]) + return (0); + if (str[i] == '-' || str[i] == '+') + i++; + if (!str[i]) + return (0); + while (str[i]) + { + if (!ft_isdigit(str[i])) + return (0); + i++; + } + return (1); +} + +int check_positive_overflow(long long result, char digit) +{ + if (result > (LLONG_MAX - (digit - '0')) / 10) + return (1); + return (0); +} + +int check_negative_overflow(long long result, char digit) +{ + if (result > (-(LLONG_MIN + (digit - '0'))) / 10) + return (1); + return (0); +} diff --git a/src/builtins/export.c b/src/builtins/export.c new file mode 100644 index 0000000..26cc611 --- /dev/null +++ b/src/builtins/export.c @@ -0,0 +1,126 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* export.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/23 11:54:38 by lfirmin #+# #+# */ +/* Updated: 2025/06/01 21:30:55 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +int update_env_var(char **env, char *var) +{ + int i; + char *equal_sign; + int var_name_len; + + equal_sign = ft_strchr(var, '='); + if (!equal_sign) + return (0); + var_name_len = equal_sign - var; + i = 0; + while (env[i]) + { + if (ft_strncmp(env[i], var, var_name_len) == 0 + && (env[i][var_name_len] == '=' || env[i][var_name_len] == '\0')) + { + free(env[i]); + env[i] = ft_strdup(var); + if (!env[i]) + return (-1); + return (1); + } + i++; + } + return (0); +} + +int handle_export_validation(char *arg) +{ + int validity; + + validity = is_valid_identifier(arg); + if (validity <= 0) + { + ft_putstr_fd("export: '", 2); + ft_putstr_fd(arg, 2); + if (validity == -1) + { + ft_putstr_fd("': option invalide\n", 2); + return (2); + } + else + ft_putstr_fd("': not a valid identifier\n", 2); + return (1); + } + return (0); +} + +int process_single_export_arg(t_shell *shell, char *arg) +{ + int validation_result; + int status; + + validation_result = handle_export_validation(arg); + if (validation_result > 0) + { + if (validation_result == 2) + return (2); + return (1); + } + if (ft_strchr(arg, '=')) + { + status = handle_env_var(shell, arg); + if (status != 0) + return (status); + } + return (0); +} + +int process_export_args(t_shell *shell, char **args, int i) +{ + int ret; + int status; + int success; + + ret = 1; + success = 0; + while (args[i]) + { + status = process_single_export_arg(shell, args[i]); + if (status == 2) + return (2); + if (status == 1) + { + i++; + continue ; + } + if (status == 0) + success = 1; + i++; + } + if (success) + ret = 0; + return (ret); +} + +int ft_export(t_shell *shell, t_cmd *cmd) +{ + int i; + + if (!cmd->args[1]) + { + i = 0; + while (shell->env[i]) + { + printf("declare -x %s\n", shell->env[i]); + i++; + } + return (0); + } + return (process_export_args(shell, cmd->args, 1)); +} diff --git a/src/builtins/export_utils.c b/src/builtins/export_utils.c new file mode 100644 index 0000000..305041a --- /dev/null +++ b/src/builtins/export_utils.c @@ -0,0 +1,99 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* export_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/23 11:57:58 by lfirmin #+# #+# */ +/* Updated: 2025/06/01 21:39:05 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +char *handle_quotes_in_env_var(char *arg) +{ + char *equal_sign; + char *var_name; + char *var_value; + char *clean_value; + char *result; + + equal_sign = ft_strchr(arg, '='); + if (!equal_sign) + return (ft_strdup(arg)); + var_name = ft_substr(arg, 0, equal_sign - arg + 1); + if (!var_name) + return (NULL); + var_value = equal_sign + 1; + clean_value = malloc(ft_strlen(var_value) + 1); + if (!clean_value) + return (free(var_name), NULL); + process_quotes(var_value, clean_value); + result = ft_strjoin(var_name, clean_value); + free(var_name); + free(clean_value); + return (result); +} + +static int handle_expansion_error(char *expanded_arg) +{ + if (!expanded_arg) + { + ft_putstr_fd("export: memory allocation error\n", 2); + return (1); + } + return (0); +} + +static int handle_processing_error(char *expanded_arg, char *processed_arg) +{ + free(expanded_arg); + if (!processed_arg) + { + ft_putstr_fd("export: memory allocation error\n", 2); + return (1); + } + return (0); +} + +static int handle_update_result(t_shell *shell, char *processed_arg, + int update_result) +{ + if (update_result == 0) + { + shell->env = add_env_var(shell->env, processed_arg); + free(processed_arg); + if (!shell->env) + { + ft_putstr_fd("export: memory allocation error\n", 2); + return (1); + } + } + else if (update_result == -1) + { + free(processed_arg); + ft_putstr_fd("export: memory allocation error\n", 2); + return (1); + } + else + free(processed_arg); + return (0); +} + +int handle_env_var(t_shell *shell, char *arg) +{ + int update_result; + char *expanded_arg; + char *processed_arg; + + expanded_arg = expand_env_variables(arg, shell->env); + if (handle_expansion_error(expanded_arg)) + return (1); + processed_arg = handle_quotes_in_env_var(expanded_arg); + if (handle_processing_error(expanded_arg, processed_arg)) + return (1); + update_result = update_env_var(shell->env, processed_arg); + return (handle_update_result(shell, processed_arg, update_result)); +} diff --git a/src/builtins/export_utils2.c b/src/builtins/export_utils2.c new file mode 100644 index 0000000..60c3fdf --- /dev/null +++ b/src/builtins/export_utils2.c @@ -0,0 +1,117 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* export_utils2.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/01 21:39:14 by tordner #+# #+# */ +/* Updated: 2025/06/01 21:40:08 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +int is_valid_identifier(char *str) +{ + int i; + + if (!str || !*str) + return (0); + if (str[0] == '-') + return (-1); + if (!((str[0] >= 'a' && str[0] <= 'z') + || (str[0] >= 'A' && str[0] <= 'Z') + || str[0] == '_')) + return (0); + i = 1; + while (str[i] && str[i] != '=') + { + if (!((str[i] >= 'a' && str[i] <= 'z') + || (str[i] >= 'A' && str[i] <= 'Z') + || (str[i] >= '0' && str[i] <= '9') + || str[i] == '_')) + return (0); + i++; + } + return (1); +} + +char *process_single_var(char *result, char *var_start, char *var_end, + char **env) +{ + char *var_name; + char *var_value; + char *new_result; + + var_name = extract_var_name(result, var_start, var_end); + if (!var_name) + return (free(result), NULL); + var_value = get_env_value_for_expansion(env, var_name); + if (!var_value) + var_value = ""; + new_result = build_expanded_string(result, var_start, var_end, var_value); + free(var_name); + free(result); + return (new_result); +} + +char *expand_env_variables(char *str, char **env) +{ + char *result; + char *var_start; + char *var_end; + + if (!str) + return (NULL); + result = ft_strdup(str); + if (!result) + return (NULL); + while (find_next_var(result, &var_start, &var_end) && var_start) + { + result = process_single_var(result, var_start, var_end, env); + if (!result) + return (NULL); + } + return (result); +} + +void handle_quote_char(char *var_value, int *i, int *in_quotes, + char *quote_type) +{ + if (!*in_quotes && (var_value[*i] == '\'' || var_value[*i] == '"')) + { + *in_quotes = 1; + *quote_type = var_value[*i]; + (*i)++; + } + else if (*in_quotes && var_value[*i] == *quote_type) + { + *in_quotes = 0; + *quote_type = 0; + (*i)++; + } +} + +char *process_quotes(char *var_value, char *clean_value) +{ + int i; + int j; + int in_quotes; + char quote_type; + + i = 0; + j = 0; + in_quotes = 0; + quote_type = 0; + while (var_value[i]) + { + if ((var_value[i] == '\'' || var_value[i] == '"')) + handle_quote_char(var_value, &i, &in_quotes, "e_type); + else + clean_value[j++] = var_value[i++]; + } + clean_value[j] = '\0'; + return (clean_value); +} +// char **add_env_var(char **env, char *new_var) in utils.c diff --git a/src/builtins/export_utils_3.c b/src/builtins/export_utils_3.c new file mode 100644 index 0000000..48a6352 --- /dev/null +++ b/src/builtins/export_utils_3.c @@ -0,0 +1,89 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* export_utils3.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/01 21:39:14 by tordner #+# #+# */ +/* Updated: 2025/06/01 21:40:08 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +char *get_env_value_for_expansion(char **env, char *var_name) +{ + int i; + int var_len; + char *equal_pos; + + if (!env || !var_name) + return (NULL); + var_len = ft_strlen(var_name); + i = 0; + while (env[i]) + { + equal_pos = ft_strchr(env[i], '='); + if (equal_pos && (equal_pos - env[i]) == var_len + && ft_strncmp(env[i], var_name, var_len) == 0) + return (equal_pos + 1); + i++; + } + return (NULL); +} + +char *extract_var_name(char *result, char *var_start, char *var_end) +{ + return (ft_substr(result, var_start - result + 1, var_end - var_start - 1)); +} + +char *build_expanded_string(char *result, char *var_start, char *var_end, + char *var_value) +{ + char *before_var; + char *after_var; + char *temp; + char *final_result; + + before_var = ft_substr(result, 0, var_start - result); + after_var = ft_strdup(var_end); + if (!before_var || !after_var) + { + free(before_var); + free(after_var); + return (NULL); + } + temp = ft_strjoin(before_var, var_value); + free(before_var); + if (!temp) + { + free(after_var); + return (NULL); + } + final_result = ft_strjoin(temp, after_var); + free(temp); + free(after_var); + return (final_result); +} + +char *find_next_var(char *result, char **var_start, char **var_end) +{ + char *temp; + + *var_start = ft_strchr(result, '$'); + if (!*var_start) + return (result); + *var_end = *var_start + 1; + while (**var_end && (ft_isalnum(**var_end) || **var_end == '_')) + (*var_end)++; + if (*var_end == *var_start + 1) + { + temp = ft_strchr(*var_start + 1, '$'); + if (!temp) + return (result); + *var_start = temp; + return (find_next_var(result, var_start, var_end)); + } + return (result); +} diff --git a/src/builtins/pwd.c b/src/builtins/pwd.c new file mode 100644 index 0000000..e05077d --- /dev/null +++ b/src/builtins/pwd.c @@ -0,0 +1,26 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* pwd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/23 11:41:22 by lfirmin #+# #+# */ +/* Updated: 2025/04/23 11:41:34 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int ft_pwd(void) +{ + static char pwd[PATH_MAX]; + + if (getcwd(pwd, PATH_MAX) == NULL) + { + perror("getcwd() error"); + return (1); + } + printf("%s\n", pwd); + return (0); +} diff --git a/src/builtins/unset.c b/src/builtins/unset.c new file mode 100644 index 0000000..95badc1 --- /dev/null +++ b/src/builtins/unset.c @@ -0,0 +1,59 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* unset.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/23 03:34:29 by lfirmin #+# #+# */ +/* Updated: 2025/05/19 09:08:02 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int delete_line(char **array, int index) +{ + if (!array[index]) + return (0); + free(array[index]); + while (array[index + 1]) + { + array[index] = array[index + 1]; + index++; + } + array[index] = NULL; + return (1); +} + +int find_env_var(char **env, char *var) +{ + int i; + int len; + + i = 0; + len = ft_strlen(var); + while (env[i]) + { + if (ft_strncmp(env[i], var, len) == 0 && env[i][len] == '=') + return (i); + i++; + } + return (-1); +} + +int ft_unset(t_shell *shell, t_cmd *cmd) +{ + int i; + int index; + + i = 1; + while (cmd->args[i]) + { + index = find_env_var(shell->env, cmd->args[i]); + if (index != -1) + delete_line(shell->env, index); + i++; + } + return (0); +} diff --git a/src/exec/exec.c b/src/exec/exec.c new file mode 100644 index 0000000..dfb2209 --- /dev/null +++ b/src/exec/exec.c @@ -0,0 +1,41 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exec.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/12/02 13:25:52 by tordner #+# #+# */ +/* Updated: 2025/06/03 04:11:33 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int file_exists(const char *path) +{ + return (access(path, F_OK)); +} + +char *execute_ve_2(t_cmd *cmd, char *path_env, char *full_path) +{ + if (!path_env) + { + write(2, "Error: PATH not found\n", 22); + exit(127); + } + full_path = find_command(ft_split(path_env, ':'), cmd->args[0]); + if (!full_path) + { + write(2, "Error: Command not found\n", 25); + exit(127); + } + return (full_path); +} + +void run_child_process(t_cmd *cmd, char **envp) +{ + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + execute_ve(cmd, envp); +} diff --git a/src/exec/exec_utils.c b/src/exec/exec_utils.c new file mode 100644 index 0000000..85af292 --- /dev/null +++ b/src/exec/exec_utils.c @@ -0,0 +1,93 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exec_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/02 00:42:13 by tordner #+# #+# */ +/* Updated: 2025/06/02 01:03:26 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int setup_pipe(int pipefd[2]) +{ + if (pipe(pipefd) == -1) + { + write(2, "Error creating pipe\n", 21); + return (1); + } + return (0); +} + +int open_file(char *file, int flags, int mode) +{ + int fd; + + if (!file) + return (-1); + fd = open(file, flags, mode); + if (fd == -1) + { + perror(file); + return (-1); + } + return (fd); +} + +int wait_for_children(pid_t last_pid) +{ + int status; + int exit_status; + pid_t pid; + + exit_status = 0; + pid = wait(&status); + while (pid > 0) + { + if (WIFEXITED(status)) + { + if (pid == last_pid || last_pid == -1) + exit_status = WEXITSTATUS(status); + } + else if (WIFSIGNALED(status)) + { + exit_status = 128 + WTERMSIG(status); + if (WTERMSIG(status) == SIGINT) + g_signal = 128 + SIGINT; + else if (WTERMSIG(status) == SIGQUIT) + g_signal = 128 + SIGQUIT; + } + pid = wait(&status); + } + return (exit_status); +} + +void handle_child(t_cmd *cmd, int infile, int pipefd[2], t_shell *shell) +{ + set_signal_child(); + if (cmd->redir && setup_input_redirections(cmd->redir) != 0) + exit(1); + if (!has_input_redirection(cmd->redir)) + { + if (dup2(infile, STDIN_FILENO) == -1) + exit(1); + } + if (cmd->next && dup2(pipefd[1], STDOUT_FILENO) == -1) + exit(1); + if (infile != STDIN_FILENO) + close(infile); + if (cmd->next) + { + close(pipefd[0]); + close(pipefd[1]); + } + if (cmd->redir && setup_output_redirections(cmd->redir) != 0) + exit(1); + if (is_builtin(cmd->args[0])) + exit(execute_builtin(cmd, shell)); + execute_ve(cmd, shell->env); + exit(1); +} diff --git a/src/exec/execute_pipeline.c b/src/exec/execute_pipeline.c new file mode 100644 index 0000000..9c74095 --- /dev/null +++ b/src/exec/execute_pipeline.c @@ -0,0 +1,52 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* execute_pipeline.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 03:04:07 by tordner #+# #+# */ +/* Updated: 2025/06/03 03:04:35 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int handle_single_builtin(t_cmd *cmd, t_shell *shell) +{ + int saved_stdin; + int saved_stdout; + int redir_status; + + if (!cmd->redir) + return (execute_builtin(cmd, shell)); + saved_stdin = dup(STDIN_FILENO); + saved_stdout = dup(STDOUT_FILENO); + shell->signaled = 0; + redir_status = loop_open_files(cmd); + if (redir_status != 0) + { + restore_fds(saved_stdin, saved_stdout); + return (1); + } + shell->exit_status = execute_builtin(cmd, shell); + restore_fds(saved_stdin, saved_stdout); + if (g_signal) + { + shell->signaled = 1; + shell->exit_status = g_signal; + } + return (shell->exit_status); +} + +static int handle_pipeline(t_cmd *cmd_list, t_shell *shell) +{ + return (spawn_pipeline(cmd_list, shell)); +} + +int execute_pipeline(t_cmd *cmd_list, t_shell *shell) +{ + if (cmd_list && !cmd_list->next && is_builtin(cmd_list->args[0])) + return (handle_single_builtin(cmd_list, shell)); + return (handle_pipeline(cmd_list, shell)); +} diff --git a/src/exec/execute_ve.c b/src/exec/execute_ve.c new file mode 100644 index 0000000..30d1c75 --- /dev/null +++ b/src/exec/execute_ve.c @@ -0,0 +1,61 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* execute_ve.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 03:53:31 by tordner #+# #+# */ +/* Updated: 2025/06/03 04:01:20 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" +#include + +static int check_absolute_path(t_cmd *cmd) +{ + struct stat file_stat; + + if (file_exists(cmd->args[0]) != 0) + { + ft_putstr_fd(cmd->args[0], 2); + ft_putstr_fd(": No such file or directory\n", 2); + exit(127); + } + if (stat(cmd->args[0], &file_stat) == 0 && S_ISDIR(file_stat.st_mode)) + { + ft_putstr_fd(cmd->args[0], 2); + ft_putstr_fd(": Is a directory\n", 2); + exit(126); + } + if (access(cmd->args[0], X_OK) == 0) + return (1); + ft_putstr_fd(cmd->args[0], 2); + ft_putstr_fd(": Permission denied\n", 2); + exit(126); +} + +static void handle_path_execution(t_cmd *cmd, char **envp) +{ + char *full_path; + char *path_env; + + path_env = get_path_env(envp); + full_path = execute_ve_2(cmd, path_env, NULL); + if (full_path) + execve(full_path, cmd->args, envp); + ft_putstr_fd("Error: Command execution failed\n", 2); + exit(126); +} + +int execute_ve(t_cmd *cmd, char **envp) +{ + if (cmd->args[0][0] == '/' || cmd->args[0][0] == '.') + { + if (check_absolute_path(cmd)) + execve(cmd->args[0], cmd->args, envp); + } + handle_path_execution(cmd, envp); + return (0); +} diff --git a/src/exec/file_handler.c b/src/exec/file_handler.c new file mode 100644 index 0000000..7147f30 --- /dev/null +++ b/src/exec/file_handler.c @@ -0,0 +1,74 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* file_handler.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/12/02 16:27:31 by tordner #+# #+# */ +/* Updated: 2025/06/03 03:51:22 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int loop_open_files(t_cmd *cmd) +{ + t_redirection *redir; + int result; + + if (!cmd || !cmd->redir) + return (0); + redir = cmd->redir; + while (redir) + { + result = setup_files(redir); + if (result != 0) + return (result); + redir = redir->next; + } + return (0); +} + +int setup_input_redirections(t_redirection *redir) +{ + int fd; + t_redirection *current; + + current = redir; + while (current) + { + if (current->type == 1) + { + fd = open(current->file, O_RDONLY); + if (fd == -1) + { + perror(current->file); + return (1); + } + dup2(fd, STDIN_FILENO); + close(fd); + } + else if (current->type == 4) + { + if (handle_heredoc(current->file) != 0) + return (1); + } + current = current->next; + } + return (0); +} + +int has_input_redirection(t_redirection *redir) +{ + t_redirection *current; + + current = redir; + while (current) + { + if (current->type == 1 || current->type == 4) + return (1); + current = current->next; + } + return (0); +} diff --git a/src/exec/ft_exec.c b/src/exec/ft_exec.c new file mode 100644 index 0000000..af00a1b --- /dev/null +++ b/src/exec/ft_exec.c @@ -0,0 +1,56 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_exec.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 04:08:12 by tordner #+# #+# */ +/* Updated: 2025/06/03 04:09:39 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static void handle_child_process(t_cmd *cmd, char **envp) +{ + if (cmd->redir) + { + if (loop_open_files(cmd) != 0) + exit(1); + } + run_child_process(cmd, envp); +} + +static int get_exit_status(int status) +{ + if (WIFEXITED(status)) + return (WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + { + if (WTERMSIG(status) == SIGINT) + return (130); + return (128 + WTERMSIG(status)); + } + return (1); +} + +int ft_exec(t_cmd *cmd, char **envp, t_shell *shell) +{ + pid_t pid; + int status; + + shell->child_running = 1; + pid = fork(); + if (pid == -1) + { + write(2, "Error forking process\n", 23); + shell->child_running = 0; + return (1); + } + if (pid == 0) + handle_child_process(cmd, envp); + waitpid(pid, &status, 0); + shell->child_running = 0; + return (get_exit_status(status)); +} diff --git a/src/exec/get_env.c b/src/exec/get_env.c new file mode 100644 index 0000000..3a8c41d --- /dev/null +++ b/src/exec/get_env.c @@ -0,0 +1,68 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* get_env.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/12/03 16:30:02 by tordner #+# #+# */ +/* Updated: 2025/04/19 12:39:55 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +char *join_path(char *directory, char *cmd) +{ + char *path; + size_t dir_len; + size_t cmd_len; + size_t total_len; + + dir_len = ft_strlen(directory); + cmd_len = ft_strlen(cmd); + total_len = dir_len + cmd_len + 2; + path = malloc(total_len); + if (!path) + return (NULL); + ft_strcpy(path, directory); + path[dir_len] = '/'; + ft_strcpy(path + dir_len + 1, cmd); + return (path); +} + +char *get_path_env(char **envp) +{ + int i; + char *path_env; + + i = 0; + path_env = NULL; + while (envp[i]) + { + if (ft_strncmp(envp[i], "PATH=", 5) == 0) + { + path_env = envp[i] + 5; + break ; + } + i++; + } + return (path_env); +} + +char *find_command(char **paths, char *cmd) +{ + char *full_path; + int i; + + i = 0; + while (paths[i]) + { + full_path = join_path(paths[i], cmd); + if (access(full_path, X_OK) == 0) + return (full_path); + free(full_path); + i++; + } + return (NULL); +} diff --git a/src/exec/heredoc.c b/src/exec/heredoc.c new file mode 100644 index 0000000..79f1187 --- /dev/null +++ b/src/exec/heredoc.c @@ -0,0 +1,67 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* heredoc.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/23 01:17:12 by lfirmin #+# #+# */ +/* Updated: 2025/06/03 03:37:59 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +static int create_heredoc_pipe(int pipefd[2]) +{ + if (pipe(pipefd) == -1) + { + perror("minishell: pipe"); + return (1); + } + return (0); +} + +static void process_heredoc_input(int pipefd[2], char *delim) +{ + char *line; + + while (1) + { + line = readline("> "); + if (!line) + { + ft_putstr_fd(\ + "minishell: warning: here-document delimited " + "by end-of-file\n", 2); + break ; + } + if (ft_strcmp(line, delim) == 0) + { + free(line); + break ; + } + write(pipefd[1], line, ft_strlen(line)); + write(pipefd[1], "\n", 1); + free(line); + } +} + +int handle_heredoc(char *delim) +{ + int pipefd[2]; + + if (!delim) + return (1); + if (create_heredoc_pipe(pipefd)) + return (1); + process_heredoc_input(pipefd, delim); + close(pipefd[1]); + if (dup2(pipefd[0], STDIN_FILENO) == -1) + { + close(pipefd[0]); + return (1); + } + close(pipefd[0]); + return (0); +} diff --git a/src/exec/pipe.c b/src/exec/pipe.c new file mode 100644 index 0000000..d453dd4 --- /dev/null +++ b/src/exec/pipe.c @@ -0,0 +1,83 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* pipe.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/12/02 13:25:59 by tordner #+# #+# */ +/* Updated: 2025/06/03 03:05:55 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +void handle_parent(int *infile, int pipefd[2], t_cmd *cmd) +{ + if (*infile != STDIN_FILENO) + close(*infile); + if (cmd->next) + { + close(pipefd[1]); + *infile = pipefd[0]; + } + else if (pipefd[0] != -1) + close(pipefd[0]); +} + +int run_child_pipe(t_cmd *cmd, t_shell *shell, int *infile) +{ + int pipefd[2]; + pid_t pid; + + if (cmd->next && pipe(pipefd) == -1) + return (1); + else if (!cmd->next) + { + pipefd[0] = -1; + pipefd[1] = STDOUT_FILENO; + } + pid = fork(); + if (pid == -1) + return (1); + if (pid == 0) + handle_child(cmd, *infile, pipefd, shell); + handle_parent(infile, pipefd, cmd); + return (0); +} + +int spawn_pipeline(t_cmd *cmd, t_shell *shell) +{ + int infile; + int exit_status; + + shell->child_running = 1; + shell->signaled = 0; + set_signal_parent_exec(); + infile = STDIN_FILENO; + while (cmd) + { + if (run_child_pipe(cmd, shell, &infile) != 0) + { + shell->child_running = 0; + set_signal_parent(); + return (1); + } + cmd = cmd->next; + } + exit_status = 0; + exit_status = wait_for_children(-1); + shell->child_running = 0; + if (g_signal) + shell->signaled = 1; + set_signal_parent(); + return (exit_status); +} + +void restore_fds(int saved_stdin, int saved_stdout) +{ + dup2(saved_stdin, STDIN_FILENO); + dup2(saved_stdout, STDOUT_FILENO); + close(saved_stdin); + close(saved_stdout); +} diff --git a/src/exec/setup_files.c b/src/exec/setup_files.c new file mode 100644 index 0000000..2f430ad --- /dev/null +++ b/src/exec/setup_files.c @@ -0,0 +1,73 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* setup_files.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 03:42:14 by tordner #+# #+# */ +/* Updated: 2025/06/03 03:43:42 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int handle_input_redir(t_redirection *redir) +{ + int fd; + + fd = open(redir->file, O_RDONLY); + if (fd == -1) + { + perror(redir->file); + return (1); + } + dup2(fd, STDIN_FILENO); + close(fd); + return (0); +} + +static int handle_output_redir(t_redirection *redir) +{ + int fd; + + fd = open(redir->file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) + { + perror(redir->file); + return (1); + } + dup2(fd, STDOUT_FILENO); + close(fd); + return (0); +} + +static int handle_append_redir(t_redirection *redir) +{ + int fd; + + fd = open(redir->file, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (fd == -1) + { + perror(redir->file); + return (1); + } + dup2(fd, STDOUT_FILENO); + close(fd); + return (0); +} + +int setup_files(t_redirection *redir) +{ + if (!redir || !redir->file) + return (1); + if (redir->type == 1) + return (handle_input_redir(redir)); + else if (redir->type == 2) + return (handle_output_redir(redir)); + else if (redir->type == 3) + return (handle_append_redir(redir)); + else if (redir->type == 4) + return (handle_heredoc(redir->file)); + return (0); +} diff --git a/src/exec/setup_output_redirections.c b/src/exec/setup_output_redirections.c new file mode 100644 index 0000000..51194f3 --- /dev/null +++ b/src/exec/setup_output_redirections.c @@ -0,0 +1,65 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* setup_output_redirections.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 03:48:01 by tordner #+# #+# */ +/* Updated: 2025/06/03 03:48:24 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int handle_trunc_redir(t_redirection *redir) +{ + int fd; + + fd = open(redir->file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) + { + perror(redir->file); + return (1); + } + dup2(fd, STDOUT_FILENO); + close(fd); + return (0); +} + +static int handle_append_redir(t_redirection *redir) +{ + int fd; + + fd = open(redir->file, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (fd == -1) + { + perror(redir->file); + return (1); + } + dup2(fd, STDOUT_FILENO); + close(fd); + return (0); +} + +int setup_output_redirections(t_redirection *redir) +{ + t_redirection *current; + + current = redir; + while (current) + { + if (current->type == 2) + { + if (handle_trunc_redir(current)) + return (1); + } + else if (current->type == 3) + { + if (handle_append_redir(current)) + return (1); + } + current = current->next; + } + return (0); +} diff --git a/src/main/input.c b/src/main/input.c new file mode 100644 index 0000000..8ac65ec --- /dev/null +++ b/src/main/input.c @@ -0,0 +1,60 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* input.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/30 17:17:15 by lfirmin #+# #+# */ +/* Updated: 2025/06/03 04:15:00 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +char **parse_input(char *input, t_shell *shell) +{ + char **tokens; + int i; + + tokens = tokenize_command(input, shell); + if (!tokens) + { + printf(ERROR_TOKEN); + shell->exit_status = 1; + return (NULL); + } + if (validate_syntax(tokens)) + { + i = 0; + shell->exit_status = 2; + while (tokens[i]) + free(tokens[i++]); + free(tokens); + return (NULL); + } + return (tokens); +} + +void process_input(char *input, t_shell *shell) +{ + char **tokens; + int i; + int ret; + t_cmd *cmd_list; + + tokens = parse_input(input, shell); + if (!tokens) + return ; + cmd_list = parse_tokens_to_list(tokens); + if (cmd_list) + { + ret = execute_pipeline(cmd_list, shell); + shell->exit_status = ret; + free_cmd_list(cmd_list); + } + i = 0; + while (tokens[i]) + free(tokens[i++]); + free(tokens); +} diff --git a/src/main/main.c b/src/main/main.c new file mode 100644 index 0000000..1bce7dc --- /dev/null +++ b/src/main/main.c @@ -0,0 +1,95 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* main.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/30 17:17:15 by lfirmin #+# #+# */ +/* Updated: 2025/06/01 21:32:22 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +void initialize_shell(t_shell *shell, char **envp) +{ + shell->env = copy_env(envp); + shell->exit_status = 0; + shell->running = 1; + shell->signaled = 0; +} + +int is_builtin(char *cmd) +{ + return (ft_strcmp(cmd, "echo") == 0 + || ft_strcmp(cmd, "cd") == 0 + || ft_strcmp(cmd, "pwd") == 0 + || ft_strcmp(cmd, "exit") == 0 + || ft_strcmp(cmd, "env") == 0 + || ft_strcmp(cmd, "export") == 0 + || ft_strcmp(cmd, "unset") == 0); +} + +int execute_builtin(t_cmd *cmd, t_shell *shell) +{ + if (!cmd || !cmd->args || !cmd->args[0]) + return (1); + if (ft_strcmp(cmd->args[0], "echo") == 0) + return (ft_echo(cmd, shell)); + else if (ft_strcmp(cmd->args[0], "cd") == 0) + return (ft_cd(cmd, shell)); + else if (ft_strcmp(cmd->args[0], "pwd") == 0) + return (ft_pwd()); + else if (ft_strcmp(cmd->args[0], "exit") == 0) + return (ft_exit(cmd, shell)); + else if (ft_strcmp(cmd->args[0], "env") == 0) + return (ft_env(shell, cmd)); + else if (ft_strcmp(cmd->args[0], "export") == 0) + return (ft_export(shell, cmd)); + else if (ft_strcmp(cmd->args[0], "unset") == 0) + return (ft_unset(shell, cmd)); + return (1); +} + +int execute_command(t_cmd *cmd, t_shell *shell) +{ + int saved_stdin; + int saved_stdout; + + if (!cmd || !cmd->args || !cmd->args[0]) + return (1); + if (is_builtin(cmd->args[0])) + { + saved_stdin = dup(STDIN_FILENO); + saved_stdout = dup(STDOUT_FILENO); + if (cmd->redir) + loop_open_files(cmd); + shell->exit_status = execute_builtin(cmd, shell); + dup2(saved_stdin, STDIN_FILENO); + dup2(saved_stdout, STDOUT_FILENO); + close(saved_stdin); + close(saved_stdout); + } + else + shell->exit_status = ft_exec(cmd, shell->env, shell); + return (shell->exit_status); +} + +int main(void) +{ + t_shell shell; + extern char **environ; + int i; + + initialize_shell(&shell, environ); + minishell_loop(&shell); + if (shell.env) + { + i = 0; + while (shell.env[i]) + free(shell.env[i++]); + free(shell.env); + } + return (shell.exit_status); +} diff --git a/src/main/prompt.c b/src/main/prompt.c new file mode 100644 index 0000000..d6dd212 --- /dev/null +++ b/src/main/prompt.c @@ -0,0 +1,54 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* prompt.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 02:58:34 by tordner #+# #+# */ +/* Updated: 2025/06/03 02:58:59 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +char *create_standard_prompt(char *dir_name, int exit_status) +{ + char *prompt; + char *tmp; + + if (exit_status == 0) + { + tmp = ft_strjoin(GREEN "➜\001\033[0m\002 \001\033[1;36m\002", dir_name); + if (!tmp) + return (NULL); + prompt = ft_strjoin(tmp, "\001\033[0m\002 ❯ "); + free(tmp); + } + else + { + tmp = ft_strjoin(RED "➜\001\033[0m\002 \001\033[1;36m\002", dir_name); + if (!tmp) + return (NULL); + prompt = ft_strjoin(tmp, "\001\033[0m\002 ❯ "); + free(tmp); + } + return (prompt); +} + +char *generate_prompt(t_shell *shell) +{ + char *dir_name; + char *prompt; + + dir_name = get_current_dir_name(); + if (!dir_name) + return (ft_strdup("➜ ❯ ")); + else + prompt = create_standard_prompt(dir_name, shell->exit_status); + free(dir_name); + if (prompt) + return (prompt); + else + return (ft_strdup("➜ ❯ ")); +} diff --git a/src/main/shell.c b/src/main/shell.c new file mode 100644 index 0000000..26faa55 --- /dev/null +++ b/src/main/shell.c @@ -0,0 +1,77 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* shell.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/11/21 15:38:19 by lfirmin #+# #+# */ +/* Updated: 2025/06/03 03:01:28 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../includes/minishell.h" + +void handle_input(char *input, t_shell *shell) +{ + int i; + + i = 0; + while (input[i] && (input[i] == ' ' || input[i] == '\t')) + i++; + if (input[i] != '\0') + { + add_history(input); + process_input(input, shell); + } +} + +static void handle_signal_state(t_shell *shell) +{ + if (g_signal && !shell->child_running) + { + shell->exit_status = g_signal; + g_signal = 0; + } +} + +static char *get_input(char *prompt) +{ + char *input; + + input = readline(prompt); + free(prompt); + return (input); +} + +static void init_terminal_settings(void) +{ + struct termios term; + + tcgetattr(STDIN_FILENO, &term); + term.c_lflag &= ~(ECHOCTL); + tcsetattr(STDIN_FILENO, TCSANOW, &term); + rl_initialize(); +} + +void minishell_loop(t_shell *shell) +{ + char *input; + char *prompt; + + init_terminal_settings(); + while (shell->running) + { + set_signal_parent(); + prompt = generate_prompt(shell); + input = get_input(prompt); + if (!input) + { + printf("exit\n"); + break ; + } + handle_signal_state(shell); + handle_input(input, shell); + free(input); + } +} diff --git a/src/main/signals.c b/src/main/signals.c new file mode 100644 index 0000000..455ccdd --- /dev/null +++ b/src/main/signals.c @@ -0,0 +1,64 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* signals.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/27 00:00:00 by lfirmin #+# #+# */ +/* Updated: 2025/06/02 01:05:49 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "../../includes/minishell.h" + +int g_signal = 0; + +void if_sigint(int sig) +{ + g_signal = 128 + sig; + rl_done = 1; +} + +void set_status_if_signal(t_shell *shell) +{ + shell->exit_status = g_signal; + g_signal = 0; +} + +void set_signal_child(void) +{ + rl_event_hook = sig_event; + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGTSTP, SIG_IGN); +} + +void set_signal_parent_exec(void) +{ + struct sigaction sa; + struct sigaction sb; + + rl_event_hook = sig_event; + ft_memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handle_signal_parent; + sa.sa_flags = SA_RESTART; + sigaction(SIGINT, &sa, NULL); + ft_memset(&sb, 0, sizeof(sb)); + sb.sa_handler = handle_signal_parent; + sb.sa_flags = SA_RESTART; + sigaction(SIGQUIT, &sb, NULL); +} + +void set_signal_parent(void) +{ + struct sigaction sa; + + rl_event_hook = sig_event; + ft_memset(&sa, 0, sizeof(sa)); + sa.sa_handler = if_sigint; + sa.sa_flags = SA_RESTART; + sigaction(SIGINT, &sa, NULL); + signal(SIGQUIT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); +} diff --git a/src/main/signals_utils.c b/src/main/signals_utils.c new file mode 100644 index 0000000..71bf86f --- /dev/null +++ b/src/main/signals_utils.c @@ -0,0 +1,44 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* signals_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/02 00:58:26 by tordner #+# #+# */ +/* Updated: 2025/06/03 02:58:02 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +// void check_if_signal(t_shell *shell) +// { +// if (shell->signaled == 1 && g_signal == 128 + SIGQUIT) +// { +// ft_putstr_fd("Quit (core dumped)\n", 2); +// shell->exit_status = g_signal; +// } +// if (g_signal == 128 + SIGINT && shell->signaled == 1) +// { +// write(STDERR_FILENO, "\n", 1); +// shell->exit_status = g_signal; +// } +// if (shell->exit_status == 128 + SIGSEGV && shell->signaled == 1) +// ft_putstr_fd("Segmentation fault (core dumped)\n", STDERR_FILENO); +// if (shell->signaled == 1) +// { +// shell->signaled = 0; +// g_signal = 0; +// } +// } + +void handle_signal_parent(int num) +{ + g_signal = num + 128; +} + +int sig_event(void) +{ + return (EXIT_SUCCESS); +} diff --git a/src/tokens/check_pipes.c b/src/tokens/check_pipes.c new file mode 100644 index 0000000..7894bf2 --- /dev/null +++ b/src/tokens/check_pipes.c @@ -0,0 +1,98 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* check_pipes.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/03/06 16:55:42 by tordner #+# #+# */ +/* Updated: 2025/06/03 02:50:07 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +int check_before_pipe(char **tokens) +{ + int i; + + i = 0; + while (tokens[i]) + { + if (classify_token(tokens[i]) == TOKEN_PIPE && i > 0) + { + if (classify_token(tokens[i - 1]) == TOKEN_REDIRECTION_IN + || classify_token(tokens[i - 1]) == TOKEN_REDIRECTION_OUT + || classify_token(tokens[i - 1]) == TOKEN_APPEND + || classify_token(tokens[i - 1]) == TOKEN_HEREDOC) + return (1); + } + i++; + } + return (0); +} + +static int has_consecutive_pipes(char **tokens) +{ + int i; + + i = 0; + while (tokens[i]) + { + if (classify_token(tokens[i]) == TOKEN_PIPE && tokens[i + 1] + && classify_token(tokens[i + 1]) == TOKEN_PIPE) + return (1); + i++; + } + return (0); +} + +static int has_valid_command_after_pipe(char **tokens, int pipe_pos) +{ + int j; + int has_command; + + j = pipe_pos + 1; + has_command = 0; + while (tokens[j] && classify_token(tokens[j]) != TOKEN_PIPE) + { + if (classify_token(tokens[j]) == TOKEN_WORD) + { + if (j == pipe_pos + 1 \ + || classify_token(tokens[j - 1]) == TOKEN_WORD) + has_command = 1; + } + j++; + } + return (has_command); +} + +static int check_pipe_commands(char **tokens) +{ + int i; + + i = 0; + while (tokens[i]) + { + if (classify_token(tokens[i]) == TOKEN_PIPE && tokens[i + 1]) + { + if (!has_valid_command_after_pipe(tokens, i)) + return (1); + } + i++; + } + return (0); +} + +int pipe_sequence_invalid(char **tokens) +{ + if (!tokens) + return (1); + if (has_consecutive_pipes(tokens)) + return (1); + if (check_before_pipe(tokens)) + return (1); + if (check_pipe_commands(tokens)) + return (1); + return (0); +} diff --git a/src/tokens/check_redirections.c b/src/tokens/check_redirections.c new file mode 100644 index 0000000..09c4d8c --- /dev/null +++ b/src/tokens/check_redirections.c @@ -0,0 +1,92 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* check_redirections.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/03/06 17:17:19 by tordner #+# #+# */ +/* Updated: 2025/06/03 02:50:31 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +int is_redirection(char *token) +{ + t_token_type type; + + type = classify_token(token); + return (type == TOKEN_REDIRECTION_IN || type == TOKEN_REDIRECTION_OUT + || type == TOKEN_APPEND || type == TOKEN_HEREDOC); +} + +int check_further_redirections(char **tokens, int i) +{ + if (is_redirection(tokens[i]) && !tokens[i + 1]) + { + write(STDERR_FILENO, \ + "Syntax error: Redirection cannot appear at the end\n", 52); + return (2); + } + if (is_redirection(tokens[i]) && is_redirection(tokens[i + 1])) + { + write(STDERR_FILENO, "Syntax error: Consecutive redirection operators " + "are not allowed\n", 65); + return (2); + } + return (0); +} + +static int has_valid_command(char **tokens) +{ + int j; + int has_command; + + j = 0; + has_command = 0; + while (tokens[j]) + { + if (classify_token(tokens[j]) == TOKEN_WORD) + { + if (j == 0 || !is_redirection(tokens[j - 1])) + has_command = 1; + } + j++; + } + if (!has_command) + { + write(STDERR_FILENO, "Syntax error: No command found\n", 32); + return (0); + } + return (1); +} + +int validate_redirections(char **tokens) +{ + int i; + + if (!has_valid_command(tokens)) + return (2); + i = 0; + while (tokens[i]) + { + if (check_further_redirections(tokens, i)) + return (2); + i++; + } + return (0); +} + +int validate_pipes(char **tokens) +{ + int end; + + end = 0; + while (tokens[end + 1] != NULL) + end++; + if (classify_token(tokens[0]) == TOKEN_PIPE + || classify_token(tokens[end]) == TOKEN_PIPE) + return (1); + return (pipe_sequence_invalid(tokens)); +} diff --git a/src/tokens/expander.c b/src/tokens/expander.c new file mode 100644 index 0000000..19d7f63 --- /dev/null +++ b/src/tokens/expander.c @@ -0,0 +1,82 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* expander.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/01 22:59:57 by tordner #+# #+# */ +/* Updated: 2025/06/02 01:19:06 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static char *append_status(char *res, t_shell *sh, int *i) +{ + char *val; + char *tmp; + + val = ft_itoa(sh->exit_status); + tmp = ft_strjoin(res, val); + free(res); + free(val); + *i += 2; + return (tmp); +} + +static char *append_env(char *res, char *str, t_shell *sh, int *i) +{ + int start; + char *var; + char *val; + char *tmp; + + start = ++(*i); + while (str[*i] && (ft_isalnum(str[*i]) || str[*i] == '_')) + (*i)++; + var = ft_substr(str, start, *i - start); + val = get_env_value(var, sh); + if (!val) + val = ""; + tmp = ft_strjoin(res, val); + free(res); + free(var); + return (tmp); +} + +static char *append_char(char *res, char c) +{ + char buf[2]; + char *tmp; + + buf[0] = c; + buf[1] = '\0'; + tmp = ft_strjoin(res, buf); + free(res); + return (tmp); +} + +char *expand_variables(char *str, t_shell *sh) +{ + int i; + char *res; + + i = 0; + res = ft_calloc(1, 1); + while (str && str[i]) + { + if (str[i] == '$' && str[i + 1]) + { + if (str[i + 1] == '?') + res = append_status(res, sh, &i); + else if (ft_isalnum(str[i + 1]) || str[i + 1] == '_') + res = append_env(res, str, sh, &i); + else + res = append_char(res, str[i++]); + } + else + res = append_char(res, str[i++]); + } + return (res); +} diff --git a/src/tokens/extract_quoted_content.c b/src/tokens/extract_quoted_content.c new file mode 100644 index 0000000..58fb9dd --- /dev/null +++ b/src/tokens/extract_quoted_content.c @@ -0,0 +1,68 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* extract_quoted_content.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 00:39:01 by tordner #+# #+# */ +/* Updated: 2025/06/03 01:08:06 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int handle_double_quote_escape(t_escape_handler *m, int i) +{ + if (m->input[i + 1] == '"' || m->input[i + 1] == '\\' \ + || m->input[i + 1] == '$' || m->input[i + 1] == '`' \ + || m->input[i + 1] == '\n') + { + m->content[m->j++] = m->input[i + 1]; + return (2); + } + m->content[m->j++] = m->input[i]; + return (1); +} + +static int handle_single_quote_escape(t_escape_handler *m, int i) +{ + if (m->input[i + 1] == '\'') + { + m->content[m->j++] = '\''; + return (2); + } + m->content[m->j++] = m->input[i]; + return (1); +} + +static int handle_escapes(t_escape_handler *mini_data, char quote) +{ + if (quote == '"') + return (handle_double_quote_escape(mini_data, mini_data->i)); + else if (quote == '\'') + return (handle_single_quote_escape(mini_data, mini_data->i)); + mini_data->content[mini_data->j++] = mini_data->input[mini_data->i + 1]; + return (2); +} + +char *extract_quoted_content(char *input, int start, \ + int len, char quote_char) +{ + char *content; + t_escape_handler mini_data; + + content = malloc(sizeof(char) * (len + 1)); + if (!content) + return (NULL); + mini_data = (t_escape_handler){input, content, start, 0}; + while (mini_data.i < start + len) + { + if (input[mini_data.i] == '\\' && mini_data.i + 1 < start + len) + mini_data.i += handle_escapes(&mini_data, quote_char); + else + mini_data.content[mini_data.j++] = mini_data.input[mini_data.i++]; + } + mini_data.content[mini_data.j] = '\0'; + return (content); +} diff --git a/src/tokens/extract_token_len.c b/src/tokens/extract_token_len.c new file mode 100644 index 0000000..796e02a --- /dev/null +++ b/src/tokens/extract_token_len.c @@ -0,0 +1,64 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* extract_token_len.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 00:28:00 by tordner #+# #+# */ +/* Updated: 2025/06/03 00:28:37 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int skip_whitespace(char *input, int *index) +{ + while (input[*index] && (input[*index] == ' ' || input[*index] == '\t')) + (*index)++; + return (*index); +} + +static int handle_quotes_in_token(char *input, int *index) +{ + char quote; + + quote = input[*index]; + (*index)++; + while (input[*index] && input[*index] != quote) + (*index)++; + if (input[*index] == quote) + (*index)++; + return (0); +} + +static int handle_normal_token(char *input, int *index) +{ + while (input[*index] && !is_delimiter(input[*index]) && \ + !is_special(input[*index])) + { + if (input[*index] == '\'' || input[*index] == '\"') + handle_quotes_in_token(input, index); + else + (*index)++; + } + return (*index); +} + +int extract_token_len(char *input, int *index, int *start) +{ + int token_len; + + skip_whitespace(input, index); + *start = *index; + if (input[*index] == '\'' || input[*index] == '\"') + token_len = handle_quoted_token(input, index, start); + else if (is_special(input[*index])) + token_len = handle_special_token(input, index); + else + { + handle_normal_token(input, index); + token_len = *index - *start; + } + return (token_len); +} diff --git a/src/tokens/handle_quoted_count.c b/src/tokens/handle_quoted_count.c new file mode 100644 index 0000000..ac0531c --- /dev/null +++ b/src/tokens/handle_quoted_count.c @@ -0,0 +1,55 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* handle_quoted_count.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 00:36:34 by tordner #+# #+# */ +/* Updated: 2025/06/03 00:36:43 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int is_escaped_in_double_quote(char *str, int i) +{ + if (str[i + 1] == '"' || str[i + 1] == '\\' || str[i + 1] == '$' + || str[i + 1] == '`' || str[i + 1] == '\n') + return (1); + return (0); +} + +static int is_escaped_in_single_quote(char *str, int i) +{ + if (str[i + 1] == '\'') + return (1); + return (0); +} + +void handle_quoted_count(char *str, int *i, char quote) +{ + (*i)++; + while (str[*i]) + { + if (str[*i] == '\\' && str[*i + 1]) + { + if (quote == '"' && is_escaped_in_double_quote(str, *i)) + { + (*i) += 2; + continue ; + } + if (quote == '\'' && is_escaped_in_single_quote(str, *i)) + { + (*i) += 2; + continue ; + } + } + if (str[*i] == quote) + { + (*i)++; + break ; + } + (*i)++; + } +} diff --git a/src/tokens/syntax.c b/src/tokens/syntax.c new file mode 100644 index 0000000..0c7a5dd --- /dev/null +++ b/src/tokens/syntax.c @@ -0,0 +1,40 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* syntax.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/25 17:40:53 by thorgal #+# #+# */ +/* Updated: 2025/05/30 15:16:30 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +t_token_type classify_token(char *token) +{ + if (ft_strcmp(token, "|") == 0) + return (TOKEN_PIPE); + if (ft_strcmp(token, ">") == 0) + return (TOKEN_REDIRECTION_OUT); + if (ft_strcmp(token, ">>") == 0) + return (TOKEN_APPEND); + if (ft_strcmp(token, "<") == 0) + return (TOKEN_REDIRECTION_IN); + if (ft_strcmp(token, "<<") == 0) + return (TOKEN_HEREDOC); + return (TOKEN_WORD); +} + +int validate_syntax(char **tokens) +{ + if (validate_pipes(tokens)) + { + write(STDERR_FILENO, "Syntax error: unexpected pipe\n", 30); + return (1); + } + if (validate_redirections(tokens)) + return (2); + return (0); +} diff --git a/src/tokens/token_list.c b/src/tokens/token_list.c new file mode 100644 index 0000000..4545fb0 --- /dev/null +++ b/src/tokens/token_list.c @@ -0,0 +1,102 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* token_list.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/03/06 18:11:25 by tordner #+# #+# */ +/* Updated: 2025/04/23 03:06:49 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +void free_cmd_node(t_cmd *cmd) +{ + int i; + t_redirection *redir; + t_redirection *next_redir; + + if (cmd->args) + { + i = 0; + while (cmd->args[i]) + free(cmd->args[i++]); + free(cmd->args); + } + redir = cmd->redir; + while (redir) + { + next_redir = redir->next; + free(redir->file); + free(redir); + redir = next_redir; + } +} + +t_cmd *create_command_node(void) +{ + t_cmd *new_node; + + new_node = malloc(sizeof(t_cmd)); + if (!new_node) + return (NULL); + new_node->args = NULL; + new_node->redir = NULL; + new_node->next = NULL; + return (new_node); +} + +t_redirection *create_redirection_node(int type, char *file) +{ + t_redirection *node; + + node = malloc(sizeof(t_redirection)); + if (!node) + return (NULL); + node->type = type; + node->file = file; + node->next = NULL; + return (node); +} + +int add_argument(t_cmd *cmd, char *arg) +{ + int count; + char **new_args; + int i; + + count = 0; + if (cmd->args) + while (cmd->args[count]) + count++; + new_args = (char **)malloc(sizeof(char *) * (count + 2)); + if (!new_args) + return (0); + i = -1; + while (++i < count) + new_args[i] = cmd->args[i]; + new_args[count] = arg; + new_args[count + 1] = NULL; + free(cmd->args); + cmd->args = new_args; + return (1); +} + +void add_redirection(t_cmd *cmd, t_redirection *redir) +{ + t_redirection *last; + + if (!cmd || !redir) + return ; + if (!cmd->redir) + cmd->redir = redir; + else + { + last = cmd->redir; + while (last->next) + last = last->next; + last->next = redir; + } +} diff --git a/src/tokens/tokenize_command.c b/src/tokens/tokenize_command.c new file mode 100644 index 0000000..6992501 --- /dev/null +++ b/src/tokens/tokenize_command.c @@ -0,0 +1,65 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* tokenize_command.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/03 00:05:01 by tordner #+# #+# */ +/* Updated: 2025/06/03 00:05:13 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static char *process_token(char *token, t_shell *shell) +{ + char *expanded; + + expanded = NULL; + if (shell->single_quoted_token != 1) + { + expanded = expand_variables(token, shell); + free(token); + shell->single_quoted_token = -1; + return (expanded); + } + return (token); +} + +static char **allocate_tokens(int count) +{ + char **tokens; + + tokens = malloc(sizeof(char *) * (count + 1)); + if (!tokens) + return (NULL); + return (tokens); +} + +char **tokenize_command(char *input, t_shell *shell) +{ + char **tokens; + int count; + int i; + int index; + + count = count_tokens(input); + tokens = allocate_tokens(count); + if (!tokens) + return (NULL); + i = 0; + index = 0; + while (i < count) + { + tokens[i] = extract_token(input, &index, shell); + if (!tokens[i]) + return (free_tokens(tokens, i)); + tokens[i] = process_token(tokens[i], shell); + i++; + } + tokens[i] = NULL; + if (check_quotes(input) == 1) + return (free_tokens(tokens, i)); + return (tokens); +} diff --git a/src/tokens/tokens.c b/src/tokens/tokens.c new file mode 100644 index 0000000..a784bc3 --- /dev/null +++ b/src/tokens/tokens.c @@ -0,0 +1,70 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* tokens.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/03/10 17:47:48 by thorgal #+# #+# */ +/* Updated: 2025/06/03 02:42:27 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +int is_delimiter(char c) +{ + return (c == ' ' || c == '\t' || c == '\0'); +} + +int is_special(char c) +{ + return (c == '|' || c == '<' || c == '>'); +} + +void skip_delimiters(char *str, int *i) +{ + while (str[*i] && is_delimiter(str[*i])) + (*i)++; +} + +static int handle_escape_in_quote(char *input, int *i, int *count, char quote) +{ + if (quote == '"' && (input[*i + 1] == '"' || input[*i + 1] == '\\' + || input[*i + 1] == '$' || input[*i + 1] == '`' + || input[*i + 1] == '\n')) + { + *i += 2; + *count += 2; + return (1); + } + else if (quote == '\'' && input[*i + 1] == '\'') + { + *i += 2; + *count += 2; + return (1); + } + return (0); +} + +int extract_quoted_token(char *input, int *index, char quote_char) +{ + int count; + + count = 0; + (*index)++; + while (input[*index]) + { + if (input[*index] == '\\' && input[*index + 1] && \ + handle_escape_in_quote(input, index, &count, quote_char)) + continue ; + if (input[*index] == quote_char) + { + (*index)++; + return (0); + } + (*index)++; + count++; + } + return (1); +} diff --git a/src/tokens/tokens_list2.c b/src/tokens/tokens_list2.c new file mode 100644 index 0000000..3b71d94 --- /dev/null +++ b/src/tokens/tokens_list2.c @@ -0,0 +1,114 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* tokens_list2.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lfirmin +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/23 02:48:30 by lfirmin #+# #+# */ +/* Updated: 2025/04/23 03:17:37 by lfirmin ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +int handle_redirection(t_cmd *cmd, char **tokens, int *i) +{ + t_redirection *redir; + int type; + int token_type; + + token_type = classify_token(tokens[*i]); + if (!tokens[*i + 1]) + return (0); + if (token_type == TOKEN_REDIRECTION_IN) + type = 1; + else if (token_type == TOKEN_REDIRECTION_OUT) + type = 2; + else if (token_type == TOKEN_APPEND) + type = 3; + else if (token_type == TOKEN_HEREDOC) + type = 4; + else + type = 0; + redir = create_redirection_node(type, ft_strdup(tokens[*i + 1])); + if (!redir) + return (0); + add_redirection(cmd, redir); + (*i)++; + return (1); +} + +t_cmd *init_cmd_segment(t_cmd **cmd_list, char **tokens, int *i) +{ + t_cmd *new; + t_cmd *tmp; + + if (classify_token(tokens[*i]) == TOKEN_PIPE) + (*i)++; + new = create_command_node(); + if (!new) + return (NULL); + if (!*cmd_list) + *cmd_list = new; + else + { + tmp = *cmd_list; + while (tmp->next) + tmp = tmp->next; + tmp->next = new; + } + return (new); +} + +int add_token_to_cmd(t_cmd *current, char **tokens, int *i) +{ + if (classify_token(tokens[*i]) == TOKEN_WORD) + { + if (!add_argument(current, ft_strdup(tokens[*i]))) + return (0); + } + else if (is_redirection(tokens[*i])) + { + if (!handle_redirection(current, tokens, i)) + return (0); + } + return (1); +} + +t_cmd *parse_tokens_to_list(char **tokens) +{ + t_cmd *cmd_list; + t_cmd *current; + int i; + + cmd_list = NULL; + current = NULL; + i = 0; + while (tokens[i]) + { + if (!current || classify_token(tokens[i]) == TOKEN_PIPE) + { + current = init_cmd_segment(&cmd_list, tokens, &i); + if (!current) + return (free_cmd_list(cmd_list), NULL); + } + if (!add_token_to_cmd(current, tokens, &i)) + return (free_cmd_list(cmd_list), NULL); + i++; + } + return (cmd_list); +} + +void free_cmd_list(t_cmd *cmd_list) +{ + t_cmd *tmp; + + while (cmd_list) + { + tmp = cmd_list->next; + free_cmd_node(cmd_list); + free(cmd_list); + cmd_list = tmp; + } +} diff --git a/src/tokens/tokens_utils.c b/src/tokens/tokens_utils.c new file mode 100644 index 0000000..0abd52f --- /dev/null +++ b/src/tokens/tokens_utils.c @@ -0,0 +1,73 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* tokens_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/04 17:21:22 by thorgal #+# #+# */ +/* Updated: 2025/06/03 00:37:50 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +void handle_special_count(char *str, int *i) +{ + if ((str[*i] == '<' && str[*i + 1] == '<') + || (str[*i] == '>' && str[*i + 1] == '>')) + (*i) += 2; + else + (*i)++; +} + +int count_tokens(char *str) +{ + int i; + int count; + + i = 0; + count = 0; + if (!str) + return (0); + while (str[i]) + { + skip_delimiters(str, &i); + if (!str[i]) + break ; + count++; + if (str[i] == '\'' || str[i] == '\"') + handle_quoted_count(str, &i, str[i]); + else if (is_special(str[i])) + handle_special_count(str, &i); + else + handle_word_count(str, &i); + } + return (count); +} + +int handle_quoted_token(char *input, int *index, int *start) +{ + *start = *index + 1; + if (extract_quoted_token(input, index, input[*index]) == 1) + return (-1); + return ((*index - 1) - *start); +} + +int handle_special_token(char *input, int *index) +{ + int token_len; + + if ((input[*index] == '<' && input[*index + 1] == '<') + || (input[*index] == '>' && input[*index + 1] == '>')) + { + (*index) += 2; + token_len = 2; + } + else + { + (*index)++; + token_len = 1; + } + return (token_len); +} diff --git a/src/tokens/tokens_utils2.c b/src/tokens/tokens_utils2.c new file mode 100644 index 0000000..544f337 --- /dev/null +++ b/src/tokens/tokens_utils2.c @@ -0,0 +1,99 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* tokens_utils2.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/23 03:25:24 by lfirmin #+# #+# */ +/* Updated: 2025/06/03 00:34:07 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static char *extract_simple_token(char *input, int start, int token_len) +{ + char *token; + + token = malloc(sizeof(char) * (token_len + 1)); + if (!token) + return (NULL); + ft_strlcpy(token, input + start, token_len + 1); + return (token); +} + +char *extract_token(char *input, int *index, t_shell *shell) +{ + char *token; + int start; + int token_len; + int temp_index; + char quote_char; + + shell->single_quoted_token = -1; + temp_index = *index; + while (input[temp_index] && (input[temp_index] == ' ' \ + || input[temp_index] == '\t')) + temp_index++; + token_len = extract_token_len(input, index, &start); + if (token_len == -1) + return (NULL); + if (input[temp_index] == '\'' || input[temp_index] == '\"') + { + if (input[temp_index] == '\'') + shell->single_quoted_token = 1; + quote_char = input[temp_index]; + token = extract_quoted_content(input, start, token_len, quote_char); + } + else + token = extract_simple_token(input, start, token_len); + return (token); +} + +int check_quotes(char *input) +{ + bool in_squote; + bool in_dquote; + int i; + + in_squote = false; + in_dquote = false; + i = 0; + while (input[i]) + { + if (input[i] == '\\' && input[i + 1]) + { + i += 2; + continue ; + } + if (input[i] == '\'' && !in_dquote) + in_squote = !in_squote; + else if (input[i] == '"' && !in_squote) + in_dquote = !in_dquote; + i++; + } + if (in_squote || in_dquote) + return (1); + return (0); +} + +void handle_word_count(char *str, int *i) +{ + char quote; + + while (str[*i] && !is_delimiter(str[*i]) && !is_special(str[*i])) + { + if (str[*i] == '\'' || str[*i] == '\"') + { + quote = str[*i]; + (*i)++; + while (str[*i] && str[*i] != quote) + (*i)++; + if (str[*i] == quote) + (*i)++; + } + else + (*i)++; + } +} diff --git a/src/utils/free.c b/src/utils/free.c new file mode 100644 index 0000000..bedc4a0 --- /dev/null +++ b/src/utils/free.c @@ -0,0 +1,24 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* free.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/11/21 15:38:19 by lfirmin #+# #+# */ +/* Updated: 2025/04/18 13:56:26 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +void *free_tokens(char **tokens, int count) +{ + int i; + + i = 0; + while (i < count) + free(tokens[i++]); + free(tokens); + return (NULL); +} diff --git a/src/utils/get_env_value.c b/src/utils/get_env_value.c new file mode 100644 index 0000000..64648fc --- /dev/null +++ b/src/utils/get_env_value.c @@ -0,0 +1,68 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* get_env_value.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/06/02 23:59:04 by tordner #+# #+# */ +/* Updated: 2025/06/03 00:02:52 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static char *handle_special_vars(char *var_name, t_shell *shell) +{ + if (!var_name || !shell) + return (NULL); + if (var_name[0] == '$') + var_name++; + if (var_name[0] == '?') + { + printf("%d", shell->exit_status); + return (NULL); + } + return (var_name); +} + +static int get_var_name_length(char *var_name) +{ + int len; + + len = 0; + while (var_name[len] && (ft_isalnum(var_name[len]) || var_name[len] == '_')) + len++; + return (len); +} + +static char *search_env(char *var_name, int var_len, char **env) +{ + int i; + + i = 0; + while (env && env[i]) + { + if (ft_strncmp(env[i], var_name, var_len) \ + == 0 && env[i][var_len] == '=') + return (env[i] + var_len + 1); + i++; + } + return (NULL); +} + +char *get_env_value(char *var_name, t_shell *shell) +{ + char *clean_var_name; + int var_len; + + if (!var_name || !shell || !shell->env) + return (NULL); + clean_var_name = handle_special_vars(var_name, shell); + if (!clean_var_name) + return (NULL); + var_len = get_var_name_length(clean_var_name); + if (var_len == 0) + return (NULL); + return (search_env(clean_var_name, var_len, shell->env)); +} diff --git a/src/utils/utils.c b/src/utils/utils.c new file mode 100644 index 0000000..4295360 --- /dev/null +++ b/src/utils/utils.c @@ -0,0 +1,96 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tordner +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/04 15:49:05 by thorgal #+# #+# */ +/* Updated: 2025/06/02 23:59:34 by tordner ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +char *get_current_dir_name(void) +{ + char pwd[PATH_MAX]; + char *dir; + + if (getcwd(pwd, PATH_MAX) == NULL) + return (strdup("minishell")); + dir = strrchr(pwd, '/'); + if (!dir || !dir[1]) + return (strdup(pwd)); + return (strdup(dir + 1)); +} + +char *ft_get_env_var(char **env, char *var) +{ + int i; + int len; + + i = 0; + len = ft_strlen(var); + while (env[i]) + { + if (ft_strncmp(env[i], var, len) == 0 && env[i][len] == '=') + return (&env[i][len + 1]); + i++; + } + return (NULL); +} + +char **copy_env(char **envp) +{ + char **env; + int i; + + i = 0; + while (envp[i]) + i++; + env = malloc(sizeof(char *) * (i + 1)); + if (!env) + return (NULL); + i = 0; + while (envp[i]) + { + env[i] = strdup(envp[i]); + if (!env[i]) + { + while (--i >= 0) + free(env[i]); + free(env); + return (NULL); + } + i++; + } + env[i] = NULL; + return (env); +} + +char **add_env_var(char **env, char *new_var) +{ + char **new_env; + int i; + int count; + + count = 0; + while (env[count]) + count++; + new_env = malloc(sizeof(char *) * (count + 2)); + if (!new_env) + return (NULL); + i = 0; + while (i < count) + { + new_env[i] = env[i]; + i++; + } + new_env[i] = ft_strdup(new_var); + if (!new_env[i]) + return (free(new_env), NULL); + new_env[i + 1] = NULL; + free(env); + return (new_env); +}