diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a77d767 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.o +libft.a +minishell +build +.DS_Store \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..cbe9089 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Unity"] + path = Unity + url = https://github.com/ThrowTheSwitch/Unity.git diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..65242c9 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "name": "(lldb) Launch", + "type": "lldb", + "request": "launch", + "program": "${workspaceFolder}/minishell", + "args": [], + "stopAtEntry": true, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true, + "MIMode": "lldb", + "setupCommands": [ + { + "description": "Enable pretty-printing for lldb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "build", + "disableOptimisticBPs": true + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b643038 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "files.autoSave": "onFocusChange", + "files.associations": { + "stdio.h": "c", + "readline.h": "c", + "libft.h": "c", + "executor.h": "c", + "sstream": "c" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..5f75ac2 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,12 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "make; export SHLVL=1", + "group": "build", + "problemMatcher": "$gcc" + }, + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile index ed64e64..9c0b86b 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ LIBFTP = libraries/libft PATHB = build/ PATHO = build/objs/ PATHS = src/ -PATHSL = src/lexer/ +PATHSL = src/lexor/ PATHSP = src/parser/ PATHSB = src/builtins/ PATHSEX = src/expander/ @@ -20,9 +20,9 @@ BUILD_PATHS = $(PATHB) $(PATHO) src = src/main.c \ src/signals.c \ - src/lexer/handle_quotes.c \ - src/lexer/handle_token.c \ - src/lexer/token_reader.c \ + src/lexor/handle_quotes.c \ + src/lexor/handle_token.c \ + src/lexor/token_reader.c \ src/parser/handle_redirections.c \ src/parser/parser.c \ src/parser/parser_utils.c \ @@ -37,8 +37,8 @@ src = src/main.c \ src/builtins/utils_builtins.c \ src/utils/minishell_loop.c \ src/utils/parse_envp.c \ - src/utils/t_lexer_clear_utils.c \ - src/utils/t_lexer_utils.c \ + src/utils/t_lexor_clear_utils.c \ + src/utils/t_lexor_utils.c \ src/utils/t_simple_cmds_utils.c \ src/utils/utils.c \ src/error/error_handling.c \ @@ -62,7 +62,7 @@ HEADER = .includes/builtins.h \ .includes/color.h \ .includes/error.h \ .includes/executor.h \ - .includes/lexer.h \ + .includes/lexor.h \ .includes/minishell.h \ .includes/parser.h \ .includes/utils.h @@ -111,6 +111,7 @@ $(NAME): $(LIBFT) $(OBJS) $(HEADERS) @$(CC) $(FLAGS) $(LIBFT) $(OBJS) $(READLINE_LIB) -o $(NAME) @echo "Success" + $(LIBFT): @$(MAKE) -C ./libraries/libft @@ -125,7 +126,6 @@ clean: @echo "Cleaning" @rm -f $(OBJS) @rm -f $(PATHB).tmp* - @rmdir $(PATHO) $(PATHB) @make fclean -C libraries/libft fclean: clean diff --git a/README.md b/README.md deleted file mode 100644 index 7b35484..0000000 --- a/README.md +++ /dev/null @@ -1,200 +0,0 @@ -# minishell - -

- - - philosophers - - -

