## understanding some things :
- [how to send EOF to stdin of a shell process](https://unix.stackexchange.com/questions/493578/how-to-send-d-eot-character-to-stdin-of-a-shell-process)
	- [get root access 1](https://vitux.com/how-to-become-root-user-in-ubuntu-command-line-using-su-and-sudo/)
	- [get root access using sudo su](https://superuser.com/questions/408990/how-do-i-log-out-of-sudo-su)
- [what is a tty](https://www.howtogeek.com/428174/what-is-a-tty-on-linux-and-how-to-use-the-tty-command/)
- [really handling process](https://stackoverflow.com/questions/47489128/handling-signals-sigstp-sigcont-sigint-with-child-process)
- [signal in a child process](https://stackoverflow.com/questions/55190460/using-signals-in-a-child-process)
- [send signal to process and childs](https://linuxconfig.org/how-to-propagate-a-signal-to-child-processes-from-a-bash-script)
- commande utile pour tester les process parents et enfants :  while true ; do ps -o pid,pgid,cmd -C bash ; sleep 0.1 ; echo "\n" ; done

```text
                                 |     BASH       |    MINISHELL   |
                                 -----------------------------------
                                 | print | action | print | action |
---------------|-----------------|----------------|----------------|
               | SIGINT / ctrl-C |   ^C  |   \n   |   ^C  |  exit  |
       prompt> |-----------------|----------------|----------------|
               |    EOF / ctrl-D |  exit |  exit  |    Ø  |   \n   |
---------------|-----------------|----------------|----------------|
               | SIGINT / ctrl-C | bla^C |   \n   | bla^C |  exit  |
prompt> blabla |-----------------|----------------|----------------|
               |    EOF / ctrl-D |    Ø  |    Ø   |    Ø  |    Ø   |
---------------|-----------------|----------------|----------------|

-> change signal handler for SIGINT, to print a \n instead of exit
-> change when readline receive an EOF and line is empty, to print exit and exit
   -> when readline receive an EOF and line is empty, it return NULL
   -> if line isn't empty it does nothing

```

## sommaire :
---
- [1. todo list :](#markdown-header-1-todo-list)
- [2. external functions :](#markdown-header-2-external-functions)
- [3. parsing :](#markdown-header-3-parsing)
	- [3.1. methode arbre binaire :](#markdown-header-31-methode-arbre-binaire)
- [4. gerer les quotes et la separation des arguments :](#markdown-header-4-gerer-les-quotes-et-la-separation-des-arguments)
	- [4.1. tentative methode 1 :](#markdown-header-41-tentative-methode-1)
		- [4.1.1. pseudo code :](#markdown-header-411-pseudo-code)
		- [4.1.2. application :](#markdown-header-412-application)
		- [4.1.3. erreur :](#markdown-header-413-erreur)
	- [4.2. tentative methode 2 :](#markdown-header-42-tentative-methode-2)
		- [4.2.1. deroulement :](#markdown-header-421-deroulement)
		- [4.2.2. application :](#markdown-header-422-application)
	- [4.3. comportement reel chelou :](#markdown-header-43-comportement-reel-chelou)
- [5. notes :](#markdown-header-5-notes)

## 1. todo list :
---

- **global features :**
	- `prompt` *show a prompt*
	- `history` **? the command history ?**
	- `binaries` *fetch and launch the right executable*
	- `'` `"` `;` `\` **? don't interpret special characters and unclosed quotes ?**
- **pipes :** [video vulgarisation](https://www.youtube.com/watch?v=bKzonnwoR2I)
	- `|` *pipes*
- **expensions :**
	- `$` *variable expension*
	- `$?` *exit return of last executed process* [ressource stackoverflow](https://stackoverflow.com/questions/7248031/meaning-of-dollar-question-mark-in-shell-scripts)
- **quotes :** [ressource](https://linuxhandbook.com/quotes-in-bash/)
	- `'`  *(ignore any special characters)*
	- `"`  *(ignore any special characters except '$')*
- **redirections & heredocs :** [ressource](https://www.gnu.org/software/bash/manual/html_node/Redirections.html) / [heredocs for readability](https://www.techrepublic.com/article/use-heredoc-in-shell-scripts/)
	- `<` *redirect input*
	- `>` *redirect output*
	- `<<` *read input until empty line --* **? doesn't update history ?**
	- `>>` *redirect and append*
- **signals :**
	- `^C` *close process*
	- `^D` *exit minishell*
	- `^\` *do nothing*
- **builtins (can't be executed in child process) :**
	- `cd <relative path>`
	- `cd <absolute path>`
	- `pwd`
	- `export`
	- `unset`
	- ~~`exit`~~
- **builtins (don't need to be) :** [source](https://git.42l.fr/Fabien/minishell)
	- `env`
	- ~~`echo`~~
	- `echo -n`
- **autres :**
	- `termcap` [man](https://www.gnu.org/software/termutils/manual/termcap-1.3/html_chapter/termcap_toc.html)
	- `readline` [man](https://tiswww.case.edu/php/chet/readline/rltop.html) / [second source](https://tiswww.case.edu/php/chet/readline/README)

*[\go to sommaire](#markdown-header-sommaire)*

## 2. external functions :
---
(extracts of manuals)
### readline :
- **readline** : `char *readline (const char *prompt);` will read a line from the terminal and return it, using prompt as a prompt
- **rl_clear_history** : `void rl_clear_history (void)` clear the history list by deleting all of the entries, in the same manner as the History library's clear_history() function
- **rl_on_new_line** : `int rl_on_new_line (void)` tell the update functions that we have moved onto a new (empty) line, usually after outputting a newline
- **rl_replace_line** : `void rl_replace_line (const char *text, int clear_undo)` replace the contents of rl_line_buffer with text. The point and mark are preserved, if possible. If clear_undo is non-zero, the undo list associated with the current line is cleared
- **rl_redisplay** : `void rl_redisplay (void)` change what's displayed on the screen to reflect the current contents of rl_line_buffer
- **add_history** : `bool readline_add_history (string $prompt)` save the line away in a history list of such lines
### files :
- **access** : `int access(const char *pathname, int mode);` checks whether the calling process can access the file pathname
- **open** : `int open(const char *pathname, int flags, [mode_t mode]);` system call opens the file specified by pathname
- **read** : `ssize_t read(int fd, void *buf, size_t count);` attempts to read up to count bytes from file descriptor fd into the buffer starting at buf
- **close** : `int close(int fd);` closes a file descriptor, so that it no longer refers to any file and may be reused
- **dup** : `int dup(int oldfd);` creates a copy of the file descriptor oldfd, using the lowest-numbered unused file descriptor for the new descriptor
- **dup2** : `int dup2(int oldfd, int newfd);` performs the same task as dup(), but instead of using the  lowest-numbered  unused  file descriptor, it uses the file descriptor number specified in newfd
- **pipe** : `int pipe(int pipefd[2]);` creates a pipe, a unidirectional data channel that can be used for interprocess communication. The array pipefd is used to return two file descriptors referring to the ends of the pipe. pipefd[0] refers to the read end of the pipe. pipefd[1] refers to the write end of the pipe
- **stat** : `int stat(const char *pathname, struct stat *statbuf);` returns information about a file, in the buffer pointed to by statbuf
- **lstat** : `int fstat(int fd, struct stat *statbuf);` lstat() is  identical  to stat(), except that if pathname is a symbolic link, then it returns information about the link itself, not the file that it refers to
- **fstat** : `int lstat(const char *pathname, struct stat *statbuf);` fstat() is identical to stat(), except that the file about which information is to be retrieved is specified by the file descriptor fd
- **unlink** : `int unlink(const char *pathname);` unlink() deletes a name from the filesystem
### process :
- **fork** : `pid_t fork(void);` creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process
- **wait** : `pid_t wait(int *wstatus);` suspends execution of the calling process until one of its children terminates. The call wait(&wstatus) is equivalent to: waitpid(-1, &wstatus, 0);
- **waitpid** : `pid_t waitpid(pid_t pid, int *wstatus, int options);` suspends execution of the calling process until a child specified by pid argument has changed state
- **wait3** : `pid_t wait3(int *wstatus, int options, struct rusage *rusage);` obsolete; use waitpid(2). similar to waitpid(2), but additionally return resource usage information about the child in the structure pointed to by rusage
- **wait4** : `pid_t wait4(pid_t pid, int *wstatus, int options, struct rusage *rusage);` like wait3() but additionally can be used to select a specific child
- **exit** : `void exit(int status);` causes normal process termination and the value of status & 0377 is returned to the parent (see wait())
### signals :
- **signal** : `sighandler_t signal(int signum, sighandler_t handler(int));` sets the disposition of the signal signum to handler, which is either SIG_IGN, SIG_DFL, or the address of a  programmer-defined function (a "signal handler")
- **sigaction** : `int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);` change the action taken by a process on receipt of a specific signal. 
- **kill** : `int kill(pid_t pid, int sig);` send any signal to any process group or process
### directories :
- **getcwd** : `char *getcwd(char *buf, size_t size);` returns a null-terminated string containing an absolute pathname that is the current working directory of the calling process
- **chdir** : `int chdir(const char *path);` changes the current working directory of the calling process to the directory specified in path
- **execve** : `int execve(const char *filename, char *const argv[], char *const envp[]);` executes the program pointed to by filename
- **opendir** : `DIR *opendir(const char *name);` opens a directory stream corresponding to the directory name, and returns a pointer to the directory stream
- **readdir** : `struct dirent *readdir(DIR *dirp);` returns a pointer to a dirent structure representing the next directory entry in the directory stream pointed to by dirp
- **closedir** : `int closedir(DIR *dirp);` closes the directory stream associated with dirp
### errors :
- **strerror** : `char *strerror(int errnum);` returns a pointer to a string that describes the error code passed in the argument errnum
- **perror** : `void perror(const char *s);` produces a message on standard error describing the last error encountered during a call to a system or library function
### termcap :
The termcap data base describes the capabilities of hundreds of different display terminals in great detail
The termcap library is provided for easy access this data base in programs that want to do terminal-independent character-based display output

- **tgetent** : `int tgetent (char *buffer, char *termtype);` finds the description of the terminal type and remembers it internally so that you can interrogate it about specific terminal capabilities

Each piece of information recorded in a terminal description is called a capability
There are three functions to use to get the value of a capability :

- **tgetflag** : `int tgetflag (char *name);` get a boolean value
- **tgetnum** : `int tgetnum (char *name);` get a capability value that is numeric
- **tgetstr** : `char *tgetstr (char *name, char **area);` get a string value
- **tgoto** : `char *tgoto (char *cstring, int hpos, int vpos)` encoding numeric parameters such as cursor positions into the terminal-specific form required for display commands
- **tputs** : `int tputs (char *string, int nlines, int (*outfun) ());` output a string containing an optional padding spec
### other :
- **printf** : `int printf(const char *format, ...);` produce output to stdout according to a specified format
- **malloc** : `void *malloc(size_t size);` allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized
- **free** : `void free(void *ptr);` frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc()
- **write** : `ssize_t write(int fd, const void *buf, size_t count);` writes up to <count> bytes from the buffer starting at <buf> to the file referred to by the file descriptor <fd>
- **isatty** : `int isatty(int fd);` tests whether fd is an open file descriptor referring to a terminal
- **ttyname** : `char *ttyname(int fd);` returns a pointer to the null-terminated pathname of the terminal device that is open on the file descriptor fd, or NULL on error (for example, if fd is not connected to a terminal)
- **ttyslot** : `int ttyslot(void);` returns the index of the current user's entry in some file
- **ioctl** : `int ioctl(int fd, unsigned long request, ...);` manipulates the underlying device parameters of special files. In particular, many operating characteristics of character special files (e.g., terminals) may be controlled with ioctl() requests. The argument fd must be an open file descriptor
- **getenv** : `char *getenv(const char *name);` searches the environment list to find the environment variable name, and returns a pointer to the corresponding value string, or NULL if not found
- **tcsetattr** : `int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);` tcsetattr() only works in an environment where either a controlling terminal exists, or stdin and stderr refer to tty devices. Specifically, it does not work in a TSO environment. Changes the attributes associated with a terminal. New attributes are specified with a termios control structure. Programs should always issue a tcgetattr() first, modify the desired fields, and then issue a tcsetattr(). tcsetattr() should never be issued using a termios structure that was not obtained using tcgetattr(). tcsetattr() should use only a termios structure that was obtained by tcgetattr()
- **tcgetattr** : `int tcgetattr(int fildes, struct termios *termptr);` Gets a termios structure, which contains control information for a terminal associated with fildes. It stores that information in a memory location that termptr points to. The contents of a termios structure are described in tcsetattr()


*[\go to sommaire](#markdown-header-sommaire)*

## 3. parsing :
---

### 3.1 methode arbre binaire :

[transformer arbre normal en arbre binaire](https://fr.wikipedia.org/wiki/Arbre_binaire#Transformation_d'un_arbre_quelconque_en_un_arbre_binaire)

```text
ARCHITECTURE :
	all
	expend $
	.	pipes
	.	.	redirections (program function or file)
	.	.	.	arguments (nom arg arg arg ...)
	.	.	.	.
EXEMPLE :	.	.
	[sort < ./prgrm 'arg1 '$VARIABLE" arg3" | grep "word.$EXTENSION" | wc -l > file]
	[sort < ./prgrm 'arg1 'arg2" arg3" | grep "word.md" | wc -l > file]
	.	[sort < ./prgrm 'arg1 'arg2" arg3"]
	.	.	[sort]
	.	.	[./prgrm 'arg1 'arg2" arg3"]
	.	.	.	[./prgrm]
	.	.	.	['arg1 ']
	.	.	.	[arg2]
	.	.	.	[" arg3"]
	.	[grep "word.md"]
	.	.	.	[grep]
	.	.	.	["word.md"]
	.	[wc -l > file]
	.	.	[wc -l]
	.	.	.	[wc]
	.	.	.	[-l]
	.	.	[file]
```

*[\go to sommaire](#markdown-header-sommaire)*

## 4. gerer les quotes et la separation des arguments :
---

### 4.1 tentative methode 1 :

#### 4.1.1 pseudo code :
```text
q = 0  // first quote
c = 0  // count
i = 0
while (str[i])
{
	if (str[i] == ')
	{
		if (q == ')
		{
			c--;
			if (c == 0)
			{
				q = 0;
				create_new_substr;
			}
		}
		else
		{
			c++;
			if (q == 0)
				q = ';
		}
	}
	if (str[i] == ")
	{
		if (q == ")
		{
			c--;
			if (c == 0)
			{
				q = 0;
				create_new_substr;
			}
		}
		else
		{
			c++;
			if (q == 0)
				q = ";
		}
	}
	i++;
}
```

*[\go to sommaire](#markdown-header-sommaire)*

#### 4.1.2 application :
```text
      ['][a][r][g][1][ ]['][a][r][g][2]["][ ][a][r][g][3]["]
c = 0  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
c =    1  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  str[i] == '     ;  q == 0  c == 0  ->  c++; q = '
c =    .  1  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  1  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  1  .  .  .  .  .  .  .  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  1  .  .  .  .  .  .  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  1  .  .  .  .  .  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  0  .  .  .  .  .  .  .  .  .  .  .  str[i] == '     ;  q == '  c == 1  ->  c--; q = 0;
  arg1 = [a][r][g][1][ ]
c =    .  .  .  .  .  .  .  0  .  .  .  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  0  .  .  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  .  0  .  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  .  .  0  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  .  .  .  1  .  .  .  .  .  .  str[i] == "     ;  q != "  c == 0  ->  c++; q = ";
                    arg2 = [a][r][g][2]
c =    .  .  .  .  .  .  .  .  .  .  .  .  1  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  .  .  .  .  .  1  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  .  .  .  .  .  .  1  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  1  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  1  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  0  str[i] == "     ;  q == "  c == 1  ->  c--; q = 0;
                                   arg3 = [ ][a][r][g][3]

      ['][a]["][r]['][g][']["][1][']
c = 0  .  .  .  .  .  .  .  .  .  .  
c =    1  .  .  .  .  .  .  .  .  .  str[i] == '     ;  q == 0  c == 0  ->  c++; q = '
c =    .  1  .  .  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  2  .  .  .  .  .  .  .  str[i] == "     ;  q != "  c == 1  ->  c++;
c =    .  .  .  2  .  .  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  3  .  .  .  .  .  str[i] == ' | " ;  q == '  c == 2  ->  c++;
c =    .  .  .  .  .  3  .  .  .  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  2  .  .  .  str[i] == '     ;  q == '  c == 3  ->  c--; q = 0;
c =    .  .  .  .  .  .  .  1  .  .  str[i] == "     ;  q != "  c == 2  ->
ERROR ...
c =    .  .  .  .  .  .  .  .  1  .  str[i] != ' | " ;                  ->
c =    .  .  .  .  .  .  .  .  .  0  str[i] != ' | " ;                  ->
```

*[\go to sommaire](#markdown-header-sommaire)*

#### 4.1.3 erreur :
->	comment le programme sait que cette fois il doit decrementer "c" ?
	en retenant dans l'ordre toutes les dernieres valeurs de "q" !

->	donc plutot partir sur une recursive

*[\go to sommaire](#markdown-header-sommaire)*

### 4.2 tentative methode 2 :

#### 4.2.1 deroulement :
```text
      .--------------------------------------------.
      :  .--------------------------------------.  :
      :  :  .--------------------------------.  :  :
      :  :  :        .--------.  .--------.  :  :  :
      :  :  :  .--.  :  .--.  :  :  .--.  :  :  :  :
      '__"__'__"__"__"__'__'__"__"__'__'__"__'__"__'
     01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
```
-> identifier les paires de quotes ou dquotes
-> piège :
```text
                              |  |
               .--.     .--.  v  v  .--.
      '__"__'__"__"__"__'__'__"__"__'__'__"__'__"__'
     00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
```

0. envoyer une copie de la str dans une fonction
1. chercher la premiere pair
2. l'effacer
3. recommencer en boucle
4. stop quand la premier quote a trouvé sa paire
5. renvoyer l'emplacement de la pair

*[\go to sommaire](#markdown-header-sommaire)*

#### 4.2.2 application :
```text
               .--.
1 :   '__"__'__"__"__"__'__'__"__"__'__'__"__'__"__'

                        .--.
2 :   '__"__'________"__'__'__"__"__'__'__"__'__"__'

                     .--------.
3 :   '__"__'________"________"__"__'__'__"__'__"__'

                                    .--.
4 :   '__"__'____________________"__'__'__"__'__"__'

                                 .--------.
5 :   '__"__'____________________"________"__'__"__'

            .--------------------------------.
6 :   '__"__'________________________________'__"__'

         .--------------------------------------.
7 :   '__"______________________________________"__'

      .--------------------------------------------.
8 :   '____________________________________________'

```

*[\go to sommaire](#markdown-header-sommaire)*

### 4.3 comportement reel chelou :
```text
echo "_"
_

echo "_'_'_"
_'_'_

echo "_'_"_"_'_"
_'___'_

echo "_'_"_'_'_"_'_" 
_'_____'_

echo "_'_"_'_"_"_'_"_'_"
_'___"_"___'_

echo "_'_"_"_"_"_'_"    
_'_____'_

echo "_'_"_'_"_"_"_"_'_"_'_"
_'___"_"_"_"___'_

echo "_'_"_'_"_'_'_"_'_"_'_"
_'___"___"___'_

echo "_'_"_'_"_'_"_"_'_"_'_"_'_"
_'___"_____"___'_

echo "_'_"_'_"_'_"_'_'_"_'_"_'_"_'_"
_'___"___'_'___"___'_

echo "_'_"_'_"_'_"_'_"_"_'_"_'_"_'_"_'_"
_'___"___'___'___"___'_

echo "_'_"_'_"_'_"_'_"_'_'_"_'_"_'_"_'_"_'_"
_'___"___'_____'___"___'_

echo "_'_"_'_"_'_"_'_"_'_"_"_'_"_'_"_'_"_'_"_'_"
_'___"___'___"_"___'___"___'_

```

*[\go to sommaire](#markdown-header-sommaire)*

## 5. notes :
---

Ordre Interpreteur :
1) Couper les mots (comment faire ? je ne vois pas comment gerer ce genre de bordel ci dessous)
```
shell@prompt> ./arg_test 'mot1 '$NAME" mot2"
	argc = 2
	argv[0] = |./arg_test|
	argv[1] = |mot1 Tour-Lemdows10 mot2|
shell@prompt>
```
2) $ - Env Vars Expand. if $VAR not set, expand to nothing("").
	Dont save it as "" argument for fonctions, just delete.

*[\go to sommaire](#markdown-header-sommaire)*

--------------

Commandes dans variables d'env fonctionne :
```
shell@prompt> export VAR_TEST="echo"
shell@prompt> $VAR_TEST "string :)"
string :)
shell@prompt>
```
*[\go to sommaire](#markdown-header-sommaire)*

--------------

l'expension des variables dans des variables est fait au moment de export(),
donc pas de recursivité infini et de prise de tête au moment de l'interpretation.
Il suffit de faire "une passe" pour dévelloper les variables,
aucun besoin de refaire des passes succesives pour d'éventuels nouvelles variables aprés dévellopement :

```
export :
	export VAR_TEST="test $NAME"
dans l'env :
	NAME="Tour-Lemdows10"
	VAR_TEST="test Tour-Lemdows10"

export :
	export NAME="Un nouveau nom"
dans l'env :
	NAME="Un nouveau nom"
	VAR_TEST="test Tour-Lemdows10"
```
```
export :
	export VAR_TEST="test $VAR_TEST"
dans l'env :
	VAR_TEST="test test Tour-Lemdows10"

export :
	export VAR_TEST="test $VAR_TEST"
dans l'env :
	VAR_TEST="test test test Tour-Lemdows10"
```

*[\go to sommaire](#markdown-header-sommaire)*

-------------------

Tests pour Hugo, pour illustrer les pipes simultanés :
```
sleep 3 ; sleep 3 ; sleep 3 ; sleep 3
sleep 3 | sleep 3 | sleep 3 | sleep 3

sleep 5 ; ls | wc -l
sleep 5 | ls | wc -l
```

*[\go to sommaire](#markdown-header-sommaire)*

-------------------

argv passé à execv(), telle quelle ou aprés avoir trouvé le PATH ?
exemple, si j'apelle "cat file.txt", dans un shell genre bash/zsh,
la commande cat recoit t'elle :
```
argv[0] == "cat"
argv[1] == "file.txt"
```
OU
```
argv[0] == "/bin/cat"
argv[1] == "file.txt"
```

*[\go to sommaire](#markdown-header-sommaire)*

-------------------

A test sur bash et minishell :

	echo "phrase quelquonque" > file1 > file2 > file3

*[\go to sommaire](#markdown-header-sommaire)*

-------------------

Pour les builtins dans une commande simple :
1) detecter la commande builtin
2) Ne pas fork() et execv().
	A la place, chercher la fonction aproprié dans un tableau contenant les pointeurs vers les fonctions builtins.
	Puis appeler la fonction dans le genre : builtin(ft_arrlen(cmd->argv), cmd->argv, &c).


Pour les builtins dans une commande complexe (pipes, redirections, here doc, ...) :
1) detecter la commande builtin
2) fork()
3) Ne pas execv().
	A la place, chercher la fonction aproprié dans un tableau contenant les pointeurs vers les fonctions builtins.
	Puis appeler la fonction dans le genre : builtin(ft_arrlen(cmd->argv), cmd->argv, &c).
4) aprés la fin de la commande, free toute la mémoire du sous_processus, puis quitter le sous_processus en renvoyant le return de la commande builtin.
par exemple comme ça :
	free_exit(&c, builtin(ft_arrlen(cmd->argv), cmd->argv, &c))


Peut-être faire un champ "void *builtin_command" dans une struct "cmd" pour contenir l'adresse de la fonction builtin.
```
typedef struct s_cmd
{
	char	**argv;
	pid_t	pid;
	void	*builtin_command;
}				t_cmd;
```
Si la commande n'est pas builtin

	cmd->builtin_command == NULL.

*[\go to sommaire](#markdown-header-sommaire)*

-------------------

tester comment ce comporte minishell aprés le crash d'une commande (message sigfault comme dans bash ? Autres ?)

*[\go to sommaire](#markdown-header-sommaire)*

-------------------

Implementer les exit status dans les builtins

*[\go to sommaire](#markdown-header-sommaire)*

-------------------

EDIT : Aprés reflexion et verification, ça semble en effet le mieux a faire.
En l'etat le return de la derniere fonction marche correctement, j'ai verifier pas de problemes.
Si le child est deja fini avant l'apelle de wait, ça return quand même.
Cependant, pour optimiser la liberation des resources dés que possible,
il semble plus logique de liberer les sous_processus dés qu'ils ont terminés,
et donc, pas nécessairement dans l'ordre de la pipeline.
Donc, un waitpid() sur la derniere commande pour sauvegarder le retour,
puis wait() pour les autres, l'ordre n'ayant plus d'importance.

Revoir le wait() de mon pipex. Il n'est peut être pas correct.
En effet, j'attend que le premier process se ferme avec waitpid(), puis le deuxiéme, le troisiéme, ...
Mais en faite, il vaudrait peut être mieux attendre qu'un sous process QUELQUONQUE se ferme, puis le suivant, et le suivant, ...

Vu le fonctionnement des pipes, je crois que ce n'est pas toujours la premiere commande qui ce termine en premier,
et donc, qu'il ne faudrait pas attendre la fin de la premiere commande en particulier,
mais d'une commande QUELQUONQUE avec wait() plutot que waitpid().

IDÉE :
Attendre avec waitpid() la derniere commande pour obtenir son status, puis wait() en boucle les autres commandes,
et enfin renvoyer le status.

*[\go to sommaire](#markdown-header-sommaire)*

-------------------

Faire des test avec 

	"env -i ./minishell"
pour voir si ça ne crash pas.

Normal si le comportement attendu n'est pas correct (en l'absence de PATH et tout ça) mais ça ne devrait pas crasher pour autant.

*[\go to sommaire](#markdown-header-sommaire)*