- -*A mini recreation of bash. Implementing previously learned concepts like file descriptors and processes. Made with [Alfred Polycarpe](https://github.com/Alfredpoly).* - -## Table of Contents -- [The Challenge](#the-challenge) - - [What Is Bash and How Does It Work?](#what-is-bash-and-how-does-it-work) -- [Implementation](#implementation) - - [The Lexer](#the-lexer) - - [The Parser](#the-parser) - - [Builtins](#builtins) - - [Executor](#executor) - - [Expander](#expander) - - [Heredoc](#heredoc) - - [Single Command](#single-command) - - [Multiple Commands](#multiple-commands) - - [Reset](#reset) -- [My Take Away](#my-take-away) -- [Installation](#installation) - -## The Challenge -This was probably the biggest project I've done so far, as well as the first one I did as a group. The goal was to create a mini version of bash, I say mini but it was still a huge project. We had to learn how bash takes arguments, parses them, and executes them. We had to incorporate the following features: -- Display a promt while waiting for a new commmand. -- Have a working history. -- Find and launch executables (using the `PATH` variable or an absolute path). -- Handle `'` (single) and `"` (double) **quotes** like in bash. -- Implement **redirections** such as: - - `<` redirect input. - - `>` redirect output. - - `<<` heredoc (doesn't affect history). - - `>>` redirect output in append mode. -- Implement `|` (**pipes**). -- Handle **environment variables**. -- Handle `$?`. -- `ctrl-C`, `ctrl-D`, and `ctrl-\` should behave like in bash. -- Recreate the following **builtins**: - - `echo` with option `-n`. - - `cd` with only a relative or absolute path. - - `pwd` (no flags). - - `export` (no flags). - - `unset` (no flags). - - `env` (no flags or arguments). - - `exit` (no flags). - -We didn't have to implement && and ||, or wildcards, as well as any special symbols that weren't specifically asked for. We were also told that when in doubt, take bash as a reference. This sometimes led to discussions on wether or not we had to implement something, the result of which was usually "probably??? 🤷‍♀️". - -### What Is Bash and How Does It Work? -The shell is a program that the user can use to interact with an operating system's services. Bash is the GNU shell, and is currently the most common shell program. We took the challenge of recreating bash very literally, so the first thing we did was learn how bash actually works with the help of [this article](https://www.cs.purdue.edu/homes/grr/SystemsProgrammingBook/Book/Chapter5-WritingYourOwnShell.pdf). Essentially it breaks down the process into 4 steps: `lexer` → `parser` → `expander` → `executor`, which we replicated in our project. - -![bash steps](https://user-images.githubusercontent.com/68693691/193665518-0c0c7fec-38a9-4f6c-91ca-fef606abfb0d.png) - - -I'll delve further into each step in the implementation section bellow. - -## Implementation - -The program is run without arguments (and will throw an error if any are used). The program essentially comprises of two functions that call each other indefinitely. The first, `minishell_loop` performs the functions of minishell, the other cleans up and prepares for the next line. In `minishell_loop`, a command prompt shows up, which is implemented through [readline](https://www.man7.org/linux/man-pages/man3/readline.3.html). This also allowed us to use the built-in history function. Once a line has been inputted it checks for any unclosed quotes. If it doesn't find any it sends the line to the lexer. - -### The Lexer -The lexer, also called the tokenizer, takes as the entered line as input. It then reads through the line word by word, using white space as delimiters. First it checks wether or not the word is a token, ie: `|`, `<`, `<<`, `>`, or `>>`, and otherwise it assumes it is a word. Which it then adds to the following linked list: - -```C -typedef struct s_lexer -{ - char *str; - t_tokens token; - int i; - struct s_lexer *next; - struct s_lexer *prev; -} t_lexer; -``` -Each node contains either a `char *` containing the word or a `t_token`. We also assign each node an index so that we can easily delete them later. - -### The Parser -The lexer then gets sent to the parser which then groups the different nodes together based on the tokens. Each group becomes a command. - -```C -typedef struct s_simple_cmds -{ - char **str; - int (*builtin)(t_tools *, struct s_simple_cmds *); - int num_redirections; - char *hd_file_name; - t_lexer *redirections; - struct s_simple_cmds *next; - struct s_simple_cmds *prev; -} t_simple_cmds; -``` - -The first thing the parser does is loop through the lexer list until it encounters a pipe. It then takes all the nodes before the pipe as one command, and creates a node in the `t_simple_cmds` struct. If it doesn't find a pipe it takes all the (remaining) nodes as one command. - -![parser 001](https://user-images.githubusercontent.com/68693691/194295673-3c9e17c3-d5ab-40dc-82ef-72b909f4acb3.png) -*The parser takes the `t_lexer` list (left) and converts it into the `t_simple_cmds` list (right)* - -For each command it first checks for redirections, which it stores in the `*redirections` linked list, which holds both the token and the filename or delimiter in the case of a heredoc. When the nodes are added to the `*redirections` list, they are deleted from the lexer list. Next it checks if the first word is a builtin, in which case it stores a function pointer to the corresponding function, more on this bellow. As the redirections have been removed from the lexer list, the parser can easily combines all remaining words into a 2D array, which is a required execve argument. It also makes it easier to handle situations where the words may be seperated by redirections, for example: -``` -cat > file -e -``` -As `>` and `file` are already deleted from the lexer list when they are added to the redirections list, all that remains is `cat` and `-e`. Which then can easily be added into an array. - -This process is repeated until the end of the lexer list. - -### Builtins -We handle builtins, as discussed above through storing a function pointer in the `t_simple_cmds`. We achieve this by sending the the first word of a command to a function `builtin_arr` which loops through a static array of the different builtin functions. If it finds a corresponding function it returns it to the parser, else it returns `NULL`. For me, this was a way to learn about function pointers, which I had never worked with before. Also by determining the builtin at the parser stage, it greatly simplifies the executor as executing the builtin requires just two lines of code: -``` C -if (cmd->builtin != NULL) - cmd->builtin(tools, cmd); -``` -The builtins we incorporated (as per the subject) are: -| Command | Description | -|---|---| -|`cd`| Changes the working directory of the current shell execution environment and updates the environment variables `PWD` and `OLDPWD`.
Without arguments it change the working directory to the home directory.
`-` changes the directory to the `OLDPWD`. | -|`echo`| Displays a line of text
Optional flag `-n`: do not output the trailing newline| -|`env` | Displays the environment variables| -|`exit`| Terminates the shell.
Accepts optional argument `n`, which sets the exit status to `n`. | -|`export`| Accepts arguments `name[=value]`.
Adds name to the environment. Set's value of name to `value`.
If no argument is given, displays list of exported variables.| -|`pwd`| Shows the current directory as an absolute path.| -|`unset`|Accepts argument `name`.
Removes the variable `name` from the environment.| - -### Executor -When the parser returns the `t_simple_cmds` list back to `minishell_loop`, a simple check is done to determine how many commands there are, as they are handled by different functions. However, with the exception of a few builtins, the commands are ultimately executed by the same function `handle_cmd`, which finds, and if successful, executes the command. - -#### Expander -Before a node from `t_simple_cmds` is handled it is expanded. The expander takes variables, identified by `$`, and replaces them with their value from the environment variables. Such that `$USER` becomes `mgraaf`, and `$?` is replaced with the exit code. - -#### Heredoc -Before creating a child process, the parent process executes heredocs. We handled heredocs by creating a temporary file to write the input to. The filename is stored in the related `t_simple_cmds` node so that it can be used to replace `STDIN`. If there are multiple heredocs in a single `t_simple_cmds` node, then the file name ultimately stored would be that of the last heredoc. Using a file comes with limitations and security issues however we felt it was the simplest way dealing with it, and is close to how bash does it. - -#### Single Command -Like in bash, builtin commands, specifically `cd`, `exit`, `export`, and `unset` cannot be run in a separate process, as then the environmentally variable cannot be properly altered. If there is only one command, and it is one of the aforementioned builtins, it is executed in the parent process and the function returns back to the `minishell_loop`. If the command is not a builtin the single command function creates a new process and sends the command to `handle_cmd`. - -#### Multiple Commands -If there are multiple commands, the executor loops through each `t_simple_cmds` node and creates a child process for it using `fork()`, and using `pipe()` creates a pipe in order to send the output of one command as the input to the next. Checkout [pipex](https://github.com/maiadegraaf/pipex) to learn more about these functions. - -Essentially for each command the following happens: -1. The command is expanded. -2. A pipe is created with `end[0]` and `end[1]`, except the last command. -3. Using `fork()` a child process is created. In the child process: - 1. With the exception of the first command, `dup2` replaces `STDIN` with the output of the previous command. - 2. With the exception of the last command, `dup2` replaces `STDOUT` with `end[1]`. - 3. In the case of redirections, the `STDIN` or `STDOUT` is replaced with their respective file descriptors. - 4. `handle_cmd` finds and executes the command. -4. `end[0]` is stored for the next command. - -The parent process then waits for all the children to end, then returns back to the `minishell_loop`. - -### Reset -The program then does a full reset, freeing all nodes that have not been freed or deleted yet, and resets various variables so that the program can start again by displaying a new prompt. - -## My Take Away -As previously mentioned, this was the first project I did in a group, which for me was an overall joyful experience. This is a huge and daunting project and doing it alone would have been a massive challenge. What I think we did well was dividing up the different parts of the project while also supporting each other if we ran into issues. Although I wrote most of the lexer and parser, Alfred did contribute to both. I also wrote the executor while Alfred worked on the builtins and expander. - -By far the hardest part of this project was handling all the edge cases. Before handing in the project we had done our best to manage all of the ones we we're aware of, which was a considerable list. Often by solving one case, we would break another part of our code. The easiest way to handle an edge case was by replicating and understanding the way bash does it. However in some cases it was a complete mystery which only made it more confusing. Only once we handed in the project the first time did we discover how many edge cases there truly were as each person who evaluated us found new holes in our program. In the end we passed the second time we handed it in, after correcting all the issues. - -## Installation -### Clone the repository: -``` -git clone https://github.com/maiadegraaf/minishell.git -cd minishell -make -``` -### Run Minishell -``` -./minishell -``` - -### Some commands to try: - -As this project is made to mimic bash, you can try any commands you normally would try in bash. - -If you really can't think of anything try some of the following. You do have to enter each line separately as the program doesn't handle new lines. -``` -ls -la | grep a | tr 'a-z' 'A-Z' -``` - -``` -cat << EOF > file -cat file -rm file -``` - -``` -ls | rev > file -cat file -rev file | cat -rm file -``` - -*to exit the program:* -``` -exit -``` \ No newline at end of file diff --git a/Unity b/Unity new file mode 160000 index 0000000..8286aaf --- /dev/null +++ b/Unity @@ -0,0 +1 @@ +Subproject commit 8286aaf32cfc2362b4355f809599a482a9b32578 diff --git a/banaan b/banaan new file mode 100644 index 0000000..c772f40 --- /dev/null +++ b/banaan @@ -0,0 +1,18 @@ +total 176 +drwxr-xr-x 17 mgraaf piscine 578 Apr 18 17:24 . +drwx------ 24 mgraaf piscine 816 Apr 12 15:35 .. +drwxr-xr-x 19 mgraaf piscine 646 Apr 18 17:15 .git +-rw-r--r-- 1 mgraaf piscine 37 Apr 15 17:47 .gitignore +-rw-r--r-- 1 mgraaf piscine 85 Apr 15 17:47 .gitmodules +drwxr-xr-x 5 mgraaf piscine 170 Apr 15 17:47 .vscode +-rw-r--r-- 1 mgraaf piscine 3274 Apr 18 17:13 Makefile +drwxr-xr-x 18 mgraaf piscine 612 Mar 28 12:53 Unity +-rw-r--r-- 1 mgraaf piscine 0 Apr 18 17:24 banaan +drwxr-xr-x 6 mgraaf piscine 204 Apr 18 17:15 build +drwxr-xr-x 10 mgraaf piscine 340 Apr 18 17:13 includes +drwxr-xr-x 3 mgraaf piscine 102 Feb 14 12:06 libraries +-rwxr-xr-x 1 mgraaf piscine 62860 Apr 18 17:15 minishell +drwxr-xr-x 12 mgraaf piscine 408 Apr 18 12:45 src +drwxr-xr-x 11 mgraaf piscine 374 Apr 15 17:47 test +-rwxrwxrwx 1 mgraaf piscine 8922 Apr 18 15:02 tester.sh +drwxr-xr-x 3 mgraaf piscine 102 Apr 15 17:47 utilities diff --git a/includes/error.h b/includes/error.h index 596845a..db750cb 100644 --- a/includes/error.h +++ b/includes/error.h @@ -6,7 +6,7 @@ /* By: maiadegraaf +#+ */ /* +#+ */ /* Created: 2022/02/24 15:17:39 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/18 17:09:10 by mgraaf ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -15,8 +15,8 @@ # include "minishell.h" // check_redirections -// int check_outfile(t_lexer *redirections); -// int check_infile(t_lexer *redirections); +// int check_outfile(t_lexor *redirections); +// int check_infile(t_lexor *redirections); // int handle_redirections(t_simple_cmds *cmd, t_tools *tools); int check_redirections(t_simple_cmds *cmd); diff --git a/includes/lexer.h b/includes/lexor.h similarity index 90% rename from includes/lexer.h rename to includes/lexor.h index 542af30..3676dbf 100644 --- a/includes/lexer.h +++ b/includes/lexor.h @@ -6,12 +6,12 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/17 17:55:06 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/08 10:55:02 by fpolycar ######## odam.nl */ /* */ /* ************************************************************************** */ -#ifndef lexer_H -# define lexer_H +#ifndef LEXOR_H +# define LEXOR_H # include "minishell.h" int handle_quotes(int i, char *str, char del); diff --git a/includes/minishell.h b/includes/minishell.h index 27fa989..55ce54a 100644 --- a/includes/minishell.h +++ b/includes/minishell.h @@ -6,7 +6,7 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/14 13:46:41 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/18 16:35:59 by fpolycar ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -16,15 +16,14 @@ # include # include # include -# include -# include # include # include # include +# include "pipex.h" # include "parser.h" # include "utils.h" # include "error.h" -# include "lexer.h" +# include "lexor.h" # include "color.h" # include "builtins.h" # include "executor.h" @@ -48,6 +47,7 @@ char *delete_quotes(char *str, char c); char *delete_quotes_export(char *str, char c); int question_mark(char **tmp); + //builtins int (*builtin_arr(char *str))(t_tools *tools, t_simple_cmds *simple_cmd); @@ -55,7 +55,6 @@ typedef struct s_global { int error_num; int stop_heredoc; - int in_cmd; int in_heredoc; } t_global; diff --git a/includes/parser.h b/includes/parser.h index ca4ca4f..fe15657 100644 --- a/includes/parser.h +++ b/includes/parser.h @@ -6,7 +6,7 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/17 17:59:38 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/19 15:10:01 by maiadegraaf ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -23,19 +23,19 @@ typedef enum s_tokens LESS_LESS, } t_tokens; -typedef struct s_lexer +typedef struct s_lexor { char *str; t_tokens token; int i; - struct s_lexer *next; - struct s_lexer *prev; -} t_lexer; + struct s_lexor *next; + struct s_lexor *prev; +} t_lexor; typedef struct s_parser_tools { - t_lexer *lexer_list; - t_lexer *redirections; + t_lexor *lexor_list; + t_lexor *redirections; int num_redirections; struct s_tools *tools; } t_parser_tools; @@ -46,7 +46,7 @@ typedef struct s_tools char **paths; char **envp; struct s_simple_cmds *simple_cmds; - t_lexer *lexer_list; + t_lexor *lexor_list; char *pwd; char *old_pwd; int pipes; @@ -61,7 +61,7 @@ typedef struct s_simple_cmds int (*builtin)(t_tools *, struct s_simple_cmds *); int num_redirections; char *hd_file_name; - t_lexer *redirections; + t_lexor *redirections; struct s_simple_cmds *next; struct s_simple_cmds *prev; } t_simple_cmds; @@ -71,14 +71,14 @@ int find_pwd(t_tools *tools); int parser(t_tools *tools); //parser_utils -t_parser_tools init_parser_tools(t_lexer *lexer_list, t_tools *tools); -void count_pipes(t_lexer *lexer_list, t_tools *tools); -int count_args(t_lexer *lexer_list); -t_lexer *find_next_cmd(t_lexer *lexer_lst); +t_parser_tools init_parser_tools(t_lexor *lexor_list, t_tools *tools); +void count_pipes(t_lexor *lexor_list, t_tools *tools); +int count_args(t_lexor *lexor_list); +t_lexor *find_next_cmd(t_lexor *lexor_lst); //handle_redirections -int add_new_redirection(t_lexer *tmp, t_parser_tools *parser_tools); -int handle_heredoc(t_parser_tools *parser_tools, t_lexer *tmp); +int add_new_redirection(t_lexor *tmp, t_parser_tools *parser_tools); +int handle_heredoc(t_parser_tools *parser_tools, t_lexor *tmp); void rm_redirections(t_parser_tools *parser_tools); #endif diff --git a/includes/utils.h b/includes/utils.h index 6f6f7b7..3692274 100644 --- a/includes/utils.h +++ b/includes/utils.h @@ -6,7 +6,7 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/17 15:36:23 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/18 16:33:17 by mgraaf ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -23,22 +23,29 @@ int minishell_loop(t_tools *tools); //t_simple_cmds_utils t_simple_cmds *ft_simple_cmdsnew(char **str, - int num_redirections, t_lexer *redirections); + int num_redirections, t_lexor *redirections); void ft_simple_cmdsadd_back(t_simple_cmds **lst, t_simple_cmds *new); void ft_simple_cmds_rm_first(t_simple_cmds **lst); void ft_simple_cmdsclear(t_simple_cmds **lst); t_simple_cmds *ft_simple_cmdsfirst(t_simple_cmds *map); -//t_lexer_utils -t_lexer *ft_lexernew(char *str, int token); -void ft_lexeradd_back(t_lexer **lst, t_lexer *new); -void ft_lexerdelone(t_lexer **lst, int i); -void ft_lexerclear(t_lexer **lst); +//t_lexor_utils +t_lexor *ft_lexornew(char *str, int token); +void ft_lexoradd_back(t_lexor **lst, t_lexor *new); +void ft_lexordelone(t_lexor **lst, int i); +void ft_lexorclear(t_lexor **lst); + +//t_heredoc_utils +// t_heredoc *ft_heredocnew(char *del); +// void ft_heredocadd_back(t_heredoc **lst, t_heredoc *new); +// int ft_heredocsize(t_heredoc *lst); +// void ft_heredocclear(t_heredoc **lst); +// t_heredoc *ft_heredocfirst(t_heredoc *map); // int token_reader(t_tools *tools); -int add_node(char *str, t_tokens token, t_lexer **lexer_list); +int add_node(char *str, t_tokens token, t_lexor **lexor_list); t_tokens check_token(int c); -int handle_token(char *str, int i, t_lexer **lexer_list); +int handle_token(char *str, int i, t_lexor **lexor_list); #endif diff --git a/oufile b/oufile new file mode 100644 index 0000000..fc7764b --- /dev/null +++ b/oufile @@ -0,0 +1 @@ +dsfdsf diff --git a/outfile b/outfile new file mode 100644 index 0000000..c772f40 --- /dev/null +++ b/outfile @@ -0,0 +1,18 @@ +total 176 +drwxr-xr-x 17 mgraaf piscine 578 Apr 18 17:24 . +drwx------ 24 mgraaf piscine 816 Apr 12 15:35 .. +drwxr-xr-x 19 mgraaf piscine 646 Apr 18 17:15 .git +-rw-r--r-- 1 mgraaf piscine 37 Apr 15 17:47 .gitignore +-rw-r--r-- 1 mgraaf piscine 85 Apr 15 17:47 .gitmodules +drwxr-xr-x 5 mgraaf piscine 170 Apr 15 17:47 .vscode +-rw-r--r-- 1 mgraaf piscine 3274 Apr 18 17:13 Makefile +drwxr-xr-x 18 mgraaf piscine 612 Mar 28 12:53 Unity +-rw-r--r-- 1 mgraaf piscine 0 Apr 18 17:24 banaan +drwxr-xr-x 6 mgraaf piscine 204 Apr 18 17:15 build +drwxr-xr-x 10 mgraaf piscine 340 Apr 18 17:13 includes +drwxr-xr-x 3 mgraaf piscine 102 Feb 14 12:06 libraries +-rwxr-xr-x 1 mgraaf piscine 62860 Apr 18 17:15 minishell +drwxr-xr-x 12 mgraaf piscine 408 Apr 18 12:45 src +drwxr-xr-x 11 mgraaf piscine 374 Apr 15 17:47 test +-rwxrwxrwx 1 mgraaf piscine 8922 Apr 18 15:02 tester.sh +drwxr-xr-x 3 mgraaf piscine 102 Apr 15 17:47 utilities diff --git a/src/builtins/builtins.c b/src/builtins/builtins.c index 30859dc..b1ff949 100644 --- a/src/builtins/builtins.c +++ b/src/builtins/builtins.c @@ -6,7 +6,7 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/15 11:42:32 by mgraaf #+# #+# */ -/* Updated: 2022/04/19 15:24:14 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/19 15:10:36 by maiadegraaf ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -35,5 +35,6 @@ int (*builtin_arr(char *str))(t_tools *tools, t_simple_cmds *simple_cmd) } i++; } + printf("return null from builtin\n"); return (NULL); } diff --git a/src/builtins/mini_exit.c b/src/builtins/mini_exit.c index 81ae43a..48987fd 100644 --- a/src/builtins/mini_exit.c +++ b/src/builtins/mini_exit.c @@ -6,7 +6,7 @@ /* By: maiadegraaf lexer_list); + ft_lexorclear(&tools->lexor_list); ft_error(error, tools); } diff --git a/src/executor/check_redirections.c b/src/executor/check_redirections.c index 7cd5721..2a0f8aa 100644 --- a/src/executor/check_redirections.c +++ b/src/executor/check_redirections.c @@ -6,19 +6,19 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/25 11:39:57 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/18 17:08:32 by mgraaf ######## odam.nl */ /* */ /* ************************************************************************** */ #include "executor.h" -int check_append_outfile(t_lexer *redirections) +int check_append_outfile(t_lexor *redirections) { int fd; - if (redirections->token == GREAT_GREAT) + if (redirections->token == GREAT) fd = open(redirections->str, - O_CREAT | O_RDWR | O_APPEND, 0644); + O_CREAT | O_RDWR | O_TRUNC | O_APPEND, 0644); else fd = open(redirections->str, O_CREAT | O_RDWR | O_TRUNC, 0644); @@ -46,7 +46,7 @@ int handle_infile(char *file) return (EXIT_SUCCESS); } -int handle_outfile(t_lexer *redirection) +int handle_outfile(t_lexor *redirection) { int fd; @@ -68,7 +68,7 @@ int handle_outfile(t_lexer *redirection) int check_redirections(t_simple_cmds *cmd) { - t_lexer *start; + t_lexor *start; start = cmd->redirections; while (cmd->redirections) diff --git a/src/executor/executor.c b/src/executor/executor.c index 49010ab..1b1e5d9 100644 --- a/src/executor/executor.c +++ b/src/executor/executor.c @@ -6,7 +6,7 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/24 15:09:50 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/18 17:26:25 by mgraaf ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -14,15 +14,14 @@ t_simple_cmds *call_expander(t_tools *tools, t_simple_cmds *cmd) { - t_lexer *start; + t_lexor *start; cmd->str = expander(tools, cmd->str); start = cmd->redirections; while (cmd->redirections) { - if (cmd->redirections->token != LESS_LESS) - cmd->redirections->str - = expander_str(tools, cmd->redirections->str); + cmd->redirections->str + = expander_str(tools, cmd->redirections->str); cmd->redirections = cmd->redirections->next; } cmd->redirections = start; diff --git a/src/executor/handle_cmd.c b/src/executor/handle_cmd.c index f316790..566a994 100644 --- a/src/executor/handle_cmd.c +++ b/src/executor/handle_cmd.c @@ -6,7 +6,7 @@ /* By: maiadegraaf str); fd = open(file_name, O_CREAT | O_RDWR | O_TRUNC, 0644); line = readline(HEREDOC_MSG); while (line && ft_strncmp(heredoc->str, line, ft_strlen(heredoc->str)) && !g_global.stop_heredoc) { if (quotes == false) - line = expander_str(tools, line); + line = send_expander(tools, line); write(fd, line, ft_strlen(line)); - write(fd, "\n", 1); free(line); line = readline(HEREDOC_MSG); } free(line); + if (!line) + ft_putstr_fd("\n", STDERR_FILENO); if (g_global.stop_heredoc || !line) return (EXIT_FAILURE); close(fd); return (EXIT_SUCCESS); } -int ft_heredoc(t_tools *tools, t_lexer *heredoc, char *file_name) +int ft_heredoc(t_tools *tools, t_lexor *heredoc, char *file_name) { bool quotes; int sl; sl = EXIT_SUCCESS; - if ((heredoc->str[0] == '\"' - && heredoc->str[ft_strlen(heredoc->str) - 1] == '\"') - || (heredoc->str[0] == '\'' - && heredoc->str[ft_strlen(heredoc->str) - 1] == '\'')) + if (heredoc->str[0] == '\"' + && heredoc->str[ft_strlen(heredoc->str) - 1] == '\"') quotes = true; else quotes = false; - delete_quotes(heredoc->str, '\"'); - delete_quotes(heredoc->str, '\''); g_global.stop_heredoc = 0; g_global.in_heredoc = 1; sl = create_heredoc(heredoc, quotes, tools, file_name); @@ -74,7 +85,7 @@ char *generate_heredoc_filename(void) int send_heredoc(t_tools *tools, t_simple_cmds *cmd) { - t_lexer *start; + t_lexor *start; int sl; start = cmd->redirections; diff --git a/src/lexer/handle_quotes.c b/src/lexor/handle_quotes.c similarity index 92% rename from src/lexer/handle_quotes.c rename to src/lexor/handle_quotes.c index abc6d4c..3ec3136 100644 --- a/src/lexer/handle_quotes.c +++ b/src/lexor/handle_quotes.c @@ -6,11 +6,11 @@ /* By: maiadegraaf +#+ */ /* +#+ */ /* Created: 2022/02/18 10:27:43 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/03/16 11:48:36 by maiadegraaf ######## odam.nl */ /* */ /* ************************************************************************** */ #include "utils.h" -#include "lexer.h" +#include "lexor.h" t_tokens check_token(int c) { @@ -32,26 +32,26 @@ t_tokens check_token(int c) return (0); } -int handle_token(char *str, int i, t_lexer **lexer_list) +int handle_token(char *str, int i, t_lexor **lexor_list) { t_tokens token; token = check_token(str[i]); if (token == GREAT && check_token(str[i + 1]) == GREAT) { - if (!add_node(NULL, GREAT_GREAT, lexer_list)) + if (!add_node(NULL, GREAT_GREAT, lexor_list)) return (-1); return (2); } else if (token == LESS && check_token(str[i + 1]) == LESS) { - if (!add_node(NULL, LESS_LESS, lexer_list)) + if (!add_node(NULL, LESS_LESS, lexor_list)) return (-1); return (2); } else if (token) { - if (!add_node(NULL, token, lexer_list)) + if (!add_node(NULL, token, lexor_list)) return (-1); return (1); } diff --git a/src/lexer/token_reader.c b/src/lexor/token_reader.c similarity index 77% rename from src/lexer/token_reader.c rename to src/lexor/token_reader.c index 38f7f67..92d0c47 100644 --- a/src/lexer/token_reader.c +++ b/src/lexor/token_reader.c @@ -6,11 +6,11 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/17 17:11:20 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/08 10:45:54 by fpolycar ######## odam.nl */ /* */ /* ************************************************************************** */ -#include "lexer.h" +#include "lexor.h" int is_whitespace(char c) { @@ -27,18 +27,18 @@ int skip_spaces(char *str, int i) return (j); } -int add_node(char *str, t_tokens token, t_lexer **lexer_list) +int add_node(char *str, t_tokens token, t_lexor **lexor_list) { - t_lexer *node; + t_lexor *node; - node = ft_lexernew(str, token); + node = ft_lexornew(str, token); if (!node) return (0); - ft_lexeradd_back(lexer_list, node); + ft_lexoradd_back(lexor_list, node); return (1); } -int read_words(int i, char *str, t_lexer **lexer_list) +int read_words(int i, char *str, t_lexor **lexor_list) { int j; @@ -52,7 +52,7 @@ int read_words(int i, char *str, t_lexer **lexer_list) else j++; } - if (!add_node(ft_substr(str, i, j), 0, lexer_list)) + if (!add_node(ft_substr(str, i, j), 0, lexor_list)) return (-1); return (j); } @@ -68,9 +68,9 @@ int token_reader(t_tools *tools) j = 0; i += skip_spaces(tools->args, i); if (check_token(tools->args[i])) - j = handle_token(tools->args, i, &tools->lexer_list); + j = handle_token(tools->args, i, &tools->lexor_list); else - j = read_words(i, tools->args, &tools->lexer_list); + j = read_words(i, tools->args, &tools->lexor_list); if (j < 0) return (0); i += j; diff --git a/src/main.c b/src/main.c index 502aa5d..8fa0535 100644 --- a/src/main.c +++ b/src/main.c @@ -6,7 +6,7 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/14 12:04:02 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 16:38:34 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/19 15:13:39 by maiadegraaf ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -15,14 +15,17 @@ int main(int argc, char **argv, char **envp) { t_tools tools; + int i; + i = 0; if (argc != 1 || argv[1]) { printf("This program does not accept arguments\n"); exit(0); } tools.envp = ft_arrdup(envp); - find_pwd(&tools); + init_signals(); + parse_envp(&tools); implement_tools(&tools); printf("\n%s\n\n", WELCOME_MSG); minishell_loop(&tools); diff --git a/src/parser/handle_redirections.c b/src/parser/handle_redirections.c index 3825fc7..071177b 100644 --- a/src/parser/handle_redirections.c +++ b/src/parser/handle_redirections.c @@ -6,7 +6,7 @@ /* By: maiadegraaf next->str), tmp->token); + node = ft_lexornew(ft_strdup(tmp->next->str), tmp->token); if (!node) - parser_error(1, parser_tools->tools, parser_tools->lexer_list); - ft_lexeradd_back(&parser_tools->redirections, node); + parser_error(1, parser_tools->tools, parser_tools->lexor_list); + ft_lexoradd_back(&parser_tools->redirections, node); index_1 = tmp->i; index_2 = tmp->next->i; - ft_lexerdelone(&parser_tools->lexer_list, index_1); - ft_lexerdelone(&parser_tools->lexer_list, index_2); + ft_lexordelone(&parser_tools->lexor_list, index_1); + ft_lexordelone(&parser_tools->lexor_list, index_2); parser_tools->num_redirections++; return (0); } void rm_redirections(t_parser_tools *parser_tools) { - t_lexer *tmp; + t_lexor *tmp; - tmp = parser_tools->lexer_list; + tmp = parser_tools->lexor_list; while (tmp && tmp->token == 0) tmp = tmp->next; if (!tmp || tmp->token == PIPE) return ; if (!tmp->next) - parser_error(0, parser_tools->tools, parser_tools->lexer_list); + parser_error(0, parser_tools->tools, parser_tools->lexor_list); if (tmp->next->token) parser_double_token_error(parser_tools->tools, - parser_tools->lexer_list, tmp->next->token); + parser_tools->lexor_list, tmp->next->token); if ((tmp->token >= GREAT && tmp->token <= LESS_LESS)) add_new_redirection(tmp, parser_tools); diff --git a/src/parser/parser.c b/src/parser/parser.c index bc67dfe..a7ccb9c 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -6,7 +6,7 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/17 15:28:22 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/19 15:12:08 by maiadegraaf ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -19,22 +19,22 @@ t_simple_cmds *initialize_cmd(t_parser_tools *parser_tools) char **str; int i; int arg_size; - t_lexer *tmp; + t_lexor *tmp; i = 0; rm_redirections(parser_tools); - arg_size = count_args(parser_tools->lexer_list); + arg_size = count_args(parser_tools->lexor_list); str = ft_calloc(arg_size + 1, sizeof(char *)); if (!str) - parser_error(1, parser_tools->tools, parser_tools->lexer_list); - tmp = parser_tools->lexer_list; + parser_error(1, parser_tools->tools, parser_tools->lexor_list); + tmp = parser_tools->lexor_list; while (arg_size > 0) { if (tmp->str) { str[i++] = ft_strdup(tmp->str); - ft_lexerdelone(&parser_tools->lexer_list, tmp->i); - tmp = parser_tools->lexer_list; + ft_lexordelone(&parser_tools->lexor_list, tmp->i); + tmp = parser_tools->lexor_list; } arg_size--; } @@ -46,13 +46,13 @@ int handle_pipe_errors(t_tools *tools, t_tokens token) { if (token == PIPE) { - parser_double_token_error(tools, tools->lexer_list, - tools->lexer_list->token); + parser_double_token_error(tools, tools->lexor_list, + tools->lexor_list->token); return (EXIT_FAILURE); } - if (!tools->lexer_list) + if (!tools->lexor_list) { - parser_error(0, tools, tools->lexer_list); + parser_error(0, tools, tools->lexor_list); return (EXIT_FAILURE); } return (EXIT_SUCCESS); @@ -64,25 +64,25 @@ int parser(t_tools *tools) t_parser_tools parser_tools; tools->simple_cmds = NULL; - count_pipes(tools->lexer_list, tools); - if (tools->lexer_list->token == PIPE) - return (parser_double_token_error(tools, tools->lexer_list, - tools->lexer_list->token)); - while (tools->lexer_list) + count_pipes(tools->lexor_list, tools); + if (tools->lexor_list->token == PIPE) + return (parser_double_token_error(tools, tools->lexor_list, + tools->lexor_list->token)); + while (tools->lexor_list) { - if (tools->lexer_list && tools->lexer_list->token == PIPE) - ft_lexerdelone(&tools->lexer_list, tools->lexer_list->i); - if (handle_pipe_errors(tools, tools->lexer_list->token)) + if (tools->lexor_list && tools->lexor_list->token == PIPE) + ft_lexordelone(&tools->lexor_list, tools->lexor_list->i); + if (handle_pipe_errors(tools, tools->lexor_list->token)) return (EXIT_FAILURE); - parser_tools = init_parser_tools(tools->lexer_list, tools); + parser_tools = init_parser_tools(tools->lexor_list, tools); node = initialize_cmd(&parser_tools); if (!node) - parser_error(0, tools, parser_tools.lexer_list); + parser_error(0, tools, parser_tools.lexor_list); if (!tools->simple_cmds) tools->simple_cmds = node; else ft_simple_cmdsadd_back(&tools->simple_cmds, node); - tools->lexer_list = parser_tools.lexer_list; + tools->lexor_list = parser_tools.lexor_list; } return (EXIT_SUCCESS); } diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c index 7cf023f..6e3b71f 100644 --- a/src/parser/parser_utils.c +++ b/src/parser/parser_utils.c @@ -6,28 +6,28 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/03/04 11:52:02 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/18 16:36:48 by mgraaf ######## odam.nl */ /* */ /* ************************************************************************** */ #include "minishell.h" -t_parser_tools init_parser_tools(t_lexer *lexer_list, t_tools *tools) +t_parser_tools init_parser_tools(t_lexor *lexor_list, t_tools *tools) { t_parser_tools parser_tools; - parser_tools.lexer_list = lexer_list; + parser_tools.lexor_list = lexor_list; parser_tools.redirections = NULL; parser_tools.num_redirections = 0; parser_tools.tools = tools; return (parser_tools); } -void count_pipes(t_lexer *lexer_list, t_tools *tools) +void count_pipes(t_lexor *lexor_list, t_tools *tools) { - t_lexer *tmp; + t_lexor *tmp; - tmp = lexer_list; + tmp = lexor_list; tools->pipes = 0; while (tmp) { @@ -37,13 +37,13 @@ void count_pipes(t_lexer *lexer_list, t_tools *tools) } } -int count_args(t_lexer *lexer_list) +int count_args(t_lexor *lexor_list) { - t_lexer *tmp; + t_lexor *tmp; int i; i = 0; - tmp = lexer_list; + tmp = lexor_list; while (tmp && tmp->token != PIPE) { if (tmp->i >= 0) @@ -53,9 +53,9 @@ int count_args(t_lexer *lexer_list) return (i); } -t_lexer *find_next_cmd(t_lexer *lexer_lst) +t_lexor *find_next_cmd(t_lexor *lexor_lst) { - while (lexer_lst && lexer_lst->token != PIPE) - lexer_lst = lexer_lst->next; - return (lexer_lst); + while (lexor_lst && lexor_lst->token != PIPE) + lexor_lst = lexor_lst->next; + return (lexor_lst); } diff --git a/src/pipex/pipex.c b/src/pipex/pipex.c new file mode 100644 index 0000000..69f7686 --- /dev/null +++ b/src/pipex/pipex.c @@ -0,0 +1,109 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* pipex.c :+: :+: */ +/* +:+ */ +/* By: mgraaf +#+ */ +/* +#+ */ +/* Created: 2021/12/16 14:58:07 by mgraaf #+# #+# */ +/* Updated: 2022/02/14 14:20:37 by mgraaf ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +#include "pipex.h" + +void child1_process(t_pipex *info, int *end) +{ + int i; + char *mycmd; + + if (dup2(info->f1, STDIN_FILENO) < 0) + return (perror("Dup ")); + if (dup2(end[1], STDOUT_FILENO) < 0) + return (perror("Dup ")); + close(end[0]); + close(info->f1); + i = 0; + while ((info->paths)[i]) + { + mycmd = ft_strjoin((info->paths)[i], (info->cmds1)[0]); + if (!access(mycmd, F_OK && X_OK)) + execve(mycmd, info->cmds1, info->envp); + free(mycmd); + i++; + } + perror("Cmd not found "); + exit(EXIT_FAILURE); +} + +void child2_process(t_pipex *info, int *end) +{ + int i; + char *mycmd; + + if (dup2(info->f2, STDOUT_FILENO) < 0) + return (perror("Dup ")); + if (dup2(end[0], STDIN_FILENO) < 0) + return (perror("Dup ")); + close(end[1]); + close(info->f2); + i = 0; + while ((info->paths)[i]) + { + mycmd = ft_strjoin((info->paths)[i], (info->cmds2)[0]); + if (!access(mycmd, F_OK && X_OK)) + execve(mycmd, info->cmds2, info->envp); + free(mycmd); + i++; + } + perror("Cmd not found "); + exit(EXIT_FAILURE); +} + +void pipex(t_pipex *info) +{ + int end[2]; + int status; + pid_t child1; + pid_t child2; + + pipe(end); + child1 = fork(); + if (child1 < 0) + return (perror("Fork: ")); + if (child1 == 0) + child1_process(info, end); + child2 = fork(); + if (child2 < 0) + return (perror("Fork: ")); + if (child2 == 0) + child2_process(info, end); + close(end[0]); + close(end[1]); + waitpid(child1, &status, 0); + waitpid(child2, &status, 0); +} + +// int main(int argc, char **argv, char **envp) +// { +// t_pipex info; + +// if (argc != 5) +// { +// perror("Invalid number of arguments"); +// exit(EXIT_FAILURE); +// } +// info.f1 = open(argv[1], O_RDONLY); +// info.f2 = open(argv[4], O_CREAT | O_RDWR | O_TRUNC, 0644); +// if (info.f1 < 0 || info.f2 < 0) +// { +// perror("Open "); +// exit(EXIT_FAILURE); +// } +// info.envp = envp; +// info.cmds1 = ft_split(argv[2], ' '); +// info.cmds2 = ft_split(argv[3], ' '); +// info.paths = parse_envp(argv, envp); +// pipex(&info); +// return (0); +// } diff --git a/src/pipex/pipex.h b/src/pipex/pipex.h new file mode 100644 index 0000000..78b5eac --- /dev/null +++ b/src/pipex/pipex.h @@ -0,0 +1,32 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* pipex.h :+: :+: */ +/* +:+ */ +/* By: mgraaf +#+ */ +/* +#+ */ +/* Created: 2021/12/17 10:59:55 by mgraaf #+# #+# */ +/* Updated: 2022/02/15 17:07:32 by mgraaf ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +#ifndef PIPEX_H +# define PIPEX_H +# include "../../libraries/libft/libft.h" +# include +# include +# include + +typedef struct s_pipex +{ + char **paths; + int f1; + int f2; + char **envp; + char **cmds1; + char **cmds2; +} t_pipex; + +//char **parse_envp(char **envp); + +#endif \ No newline at end of file diff --git a/src/signals.c b/src/signals.c index e3b3ab7..0148fde 100644 --- a/src/signals.c +++ b/src/signals.c @@ -6,7 +6,7 @@ /* By: fpolycar +#+ */ /* +#+ */ /* Created: 2022/04/08 14:35:54 by fpolycar #+# #+# */ -/* Updated: 2022/04/20 15:00:21 by fpolycar ######## odam.nl */ +/* Updated: 2022/04/15 17:17:36 by fpolycar ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -19,9 +19,7 @@ int event(void) void sigint_handler(int sig) { - if (!g_global.in_heredoc) - ft_putstr_fd("\n", STDERR_FILENO); - if (g_global.in_cmd) + if (g_global.in_heredoc) { g_global.stop_heredoc = 1; rl_replace_line("", 0); @@ -29,22 +27,15 @@ void sigint_handler(int sig) rl_done = 1; return ; } + ft_putstr_fd("\n", STDERR_FILENO); rl_on_new_line(); rl_replace_line("", 0); rl_redisplay(); (void) sig; } -void sigquit_handler(int sig) -{ - ft_putstr_fd("Quit: ", STDERR_FILENO); - ft_putnbr_fd(sig, STDERR_FILENO); - ft_putchar_fd('\n', STDERR_FILENO); -} - void init_signals(void) { rl_event_hook = event; signal(SIGINT, sigint_handler); - signal(SIGQUIT, SIG_IGN); } diff --git a/src/utils/minishell_loop.c b/src/utils/minishell_loop.c index f5c4d2d..e59a51b 100644 --- a/src/utils/minishell_loop.c +++ b/src/utils/minishell_loop.c @@ -6,7 +6,7 @@ /* By: fpolycar +#+ */ /* +#+ */ /* Created: 2022/03/24 16:06:58 by fpolycar #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/18 13:13:36 by fpolycar ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -17,15 +17,12 @@ int minishell_loop(t_tools *tools); int implement_tools(t_tools *tools) { tools->simple_cmds = NULL; - tools->lexer_list = NULL; + tools->lexor_list = NULL; tools->reset = false; tools->pid = NULL; tools->heredoc = false; g_global.stop_heredoc = 0; - g_global.in_cmd = 0; g_global.in_heredoc = 0; - parse_envp(tools); - init_signals(); return (1); } @@ -35,17 +32,15 @@ int reset_tools(t_tools *tools) free(tools->args); if (tools->pid) free(tools->pid); - free_arr(tools->paths); implement_tools(tools); tools->reset = true; + // system("leaks minishell"); minishell_loop(tools); return (1); } int prepare_executor(t_tools *tools) { - signal(SIGQUIT, sigquit_handler); - g_global.in_cmd = 1; if (tools->pipes == 0) single_cmd(tools->simple_cmds, tools); else @@ -55,7 +50,6 @@ int prepare_executor(t_tools *tools) return (ft_error(1, tools)); executor(tools); } - g_global.in_cmd = 0; return (EXIT_SUCCESS); } diff --git a/src/utils/parse_envp.c b/src/utils/parse_envp.c index e6e385a..80b2da6 100644 --- a/src/utils/parse_envp.c +++ b/src/utils/parse_envp.c @@ -6,7 +6,7 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2021/12/17 16:16:57 by mgraaf #+# #+# */ -/* Updated: 2022/04/20 15:15:58 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/03/23 15:01:24 by fpolycar ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -32,16 +32,17 @@ int find_pwd(t_tools *tools) char *find_path(char **envp) { + char *path_from_envp; int i; i = 0; while (envp[i]) { if (!ft_strncmp(envp[i], "PATH=", 5)) - return (ft_substr(envp[i], 5, ft_strlen(envp[i]) - 5)); + path_from_envp = ft_substr(envp[i], 5, ft_strlen(envp[i]) - 5); i++; } - return (ft_strdup("\0")); + return (path_from_envp); } int parse_envp(t_tools *tools) @@ -65,5 +66,6 @@ int parse_envp(t_tools *tools) } i++; } - return (EXIT_SUCCESS); + find_pwd(tools); + return (1); } diff --git a/src/utils/t_heredoc_utils.c b/src/utils/t_heredoc_utils.c new file mode 100644 index 0000000..a3eca21 --- /dev/null +++ b/src/utils/t_heredoc_utils.c @@ -0,0 +1,91 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* t_heredoc_utils.c :+: :+: */ +/* +:+ */ +/* By: mgraaf +#+ */ +/* +#+ */ +/* Created: 2022/02/17 15:31:53 by mgraaf #+# #+# */ +/* Updated: 2022/04/15 16:06:32 by mgraaf ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +#include "utils.h" + +t_heredoc *ft_heredocnew(char *del) +{ + t_heredoc *new_element; + + new_element = (t_heredoc *)malloc(sizeof(t_heredoc)); + if (!new_element) + return (0); + new_element->del = del; + new_element->next = NULL; + new_element->prev = NULL; + return (new_element); +} + +void ft_heredocadd_back(t_heredoc **lst, t_heredoc *new) +{ + t_heredoc *tmp; + t_heredoc *prev; + + tmp = *lst; + if (*lst == NULL) + { + *lst = new; + return ; + } + while (tmp->next != NULL) + { + prev = tmp; + tmp = tmp->next; + } + tmp->next = new; + new->prev = tmp; +} + +int ft_heredocsize(t_heredoc *lst) +{ + int i; + + i = 0; + while (lst != NULL) + { + lst = lst->next; + i++; + } + return (i); +} + +void ft_heredocclear(t_heredoc **lst) +{ + t_heredoc *tmp; + + if (!*lst) + return ; + while (*lst) + { + tmp = (*lst)->next; + free((*lst)->del); + (*lst)->del = NULL; + free(*lst); + *lst = tmp; + } + *lst = NULL; +} + +t_heredoc *ft_heredocfirst(t_heredoc *map) +{ + int i; + + i = 0; + if (!map) + return (NULL); + while (map->prev != NULL) + { + map = map->prev; + i++; + } + return (map); +} diff --git a/src/utils/t_lexer_clear_utils.c b/src/utils/t_lexor_clear_utils.c similarity index 79% rename from src/utils/t_lexer_clear_utils.c rename to src/utils/t_lexor_clear_utils.c index b563643..02c8849 100644 --- a/src/utils/t_lexer_clear_utils.c +++ b/src/utils/t_lexor_clear_utils.c @@ -6,13 +6,13 @@ /* By: maiadegraaf str) { @@ -24,28 +24,28 @@ t_lexer *ft_lexerclear_one(t_lexer **lst) return (NULL); } -void ft_lexerdel_first(t_lexer **lst) +void ft_lexordel_first(t_lexor **lst) { - t_lexer *node; + t_lexor *node; node = *lst; *lst = node->next; - ft_lexerclear_one(&node); + ft_lexorclear_one(&node); if (*lst) (*lst)->prev = NULL; } -void ft_lexerdelone(t_lexer **lst, int key) +void ft_lexordelone(t_lexor **lst, int key) { - t_lexer *node; - t_lexer *prev; - t_lexer *start; + t_lexor *node; + t_lexor *prev; + t_lexor *start; start = *lst; node = start; if ((*lst)->i == key) { - ft_lexerdel_first(lst); + ft_lexordel_first(lst); return ; } while (node && node->i != key) @@ -59,13 +59,13 @@ void ft_lexerdelone(t_lexer **lst, int key) prev->next = NULL; if (prev->next) prev->next->prev = prev; - ft_lexerclear_one(&node); + ft_lexorclear_one(&node); *lst = start; } -void ft_lexerclear(t_lexer **lst) +void ft_lexorclear(t_lexor **lst) { - t_lexer *tmp; + t_lexor *tmp; if (!*lst) return ; diff --git a/src/utils/t_lexer_utils.c b/src/utils/t_lexor_utils.c similarity index 80% rename from src/utils/t_lexer_utils.c rename to src/utils/t_lexor_utils.c index 559e4b6..8f1a572 100644 --- a/src/utils/t_lexer_utils.c +++ b/src/utils/t_lexor_utils.c @@ -1,7 +1,7 @@ /* ************************************************************************** */ /* */ /* :::::::: */ -/* t_lexer_utils.c :+: :+: */ +/* t_lexor_utils.c :+: :+: */ /* +:+ */ /* By: mgraaf +#+ */ /* +#+ */ @@ -12,12 +12,12 @@ #include "utils.h" -t_lexer *ft_lexernew(char *str, int token) +t_lexor *ft_lexornew(char *str, int token) { - t_lexer *new_element; + t_lexor *new_element; static int i = 0; - new_element = (t_lexer *)malloc(sizeof(t_lexer)); + new_element = (t_lexor *)malloc(sizeof(t_lexor)); if (!new_element) return (0); new_element->str = str; @@ -28,9 +28,10 @@ t_lexer *ft_lexernew(char *str, int token) return (new_element); } -void ft_lexeradd_back(t_lexer **lst, t_lexer *new) +void ft_lexoradd_back(t_lexor **lst, t_lexor *new) { - t_lexer *tmp; + t_lexor *tmp; + t_lexor *prev; tmp = *lst; if (*lst == NULL) @@ -39,7 +40,10 @@ void ft_lexeradd_back(t_lexer **lst, t_lexer *new) return ; } while (tmp->next != NULL) + { + prev = tmp; tmp = tmp->next; + } tmp->next = new; new->prev = tmp; } diff --git a/src/utils/t_simple_cmds_utils.c b/src/utils/t_simple_cmds_utils.c index 64380f0..8a4b14b 100644 --- a/src/utils/t_simple_cmds_utils.c +++ b/src/utils/t_simple_cmds_utils.c @@ -6,14 +6,14 @@ /* By: mgraaf +#+ */ /* +#+ */ /* Created: 2022/02/17 15:31:53 by mgraaf #+# #+# */ -/* Updated: 2022/10/03 17:56:15 by maiadegraaf ######## odam.nl */ +/* Updated: 2022/04/19 15:13:32 by maiadegraaf ######## odam.nl */ /* */ /* ************************************************************************** */ #include "utils.h" t_simple_cmds *ft_simple_cmdsnew(char **str, - int num_redirections, t_lexer *redirections) + int num_redirections, t_lexor *redirections) { t_simple_cmds *new_element; @@ -33,6 +33,7 @@ t_simple_cmds *ft_simple_cmdsnew(char **str, void ft_simple_cmdsadd_back(t_simple_cmds **lst, t_simple_cmds *new) { t_simple_cmds *tmp; + t_simple_cmds *prev; tmp = *lst; if (*lst == NULL) @@ -41,7 +42,10 @@ void ft_simple_cmdsadd_back(t_simple_cmds **lst, t_simple_cmds *new) return ; } while (tmp->next != NULL) + { + prev = tmp; tmp = tmp->next; + } tmp->next = new; new->prev = tmp; } @@ -53,7 +57,7 @@ void ft_simple_cmds_rm_first(t_simple_cmds **lst) if (!*lst) return ; tmp = (*lst)->next; - ft_lexerclear(&(*lst)->redirections); + ft_lexorclear(&(*lst)->redirections); free(*lst); *lst = tmp; } @@ -61,7 +65,7 @@ void ft_simple_cmds_rm_first(t_simple_cmds **lst) void ft_simple_cmdsclear(t_simple_cmds **lst) { t_simple_cmds *tmp; - t_lexer *redirections_tmp; + t_lexor *redirections_tmp; if (!*lst) return ; @@ -69,7 +73,7 @@ void ft_simple_cmdsclear(t_simple_cmds **lst) { tmp = (*lst)->next; redirections_tmp = (*lst)->redirections; - ft_lexerclear(&redirections_tmp); + ft_lexorclear(&redirections_tmp); if ((*lst)->str) free_arr((*lst)->str); if ((*lst)->hd_file_name) diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..66e8ccb --- /dev/null +++ b/test/Makefile @@ -0,0 +1,123 @@ +CLEANUP=rm -f +MKDIR=mkdir -p +TARGET_EXTENSION=out +UNITY_CONFIG_DEFINES = -D UNITY_OUTPUT_COLOR \ + -D UNITY_FIXTURE_NO_EXTRAS + +.PHONY: clean +.PHONY: re +.PHONY: test + +PATHLIBFT = ../libraries/libft +PATHU = ../unity/src/ +PATHI = ../includes/ +PATHS = ../src/ +PATHSL = ../src/lexor/ +PATHSP = ../src/parser/ +PATHP = ../src/pipex/ +PATHSU = ../src/utils/ +PATHSB = ../src/builtins/ +PATHSE = ../src/error/ +PATHSEXP = ../src/expander/ +PATHSEXC = ../src/executor/ +PATHT = ../test/ +PATHB = ../build/ +PATHO = ../build/objs/ +PATHR = ../build/results/ + +LIBFT = ../libraries/libft/libft.a + +BUILD_PATHS = $(PATHB) $(PATHD) $(PATHO) $(PATHR) + +HEADER = $(wildcard $(PATHI)*.h) + +SRCT = $(wildcard $(PATHT)*.c) + +src = $(wildcard $(PATHSL)*.c) \ + $(wildcard $(PATHSP)*.c) \ + $(wildcard $(PATHSU)*.c) \ + $(wildcard $(PATHSB)*.c) \ + $(wildcard $(PATHSEXC)*.c) \ + $(wildcard $(PATHSEXP)*.c) \ + $(wildcard $(PATHSE)*.c) + +COMPILE=gcc -c + +LINK=gcc + +CFLAGS= -I. -I$(PATHU) -I$(PATHLIBFT) -I$(PATHS) -I$(PATHP) -I$(PATHI) + +RESULTS = $(patsubst $(PATHT)Test%.c,$(PATHR)Test%.txt, $(SRCT)) + +OBJS = $(addprefix $(PATHO), $(notdir $(patsubst %.c, %.o, $(src)))) + +test: $(BUILD_PATHS) $(RESULTS) + @./call_read_tester.sh + +$(PATHR)%.txt: $(PATHO)%.$(TARGET_EXTENSION) + -./$< > $@ 2>&1 + +$(PATHO)Test%.$(TARGET_EXTENSION): $(LIBFT) $(OBJS) $(PATHO)Test%.o $(PATHO)%.o $(PATHU)unity.o + @$(LINK) -lreadline -o $@ $^ + +# $(PATHO)%.o:: $(PATHT)%.c $(PATHSL)%.c $(PATHSP)%.c $(PATHSU)%.c $(PATHSB)%.c $(PATHSE)%.c $(HEADERS) +# $(COMPILE) $(CFLAGS) $(UNITY_CONFIG_DEFINES) $< -o $@ + +$(PATHO)%.o:: $(PATHT)%.c $(HEADERS) + @$(COMPILE) $(CFLAGS) $< -o $@ + +# $(PATHO)%.o:: $(PATHS)%.c $(HEADERS) +# $(COMPILE) $(CFLAGS) $< -o $@ + +$(PATHO)%.o:: $(PATHSL)%.c $(HEADERS) + @$(COMPILE) $(CFLAGS) $< -o $@ + +$(PATHO)%.o:: $(PATHSP)%.c $(HEADERS) + @$(COMPILE) $(CFLAGS) $< -o $@ + +$(PATHO)%.o:: $(PATHSU)%.c $(HEADERS) + @$(COMPILE) $(CFLAGS) $< -o $@ + +$(PATHO)%.o:: $(PATHSB)%.c $(HEADERS) + @$(COMPILE) $(CFLAGS) $< -o $@ + +$(PATHO)%.o:: $(PATHSE)%.c $(HEADERS) + @$(COMPILE) $(CFLAGS) $< -o $@ + +$(PATHO)%.o:: $(PATHSEXP)%.c $(HEADERS) + @$(COMPILE) $(CFLAGS) $< -o $@ + +$(PATHO)%.o:: $(PATHSEXC)%.c $(HEADERS) + @$(COMPILE) $(CFLAGS) $< -o $@ + +$(PATHO)%.o:: $(PATHU)%.c $(PATHU)%.h + @$(COMPILE) $(CFLAGS) $< -o $@ + +# $(PATHO)%.o:: $(PATHU)%.c $(PATHU)%.h +# @$(COMPILE) $(CFLAGS) $(UNITY_CONFIG_DEFINES) $< -o $@ + +$(PATHB): + @$(MKDIR) $(PATHB) + +$(PATHO): + @$(MKDIR) $(PATHO) + +$(PATHR): + @$(MKDIR) $(PATHR) + +$(LIBFT): + @$(MAKE) -C $(PATHLIBFT) + +clean: + $(CLEANUP) $(PATHO)*.o + $(CLEANUP) $(PATHB)*.$(TARGET_EXTENSION) + $(CLEANUP) $(PATHR)*.txt + rm -rdf $(PATHB) + make fclean -C $(PATHLIBFT) + +re: clean test + +.PRECIOUS: $(PATHB)Test%.$(TARGET_EXTENSION) +.PRECIOUS: $(PATHD)%.d +.PRECIOUS: $(PATHO)%.o +.PRECIOUS: $(PATHR)%.txt diff --git a/test/Testbuiltins.cttttt b/test/Testbuiltins.cttttt new file mode 100644 index 0000000..642f02d --- /dev/null +++ b/test/Testbuiltins.cttttt @@ -0,0 +1,198 @@ +#include "unity.h" +#include "minishell.h" +#include "parser.h" +#include + +t_tools test_tools; +t_simple_cmds test_simple_cmd; +char *path_to_test; +char *path_to_minishell; +char **test_envp; + +void setUp(void) +{ + // set stuff up here +} + +void tearDown(void) +{ + // clean stuff up here +} + +void init_test(char *line) +{ + implement_tools(&test_tools); + test_tools.out = open("tmp.text", O_CREAT | O_RDWR | O_TRUNC, 0644); + test_simple_cmd.str = ft_split(line, ' '); + test_simple_cmd.builtin = builtin_arr(test_simple_cmd.str[0]); + test_simple_cmd.num_redirections = 0; + test_simple_cmd.redirections = NULL; + test_simple_cmd.builtin(&test_tools, &test_simple_cmd); +} + +void assert_mini_echo(void) +{ + TEST_ASSERT_NOT_NULL_MESSAGE(test_simple_cmd.builtin, "Builtin function not connected."); +} + +void assert_mini_cd(char *expected_new_path, char *expected_old_path) +{ + TEST_ASSERT_NOT_NULL_MESSAGE(test_simple_cmd.builtin, "Builtin function not connected."); + TEST_ASSERT_EQUAL_STRING_MESSAGE(expected_new_path, test_tools.pwd, "New path incorrectly assigned"); + TEST_ASSERT_EQUAL_STRING_MESSAGE(expected_old_path, test_tools.old_pwd, "Old path incorectly assigned"); +} + +void assert_mini_env(char **expected_envp) +{ + TEST_ASSERT_NOT_NULL_MESSAGE(test_simple_cmd.builtin, "Builtin function not connected."); + TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected_envp, test_tools.envp, ft_strlen(*expected_envp), "Incorrect ENV"); +} + +// void assert_mini_exit(void) +// { +// TEST_ASSERT_NOT_NULL_MESSAGE(test_simple_cmd.builtin, "Builtin function not connected."); +// } + +void assert_mini_export(char *variable_name, char *expected) +{ + TEST_ASSERT_NOT_NULL_MESSAGE(test_simple_cmd.builtin, "Builtin function not connected."); + int i = 0; + int x = 0; + while (test_tools.envp[i]) + { + if (!ft_strncmp(variable_name, test_tools.envp[i], ft_strlen(variable_name))) + { + TEST_ASSERT_EQUAL_STRING(expected, test_tools.envp[i]); + x++; + } + i++; + } + TEST_ASSERT_FALSE_MESSAGE(x != 1, "Variable exists more than once or is not present in ENVP"); +} + +void assert_mini_pwd(char *pwd) +{ + TEST_ASSERT_NOT_NULL_MESSAGE(test_simple_cmd.builtin, "Builtin function not connected."); + TEST_ASSERT_EQUAL_STRING(pwd, test_tools.pwd); +} + +void assert_mini_unset(char *variable_name) +{ + TEST_ASSERT_NOT_NULL_MESSAGE(test_simple_cmd.builtin, "Builtin function not connected."); + int i = 0; + while (test_tools.envp[i]) + { + if (!ft_strncmp(variable_name, test_tools.envp[i], ft_strlen(variable_name))) + { + TEST_FAIL_MESSAGE("Variable still exists in ENVP"); + } + i++; + } +} + +void test_builtin_1(void) +{ + init_test("echo hello"); + assert_mini_echo(); +} + +void test_builtin_2(void) +{ + init_test("env"); + assert_mini_env(test_envp); +} + +void test_builtin_3(void) +{ + init_test("cd .."); + assert_mini_cd(path_to_minishell, path_to_test); +} + +void test_builtin_4(void) +{ + init_test(ft_strjoin("cd /Users/", ft_strjoin(getenv("USER"), "/Documents"))); + assert_mini_cd(ft_strjoin("/Users/", ft_strjoin(getenv("USER"), "/Documents")), path_to_minishell); +} + +void test_builtin_5(void) +{ + init_test(ft_strjoin(ft_strjoin("cd ", path_to_minishell), "/src")); + assert_mini_cd(ft_strjoin(path_to_minishell, "/src"), ft_strjoin("/Users/", ft_strjoin(getenv("USER"), "/Documents"))); +} + +void test_builtin_6(void) +{ + init_test("export test=\"a\""); + assert_mini_export("test", "test=a"); +} + +void test_builtin_7(void) +{ + init_test("export test=\'b\'"); + assert_mini_export("test", "test=b"); +} + +void test_builtin_8(void) +{ + init_test("unset test"); + assert_mini_unset("test"); +} + +void test_builtin_9(void) +{ + init_test("export test2=c"); + assert_mini_export("test2", "test2=c"); +} + +void test_builtin_10(void) +{ + init_test("env"); + assert_mini_env(test_envp); +} + +void test_builtin_11(void) +{ + init_test("pwd"); + assert_mini_pwd(getcwd(NULL, sizeof(NULL))); +} + +void test_builtin_12(void) +{ + init_test("unset test2"); + assert_mini_unset("test2"); +} + +int main(int argc, char **argv, char **envp) +{ + UNITY_BEGIN(); + test_envp = envp; + test_tools.envp = ft_arrdup(envp); + parse_envp(&test_tools); + path_to_test = getenv("PWD"); + path_to_minishell = ft_substr(path_to_test, 0, ft_strlen(path_to_test) - ft_strlen("/test")); + RUN_TEST(test_builtin_1); + TEST_MESSAGE("1: {echo hello}"); + RUN_TEST(test_builtin_2); + TEST_MESSAGE("2: env"); + RUN_TEST(test_builtin_3); + TEST_MESSAGE("3: {cd ..}"); + RUN_TEST(test_builtin_4); + TEST_MESSAGE("4: {cd {path to} Documents'}"); + RUN_TEST(test_builtin_5); + TEST_MESSAGE("5: {cd {path from Documents to} minishell/src}"); + RUN_TEST(test_builtin_6); + TEST_MESSAGE("6: {export test=\"a\"}"); + RUN_TEST(test_builtin_7); + TEST_MESSAGE("7: {export test=\"b\"}"); + RUN_TEST(test_builtin_8); + TEST_MESSAGE("8: {unset test}"); + RUN_TEST(test_builtin_9); + TEST_MESSAGE("9: {export test2=c}"); + // RUN_TEST(test_builtin_10); + // TEST_MESSAGE("10: {env}"); + RUN_TEST(test_builtin_11); + TEST_MESSAGE("11: {pwd}"); + RUN_TEST(test_builtin_12); + TEST_MESSAGE("12: {unset test2}"); + return UNITY_END(); +} \ No newline at end of file diff --git a/test/Testexecutor.cx b/test/Testexecutor.cx new file mode 100644 index 0000000..5b25464 --- /dev/null +++ b/test/Testexecutor.cx @@ -0,0 +1,145 @@ +#include "unity.h" +#include "minishell.h" +#include "parser.h" +#include + +t_tools test_tools; +t_simple_cmds test_simple_cmd; + +void setUp(void) +{ + // set stuff up here +} + +void tearDown(void) +{ + // clean stuff up here +} + +void init_test(char *line) +{ + test_tools.args = line; + token_reader(&test_tools); + parser(&test_tools); + expander(&test_tools, test_tools.simple_cmds); +} + +void assert_executor(char **expected) +{ + TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, test_tools.simple_cmds->str, (ft_strlen(*expected) - 2), "Incorrect variable replacement"); +} + +void test_executor_1(void) +{ + init_test("echo $USER"); + assert_executor(ft_split(ft_strjoin("echo ", getenv("USER")), ' ')); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_executor_2(void) +{ + init_test("echo \"$HOME\""); + assert_executor(ft_split(ft_strjoin("echo ", getenv("HOME")), ' ')); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_executor_3(void) +{ + init_test("echo \'$HOME\'"); + assert_executor(ft_split("echo \'$HOME\'", ' ')); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +// void test_executor_4(void) +// { +// init_test(ft_strjoin("cd /Users/", ft_strjoin(getenv("USER"), "/Documents"))); +// assert_executor(ft_strjoin("/Users/", ft_strjoin(getenv("USER"), "/Documents")), path_to_minishell); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_executor_5(void) +// { +// init_test(ft_strjoin(ft_strjoin("cd ", path_to_minishell), "/src")); +// assert_executor(ft_strjoin(path_to_minishell, "/src"), ft_strjoin("/Users/", ft_strjoin(getenv("USER"), "/Documents"))); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_executor_6(void) +// { +// init_test("export test=\"a\""); +// assert_executor("test", "test=a"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_executor_7(void) +// { +// init_test("export test=\"b\""); +// assert_executor("test", "test=b"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_executor_8(void) +// { +// init_test("unset test"); +// assert_executor("test"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_executor_9(void) +// { +// init_test("export test2=c"); +// assert_executor("test2", "test2=c"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_executor_10(void) +// { +// init_test("env"); +// assert_executor(test_envp); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_executor_11(void) +// { +// init_test("pwd"); +// assert_executor(getcwd(NULL, sizeof(NULL))); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_executor_12(void) +// { +// init_test("unset test2"); +// assert_executor("test2"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +int main(int argc, char **argv, char **envp) +{ + test_tools.envp = ft_arrdup(envp); + UNITY_BEGIN(); + // RUN_TEST(test_executor_1); + // TEST_MESSAGE("1: {echo $USER}"); + // RUN_TEST(test_executor_2); + // TEST_MESSAGE("2: {echo \"$HOME\"}"); + // RUN_TEST(test_executor_3); + // TEST_MESSAGE("3: {echo \'$HOME\'}"); + // RUN_TEST(test_executor_4); + // TEST_MESSAGE("4: {cd {path to} Documents'}"); + // RUN_TEST(test_executor_5); + // TEST_MESSAGE("5: {cd {path from Documents to} minishell/src}"); + // RUN_TEST(test_executor_6); + // TEST_MESSAGE("6: {export test=\"a\"}"); + // RUN_TEST(test_executor_7); + // TEST_MESSAGE("7: {export test=\"b\"}"); + // RUN_TEST(test_executor_8); + // TEST_MESSAGE("8: {unset test}"); + // RUN_TEST(test_executor_9); + // TEST_MESSAGE("9: {export test2=c}"); + // // RUN_TEST(test_executor_10); + // // TEST_MESSAGE("10: {env}"); + // RUN_TEST(test_executor_11); + // TEST_MESSAGE("11: {pwd}"); + // RUN_TEST(test_executor_12); + // TEST_MESSAGE("12: {unset test2}"); + return UNITY_END(); +} \ No newline at end of file diff --git a/test/Testexpander.cttttt b/test/Testexpander.cttttt new file mode 100644 index 0000000..54f83ed --- /dev/null +++ b/test/Testexpander.cttttt @@ -0,0 +1,145 @@ +#include "unity.h" +#include "minishell.h" +#include "parser.h" +#include + +t_tools test_tools; +t_simple_cmds test_simple_cmd; + +void setUp(void) +{ + // set stuff up here +} + +void tearDown(void) +{ + // clean stuff up here +} + +void init_test(char *line) +{ + test_tools.args = line; + token_reader(&test_tools); + parser(&test_tools); + expander(&test_tools); +} + +void assert_expander(char **expected) +{ + TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, test_tools.simple_cmds->str, (ft_strlen(*expected) - 2), "Incorrect variable replacement"); +} + +void test_expander_1(void) +{ + init_test("echo $USER"); + assert_expander(ft_split(ft_strjoin("echo ", getenv("USER")), ' ')); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_expander_2(void) +{ + init_test("echo \"$HOME\""); + assert_expander(ft_split(ft_strjoin("echo ", getenv("HOME")), ' ')); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_expander_3(void) +{ + init_test("echo \'$HOME\'"); + assert_expander(ft_split("echo \'$HOME\'", ' ')); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +// void test_expander_4(void) +// { +// init_test(ft_strjoin("cd /Users/", ft_strjoin(getenv("USER"), "/Documents"))); +// assert_expander(ft_strjoin("/Users/", ft_strjoin(getenv("USER"), "/Documents")), path_to_minishell); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_expander_5(void) +// { +// init_test(ft_strjoin(ft_strjoin("cd ", path_to_minishell), "/src")); +// assert_expander(ft_strjoin(path_to_minishell, "/src"), ft_strjoin("/Users/", ft_strjoin(getenv("USER"), "/Documents"))); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_expander_6(void) +// { +// init_test("export test=\"a\""); +// assert_expander("test", "test=a"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_expander_7(void) +// { +// init_test("export test=\"b\""); +// assert_expander("test", "test=b"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_expander_8(void) +// { +// init_test("unset test"); +// assert_expander("test"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_expander_9(void) +// { +// init_test("export test2=c"); +// assert_expander("test2", "test2=c"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_expander_10(void) +// { +// init_test("env"); +// assert_expander(test_envp); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_expander_11(void) +// { +// init_test("pwd"); +// assert_expander(getcwd(NULL, sizeof(NULL))); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +// void test_expander_12(void) +// { +// init_test("unset test2"); +// assert_expander("test2"); +// ft_simple_cmdsclear(&test_tools.simple_cmds); +// } + +int main(int argc, char **argv, char **envp) +{ + test_tools.envp = ft_arrdup(envp); + UNITY_BEGIN(); + RUN_TEST(test_expander_1); + TEST_MESSAGE("1: {echo $USER}"); + RUN_TEST(test_expander_2); + TEST_MESSAGE("2: {echo \"$HOME\"}"); + RUN_TEST(test_expander_3); + TEST_MESSAGE("3: {echo \'$HOME\'}"); + // RUN_TEST(test_expander_4); + // TEST_MESSAGE("4: {cd {path to} Documents'}"); + // RUN_TEST(test_expander_5); + // TEST_MESSAGE("5: {cd {path from Documents to} minishell/src}"); + // RUN_TEST(test_expander_6); + // TEST_MESSAGE("6: {export test=\"a\"}"); + // RUN_TEST(test_expander_7); + // TEST_MESSAGE("7: {export test=\"b\"}"); + // RUN_TEST(test_expander_8); + // TEST_MESSAGE("8: {unset test}"); + // RUN_TEST(test_expander_9); + // TEST_MESSAGE("9: {export test2=c}"); + // // RUN_TEST(test_expander_10); + // // TEST_MESSAGE("10: {env}"); + // RUN_TEST(test_expander_11); + // TEST_MESSAGE("11: {pwd}"); + // RUN_TEST(test_expander_12); + // TEST_MESSAGE("12: {unset test2}"); + return UNITY_END(); +} \ No newline at end of file diff --git a/test/Testparser.c b/test/Testparser.c new file mode 100644 index 0000000..5f7aa00 --- /dev/null +++ b/test/Testparser.c @@ -0,0 +1,180 @@ +#include "unity.h" +#include "lexor.h" +#include + +t_tools test_tools; + +void setUp(void) +{ + // set stuff up here +} + +void tearDown(void) +{ + // clean stuff up here +} + +void init_test(char *line) +{ + test_tools.args = line; + token_reader(&test_tools); + parser(&test_tools); +} + +void assert_parser(char **expected, char *builtin, int num_directions, t_lexor *expected_redirection) +{ + int i; + + i = 0; + if (expected) + { + while (expected[i]) + { + TEST_ASSERT_EQUAL_STRING_MESSAGE(expected[i], test_tools.simple_cmds->str[i], "Incorrect: STR"); + i++; + } + } + if (builtin) + TEST_ASSERT_NOT_NULL_MESSAGE(test_tools.simple_cmds->builtin, "Incorrect: BUILTIN"); + else + TEST_ASSERT_NULL(test_tools.simple_cmds->builtin); + TEST_ASSERT_EQUAL_INT_MESSAGE(num_directions, test_tools.simple_cmds->num_redirections, "Incorrect: NUM REDIRECTIONS"); + if (expected_redirection) + { + t_lexor *start = expected_redirection; + while (expected_redirection) + { + TEST_ASSERT_EQUAL_STRING(expected_redirection->str, test_tools.simple_cmds->redirections->str); + TEST_ASSERT_EQUAL_INT(expected_redirection->token, test_tools.simple_cmds->redirections->token); + test_tools.simple_cmds->redirections = test_tools.simple_cmds->redirections->next; + expected_redirection = expected_redirection->next; + } + } + test_tools.simple_cmds = test_tools.simple_cmds->next; +} + +void test_parser_1(void) +{ + init_test("test test"); + assert_parser(ft_split("test test", ' '), NULL, 0, NULL); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_2(void) +{ + init_test("test test | test"); + assert_parser(ft_split("test test", ' '), NULL, 0, NULL); + assert_parser(ft_split("test", ' '), NULL, 0, NULL); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_3(void) +{ + init_test("test test | test | \'test\'"); + assert_parser(ft_split("test test", ' '), NULL, 0, NULL); + assert_parser(ft_split("test", ' '), NULL, 0, NULL); + assert_parser(ft_split("\'test\'", ' '), NULL, 0, NULL); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_4(void) +{ + init_test("< redirection"); + assert_parser(NULL, NULL, 1, ft_lexornew("redirection", LESS)); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_5(void) +{ + init_test("test > redirection"); + assert_parser(ft_split("test", ' '), NULL, 1, ft_lexornew("redirection", GREAT)); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_6(void) +{ + init_test("test > redirection < redirection >> redirection"); + t_lexor *lst= ft_lexornew("redirection", GREAT); + ft_lexoradd_back(&lst, ft_lexornew("redirection", LESS)); + ft_lexoradd_back(&lst, ft_lexornew("redirection", GREAT_GREAT)); + assert_parser(ft_split("test", ' '), NULL, 3, lst); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_7(void) +{ + init_test("test > redirection < redirection | heredoc << EOF"); + t_lexor *lst = ft_lexornew("redirection", GREAT); + ft_lexoradd_back(&lst, ft_lexornew("redirection", LESS)); + assert_parser(ft_split("test", ' '), NULL, 2, lst); + assert_parser(NULL, NULL, 1, ft_lexornew("heredoc|EOF", LESS_LESS)); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_8(void) +{ + init_test("test > redirection < redirection | heredoc < redirection >> redirection << EOF"); + t_lexor *lst = ft_lexornew("redirection", GREAT); + ft_lexoradd_back(&lst, ft_lexornew("redirection", LESS)); + assert_parser(ft_split("test", ' '), NULL, 2, lst); + t_lexor *lst2 = ft_lexornew("redirection", LESS); + ft_lexoradd_back(&lst2, ft_lexornew("redirection", GREAT_GREAT)); + ft_lexoradd_back(&lst2, ft_lexornew("heredoc|EOF", LESS_LESS)); + assert_parser(NULL, NULL, 3, lst2); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_9(void) +{ + init_test("cat test | test < redirection | echo test"); + assert_parser(ft_split("cat test", ' '), NULL, 0, NULL); + assert_parser(ft_split("test", ' '), NULL, 1, ft_lexornew("redirection", LESS)); + assert_parser(ft_split("echo test", ' '), "YES", 0, NULL); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_10(void) +{ + init_test("cd test | env < redirection | exit test"); + assert_parser(ft_split("cd test", ' '), "YES", 0, NULL); + assert_parser(ft_split("env", ' '), "YES", 1, ft_lexornew("redirection", LESS)); + assert_parser(ft_split("exit test", ' '), "YES", 0, NULL); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +void test_parser_11(void) +{ + init_test("export test | pwd < redirection | unset test"); + assert_parser(ft_split("export test", ' '), "YES", 0, NULL); + assert_parser(ft_split("pwd", ' '), "YES", 1, ft_lexornew("redirection", LESS)); + assert_parser(ft_split("unset test", ' '), "YES", 0, NULL); + ft_simple_cmdsclear(&test_tools.simple_cmds); +} + +int main(void) +{ + UNITY_BEGIN(); + RUN_TEST(test_parser_1); + TEST_MESSAGE("1: {test test}"); + RUN_TEST(test_parser_2); + TEST_MESSAGE("2: {test test | test}"); + RUN_TEST(test_parser_3); + TEST_MESSAGE("3: {test test | test | \'test\'}"); + RUN_TEST(test_parser_4); + TEST_MESSAGE("4: {< redirection}"); + RUN_TEST(test_parser_5); + TEST_MESSAGE("5: {test > redirection}"); + RUN_TEST(test_parser_6); + TEST_MESSAGE("6: {test > redirection < redirection >> redirection}"); + RUN_TEST(test_parser_7); + TEST_MESSAGE("7: {test > redirection < redirection | heredoc << EOF}"); + RUN_TEST(test_parser_8); + TEST_MESSAGE("8: {test > redirection < redirection | heredoc < redirection >> redirection << EOF}"); + RUN_TEST(test_parser_9); + TEST_MESSAGE("9: {cat test | test < redirection | echo test}"); + RUN_TEST(test_parser_10); + TEST_MESSAGE("10: {cd test | env < redirection | exit test}"); + RUN_TEST(test_parser_11); + TEST_MESSAGE("11: {export test | pwd < redirection | unset test}"); + return UNITY_END(); +} \ No newline at end of file diff --git a/test/Testtoken_reader.c b/test/Testtoken_reader.c new file mode 100644 index 0000000..e471363 --- /dev/null +++ b/test/Testtoken_reader.c @@ -0,0 +1,190 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* Testtoken_reader.c :+: :+: */ +/* +:+ */ +/* By: fpolycar +#+ */ +/* +#+ */ +/* Created: 2022/02/28 11:12:08 by fpolycar #+# #+# */ +/* Updated: 2022/04/19 15:13:23 by maiadegraaf ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +#include "unity.h" +#include "lexor.h" +#include "minishell.h" + +t_tools test_tools; + +void setUp(void) { + // set stuff up here +} + +void tearDown(void) { + // clean stuff up here +} + +void init_test(char *line) +{ + test_tools.args = line; + token_reader(&test_tools); +} + +void assert_token(int token, char *expected) +{ + TEST_ASSERT_EQUAL_STRING(expected, test_tools.lexor_list->str); + TEST_ASSERT_EQUAL_INT(token, test_tools.lexor_list->token); + test_tools.lexor_list = test_tools.lexor_list->next; +} + +void test_lexer_1(void) +{ + init_test(" test "); + assert_token( 0, "test"); +} + +void test_lexer_2(void) +{ + init_test(" test | test "); + assert_token(0, "test"); + assert_token(PIPE, NULL); + assert_token(0, "test"); +} + +void test_lexer_3(void) +{ + init_test(" test test test test || test test"); + assert_token(0, "test"); + assert_token(0, "test"); + assert_token(0, "test"); + assert_token(0, "test"); + assert_token(PIPE, NULL); + assert_token(PIPE, NULL); + assert_token(0, "test"); + assert_token(0, "test"); +} + +void test_lexer_4(void) +{ + init_test(" test test test"); + assert_token(0, "test"); + assert_token(0, "test"); + assert_token(0, "test"); +} + +void test_lexer_5(void) +{ + init_test("test ' test | test' ' "); + assert_token(0, "test"); + assert_token(0, "' test | test'"); +} + +void test_lexer_6(void) +{ + init_test("test \" | test\""); + assert_token(0, "test"); + assert_token(0, "\" | test\""); +} + +void test_lexer_7(void) +{ + init_test("test < | test > | test << | test >> |"); + assert_token(0, "test"); + assert_token(LESS, NULL); + assert_token(PIPE, NULL); + assert_token(0, "test"); + assert_token(GREAT, NULL); + assert_token(PIPE, NULL); + assert_token(0, "test"); + assert_token(LESS_LESS, NULL); + assert_token(PIPE, NULL); + assert_token(0, "test"); + assert_token(GREAT_GREAT, NULL); + assert_token(PIPE, NULL); +} + +void test_lexer_8(void) +{ + init_test("test -nBa -n"); + assert_token(0, "test"); + assert_token(0, "-nBa"); + assert_token(0, "-n"); +} + +void test_lexer_9(void) +{ + init_test("test $BLA$BLA=10$BLA"); + assert_token(0, "test"); + assert_token(0, "$BLA$BLA=10$BLA"); +} + +void test_lexer_10(void) +{ + init_test("test bla=\"test\" bla=\"t est\""); + assert_token(0, "test"); + assert_token(0, "bla=\"test\""); + assert_token(0, "bla=\"t est\""); +} + +void test_lexer_11(void) +{ + init_test("test\n\ntest\ftest\rtest\ttest"); + assert_token(0, "test"); + assert_token(0, "test"); + assert_token(0, "test"); + assert_token(0, "test"); + assert_token(0, "test"); +} + +void test_lexer_12(void) +{ + init_test("test|test|test>test>" "$INFO_INFO" + printf "${RED}%s${NC}\n" "$FAIL_INFO" + I=0; + fi + if [[ "$line" == *"PASS"* ]] + then + printf "${GREEN}[OK]${NC}" + elif [[ "$line" == *"FAIL"* ]] + then + printf "\n${RED}[KO]${NC}" + FAIL_INFO=$(echo $line | awk -F 'FAIL:' '{ print $2 }') + I=1; + fi + if [[ "$line" == *"Tests"*"Failures"* ]] + then + FAILURES=$(echo $line | awk -F 'Tests ' '{ print $2 }' | awk -F ' Failures' '{ print $1 }') + TESTS=$(echo $line | awk -F 'Tests' '{ print $1 }') + PASSED=$(expr $TESTS - $FAILURES) + printf "\n\n$PASSED/$TESTS\n\n" + if [ $FAILURES -gt 0 ] + then + printf "${RED}yeah no......${NC}" + else + printf "🎉🥳${GREEN}you never cease to amaze me${NC}👏🎉" + fi + break + fi +done < "$FILE" + +echo '' +center "" +echo '\n' diff --git a/test/tmp.text b/test/tmp.text new file mode 100644 index 0000000..e69de29 diff --git a/tester.sh b/tester.sh new file mode 100755 index 0000000..62a4965 --- /dev/null +++ b/tester.sh @@ -0,0 +1,281 @@ +#!/bin/bash +#set -x +#set -e + +export ASAN_OPTIONS='detect_leaks=1' +export LSAN_OPTIONS='suppressions=leak_suppression.txt print_suppressions=0' + +function check() +{ + if [ $2 -ne $3 ]; then + echo "found exit status difference for: \"$1\""; + echo "bash exit status:" $3; + echo "minishell exit status:" $2; + fi + diff minishell_out bash_out || { echo "std output test failed for: \"$1\""; echo -e "\n\n\n";} + diff minishell_err bash_err || { echo "error output test failed for: \"$1\""; echo -e "\n\n\n";} + diff minishell_outfile bash_outfile || { echo "outfile of output test failed for: \"$1\""; echo -e "\n\n\n";} +} + +function shell_test() +{ + > minishell_outfile + > bash_outfile + export OUTFILE=minishell_outfile + echo -e $1 | minishell > minishell_out 2> minishell_err + export minishell_status=$? + export OUTFILE=bash_outfile + echo -e $1 | bash > bash_out 2> bash_err + export bash_status=$? + check "$1" $minishell_status $bash_status +} + +function environment_test() +{ + export minishell_status=0 + export bash_status=0 + > minishell_outfile + > bash_outfile + export OUTFILE=minishell_outfile + echo -e $1 | minishell 2> minishell_err | sort | grep -v -f environment_exceptions > minishell_out + export minishell_status=$? + export OUTFILE=bash_outfile + echo -e $1 | bash 2> bash_err | sort | grep -v -f environment_exceptions > bash_out + export bash_status=$? + check "$1" $minishell_status $bash_status +} + +#test by hand: +########## +# cat +# -\ +# signals in here_doc +# cd < minishell.c - +########## + +#make DEBUG=1 -C .. +make re DEBUG=1 -C .. + +#new tests +shell_test 'export bla="s -a"\nl$bla' +shell_test 'export bla="s -a"\nl"$bla"' + +# Generic tests +shell_test '' +shell_test '\n\n\n\n' +shell_test 'ls\nls' +shell_test '/bin/ls' + +# Echo tests +shell_test 'echo' +shell_test 'echo ""' +shell_test 'echo < |' +shell_test 'echo > |' +shell_test 'echo << |' +shell_test 'echo >> |' +shell_test 'echo -nABC' +shell_test 'echo $BLA$BLA=10$BLA' +shell_test 'echo a"bc"d' +shell_test 'echo a"bcd"e' +shell_test "echo 'hoi'"'"bla"' +shell_test 'echo -n' +shell_test 'echo bla -n' +shell_test 'echo -n -n -n' +shell_test 'echo -n -n -n bla' +shell_test 'ls | echo -n bla' +shell_test 'echo -nnnn' +shell_test 'echo -nnnn bla' + +# CD tests +shell_test 'cd\npwd' +shell_test 'cd\npwd\ncd -\npwd' +shell_test 'cd ..\ncd tests\npwd' +shell_test 'cd ..\ncd tests/\npwd' +shell_test 'cd ../../..\npwd' +shell_test 'cd banaan' +shell_test 'cd /usr\npwd' +shell_test 'cd /usr/bin\npwd' +shell_test 'cd /bla' +shell_test 'cd /\npwd' +shell_test 'cd ..\necho $OLDPWD\ncd tests\necho $OLDPWD' +shell_test 'echo $OLDPWDcd /\necho $OLDPWD\ncd tests\necho $OLDPWD' +shell_test 'cd\nunset OLDPWD\necho oldpwd after unset: $OLDPWD\ncd -\npwd' +shell_test 'ls | ls | unset OLDPWD\necho oldpwd after unset: $OLDPWD\ncd -\npwd' +#shell_test 'unset HOME\necho home after unset: $HOME\ncd\npwd' +shell_test 'mkdir TESTDIR\ncd TESTDIR\nrmdir ../TESTDIR\npwd' + +# PWD Tests +shell_test 'pwd' +shell_test 'pwd lalala' + +# Export tests +environment_test 'export' +environment_test 'export a\nexport a=42\nexport' +environment_test 'export a=\nexport a=42\nexport' +environment_test 'export a=\nexport a\nexport' +shell_test 'export =' +shell_test 'export =10' +shell_test 'export "|"=10' +shell_test 'export ">"=10' +shell_test 'export "$"=10' +shell_test 'export "["=10' +shell_test 'export "111"="222"' +environment_test 'export A=bla\nexport' +environment_test 'export 1A=bla\nexport' +environment_test 'export A1=bla\nexport' +environment_test 'export _A=bla\nexport' +environment_test 'export A_=bla\nexport' +environment_test 'export A=bla\nexport A=bloe\nexport' +environment_test 'export A=bla\nexport A=$A-bloe\nexport' +environment_test 'export PATH=$PATH:/banaan/konijn\nexport' +shell_test 'export A$B=10\necho $A$B' +shell_test 'export B=3\necho $A$B' +shell_test 'export B+=3\necho $A$B' +shell_test 'export HOME+=3\necho $HOME' +shell_test 'export HOME=+3\necho $HOME' +environment_test 'export +=3\nexport' +shell_test 'export HOME+=\necho $HOME' +shell_test 'export A$B=10\necho $A$B\nexport B=3\necho $A$B' +environment_test 'export PA=10\nexport' +environment_test 'export a1=10\nunset a1\nexport' +environment_test 'export a=5=5\nexport' + +# unset tests +shell_test 'unset PATH\necho $PATH' +#shell_test 'unset HOME\necho $HOME' +environment_test 'unset $PATH\nexport' +environment_test 'unset a1=10\nexport' +environment_test 'unset $PATH\nexport' +environment_test 'unset PATH\nexport' +environment_test 'unset PPATH\nexport' +environment_test 'unset PATHH\nexport' +environment_test 'unset "PATH "\nexport' +environment_test 'unset " PATH"\nexport' +environment_test 'unset PATH=\nexport' +environment_test 'unset 1a\nexport' +environment_test 'unset a-\nexport' +environment_test 'unset a-\nexport' +environment_test 'unset a_\nexport' + +# ENV tests +environment_test 'env' + +# Exit tests +shell_test "exit" +shell_test "exit 0" +shell_test "exit 1" +shell_test "exit 42" +shell_test "exit 1 1" +shell_test "exit banaan" +shell_test "exit 1000000000" + +# Redirection tests +shell_test 'pwd > $OUTFILE' +shell_test '> $OUTFILE pwd' +shell_test '> $OUTFILE ls -a' +shell_test 'cat test_shell_split.c > $OUTFILE -e' +shell_test 'cat > $OUTFILE < test_shell_split.c -e' +shell_test 'cat < test_shell_split.c > $OUTFILE -e' +shell_test '< test_shell_split.c << bla cat\nasdf\nbla\n' + +# Here doc tests +shell_test 'cat << bla -e\nasdf\n' +shell_test 'cat << bla -e\nasdf\nbla\n' +shell_test 'cat << bla\nasdf\nbla\n' +shell_test '<< bla cat\nasdf\nbla\n' +shell_test '<< bla\nasdf\nbla\n cat' +shell_test '<< bla cat\nasdf\nbla\necho banaan' +shell_test '<< bla cat < test_shell_split.c\nasdf\nbla\n' +shell_test '<< wildcard.c ls -la | wc -w >> $OUTFILE\nwildcard.c' + +# Pipe tests +shell_test 'ls | grep t' +shell_test 'ls|cat -e' +shell_test 'ls|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e|cat -e' +shell_test 'ls | < banaan | ls' +shell_test 'ls | cat > $OUTFILE' +shell_test 'ls < lol.c | grep "a"' +shell_test 'ls < test_shell_split.c | grep "a"' +shell_test '< test_shell_split.c grep a | cat -e' +shell_test '< test_shell_split.c | cat -e > $OUTFILE' +shell_test '< test_shell_split.c | ls | cat -e > $OUTFILE' +shell_test '< test_shell_split.c grep a | > $OUTFILE' +shell_test '< test_shell_split.c grep a | cat -e > $OUTFILE' +shell_test '< test_shell_split.c grep "a"|grep "m" | wc -l|cat -e > $OUTFILE' +shell_test 'ls | cat > $OUTFILE < test_shell_split.c -e' +shell_test 'cat > $OUTFILE < test_shell_split.c -e | ls' +shell_test 'ls | < integration_tests grep "a" | cat -e' +shell_test 'ls | head -n 10 | tail -n 9 | rev | sort | rev | cat -e' +shell_test 'cat | cat | ls\n' + +# Wildcard and dollar extension tests +shell_test "echo '$PATH'" +shell_test 'echo "$ a"' +shell_test 'echo $' +shell_test 'echo $9' +shell_test 'echo $9a' +shell_test 'echo $98a' +shell_test 'echo $PA' +shell_test 'echo $PA:' +shell_test 'echo $PATH:' +shell_test 'echo $HOME' +shell_test 'echo "$HOME"' +shell_test 'echo $HO"ME"' +shell_test 'echo $"HOME"' +shell_test 'echo $ "HOME"' +shell_test 'echo '\''$"HOME"'\' +shell_test 'echo "'\''$HOME'\'\" +shell_test 'echo bla $bla' +shell_test 'echo bla $bla | cat -e' + +# Quote tests +shell_test 'cat test_shell_split.c' +shell_test 'cat test_sh"ell_split.c"' +shell_test 'cat "test_sh"ell_split.c' +shell_test 'cat '"tes't_s'h"'ell_"spl"it.c' +shell_test 'exit "42"' + +# Combination tests +shell_test 'echo bla | export $BLA=bla\necho $BLA' +shell_test 'ls | > tmp_file | ls\nrm tmp_file' +shell_test 'ls | cat << bla\nasdf\nbla\n' +shell_test 'cat << bla | cat\nasdf\nbla\n' +shell_test '<< bla cat | << bloe cat\nfirst\nbla\nsecond\nbloe\n' +shell_test '<< bla cat | << bloe cat\nfirst\nbla\nsecond\nbloe\nls\n' +shell_test 'cat << bla | echo bla\nasdf\nbla\n' + +# Error tests +shell_test '|' +shell_test '<' +shell_test '>' +shell_test '< <' +shell_test '> <' +shell_test '<<' +shell_test '<< <' +shell_test '> > outfile' +shell_test 'ls | >' +shell_test 'ls | > >' +shell_test 'ls | > >>' +shell_test 'ls | <' +shell_test '< | ls' +shell_test 'ls | banaan' +shell_test 'ls | "|"' +shell_test '| ls' +shell_test 'ls |' +shell_test 'ls | | ls' +shell_test 'ls ||| cat' +shell_test 'ls\n\n\nls ||| cat' +shell_test 'ls\n\n\nexit banaan' +shell_test 'ls\n\n\nexport "$"=10' +shell_test 'ls\n\n\ncd banaan' + + +# For the next two tests with multiple output redirections, to the same file, minishell always does the same thing, but bash doesn't. +# Bash seems to open the file from different forks and they put in information at the same time, which causes race conditions. Minishell puts in information in order. + +# shell_test 'rm $OUTFILE | cat >> $OUTFILE << hd1 << hd2 -e | >> $OUTFILE << hd3 | cat < test_shell_split.c << hd4 >> $OUTFILE | >> $OUTFILE echo *$PATH * $PATH "*"$PATH -e\n1\nhd1\n2\nhd2\n3\nhd3\n4\nhd4\n' +# shell_test 'cat > $OUTFILE << hd1 << hd2 -e | >> $OUTFILE << hd3 | cat < test_shell_split.c >> $OUTFILE << hd4 -e\n1\nhd1\n2\nhd2\n3\nhd3\n4\nhd4\n' + +norminette src + +echo integration tests finished! \ No newline at end of file diff --git a/utilities/minitalk/Makefile b/utilities/minitalk/Makefile new file mode 100644 index 0000000..5757550 --- /dev/null +++ b/utilities/minitalk/Makefile @@ -0,0 +1,45 @@ +# **************************************************************************** # +# # +# :::::::: # +# Makefile :+: :+: # +# +:+ # +# By: fpolycar +#+ # +# +#+ # +# Created: 2021/12/15 10:49:26 by fpolycar #+# #+# # +# Updated: 2022/02/04 14:06:57 by fpolycar ######## odam.nl # +# # +# **************************************************************************** # + +SERVER = server +CLIENT = client +CC = gcc +CFLAGS = -Wall -Werror -Wextra +AR = ar ru +RM = rm -f +LIBFT = ./libft/libft.a + +all: $(LIBFT) $(SERVER) $(CLIENT) + +$(LIBFT): + @make bonus -C libft + +$(SERVER): server.o minitalk.h + $(CC) server.o $(LIBFT) -o $@ + @printf "\e[38;5;226m./$@ successfully build\e[0m\n" + +$(CLIENT): client.o minitalk.h + $(CC) client.o $(LIBFT) -o $@ + @printf "\e[38;5;46m./$@ successfully build\e[0m\n" + +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $< + +clean: + @make clean -C libft + $(RM) *.o + +fclean: clean + @make fclean -C libft + rm -f $(CLIENT) $(SERVER) + +re: fclean all diff --git a/utilities/minitalk/client.c b/utilities/minitalk/client.c new file mode 100644 index 0000000..0ffc357 --- /dev/null +++ b/utilities/minitalk/client.c @@ -0,0 +1,75 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* client.c :+: :+: */ +/* +:+ */ +/* By: fpolycar +#+ */ +/* +#+ */ +/* Created: 2021/12/15 10:49:04 by fpolycar #+# #+# */ +/* Updated: 2021/12/17 15:17:43 by fpolycar ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +#include "minitalk.h" + +void send_binary(int pid, int *bin) +{ + int i; + + i = 7; + while (i >= 0) + { + if (bin[i] == 1) + { + kill(pid, SIGUSR2); + } + if (bin[i] == 0) + { + kill(pid, SIGUSR1); + } + usleep(100); + i--; + } +} + +int *char_to_bin(char c) +{ + int *binary; + int i; + int n; + + binary = ft_calloc(8, sizeof(int)); + if (!binary) + return (NULL); + n = (unsigned int)c; + i = 7; + while (i >= 0) + { + binary[i] = n & 1; + i--; + n >>= 1; + } + return (binary); +} + +int main(int argc, char **argv) +{ + int pid; + int i; + int *bin; + + if (argc == 3) + { + i = 0; + pid = ft_atoi(argv[1]); + while (argv[2][i] != 0) + { + bin = char_to_bin(argv[2][i]); + send_binary(pid, bin); + i++; + free(bin); + } + } + else + write(1, "\nERROR expected: ./execute [pid] [str]\n\n", 43); +} diff --git a/utilities/minitalk/minitalk.h b/utilities/minitalk/minitalk.h new file mode 100644 index 0000000..a75cb66 --- /dev/null +++ b/utilities/minitalk/minitalk.h @@ -0,0 +1,26 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* minitalk.h :+: :+: */ +/* +:+ */ +/* By: fpolycar +#+ */ +/* +#+ */ +/* Created: 2021/12/15 10:52:13 by fpolycar #+# #+# */ +/* Updated: 2021/12/15 13:43:39 by fpolycar ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +#ifndef MINITALK_H +# define MINITALK_H +# include +# include +# include +# include "libft/libft.h" + +typedef struct s_msg +{ + char c; + size_t size; +} t_msg; + +#endif \ No newline at end of file diff --git a/utilities/minitalk/server.c b/utilities/minitalk/server.c new file mode 100644 index 0000000..3ae787b --- /dev/null +++ b/utilities/minitalk/server.c @@ -0,0 +1,59 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* server.c :+: :+: */ +/* +:+ */ +/* By: fpolycar +#+ */ +/* +#+ */ +/* Created: 2021/12/15 10:49:07 by fpolycar #+# #+# */ +/* Updated: 2021/12/15 13:44:26 by fpolycar ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +#include "minitalk.h" + +static t_msg g_msg; + +static void handler_msg(int signum) +{ + g_msg.c += ((signum & 1) << (g_msg.size)); + g_msg.size++; + if (g_msg.size == 8) + { + ft_putchar_fd(g_msg.c, 1); + if (!g_msg.c) + ft_putchar_fd('\n', 1); + g_msg.c = 0; + g_msg.size = 0; + } +} + +void display_pid(void) +{ + int pid; + char *str_pid; + + pid = getpid(); + str_pid = ft_itoa(pid); + if (!str_pid) + { + ft_putendl_fd("Error at ft_itoa()", 1); + return ; + } + ft_putstr_fd("PID: ", 1); + ft_putendl_fd(str_pid, 1); + free(str_pid); +} + +int main(void) +{ + g_msg.c = 0; + g_msg.size = 0; + display_pid(); + while (1) + { + signal(SIGUSR2, handler_msg); + signal(SIGUSR1, handler_msg); + pause(); + } +}